@knighted/module 1.0.0-beta.0 → 1.0.0-beta.2
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/exports.d.cts +6 -0
- package/dist/cjs/format.cjs +315 -12
- package/dist/cjs/format.d.cts +3 -2
- package/dist/cjs/formatters/assignmentExpression.cjs +1 -1
- package/dist/cjs/formatters/identifier.cjs +4 -4
- package/dist/cjs/formatters/memberExpression.cjs +2 -2
- package/dist/cjs/formatters/metaProperty.cjs +19 -1
- package/dist/cjs/identifiers.d.cts +19 -0
- package/dist/cjs/lang.d.cts +4 -0
- package/dist/cjs/module.cjs +5 -4
- package/dist/cjs/types.d.cts +9 -0
- package/dist/cjs/url.d.cts +2 -0
- package/dist/cjs/utils/exports.cjs +227 -0
- package/dist/cjs/utils/identifiers.cjs +190 -0
- package/dist/cjs/utils/lang.cjs +25 -0
- package/dist/cjs/utils/url.cjs +16 -0
- package/dist/cjs/utils.cjs +71 -1
- package/dist/cjs/utils.d.cts +3 -2
- package/dist/exports.d.ts +6 -0
- package/dist/format.d.ts +3 -2
- package/dist/format.js +311 -9
- package/dist/formatters/assignmentExpression.js +1 -1
- package/dist/formatters/identifier.js +2 -2
- package/dist/formatters/memberExpression.js +1 -1
- package/dist/formatters/metaProperty.js +19 -1
- package/dist/identifiers.d.ts +19 -0
- package/dist/lang.d.ts +4 -0
- package/dist/module.js +4 -3
- package/dist/src/format.d.ts +9 -0
- package/dist/src/module.d.ts +3 -0
- package/dist/src/parse.d.ts +2 -0
- package/dist/src/types.d.ts +44 -0
- package/dist/src/utils/exports.d.ts +6 -0
- package/dist/src/utils/identifiers.d.ts +19 -0
- package/dist/src/utils/lang.d.ts +4 -0
- package/dist/src/utils/url.d.ts +2 -0
- package/dist/src/utils.d.ts +26 -0
- package/dist/src/walk.d.ts +20 -0
- package/dist/types.d.ts +9 -0
- package/dist/url.d.ts +2 -0
- package/dist/utils/exports.js +221 -0
- package/dist/utils/identifiers.js +183 -0
- package/dist/utils/lang.js +20 -0
- package/dist/utils/url.js +10 -0
- package/dist/utils.d.ts +3 -2
- package/dist/utils.js +70 -1
- package/package.json +4 -4
- /package/dist/{formatters → src/formatters}/assignmentExpression.d.ts +0 -0
- /package/dist/{formatters → src/formatters}/expressionStatement.d.ts +0 -0
- /package/dist/{formatters → src/formatters}/identifier.d.ts +0 -0
- /package/dist/{formatters → src/formatters}/memberExpression.d.ts +0 -0
- /package/dist/{formatters → src/formatters}/metaProperty.d.ts +0 -0
- /package/dist/{helpers → src/helpers}/identifier.d.ts +0 -0
- /package/dist/{helpers → src/helpers}/scope.d.ts +0 -0
package/dist/format.js
CHANGED
|
@@ -1,15 +1,251 @@
|
|
|
1
1
|
import MagicString from 'magic-string';
|
|
2
|
-
import { identifier } from '
|
|
3
|
-
import { metaProperty } from '
|
|
4
|
-
import { memberExpression } from '
|
|
5
|
-
import { assignmentExpression } from '
|
|
6
|
-
import { isValidUrl
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { identifier } from '#formatters/identifier.js';
|
|
3
|
+
import { metaProperty } from '#formatters/metaProperty.js';
|
|
4
|
+
import { memberExpression } from '#formatters/memberExpression.js';
|
|
5
|
+
import { assignmentExpression } from '#formatters/assignmentExpression.js';
|
|
6
|
+
import { isValidUrl } from '#utils/url.js';
|
|
7
|
+
import { exportsRename, collectCjsExports } from '#utils/exports.js';
|
|
8
|
+
import { collectModuleIdentifiers } from '#utils/identifiers.js';
|
|
9
|
+
import { isIdentifierName } from '#helpers/identifier.js';
|
|
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 hasTopLevelAwait = program => {
|
|
23
|
+
let found = false;
|
|
24
|
+
const walkNode = (node, inFunction) => {
|
|
25
|
+
if (found) return;
|
|
26
|
+
switch (node.type) {
|
|
27
|
+
case 'FunctionDeclaration':
|
|
28
|
+
case 'FunctionExpression':
|
|
29
|
+
case 'ArrowFunctionExpression':
|
|
30
|
+
case 'ClassDeclaration':
|
|
31
|
+
case 'ClassExpression':
|
|
32
|
+
inFunction = true;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (!inFunction && node.type === 'AwaitExpression') {
|
|
36
|
+
found = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const keys = Object.keys(node);
|
|
40
|
+
for (const key of keys) {
|
|
41
|
+
const value = node[key];
|
|
42
|
+
if (!value) continue;
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
for (const item of value) {
|
|
45
|
+
if (item && typeof item === 'object') {
|
|
46
|
+
walkNode(item, inFunction);
|
|
47
|
+
if (found) return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} else if (value && typeof value === 'object') {
|
|
51
|
+
walkNode(value, inFunction);
|
|
52
|
+
if (found) return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
walkNode(program, false);
|
|
57
|
+
return found;
|
|
58
|
+
};
|
|
59
|
+
const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
|
|
60
|
+
const live = opts.liveBindings ?? 'strict';
|
|
61
|
+
const importTransforms = [];
|
|
62
|
+
const exportTransforms = [];
|
|
63
|
+
let needsInterop = false;
|
|
64
|
+
let importIndex = 0;
|
|
65
|
+
for (const node of program.body) {
|
|
66
|
+
if (node.type === 'ImportDeclaration') {
|
|
67
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
68
|
+
const specifiers = node.specifiers ?? [];
|
|
69
|
+
const defaultSpec = specifiers.find(s => s.type === 'ImportDefaultSpecifier');
|
|
70
|
+
const namespaceSpec = specifiers.find(s => s.type === 'ImportNamespaceSpecifier');
|
|
71
|
+
const namedSpecs = specifiers.filter(s => s.type === 'ImportSpecifier');
|
|
72
|
+
|
|
73
|
+
// Side-effect import
|
|
74
|
+
if (!specifiers.length) {
|
|
75
|
+
importTransforms.push({
|
|
76
|
+
start: node.start,
|
|
77
|
+
end: node.end,
|
|
78
|
+
code: `require(${srcLiteral});\n`,
|
|
79
|
+
needsInterop: false
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const modIdent = `__mod${importIndex++}`;
|
|
84
|
+
const lines = [];
|
|
85
|
+
lines.push(`const ${modIdent} = require(${srcLiteral});`);
|
|
86
|
+
if (namespaceSpec) {
|
|
87
|
+
lines.push(`const ${namespaceSpec.local.name} = ${modIdent};`);
|
|
88
|
+
}
|
|
89
|
+
if (defaultSpec) {
|
|
90
|
+
let init = modIdent;
|
|
91
|
+
switch (opts.cjsDefault) {
|
|
92
|
+
case 'module-exports':
|
|
93
|
+
init = modIdent;
|
|
94
|
+
break;
|
|
95
|
+
case 'none':
|
|
96
|
+
init = `${modIdent}.default`;
|
|
97
|
+
break;
|
|
98
|
+
case 'auto':
|
|
99
|
+
default:
|
|
100
|
+
init = `${defaultInteropName}(${modIdent})`;
|
|
101
|
+
needsInterop = true;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
lines.push(`const ${defaultSpec.local.name} = ${init};`);
|
|
105
|
+
}
|
|
106
|
+
if (namedSpecs.length) {
|
|
107
|
+
const pairs = namedSpecs.map(s => {
|
|
108
|
+
const imported = s.imported.name;
|
|
109
|
+
const local = s.local.name;
|
|
110
|
+
return imported === local ? imported : `${imported}: ${local}`;
|
|
111
|
+
});
|
|
112
|
+
lines.push(`const { ${pairs.join(', ')} } = ${modIdent};`);
|
|
113
|
+
}
|
|
114
|
+
importTransforms.push({
|
|
115
|
+
start: node.start,
|
|
116
|
+
end: node.end,
|
|
117
|
+
code: `${lines.join('\n')}\n`,
|
|
118
|
+
needsInterop
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
122
|
+
// Handle declaration exports
|
|
123
|
+
if (node.declaration) {
|
|
124
|
+
const decl = node.declaration;
|
|
125
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
126
|
+
const exportedNames = [];
|
|
127
|
+
if (decl.type === 'VariableDeclaration') {
|
|
128
|
+
for (const d of decl.declarations) {
|
|
129
|
+
if (d.id.type === 'Identifier') {
|
|
130
|
+
exportedNames.push(d.id.name);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} else if (decl.id?.type === 'Identifier') {
|
|
134
|
+
exportedNames.push(decl.id.name);
|
|
135
|
+
}
|
|
136
|
+
const exportLines = exportedNames.map(name => exportAssignment(name, name, live));
|
|
137
|
+
exportTransforms.push({
|
|
138
|
+
start: node.start,
|
|
139
|
+
end: node.end,
|
|
140
|
+
code: `${declSrc}\n${exportLines.join('\n')}\n`
|
|
141
|
+
});
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
9
144
|
|
|
145
|
+
// Handle re-export or local specifiers
|
|
146
|
+
if (node.specifiers?.length) {
|
|
147
|
+
if (node.source) {
|
|
148
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
149
|
+
const modIdent = `__mod${importIndex++}`;
|
|
150
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`];
|
|
151
|
+
for (const spec of node.specifiers) {
|
|
152
|
+
if (spec.type !== 'ExportSpecifier') continue;
|
|
153
|
+
const exported = spec.exported.name;
|
|
154
|
+
const imported = spec.local.name;
|
|
155
|
+
let rhs = `${modIdent}.${imported}`;
|
|
156
|
+
if (imported === 'default') {
|
|
157
|
+
rhs = `${defaultInteropName}(${modIdent})`;
|
|
158
|
+
needsInterop = true;
|
|
159
|
+
}
|
|
160
|
+
lines.push(exportAssignment(exported, rhs, live));
|
|
161
|
+
}
|
|
162
|
+
exportTransforms.push({
|
|
163
|
+
start: node.start,
|
|
164
|
+
end: node.end,
|
|
165
|
+
code: `${lines.join('\n')}\n`,
|
|
166
|
+
needsInterop
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
const lines = [];
|
|
170
|
+
for (const spec of node.specifiers) {
|
|
171
|
+
if (spec.type !== 'ExportSpecifier') continue;
|
|
172
|
+
const exported = spec.exported.name;
|
|
173
|
+
const local = spec.local.name;
|
|
174
|
+
lines.push(exportAssignment(exported, local, live));
|
|
175
|
+
}
|
|
176
|
+
exportTransforms.push({
|
|
177
|
+
start: node.start,
|
|
178
|
+
end: node.end,
|
|
179
|
+
code: `${lines.join('\n')}\n`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
185
|
+
const decl = node.declaration;
|
|
186
|
+
const useExportsObject = containsTopLevelAwait && opts.topLevelAwait !== 'error';
|
|
187
|
+
if (decl.type === 'FunctionDeclaration' || decl.type === 'ClassDeclaration') {
|
|
188
|
+
if (decl.id?.name) {
|
|
189
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
190
|
+
const assign = useExportsObject ? `exports.default = ${decl.id.name};` : `module.exports = ${decl.id.name};`;
|
|
191
|
+
exportTransforms.push({
|
|
192
|
+
start: node.start,
|
|
193
|
+
end: node.end,
|
|
194
|
+
code: `${declSrc}\n${assign}\n`
|
|
195
|
+
});
|
|
196
|
+
} else {
|
|
197
|
+
const declSrc = code.slice(decl.start, decl.end);
|
|
198
|
+
const assign = useExportsObject ? `exports.default = ${declSrc};` : `module.exports = ${declSrc};`;
|
|
199
|
+
exportTransforms.push({
|
|
200
|
+
start: node.start,
|
|
201
|
+
end: node.end,
|
|
202
|
+
code: `${assign}\n`
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
const exprSrc = code.slice(decl.start, decl.end);
|
|
207
|
+
const assign = useExportsObject ? `exports.default = ${exprSrc};` : `module.exports = ${exprSrc};`;
|
|
208
|
+
exportTransforms.push({
|
|
209
|
+
start: node.start,
|
|
210
|
+
end: node.end,
|
|
211
|
+
code: `${assign}\n`
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (node.type === 'ExportAllDeclaration') {
|
|
216
|
+
const srcLiteral = code.slice(node.source.start, node.source.end);
|
|
217
|
+
if (node.exported) {
|
|
218
|
+
const exported = node.exported.name;
|
|
219
|
+
const modIdent = `__mod${importIndex++}`;
|
|
220
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`, exportAssignment(exported, modIdent, live)];
|
|
221
|
+
exportTransforms.push({
|
|
222
|
+
start: node.start,
|
|
223
|
+
end: node.end,
|
|
224
|
+
code: `${lines.join('\n')}\n`
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
const modIdent = `__mod${importIndex++}`;
|
|
228
|
+
const lines = [`const ${modIdent} = require(${srcLiteral});`];
|
|
229
|
+
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}`;
|
|
230
|
+
lines.push(loop);
|
|
231
|
+
exportTransforms.push({
|
|
232
|
+
start: node.start,
|
|
233
|
+
end: node.end,
|
|
234
|
+
code: `${lines.join('\n')}\n`
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
importTransforms,
|
|
241
|
+
exportTransforms,
|
|
242
|
+
needsInterop
|
|
243
|
+
};
|
|
244
|
+
};
|
|
10
245
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
246
|
+
* Node added support for import.meta.main.
|
|
247
|
+
* Added in: v24.2.0, v22.18.0
|
|
248
|
+
* @see https://nodejs.org/api/esm.html#importmetamain
|
|
13
249
|
*/
|
|
14
250
|
const format = async (src, ast, opts) => {
|
|
15
251
|
const code = new MagicString(src);
|
|
@@ -19,7 +255,15 @@ const format = async (src, ast, opts) => {
|
|
|
19
255
|
hasDefaultExportBeenReassigned: false,
|
|
20
256
|
hasDefaultExportBeenAssigned: false
|
|
21
257
|
};
|
|
258
|
+
const exportTable = opts.target === 'module' ? await collectCjsExports(ast.program) : null;
|
|
22
259
|
await collectModuleIdentifiers(ast.program);
|
|
260
|
+
const shouldCheckTopLevelAwait = opts.target === 'commonjs' && opts.transformSyntax;
|
|
261
|
+
const containsTopLevelAwait = shouldCheckTopLevelAwait ? hasTopLevelAwait(ast.program) : false;
|
|
262
|
+
const shouldLowerCjs = opts.target === 'commonjs' && opts.transformSyntax;
|
|
263
|
+
let pendingCjsTransforms = null;
|
|
264
|
+
if (shouldLowerCjs && opts.topLevelAwait === 'error' && containsTopLevelAwait) {
|
|
265
|
+
throw new Error('Top-level await is not supported when targeting CommonJS (set topLevelAwait to "wrap" or "preserve" to override).');
|
|
266
|
+
}
|
|
23
267
|
if (opts.target === 'module' && opts.transformSyntax) {
|
|
24
268
|
/**
|
|
25
269
|
* Prepare ESM output by renaming `exports` to `__exports` and seeding an
|
|
@@ -104,6 +348,64 @@ void import.meta.filename;
|
|
|
104
348
|
}
|
|
105
349
|
}
|
|
106
350
|
});
|
|
351
|
+
if (shouldLowerCjs) {
|
|
352
|
+
const {
|
|
353
|
+
importTransforms,
|
|
354
|
+
exportTransforms,
|
|
355
|
+
needsInterop
|
|
356
|
+
} = lowerEsmToCjs(ast.program, code, opts, containsTopLevelAwait);
|
|
357
|
+
pendingCjsTransforms = {
|
|
358
|
+
transforms: [...importTransforms, ...exportTransforms].sort((a, b) => a.start - b.start),
|
|
359
|
+
needsInterop
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (pendingCjsTransforms) {
|
|
363
|
+
for (const t of pendingCjsTransforms.transforms) {
|
|
364
|
+
code.overwrite(t.start, t.end, t.code);
|
|
365
|
+
}
|
|
366
|
+
if (pendingCjsTransforms.needsInterop) {
|
|
367
|
+
code.prepend(`${interopHelper}exports.__esModule = true;\n`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (opts.target === 'module' && opts.transformSyntax && exportTable) {
|
|
371
|
+
const isValidExportName = name => /^[$A-Z_a-z][$\w]*$/.test(name);
|
|
372
|
+
const asExportName = name => isValidExportName(name) ? name : JSON.stringify(name);
|
|
373
|
+
const accessProp = name => isValidExportName(name) ? `${exportsRename}.${name}` : `${exportsRename}[${JSON.stringify(name)}]`;
|
|
374
|
+
const tempNameFor = name => {
|
|
375
|
+
const sanitized = name.replace(/[^$\w]/g, '_') || 'value';
|
|
376
|
+
const safe = /^[0-9]/.test(sanitized) ? `_${sanitized}` : sanitized;
|
|
377
|
+
return `__export_${safe}`;
|
|
378
|
+
};
|
|
379
|
+
const lines = [];
|
|
380
|
+
const defaultEntry = exportTable.get('default');
|
|
381
|
+
if (defaultEntry) {
|
|
382
|
+
const def = defaultEntry.fromIdentifier ?? exportsRename;
|
|
383
|
+
lines.push(`export default ${def};`);
|
|
384
|
+
}
|
|
385
|
+
for (const [key, entry] of exportTable) {
|
|
386
|
+
if (key === 'default') continue;
|
|
387
|
+
if (entry.fromIdentifier) {
|
|
388
|
+
lines.push(`export { ${entry.fromIdentifier} as ${asExportName(key)} };`);
|
|
389
|
+
} else {
|
|
390
|
+
const temp = tempNameFor(key);
|
|
391
|
+
lines.push(`const ${temp} = ${accessProp(key)};`);
|
|
392
|
+
lines.push(`export { ${temp} as ${asExportName(key)} };`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (lines.length) {
|
|
396
|
+
code.append(`\n${lines.join('\n')}\n`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (opts.target === 'commonjs' && opts.transformSyntax && containsTopLevelAwait) {
|
|
400
|
+
const body = code.toString();
|
|
401
|
+
if (opts.topLevelAwait === 'wrap') {
|
|
402
|
+
const tlaPromise = `const __tla = (async () => {\n${body}\nreturn module.exports;\n})();\n`;
|
|
403
|
+
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`;
|
|
404
|
+
const attach = `__setTla(module.exports);\n__tla.then(resolved => __setTla(resolved), err => { throw err; });\n`;
|
|
405
|
+
return `${tlaPromise}${setPromise}${attach}`;
|
|
406
|
+
}
|
|
407
|
+
return `;(async () => {\n${body}\n})();\n`;
|
|
408
|
+
}
|
|
107
409
|
return code.toString();
|
|
108
410
|
};
|
|
109
411
|
export { format };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { exportsRename } from '
|
|
2
|
-
import { identifier as ident } from '
|
|
1
|
+
import { exportsRename } from '#utils/exports.js';
|
|
2
|
+
import { identifier as ident } from '#helpers/identifier.js';
|
|
3
3
|
export const identifier = ({
|
|
4
4
|
node,
|
|
5
5
|
ancestors,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { exportsRename } from '
|
|
1
|
+
import { exportsRename } from '#utils/exports.js';
|
|
2
2
|
export const memberExpression = (node, parent, src, options) => {
|
|
3
3
|
if (options.target === 'module') {
|
|
4
4
|
if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'exports') {
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Node } from 'oxc-parser';
|
|
2
|
+
import type { IdentMeta, Scope } from '../types.js';
|
|
3
|
+
declare const collectScopeIdentifiers: (node: Node, scopes: Scope[]) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Collects all module scope identifiers in the AST.
|
|
6
|
+
*
|
|
7
|
+
* Ignores identifiers that are in functions or classes.
|
|
8
|
+
* Ignores new scopes for StaticBlock nodes (can only reference static class members).
|
|
9
|
+
*
|
|
10
|
+
* Special case handling for these which create their own scopes,
|
|
11
|
+
* but are also valid module scope identifiers:
|
|
12
|
+
* - ClassDeclaration
|
|
13
|
+
* - FunctionDeclaration
|
|
14
|
+
*
|
|
15
|
+
* Special case handling for var inside BlockStatement
|
|
16
|
+
* which are also valid module scope identifiers.
|
|
17
|
+
*/
|
|
18
|
+
declare const collectModuleIdentifiers: (ast: Node, hoisting?: boolean) => Promise<Map<string, IdentMeta>>;
|
|
19
|
+
export { collectScopeIdentifiers, collectModuleIdentifiers };
|
package/dist/lang.d.ts
ADDED
package/dist/module.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { specifier } from '@knighted/specifier';
|
|
4
|
-
import { parse } from '
|
|
5
|
-
import { format } from '
|
|
6
|
-
import { getLangFromExt } from '
|
|
4
|
+
import { parse } from '#parse';
|
|
5
|
+
import { format } from '#format';
|
|
6
|
+
import { getLangFromExt } from '#utils/lang.js';
|
|
7
7
|
const defaultOptions = {
|
|
8
8
|
target: 'commonjs',
|
|
9
9
|
sourceType: 'auto',
|
|
@@ -12,6 +12,7 @@ const defaultOptions = {
|
|
|
12
12
|
rewriteSpecifier: undefined,
|
|
13
13
|
dirFilename: 'inject',
|
|
14
14
|
importMeta: 'shim',
|
|
15
|
+
importMetaMain: 'shim',
|
|
15
16
|
requireSource: 'builtin',
|
|
16
17
|
cjsDefault: 'auto',
|
|
17
18
|
topLevelAwait: 'error',
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParseResult } from 'oxc-parser';
|
|
2
|
+
import type { FormatterOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Node added support for import.meta.main.
|
|
5
|
+
* Added in: v24.2.0, v22.18.0
|
|
6
|
+
* @see https://nodejs.org/api/esm.html#importmetamain
|
|
7
|
+
*/
|
|
8
|
+
declare const format: (src: string, ast: ParseResult, opts: FormatterOptions) => Promise<string>;
|
|
9
|
+
export { format };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Node, Span, IdentifierName, IdentifierReference, BindingIdentifier, LabelIdentifier, TSIndexSignatureName } from 'oxc-parser';
|
|
2
|
+
export type RewriteSpecifier = '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts' | ((value: string) => string | null | undefined);
|
|
3
|
+
export type ModuleOptions = {
|
|
4
|
+
target: 'module' | 'commonjs';
|
|
5
|
+
sourceType?: 'auto' | 'module' | 'commonjs';
|
|
6
|
+
transformSyntax?: boolean;
|
|
7
|
+
liveBindings?: 'strict' | 'loose' | 'off';
|
|
8
|
+
rewriteSpecifier?: RewriteSpecifier;
|
|
9
|
+
dirFilename?: 'inject' | 'preserve' | 'error';
|
|
10
|
+
importMeta?: 'preserve' | 'shim' | 'error';
|
|
11
|
+
importMetaMain?: 'shim' | 'warn' | 'error';
|
|
12
|
+
requireSource?: 'builtin' | 'create-require';
|
|
13
|
+
cjsDefault?: 'module-exports' | 'auto' | 'none';
|
|
14
|
+
topLevelAwait?: 'error' | 'wrap' | 'preserve';
|
|
15
|
+
out?: string;
|
|
16
|
+
inPlace?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export type SpannedNode = Node & Span;
|
|
19
|
+
export type ExportsMeta = {
|
|
20
|
+
hasExportsBeenReassigned: boolean;
|
|
21
|
+
hasDefaultExportBeenReassigned: boolean;
|
|
22
|
+
hasDefaultExportBeenAssigned: boolean;
|
|
23
|
+
defaultExportValue: unknown;
|
|
24
|
+
};
|
|
25
|
+
export type CjsExport = {
|
|
26
|
+
key: string;
|
|
27
|
+
writes: SpannedNode[];
|
|
28
|
+
fromIdentifier?: string;
|
|
29
|
+
via: Set<'exports' | 'module.exports'>;
|
|
30
|
+
reassignments: SpannedNode[];
|
|
31
|
+
hasGetter?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export type IdentMeta = {
|
|
34
|
+
declare: SpannedNode[];
|
|
35
|
+
read: SpannedNode[];
|
|
36
|
+
};
|
|
37
|
+
export type Scope = {
|
|
38
|
+
type: string;
|
|
39
|
+
name: string;
|
|
40
|
+
node: Node;
|
|
41
|
+
idents: Set<string>;
|
|
42
|
+
};
|
|
43
|
+
export type FormatterOptions = Omit<ModuleOptions, 'out' | 'inPlace'>;
|
|
44
|
+
export type Identifier = IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSIndexSignatureName;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Node } from 'oxc-parser';
|
|
2
|
+
import type { CjsExport } from '../types.js';
|
|
3
|
+
declare const exportsRename = "__exports";
|
|
4
|
+
declare const requireMainRgx: RegExp;
|
|
5
|
+
declare const collectCjsExports: (ast: Node) => Promise<Map<string, CjsExport>>;
|
|
6
|
+
export { exportsRename, requireMainRgx, collectCjsExports };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Node } from 'oxc-parser';
|
|
2
|
+
import type { IdentMeta, Scope } from '../types.js';
|
|
3
|
+
declare const collectScopeIdentifiers: (node: Node, scopes: Scope[]) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Collects all module scope identifiers in the AST.
|
|
6
|
+
*
|
|
7
|
+
* Ignores identifiers that are in functions or classes.
|
|
8
|
+
* Ignores new scopes for StaticBlock nodes (can only reference static class members).
|
|
9
|
+
*
|
|
10
|
+
* Special case handling for these which create their own scopes,
|
|
11
|
+
* but are also valid module scope identifiers:
|
|
12
|
+
* - ClassDeclaration
|
|
13
|
+
* - FunctionDeclaration
|
|
14
|
+
*
|
|
15
|
+
* Special case handling for var inside BlockStatement
|
|
16
|
+
* which are also valid module scope identifiers.
|
|
17
|
+
*/
|
|
18
|
+
declare const collectModuleIdentifiers: (ast: Node, hoisting?: boolean) => Promise<Map<string, IdentMeta>>;
|
|
19
|
+
export { collectScopeIdentifiers, collectModuleIdentifiers };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Node } from 'oxc-parser';
|
|
2
|
+
import type { Specifier } from '@knighted/specifier';
|
|
3
|
+
import type { IdentMeta, Scope, CjsExport } from './types.js';
|
|
4
|
+
type UpdateSrcLang = Parameters<Specifier['updateSrc']>[1];
|
|
5
|
+
declare const getLangFromExt: (filename: string) => UpdateSrcLang;
|
|
6
|
+
declare const isValidUrl: (url: string) => boolean;
|
|
7
|
+
declare const exportsRename = "__exports";
|
|
8
|
+
declare const requireMainRgx: RegExp;
|
|
9
|
+
declare const collectCjsExports: (ast: Node) => Promise<Map<string, CjsExport>>;
|
|
10
|
+
declare const collectScopeIdentifiers: (node: Node, scopes: Scope[]) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Collects all module scope identifiers in the AST.
|
|
13
|
+
*
|
|
14
|
+
* Ignores identifiers that are in functions or classes.
|
|
15
|
+
* Ignores new scopes for StaticBlock nodes (can only reference static class members).
|
|
16
|
+
*
|
|
17
|
+
* Special case handling for these which create their own scopes,
|
|
18
|
+
* but are also valid module scope identifiers:
|
|
19
|
+
* - ClassDeclaration
|
|
20
|
+
* - FunctionDeclaration
|
|
21
|
+
*
|
|
22
|
+
* Special case handling for var inside BlockStatement
|
|
23
|
+
* which are also valid module scope identifiers.
|
|
24
|
+
*/
|
|
25
|
+
declare const collectModuleIdentifiers: (ast: Node, hoisting?: boolean) => Promise<Map<string, IdentMeta>>;
|
|
26
|
+
export { getLangFromExt, isValidUrl, collectScopeIdentifiers, collectModuleIdentifiers, collectCjsExports, exportsRename, requireMainRgx, };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Node } from 'oxc-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Using visitorKeys instead of oxc Visitor to keep
|
|
4
|
+
* an ancestor-aware enter/leave API with this.skip()
|
|
5
|
+
* without per-node method boilerplate.
|
|
6
|
+
*/
|
|
7
|
+
type AncestorContext = {
|
|
8
|
+
skip: () => void;
|
|
9
|
+
};
|
|
10
|
+
type AncestorVisitor = {
|
|
11
|
+
enter?: (this: AncestorContext, node: Node, ancestors: Node[]) => void | Promise<void>;
|
|
12
|
+
leave?: (this: AncestorContext, node: Node, ancestors: Node[]) => void | Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
type WalkVisitor = {
|
|
15
|
+
enter?: (this: AncestorContext, node: Node, parent: Node | null) => void | Promise<void>;
|
|
16
|
+
leave?: (this: AncestorContext, node: Node, parent: Node | null) => void | Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
declare const ancestorWalk: (node: Node, visitors: AncestorVisitor) => Promise<void>;
|
|
19
|
+
declare const walk: (node: Node, visitors: WalkVisitor) => Promise<void>;
|
|
20
|
+
export { ancestorWalk, walk };
|
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';
|
|
@@ -21,6 +22,14 @@ export type ExportsMeta = {
|
|
|
21
22
|
hasDefaultExportBeenAssigned: boolean;
|
|
22
23
|
defaultExportValue: unknown;
|
|
23
24
|
};
|
|
25
|
+
export type CjsExport = {
|
|
26
|
+
key: string;
|
|
27
|
+
writes: SpannedNode[];
|
|
28
|
+
fromIdentifier?: string;
|
|
29
|
+
via: Set<'exports' | 'module.exports'>;
|
|
30
|
+
reassignments: SpannedNode[];
|
|
31
|
+
hasGetter?: boolean;
|
|
32
|
+
};
|
|
24
33
|
export type IdentMeta = {
|
|
25
34
|
declare: SpannedNode[];
|
|
26
35
|
read: SpannedNode[];
|
package/dist/url.d.ts
ADDED