@knighted/module 1.0.0-alpha.9 → 1.0.0-beta.1

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 (85) hide show
  1. package/README.md +28 -16
  2. package/dist/assignmentExpression.d.ts +12 -0
  3. package/dist/cjs/assignmentExpression.d.cts +12 -0
  4. package/dist/cjs/exports.d.cts +6 -0
  5. package/dist/cjs/expressionStatement.d.cts +2 -3
  6. package/dist/cjs/format.cjs +133 -26
  7. package/dist/cjs/format.d.cts +6 -6
  8. package/dist/cjs/formatters/assignmentExpression.cjs +37 -0
  9. package/dist/cjs/formatters/expressionStatement.cjs +36 -55
  10. package/dist/cjs/formatters/identifier.cjs +31 -31
  11. package/dist/cjs/formatters/memberExpression.cjs +24 -11
  12. package/dist/cjs/formatters/metaProperty.cjs +23 -35
  13. package/dist/cjs/helpers/identifier.cjs +132 -0
  14. package/dist/cjs/helpers/scope.cjs +12 -0
  15. package/dist/cjs/identifier.d.cts +31 -5
  16. package/dist/cjs/identifiers.d.cts +19 -0
  17. package/dist/cjs/lang.d.cts +4 -0
  18. package/dist/cjs/memberExpression.d.cts +2 -3
  19. package/dist/cjs/metaProperty.d.cts +2 -3
  20. package/dist/cjs/module.cjs +26 -27
  21. package/dist/cjs/parse.cjs +3 -14
  22. package/dist/cjs/parse.d.cts +1 -1
  23. package/dist/cjs/scope.d.cts +6 -0
  24. package/dist/cjs/types.d.cts +40 -4
  25. package/dist/cjs/url.d.cts +2 -0
  26. package/dist/cjs/utils/exports.cjs +227 -0
  27. package/dist/cjs/utils/identifiers.cjs +190 -0
  28. package/dist/cjs/utils/lang.cjs +25 -0
  29. package/dist/cjs/utils/url.cjs +16 -0
  30. package/dist/cjs/utils.cjs +288 -0
  31. package/dist/cjs/utils.d.cts +26 -0
  32. package/dist/cjs/walk.cjs +75 -0
  33. package/dist/cjs/walk.d.cts +20 -0
  34. package/dist/exports.d.ts +6 -0
  35. package/dist/expressionStatement.d.ts +2 -3
  36. package/dist/format.d.ts +6 -6
  37. package/dist/format.js +135 -27
  38. package/dist/formatters/assignmentExpression.js +30 -0
  39. package/dist/formatters/expressionStatement.js +36 -55
  40. package/dist/formatters/identifier.js +31 -31
  41. package/dist/formatters/memberExpression.js +24 -11
  42. package/dist/formatters/metaProperty.js +23 -35
  43. package/dist/helpers/identifier.js +127 -0
  44. package/dist/helpers/scope.js +7 -0
  45. package/dist/identifier.d.ts +31 -5
  46. package/dist/identifiers.d.ts +19 -0
  47. package/dist/lang.d.ts +4 -0
  48. package/dist/memberExpression.d.ts +2 -3
  49. package/dist/metaProperty.d.ts +2 -3
  50. package/dist/module.js +26 -27
  51. package/dist/parse.d.ts +1 -1
  52. package/dist/parse.js +3 -14
  53. package/dist/scope.d.ts +6 -0
  54. package/dist/src/format.d.ts +9 -0
  55. package/dist/src/formatters/assignmentExpression.d.ts +12 -0
  56. package/dist/src/formatters/expressionStatement.d.ts +4 -0
  57. package/dist/src/formatters/identifier.d.ts +12 -0
  58. package/dist/src/formatters/memberExpression.d.ts +4 -0
  59. package/dist/src/formatters/metaProperty.d.ts +4 -0
  60. package/dist/src/helpers/identifier.d.ts +31 -0
  61. package/dist/src/helpers/scope.d.ts +6 -0
  62. package/dist/src/module.d.ts +3 -0
  63. package/dist/src/parse.d.ts +2 -0
  64. package/dist/src/types.d.ts +43 -0
  65. package/dist/src/utils/exports.d.ts +6 -0
  66. package/dist/src/utils/identifiers.d.ts +19 -0
  67. package/dist/src/utils/lang.d.ts +4 -0
  68. package/dist/src/utils/url.d.ts +2 -0
  69. package/dist/src/utils.d.ts +26 -0
  70. package/dist/src/walk.d.ts +20 -0
  71. package/dist/types.d.ts +40 -4
  72. package/dist/url.d.ts +2 -0
  73. package/dist/utils/exports.js +221 -0
  74. package/dist/utils/identifiers.js +183 -0
  75. package/dist/utils/lang.js +20 -0
  76. package/dist/utils/url.js +10 -0
  77. package/dist/utils.d.ts +26 -0
  78. package/dist/utils.js +278 -0
  79. package/dist/walk.d.ts +20 -0
  80. package/dist/walk.js +69 -0
  81. package/package.json +43 -25
  82. package/dist/formatters/expressionStatement.d.ts +0 -5
  83. package/dist/formatters/identifier.d.ts +0 -5
  84. package/dist/formatters/memberExpression.d.ts +0 -5
  85. package/dist/formatters/metaProperty.d.ts +0 -5
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isIdentifierName = exports.identifier = void 0;
7
+ var _periscopic = require("periscopic");
8
+ /**
9
+ * Focus exclusively on IdentifierName type as it has the name property,
10
+ * which is what the identifer utilities are interested in.
11
+ *
12
+ * Explicitly ignore the TSThisParameter type as it is not a valid identifier name.
13
+ */
14
+ const isIdentifierName = node => {
15
+ return node.type === 'Identifier' && typeof node.name === 'string' && node.name !== 'this';
16
+ };
17
+ exports.isIdentifierName = isIdentifierName;
18
+ const scopeCache = new WeakMap();
19
+ const getScopeContext = program => {
20
+ const cached = scopeCache.get(program);
21
+ if (cached) {
22
+ return cached;
23
+ }
24
+ const {
25
+ scope
26
+ } = (0, _periscopic.analyze)(program);
27
+ const context = {
28
+ scope
29
+ };
30
+ scopeCache.set(program, context);
31
+ return context;
32
+ };
33
+
34
+ /**
35
+ * All methods receive the full set of ancestors, which
36
+ * specifically includes the node itself as the last element.
37
+ * The second to last element is the parent node, and so on.
38
+ * The first element is the root node.
39
+ */
40
+ const identifier = exports.identifier = {
41
+ isNamed: node => {
42
+ return isIdentifierName(node);
43
+ },
44
+ isMetaProperty(ancestors) {
45
+ const parent = ancestors[ancestors.length - 2];
46
+ return parent.type === 'MetaProperty' || parent.type === 'MemberExpression' && parent.object.type === 'MetaProperty';
47
+ },
48
+ isModuleScope(ancestors, includeImports = false) {
49
+ const node = ancestors[ancestors.length - 1];
50
+ const parent = ancestors[ancestors.length - 2];
51
+ const program = ancestors[0];
52
+ if (!identifier.isNamed(node) || identifier.isMetaProperty(ancestors) || parent.type === 'LabeledStatement' || parent.type === 'BreakStatement' || parent.type === 'ContinueStatement') {
53
+ return false;
54
+ }
55
+ if (parent.type === 'ImportSpecifier' || parent.type === 'ImportDefaultSpecifier' || parent.type === 'ImportNamespaceSpecifier') {
56
+ return includeImports && parent.local.name === node.name;
57
+ }
58
+ if (parent.type === 'Property' && parent.key === node && !parent.computed) {
59
+ return false;
60
+ }
61
+ if (parent.type === 'MemberExpression' && parent.property === node && !parent.computed) {
62
+ return false;
63
+ }
64
+ const {
65
+ scope: rootScope
66
+ } = getScopeContext(program);
67
+ const owner = rootScope.find_owner(node.name);
68
+ if (!owner) {
69
+ return node.name === 'exports';
70
+ }
71
+ return owner === rootScope;
72
+ },
73
+ isMemberExpressionRoot(ancestors) {
74
+ const node = ancestors[ancestors.length - 1];
75
+ const parent = ancestors[ancestors.length - 2];
76
+ const grandParent = ancestors[ancestors.length - 3];
77
+ return parent.type === 'MemberExpression' && parent.object === node && grandParent.type !== 'MemberExpression';
78
+ },
79
+ isDeclaration(ancestors) {
80
+ const node = ancestors[ancestors.length - 1];
81
+ const parent = ancestors[ancestors.length - 2];
82
+ return (parent.type === 'VariableDeclarator' || parent.type === 'FunctionDeclaration' || parent.type === 'ClassDeclaration') && parent.id === node;
83
+ },
84
+ isClassOrFuncDeclarationId(ancestors) {
85
+ const node = ancestors[ancestors.length - 1];
86
+ const parent = ancestors[ancestors.length - 2];
87
+ return (parent.type === 'ClassDeclaration' || parent.type === 'FunctionDeclaration') && parent.id === node && ancestors.length <= 3;
88
+ },
89
+ isVarDeclarationInGlobalScope(ancestors) {
90
+ const node = ancestors[ancestors.length - 1];
91
+ const parent = ancestors[ancestors.length - 2];
92
+ const grandParent = ancestors[ancestors.length - 3];
93
+ const varBoundScopes = ['ClassDeclaration', 'ClassExpression', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'];
94
+ return parent.type === 'VariableDeclarator' && parent.id === node && grandParent.type === 'VariableDeclaration' && grandParent.kind === 'var' && ancestors.every(ancestor => {
95
+ return !varBoundScopes.includes(ancestor.type);
96
+ });
97
+ },
98
+ isIife(ancestors) {
99
+ const parent = ancestors[ancestors.length - 2];
100
+ return parent.type === 'FunctionExpression' && ancestors.some(ancestor => ancestor.type === 'ParenthesizedExpression');
101
+ },
102
+ isFunctionExpressionId(ancestors) {
103
+ const node = ancestors[ancestors.length - 1];
104
+ const parent = ancestors[ancestors.length - 2];
105
+ return parent.type === 'FunctionExpression' && parent.id === node;
106
+ },
107
+ isExportSpecifierAlias(ancestors) {
108
+ const node = ancestors[ancestors.length - 1];
109
+ const parent = ancestors[ancestors.length - 2];
110
+ return parent.type === 'ExportSpecifier' && parent.exported === node;
111
+ },
112
+ isClassPropertyKey(ancestors) {
113
+ const node = ancestors[ancestors.length - 1];
114
+ const parent = ancestors[ancestors.length - 2];
115
+ return parent.type === 'PropertyDefinition' && parent.key === node;
116
+ },
117
+ isMethodDefinitionKey(ancestors) {
118
+ const node = ancestors[ancestors.length - 1];
119
+ const parent = ancestors[ancestors.length - 2];
120
+ return parent.type === 'MethodDefinition' && parent.key === node;
121
+ },
122
+ isMemberKey(ancestors) {
123
+ const node = ancestors[ancestors.length - 1];
124
+ const parent = ancestors[ancestors.length - 2];
125
+ return parent.type === 'MemberExpression' && parent.property === node;
126
+ },
127
+ isPropertyKey(ancestors) {
128
+ const node = ancestors[ancestors.length - 1];
129
+ const parent = ancestors[ancestors.length - 2];
130
+ return parent.type === 'Property' && parent.key === node;
131
+ }
132
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.scopes = exports.scope = void 0;
7
+ const scopes = exports.scopes = ['BlockStatement', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassDeclaration', 'ClassExpression', 'ClassBody', 'StaticBlock'];
8
+ const scope = exports.scope = {
9
+ isScope(node) {
10
+ return scopes.includes(node.type);
11
+ }
12
+ };
@@ -1,5 +1,31 @@
1
- import MagicString from 'magic-string';
2
- import type { NodePath } from '@babel/traverse';
3
- import type { Identifier } from '@babel/types';
4
- import type { FormatterOptions } from '../types.cjs';
5
- export declare const identifier: (nodePath: NodePath<Identifier>, src: MagicString, options: FormatterOptions) => void;
1
+ import type { Node, IdentifierName } from 'oxc-parser';
2
+ /**
3
+ * Focus exclusively on IdentifierName type as it has the name property,
4
+ * which is what the identifer utilities are interested in.
5
+ *
6
+ * Explicitly ignore the TSThisParameter type as it is not a valid identifier name.
7
+ */
8
+ declare const isIdentifierName: (node: Node) => node is IdentifierName;
9
+ /**
10
+ * All methods receive the full set of ancestors, which
11
+ * specifically includes the node itself as the last element.
12
+ * The second to last element is the parent node, and so on.
13
+ * The first element is the root node.
14
+ */
15
+ declare const identifier: {
16
+ isNamed: (node: Node) => node is IdentifierName;
17
+ isMetaProperty(ancestors: Node[]): boolean;
18
+ isModuleScope(ancestors: Node[], includeImports?: boolean): boolean;
19
+ isMemberExpressionRoot(ancestors: Node[]): boolean;
20
+ isDeclaration(ancestors: Node[]): boolean;
21
+ isClassOrFuncDeclarationId(ancestors: Node[]): boolean;
22
+ isVarDeclarationInGlobalScope(ancestors: Node[]): boolean;
23
+ isIife(ancestors: Node[]): boolean;
24
+ isFunctionExpressionId(ancestors: Node[]): boolean;
25
+ isExportSpecifierAlias(ancestors: Node[]): boolean;
26
+ isClassPropertyKey(ancestors: Node[]): boolean;
27
+ isMethodDefinitionKey(ancestors: Node[]): boolean;
28
+ isMemberKey(ancestors: Node[]): boolean;
29
+ isPropertyKey(ancestors: Node[]): boolean;
30
+ };
31
+ export { identifier, isIdentifierName };
@@ -0,0 +1,19 @@
1
+ import type { Node } from 'oxc-parser';
2
+ import type { IdentMeta, Scope } from '../types.cjs';
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,4 @@
1
+ import type { Specifier } from '@knighted/specifier';
2
+ type UpdateSrcLang = Parameters<Specifier['updateSrc']>[1];
3
+ declare const getLangFromExt: (filename: string) => UpdateSrcLang;
4
+ export { getLangFromExt };
@@ -1,5 +1,4 @@
1
1
  import MagicString from 'magic-string';
2
- import type { NodePath } from '@babel/traverse';
3
- import type { MemberExpression } from '@babel/types';
2
+ import type { MemberExpression, Node } from 'oxc-parser';
4
3
  import type { FormatterOptions } from '../types.cjs';
5
- export declare const memberExpression: (nodePath: NodePath<MemberExpression>, src: MagicString, options: FormatterOptions) => void;
4
+ export declare const memberExpression: (node: MemberExpression, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
@@ -1,5 +1,4 @@
1
1
  import MagicString from 'magic-string';
2
- import type { NodePath } from '@babel/traverse';
3
- import type { MetaProperty } from '@babel/types';
2
+ import type { Node, MetaProperty } from 'oxc-parser';
4
3
  import type { FormatterOptions } from '../types.cjs';
5
- export declare const metaProperty: (nodePath: NodePath<MetaProperty>, src: MagicString, options: FormatterOptions) => void;
4
+ export declare const metaProperty: (node: MetaProperty, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
@@ -7,28 +7,22 @@ exports.transform = void 0;
7
7
  var _nodePath = require("node:path");
8
8
  var _promises = require("node:fs/promises");
9
9
  var _specifier = require("@knighted/specifier");
10
- var _parse = require("./parse.cjs");
11
- var _format = require("./format.cjs");
10
+ var _parse = require("#parse");
11
+ var _format = require("#format");
12
+ var _lang = require("#utils/lang.js");
12
13
  const defaultOptions = {
13
- type: 'commonjs',
14
+ target: 'commonjs',
15
+ sourceType: 'auto',
16
+ transformSyntax: true,
17
+ liveBindings: 'strict',
18
+ rewriteSpecifier: undefined,
19
+ dirFilename: 'inject',
20
+ importMeta: 'shim',
21
+ requireSource: 'builtin',
22
+ cjsDefault: 'auto',
23
+ topLevelAwait: 'error',
14
24
  out: undefined,
15
- modules: false,
16
- specifier: undefined
17
- };
18
- const getLangFromExt = filename => {
19
- const ext = (0, _nodePath.extname)(filename);
20
- if (/\.js$/.test(ext)) {
21
- return 'js';
22
- }
23
- if (/\.ts$/.test(ext)) {
24
- return 'ts';
25
- }
26
- if (ext === '.tsx') {
27
- return 'tsx';
28
- }
29
- if (ext === '.jsx') {
30
- return 'jsx';
31
- }
25
+ inPlace: false
32
26
  };
33
27
  const transform = async (filename, options = defaultOptions) => {
34
28
  const opts = {
@@ -37,24 +31,29 @@ const transform = async (filename, options = defaultOptions) => {
37
31
  };
38
32
  const file = (0, _nodePath.resolve)(filename);
39
33
  const code = (await (0, _promises.readFile)(file)).toString();
40
- const ast = (0, _parse.parse)(code);
41
- let source = (0, _format.format)(code, ast, opts).toString();
42
- if (options.specifier) {
43
- const code = await _specifier.specifier.updateSrc(source, getLangFromExt(filename), ({
34
+ const ast = (0, _parse.parse)(filename, code);
35
+ let source = await (0, _format.format)(code, ast, opts);
36
+ if (opts.rewriteSpecifier) {
37
+ const code = await _specifier.specifier.updateSrc(source, (0, _lang.getLangFromExt)(filename), ({
44
38
  value
45
39
  }) => {
40
+ if (typeof opts.rewriteSpecifier === 'function') {
41
+ return opts.rewriteSpecifier(value) ?? undefined;
42
+ }
43
+
46
44
  // Collapse any BinaryExpression or NewExpression to test for a relative specifier
47
45
  const collapsed = value.replace(/['"`+)\s]|new String\(/g, '');
48
46
  const relative = /^(?:\.|\.\.)\//;
49
47
  if (relative.test(collapsed)) {
50
48
  // $2 is for any closing quotation/parens around BE or NE
51
- return value.replace(/(.+)\.(?:m|c)?(?:j|t)s([)'"`]*)?$/, `$1${options.specifier}$2`);
49
+ return value.replace(/(.+)\.(?:m|c)?(?:j|t)s([)'"]*)?$/, `$1${opts.rewriteSpecifier}$2`);
52
50
  }
53
51
  });
54
52
  source = code;
55
53
  }
56
- if (opts.out) {
57
- await (0, _promises.writeFile)((0, _nodePath.resolve)(opts.out), source);
54
+ const outputPath = opts.inPlace ? file : opts.out ? (0, _nodePath.resolve)(opts.out) : undefined;
55
+ if (outputPath) {
56
+ await (0, _promises.writeFile)(outputPath, source);
58
57
  }
59
58
  return source;
60
59
  };
@@ -4,19 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.parse = void 0;
7
- var _parser = require("@babel/parser");
8
- const parse = (source, dts = false) => {
9
- const ast = (0, _parser.parse)(source, {
10
- sourceType: 'module',
11
- allowAwaitOutsideFunction: true,
12
- allowReturnOutsideFunction: true,
13
- allowImportExportEverywhere: true,
14
- plugins: ['jsx', ['importAttributes', {
15
- deprecatedAssertSyntax: true
16
- }], ['typescript', {
17
- dts
18
- }]]
19
- });
20
- return ast;
7
+ var _oxcParser = require("oxc-parser");
8
+ const parse = (filename, code) => {
9
+ return (0, _oxcParser.parseSync)(filename, code);
21
10
  };
22
11
  exports.parse = parse;
@@ -1,2 +1,2 @@
1
- declare const parse: (source: string, dts?: boolean) => import("@babel/parser").ParseResult<import("@babel/types").File>;
1
+ declare const parse: (filename: string, code: string) => import("oxc-parser").ParseResult;
2
2
  export { parse };
@@ -0,0 +1,6 @@
1
+ import type { Node } from 'oxc-parser';
2
+ declare const scopes: string[];
3
+ declare const scope: {
4
+ isScope(node: Node): boolean;
5
+ };
6
+ export { scopes, scope };
@@ -1,7 +1,43 @@
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);
1
3
  export type ModuleOptions = {
2
- type?: 'module' | 'commonjs';
3
- modules?: boolean;
4
- specifier?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts';
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
+ requireSource?: 'builtin' | 'create-require';
12
+ cjsDefault?: 'module-exports' | 'auto' | 'none';
13
+ topLevelAwait?: 'error' | 'wrap' | 'preserve';
5
14
  out?: string;
15
+ inPlace?: boolean;
6
16
  };
7
- export type FormatterOptions = Omit<ModuleOptions, 'out'> & Required<Pick<ModuleOptions, 'type'>>;
17
+ export type SpannedNode = Node & Span;
18
+ export type ExportsMeta = {
19
+ hasExportsBeenReassigned: boolean;
20
+ hasDefaultExportBeenReassigned: boolean;
21
+ hasDefaultExportBeenAssigned: boolean;
22
+ defaultExportValue: unknown;
23
+ };
24
+ export type CjsExport = {
25
+ key: string;
26
+ writes: SpannedNode[];
27
+ fromIdentifier?: string;
28
+ via: Set<'exports' | 'module.exports'>;
29
+ reassignments: SpannedNode[];
30
+ hasGetter?: boolean;
31
+ };
32
+ export type IdentMeta = {
33
+ declare: SpannedNode[];
34
+ read: SpannedNode[];
35
+ };
36
+ export type Scope = {
37
+ type: string;
38
+ name: string;
39
+ node: Node;
40
+ idents: Set<string>;
41
+ };
42
+ export type FormatterOptions = Omit<ModuleOptions, 'out' | 'inPlace'>;
43
+ export type Identifier = IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSIndexSignatureName;
@@ -0,0 +1,2 @@
1
+ declare const isValidUrl: (url: string) => boolean;
2
+ export { isValidUrl };
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.requireMainRgx = exports.exportsRename = exports.collectCjsExports = void 0;
7
+ var _walk = require("#walk");
8
+ const exportsRename = exports.exportsRename = '__exports';
9
+ const requireMainRgx = exports.requireMainRgx = /(require\.main\s*===\s*module|module\s*===\s*require\.main)/g;
10
+ const literalPropName = (prop, literals) => {
11
+ if (prop.type === 'Identifier') return literals?.get(prop.name)?.toString() ?? prop.name;
12
+ if (prop.type === 'Literal' && (typeof prop.value === 'string' || typeof prop.value === 'number')) {
13
+ return String(prop.value);
14
+ }
15
+ if (prop.type === 'TemplateLiteral' && prop.expressions.length === 0 && prop.quasis.length === 1) {
16
+ return prop.quasis[0].value.cooked ?? prop.quasis[0].value.raw;
17
+ }
18
+ return null;
19
+ };
20
+ const resolveExportTarget = (node, aliases, literals) => {
21
+ if (node.type === 'Identifier' && node.name === 'exports') {
22
+ return {
23
+ key: 'default',
24
+ via: 'exports'
25
+ };
26
+ }
27
+ if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'module' && node.property.type === 'Identifier' && node.property.name === 'exports') {
28
+ return {
29
+ key: 'default',
30
+ via: 'module.exports'
31
+ };
32
+ }
33
+ if (node.type !== 'MemberExpression') return null;
34
+ const base = node.object;
35
+ const prop = node.property;
36
+ const key = literalPropName(prop, literals);
37
+ if (!key) return null;
38
+ const baseVia = resolveBase(base, aliases);
39
+ if (!baseVia) return null;
40
+ if (baseVia === 'module.exports' && key === 'exports') {
41
+ return {
42
+ key: 'default',
43
+ via: 'module.exports'
44
+ };
45
+ }
46
+ return {
47
+ key,
48
+ via: baseVia
49
+ };
50
+ };
51
+ const resolveBase = (node, aliases) => {
52
+ if (node.type === 'Identifier') {
53
+ if (node.name === 'exports') return 'exports';
54
+ const alias = aliases.get(node.name);
55
+ if (alias) return alias;
56
+ }
57
+ if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'module' && node.property.type === 'Identifier' && node.property.name === 'exports') {
58
+ return 'module.exports';
59
+ }
60
+ return null;
61
+ };
62
+ const collectCjsExports = async ast => {
63
+ const exportsMap = new Map();
64
+ const localToExport = new Map();
65
+ const aliases = new Map();
66
+ const literals = new Map();
67
+ const addExport = (ref, node, rhs, options) => {
68
+ const entry = exportsMap.get(ref.key) ?? {
69
+ key: ref.key,
70
+ writes: [],
71
+ via: new Set(),
72
+ reassignments: []
73
+ };
74
+ entry.via.add(ref.via);
75
+ entry.writes.push(node);
76
+ if (options?.hasGetter) {
77
+ entry.hasGetter = true;
78
+ }
79
+ if (rhs) {
80
+ entry.fromIdentifier ??= rhs.name;
81
+ const set = localToExport.get(rhs.name) ?? new Set();
82
+ set.add(ref.key);
83
+ localToExport.set(rhs.name, set);
84
+ }
85
+ exportsMap.set(ref.key, entry);
86
+ };
87
+ await (0, _walk.ancestorWalk)(ast, {
88
+ enter(node) {
89
+ if (node.type === 'VariableDeclarator' && node.id.type === 'Identifier' && node.init) {
90
+ const via = resolveBase(node.init, aliases);
91
+ if (via) {
92
+ aliases.set(node.id.name, via);
93
+ }
94
+ if (node.init.type === 'Literal' && (typeof node.init.value === 'string' || typeof node.init.value === 'number')) {
95
+ literals.set(node.id.name, node.init.value);
96
+ }
97
+ if (node.init.type === 'TemplateLiteral' && node.init.expressions.length === 0 && node.init.quasis.length === 1) {
98
+ const cooked = node.init.quasis[0].value.cooked ?? node.init.quasis[0].value.raw;
99
+ literals.set(node.id.name, cooked);
100
+ }
101
+ }
102
+ if (node.type === 'AssignmentExpression') {
103
+ const target = resolveExportTarget(node.left, aliases, literals);
104
+ if (target) {
105
+ const rhsIdent = node.right.type === 'Identifier' ? node.right : undefined;
106
+ addExport(target, node, rhsIdent);
107
+ return;
108
+ }
109
+ if (node.left.type === 'Identifier') {
110
+ const keys = localToExport.get(node.left.name);
111
+ if (keys) {
112
+ keys.forEach(key => {
113
+ const entry = exportsMap.get(key);
114
+ if (entry) {
115
+ entry.reassignments.push(node);
116
+ exportsMap.set(key, entry);
117
+ }
118
+ });
119
+ }
120
+ }
121
+ if (node.left.type === 'ObjectPattern') {
122
+ for (const prop of node.left.properties) {
123
+ if (prop.type === 'Property' && prop.value.type === 'MemberExpression') {
124
+ const ref = resolveExportTarget(prop.value, aliases, literals);
125
+ if (ref) {
126
+ addExport(ref, node);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ if (node.type === 'CallExpression') {
133
+ const callee = node.callee;
134
+
135
+ // Object.assign(exports, { foo: bar })
136
+ if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'Object' && callee.property.type === 'Identifier' && callee.property.name === 'assign' && node.arguments.length >= 2) {
137
+ const targetArg = node.arguments[0];
138
+ const ref = resolveBase(targetArg, aliases);
139
+ if (!ref) return;
140
+ for (let i = 1; i < node.arguments.length; i++) {
141
+ const arg = node.arguments[i];
142
+ if (arg.type === 'ObjectExpression') {
143
+ for (const prop of arg.properties) {
144
+ if (prop.type !== 'Property') continue;
145
+ const keyName = literalPropName(prop.key, literals);
146
+ if (!keyName) continue;
147
+ let rhsIdent;
148
+ if (prop.value.type === 'Identifier') {
149
+ rhsIdent = prop.value;
150
+ }
151
+ addExport({
152
+ key: keyName,
153
+ via: ref
154
+ }, node, rhsIdent);
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ // Object.defineProperty(exports, 'foo', { value, get, set })
161
+ if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'Object' && callee.property.type === 'Identifier' && callee.property.name === 'defineProperty' && node.arguments.length >= 3) {
162
+ const target = resolveBase(node.arguments[0], aliases);
163
+ if (!target) return;
164
+ const keyName = literalPropName(node.arguments[1], literals);
165
+ if (!keyName) return;
166
+ const desc = node.arguments[2];
167
+ if (desc.type !== 'ObjectExpression') return;
168
+ let rhsIdent;
169
+ let hasGetter = false;
170
+ for (const prop of desc.properties) {
171
+ if (prop.type !== 'Property') continue;
172
+ if (prop.key.type !== 'Identifier') continue;
173
+ if (prop.key.name === 'value' && prop.value.type === 'Identifier') {
174
+ rhsIdent = prop.value;
175
+ }
176
+ if (prop.key.name === 'get' && prop.value.type === 'Identifier') {
177
+ hasGetter = true;
178
+ }
179
+ if (prop.key.name === 'set' && prop.value.type === 'Identifier') {
180
+ // Setter-only doesn’t create a readable export; ignore beyond marking write
181
+ }
182
+ }
183
+ addExport({
184
+ key: keyName,
185
+ via: target
186
+ }, node, rhsIdent, {
187
+ hasGetter
188
+ });
189
+ }
190
+
191
+ // Object.defineProperties(exports, { foo: { value: ... }, bar: { get: ... } })
192
+ if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'Object' && callee.property.type === 'Identifier' && callee.property.name === 'defineProperties' && node.arguments.length >= 2) {
193
+ const target = resolveBase(node.arguments[0], aliases);
194
+ if (!target) return;
195
+ const descMap = node.arguments[1];
196
+ if (descMap.type !== 'ObjectExpression') return;
197
+ for (const prop of descMap.properties) {
198
+ if (prop.type !== 'Property') continue;
199
+ const keyName = literalPropName(prop.key, literals);
200
+ if (!keyName) continue;
201
+ if (prop.value.type !== 'ObjectExpression') continue;
202
+ let rhsIdent;
203
+ let hasGetter = false;
204
+ for (const descProp of prop.value.properties) {
205
+ if (descProp.type !== 'Property') continue;
206
+ if (descProp.key.type !== 'Identifier') continue;
207
+ if (descProp.key.name === 'value' && descProp.value.type === 'Identifier') {
208
+ rhsIdent = descProp.value;
209
+ }
210
+ if (descProp.key.name === 'get' && descProp.value.type === 'Identifier') {
211
+ hasGetter = true;
212
+ }
213
+ }
214
+ addExport({
215
+ key: keyName,
216
+ via: target
217
+ }, node, rhsIdent, {
218
+ hasGetter
219
+ });
220
+ }
221
+ }
222
+ }
223
+ }
224
+ });
225
+ return exportsMap;
226
+ };
227
+ exports.collectCjsExports = collectCjsExports;