@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
package/dist/format.js CHANGED
@@ -1,34 +1,142 @@
1
1
  import MagicString from 'magic-string';
2
- import _traverse from '@babel/traverse';
3
- import { moduleType } from 'node-module-type';
4
- import { identifier } from './formatters/identifier.js';
5
- import { metaProperty } from './formatters/metaProperty.js';
6
- import { memberExpression } from './formatters/memberExpression.js';
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';
7
11
 
8
12
  /**
9
- * Runtime hack to prevent issues with babel's default interop while dual building with tsc.
10
- * @see https://github.com/babel/babel/discussions/13093#discussioncomment-12705927
11
- * Temporary fix until I switch to oxc-parser.
13
+ * Node added support for import.meta.main.
14
+ * Added in: v24.2.0, v22.18.0
15
+ * @see https://nodejs.org/api/esm.html#importmetamain
12
16
  */
13
- const type = moduleType();
14
- const traverse = typeof _traverse === 'function' || type === 'commonjs' ? _traverse : _traverse.default;
17
+ const format = async (src, ast, opts) => {
18
+ const code = new MagicString(src);
19
+ const exportsMeta = {
20
+ hasExportsBeenReassigned: false,
21
+ defaultExportValue: undefined,
22
+ hasDefaultExportBeenReassigned: false,
23
+ hasDefaultExportBeenAssigned: false
24
+ };
25
+ const exportTable = opts.target === 'module' ? await collectCjsExports(ast.program) : null;
26
+ await collectModuleIdentifiers(ast.program);
27
+ if (opts.target === 'module' && opts.transformSyntax) {
28
+ /**
29
+ * Prepare ESM output by renaming `exports` to `__exports` and seeding an
30
+ * `import.meta.filename` touch so import.meta is present even when the
31
+ * original source never referenced it.
32
+ */
33
+ code.prepend(`let ${exportsRename} = {};
34
+ void import.meta.filename;
35
+ `);
36
+ }
37
+ await ancestorWalk(ast.program, {
38
+ async enter(node, ancestors) {
39
+ const parent = ancestors[ancestors.length - 2] ?? null;
40
+ if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
41
+ const skipped = ['__filename', '__dirname'];
42
+ const skippedParams = node.params.filter(param => param.type === 'Identifier' && skipped.includes(param.name));
43
+ const skippedFuncIdentifier = node.id?.type === 'Identifier' && skipped.includes(node.id.name);
44
+ if (skippedParams.length || skippedFuncIdentifier) {
45
+ this.skip();
46
+ }
47
+ }
15
48
 
16
- /**
17
- * Note, there is no specific conversion for `import.meta.main` as it does not exist.
18
- * @see https://github.com/nodejs/node/issues/49440
19
- */
20
- export const format = (code, ast, options) => {
21
- const src = new MagicString(code);
22
- traverse(ast, {
23
- Identifier(path) {
24
- identifier(path, src, options);
25
- },
26
- MetaProperty(path) {
27
- metaProperty(path, src, options);
28
- },
29
- MemberExpression(path) {
30
- memberExpression(path, src, options);
49
+ /**
50
+ * Check for assignment to `import.meta.url`.
51
+ */
52
+ if (node.type === 'AssignmentExpression' && node.left.type === 'MemberExpression' && node.left.object.type === 'MetaProperty' && node.left.property.type === 'Identifier' && node.left.property.name === 'url') {
53
+ if (node.right.type === 'Literal' && typeof node.right.value === 'string') {
54
+ if (!isValidUrl(node.right.value)) {
55
+ const rhs = code.snip(node.right.start, node.right.end).toString();
56
+ const assignment = code.snip(node.start, node.end).toString();
57
+ code.update(node.start, node.end, `/* Invalid assignment: ${rhs} is not a URL. ${assignment} */`);
58
+ this.skip();
59
+ }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Skip module scope CJS globals when they are object properties.
65
+ * Ignoring `exports` here.
66
+ */
67
+ if (node.type === 'MemberExpression' && node.property.type === 'Identifier' && ['__filename', '__dirname'].includes(node.property.name)) {
68
+ this.skip();
69
+ }
70
+
71
+ /**
72
+ * Check for bare `module.exports` expressions.
73
+ */
74
+ if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'module' && node.property.type === 'Identifier' && node.property.name === 'exports' && parent?.type === 'ExpressionStatement') {
75
+ if (opts.target === 'module') {
76
+ code.update(node.start, node.end, ';');
77
+ // Prevent parsing the `exports` identifier again.
78
+ this.skip();
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Format `module.exports` and `exports` assignments.
84
+ */
85
+ if (node.type === 'AssignmentExpression') {
86
+ await assignmentExpression({
87
+ node,
88
+ parent,
89
+ code,
90
+ opts,
91
+ meta: exportsMeta
92
+ });
93
+ }
94
+ if (node.type === 'MetaProperty') {
95
+ metaProperty(node, parent, code, opts);
96
+ }
97
+ if (node.type === 'MemberExpression') {
98
+ memberExpression(node, parent, code, opts);
99
+ }
100
+ if (isIdentifierName(node)) {
101
+ identifier({
102
+ node,
103
+ ancestors,
104
+ code,
105
+ opts,
106
+ meta: exportsMeta
107
+ });
108
+ }
31
109
  }
32
110
  });
33
- return src;
34
- };
111
+ if (opts.target === 'module' && opts.transformSyntax && exportTable) {
112
+ const isValidExportName = name => /^[$A-Z_a-z][$\w]*$/.test(name);
113
+ const asExportName = name => isValidExportName(name) ? name : JSON.stringify(name);
114
+ const accessProp = name => isValidExportName(name) ? `${exportsRename}.${name}` : `${exportsRename}[${JSON.stringify(name)}]`;
115
+ const tempNameFor = name => {
116
+ const sanitized = name.replace(/[^$\w]/g, '_') || 'value';
117
+ const safe = /^[0-9]/.test(sanitized) ? `_${sanitized}` : sanitized;
118
+ return `__export_${safe}`;
119
+ };
120
+ const lines = [];
121
+ const defaultEntry = exportTable.get('default');
122
+ if (defaultEntry) {
123
+ const def = defaultEntry.fromIdentifier ?? exportsRename;
124
+ lines.push(`export default ${def};`);
125
+ }
126
+ for (const [key, entry] of exportTable) {
127
+ if (key === 'default') continue;
128
+ if (entry.fromIdentifier) {
129
+ lines.push(`export { ${entry.fromIdentifier} as ${asExportName(key)} };`);
130
+ } else {
131
+ const temp = tempNameFor(key);
132
+ lines.push(`const ${temp} = ${accessProp(key)};`);
133
+ lines.push(`export { ${temp} as ${asExportName(key)} };`);
134
+ }
135
+ }
136
+ if (lines.length) {
137
+ code.append(`\n${lines.join('\n')}\n`);
138
+ }
139
+ }
140
+ return code.toString();
141
+ };
142
+ export { format };
@@ -0,0 +1,30 @@
1
+ import { walk } from '#walk';
2
+ export const assignmentExpression = async ({
3
+ node,
4
+ parent: _parent,
5
+ code: _code,
6
+ opts,
7
+ meta: _meta
8
+ }) => {
9
+ if (opts.target === 'module' && opts.transformSyntax) {
10
+ await walk(node, {
11
+ enter(childNode, childParent) {
12
+ if (childNode.type === 'Identifier' && childNode.name === 'exports') {
13
+ if (childParent === node && node.left === childNode) {
14
+ /**
15
+ * The code is reassigning `exports` to something else.
16
+ * Redeclare it with a new variable name using var.
17
+ */
18
+ //meta.hasExportsBeenReassigned = true
19
+ //console.log('writing exports reassignment')
20
+ //code.update(node.left.start, node.left.end, exportsRename)
21
+ //console.log(code.slice(node.start, node.end))
22
+ //code.update(childNode.start, childNode.end, exportsRename)
23
+ //console.log('reassigning exports', childParent, code.update(node.left.start, node.left.end, exportsRename))
24
+ }
25
+ //console.log('found exports assignment', meta.hasExportsBeenReassigned, expr)
26
+ }
27
+ }
28
+ });
29
+ }
30
+ };
@@ -1,61 +1,42 @@
1
- export const expressionStatement = (nodePath, src, options) => {
2
- if (options.type === 'module') {
3
- const {
4
- node
5
- } = nodePath;
6
- const {
7
- start,
8
- end
9
- } = node;
10
- if (typeof start === 'number' && typeof end === 'number') {
11
- const isMemberExpressionModuleExports = expression => {
12
- return expression.object.type === 'Identifier' && expression.object.name === 'module' && expression.property.type === 'Identifier' && expression.property.name === 'exports';
13
- };
14
- if (node.expression.type === 'Identifier') {
15
- const name = node.expression.name;
1
+ export const expressionStatement = (node, parent, src, options) => {
2
+ if (options.target === 'module') {
3
+ if (node.expression.type === 'Identifier') {
4
+ const {
5
+ start,
6
+ end
7
+ } = node;
8
+ const name = node.expression.name;
16
9
 
17
- // CommonJS globals
18
- switch (name) {
19
- case 'module':
20
- src.update(start, end, 'import.meta');
21
- break;
22
- case 'exports':
23
- src.update(start, end, '{}');
24
- break;
25
- case '__filename':
26
- src.update(start, end, 'import.meta.filename');
27
- break;
28
- case '__dirname':
29
- src.update(start, end, 'import.meta.dirname');
30
- break;
31
- }
32
- }
33
- if (node.expression.type === 'MemberExpression') {
34
- const {
35
- expression
36
- } = node;
37
-
38
- // Check for `module.exports` without an assignment
39
- if (isMemberExpressionModuleExports(expression)) {
40
- /**
41
- * @TODO: Should this depend on `options.modules` being enabled?
42
- * Probably not for the same reason `exports` is converted to an empty object (ReferenceError in ESM).
43
- * This is a standalone reference to `module.exports` without being part of an AssignmentExpression.
44
- */
10
+ // CommonJS globals (as bare identifiers)
11
+ switch (name) {
12
+ case 'require':
13
+ src.remove(start, end);
14
+ break;
15
+ case 'module':
16
+ src.update(start, end, 'import.meta');
17
+ break;
18
+ case 'exports':
45
19
  src.update(start, end, '{}');
46
- }
47
- }
48
-
49
- /*
50
- if (
51
- options.modules &&
52
- node.expression.type === 'AssignmentExpression' &&
53
- node.expression.left.type === 'MemberExpression' &&
54
- isMemberExpressionModuleExports(node.expression.left)
55
- ) {
56
- // @TODO support `modules` option.
20
+ break;
21
+ case '__filename':
22
+ src.update(start, end, 'import.meta.filename');
23
+ break;
24
+ case '__dirname':
25
+ src.update(start, end, 'import.meta.dirname');
26
+ break;
57
27
  }
58
- */
28
+ }
29
+ }
30
+ if (options.target === 'commonjs') {
31
+ if (node.expression.type === 'Identifier') {
32
+ const {
33
+ start,
34
+ end
35
+ } = node;
36
+ const name = node.expression.name;
37
+ void start;
38
+ void end;
39
+ void name;
59
40
  }
60
41
  }
61
42
  };
@@ -1,41 +1,41 @@
1
- export const identifier = (nodePath, src, options) => {
2
- if (options.type === 'module') {
3
- const {
4
- node
5
- } = nodePath;
1
+ import { exportsRename } from '#utils/exports.js';
2
+ import { identifier as ident } from '#helpers/identifier.js';
3
+ export const identifier = ({
4
+ node,
5
+ ancestors,
6
+ code,
7
+ opts,
8
+ meta
9
+ }) => {
10
+ if (opts.target === 'module') {
6
11
  const {
7
12
  start,
8
- end
13
+ end,
14
+ name
9
15
  } = node;
10
- if (typeof start === 'number' && typeof end === 'number' && node.type === 'Identifier') {
11
- const {
12
- name
13
- } = node;
14
- const isMemberExpression = Boolean(nodePath.findParent(path => path.isMemberExpression()));
16
+ switch (name) {
17
+ case '__filename':
18
+ code.update(start, end, 'import.meta.url');
19
+ break;
20
+ case '__dirname':
21
+ code.update(start, end, 'import.meta.dirname');
22
+ break;
23
+ case 'exports':
24
+ {
25
+ const parent = ancestors[ancestors.length - 2];
26
+ if (opts.transformSyntax) {
27
+ if (parent.type === 'AssignmentExpression' && parent.left === node) {
28
+ // The code is reassigning `exports` to something else.
15
29
 
16
- // CommonJS globals in expression/statement
17
- switch (name) {
18
- case 'module':
19
- {
20
- if (!isMemberExpression) {
21
- src.update(start, end, 'import.meta');
30
+ meta.hasExportsBeenReassigned = true;
31
+ code.update(parent.left.start, parent.left.end, exportsRename);
22
32
  }
23
- break;
24
- }
25
- case 'exports':
26
- {
27
- if (!isMemberExpression) {
28
- src.update(start, end, '{}');
33
+ if (ident.isModuleScope(ancestors) && !ident.isFunctionExpressionId(ancestors) && !ident.isExportSpecifierAlias(ancestors) && !ident.isClassPropertyKey(ancestors) && !ident.isMethodDefinitionKey(ancestors) && !ident.isMemberKey(ancestors) && !ident.isPropertyKey(ancestors) && !ident.isIife(ancestors)) {
34
+ code.update(start, end, exportsRename);
29
35
  }
30
- break;
31
36
  }
32
- case '__filename':
33
- src.update(start, end, 'import.meta.filename');
34
- break;
35
- case '__dirname':
36
- src.update(start, end, 'import.meta.dirname');
37
- break;
38
- }
37
+ }
38
+ break;
39
39
  }
40
40
  }
41
41
  };
@@ -1,13 +1,15 @@
1
- export const memberExpression = (nodePath, src, options) => {
2
- if (options.type === 'module') {
3
- const {
4
- node
5
- } = nodePath;
6
- const {
7
- start,
8
- end
9
- } = node;
10
- if (typeof start === 'number' && typeof end === 'number' && node.object.type === 'Identifier' && node.object.name === 'require' && node.property.type === 'Identifier') {
1
+ import { exportsRename } from '#utils/exports.js';
2
+ export const memberExpression = (node, parent, src, options) => {
3
+ if (options.target === 'module') {
4
+ if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'exports') {
5
+ src.update(node.start, node.end, exportsRename);
6
+ return;
7
+ }
8
+ if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'require') {
9
+ const {
10
+ start,
11
+ end
12
+ } = node;
11
13
  const {
12
14
  name
13
15
  } = node.property;
@@ -15,7 +17,18 @@ export const memberExpression = (nodePath, src, options) => {
15
17
  // CommonJS properties of `require`
16
18
  switch (name) {
17
19
  case 'main':
18
- src.update(start, end, 'import.meta');
20
+ /**
21
+ * Node.js team still quibbling over import.meta.main ¯\_(ツ)_/¯
22
+ * @see https://github.com/nodejs/node/pull/32223
23
+ */
24
+ if (parent?.type === 'ExpressionStatement') {
25
+ // This is a standalone expression so remove it to not cause run-time errors.
26
+ src.remove(start, end);
27
+ }
28
+ /**
29
+ * Transform require.main === module.
30
+ */
31
+ if (parent?.type === 'BinaryExpression') {}
19
32
  break;
20
33
  case 'resolve':
21
34
  src.update(start, end, 'import.meta.resolve');
@@ -1,42 +1,30 @@
1
- export const metaProperty = (nodePath, src, options) => {
2
- if (options.type === 'commonjs') {
3
- const path = nodePath.findParent(path => path.isMemberExpression());
4
- if (path) {
5
- const {
6
- node
7
- } = path;
8
- const {
9
- start,
10
- end
11
- } = node;
12
- if (node.type === 'MemberExpression' && node.property.type === 'Identifier' && typeof start == 'number' && typeof end === 'number') {
13
- const name = node.property.name;
14
- switch (name) {
15
- case 'url':
16
- src.update(start, end, 'require("node:url").pathToFileURL(__filename).toString()');
17
- break;
18
- case 'filename':
19
- src.update(start, end, '__filename');
20
- break;
21
- case 'dirname':
22
- src.update(start, end, '__dirname');
23
- break;
24
- case 'resolve':
25
- src.update(start, end, 'require.resolve');
26
- break;
27
- }
28
- }
29
- } else {
30
- const {
31
- node
32
- } = nodePath;
1
+ export const metaProperty = (node, parent, src, options) => {
2
+ if (options.target === 'commonjs') {
3
+ if (parent?.type !== 'MemberExpression') {
4
+ // This is a bare `import.meta` expression
33
5
  const {
34
6
  start,
35
7
  end
36
8
  } = node;
37
- if (node.property.type === 'Identifier' && node.property.name === 'meta' && typeof start === 'number' && typeof end === 'number') {
38
- // This is an `import.meta` expression
39
- src.update(start, end, 'require.main');
9
+ src.update(start, end, 'module');
10
+ }
11
+ if (parent?.type === 'MemberExpression' && parent.property.type === 'Identifier') {
12
+ switch (parent.property.name) {
13
+ case 'url':
14
+ src.update(parent.start, parent.end, 'require("node:url").pathToFileURL(__filename).href');
15
+ break;
16
+ case 'filename':
17
+ src.update(parent.start, parent.end, '__filename');
18
+ break;
19
+ case 'dirname':
20
+ src.update(parent.start, parent.end, '__dirname');
21
+ break;
22
+ case 'resolve':
23
+ /**
24
+ * Should this be `require('node:url').pathToFileURL(require.resolve(<parsed specifier>)).href`?
25
+ */
26
+ src.update(parent.start, parent.end, 'require.resolve');
27
+ break;
40
28
  }
41
29
  }
42
30
  }
@@ -0,0 +1,127 @@
1
+ import { analyze } from 'periscopic';
2
+
3
+ /**
4
+ * Focus exclusively on IdentifierName type as it has the name property,
5
+ * which is what the identifer utilities are interested in.
6
+ *
7
+ * Explicitly ignore the TSThisParameter type as it is not a valid identifier name.
8
+ */
9
+ const isIdentifierName = node => {
10
+ return node.type === 'Identifier' && typeof node.name === 'string' && node.name !== 'this';
11
+ };
12
+ const scopeCache = new WeakMap();
13
+ const getScopeContext = program => {
14
+ const cached = scopeCache.get(program);
15
+ if (cached) {
16
+ return cached;
17
+ }
18
+ const {
19
+ scope
20
+ } = analyze(program);
21
+ const context = {
22
+ scope
23
+ };
24
+ scopeCache.set(program, context);
25
+ return context;
26
+ };
27
+
28
+ /**
29
+ * All methods receive the full set of ancestors, which
30
+ * specifically includes the node itself as the last element.
31
+ * The second to last element is the parent node, and so on.
32
+ * The first element is the root node.
33
+ */
34
+ const identifier = {
35
+ isNamed: node => {
36
+ return isIdentifierName(node);
37
+ },
38
+ isMetaProperty(ancestors) {
39
+ const parent = ancestors[ancestors.length - 2];
40
+ return parent.type === 'MetaProperty' || parent.type === 'MemberExpression' && parent.object.type === 'MetaProperty';
41
+ },
42
+ isModuleScope(ancestors, includeImports = false) {
43
+ const node = ancestors[ancestors.length - 1];
44
+ const parent = ancestors[ancestors.length - 2];
45
+ const program = ancestors[0];
46
+ if (!identifier.isNamed(node) || identifier.isMetaProperty(ancestors) || parent.type === 'LabeledStatement' || parent.type === 'BreakStatement' || parent.type === 'ContinueStatement') {
47
+ return false;
48
+ }
49
+ if (parent.type === 'ImportSpecifier' || parent.type === 'ImportDefaultSpecifier' || parent.type === 'ImportNamespaceSpecifier') {
50
+ return includeImports && parent.local.name === node.name;
51
+ }
52
+ if (parent.type === 'Property' && parent.key === node && !parent.computed) {
53
+ return false;
54
+ }
55
+ if (parent.type === 'MemberExpression' && parent.property === node && !parent.computed) {
56
+ return false;
57
+ }
58
+ const {
59
+ scope: rootScope
60
+ } = getScopeContext(program);
61
+ const owner = rootScope.find_owner(node.name);
62
+ if (!owner) {
63
+ return node.name === 'exports';
64
+ }
65
+ return owner === rootScope;
66
+ },
67
+ isMemberExpressionRoot(ancestors) {
68
+ const node = ancestors[ancestors.length - 1];
69
+ const parent = ancestors[ancestors.length - 2];
70
+ const grandParent = ancestors[ancestors.length - 3];
71
+ return parent.type === 'MemberExpression' && parent.object === node && grandParent.type !== 'MemberExpression';
72
+ },
73
+ isDeclaration(ancestors) {
74
+ const node = ancestors[ancestors.length - 1];
75
+ const parent = ancestors[ancestors.length - 2];
76
+ return (parent.type === 'VariableDeclarator' || parent.type === 'FunctionDeclaration' || parent.type === 'ClassDeclaration') && parent.id === node;
77
+ },
78
+ isClassOrFuncDeclarationId(ancestors) {
79
+ const node = ancestors[ancestors.length - 1];
80
+ const parent = ancestors[ancestors.length - 2];
81
+ return (parent.type === 'ClassDeclaration' || parent.type === 'FunctionDeclaration') && parent.id === node && ancestors.length <= 3;
82
+ },
83
+ isVarDeclarationInGlobalScope(ancestors) {
84
+ const node = ancestors[ancestors.length - 1];
85
+ const parent = ancestors[ancestors.length - 2];
86
+ const grandParent = ancestors[ancestors.length - 3];
87
+ const varBoundScopes = ['ClassDeclaration', 'ClassExpression', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'];
88
+ return parent.type === 'VariableDeclarator' && parent.id === node && grandParent.type === 'VariableDeclaration' && grandParent.kind === 'var' && ancestors.every(ancestor => {
89
+ return !varBoundScopes.includes(ancestor.type);
90
+ });
91
+ },
92
+ isIife(ancestors) {
93
+ const parent = ancestors[ancestors.length - 2];
94
+ return parent.type === 'FunctionExpression' && ancestors.some(ancestor => ancestor.type === 'ParenthesizedExpression');
95
+ },
96
+ isFunctionExpressionId(ancestors) {
97
+ const node = ancestors[ancestors.length - 1];
98
+ const parent = ancestors[ancestors.length - 2];
99
+ return parent.type === 'FunctionExpression' && parent.id === node;
100
+ },
101
+ isExportSpecifierAlias(ancestors) {
102
+ const node = ancestors[ancestors.length - 1];
103
+ const parent = ancestors[ancestors.length - 2];
104
+ return parent.type === 'ExportSpecifier' && parent.exported === node;
105
+ },
106
+ isClassPropertyKey(ancestors) {
107
+ const node = ancestors[ancestors.length - 1];
108
+ const parent = ancestors[ancestors.length - 2];
109
+ return parent.type === 'PropertyDefinition' && parent.key === node;
110
+ },
111
+ isMethodDefinitionKey(ancestors) {
112
+ const node = ancestors[ancestors.length - 1];
113
+ const parent = ancestors[ancestors.length - 2];
114
+ return parent.type === 'MethodDefinition' && parent.key === node;
115
+ },
116
+ isMemberKey(ancestors) {
117
+ const node = ancestors[ancestors.length - 1];
118
+ const parent = ancestors[ancestors.length - 2];
119
+ return parent.type === 'MemberExpression' && parent.property === node;
120
+ },
121
+ isPropertyKey(ancestors) {
122
+ const node = ancestors[ancestors.length - 1];
123
+ const parent = ancestors[ancestors.length - 2];
124
+ return parent.type === 'Property' && parent.key === node;
125
+ }
126
+ };
127
+ export { identifier, isIdentifierName };
@@ -0,0 +1,7 @@
1
+ const scopes = ['BlockStatement', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassDeclaration', 'ClassExpression', 'ClassBody', 'StaticBlock'];
2
+ const scope = {
3
+ isScope(node) {
4
+ return scopes.includes(node.type);
5
+ }
6
+ };
7
+ export { scopes, scope };
@@ -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.js';
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 };