@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.
- package/README.md +28 -16
- package/dist/assignmentExpression.d.ts +12 -0
- package/dist/cjs/assignmentExpression.d.cts +12 -0
- package/dist/cjs/exports.d.cts +6 -0
- package/dist/cjs/expressionStatement.d.cts +2 -3
- package/dist/cjs/format.cjs +133 -26
- package/dist/cjs/format.d.cts +6 -6
- package/dist/cjs/formatters/assignmentExpression.cjs +37 -0
- package/dist/cjs/formatters/expressionStatement.cjs +36 -55
- package/dist/cjs/formatters/identifier.cjs +31 -31
- package/dist/cjs/formatters/memberExpression.cjs +24 -11
- package/dist/cjs/formatters/metaProperty.cjs +23 -35
- package/dist/cjs/helpers/identifier.cjs +132 -0
- package/dist/cjs/helpers/scope.cjs +12 -0
- package/dist/cjs/identifier.d.cts +31 -5
- package/dist/cjs/identifiers.d.cts +19 -0
- package/dist/cjs/lang.d.cts +4 -0
- package/dist/cjs/memberExpression.d.cts +2 -3
- package/dist/cjs/metaProperty.d.cts +2 -3
- package/dist/cjs/module.cjs +26 -27
- package/dist/cjs/parse.cjs +3 -14
- package/dist/cjs/parse.d.cts +1 -1
- package/dist/cjs/scope.d.cts +6 -0
- package/dist/cjs/types.d.cts +40 -4
- package/dist/cjs/url.d.cts +2 -0
- package/dist/cjs/utils/exports.cjs +227 -0
- package/dist/cjs/utils/identifiers.cjs +190 -0
- package/dist/cjs/utils/lang.cjs +25 -0
- package/dist/cjs/utils/url.cjs +16 -0
- package/dist/cjs/utils.cjs +288 -0
- package/dist/cjs/utils.d.cts +26 -0
- package/dist/cjs/walk.cjs +75 -0
- package/dist/cjs/walk.d.cts +20 -0
- package/dist/exports.d.ts +6 -0
- package/dist/expressionStatement.d.ts +2 -3
- package/dist/format.d.ts +6 -6
- package/dist/format.js +135 -27
- package/dist/formatters/assignmentExpression.js +30 -0
- package/dist/formatters/expressionStatement.js +36 -55
- package/dist/formatters/identifier.js +31 -31
- package/dist/formatters/memberExpression.js +24 -11
- package/dist/formatters/metaProperty.js +23 -35
- package/dist/helpers/identifier.js +127 -0
- package/dist/helpers/scope.js +7 -0
- package/dist/identifier.d.ts +31 -5
- package/dist/identifiers.d.ts +19 -0
- package/dist/lang.d.ts +4 -0
- package/dist/memberExpression.d.ts +2 -3
- package/dist/metaProperty.d.ts +2 -3
- package/dist/module.js +26 -27
- package/dist/parse.d.ts +1 -1
- package/dist/parse.js +3 -14
- package/dist/scope.d.ts +6 -0
- package/dist/src/format.d.ts +9 -0
- package/dist/src/formatters/assignmentExpression.d.ts +12 -0
- package/dist/src/formatters/expressionStatement.d.ts +4 -0
- package/dist/src/formatters/identifier.d.ts +12 -0
- package/dist/src/formatters/memberExpression.d.ts +4 -0
- package/dist/src/formatters/metaProperty.d.ts +4 -0
- package/dist/src/helpers/identifier.d.ts +31 -0
- package/dist/src/helpers/scope.d.ts +6 -0
- package/dist/src/module.d.ts +3 -0
- package/dist/src/parse.d.ts +2 -0
- package/dist/src/types.d.ts +43 -0
- package/dist/src/utils/exports.d.ts +6 -0
- package/dist/src/utils/identifiers.d.ts +19 -0
- package/dist/src/utils/lang.d.ts +4 -0
- package/dist/src/utils/url.d.ts +2 -0
- package/dist/src/utils.d.ts +26 -0
- package/dist/src/walk.d.ts +20 -0
- package/dist/types.d.ts +40 -4
- package/dist/url.d.ts +2 -0
- package/dist/utils/exports.js +221 -0
- package/dist/utils/identifiers.js +183 -0
- package/dist/utils/lang.js +20 -0
- package/dist/utils/url.js +10 -0
- package/dist/utils.d.ts +26 -0
- package/dist/utils.js +278 -0
- package/dist/walk.d.ts +20 -0
- package/dist/walk.js +69 -0
- package/package.json +43 -25
- package/dist/formatters/expressionStatement.d.ts +0 -5
- package/dist/formatters/identifier.d.ts +0 -5
- package/dist/formatters/memberExpression.d.ts +0 -5
- 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
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
|
14
|
-
const
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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 = (
|
|
2
|
-
if (options.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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 = (
|
|
2
|
-
if (options.
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 };
|
package/dist/identifier.d.ts
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 };
|