@knighted/module 1.0.0-beta.1 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -4
- package/dist/cjs/format.cjs +414 -12
- package/dist/cjs/formatters/identifier.cjs +5 -1
- package/dist/cjs/formatters/memberExpression.cjs +12 -12
- package/dist/cjs/formatters/metaProperty.cjs +19 -1
- package/dist/cjs/memberExpression.d.cts +1 -1
- package/dist/cjs/module.cjs +1 -0
- package/dist/cjs/types.d.cts +1 -0
- package/dist/format.js +413 -12
- package/dist/formatters/identifier.js +5 -1
- package/dist/formatters/memberExpression.js +12 -12
- package/dist/formatters/metaProperty.js +19 -1
- package/dist/memberExpression.d.ts +1 -1
- package/dist/module.js +1 -0
- package/dist/src/formatters/identifier.d.ts +2 -1
- package/dist/src/formatters/memberExpression.d.ts +1 -1
- package/dist/src/types.d.ts +1 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ Node.js utility for transforming a JavaScript or TypeScript file from an ES modu
|
|
|
9
9
|
- ES module ➡️ CommonJS
|
|
10
10
|
- CommonJS ➡️ ES module
|
|
11
11
|
|
|
12
|
+
Highlights
|
|
13
|
+
|
|
14
|
+
- Defaults to safe CommonJS output: strict live bindings, import.meta shims, and specifier preservation.
|
|
15
|
+
- Opt into stricter/looser behaviors: live binding enforcement, import.meta.main gating, and top-level await strategies.
|
|
16
|
+
- Can optionally rewrite relative specifiers and write transformed output to disk.
|
|
17
|
+
|
|
12
18
|
> [!IMPORTANT]
|
|
13
19
|
> All parsing logic is applied under the assumption the code is in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) which [modules run under by default](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#other_differences_between_modules_and_classic_scripts).
|
|
14
20
|
|
|
@@ -18,9 +24,15 @@ By default `@knighted/module` transforms the one-to-one [differences between ES
|
|
|
18
24
|
|
|
19
25
|
- Node >= 20.11.0
|
|
20
26
|
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @knighted/module
|
|
31
|
+
```
|
|
32
|
+
|
|
21
33
|
## Example
|
|
22
34
|
|
|
23
|
-
Given an ES module
|
|
35
|
+
Given an ES module:
|
|
24
36
|
|
|
25
37
|
**file.js**
|
|
26
38
|
|
|
@@ -40,7 +52,7 @@ const detectCalledFromCli = async path => {
|
|
|
40
52
|
detectCalledFromCli(argv[1])
|
|
41
53
|
```
|
|
42
54
|
|
|
43
|
-
|
|
55
|
+
Transform it to CommonJS:
|
|
44
56
|
|
|
45
57
|
```js
|
|
46
58
|
import { transform } from '@knighted/module'
|
|
@@ -51,7 +63,7 @@ await transform('./file.js', {
|
|
|
51
63
|
})
|
|
52
64
|
```
|
|
53
65
|
|
|
54
|
-
Which produces
|
|
66
|
+
Which produces:
|
|
55
67
|
|
|
56
68
|
**file.cjs**
|
|
57
69
|
|
|
@@ -99,6 +111,7 @@ type ModuleOptions = {
|
|
|
99
111
|
| ((value: string) => string | null | undefined)
|
|
100
112
|
dirFilename?: 'inject' | 'preserve' | 'error'
|
|
101
113
|
importMeta?: 'preserve' | 'shim' | 'error'
|
|
114
|
+
importMetaMain?: 'shim' | 'warn' | 'error'
|
|
102
115
|
requireSource?: 'builtin' | 'create-require'
|
|
103
116
|
cjsDefault?: 'module-exports' | 'auto' | 'none'
|
|
104
117
|
topLevelAwait?: 'error' | 'wrap' | 'preserve'
|
|
@@ -107,7 +120,24 @@ type ModuleOptions = {
|
|
|
107
120
|
}
|
|
108
121
|
```
|
|
109
122
|
|
|
123
|
+
Behavior notes (defaults in parentheses)
|
|
124
|
+
|
|
125
|
+
- `target` (`commonjs`): output module system.
|
|
126
|
+
- `transformSyntax` (true): enable/disable the ESM↔CJS lowering pass.
|
|
127
|
+
- `liveBindings` (`strict`): getter-based live bindings, or snapshot (`loose`/`off`).
|
|
128
|
+
- `dirFilename` (`inject`): inject `__dirname`/`__filename`, preserve existing, or throw.
|
|
129
|
+
- `importMeta` (`shim`): rewrite `import.meta.*` to CommonJS equivalents.
|
|
130
|
+
- `importMetaMain` (`shim`): gate `import.meta.main` with shimming/warning/error when Node support is too old.
|
|
131
|
+
- `topLevelAwait` (`error`): throw, wrap, or preserve when TLA appears in CommonJS output.
|
|
132
|
+
- `rewriteSpecifier` (off): rewrite relative specifiers to a chosen extension or via a callback.
|
|
133
|
+
- `requireSource` (`builtin`): whether `require` comes from Node or `createRequire`.
|
|
134
|
+
- `cjsDefault` (`auto`): bundler-style default interop vs direct `module.exports`.
|
|
135
|
+
- `out`/`inPlace`: write the transformed code to a file; otherwise the function returns the transformed string only.
|
|
136
|
+
|
|
137
|
+
See [docs/esm-to-cjs.md](docs/esm-to-cjs.md) for deeper notes on live bindings, interop helpers, top-level await behavior, and `import.meta.main` handling. For CommonJS to ESM lowering details, read [docs/cjs-to-esm.md](docs/cjs-to-esm.md).
|
|
138
|
+
|
|
110
139
|
## Roadmap
|
|
111
140
|
|
|
112
141
|
- Remove `@knighted/specifier` and avoid double parsing.
|
|
113
|
-
-
|
|
142
|
+
- Emit source maps and clearer diagnostics for transform choices.
|
|
143
|
+
- Broaden fixtures covering live-binding and top-level await edge cases across Node versions.
|
package/dist/cjs/format.cjs
CHANGED
|
@@ -15,6 +15,313 @@ var _identifiers = require("#utils/identifiers.js");
|
|
|
15
15
|
var _identifier2 = require("#helpers/identifier.js");
|
|
16
16
|
var _walk = require("#walk");
|
|
17
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
|
+
const isValidIdent = name => /^[$A-Z_a-z][$\w]*$/.test(name);
|
|
19
|
+
const exportAssignment = (name, expr, live) => {
|
|
20
|
+
const prop = isValidIdent(name) ? `.${name}` : `[${JSON.stringify(name)}]`;
|
|
21
|
+
if (live === 'strict') {
|
|
22
|
+
const key = JSON.stringify(name);
|
|
23
|
+
return `Object.defineProperty(exports, ${key}, { enumerable: true, get: () => ${expr} });`;
|
|
24
|
+
}
|
|
25
|
+
return `exports${prop} = ${expr};`;
|
|
26
|
+
};
|
|
27
|
+
const defaultInteropName = '__interopDefault';
|
|
28
|
+
const interopHelper = `const ${defaultInteropName} = mod => (mod && mod.__esModule ? mod.default : mod);\n`;
|
|
29
|
+
const isRequireCallee = (callee, shadowed) => {
|
|
30
|
+
if (callee.type === 'Identifier' && callee.name === 'require' && !shadowed.has('require')) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'module' && !shadowed.has('module') && callee.property.type === 'Identifier' && callee.property.name === 'require') {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
const isStaticRequire = (node, shadowed) => node.type === 'CallExpression' && isRequireCallee(node.callee, shadowed) && node.arguments.length === 1 && node.arguments[0].type === 'Literal' && typeof node.arguments[0].value === 'string';
|
|
39
|
+
const isRequireCall = (node, shadowed) => node.type === 'CallExpression' && isRequireCallee(node.callee, shadowed);
|
|
40
|
+
const lowerCjsRequireToImports = (program, code, shadowed) => {
|
|
41
|
+
const transforms = [];
|
|
42
|
+
const imports = [];
|
|
43
|
+
let nsIndex = 0;
|
|
44
|
+
let needsCreateRequire = false;
|
|
45
|
+
for (const stmt of program.body) {
|
|
46
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
47
|
+
const decls = stmt.declarations;
|
|
48
|
+
const allStatic = decls.length > 0 && decls.every(decl => decl.init && isStaticRequire(decl.init, shadowed));
|
|
49
|
+
if (allStatic) {
|
|
50
|
+
for (const decl of decls) {
|
|
51
|
+
const init = decl.init;
|
|
52
|
+
const source = code.slice(init.arguments[0].start, init.arguments[0].end);
|
|
53
|
+
if (decl.id.type === 'Identifier') {
|
|
54
|
+
imports.push(`import * as ${decl.id.name} from ${source};\n`);
|
|
55
|
+
} else if (decl.id.type === 'ObjectPattern') {
|
|
56
|
+
const ns = `__cjsImport${nsIndex++}`;
|
|
57
|
+
const pattern = code.slice(decl.id.start, decl.id.end);
|
|
58
|
+
imports.push(`import * as ${ns} from ${source};\n`);
|
|
59
|
+
imports.push(`const ${pattern} = ${ns};\n`);
|
|
60
|
+
} else {
|
|
61
|
+
needsCreateRequire = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
transforms.push({
|
|
65
|
+
start: stmt.start,
|
|
66
|
+
end: stmt.end,
|
|
67
|
+
code: ';\n'
|
|
68
|
+
});
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
for (const decl of decls) {
|
|
72
|
+
const init = decl.init;
|
|
73
|
+
if (init && isRequireCall(init, shadowed)) {
|
|
74
|
+
needsCreateRequire = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (stmt.type === 'ExpressionStatement') {
|
|
79
|
+
const expr = stmt.expression;
|
|
80
|
+
if (expr && isStaticRequire(expr, shadowed)) {
|
|
81
|
+
const source = code.slice(expr.arguments[0].start, expr.arguments[0].end);
|
|
82
|
+
imports.push(`import ${source};\n`);
|
|
83
|
+
transforms.push({
|
|
84
|
+
start: stmt.start,
|
|
85
|
+
end: stmt.end,
|
|
86
|
+
code: ';\n'
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (expr && isRequireCall(expr, shadowed)) {
|
|
91
|
+
needsCreateRequire = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
transforms,
|
|
97
|
+
imports,
|
|
98
|
+
needsCreateRequire
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
const isRequireMainMember = (node, shadowed) => node && node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'require' && !shadowed.has('require') && node.property.type === 'Identifier' && node.property.name === 'main';
|
|
102
|
+
const hasTopLevelAwait = program => {
|
|
103
|
+
let found = false;
|
|
104
|
+
const walkNode = (node, inFunction) => {
|
|
105
|
+
if (found) return;
|
|
106
|
+
switch (node.type) {
|
|
107
|
+
case 'FunctionDeclaration':
|
|
108
|
+
case 'FunctionExpression':
|
|
109
|
+
case 'ArrowFunctionExpression':
|
|
110
|
+
case 'ClassDeclaration':
|
|
111
|
+
case 'ClassExpression':
|
|
112
|
+
inFunction = true;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
if (!inFunction && node.type === 'AwaitExpression') {
|
|
116
|
+
found = true;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const keys = Object.keys(node);
|
|
120
|
+
for (const key of keys) {
|
|
121
|
+
const value = node[key];
|
|
122
|
+
if (!value) continue;
|
|
123
|
+
if (Array.isArray(value)) {
|
|
124
|
+
for (const item of value) {
|
|
125
|
+
if (item && typeof item === 'object') {
|
|
126
|
+
walkNode(item, inFunction);
|
|
127
|
+
if (found) return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} else if (value && typeof value === 'object') {
|
|
131
|
+
walkNode(value, inFunction);
|
|
132
|
+
if (found) return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
walkNode(program, false);
|
|
137
|
+
return found;
|
|
138
|
+
};
|
|
139
|
+
const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
|
|
140
|
+
const live = opts.liveBindings ?? 'strict';
|
|
141
|
+
const importTransforms = [];
|
|
142
|
+
const exportTransforms = [];
|
|
143
|
+
let needsInterop = false;
|
|
144
|
+
let importIndex = 0;
|
|
145
|
+
for (const node of program.body) {
|
|
146
|
+
if (node.type === 'ImportDeclaration') {
|
|
147
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
148
|
+
const specifiers = node.specifiers ?? [];
|
|
149
|
+
const defaultSpec = specifiers.find(s => s.type === 'ImportDefaultSpecifier');
|
|
150
|
+
const namespaceSpec = specifiers.find(s => s.type === 'ImportNamespaceSpecifier');
|
|
151
|
+
const namedSpecs = specifiers.filter(s => s.type === 'ImportSpecifier');
|
|
152
|
+
|
|
153
|
+
// Side-effect import
|
|
154
|
+
if (!specifiers.length) {
|
|
155
|
+
importTransforms.push({
|
|
156
|
+
start: node.start,
|
|
157
|
+
end: node.end,
|
|
158
|
+
code: `require(${srcLiteral});\n`,
|
|
159
|
+
needsInterop: false
|
|
160
|
+
});
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const modIdent = `__mod${importIndex++}`;
|
|
164
|
+
const lines = [];
|
|
165
|
+
lines.push(`const ${modIdent} = require(${srcLiteral});`);
|
|
166
|
+
if (namespaceSpec) {
|
|
167
|
+
lines.push(`const ${namespaceSpec.local.name} = ${modIdent};`);
|
|
168
|
+
}
|
|
169
|
+
if (defaultSpec) {
|
|
170
|
+
let init = modIdent;
|
|
171
|
+
switch (opts.cjsDefault) {
|
|
172
|
+
case 'module-exports':
|
|
173
|
+
init = modIdent;
|
|
174
|
+
break;
|
|
175
|
+
case 'none':
|
|
176
|
+
init = `${modIdent}.default`;
|
|
177
|
+
break;
|
|
178
|
+
case 'auto':
|
|
179
|
+
default:
|
|
180
|
+
init = `${defaultInteropName}(${modIdent})`;
|
|
181
|
+
needsInterop = true;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
lines.push(`const ${defaultSpec.local.name} = ${init};`);
|
|
185
|
+
}
|
|
186
|
+
if (namedSpecs.length) {
|
|
187
|
+
const pairs = namedSpecs.map(s => {
|
|
188
|
+
const imported = s.imported.name;
|
|
189
|
+
const local = s.local.name;
|
|
190
|
+
return imported === local ? imported : `${imported}: ${local}`;
|
|
191
|
+
});
|
|
192
|
+
lines.push(`const { ${pairs.join(', ')} } = ${modIdent};`);
|
|
193
|
+
}
|
|
194
|
+
importTransforms.push({
|
|
195
|
+
start: node.start,
|
|
196
|
+
end: node.end,
|
|
197
|
+
code: `${lines.join('\n')}\n`,
|
|
198
|
+
needsInterop
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
202
|
+
// Handle declaration exports
|
|
203
|
+
if (node.declaration) {
|
|
204
|
+
const decl = node.declaration;
|
|
205
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
206
|
+
const exportedNames = [];
|
|
207
|
+
if (decl.type === 'VariableDeclaration') {
|
|
208
|
+
for (const d of decl.declarations) {
|
|
209
|
+
if (d.id.type === 'Identifier') {
|
|
210
|
+
exportedNames.push(d.id.name);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} else if (decl.id?.type === 'Identifier') {
|
|
214
|
+
exportedNames.push(decl.id.name);
|
|
215
|
+
}
|
|
216
|
+
const exportLines = exportedNames.map(name => exportAssignment(name, name, live));
|
|
217
|
+
exportTransforms.push({
|
|
218
|
+
start: node.start,
|
|
219
|
+
end: node.end,
|
|
220
|
+
code: `${declSrc}\n${exportLines.join('\n')}\n`
|
|
221
|
+
});
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Handle re-export or local specifiers
|
|
226
|
+
if (node.specifiers?.length) {
|
|
227
|
+
if (node.source) {
|
|
228
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
229
|
+
const modIdent = `__mod${importIndex++}`;
|
|
230
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`];
|
|
231
|
+
for (const spec of node.specifiers) {
|
|
232
|
+
if (spec.type !== 'ExportSpecifier') continue;
|
|
233
|
+
const exported = spec.exported.name;
|
|
234
|
+
const imported = spec.local.name;
|
|
235
|
+
let rhs = `${modIdent}.${imported}`;
|
|
236
|
+
if (imported === 'default') {
|
|
237
|
+
rhs = `${defaultInteropName}(${modIdent})`;
|
|
238
|
+
needsInterop = true;
|
|
239
|
+
}
|
|
240
|
+
lines.push(exportAssignment(exported, rhs, live));
|
|
241
|
+
}
|
|
242
|
+
exportTransforms.push({
|
|
243
|
+
start: node.start,
|
|
244
|
+
end: node.end,
|
|
245
|
+
code: `${lines.join('\n')}\n`,
|
|
246
|
+
needsInterop
|
|
247
|
+
});
|
|
248
|
+
} else {
|
|
249
|
+
const lines = [];
|
|
250
|
+
for (const spec of node.specifiers) {
|
|
251
|
+
if (spec.type !== 'ExportSpecifier') continue;
|
|
252
|
+
const exported = spec.exported.name;
|
|
253
|
+
const local = spec.local.name;
|
|
254
|
+
lines.push(exportAssignment(exported, local, live));
|
|
255
|
+
}
|
|
256
|
+
exportTransforms.push({
|
|
257
|
+
start: node.start,
|
|
258
|
+
end: node.end,
|
|
259
|
+
code: `${lines.join('\n')}\n`
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
265
|
+
const decl = node.declaration;
|
|
266
|
+
const useExportsObject = containsTopLevelAwait && opts.topLevelAwait !== 'error';
|
|
267
|
+
if (decl.type === 'FunctionDeclaration' || decl.type === 'ClassDeclaration') {
|
|
268
|
+
if (decl.id?.name) {
|
|
269
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
270
|
+
const assign = useExportsObject ? `exports.default = ${decl.id.name};` : `module.exports = ${decl.id.name};`;
|
|
271
|
+
exportTransforms.push({
|
|
272
|
+
start: node.start,
|
|
273
|
+
end: node.end,
|
|
274
|
+
code: `${declSrc}\n${assign}\n`
|
|
275
|
+
});
|
|
276
|
+
} else {
|
|
277
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
278
|
+
const assign = useExportsObject ? `exports.default = ${declSrc};` : `module.exports = ${declSrc};`;
|
|
279
|
+
exportTransforms.push({
|
|
280
|
+
start: node.start,
|
|
281
|
+
end: node.end,
|
|
282
|
+
code: `${assign}\n`
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
const exprSrc = code.slice(decl.start, decl.end);
|
|
287
|
+
const assign = useExportsObject ? `exports.default = ${exprSrc};` : `module.exports = ${exprSrc};`;
|
|
288
|
+
exportTransforms.push({
|
|
289
|
+
start: node.start,
|
|
290
|
+
end: node.end,
|
|
291
|
+
code: `${assign}\n`
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (node.type === 'ExportAllDeclaration') {
|
|
296
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
297
|
+
if (node.exported) {
|
|
298
|
+
const exported = node.exported.name;
|
|
299
|
+
const modIdent = `__mod${importIndex++}`;
|
|
300
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`, exportAssignment(exported, modIdent, live)];
|
|
301
|
+
exportTransforms.push({
|
|
302
|
+
start: node.start,
|
|
303
|
+
end: node.end,
|
|
304
|
+
code: `${lines.join('\n')}\n`
|
|
305
|
+
});
|
|
306
|
+
} else {
|
|
307
|
+
const modIdent = `__mod${importIndex++}`;
|
|
308
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`];
|
|
309
|
+
const loop = `for (const k in ${modIdent}) {\n if (k === 'default') continue;\n if (!Object.prototype.hasOwnProperty.call(${modIdent}, k)) continue;\n Object.defineProperty(exports, k, { enumerable: true, get: () => ${modIdent}[k] });\n}`;
|
|
310
|
+
lines.push(loop);
|
|
311
|
+
exportTransforms.push({
|
|
312
|
+
start: node.start,
|
|
313
|
+
end: node.end,
|
|
314
|
+
code: `${lines.join('\n')}\n`
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
importTransforms,
|
|
321
|
+
exportTransforms,
|
|
322
|
+
needsInterop
|
|
323
|
+
};
|
|
324
|
+
};
|
|
18
325
|
/**
|
|
19
326
|
* Node added support for import.meta.main.
|
|
20
327
|
* Added in: v24.2.0, v22.18.0
|
|
@@ -28,21 +335,67 @@ const format = async (src, ast, opts) => {
|
|
|
28
335
|
hasDefaultExportBeenReassigned: false,
|
|
29
336
|
hasDefaultExportBeenAssigned: false
|
|
30
337
|
};
|
|
31
|
-
const
|
|
32
|
-
|
|
338
|
+
const moduleIdentifiers = await (0, _identifiers.collectModuleIdentifiers)(ast.program);
|
|
339
|
+
const shadowedBindings = new Set([...moduleIdentifiers.entries()].filter(([, meta]) => meta.declare.length > 0).map(([name]) => name));
|
|
33
340
|
if (opts.target === 'module' && opts.transformSyntax) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
341
|
+
if (shadowedBindings.has('module') || shadowedBindings.has('exports')) {
|
|
342
|
+
throw new Error('Cannot transform to ESM: module or exports is shadowed in module scope.');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const exportTable = opts.target === 'module' ? await (0, _exports.collectCjsExports)(ast.program) : null;
|
|
346
|
+
const shouldCheckTopLevelAwait = opts.target === 'commonjs' && opts.transformSyntax;
|
|
347
|
+
const containsTopLevelAwait = shouldCheckTopLevelAwait ? hasTopLevelAwait(ast.program) : false;
|
|
348
|
+
const shouldLowerCjs = opts.target === 'commonjs' && opts.transformSyntax;
|
|
349
|
+
const shouldRaiseEsm = opts.target === 'module' && opts.transformSyntax;
|
|
350
|
+
let hoistedImports = [];
|
|
351
|
+
let pendingRequireTransforms = [];
|
|
352
|
+
let needsCreateRequire = false;
|
|
353
|
+
let pendingCjsTransforms = null;
|
|
354
|
+
if (shouldLowerCjs && opts.topLevelAwait === 'error' && containsTopLevelAwait) {
|
|
355
|
+
throw new Error('Top-level await is not supported when targeting CommonJS (set topLevelAwait to "wrap" or "preserve" to override).');
|
|
356
|
+
}
|
|
357
|
+
if (shouldRaiseEsm) {
|
|
358
|
+
const {
|
|
359
|
+
transforms,
|
|
360
|
+
imports,
|
|
361
|
+
needsCreateRequire: reqCreate
|
|
362
|
+
} = lowerCjsRequireToImports(ast.program, code, shadowedBindings);
|
|
363
|
+
pendingRequireTransforms = transforms;
|
|
364
|
+
hoistedImports = imports;
|
|
365
|
+
needsCreateRequire = reqCreate;
|
|
42
366
|
}
|
|
43
367
|
await (0, _walk.ancestorWalk)(ast.program, {
|
|
44
368
|
async enter(node, ancestors) {
|
|
45
369
|
const parent = ancestors[ancestors.length - 2] ?? null;
|
|
370
|
+
if (shouldRaiseEsm && node.type === 'BinaryExpression') {
|
|
371
|
+
const op = node.operator;
|
|
372
|
+
const isEquality = op === '===' || op === '==' || op === '!==' || op === '!=';
|
|
373
|
+
if (isEquality) {
|
|
374
|
+
const leftMain = isRequireMainMember(node.left, shadowedBindings);
|
|
375
|
+
const rightMain = isRequireMainMember(node.right, shadowedBindings);
|
|
376
|
+
const leftModule = node.left.type === 'Identifier' && node.left.name === 'module' && !shadowedBindings.has('module');
|
|
377
|
+
const rightModule = node.right.type === 'Identifier' && node.right.name === 'module' && !shadowedBindings.has('module');
|
|
378
|
+
if (leftMain && rightModule || rightMain && leftModule) {
|
|
379
|
+
const negate = op === '!==' || op === '!=';
|
|
380
|
+
code.update(node.start, node.end, negate ? '!import.meta.main' : 'import.meta.main');
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (shouldRaiseEsm && node.type === 'CallExpression' && isRequireCall(node, shadowedBindings)) {
|
|
386
|
+
const isStatic = isStaticRequire(node, shadowedBindings);
|
|
387
|
+
const parent = ancestors[ancestors.length - 2] ?? null;
|
|
388
|
+
const grandparent = ancestors[ancestors.length - 3] ?? null;
|
|
389
|
+
const greatGrandparent = ancestors[ancestors.length - 4] ?? null;
|
|
390
|
+
|
|
391
|
+
// Hoistable cases are handled separately and don't need createRequire.
|
|
392
|
+
const topLevelExprStmt = parent?.type === 'ExpressionStatement' && grandparent?.type === 'Program';
|
|
393
|
+
const topLevelVarDecl = parent?.type === 'VariableDeclarator' && grandparent?.type === 'VariableDeclaration' && greatGrandparent?.type === 'Program';
|
|
394
|
+
const hoistableTopLevel = isStatic && (topLevelExprStmt || topLevelVarDecl);
|
|
395
|
+
if (!isStatic || !hoistableTopLevel) {
|
|
396
|
+
needsCreateRequire = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
46
399
|
if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
|
|
47
400
|
const skipped = ['__filename', '__dirname'];
|
|
48
401
|
const skippedParams = node.params.filter(param => param.type === 'Identifier' && skipped.includes(param.name));
|
|
@@ -101,7 +454,7 @@ void import.meta.filename;
|
|
|
101
454
|
(0, _metaProperty.metaProperty)(node, parent, code, opts);
|
|
102
455
|
}
|
|
103
456
|
if (node.type === 'MemberExpression') {
|
|
104
|
-
(0, _memberExpression.memberExpression)(node, parent, code, opts);
|
|
457
|
+
(0, _memberExpression.memberExpression)(node, parent, code, opts, shadowedBindings);
|
|
105
458
|
}
|
|
106
459
|
if ((0, _identifier2.isIdentifierName)(node)) {
|
|
107
460
|
(0, _identifier.identifier)({
|
|
@@ -109,11 +462,36 @@ void import.meta.filename;
|
|
|
109
462
|
ancestors,
|
|
110
463
|
code,
|
|
111
464
|
opts,
|
|
112
|
-
meta: exportsMeta
|
|
465
|
+
meta: exportsMeta,
|
|
466
|
+
shadowed: shadowedBindings
|
|
113
467
|
});
|
|
114
468
|
}
|
|
115
469
|
}
|
|
116
470
|
});
|
|
471
|
+
if (pendingRequireTransforms.length) {
|
|
472
|
+
for (const t of pendingRequireTransforms) {
|
|
473
|
+
code.overwrite(t.start, t.end, t.code);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (shouldLowerCjs) {
|
|
477
|
+
const {
|
|
478
|
+
importTransforms,
|
|
479
|
+
exportTransforms,
|
|
480
|
+
needsInterop
|
|
481
|
+
} = lowerEsmToCjs(ast.program, code, opts, containsTopLevelAwait);
|
|
482
|
+
pendingCjsTransforms = {
|
|
483
|
+
transforms: [...importTransforms, ...exportTransforms].sort((a, b) => a.start - b.start),
|
|
484
|
+
needsInterop
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
if (pendingCjsTransforms) {
|
|
488
|
+
for (const t of pendingCjsTransforms.transforms) {
|
|
489
|
+
code.overwrite(t.start, t.end, t.code);
|
|
490
|
+
}
|
|
491
|
+
if (pendingCjsTransforms.needsInterop) {
|
|
492
|
+
code.prepend(`${interopHelper}exports.__esModule = true;\n`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
117
495
|
if (opts.target === 'module' && opts.transformSyntax && exportTable) {
|
|
118
496
|
const isValidExportName = name => /^[$A-Z_a-z][$\w]*$/.test(name);
|
|
119
497
|
const asExportName = name => isValidExportName(name) ? name : JSON.stringify(name);
|
|
@@ -143,6 +521,30 @@ void import.meta.filename;
|
|
|
143
521
|
code.append(`\n${lines.join('\n')}\n`);
|
|
144
522
|
}
|
|
145
523
|
}
|
|
524
|
+
if (shouldRaiseEsm && opts.transformSyntax) {
|
|
525
|
+
const importPrelude = [];
|
|
526
|
+
if (needsCreateRequire) {
|
|
527
|
+
importPrelude.push('import { createRequire } from "node:module";\n');
|
|
528
|
+
}
|
|
529
|
+
if (hoistedImports.length) {
|
|
530
|
+
importPrelude.push(...hoistedImports);
|
|
531
|
+
}
|
|
532
|
+
const requireInit = needsCreateRequire ? 'const require = createRequire(import.meta.url);\n' : '';
|
|
533
|
+
const prelude = `${importPrelude.join('')}${importPrelude.length ? '\n' : ''}${requireInit}let ${_exports.exportsRename} = {};
|
|
534
|
+
void import.meta.filename;
|
|
535
|
+
`;
|
|
536
|
+
code.prepend(prelude);
|
|
537
|
+
}
|
|
538
|
+
if (opts.target === 'commonjs' && opts.transformSyntax && containsTopLevelAwait) {
|
|
539
|
+
const body = code.toString();
|
|
540
|
+
if (opts.topLevelAwait === 'wrap') {
|
|
541
|
+
const tlaPromise = `const __tla = (async () => {\n${body}\nreturn module.exports;\n})();\n`;
|
|
542
|
+
const setPromise = `const __setTla = target => {\n if (!target) return;\n const type = typeof target;\n if (type !== 'object' && type !== 'function') return;\n target.__tla = __tla;\n};\n`;
|
|
543
|
+
const attach = `__setTla(module.exports);\n__tla.then(resolved => __setTla(resolved), err => { throw err; });\n`;
|
|
544
|
+
return `${tlaPromise}${setPromise}${attach}`;
|
|
545
|
+
}
|
|
546
|
+
return `;(async () => {\n${body}\n})();\n`;
|
|
547
|
+
}
|
|
146
548
|
return code.toString();
|
|
147
549
|
};
|
|
148
550
|
exports.format = format;
|
|
@@ -11,7 +11,8 @@ const identifier = ({
|
|
|
11
11
|
ancestors,
|
|
12
12
|
code,
|
|
13
13
|
opts,
|
|
14
|
-
meta
|
|
14
|
+
meta,
|
|
15
|
+
shadowed
|
|
15
16
|
}) => {
|
|
16
17
|
if (opts.target === 'module') {
|
|
17
18
|
const {
|
|
@@ -19,6 +20,9 @@ const identifier = ({
|
|
|
19
20
|
end,
|
|
20
21
|
name
|
|
21
22
|
} = node;
|
|
23
|
+
if (shadowed?.has(name)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
22
26
|
switch (name) {
|
|
23
27
|
case '__filename':
|
|
24
28
|
code.update(start, end, 'import.meta.url');
|
|
@@ -5,8 +5,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.memberExpression = void 0;
|
|
7
7
|
var _exports = require("#utils/exports.js");
|
|
8
|
-
const memberExpression = (node, parent, src, options) => {
|
|
8
|
+
const memberExpression = (node, parent, src, options, shadowed) => {
|
|
9
9
|
if (options.target === 'module') {
|
|
10
|
+
if (node.object.type === 'Identifier' && shadowed?.has(node.object.name) || node.property.type === 'Identifier' && shadowed?.has(node.property.name)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
10
13
|
if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'exports') {
|
|
11
14
|
src.update(node.start, node.end, _exports.exportsRename);
|
|
12
15
|
return;
|
|
@@ -23,18 +26,10 @@ const memberExpression = (node, parent, src, options) => {
|
|
|
23
26
|
// CommonJS properties of `require`
|
|
24
27
|
switch (name) {
|
|
25
28
|
case 'main':
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* @see https://github.com/nodejs/node/pull/32223
|
|
29
|
-
*/
|
|
30
|
-
if (parent?.type === 'ExpressionStatement') {
|
|
31
|
-
// This is a standalone expression so remove it to not cause run-time errors.
|
|
32
|
-
src.remove(start, end);
|
|
29
|
+
if (parent?.type === 'BinaryExpression') {
|
|
30
|
+
return;
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
* Transform require.main === module.
|
|
36
|
-
*/
|
|
37
|
-
if (parent?.type === 'BinaryExpression') {}
|
|
32
|
+
src.update(start, end, 'import.meta.main');
|
|
38
33
|
break;
|
|
39
34
|
case 'resolve':
|
|
40
35
|
src.update(start, end, 'import.meta.resolve');
|
|
@@ -48,6 +43,11 @@ const memberExpression = (node, parent, src, options) => {
|
|
|
48
43
|
break;
|
|
49
44
|
}
|
|
50
45
|
}
|
|
46
|
+
if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'require') {
|
|
47
|
+
if (!shadowed?.has('module')) {
|
|
48
|
+
src.update(node.start, node.end, 'require');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
exports.memberExpression = memberExpression;
|
|
@@ -4,6 +4,19 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.metaProperty = void 0;
|
|
7
|
+
const importMetaMainSupport = '(() => { const [__nmaj, __nmin] = process.versions.node.split(".").map(n => parseInt(n, 10) || 0); return (__nmaj > 24 || (__nmaj === 24 && __nmin >= 2) || (__nmaj === 22 && __nmin >= 18)); })()';
|
|
8
|
+
const importMetaMainShim = 'process.argv[1] === __filename';
|
|
9
|
+
const importMetaMainExpr = mode => {
|
|
10
|
+
switch (mode) {
|
|
11
|
+
case 'warn':
|
|
12
|
+
return `(${importMetaMainSupport} ? ${importMetaMainShim} : (console.warn("import.meta.main is not supported before Node 22.18/24.2; falling back to shim."), ${importMetaMainShim}))`;
|
|
13
|
+
case 'error':
|
|
14
|
+
return `(${importMetaMainSupport} ? ${importMetaMainShim} : (() => { throw new Error("import.meta.main is not supported before Node 22.18/24.2"); })())`;
|
|
15
|
+
case 'shim':
|
|
16
|
+
default:
|
|
17
|
+
return importMetaMainShim;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
7
20
|
const metaProperty = (node, parent, src, options) => {
|
|
8
21
|
if (options.target === 'commonjs') {
|
|
9
22
|
if (parent?.type !== 'MemberExpression') {
|
|
@@ -27,10 +40,15 @@ const metaProperty = (node, parent, src, options) => {
|
|
|
27
40
|
break;
|
|
28
41
|
case 'resolve':
|
|
29
42
|
/**
|
|
30
|
-
*
|
|
43
|
+
* Map to require.resolve intentionally: matches CJS resolution semantics.
|
|
44
|
+
* Wrapping in pathToFileURL(...) would change the return shape (URL string)
|
|
45
|
+
* without truly emulating ESM import.meta.resolve rules.
|
|
31
46
|
*/
|
|
32
47
|
src.update(parent.start, parent.end, 'require.resolve');
|
|
33
48
|
break;
|
|
49
|
+
case 'main':
|
|
50
|
+
src.update(parent.start, parent.end, importMetaMainExpr(options.importMetaMain));
|
|
51
|
+
break;
|
|
34
52
|
}
|
|
35
53
|
}
|
|
36
54
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import MagicString from 'magic-string';
|
|
2
2
|
import type { MemberExpression, Node } from 'oxc-parser';
|
|
3
3
|
import type { FormatterOptions } from '../types.cjs';
|
|
4
|
-
export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
|
|
4
|
+
export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions, shadowed?: Set<string>) => void;
|
package/dist/cjs/module.cjs
CHANGED
package/dist/cjs/types.d.cts
CHANGED
|
@@ -8,6 +8,7 @@ export type ModuleOptions = {
|
|
|
8
8
|
rewriteSpecifier?: RewriteSpecifier;
|
|
9
9
|
dirFilename?: 'inject' | 'preserve' | 'error';
|
|
10
10
|
importMeta?: 'preserve' | 'shim' | 'error';
|
|
11
|
+
importMetaMain?: 'shim' | 'warn' | 'error';
|
|
11
12
|
requireSource?: 'builtin' | 'create-require';
|
|
12
13
|
cjsDefault?: 'module-exports' | 'auto' | 'none';
|
|
13
14
|
topLevelAwait?: 'error' | 'wrap' | 'preserve';
|
package/dist/format.js
CHANGED
|
@@ -8,7 +8,313 @@ import { exportsRename, collectCjsExports } from '#utils/exports.js';
|
|
|
8
8
|
import { collectModuleIdentifiers } from '#utils/identifiers.js';
|
|
9
9
|
import { isIdentifierName } from '#helpers/identifier.js';
|
|
10
10
|
import { ancestorWalk } from '#walk';
|
|
11
|
+
const isValidIdent = name => /^[$A-Z_a-z][$\w]*$/.test(name);
|
|
12
|
+
const exportAssignment = (name, expr, live) => {
|
|
13
|
+
const prop = isValidIdent(name) ? `.${name}` : `[${JSON.stringify(name)}]`;
|
|
14
|
+
if (live === 'strict') {
|
|
15
|
+
const key = JSON.stringify(name);
|
|
16
|
+
return `Object.defineProperty(exports, ${key}, { enumerable: true, get: () => ${expr} });`;
|
|
17
|
+
}
|
|
18
|
+
return `exports${prop} = ${expr};`;
|
|
19
|
+
};
|
|
20
|
+
const defaultInteropName = '__interopDefault';
|
|
21
|
+
const interopHelper = `const ${defaultInteropName} = mod => (mod && mod.__esModule ? mod.default : mod);\n`;
|
|
22
|
+
const isRequireCallee = (callee, shadowed) => {
|
|
23
|
+
if (callee.type === 'Identifier' && callee.name === 'require' && !shadowed.has('require')) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'module' && !shadowed.has('module') && callee.property.type === 'Identifier' && callee.property.name === 'require') {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
31
|
+
const isStaticRequire = (node, shadowed) => node.type === 'CallExpression' && isRequireCallee(node.callee, shadowed) && node.arguments.length === 1 && node.arguments[0].type === 'Literal' && typeof node.arguments[0].value === 'string';
|
|
32
|
+
const isRequireCall = (node, shadowed) => node.type === 'CallExpression' && isRequireCallee(node.callee, shadowed);
|
|
33
|
+
const lowerCjsRequireToImports = (program, code, shadowed) => {
|
|
34
|
+
const transforms = [];
|
|
35
|
+
const imports = [];
|
|
36
|
+
let nsIndex = 0;
|
|
37
|
+
let needsCreateRequire = false;
|
|
38
|
+
for (const stmt of program.body) {
|
|
39
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
40
|
+
const decls = stmt.declarations;
|
|
41
|
+
const allStatic = decls.length > 0 && decls.every(decl => decl.init && isStaticRequire(decl.init, shadowed));
|
|
42
|
+
if (allStatic) {
|
|
43
|
+
for (const decl of decls) {
|
|
44
|
+
const init = decl.init;
|
|
45
|
+
const source = code.slice(init.arguments[0].start, init.arguments[0].end);
|
|
46
|
+
if (decl.id.type === 'Identifier') {
|
|
47
|
+
imports.push(`import * as ${decl.id.name} from ${source};\n`);
|
|
48
|
+
} else if (decl.id.type === 'ObjectPattern') {
|
|
49
|
+
const ns = `__cjsImport${nsIndex++}`;
|
|
50
|
+
const pattern = code.slice(decl.id.start, decl.id.end);
|
|
51
|
+
imports.push(`import * as ${ns} from ${source};\n`);
|
|
52
|
+
imports.push(`const ${pattern} = ${ns};\n`);
|
|
53
|
+
} else {
|
|
54
|
+
needsCreateRequire = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
transforms.push({
|
|
58
|
+
start: stmt.start,
|
|
59
|
+
end: stmt.end,
|
|
60
|
+
code: ';\n'
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
for (const decl of decls) {
|
|
65
|
+
const init = decl.init;
|
|
66
|
+
if (init && isRequireCall(init, shadowed)) {
|
|
67
|
+
needsCreateRequire = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (stmt.type === 'ExpressionStatement') {
|
|
72
|
+
const expr = stmt.expression;
|
|
73
|
+
if (expr && isStaticRequire(expr, shadowed)) {
|
|
74
|
+
const source = code.slice(expr.arguments[0].start, expr.arguments[0].end);
|
|
75
|
+
imports.push(`import ${source};\n`);
|
|
76
|
+
transforms.push({
|
|
77
|
+
start: stmt.start,
|
|
78
|
+
end: stmt.end,
|
|
79
|
+
code: ';\n'
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (expr && isRequireCall(expr, shadowed)) {
|
|
84
|
+
needsCreateRequire = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
transforms,
|
|
90
|
+
imports,
|
|
91
|
+
needsCreateRequire
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const isRequireMainMember = (node, shadowed) => node && node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'require' && !shadowed.has('require') && node.property.type === 'Identifier' && node.property.name === 'main';
|
|
95
|
+
const hasTopLevelAwait = program => {
|
|
96
|
+
let found = false;
|
|
97
|
+
const walkNode = (node, inFunction) => {
|
|
98
|
+
if (found) return;
|
|
99
|
+
switch (node.type) {
|
|
100
|
+
case 'FunctionDeclaration':
|
|
101
|
+
case 'FunctionExpression':
|
|
102
|
+
case 'ArrowFunctionExpression':
|
|
103
|
+
case 'ClassDeclaration':
|
|
104
|
+
case 'ClassExpression':
|
|
105
|
+
inFunction = true;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
if (!inFunction && node.type === 'AwaitExpression') {
|
|
109
|
+
found = true;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const keys = Object.keys(node);
|
|
113
|
+
for (const key of keys) {
|
|
114
|
+
const value = node[key];
|
|
115
|
+
if (!value) continue;
|
|
116
|
+
if (Array.isArray(value)) {
|
|
117
|
+
for (const item of value) {
|
|
118
|
+
if (item && typeof item === 'object') {
|
|
119
|
+
walkNode(item, inFunction);
|
|
120
|
+
if (found) return;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else if (value && typeof value === 'object') {
|
|
124
|
+
walkNode(value, inFunction);
|
|
125
|
+
if (found) return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
walkNode(program, false);
|
|
130
|
+
return found;
|
|
131
|
+
};
|
|
132
|
+
const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
|
|
133
|
+
const live = opts.liveBindings ?? 'strict';
|
|
134
|
+
const importTransforms = [];
|
|
135
|
+
const exportTransforms = [];
|
|
136
|
+
let needsInterop = false;
|
|
137
|
+
let importIndex = 0;
|
|
138
|
+
for (const node of program.body) {
|
|
139
|
+
if (node.type === 'ImportDeclaration') {
|
|
140
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
141
|
+
const specifiers = node.specifiers ?? [];
|
|
142
|
+
const defaultSpec = specifiers.find(s => s.type === 'ImportDefaultSpecifier');
|
|
143
|
+
const namespaceSpec = specifiers.find(s => s.type === 'ImportNamespaceSpecifier');
|
|
144
|
+
const namedSpecs = specifiers.filter(s => s.type === 'ImportSpecifier');
|
|
11
145
|
|
|
146
|
+
// Side-effect import
|
|
147
|
+
if (!specifiers.length) {
|
|
148
|
+
importTransforms.push({
|
|
149
|
+
start: node.start,
|
|
150
|
+
end: node.end,
|
|
151
|
+
code: `require(${srcLiteral});\n`,
|
|
152
|
+
needsInterop: false
|
|
153
|
+
});
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const modIdent = `__mod${importIndex++}`;
|
|
157
|
+
const lines = [];
|
|
158
|
+
lines.push(`const ${modIdent} = require(${srcLiteral});`);
|
|
159
|
+
if (namespaceSpec) {
|
|
160
|
+
lines.push(`const ${namespaceSpec.local.name} = ${modIdent};`);
|
|
161
|
+
}
|
|
162
|
+
if (defaultSpec) {
|
|
163
|
+
let init = modIdent;
|
|
164
|
+
switch (opts.cjsDefault) {
|
|
165
|
+
case 'module-exports':
|
|
166
|
+
init = modIdent;
|
|
167
|
+
break;
|
|
168
|
+
case 'none':
|
|
169
|
+
init = `${modIdent}.default`;
|
|
170
|
+
break;
|
|
171
|
+
case 'auto':
|
|
172
|
+
default:
|
|
173
|
+
init = `${defaultInteropName}(${modIdent})`;
|
|
174
|
+
needsInterop = true;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
lines.push(`const ${defaultSpec.local.name} = ${init};`);
|
|
178
|
+
}
|
|
179
|
+
if (namedSpecs.length) {
|
|
180
|
+
const pairs = namedSpecs.map(s => {
|
|
181
|
+
const imported = s.imported.name;
|
|
182
|
+
const local = s.local.name;
|
|
183
|
+
return imported === local ? imported : `${imported}: ${local}`;
|
|
184
|
+
});
|
|
185
|
+
lines.push(`const { ${pairs.join(', ')} } = ${modIdent};`);
|
|
186
|
+
}
|
|
187
|
+
importTransforms.push({
|
|
188
|
+
start: node.start,
|
|
189
|
+
end: node.end,
|
|
190
|
+
code: `${lines.join('\n')}\n`,
|
|
191
|
+
needsInterop
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
195
|
+
// Handle declaration exports
|
|
196
|
+
if (node.declaration) {
|
|
197
|
+
const decl = node.declaration;
|
|
198
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
199
|
+
const exportedNames = [];
|
|
200
|
+
if (decl.type === 'VariableDeclaration') {
|
|
201
|
+
for (const d of decl.declarations) {
|
|
202
|
+
if (d.id.type === 'Identifier') {
|
|
203
|
+
exportedNames.push(d.id.name);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} else if (decl.id?.type === 'Identifier') {
|
|
207
|
+
exportedNames.push(decl.id.name);
|
|
208
|
+
}
|
|
209
|
+
const exportLines = exportedNames.map(name => exportAssignment(name, name, live));
|
|
210
|
+
exportTransforms.push({
|
|
211
|
+
start: node.start,
|
|
212
|
+
end: node.end,
|
|
213
|
+
code: `${declSrc}\n${exportLines.join('\n')}\n`
|
|
214
|
+
});
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Handle re-export or local specifiers
|
|
219
|
+
if (node.specifiers?.length) {
|
|
220
|
+
if (node.source) {
|
|
221
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
222
|
+
const modIdent = `__mod${importIndex++}`;
|
|
223
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`];
|
|
224
|
+
for (const spec of node.specifiers) {
|
|
225
|
+
if (spec.type !== 'ExportSpecifier') continue;
|
|
226
|
+
const exported = spec.exported.name;
|
|
227
|
+
const imported = spec.local.name;
|
|
228
|
+
let rhs = `${modIdent}.${imported}`;
|
|
229
|
+
if (imported === 'default') {
|
|
230
|
+
rhs = `${defaultInteropName}(${modIdent})`;
|
|
231
|
+
needsInterop = true;
|
|
232
|
+
}
|
|
233
|
+
lines.push(exportAssignment(exported, rhs, live));
|
|
234
|
+
}
|
|
235
|
+
exportTransforms.push({
|
|
236
|
+
start: node.start,
|
|
237
|
+
end: node.end,
|
|
238
|
+
code: `${lines.join('\n')}\n`,
|
|
239
|
+
needsInterop
|
|
240
|
+
});
|
|
241
|
+
} else {
|
|
242
|
+
const lines = [];
|
|
243
|
+
for (const spec of node.specifiers) {
|
|
244
|
+
if (spec.type !== 'ExportSpecifier') continue;
|
|
245
|
+
const exported = spec.exported.name;
|
|
246
|
+
const local = spec.local.name;
|
|
247
|
+
lines.push(exportAssignment(exported, local, live));
|
|
248
|
+
}
|
|
249
|
+
exportTransforms.push({
|
|
250
|
+
start: node.start,
|
|
251
|
+
end: node.end,
|
|
252
|
+
code: `${lines.join('\n')}\n`
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
258
|
+
const decl = node.declaration;
|
|
259
|
+
const useExportsObject = containsTopLevelAwait && opts.topLevelAwait !== 'error';
|
|
260
|
+
if (decl.type === 'FunctionDeclaration' || decl.type === 'ClassDeclaration') {
|
|
261
|
+
if (decl.id?.name) {
|
|
262
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
263
|
+
const assign = useExportsObject ? `exports.default = ${decl.id.name};` : `module.exports = ${decl.id.name};`;
|
|
264
|
+
exportTransforms.push({
|
|
265
|
+
start: node.start,
|
|
266
|
+
end: node.end,
|
|
267
|
+
code: `${declSrc}\n${assign}\n`
|
|
268
|
+
});
|
|
269
|
+
} else {
|
|
270
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
271
|
+
const assign = useExportsObject ? `exports.default = ${declSrc};` : `module.exports = ${declSrc};`;
|
|
272
|
+
exportTransforms.push({
|
|
273
|
+
start: node.start,
|
|
274
|
+
end: node.end,
|
|
275
|
+
code: `${assign}\n`
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
const exprSrc = code.slice(decl.start, decl.end);
|
|
280
|
+
const assign = useExportsObject ? `exports.default = ${exprSrc};` : `module.exports = ${exprSrc};`;
|
|
281
|
+
exportTransforms.push({
|
|
282
|
+
start: node.start,
|
|
283
|
+
end: node.end,
|
|
284
|
+
code: `${assign}\n`
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (node.type === 'ExportAllDeclaration') {
|
|
289
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
290
|
+
if (node.exported) {
|
|
291
|
+
const exported = node.exported.name;
|
|
292
|
+
const modIdent = `__mod${importIndex++}`;
|
|
293
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`, exportAssignment(exported, modIdent, live)];
|
|
294
|
+
exportTransforms.push({
|
|
295
|
+
start: node.start,
|
|
296
|
+
end: node.end,
|
|
297
|
+
code: `${lines.join('\n')}\n`
|
|
298
|
+
});
|
|
299
|
+
} else {
|
|
300
|
+
const modIdent = `__mod${importIndex++}`;
|
|
301
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`];
|
|
302
|
+
const loop = `for (const k in ${modIdent}) {\n if (k === 'default') continue;\n if (!Object.prototype.hasOwnProperty.call(${modIdent}, k)) continue;\n Object.defineProperty(exports, k, { enumerable: true, get: () => ${modIdent}[k] });\n}`;
|
|
303
|
+
lines.push(loop);
|
|
304
|
+
exportTransforms.push({
|
|
305
|
+
start: node.start,
|
|
306
|
+
end: node.end,
|
|
307
|
+
code: `${lines.join('\n')}\n`
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
importTransforms,
|
|
314
|
+
exportTransforms,
|
|
315
|
+
needsInterop
|
|
316
|
+
};
|
|
317
|
+
};
|
|
12
318
|
/**
|
|
13
319
|
* Node added support for import.meta.main.
|
|
14
320
|
* Added in: v24.2.0, v22.18.0
|
|
@@ -22,21 +328,67 @@ const format = async (src, ast, opts) => {
|
|
|
22
328
|
hasDefaultExportBeenReassigned: false,
|
|
23
329
|
hasDefaultExportBeenAssigned: false
|
|
24
330
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
331
|
+
const moduleIdentifiers = await collectModuleIdentifiers(ast.program);
|
|
332
|
+
const shadowedBindings = new Set([...moduleIdentifiers.entries()].filter(([, meta]) => meta.declare.length > 0).map(([name]) => name));
|
|
27
333
|
if (opts.target === 'module' && opts.transformSyntax) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
334
|
+
if (shadowedBindings.has('module') || shadowedBindings.has('exports')) {
|
|
335
|
+
throw new Error('Cannot transform to ESM: module or exports is shadowed in module scope.');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const exportTable = opts.target === 'module' ? await collectCjsExports(ast.program) : null;
|
|
339
|
+
const shouldCheckTopLevelAwait = opts.target === 'commonjs' && opts.transformSyntax;
|
|
340
|
+
const containsTopLevelAwait = shouldCheckTopLevelAwait ? hasTopLevelAwait(ast.program) : false;
|
|
341
|
+
const shouldLowerCjs = opts.target === 'commonjs' && opts.transformSyntax;
|
|
342
|
+
const shouldRaiseEsm = opts.target === 'module' && opts.transformSyntax;
|
|
343
|
+
let hoistedImports = [];
|
|
344
|
+
let pendingRequireTransforms = [];
|
|
345
|
+
let needsCreateRequire = false;
|
|
346
|
+
let pendingCjsTransforms = null;
|
|
347
|
+
if (shouldLowerCjs && opts.topLevelAwait === 'error' && containsTopLevelAwait) {
|
|
348
|
+
throw new Error('Top-level await is not supported when targeting CommonJS (set topLevelAwait to "wrap" or "preserve" to override).');
|
|
349
|
+
}
|
|
350
|
+
if (shouldRaiseEsm) {
|
|
351
|
+
const {
|
|
352
|
+
transforms,
|
|
353
|
+
imports,
|
|
354
|
+
needsCreateRequire: reqCreate
|
|
355
|
+
} = lowerCjsRequireToImports(ast.program, code, shadowedBindings);
|
|
356
|
+
pendingRequireTransforms = transforms;
|
|
357
|
+
hoistedImports = imports;
|
|
358
|
+
needsCreateRequire = reqCreate;
|
|
36
359
|
}
|
|
37
360
|
await ancestorWalk(ast.program, {
|
|
38
361
|
async enter(node, ancestors) {
|
|
39
362
|
const parent = ancestors[ancestors.length - 2] ?? null;
|
|
363
|
+
if (shouldRaiseEsm && node.type === 'BinaryExpression') {
|
|
364
|
+
const op = node.operator;
|
|
365
|
+
const isEquality = op === '===' || op === '==' || op === '!==' || op === '!=';
|
|
366
|
+
if (isEquality) {
|
|
367
|
+
const leftMain = isRequireMainMember(node.left, shadowedBindings);
|
|
368
|
+
const rightMain = isRequireMainMember(node.right, shadowedBindings);
|
|
369
|
+
const leftModule = node.left.type === 'Identifier' && node.left.name === 'module' && !shadowedBindings.has('module');
|
|
370
|
+
const rightModule = node.right.type === 'Identifier' && node.right.name === 'module' && !shadowedBindings.has('module');
|
|
371
|
+
if (leftMain && rightModule || rightMain && leftModule) {
|
|
372
|
+
const negate = op === '!==' || op === '!=';
|
|
373
|
+
code.update(node.start, node.end, negate ? '!import.meta.main' : 'import.meta.main');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (shouldRaiseEsm && node.type === 'CallExpression' && isRequireCall(node, shadowedBindings)) {
|
|
379
|
+
const isStatic = isStaticRequire(node, shadowedBindings);
|
|
380
|
+
const parent = ancestors[ancestors.length - 2] ?? null;
|
|
381
|
+
const grandparent = ancestors[ancestors.length - 3] ?? null;
|
|
382
|
+
const greatGrandparent = ancestors[ancestors.length - 4] ?? null;
|
|
383
|
+
|
|
384
|
+
// Hoistable cases are handled separately and don't need createRequire.
|
|
385
|
+
const topLevelExprStmt = parent?.type === 'ExpressionStatement' && grandparent?.type === 'Program';
|
|
386
|
+
const topLevelVarDecl = parent?.type === 'VariableDeclarator' && grandparent?.type === 'VariableDeclaration' && greatGrandparent?.type === 'Program';
|
|
387
|
+
const hoistableTopLevel = isStatic && (topLevelExprStmt || topLevelVarDecl);
|
|
388
|
+
if (!isStatic || !hoistableTopLevel) {
|
|
389
|
+
needsCreateRequire = true;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
40
392
|
if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
|
|
41
393
|
const skipped = ['__filename', '__dirname'];
|
|
42
394
|
const skippedParams = node.params.filter(param => param.type === 'Identifier' && skipped.includes(param.name));
|
|
@@ -95,7 +447,7 @@ void import.meta.filename;
|
|
|
95
447
|
metaProperty(node, parent, code, opts);
|
|
96
448
|
}
|
|
97
449
|
if (node.type === 'MemberExpression') {
|
|
98
|
-
memberExpression(node, parent, code, opts);
|
|
450
|
+
memberExpression(node, parent, code, opts, shadowedBindings);
|
|
99
451
|
}
|
|
100
452
|
if (isIdentifierName(node)) {
|
|
101
453
|
identifier({
|
|
@@ -103,11 +455,36 @@ void import.meta.filename;
|
|
|
103
455
|
ancestors,
|
|
104
456
|
code,
|
|
105
457
|
opts,
|
|
106
|
-
meta: exportsMeta
|
|
458
|
+
meta: exportsMeta,
|
|
459
|
+
shadowed: shadowedBindings
|
|
107
460
|
});
|
|
108
461
|
}
|
|
109
462
|
}
|
|
110
463
|
});
|
|
464
|
+
if (pendingRequireTransforms.length) {
|
|
465
|
+
for (const t of pendingRequireTransforms) {
|
|
466
|
+
code.overwrite(t.start, t.end, t.code);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (shouldLowerCjs) {
|
|
470
|
+
const {
|
|
471
|
+
importTransforms,
|
|
472
|
+
exportTransforms,
|
|
473
|
+
needsInterop
|
|
474
|
+
} = lowerEsmToCjs(ast.program, code, opts, containsTopLevelAwait);
|
|
475
|
+
pendingCjsTransforms = {
|
|
476
|
+
transforms: [...importTransforms, ...exportTransforms].sort((a, b) => a.start - b.start),
|
|
477
|
+
needsInterop
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
if (pendingCjsTransforms) {
|
|
481
|
+
for (const t of pendingCjsTransforms.transforms) {
|
|
482
|
+
code.overwrite(t.start, t.end, t.code);
|
|
483
|
+
}
|
|
484
|
+
if (pendingCjsTransforms.needsInterop) {
|
|
485
|
+
code.prepend(`${interopHelper}exports.__esModule = true;\n`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
111
488
|
if (opts.target === 'module' && opts.transformSyntax && exportTable) {
|
|
112
489
|
const isValidExportName = name => /^[$A-Z_a-z][$\w]*$/.test(name);
|
|
113
490
|
const asExportName = name => isValidExportName(name) ? name : JSON.stringify(name);
|
|
@@ -137,6 +514,30 @@ void import.meta.filename;
|
|
|
137
514
|
code.append(`\n${lines.join('\n')}\n`);
|
|
138
515
|
}
|
|
139
516
|
}
|
|
517
|
+
if (shouldRaiseEsm && opts.transformSyntax) {
|
|
518
|
+
const importPrelude = [];
|
|
519
|
+
if (needsCreateRequire) {
|
|
520
|
+
importPrelude.push('import { createRequire } from "node:module";\n');
|
|
521
|
+
}
|
|
522
|
+
if (hoistedImports.length) {
|
|
523
|
+
importPrelude.push(...hoistedImports);
|
|
524
|
+
}
|
|
525
|
+
const requireInit = needsCreateRequire ? 'const require = createRequire(import.meta.url);\n' : '';
|
|
526
|
+
const prelude = `${importPrelude.join('')}${importPrelude.length ? '\n' : ''}${requireInit}let ${exportsRename} = {};
|
|
527
|
+
void import.meta.filename;
|
|
528
|
+
`;
|
|
529
|
+
code.prepend(prelude);
|
|
530
|
+
}
|
|
531
|
+
if (opts.target === 'commonjs' && opts.transformSyntax && containsTopLevelAwait) {
|
|
532
|
+
const body = code.toString();
|
|
533
|
+
if (opts.topLevelAwait === 'wrap') {
|
|
534
|
+
const tlaPromise = `const __tla = (async () => {\n${body}\nreturn module.exports;\n})();\n`;
|
|
535
|
+
const setPromise = `const __setTla = target => {\n if (!target) return;\n const type = typeof target;\n if (type !== 'object' && type !== 'function') return;\n target.__tla = __tla;\n};\n`;
|
|
536
|
+
const attach = `__setTla(module.exports);\n__tla.then(resolved => __setTla(resolved), err => { throw err; });\n`;
|
|
537
|
+
return `${tlaPromise}${setPromise}${attach}`;
|
|
538
|
+
}
|
|
539
|
+
return `;(async () => {\n${body}\n})();\n`;
|
|
540
|
+
}
|
|
140
541
|
return code.toString();
|
|
141
542
|
};
|
|
142
543
|
export { format };
|
|
@@ -5,7 +5,8 @@ export const identifier = ({
|
|
|
5
5
|
ancestors,
|
|
6
6
|
code,
|
|
7
7
|
opts,
|
|
8
|
-
meta
|
|
8
|
+
meta,
|
|
9
|
+
shadowed
|
|
9
10
|
}) => {
|
|
10
11
|
if (opts.target === 'module') {
|
|
11
12
|
const {
|
|
@@ -13,6 +14,9 @@ export const identifier = ({
|
|
|
13
14
|
end,
|
|
14
15
|
name
|
|
15
16
|
} = node;
|
|
17
|
+
if (shadowed?.has(name)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
16
20
|
switch (name) {
|
|
17
21
|
case '__filename':
|
|
18
22
|
code.update(start, end, 'import.meta.url');
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { exportsRename } from '#utils/exports.js';
|
|
2
|
-
export const memberExpression = (node, parent, src, options) => {
|
|
2
|
+
export const memberExpression = (node, parent, src, options, shadowed) => {
|
|
3
3
|
if (options.target === 'module') {
|
|
4
|
+
if (node.object.type === 'Identifier' && shadowed?.has(node.object.name) || node.property.type === 'Identifier' && shadowed?.has(node.property.name)) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
4
7
|
if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'exports') {
|
|
5
8
|
src.update(node.start, node.end, exportsRename);
|
|
6
9
|
return;
|
|
@@ -17,18 +20,10 @@ export const memberExpression = (node, parent, src, options) => {
|
|
|
17
20
|
// CommonJS properties of `require`
|
|
18
21
|
switch (name) {
|
|
19
22
|
case 'main':
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* @see https://github.com/nodejs/node/pull/32223
|
|
23
|
-
*/
|
|
24
|
-
if (parent?.type === 'ExpressionStatement') {
|
|
25
|
-
// This is a standalone expression so remove it to not cause run-time errors.
|
|
26
|
-
src.remove(start, end);
|
|
23
|
+
if (parent?.type === 'BinaryExpression') {
|
|
24
|
+
return;
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
* Transform require.main === module.
|
|
30
|
-
*/
|
|
31
|
-
if (parent?.type === 'BinaryExpression') {}
|
|
26
|
+
src.update(start, end, 'import.meta.main');
|
|
32
27
|
break;
|
|
33
28
|
case 'resolve':
|
|
34
29
|
src.update(start, end, 'import.meta.resolve');
|
|
@@ -42,5 +37,10 @@ export const memberExpression = (node, parent, src, options) => {
|
|
|
42
37
|
break;
|
|
43
38
|
}
|
|
44
39
|
}
|
|
40
|
+
if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'require') {
|
|
41
|
+
if (!shadowed?.has('module')) {
|
|
42
|
+
src.update(node.start, node.end, 'require');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
45
|
}
|
|
46
46
|
};
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
const importMetaMainSupport = '(() => { const [__nmaj, __nmin] = process.versions.node.split(".").map(n => parseInt(n, 10) || 0); return (__nmaj > 24 || (__nmaj === 24 && __nmin >= 2) || (__nmaj === 22 && __nmin >= 18)); })()';
|
|
2
|
+
const importMetaMainShim = 'process.argv[1] === __filename';
|
|
3
|
+
const importMetaMainExpr = mode => {
|
|
4
|
+
switch (mode) {
|
|
5
|
+
case 'warn':
|
|
6
|
+
return `(${importMetaMainSupport} ? ${importMetaMainShim} : (console.warn("import.meta.main is not supported before Node 22.18/24.2; falling back to shim."), ${importMetaMainShim}))`;
|
|
7
|
+
case 'error':
|
|
8
|
+
return `(${importMetaMainSupport} ? ${importMetaMainShim} : (() => { throw new Error("import.meta.main is not supported before Node 22.18/24.2"); })())`;
|
|
9
|
+
case 'shim':
|
|
10
|
+
default:
|
|
11
|
+
return importMetaMainShim;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
1
14
|
export const metaProperty = (node, parent, src, options) => {
|
|
2
15
|
if (options.target === 'commonjs') {
|
|
3
16
|
if (parent?.type !== 'MemberExpression') {
|
|
@@ -21,10 +34,15 @@ export const metaProperty = (node, parent, src, options) => {
|
|
|
21
34
|
break;
|
|
22
35
|
case 'resolve':
|
|
23
36
|
/**
|
|
24
|
-
*
|
|
37
|
+
* Map to require.resolve intentionally: matches CJS resolution semantics.
|
|
38
|
+
* Wrapping in pathToFileURL(...) would change the return shape (URL string)
|
|
39
|
+
* without truly emulating ESM import.meta.resolve rules.
|
|
25
40
|
*/
|
|
26
41
|
src.update(parent.start, parent.end, 'require.resolve');
|
|
27
42
|
break;
|
|
43
|
+
case 'main':
|
|
44
|
+
src.update(parent.start, parent.end, importMetaMainExpr(options.importMetaMain));
|
|
45
|
+
break;
|
|
28
46
|
}
|
|
29
47
|
}
|
|
30
48
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import MagicString from 'magic-string';
|
|
2
2
|
import type { MemberExpression, Node } from 'oxc-parser';
|
|
3
3
|
import type { FormatterOptions } from '../types.js';
|
|
4
|
-
export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
|
|
4
|
+
export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions, shadowed?: Set<string>) => void;
|
package/dist/module.js
CHANGED
|
@@ -7,6 +7,7 @@ type IdentifierArg = {
|
|
|
7
7
|
code: MagicString;
|
|
8
8
|
opts: FormatterOptions;
|
|
9
9
|
meta: ExportsMeta;
|
|
10
|
+
shadowed?: Set<string>;
|
|
10
11
|
};
|
|
11
|
-
export declare const identifier: ({ node, ancestors, code, opts, meta }: IdentifierArg) => void;
|
|
12
|
+
export declare const identifier: ({ node, ancestors, code, opts, meta, shadowed, }: IdentifierArg) => void;
|
|
12
13
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import MagicString from 'magic-string';
|
|
2
2
|
import type { MemberExpression, Node } from 'oxc-parser';
|
|
3
3
|
import type { FormatterOptions } from '../types.js';
|
|
4
|
-
export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
|
|
4
|
+
export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions, shadowed?: Set<string>) => void;
|
package/dist/src/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type ModuleOptions = {
|
|
|
8
8
|
rewriteSpecifier?: RewriteSpecifier;
|
|
9
9
|
dirFilename?: 'inject' | 'preserve' | 'error';
|
|
10
10
|
importMeta?: 'preserve' | 'shim' | 'error';
|
|
11
|
+
importMetaMain?: 'shim' | 'warn' | 'error';
|
|
11
12
|
requireSource?: 'builtin' | 'create-require';
|
|
12
13
|
cjsDefault?: 'module-exports' | 'auto' | 'none';
|
|
13
14
|
topLevelAwait?: 'error' | 'wrap' | 'preserve';
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type ModuleOptions = {
|
|
|
8
8
|
rewriteSpecifier?: RewriteSpecifier;
|
|
9
9
|
dirFilename?: 'inject' | 'preserve' | 'error';
|
|
10
10
|
importMeta?: 'preserve' | 'shim' | 'error';
|
|
11
|
+
importMetaMain?: 'shim' | 'warn' | 'error';
|
|
11
12
|
requireSource?: 'builtin' | 'create-require';
|
|
12
13
|
cjsDefault?: 'module-exports' | 'auto' | 'none';
|
|
13
14
|
topLevelAwait?: 'error' | 'wrap' | 'preserve';
|