@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
package/README.md CHANGED
@@ -9,11 +9,10 @@ Node.js utility for transforming a JavaScript or TypeScript file from an ES modu
9
9
  - ES module ➡️ CommonJS
10
10
  - CommonJS ➡️ ES module
11
11
 
12
- By default `@knighted/module` transforms the one-to-one [differences between ES modules and CommonJS](https://nodejs.org/api/esm.html#differences-between-es-modules-and-commonjs), but it also accepts options that allow:
12
+ > [!IMPORTANT]
13
+ > All parsing logic is applied under the assumption the code is in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) which [modules run under by default](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#other_differences_between_modules_and_classic_scripts).
13
14
 
14
- - Converting `import`/`export` to `require`/`exports`
15
- - Extensions to be updated in relative specifiers
16
- - Write transformed source code to a filename
15
+ By default `@knighted/module` transforms the one-to-one [differences between ES modules and CommonJS](https://nodejs.org/api/esm.html#differences-between-es-modules-and-commonjs). Options let you control syntax rewriting, specifier updates, and output.
17
16
 
18
17
  ## Requirements
19
18
 
@@ -47,9 +46,8 @@ You can transform it to the equivalent CommonJS module
47
46
  import { transform } from '@knighted/module'
48
47
 
49
48
  await transform('./file.js', {
50
- type: 'commonjs'
51
- moduleLoading: true,
52
- out: './file.cjs'
49
+ target: 'commonjs',
50
+ out: './file.cjs',
53
51
  })
54
52
  ```
55
53
 
@@ -65,7 +63,10 @@ const { realpath } = require('node:fs/promises')
65
63
  const detectCalledFromCli = async path => {
66
64
  const realPath = await realpath(path)
67
65
 
68
- if (require('node:url').pathToFileURL(__filename).toString() === pathToFileURL(realPath).href) {
66
+ if (
67
+ require('node:url').pathToFileURL(__filename).toString() ===
68
+ pathToFileURL(realPath).href
69
+ ) {
69
70
  console.log('invoked directly by node')
70
71
  }
71
72
  }
@@ -84,18 +85,29 @@ invoked directly by node
84
85
 
85
86
  ```ts
86
87
  type ModuleOptions = {
87
- /* What module system to convert to. */
88
- type?: 'module' | 'commonjs'
89
- /* Whether import/export and require/exports should be transformed. */
90
- modules?: boolean
91
- /* Whether to change specifier extensions to the assigned value. If omitted they are left alone. */
92
- specifier?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts'
93
- /* What filepath to write the transformed source to. */
88
+ target: 'module' | 'commonjs'
89
+ sourceType?: 'auto' | 'module' | 'commonjs'
90
+ transformSyntax?: boolean
91
+ liveBindings?: 'strict' | 'loose' | 'off'
92
+ rewriteSpecifier?:
93
+ | '.js'
94
+ | '.mjs'
95
+ | '.cjs'
96
+ | '.ts'
97
+ | '.mts'
98
+ | '.cts'
99
+ | ((value: string) => string | null | undefined)
100
+ dirFilename?: 'inject' | 'preserve' | 'error'
101
+ importMeta?: 'preserve' | 'shim' | 'error'
102
+ requireSource?: 'builtin' | 'create-require'
103
+ cjsDefault?: 'module-exports' | 'auto' | 'none'
104
+ topLevelAwait?: 'error' | 'wrap' | 'preserve'
94
105
  out?: string
106
+ inPlace?: boolean
95
107
  }
96
108
  ```
97
109
 
98
110
  ## Roadmap
99
111
 
100
- - Support option `modules`.
101
112
  - Remove `@knighted/specifier` and avoid double parsing.
113
+ - Flesh out live-binding and top-level await handling.
@@ -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,12 @@
1
+ import MagicString from 'magic-string';
2
+ import type { Node, AssignmentExpression } from 'oxc-parser';
3
+ import type { FormatterOptions, ExportsMeta } from '../types.cjs';
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 {};
@@ -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.cjs';
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;
@@ -5,37 +5,111 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.format = void 0;
7
7
  var _magicString = _interopRequireDefault(require("magic-string"));
8
- var _traverse2 = _interopRequireDefault(require("@babel/traverse"));
9
- var _nodeModuleType = require("node-module-type");
10
8
  var _identifier = require("./formatters/identifier.cjs");
11
9
  var _metaProperty = require("./formatters/metaProperty.cjs");
12
10
  var _memberExpression = require("./formatters/memberExpression.cjs");
11
+ var _assignmentExpression = require("./formatters/assignmentExpression.cjs");
12
+ var _utils = require("./utils.cjs");
13
+ var _identifier2 = require("./helpers/identifier.cjs");
14
+ var _walk = require("./walk.cjs");
13
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
- /**
15
- * Runtime hack to prevent issues with babel's default interop while dual building with tsc.
16
- * @see https://github.com/babel/babel/discussions/13093#discussioncomment-12705927
17
- * Temporary fix until I switch to oxc-parser.
18
- */
19
- const type = (0, _nodeModuleType.moduleType)();
20
- const traverse = typeof _traverse2.default === 'function' || type === 'commonjs' ? _traverse2.default : _traverse2.default.default;
21
-
22
16
  /**
23
17
  * Note, there is no specific conversion for `import.meta.main` as it does not exist.
24
18
  * @see https://github.com/nodejs/node/issues/49440
25
19
  */
26
- const format = (code, ast, options) => {
27
- const src = new _magicString.default(code);
28
- traverse(ast, {
29
- Identifier(path) {
30
- (0, _identifier.identifier)(path, src, options);
31
- },
32
- MetaProperty(path) {
33
- (0, _metaProperty.metaProperty)(path, src, options);
34
- },
35
- MemberExpression(path) {
36
- (0, _memberExpression.memberExpression)(path, src, options);
20
+ const format = async (src, ast, opts) => {
21
+ const code = new _magicString.default(src);
22
+ const exportsMeta = {
23
+ hasExportsBeenReassigned: false,
24
+ defaultExportValue: undefined,
25
+ hasDefaultExportBeenReassigned: false,
26
+ hasDefaultExportBeenAssigned: false
27
+ };
28
+ await (0, _utils.collectModuleIdentifiers)(ast.program);
29
+ if (opts.target === 'module' && opts.transformSyntax) {
30
+ /**
31
+ * Prepare ESM output by renaming `exports` to `__exports` and seeding an
32
+ * `import.meta.filename` touch so import.meta is present even when the
33
+ * original source never referenced it.
34
+ */
35
+ code.prepend(`let ${_utils.exportsRename} = {};
36
+ void import.meta.filename;
37
+ `);
38
+ }
39
+ await (0, _walk.ancestorWalk)(ast.program, {
40
+ async enter(node, ancestors) {
41
+ const parent = ancestors[ancestors.length - 2] ?? null;
42
+ if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
43
+ const skipped = ['__filename', '__dirname'];
44
+ const skippedParams = node.params.filter(param => param.type === 'Identifier' && skipped.includes(param.name));
45
+ const skippedFuncIdentifier = node.id?.type === 'Identifier' && skipped.includes(node.id.name);
46
+ if (skippedParams.length || skippedFuncIdentifier) {
47
+ this.skip();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Check for assignment to `import.meta.url`.
53
+ */
54
+ if (node.type === 'AssignmentExpression' && node.left.type === 'MemberExpression' && node.left.object.type === 'MetaProperty' && node.left.property.type === 'Identifier' && node.left.property.name === 'url') {
55
+ if (node.right.type === 'Literal' && typeof node.right.value === 'string') {
56
+ if (!(0, _utils.isValidUrl)(node.right.value)) {
57
+ const rhs = code.snip(node.right.start, node.right.end).toString();
58
+ const assignment = code.snip(node.start, node.end).toString();
59
+ code.update(node.start, node.end, `/* Invalid assignment: ${rhs} is not a URL. ${assignment} */`);
60
+ this.skip();
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Skip module scope CJS globals when they are object properties.
67
+ * Ignoring `exports` here.
68
+ */
69
+ if (node.type === 'MemberExpression' && node.property.type === 'Identifier' && ['__filename', '__dirname'].includes(node.property.name)) {
70
+ this.skip();
71
+ }
72
+
73
+ /**
74
+ * Check for bare `module.exports` expressions.
75
+ */
76
+ if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'module' && node.property.type === 'Identifier' && node.property.name === 'exports' && parent?.type === 'ExpressionStatement') {
77
+ if (opts.target === 'module') {
78
+ code.update(node.start, node.end, ';');
79
+ // Prevent parsing the `exports` identifier again.
80
+ this.skip();
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Format `module.exports` and `exports` assignments.
86
+ */
87
+ if (node.type === 'AssignmentExpression') {
88
+ await (0, _assignmentExpression.assignmentExpression)({
89
+ node,
90
+ parent,
91
+ code,
92
+ opts,
93
+ meta: exportsMeta
94
+ });
95
+ }
96
+ if (node.type === 'MetaProperty') {
97
+ (0, _metaProperty.metaProperty)(node, parent, code, opts);
98
+ }
99
+ if (node.type === 'MemberExpression') {
100
+ (0, _memberExpression.memberExpression)(node, parent, code, opts);
101
+ }
102
+ if ((0, _identifier2.isIdentifierName)(node)) {
103
+ (0, _identifier.identifier)({
104
+ node,
105
+ ancestors,
106
+ code,
107
+ opts,
108
+ meta: exportsMeta
109
+ });
110
+ }
37
111
  }
38
112
  });
39
- return src;
113
+ return code.toString();
40
114
  };
41
115
  exports.format = format;
@@ -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.cjs';
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 };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.assignmentExpression = void 0;
7
+ var _walk = require("../walk.cjs");
8
+ const assignmentExpression = async ({
9
+ node,
10
+ parent: _parent,
11
+ code: _code,
12
+ opts,
13
+ meta: _meta
14
+ }) => {
15
+ if (opts.target === 'module' && opts.transformSyntax) {
16
+ await (0, _walk.walk)(node, {
17
+ enter(childNode, childParent) {
18
+ if (childNode.type === 'Identifier' && childNode.name === 'exports') {
19
+ if (childParent === node && node.left === childNode) {
20
+ /**
21
+ * The code is reassigning `exports` to something else.
22
+ * Redeclare it with a new variable name using var.
23
+ */
24
+ //meta.hasExportsBeenReassigned = true
25
+ //console.log('writing exports reassignment')
26
+ //code.update(node.left.start, node.left.end, exportsRename)
27
+ //console.log(code.slice(node.start, node.end))
28
+ //code.update(childNode.start, childNode.end, exportsRename)
29
+ //console.log('reassigning exports', childParent, code.update(node.left.start, node.left.end, exportsRename))
30
+ }
31
+ //console.log('found exports assignment', meta.hasExportsBeenReassigned, expr)
32
+ }
33
+ }
34
+ });
35
+ }
36
+ };
37
+ exports.assignmentExpression = assignmentExpression;
@@ -4,64 +4,45 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.expressionStatement = void 0;
7
- const expressionStatement = (nodePath, src, options) => {
8
- if (options.type === 'module') {
9
- const {
10
- node
11
- } = nodePath;
12
- const {
13
- start,
14
- end
15
- } = node;
16
- if (typeof start === 'number' && typeof end === 'number') {
17
- const isMemberExpressionModuleExports = expression => {
18
- return expression.object.type === 'Identifier' && expression.object.name === 'module' && expression.property.type === 'Identifier' && expression.property.name === 'exports';
19
- };
20
- if (node.expression.type === 'Identifier') {
21
- const name = node.expression.name;
7
+ const expressionStatement = (node, parent, src, options) => {
8
+ if (options.target === 'module') {
9
+ if (node.expression.type === 'Identifier') {
10
+ const {
11
+ start,
12
+ end
13
+ } = node;
14
+ const name = node.expression.name;
22
15
 
23
- // CommonJS globals
24
- switch (name) {
25
- case 'module':
26
- src.update(start, end, 'import.meta');
27
- break;
28
- case 'exports':
29
- src.update(start, end, '{}');
30
- break;
31
- case '__filename':
32
- src.update(start, end, 'import.meta.filename');
33
- break;
34
- case '__dirname':
35
- src.update(start, end, 'import.meta.dirname');
36
- break;
37
- }
38
- }
39
- if (node.expression.type === 'MemberExpression') {
40
- const {
41
- expression
42
- } = node;
43
-
44
- // Check for `module.exports` without an assignment
45
- if (isMemberExpressionModuleExports(expression)) {
46
- /**
47
- * @TODO: Should this depend on `options.modules` being enabled?
48
- * Probably not for the same reason `exports` is converted to an empty object (ReferenceError in ESM).
49
- * This is a standalone reference to `module.exports` without being part of an AssignmentExpression.
50
- */
16
+ // CommonJS globals (as bare identifiers)
17
+ switch (name) {
18
+ case 'require':
19
+ src.remove(start, end);
20
+ break;
21
+ case 'module':
22
+ src.update(start, end, 'import.meta');
23
+ break;
24
+ case 'exports':
51
25
  src.update(start, end, '{}');
52
- }
53
- }
54
-
55
- /*
56
- if (
57
- options.modules &&
58
- node.expression.type === 'AssignmentExpression' &&
59
- node.expression.left.type === 'MemberExpression' &&
60
- isMemberExpressionModuleExports(node.expression.left)
61
- ) {
62
- // @TODO support `modules` option.
26
+ break;
27
+ case '__filename':
28
+ src.update(start, end, 'import.meta.filename');
29
+ break;
30
+ case '__dirname':
31
+ src.update(start, end, 'import.meta.dirname');
32
+ break;
63
33
  }
64
- */
34
+ }
35
+ }
36
+ if (options.target === 'commonjs') {
37
+ if (node.expression.type === 'Identifier') {
38
+ const {
39
+ start,
40
+ end
41
+ } = node;
42
+ const name = node.expression.name;
43
+ void start;
44
+ void end;
45
+ void name;
65
46
  }
66
47
  }
67
48
  };
@@ -4,44 +4,44 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.identifier = void 0;
7
- const identifier = (nodePath, src, options) => {
8
- if (options.type === 'module') {
9
- const {
10
- node
11
- } = nodePath;
7
+ var _utils = require("../utils.cjs");
8
+ var _identifier = require("../helpers/identifier.cjs");
9
+ const identifier = ({
10
+ node,
11
+ ancestors,
12
+ code,
13
+ opts,
14
+ meta
15
+ }) => {
16
+ if (opts.target === 'module') {
12
17
  const {
13
18
  start,
14
- end
19
+ end,
20
+ name
15
21
  } = node;
16
- if (typeof start === 'number' && typeof end === 'number' && node.type === 'Identifier') {
17
- const {
18
- name
19
- } = node;
20
- const isMemberExpression = Boolean(nodePath.findParent(path => path.isMemberExpression()));
22
+ switch (name) {
23
+ case '__filename':
24
+ code.update(start, end, 'import.meta.url');
25
+ break;
26
+ case '__dirname':
27
+ code.update(start, end, 'import.meta.dirname');
28
+ break;
29
+ case 'exports':
30
+ {
31
+ const parent = ancestors[ancestors.length - 2];
32
+ if (opts.transformSyntax) {
33
+ if (parent.type === 'AssignmentExpression' && parent.left === node) {
34
+ // The code is reassigning `exports` to something else.
21
35
 
22
- // CommonJS globals in expression/statement
23
- switch (name) {
24
- case 'module':
25
- {
26
- if (!isMemberExpression) {
27
- src.update(start, end, 'import.meta');
36
+ meta.hasExportsBeenReassigned = true;
37
+ code.update(parent.left.start, parent.left.end, _utils.exportsRename);
28
38
  }
29
- break;
30
- }
31
- case 'exports':
32
- {
33
- if (!isMemberExpression) {
34
- src.update(start, end, '{}');
39
+ if (_identifier.identifier.isModuleScope(ancestors) && !_identifier.identifier.isFunctionExpressionId(ancestors) && !_identifier.identifier.isExportSpecifierAlias(ancestors) && !_identifier.identifier.isClassPropertyKey(ancestors) && !_identifier.identifier.isMethodDefinitionKey(ancestors) && !_identifier.identifier.isMemberKey(ancestors) && !_identifier.identifier.isPropertyKey(ancestors) && !_identifier.identifier.isIife(ancestors)) {
40
+ code.update(start, end, _utils.exportsRename);
35
41
  }
36
- break;
37
42
  }
38
- case '__filename':
39
- src.update(start, end, 'import.meta.filename');
40
- break;
41
- case '__dirname':
42
- src.update(start, end, 'import.meta.dirname');
43
- break;
44
- }
43
+ }
44
+ break;
45
45
  }
46
46
  }
47
47
  };
@@ -4,16 +4,18 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.memberExpression = void 0;
7
- const memberExpression = (nodePath, src, options) => {
8
- if (options.type === 'module') {
9
- const {
10
- node
11
- } = nodePath;
12
- const {
13
- start,
14
- end
15
- } = node;
16
- if (typeof start === 'number' && typeof end === 'number' && node.object.type === 'Identifier' && node.object.name === 'require' && node.property.type === 'Identifier') {
7
+ var _utils = require("../utils.cjs");
8
+ const memberExpression = (node, parent, src, options) => {
9
+ if (options.target === 'module') {
10
+ if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'exports') {
11
+ src.update(node.start, node.end, _utils.exportsRename);
12
+ return;
13
+ }
14
+ if (node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'require') {
15
+ const {
16
+ start,
17
+ end
18
+ } = node;
17
19
  const {
18
20
  name
19
21
  } = node.property;
@@ -21,7 +23,18 @@ const memberExpression = (nodePath, src, options) => {
21
23
  // CommonJS properties of `require`
22
24
  switch (name) {
23
25
  case 'main':
24
- src.update(start, end, 'import.meta');
26
+ /**
27
+ * Node.js team still quibbling over import.meta.main ¯\_(ツ)_/¯
28
+ * @see https://github.com/nodejs/node/pull/32223
29
+ */
30
+ if (parent?.type === 'ExpressionStatement') {
31
+ // This is a standalone expression so remove it to not cause run-time errors.
32
+ src.remove(start, end);
33
+ }
34
+ /**
35
+ * Transform require.main === module.
36
+ */
37
+ if (parent?.type === 'BinaryExpression') {}
25
38
  break;
26
39
  case 'resolve':
27
40
  src.update(start, end, 'import.meta.resolve');
@@ -4,45 +4,33 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.metaProperty = void 0;
7
- const metaProperty = (nodePath, src, options) => {
8
- if (options.type === 'commonjs') {
9
- const path = nodePath.findParent(path => path.isMemberExpression());
10
- if (path) {
11
- const {
12
- node
13
- } = path;
14
- const {
15
- start,
16
- end
17
- } = node;
18
- if (node.type === 'MemberExpression' && node.property.type === 'Identifier' && typeof start == 'number' && typeof end === 'number') {
19
- const name = node.property.name;
20
- switch (name) {
21
- case 'url':
22
- src.update(start, end, 'require("node:url").pathToFileURL(__filename).toString()');
23
- break;
24
- case 'filename':
25
- src.update(start, end, '__filename');
26
- break;
27
- case 'dirname':
28
- src.update(start, end, '__dirname');
29
- break;
30
- case 'resolve':
31
- src.update(start, end, 'require.resolve');
32
- break;
33
- }
34
- }
35
- } else {
36
- const {
37
- node
38
- } = nodePath;
7
+ const metaProperty = (node, parent, src, options) => {
8
+ if (options.target === 'commonjs') {
9
+ if (parent?.type !== 'MemberExpression') {
10
+ // This is a bare `import.meta` expression
39
11
  const {
40
12
  start,
41
13
  end
42
14
  } = node;
43
- if (node.property.type === 'Identifier' && node.property.name === 'meta' && typeof start === 'number' && typeof end === 'number') {
44
- // This is an `import.meta` expression
45
- src.update(start, end, 'require.main');
15
+ src.update(start, end, 'module');
16
+ }
17
+ if (parent?.type === 'MemberExpression' && parent.property.type === 'Identifier') {
18
+ switch (parent.property.name) {
19
+ case 'url':
20
+ src.update(parent.start, parent.end, 'require("node:url").pathToFileURL(__filename).href');
21
+ break;
22
+ case 'filename':
23
+ src.update(parent.start, parent.end, '__filename');
24
+ break;
25
+ case 'dirname':
26
+ src.update(parent.start, parent.end, '__dirname');
27
+ break;
28
+ case 'resolve':
29
+ /**
30
+ * Should this be `require('node:url').pathToFileURL(require.resolve(<parsed specifier>)).href`?
31
+ */
32
+ src.update(parent.start, parent.end, 'require.resolve');
33
+ break;
46
34
  }
47
35
  }
48
36
  }