|
3 | 3 | // Each function and variable below must have a comment linking to the source in node's github repo.
|
4 | 4 |
|
5 | 5 | const path = require('path');
|
6 |
| -const packageJsonReader = require('./node-package-json-reader'); |
7 | 6 | const {JSONParse} = require('./node-primordials');
|
8 | 7 | const {normalizeSlashes} = require('../dist/util');
|
9 | 8 |
|
10 |
| -module.exports.assertScriptCanLoadAsCJSImpl = assertScriptCanLoadAsCJSImpl; |
| 9 | +/** @param {ReturnType<typeof import('./node-package-json-reader').createNodePackageJsonReader>} packageJsonReader */ |
| 10 | +function createNodeCjsLoaderUtils(packageJsonReader) { |
11 | 11 |
|
12 |
| -/** |
13 |
| - * copied from Module._extensions['.js'] |
14 |
| - * https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120 |
15 |
| - * @param {import('../src/index').Service} service |
16 |
| - * @param {NodeJS.Module} module |
17 |
| - * @param {string} filename |
18 |
| - */ |
19 |
| -function assertScriptCanLoadAsCJSImpl(service, module, filename) { |
20 |
| - const pkg = readPackageScope(filename); |
| 12 | + /** |
| 13 | + * copied from Module._extensions['.js'] |
| 14 | + * https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120 |
| 15 | + * @param {import('../src/index').Service} service |
| 16 | + * @param {NodeJS.Module} module |
| 17 | + * @param {string} filename |
| 18 | + */ |
| 19 | + function assertScriptCanLoadAsCJSImpl(service, module, filename) { |
| 20 | + const pkg = readPackageScope(filename); |
21 | 21 |
|
22 |
| - // ts-node modification: allow our configuration to override |
23 |
| - const tsNodeClassification = service.moduleTypeClassifier.classifyModule(normalizeSlashes(filename)); |
24 |
| - if(tsNodeClassification.moduleType === 'cjs') return; |
| 22 | + // ts-node modification: allow our configuration to override |
| 23 | + const tsNodeClassification = service.moduleTypeClassifier.classifyModule(normalizeSlashes(filename)); |
| 24 | + if(tsNodeClassification.moduleType === 'cjs') return; |
25 | 25 |
|
26 |
| - // Function require shouldn't be used in ES modules. |
27 |
| - if (tsNodeClassification.moduleType === 'esm' || (pkg && pkg.data && pkg.data.type === 'module')) { |
28 |
| - const parentPath = module.parent && module.parent.filename; |
29 |
| - const packageJsonPath = pkg ? path.resolve(pkg.path, 'package.json') : null; |
30 |
| - throw createErrRequireEsm(filename, parentPath, packageJsonPath); |
| 26 | + // Function require shouldn't be used in ES modules. |
| 27 | + if (tsNodeClassification.moduleType === 'esm' || (pkg && pkg.data && pkg.data.type === 'module')) { |
| 28 | + const parentPath = module.parent && module.parent.filename; |
| 29 | + const packageJsonPath = pkg ? path.resolve(pkg.path, 'package.json') : null; |
| 30 | + throw createErrRequireEsm(filename, parentPath, packageJsonPath); |
| 31 | + } |
31 | 32 | }
|
32 |
| -} |
33 | 33 |
|
34 |
| -// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L285-L301 |
35 |
| -function readPackageScope(checkPath) { |
36 |
| - const rootSeparatorIndex = checkPath.indexOf(path.sep); |
37 |
| - let separatorIndex; |
38 |
| - while ( |
39 |
| - (separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex |
40 |
| - ) { |
41 |
| - checkPath = checkPath.slice(0, separatorIndex); |
42 |
| - if (checkPath.endsWith(path.sep + 'node_modules')) |
43 |
| - return false; |
44 |
| - const pjson = readPackage(checkPath); |
45 |
| - if (pjson) return { |
46 |
| - path: checkPath, |
47 |
| - data: pjson |
48 |
| - }; |
| 34 | + // Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L285-L301 |
| 35 | + function readPackageScope(checkPath) { |
| 36 | + const rootSeparatorIndex = checkPath.indexOf(path.sep); |
| 37 | + let separatorIndex; |
| 38 | + while ( |
| 39 | + (separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex |
| 40 | + ) { |
| 41 | + checkPath = checkPath.slice(0, separatorIndex); |
| 42 | + if (checkPath.endsWith(path.sep + 'node_modules')) |
| 43 | + return false; |
| 44 | + const pjson = readPackage(checkPath); |
| 45 | + if (pjson) return { |
| 46 | + path: checkPath, |
| 47 | + data: pjson |
| 48 | + }; |
| 49 | + } |
| 50 | + return false; |
49 | 51 | }
|
50 |
| - return false; |
51 |
| -} |
52 | 52 |
|
53 |
| -// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L249 |
54 |
| -const packageJsonCache = new Map(); |
| 53 | + // Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L249 |
| 54 | + const packageJsonCache = new Map(); |
55 | 55 |
|
56 |
| -// Copied from https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L275-L304 |
57 |
| -function readPackage(requestPath) { |
58 |
| - const jsonPath = path.resolve(requestPath, 'package.json'); |
| 56 | + // Copied from https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L275-L304 |
| 57 | + function readPackage(requestPath) { |
| 58 | + const jsonPath = path.resolve(requestPath, 'package.json'); |
59 | 59 |
|
60 |
| - const existing = packageJsonCache.get(jsonPath); |
61 |
| - if (existing !== undefined) return existing; |
| 60 | + const existing = packageJsonCache.get(jsonPath); |
| 61 | + if (existing !== undefined) return existing; |
62 | 62 |
|
63 |
| - const result = packageJsonReader.read(jsonPath); |
64 |
| - const json = result.containsKeys === false ? '{}' : result.string; |
65 |
| - if (json === undefined) { |
66 |
| - packageJsonCache.set(jsonPath, false); |
67 |
| - return false; |
68 |
| - } |
| 63 | + const result = packageJsonReader.read(jsonPath); |
| 64 | + const json = result.containsKeys === false ? '{}' : result.string; |
| 65 | + if (json === undefined) { |
| 66 | + packageJsonCache.set(jsonPath, false); |
| 67 | + return false; |
| 68 | + } |
69 | 69 |
|
70 |
| - try { |
71 |
| - const parsed = JSONParse(json); |
72 |
| - const filtered = { |
73 |
| - name: parsed.name, |
74 |
| - main: parsed.main, |
75 |
| - exports: parsed.exports, |
76 |
| - imports: parsed.imports, |
77 |
| - type: parsed.type |
78 |
| - }; |
79 |
| - packageJsonCache.set(jsonPath, filtered); |
80 |
| - return filtered; |
81 |
| - } catch (e) { |
82 |
| - e.path = jsonPath; |
83 |
| - e.message = 'Error parsing ' + jsonPath + ': ' + e.message; |
84 |
| - throw e; |
| 70 | + try { |
| 71 | + const parsed = JSONParse(json); |
| 72 | + const filtered = { |
| 73 | + name: parsed.name, |
| 74 | + main: parsed.main, |
| 75 | + exports: parsed.exports, |
| 76 | + imports: parsed.imports, |
| 77 | + type: parsed.type |
| 78 | + }; |
| 79 | + packageJsonCache.set(jsonPath, filtered); |
| 80 | + return filtered; |
| 81 | + } catch (e) { |
| 82 | + e.path = jsonPath; |
| 83 | + e.message = 'Error parsing ' + jsonPath + ': ' + e.message; |
| 84 | + throw e; |
| 85 | + } |
85 | 86 | }
|
86 |
| -} |
87 | 87 |
|
88 |
| -// Native ERR_REQUIRE_ESM Error is declared here: |
89 |
| -// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L1294-L1313 |
90 |
| -// Error class factory is implemented here: |
91 |
| -// function E: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L323-L341 |
92 |
| -// function makeNodeErrorWithCode: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L251-L278 |
93 |
| -// The code below should create an error that matches the native error as closely as possible. |
94 |
| -// Third-party libraries which attempt to catch the native ERR_REQUIRE_ESM should recognize our imitation error. |
95 |
| -function createErrRequireEsm(filename, parentPath, packageJsonPath) { |
96 |
| - const code = 'ERR_REQUIRE_ESM' |
97 |
| - const err = new Error(getMessage(filename, parentPath, packageJsonPath)) |
98 |
| - // Set `name` to be used in stack trace, generate stack trace with that name baked in, then re-declare the `name` field. |
99 |
| - // This trick is copied from node's source. |
100 |
| - err.name = `Error [${ code }]` |
101 |
| - err.stack |
102 |
| - Object.defineProperty(err, 'name', { |
103 |
| - value: 'Error', |
104 |
| - enumerable: false, |
105 |
| - writable: true, |
106 |
| - configurable: true |
107 |
| - }) |
108 |
| - err.code = code |
109 |
| - return err |
| 88 | + // Native ERR_REQUIRE_ESM Error is declared here: |
| 89 | + // https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L1294-L1313 |
| 90 | + // Error class factory is implemented here: |
| 91 | + // function E: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L323-L341 |
| 92 | + // function makeNodeErrorWithCode: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L251-L278 |
| 93 | + // The code below should create an error that matches the native error as closely as possible. |
| 94 | + // Third-party libraries which attempt to catch the native ERR_REQUIRE_ESM should recognize our imitation error. |
| 95 | + function createErrRequireEsm(filename, parentPath, packageJsonPath) { |
| 96 | + const code = 'ERR_REQUIRE_ESM' |
| 97 | + const err = new Error(getMessage(filename, parentPath, packageJsonPath)) |
| 98 | + // Set `name` to be used in stack trace, generate stack trace with that name baked in, then re-declare the `name` field. |
| 99 | + // This trick is copied from node's source. |
| 100 | + err.name = `Error [${ code }]` |
| 101 | + err.stack |
| 102 | + Object.defineProperty(err, 'name', { |
| 103 | + value: 'Error', |
| 104 | + enumerable: false, |
| 105 | + writable: true, |
| 106 | + configurable: true |
| 107 | + }) |
| 108 | + err.code = code |
| 109 | + return err |
110 | 110 |
|
111 |
| - // Copy-pasted from https://github.com/nodejs/node/blob/b533fb3508009e5f567cc776daba8fbf665386a6/lib/internal/errors.js#L1293-L1311 |
112 |
| - // so that our error message is identical to the native message. |
113 |
| - function getMessage(filename, parentPath = null, packageJsonPath = null) { |
114 |
| - const ext = path.extname(filename) |
115 |
| - let msg = `Must use import to load ES Module: ${filename}`; |
116 |
| - if (parentPath && packageJsonPath) { |
117 |
| - const path = require('path'); |
118 |
| - const basename = path.basename(filename) === path.basename(parentPath) ? |
119 |
| - filename : path.basename(filename); |
120 |
| - msg += |
121 |
| - '\nrequire() of ES modules is not supported.\nrequire() of ' + |
122 |
| - `${filename} ${parentPath ? `from ${parentPath} ` : ''}` + |
123 |
| - `is an ES module file as it is a ${ext} file whose nearest parent ` + |
124 |
| - `package.json contains "type": "module" which defines all ${ext} ` + |
125 |
| - 'files in that package scope as ES modules.\nInstead ' + |
126 |
| - 'change the requiring code to use ' + |
127 |
| - 'import(), or remove "type": "module" from ' + |
128 |
| - `${packageJsonPath}.\n`; |
| 111 | + // Copy-pasted from https://github.com/nodejs/node/blob/b533fb3508009e5f567cc776daba8fbf665386a6/lib/internal/errors.js#L1293-L1311 |
| 112 | + // so that our error message is identical to the native message. |
| 113 | + function getMessage(filename, parentPath = null, packageJsonPath = null) { |
| 114 | + const ext = path.extname(filename) |
| 115 | + let msg = `Must use import to load ES Module: ${filename}`; |
| 116 | + if (parentPath && packageJsonPath) { |
| 117 | + const path = require('path'); |
| 118 | + const basename = path.basename(filename) === path.basename(parentPath) ? |
| 119 | + filename : path.basename(filename); |
| 120 | + msg += |
| 121 | + '\nrequire() of ES modules is not supported.\nrequire() of ' + |
| 122 | + `${filename} ${parentPath ? `from ${parentPath} ` : ''}` + |
| 123 | + `is an ES module file as it is a ${ext} file whose nearest parent ` + |
| 124 | + `package.json contains "type": "module" which defines all ${ext} ` + |
| 125 | + 'files in that package scope as ES modules.\nInstead ' + |
| 126 | + 'change the requiring code to use ' + |
| 127 | + 'import(), or remove "type": "module" from ' + |
| 128 | + `${packageJsonPath}.\n`; |
| 129 | + return msg; |
| 130 | + } |
129 | 131 | return msg;
|
130 | 132 | }
|
131 |
| - return msg; |
132 | 133 | }
|
| 134 | + |
| 135 | + return {assertScriptCanLoadAsCJSImpl}; |
133 | 136 | }
|
| 137 | + |
| 138 | +module.exports.createNodeCjsLoaderUtils = createNodeCjsLoaderUtils; |
0 commit comments