@wyw-in-js/transform 1.0.6 → 1.0.8
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/cache.js +160 -12
- package/esm/cache.js.map +1 -1
- package/esm/debug/fileReporter.js.map +1 -1
- package/esm/module.js +59 -5
- package/esm/module.js.map +1 -1
- package/esm/plugins/shaker.js +152 -13
- package/esm/plugins/shaker.js.map +1 -1
- package/esm/shaker.js +51 -23
- package/esm/shaker.js.map +1 -1
- package/esm/transform/BaseEntrypoint.js +3 -1
- package/esm/transform/BaseEntrypoint.js.map +1 -1
- package/esm/transform/Entrypoint.js +68 -20
- package/esm/transform/Entrypoint.js.map +1 -1
- package/esm/transform/EvaluatedEntrypoint.js.map +1 -1
- package/esm/transform/actions/BaseAction.js +2 -1
- package/esm/transform/actions/BaseAction.js.map +1 -1
- package/esm/transform/actions/actionRunner.js +2 -2
- package/esm/transform/actions/actionRunner.js.map +1 -1
- package/esm/transform/barrelManifest.js +291 -0
- package/esm/transform/barrelManifest.js.map +1 -0
- package/esm/transform/generators/getExports.js +5 -0
- package/esm/transform/generators/getExports.js.map +1 -1
- package/esm/transform/generators/processEntrypoint.js +31 -1
- package/esm/transform/generators/processEntrypoint.js.map +1 -1
- package/esm/transform/generators/resolveImports.js +29 -5
- package/esm/transform/generators/resolveImports.js.map +1 -1
- package/esm/transform/generators/rewriteBarrelImports.js +733 -0
- package/esm/transform/generators/rewriteBarrelImports.js.map +1 -0
- package/esm/transform/generators/transform.js +154 -21
- package/esm/transform/generators/transform.js.map +1 -1
- package/esm/transform/types.js.map +1 -1
- package/esm/transform.js +45 -23
- package/esm/transform.js.map +1 -1
- package/esm/utils/collectTemplateDependencies.js +9 -0
- package/esm/utils/collectTemplateDependencies.js.map +1 -1
- package/lib/cache.js +163 -12
- package/lib/cache.js.map +1 -1
- package/lib/debug/fileReporter.js.map +1 -1
- package/lib/module.js +61 -7
- package/lib/module.js.map +1 -1
- package/lib/plugins/shaker.js +152 -13
- package/lib/plugins/shaker.js.map +1 -1
- package/lib/shaker.js +58 -26
- package/lib/shaker.js.map +1 -1
- package/lib/transform/BaseEntrypoint.js +3 -1
- package/lib/transform/BaseEntrypoint.js.map +1 -1
- package/lib/transform/Entrypoint.js +69 -20
- package/lib/transform/Entrypoint.js.map +1 -1
- package/lib/transform/EvaluatedEntrypoint.js.map +1 -1
- package/lib/transform/actions/BaseAction.js +2 -1
- package/lib/transform/actions/BaseAction.js.map +1 -1
- package/lib/transform/actions/actionRunner.js +2 -2
- package/lib/transform/actions/actionRunner.js.map +1 -1
- package/lib/transform/barrelManifest.js +300 -0
- package/lib/transform/barrelManifest.js.map +1 -0
- package/lib/transform/generators/getExports.js +5 -0
- package/lib/transform/generators/getExports.js.map +1 -1
- package/lib/transform/generators/processEntrypoint.js +31 -1
- package/lib/transform/generators/processEntrypoint.js.map +1 -1
- package/lib/transform/generators/resolveImports.js +29 -5
- package/lib/transform/generators/resolveImports.js.map +1 -1
- package/lib/transform/generators/rewriteBarrelImports.js +743 -0
- package/lib/transform/generators/rewriteBarrelImports.js.map +1 -0
- package/lib/transform/generators/transform.js +158 -22
- package/lib/transform/generators/transform.js.map +1 -1
- package/lib/transform/types.js.map +1 -1
- package/lib/transform.js +45 -23
- package/lib/transform.js.map +1 -1
- package/lib/utils/collectTemplateDependencies.js +9 -0
- package/lib/utils/collectTemplateDependencies.js.map +1 -1
- package/package.json +8 -4
- package/types/cache.d.ts +23 -2
- package/types/cache.js +170 -10
- package/types/debug/fileReporter.d.ts +1 -0
- package/types/module.d.ts +3 -0
- package/types/module.js +65 -5
- package/types/plugins/shaker.js +161 -16
- package/types/shaker.d.ts +10 -1
- package/types/shaker.js +56 -28
- package/types/transform/BaseEntrypoint.d.ts +3 -1
- package/types/transform/BaseEntrypoint.js +5 -1
- package/types/transform/Entrypoint.d.ts +10 -1
- package/types/transform/Entrypoint.js +81 -23
- package/types/transform/EvaluatedEntrypoint.d.ts +2 -0
- package/types/transform/actions/BaseAction.d.ts +2 -1
- package/types/transform/actions/BaseAction.js +3 -1
- package/types/transform/actions/actionRunner.js +2 -2
- package/types/transform/barrelManifest.d.ts +42 -0
- package/types/transform/barrelManifest.js +300 -0
- package/types/transform/generators/getExports.js +5 -0
- package/types/transform/generators/processEntrypoint.js +29 -1
- package/types/transform/generators/resolveImports.js +29 -5
- package/types/transform/generators/rewriteBarrelImports.d.ts +15 -0
- package/types/transform/generators/rewriteBarrelImports.js +815 -0
- package/types/transform/generators/transform.js +148 -19
- package/types/transform/types.d.ts +3 -0
- package/types/transform.js +47 -23
- package/types/utils/collectTemplateDependencies.js +9 -0
package/types/plugins/shaker.js
CHANGED
|
@@ -49,6 +49,9 @@ function getBindingForExport(exportPath) {
|
|
|
49
49
|
}
|
|
50
50
|
return getNonParamBinding(exportPath, id.name);
|
|
51
51
|
}
|
|
52
|
+
if (exportPath.isTSEnumDeclaration()) {
|
|
53
|
+
return getNonParamBinding(exportPath, exportPath.node.id.name);
|
|
54
|
+
}
|
|
52
55
|
return undefined;
|
|
53
56
|
}
|
|
54
57
|
const withoutRemoved = (items) => items.filter(({ local }) => !(0, isRemoved_1.isRemoved)(local));
|
|
@@ -119,28 +122,118 @@ const getPropertyAssignmentStatement = (ref, bindingName) => {
|
|
|
119
122
|
return statement?.isExpressionStatement() ? statement : null;
|
|
120
123
|
};
|
|
121
124
|
const isWithinAliveExport = (ref, aliveExports) => [...aliveExports].some((alive) => alive === ref || alive.isAncestor(ref));
|
|
122
|
-
function
|
|
125
|
+
function getExportPathsForVariableDeclaration(declaration, exports) {
|
|
126
|
+
const exportPaths = [];
|
|
127
|
+
declaration.get('declarations').forEach((declarator) => {
|
|
128
|
+
Object.keys(declarator.getOuterBindingIdentifiers()).forEach((name) => {
|
|
129
|
+
const exportPath = exports[name];
|
|
130
|
+
if (exportPath && !exportPaths.includes(exportPath)) {
|
|
131
|
+
exportPaths.push(exportPath);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
return exportPaths;
|
|
136
|
+
}
|
|
137
|
+
function getDeclaratorExportLiveness(declarator, exports, aliveExports) {
|
|
138
|
+
const bindingNames = Object.keys(declarator.getOuterBindingIdentifiers());
|
|
139
|
+
if (bindingNames.length === 0) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
let liveness = null;
|
|
143
|
+
for (const name of bindingNames) {
|
|
144
|
+
const exportPath = exports[name];
|
|
145
|
+
if (!exportPath) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const isAlive = aliveExports.has(exportPath);
|
|
149
|
+
if (liveness === null) {
|
|
150
|
+
liveness = isAlive;
|
|
151
|
+
}
|
|
152
|
+
else if (liveness !== isAlive) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return liveness;
|
|
157
|
+
}
|
|
158
|
+
function hasRuntimeReferencesToEnum(path) {
|
|
159
|
+
if (!path.isTSEnumDeclaration()) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const enumId = path.get('id');
|
|
163
|
+
const bindingName = enumId.node.name;
|
|
164
|
+
const program = path.scope.getProgramParent().path;
|
|
165
|
+
let hasReference = false;
|
|
166
|
+
program.traverse({
|
|
167
|
+
Identifier(identifier) {
|
|
168
|
+
if (hasReference || identifier.node.name !== bindingName) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (identifier.findParent((ancestor) => ancestor === path)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (identifier.find((ancestor) => ancestor.isTSType() || ancestor.isFlowType())) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (!identifier.isReferencedIdentifier()) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const localBinding = identifier.scope.getBinding(bindingName);
|
|
181
|
+
if (localBinding && localBinding.path !== enumId) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
hasReference = true;
|
|
185
|
+
identifier.stop();
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
return hasReference;
|
|
189
|
+
}
|
|
190
|
+
function stripExportKeepDeclaration(path, exports, aliveExports, t) {
|
|
123
191
|
const exportDeclaration = path.findParent((p) => p.isExportNamedDeclaration());
|
|
124
192
|
if (!exportDeclaration)
|
|
125
|
-
return
|
|
193
|
+
return null;
|
|
126
194
|
const declaration = exportDeclaration.get('declaration');
|
|
127
195
|
if (!declaration.node)
|
|
128
|
-
return
|
|
196
|
+
return null;
|
|
129
197
|
if (declaration.isFunctionDeclaration() ||
|
|
130
198
|
declaration.isClassDeclaration() ||
|
|
131
199
|
declaration.isTSEnumDeclaration()) {
|
|
132
|
-
exportDeclaration.replaceWith(declaration.node);
|
|
133
|
-
return
|
|
200
|
+
exportDeclaration.replaceWith(t.cloneNode(declaration.node, true));
|
|
201
|
+
return [path];
|
|
134
202
|
}
|
|
135
203
|
if (declaration.isVariableDeclaration()) {
|
|
136
204
|
const declarators = declaration.get('declarations');
|
|
137
|
-
|
|
138
|
-
|
|
205
|
+
const staleExportPaths = getExportPathsForVariableDeclaration(declaration, exports);
|
|
206
|
+
if (declarators.length === 1) {
|
|
207
|
+
exportDeclaration.replaceWith(t.cloneNode(declaration.node, true));
|
|
208
|
+
return staleExportPaths.length > 0 ? staleExportPaths : [path];
|
|
139
209
|
}
|
|
140
|
-
|
|
141
|
-
|
|
210
|
+
const segments = [];
|
|
211
|
+
for (const declarator of declarators) {
|
|
212
|
+
const isAlive = getDeclaratorExportLiveness(declarator, exports, aliveExports);
|
|
213
|
+
if (isAlive === null) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const clonedDeclarator = t.cloneNode(declarator.node, true);
|
|
217
|
+
const currentSegment = segments[segments.length - 1];
|
|
218
|
+
if (currentSegment && currentSegment.alive === isAlive) {
|
|
219
|
+
currentSegment.declarators.push(clonedDeclarator);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
segments.push({
|
|
223
|
+
alive: isAlive,
|
|
224
|
+
declarators: [clonedDeclarator],
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
exportDeclaration.replaceWithMultiple(segments.map(({ alive, declarators: groupedDeclarators }) => {
|
|
229
|
+
const groupedDeclaration = t.variableDeclaration(declaration.node.kind, groupedDeclarators);
|
|
230
|
+
return alive
|
|
231
|
+
? t.exportNamedDeclaration(groupedDeclaration, [])
|
|
232
|
+
: groupedDeclaration;
|
|
233
|
+
}));
|
|
234
|
+
return staleExportPaths.length > 0 ? staleExportPaths : [path];
|
|
142
235
|
}
|
|
143
|
-
return
|
|
236
|
+
return null;
|
|
144
237
|
}
|
|
145
238
|
function shakerPlugin(babel, { keepSideEffects = false, ifUnknownExport = 'skip-shaking', importOverrides, onlyExports, root, }) {
|
|
146
239
|
const shakerLogger = shared_1.logger.extend('shaker');
|
|
@@ -377,17 +470,58 @@ function shakerPlugin(babel, { keepSideEffects = false, ifUnknownExport = 'skip-
|
|
|
377
470
|
(0, scopeHelpers_1.dereference)(path);
|
|
378
471
|
dereferenced.push(path);
|
|
379
472
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
473
|
+
const strippedEnum = !deleted.has(path) && hasRuntimeReferencesToEnum(path)
|
|
474
|
+
? stripExportKeepDeclaration(path, exports, aliveExports, babel.types)
|
|
475
|
+
: null;
|
|
476
|
+
if (strippedEnum) {
|
|
477
|
+
strippedEnum.forEach((stalePath) => {
|
|
478
|
+
deleted.add(stalePath);
|
|
479
|
+
});
|
|
480
|
+
changed = true;
|
|
481
|
+
// eslint-disable-next-line no-continue
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
const strippedWithBlocking = !deleted.has(path) && binding && blockingReferences.length > 0
|
|
485
|
+
? stripExportKeepDeclaration(path, exports, aliveExports, babel.types)
|
|
486
|
+
: null;
|
|
487
|
+
if (strippedWithBlocking) {
|
|
488
|
+
strippedWithBlocking.forEach((stalePath) => {
|
|
489
|
+
deleted.add(stalePath);
|
|
490
|
+
});
|
|
385
491
|
changed = true;
|
|
386
492
|
// eslint-disable-next-line no-continue
|
|
387
493
|
continue;
|
|
388
494
|
}
|
|
389
495
|
if (!deleted.has(path) &&
|
|
390
496
|
(!binding || blockingReferences.length === 0)) {
|
|
497
|
+
// For variable declaration exports, `path` is the init expression
|
|
498
|
+
// (not the Identifier). Other forDeleting candidates whose init
|
|
499
|
+
// expressions are ancestors of references to this binding can
|
|
500
|
+
// incorrectly filter them out of outerReferences. Those candidates
|
|
501
|
+
// may later survive via stripExportKeepDeclaration, leaving a
|
|
502
|
+
// dangling reference. Strip the export keyword but keep the
|
|
503
|
+
// declaration so the unreferenced sweep removes it only when dead.
|
|
504
|
+
// This only applies to expression paths (variable init), not
|
|
505
|
+
// Identifiers (function/class declarations) which can't be
|
|
506
|
+
// ancestors of external references.
|
|
507
|
+
const strippedWithoutBlocking = binding && !path.isIdentifier()
|
|
508
|
+
? stripExportKeepDeclaration(path, exports, aliveExports, babel.types)
|
|
509
|
+
: null;
|
|
510
|
+
if (strippedWithoutBlocking) {
|
|
511
|
+
strippedWithoutBlocking.forEach((stalePath) => {
|
|
512
|
+
deleted.add(stalePath);
|
|
513
|
+
});
|
|
514
|
+
if (removableAssignmentStatements.size > 0) {
|
|
515
|
+
for (const statement of removableAssignmentStatements) {
|
|
516
|
+
if (queueForDeleting(statement)) {
|
|
517
|
+
changed = true;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
changed = true;
|
|
522
|
+
// eslint-disable-next-line no-continue
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
391
525
|
if (removableAssignmentStatements.size > 0) {
|
|
392
526
|
for (const statement of removableAssignmentStatements) {
|
|
393
527
|
if (queueForDeleting(statement)) {
|
|
@@ -412,12 +546,23 @@ function shakerPlugin(babel, { keepSideEffects = false, ifUnknownExport = 'skip-
|
|
|
412
546
|
}
|
|
413
547
|
});
|
|
414
548
|
dereferenced = [];
|
|
549
|
+
// stripExportKeepDeclaration replaces ExportNamedDeclaration with
|
|
550
|
+
// its declaration, creating new AST nodes. The old scope bindings
|
|
551
|
+
// become stale (pointing at disconnected paths). Recrawl so
|
|
552
|
+
// getAllBindings() returns fresh bindings with correct .referenced.
|
|
553
|
+
file.scope.crawl();
|
|
415
554
|
// Find and mark for deleting all unreferenced variables
|
|
416
555
|
const unreferenced = Object.values(file.scope.getAllBindings()).filter((i) => !i.referenced);
|
|
417
556
|
for (const binding of unreferenced) {
|
|
418
557
|
if (binding.path.isVariableDeclarator()) {
|
|
419
558
|
const id = binding.path.get('id');
|
|
420
|
-
|
|
559
|
+
// Skip destructured patterns — removing the declarator would kill
|
|
560
|
+
// sibling bindings that may still be referenced (e.g. export {B}
|
|
561
|
+
// from `const [A, B] = createContext(...)` when only A is dead).
|
|
562
|
+
if (!id.isArrayPattern() &&
|
|
563
|
+
!id.isObjectPattern() &&
|
|
564
|
+
!(0, isRemoved_1.isRemoved)(id) &&
|
|
565
|
+
!forDeletingSet.has(id)) {
|
|
421
566
|
// Drop dead variable declarations, e.g. `const foo = make();` when `foo` is no longer referenced.
|
|
422
567
|
for (const violation of binding.constantViolations) {
|
|
423
568
|
if (queueForDeleting(violation)) {
|
package/types/shaker.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TransformOptions } from '@babel/core';
|
|
2
|
+
import type { File } from '@babel/types';
|
|
3
|
+
import type { Evaluator, EvaluatorConfig } from '@wyw-in-js/shared';
|
|
4
|
+
type ShakerStageResult = [
|
|
5
|
+
ast: File,
|
|
6
|
+
code: string,
|
|
7
|
+
imports: Map<string, string[]> | null
|
|
8
|
+
];
|
|
9
|
+
export declare const shakeToESM: (evalConfig: TransformOptions, ast: File, code: string, config: EvaluatorConfig, babel: Parameters<Evaluator>[4]) => ShakerStageResult;
|
|
10
|
+
export declare const emitCommonJS: (evalConfig: TransformOptions, ast: File, code: string, babel: Parameters<Evaluator>[4]) => [ast: File, code: string];
|
|
2
11
|
export declare const shaker: Evaluator;
|
|
3
12
|
export default shaker;
|
package/types/shaker.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.shaker = void 0;
|
|
6
|
+
exports.shaker = exports.emitCommonJS = exports.shakeToESM = void 0;
|
|
7
7
|
const shaker_1 = __importDefault(require("./plugins/shaker"));
|
|
8
8
|
const ShakerMetadata_1 = require("./utils/ShakerMetadata");
|
|
9
9
|
const getPluginKey_1 = require("./utils/getPluginKey");
|
|
@@ -11,6 +11,7 @@ const hasKeyInList = (plugin, list) => {
|
|
|
11
11
|
const pluginKey = (0, getPluginKey_1.getPluginKey)(plugin);
|
|
12
12
|
return pluginKey ? list.some((i) => pluginKey.includes(i)) : false;
|
|
13
13
|
};
|
|
14
|
+
const isCommonJSPlugin = (plugin) => (0, getPluginKey_1.getPluginKey)(plugin) === 'transform-modules-commonjs';
|
|
14
15
|
const safeResolve = (id, paths) => {
|
|
15
16
|
try {
|
|
16
17
|
return require.resolve(id, {
|
|
@@ -21,44 +22,50 @@ const safeResolve = (id, paths) => {
|
|
|
21
22
|
return null;
|
|
22
23
|
}
|
|
23
24
|
};
|
|
24
|
-
const
|
|
25
|
+
const ensureTypescriptPlugin = (plugins, evalConfig) => {
|
|
26
|
+
if (!evalConfig.filename?.endsWith('.ts') &&
|
|
27
|
+
!evalConfig.filename?.endsWith('.tsx') &&
|
|
28
|
+
!evalConfig.filename?.endsWith('.mts') &&
|
|
29
|
+
!evalConfig.filename?.endsWith('.cts')) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const hasTypescriptPlugin = plugins.some((i) => (0, getPluginKey_1.getPluginKey)(i) === 'transform-typescript');
|
|
33
|
+
if (hasTypescriptPlugin) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const preset = safeResolve('@babel/preset-typescript', [evalConfig.filename]);
|
|
37
|
+
const plugin = safeResolve('@babel/plugin-transform-typescript', [
|
|
38
|
+
evalConfig.filename,
|
|
39
|
+
preset,
|
|
40
|
+
]);
|
|
41
|
+
if (plugin) {
|
|
42
|
+
plugins.push([plugin, { allowDeclareFields: true }]);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const createShakerPlugins = (evalConfig, config, includeCommonJS) => {
|
|
46
|
+
const { highPriorityPlugins, ...shakerConfig } = config;
|
|
25
47
|
const preShakePlugins = evalConfig.plugins?.filter((i) => hasKeyInList(i, highPriorityPlugins)) ??
|
|
26
48
|
[];
|
|
27
49
|
const plugins = [
|
|
28
50
|
...preShakePlugins,
|
|
29
|
-
[shaker_1.default,
|
|
30
|
-
...(evalConfig.plugins ?? []).filter((i) => !hasKeyInList(i, highPriorityPlugins)),
|
|
51
|
+
[shaker_1.default, shakerConfig],
|
|
52
|
+
...(evalConfig.plugins ?? []).filter((i) => !hasKeyInList(i, highPriorityPlugins) && !isCommonJSPlugin(i)),
|
|
31
53
|
];
|
|
32
|
-
|
|
33
|
-
if (
|
|
54
|
+
ensureTypescriptPlugin(plugins, evalConfig);
|
|
55
|
+
if (includeCommonJS) {
|
|
34
56
|
plugins.push(require.resolve('@babel/plugin-transform-modules-commonjs'));
|
|
35
57
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const hasTypescriptPlugin = evalConfig.plugins?.some((i) => (0, getPluginKey_1.getPluginKey)(i) === 'transform-typescript');
|
|
41
|
-
if (!hasTypescriptPlugin) {
|
|
42
|
-
const preset = safeResolve('@babel/preset-typescript', [
|
|
43
|
-
evalConfig.filename,
|
|
44
|
-
]);
|
|
45
|
-
const plugin = safeResolve('@babel/plugin-transform-typescript', [
|
|
46
|
-
evalConfig.filename,
|
|
47
|
-
preset,
|
|
48
|
-
]);
|
|
49
|
-
if (plugin) {
|
|
50
|
-
plugins.push([plugin, { allowDeclareFields: true }]);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const transformOptions = {
|
|
58
|
+
return plugins;
|
|
59
|
+
};
|
|
60
|
+
const shakeToESM = (evalConfig, ast, code, config, babel) => {
|
|
61
|
+
const transformed = babel.transformFromAstSync(ast, code, {
|
|
55
62
|
...evalConfig,
|
|
63
|
+
ast: true,
|
|
56
64
|
caller: {
|
|
57
65
|
name: 'wyw-in-js',
|
|
58
66
|
},
|
|
59
|
-
plugins,
|
|
60
|
-
};
|
|
61
|
-
const transformed = babel.transformFromAstSync(ast, code, transformOptions);
|
|
67
|
+
plugins: createShakerPlugins(evalConfig, config, false),
|
|
68
|
+
});
|
|
62
69
|
if (!transformed || !(0, ShakerMetadata_1.hasShakerMetadata)(transformed.metadata)) {
|
|
63
70
|
throw new Error(`${evalConfig.filename} has no shaker metadata`);
|
|
64
71
|
}
|
|
@@ -68,5 +75,26 @@ const shaker = (evalConfig, ast, code, { highPriorityPlugins, ...config }, babel
|
|
|
68
75
|
transformed.metadata.wywEvaluator.imports,
|
|
69
76
|
];
|
|
70
77
|
};
|
|
78
|
+
exports.shakeToESM = shakeToESM;
|
|
79
|
+
const emitCommonJS = (evalConfig, ast, code, babel) => {
|
|
80
|
+
const transformed = babel.transformFromAstSync(ast, code, {
|
|
81
|
+
...evalConfig,
|
|
82
|
+
ast: true,
|
|
83
|
+
caller: {
|
|
84
|
+
name: 'wyw-in-js',
|
|
85
|
+
},
|
|
86
|
+
plugins: [require.resolve('@babel/plugin-transform-modules-commonjs')],
|
|
87
|
+
});
|
|
88
|
+
if (!transformed?.ast) {
|
|
89
|
+
throw new Error('Babel transform failed');
|
|
90
|
+
}
|
|
91
|
+
return [transformed.ast, transformed.code ?? ''];
|
|
92
|
+
};
|
|
93
|
+
exports.emitCommonJS = emitCommonJS;
|
|
94
|
+
const shaker = (evalConfig, ast, code, config, babel) => {
|
|
95
|
+
const [esmAst, esmCode, imports] = (0, exports.shakeToESM)(evalConfig, ast, code, config, babel);
|
|
96
|
+
const [, commonJSCode] = (0, exports.emitCommonJS)(evalConfig, esmAst, esmCode, babel);
|
|
97
|
+
return [esmAst, commonJSCode, imports];
|
|
98
|
+
};
|
|
71
99
|
exports.shaker = shaker;
|
|
72
100
|
exports.default = exports.shaker;
|
|
@@ -12,11 +12,13 @@ export declare abstract class BaseEntrypoint {
|
|
|
12
12
|
readonly only: string[];
|
|
13
13
|
readonly parents: ParentEntrypoint[];
|
|
14
14
|
readonly dependencies: Map<string, IEntrypointDependency>;
|
|
15
|
+
readonly invalidationDependencies: Map<string, IEntrypointDependency>;
|
|
16
|
+
readonly invalidateOnDependencyChange: Set<string>;
|
|
15
17
|
static createExports: (log: Debugger) => Record<string | symbol, unknown>;
|
|
16
18
|
readonly idx: string;
|
|
17
19
|
readonly log: Debugger;
|
|
18
20
|
readonly seqId: number;
|
|
19
|
-
protected constructor(services: Services, evaluatedOnly: string[], exports: Record<string | symbol, unknown> | undefined, generation: number, name: string, only: string[], parents: ParentEntrypoint[], dependencies: Map<string, IEntrypointDependency>);
|
|
21
|
+
protected constructor(services: Services, evaluatedOnly: string[], exports: Record<string | symbol, unknown> | undefined, generation: number, name: string, only: string[], parents: ParentEntrypoint[], dependencies: Map<string, IEntrypointDependency>, invalidationDependencies: Map<string, IEntrypointDependency>, invalidateOnDependencyChange: Set<string>);
|
|
20
22
|
get exports(): Record<string | symbol, unknown>;
|
|
21
23
|
set exports(value: unknown);
|
|
22
24
|
get ref(): string;
|
|
@@ -116,13 +116,15 @@ class BaseEntrypoint {
|
|
|
116
116
|
only;
|
|
117
117
|
parents;
|
|
118
118
|
dependencies;
|
|
119
|
+
invalidationDependencies;
|
|
120
|
+
invalidateOnDependencyChange;
|
|
119
121
|
static createExports = exports.createExports;
|
|
120
122
|
idx;
|
|
121
123
|
log;
|
|
122
124
|
// eslint-disable-next-line no-plusplus
|
|
123
125
|
seqId = entrypointSeqId++;
|
|
124
126
|
#exports;
|
|
125
|
-
constructor(services, evaluatedOnly, exports, generation, name, only, parents, dependencies) {
|
|
127
|
+
constructor(services, evaluatedOnly, exports, generation, name, only, parents, dependencies, invalidationDependencies, invalidateOnDependencyChange) {
|
|
126
128
|
this.services = services;
|
|
127
129
|
this.evaluatedOnly = evaluatedOnly;
|
|
128
130
|
this.generation = generation;
|
|
@@ -130,6 +132,8 @@ class BaseEntrypoint {
|
|
|
130
132
|
this.only = only;
|
|
131
133
|
this.parents = parents;
|
|
132
134
|
this.dependencies = dependencies;
|
|
135
|
+
this.invalidationDependencies = invalidationDependencies;
|
|
136
|
+
this.invalidateOnDependencyChange = invalidateOnDependencyChange;
|
|
133
137
|
this.idx = (0, getFileIdx_1.getFileIdx)(name);
|
|
134
138
|
this.log =
|
|
135
139
|
parents[0]?.log.extend(this.ref, '->') ?? services.log.extend(this.ref);
|
|
@@ -10,6 +10,8 @@ export declare class Entrypoint extends BaseEntrypoint {
|
|
|
10
10
|
readonly initialCode: string | undefined;
|
|
11
11
|
protected readonly resolveTasks: Map<string, Promise<IEntrypointDependency>>;
|
|
12
12
|
readonly dependencies: Map<string, IEntrypointDependency>;
|
|
13
|
+
readonly invalidationDependencies: Map<string, IEntrypointDependency>;
|
|
14
|
+
readonly invalidateOnDependencyChange: Set<string>;
|
|
13
15
|
readonly evaluated = false;
|
|
14
16
|
readonly loadedAndParsed: IEntrypointCode | IIgnoredEntrypoint;
|
|
15
17
|
protected onSupersedeHandlers: Array<(newEntrypoint: Entrypoint) => void>;
|
|
@@ -35,16 +37,23 @@ export declare class Entrypoint extends BaseEntrypoint {
|
|
|
35
37
|
protected static create(services: Services, parent: ParentEntrypoint | null, name: string, only: string[], loadedCode: string | undefined): Entrypoint | 'loop';
|
|
36
38
|
private static innerCreate;
|
|
37
39
|
addDependency(dependency: IEntrypointDependency): void;
|
|
40
|
+
addInvalidationDependency(dependency: IEntrypointDependency): void;
|
|
38
41
|
addResolveTask(name: string, dependency: Promise<IEntrypointDependency>): void;
|
|
42
|
+
applyDeferredSupersede(): Entrypoint | null;
|
|
39
43
|
assertNotSuperseded(): void;
|
|
40
44
|
assertTransformed(): void;
|
|
41
|
-
|
|
45
|
+
beginProcessing(): void;
|
|
46
|
+
createAction<TType extends ActionTypes, TAction extends ActionByType<TType>>(actionType: TType, data: TAction['data'], abortSignal?: AbortSignal | null, actionContext?: unknown): BaseAction<TAction>;
|
|
42
47
|
createChild(name: string, only: string[], loadedCode?: string): Entrypoint | 'loop';
|
|
43
48
|
createEvaluated(): EvaluatedEntrypoint;
|
|
49
|
+
endProcessing(): void;
|
|
44
50
|
getDependency(name: string): IEntrypointDependency | undefined;
|
|
51
|
+
getInvalidationDependency(name: string): IEntrypointDependency | undefined;
|
|
52
|
+
markInvalidateOnDependencyChange(filename: string): void;
|
|
45
53
|
getResolveTask(name: string): Promise<IEntrypointDependency> | undefined;
|
|
46
54
|
hasWywMetadata(): boolean;
|
|
47
55
|
onSupersede(callback: (newEntrypoint: Entrypoint) => void): () => void;
|
|
48
56
|
setTransformResult(res: ITransformFileResult | null): void;
|
|
57
|
+
private deferOnlySupersede;
|
|
49
58
|
private supersede;
|
|
50
59
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.Entrypoint = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
4
8
|
const ts_invariant_1 = require("ts-invariant");
|
|
5
9
|
const BaseEntrypoint_1 = require("./BaseEntrypoint");
|
|
6
10
|
const Entrypoint_helpers_1 = require("./Entrypoint.helpers");
|
|
7
|
-
const isStaticallyEvaluatableModule_1 = require("./isStaticallyEvaluatableModule");
|
|
8
11
|
const EvaluatedEntrypoint_1 = require("./EvaluatedEntrypoint");
|
|
9
12
|
const AbortError_1 = require("./actions/AbortError");
|
|
10
13
|
const BaseAction_1 = require("./actions/BaseAction");
|
|
11
14
|
const UnprocessedEntrypointError_1 = require("./actions/UnprocessedEntrypointError");
|
|
15
|
+
const parseRequest_1 = require("../utils/parseRequest");
|
|
12
16
|
const EMPTY_FILE = '=== empty file ===';
|
|
17
|
+
const DEFAULT_ACTION_CONTEXT = Symbol('defaultActionContext');
|
|
13
18
|
function hasLoop(name, parent, processed = []) {
|
|
14
19
|
if (parent.name === name || processed.includes(parent.name)) {
|
|
15
20
|
return true;
|
|
@@ -26,18 +31,24 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
26
31
|
initialCode;
|
|
27
32
|
resolveTasks;
|
|
28
33
|
dependencies;
|
|
34
|
+
invalidationDependencies;
|
|
35
|
+
invalidateOnDependencyChange;
|
|
29
36
|
evaluated = false;
|
|
30
37
|
loadedAndParsed;
|
|
31
38
|
onSupersedeHandlers = [];
|
|
32
39
|
actionsCache = new Map();
|
|
33
40
|
#hasWywMetadata = false;
|
|
41
|
+
#isProcessing = false;
|
|
42
|
+
#pendingOnly = null;
|
|
34
43
|
#supersededWith = null;
|
|
35
44
|
#transformResultCode = null;
|
|
36
|
-
constructor(services, parents, initialCode, name, only, exports, evaluatedOnly, loadedAndParsed, resolveTasks = new Map(), dependencies = new Map(), generation = 1) {
|
|
37
|
-
super(services, evaluatedOnly, exports, generation, name, only, parents, dependencies);
|
|
45
|
+
constructor(services, parents, initialCode, name, only, exports, evaluatedOnly, loadedAndParsed, resolveTasks = new Map(), dependencies = new Map(), invalidationDependencies = new Map(), invalidateOnDependencyChange = new Set(), generation = 1) {
|
|
46
|
+
super(services, evaluatedOnly, exports, generation, name, only, parents, dependencies, invalidationDependencies, invalidateOnDependencyChange);
|
|
38
47
|
this.initialCode = initialCode;
|
|
39
48
|
this.resolveTasks = resolveTasks;
|
|
40
49
|
this.dependencies = dependencies;
|
|
50
|
+
this.invalidationDependencies = invalidationDependencies;
|
|
51
|
+
this.invalidateOnDependencyChange = invalidateOnDependencyChange;
|
|
41
52
|
this.loadedAndParsed =
|
|
42
53
|
loadedAndParsed ??
|
|
43
54
|
services.loadAndParseFn(services, name, initialCode, parents[0]?.log ?? services.log);
|
|
@@ -99,9 +110,18 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
99
110
|
static innerCreate(services, parent, name, only, loadedCode) {
|
|
100
111
|
const { cache } = services;
|
|
101
112
|
const cached = cache.get('entrypoints', name);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
let changed = false;
|
|
114
|
+
if (loadedCode !== undefined) {
|
|
115
|
+
changed = cache.invalidateIfChanged(name, loadedCode, undefined, 'loaded');
|
|
116
|
+
}
|
|
117
|
+
else if (cached && cached.initialCode === undefined) {
|
|
118
|
+
try {
|
|
119
|
+
changed = cache.invalidateIfChanged(name, node_fs_1.default.readFileSync((0, parseRequest_1.stripQueryAndHash)(name), 'utf8'), undefined, 'fs');
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
changed = false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
105
125
|
if (!cached?.evaluated && cached?.ignored) {
|
|
106
126
|
return ['cached', cached];
|
|
107
127
|
}
|
|
@@ -124,20 +144,18 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
124
144
|
return [isLoop ? 'loop' : 'cached', cached];
|
|
125
145
|
}
|
|
126
146
|
cached.log('is cached, but with different `only` %o (the cached one %o)', only, cached?.only);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
!newEntrypoint.only.includes('*') &&
|
|
132
|
-
!newEntrypoint.only.includes('__wywPreval') &&
|
|
133
|
-
!newEntrypoint.only.includes('side-effect')) {
|
|
134
|
-
const { ast } = newEntrypoint.loadedAndParsed;
|
|
135
|
-
if (ast && (0, isStaticallyEvaluatableModule_1.isStaticallyEvaluatableModule)(ast)) {
|
|
136
|
-
newEntrypoint.log('[entrypoint] promote `only` to "*" for statically evaluatable module');
|
|
137
|
-
newEntrypoint.only.length = 0;
|
|
138
|
-
newEntrypoint.only.push('*');
|
|
147
|
+
if (cached.#isProcessing) {
|
|
148
|
+
cached.deferOnlySupersede(mergedOnly);
|
|
149
|
+
cached.log('is being processed, defer supersede (%o -> %o)', cached.only, mergedOnly);
|
|
150
|
+
return [isLoop ? 'loop' : 'cached', cached];
|
|
139
151
|
}
|
|
152
|
+
return [isLoop ? 'loop' : 'created', cached.supersede(mergedOnly)];
|
|
140
153
|
}
|
|
154
|
+
const newEntrypoint = new Entrypoint(services, parent ? [parent] : [], loadedCode, name, mergedOnly, exports, evaluatedOnly, undefined, cached && 'resolveTasks' in cached ? cached.resolveTasks : undefined, cached && 'dependencies' in cached ? cached.dependencies : undefined, cached && 'invalidationDependencies' in cached
|
|
155
|
+
? cached.invalidationDependencies
|
|
156
|
+
: undefined, cached && 'invalidateOnDependencyChange' in cached
|
|
157
|
+
? cached.invalidateOnDependencyChange
|
|
158
|
+
: undefined, cached ? cached.generation + 1 : 1);
|
|
141
159
|
if (cached && !cached.evaluated) {
|
|
142
160
|
cached.log('is cached, but with different code');
|
|
143
161
|
cached.supersede(newEntrypoint);
|
|
@@ -148,9 +166,27 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
148
166
|
this.resolveTasks.delete(dependency.source);
|
|
149
167
|
this.dependencies.set(dependency.source, dependency);
|
|
150
168
|
}
|
|
169
|
+
addInvalidationDependency(dependency) {
|
|
170
|
+
this.resolveTasks.delete(dependency.source);
|
|
171
|
+
this.invalidationDependencies.set(dependency.source, dependency);
|
|
172
|
+
}
|
|
151
173
|
addResolveTask(name, dependency) {
|
|
152
174
|
this.resolveTasks.set(name, dependency);
|
|
153
175
|
}
|
|
176
|
+
applyDeferredSupersede() {
|
|
177
|
+
if (this.#supersededWith || this.#pendingOnly === null) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const mergedOnly = (0, Entrypoint_helpers_1.mergeOnly)(this.only, this.#pendingOnly);
|
|
181
|
+
this.#pendingOnly = null;
|
|
182
|
+
if ((0, Entrypoint_helpers_1.isSuperSet)(this.only, mergedOnly)) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
this.log('apply deferred supersede (%o -> %o)', this.only, mergedOnly);
|
|
186
|
+
const nextEntrypoint = this.supersede(mergedOnly);
|
|
187
|
+
this.services.cache.add('entrypoints', this.name, nextEntrypoint);
|
|
188
|
+
return nextEntrypoint;
|
|
189
|
+
}
|
|
154
190
|
assertNotSuperseded() {
|
|
155
191
|
if (this.supersededWith) {
|
|
156
192
|
this.log('superseded');
|
|
@@ -163,16 +199,23 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
163
199
|
throw new UnprocessedEntrypointError_1.UnprocessedEntrypointError(this.supersededWith ?? this);
|
|
164
200
|
}
|
|
165
201
|
}
|
|
166
|
-
|
|
202
|
+
beginProcessing() {
|
|
203
|
+
this.#isProcessing = true;
|
|
204
|
+
}
|
|
205
|
+
createAction(actionType, data, abortSignal = null, actionContext = DEFAULT_ACTION_CONTEXT) {
|
|
167
206
|
if (!this.actionsCache.has(actionType)) {
|
|
168
207
|
this.actionsCache.set(actionType, new Map());
|
|
169
208
|
}
|
|
170
|
-
const
|
|
209
|
+
const contexts = this.actionsCache.get(actionType);
|
|
210
|
+
if (!contexts.has(actionContext)) {
|
|
211
|
+
contexts.set(actionContext, new Map());
|
|
212
|
+
}
|
|
213
|
+
const cache = contexts.get(actionContext);
|
|
171
214
|
const cached = cache.get(data);
|
|
172
215
|
if (cached && !cached.abortSignal?.aborted) {
|
|
173
216
|
return cached;
|
|
174
217
|
}
|
|
175
|
-
const newAction = new BaseAction_1.BaseAction(actionType, this.services, this, data, abortSignal);
|
|
218
|
+
const newAction = new BaseAction_1.BaseAction(actionType, this.services, this, data, abortSignal, actionContext);
|
|
176
219
|
cache.set(data, newAction);
|
|
177
220
|
this.services.eventEmitter.entrypointEvent(this.seqId, {
|
|
178
221
|
type: 'actionCreated',
|
|
@@ -187,13 +230,22 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
187
230
|
createEvaluated() {
|
|
188
231
|
const evaluatedOnly = (0, Entrypoint_helpers_1.mergeOnly)(this.evaluatedOnly, this.only);
|
|
189
232
|
this.log('create EvaluatedEntrypoint for %o', evaluatedOnly);
|
|
190
|
-
const evaluated = new EvaluatedEntrypoint_1.EvaluatedEntrypoint(this.services, evaluatedOnly, this.exportsProxy, this.generation + 1, this.name, this.only, this.parents, this.dependencies);
|
|
233
|
+
const evaluated = new EvaluatedEntrypoint_1.EvaluatedEntrypoint(this.services, evaluatedOnly, this.exportsProxy, this.generation + 1, this.name, this.only, this.parents, this.dependencies, this.invalidationDependencies, this.invalidateOnDependencyChange);
|
|
191
234
|
evaluated.initialCode = this.initialCode;
|
|
192
235
|
return evaluated;
|
|
193
236
|
}
|
|
237
|
+
endProcessing() {
|
|
238
|
+
this.#isProcessing = false;
|
|
239
|
+
}
|
|
194
240
|
getDependency(name) {
|
|
195
241
|
return this.dependencies.get(name);
|
|
196
242
|
}
|
|
243
|
+
getInvalidationDependency(name) {
|
|
244
|
+
return this.invalidationDependencies.get(name);
|
|
245
|
+
}
|
|
246
|
+
markInvalidateOnDependencyChange(filename) {
|
|
247
|
+
this.invalidateOnDependencyChange.add(filename);
|
|
248
|
+
}
|
|
197
249
|
getResolveTask(name) {
|
|
198
250
|
return this.resolveTasks.get(name);
|
|
199
251
|
}
|
|
@@ -221,10 +273,16 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
|
|
|
221
273
|
type: 'setTransformResult',
|
|
222
274
|
});
|
|
223
275
|
}
|
|
276
|
+
deferOnlySupersede(only) {
|
|
277
|
+
this.#pendingOnly = this.#pendingOnly
|
|
278
|
+
? (0, Entrypoint_helpers_1.mergeOnly)(this.#pendingOnly, only)
|
|
279
|
+
: [...only];
|
|
280
|
+
}
|
|
224
281
|
supersede(newOnlyOrEntrypoint) {
|
|
282
|
+
this.#pendingOnly = null;
|
|
225
283
|
const newEntrypoint = newOnlyOrEntrypoint instanceof Entrypoint
|
|
226
284
|
? newOnlyOrEntrypoint
|
|
227
|
-
: new Entrypoint(this.services, this.parents, this.initialCode, this.name, newOnlyOrEntrypoint, this.exports, this.evaluatedOnly, this.loadedAndParsed, this.resolveTasks, this.dependencies, this.generation + 1);
|
|
285
|
+
: new Entrypoint(this.services, this.parents, this.initialCode, this.name, newOnlyOrEntrypoint, this.exports, this.evaluatedOnly, this.loadedAndParsed, this.resolveTasks, this.dependencies, this.invalidationDependencies, this.invalidateOnDependencyChange, this.generation + 1);
|
|
228
286
|
this.services.eventEmitter.entrypointEvent(this.seqId, {
|
|
229
287
|
type: 'superseded',
|
|
230
288
|
with: newEntrypoint.seqId,
|