@knighted/module 1.0.0-alpha.9 → 1.0.0-beta.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 (55) 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/expressionStatement.d.cts +2 -3
  5. package/dist/cjs/format.cjs +96 -22
  6. package/dist/cjs/format.d.cts +3 -4
  7. package/dist/cjs/formatters/assignmentExpression.cjs +37 -0
  8. package/dist/cjs/formatters/expressionStatement.cjs +36 -55
  9. package/dist/cjs/formatters/identifier.cjs +31 -31
  10. package/dist/cjs/formatters/memberExpression.cjs +24 -11
  11. package/dist/cjs/formatters/metaProperty.cjs +23 -35
  12. package/dist/cjs/helpers/identifier.cjs +132 -0
  13. package/dist/cjs/helpers/scope.cjs +12 -0
  14. package/dist/cjs/identifier.d.cts +31 -5
  15. package/dist/cjs/memberExpression.d.cts +2 -3
  16. package/dist/cjs/metaProperty.d.cts +2 -3
  17. package/dist/cjs/module.cjs +24 -25
  18. package/dist/cjs/parse.cjs +3 -14
  19. package/dist/cjs/parse.d.cts +1 -1
  20. package/dist/cjs/scope.d.cts +6 -0
  21. package/dist/cjs/types.d.cts +32 -4
  22. package/dist/cjs/utils.cjs +218 -0
  23. package/dist/cjs/utils.d.cts +25 -0
  24. package/dist/cjs/walk.cjs +75 -0
  25. package/dist/cjs/walk.d.cts +20 -0
  26. package/dist/expressionStatement.d.ts +2 -3
  27. package/dist/format.d.ts +3 -4
  28. package/dist/format.js +98 -23
  29. package/dist/formatters/assignmentExpression.d.ts +12 -0
  30. package/dist/formatters/assignmentExpression.js +30 -0
  31. package/dist/formatters/expressionStatement.d.ts +2 -3
  32. package/dist/formatters/expressionStatement.js +36 -55
  33. package/dist/formatters/identifier.d.ts +11 -4
  34. package/dist/formatters/identifier.js +31 -31
  35. package/dist/formatters/memberExpression.d.ts +2 -3
  36. package/dist/formatters/memberExpression.js +24 -11
  37. package/dist/formatters/metaProperty.d.ts +2 -3
  38. package/dist/formatters/metaProperty.js +23 -35
  39. package/dist/helpers/identifier.d.ts +31 -0
  40. package/dist/helpers/identifier.js +127 -0
  41. package/dist/helpers/scope.d.ts +6 -0
  42. package/dist/helpers/scope.js +7 -0
  43. package/dist/identifier.d.ts +31 -5
  44. package/dist/memberExpression.d.ts +2 -3
  45. package/dist/metaProperty.d.ts +2 -3
  46. package/dist/module.js +24 -25
  47. package/dist/parse.d.ts +1 -1
  48. package/dist/parse.js +3 -14
  49. package/dist/scope.d.ts +6 -0
  50. package/dist/types.d.ts +32 -4
  51. package/dist/utils.d.ts +25 -0
  52. package/dist/utils.js +209 -0
  53. package/dist/walk.d.ts +20 -0
  54. package/dist/walk.js +69 -0
  55. package/package.json +43 -25
@@ -0,0 +1,20 @@
1
+ import type { Node } from 'oxc-parser';
2
+ /**
3
+ * Using visitorKeys instead of oxc Visitor to keep
4
+ * an ancestor-aware enter/leave API with this.skip()
5
+ * without per-node method boilerplate.
6
+ */
7
+ type AncestorContext = {
8
+ skip: () => void;
9
+ };
10
+ type AncestorVisitor = {
11
+ enter?: (this: AncestorContext, node: Node, ancestors: Node[]) => void | Promise<void>;
12
+ leave?: (this: AncestorContext, node: Node, ancestors: Node[]) => void | Promise<void>;
13
+ };
14
+ type WalkVisitor = {
15
+ enter?: (this: AncestorContext, node: Node, parent: Node | null) => void | Promise<void>;
16
+ leave?: (this: AncestorContext, node: Node, parent: Node | null) => void | Promise<void>;
17
+ };
18
+ declare const ancestorWalk: (node: Node, visitors: AncestorVisitor) => Promise<void>;
19
+ declare const walk: (node: Node, visitors: WalkVisitor) => Promise<void>;
20
+ export { ancestorWalk, walk };
@@ -1,5 +1,4 @@
1
1
  import MagicString from 'magic-string';
2
- import type { NodePath } from '@babel/traverse';
3
- import type { ExpressionStatement } from '@babel/types';
2
+ import type { Node, ExpressionStatement } from 'oxc-parser';
4
3
  import type { FormatterOptions } from '../types.js';
5
- export declare const expressionStatement: (nodePath: NodePath<ExpressionStatement>, src: MagicString, options: FormatterOptions) => void;
4
+ export declare const expressionStatement: (node: ExpressionStatement, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
package/dist/format.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import MagicString from 'magic-string';
2
- import type { ParseResult } from '@babel/parser';
3
- import type { File } from '@babel/types';
1
+ import type { ParseResult } from 'oxc-parser';
4
2
  import type { FormatterOptions } from './types.js';
5
3
  /**
6
4
  * Note, there is no specific conversion for `import.meta.main` as it does not exist.
7
5
  * @see https://github.com/nodejs/node/issues/49440
8
6
  */
9
- export declare const format: (code: string, ast: ParseResult<File>, options: FormatterOptions) => MagicString;
7
+ declare const format: (src: string, ast: ParseResult, opts: FormatterOptions) => Promise<string>;
8
+ export { format };
package/dist/format.js CHANGED
@@ -1,34 +1,109 @@
1
1
  import MagicString from 'magic-string';
2
- import _traverse from '@babel/traverse';
3
- import { moduleType } from 'node-module-type';
4
2
  import { identifier } from './formatters/identifier.js';
5
3
  import { metaProperty } from './formatters/metaProperty.js';
6
4
  import { memberExpression } from './formatters/memberExpression.js';
7
-
8
- /**
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.
12
- */
13
- const type = moduleType();
14
- const traverse = typeof _traverse === 'function' || type === 'commonjs' ? _traverse : _traverse.default;
5
+ import { assignmentExpression } from './formatters/assignmentExpression.js';
6
+ import { isValidUrl, exportsRename, collectModuleIdentifiers } from './utils.js';
7
+ import { isIdentifierName } from './helpers/identifier.js';
8
+ import { ancestorWalk } from './walk.js';
15
9
 
16
10
  /**
17
11
  * Note, there is no specific conversion for `import.meta.main` as it does not exist.
18
12
  * @see https://github.com/nodejs/node/issues/49440
19
13
  */
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);
14
+ const format = async (src, ast, opts) => {
15
+ const code = new MagicString(src);
16
+ const exportsMeta = {
17
+ hasExportsBeenReassigned: false,
18
+ defaultExportValue: undefined,
19
+ hasDefaultExportBeenReassigned: false,
20
+ hasDefaultExportBeenAssigned: false
21
+ };
22
+ await collectModuleIdentifiers(ast.program);
23
+ if (opts.target === 'module' && opts.transformSyntax) {
24
+ /**
25
+ * Prepare ESM output by renaming `exports` to `__exports` and seeding an
26
+ * `import.meta.filename` touch so import.meta is present even when the
27
+ * original source never referenced it.
28
+ */
29
+ code.prepend(`let ${exportsRename} = {};
30
+ void import.meta.filename;
31
+ `);
32
+ }
33
+ await ancestorWalk(ast.program, {
34
+ async enter(node, ancestors) {
35
+ const parent = ancestors[ancestors.length - 2] ?? null;
36
+ if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
37
+ const skipped = ['__filename', '__dirname'];
38
+ const skippedParams = node.params.filter(param => param.type === 'Identifier' && skipped.includes(param.name));
39
+ const skippedFuncIdentifier = node.id?.type === 'Identifier' && skipped.includes(node.id.name);
40
+ if (skippedParams.length || skippedFuncIdentifier) {
41
+ this.skip();
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Check for assignment to `import.meta.url`.
47
+ */
48
+ if (node.type === 'AssignmentExpression' && node.left.type === 'MemberExpression' && node.left.object.type === 'MetaProperty' && node.left.property.type === 'Identifier' && node.left.property.name === 'url') {
49
+ if (node.right.type === 'Literal' && typeof node.right.value === 'string') {
50
+ if (!isValidUrl(node.right.value)) {
51
+ const rhs = code.snip(node.right.start, node.right.end).toString();
52
+ const assignment = code.snip(node.start, node.end).toString();
53
+ code.update(node.start, node.end, `/* Invalid assignment: ${rhs} is not a URL. ${assignment} */`);
54
+ this.skip();
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Skip module scope CJS globals when they are object properties.
61
+ * Ignoring `exports` here.
62
+ */
63
+ if (node.type === 'MemberExpression' && node.property.type === 'Identifier' && ['__filename', '__dirname'].includes(node.property.name)) {
64
+ this.skip();
65
+ }
66
+
67
+ /**
68
+ * Check for bare `module.exports` expressions.
69
+ */
70
+ if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'module' && node.property.type === 'Identifier' && node.property.name === 'exports' && parent?.type === 'ExpressionStatement') {
71
+ if (opts.target === 'module') {
72
+ code.update(node.start, node.end, ';');
73
+ // Prevent parsing the `exports` identifier again.
74
+ this.skip();
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Format `module.exports` and `exports` assignments.
80
+ */
81
+ if (node.type === 'AssignmentExpression') {
82
+ await assignmentExpression({
83
+ node,
84
+ parent,
85
+ code,
86
+ opts,
87
+ meta: exportsMeta
88
+ });
89
+ }
90
+ if (node.type === 'MetaProperty') {
91
+ metaProperty(node, parent, code, opts);
92
+ }
93
+ if (node.type === 'MemberExpression') {
94
+ memberExpression(node, parent, code, opts);
95
+ }
96
+ if (isIdentifierName(node)) {
97
+ identifier({
98
+ node,
99
+ ancestors,
100
+ code,
101
+ opts,
102
+ meta: exportsMeta
103
+ });
104
+ }
31
105
  }
32
106
  });
33
- return src;
34
- };
107
+ return code.toString();
108
+ };
109
+ export { format };
@@ -0,0 +1,12 @@
1
+ import MagicString from 'magic-string';
2
+ import type { Node, AssignmentExpression } from 'oxc-parser';
3
+ import type { FormatterOptions, ExportsMeta } from '../types.js';
4
+ type AssignmentExpressionArg = {
5
+ node: AssignmentExpression;
6
+ parent: Node | null;
7
+ code: MagicString;
8
+ opts: FormatterOptions;
9
+ meta: ExportsMeta;
10
+ };
11
+ export declare const assignmentExpression: ({ node, parent: _parent, code: _code, opts, meta: _meta, }: AssignmentExpressionArg) => Promise<void>;
12
+ export {};
@@ -0,0 +1,30 @@
1
+ import { walk } from '../walk.js';
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,5 +1,4 @@
1
1
  import MagicString from 'magic-string';
2
- import type { NodePath } from '@babel/traverse';
3
- import type { ExpressionStatement } from '@babel/types';
2
+ import type { Node, ExpressionStatement } from 'oxc-parser';
4
3
  import type { FormatterOptions } from '../types.js';
5
- export declare const expressionStatement: (nodePath: NodePath<ExpressionStatement>, src: MagicString, options: FormatterOptions) => void;
4
+ export declare const expressionStatement: (node: ExpressionStatement, parent: Node | null, src: MagicString, options: FormatterOptions) => void;
@@ -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,5 +1,12 @@
1
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;
2
+ import type { Node, IdentifierName } from 'oxc-parser';
3
+ import type { FormatterOptions, ExportsMeta } from '../types.js';
4
+ type IdentifierArg = {
5
+ node: IdentifierName;
6
+ ancestors: Node[];
7
+ code: MagicString;
8
+ opts: FormatterOptions;
9
+ meta: ExportsMeta;
10
+ };
11
+ export declare const identifier: ({ node, ancestors, code, opts, meta }: IdentifierArg) => void;
12
+ export {};
@@ -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.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,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.js';
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,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.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,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.js';
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;
@@ -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,31 @@
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 };