@knighted/module 1.1.0 → 1.2.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.
Files changed (51) hide show
  1. package/README.md +2 -7
  2. package/dist/ast.d.ts +39 -0
  3. package/dist/cjs/ast.d.cts +39 -0
  4. package/dist/cjs/exports.d.cts +4 -1
  5. package/dist/cjs/format.cjs +43 -25
  6. package/dist/cjs/formatters/assignmentExpression.cjs +1 -1
  7. package/dist/cjs/formatters/identifier.cjs +2 -2
  8. package/dist/cjs/formatters/memberExpression.cjs +1 -1
  9. package/dist/cjs/helpers/ast.cjs +29 -0
  10. package/dist/cjs/helpers/identifier.cjs +5 -3
  11. package/dist/cjs/module.cjs +8 -6
  12. package/dist/cjs/specifier.cjs +1 -1
  13. package/dist/cjs/types.d.cts +2 -0
  14. package/dist/cjs/utils/exports.cjs +1 -1
  15. package/dist/cjs/utils/identifiers.cjs +2 -2
  16. package/dist/exports.d.ts +4 -1
  17. package/dist/format.js +43 -25
  18. package/dist/formatters/assignmentExpression.js +1 -1
  19. package/dist/formatters/identifier.js +2 -2
  20. package/dist/formatters/memberExpression.js +1 -1
  21. package/dist/helpers/ast.d.ts +39 -0
  22. package/dist/helpers/ast.js +18 -0
  23. package/dist/helpers/identifier.js +5 -4
  24. package/dist/module.js +9 -7
  25. package/dist/specifier.js +1 -1
  26. package/dist/types.d.ts +2 -0
  27. package/dist/{src/utils → utils}/exports.d.ts +4 -1
  28. package/dist/utils/exports.js +1 -1
  29. package/dist/utils/identifiers.js +2 -2
  30. package/package.json +10 -13
  31. package/dist/cjs/utils.cjs +0 -274
  32. package/dist/cjs/utils.d.cts +0 -23
  33. package/dist/src/format.d.ts +0 -9
  34. package/dist/src/module.d.ts +0 -3
  35. package/dist/src/parse.d.ts +0 -2
  36. package/dist/src/specifier.d.ts +0 -16
  37. package/dist/src/types.d.ts +0 -93
  38. package/dist/src/utils.d.ts +0 -23
  39. package/dist/src/walk.d.ts +0 -20
  40. package/dist/utils.d.ts +0 -23
  41. package/dist/utils.js +0 -265
  42. /package/dist/{src/formatters → formatters}/assignmentExpression.d.ts +0 -0
  43. /package/dist/{src/formatters → formatters}/expressionStatement.d.ts +0 -0
  44. /package/dist/{src/formatters → formatters}/identifier.d.ts +0 -0
  45. /package/dist/{src/formatters → formatters}/memberExpression.d.ts +0 -0
  46. /package/dist/{src/formatters → formatters}/metaProperty.d.ts +0 -0
  47. /package/dist/{src/helpers → helpers}/identifier.d.ts +0 -0
  48. /package/dist/{src/utils → utils}/identifiers.d.ts +0 -0
  49. /package/dist/{src/utils → utils}/lang.d.ts +0 -0
  50. /package/dist/{src/utils → utils}/scopeNodes.d.ts +0 -0
  51. /package/dist/{src/utils → utils}/url.d.ts +0 -0
package/README.md CHANGED
@@ -135,6 +135,7 @@ type ModuleOptions = {
135
135
  idiomaticExports?: 'off' | 'safe' | 'aggressive'
136
136
  topLevelAwait?: 'error' | 'wrap' | 'preserve'
137
137
  out?: string
138
+ cwd?: string
138
139
  inPlace?: boolean
139
140
  }
140
141
  ```
@@ -159,7 +160,7 @@ type ModuleOptions = {
159
160
  - `cjsDefault` (`auto`): bundler-style default interop vs direct `module.exports`.
160
161
  - `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.
161
162
  - `out`/`inPlace`: write the transformed code to a file; otherwise the function returns the transformed string only.
162
- - CommonJS ESM lowering will throw on `with` statements and unshadowed `eval` calls to avoid unsound rewrites.
163
+ - `cwd` (`process.cwd()`): Base directory used to resolve relative `out` paths.
163
164
 
164
165
  > [!NOTE]
165
166
  > Package-level metadata (`package.json` updates such as setting `"type": "module"` or authoring `exports`) is not edited by this tool today; plan that change outside the per-file transform.
@@ -229,9 +230,3 @@ for (const file of files) {
229
230
  ```
230
231
 
231
232
  This pre-`tsc` step removes the flagged globals in the compiled orientation; runtime semantics still match the target build.
232
-
233
- ## Roadmap
234
-
235
- - Emit source maps and clearer diagnostics for transform choices.
236
- - Broaden fixtures covering live-binding and top-level await edge cases across Node versions.
237
- - Benchmark scope analysis choices: compare `periscopic`, `scope-analyzer`, and `eslint-scope` on fixtures and pick the final adapter.
package/dist/ast.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import type { Node } from 'oxc-parser';
2
+ import type { CjsExport } from '../types.js';
3
+ export type IdentifierNode = Extract<Node, {
4
+ type: 'Identifier';
5
+ }>;
6
+ export type LiteralNode = Extract<Node, {
7
+ type: 'Literal';
8
+ value?: unknown;
9
+ }>;
10
+ export type MemberExpressionNode = Extract<Node, {
11
+ type: 'MemberExpression';
12
+ }>;
13
+ export type CallExpressionNode = Extract<Node, {
14
+ type: 'CallExpression';
15
+ }>;
16
+ export type ProgramNode = Extract<Node, {
17
+ type: 'Program';
18
+ body: Node[];
19
+ }>;
20
+ export type ModuleExportNameNode = Extract<Node, {
21
+ type: 'Identifier' | 'Literal';
22
+ }>;
23
+ export type ImportDefaultSpecifierNode = Extract<Node, {
24
+ type: 'ImportDefaultSpecifier';
25
+ }>;
26
+ export type ImportNamespaceSpecifierNode = Extract<Node, {
27
+ type: 'ImportNamespaceSpecifier';
28
+ }>;
29
+ export type ImportSpecifierNode = Extract<Node, {
30
+ type: 'ImportSpecifier';
31
+ }>;
32
+ export type ExportsMap = Map<string, CjsExport> & {
33
+ hasUnsupportedExportWrite?: boolean;
34
+ };
35
+ export declare const isAstNode: (value: unknown) => value is Node;
36
+ export declare const isIdentifierNode: (node: Node | null | undefined) => node is IdentifierNode;
37
+ export declare const isMemberExpressionNode: (node: Node | null | undefined) => node is MemberExpressionNode;
38
+ export declare const isCallExpressionNode: (node: Node | null | undefined) => node is CallExpressionNode;
39
+ export declare const getModuleExportName: (name: ModuleExportNameNode | null | undefined) => string | null;
@@ -0,0 +1,39 @@
1
+ import type { Node } from 'oxc-parser';
2
+ import type { CjsExport } from '../types.cjs';
3
+ export type IdentifierNode = Extract<Node, {
4
+ type: 'Identifier';
5
+ }>;
6
+ export type LiteralNode = Extract<Node, {
7
+ type: 'Literal';
8
+ value?: unknown;
9
+ }>;
10
+ export type MemberExpressionNode = Extract<Node, {
11
+ type: 'MemberExpression';
12
+ }>;
13
+ export type CallExpressionNode = Extract<Node, {
14
+ type: 'CallExpression';
15
+ }>;
16
+ export type ProgramNode = Extract<Node, {
17
+ type: 'Program';
18
+ body: Node[];
19
+ }>;
20
+ export type ModuleExportNameNode = Extract<Node, {
21
+ type: 'Identifier' | 'Literal';
22
+ }>;
23
+ export type ImportDefaultSpecifierNode = Extract<Node, {
24
+ type: 'ImportDefaultSpecifier';
25
+ }>;
26
+ export type ImportNamespaceSpecifierNode = Extract<Node, {
27
+ type: 'ImportNamespaceSpecifier';
28
+ }>;
29
+ export type ImportSpecifierNode = Extract<Node, {
30
+ type: 'ImportSpecifier';
31
+ }>;
32
+ export type ExportsMap = Map<string, CjsExport> & {
33
+ hasUnsupportedExportWrite?: boolean;
34
+ };
35
+ export declare const isAstNode: (value: unknown) => value is Node;
36
+ export declare const isIdentifierNode: (node: Node | null | undefined) => node is IdentifierNode;
37
+ export declare const isMemberExpressionNode: (node: Node | null | undefined) => node is MemberExpressionNode;
38
+ export declare const isCallExpressionNode: (node: Node | null | undefined) => node is CallExpressionNode;
39
+ export declare const getModuleExportName: (name: ModuleExportNameNode | null | undefined) => string | null;
@@ -2,5 +2,8 @@ import type { Node } from 'oxc-parser';
2
2
  import type { CjsExport } from '../types.cjs';
3
3
  declare const exportsRename = "__exports";
4
4
  declare const requireMainRgx: RegExp;
5
- declare const collectCjsExports: (ast: Node) => Promise<Map<string, CjsExport>>;
5
+ type ExportsMap = Map<string, CjsExport> & {
6
+ hasUnsupportedExportWrite?: boolean;
7
+ };
8
+ declare const collectCjsExports: (ast: Node) => Promise<ExportsMap>;
6
9
  export { exportsRename, requireMainRgx, collectCjsExports };
@@ -4,33 +4,35 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.format = void 0;
7
+ var _ast = require("./helpers/ast.cjs");
7
8
  var _magicString = _interopRequireDefault(require("magic-string"));
8
- var _identifier = require("#formatters/identifier.js");
9
- var _metaProperty = require("#formatters/metaProperty.js");
10
- var _memberExpression = require("#formatters/memberExpression.js");
11
- var _assignmentExpression = require("#formatters/assignmentExpression.js");
12
- var _url = require("#utils/url.js");
13
- var _exports = require("#utils/exports.js");
14
- var _identifiers = require("#utils/identifiers.js");
15
- var _identifier2 = require("#helpers/identifier.js");
16
- var _walk = require("#walk");
9
+ var _identifier = require("./formatters/identifier.cjs");
10
+ var _metaProperty = require("./formatters/metaProperty.cjs");
11
+ var _memberExpression = require("./formatters/memberExpression.cjs");
12
+ var _assignmentExpression = require("./formatters/assignmentExpression.cjs");
13
+ var _url = require("./utils/url.cjs");
14
+ var _exports = require("./utils/exports.cjs");
15
+ var _identifiers = require("./utils/identifiers.cjs");
16
+ var _identifier2 = require("./helpers/identifier.cjs");
17
+ var _walk = require("./walk.cjs");
17
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
19
  const isValidIdent = name => /^[$A-Z_a-z][$\w]*$/.test(name);
19
20
  const expressionHasRequireCall = (node, shadowed) => {
20
21
  let found = false;
21
22
  const walkNode = n => {
22
- if (!n || found) return;
23
- if (n.type === 'CallExpression' && n.callee?.type === 'Identifier' && n.callee.name === 'require' && !shadowed.has('require')) {
23
+ if (!(0, _ast.isAstNode)(n) || found) return;
24
+ if ((0, _ast.isCallExpressionNode)(n) && (0, _ast.isIdentifierNode)(n.callee) && n.callee.name === 'require' && !shadowed.has('require')) {
24
25
  found = true;
25
26
  return;
26
27
  }
27
- if (n.type === 'CallExpression' && n.callee?.type === 'MemberExpression' && n.callee.object?.type === 'Identifier' && n.callee.object.name === 'require' && !shadowed.has('require')) {
28
+ if ((0, _ast.isCallExpressionNode)(n) && (0, _ast.isMemberExpressionNode)(n.callee) && (0, _ast.isIdentifierNode)(n.callee.object) && n.callee.object.name === 'require' && !shadowed.has('require')) {
28
29
  found = true;
29
30
  return;
30
31
  }
31
- const keys = Object.keys(n);
32
+ const record = n;
33
+ const keys = Object.keys(record);
32
34
  for (const key of keys) {
33
- const value = n[key];
35
+ const value = record[key];
34
36
  if (!value) continue;
35
37
  if (Array.isArray(value)) {
36
38
  for (const item of value) {
@@ -87,6 +89,10 @@ const lowerCjsRequireToImports = (program, code, shadowed) => {
87
89
  if (allStatic) {
88
90
  for (const decl of decls) {
89
91
  const init = decl.init;
92
+ if (!init || !(0, _ast.isCallExpressionNode)(init)) {
93
+ needsCreateRequire = true;
94
+ continue;
95
+ }
90
96
  const arg = init.arguments[0];
91
97
  const source = code.slice(arg.start, arg.end);
92
98
  const value = arg.value;
@@ -123,6 +129,10 @@ const lowerCjsRequireToImports = (program, code, shadowed) => {
123
129
  if (stmt.type === 'ExpressionStatement') {
124
130
  const expr = stmt.expression;
125
131
  if (expr && isStaticRequire(expr, shadowed)) {
132
+ if (!(0, _ast.isCallExpressionNode)(expr)) {
133
+ needsCreateRequire = true;
134
+ continue;
135
+ }
126
136
  const arg = expr.arguments[0];
127
137
  const source = code.slice(arg.start, arg.end);
128
138
  const value = arg.value;
@@ -149,11 +159,12 @@ const lowerCjsRequireToImports = (program, code, shadowed) => {
149
159
  needsInteropHelper
150
160
  };
151
161
  };
152
- 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';
162
+ const isRequireMainMember = (node, shadowed) => node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'require' && !shadowed.has('require') && node.property.type === 'Identifier' && node.property.name === 'main';
153
163
  const hasTopLevelAwait = program => {
154
164
  let found = false;
155
165
  const walkNode = (node, inFunction) => {
156
166
  if (found) return;
167
+ if (!(0, _ast.isAstNode)(node)) return;
157
168
  switch (node.type) {
158
169
  case 'FunctionDeclaration':
159
170
  case 'FunctionExpression':
@@ -167,9 +178,10 @@ const hasTopLevelAwait = program => {
167
178
  found = true;
168
179
  return;
169
180
  }
170
- const keys = Object.keys(node);
181
+ const record = node;
182
+ const keys = Object.keys(record);
171
183
  for (const key of keys) {
172
- const value = node[key];
184
+ const value = record[key];
173
185
  if (!value) continue;
174
186
  if (Array.isArray(value)) {
175
187
  for (const item of value) {
@@ -250,7 +262,8 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
250
262
  }
251
263
  if (namedSpecs.length) {
252
264
  const pairs = namedSpecs.map(s => {
253
- const imported = s.imported.name;
265
+ const imported = (0, _ast.getModuleExportName)(s.imported);
266
+ if (!imported) return s.local.name;
254
267
  const local = s.local.name;
255
268
  return imported === local ? imported : `${imported}: ${local}`;
256
269
  });
@@ -275,7 +288,7 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
275
288
  exportedNames.push(d.id.name);
276
289
  }
277
290
  }
278
- } else if (decl.id?.type === 'Identifier') {
291
+ } else if ('id' in decl && decl.id?.type === 'Identifier') {
279
292
  exportedNames.push(decl.id.name);
280
293
  }
281
294
  const exportLines = exportedNames.map(name => exportAssignment(name, name, live));
@@ -295,8 +308,9 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
295
308
  const lines = [`const ${modIdent} = require(${srcLiteral});`];
296
309
  for (const spec of node.specifiers) {
297
310
  if (spec.type !== 'ExportSpecifier') continue;
298
- const exported = spec.exported.name;
299
- const imported = spec.local.name;
311
+ const exported = (0, _ast.getModuleExportName)(spec.exported);
312
+ const imported = (0, _ast.getModuleExportName)(spec.local);
313
+ if (!exported || !imported) continue;
300
314
  let rhs = `${modIdent}.${imported}`;
301
315
  if (imported === 'default') {
302
316
  rhs = `${defaultInteropName}(${modIdent})`;
@@ -314,8 +328,9 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
314
328
  const lines = [];
315
329
  for (const spec of node.specifiers) {
316
330
  if (spec.type !== 'ExportSpecifier') continue;
317
- const exported = spec.exported.name;
318
- const local = spec.local.name;
331
+ const exported = (0, _ast.getModuleExportName)(spec.exported);
332
+ const local = (0, _ast.getModuleExportName)(spec.local);
333
+ if (!exported || !local) continue;
319
334
  lines.push(exportAssignment(exported, local, live));
320
335
  }
321
336
  exportTransforms.push({
@@ -359,8 +374,11 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
359
374
  }
360
375
  if (node.type === 'ExportAllDeclaration') {
361
376
  const srcLiteral = code.slice(node.source.start, node.source.end);
362
- if (node.exported) {
363
- const exported = node.exported.name;
377
+ if ('exported' in node && node.exported) {
378
+ const exported = (0, _ast.getModuleExportName)(node.exported);
379
+ if (!exported) {
380
+ continue;
381
+ }
364
382
  const modIdent = `__mod${importIndex++}`;
365
383
  const lines = [`const ${modIdent} = require(${srcLiteral});`, exportAssignment(exported, modIdent, live)];
366
384
  exportTransforms.push({
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.assignmentExpression = void 0;
7
- var _walk = require("#walk");
7
+ var _walk = require("../walk.cjs");
8
8
  const assignmentExpression = async ({
9
9
  node,
10
10
  parent: _parent,
@@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.identifier = void 0;
7
- var _exports = require("#utils/exports.js");
8
- var _identifier = require("#helpers/identifier.js");
7
+ var _exports = require("../utils/exports.cjs");
8
+ var _identifier = require("../helpers/identifier.cjs");
9
9
  const identifier = ({
10
10
  node,
11
11
  ancestors,
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.memberExpression = void 0;
7
- var _exports = require("#utils/exports.js");
7
+ var _exports = require("../utils/exports.cjs");
8
8
  const memberExpression = (node, parent, src, options, shadowed, extras, useExportsBag = true, rewriteExports = true) => {
9
9
  if (options.target === 'module') {
10
10
  if (rewriteExports && !useExportsBag) {
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isMemberExpressionNode = exports.isIdentifierNode = exports.isCallExpressionNode = exports.isAstNode = exports.getModuleExportName = void 0;
7
+ const isAstNode = value => {
8
+ return Boolean(value) && typeof value === 'object' && 'type' in value;
9
+ };
10
+ exports.isAstNode = isAstNode;
11
+ const isIdentifierNode = node => {
12
+ return node?.type === 'Identifier';
13
+ };
14
+ exports.isIdentifierNode = isIdentifierNode;
15
+ const isMemberExpressionNode = node => {
16
+ return node?.type === 'MemberExpression';
17
+ };
18
+ exports.isMemberExpressionNode = isMemberExpressionNode;
19
+ const isCallExpressionNode = node => {
20
+ return node?.type === 'CallExpression';
21
+ };
22
+ exports.isCallExpressionNode = isCallExpressionNode;
23
+ const getModuleExportName = name => {
24
+ if (!name) return null;
25
+ if (name.type === 'Identifier') return name.name;
26
+ if (name.type === 'Literal' && typeof name.value === 'string') return name.value;
27
+ return null;
28
+ };
29
+ exports.getModuleExportName = getModuleExportName;
@@ -127,14 +127,16 @@ const identifier = exports.identifier = {
127
127
  const node = ancestors[ancestors.length - 1];
128
128
  const varBoundScopes = ['ClassDeclaration', 'ClassExpression', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'];
129
129
  const declaratorIndex = ancestors.findIndex(ancestor => {
130
- return ancestor.type === 'VariableDeclarator' && (ancestor === node || isInBindingPattern(ancestor.id, node));
130
+ if (ancestor.type !== 'VariableDeclarator') return false;
131
+ return ancestor === node || isInBindingPattern(ancestor.id, node);
131
132
  });
132
133
  if (declaratorIndex === -1) return false;
133
- const declarator = ancestors[declaratorIndex];
134
+ const declaratorNode = ancestors[declaratorIndex];
134
135
  const declaration = ancestors[declaratorIndex - 1];
136
+ if (declaratorNode?.type !== 'VariableDeclarator') return false;
135
137
  return declaration?.type === 'VariableDeclaration' && declaration.kind === 'var' && ancestors.every(ancestor => {
136
138
  return !varBoundScopes.includes(ancestor.type);
137
- }) && (declarator.id === node || isInBindingPattern(declarator.id, node));
139
+ }) && (declaratorNode.id === node || isInBindingPattern(declaratorNode.id, node));
138
140
  },
139
141
  isIife(ancestors) {
140
142
  const parent = ancestors[ancestors.length - 2];
@@ -7,11 +7,11 @@ exports.transform = void 0;
7
7
  var _nodePath = require("node:path");
8
8
  var _promises = require("node:fs/promises");
9
9
  var _specifier = require("./specifier.cjs");
10
- var _parse = require("#parse");
11
- var _format = require("#format");
12
- var _lang = require("#utils/lang.js");
10
+ var _parse = require("./parse.cjs");
11
+ var _format = require("./format.cjs");
12
+ var _lang = require("./utils/lang.cjs");
13
13
  var _nodeModule = require("node:module");
14
- var _walk = require("#walk");
14
+ var _walk = require("./walk.cjs");
15
15
  const collapseSpecifier = value => value.replace(/['"`+)\s]|new String\(/g, '');
16
16
  const builtinSpecifiers = new Set(_nodeModule.builtinModules.map(mod => mod.startsWith('node:') ? mod.slice(5) : mod).flatMap(mod => {
17
17
  const parts = mod.split('/');
@@ -163,6 +163,7 @@ const defaultOptions = {
163
163
  idiomaticExports: 'safe',
164
164
  importMetaPrelude: 'auto',
165
165
  topLevelAwait: 'error',
166
+ cwd: undefined,
166
167
  out: undefined,
167
168
  inPlace: false
168
169
  };
@@ -172,10 +173,11 @@ const transform = async (filename, options = defaultOptions) => {
172
173
  ...options,
173
174
  filePath: filename
174
175
  };
176
+ const cwdBase = opts.cwd ? (0, _nodePath.resolve)(opts.cwd) : process.cwd();
175
177
  const appendMode = options?.appendJsExtension ?? (opts.target === 'module' ? 'relative-only' : 'off');
176
178
  const dirIndex = opts.appendDirectoryIndex === undefined ? 'index.js' : opts.appendDirectoryIndex;
177
179
  const detectCycles = opts.detectCircularRequires ?? 'off';
178
- const file = (0, _nodePath.resolve)(filename);
180
+ const file = (0, _nodePath.resolve)(cwdBase, filename);
179
181
  const code = (await (0, _promises.readFile)(file)).toString();
180
182
  const ast = (0, _parse.parse)(filename, code);
181
183
  let source = await (0, _format.format)(code, ast, opts);
@@ -192,7 +194,7 @@ const transform = async (filename, options = defaultOptions) => {
192
194
  if (detectCycles !== 'off' && opts.target === 'module' && opts.transformSyntax) {
193
195
  await detectCircularRequireGraph(file, detectCycles, dirIndex || 'index.js');
194
196
  }
195
- const outputPath = opts.inPlace ? file : opts.out ? (0, _nodePath.resolve)(opts.out) : undefined;
197
+ const outputPath = opts.inPlace ? file : opts.out ? (0, _nodePath.resolve)(cwdBase, opts.out) : undefined;
196
198
  if (outputPath) {
197
199
  await (0, _promises.writeFile)(outputPath, source);
198
200
  }
@@ -8,7 +8,7 @@ var _nodePath = require("node:path");
8
8
  var _promises = require("node:fs/promises");
9
9
  var _magicString = _interopRequireDefault(require("magic-string"));
10
10
  var _oxcParser = require("oxc-parser");
11
- var _walk = require("#walk");
11
+ var _walk = require("./walk.cjs");
12
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
13
  const isStringLiteral = node => {
14
14
  return node.type === 'Literal' && typeof node.value === 'string';
@@ -48,6 +48,8 @@ export type ModuleOptions = {
48
48
  diagnostics?: (diag: Diagnostic) => void;
49
49
  /** Optional source file path used for diagnostics context. */
50
50
  filePath?: string;
51
+ /** Base directory used to resolve relative `out` paths; defaults to process.cwd(). */
52
+ cwd?: string;
51
53
  /** Output directory or file path when writing. */
52
54
  out?: string;
53
55
  /** Overwrite input files instead of writing to out. */
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.requireMainRgx = exports.exportsRename = exports.collectCjsExports = void 0;
7
- var _walk = require("#walk");
7
+ var _walk = require("../walk.cjs");
8
8
  const exportsRename = exports.exportsRename = '__exports';
9
9
  const requireMainRgx = exports.requireMainRgx = /(require\.main\s*===\s*module|module\s*===\s*require\.main)/g;
10
10
  const literalPropName = (prop, literals) => {
@@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.collectScopeIdentifiers = exports.collectModuleIdentifiers = void 0;
7
- var _walk = require("#walk");
8
- var _identifier = require("#helpers/identifier.js");
7
+ var _walk = require("../walk.cjs");
8
+ var _identifier = require("../helpers/identifier.cjs");
9
9
  var _scopeNodes = require("./scopeNodes.cjs");
10
10
  const addBindingNames = (pattern, into) => {
11
11
  if (!pattern) return;
package/dist/exports.d.ts CHANGED
@@ -2,5 +2,8 @@ import type { Node } from 'oxc-parser';
2
2
  import type { CjsExport } from '../types.js';
3
3
  declare const exportsRename = "__exports";
4
4
  declare const requireMainRgx: RegExp;
5
- declare const collectCjsExports: (ast: Node) => Promise<Map<string, CjsExport>>;
5
+ type ExportsMap = Map<string, CjsExport> & {
6
+ hasUnsupportedExportWrite?: boolean;
7
+ };
8
+ declare const collectCjsExports: (ast: Node) => Promise<ExportsMap>;
6
9
  export { exportsRename, requireMainRgx, collectCjsExports };
package/dist/format.js CHANGED
@@ -1,29 +1,31 @@
1
+ import { getModuleExportName, isAstNode, isCallExpressionNode, isIdentifierNode, isMemberExpressionNode } from './helpers/ast.js';
1
2
  import MagicString from 'magic-string';
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';
3
+ import { identifier } from './formatters/identifier.js';
4
+ import { metaProperty } from './formatters/metaProperty.js';
5
+ import { memberExpression } from './formatters/memberExpression.js';
6
+ import { assignmentExpression } from './formatters/assignmentExpression.js';
7
+ import { isValidUrl } from './utils/url.js';
8
+ import { exportsRename, collectCjsExports } from './utils/exports.js';
9
+ import { collectModuleIdentifiers } from './utils/identifiers.js';
10
+ import { isIdentifierName } from './helpers/identifier.js';
11
+ import { ancestorWalk } from './walk.js';
11
12
  const isValidIdent = name => /^[$A-Z_a-z][$\w]*$/.test(name);
12
13
  const expressionHasRequireCall = (node, shadowed) => {
13
14
  let found = false;
14
15
  const walkNode = n => {
15
- if (!n || found) return;
16
- if (n.type === 'CallExpression' && n.callee?.type === 'Identifier' && n.callee.name === 'require' && !shadowed.has('require')) {
16
+ if (!isAstNode(n) || found) return;
17
+ if (isCallExpressionNode(n) && isIdentifierNode(n.callee) && n.callee.name === 'require' && !shadowed.has('require')) {
17
18
  found = true;
18
19
  return;
19
20
  }
20
- if (n.type === 'CallExpression' && n.callee?.type === 'MemberExpression' && n.callee.object?.type === 'Identifier' && n.callee.object.name === 'require' && !shadowed.has('require')) {
21
+ if (isCallExpressionNode(n) && isMemberExpressionNode(n.callee) && isIdentifierNode(n.callee.object) && n.callee.object.name === 'require' && !shadowed.has('require')) {
21
22
  found = true;
22
23
  return;
23
24
  }
24
- const keys = Object.keys(n);
25
+ const record = n;
26
+ const keys = Object.keys(record);
25
27
  for (const key of keys) {
26
- const value = n[key];
28
+ const value = record[key];
27
29
  if (!value) continue;
28
30
  if (Array.isArray(value)) {
29
31
  for (const item of value) {
@@ -80,6 +82,10 @@ const lowerCjsRequireToImports = (program, code, shadowed) => {
80
82
  if (allStatic) {
81
83
  for (const decl of decls) {
82
84
  const init = decl.init;
85
+ if (!init || !isCallExpressionNode(init)) {
86
+ needsCreateRequire = true;
87
+ continue;
88
+ }
83
89
  const arg = init.arguments[0];
84
90
  const source = code.slice(arg.start, arg.end);
85
91
  const value = arg.value;
@@ -116,6 +122,10 @@ const lowerCjsRequireToImports = (program, code, shadowed) => {
116
122
  if (stmt.type === 'ExpressionStatement') {
117
123
  const expr = stmt.expression;
118
124
  if (expr && isStaticRequire(expr, shadowed)) {
125
+ if (!isCallExpressionNode(expr)) {
126
+ needsCreateRequire = true;
127
+ continue;
128
+ }
119
129
  const arg = expr.arguments[0];
120
130
  const source = code.slice(arg.start, arg.end);
121
131
  const value = arg.value;
@@ -142,11 +152,12 @@ const lowerCjsRequireToImports = (program, code, shadowed) => {
142
152
  needsInteropHelper
143
153
  };
144
154
  };
145
- 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';
155
+ const isRequireMainMember = (node, shadowed) => node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'require' && !shadowed.has('require') && node.property.type === 'Identifier' && node.property.name === 'main';
146
156
  const hasTopLevelAwait = program => {
147
157
  let found = false;
148
158
  const walkNode = (node, inFunction) => {
149
159
  if (found) return;
160
+ if (!isAstNode(node)) return;
150
161
  switch (node.type) {
151
162
  case 'FunctionDeclaration':
152
163
  case 'FunctionExpression':
@@ -160,9 +171,10 @@ const hasTopLevelAwait = program => {
160
171
  found = true;
161
172
  return;
162
173
  }
163
- const keys = Object.keys(node);
174
+ const record = node;
175
+ const keys = Object.keys(record);
164
176
  for (const key of keys) {
165
- const value = node[key];
177
+ const value = record[key];
166
178
  if (!value) continue;
167
179
  if (Array.isArray(value)) {
168
180
  for (const item of value) {
@@ -243,7 +255,8 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
243
255
  }
244
256
  if (namedSpecs.length) {
245
257
  const pairs = namedSpecs.map(s => {
246
- const imported = s.imported.name;
258
+ const imported = getModuleExportName(s.imported);
259
+ if (!imported) return s.local.name;
247
260
  const local = s.local.name;
248
261
  return imported === local ? imported : `${imported}: ${local}`;
249
262
  });
@@ -268,7 +281,7 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
268
281
  exportedNames.push(d.id.name);
269
282
  }
270
283
  }
271
- } else if (decl.id?.type === 'Identifier') {
284
+ } else if ('id' in decl && decl.id?.type === 'Identifier') {
272
285
  exportedNames.push(decl.id.name);
273
286
  }
274
287
  const exportLines = exportedNames.map(name => exportAssignment(name, name, live));
@@ -288,8 +301,9 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
288
301
  const lines = [`const ${modIdent} = require(${srcLiteral});`];
289
302
  for (const spec of node.specifiers) {
290
303
  if (spec.type !== 'ExportSpecifier') continue;
291
- const exported = spec.exported.name;
292
- const imported = spec.local.name;
304
+ const exported = getModuleExportName(spec.exported);
305
+ const imported = getModuleExportName(spec.local);
306
+ if (!exported || !imported) continue;
293
307
  let rhs = `${modIdent}.${imported}`;
294
308
  if (imported === 'default') {
295
309
  rhs = `${defaultInteropName}(${modIdent})`;
@@ -307,8 +321,9 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
307
321
  const lines = [];
308
322
  for (const spec of node.specifiers) {
309
323
  if (spec.type !== 'ExportSpecifier') continue;
310
- const exported = spec.exported.name;
311
- const local = spec.local.name;
324
+ const exported = getModuleExportName(spec.exported);
325
+ const local = getModuleExportName(spec.local);
326
+ if (!exported || !local) continue;
312
327
  lines.push(exportAssignment(exported, local, live));
313
328
  }
314
329
  exportTransforms.push({
@@ -352,8 +367,11 @@ const lowerEsmToCjs = (program, code, opts, containsTopLevelAwait) => {
352
367
  }
353
368
  if (node.type === 'ExportAllDeclaration') {
354
369
  const srcLiteral = code.slice(node.source.start, node.source.end);
355
- if (node.exported) {
356
- const exported = node.exported.name;
370
+ if ('exported' in node && node.exported) {
371
+ const exported = getModuleExportName(node.exported);
372
+ if (!exported) {
373
+ continue;
374
+ }
357
375
  const modIdent = `__mod${importIndex++}`;
358
376
  const lines = [`const ${modIdent} = require(${srcLiteral});`, exportAssignment(exported, modIdent, live)];
359
377
  exportTransforms.push({
@@ -1,4 +1,4 @@
1
- import { walk } from '#walk';
1
+ import { walk } from '../walk.js';
2
2
  export const assignmentExpression = async ({
3
3
  node,
4
4
  parent: _parent,
@@ -1,5 +1,5 @@
1
- import { exportsRename } from '#utils/exports.js';
2
- import { identifier as ident } from '#helpers/identifier.js';
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 '#utils/exports.js';
1
+ import { exportsRename } from '../utils/exports.js';
2
2
  export const memberExpression = (node, parent, src, options, shadowed, extras, useExportsBag = true, rewriteExports = true) => {
3
3
  if (options.target === 'module') {
4
4
  if (rewriteExports && !useExportsBag) {