@knighted/module 1.4.0 → 1.5.0
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 +4 -0
- package/dist/cjs/cli.cjs +115 -7
- package/dist/cjs/format.cjs +21 -19
- package/dist/cjs/format.d.cts +6 -6
- package/dist/cjs/module.cjs +41 -9
- package/dist/cjs/module.d.cts +14 -1
- package/dist/cjs/specifier.cjs +10 -5
- package/dist/cjs/specifier.d.cts +3 -1
- package/dist/cjs/types.d.cts +4 -0
- package/dist/cli.js +117 -9
- package/dist/format.d.ts +6 -6
- package/dist/format.js +19 -17
- package/dist/module.d.ts +14 -1
- package/dist/module.js +39 -7
- package/dist/specifier.d.ts +3 -1
- package/dist/specifier.js +10 -5
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,6 +114,7 @@ type ModuleOptions = {
|
|
|
114
114
|
target: 'module' | 'commonjs'
|
|
115
115
|
sourceType?: 'auto' | 'module' | 'commonjs'
|
|
116
116
|
transformSyntax?: boolean | 'globals-only'
|
|
117
|
+
sourceMap?: boolean
|
|
117
118
|
liveBindings?: 'strict' | 'loose' | 'off'
|
|
118
119
|
appendJsExtension?: 'off' | 'relative-only' | 'all'
|
|
119
120
|
appendDirectoryIndex?: string | false
|
|
@@ -133,6 +134,7 @@ type ModuleOptions = {
|
|
|
133
134
|
detectCircularRequires?: 'off' | 'warn' | 'error'
|
|
134
135
|
detectDualPackageHazard?: 'off' | 'warn' | 'error'
|
|
135
136
|
dualPackageHazardScope?: 'file' | 'project'
|
|
137
|
+
dualPackageHazardAllowlist?: string[]
|
|
136
138
|
requireSource?: 'builtin' | 'create-require'
|
|
137
139
|
importMetaPrelude?: 'off' | 'auto' | 'on'
|
|
138
140
|
cjsDefault?: 'module-exports' | 'auto' | 'none'
|
|
@@ -161,12 +163,14 @@ type ModuleOptions = {
|
|
|
161
163
|
- `detectCircularRequires` (`off`): optionally detect relative static require cycles across `.js`/`.mjs`/`.cjs`/`.ts`/`.mts`/`.cts` (realpath-normalized) and warn/throw.
|
|
162
164
|
- `detectDualPackageHazard` (`warn`): flag when `import` and `require` mix for the same package or root/subpath are combined in ways that can resolve to separate module instances (dual packages). Set to `error` to fail the transform.
|
|
163
165
|
- `dualPackageHazardScope` (`file`): `file` preserves the legacy per-file detector; `project` aggregates package usage across all CLI inputs (useful in monorepos/hoisted installs) and emits one diagnostic per package.
|
|
166
|
+
- `dualPackageHazardAllowlist` (`[]`): suppress dual-package hazard diagnostics for the listed packages. Accepts an array in the API; entries are trimmed and empty values dropped. The CLI flag `--dual-package-hazard-allowlist pkg1,pkg2` parses a comma- or space-separated string into this array. Applies to both `file` and `project` scopes.
|
|
164
167
|
- `topLevelAwait` (`error`): throw, wrap, or preserve when TLA appears in CommonJS output. `wrap` runs the file body inside an async IIFE (exports may resolve after the initial tick); `preserve` leaves `await` at top level, which Node will reject for CJS.
|
|
165
168
|
- `rewriteSpecifier` (off): rewrite relative specifiers to a chosen extension or via a callback. Precedence: the callback (if provided) runs first; if it returns a string, that wins. If it returns `undefined` or `null`, the appenders still apply.
|
|
166
169
|
- `requireSource` (`builtin`): whether `require` comes from Node or `createRequire`.
|
|
167
170
|
- `cjsDefault` (`auto`): bundler-style default interop vs direct `module.exports`.
|
|
168
171
|
- `idiomaticExports` (`safe`): when raising CJS to ESM, attempt to synthesize `export` statements directly when it is safe. `off` always uses the helper bag; `aggressive` currently matches `safe` heuristics.
|
|
169
172
|
- `out`/`inPlace`: choose output location. Default returns the transformed string (CLI emits to stdout). `out` writes to the provided path. `inPlace` overwrites the input files on disk and does not return/emit the code.
|
|
173
|
+
- `sourceMap` (`false`): when true, returns `{ code, map }` from `transform` and writes the map if you also set `out`/`inPlace`. Maps are generated from the same MagicString pipeline used for the code.
|
|
170
174
|
- `cwd` (`process.cwd()`): Base directory used to resolve relative `out` paths.
|
|
171
175
|
|
|
172
176
|
> [!NOTE]
|
package/dist/cjs/cli.cjs
CHANGED
|
@@ -32,12 +32,14 @@ const defaultOptions = {
|
|
|
32
32
|
detectCircularRequires: 'off',
|
|
33
33
|
detectDualPackageHazard: 'warn',
|
|
34
34
|
dualPackageHazardScope: 'file',
|
|
35
|
+
dualPackageHazardAllowlist: [],
|
|
35
36
|
requireSource: 'builtin',
|
|
36
37
|
nestedRequireStrategy: 'create-require',
|
|
37
38
|
cjsDefault: 'auto',
|
|
38
39
|
idiomaticExports: 'safe',
|
|
39
40
|
importMetaPrelude: 'auto',
|
|
40
41
|
topLevelAwait: 'error',
|
|
42
|
+
sourceMap: false,
|
|
41
43
|
cwd: undefined,
|
|
42
44
|
out: undefined,
|
|
43
45
|
inPlace: false
|
|
@@ -163,6 +165,11 @@ const optionsTable = [{
|
|
|
163
165
|
short: undefined,
|
|
164
166
|
type: 'string',
|
|
165
167
|
desc: 'Scope for dual package hazard detection (file|project)'
|
|
168
|
+
}, {
|
|
169
|
+
long: 'dual-package-hazard-allowlist',
|
|
170
|
+
short: undefined,
|
|
171
|
+
type: 'string',
|
|
172
|
+
desc: 'Comma-separated packages to ignore for dual package hazard checks'
|
|
166
173
|
}, {
|
|
167
174
|
long: 'top-level-await',
|
|
168
175
|
short: 'a',
|
|
@@ -183,6 +190,11 @@ const optionsTable = [{
|
|
|
183
190
|
short: 'm',
|
|
184
191
|
type: 'string',
|
|
185
192
|
desc: 'Emit import.meta prelude (off|auto|on)'
|
|
193
|
+
}, {
|
|
194
|
+
long: 'source-map',
|
|
195
|
+
short: undefined,
|
|
196
|
+
type: 'boolean',
|
|
197
|
+
desc: 'Emit a source map alongside transformed output (use --source-map=inline for stdout)'
|
|
186
198
|
}, {
|
|
187
199
|
long: 'nested-require-strategy',
|
|
188
200
|
short: 'n',
|
|
@@ -281,12 +293,17 @@ const parseAppendDirectoryIndex = value => {
|
|
|
281
293
|
if (value === 'false') return false;
|
|
282
294
|
return value;
|
|
283
295
|
};
|
|
296
|
+
const parseAllowlist = value => {
|
|
297
|
+
const values = value === undefined ? [] : Array.isArray(value) ? value : [value];
|
|
298
|
+
return values.flatMap(entry => String(entry).split(',')).map(item => item.trim()).filter(Boolean);
|
|
299
|
+
};
|
|
284
300
|
const toModuleOptions = values => {
|
|
285
301
|
const target = parseEnum(values.target, ['module', 'commonjs']) ?? defaultOptions.target;
|
|
286
302
|
const transformSyntax = parseTransformSyntax(values['transform-syntax']);
|
|
287
303
|
const rewriteTemplateLiterals = parseEnum(values['rewrite-template-literals'], ['allow', 'static-only']) ?? defaultOptions.rewriteTemplateLiterals;
|
|
288
304
|
const appendJsExtension = parseEnum(values['append-js-extension'], ['off', 'relative-only', 'all']);
|
|
289
305
|
const appendDirectoryIndex = parseAppendDirectoryIndex(values['append-directory-index']);
|
|
306
|
+
const dualPackageHazardAllowlist = parseAllowlist(values['dual-package-hazard-allowlist']);
|
|
290
307
|
const opts = {
|
|
291
308
|
...defaultOptions,
|
|
292
309
|
target,
|
|
@@ -298,6 +315,7 @@ const toModuleOptions = values => {
|
|
|
298
315
|
detectCircularRequires: parseEnum(values['detect-circular-requires'], ['off', 'warn', 'error']) ?? defaultOptions.detectCircularRequires,
|
|
299
316
|
detectDualPackageHazard: parseEnum(values['detect-dual-package-hazard'], ['off', 'warn', 'error']) ?? defaultOptions.detectDualPackageHazard,
|
|
300
317
|
dualPackageHazardScope: parseEnum(values['dual-package-hazard-scope'], ['file', 'project']) ?? defaultOptions.dualPackageHazardScope,
|
|
318
|
+
dualPackageHazardAllowlist,
|
|
301
319
|
topLevelAwait: parseEnum(values['top-level-await'], ['error', 'wrap', 'preserve']) ?? defaultOptions.topLevelAwait,
|
|
302
320
|
cjsDefault: parseEnum(values['cjs-default'], ['module-exports', 'auto', 'none']) ?? defaultOptions.cjsDefault,
|
|
303
321
|
idiomaticExports: parseEnum(values['idiomatic-exports'], ['off', 'safe', 'aggressive']) ?? defaultOptions.idiomaticExports,
|
|
@@ -305,6 +323,7 @@ const toModuleOptions = values => {
|
|
|
305
323
|
nestedRequireStrategy: parseEnum(values['nested-require-strategy'], ['create-require', 'dynamic-import']) ?? defaultOptions.nestedRequireStrategy,
|
|
306
324
|
requireMainStrategy: parseEnum(values['require-main-strategy'], ['import-meta-main', 'realpath']) ?? defaultOptions.requireMainStrategy,
|
|
307
325
|
liveBindings: parseEnum(values['live-bindings'], ['strict', 'loose', 'off']) ?? defaultOptions.liveBindings,
|
|
326
|
+
sourceMap: Boolean(values['source-map']),
|
|
308
327
|
cwd: values.cwd ? (0, _nodePath.resolve)(String(values.cwd)) : defaultOptions.cwd
|
|
309
328
|
};
|
|
310
329
|
return opts;
|
|
@@ -316,6 +335,55 @@ const readStdin = async stdin => {
|
|
|
316
335
|
}
|
|
317
336
|
return Buffer.concat(chunks).toString('utf8');
|
|
318
337
|
};
|
|
338
|
+
const normalizeSourceMapArgv = argv => {
|
|
339
|
+
let sourceMapInline = false;
|
|
340
|
+
let invalidSourceMapValue = null;
|
|
341
|
+
const normalized = [];
|
|
342
|
+
const recordInvalid = value => {
|
|
343
|
+
if (!invalidSourceMapValue) invalidSourceMapValue = value;
|
|
344
|
+
};
|
|
345
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
346
|
+
const arg = argv[i];
|
|
347
|
+
if (arg === '--source-map') {
|
|
348
|
+
const next = argv[i + 1];
|
|
349
|
+
if (next === 'inline') {
|
|
350
|
+
sourceMapInline = true;
|
|
351
|
+
normalized.push('--source-map');
|
|
352
|
+
i += 1;
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (next === 'true' || next === 'false') {
|
|
356
|
+
normalized.push(`--source-map=${next}`);
|
|
357
|
+
i += 1;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (arg.startsWith('--source-map=')) {
|
|
362
|
+
const value = arg.slice('--source-map='.length);
|
|
363
|
+
if (value === 'inline') {
|
|
364
|
+
sourceMapInline = true;
|
|
365
|
+
normalized.push('--source-map');
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (value === 'true' || value === 'false') {
|
|
369
|
+
normalized.push(arg);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
recordInvalid(value);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (arg === '--source-map' && argv[i + 1] && argv[i + 1].startsWith('--')) {
|
|
376
|
+
normalized.push('--source-map');
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
normalized.push(arg);
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
argv: normalized,
|
|
383
|
+
sourceMapInline,
|
|
384
|
+
invalidSourceMapValue
|
|
385
|
+
};
|
|
386
|
+
};
|
|
319
387
|
const expandFiles = async (patterns, cwd, ignore) => {
|
|
320
388
|
const files = new Set();
|
|
321
389
|
for (const pattern of patterns) {
|
|
@@ -403,8 +471,10 @@ const runFiles = async (files, moduleOpts, io, flags) => {
|
|
|
403
471
|
filePath: file,
|
|
404
472
|
detectDualPackageHazard: hazardScope === 'project' ? 'off' : moduleOpts.detectDualPackageHazard
|
|
405
473
|
};
|
|
474
|
+
const allowWrites = !flags.dryRun && !flags.list;
|
|
475
|
+
const writeInPlace = allowWrites && flags.inPlace;
|
|
406
476
|
let writeTarget;
|
|
407
|
-
if (
|
|
477
|
+
if (allowWrites) {
|
|
408
478
|
if (flags.inPlace) {
|
|
409
479
|
perFileOpts.inPlace = true;
|
|
410
480
|
} else if (outPath) {
|
|
@@ -421,8 +491,15 @@ const runFiles = async (files, moduleOpts, io, flags) => {
|
|
|
421
491
|
};
|
|
422
492
|
}
|
|
423
493
|
}
|
|
424
|
-
|
|
494
|
+
if (moduleOpts.sourceMap && (writeTarget || writeInPlace)) {
|
|
495
|
+
perFileOpts.out = undefined;
|
|
496
|
+
perFileOpts.inPlace = false;
|
|
497
|
+
}
|
|
498
|
+
const transformed = await (0, _module.transform)(file, perFileOpts);
|
|
499
|
+
const output = typeof transformed === 'string' ? transformed : transformed.code;
|
|
500
|
+
const map = typeof transformed === 'string' ? null : transformed.map;
|
|
425
501
|
const changed = output !== original;
|
|
502
|
+
let finalOutput = output;
|
|
426
503
|
if (projectHazards) {
|
|
427
504
|
const extras = projectHazards.get(file);
|
|
428
505
|
if (extras?.length) diagnostics.push(...extras);
|
|
@@ -430,8 +507,24 @@ const runFiles = async (files, moduleOpts, io, flags) => {
|
|
|
430
507
|
if (flags.list && changed) {
|
|
431
508
|
logger.info(file);
|
|
432
509
|
}
|
|
433
|
-
if (
|
|
434
|
-
|
|
510
|
+
if (map && flags.sourceMapInline && !writeTarget && !writeInPlace) {
|
|
511
|
+
const mapUri = Buffer.from(JSON.stringify(map)).toString('base64');
|
|
512
|
+
finalOutput = `${output.replace(/\/\/# sourceMappingURL=.*/g, '').trimEnd()}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${mapUri}\n`;
|
|
513
|
+
} else if (map && (writeTarget || writeInPlace)) {
|
|
514
|
+
const target = writeTarget ?? file;
|
|
515
|
+
const mapPath = `${target}.map`;
|
|
516
|
+
const mapFile = (0, _nodePath.basename)(mapPath);
|
|
517
|
+
map.file = (0, _nodePath.basename)(target);
|
|
518
|
+
const updated = `${output.replace(/\/\/# sourceMappingURL=.*/g, '').trimEnd()}\n//# sourceMappingURL=${mapFile}\n`;
|
|
519
|
+
await (0, _promises.writeFile)(mapPath, JSON.stringify(map));
|
|
520
|
+
if (writeTarget) {
|
|
521
|
+
await (0, _promises.writeFile)(writeTarget, updated);
|
|
522
|
+
} else if (writeInPlace) {
|
|
523
|
+
await (0, _promises.writeFile)(file, updated);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (!flags.dryRun && !flags.list && !writeTarget && !writeInPlace) {
|
|
527
|
+
io.stdout.write(finalOutput);
|
|
435
528
|
}
|
|
436
529
|
results.push({
|
|
437
530
|
filePath: file,
|
|
@@ -468,11 +561,21 @@ const runCli = async ({
|
|
|
468
561
|
stdout = _nodeProcess.stdout,
|
|
469
562
|
stderr = _nodeProcess.stderr
|
|
470
563
|
} = {}) => {
|
|
564
|
+
const logger = makeLogger(stdout, stderr);
|
|
565
|
+
const {
|
|
566
|
+
argv: normalizedArgv,
|
|
567
|
+
sourceMapInline,
|
|
568
|
+
invalidSourceMapValue
|
|
569
|
+
} = normalizeSourceMapArgv(argv);
|
|
570
|
+
if (invalidSourceMapValue) {
|
|
571
|
+
logger.error(`Invalid --source-map value: ${invalidSourceMapValue}`);
|
|
572
|
+
return 2;
|
|
573
|
+
}
|
|
471
574
|
const {
|
|
472
575
|
values,
|
|
473
576
|
positionals
|
|
474
577
|
} = (0, _nodeUtil.parseArgs)({
|
|
475
|
-
args:
|
|
578
|
+
args: normalizedArgv,
|
|
476
579
|
allowPositionals: true,
|
|
477
580
|
options: Object.fromEntries(optionsTable.map(opt => [opt.long, {
|
|
478
581
|
type: opt.type,
|
|
@@ -481,7 +584,6 @@ const runCli = async ({
|
|
|
481
584
|
} : {})
|
|
482
585
|
}]))
|
|
483
586
|
});
|
|
484
|
-
const logger = makeLogger(stdout, stderr);
|
|
485
587
|
if (values.help) {
|
|
486
588
|
stdout.write(buildHelp(stdout.isTTY ?? false));
|
|
487
589
|
return 0;
|
|
@@ -492,6 +594,7 @@ const runCli = async ({
|
|
|
492
594
|
return 0;
|
|
493
595
|
}
|
|
494
596
|
const moduleOpts = toModuleOptions(values);
|
|
597
|
+
if (sourceMapInline) moduleOpts.sourceMap = true;
|
|
495
598
|
const cwd = moduleOpts.cwd ?? process.cwd();
|
|
496
599
|
const allowStdout = positionals.length <= 1;
|
|
497
600
|
const fromStdin = positionals.length === 0 || positionals.includes('-');
|
|
@@ -504,6 +607,10 @@ const runCli = async ({
|
|
|
504
607
|
const list = Boolean(values.list);
|
|
505
608
|
const summary = Boolean(values.summary);
|
|
506
609
|
const json = Boolean(values.json);
|
|
610
|
+
if (sourceMapInline && (outDir || inPlace)) {
|
|
611
|
+
logger.error('Inline source maps are only supported when writing to stdout');
|
|
612
|
+
return 2;
|
|
613
|
+
}
|
|
507
614
|
if (outDir && inPlace) {
|
|
508
615
|
logger.error('Choose either --out-dir or --in-place, not both');
|
|
509
616
|
return 2;
|
|
@@ -558,7 +665,8 @@ const runCli = async ({
|
|
|
558
665
|
json,
|
|
559
666
|
outDir,
|
|
560
667
|
inPlace,
|
|
561
|
-
allowStdout
|
|
668
|
+
allowStdout,
|
|
669
|
+
sourceMapInline
|
|
562
670
|
});
|
|
563
671
|
if (typeof result.code === 'number' && result.code !== 0) return result.code;
|
|
564
672
|
tasks.push(...result.results);
|
package/dist/cjs/format.cjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.dualPackageHazardDiagnostics = exports.collectDualPackageUsage = void 0;
|
|
7
|
+
exports.format = format;
|
|
7
8
|
var _nodePath = require("node:path");
|
|
8
9
|
var _promises = require("node:fs/promises");
|
|
9
10
|
var _magicString = _interopRequireDefault(require("magic-string"));
|
|
@@ -148,6 +149,9 @@ const describeDualPackage = pkgJson => {
|
|
|
148
149
|
requireTarget
|
|
149
150
|
};
|
|
150
151
|
};
|
|
152
|
+
const normalizeAllowlist = allowlist => {
|
|
153
|
+
return new Set([...(allowlist ?? [])].map(item => item.trim()).filter(item => item.length > 0));
|
|
154
|
+
};
|
|
151
155
|
const recordUsage = (usages, pkg, kind, spec, subpath, loc, filePath) => {
|
|
152
156
|
const existing = usages.get(pkg) ?? {
|
|
153
157
|
imports: [],
|
|
@@ -217,8 +221,10 @@ const dualPackageHazardDiagnostics = async params => {
|
|
|
217
221
|
cwd
|
|
218
222
|
} = params;
|
|
219
223
|
const manifestCache = params.manifestCache ?? new Map();
|
|
224
|
+
const allowlist = normalizeAllowlist(params.hazardAllowlist);
|
|
220
225
|
const diags = [];
|
|
221
226
|
for (const [pkg, usage] of usages) {
|
|
227
|
+
if (allowlist.has(pkg)) continue;
|
|
222
228
|
const hasImport = usage.imports.length > 0;
|
|
223
229
|
const hasRequire = usage.requires.length > 0;
|
|
224
230
|
const combined = [...usage.imports, ...usage.requires];
|
|
@@ -285,19 +291,14 @@ const detectDualPackageHazards = async params => {
|
|
|
285
291
|
hazardLevel,
|
|
286
292
|
filePath,
|
|
287
293
|
cwd,
|
|
288
|
-
manifestCache
|
|
294
|
+
manifestCache,
|
|
295
|
+
hazardAllowlist: params.hazardAllowlist
|
|
289
296
|
});
|
|
290
297
|
for (const diag of diags) {
|
|
291
298
|
diagOnce(diag.level, diag.code, diag.message, diag.loc);
|
|
292
299
|
}
|
|
293
300
|
};
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Node added support for import.meta.main.
|
|
297
|
-
* Added in: v24.2.0, v22.18.0
|
|
298
|
-
* @see https://nodejs.org/api/esm.html#importmetamain
|
|
299
|
-
*/
|
|
300
|
-
const format = async (src, ast, opts) => {
|
|
301
|
+
async function format(src, ast, opts) {
|
|
301
302
|
const code = new _magicString.default(src);
|
|
302
303
|
const exportsMeta = {
|
|
303
304
|
hasExportsBeenReassigned: false,
|
|
@@ -346,7 +347,8 @@ const format = async (src, ast, opts) => {
|
|
|
346
347
|
hazardLevel,
|
|
347
348
|
filePath: opts.filePath,
|
|
348
349
|
cwd: opts.cwd,
|
|
349
|
-
diagOnce
|
|
350
|
+
diagOnce,
|
|
351
|
+
hazardAllowlist: opts.dualPackageHazardAllowlist
|
|
350
352
|
});
|
|
351
353
|
}
|
|
352
354
|
if (opts.target === 'module' && fullTransform) {
|
|
@@ -522,15 +524,15 @@ const format = async (src, ast, opts) => {
|
|
|
522
524
|
code.prepend(prelude);
|
|
523
525
|
}
|
|
524
526
|
if (opts.target === 'commonjs' && fullTransform && containsTopLevelAwait) {
|
|
525
|
-
const body = code.toString();
|
|
526
527
|
if (opts.topLevelAwait === 'wrap') {
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
|
|
528
|
+
code.prepend('const __tla = (async () => {\n');
|
|
529
|
+
code.append('\nreturn module.exports;\n})();\n');
|
|
530
|
+
code.append('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');
|
|
531
|
+
code.append('__setTla(module.exports);\n__tla.then(resolved => __setTla(resolved), err => { throw err; });\n');
|
|
532
|
+
} else {
|
|
533
|
+
code.prepend(';(async () => {\n');
|
|
534
|
+
code.append('\n})();\n');
|
|
531
535
|
}
|
|
532
|
-
return `;(async () => {\n${body}\n})();\n`;
|
|
533
536
|
}
|
|
534
|
-
return code.toString();
|
|
535
|
-
}
|
|
536
|
-
exports.format = format;
|
|
537
|
+
return opts.sourceMap ? code : code.toString();
|
|
538
|
+
}
|
package/dist/cjs/format.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Node, ParseResult } from 'oxc-parser';
|
|
2
|
+
import MagicString from 'magic-string';
|
|
2
3
|
import type { Diagnostic, FormatterOptions } from './types.cjs';
|
|
3
4
|
type HazardLevel = 'warning' | 'error';
|
|
4
5
|
export type PackageUse = {
|
|
@@ -21,11 +22,10 @@ declare const dualPackageHazardDiagnostics: (params: {
|
|
|
21
22
|
filePath?: string;
|
|
22
23
|
cwd?: string;
|
|
23
24
|
manifestCache?: Map<string, any | null>;
|
|
25
|
+
hazardAllowlist?: Iterable<string>;
|
|
24
26
|
}) => Promise<Diagnostic[]>;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*/
|
|
30
|
-
declare const format: (src: string, ast: ParseResult, opts: FormatterOptions) => Promise<string>;
|
|
27
|
+
declare function format(src: string, ast: ParseResult, opts: FormatterOptions & {
|
|
28
|
+
sourceMap: true;
|
|
29
|
+
}): Promise<MagicString>;
|
|
30
|
+
declare function format(src: string, ast: ParseResult, opts: FormatterOptions): Promise<string>;
|
|
31
31
|
export { format, collectDualPackageUsage, dualPackageHazardDiagnostics };
|
package/dist/cjs/module.cjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.collectProjectDualPackageHazards = void 0;
|
|
7
|
+
exports.transform = transform;
|
|
7
8
|
var _nodePath = require("node:path");
|
|
8
9
|
var _promises = require("node:fs/promises");
|
|
9
10
|
var _specifier = require("./specifier.cjs");
|
|
@@ -170,8 +171,10 @@ const collectProjectDualPackageHazards = async (files, opts) => {
|
|
|
170
171
|
const diags = await (0, _format.dualPackageHazardDiagnostics)({
|
|
171
172
|
usages,
|
|
172
173
|
hazardLevel,
|
|
174
|
+
filePath: opts.filePath,
|
|
173
175
|
cwd: opts.cwd,
|
|
174
|
-
manifestCache
|
|
176
|
+
manifestCache,
|
|
177
|
+
hazardAllowlist: opts.dualPackageHazardAllowlist
|
|
175
178
|
});
|
|
176
179
|
const byFile = new Map();
|
|
177
180
|
for (const diag of diags) {
|
|
@@ -199,17 +202,19 @@ const createDefaultOptions = () => ({
|
|
|
199
202
|
detectCircularRequires: 'off',
|
|
200
203
|
detectDualPackageHazard: 'warn',
|
|
201
204
|
dualPackageHazardScope: 'file',
|
|
205
|
+
dualPackageHazardAllowlist: [],
|
|
202
206
|
requireSource: 'builtin',
|
|
203
207
|
nestedRequireStrategy: 'create-require',
|
|
204
208
|
cjsDefault: 'auto',
|
|
205
209
|
idiomaticExports: 'safe',
|
|
206
210
|
importMetaPrelude: 'auto',
|
|
207
211
|
topLevelAwait: 'error',
|
|
212
|
+
sourceMap: false,
|
|
208
213
|
cwd: undefined,
|
|
209
214
|
out: undefined,
|
|
210
215
|
inPlace: false
|
|
211
216
|
});
|
|
212
|
-
|
|
217
|
+
async function transform(filename, options) {
|
|
213
218
|
const base = createDefaultOptions();
|
|
214
219
|
const opts = options ? {
|
|
215
220
|
...base,
|
|
@@ -226,9 +231,19 @@ const transform = async (filename, options) => {
|
|
|
226
231
|
const file = (0, _nodePath.resolve)(cwdBase, filename);
|
|
227
232
|
const code = (await (0, _promises.readFile)(file)).toString();
|
|
228
233
|
const ast = (0, _parse.parse)(filename, code);
|
|
229
|
-
let
|
|
234
|
+
let sourceCode = null;
|
|
235
|
+
let source;
|
|
236
|
+
if (opts.sourceMap) {
|
|
237
|
+
sourceCode = await (0, _format.format)(code, ast, {
|
|
238
|
+
...opts,
|
|
239
|
+
sourceMap: true
|
|
240
|
+
});
|
|
241
|
+
source = sourceCode.toString();
|
|
242
|
+
} else {
|
|
243
|
+
source = await (0, _format.format)(code, ast, opts);
|
|
244
|
+
}
|
|
230
245
|
if (opts.rewriteSpecifier || appendMode !== 'off' || dirIndex) {
|
|
231
|
-
const
|
|
246
|
+
const applyRewrite = spec => {
|
|
232
247
|
if (spec.type === 'TemplateLiteral' && opts.rewriteTemplateLiterals === 'static-only') {
|
|
233
248
|
const node = spec.node;
|
|
234
249
|
if (node.expressions.length > 0) return;
|
|
@@ -238,8 +253,14 @@ const transform = async (filename, options) => {
|
|
|
238
253
|
const baseValue = rewritten ?? normalized ?? spec.value;
|
|
239
254
|
const appended = appendExtensionIfNeeded(spec, appendMode, dirIndex, baseValue);
|
|
240
255
|
return appended ?? rewritten ?? normalized ?? undefined;
|
|
241
|
-
}
|
|
242
|
-
|
|
256
|
+
};
|
|
257
|
+
if (opts.sourceMap && sourceCode) {
|
|
258
|
+
await _specifier.specifier.updateMagicString(sourceCode, code, ast, applyRewrite);
|
|
259
|
+
source = sourceCode.toString();
|
|
260
|
+
} else {
|
|
261
|
+
const rewritten = await _specifier.specifier.updateSrc(source, (0, _lang.getLangFromExt)(filename), applyRewrite);
|
|
262
|
+
source = rewritten;
|
|
263
|
+
}
|
|
243
264
|
}
|
|
244
265
|
if (detectCycles !== 'off' && opts.target === 'module' && opts.transformSyntax) {
|
|
245
266
|
await detectCircularRequireGraph(file, detectCycles, dirIndex || 'index.js');
|
|
@@ -248,6 +269,17 @@ const transform = async (filename, options) => {
|
|
|
248
269
|
if (outputPath) {
|
|
249
270
|
await (0, _promises.writeFile)(outputPath, source);
|
|
250
271
|
}
|
|
272
|
+
if (opts.sourceMap && sourceCode) {
|
|
273
|
+
const map = sourceCode.generateMap({
|
|
274
|
+
hires: true,
|
|
275
|
+
includeContent: true,
|
|
276
|
+
file: outputPath ?? filename,
|
|
277
|
+
source: opts.filePath ?? filename
|
|
278
|
+
});
|
|
279
|
+
return {
|
|
280
|
+
code: source,
|
|
281
|
+
map
|
|
282
|
+
};
|
|
283
|
+
}
|
|
251
284
|
return source;
|
|
252
|
-
}
|
|
253
|
-
exports.transform = transform;
|
|
285
|
+
}
|
package/dist/cjs/module.d.cts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import type { ModuleOptions, Diagnostic } from './types.cjs';
|
|
2
|
+
import type { SourceMap } from 'magic-string';
|
|
2
3
|
declare const collectProjectDualPackageHazards: (files: string[], opts: ModuleOptions) => Promise<Map<string, Diagnostic[]>>;
|
|
3
|
-
declare
|
|
4
|
+
declare function transform(filename: string, options: ModuleOptions & {
|
|
5
|
+
sourceMap: true;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
code: string;
|
|
8
|
+
map: SourceMap;
|
|
9
|
+
}>;
|
|
10
|
+
declare function transform(filename: string, options?: ModuleOptions & {
|
|
11
|
+
sourceMap?: false | undefined;
|
|
12
|
+
}): Promise<string>;
|
|
13
|
+
declare function transform(filename: string, options?: ModuleOptions): Promise<string | {
|
|
14
|
+
code: string;
|
|
15
|
+
map: SourceMap;
|
|
16
|
+
}>;
|
|
4
17
|
export { transform, collectProjectDualPackageHazards };
|
package/dist/cjs/specifier.cjs
CHANGED
|
@@ -20,8 +20,7 @@ const isBinaryExpression = node => {
|
|
|
20
20
|
const isCallExpression = node => {
|
|
21
21
|
return node.type === 'CallExpression' && node.callee !== undefined;
|
|
22
22
|
};
|
|
23
|
-
const formatSpecifiers = async (src, ast, cb) => {
|
|
24
|
-
const code = new _magicString.default(src);
|
|
23
|
+
const formatSpecifiers = async (src, ast, cb, code = new _magicString.default(src)) => {
|
|
25
24
|
const formatExpression = expression => {
|
|
26
25
|
const node = isCallExpression(expression) ? expression.arguments[0] : expression.source;
|
|
27
26
|
const {
|
|
@@ -235,7 +234,7 @@ const formatSpecifiers = async (src, ast, cb) => {
|
|
|
235
234
|
}
|
|
236
235
|
}
|
|
237
236
|
});
|
|
238
|
-
return code
|
|
237
|
+
return code;
|
|
239
238
|
};
|
|
240
239
|
const isValidFilename = async filename => {
|
|
241
240
|
let stats;
|
|
@@ -258,11 +257,17 @@ const specifier = exports.specifier = {
|
|
|
258
257
|
}
|
|
259
258
|
const src = (await (0, _promises.readFile)(filename)).toString();
|
|
260
259
|
const ast = (0, _oxcParser.parseSync)(filename, src);
|
|
261
|
-
|
|
260
|
+
const code = await formatSpecifiers(src, ast, callback);
|
|
261
|
+
return code.toString();
|
|
262
262
|
},
|
|
263
263
|
async updateSrc(src, lang, callback) {
|
|
264
264
|
const filename = lang === 'ts' ? 'file.ts' : lang === 'tsx' ? 'file.tsx' : lang === 'js' ? 'file.js' : 'file.jsx';
|
|
265
265
|
const ast = (0, _oxcParser.parseSync)(filename, src);
|
|
266
|
-
|
|
266
|
+
const code = await formatSpecifiers(src, ast, callback);
|
|
267
|
+
return code.toString();
|
|
268
|
+
},
|
|
269
|
+
async updateMagicString(code, src, ast, callback) {
|
|
270
|
+
await formatSpecifiers(src, ast, callback, code);
|
|
271
|
+
return code;
|
|
267
272
|
}
|
|
268
273
|
};
|
package/dist/cjs/specifier.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import MagicString from 'magic-string';
|
|
2
|
+
import type { ParserOptions, ParseResult, StringLiteral, TemplateLiteral, BinaryExpression, NewExpression, ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration, TSImportType, ImportExpression, CallExpression } from 'oxc-parser';
|
|
2
3
|
type Spec = {
|
|
3
4
|
type: 'StringLiteral' | 'TemplateLiteral' | 'BinaryExpression' | 'NewExpression';
|
|
4
5
|
node: StringLiteral | TemplateLiteral | BinaryExpression | NewExpression;
|
|
@@ -11,6 +12,7 @@ type Callback = (spec: Spec) => string | void;
|
|
|
11
12
|
declare const specifier: {
|
|
12
13
|
update(path: string, callback: Callback): Promise<string>;
|
|
13
14
|
updateSrc(src: string, lang: ParserOptions["lang"], callback: Callback): Promise<string>;
|
|
15
|
+
updateMagicString(code: MagicString, src: string, ast: ParseResult, callback: Callback): Promise<MagicString>;
|
|
14
16
|
};
|
|
15
17
|
export { specifier };
|
|
16
18
|
export type { Spec, Callback };
|
package/dist/cjs/types.d.cts
CHANGED
|
@@ -6,6 +6,8 @@ export type ModuleOptions = {
|
|
|
6
6
|
target: 'module' | 'commonjs';
|
|
7
7
|
/** Explicit source type; auto infers from file extension. */
|
|
8
8
|
sourceType?: 'auto' | 'module' | 'commonjs';
|
|
9
|
+
/** Emit a source map alongside the transformed code. */
|
|
10
|
+
sourceMap?: boolean;
|
|
9
11
|
/**
|
|
10
12
|
* Enable syntax transforms beyond parsing.
|
|
11
13
|
* - true: full CJS↔ESM lowering/raising
|
|
@@ -38,6 +40,8 @@ export type ModuleOptions = {
|
|
|
38
40
|
detectDualPackageHazard?: 'off' | 'warn' | 'error';
|
|
39
41
|
/** Scope for dual package hazard detection. */
|
|
40
42
|
dualPackageHazardScope?: 'file' | 'project';
|
|
43
|
+
/** Packages to ignore for dual package hazard diagnostics. */
|
|
44
|
+
dualPackageHazardAllowlist?: string[];
|
|
41
45
|
/** Source used to provide require in ESM output. */
|
|
42
46
|
requireSource?: 'builtin' | 'create-require';
|
|
43
47
|
/** How to rewrite nested or non-hoistable require calls. */
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { stdin as defaultStdin, stdout as defaultStdout, stderr as defaultStderr } from 'node:process';
|
|
3
3
|
import { parseArgs } from 'node:util';
|
|
4
|
-
import { readFile, mkdir } from 'node:fs/promises';
|
|
5
|
-
import { dirname, resolve, relative, join } from 'node:path';
|
|
4
|
+
import { readFile, mkdir, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { dirname, resolve, relative, join, basename } from 'node:path';
|
|
6
6
|
import { glob } from 'glob';
|
|
7
7
|
import { transform, collectProjectDualPackageHazards } from './module.js';
|
|
8
8
|
import { parse } from './parse.js';
|
|
@@ -26,12 +26,14 @@ const defaultOptions = {
|
|
|
26
26
|
detectCircularRequires: 'off',
|
|
27
27
|
detectDualPackageHazard: 'warn',
|
|
28
28
|
dualPackageHazardScope: 'file',
|
|
29
|
+
dualPackageHazardAllowlist: [],
|
|
29
30
|
requireSource: 'builtin',
|
|
30
31
|
nestedRequireStrategy: 'create-require',
|
|
31
32
|
cjsDefault: 'auto',
|
|
32
33
|
idiomaticExports: 'safe',
|
|
33
34
|
importMetaPrelude: 'auto',
|
|
34
35
|
topLevelAwait: 'error',
|
|
36
|
+
sourceMap: false,
|
|
35
37
|
cwd: undefined,
|
|
36
38
|
out: undefined,
|
|
37
39
|
inPlace: false
|
|
@@ -157,6 +159,11 @@ const optionsTable = [{
|
|
|
157
159
|
short: undefined,
|
|
158
160
|
type: 'string',
|
|
159
161
|
desc: 'Scope for dual package hazard detection (file|project)'
|
|
162
|
+
}, {
|
|
163
|
+
long: 'dual-package-hazard-allowlist',
|
|
164
|
+
short: undefined,
|
|
165
|
+
type: 'string',
|
|
166
|
+
desc: 'Comma-separated packages to ignore for dual package hazard checks'
|
|
160
167
|
}, {
|
|
161
168
|
long: 'top-level-await',
|
|
162
169
|
short: 'a',
|
|
@@ -177,6 +184,11 @@ const optionsTable = [{
|
|
|
177
184
|
short: 'm',
|
|
178
185
|
type: 'string',
|
|
179
186
|
desc: 'Emit import.meta prelude (off|auto|on)'
|
|
187
|
+
}, {
|
|
188
|
+
long: 'source-map',
|
|
189
|
+
short: undefined,
|
|
190
|
+
type: 'boolean',
|
|
191
|
+
desc: 'Emit a source map alongside transformed output (use --source-map=inline for stdout)'
|
|
180
192
|
}, {
|
|
181
193
|
long: 'nested-require-strategy',
|
|
182
194
|
short: 'n',
|
|
@@ -275,12 +287,17 @@ const parseAppendDirectoryIndex = value => {
|
|
|
275
287
|
if (value === 'false') return false;
|
|
276
288
|
return value;
|
|
277
289
|
};
|
|
290
|
+
const parseAllowlist = value => {
|
|
291
|
+
const values = value === undefined ? [] : Array.isArray(value) ? value : [value];
|
|
292
|
+
return values.flatMap(entry => String(entry).split(',')).map(item => item.trim()).filter(Boolean);
|
|
293
|
+
};
|
|
278
294
|
const toModuleOptions = values => {
|
|
279
295
|
const target = parseEnum(values.target, ['module', 'commonjs']) ?? defaultOptions.target;
|
|
280
296
|
const transformSyntax = parseTransformSyntax(values['transform-syntax']);
|
|
281
297
|
const rewriteTemplateLiterals = parseEnum(values['rewrite-template-literals'], ['allow', 'static-only']) ?? defaultOptions.rewriteTemplateLiterals;
|
|
282
298
|
const appendJsExtension = parseEnum(values['append-js-extension'], ['off', 'relative-only', 'all']);
|
|
283
299
|
const appendDirectoryIndex = parseAppendDirectoryIndex(values['append-directory-index']);
|
|
300
|
+
const dualPackageHazardAllowlist = parseAllowlist(values['dual-package-hazard-allowlist']);
|
|
284
301
|
const opts = {
|
|
285
302
|
...defaultOptions,
|
|
286
303
|
target,
|
|
@@ -292,6 +309,7 @@ const toModuleOptions = values => {
|
|
|
292
309
|
detectCircularRequires: parseEnum(values['detect-circular-requires'], ['off', 'warn', 'error']) ?? defaultOptions.detectCircularRequires,
|
|
293
310
|
detectDualPackageHazard: parseEnum(values['detect-dual-package-hazard'], ['off', 'warn', 'error']) ?? defaultOptions.detectDualPackageHazard,
|
|
294
311
|
dualPackageHazardScope: parseEnum(values['dual-package-hazard-scope'], ['file', 'project']) ?? defaultOptions.dualPackageHazardScope,
|
|
312
|
+
dualPackageHazardAllowlist,
|
|
295
313
|
topLevelAwait: parseEnum(values['top-level-await'], ['error', 'wrap', 'preserve']) ?? defaultOptions.topLevelAwait,
|
|
296
314
|
cjsDefault: parseEnum(values['cjs-default'], ['module-exports', 'auto', 'none']) ?? defaultOptions.cjsDefault,
|
|
297
315
|
idiomaticExports: parseEnum(values['idiomatic-exports'], ['off', 'safe', 'aggressive']) ?? defaultOptions.idiomaticExports,
|
|
@@ -299,6 +317,7 @@ const toModuleOptions = values => {
|
|
|
299
317
|
nestedRequireStrategy: parseEnum(values['nested-require-strategy'], ['create-require', 'dynamic-import']) ?? defaultOptions.nestedRequireStrategy,
|
|
300
318
|
requireMainStrategy: parseEnum(values['require-main-strategy'], ['import-meta-main', 'realpath']) ?? defaultOptions.requireMainStrategy,
|
|
301
319
|
liveBindings: parseEnum(values['live-bindings'], ['strict', 'loose', 'off']) ?? defaultOptions.liveBindings,
|
|
320
|
+
sourceMap: Boolean(values['source-map']),
|
|
302
321
|
cwd: values.cwd ? resolve(String(values.cwd)) : defaultOptions.cwd
|
|
303
322
|
};
|
|
304
323
|
return opts;
|
|
@@ -310,6 +329,55 @@ const readStdin = async stdin => {
|
|
|
310
329
|
}
|
|
311
330
|
return Buffer.concat(chunks).toString('utf8');
|
|
312
331
|
};
|
|
332
|
+
const normalizeSourceMapArgv = argv => {
|
|
333
|
+
let sourceMapInline = false;
|
|
334
|
+
let invalidSourceMapValue = null;
|
|
335
|
+
const normalized = [];
|
|
336
|
+
const recordInvalid = value => {
|
|
337
|
+
if (!invalidSourceMapValue) invalidSourceMapValue = value;
|
|
338
|
+
};
|
|
339
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
340
|
+
const arg = argv[i];
|
|
341
|
+
if (arg === '--source-map') {
|
|
342
|
+
const next = argv[i + 1];
|
|
343
|
+
if (next === 'inline') {
|
|
344
|
+
sourceMapInline = true;
|
|
345
|
+
normalized.push('--source-map');
|
|
346
|
+
i += 1;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (next === 'true' || next === 'false') {
|
|
350
|
+
normalized.push(`--source-map=${next}`);
|
|
351
|
+
i += 1;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (arg.startsWith('--source-map=')) {
|
|
356
|
+
const value = arg.slice('--source-map='.length);
|
|
357
|
+
if (value === 'inline') {
|
|
358
|
+
sourceMapInline = true;
|
|
359
|
+
normalized.push('--source-map');
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (value === 'true' || value === 'false') {
|
|
363
|
+
normalized.push(arg);
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
recordInvalid(value);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (arg === '--source-map' && argv[i + 1] && argv[i + 1].startsWith('--')) {
|
|
370
|
+
normalized.push('--source-map');
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
normalized.push(arg);
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
argv: normalized,
|
|
377
|
+
sourceMapInline,
|
|
378
|
+
invalidSourceMapValue
|
|
379
|
+
};
|
|
380
|
+
};
|
|
313
381
|
const expandFiles = async (patterns, cwd, ignore) => {
|
|
314
382
|
const files = new Set();
|
|
315
383
|
for (const pattern of patterns) {
|
|
@@ -397,8 +465,10 @@ const runFiles = async (files, moduleOpts, io, flags) => {
|
|
|
397
465
|
filePath: file,
|
|
398
466
|
detectDualPackageHazard: hazardScope === 'project' ? 'off' : moduleOpts.detectDualPackageHazard
|
|
399
467
|
};
|
|
468
|
+
const allowWrites = !flags.dryRun && !flags.list;
|
|
469
|
+
const writeInPlace = allowWrites && flags.inPlace;
|
|
400
470
|
let writeTarget;
|
|
401
|
-
if (
|
|
471
|
+
if (allowWrites) {
|
|
402
472
|
if (flags.inPlace) {
|
|
403
473
|
perFileOpts.inPlace = true;
|
|
404
474
|
} else if (outPath) {
|
|
@@ -415,8 +485,15 @@ const runFiles = async (files, moduleOpts, io, flags) => {
|
|
|
415
485
|
};
|
|
416
486
|
}
|
|
417
487
|
}
|
|
418
|
-
|
|
488
|
+
if (moduleOpts.sourceMap && (writeTarget || writeInPlace)) {
|
|
489
|
+
perFileOpts.out = undefined;
|
|
490
|
+
perFileOpts.inPlace = false;
|
|
491
|
+
}
|
|
492
|
+
const transformed = await transform(file, perFileOpts);
|
|
493
|
+
const output = typeof transformed === 'string' ? transformed : transformed.code;
|
|
494
|
+
const map = typeof transformed === 'string' ? null : transformed.map;
|
|
419
495
|
const changed = output !== original;
|
|
496
|
+
let finalOutput = output;
|
|
420
497
|
if (projectHazards) {
|
|
421
498
|
const extras = projectHazards.get(file);
|
|
422
499
|
if (extras?.length) diagnostics.push(...extras);
|
|
@@ -424,8 +501,24 @@ const runFiles = async (files, moduleOpts, io, flags) => {
|
|
|
424
501
|
if (flags.list && changed) {
|
|
425
502
|
logger.info(file);
|
|
426
503
|
}
|
|
427
|
-
if (
|
|
428
|
-
|
|
504
|
+
if (map && flags.sourceMapInline && !writeTarget && !writeInPlace) {
|
|
505
|
+
const mapUri = Buffer.from(JSON.stringify(map)).toString('base64');
|
|
506
|
+
finalOutput = `${output.replace(/\/\/# sourceMappingURL=.*/g, '').trimEnd()}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${mapUri}\n`;
|
|
507
|
+
} else if (map && (writeTarget || writeInPlace)) {
|
|
508
|
+
const target = writeTarget ?? file;
|
|
509
|
+
const mapPath = `${target}.map`;
|
|
510
|
+
const mapFile = basename(mapPath);
|
|
511
|
+
map.file = basename(target);
|
|
512
|
+
const updated = `${output.replace(/\/\/# sourceMappingURL=.*/g, '').trimEnd()}\n//# sourceMappingURL=${mapFile}\n`;
|
|
513
|
+
await writeFile(mapPath, JSON.stringify(map));
|
|
514
|
+
if (writeTarget) {
|
|
515
|
+
await writeFile(writeTarget, updated);
|
|
516
|
+
} else if (writeInPlace) {
|
|
517
|
+
await writeFile(file, updated);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (!flags.dryRun && !flags.list && !writeTarget && !writeInPlace) {
|
|
521
|
+
io.stdout.write(finalOutput);
|
|
429
522
|
}
|
|
430
523
|
results.push({
|
|
431
524
|
filePath: file,
|
|
@@ -462,11 +555,21 @@ const runCli = async ({
|
|
|
462
555
|
stdout = defaultStdout,
|
|
463
556
|
stderr = defaultStderr
|
|
464
557
|
} = {}) => {
|
|
558
|
+
const logger = makeLogger(stdout, stderr);
|
|
559
|
+
const {
|
|
560
|
+
argv: normalizedArgv,
|
|
561
|
+
sourceMapInline,
|
|
562
|
+
invalidSourceMapValue
|
|
563
|
+
} = normalizeSourceMapArgv(argv);
|
|
564
|
+
if (invalidSourceMapValue) {
|
|
565
|
+
logger.error(`Invalid --source-map value: ${invalidSourceMapValue}`);
|
|
566
|
+
return 2;
|
|
567
|
+
}
|
|
465
568
|
const {
|
|
466
569
|
values,
|
|
467
570
|
positionals
|
|
468
571
|
} = parseArgs({
|
|
469
|
-
args:
|
|
572
|
+
args: normalizedArgv,
|
|
470
573
|
allowPositionals: true,
|
|
471
574
|
options: Object.fromEntries(optionsTable.map(opt => [opt.long, {
|
|
472
575
|
type: opt.type,
|
|
@@ -475,7 +578,6 @@ const runCli = async ({
|
|
|
475
578
|
} : {})
|
|
476
579
|
}]))
|
|
477
580
|
});
|
|
478
|
-
const logger = makeLogger(stdout, stderr);
|
|
479
581
|
if (values.help) {
|
|
480
582
|
stdout.write(buildHelp(stdout.isTTY ?? false));
|
|
481
583
|
return 0;
|
|
@@ -486,6 +588,7 @@ const runCli = async ({
|
|
|
486
588
|
return 0;
|
|
487
589
|
}
|
|
488
590
|
const moduleOpts = toModuleOptions(values);
|
|
591
|
+
if (sourceMapInline) moduleOpts.sourceMap = true;
|
|
489
592
|
const cwd = moduleOpts.cwd ?? process.cwd();
|
|
490
593
|
const allowStdout = positionals.length <= 1;
|
|
491
594
|
const fromStdin = positionals.length === 0 || positionals.includes('-');
|
|
@@ -498,6 +601,10 @@ const runCli = async ({
|
|
|
498
601
|
const list = Boolean(values.list);
|
|
499
602
|
const summary = Boolean(values.summary);
|
|
500
603
|
const json = Boolean(values.json);
|
|
604
|
+
if (sourceMapInline && (outDir || inPlace)) {
|
|
605
|
+
logger.error('Inline source maps are only supported when writing to stdout');
|
|
606
|
+
return 2;
|
|
607
|
+
}
|
|
501
608
|
if (outDir && inPlace) {
|
|
502
609
|
logger.error('Choose either --out-dir or --in-place, not both');
|
|
503
610
|
return 2;
|
|
@@ -552,7 +659,8 @@ const runCli = async ({
|
|
|
552
659
|
json,
|
|
553
660
|
outDir,
|
|
554
661
|
inPlace,
|
|
555
|
-
allowStdout
|
|
662
|
+
allowStdout,
|
|
663
|
+
sourceMapInline
|
|
556
664
|
});
|
|
557
665
|
if (typeof result.code === 'number' && result.code !== 0) return result.code;
|
|
558
666
|
tasks.push(...result.results);
|
package/dist/format.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Node, ParseResult } from 'oxc-parser';
|
|
2
|
+
import MagicString from 'magic-string';
|
|
2
3
|
import type { Diagnostic, FormatterOptions } from './types.js';
|
|
3
4
|
type HazardLevel = 'warning' | 'error';
|
|
4
5
|
export type PackageUse = {
|
|
@@ -21,11 +22,10 @@ declare const dualPackageHazardDiagnostics: (params: {
|
|
|
21
22
|
filePath?: string;
|
|
22
23
|
cwd?: string;
|
|
23
24
|
manifestCache?: Map<string, any | null>;
|
|
25
|
+
hazardAllowlist?: Iterable<string>;
|
|
24
26
|
}) => Promise<Diagnostic[]>;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*/
|
|
30
|
-
declare const format: (src: string, ast: ParseResult, opts: FormatterOptions) => Promise<string>;
|
|
27
|
+
declare function format(src: string, ast: ParseResult, opts: FormatterOptions & {
|
|
28
|
+
sourceMap: true;
|
|
29
|
+
}): Promise<MagicString>;
|
|
30
|
+
declare function format(src: string, ast: ParseResult, opts: FormatterOptions): Promise<string>;
|
|
31
31
|
export { format, collectDualPackageUsage, dualPackageHazardDiagnostics };
|
package/dist/format.js
CHANGED
|
@@ -141,6 +141,9 @@ const describeDualPackage = pkgJson => {
|
|
|
141
141
|
requireTarget
|
|
142
142
|
};
|
|
143
143
|
};
|
|
144
|
+
const normalizeAllowlist = allowlist => {
|
|
145
|
+
return new Set([...(allowlist ?? [])].map(item => item.trim()).filter(item => item.length > 0));
|
|
146
|
+
};
|
|
144
147
|
const recordUsage = (usages, pkg, kind, spec, subpath, loc, filePath) => {
|
|
145
148
|
const existing = usages.get(pkg) ?? {
|
|
146
149
|
imports: [],
|
|
@@ -209,8 +212,10 @@ const dualPackageHazardDiagnostics = async params => {
|
|
|
209
212
|
cwd
|
|
210
213
|
} = params;
|
|
211
214
|
const manifestCache = params.manifestCache ?? new Map();
|
|
215
|
+
const allowlist = normalizeAllowlist(params.hazardAllowlist);
|
|
212
216
|
const diags = [];
|
|
213
217
|
for (const [pkg, usage] of usages) {
|
|
218
|
+
if (allowlist.has(pkg)) continue;
|
|
214
219
|
const hasImport = usage.imports.length > 0;
|
|
215
220
|
const hasRequire = usage.requires.length > 0;
|
|
216
221
|
const combined = [...usage.imports, ...usage.requires];
|
|
@@ -276,19 +281,14 @@ const detectDualPackageHazards = async params => {
|
|
|
276
281
|
hazardLevel,
|
|
277
282
|
filePath,
|
|
278
283
|
cwd,
|
|
279
|
-
manifestCache
|
|
284
|
+
manifestCache,
|
|
285
|
+
hazardAllowlist: params.hazardAllowlist
|
|
280
286
|
});
|
|
281
287
|
for (const diag of diags) {
|
|
282
288
|
diagOnce(diag.level, diag.code, diag.message, diag.loc);
|
|
283
289
|
}
|
|
284
290
|
};
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Node added support for import.meta.main.
|
|
288
|
-
* Added in: v24.2.0, v22.18.0
|
|
289
|
-
* @see https://nodejs.org/api/esm.html#importmetamain
|
|
290
|
-
*/
|
|
291
|
-
const format = async (src, ast, opts) => {
|
|
291
|
+
async function format(src, ast, opts) {
|
|
292
292
|
const code = new MagicString(src);
|
|
293
293
|
const exportsMeta = {
|
|
294
294
|
hasExportsBeenReassigned: false,
|
|
@@ -337,7 +337,8 @@ const format = async (src, ast, opts) => {
|
|
|
337
337
|
hazardLevel,
|
|
338
338
|
filePath: opts.filePath,
|
|
339
339
|
cwd: opts.cwd,
|
|
340
|
-
diagOnce
|
|
340
|
+
diagOnce,
|
|
341
|
+
hazardAllowlist: opts.dualPackageHazardAllowlist
|
|
341
342
|
});
|
|
342
343
|
}
|
|
343
344
|
if (opts.target === 'module' && fullTransform) {
|
|
@@ -513,15 +514,16 @@ const format = async (src, ast, opts) => {
|
|
|
513
514
|
code.prepend(prelude);
|
|
514
515
|
}
|
|
515
516
|
if (opts.target === 'commonjs' && fullTransform && containsTopLevelAwait) {
|
|
516
|
-
const body = code.toString();
|
|
517
517
|
if (opts.topLevelAwait === 'wrap') {
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
const
|
|
521
|
-
|
|
518
|
+
code.prepend('const __tla = (async () => {\n');
|
|
519
|
+
code.append('\nreturn module.exports;\n})();\n');
|
|
520
|
+
code.append('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');
|
|
521
|
+
code.append('__setTla(module.exports);\n__tla.then(resolved => __setTla(resolved), err => { throw err; });\n');
|
|
522
|
+
} else {
|
|
523
|
+
code.prepend(';(async () => {\n');
|
|
524
|
+
code.append('\n})();\n');
|
|
522
525
|
}
|
|
523
|
-
return `;(async () => {\n${body}\n})();\n`;
|
|
524
526
|
}
|
|
525
|
-
return code.toString();
|
|
526
|
-
}
|
|
527
|
+
return opts.sourceMap ? code : code.toString();
|
|
528
|
+
}
|
|
527
529
|
export { format, collectDualPackageUsage, dualPackageHazardDiagnostics };
|
package/dist/module.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import type { ModuleOptions, Diagnostic } from './types.js';
|
|
2
|
+
import type { SourceMap } from 'magic-string';
|
|
2
3
|
declare const collectProjectDualPackageHazards: (files: string[], opts: ModuleOptions) => Promise<Map<string, Diagnostic[]>>;
|
|
3
|
-
declare
|
|
4
|
+
declare function transform(filename: string, options: ModuleOptions & {
|
|
5
|
+
sourceMap: true;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
code: string;
|
|
8
|
+
map: SourceMap;
|
|
9
|
+
}>;
|
|
10
|
+
declare function transform(filename: string, options?: ModuleOptions & {
|
|
11
|
+
sourceMap?: false | undefined;
|
|
12
|
+
}): Promise<string>;
|
|
13
|
+
declare function transform(filename: string, options?: ModuleOptions): Promise<string | {
|
|
14
|
+
code: string;
|
|
15
|
+
map: SourceMap;
|
|
16
|
+
}>;
|
|
4
17
|
export { transform, collectProjectDualPackageHazards };
|
package/dist/module.js
CHANGED
|
@@ -167,8 +167,10 @@ const collectProjectDualPackageHazards = async (files, opts) => {
|
|
|
167
167
|
const diags = await dualPackageHazardDiagnostics({
|
|
168
168
|
usages,
|
|
169
169
|
hazardLevel,
|
|
170
|
+
filePath: opts.filePath,
|
|
170
171
|
cwd: opts.cwd,
|
|
171
|
-
manifestCache
|
|
172
|
+
manifestCache,
|
|
173
|
+
hazardAllowlist: opts.dualPackageHazardAllowlist
|
|
172
174
|
});
|
|
173
175
|
const byFile = new Map();
|
|
174
176
|
for (const diag of diags) {
|
|
@@ -195,17 +197,19 @@ const createDefaultOptions = () => ({
|
|
|
195
197
|
detectCircularRequires: 'off',
|
|
196
198
|
detectDualPackageHazard: 'warn',
|
|
197
199
|
dualPackageHazardScope: 'file',
|
|
200
|
+
dualPackageHazardAllowlist: [],
|
|
198
201
|
requireSource: 'builtin',
|
|
199
202
|
nestedRequireStrategy: 'create-require',
|
|
200
203
|
cjsDefault: 'auto',
|
|
201
204
|
idiomaticExports: 'safe',
|
|
202
205
|
importMetaPrelude: 'auto',
|
|
203
206
|
topLevelAwait: 'error',
|
|
207
|
+
sourceMap: false,
|
|
204
208
|
cwd: undefined,
|
|
205
209
|
out: undefined,
|
|
206
210
|
inPlace: false
|
|
207
211
|
});
|
|
208
|
-
|
|
212
|
+
async function transform(filename, options) {
|
|
209
213
|
const base = createDefaultOptions();
|
|
210
214
|
const opts = options ? {
|
|
211
215
|
...base,
|
|
@@ -222,9 +226,19 @@ const transform = async (filename, options) => {
|
|
|
222
226
|
const file = resolve(cwdBase, filename);
|
|
223
227
|
const code = (await readFile(file)).toString();
|
|
224
228
|
const ast = parse(filename, code);
|
|
225
|
-
let
|
|
229
|
+
let sourceCode = null;
|
|
230
|
+
let source;
|
|
231
|
+
if (opts.sourceMap) {
|
|
232
|
+
sourceCode = await format(code, ast, {
|
|
233
|
+
...opts,
|
|
234
|
+
sourceMap: true
|
|
235
|
+
});
|
|
236
|
+
source = sourceCode.toString();
|
|
237
|
+
} else {
|
|
238
|
+
source = await format(code, ast, opts);
|
|
239
|
+
}
|
|
226
240
|
if (opts.rewriteSpecifier || appendMode !== 'off' || dirIndex) {
|
|
227
|
-
const
|
|
241
|
+
const applyRewrite = spec => {
|
|
228
242
|
if (spec.type === 'TemplateLiteral' && opts.rewriteTemplateLiterals === 'static-only') {
|
|
229
243
|
const node = spec.node;
|
|
230
244
|
if (node.expressions.length > 0) return;
|
|
@@ -234,8 +248,14 @@ const transform = async (filename, options) => {
|
|
|
234
248
|
const baseValue = rewritten ?? normalized ?? spec.value;
|
|
235
249
|
const appended = appendExtensionIfNeeded(spec, appendMode, dirIndex, baseValue);
|
|
236
250
|
return appended ?? rewritten ?? normalized ?? undefined;
|
|
237
|
-
}
|
|
238
|
-
|
|
251
|
+
};
|
|
252
|
+
if (opts.sourceMap && sourceCode) {
|
|
253
|
+
await specifier.updateMagicString(sourceCode, code, ast, applyRewrite);
|
|
254
|
+
source = sourceCode.toString();
|
|
255
|
+
} else {
|
|
256
|
+
const rewritten = await specifier.updateSrc(source, getLangFromExt(filename), applyRewrite);
|
|
257
|
+
source = rewritten;
|
|
258
|
+
}
|
|
239
259
|
}
|
|
240
260
|
if (detectCycles !== 'off' && opts.target === 'module' && opts.transformSyntax) {
|
|
241
261
|
await detectCircularRequireGraph(file, detectCycles, dirIndex || 'index.js');
|
|
@@ -244,6 +264,18 @@ const transform = async (filename, options) => {
|
|
|
244
264
|
if (outputPath) {
|
|
245
265
|
await writeFile(outputPath, source);
|
|
246
266
|
}
|
|
267
|
+
if (opts.sourceMap && sourceCode) {
|
|
268
|
+
const map = sourceCode.generateMap({
|
|
269
|
+
hires: true,
|
|
270
|
+
includeContent: true,
|
|
271
|
+
file: outputPath ?? filename,
|
|
272
|
+
source: opts.filePath ?? filename
|
|
273
|
+
});
|
|
274
|
+
return {
|
|
275
|
+
code: source,
|
|
276
|
+
map
|
|
277
|
+
};
|
|
278
|
+
}
|
|
247
279
|
return source;
|
|
248
|
-
}
|
|
280
|
+
}
|
|
249
281
|
export { transform, collectProjectDualPackageHazards };
|
package/dist/specifier.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import MagicString from 'magic-string';
|
|
2
|
+
import type { ParserOptions, ParseResult, StringLiteral, TemplateLiteral, BinaryExpression, NewExpression, ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration, TSImportType, ImportExpression, CallExpression } from 'oxc-parser';
|
|
2
3
|
type Spec = {
|
|
3
4
|
type: 'StringLiteral' | 'TemplateLiteral' | 'BinaryExpression' | 'NewExpression';
|
|
4
5
|
node: StringLiteral | TemplateLiteral | BinaryExpression | NewExpression;
|
|
@@ -11,6 +12,7 @@ type Callback = (spec: Spec) => string | void;
|
|
|
11
12
|
declare const specifier: {
|
|
12
13
|
update(path: string, callback: Callback): Promise<string>;
|
|
13
14
|
updateSrc(src: string, lang: ParserOptions["lang"], callback: Callback): Promise<string>;
|
|
15
|
+
updateMagicString(code: MagicString, src: string, ast: ParseResult, callback: Callback): Promise<MagicString>;
|
|
14
16
|
};
|
|
15
17
|
export { specifier };
|
|
16
18
|
export type { Spec, Callback };
|
package/dist/specifier.js
CHANGED
|
@@ -13,8 +13,7 @@ const isBinaryExpression = node => {
|
|
|
13
13
|
const isCallExpression = node => {
|
|
14
14
|
return node.type === 'CallExpression' && node.callee !== undefined;
|
|
15
15
|
};
|
|
16
|
-
const formatSpecifiers = async (src, ast, cb) => {
|
|
17
|
-
const code = new MagicString(src);
|
|
16
|
+
const formatSpecifiers = async (src, ast, cb, code = new MagicString(src)) => {
|
|
18
17
|
const formatExpression = expression => {
|
|
19
18
|
const node = isCallExpression(expression) ? expression.arguments[0] : expression.source;
|
|
20
19
|
const {
|
|
@@ -228,7 +227,7 @@ const formatSpecifiers = async (src, ast, cb) => {
|
|
|
228
227
|
}
|
|
229
228
|
}
|
|
230
229
|
});
|
|
231
|
-
return code
|
|
230
|
+
return code;
|
|
232
231
|
};
|
|
233
232
|
const isValidFilename = async filename => {
|
|
234
233
|
let stats;
|
|
@@ -251,12 +250,18 @@ const specifier = {
|
|
|
251
250
|
}
|
|
252
251
|
const src = (await readFile(filename)).toString();
|
|
253
252
|
const ast = parseSync(filename, src);
|
|
254
|
-
|
|
253
|
+
const code = await formatSpecifiers(src, ast, callback);
|
|
254
|
+
return code.toString();
|
|
255
255
|
},
|
|
256
256
|
async updateSrc(src, lang, callback) {
|
|
257
257
|
const filename = lang === 'ts' ? 'file.ts' : lang === 'tsx' ? 'file.tsx' : lang === 'js' ? 'file.js' : 'file.jsx';
|
|
258
258
|
const ast = parseSync(filename, src);
|
|
259
|
-
|
|
259
|
+
const code = await formatSpecifiers(src, ast, callback);
|
|
260
|
+
return code.toString();
|
|
261
|
+
},
|
|
262
|
+
async updateMagicString(code, src, ast, callback) {
|
|
263
|
+
await formatSpecifiers(src, ast, callback, code);
|
|
264
|
+
return code;
|
|
260
265
|
}
|
|
261
266
|
};
|
|
262
267
|
export { specifier };
|
package/dist/types.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type ModuleOptions = {
|
|
|
6
6
|
target: 'module' | 'commonjs';
|
|
7
7
|
/** Explicit source type; auto infers from file extension. */
|
|
8
8
|
sourceType?: 'auto' | 'module' | 'commonjs';
|
|
9
|
+
/** Emit a source map alongside the transformed code. */
|
|
10
|
+
sourceMap?: boolean;
|
|
9
11
|
/**
|
|
10
12
|
* Enable syntax transforms beyond parsing.
|
|
11
13
|
* - true: full CJS↔ESM lowering/raising
|
|
@@ -38,6 +40,8 @@ export type ModuleOptions = {
|
|
|
38
40
|
detectDualPackageHazard?: 'off' | 'warn' | 'error';
|
|
39
41
|
/** Scope for dual package hazard detection. */
|
|
40
42
|
dualPackageHazardScope?: 'file' | 'project';
|
|
43
|
+
/** Packages to ignore for dual package hazard diagnostics. */
|
|
44
|
+
dualPackageHazardAllowlist?: string[];
|
|
41
45
|
/** Source used to provide require in ESM output. */
|
|
42
46
|
requireSource?: 'builtin' | 'create-require';
|
|
43
47
|
/** How to rewrite nested or non-hoistable require calls. */
|