@wyw-in-js/transform 2.0.0-alpha.1 → 2.0.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.
- package/esm/transform/Entrypoint.types.js.map +1 -1
- package/esm/transform/generators/collect.js +1 -0
- package/esm/transform/generators/collect.js.map +1 -1
- package/esm/transform/generators/resolveStaticOxcValues/prune.js +91 -5
- package/esm/transform/generators/resolveStaticOxcValues/prune.js.map +1 -1
- package/esm/transform/generators/resolveStaticOxcValues/resolveStaticOxcPreevalValues.js +2 -1
- package/esm/transform/generators/resolveStaticOxcValues/resolveStaticOxcPreevalValues.js.map +1 -1
- package/esm/transform/generators/transform.js +1 -0
- package/esm/transform/generators/transform.js.map +1 -1
- package/esm/utils/EventEmitter.js +13 -0
- package/esm/utils/EventEmitter.js.map +1 -1
- package/esm/utils/applyOxcProcessors/applyOxcProcessors.js +1 -1
- package/esm/utils/applyOxcProcessors/applyOxcProcessors.js.map +1 -1
- package/esm/utils/applyOxcProcessors/cleanupRemovals.js +102 -16
- package/esm/utils/applyOxcProcessors/cleanupRemovals.js.map +1 -1
- package/esm/utils/collectOxcExportsAndImports.js +8 -0
- package/esm/utils/collectOxcExportsAndImports.js.map +1 -1
- package/esm/utils/collectOxcRuntime/types.js.map +1 -1
- package/esm/utils/oxc/ast.js +42 -12
- package/esm/utils/oxc/ast.js.map +1 -1
- package/esm/utils/oxcPreevalTransforms.js +94 -65
- package/esm/utils/oxcPreevalTransforms.js.map +1 -1
- package/esm/utils/parseOxc.js +6 -1
- package/esm/utils/parseOxc.js.map +1 -1
- package/package.json +5 -5
- package/types/transform/Entrypoint.types.d.ts +1 -0
- package/types/transform/generators/collect.js +1 -0
- package/types/transform/generators/resolveStaticOxcValues/prune.d.ts +1 -1
- package/types/transform/generators/resolveStaticOxcValues/prune.js +96 -4
- package/types/transform/generators/resolveStaticOxcValues/resolveStaticOxcPreevalValues.js +2 -1
- package/types/transform/generators/transform.js +1 -0
- package/types/utils/EventEmitter.js +13 -0
- package/types/utils/applyOxcProcessors/applyOxcProcessors.d.ts +1 -0
- package/types/utils/applyOxcProcessors/applyOxcProcessors.js +3 -1
- package/types/utils/applyOxcProcessors/cleanupRemovals.d.ts +2 -2
- package/types/utils/applyOxcProcessors/cleanupRemovals.js +104 -19
- package/types/utils/collectOxcExportsAndImports.js +8 -0
- package/types/utils/collectOxcRuntime/types.d.ts +1 -0
- package/types/utils/oxc/ast.js +42 -18
- package/types/utils/oxcPreevalTransforms.js +97 -74
- package/types/utils/parseOxc.js +6 -1
package/esm/utils/oxc/ast.js
CHANGED
|
@@ -1,28 +1,58 @@
|
|
|
1
1
|
export const isOxcNode = (value) => !!value && typeof value === "object" && "type" in value && typeof value.type === "string";
|
|
2
|
+
// Cache visitor-key lists per node.type. oxc-parser AST nodes have a stable
|
|
3
|
+
// shape per `type` — optional children are present as null/undefined, not
|
|
4
|
+
// omitted — so Object.keys() returns the same key set for every instance of
|
|
5
|
+
// the same kind. First instance pays the discovery cost; the rest do an
|
|
6
|
+
// indexed lookup. getOxcNodeChildren is invoked tens of millions of times
|
|
7
|
+
// on a cold build of a large monorepo, so this matters a lot.
|
|
8
|
+
//
|
|
9
|
+
// An instance-level WeakMap cache of the resulting Node[] was tried and
|
|
10
|
+
// regressed wall time ~20% (WeakMap.get/set per call beat the recompute
|
|
11
|
+
// savings for small children arrays + pinned arrays into older generations
|
|
12
|
+
// and increased GC pressure). Per-type key cache only.
|
|
13
|
+
const META_KEYS = new Set([
|
|
14
|
+
"comments",
|
|
15
|
+
"end",
|
|
16
|
+
"errors",
|
|
17
|
+
"parent",
|
|
18
|
+
"range",
|
|
19
|
+
"span",
|
|
20
|
+
"start",
|
|
21
|
+
"type"
|
|
22
|
+
]);
|
|
23
|
+
const VISITOR_KEYS_BY_TYPE = new Map();
|
|
24
|
+
const visitorKeysFor = (node) => {
|
|
25
|
+
let keys = VISITOR_KEYS_BY_TYPE.get(node.type);
|
|
26
|
+
if (keys === undefined) {
|
|
27
|
+
keys = Object.keys(node).filter((key) => !META_KEYS.has(key));
|
|
28
|
+
VISITOR_KEYS_BY_TYPE.set(node.type, keys);
|
|
29
|
+
}
|
|
30
|
+
return keys;
|
|
31
|
+
};
|
|
2
32
|
export const getOxcNodeChildren = (node) => {
|
|
3
33
|
const result = [];
|
|
4
34
|
const record = node;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
const value = record[key];
|
|
35
|
+
const keys = visitorKeysFor(record);
|
|
36
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
37
|
+
const value = record[keys[i]];
|
|
10
38
|
if (isOxcNode(value)) {
|
|
11
39
|
result.push(value);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
value.forEach((item) => {
|
|
40
|
+
} else if (Array.isArray(value)) {
|
|
41
|
+
for (let j = 0; j < value.length; j += 1) {
|
|
42
|
+
const item = value[j];
|
|
16
43
|
if (isOxcNode(item)) {
|
|
17
44
|
result.push(item);
|
|
18
45
|
}
|
|
19
|
-
}
|
|
46
|
+
}
|
|
20
47
|
}
|
|
21
|
-
}
|
|
48
|
+
}
|
|
22
49
|
return result;
|
|
23
50
|
};
|
|
24
51
|
export const walkOxc = (node, enter, parent = null) => {
|
|
25
52
|
enter(node, parent);
|
|
26
|
-
|
|
53
|
+
const children = getOxcNodeChildren(node);
|
|
54
|
+
for (let i = 0; i < children.length; i += 1) {
|
|
55
|
+
walkOxc(children[i], enter, node);
|
|
56
|
+
}
|
|
27
57
|
};
|
|
28
58
|
//# sourceMappingURL=ast.js.map
|
package/esm/utils/oxc/ast.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAIA,OAAO,MAAM,aAAa,UACxB,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,UAAU,SACV,OAAQ,MAA6B,SAAS;
|
|
1
|
+
{"mappings":"AAIA,OAAO,MAAM,aAAa,UACxB,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,UAAU,SACV,OAAQ,MAA6B,SAAS;;;;;;;;;;;;AAahD,MAAM,YAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AACF,MAAM,uBAAuB,IAAI,KAAgC;AACjE,MAAM,kBAAkB,SAAwC;CAC9D,IAAI,OAAO,qBAAqB,IAAI,KAAK,KAAK;AAC9C,KAAI,SAAS,WAAW;AACtB,SAAO,OAAO,KAAK,KAAK,CAAC,QAAQ,QAAQ,CAAC,UAAU,IAAI,IAAI,CAAC;AAC7D,uBAAqB,IAAI,KAAK,MAAM,KAAK;;AAE3C,QAAO;;AAGT,OAAO,MAAM,sBAAsB,SAAuB;CACxD,MAAM,SAAiB,EAAE;CACzB,MAAM,SAAS;CACf,MAAM,OAAO,eAAe,OAAO;AACnC,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;EACvC,MAAM,QAAQ,OAAO,KAAK;AAC1B,MAAI,UAAU,MAAM,EAAE;AACpB,UAAO,KAAK,MAAM;aACT,MAAM,QAAQ,MAAM,EAAE;AAC/B,QAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;IACxC,MAAM,OAAO,MAAM;AACnB,QAAI,UAAU,KAAK,EAAE;AACnB,YAAO,KAAK,KAAK;;;;;AAKzB,QAAO;;AAGT,OAAO,MAAM,WACX,MACA,OACA,SAAsB,SACb;AACT,OAAM,MAAM,OAAO;CACnB,MAAM,WAAW,mBAAmB,KAAK;AACzC,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;AAC3C,UAAQ,SAAS,IAAI,OAAO,KAAK","names":[],"sources":["../../../src/utils/oxc/ast.ts"],"version":3,"sourcesContent":["import type { Node } from 'oxc-parser';\n\ntype AnyOxcNode = Node & Record<string, unknown>;\n\nexport const isOxcNode = (value: unknown): value is Node =>\n !!value &&\n typeof value === 'object' &&\n 'type' in value &&\n typeof (value as { type?: unknown }).type === 'string';\n\n// Cache visitor-key lists per node.type. oxc-parser AST nodes have a stable\n// shape per `type` — optional children are present as null/undefined, not\n// omitted — so Object.keys() returns the same key set for every instance of\n// the same kind. First instance pays the discovery cost; the rest do an\n// indexed lookup. getOxcNodeChildren is invoked tens of millions of times\n// on a cold build of a large monorepo, so this matters a lot.\n//\n// An instance-level WeakMap cache of the resulting Node[] was tried and\n// regressed wall time ~20% (WeakMap.get/set per call beat the recompute\n// savings for small children arrays + pinned arrays into older generations\n// and increased GC pressure). Per-type key cache only.\nconst META_KEYS = new Set([\n 'comments',\n 'end',\n 'errors',\n 'parent',\n 'range',\n 'span',\n 'start',\n 'type',\n]);\nconst VISITOR_KEYS_BY_TYPE = new Map<string, readonly string[]>();\nconst visitorKeysFor = (node: AnyOxcNode): readonly string[] => {\n let keys = VISITOR_KEYS_BY_TYPE.get(node.type);\n if (keys === undefined) {\n keys = Object.keys(node).filter((key) => !META_KEYS.has(key));\n VISITOR_KEYS_BY_TYPE.set(node.type, keys);\n }\n return keys;\n};\n\nexport const getOxcNodeChildren = (node: Node): Node[] => {\n const result: Node[] = [];\n const record = node as AnyOxcNode;\n const keys = visitorKeysFor(record);\n for (let i = 0; i < keys.length; i += 1) {\n const value = record[keys[i]];\n if (isOxcNode(value)) {\n result.push(value);\n } else if (Array.isArray(value)) {\n for (let j = 0; j < value.length; j += 1) {\n const item = value[j];\n if (isOxcNode(item)) {\n result.push(item);\n }\n }\n }\n }\n return result;\n};\n\nexport const walkOxc = (\n node: Node,\n enter: (node: Node, parent: Node | null) => void,\n parent: Node | null = null\n): void => {\n enter(node, parent);\n const children = getOxcNodeChildren(node);\n for (let i = 0; i < children.length; i += 1) {\n walkOxc(children[i], enter, node);\n }\n};\n"],"file":"ast.js"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { collectOxcExportsAndImports } from "./collectOxcExportsAndImports.js";
|
|
2
2
|
import { EventEmitter } from "./EventEmitter.js";
|
|
3
|
+
import { getOxcNodeChildren } from "./oxc/ast.js";
|
|
3
4
|
import { parseOxcProgramCached } from "./parseOxc.js";
|
|
4
5
|
const ssrCheckFields = new Set([
|
|
5
6
|
"document",
|
|
@@ -97,28 +98,11 @@ const getStaticBinding = (scope, name) => {
|
|
|
97
98
|
};
|
|
98
99
|
const isFileLikeRequireSpecifier = (value) => value.startsWith(".") || value.startsWith("/") || value.startsWith("file:");
|
|
99
100
|
const isNode = (value) => !!value && typeof value === "object" && "type" in value && typeof value.type === "string";
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const value = record[key];
|
|
108
|
-
if (isNode(value)) {
|
|
109
|
-
result.push(value);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (Array.isArray(value)) {
|
|
113
|
-
value.forEach((item) => {
|
|
114
|
-
if (isNode(item)) {
|
|
115
|
-
result.push(item);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
return result;
|
|
121
|
-
};
|
|
101
|
+
// Reuses the per-node.type visitor-key cache in utils/oxc/ast.ts. This file's
|
|
102
|
+
// getChildren shape historically diverged from the canonical one (a smaller
|
|
103
|
+
// metadata-key skip set), but the produced children list is identical in
|
|
104
|
+
// practice because oxc-parser nodes don't carry the extra metadata fields.
|
|
105
|
+
const getChildren = getOxcNodeChildren;
|
|
122
106
|
const parseOxc = (code, filename) => {
|
|
123
107
|
return parseOxcProgramCached(filename, code, "unambiguous");
|
|
124
108
|
};
|
|
@@ -314,57 +298,92 @@ const predeclareScopeNames = (node, scope) => {
|
|
|
314
298
|
});
|
|
315
299
|
}
|
|
316
300
|
const visitScopeDescendants = (child) => {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
301
|
+
switch (child.type) {
|
|
302
|
+
case "VariableDeclarator": {
|
|
303
|
+
const names = collectBindingNames(child.id);
|
|
304
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
305
|
+
scope.names.add(names[i]);
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case "FunctionDeclaration":
|
|
310
|
+
case "ClassDeclaration":
|
|
311
|
+
if (child.id) {
|
|
312
|
+
scope.names.add(child.id.name);
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
case "ImportDefaultSpecifier":
|
|
316
|
+
case "ImportNamespaceSpecifier":
|
|
317
|
+
case "ImportSpecifier":
|
|
318
|
+
scope.names.add(child.local.name);
|
|
319
|
+
break;
|
|
320
|
+
default: break;
|
|
327
321
|
}
|
|
328
322
|
if (createsScope(child)) {
|
|
329
323
|
return;
|
|
330
324
|
}
|
|
331
|
-
getChildren(child)
|
|
325
|
+
const children = getChildren(child);
|
|
326
|
+
for (let i = 0; i < children.length; i += 1) {
|
|
327
|
+
visitScopeDescendants(children[i]);
|
|
328
|
+
}
|
|
332
329
|
};
|
|
333
|
-
getChildren(node)
|
|
330
|
+
const rootChildren = getChildren(node);
|
|
331
|
+
for (let i = 0; i < rootChildren.length; i += 1) {
|
|
332
|
+
visitScopeDescendants(rootChildren[i]);
|
|
333
|
+
}
|
|
334
334
|
};
|
|
335
335
|
const declareBindings = (node, scope) => {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
if (node.type === "FunctionDeclaration" && node.id) {
|
|
348
|
-
scope.names.add(node.id.name);
|
|
349
|
-
scope.bindings.set(node.id.name, null);
|
|
350
|
-
}
|
|
351
|
-
if (node.type === "ClassDeclaration" && node.id) {
|
|
352
|
-
scope.names.add(node.id.name);
|
|
353
|
-
scope.bindings.set(node.id.name, null);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
if (node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier" || node.type === "ImportSpecifier") {
|
|
357
|
-
scope.names.add(node.local.name);
|
|
358
|
-
scope.bindings.set(node.local.name, null);
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
|
|
362
|
-
node.params.forEach((param) => {
|
|
363
|
-
collectBindingNames(param).forEach((name) => {
|
|
336
|
+
// Called for every visited AST node, so the dispatch is hot. A switch lets
|
|
337
|
+
// V8 generate a jump table on node.type; the previous chained `if`s walked
|
|
338
|
+
// each branch's string-compare for every non-matching node.
|
|
339
|
+
switch (node.type) {
|
|
340
|
+
case "VariableDeclarator": {
|
|
341
|
+
const names = collectBindingNames(node.id);
|
|
342
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
343
|
+
const name = names[i];
|
|
364
344
|
scope.names.add(name);
|
|
365
345
|
scope.bindings.set(name, null);
|
|
366
|
-
}
|
|
367
|
-
|
|
346
|
+
}
|
|
347
|
+
if (node.id.type === "Identifier" && node.init) {
|
|
348
|
+
scope.bindings.set(node.id.name, node.init);
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
case "ClassDeclaration": {
|
|
353
|
+
if (node.id) {
|
|
354
|
+
scope.names.add(node.id.name);
|
|
355
|
+
scope.bindings.set(node.id.name, null);
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
case "ImportDefaultSpecifier":
|
|
360
|
+
case "ImportNamespaceSpecifier":
|
|
361
|
+
case "ImportSpecifier": {
|
|
362
|
+
scope.names.add(node.local.name);
|
|
363
|
+
scope.bindings.set(node.local.name, null);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
case "FunctionDeclaration": {
|
|
367
|
+
if (node.id) {
|
|
368
|
+
scope.names.add(node.id.name);
|
|
369
|
+
scope.bindings.set(node.id.name, null);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// eslint-disable-next-line no-fallthrough
|
|
373
|
+
case "FunctionExpression":
|
|
374
|
+
case "ArrowFunctionExpression": {
|
|
375
|
+
const { params } = node;
|
|
376
|
+
for (let i = 0; i < params.length; i += 1) {
|
|
377
|
+
const names = collectBindingNames(params[i]);
|
|
378
|
+
for (let j = 0; j < names.length; j += 1) {
|
|
379
|
+
const name = names[j];
|
|
380
|
+
scope.names.add(name);
|
|
381
|
+
scope.bindings.set(name, null);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
default: break;
|
|
368
387
|
}
|
|
369
388
|
};
|
|
370
389
|
const visit = (node, scope, enter, parent = null, ancestors = []) => {
|
|
@@ -375,7 +394,17 @@ const visit = (node, scope, enter, parent = null, ancestors = []) => {
|
|
|
375
394
|
}
|
|
376
395
|
declareBindings(node, currentScope);
|
|
377
396
|
enter(node, currentScope, parent, ancestors);
|
|
378
|
-
|
|
397
|
+
// Push onto a shared ancestors stack instead of allocating `[...ancestors,
|
|
398
|
+
// node]` per child step (O(n × depth) extra allocation on deep ASTs).
|
|
399
|
+
// Every consumer of `ancestors` in this file reads it synchronously inside
|
|
400
|
+
// the enter callback; future callers that need to retain the reference
|
|
401
|
+
// must .slice() it themselves.
|
|
402
|
+
ancestors.push(node);
|
|
403
|
+
const children = getChildren(node);
|
|
404
|
+
for (let i = 0; i < children.length; i += 1) {
|
|
405
|
+
visit(children[i], currentScope, enter, node, ancestors);
|
|
406
|
+
}
|
|
407
|
+
ancestors.pop();
|
|
379
408
|
};
|
|
380
409
|
export const replaceImportMetaEnvWithOxc = (code, filename) => {
|
|
381
410
|
if (!importMetaEnvRe.test(code)) {
|