@animus-ui/vite-plugin 0.1.6 → 0.1.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/dist/build-start.d.ts.map +1 -1
- package/dist/context.d.ts +21 -31
- package/dist/context.d.ts.map +1 -1
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hot-update-events.d.ts +4 -3
- package/dist/hot-update-events.d.ts.map +1 -1
- package/dist/index.cjs +323 -57
- package/dist/module-invalidation.d.ts +15 -0
- package/dist/module-invalidation.d.ts.map +1 -0
- package/dist/rediscovery.d.ts +40 -0
- package/dist/rediscovery.d.ts.map +1 -0
- package/dist/transform.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-start.d.ts","sourceRoot":"","sources":["../src/build-start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-start.d.ts","sourceRoot":"","sources":["../src/build-start.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAC/D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,MAAM,GAC3D,OAAO,CAAC,IAAI,CAAC,CA2Rf"}
|
package/dist/context.d.ts
CHANGED
|
@@ -44,34 +44,6 @@ export declare function buildFileEntriesFromCache(cache: Map<string, {
|
|
|
44
44
|
* behavioral test doubles — carry no memo and generate here instead.
|
|
45
45
|
*/
|
|
46
46
|
export declare function systemPropsModuleSource(ctx: PluginContext): string;
|
|
47
|
-
/**
|
|
48
|
-
* Run project analysis and report whether the served system-props module
|
|
49
|
-
* CHANGED.
|
|
50
|
-
*
|
|
51
|
-
* The module is imported by every module that renders a system prop, so
|
|
52
|
-
* re-delivering it pushes an update through all of them; every analysis
|
|
53
|
-
* republishes its inputs whether or not they moved, so a new analysis is not
|
|
54
|
-
* itself an admissible trigger (openspec: vite-extraction-plugin, "System prop
|
|
55
|
-
* map HMR invalidation").
|
|
56
|
-
*
|
|
57
|
-
* The comparison is over the GENERATED MODULE, not over the prop map alone.
|
|
58
|
-
* The map is one of four inputs, and they move independently: widening a
|
|
59
|
-
* component's `.system({ ... })` opt-in adds a `dynamicPropConfig` entry while
|
|
60
|
-
* minting no new utility class, so a map-only comparison reports "unchanged"
|
|
61
|
-
* and the client is left with a config missing the new prop — permanently,
|
|
62
|
-
* since Vite keeps serving the module's cached transform result across full
|
|
63
|
-
* page reloads. Comparing the artifact itself needs no argument about which
|
|
64
|
-
* inputs are volatile this month.
|
|
65
|
-
*
|
|
66
|
-
* A free function rather than a method: the comparison must run for real
|
|
67
|
-
* against any context the caller holds, including the behavioral test doubles
|
|
68
|
-
* that stand in for the engine.
|
|
69
|
-
*/
|
|
70
|
-
export declare function runAnalysisTrackingSystemProps(ctx: PluginContext, fileEntries: Array<{
|
|
71
|
-
path: string;
|
|
72
|
-
source: string;
|
|
73
|
-
hash?: string;
|
|
74
|
-
}>): boolean;
|
|
75
47
|
/**
|
|
76
48
|
* Drop a deleted (or renamed-away) file from the dev file cache so its
|
|
77
49
|
* last-known source stops riding along as a ghost entry on every later
|
|
@@ -115,12 +87,22 @@ export declare class PluginContext {
|
|
|
115
87
|
layerDeclaration: string;
|
|
116
88
|
transformOutputHashes: Map<string, string>;
|
|
117
89
|
recordTransformOutput(relativePath: string, code: string): void;
|
|
90
|
+
/**
|
|
91
|
+
* The consumer system's OWN keyframes collections, captured at load time
|
|
92
|
+
* before any external merge touches `system.keyframesJson`. Every
|
|
93
|
+
* `applyExternalKeyframes` merge starts from this baseline, so repeated
|
|
94
|
+
* merges (a --watch rebuild's loadSystem + rediscovery, a geological
|
|
95
|
+
* reset) never compound prior external state — a removed include's
|
|
96
|
+
* keyframes disappear with it.
|
|
97
|
+
*/
|
|
98
|
+
private consumerKeyframesJson;
|
|
118
99
|
/**
|
|
119
100
|
* Merge `Keyframes` collections from discovered external package entries
|
|
120
101
|
* into the system's collections (keyframes-only carve-out — the consumer
|
|
121
102
|
* system stays the singular config authority). Runs after buildStart
|
|
122
103
|
* discovery AND after every geological-reset system reload, since a reload
|
|
123
|
-
* rebuilds `this.system` from the consumer entry alone.
|
|
104
|
+
* rebuilds `this.system` from the consumer entry alone. Merges from the
|
|
105
|
+
* consumer-only baseline, never from the previously merged value.
|
|
124
106
|
*/
|
|
125
107
|
applyExternalKeyframes(): void;
|
|
126
108
|
/** Discovery-time keyframes diagnostics awaiting the next analysis's
|
|
@@ -135,7 +117,9 @@ export declare class PluginContext {
|
|
|
135
117
|
hash: string;
|
|
136
118
|
source: string;
|
|
137
119
|
}>;
|
|
120
|
+
rawExtensionFallbacks: Set<string>;
|
|
138
121
|
readonly hotUpdateEvents: HotUpdateEvents;
|
|
122
|
+
private pendingReloadTimer;
|
|
139
123
|
packageMap: Record<string, string>;
|
|
140
124
|
base: string;
|
|
141
125
|
assetUrlBySpecifier: Map<string, string>;
|
|
@@ -145,6 +129,7 @@ export declare class PluginContext {
|
|
|
145
129
|
externalDirOwners: Record<string, string>;
|
|
146
130
|
externalFileOwners: Record<string, string>;
|
|
147
131
|
externalSourceEntries: Map<string, string>;
|
|
132
|
+
externalKeyframesScanEntries: Map<string, string>;
|
|
148
133
|
externalPackageOutcomes: ExternalPackageOutcome[];
|
|
149
134
|
devServer: any;
|
|
150
135
|
resolvedSystemPath: string | null;
|
|
@@ -174,13 +159,18 @@ export declare class PluginContext {
|
|
|
174
159
|
loadSystem(): void;
|
|
175
160
|
/**
|
|
176
161
|
* Run project analysis via the shared `runProjectAnalysis` and update
|
|
177
|
-
* all manifest-derived state.
|
|
162
|
+
* all manifest-derived state. Returns whether the analysis PUBLISHED —
|
|
163
|
+
* `false` means the previous manifest is still current, and callers that
|
|
164
|
+
* advanced the file cache for this attempt must roll that entry back or
|
|
165
|
+
* the content-hash gate will suppress the same-content retry forever
|
|
166
|
+
* (openspec: dev-transform-coherence, "Failed analyses do not suppress
|
|
167
|
+
* equal-content retries"). Strict mode still throws.
|
|
178
168
|
*/
|
|
179
169
|
runAnalysis(fileEntries: Array<{
|
|
180
170
|
path: string;
|
|
181
171
|
source: string;
|
|
182
172
|
hash?: string;
|
|
183
|
-
}>):
|
|
173
|
+
}>): boolean;
|
|
184
174
|
/** Base-prefixed dev URL for an absolute file (Vite mounts /@fs under base). */
|
|
185
175
|
devFsUrl(absPath: string): string;
|
|
186
176
|
/**
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAClB,YAAY,EAEb,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EACpD,WAAW,CAAC,EAAE,MAAM,GACnB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAUvD;AAYD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAKlE;AAED
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
package/dist/hmr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,MAAM,CAAC;AAEd;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,WAAW,EAAE,cAAc,EAC3B,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,gBAAgB,GACzD,OAAO,CAAC,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAqEzC"}
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* modules in its own graph. `staleDefinitionFiles` are rootDir-relative
|
|
11
11
|
* definition files whose component replacement changed (the changed file
|
|
12
12
|
* itself is never listed). `systemPropsChanged` reports whether the served
|
|
13
|
-
* system-props module moved (see
|
|
14
|
-
*
|
|
15
|
-
* it travels with the decision rather than being
|
|
13
|
+
* system-props module moved (see the transaction-spanning compare in
|
|
14
|
+
* hmr.ts `analyzeChangedFile`) — only the owning dispatch holds the
|
|
15
|
+
* before/after values, so it travels with the decision rather than being
|
|
16
|
+
* re-derived per environment.
|
|
16
17
|
* `presentationOnly` reports that the changed file's transform output is
|
|
17
18
|
* byte-identical before and after the edit (style values are not part of
|
|
18
19
|
* the emitted replacement — class names hash `filename::binding`): every
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hot-update-events.d.ts","sourceRoot":"","sources":["../src/hot-update-events.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hot-update-events.d.ts","sourceRoot":"","sources":["../src/hot-update-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEN;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,eAAe;IAGd,OAAO,CAAC,QAAQ,CAAC,YAAY;IAFzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D,YAA6B,YAAY,SAAK,EAAI;IAElD,0EAA0E;IAC1E,KAAK,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAUvE;IAED,wEAAwE;IACxE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAErE;IAED,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CAEzD;CACF"}
|
package/dist/index.cjs
CHANGED
|
@@ -117,6 +117,7 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
|
|
|
117
117
|
const localFileCount = fileEntries.length;
|
|
118
118
|
const packageSpecifiers = (0, _animus_ui_extract_pipeline.extractSystemFilePackages)(ctx.resolvedSystemPath);
|
|
119
119
|
ctx.externalSourceEntries.clear();
|
|
120
|
+
ctx.externalKeyframesScanEntries.clear();
|
|
120
121
|
const collected = await (0, _animus_ui_extract_pipeline.collectExternalPackageSources)({
|
|
121
122
|
specifiers: packageSpecifiers,
|
|
122
123
|
resolveSpecifier,
|
|
@@ -134,10 +135,11 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
|
|
|
134
135
|
});
|
|
135
136
|
ctx.packageMap = collected.packageMap;
|
|
136
137
|
ctx.externalPackageOutcomes = collected.outcomes;
|
|
137
|
-
ctx.externalDirOwners = collected.
|
|
138
|
+
ctx.externalDirOwners = (0, _animus_ui_extract_pipeline.firstOwners)(collected.dirOwnerSets);
|
|
138
139
|
ctx.externalFileOwners = collected.fileOwners;
|
|
139
140
|
ctx.enforceIncludeResolution();
|
|
140
141
|
for (const [specifier, srcEntry] of collected.sourceEntries) ctx.externalSourceEntries.set(specifier, srcEntry);
|
|
142
|
+
for (const [specifier, scanEntry] of collected.keyframesScanEntries) ctx.externalKeyframesScanEntries.set(specifier, scanEntry);
|
|
141
143
|
for (const entry of collected.entries) {
|
|
142
144
|
const hash = !ctx.isProd ? (0, _animus_ui_extract_pipeline.contentHash)(entry.source) : void 0;
|
|
143
145
|
fileEntries.push({
|
|
@@ -396,34 +398,6 @@ function systemPropsModuleSource(ctx) {
|
|
|
396
398
|
return ctx.systemPropsModuleMemo ??= generateSystemPropsModule(ctx);
|
|
397
399
|
}
|
|
398
400
|
/**
|
|
399
|
-
* Run project analysis and report whether the served system-props module
|
|
400
|
-
* CHANGED.
|
|
401
|
-
*
|
|
402
|
-
* The module is imported by every module that renders a system prop, so
|
|
403
|
-
* re-delivering it pushes an update through all of them; every analysis
|
|
404
|
-
* republishes its inputs whether or not they moved, so a new analysis is not
|
|
405
|
-
* itself an admissible trigger (openspec: vite-extraction-plugin, "System prop
|
|
406
|
-
* map HMR invalidation").
|
|
407
|
-
*
|
|
408
|
-
* The comparison is over the GENERATED MODULE, not over the prop map alone.
|
|
409
|
-
* The map is one of four inputs, and they move independently: widening a
|
|
410
|
-
* component's `.system({ ... })` opt-in adds a `dynamicPropConfig` entry while
|
|
411
|
-
* minting no new utility class, so a map-only comparison reports "unchanged"
|
|
412
|
-
* and the client is left with a config missing the new prop — permanently,
|
|
413
|
-
* since Vite keeps serving the module's cached transform result across full
|
|
414
|
-
* page reloads. Comparing the artifact itself needs no argument about which
|
|
415
|
-
* inputs are volatile this month.
|
|
416
|
-
*
|
|
417
|
-
* A free function rather than a method: the comparison must run for real
|
|
418
|
-
* against any context the caller holds, including the behavioral test doubles
|
|
419
|
-
* that stand in for the engine.
|
|
420
|
-
*/
|
|
421
|
-
function runAnalysisTrackingSystemProps(ctx, fileEntries) {
|
|
422
|
-
const before = systemPropsModuleSource(ctx);
|
|
423
|
-
ctx.runAnalysis(fileEntries);
|
|
424
|
-
return systemPropsModuleSource(ctx) !== before;
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
401
|
* Drop a deleted (or renamed-away) file from the dev file cache so its
|
|
428
402
|
* last-known source stops riding along as a ghost entry on every later
|
|
429
403
|
* re-analysis. Both key forms are tried: the plain rootDir-relative path, and
|
|
@@ -469,15 +443,29 @@ var PluginContext = class {
|
|
|
469
443
|
this.transformOutputHashes.set(relativePath, (0, _animus_ui_extract_pipeline.contentHash)(code));
|
|
470
444
|
}
|
|
471
445
|
/**
|
|
446
|
+
* The consumer system's OWN keyframes collections, captured at load time
|
|
447
|
+
* before any external merge touches `system.keyframesJson`. Every
|
|
448
|
+
* `applyExternalKeyframes` merge starts from this baseline, so repeated
|
|
449
|
+
* merges (a --watch rebuild's loadSystem + rediscovery, a geological
|
|
450
|
+
* reset) never compound prior external state — a removed include's
|
|
451
|
+
* keyframes disappear with it.
|
|
452
|
+
*/
|
|
453
|
+
consumerKeyframesJson = null;
|
|
454
|
+
/**
|
|
472
455
|
* Merge `Keyframes` collections from discovered external package entries
|
|
473
456
|
* into the system's collections (keyframes-only carve-out — the consumer
|
|
474
457
|
* system stays the singular config authority). Runs after buildStart
|
|
475
458
|
* discovery AND after every geological-reset system reload, since a reload
|
|
476
|
-
* rebuilds `this.system` from the consumer entry alone.
|
|
459
|
+
* rebuilds `this.system` from the consumer entry alone. Merges from the
|
|
460
|
+
* consumer-only baseline, never from the previously merged value.
|
|
477
461
|
*/
|
|
478
462
|
applyExternalKeyframes() {
|
|
479
|
-
if (this.
|
|
480
|
-
|
|
463
|
+
if (this.externalKeyframesScanEntries.size === 0) {
|
|
464
|
+
this.system.keyframesJson = this.consumerKeyframesJson;
|
|
465
|
+
this.externalKeyframesDiagnostics = [];
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const merge = (0, _animus_ui_extract_pipeline.mergeExternalKeyframes)((entry, root) => this.engineApi().scanKeyframesExports(entry, root), this.consumerKeyframesJson, this.externalKeyframesScanEntries.values(), this.rootDir);
|
|
481
469
|
this.system.keyframesJson = merge.keyframesJson;
|
|
482
470
|
this.externalKeyframesDiagnostics = merge.diagnostics;
|
|
483
471
|
}
|
|
@@ -490,7 +478,9 @@ var PluginContext = class {
|
|
|
490
478
|
storedTransformsSource = "{}";
|
|
491
479
|
systemPropsModuleMemo = null;
|
|
492
480
|
fileCache = /* @__PURE__ */ new Map();
|
|
481
|
+
rawExtensionFallbacks = /* @__PURE__ */ new Set();
|
|
493
482
|
hotUpdateEvents = new HotUpdateEvents();
|
|
483
|
+
pendingReloadTimer = null;
|
|
494
484
|
packageMap = {};
|
|
495
485
|
base = "/";
|
|
496
486
|
assetUrlBySpecifier = /* @__PURE__ */ new Map();
|
|
@@ -500,6 +490,7 @@ var PluginContext = class {
|
|
|
500
490
|
externalDirOwners = {};
|
|
501
491
|
externalFileOwners = {};
|
|
502
492
|
externalSourceEntries = /* @__PURE__ */ new Map();
|
|
493
|
+
externalKeyframesScanEntries = /* @__PURE__ */ new Map();
|
|
503
494
|
externalPackageOutcomes = [];
|
|
504
495
|
devServer;
|
|
505
496
|
resolvedSystemPath = null;
|
|
@@ -589,6 +580,7 @@ var PluginContext = class {
|
|
|
589
580
|
this.systemDependencyKeys = keys;
|
|
590
581
|
this.systemDependencyPaths = deps;
|
|
591
582
|
this.registerSystemWatchPaths();
|
|
583
|
+
this.consumerKeyframesJson = this.system.keyframesJson;
|
|
592
584
|
this.applyExternalKeyframes();
|
|
593
585
|
} catch (e) {
|
|
594
586
|
if (this.options.strict) throw new Error(`[animus-extract] Failed to load system from ${this.resolvedSystemPath}: ${e}`, { cause: e });
|
|
@@ -598,7 +590,12 @@ var PluginContext = class {
|
|
|
598
590
|
}
|
|
599
591
|
/**
|
|
600
592
|
* Run project analysis via the shared `runProjectAnalysis` and update
|
|
601
|
-
* all manifest-derived state.
|
|
593
|
+
* all manifest-derived state. Returns whether the analysis PUBLISHED —
|
|
594
|
+
* `false` means the previous manifest is still current, and callers that
|
|
595
|
+
* advanced the file cache for this attempt must roll that entry back or
|
|
596
|
+
* the content-hash gate will suppress the same-content retry forever
|
|
597
|
+
* (openspec: dev-transform-coherence, "Failed analyses do not suppress
|
|
598
|
+
* equal-content retries"). Strict mode still throws.
|
|
602
599
|
*/
|
|
603
600
|
runAnalysis(fileEntries) {
|
|
604
601
|
try {
|
|
@@ -629,11 +626,12 @@ var PluginContext = class {
|
|
|
629
626
|
} catch (e) {
|
|
630
627
|
if (this.options.strict) throw new Error(`[animus-extract] analyzeProject failed: ${e}`, { cause: e });
|
|
631
628
|
console.warn("[animus-extract] analyzeProject failed:", e);
|
|
632
|
-
return;
|
|
629
|
+
return false;
|
|
633
630
|
}
|
|
634
631
|
this.systemPropsModuleMemo = generateSystemPropsModule(this);
|
|
635
632
|
this.applyAssetSubstitutions();
|
|
636
633
|
this.enforceExternalTokenContracts();
|
|
634
|
+
return true;
|
|
637
635
|
}
|
|
638
636
|
/** Base-prefixed dev URL for an absolute file (Vite mounts /@fs under base). */
|
|
639
637
|
devFsUrl(absPath) {
|
|
@@ -781,7 +779,9 @@ var PluginContext = class {
|
|
|
781
779
|
const mod = server.moduleGraph.getModuleById(moduleId);
|
|
782
780
|
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
783
781
|
}
|
|
784
|
-
|
|
782
|
+
if (this.pendingReloadTimer) return;
|
|
783
|
+
this.pendingReloadTimer = setTimeout(() => {
|
|
784
|
+
this.pendingReloadTimer = null;
|
|
785
785
|
this.devServer?.hot?.send({ type: "full-reload" });
|
|
786
786
|
}, 100);
|
|
787
787
|
}
|
|
@@ -849,6 +849,212 @@ var PluginContext = class {
|
|
|
849
849
|
}
|
|
850
850
|
};
|
|
851
851
|
//#endregion
|
|
852
|
+
//#region src/module-invalidation.ts
|
|
853
|
+
/**
|
|
854
|
+
* Evict every module node the dev server holds for each file — every
|
|
855
|
+
* environment graph (client, ssr, and any custom environment), by-file node
|
|
856
|
+
* sets (covers query-suffixed variants), plus the absolute-path id lookup.
|
|
857
|
+
* Falls back to the mixed compat graph for hosts without environment
|
|
858
|
+
* graphs. Returns the number of nodes invalidated.
|
|
859
|
+
*
|
|
860
|
+
* Completeness here is load-bearing: the file-plan diff is the ONLY
|
|
861
|
+
* invalidation candidate source, so a node shape this enumeration misses
|
|
862
|
+
* stays stale for the life of the server (openspec: dev-transform-coherence,
|
|
863
|
+
* "Client and SSR nodes are both evicted").
|
|
864
|
+
*/
|
|
865
|
+
function invalidateFileModules(ctx, relPaths) {
|
|
866
|
+
const server = ctx.devServer;
|
|
867
|
+
if (!server || relPaths.length === 0) return 0;
|
|
868
|
+
const graphs = server.environments ? Object.values(server.environments).map((env) => env?.moduleGraph).filter(Boolean) : [server.moduleGraph].filter(Boolean);
|
|
869
|
+
let total = 0;
|
|
870
|
+
for (const relPath of relPaths) {
|
|
871
|
+
const absPath = (0, path.resolve)(ctx.rootDir, relPath);
|
|
872
|
+
let fileCount = 0;
|
|
873
|
+
for (const graph of graphs) {
|
|
874
|
+
const nodes = /* @__PURE__ */ new Set();
|
|
875
|
+
const byFile = graph.getModulesByFile?.(absPath);
|
|
876
|
+
if (byFile) for (const mod of byFile) nodes.add(mod);
|
|
877
|
+
const byId = graph.getModuleById?.(absPath);
|
|
878
|
+
if (byId) nodes.add(byId);
|
|
879
|
+
for (const mod of nodes) {
|
|
880
|
+
graph.invalidateModule(mod);
|
|
881
|
+
fileCount++;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
if (fileCount > 0) ctx.log(`HMR invalidate: ${relPath} (plan changed, ${fileCount} nodes)`);
|
|
885
|
+
total += fileCount;
|
|
886
|
+
}
|
|
887
|
+
return total;
|
|
888
|
+
}
|
|
889
|
+
//#endregion
|
|
890
|
+
//#region src/rediscovery.ts
|
|
891
|
+
/** The current manifest's unresolved-parent drops, parsed from diagnostics
|
|
892
|
+
* (shared Rust-mirror matcher — the regex lives in manifest-diagnostics). */
|
|
893
|
+
function unresolvedParentDrops(ctx) {
|
|
894
|
+
const drops = [];
|
|
895
|
+
for (const d of ctx.storedManifest?.diagnostics ?? []) {
|
|
896
|
+
const parent = (0, _animus_ui_extract_pipeline.unresolvedParentName)(d);
|
|
897
|
+
if (parent !== null) drops.push({
|
|
898
|
+
file: String(d.file ?? ""),
|
|
899
|
+
component: String(d.component ?? ""),
|
|
900
|
+
parent
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
return drops;
|
|
904
|
+
}
|
|
905
|
+
const EMPTY_DROP_FILES = /* @__PURE__ */ new Set();
|
|
906
|
+
const dropFilesByManifest = /* @__PURE__ */ new WeakMap();
|
|
907
|
+
/** Files carrying an unresolved-parent drop in the CURRENT manifest —
|
|
908
|
+
* derived once per manifest publication, then a set lookup. */
|
|
909
|
+
function unresolvedDropFiles(ctx) {
|
|
910
|
+
const manifest = ctx.storedManifest;
|
|
911
|
+
if (!manifest) return EMPTY_DROP_FILES;
|
|
912
|
+
let files = dropFilesByManifest.get(manifest);
|
|
913
|
+
if (!files) {
|
|
914
|
+
const derived = /* @__PURE__ */ new Set();
|
|
915
|
+
for (const d of manifest.diagnostics ?? []) if ((0, _animus_ui_extract_pipeline.isUnresolvedParentDrop)(d)) derived.add(String(d.file ?? ""));
|
|
916
|
+
files = derived;
|
|
917
|
+
dropFilesByManifest.set(manifest, files);
|
|
918
|
+
}
|
|
919
|
+
return files;
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Reconcile the discoverable on-disk source universe before an
|
|
923
|
+
* unresolved-parent result is acted on (openspec: dev-transform-coherence,
|
|
924
|
+
* "Source-universe reconciliation precedes unresolved-parent fallbacks").
|
|
925
|
+
*
|
|
926
|
+
* Drop-triggered: runs only when the current manifest reports `chain
|
|
927
|
+
* dropped: could not resolve parent component`. One discovery walk (the
|
|
928
|
+
* same walk and policy the server start uses) folds every eligible on-disk
|
|
929
|
+
* file the cache does not know, then one re-analysis resolves the whole
|
|
930
|
+
* extension graph — dependency depth never requires iteration depth, so the
|
|
931
|
+
* loop re-enters only when a re-analysis leaves NEW drops and the previous
|
|
932
|
+
* walk actually folded something (a changed discovery domain). The
|
|
933
|
+
* iteration cap is containment, not semantics.
|
|
934
|
+
*
|
|
935
|
+
* Synchronous by design — it runs inside the sync `transform` hook. `.mdx`
|
|
936
|
+
* sources need async preprocessing and are not folded here (they ingest on
|
|
937
|
+
* their first watcher edit).
|
|
938
|
+
*
|
|
939
|
+
* Returns whether any re-analysis ran (callers diff plans across the WHOLE
|
|
940
|
+
* transaction, so a fold-and-reanalyze is invisible to them beyond the
|
|
941
|
+
* final manifest).
|
|
942
|
+
*/
|
|
943
|
+
function stabilizeSourceUniverse(ctx) {
|
|
944
|
+
if (ctx.isProd) return false;
|
|
945
|
+
let reanalyzed = false;
|
|
946
|
+
for (let iteration = 0; iteration < 3; iteration++) {
|
|
947
|
+
if (unresolvedDropFiles(ctx).size === 0) {
|
|
948
|
+
warnedVerdicts.get(ctx)?.clear();
|
|
949
|
+
return reanalyzed;
|
|
950
|
+
}
|
|
951
|
+
const drops = unresolvedParentDrops(ctx);
|
|
952
|
+
const dropKey = drops.map((d) => `${d.file}\0${d.component}\0${d.parent}`).sort().join("\n");
|
|
953
|
+
const memo = barrenWalkMemos.get(ctx);
|
|
954
|
+
if (memo && memo.dropKey === dropKey && memo.cacheSize === ctx.fileCache.size) return reanalyzed;
|
|
955
|
+
const folded = foldUndiscoveredFiles(ctx);
|
|
956
|
+
if (folded === 0) {
|
|
957
|
+
barrenWalkMemos.set(ctx, {
|
|
958
|
+
dropKey,
|
|
959
|
+
cacheSize: ctx.fileCache.size
|
|
960
|
+
});
|
|
961
|
+
warnInadmissibleParents(ctx, drops);
|
|
962
|
+
return reanalyzed;
|
|
963
|
+
}
|
|
964
|
+
barrenWalkMemos.delete(ctx);
|
|
965
|
+
ctx.log(`rediscovery: folded ${folded} on-disk file(s) after unresolved-parent drop`);
|
|
966
|
+
reanalyzed = true;
|
|
967
|
+
if (ctx.runAnalysis(buildFileEntriesFromCache(ctx.fileCache)) === false) return reanalyzed;
|
|
968
|
+
}
|
|
969
|
+
if (unresolvedDropFiles(ctx).size > 0) ctx.warn("source-universe rediscovery did not stabilize after bounded retries");
|
|
970
|
+
return reanalyzed;
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* One discovery walk over the project root with the server-start policy;
|
|
974
|
+
* folds every eligible file `fileCache` does not hold. Returns the fold
|
|
975
|
+
* count.
|
|
976
|
+
*/
|
|
977
|
+
function foldUndiscoveredFiles(ctx) {
|
|
978
|
+
const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
|
|
979
|
+
const filePaths = (0, _animus_ui_extract_pipeline.discoverFiles)(ctx.rootDir, ctx.rootDir, excludePatterns, ctx.extensionsSet);
|
|
980
|
+
let folded = 0;
|
|
981
|
+
for (const filePath of filePaths) {
|
|
982
|
+
if ((0, path.extname)(filePath) === ".mdx") continue;
|
|
983
|
+
const relPath = (0, path.relative)(ctx.rootDir, filePath);
|
|
984
|
+
if (ctx.fileCache.has(relPath)) continue;
|
|
985
|
+
let source;
|
|
986
|
+
try {
|
|
987
|
+
source = (0, fs.readFileSync)(filePath, "utf-8");
|
|
988
|
+
} catch {
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
991
|
+
ctx.fileCache.set(relPath, {
|
|
992
|
+
hash: (0, _animus_ui_extract_pipeline.contentHash)(source),
|
|
993
|
+
source
|
|
994
|
+
});
|
|
995
|
+
folded++;
|
|
996
|
+
}
|
|
997
|
+
return folded;
|
|
998
|
+
}
|
|
999
|
+
/** Barren-walk memo per context: the drop tuple-set and cache size at the
|
|
1000
|
+
* last walk that folded nothing (see stabilizeSourceUniverse). */
|
|
1001
|
+
const barrenWalkMemos = /* @__PURE__ */ new WeakMap();
|
|
1002
|
+
/** Per-context (file, parent, condition) verdicts already warned — each
|
|
1003
|
+
* condition warns once; cleared when the drops disappear. */
|
|
1004
|
+
const warnedVerdicts = /* @__PURE__ */ new WeakMap();
|
|
1005
|
+
/** The narrow probe set is deliberate — NOT ctx.extensionsSet (conscious
|
|
1006
|
+
* no-behavior-change choice: the teaching probe resolves what it always did). */
|
|
1007
|
+
const PARENT_PROBE_EXTENSIONS = new Set([
|
|
1008
|
+
".tsx",
|
|
1009
|
+
".ts",
|
|
1010
|
+
".jsx",
|
|
1011
|
+
".js"
|
|
1012
|
+
]);
|
|
1013
|
+
/**
|
|
1014
|
+
* The teaching half for parents that RESOLVE on disk but cannot be admitted
|
|
1015
|
+
* (excluded by configuration, unsupported source type, outside the root).
|
|
1016
|
+
* Resolution is a best-effort scan of the consumer's own import statements
|
|
1017
|
+
* for the parent binding — enough for the relative-specifier case a
|
|
1018
|
+
* developer actually hits; a parent this scan cannot resolve keeps the
|
|
1019
|
+
* engine's own diagnostic.
|
|
1020
|
+
*/
|
|
1021
|
+
function warnInadmissibleParents(ctx, drops) {
|
|
1022
|
+
const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
|
|
1023
|
+
let warned = warnedVerdicts.get(ctx);
|
|
1024
|
+
if (!warned) {
|
|
1025
|
+
warned = /* @__PURE__ */ new Set();
|
|
1026
|
+
warnedVerdicts.set(ctx, warned);
|
|
1027
|
+
}
|
|
1028
|
+
const active = new Set(drops.map((d) => `${d.file}\0${d.parent}`));
|
|
1029
|
+
for (const key of [...warned]) if (!active.has(key.slice(0, key.lastIndexOf("\0")))) warned.delete(key);
|
|
1030
|
+
for (const drop of drops) {
|
|
1031
|
+
const consumer = ctx.fileCache.get(drop.file);
|
|
1032
|
+
if (!consumer) continue;
|
|
1033
|
+
const specifier = importSpecifierFor(consumer.source, drop.parent);
|
|
1034
|
+
if (!specifier || !specifier.startsWith(".")) continue;
|
|
1035
|
+
const resolved = (0, _animus_ui_extract_pipeline.resolveAbsolutePathSpecifier)((0, path.resolve)(ctx.rootDir, (0, path.dirname)(drop.file), specifier), PARENT_PROBE_EXTENSIONS);
|
|
1036
|
+
if (!resolved) continue;
|
|
1037
|
+
const relPath = (0, path.relative)(ctx.rootDir, resolved);
|
|
1038
|
+
const excludedBy = excludePatterns.find((pattern) => resolved.includes(pattern) || relPath.includes(pattern));
|
|
1039
|
+
const reason = excludedBy ? `which is excluded by pattern '${excludedBy}'. Include that file in the extraction universe or remove this extension.` : !(0, _animus_ui_extract_pipeline.isPathWithinRoot)(ctx.rootDir, resolved) ? "outside the extraction root. Declare its package in the system includes or move it under the project root." : !ctx.extensionsSet.has((0, path.extname)(resolved)) ? `whose extension is not in the configured source extensions.` : null;
|
|
1040
|
+
if (reason === null) continue;
|
|
1041
|
+
const verdictKey = `${drop.file}\0${drop.parent}\0${reason}`;
|
|
1042
|
+
if (warned.has(verdictKey)) continue;
|
|
1043
|
+
warned.add(verdictKey);
|
|
1044
|
+
ctx.warn(`cannot extract '${drop.component}': parent '${drop.parent}' resolves to ${relPath}, ${reason}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/** The module specifier a named import binds `binding` from, if scannable. */
|
|
1048
|
+
function importSpecifierFor(source, binding) {
|
|
1049
|
+
const importRe = /import\s+([^;]+?)\s+from\s+['"]([^'"]+)['"]/g;
|
|
1050
|
+
let match;
|
|
1051
|
+
while ((match = importRe.exec(source)) !== null) {
|
|
1052
|
+
const clause = match[1];
|
|
1053
|
+
if (new RegExp(`[{,\\s]${binding}[,\\s}]|^${binding}$`).test(clause)) return match[2];
|
|
1054
|
+
}
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
//#endregion
|
|
852
1058
|
//#region src/transform.ts
|
|
853
1059
|
/**
|
|
854
1060
|
* The dev-mode bridge prepend, shared with the hot-update gate so both
|
|
@@ -863,6 +1069,27 @@ function applyDevBridgeImport(code) {
|
|
|
863
1069
|
return prologue + `import '${VIRTUAL_BRIDGE_ID}';\n` + code.slice(prologue.length);
|
|
864
1070
|
}
|
|
865
1071
|
/**
|
|
1072
|
+
* Live raw-fallback files reachable from `relPath`'s components through
|
|
1073
|
+
* extension provenance — the transitive closure, so a grandparent's serve is
|
|
1074
|
+
* withheld exactly like a direct parent's.
|
|
1075
|
+
*/
|
|
1076
|
+
function rawFallbackDescendants(ctx, relPath) {
|
|
1077
|
+
const conflicted = /* @__PURE__ */ new Set();
|
|
1078
|
+
const queue = [...ctx.storedManifest?.files?.[relPath] ?? []];
|
|
1079
|
+
const seen = new Set(queue);
|
|
1080
|
+
while (queue.length > 0) {
|
|
1081
|
+
const id = queue.shift();
|
|
1082
|
+
for (const childId of ctx.reverseProvenance[id] ?? []) {
|
|
1083
|
+
if (seen.has(childId)) continue;
|
|
1084
|
+
seen.add(childId);
|
|
1085
|
+
queue.push(childId);
|
|
1086
|
+
const childFile = ctx.storedManifest?.components?.[childId]?.file;
|
|
1087
|
+
if (childFile && childFile !== relPath && ctx.rawExtensionFallbacks.has(childFile)) conflicted.add(childFile);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return [...conflicted].sort();
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
866
1093
|
* transform: replace builder chains with `createComponent()` calls using
|
|
867
1094
|
* the pre-built manifest; detect files created after buildStart and fold
|
|
868
1095
|
* them into the analysis.
|
|
@@ -875,17 +1102,17 @@ function applyDevBridgeImport(code) {
|
|
|
875
1102
|
function transformSource(ctx, code, id) {
|
|
876
1103
|
if (!ctx.storedManifest) return null;
|
|
877
1104
|
if (id.startsWith("\0") || id.startsWith("virtual:animus/")) return null;
|
|
878
|
-
const isExternalPkg = ctx.externalPackageDirs.some((dir) =>
|
|
1105
|
+
const isExternalPkg = ctx.externalPackageDirs.some((dir) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, id));
|
|
879
1106
|
const relativePath = (0, path.relative)(ctx.rootDir, id);
|
|
880
1107
|
if (!isExternalPkg) {
|
|
881
1108
|
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
882
1109
|
if (id.includes("node_modules")) return null;
|
|
883
|
-
if (
|
|
1110
|
+
if (!(0, _animus_ui_extract_pipeline.isPathWithinRoot)(ctx.rootDir, id)) return null;
|
|
884
1111
|
}
|
|
885
1112
|
if (!ctx.storedManifest.files?.[relativePath]?.length) {
|
|
886
1113
|
if (!ctx.isProd && !ctx.fileCache.has(relativePath)) {
|
|
887
1114
|
if (isExternalPkg) {
|
|
888
|
-
const owner = Object.entries(ctx.externalDirOwners).find(([dir]) =>
|
|
1115
|
+
const owner = Object.entries(ctx.externalDirOwners).find(([dir]) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, id));
|
|
889
1116
|
if (owner) ctx.externalFileOwners[relativePath] = owner[1];
|
|
890
1117
|
}
|
|
891
1118
|
const hash = (0, _animus_ui_extract_pipeline.contentHash)(code);
|
|
@@ -893,13 +1120,36 @@ function transformSource(ctx, code, id) {
|
|
|
893
1120
|
hash,
|
|
894
1121
|
source: code
|
|
895
1122
|
});
|
|
1123
|
+
const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest);
|
|
896
1124
|
const fileEntries = buildFileEntriesFromCache(ctx.fileCache, relativePath);
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1125
|
+
let analysisOk = false;
|
|
1126
|
+
try {
|
|
1127
|
+
analysisOk = ctx.runAnalysis(fileEntries) !== false;
|
|
1128
|
+
} finally {
|
|
1129
|
+
if (!analysisOk) ctx.fileCache.delete(relativePath);
|
|
1130
|
+
}
|
|
1131
|
+
if (analysisOk) {
|
|
1132
|
+
stabilizeSourceUniverse(ctx);
|
|
1133
|
+
invalidateFileModules(ctx, (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest), { exclude: relativePath }));
|
|
1134
|
+
const compCount = ctx.storedManifest.files?.[relativePath]?.length ?? 0;
|
|
1135
|
+
ctx.info(`New file detected: ${relativePath} — ${compCount ? `${compCount} components extracted` : "no components"}`);
|
|
1136
|
+
ctx.invalidateExtractedModules();
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
if (!ctx.storedManifest.files?.[relativePath]?.length) {
|
|
1140
|
+
if (!ctx.isProd) if (unresolvedDropFiles(ctx).has(relativePath)) ctx.rawExtensionFallbacks.add(relativePath);
|
|
1141
|
+
else ctx.rawExtensionFallbacks.delete(relativePath);
|
|
1142
|
+
return null;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (!ctx.isProd && ctx.rawExtensionFallbacks.size > 0) {
|
|
1146
|
+
const conflicted = rawFallbackDescendants(ctx, relativePath);
|
|
1147
|
+
if (conflicted.length > 0) {
|
|
1148
|
+
invalidateFileModules(ctx, conflicted);
|
|
900
1149
|
ctx.invalidateExtractedModules();
|
|
1150
|
+
for (const file of conflicted) ctx.rawExtensionFallbacks.delete(file);
|
|
1151
|
+
throw new Error(`ANIMUS_COMPOSITION_RECOVERING: '${relativePath}' extracted while extension consumer(s) ${conflicted.join(", ")} are still serving the runtime fallback — recovering via reload; this resolves on the next request.`);
|
|
901
1152
|
}
|
|
902
|
-
if (!ctx.storedManifest.files?.[relativePath]?.length) return null;
|
|
903
1153
|
}
|
|
904
1154
|
try {
|
|
905
1155
|
const { transformFile } = ctx.engineApi();
|
|
@@ -913,6 +1163,7 @@ function transformSource(ctx, code, id) {
|
|
|
913
1163
|
if (!ctx.isProd) {
|
|
914
1164
|
outputCode = applyDevBridgeImport(result.code);
|
|
915
1165
|
ctx.recordTransformOutput(relativePath, outputCode);
|
|
1166
|
+
ctx.rawExtensionFallbacks.delete(relativePath);
|
|
916
1167
|
}
|
|
917
1168
|
return {
|
|
918
1169
|
code: outputCode,
|
|
@@ -957,7 +1208,6 @@ async function handleHotUpdate(ctx, environment, { type, file, timestamp, module
|
|
|
957
1208
|
}
|
|
958
1209
|
return [];
|
|
959
1210
|
}
|
|
960
|
-
if (type === "create") return;
|
|
961
1211
|
if (type === "delete") {
|
|
962
1212
|
if (ownsEvent) pruneDeletedFile(ctx, absFile);
|
|
963
1213
|
return;
|
|
@@ -1028,7 +1278,8 @@ async function analyzeChangedFile(ctx, file, absFile, read) {
|
|
|
1028
1278
|
const ext = (0, path.extname)(file);
|
|
1029
1279
|
if (!ctx.extensionsSet.has(ext)) return { kind: "ignored" };
|
|
1030
1280
|
const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
|
|
1031
|
-
|
|
1281
|
+
const isExternalPkg = ctx.externalPackageDirs.some((dir) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, file));
|
|
1282
|
+
if (!isExternalPkg && excludePatterns.some((pattern) => file.includes(pattern) || (0, path.relative)(ctx.rootDir, file).includes(pattern))) return { kind: "ignored" };
|
|
1032
1283
|
const relPath = (0, path.relative)(ctx.rootDir, absFile);
|
|
1033
1284
|
let source;
|
|
1034
1285
|
try {
|
|
@@ -1056,13 +1307,20 @@ async function analyzeChangedFile(ctx, file, absFile, read) {
|
|
|
1056
1307
|
ctx.log(`HMR skip: ${scannerRelPath} (unchanged)`);
|
|
1057
1308
|
return { kind: "unchanged" };
|
|
1058
1309
|
}
|
|
1310
|
+
if (isExternalPkg && !ctx.externalFileOwners[scannerRelPath]) {
|
|
1311
|
+
const owner = Object.entries(ctx.externalDirOwners).find(([dir]) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, absFile));
|
|
1312
|
+
if (owner) ctx.externalFileOwners[scannerRelPath] = owner[1];
|
|
1313
|
+
}
|
|
1059
1314
|
ctx.fileCache.set(scannerRelPath, {
|
|
1060
1315
|
hash,
|
|
1061
1316
|
source
|
|
1062
1317
|
});
|
|
1318
|
+
const restoreEntry = () => {
|
|
1319
|
+
if (cached) ctx.fileCache.set(scannerRelPath, cached);
|
|
1320
|
+
else ctx.fileCache.delete(scannerRelPath);
|
|
1321
|
+
};
|
|
1063
1322
|
const hmrStart = performance.now();
|
|
1064
|
-
const
|
|
1065
|
-
if (ctx.storedManifest?.components) for (const [id, desc] of Object.entries(ctx.storedManifest.components)) prevReplacements.set(id, desc.replacement ?? "");
|
|
1323
|
+
const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest);
|
|
1066
1324
|
const directComponentIds = ctx.storedManifest?.files?.[scannerRelPath] ?? [];
|
|
1067
1325
|
const invalidatedIds = new Set(directComponentIds);
|
|
1068
1326
|
const queue = [...directComponentIds];
|
|
@@ -1078,17 +1336,23 @@ async function analyzeChangedFile(ctx, file, absFile, read) {
|
|
|
1078
1336
|
}
|
|
1079
1337
|
if (ctx.verbose && invalidatedIds.size > directComponentIds.length) ctx.log(`HMR: ${directComponentIds.length} direct + ${invalidatedIds.size - directComponentIds.length} transitive components invalidated`);
|
|
1080
1338
|
const analysisStart = performance.now();
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
staleDefinitionFiles.push(defFile);
|
|
1090
|
-
}
|
|
1339
|
+
const fileEntries = buildFileEntriesFromCache(ctx.fileCache, relPath);
|
|
1340
|
+
const systemPropsBefore = systemPropsModuleSource(ctx);
|
|
1341
|
+
let analysisOk;
|
|
1342
|
+
try {
|
|
1343
|
+
analysisOk = ctx.runAnalysis(fileEntries) !== false;
|
|
1344
|
+
} catch (e) {
|
|
1345
|
+
restoreEntry();
|
|
1346
|
+
throw e;
|
|
1091
1347
|
}
|
|
1348
|
+
if (!analysisOk) {
|
|
1349
|
+
restoreEntry();
|
|
1350
|
+
return { kind: "ignored" };
|
|
1351
|
+
}
|
|
1352
|
+
stabilizeSourceUniverse(ctx);
|
|
1353
|
+
const systemPropsChanged = systemPropsModuleSource(ctx) !== systemPropsBefore;
|
|
1354
|
+
const analysisMs = Math.round(performance.now() - analysisStart);
|
|
1355
|
+
const staleDefinitionFiles = (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest)).filter((defFile) => (0, path.resolve)(ctx.rootDir, defFile) !== absFile);
|
|
1092
1356
|
const presentationOnly = isPresentationOnlyEdit(ctx, scannerRelPath, source);
|
|
1093
1357
|
const hmrMs = Math.round(performance.now() - hmrStart);
|
|
1094
1358
|
ctx.log(`HMR update: ${relPath} — analysis ${analysisMs}ms, total ${hmrMs}ms${presentationOnly ? " (presentation-only)" : ""}`);
|
|
@@ -1136,8 +1400,10 @@ function isPresentationOnlyEdit(ctx, scannerRelPath, source) {
|
|
|
1136
1400
|
*/
|
|
1137
1401
|
function pruneDeletedFile(ctx, absFile) {
|
|
1138
1402
|
if (!pruneFileCache(ctx.fileCache, ctx.rootDir, absFile)) return;
|
|
1139
|
-
|
|
1403
|
+
const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest);
|
|
1404
|
+
const ok = ctx.runAnalysis(buildFileEntriesFromCache(ctx.fileCache)) !== false;
|
|
1140
1405
|
ctx.log(`Deleted file pruned: ${(0, path.relative)(ctx.rootDir, absFile)}`);
|
|
1406
|
+
if (ok) invalidateFileModules(ctx, (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest)));
|
|
1141
1407
|
ctx.invalidateExtractedModules();
|
|
1142
1408
|
}
|
|
1143
1409
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PluginContext } from './context';
|
|
2
|
+
/**
|
|
3
|
+
* Evict every module node the dev server holds for each file — every
|
|
4
|
+
* environment graph (client, ssr, and any custom environment), by-file node
|
|
5
|
+
* sets (covers query-suffixed variants), plus the absolute-path id lookup.
|
|
6
|
+
* Falls back to the mixed compat graph for hosts without environment
|
|
7
|
+
* graphs. Returns the number of nodes invalidated.
|
|
8
|
+
*
|
|
9
|
+
* Completeness here is load-bearing: the file-plan diff is the ONLY
|
|
10
|
+
* invalidation candidate source, so a node shape this enumeration misses
|
|
11
|
+
* stays stale for the life of the server (openspec: dev-transform-coherence,
|
|
12
|
+
* "Client and SSR nodes are both evicted").
|
|
13
|
+
*/
|
|
14
|
+
export declare function invalidateFileModules(ctx: PluginContext, relPaths: string[]): number;
|
|
15
|
+
//# sourceMappingURL=module-invalidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-invalidation.d.ts","sourceRoot":"","sources":["../src/module-invalidation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,CAmCR"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PluginContext } from './context';
|
|
2
|
+
interface UnresolvedParentDrop {
|
|
3
|
+
/** rootDir-relative consumer file the diagnostic names. */
|
|
4
|
+
file: string;
|
|
5
|
+
/** The dropped child component binding. */
|
|
6
|
+
component: string;
|
|
7
|
+
/** The parent binding as written in the consumer. */
|
|
8
|
+
parent: string;
|
|
9
|
+
}
|
|
10
|
+
/** The current manifest's unresolved-parent drops, parsed from diagnostics
|
|
11
|
+
* (shared Rust-mirror matcher — the regex lives in manifest-diagnostics). */
|
|
12
|
+
export declare function unresolvedParentDrops(ctx: PluginContext): UnresolvedParentDrop[];
|
|
13
|
+
/** Files carrying an unresolved-parent drop in the CURRENT manifest —
|
|
14
|
+
* derived once per manifest publication, then a set lookup. */
|
|
15
|
+
export declare function unresolvedDropFiles(ctx: PluginContext): ReadonlySet<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Reconcile the discoverable on-disk source universe before an
|
|
18
|
+
* unresolved-parent result is acted on (openspec: dev-transform-coherence,
|
|
19
|
+
* "Source-universe reconciliation precedes unresolved-parent fallbacks").
|
|
20
|
+
*
|
|
21
|
+
* Drop-triggered: runs only when the current manifest reports `chain
|
|
22
|
+
* dropped: could not resolve parent component`. One discovery walk (the
|
|
23
|
+
* same walk and policy the server start uses) folds every eligible on-disk
|
|
24
|
+
* file the cache does not know, then one re-analysis resolves the whole
|
|
25
|
+
* extension graph — dependency depth never requires iteration depth, so the
|
|
26
|
+
* loop re-enters only when a re-analysis leaves NEW drops and the previous
|
|
27
|
+
* walk actually folded something (a changed discovery domain). The
|
|
28
|
+
* iteration cap is containment, not semantics.
|
|
29
|
+
*
|
|
30
|
+
* Synchronous by design — it runs inside the sync `transform` hook. `.mdx`
|
|
31
|
+
* sources need async preprocessing and are not folded here (they ingest on
|
|
32
|
+
* their first watcher edit).
|
|
33
|
+
*
|
|
34
|
+
* Returns whether any re-analysis ran (callers diff plans across the WHOLE
|
|
35
|
+
* transaction, so a fold-and-reanalyze is invisible to them beyond the
|
|
36
|
+
* final manifest).
|
|
37
|
+
*/
|
|
38
|
+
export declare function stabilizeSourceUniverse(ctx: PluginContext): boolean;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=rediscovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rediscovery.d.ts","sourceRoot":"","sources":["../src/rediscovery.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,oBAAoB;IAC5B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;8EAC8E;AAC9E,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,GACjB,oBAAoB,EAAE,CAcxB;AASD;gEACgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAc3E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CA6DnE"}
|
package/dist/transform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzD;AAiCD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CA4LpC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@animus-ui/vite-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Animus static CSS extraction Vite plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"animus",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"compile": "tsc --noEmit"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@animus-ui/extract": "0.1.
|
|
42
|
+
"@animus-ui/extract": "0.1.8",
|
|
43
43
|
"browserslist": "^4.24.0",
|
|
44
44
|
"lightningcss": "^1.29.0"
|
|
45
45
|
},
|