@animus-ui/extract 0.1.24 → 0.1.26
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/crates/extract-v2/animus-extract-v2.darwin-arm64.node +0 -0
- package/crates/extract-v2/animus-extract-v2.linux-arm64-gnu.node +0 -0
- package/crates/extract-v2/animus-extract-v2.linux-x64-gnu.node +0 -0
- package/crates/extract-v2/index.d.ts +107 -6
- package/dist/index.cjs +48 -5
- package/dist/index.mjs +2 -2
- package/dist/pipeline/alias-agreement.d.ts +107 -0
- package/dist/pipeline/alias-agreement.d.ts.map +1 -0
- package/dist/pipeline/analyze-project-args.d.ts +11 -2
- package/dist/pipeline/analyze-project-args.d.ts.map +1 -1
- package/dist/pipeline/asset-copies.d.ts +20 -0
- package/dist/pipeline/asset-copies.d.ts.map +1 -0
- package/dist/pipeline/built-in-asset-types.d.ts +9 -0
- package/dist/pipeline/built-in-asset-types.d.ts.map +1 -0
- package/dist/pipeline/core-options.d.ts +31 -7
- package/dist/pipeline/core-options.d.ts.map +1 -1
- package/dist/pipeline/discover-packages.d.ts +98 -12
- package/dist/pipeline/discover-packages.d.ts.map +1 -1
- package/dist/pipeline/engine-adapter.d.ts +41 -3
- package/dist/pipeline/engine-adapter.d.ts.map +1 -1
- package/dist/pipeline/engine-retirement.d.ts +7 -1
- package/dist/pipeline/engine-retirement.d.ts.map +1 -1
- package/dist/pipeline/extension-policy.d.ts +95 -0
- package/dist/pipeline/extension-policy.d.ts.map +1 -0
- package/dist/pipeline/host-assets.d.ts +32 -0
- package/dist/pipeline/host-assets.d.ts.map +1 -0
- package/dist/pipeline/host-expansions.d.ts +92 -0
- package/dist/pipeline/host-expansions.d.ts.map +1 -0
- package/dist/pipeline/host-extensions.d.ts +64 -0
- package/dist/pipeline/host-extensions.d.ts.map +1 -0
- package/dist/pipeline/host-package-resolver.d.ts +40 -0
- package/dist/pipeline/host-package-resolver.d.ts.map +1 -0
- package/dist/pipeline/index.d.ts +32 -8
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/kit-publication.d.ts.map +1 -1
- package/dist/pipeline/manifest-diagnostics.d.ts +27 -6
- package/dist/pipeline/manifest-diagnostics.d.ts.map +1 -1
- package/dist/pipeline/manifest-schema.d.ts +16 -0
- package/dist/pipeline/manifest-schema.d.ts.map +1 -1
- package/dist/pipeline/output-targets.d.ts +52 -0
- package/dist/pipeline/output-targets.d.ts.map +1 -0
- package/dist/pipeline/probe-evidence.d.ts +58 -0
- package/dist/pipeline/probe-evidence.d.ts.map +1 -0
- package/dist/pipeline/run-analysis.d.ts +26 -0
- package/dist/pipeline/run-analysis.d.ts.map +1 -1
- package/dist/pipeline/runtime-import.d.ts +10 -0
- package/dist/pipeline/runtime-import.d.ts.map +1 -0
- package/dist/pipeline/served-files.d.ts +16 -0
- package/dist/pipeline/served-files.d.ts.map +1 -0
- package/dist/pipeline/source-corpus.d.ts +4 -0
- package/dist/pipeline/source-corpus.d.ts.map +1 -1
- package/dist/pipeline/source-ingestion.d.ts +37 -5
- package/dist/pipeline/source-ingestion.d.ts.map +1 -1
- package/dist/pipeline/system-config.d.ts +18 -0
- package/dist/pipeline/system-config.d.ts.map +1 -1
- package/dist/pipeline/system-instances.d.ts +27 -0
- package/dist/pipeline/system-instances.d.ts.map +1 -0
- package/dist/pipeline/tsconfig-paths.d.ts +4 -0
- package/dist/pipeline/tsconfig-paths.d.ts.map +1 -1
- package/dist/pipeline/vite-expansions.d.ts +40 -0
- package/dist/pipeline/vite-expansions.d.ts.map +1 -0
- package/dist/pipeline/webpack-expansions.d.ts +55 -0
- package/dist/pipeline/webpack-expansions.d.ts.map +1 -0
- package/dist/pipeline/workspace-packages.d.ts +13 -0
- package/dist/pipeline/workspace-packages.d.ts.map +1 -0
- package/dist/{pipeline-Bl20tbu_.mjs → pipeline-BzMQ_Z0M.mjs} +2293 -751
- package/dist/{pipeline-CAH9mxnK.cjs → pipeline-DyUf-eKZ.cjs} +2564 -746
- package/dist/session/coalescing-window.d.ts +34 -0
- package/dist/session/coalescing-window.d.ts.map +1 -0
- package/dist/session/extraction-session.d.ts +297 -35
- package/dist/session/extraction-session.d.ts.map +1 -1
- package/dist/session/index.d.ts +7 -3
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/published-set.d.ts +6 -1
- package/dist/session/published-set.d.ts.map +1 -1
- package/dist/session/resolve-packages.d.ts +9 -5
- package/dist/session/resolve-packages.d.ts.map +1 -1
- package/dist/session/singleton.d.ts +218 -53
- package/dist/session/singleton.d.ts.map +1 -1
- package/dist/session/turbopack-orchestrator.d.ts.map +1 -1
- package/dist/session.cjs +1462 -510
- package/dist/session.mjs +1430 -489
- package/package.json +4 -4
package/dist/session.mjs
CHANGED
|
@@ -1,7 +1,106 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as excludeCollectedPackages, $t as createSourceIdentity, A as postProcessCss, Bn as __require, C as serializeStaticCss, Ct as tsconfigChainPaths, D as clearEngineCache, Dn as findSheetAssetSpecifiers, Et as extensionPolicyJson, Ft as pruneStaleAssets, G as discoveryResolver, I as createSourceCorpus, It as writeAssetCopy, J as packageInstanceFinding, Jt as outputSourceGuard, K as AliasAgreementCache, Kt as createExcludeMatcher, Ln as assembleStylesheet, M as buildPathAliasesJson, Mt as discoverFiles, N as enforceExternalTokenContracts, Nn as contentHash, Nt as DEFAULT_RUNTIME_IMPORT, O as runProjectAnalysis, On as generatedModuleCode, P as resolveAssetFile, Pn as parseInternalWire, Pt as assertRuntimeImportSuppliesTerminals, Qt as unmatchedExcludeLines, Sn as surfaceManifestDiagnostics, St as readTsconfigAliasPairs, T as stableStringify, X as bareSpecifierPackageName, Xt as resolveMode, Y as packageReadRecord, Yt as outputSourceMessage, Z as collectExternalPackageSources, Zt as resolveVerbosity, _ as buildSystemPropsModule, _t as declaredWorkspacePackages, at as isExcludedPackageRelativePath, b as loadSystemConfig, cn as adaptedOriginals, d as toWatchKeys, dn as isEngineTransformExtension, en as isPathWithinRoot, et as extractSystemFilePackages, f as diffFilePlans, gn as SYSTEM_INSTANCE_MISMATCH, gt as walkPackageSources, ht as unresolvableIncludesMessage, it as importedKitDiagnostics, j as resolveLightningTargets, jn as substituteSheetAssets, kn as reportSurvivingAssetPlaceholders, ln as DEFAULT_EXTENSIONS, lt as nativeKitSourceRoot, m as snapshotFilePlans, nn as createV2EngineApi, nt as findPackageRoot, on as projectExternalFileOwners, ot as isPackageSpecifier, p as hashReplacementPlans, pt as staleDistIncludesMessage, q as compareAliases, rt as firstOwners, s as builtInAssetClassification, tn as sharesVolumeRoot, ut as nativePackageLocator, wn as unreadableSourceDiagnostic, wt as BUILT_IN_EXTENSION_POLICY, x as systemLoadReads, xn as severityFor, yn as isDeletedSource } from "./pipeline-BzMQ_Z0M.mjs";
|
|
2
2
|
import { randomUUID } from "crypto";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, watch, writeFileSync } from "fs";
|
|
4
|
-
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "path";
|
|
4
|
+
import { basename, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "path";
|
|
5
|
+
//#region session/coalescing-window.ts
|
|
6
|
+
/**
|
|
7
|
+
* The one coalescing window (SA19). It opens on the first pending event and
|
|
8
|
+
* fires a fixed interval later: a later event joins the open window and never
|
|
9
|
+
* pushes it back, so a steady stream of edits cannot starve the work it
|
|
10
|
+
* coalesces. Builds, startup and explicit flushes bypass it through `flush`.
|
|
11
|
+
* Hosts add no timers of their own.
|
|
12
|
+
*/
|
|
13
|
+
const COALESCING_WINDOW_MS = 75;
|
|
14
|
+
const SYSTEM_CLOCK = {
|
|
15
|
+
schedule: (fn, ms) => {
|
|
16
|
+
const timer = setTimeout(fn, ms);
|
|
17
|
+
timer.unref?.();
|
|
18
|
+
return timer;
|
|
19
|
+
},
|
|
20
|
+
cancel: (timer) => clearTimeout(timer)
|
|
21
|
+
};
|
|
22
|
+
var CoalescingWindow = class {
|
|
23
|
+
fire;
|
|
24
|
+
windowMs;
|
|
25
|
+
clock;
|
|
26
|
+
timer = null;
|
|
27
|
+
constructor(fire, windowMs = 75, clock = SYSTEM_CLOCK) {
|
|
28
|
+
this.fire = fire;
|
|
29
|
+
this.windowMs = windowMs;
|
|
30
|
+
this.clock = clock;
|
|
31
|
+
}
|
|
32
|
+
/** A pending event: opens the window, or joins the open one. */
|
|
33
|
+
note() {
|
|
34
|
+
if (this.timer !== null) return;
|
|
35
|
+
this.timer = this.clock.schedule(() => {
|
|
36
|
+
this.timer = null;
|
|
37
|
+
return this.fire();
|
|
38
|
+
}, this.windowMs);
|
|
39
|
+
}
|
|
40
|
+
/** Fires now, closing any open window: the bypass. */
|
|
41
|
+
flush() {
|
|
42
|
+
this.cancel();
|
|
43
|
+
return this.fire();
|
|
44
|
+
}
|
|
45
|
+
/** Closes an open window without firing it. */
|
|
46
|
+
cancel() {
|
|
47
|
+
if (this.timer === null) return;
|
|
48
|
+
this.clock.cancel(this.timer);
|
|
49
|
+
this.timer = null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region pipeline/system-instances.ts
|
|
54
|
+
/**
|
|
55
|
+
* The system and the analysis read one instance of each kit (spec §2.2
|
|
56
|
+
* A4). Discovery asks the host which instance a kit specifier names; the
|
|
57
|
+
* system loader resolves the system file's imports itself. Until the loader
|
|
58
|
+
* takes the host's instance, a kit whose analysed instance differs from the
|
|
59
|
+
* one the system evaluated is refused: its components would be extracted
|
|
60
|
+
* against another instance's vocabulary.
|
|
61
|
+
*/
|
|
62
|
+
function realPath(path) {
|
|
63
|
+
try {
|
|
64
|
+
return realpathSync(path);
|
|
65
|
+
} catch {
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* One error for each system-file kit specifier whose analysed package
|
|
71
|
+
* instance is not the one the system load evaluated: the file the loader's
|
|
72
|
+
* own resolution names must be among the files the load read, and lie in
|
|
73
|
+
* another package root than the instance discovery read for its package.
|
|
74
|
+
*/
|
|
75
|
+
function systemInstanceMismatches(input) {
|
|
76
|
+
const evaluated = new Set(input.evaluated.map(realPath));
|
|
77
|
+
const shown = (path) => relative(input.rootDir, path).split(sep).join("/");
|
|
78
|
+
const diagnostics = [];
|
|
79
|
+
for (const specifier of input.specifiers) {
|
|
80
|
+
if (!isPackageSpecifier(specifier)) continue;
|
|
81
|
+
const analysed = input.instances[bareSpecifierPackageName(specifier)];
|
|
82
|
+
if (analysed === void 0) continue;
|
|
83
|
+
let file;
|
|
84
|
+
try {
|
|
85
|
+
file = input.loaderResolve(specifier);
|
|
86
|
+
} catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (file === null || !evaluated.has(realPath(file))) continue;
|
|
90
|
+
const system = realPath(findPackageRoot(realPath(file)));
|
|
91
|
+
if (system === analysed) continue;
|
|
92
|
+
diagnostics.push({
|
|
93
|
+
file: specifier,
|
|
94
|
+
component: "kit",
|
|
95
|
+
kind: "error",
|
|
96
|
+
message: `the system evaluates '${specifier}' from ${shown(system)}, but the host bundler resolves it to ${shown(analysed)}, which extraction analyses, so its components would be extracted against another instance's vocabulary — make the bundler and the system resolve '${specifier}' to one instance`,
|
|
97
|
+
code: SYSTEM_INSTANCE_MISMATCH,
|
|
98
|
+
severity: severityFor(SYSTEM_INSTANCE_MISMATCH)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return diagnostics;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
5
104
|
//#region session/session-paths.ts
|
|
6
105
|
/**
|
|
7
106
|
* Session artifact names, path derivations, and artifact shapes. Imports no
|
|
@@ -168,9 +267,11 @@ function readCliLockRecord(dir) {
|
|
|
168
267
|
if (!isPublishedSetRecord(candidate) || !isPublishedSetNumber(candidate.pid)) return { kind: "indeterminate" };
|
|
169
268
|
const startedAt = candidate.startedAt;
|
|
170
269
|
const heartbeatAt = candidate.heartbeatAt;
|
|
270
|
+
const build = candidate.build;
|
|
171
271
|
const record = { pid: candidate.pid };
|
|
172
272
|
if (isPublishedSetString(startedAt)) record.startedAt = startedAt;
|
|
173
273
|
if (isPublishedSetString(heartbeatAt)) record.heartbeatAt = heartbeatAt;
|
|
274
|
+
if (isPublishedSetString(build)) record.build = build;
|
|
174
275
|
return {
|
|
175
276
|
kind: "held",
|
|
176
277
|
record
|
|
@@ -201,12 +302,14 @@ function checkLockLiveness(record) {
|
|
|
201
302
|
reason: `holder pid ${record.pid} is running but its lock heartbeat (${record.heartbeatAt}) is ${Math.round(ageMs / 1e3)}s old, past the ${CLI_LOCK_STALE_AFTER_MS / 1e3}s staleness window — the pid names a different process now`
|
|
202
303
|
};
|
|
203
304
|
}
|
|
204
|
-
function lockRecordBytes(startedAt) {
|
|
205
|
-
|
|
305
|
+
function lockRecordBytes(startedAt, build) {
|
|
306
|
+
const record = {
|
|
206
307
|
pid: process.pid,
|
|
207
308
|
startedAt,
|
|
208
309
|
heartbeatAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
209
|
-
}
|
|
310
|
+
};
|
|
311
|
+
if (build !== void 0) record.build = build;
|
|
312
|
+
return JSON.stringify(record);
|
|
210
313
|
}
|
|
211
314
|
const HEARTBEAT_TEMP_PREFIX = ".lock-heartbeat-";
|
|
212
315
|
function holdDirectoryClaim(dir, options = {}) {
|
|
@@ -224,9 +327,9 @@ function holdDirectoryClaim(dir, options = {}) {
|
|
|
224
327
|
const stamp = () => {
|
|
225
328
|
try {
|
|
226
329
|
if (rename) {
|
|
227
|
-
writeFileSync(tempPath, lockRecordBytes(startedAt));
|
|
330
|
+
writeFileSync(tempPath, lockRecordBytes(startedAt, options.build));
|
|
228
331
|
renameSync(tempPath, path);
|
|
229
|
-
} else writeFileSync(path, lockRecordBytes(startedAt));
|
|
332
|
+
} else writeFileSync(path, lockRecordBytes(startedAt, options.build));
|
|
230
333
|
} catch (error) {
|
|
231
334
|
stop();
|
|
232
335
|
if (isMissingFile(error)) return;
|
|
@@ -256,320 +359,424 @@ function collectSessionAssets(sessionDir) {
|
|
|
256
359
|
}));
|
|
257
360
|
}
|
|
258
361
|
//#endregion
|
|
259
|
-
//#region session/resolve-packages.ts
|
|
260
|
-
/** An exports target under the `import` condition, then `default`, as the
|
|
261
|
-
* system loader reads it; an array offers its targets in order. */
|
|
262
|
-
function importTarget(value) {
|
|
263
|
-
if (isJsonString(value)) return value;
|
|
264
|
-
if (Array.isArray(value)) {
|
|
265
|
-
for (const entry of value) {
|
|
266
|
-
const target = importTarget(entry);
|
|
267
|
-
if (target !== null) return target;
|
|
268
|
-
}
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
if (!isJsonBlock(value)) return null;
|
|
272
|
-
return importTarget(value.import) ?? importTarget(value.default);
|
|
273
|
-
}
|
|
274
|
-
/** The exports entry for `subpath`: an exact key answers alone; otherwise
|
|
275
|
-
* the pattern with the longest prefix, then the longest suffix, wins. */
|
|
276
|
-
function exportsTarget(exports, subpath) {
|
|
277
|
-
const map = isJsonBlock(exports) && Object.keys(exports).some((k) => k.startsWith(".")) ? exports : { ".": exports };
|
|
278
|
-
if (subpath in map) return importTarget(map[subpath]);
|
|
279
|
-
let best = null;
|
|
280
|
-
for (const [pattern, value] of Object.entries(map)) {
|
|
281
|
-
const star = pattern.indexOf("*");
|
|
282
|
-
if (star === -1 || pattern.indexOf("*", star + 1) !== -1) continue;
|
|
283
|
-
const prefix = pattern.slice(0, star);
|
|
284
|
-
const suffix = pattern.slice(star + 1);
|
|
285
|
-
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix) || subpath.length < prefix.length + suffix.length) continue;
|
|
286
|
-
if (!best || prefix.length > best.prefix.length || prefix.length === best.prefix.length && suffix.length > best.suffix.length) best = {
|
|
287
|
-
prefix,
|
|
288
|
-
suffix,
|
|
289
|
-
value
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
if (!best) return null;
|
|
293
|
-
const matched = subpath.slice(best.prefix.length, subpath.length - best.suffix.length);
|
|
294
|
-
return importTarget(best.value)?.replaceAll("*", matched) ?? null;
|
|
295
|
-
}
|
|
296
|
-
/** The entry an ES import of `name` resolves to through the package's
|
|
297
|
-
* `exports`, under the `import` condition, then `default`: what the Vite
|
|
298
|
-
* host and the system loader resolve. Null without an `exports` field, or
|
|
299
|
-
* when no target exists. */
|
|
300
|
-
function resolveImportEntry(rootDir, name) {
|
|
301
|
-
const packageName = name.split("/").slice(0, name.startsWith("@") ? 2 : 1).join("/");
|
|
302
|
-
const subpath = `.${name.slice(packageName.length)}`;
|
|
303
|
-
for (let dir = rootDir;; dir = dirname(dir)) {
|
|
304
|
-
const manifest = join(dir, "node_modules", packageName, "package.json");
|
|
305
|
-
if (existsSync(manifest)) {
|
|
306
|
-
let exports;
|
|
307
|
-
try {
|
|
308
|
-
const parsed = parseInternalWire(readFileSync(manifest, "utf-8"), `${manifest} (a package manifest)`);
|
|
309
|
-
exports = isJsonBlock(parsed) ? parsed.exports : void 0;
|
|
310
|
-
} catch {
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
if (exports === void 0 || exports === null) return null;
|
|
314
|
-
const target = exportsTarget(exports, subpath);
|
|
315
|
-
if (target === null) return null;
|
|
316
|
-
const entryPath = resolve(dirname(manifest), target);
|
|
317
|
-
return existsSync(entryPath) ? realpathSync(entryPath) : null;
|
|
318
|
-
}
|
|
319
|
-
if (dir === dirname(dir)) return null;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
function resolvePackagesByName(rootDir, names) {
|
|
323
|
-
if (names.length === 0) return {};
|
|
324
|
-
const nameSet = new Set(names);
|
|
325
|
-
const resolved = /* @__PURE__ */ new Set();
|
|
326
|
-
const packageMap = {};
|
|
327
|
-
try {
|
|
328
|
-
const rootPkg = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf-8"));
|
|
329
|
-
const workspaces = Array.isArray(rootPkg.workspaces) ? rootPkg.workspaces : rootPkg.workspaces?.packages ?? [];
|
|
330
|
-
for (const ws of workspaces) {
|
|
331
|
-
const wsDir = resolve(rootDir, ws);
|
|
332
|
-
if (!existsSync(wsDir)) continue;
|
|
333
|
-
try {
|
|
334
|
-
const pkg = JSON.parse(readFileSync(join(wsDir, "package.json"), "utf-8"));
|
|
335
|
-
const name = pkg.name || "";
|
|
336
|
-
if (nameSet.has(name)) {
|
|
337
|
-
const main = pkg.main || pkg.module || "index.ts";
|
|
338
|
-
const entryPath = resolve(wsDir, main);
|
|
339
|
-
if (existsSync(entryPath)) {
|
|
340
|
-
packageMap[name] = relative(rootDir, entryPath);
|
|
341
|
-
resolved.add(name);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
} catch {}
|
|
345
|
-
}
|
|
346
|
-
} catch {}
|
|
347
|
-
for (const name of nameSet) {
|
|
348
|
-
if (resolved.has(name)) continue;
|
|
349
|
-
const importEntry = resolveImportEntry(rootDir, name);
|
|
350
|
-
if (importEntry !== null) {
|
|
351
|
-
packageMap[name] = relative(rootDir, importEntry);
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
try {
|
|
355
|
-
const entryPath = __require.resolve(name, { paths: [rootDir] });
|
|
356
|
-
packageMap[name] = relative(rootDir, entryPath);
|
|
357
|
-
} catch {}
|
|
358
|
-
}
|
|
359
|
-
return packageMap;
|
|
360
|
-
}
|
|
361
|
-
//#endregion
|
|
362
362
|
//#region session/singleton.ts
|
|
363
363
|
/**
|
|
364
|
-
*
|
|
365
|
-
*
|
|
364
|
+
* A build's shared state lives in one registry on `globalThis`, keyed by its
|
|
365
|
+
* `SessionKey`, so the ESM plugin copy and the CJS webpack-loader copy of
|
|
366
|
+
* this module find the same entry, and two builds of one root never share
|
|
367
|
+
* one. A reader of a build no participant has joined gets the empty value;
|
|
368
|
+
* a writer must have joined it.
|
|
366
369
|
*/
|
|
367
|
-
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const ANALYZED_HASHES_KEY = "__animus_analyzed_hashes__";
|
|
375
|
-
const REPLACEMENT_EPOCH_KEY = "__animus_replacement_epoch__";
|
|
376
|
-
const WATCH_TRANSACTION_KEY = "__animus_watch_transaction__";
|
|
377
|
-
const PROCESS_SESSION_ID_KEY = "__animus_process_session_id__";
|
|
378
|
-
const SESSION_ARTIFACT_DIR_KEY = "__animus_session_artifact_dir__";
|
|
379
|
-
const OWNING_WATCH_SESSION_KEY = "__animus_owning_watch_session__";
|
|
380
|
-
const EXCLUSIVE_SESSION_OWNER_KEY = "__animus_exclusive_session_owner__";
|
|
381
|
-
const ENGINE_KEY = "__animus_engine__";
|
|
382
|
-
const V2_ENGINE_KEY = "__animus_v2_engine__";
|
|
383
|
-
const V2_SENT_SOURCES_KEY = "__animus_v2_sent_sources__";
|
|
384
|
-
const V2_DRIFT_WARNED_KEY = "__animus_v2_drift_warned__";
|
|
385
|
-
const ENGINE_API_OVERRIDE_KEY = "__animus_engine_api_override__";
|
|
386
|
-
const singletonStore = globalThis;
|
|
387
|
-
const isSingletonString = (value) => {
|
|
388
|
-
if (Object(value) === value) return false;
|
|
389
|
-
try {
|
|
390
|
-
String.prototype.valueOf.call(value);
|
|
391
|
-
return true;
|
|
392
|
-
} catch {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
function getManifestJson() {
|
|
397
|
-
return singletonStore[MANIFEST_KEY];
|
|
370
|
+
function joined(key) {
|
|
371
|
+
const state = findSession(key);
|
|
372
|
+
if (state === void 0) throw new Error(`[animus] no participant has joined build ${key.build} of ${key.root}`);
|
|
373
|
+
return state;
|
|
374
|
+
}
|
|
375
|
+
function getManifestJson(key) {
|
|
376
|
+
return findSession(key)?.manifestJson ?? null;
|
|
398
377
|
}
|
|
399
|
-
function setManifestJson(json) {
|
|
400
|
-
|
|
378
|
+
function setManifestJson(key, json) {
|
|
379
|
+
joined(key).manifestJson = json;
|
|
401
380
|
}
|
|
402
381
|
/**
|
|
403
382
|
* A latch over the most recently STARTED analysis, never cleared on settle:
|
|
404
383
|
* non-null means one was scheduled. In-flight lives in getWatchTransaction.
|
|
405
384
|
*/
|
|
406
|
-
function getAnalysisStartedPromise() {
|
|
407
|
-
return
|
|
385
|
+
function getAnalysisStartedPromise(key) {
|
|
386
|
+
return findSession(key)?.analysisStarted ?? null;
|
|
408
387
|
}
|
|
409
|
-
function setAnalysisStartedPromise(promise) {
|
|
410
|
-
|
|
388
|
+
function setAnalysisStartedPromise(key, promise) {
|
|
389
|
+
joined(key).analysisStarted = promise;
|
|
411
390
|
}
|
|
412
|
-
function resetAnalysisStartedPromise() {
|
|
413
|
-
|
|
391
|
+
function resetAnalysisStartedPromise(key) {
|
|
392
|
+
const state = findSession(key);
|
|
393
|
+
if (state !== void 0) state.analysisStarted = null;
|
|
414
394
|
}
|
|
415
|
-
|
|
416
|
-
|
|
395
|
+
/** True for the build's first caller only: the one that reports its
|
|
396
|
+
* unmatched user excludes. */
|
|
397
|
+
function claimUnmatchedExcludeReport(key) {
|
|
398
|
+
const state = joined(key);
|
|
399
|
+
if (state.unmatchedExcludesReported) return false;
|
|
400
|
+
state.unmatchedExcludesReported = true;
|
|
401
|
+
return true;
|
|
417
402
|
}
|
|
418
|
-
function
|
|
419
|
-
|
|
403
|
+
function getSharedCss(key) {
|
|
404
|
+
return findSession(key)?.sharedCss ?? "";
|
|
420
405
|
}
|
|
421
|
-
function
|
|
422
|
-
|
|
406
|
+
function setSharedCss(key, css) {
|
|
407
|
+
joined(key).sharedCss = css;
|
|
423
408
|
}
|
|
424
|
-
function
|
|
425
|
-
|
|
409
|
+
function getSharedSystemProps(key) {
|
|
410
|
+
return findSession(key)?.sharedSystemProps ?? "";
|
|
426
411
|
}
|
|
427
|
-
function
|
|
428
|
-
|
|
412
|
+
function setSharedSystemProps(key, content) {
|
|
413
|
+
joined(key).sharedSystemProps = content;
|
|
429
414
|
}
|
|
430
|
-
function
|
|
431
|
-
|
|
415
|
+
function getSharedExternalDirs(key) {
|
|
416
|
+
return findSession(key)?.externalDirs ?? [];
|
|
432
417
|
}
|
|
433
|
-
function
|
|
434
|
-
|
|
418
|
+
function setSharedExternalDirs(key, dirs) {
|
|
419
|
+
joined(key).externalDirs = dirs;
|
|
435
420
|
}
|
|
436
|
-
function
|
|
437
|
-
|
|
421
|
+
function getSharedExternalEntries(key) {
|
|
422
|
+
return findSession(key)?.externalEntries ?? /* @__PURE__ */ new Map();
|
|
423
|
+
}
|
|
424
|
+
function setSharedExternalEntries(key, entries) {
|
|
425
|
+
joined(key).externalEntries = entries;
|
|
438
426
|
}
|
|
439
427
|
/** Specifier → its source entry's side effects, published with the shared
|
|
440
428
|
* entries; absent leaves the bundler's own classification. */
|
|
441
|
-
function getSharedExternalSideEffects() {
|
|
442
|
-
return
|
|
429
|
+
function getSharedExternalSideEffects(key) {
|
|
430
|
+
return findSession(key)?.externalSideEffects ?? /* @__PURE__ */ new Map();
|
|
443
431
|
}
|
|
444
|
-
function setSharedExternalSideEffects(sideEffects) {
|
|
445
|
-
|
|
432
|
+
function setSharedExternalSideEffects(key, sideEffects) {
|
|
433
|
+
joined(key).externalSideEffects = sideEffects;
|
|
446
434
|
}
|
|
447
|
-
function globalSlot(key) {
|
|
448
|
-
return {
|
|
449
|
-
get: () => singletonStore[key] ?? null,
|
|
450
|
-
set: (value) => {
|
|
451
|
-
singletonStore[key] = value;
|
|
452
|
-
}
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
const analyzedHashesSlot = globalSlot(ANALYZED_HASHES_KEY);
|
|
456
|
-
const replacementEpochSlot = globalSlot(REPLACEMENT_EPOCH_KEY);
|
|
457
|
-
const watchTransactionSlot = globalSlot(WATCH_TRANSACTION_KEY);
|
|
458
|
-
const sessionArtifactDirSlot = globalSlot(SESSION_ARTIFACT_DIR_KEY);
|
|
459
|
-
const owningWatchSessionSlot = globalSlot(OWNING_WATCH_SESSION_KEY);
|
|
460
435
|
/**
|
|
461
|
-
* The only session that can run watch analysis. A non-owning
|
|
462
|
-
*
|
|
436
|
+
* The only session of a build that can run watch analysis. A non-owning
|
|
437
|
+
* session's observations queue for it; dropping them loses files only that
|
|
438
|
+
* watcher sees.
|
|
463
439
|
*/
|
|
464
|
-
function getOwningWatchSession() {
|
|
465
|
-
return
|
|
440
|
+
function getOwningWatchSession(key) {
|
|
441
|
+
return findSession(key)?.authority ?? null;
|
|
466
442
|
}
|
|
467
|
-
function setOwningWatchSession(session) {
|
|
468
|
-
|
|
443
|
+
function setOwningWatchSession(key, session) {
|
|
444
|
+
joined(key).authority = session;
|
|
469
445
|
}
|
|
470
446
|
/**
|
|
471
447
|
* Per-file content hashes of the last published analysis (relPath → hash of
|
|
472
448
|
* the exact bytes analyzed), including files that produced zero entries.
|
|
473
449
|
*/
|
|
474
|
-
function getAnalyzedHashes() {
|
|
475
|
-
return
|
|
450
|
+
function getAnalyzedHashes(key) {
|
|
451
|
+
return findSession(key)?.analyzedHashes ?? null;
|
|
476
452
|
}
|
|
477
|
-
function setAnalyzedHashes(hashes) {
|
|
478
|
-
|
|
453
|
+
function setAnalyzedHashes(key, hashes) {
|
|
454
|
+
joined(key).analyzedHashes = hashes;
|
|
479
455
|
}
|
|
480
|
-
/**
|
|
481
|
-
*
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const fresh = randomUUID();
|
|
488
|
-
singletonStore[PROCESS_SESSION_ID_KEY] = fresh;
|
|
489
|
-
return fresh;
|
|
456
|
+
/** What the build's last published analysis read of the discovered
|
|
457
|
+
* packages (spec §2.2 A4); null before one publishes. */
|
|
458
|
+
function getSharedPackageReadRecord(key) {
|
|
459
|
+
return findSession(key)?.packageReadRecord ?? null;
|
|
460
|
+
}
|
|
461
|
+
function setSharedPackageReadRecord(key, record) {
|
|
462
|
+
joined(key).packageReadRecord = record;
|
|
490
463
|
}
|
|
491
464
|
/**
|
|
492
|
-
*
|
|
493
|
-
*
|
|
465
|
+
* One participant publishes a build's analysis, holding this claim until it
|
|
466
|
+
* closes: a second publisher would clobber its artifacts. Two builds never
|
|
467
|
+
* exclude each other; sequential claim and release cycles are legal.
|
|
494
468
|
*/
|
|
495
|
-
function claimExclusiveSessionOwner(label) {
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
469
|
+
function claimExclusiveSessionOwner(key, label) {
|
|
470
|
+
const state = joined(key);
|
|
471
|
+
const active = state.activeAttempt;
|
|
472
|
+
if (active !== null) throw new Error(`[animus] "${label}" started an analysis of build ${key.build} of ${key.root}, which "${active}" publishes. A build's participants share one analysis; run it once and let the others read its results.`);
|
|
473
|
+
state.activeAttempt = label;
|
|
499
474
|
return () => {
|
|
500
|
-
if (
|
|
475
|
+
if (state.activeAttempt === label) state.activeAttempt = null;
|
|
501
476
|
};
|
|
502
477
|
}
|
|
503
478
|
/**
|
|
504
|
-
* Absolute artifact directory of the
|
|
479
|
+
* Absolute artifact directory of the build's last publication. The
|
|
505
480
|
* Turbopack loader runs out of process and receives it via options instead.
|
|
506
481
|
*/
|
|
507
|
-
function getSessionArtifactDir() {
|
|
508
|
-
return
|
|
482
|
+
function getSessionArtifactDir(key) {
|
|
483
|
+
return findSession(key)?.artifactDir ?? null;
|
|
509
484
|
}
|
|
510
|
-
function setSessionArtifactDir(dir) {
|
|
511
|
-
|
|
485
|
+
function setSessionArtifactDir(key, dir) {
|
|
486
|
+
joined(key).artifactDir = dir;
|
|
512
487
|
}
|
|
513
488
|
/**
|
|
514
489
|
* Replacement epoch of the last published analysis, written AFTER the
|
|
515
490
|
* manifest so an epoch reader always sees at least that generation's manifest.
|
|
516
491
|
*/
|
|
517
|
-
function getReplacementEpoch() {
|
|
518
|
-
return
|
|
492
|
+
function getReplacementEpoch(key) {
|
|
493
|
+
return findSession(key)?.replacementEpoch ?? null;
|
|
519
494
|
}
|
|
520
|
-
function setReplacementEpoch(epoch) {
|
|
521
|
-
|
|
495
|
+
function setReplacementEpoch(key, epoch) {
|
|
496
|
+
joined(key).replacementEpoch = epoch;
|
|
522
497
|
}
|
|
523
498
|
/**
|
|
524
|
-
* The one in-flight watch-analysis transaction: a
|
|
525
|
-
* it joins this promise rather than read a pre-transaction
|
|
499
|
+
* The build's one in-flight watch-analysis transaction: a participant that
|
|
500
|
+
* did not start it joins this promise rather than read a pre-transaction
|
|
501
|
+
* generation.
|
|
526
502
|
*/
|
|
527
|
-
function getWatchTransaction() {
|
|
528
|
-
return
|
|
503
|
+
function getWatchTransaction(key) {
|
|
504
|
+
return findSession(key)?.watchTransaction ?? null;
|
|
529
505
|
}
|
|
530
|
-
function
|
|
531
|
-
|
|
506
|
+
function observationQueue(key) {
|
|
507
|
+
return joined(key).observations;
|
|
532
508
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
function setSharedEngine(engine) {
|
|
536
|
-
singletonStore[ENGINE_KEY] = engine;
|
|
509
|
+
function getSystemAuthority(key) {
|
|
510
|
+
return findSession(key)?.systemAuthority ?? null;
|
|
537
511
|
}
|
|
538
|
-
function
|
|
539
|
-
|
|
512
|
+
function setSystemAuthority(key, authority) {
|
|
513
|
+
joined(key).systemAuthority = authority;
|
|
514
|
+
}
|
|
515
|
+
function setWatchTransaction(key, transaction) {
|
|
516
|
+
joined(key).watchTransaction = transaction;
|
|
540
517
|
}
|
|
541
518
|
/** Single choke-point for every native extraction call; the NAPI module's
|
|
542
519
|
* own `.d.ts` is the authoritative surface for what it returns. */
|
|
543
520
|
function requireEngine() {
|
|
544
521
|
return __require("@animus-ui/extract");
|
|
545
522
|
}
|
|
523
|
+
const ENGINE_API_OVERRIDE_KEY = "__animus_engine_api_override__";
|
|
524
|
+
const overrideGlobal = globalThis;
|
|
525
|
+
/** The native engine module could not be loaded: an environment failure,
|
|
526
|
+
* never answered by another engine. */
|
|
527
|
+
var EnvironmentFailure = class extends Error {
|
|
528
|
+
code = "EnvironmentFailure";
|
|
529
|
+
constructor(cause) {
|
|
530
|
+
super(`[animus] EnvironmentFailure: the native extraction engine could not be loaded: ${String(cause)}`, { cause });
|
|
531
|
+
this.name = "EnvironmentFailure";
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
let loadEngineFactory = requireEngine;
|
|
535
|
+
/** The native factory, loaded once for every build in the process. A load
|
|
536
|
+
* failure is an EnvironmentFailure, and is not cached: the next use tries
|
|
537
|
+
* the load again. */
|
|
538
|
+
function engineFactory() {
|
|
539
|
+
const registry = sessionRegistry();
|
|
540
|
+
if (registry.factory === null) try {
|
|
541
|
+
registry.factory = loadEngineFactory();
|
|
542
|
+
} catch (error) {
|
|
543
|
+
throw new EnvironmentFailure(error instanceof Error ? error : String(error));
|
|
544
|
+
}
|
|
545
|
+
return registry.factory;
|
|
546
|
+
}
|
|
546
547
|
/**
|
|
547
|
-
*
|
|
548
|
-
*
|
|
548
|
+
* One engine-handle store (SA18): the engine API over `key`'s own engine
|
|
549
|
+
* state, made once per key in the registry every module copy joins. The
|
|
550
|
+
* native factory is shared; each key's engine instance, analyze-time
|
|
551
|
+
* sources and drift flag are its own, and its build's retirement releases
|
|
552
|
+
* them. A key need not be a joined build's: a Vite context or a Turbopack
|
|
553
|
+
* worker keys its own.
|
|
549
554
|
*/
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
555
|
+
function engineHandle(key, options) {
|
|
556
|
+
const engines = sessionRegistry().engines;
|
|
557
|
+
const id = sessionKeyId(key);
|
|
558
|
+
let api = engines.get(id);
|
|
559
|
+
if (api === void 0) {
|
|
560
|
+
let engine = null;
|
|
561
|
+
let sentSources = null;
|
|
562
|
+
let driftWarned = false;
|
|
563
|
+
api = createV2EngineApi({
|
|
564
|
+
...options,
|
|
565
|
+
isV2: () => true,
|
|
566
|
+
loadNativeEngine: engineFactory,
|
|
567
|
+
store: {
|
|
568
|
+
getEngine: () => engine,
|
|
569
|
+
setEngine: (next) => {
|
|
570
|
+
engine = next;
|
|
571
|
+
},
|
|
572
|
+
getSentSources: () => sentSources,
|
|
573
|
+
setSentSources: (sources) => {
|
|
574
|
+
sentSources = sources;
|
|
575
|
+
},
|
|
576
|
+
getDriftWarned: () => driftWarned,
|
|
577
|
+
setDriftWarned: (value) => {
|
|
578
|
+
driftWarned = value;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
engines.set(id, api);
|
|
583
|
+
}
|
|
584
|
+
return api;
|
|
585
|
+
}
|
|
586
|
+
/** Releases a standalone handle, one no joined build retires: its host
|
|
587
|
+
* calls this when it closes. */
|
|
588
|
+
function releaseEngineHandle(key) {
|
|
589
|
+
sessionRegistry().engines.delete(sessionKeyId(key));
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* The build's engine API, from the one engine-handle store.
|
|
593
|
+
*/
|
|
594
|
+
function engineApi(key) {
|
|
595
|
+
const override = overrideGlobal[ENGINE_API_OVERRIDE_KEY];
|
|
596
|
+
if (override) return override();
|
|
597
|
+
joined(key);
|
|
598
|
+
return engineHandle(key, {
|
|
599
|
+
label: "animus",
|
|
600
|
+
passThroughUnknownPaths: true
|
|
601
|
+
})();
|
|
602
|
+
}
|
|
603
|
+
/** A fresh build id, created once by the owning host wrapper. */
|
|
604
|
+
function createBuildId() {
|
|
605
|
+
return randomUUID();
|
|
606
|
+
}
|
|
607
|
+
/** The key of build `build` of `root`, by the root's canonical path. */
|
|
608
|
+
function sessionKey(build, root) {
|
|
609
|
+
const absolute = resolve(root);
|
|
610
|
+
let canonical = absolute;
|
|
611
|
+
try {
|
|
612
|
+
canonical = realpathSync(absolute);
|
|
613
|
+
} catch {}
|
|
614
|
+
return {
|
|
615
|
+
build,
|
|
616
|
+
root: canonical,
|
|
617
|
+
protocol: 1
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function sessionKeyId(key) {
|
|
621
|
+
return JSON.stringify([
|
|
622
|
+
key.protocol,
|
|
623
|
+
key.build,
|
|
624
|
+
key.root
|
|
625
|
+
]);
|
|
626
|
+
}
|
|
627
|
+
/** A participant joined a session with semantic options that differ from
|
|
628
|
+
* those the session was created with. */
|
|
629
|
+
var SessionConfigurationConflict = class extends Error {
|
|
630
|
+
key;
|
|
631
|
+
established;
|
|
632
|
+
joining;
|
|
633
|
+
differing;
|
|
634
|
+
code = "SessionConfigurationConflict";
|
|
635
|
+
constructor(key, established, joining, differing, requirement = "Every participant of one build must use the same Animus options.") {
|
|
636
|
+
super(`[animus] SessionConfigurationConflict: "${joining}" joined build ${key.build} of ${key.root} with ${differing.join(", ")} differing from "${established}". ${requirement}`);
|
|
637
|
+
this.key = key;
|
|
638
|
+
this.established = established;
|
|
639
|
+
this.joining = joining;
|
|
640
|
+
this.differing = differing;
|
|
641
|
+
this.name = "SessionConfigurationConflict";
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
function digestOf(field) {
|
|
645
|
+
return {
|
|
646
|
+
field,
|
|
647
|
+
text: (options) => {
|
|
648
|
+
const value = options[field];
|
|
649
|
+
return value === void 0 ? void 0 : stableStringify(value);
|
|
567
650
|
}
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Every option, classified: one a build's analysis depends on, which every
|
|
655
|
+
* participant must agree on, or one deliberately excluded. `verbose` changes
|
|
656
|
+
* no output, and the root is the key's. The type checker rejects an option
|
|
657
|
+
* added to `AnimusCoreOptions` until it is classified here.
|
|
658
|
+
*/
|
|
659
|
+
const OPTION_CLASSES = {
|
|
660
|
+
system: digestOf("system"),
|
|
661
|
+
exclude: digestOf("exclude"),
|
|
662
|
+
extensions: digestOf("extensions"),
|
|
663
|
+
strict: digestOf("strict"),
|
|
664
|
+
diagnostics: digestOf("diagnostics"),
|
|
665
|
+
verbose: "excluded",
|
|
666
|
+
prefix: digestOf("prefix"),
|
|
667
|
+
prefixContextualVars: digestOf("prefixContextualVars"),
|
|
668
|
+
targets: digestOf("targets"),
|
|
669
|
+
minify: digestOf("minify"),
|
|
670
|
+
staticCss: digestOf("staticCss"),
|
|
671
|
+
layers: digestOf("layers"),
|
|
672
|
+
engine: digestOf("engine"),
|
|
673
|
+
mode: digestOf("mode"),
|
|
674
|
+
root: "excluded"
|
|
675
|
+
};
|
|
676
|
+
/** The options a build's analysis depends on, each as stable text; each is
|
|
677
|
+
* data by its type, so equal text is an equal value. A host's own options
|
|
678
|
+
* are not the build's. */
|
|
679
|
+
function semanticOptions(options) {
|
|
680
|
+
const present = [];
|
|
681
|
+
for (const [name, digest] of Object.entries(OPTION_CLASSES)) {
|
|
682
|
+
if (digest === "excluded") continue;
|
|
683
|
+
const text = digest.text(options);
|
|
684
|
+
if (text !== void 0) present.push([name, text]);
|
|
685
|
+
}
|
|
686
|
+
return new Map(present);
|
|
687
|
+
}
|
|
688
|
+
const SESSION_REGISTRY = Symbol.for("animus.session-registry.v1");
|
|
689
|
+
const registryGlobal = globalThis;
|
|
690
|
+
function sessionRegistry() {
|
|
691
|
+
return registryGlobal[SESSION_REGISTRY] ??= {
|
|
692
|
+
sessions: /* @__PURE__ */ new Map(),
|
|
693
|
+
engines: /* @__PURE__ */ new Map(),
|
|
694
|
+
factory: null
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Joins `participant` to the session of `key`, creating it with `options` on
|
|
699
|
+
* the first join. A later participant must bring the same semantic options.
|
|
700
|
+
*/
|
|
701
|
+
function joinSession(key, participant, options) {
|
|
702
|
+
const sessions = sessionRegistry().sessions;
|
|
703
|
+
const id = sessionKeyId(key);
|
|
704
|
+
const joining = semanticOptions(options);
|
|
705
|
+
const existing = sessions.get(id);
|
|
706
|
+
if (existing === void 0) {
|
|
707
|
+
const state = {
|
|
708
|
+
key,
|
|
709
|
+
established: participant,
|
|
710
|
+
options: joining,
|
|
711
|
+
participants: /* @__PURE__ */ new Set([participant]),
|
|
712
|
+
activeAttempt: null,
|
|
713
|
+
authority: null,
|
|
714
|
+
analysisStarted: null,
|
|
715
|
+
watchTransaction: null,
|
|
716
|
+
observations: {
|
|
717
|
+
revision: 0,
|
|
718
|
+
rescan: false,
|
|
719
|
+
untaken: /* @__PURE__ */ new Map(),
|
|
720
|
+
suppliedSources: /* @__PURE__ */ new Map(),
|
|
721
|
+
revisions: /* @__PURE__ */ new Map(),
|
|
722
|
+
active: null
|
|
723
|
+
},
|
|
724
|
+
systemAuthority: null,
|
|
725
|
+
claimRecord: null,
|
|
726
|
+
manifestJson: null,
|
|
727
|
+
sharedCss: "",
|
|
728
|
+
sharedSystemProps: "",
|
|
729
|
+
externalDirs: [],
|
|
730
|
+
externalEntries: /* @__PURE__ */ new Map(),
|
|
731
|
+
externalSideEffects: /* @__PURE__ */ new Map(),
|
|
732
|
+
analyzedHashes: null,
|
|
733
|
+
packageReadRecord: null,
|
|
734
|
+
replacementEpoch: null,
|
|
735
|
+
artifactDir: null,
|
|
736
|
+
unmatchedExcludesReported: false
|
|
737
|
+
};
|
|
738
|
+
sessions.set(id, state);
|
|
739
|
+
return state;
|
|
740
|
+
}
|
|
741
|
+
const differing = [.../* @__PURE__ */ new Set([...existing.options.keys(), ...joining.keys()])].filter((name) => existing.options.get(name) !== joining.get(name));
|
|
742
|
+
if (differing.length > 0) throw new SessionConfigurationConflict(key, existing.established, participant, differing.sort());
|
|
743
|
+
existing.participants.add(participant);
|
|
744
|
+
return existing;
|
|
745
|
+
}
|
|
746
|
+
/** The session of `key`, if a participant has joined it. */
|
|
747
|
+
function findSession(key) {
|
|
748
|
+
return sessionRegistry().sessions.get(sessionKeyId(key));
|
|
749
|
+
}
|
|
750
|
+
/** The build's on-disk claim record, which stops another process pruning
|
|
751
|
+
* its tree: held once by the build, whichever participant publishes, and
|
|
752
|
+
* released only when the build retires. */
|
|
753
|
+
function holdBuildClaimRecord(key, hold) {
|
|
754
|
+
const state = joined(key);
|
|
755
|
+
state.claimRecord ??= hold();
|
|
756
|
+
}
|
|
757
|
+
/** `participant` leaves the build of `key`. The build retires with its
|
|
758
|
+
* last participant, once no attempt is in flight: it leaves the registry
|
|
759
|
+
* and releases its claim record, so its tree is pruned once stale. */
|
|
760
|
+
function leaveSession(key, participant) {
|
|
761
|
+
const state = findSession(key);
|
|
762
|
+
if (state === void 0) return;
|
|
763
|
+
state.participants.delete(participant);
|
|
764
|
+
retireIfUnused(sessionKeyId(key), state);
|
|
765
|
+
}
|
|
766
|
+
function retireIfUnused(id, state) {
|
|
767
|
+
if (state.participants.size > 0) return;
|
|
768
|
+
const inflight = state.watchTransaction;
|
|
769
|
+
if (inflight !== null) {
|
|
770
|
+
const retry = () => retireIfUnused(id, state);
|
|
771
|
+
inflight.then(retry, retry);
|
|
772
|
+
return;
|
|
568
773
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
774
|
+
const sessions = sessionRegistry().sessions;
|
|
775
|
+
if (sessions.get(id) !== state) return;
|
|
776
|
+
sessions.delete(id);
|
|
777
|
+
sessionRegistry().engines.delete(id);
|
|
778
|
+
state.claimRecord?.();
|
|
779
|
+
state.claimRecord = null;
|
|
573
780
|
}
|
|
574
781
|
//#endregion
|
|
575
782
|
//#region session/timing.ts
|
|
@@ -605,6 +812,23 @@ function logBuildTimings(bt, rustTiming, log, verbose) {
|
|
|
605
812
|
}
|
|
606
813
|
//#endregion
|
|
607
814
|
//#region session/extraction-session.ts
|
|
815
|
+
/** An observation's state when its file is gone, or cannot be read; any
|
|
816
|
+
* other state is the content hash it was observed with. */
|
|
817
|
+
const REMOVED_OBSERVATION = "removed";
|
|
818
|
+
const UNREADABLE_OBSERVATION = "unreadable";
|
|
819
|
+
/** A loaded system's identity: its evaluated modules and a fingerprint of
|
|
820
|
+
* the whole load. */
|
|
821
|
+
function systemLoad(system) {
|
|
822
|
+
return {
|
|
823
|
+
identity: contentHash(JSON.stringify(system)),
|
|
824
|
+
dependencies: system.dependencies ?? []
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
const CONSOLE_LOGGER = {
|
|
828
|
+
info: (line) => console.error(line),
|
|
829
|
+
warn: (line) => console.warn(line),
|
|
830
|
+
error: (line) => console.error(line)
|
|
831
|
+
};
|
|
608
832
|
const SESSION_DIR_MAX_AGE_MS = 864e5;
|
|
609
833
|
const STATUS_WATCHDOG_MS = 2e3;
|
|
610
834
|
const LEGACY_FLAT_ARTIFACTS = [
|
|
@@ -623,19 +847,96 @@ function isDiskString(value) {
|
|
|
623
847
|
}
|
|
624
848
|
/** Rejection of an attempt whose corpus holds an aborted parse. */
|
|
625
849
|
var AbortedParseRejection = class extends Error {};
|
|
850
|
+
/** A reload refused because its full read would replace host-supplied
|
|
851
|
+
* bytes with the disk's: a system reload a parse hold deferred, or a full
|
|
852
|
+
* read that reaches a host-supplied file only under another spelling (a
|
|
853
|
+
* case-insensitive volume). Like a hold, it keeps the prior publication
|
|
854
|
+
* and the observed sources. */
|
|
855
|
+
var DeferredReloadRefusal = class extends Error {};
|
|
856
|
+
/** The file's canonical path, or null when it cannot be resolved. */
|
|
857
|
+
function canonicalPath(path) {
|
|
858
|
+
try {
|
|
859
|
+
return realpathSync.native(path);
|
|
860
|
+
} catch {
|
|
861
|
+
return null;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
/** The host sources a full read reaches only under another spelling: a key
|
|
865
|
+
* the read did not reach exactly, whose file is one the read reached by
|
|
866
|
+
* another path (a case-insensitive volume, a symlinked alias). A key with
|
|
867
|
+
* no such file is not read either way, and is left alone. */
|
|
868
|
+
function misspelledHostSources(hostSources, readPaths) {
|
|
869
|
+
const misses = [...hostSources.keys()].filter((path) => !readPaths.has(path));
|
|
870
|
+
if (misses.length === 0) return [];
|
|
871
|
+
const readByCanonical = /* @__PURE__ */ new Map();
|
|
872
|
+
for (const readPath of readPaths) {
|
|
873
|
+
const canonical = canonicalPath(readPath);
|
|
874
|
+
if (canonical === null) continue;
|
|
875
|
+
readByCanonical.set(canonical, [...readByCanonical.get(canonical) ?? [], readPath]);
|
|
876
|
+
}
|
|
877
|
+
return misses.flatMap((path) => {
|
|
878
|
+
const canonical = canonicalPath(path);
|
|
879
|
+
const read = canonical === null ? void 0 : readByCanonical.get(canonical);
|
|
880
|
+
return read === void 0 ? [] : [{
|
|
881
|
+
path,
|
|
882
|
+
read
|
|
883
|
+
}];
|
|
884
|
+
});
|
|
885
|
+
}
|
|
626
886
|
function isDiskNumber(value) {
|
|
627
887
|
return Object(value) !== value && Object.prototype.toString.call(value) === "[object Number]";
|
|
628
888
|
}
|
|
889
|
+
/** A file's content hash, or '' when it cannot be read. */
|
|
890
|
+
function fileHashOrEmpty(path) {
|
|
891
|
+
try {
|
|
892
|
+
return contentHash(readFileSync(path, "utf-8"));
|
|
893
|
+
} catch {
|
|
894
|
+
return "";
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
/** The first file whose content no longer has its recorded hash: an
|
|
898
|
+
* unreadable or deleted file reads as '', which mismatches a real one. */
|
|
899
|
+
function firstChangedFile(hashes) {
|
|
900
|
+
for (const [path, hash] of hashes) if (fileHashOrEmpty(path) !== hash) return path;
|
|
901
|
+
}
|
|
629
902
|
/** Bundler-agnostic extraction pipeline: system load, source ingestion,
|
|
630
903
|
* analysis, emission, and watch-cycle diffing. Carries no bundler types. */
|
|
631
904
|
var ExtractionSession = class {
|
|
632
905
|
host;
|
|
633
906
|
/** Set by the adapter before any pipeline run. */
|
|
634
907
|
rootDir = null;
|
|
908
|
+
/** The module extracted terminals import their factories from; an
|
|
909
|
+
* override must supply every terminal the analysis extracts. */
|
|
910
|
+
runtimeImport = DEFAULT_RUNTIME_IMPORT;
|
|
911
|
+
/** A host that resolves imports itself (Vite's `this.resolve`): package
|
|
912
|
+
* discovery asks it first, the loader only for a declared workspace it
|
|
913
|
+
* cannot resolve. Null resolves through the loader alone. */
|
|
914
|
+
hostResolve = null;
|
|
915
|
+
/** Each file's alias comparison, kept by content hash across analyses. */
|
|
916
|
+
aliasCache = new AliasAgreementCache();
|
|
635
917
|
/** Serialized path aliases, harvested by the adapter from bundler config. */
|
|
636
918
|
pathAliasesJson = null;
|
|
919
|
+
/** The host's aliases are the project's tsconfig `paths`: each full pass
|
|
920
|
+
* re-reads them, so a tsconfig edit takes effect. */
|
|
921
|
+
aliasesFromTsconfig = false;
|
|
922
|
+
/** The root package.json and the tsconfig chain, absent files included:
|
|
923
|
+
* a change to any is a configuration change, which runs the full pass. */
|
|
924
|
+
configInputPaths = [];
|
|
925
|
+
configInputKeys = /* @__PURE__ */ new Set();
|
|
926
|
+
/** Each configuration input's content hash at the last full pass, ''
|
|
927
|
+
* for an absent one: the probe's basis when the host reports nothing. */
|
|
928
|
+
configInputHashes = /* @__PURE__ */ new Map();
|
|
637
929
|
/** The host's export conditions, in its order, for the system loader. */
|
|
638
930
|
conditions = [];
|
|
931
|
+
/** The host's extension order, as its adapter captured it; the built-in
|
|
932
|
+
* policy where no host resolves. */
|
|
933
|
+
extensionPolicy = BUILT_IN_EXTENSION_POLICY;
|
|
934
|
+
/** Which files the host serves as assets (spec §2.2 A8); the built-in
|
|
935
|
+
* classification where no host's can be read. */
|
|
936
|
+
assetClassification = builtInAssetClassification("noHost");
|
|
937
|
+
/** How the host's bundler expands computed loads (spec §6.3); without
|
|
938
|
+
* one, every computed load keeps its widest reading. */
|
|
939
|
+
loadExpander;
|
|
639
940
|
assetCopyCache = /* @__PURE__ */ new Map();
|
|
640
941
|
/** Physical asset files registered with the host watcher. */
|
|
641
942
|
assetDependencyPaths = /* @__PURE__ */ new Set();
|
|
@@ -643,9 +944,23 @@ var ExtractionSession = class {
|
|
|
643
944
|
/** System-props module id override. Turbopack rejects absolute-path
|
|
644
945
|
* imports, so its driver sets a virtual id; null injects the abs path. */
|
|
645
946
|
systemPropsModuleId = null;
|
|
947
|
+
/** The stylesheet module generated code imports; a host that serves the
|
|
948
|
+
* stylesheet itself names its own. */
|
|
949
|
+
cssModuleId = ANIMUS_CSS_MODULE_ID;
|
|
646
950
|
/** Whether the analysis-inputs hydration corpus is written to disk. Only
|
|
647
951
|
* isolated loader workers replay it; an in-process loader reads memory. */
|
|
648
952
|
persistAnalysisInputs = false;
|
|
953
|
+
/** The host substitutes asset() URLs itself (Vite: dev copies, build
|
|
954
|
+
* emitFile markers): the published sheets keep their placeholders, and
|
|
955
|
+
* the session makes no copy and tracks no asset file. */
|
|
956
|
+
hostSubstitutesAssets = false;
|
|
957
|
+
/** Whether the session keeps its artifacts on disk: status, commit,
|
|
958
|
+
* manifest, styles, the epoch witness, asset copies and its directory
|
|
959
|
+
* claim, with the sibling reconciliation they need. A host that serves
|
|
960
|
+
* every result from memory (Vite) turns it off; the shared state still
|
|
961
|
+
* publishes. Such a host also substitutes assets (above): asset copies
|
|
962
|
+
* are artifacts. */
|
|
963
|
+
persistArtifacts = true;
|
|
649
964
|
/** Whether this session serves development (a watch), where an error-level
|
|
650
965
|
* diagnostic is reported and the session keeps running. Only a build
|
|
651
966
|
* fails on one. */
|
|
@@ -693,29 +1008,69 @@ var ExtractionSession = class {
|
|
|
693
1008
|
/** Fires exactly once per settled `handleWatchUpdate` — the failure cause,
|
|
694
1009
|
* or null when clean. Observation never alters delivery. */
|
|
695
1010
|
onCycleSettled = null;
|
|
1011
|
+
/** Fires once per published generation, and per held attempt. */
|
|
1012
|
+
onOutcome = null;
|
|
1013
|
+
/** The last published generation; null before the first. */
|
|
1014
|
+
publication = null;
|
|
1015
|
+
/** The original sources (raw, before adaptation) the session holds, by
|
|
1016
|
+
* root-relative path: the published generation's, plus any that an
|
|
1017
|
+
* attempt in flight or held by an aborted parse has read. */
|
|
1018
|
+
get heldSources() {
|
|
1019
|
+
return this.fileCache;
|
|
1020
|
+
}
|
|
1021
|
+
/** The generation an emit produced, current once its ingestion
|
|
1022
|
+
* publishes. */
|
|
1023
|
+
stagedPublication = null;
|
|
696
1024
|
options;
|
|
697
1025
|
staticCssJson;
|
|
698
1026
|
system = null;
|
|
699
|
-
/** Configured
|
|
700
|
-
*
|
|
1027
|
+
/** Configured files that could not be read. Incremental passes replay
|
|
1028
|
+
* these instead of passing strict, and add a watched change they cannot
|
|
1029
|
+
* read. */
|
|
701
1030
|
ingestionFailureDiagnostics = [];
|
|
702
1031
|
/** Whether the corpus being analyzed left a file out, whose renders the
|
|
703
1032
|
* analysis cannot see. */
|
|
704
1033
|
skippedSources = [];
|
|
1034
|
+
/** Resolver calls ingestion ended under another spelling. */
|
|
1035
|
+
ingestionOpenings = [];
|
|
1036
|
+
/** The adapted originals of the ingestion being analysed: it publishes
|
|
1037
|
+
* only after its analysis does. */
|
|
1038
|
+
ingestionAdapted = /* @__PURE__ */ new Map();
|
|
705
1039
|
/** Full package-resolution map from the last full pipeline — replayed by
|
|
706
1040
|
* incremental passes (sourceEntries alone omits dist-resolved packages). */
|
|
707
1041
|
lastPackageMap = {};
|
|
708
1042
|
fileCache = /* @__PURE__ */ new Map();
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
1043
|
+
/** Held sources whose bytes the host supplied (WatchChanges.sources),
|
|
1044
|
+
* by root-relative path; a read from disk drops the path. */
|
|
1045
|
+
hostSuppliedKeys = /* @__PURE__ */ new Set();
|
|
1046
|
+
corpus = createSourceCorpus(this.corpusHost());
|
|
1047
|
+
/** The corpus reads the driver label when it reports, so a host that
|
|
1048
|
+
* sets `driverLabel` after construction is named in its messages. */
|
|
1049
|
+
corpusHost() {
|
|
1050
|
+
const label = () => this.driverLabel;
|
|
1051
|
+
return {
|
|
1052
|
+
engineApi: () => this.engine(),
|
|
1053
|
+
get prefix() {
|
|
1054
|
+
return `[${label()}]`;
|
|
1055
|
+
},
|
|
1056
|
+
strict: () => !!this.options.strict,
|
|
1057
|
+
warn: (message) => this.warn(message),
|
|
1058
|
+
reportErrors: () => this.reportErrors(),
|
|
1059
|
+
extensions: () => this.extensionPolicy,
|
|
1060
|
+
rootDir: () => this.rootDir
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
716
1063
|
systemDependencyKeys = /* @__PURE__ */ new Set();
|
|
1064
|
+
/** Whether `path` is the system module, one of its dependencies, or a
|
|
1065
|
+
* path its load found absent: a change to it reloads the system. */
|
|
1066
|
+
isSystemDependency(path) {
|
|
1067
|
+
return toWatchKeys(path).some((key) => this.systemDependencyKeys.has(key));
|
|
1068
|
+
}
|
|
717
1069
|
/** Loader-reported dependency paths for bundler watch registration. */
|
|
718
1070
|
systemDependencyPaths = [];
|
|
1071
|
+
/** Paths the system load looked for and found absent: a host registers
|
|
1072
|
+
* them for creation, which reloads the system. */
|
|
1073
|
+
systemMissingPaths = [];
|
|
719
1074
|
systemDependencyHashes = /* @__PURE__ */ new Map();
|
|
720
1075
|
lastSystemPropsHash = null;
|
|
721
1076
|
artifactRecords = {
|
|
@@ -729,9 +1084,20 @@ var ExtractionSession = class {
|
|
|
729
1084
|
/** Release handle for the in-process owner slot AND the directory's
|
|
730
1085
|
* on-disk owner record, taken and released as one; null when unheld. */
|
|
731
1086
|
releasePublicationClaim = null;
|
|
732
|
-
/**
|
|
733
|
-
*
|
|
734
|
-
|
|
1087
|
+
/** The build this session takes part in: every participant of one build
|
|
1088
|
+
* shares its artifact tree and state; another build of the root never
|
|
1089
|
+
* does. */
|
|
1090
|
+
sessionId;
|
|
1091
|
+
/** The log tier, from the option and `ANIMUS_DEBUG` at construction. */
|
|
1092
|
+
verbosity;
|
|
1093
|
+
/** The emission mode at construction: explicit, else `NODE_ENV`'s. It
|
|
1094
|
+
* defaults minify. */
|
|
1095
|
+
startupMode;
|
|
1096
|
+
joinedKey = null;
|
|
1097
|
+
/** This instance as a participant of its build, once joined. */
|
|
1098
|
+
participant = null;
|
|
1099
|
+
/** Closed: it left its build and starts no attempt until it reattaches. */
|
|
1100
|
+
detached = false;
|
|
735
1101
|
/** Epoch of the last published analysis; null seeds from disk so a
|
|
736
1102
|
* same-session restart with unchanged plans rewrites no bytes. */
|
|
737
1103
|
lastEpochValue = null;
|
|
@@ -746,10 +1112,23 @@ var ExtractionSession = class {
|
|
|
746
1112
|
* the cache keeps every observed source so the repair publishes them in
|
|
747
1113
|
* one generation; a successful publication clears it. */
|
|
748
1114
|
heldRejection = null;
|
|
749
|
-
/**
|
|
750
|
-
*
|
|
751
|
-
*
|
|
1115
|
+
/** Reload debt: a full pass that failed with a committed system to
|
|
1116
|
+
* hold, in development or under an aborted parse, owed until one
|
|
1117
|
+
* succeeds. runFullPipeline alone sets and clears it. While it stands, every batch retries the full reload and
|
|
1118
|
+
* nothing publishes against the stale system. Under an aborted parse's
|
|
1119
|
+
* hold, the first batch that passes the parse check pays it instead. */
|
|
752
1120
|
systemReloadOwed = false;
|
|
1121
|
+
/** The system dependencies the last committed full pass recorded: a
|
|
1122
|
+
* failed reload watches these and its own, never an earlier failure's. */
|
|
1123
|
+
lastGoodSystemDependencies = {
|
|
1124
|
+
keys: /* @__PURE__ */ new Set(),
|
|
1125
|
+
paths: [],
|
|
1126
|
+
missing: [],
|
|
1127
|
+
hashes: /* @__PURE__ */ new Map()
|
|
1128
|
+
};
|
|
1129
|
+
/** Whether the current full pass's system load recorded its
|
|
1130
|
+
* dependencies. */
|
|
1131
|
+
attemptRecordedSystemDependencies = false;
|
|
753
1132
|
/** Monotonic readiness witness: flips true on the first complete
|
|
754
1133
|
* publication and never regresses; every later status write carries it. */
|
|
755
1134
|
firstEmissionComplete = false;
|
|
@@ -760,27 +1139,53 @@ var ExtractionSession = class {
|
|
|
760
1139
|
constructor(options, host = {}) {
|
|
761
1140
|
this.host = host;
|
|
762
1141
|
this.options = options;
|
|
1142
|
+
this.sessionId = host.build ?? createBuildId();
|
|
763
1143
|
this.staticCssJson = serializeStaticCss(options.staticCss);
|
|
1144
|
+
this.verbosity = resolveVerbosity(options.verbose, process.env.ANIMUS_DEBUG);
|
|
1145
|
+
this.startupMode = resolveMode(options.mode, () => process.env.NODE_ENV === "production" ? "production" : "development").mode;
|
|
764
1146
|
}
|
|
765
1147
|
/** Forgets that `relPath` could not be read once an incremental pass reads
|
|
766
|
-
* or deletes it, so its cost stops holding pruning off.
|
|
1148
|
+
* or deletes it, so its cost stops holding pruning off. Whether one was
|
|
1149
|
+
* recorded. */
|
|
767
1150
|
clearIngestionFailure(relPath) {
|
|
1151
|
+
const before = this.ingestionFailureDiagnostics.length;
|
|
768
1152
|
this.ingestionFailureDiagnostics = this.ingestionFailureDiagnostics.filter((diagnostic) => diagnostic.file !== relPath);
|
|
1153
|
+
return this.ingestionFailureDiagnostics.length !== before;
|
|
769
1154
|
}
|
|
770
1155
|
get sessionDir() {
|
|
771
1156
|
return sessionArtifactDir(this.rootDir, this.sessionId);
|
|
772
1157
|
}
|
|
1158
|
+
/** This session's build of its root, joined on first use: a participant
|
|
1159
|
+
* whose options differ from the build's fails with
|
|
1160
|
+
* `SessionConfigurationConflict`. */
|
|
1161
|
+
get key() {
|
|
1162
|
+
if (this.joinedKey === null) {
|
|
1163
|
+
const key = sessionKey(this.sessionId, this.rootDir);
|
|
1164
|
+
const participant = `${this.driverLabel}#${randomUUID()}`;
|
|
1165
|
+
joinSession(key, participant, this.options);
|
|
1166
|
+
this.participant = participant;
|
|
1167
|
+
this.joinedKey = key;
|
|
1168
|
+
}
|
|
1169
|
+
return this.joinedKey;
|
|
1170
|
+
}
|
|
773
1171
|
get verbose() {
|
|
774
|
-
return
|
|
1172
|
+
return this.verbosity !== "quiet";
|
|
1173
|
+
}
|
|
1174
|
+
/** The engine of this session's build. */
|
|
1175
|
+
engine() {
|
|
1176
|
+
return this.host.engine?.() ?? engineApi(this.key);
|
|
1177
|
+
}
|
|
1178
|
+
get logger() {
|
|
1179
|
+
return this.host.logger ?? CONSOLE_LOGGER;
|
|
775
1180
|
}
|
|
776
1181
|
log(msg) {
|
|
777
|
-
if (this.verbose)
|
|
1182
|
+
if (this.verbose) this.logger.info(`[animus] ${msg}`);
|
|
778
1183
|
}
|
|
779
1184
|
warn(msg) {
|
|
780
|
-
|
|
1185
|
+
this.logger.warn(`[animus] ${msg}`);
|
|
781
1186
|
}
|
|
782
1187
|
reportErrors() {
|
|
783
|
-
return this.development ? (message) =>
|
|
1188
|
+
return this.development ? (message) => this.logger.error(message) : void 0;
|
|
784
1189
|
}
|
|
785
1190
|
/** A build-strictness check that failed: a build throws `message`, and
|
|
786
1191
|
* development reports it at error level and takes the non-strict path. */
|
|
@@ -789,6 +1194,11 @@ var ExtractionSession = class {
|
|
|
789
1194
|
if (!report) throw new Error(message);
|
|
790
1195
|
report(message);
|
|
791
1196
|
}
|
|
1197
|
+
/** A finding `strict` turns into a strict failure; otherwise a warning. */
|
|
1198
|
+
strictOrWarn(message, strictMessage = message) {
|
|
1199
|
+
if (this.options.strict) this.strictFailure(strictMessage);
|
|
1200
|
+
else this.warn(message);
|
|
1201
|
+
}
|
|
792
1202
|
now() {
|
|
793
1203
|
return this.verbose ? performance.now() : 0;
|
|
794
1204
|
}
|
|
@@ -803,6 +1213,11 @@ var ExtractionSession = class {
|
|
|
803
1213
|
lastExternalOutcomes = [];
|
|
804
1214
|
/** The analysed kits' descriptors, from the last discovery. */
|
|
805
1215
|
kitDescriptors = [];
|
|
1216
|
+
/** Package name → the real root of the instance discovery read. */
|
|
1217
|
+
packageInstances = {};
|
|
1218
|
+
/** What this attempt's analysis read of the discovered packages; the
|
|
1219
|
+
* build's shared record once the analysis publishes. */
|
|
1220
|
+
packageReadRecord = null;
|
|
806
1221
|
/** Component count of the last published analysis, null before the first —
|
|
807
1222
|
* read by drivers instead of re-parsing the manifest JSON every cycle. */
|
|
808
1223
|
lastComponentCount = null;
|
|
@@ -813,18 +1228,15 @@ var ExtractionSession = class {
|
|
|
813
1228
|
/** When superseded asset copies leave `assets/`: `'full-pipeline'` suits a
|
|
814
1229
|
* driver serving the dir in place, `'every-cycle'` one republishing it. */
|
|
815
1230
|
staleAssetPruning = "full-pipeline";
|
|
816
|
-
/**
|
|
817
|
-
*
|
|
1231
|
+
/** The host's output directories (`outputExclusion`): root-relative,
|
|
1232
|
+
* excluded as literal path prefixes from discovery and from package
|
|
1233
|
+
* collection, whatever the user's list. */
|
|
818
1234
|
structuralExclude = [];
|
|
819
1235
|
scanConfigMemo = null;
|
|
820
|
-
/** Per-pattern exclusion hit counts from this session's matcher —
|
|
821
|
-
* driver-consumed reporting surface (dead-pattern visibility). */
|
|
822
|
-
getExcludeStats() {
|
|
823
|
-
return this.resolveScanConfig().excludeMatcher.stats();
|
|
824
|
-
}
|
|
825
1236
|
/** Resolve the scan configuration from options — the single source of the
|
|
826
|
-
* exclude/extension policy shared by the full and incremental pipelines
|
|
827
|
-
|
|
1237
|
+
* exclude/extension policy shared by the full and incremental pipelines,
|
|
1238
|
+
* and by a host classifying its own file events. */
|
|
1239
|
+
get scanConfig() {
|
|
828
1240
|
if (this.scanConfigMemo === null) {
|
|
829
1241
|
const extensionsSet = new Set(this.options.extensions ?? DEFAULT_EXTENSIONS);
|
|
830
1242
|
this.scanConfigMemo = {
|
|
@@ -834,8 +1246,8 @@ var ExtractionSession = class {
|
|
|
834
1246
|
}
|
|
835
1247
|
return this.scanConfigMemo;
|
|
836
1248
|
}
|
|
837
|
-
/**
|
|
838
|
-
*
|
|
1249
|
+
/** Records the batch before any await, so an attempt that rejects never
|
|
1250
|
+
* erases it, and settles with the attempt that takes it (SA20). */
|
|
839
1251
|
async handleWatchUpdate(changes) {
|
|
840
1252
|
try {
|
|
841
1253
|
await this.routeWatchUpdate(changes);
|
|
@@ -846,36 +1258,131 @@ var ExtractionSession = class {
|
|
|
846
1258
|
this.onCycleSettled?.(null);
|
|
847
1259
|
}
|
|
848
1260
|
async routeWatchUpdate(changes) {
|
|
849
|
-
|
|
850
|
-
|
|
1261
|
+
if ((changes.modifiedFiles?.size ?? 0) > 0 || (changes.removedFiles?.size ?? 0) > 0) {
|
|
1262
|
+
await this.awaitObservation(this.recordObservation(changes));
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const inflight = getWatchTransaction(this.key);
|
|
851
1266
|
if (inflight) {
|
|
852
1267
|
await inflight;
|
|
853
|
-
if (!hasBatch) return;
|
|
854
|
-
}
|
|
855
|
-
if (!this.system) {
|
|
856
|
-
const owner = getOwningWatchSession();
|
|
857
|
-
if (owner && owner !== this && hasBatch) await owner.ingestForwardedBatch(changes);
|
|
858
1268
|
return;
|
|
859
1269
|
}
|
|
860
|
-
await this.
|
|
1270
|
+
if (this.system && !this.detached) await this.runWatchAttempt(changes);
|
|
1271
|
+
}
|
|
1272
|
+
/** Queues the batch's observations under a new revision, synchronously.
|
|
1273
|
+
* A batch equivalent to what the active attempt took joins that attempt:
|
|
1274
|
+
* a second compiler's report of the same edit never analyzes it twice. */
|
|
1275
|
+
recordObservation(changes) {
|
|
1276
|
+
const queue = observationQueue(this.key);
|
|
1277
|
+
const observed = /* @__PURE__ */ new Map();
|
|
1278
|
+
for (const path of changes.modifiedFiles ?? []) {
|
|
1279
|
+
let state;
|
|
1280
|
+
try {
|
|
1281
|
+
state = contentHash(changes.sources?.get(path) ?? readFileSync(path, "utf-8"));
|
|
1282
|
+
} catch {
|
|
1283
|
+
state = UNREADABLE_OBSERVATION;
|
|
1284
|
+
}
|
|
1285
|
+
observed.set(path, state);
|
|
1286
|
+
}
|
|
1287
|
+
for (const path of changes.removedFiles ?? []) observed.set(path, REMOVED_OBSERVATION);
|
|
1288
|
+
const revision = ++queue.revision;
|
|
1289
|
+
const active = queue.active;
|
|
1290
|
+
if (active !== null && [...observed].every(([path, state]) => !queue.untaken.has(path) && active.taken.get(path) === state)) {
|
|
1291
|
+
queue.revisions.set(revision, active.transaction);
|
|
1292
|
+
return revision;
|
|
1293
|
+
}
|
|
1294
|
+
for (const [path, state] of observed) {
|
|
1295
|
+
queue.untaken.set(path, state);
|
|
1296
|
+
const supplied = changes.sources?.get(path);
|
|
1297
|
+
if (supplied === void 0) queue.suppliedSources.delete(path);
|
|
1298
|
+
else queue.suppliedSources.set(path, supplied);
|
|
1299
|
+
}
|
|
1300
|
+
queue.revisions.set(revision, null);
|
|
1301
|
+
return revision;
|
|
861
1302
|
}
|
|
862
|
-
/**
|
|
863
|
-
*
|
|
864
|
-
async
|
|
865
|
-
|
|
1303
|
+
/** Settles with the attempt that takes `revision`. Another attempt's
|
|
1304
|
+
* rejection is its own callers': this observation runs after it. */
|
|
1305
|
+
async awaitObservation(revision) {
|
|
1306
|
+
const queue = observationQueue(this.key);
|
|
866
1307
|
for (;;) {
|
|
867
|
-
const
|
|
868
|
-
if (
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
1308
|
+
const taken = queue.revisions.get(revision);
|
|
1309
|
+
if (taken !== null && taken !== void 0) {
|
|
1310
|
+
queue.revisions.delete(revision);
|
|
1311
|
+
await taken;
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
const inflight = getWatchTransaction(this.key);
|
|
1315
|
+
if (inflight) {
|
|
1316
|
+
await inflight.catch(() => void 0);
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
const owner = this.system && !this.detached ? this : getOwningWatchSession(this.key);
|
|
1320
|
+
if (owner === null && !this.detached && getManifestJson(this.key) !== null) {
|
|
1321
|
+
await this.runFullPipeline();
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
if (owner === null || !owner.startObservedAttempt()) {
|
|
1325
|
+
queue.revisions.delete(revision);
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
877
1328
|
}
|
|
878
1329
|
}
|
|
1330
|
+
/** Starts one attempt over every untaken observation of the build. */
|
|
1331
|
+
startObservedAttempt() {
|
|
1332
|
+
if (!this.system || this.detached) return false;
|
|
1333
|
+
const { taken, rescan, sources } = this.takeObservations();
|
|
1334
|
+
const modifiedFiles = /* @__PURE__ */ new Set();
|
|
1335
|
+
const removedFiles = /* @__PURE__ */ new Set();
|
|
1336
|
+
for (const [path, state] of taken) (state === REMOVED_OBSERVATION ? removedFiles : modifiedFiles).add(path);
|
|
1337
|
+
this.settleTaken(taken, this.runWatchAttempt({
|
|
1338
|
+
modifiedFiles,
|
|
1339
|
+
removedFiles,
|
|
1340
|
+
sources
|
|
1341
|
+
}, rescan));
|
|
1342
|
+
return true;
|
|
1343
|
+
}
|
|
1344
|
+
/** Every untaken observation of the build, and whether a full rescan is
|
|
1345
|
+
* requested, which the caller's attempt now covers. */
|
|
1346
|
+
takeObservations() {
|
|
1347
|
+
const queue = observationQueue(this.key);
|
|
1348
|
+
const taken = new Map(queue.untaken);
|
|
1349
|
+
const rescan = queue.rescan;
|
|
1350
|
+
const sources = new Map(queue.suppliedSources);
|
|
1351
|
+
queue.untaken.clear();
|
|
1352
|
+
queue.suppliedSources.clear();
|
|
1353
|
+
queue.rescan = false;
|
|
1354
|
+
return {
|
|
1355
|
+
taken,
|
|
1356
|
+
rescan,
|
|
1357
|
+
sources
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
/** `transaction` settles every waiting revision, and is the active
|
|
1361
|
+
* attempt equivalent observations join until it settles. */
|
|
1362
|
+
settleTaken(taken, transaction) {
|
|
1363
|
+
const queue = observationQueue(this.key);
|
|
1364
|
+
for (const [revision, attempt] of queue.revisions) if (attempt === null) queue.revisions.set(revision, transaction);
|
|
1365
|
+
queue.active = {
|
|
1366
|
+
taken,
|
|
1367
|
+
transaction
|
|
1368
|
+
};
|
|
1369
|
+
const settle = () => {
|
|
1370
|
+
if (queue.active?.transaction === transaction) queue.active = null;
|
|
1371
|
+
};
|
|
1372
|
+
transaction.then(settle, settle);
|
|
1373
|
+
}
|
|
1374
|
+
/** Registers one attempt in the build's single-flight slot before it
|
|
1375
|
+
* processes, so a nested full system reload inherits the gate rather
|
|
1376
|
+
* than clear it, and clears the slot when it settles either way. */
|
|
1377
|
+
runWatchAttempt(changes, rescan = false) {
|
|
1378
|
+
const transaction = Promise.resolve().then(() => rescan ? this.runFullPipeline([], changes.sources) : this.processWatchUpdate(changes));
|
|
1379
|
+
setWatchTransaction(this.key, transaction);
|
|
1380
|
+
const settle = () => {
|
|
1381
|
+
if (getWatchTransaction(this.key) === transaction) setWatchTransaction(this.key, null);
|
|
1382
|
+
};
|
|
1383
|
+
transaction.then(settle, settle);
|
|
1384
|
+
return transaction;
|
|
1385
|
+
}
|
|
879
1386
|
async processWatchUpdate(changes) {
|
|
880
1387
|
const rootDir = this.rootDir;
|
|
881
1388
|
try {
|
|
@@ -886,31 +1393,25 @@ var ExtractionSession = class {
|
|
|
886
1393
|
const changed = [...changes.modifiedFiles ?? [], ...changes.removedFiles ?? []];
|
|
887
1394
|
let assetChanged = false;
|
|
888
1395
|
let systemHit;
|
|
1396
|
+
let configHit;
|
|
889
1397
|
try {
|
|
890
|
-
if (
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
} catch {}
|
|
895
|
-
if (current !== hash) {
|
|
896
|
-
systemHit = dep;
|
|
897
|
-
break;
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
else systemHit = changed.find((path) => toWatchKeys(path).some((key) => this.systemDependencyKeys.has(key)));
|
|
1398
|
+
if (changed.length === 0) {
|
|
1399
|
+
systemHit = firstChangedFile(this.systemDependencyHashes);
|
|
1400
|
+
if (systemHit === void 0) configHit = firstChangedFile(this.configInputHashes);
|
|
1401
|
+
} else systemHit = changed.find((path) => this.isSystemDependency(path));
|
|
901
1402
|
} catch (err) {
|
|
902
1403
|
this.warn(`HMR system-reload check failed: ${String(err)}`);
|
|
903
1404
|
}
|
|
904
|
-
|
|
905
|
-
|
|
1405
|
+
configHit ??= changed.find((path) => toWatchKeys(path).some((key) => this.configInputKeys.has(key)));
|
|
1406
|
+
const debtRetry = this.systemReloadOwed && this.heldRejection === null;
|
|
1407
|
+
if (systemHit || configHit || debtRetry) {
|
|
1408
|
+
this.log(systemHit ? `system reload: system dependency changed (${relative(rootDir, systemHit)})` : configHit ? `system reload: configuration changed (${relative(rootDir, configHit)})` : "system reload: retrying the reload a failure left owed");
|
|
906
1409
|
this.resetForHmr();
|
|
907
1410
|
try {
|
|
908
|
-
const promise = this.runFullPipeline(this.pendingFromBatch(changes));
|
|
909
|
-
setAnalysisStartedPromise(promise);
|
|
1411
|
+
const promise = this.runFullPipeline(this.pendingFromBatch(changes), changes.sources);
|
|
1412
|
+
setAnalysisStartedPromise(this.key, promise);
|
|
910
1413
|
await promise;
|
|
911
|
-
this.systemReloadOwed = false;
|
|
912
1414
|
} catch (err) {
|
|
913
|
-
if (err instanceof AbortedParseRejection) this.systemReloadOwed = true;
|
|
914
1415
|
try {
|
|
915
1416
|
this.beginStatusAttempt();
|
|
916
1417
|
this.writeAnalysisStatus("failed", this.pendingFromBatch(changes), String(err));
|
|
@@ -925,7 +1426,7 @@ var ExtractionSession = class {
|
|
|
925
1426
|
this.assetCopyCache.clear();
|
|
926
1427
|
assetChanged = true;
|
|
927
1428
|
}
|
|
928
|
-
const { excludeMatcher, extensionsSet } = this.
|
|
1429
|
+
const { excludeMatcher, extensionsSet } = this.scanConfig;
|
|
929
1430
|
const priorCacheEntries = /* @__PURE__ */ new Map();
|
|
930
1431
|
const priorExternalFileOwners = { ...this.externalFileOwners };
|
|
931
1432
|
const recordPrior = (key) => {
|
|
@@ -933,6 +1434,7 @@ var ExtractionSession = class {
|
|
|
933
1434
|
};
|
|
934
1435
|
const inventoryUpdates = [];
|
|
935
1436
|
const ownerRemovals = [];
|
|
1437
|
+
const removedProjectFiles = /* @__PURE__ */ new Map();
|
|
936
1438
|
let removedAny = false;
|
|
937
1439
|
if (changes.removedFiles) for (const removedPath of changes.removedFiles) {
|
|
938
1440
|
let key;
|
|
@@ -946,8 +1448,10 @@ var ExtractionSession = class {
|
|
|
946
1448
|
}
|
|
947
1449
|
recordPrior(key);
|
|
948
1450
|
this.clearIngestionFailure(key);
|
|
1451
|
+
this.hostSuppliedKeys.delete(key);
|
|
949
1452
|
if (this.fileCache.delete(key)) {
|
|
950
1453
|
removedAny = true;
|
|
1454
|
+
if (!owningRoot) removedProjectFiles.set(key, removedPath);
|
|
951
1455
|
if (owningRoot) {
|
|
952
1456
|
inventoryUpdates.push({
|
|
953
1457
|
root: owningRoot,
|
|
@@ -978,15 +1482,29 @@ var ExtractionSession = class {
|
|
|
978
1482
|
owningRoot: null
|
|
979
1483
|
}));
|
|
980
1484
|
const changedPaths = [];
|
|
1485
|
+
const inOutput = outputSourceGuard(rootDir, this.structuralExclude);
|
|
1486
|
+
let readFailuresChanged = false;
|
|
981
1487
|
for (const target of targets) {
|
|
982
1488
|
const relPath = target.key;
|
|
1489
|
+
const outputDir = inOutput(target.abs);
|
|
1490
|
+
if (outputDir !== null) {
|
|
1491
|
+
this.warn(outputSourceMessage(relPath, outputDir));
|
|
1492
|
+
continue;
|
|
1493
|
+
}
|
|
983
1494
|
let source;
|
|
984
1495
|
try {
|
|
985
|
-
|
|
986
|
-
|
|
1496
|
+
const supplied = changes.sources?.get(target.abs);
|
|
1497
|
+
source = supplied ?? readFileSync(target.abs, "utf-8");
|
|
1498
|
+
if (supplied === void 0) this.hostSuppliedKeys.delete(relPath);
|
|
1499
|
+
else this.hostSuppliedKeys.add(relPath);
|
|
1500
|
+
} catch (err) {
|
|
1501
|
+
if (isDeletedSource(err)) continue;
|
|
1502
|
+
this.clearIngestionFailure(relPath);
|
|
1503
|
+
this.ingestionFailureDiagnostics = [...this.ingestionFailureDiagnostics, unreadableSourceDiagnostic(relPath, err)];
|
|
1504
|
+
readFailuresChanged = true;
|
|
987
1505
|
continue;
|
|
988
1506
|
}
|
|
989
|
-
this.clearIngestionFailure(relPath);
|
|
1507
|
+
if (this.clearIngestionFailure(relPath)) readFailuresChanged = true;
|
|
990
1508
|
const rawHash = contentHash(source);
|
|
991
1509
|
const cached = this.fileCache.get(relPath);
|
|
992
1510
|
const hash = rawHash;
|
|
@@ -1009,7 +1527,7 @@ var ExtractionSession = class {
|
|
|
1009
1527
|
}
|
|
1010
1528
|
}
|
|
1011
1529
|
}
|
|
1012
|
-
if (changedPaths.length > 0 || removedAny || assetChanged) {
|
|
1530
|
+
if (changedPaths.length > 0 || removedAny || readFailuresChanged || assetChanged) {
|
|
1013
1531
|
const pending = changedPaths.map((rel) => [rel, this.fileCache.get(rel).hash]);
|
|
1014
1532
|
const commitObservedBatch = () => {
|
|
1015
1533
|
for (const update of inventoryUpdates) {
|
|
@@ -1035,23 +1553,30 @@ var ExtractionSession = class {
|
|
|
1035
1553
|
});
|
|
1036
1554
|
this.throwOnAbortedParse(ingested);
|
|
1037
1555
|
this.skippedSources = ingested.skippedOriginals ?? [];
|
|
1556
|
+
this.ingestionOpenings = ingested.openings ?? [];
|
|
1557
|
+
this.ingestionAdapted = adaptedOriginals(ingested.ownership);
|
|
1038
1558
|
if (this.systemReloadOwed) {
|
|
1039
1559
|
this.log("system reload: publishing the reload a parse hold deferred");
|
|
1560
|
+
const stale = this.staleHostSuppliedSources(changes.sources);
|
|
1561
|
+
if (stale.length > 0) throw new DeferredReloadRefusal(`[${this.driverLabel}] system reload not published: its full read would take ${stale.join(", ")} from disk, which does not hold the bytes the host supplied; the last generation stays served, and the reload publishes with the next change once the disk holds them`);
|
|
1040
1562
|
this.resetForHmr();
|
|
1041
|
-
await this.runFullPipeline(pending);
|
|
1042
|
-
this.systemReloadOwed = false;
|
|
1563
|
+
await this.runFullPipeline(pending, changes.sources);
|
|
1043
1564
|
return;
|
|
1044
1565
|
}
|
|
1045
1566
|
this.externalFileOwners = projectExternalFileOwners(ingested, this.externalFileOwners);
|
|
1046
|
-
resetAnalysisStartedPromise();
|
|
1567
|
+
resetAnalysisStartedPromise(this.key);
|
|
1047
1568
|
const promise = this.runIncrementalPipeline(ingested.analysisEntries, pending);
|
|
1048
|
-
setAnalysisStartedPromise(promise);
|
|
1569
|
+
setAnalysisStartedPromise(this.key, promise);
|
|
1049
1570
|
await promise;
|
|
1050
1571
|
} catch (err) {
|
|
1051
|
-
if (err instanceof AbortedParseRejection) commitObservedBatch();
|
|
1572
|
+
if (err instanceof AbortedParseRejection || err instanceof DeferredReloadRefusal) commitObservedBatch();
|
|
1052
1573
|
else {
|
|
1053
|
-
for (const [key, prior] of priorCacheEntries)
|
|
1054
|
-
|
|
1574
|
+
for (const [key, prior] of priorCacheEntries) {
|
|
1575
|
+
const removed = removedProjectFiles.get(key);
|
|
1576
|
+
if (removed !== void 0 && !existsSync(removed)) continue;
|
|
1577
|
+
if (prior === null) this.fileCache.delete(key);
|
|
1578
|
+
else this.fileCache.set(key, prior);
|
|
1579
|
+
}
|
|
1055
1580
|
this.externalFileOwners = priorExternalFileOwners;
|
|
1056
1581
|
}
|
|
1057
1582
|
if (this.statusAttemptOpen) {
|
|
@@ -1060,7 +1585,7 @@ var ExtractionSession = class {
|
|
|
1060
1585
|
}
|
|
1061
1586
|
throw err;
|
|
1062
1587
|
}
|
|
1063
|
-
this.publishSourceIngestion(ingested);
|
|
1588
|
+
this.publishSourceIngestion(ingested, "incremental", (path) => this.fileCache.get(path));
|
|
1064
1589
|
commitObservedBatch();
|
|
1065
1590
|
} else if (this.statusAttemptOpen) {
|
|
1066
1591
|
this.debouncePending.clear();
|
|
@@ -1075,88 +1600,233 @@ var ExtractionSession = class {
|
|
|
1075
1600
|
const rejection = this.corpus.rejection(prepared);
|
|
1076
1601
|
if (!rejection) return;
|
|
1077
1602
|
this.heldRejection = rejection.message;
|
|
1603
|
+
this.onOutcome?.({
|
|
1604
|
+
kind: "held",
|
|
1605
|
+
abortedOriginals: rejection.originals
|
|
1606
|
+
});
|
|
1078
1607
|
throw new AbortedParseRejection(rejection.message);
|
|
1079
1608
|
}
|
|
1080
|
-
|
|
1609
|
+
/** Held sources whose bytes the host supplied and which the disk no
|
|
1610
|
+
* longer matches: a full read not carrying them (`carried`) would
|
|
1611
|
+
* publish the disk's bytes in their place. */
|
|
1612
|
+
staleHostSuppliedSources(carried) {
|
|
1613
|
+
const stale = [];
|
|
1614
|
+
for (const key of this.hostSuppliedKeys) {
|
|
1615
|
+
const held = this.fileCache.get(key);
|
|
1616
|
+
const abs = resolve(this.rootDir, key);
|
|
1617
|
+
if (held === void 0 || carried?.has(abs)) continue;
|
|
1618
|
+
let onDisk;
|
|
1619
|
+
try {
|
|
1620
|
+
onDisk = readFileSync(abs, "utf-8");
|
|
1621
|
+
} catch {
|
|
1622
|
+
onDisk = null;
|
|
1623
|
+
}
|
|
1624
|
+
if (onDisk === null || contentHash(onDisk) !== held.hash) stale.push(key);
|
|
1625
|
+
}
|
|
1626
|
+
return stale.sort();
|
|
1627
|
+
}
|
|
1628
|
+
/** `raw` is the attempt's input by original path, from which a
|
|
1629
|
+
* quarantined original stays held: every later pass re-ingests it, so it
|
|
1630
|
+
* keeps counting as skipped (nothing it renders is pruned) and its fix
|
|
1631
|
+
* edit compares against its bytes. */
|
|
1632
|
+
publishSourceIngestion(result, pass, raw) {
|
|
1633
|
+
const endedHold = this.heldRejection !== null;
|
|
1634
|
+
const previousOwnership = this.corpus.published.ownership;
|
|
1081
1635
|
this.heldRejection = null;
|
|
1082
|
-
|
|
1636
|
+
const held = new Map(result.originalEntries.map((entry) => [entry.path, {
|
|
1083
1637
|
hash: entry.hash,
|
|
1084
1638
|
source: entry.source
|
|
1085
1639
|
}]));
|
|
1640
|
+
for (const path of result.skippedOriginals ?? []) {
|
|
1641
|
+
const entry = raw(path);
|
|
1642
|
+
if (entry) held.set(path, {
|
|
1643
|
+
hash: entry.hash ?? contentHash(entry.source),
|
|
1644
|
+
source: entry.source
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
this.fileCache = held;
|
|
1086
1648
|
this.corpus.publish(result);
|
|
1649
|
+
const staged = this.stagedPublication;
|
|
1650
|
+
if (staged === null) return;
|
|
1651
|
+
this.stagedPublication = null;
|
|
1652
|
+
const previous = this.publication;
|
|
1653
|
+
const publication = {
|
|
1654
|
+
...staged,
|
|
1655
|
+
ownership: result.ownership
|
|
1656
|
+
};
|
|
1657
|
+
this.publication = publication;
|
|
1658
|
+
this.onOutcome?.({
|
|
1659
|
+
kind: "published",
|
|
1660
|
+
publication,
|
|
1661
|
+
pass,
|
|
1662
|
+
planChanged: diffFilePlans(snapshotFilePlans(previous?.manifest ?? null), snapshotFilePlans(publication.manifest)),
|
|
1663
|
+
endedHold,
|
|
1664
|
+
redeliver: endedHold ? Object.values(result.ownership).filter((owner) => previousOwnership[owner.originalPath]?.originalHash !== owner.originalHash).map((owner) => owner.originalPath) : []
|
|
1665
|
+
});
|
|
1087
1666
|
}
|
|
1088
1667
|
/** Full analysis + publication, registered in the one in-flight
|
|
1089
|
-
* transaction slot; a nested reload leaves the enclosing registration.
|
|
1090
|
-
|
|
1668
|
+
* transaction slot; a nested reload leaves the enclosing registration.
|
|
1669
|
+
* `sources` are bytes a host already read (see WatchChanges.sources):
|
|
1670
|
+
* the full read uses them, and those of the observations it takes, in
|
|
1671
|
+
* place of the disk. */
|
|
1672
|
+
async runFullPipeline(pending = [], sources = /* @__PURE__ */ new Map()) {
|
|
1091
1673
|
if (this.releasePublicationClaim === null) {
|
|
1092
|
-
const releaseOwner = claimExclusiveSessionOwner(`${this.driverLabel}:${this.sessionDir}`);
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
};
|
|
1674
|
+
const releaseOwner = claimExclusiveSessionOwner(this.key, `${this.driverLabel}:${this.sessionDir}`);
|
|
1675
|
+
if (this.persistArtifacts) {
|
|
1676
|
+
mkdirSync(this.sessionDir, { recursive: true });
|
|
1677
|
+
holdBuildClaimRecord(this.key, () => holdDirectoryClaim(this.sessionDir, { build: this.sessionId }));
|
|
1678
|
+
}
|
|
1679
|
+
this.releasePublicationClaim = releaseOwner;
|
|
1099
1680
|
}
|
|
1100
1681
|
const priorSystem = this.system;
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1682
|
+
const priorRegistration = this.snapshotWatchRegistration();
|
|
1683
|
+
this.attemptRecordedSystemDependencies = false;
|
|
1684
|
+
const nested = getWatchTransaction(this.key) !== null;
|
|
1685
|
+
const observations = nested ? null : this.takeObservations();
|
|
1686
|
+
const taken = observations?.taken ?? null;
|
|
1687
|
+
const transaction = this.runPipelineTransaction(pending, new Map([...observations?.sources ?? [], ...sources]));
|
|
1688
|
+
if (taken !== null) {
|
|
1689
|
+
setWatchTransaction(this.key, transaction);
|
|
1690
|
+
this.settleTaken(taken, transaction);
|
|
1691
|
+
}
|
|
1104
1692
|
try {
|
|
1105
1693
|
await transaction;
|
|
1106
1694
|
} catch (error) {
|
|
1107
1695
|
this.system = priorSystem;
|
|
1696
|
+
this.restoreWatchRegistration(priorRegistration);
|
|
1697
|
+
if (priorSystem !== null && (this.development || error instanceof AbortedParseRejection)) this.systemReloadOwed = true;
|
|
1108
1698
|
throw error;
|
|
1109
1699
|
} finally {
|
|
1110
|
-
if (!nested) setWatchTransaction(null);
|
|
1700
|
+
if (!nested) setWatchTransaction(this.key, null);
|
|
1701
|
+
}
|
|
1702
|
+
this.systemReloadOwed = false;
|
|
1703
|
+
this.lastGoodSystemDependencies = {
|
|
1704
|
+
keys: this.systemDependencyKeys,
|
|
1705
|
+
paths: this.systemDependencyPaths,
|
|
1706
|
+
missing: this.systemMissingPaths,
|
|
1707
|
+
hashes: this.systemDependencyHashes
|
|
1708
|
+
};
|
|
1709
|
+
this.commitSystemAuthority();
|
|
1710
|
+
}
|
|
1711
|
+
/** This attempt's system dependencies: the files its load read, and the
|
|
1712
|
+
* paths it found absent, whose creation is a system change. */
|
|
1713
|
+
recordSystemDependencies(systemPath, dependencies, missing) {
|
|
1714
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1715
|
+
for (const path of [
|
|
1716
|
+
systemPath,
|
|
1717
|
+
...dependencies,
|
|
1718
|
+
...missing
|
|
1719
|
+
]) for (const key of toWatchKeys(path)) keys.add(key);
|
|
1720
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
1721
|
+
for (const dep of dependencies.length > 0 ? dependencies : [systemPath]) try {
|
|
1722
|
+
hashes.set(dep, contentHash(readFileSync(dep, "utf-8")));
|
|
1723
|
+
} catch {
|
|
1724
|
+
hashes.set(dep, "");
|
|
1725
|
+
}
|
|
1726
|
+
for (const path of missing) hashes.set(path, "");
|
|
1727
|
+
this.systemDependencyKeys = keys;
|
|
1728
|
+
this.systemDependencyPaths = dependencies;
|
|
1729
|
+
this.systemMissingPaths = missing;
|
|
1730
|
+
this.systemDependencyHashes = hashes;
|
|
1731
|
+
this.attemptRecordedSystemDependencies = true;
|
|
1732
|
+
}
|
|
1733
|
+
/** Records the configuration inputs and, for a tsconfig-aliased host,
|
|
1734
|
+
* re-reads its aliases. */
|
|
1735
|
+
readConfigInputs(rootDir) {
|
|
1736
|
+
this.configInputPaths = [join(rootDir, "package.json"), ...tsconfigChainPaths(rootDir)];
|
|
1737
|
+
this.configInputKeys = new Set(this.configInputPaths.flatMap((path) => toWatchKeys(path)));
|
|
1738
|
+
this.configInputHashes = new Map(this.configInputPaths.map((path) => [path, fileHashOrEmpty(path)]));
|
|
1739
|
+
if (this.aliasesFromTsconfig) this.pathAliasesJson = buildPathAliasesJson(readTsconfigAliasPairs(rootDir), rootDir)?.json ?? null;
|
|
1740
|
+
}
|
|
1741
|
+
/** What hosts watch for assets, and what the last-good generation
|
|
1742
|
+
* reported about its kits and packages, which a failed full pass must
|
|
1743
|
+
* leave in place. */
|
|
1744
|
+
snapshotWatchRegistration() {
|
|
1745
|
+
return {
|
|
1746
|
+
assetDependencyPaths: new Set(this.assetDependencyPaths),
|
|
1747
|
+
assetDependencyKeys: new Set(this.assetDependencyKeys),
|
|
1748
|
+
kitDescriptors: this.kitDescriptors,
|
|
1749
|
+
lastExternalOutcomes: this.lastExternalOutcomes
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
/** Restores the last-good registration. The system dependencies are the
|
|
1753
|
+
* last committed pass's and, when its load got that far, this failed
|
|
1754
|
+
* attempt's (spec §2.3): a fix to any of them must reach the owed reload,
|
|
1755
|
+
* and an earlier failure's are replaced, never accumulated. */
|
|
1756
|
+
restoreWatchRegistration(prior) {
|
|
1757
|
+
Object.assign(this, prior);
|
|
1758
|
+
const lastGood = this.lastGoodSystemDependencies;
|
|
1759
|
+
if (!this.attemptRecordedSystemDependencies) {
|
|
1760
|
+
this.systemDependencyKeys = lastGood.keys;
|
|
1761
|
+
this.systemDependencyPaths = lastGood.paths;
|
|
1762
|
+
this.systemMissingPaths = lastGood.missing;
|
|
1763
|
+
this.systemDependencyHashes = lastGood.hashes;
|
|
1764
|
+
return;
|
|
1111
1765
|
}
|
|
1766
|
+
this.systemMissingPaths = [.../* @__PURE__ */ new Set([...lastGood.missing, ...this.systemMissingPaths])];
|
|
1767
|
+
this.systemDependencyKeys = /* @__PURE__ */ new Set([...lastGood.keys, ...this.systemDependencyKeys]);
|
|
1768
|
+
this.systemDependencyPaths = [.../* @__PURE__ */ new Set([...lastGood.paths, ...this.systemDependencyPaths])];
|
|
1769
|
+
this.systemDependencyHashes = new Map([...this.systemDependencyHashes, ...lastGood.hashes]);
|
|
1770
|
+
}
|
|
1771
|
+
/** The build's authority becomes the system this session committed, with
|
|
1772
|
+
* it and never before: a failed reload leaves the committed one, and the
|
|
1773
|
+
* context proofs made against it. A committed reload discards every
|
|
1774
|
+
* other context's proof, even for an unchanged system: the reload may
|
|
1775
|
+
* have changed what another context resolves, so each loads again. */
|
|
1776
|
+
commitSystemAuthority() {
|
|
1777
|
+
setSystemAuthority(this.key, {
|
|
1778
|
+
...systemLoad(this.system),
|
|
1779
|
+
context: this.resolutionContextText(),
|
|
1780
|
+
label: this.resolutionContextLabel(),
|
|
1781
|
+
others: /* @__PURE__ */ new Map()
|
|
1782
|
+
});
|
|
1112
1783
|
}
|
|
1113
|
-
async runPipelineTransaction(pending) {
|
|
1784
|
+
async runPipelineTransaction(pending, hostSources) {
|
|
1114
1785
|
const pipelineStart = this.now();
|
|
1115
1786
|
const bt = {};
|
|
1116
1787
|
this.runSessionStartHygiene();
|
|
1117
|
-
setSessionArtifactDir(this.sessionDir);
|
|
1788
|
+
setSessionArtifactDir(this.key, this.sessionDir);
|
|
1118
1789
|
const rootDir = this.rootDir;
|
|
1119
1790
|
const priorSourceState = this.snapshotSourceState();
|
|
1120
1791
|
const resolvedSystemPath = resolve(rootDir, this.options.system);
|
|
1792
|
+
this.readConfigInputs(rootDir);
|
|
1793
|
+
const context = {
|
|
1794
|
+
conditions: this.conditions,
|
|
1795
|
+
workspaces: declaredWorkspacePackages(rootDir),
|
|
1796
|
+
extensions: this.extensionPolicy
|
|
1797
|
+
};
|
|
1798
|
+
this.log(`extension order: ${context.extensions.resolverVersion}`);
|
|
1121
1799
|
let t = this.now();
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
}
|
|
1800
|
+
try {
|
|
1801
|
+
this.system = this.loadSystemUnder(context);
|
|
1802
|
+
} catch (error) {
|
|
1803
|
+
const reads = systemLoadReads(error);
|
|
1804
|
+
this.recordSystemDependencies(resolvedSystemPath, reads.dependencies, reads.missing);
|
|
1805
|
+
throw error;
|
|
1806
|
+
}
|
|
1129
1807
|
this.assetCopyCache.clear();
|
|
1130
1808
|
this.assetDependencyPaths.clear();
|
|
1131
1809
|
this.assetDependencyKeys.clear();
|
|
1132
|
-
|
|
1133
|
-
const deps = this.system.dependencies ?? [];
|
|
1134
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1135
|
-
for (const key of toWatchKeys(resolvedSystemPath)) keys.add(key);
|
|
1136
|
-
for (const dep of deps) for (const key of toWatchKeys(dep)) keys.add(key);
|
|
1137
|
-
this.systemDependencyKeys = keys;
|
|
1138
|
-
this.systemDependencyPaths = deps;
|
|
1139
|
-
const hashes = /* @__PURE__ */ new Map();
|
|
1140
|
-
for (const dep of deps.length > 0 ? deps : [resolvedSystemPath]) try {
|
|
1141
|
-
hashes.set(dep, contentHash(readFileSync(dep, "utf-8")));
|
|
1142
|
-
} catch {
|
|
1143
|
-
hashes.set(dep, "");
|
|
1144
|
-
}
|
|
1145
|
-
this.systemDependencyHashes = hashes;
|
|
1146
|
-
}
|
|
1810
|
+
this.recordSystemDependencies(resolvedSystemPath, this.system.dependencies ?? [], this.system.missing ?? []);
|
|
1147
1811
|
bt.systemLoad = this.elapsed(t);
|
|
1148
1812
|
t = this.now();
|
|
1149
|
-
const { excludeMatcher, extensionsSet } = this.
|
|
1813
|
+
const { excludeMatcher, extensionsSet } = this.scanConfig;
|
|
1150
1814
|
const files = discoverFiles(rootDir, rootDir, excludeMatcher, extensionsSet);
|
|
1815
|
+
if (claimUnmatchedExcludeReport(this.key)) for (const line of unmatchedExcludeLines(excludeMatcher)) this.logger.error(line);
|
|
1151
1816
|
bt.fileDiscovery = this.elapsed(t);
|
|
1152
1817
|
t = this.now();
|
|
1153
1818
|
const rawEntries = [];
|
|
1154
1819
|
const ingestionFailures = [];
|
|
1820
|
+
const readPaths = /* @__PURE__ */ new Set();
|
|
1155
1821
|
for (const filePath of files) {
|
|
1156
1822
|
const relPath = relative(rootDir, filePath);
|
|
1823
|
+
readPaths.add(filePath);
|
|
1157
1824
|
let source;
|
|
1158
1825
|
try {
|
|
1159
|
-
|
|
1826
|
+
const supplied = hostSources.get(filePath);
|
|
1827
|
+
source = supplied ?? readFileSync(filePath, "utf-8");
|
|
1828
|
+
if (supplied === void 0) this.hostSuppliedKeys.delete(relPath);
|
|
1829
|
+
else this.hostSuppliedKeys.add(relPath);
|
|
1160
1830
|
} catch (err) {
|
|
1161
1831
|
if (!isDeletedSource(err)) ingestionFailures.push(unreadableSourceDiagnostic(relPath, err));
|
|
1162
1832
|
continue;
|
|
@@ -1168,21 +1838,36 @@ var ExtractionSession = class {
|
|
|
1168
1838
|
});
|
|
1169
1839
|
}
|
|
1170
1840
|
bt.fileRead = this.elapsed(t);
|
|
1841
|
+
const rawPaths = new Set(rawEntries.map((entry) => entry.path));
|
|
1171
1842
|
t = this.now();
|
|
1172
|
-
const
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1843
|
+
const resolver = discoveryResolver(this.hostResolve, this.engine(), {
|
|
1844
|
+
rootDir,
|
|
1845
|
+
conditions: context.conditions,
|
|
1846
|
+
workspaces: context.workspaces,
|
|
1847
|
+
extensions: context.extensions
|
|
1176
1848
|
});
|
|
1177
|
-
discoveryDiagnostics
|
|
1178
|
-
const
|
|
1849
|
+
const discoveryDiagnostics = [];
|
|
1850
|
+
const systemPackageRoot = findPackageRoot(resolvedSystemPath);
|
|
1851
|
+
const kitMembers = /* @__PURE__ */ new Map();
|
|
1852
|
+
const packageNames = await extractSystemFilePackages(resolvedSystemPath, { systemMembership: this.engine().systemMembership ?? requireEngine().systemMembership }, (diagnostic) => discoveryDiagnostics.push(diagnostic), (specifier, importer) => findPackageRoot(importer) === systemPackageRoot ? resolver.resolveSpecifier(specifier) : resolver.loaderResolve(specifier, dirname(importer)), context.extensions, kitMembers);
|
|
1853
|
+
discoveryDiagnostics.push(...importedKitDiagnostics(rawEntries, this.engine(), rootDir, packageNames, (entries) => this.corpus.facts(entries)));
|
|
1179
1854
|
const rawExternalFiles = /* @__PURE__ */ new Map();
|
|
1180
1855
|
const collected = await collectExternalPackageSources({
|
|
1856
|
+
extensions: context.extensions,
|
|
1857
|
+
kitSourceRoot: nativeKitSourceRoot(this.engine(), rootDir, context.conditions, context.workspaces, extensionPolicyJson(context.extensions)),
|
|
1858
|
+
locatePackage: nativePackageLocator(this.engine(), context.workspaces),
|
|
1181
1859
|
specifiers: packageNames,
|
|
1182
|
-
resolveSpecifier: (
|
|
1860
|
+
resolveSpecifier: async (specifier) => kitMembers.get(specifier) ?? await resolver.resolveSpecifier(specifier),
|
|
1861
|
+
locateFrom: (specifier) => {
|
|
1862
|
+
const file = kitMembers.get(specifier);
|
|
1863
|
+
return file === void 0 ? rootDir : dirname(file);
|
|
1864
|
+
},
|
|
1865
|
+
unresolvedReason: resolver.unresolvedReason,
|
|
1866
|
+
requireSourceEntry: resolver.requireSourceEntry,
|
|
1183
1867
|
rootDir,
|
|
1184
1868
|
extensionsSet,
|
|
1185
|
-
hasEntry: (relPath) =>
|
|
1869
|
+
hasEntry: (relPath) => rawPaths.has(relPath),
|
|
1870
|
+
hostOutputDirs: this.structuralExclude.map((dir) => resolve(rootDir, dir)),
|
|
1186
1871
|
onSourceRead: (source, _relPath, absPath) => {
|
|
1187
1872
|
rawExternalFiles.set(absPath, contentHash(source));
|
|
1188
1873
|
},
|
|
@@ -1201,21 +1886,22 @@ var ExtractionSession = class {
|
|
|
1201
1886
|
});
|
|
1202
1887
|
this.lastExternalOutcomes = collected.outcomes;
|
|
1203
1888
|
this.ingestionFailureDiagnostics = ingestionFailures;
|
|
1889
|
+
if (resolver.hostFirst) discoveryDiagnostics.push(...systemInstanceMismatches({
|
|
1890
|
+
rootDir,
|
|
1891
|
+
specifiers: packageNames,
|
|
1892
|
+
instances: collected.packageInstances,
|
|
1893
|
+
evaluated: this.systemDependencyPaths,
|
|
1894
|
+
loaderResolve: (specifier) => resolver.loaderResolve(specifier, dirname(resolvedSystemPath))
|
|
1895
|
+
}));
|
|
1204
1896
|
surfaceManifestDiagnostics({ diagnostics: [...discoveryDiagnostics, ...collected.diagnostics] }, (message) => this.warn(message), {
|
|
1205
1897
|
levels: this.options.diagnostics,
|
|
1206
1898
|
strict: this.options.strict,
|
|
1207
1899
|
reportErrors: this.reportErrors()
|
|
1208
1900
|
});
|
|
1209
|
-
const unresolvableMessage = unresolvableIncludesMessage(collected.outcomes);
|
|
1210
|
-
if (unresolvableMessage !== null)
|
|
1211
|
-
if (this.options.strict) this.strictFailure(unresolvableMessage);
|
|
1212
|
-
else this.warn(unresolvableMessage);
|
|
1213
|
-
}
|
|
1901
|
+
const unresolvableMessage = unresolvableIncludesMessage(collected.outcomes, relative(rootDir, resolvedSystemPath));
|
|
1902
|
+
if (unresolvableMessage !== null) this.strictOrWarn(unresolvableMessage);
|
|
1214
1903
|
const staleDistMessage = staleDistIncludesMessage(collected.outcomes);
|
|
1215
|
-
if (staleDistMessage !== null)
|
|
1216
|
-
if (this.options.strict) this.strictFailure(staleDistMessage);
|
|
1217
|
-
else this.warn(staleDistMessage);
|
|
1218
|
-
}
|
|
1904
|
+
if (staleDistMessage !== null) this.strictOrWarn(staleDistMessage);
|
|
1219
1905
|
const rejectedSpecifiers = /* @__PURE__ */ new Set();
|
|
1220
1906
|
const crossVolumeDetails = [];
|
|
1221
1907
|
for (const [dir, specifiers] of Object.entries(collected.dirOwnerSets)) {
|
|
@@ -1232,6 +1918,7 @@ var ExtractionSession = class {
|
|
|
1232
1918
|
for (const message of this.stickyDiagnostics.values()) this.warn(message);
|
|
1233
1919
|
const admitted = excludeCollectedPackages(collected, rejectedSpecifiers, rootDir);
|
|
1234
1920
|
this.kitDescriptors = admitted.kitDescriptors;
|
|
1921
|
+
this.packageInstances = admitted.packageInstances;
|
|
1235
1922
|
try {
|
|
1236
1923
|
const identity = createSourceIdentity(rootDir);
|
|
1237
1924
|
this.externalRootOwners = /* @__PURE__ */ new Map();
|
|
@@ -1267,23 +1954,29 @@ var ExtractionSession = class {
|
|
|
1267
1954
|
this.externalSourceEntries = admitted.sourceEntries;
|
|
1268
1955
|
this.externalSourceSideEffects = admitted.sourceEntrySideEffects;
|
|
1269
1956
|
for (const entry of admitted.entries) {
|
|
1270
|
-
const
|
|
1957
|
+
const entryPath = resolve(rootDir, entry.path);
|
|
1958
|
+
readPaths.add(entryPath);
|
|
1959
|
+
const source = hostSources.get(entryPath) ?? entry.source;
|
|
1271
1960
|
rawEntries.push({
|
|
1272
1961
|
path: entry.path,
|
|
1273
|
-
source
|
|
1274
|
-
hash
|
|
1962
|
+
source,
|
|
1963
|
+
hash: contentHash(source)
|
|
1275
1964
|
});
|
|
1276
1965
|
}
|
|
1277
1966
|
this.externalPackageDirs = admitted.packageDirs;
|
|
1278
1967
|
this.externalLinkedDirs = admitted.linkedDirs;
|
|
1279
1968
|
this.externalOutputDirs = admitted.outputDirs;
|
|
1280
1969
|
bt.packageResolve = this.elapsed(t);
|
|
1970
|
+
const misspelled = misspelledHostSources(hostSources, readPaths).map(({ path, read }) => `${relative(rootDir, path)} (read as ${read.map((readPath) => relative(rootDir, readPath)).join(", ")})`);
|
|
1971
|
+
if (misspelled.length > 0) throw new DeferredReloadRefusal(`[${this.driverLabel}] reload not published: the host supplied bytes for ${misspelled.join(", ")}, which the full read reaches only under another spelling; the last generation stays served`);
|
|
1281
1972
|
this.beginStatusAttempt();
|
|
1282
1973
|
let accepted;
|
|
1283
1974
|
try {
|
|
1284
|
-
accepted = await this.corpus.prepare(rawEntries);
|
|
1975
|
+
accepted = await this.corpus.prepare(this.withoutOutputSources(rawEntries));
|
|
1285
1976
|
this.throwOnAbortedParse(accepted);
|
|
1286
1977
|
this.skippedSources = accepted.skippedOriginals ?? [];
|
|
1978
|
+
this.ingestionOpenings = accepted.openings ?? [];
|
|
1979
|
+
this.ingestionAdapted = adaptedOriginals(accepted.ownership);
|
|
1287
1980
|
} catch (err) {
|
|
1288
1981
|
this.debouncePending.clear();
|
|
1289
1982
|
this.writeAnalysisStatus("failed", pending, String(err));
|
|
@@ -1291,19 +1984,30 @@ var ExtractionSession = class {
|
|
|
1291
1984
|
}
|
|
1292
1985
|
this.externalFileOwners = projectExternalFileOwners(accepted, this.externalFileOwners);
|
|
1293
1986
|
bt.fileCount = accepted.analysisEntries.length;
|
|
1294
|
-
clearEngineCache(
|
|
1987
|
+
clearEngineCache(() => this.engine());
|
|
1295
1988
|
await this.analyzeAndEmit(accepted.analysisEntries, packageMap, false, bt, pipelineStart, pending);
|
|
1296
|
-
this.publishSourceIngestion(accepted);
|
|
1297
|
-
setSharedExternalDirs(admitted.packageDirs);
|
|
1298
|
-
setSharedExternalEntries(admitted.sourceEntries);
|
|
1299
|
-
setSharedExternalSideEffects(admitted.sourceEntrySideEffects);
|
|
1989
|
+
this.publishSourceIngestion(accepted, "full", (path) => rawEntries.find((entry) => entry.path === path));
|
|
1990
|
+
setSharedExternalDirs(this.key, admitted.packageDirs);
|
|
1991
|
+
setSharedExternalEntries(this.key, admitted.sourceEntries);
|
|
1992
|
+
setSharedExternalSideEffects(this.key, admitted.sourceEntrySideEffects);
|
|
1300
1993
|
this.onExternalRootsCommitted?.(this.externalWatchRoots);
|
|
1301
|
-
setOwningWatchSession(this);
|
|
1994
|
+
setOwningWatchSession(this.key, this);
|
|
1302
1995
|
} catch (err) {
|
|
1303
1996
|
this.restoreSourceState(priorSourceState);
|
|
1304
1997
|
throw err;
|
|
1305
1998
|
}
|
|
1306
1999
|
}
|
|
2000
|
+
/** The full pass's analysis inputs, less any file whose real path lies in
|
|
2001
|
+
* an output directory, each reported. */
|
|
2002
|
+
withoutOutputSources(entries) {
|
|
2003
|
+
const inOutput = outputSourceGuard(this.rootDir, this.structuralExclude);
|
|
2004
|
+
return entries.filter((entry) => {
|
|
2005
|
+
const outputDir = inOutput(resolve(this.rootDir, entry.path));
|
|
2006
|
+
if (outputDir === null) return true;
|
|
2007
|
+
this.warn(outputSourceMessage(entry.path, outputDir));
|
|
2008
|
+
return false;
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
1307
2011
|
/** Per-generation source state captured as ONE object so the restore
|
|
1308
2012
|
* cannot omit a member; deep-copied fields are mutated in place. */
|
|
1309
2013
|
snapshotSourceState() {
|
|
@@ -1325,16 +2029,92 @@ var ExtractionSession = class {
|
|
|
1325
2029
|
restoreSourceState(snapshot) {
|
|
1326
2030
|
Object.assign(this, snapshot);
|
|
1327
2031
|
}
|
|
1328
|
-
/**
|
|
1329
|
-
*
|
|
2032
|
+
/** The system under `context`: the one load path for the build's
|
|
2033
|
+
* authority and for a participant checking its own context. */
|
|
2034
|
+
loadSystemUnder(context) {
|
|
2035
|
+
return loadSystemConfig(() => this.engine(), {
|
|
2036
|
+
systemPath: resolve(this.rootDir, this.options.system),
|
|
2037
|
+
rootDir: this.rootDir,
|
|
2038
|
+
prefix: this.options.prefix,
|
|
2039
|
+
prefixContextualVars: this.options.prefixContextualVars,
|
|
2040
|
+
conditions: context.conditions,
|
|
2041
|
+
workspaces: context.workspaces,
|
|
2042
|
+
extensions: context.extensions
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
/** What the system loader reads of this participant besides the root, as
|
|
2046
|
+
* stable text: its conditions and extension order. */
|
|
2047
|
+
resolutionContextText() {
|
|
2048
|
+
return JSON.stringify([this.conditions, extensionPolicyJson(this.extensionPolicy)]);
|
|
2049
|
+
}
|
|
2050
|
+
resolutionContextLabel() {
|
|
2051
|
+
return `${this.driverLabel} with conditions [${this.conditions.join(", ")}] and extension order ${this.extensionPolicy.resolverVersion}`;
|
|
2052
|
+
}
|
|
2053
|
+
/** One agreed system authority (SA5): a participant whose resolution
|
|
2054
|
+
* context differs from the one the build's system was loaded under loads
|
|
2055
|
+
* it once under its own, and proceeds only on the same system. Otherwise
|
|
2056
|
+
* it throws, naming both contexts, whichever participant came first. */
|
|
2057
|
+
agreeWithSystemAuthority() {
|
|
2058
|
+
const authority = getSystemAuthority(this.key);
|
|
2059
|
+
if (authority === null) return;
|
|
2060
|
+
const context = this.resolutionContextText();
|
|
2061
|
+
if (context === authority.context) return;
|
|
2062
|
+
let own = authority.others.get(context);
|
|
2063
|
+
if (own === void 0) {
|
|
2064
|
+
own = systemLoad(this.loadSystemUnder({
|
|
2065
|
+
conditions: this.conditions,
|
|
2066
|
+
workspaces: declaredWorkspacePackages(this.rootDir),
|
|
2067
|
+
extensions: this.extensionPolicy
|
|
2068
|
+
}));
|
|
2069
|
+
authority.others.set(context, own);
|
|
2070
|
+
}
|
|
2071
|
+
if (own.identity === authority.identity) return;
|
|
2072
|
+
const shared = new Set(authority.dependencies);
|
|
2073
|
+
const mine = new Set(own.dependencies);
|
|
2074
|
+
const differing = [...authority.dependencies.filter((path) => !mine.has(path)), ...own.dependencies.filter((path) => !shared.has(path))].map((path) => relative(this.rootDir, path));
|
|
2075
|
+
throw new SessionConfigurationConflict(this.key, authority.label, this.resolutionContextLabel(), differing.length > 0 ? [`system modules ${differing.join(", ")}`] : ["the evaluated system"], "Every participant of one build must evaluate the same system: give each compiler conditions that select the same system modules.");
|
|
2076
|
+
}
|
|
2077
|
+
/** Release this session's publication claim so a successor may publish,
|
|
2078
|
+
* and leave the build, which retires with its last participant.
|
|
2079
|
+
* Idempotent; `reattach` joins the build again. */
|
|
1330
2080
|
close() {
|
|
1331
2081
|
this.releasePublicationClaim?.();
|
|
1332
2082
|
this.releasePublicationClaim = null;
|
|
2083
|
+
if (this.joinedKey === null || this.participant === null) return;
|
|
2084
|
+
if (getOwningWatchSession(this.joinedKey) === this) setOwningWatchSession(this.joinedKey, null);
|
|
2085
|
+
leaveSession(this.joinedKey, this.participant);
|
|
2086
|
+
this.participant = null;
|
|
2087
|
+
this.detached = true;
|
|
2088
|
+
}
|
|
2089
|
+
/** A closed participant attaching again: its private analysis is stale,
|
|
2090
|
+
* so it is discarded, and it joins its build again. Idempotent. */
|
|
2091
|
+
reattach() {
|
|
2092
|
+
if (!this.detached) return;
|
|
2093
|
+
this.detached = false;
|
|
2094
|
+
this.system = null;
|
|
2095
|
+
this.joinedKey = null;
|
|
2096
|
+
}
|
|
2097
|
+
/** Brings a reattached participant up to date with a full rescan of a
|
|
2098
|
+
* live build, which reconciles deletions too; true then. A retired build
|
|
2099
|
+
* is false: the host starts it as at first. */
|
|
2100
|
+
async catchUp() {
|
|
2101
|
+
if (getManifestJson(this.key) === null) return false;
|
|
2102
|
+
await this.awaitObservation(this.recordRescan());
|
|
2103
|
+
return true;
|
|
2104
|
+
}
|
|
2105
|
+
/** Queues a full rescan under a new revision. It is never equivalent to
|
|
2106
|
+
* an active attempt: only a full read covers it. */
|
|
2107
|
+
recordRescan() {
|
|
2108
|
+
const queue = observationQueue(this.key);
|
|
2109
|
+
queue.rescan = true;
|
|
2110
|
+
const revision = ++queue.revision;
|
|
2111
|
+
queue.revisions.set(revision, null);
|
|
2112
|
+
return revision;
|
|
1333
2113
|
}
|
|
1334
2114
|
/** Reset analysis state for a system reload: write guards go back to null
|
|
1335
2115
|
* and reseed from the disk envelopes on the next publication. */
|
|
1336
2116
|
resetForHmr() {
|
|
1337
|
-
resetAnalysisStartedPromise();
|
|
2117
|
+
resetAnalysisStartedPromise(this.key);
|
|
1338
2118
|
this.artifactRecords = {
|
|
1339
2119
|
manifest: null,
|
|
1340
2120
|
inputs: null,
|
|
@@ -1345,7 +2125,7 @@ var ExtractionSession = class {
|
|
|
1345
2125
|
/** The (sourceKey, observed hash) pairs of a watch batch — the status
|
|
1346
2126
|
* file's pending set; loaders wait only on observed inputs. */
|
|
1347
2127
|
pendingFromBatch(changes) {
|
|
1348
|
-
const { excludeMatcher, extensionsSet } = this.
|
|
2128
|
+
const { excludeMatcher, extensionsSet } = this.scanConfig;
|
|
1349
2129
|
const pending = [];
|
|
1350
2130
|
for (const path of changes.modifiedFiles ?? []) {
|
|
1351
2131
|
const classified = this.classifyWatchPath(path, {
|
|
@@ -1354,7 +2134,7 @@ var ExtractionSession = class {
|
|
|
1354
2134
|
});
|
|
1355
2135
|
if (!classified) continue;
|
|
1356
2136
|
try {
|
|
1357
|
-
pending.push([classified.key, contentHash(readFileSync(path, "utf-8"))]);
|
|
2137
|
+
pending.push([classified.key, contentHash(changes.sources?.get(path) ?? readFileSync(path, "utf-8"))]);
|
|
1358
2138
|
} catch {}
|
|
1359
2139
|
}
|
|
1360
2140
|
return pending;
|
|
@@ -1366,7 +2146,7 @@ var ExtractionSession = class {
|
|
|
1366
2146
|
if (!identity) return changes;
|
|
1367
2147
|
if (!changes.modifiedFiles && !changes.removedFiles) return changes;
|
|
1368
2148
|
if (this.externalWatchRoots.length === 0) return changes;
|
|
1369
|
-
const { extensionsSet } = this.
|
|
2149
|
+
const { extensionsSet } = this.scanConfig;
|
|
1370
2150
|
const dirtyRoots = /* @__PURE__ */ new Set();
|
|
1371
2151
|
const modified = /* @__PURE__ */ new Set();
|
|
1372
2152
|
const removed = /* @__PURE__ */ new Set();
|
|
@@ -1404,13 +2184,14 @@ var ExtractionSession = class {
|
|
|
1404
2184
|
} catch {
|
|
1405
2185
|
continue;
|
|
1406
2186
|
}
|
|
1407
|
-
if (previous.get(resolved.sourceKey)?.hash !== rawHash) modified.add(abs);
|
|
2187
|
+
if (previous.get(resolved.sourceKey)?.hash !== rawHash || this.ingestionFailureDiagnostics.some((diagnostic) => diagnostic.file === resolved.sourceKey)) modified.add(abs);
|
|
1408
2188
|
}
|
|
1409
2189
|
for (const [key, entry] of previous) if (!seen.has(key)) removed.add(entry.abs);
|
|
1410
2190
|
}
|
|
1411
2191
|
return {
|
|
1412
2192
|
modifiedFiles: modified,
|
|
1413
|
-
removedFiles: removed
|
|
2193
|
+
removedFiles: removed,
|
|
2194
|
+
sources: changes.sources
|
|
1414
2195
|
};
|
|
1415
2196
|
}
|
|
1416
2197
|
/** Route one watcher path: a project-root member (consumer excludes apply)
|
|
@@ -1477,33 +2258,40 @@ var ExtractionSession = class {
|
|
|
1477
2258
|
packageMap,
|
|
1478
2259
|
system,
|
|
1479
2260
|
emitter: {
|
|
1480
|
-
runtimeImport:
|
|
1481
|
-
cssModuleId:
|
|
2261
|
+
runtimeImport: this.runtimeImport,
|
|
2262
|
+
cssModuleId: this.cssModuleId,
|
|
1482
2263
|
systemPropsModuleId: this.systemPropsModuleId ?? systemPropsPath(this.sessionDir)
|
|
1483
2264
|
},
|
|
1484
2265
|
pathAliasesJson: this.pathAliasesJson,
|
|
1485
2266
|
staticCssJson: this.staticCssJson,
|
|
1486
2267
|
externalDirs: this.externalPackageDirs.map((dir) => relative(this.rootDir, dir)),
|
|
2268
|
+
rootDir: this.rootDir,
|
|
2269
|
+
assets: this.assetClassification,
|
|
2270
|
+
adapted: this.ingestionAdapted,
|
|
2271
|
+
loadExpander: this.loadExpander,
|
|
1487
2272
|
devMode: this.engineDevMode(devMode),
|
|
1488
2273
|
analysisContext: {
|
|
1489
2274
|
skippedSources: [...this.skippedSources, ...this.ingestionFailureDiagnostics.map((d) => d.file)].map((file) => isAbsolute(file) ? relative(this.rootDir, file) : file),
|
|
1490
2275
|
unbundledComputedImports: this.host.unbundledComputedImports,
|
|
2276
|
+
openings: [...this.ingestionOpenings],
|
|
1491
2277
|
packageDirs: this.externalPackageDirs.map((dir) => relative(this.rootDir, dir)),
|
|
1492
2278
|
linkedDirs: this.externalLinkedDirs.map((dir) => relative(this.rootDir, dir)),
|
|
1493
|
-
outputDirs: this.externalOutputDirs.map((dir) => relative(this.rootDir, dir))
|
|
2279
|
+
outputDirs: this.externalOutputDirs.map((dir) => relative(this.rootDir, dir)),
|
|
2280
|
+
extensions: this.extensionPolicy
|
|
1494
2281
|
}
|
|
1495
2282
|
};
|
|
1496
2283
|
this.writeAnalysisStatus("analyzing", pending);
|
|
1497
|
-
const result = runProjectAnalysis(
|
|
2284
|
+
const result = runProjectAnalysis(() => this.engine(), {
|
|
1498
2285
|
...analysisOptions,
|
|
1499
2286
|
warn: (message) => this.warn(message),
|
|
1500
2287
|
info: (message) => this.log(message),
|
|
1501
2288
|
strict: this.options.strict,
|
|
1502
2289
|
diagnostics: this.options.diagnostics,
|
|
1503
2290
|
reportErrors: this.reportErrors(),
|
|
1504
|
-
extraDiagnostics: this.ingestionFailureDiagnostics,
|
|
2291
|
+
extraDiagnostics: [...this.ingestionFailureDiagnostics, ...await this.compareAliasesWithHost(fileEntries)],
|
|
1505
2292
|
kitDescriptors: this.kitDescriptors
|
|
1506
2293
|
});
|
|
2294
|
+
if (result.manifest) assertRuntimeImportSuppliesTerminals(this.runtimeImport, result.manifest);
|
|
1507
2295
|
enforceExternalTokenContracts({
|
|
1508
2296
|
diagnostics: result.manifest?.diagnostics,
|
|
1509
2297
|
fileOwners: this.externalFileOwners,
|
|
@@ -1538,12 +2326,12 @@ var ExtractionSession = class {
|
|
|
1538
2326
|
declaration,
|
|
1539
2327
|
variables,
|
|
1540
2328
|
postProcessCss(body, {
|
|
1541
|
-
minify: this.options.minify ??
|
|
2329
|
+
minify: this.options.minify ?? this.startupMode === "production",
|
|
1542
2330
|
targets: this.lcssTargets,
|
|
1543
2331
|
warnFn: (msg) => this.warn(msg)
|
|
1544
2332
|
})
|
|
1545
2333
|
].filter(Boolean).join("\n");
|
|
1546
|
-
reportSurvivingAssetPlaceholders(fullCss, {
|
|
2334
|
+
if (!this.hostSubstitutesAssets) reportSurvivingAssetPlaceholders(fullCss, {
|
|
1547
2335
|
strict: this.options.strict,
|
|
1548
2336
|
warn: (message) => this.warn(message),
|
|
1549
2337
|
reportErrors: this.reportErrors(),
|
|
@@ -1556,7 +2344,7 @@ var ExtractionSession = class {
|
|
|
1556
2344
|
prefix: `[${this.driverLabel}]`,
|
|
1557
2345
|
surface: "generated runtime modules"
|
|
1558
2346
|
});
|
|
1559
|
-
setSharedCss(fullCss);
|
|
2347
|
+
setSharedCss(this.key, fullCss);
|
|
1560
2348
|
const systemPropsContent = buildSystemPropsModule({
|
|
1561
2349
|
systemPropMapJson: JSON.stringify(manifest?.system_prop_map ?? {}),
|
|
1562
2350
|
groupRegistryJson: system.groupRegistryJson,
|
|
@@ -1564,9 +2352,20 @@ var ExtractionSession = class {
|
|
|
1564
2352
|
admittedTransforms: manifest?.admitted_transforms ?? {},
|
|
1565
2353
|
typedSystemProps: manifest?.typed_system_props ?? []
|
|
1566
2354
|
});
|
|
1567
|
-
setSharedSystemProps(systemPropsContent);
|
|
1568
|
-
setManifestJson(result.manifestJson);
|
|
1569
|
-
|
|
2355
|
+
setSharedSystemProps(this.key, systemPropsContent);
|
|
2356
|
+
setManifestJson(this.key, result.manifestJson);
|
|
2357
|
+
if (manifest) this.stagedPublication = {
|
|
2358
|
+
manifest,
|
|
2359
|
+
manifestJson: result.manifestJson,
|
|
2360
|
+
analysisGlobalCss: sheets.globalCss,
|
|
2361
|
+
analysisComponentCss: sheets.componentCss,
|
|
2362
|
+
styles: fullCss,
|
|
2363
|
+
systemPropsModule: systemPropsContent,
|
|
2364
|
+
system,
|
|
2365
|
+
packageMap
|
|
2366
|
+
};
|
|
2367
|
+
setAnalyzedHashes(this.key, new Map(fileEntries.map((entry) => [entry.path, entry.hash])));
|
|
2368
|
+
if (this.packageReadRecord !== null) setSharedPackageReadRecord(this.key, this.packageReadRecord);
|
|
1570
2369
|
this.writeAnalysisStatus("committing", pending);
|
|
1571
2370
|
const epoch = hashReplacementPlans(snapshotFilePlans(manifest), systemPropsContent);
|
|
1572
2371
|
if (this.lastCommit === null) this.lastCommit = this.seedCommitFromDisk();
|
|
@@ -1599,6 +2398,86 @@ var ExtractionSession = class {
|
|
|
1599
2398
|
}
|
|
1600
2399
|
/** Write the session's analysis-status artifact. Terminal states
|
|
1601
2400
|
* (idle/failed) close the attempt. */
|
|
2401
|
+
/** Where the host resolves a path alias the analysis reads to another
|
|
2402
|
+
* file (spec §2.2 A7, report only), and how the two were compared. */
|
|
2403
|
+
async compareAliasesWithHost(fileEntries) {
|
|
2404
|
+
const record = packageReadRecord({
|
|
2405
|
+
rootDir: this.rootDir,
|
|
2406
|
+
roots: this.packageInstances,
|
|
2407
|
+
redirected: new Set(this.externalSourceEntries.keys()),
|
|
2408
|
+
analysed: fileEntries.map((entry) => entry.path),
|
|
2409
|
+
rendersBuilder: (file) => this.rendersBuilder(file)
|
|
2410
|
+
});
|
|
2411
|
+
this.packageReadRecord = record;
|
|
2412
|
+
const { moduleSpecifiers } = this.engine();
|
|
2413
|
+
if (this.host.noBundler) return [];
|
|
2414
|
+
if (this.hostResolve === null || moduleSpecifiers === void 0) {
|
|
2415
|
+
this.log("path aliases: no host resolver, comparison unavailable");
|
|
2416
|
+
return [];
|
|
2417
|
+
}
|
|
2418
|
+
try {
|
|
2419
|
+
const { findings, unavailable } = await compareAliases({
|
|
2420
|
+
rootDir: this.rootDir,
|
|
2421
|
+
fileEntries,
|
|
2422
|
+
pathAliasesJson: this.pathAliasesJson,
|
|
2423
|
+
order: this.extensionPolicy,
|
|
2424
|
+
readings: {
|
|
2425
|
+
isAsset: this.assetClassification.isAsset,
|
|
2426
|
+
adapted: this.ingestionAdapted
|
|
2427
|
+
},
|
|
2428
|
+
moduleSpecifiers,
|
|
2429
|
+
resolve: this.hostResolve,
|
|
2430
|
+
cache: this.aliasCache,
|
|
2431
|
+
packages: record
|
|
2432
|
+
});
|
|
2433
|
+
for (const finding of findings) record.reported.add(`${finding.file}\0${finding.component}`);
|
|
2434
|
+
if (unavailable > 0) this.log(`path aliases: ${unavailable} aliased import(s) the host's resolver failed on are unavailable, not agreeing`);
|
|
2435
|
+
return findings;
|
|
2436
|
+
} catch (error) {
|
|
2437
|
+
this.log(`path aliases: comparison unavailable (${String(error)})`);
|
|
2438
|
+
return [];
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
/** Whether the file at a real path declares builder chains, by the
|
|
2442
|
+
* engine's own parse: a module that does, served unread, renders with
|
|
2443
|
+
* empty classes. One the engine cannot read counts as one that does. */
|
|
2444
|
+
rendersBuilder(file) {
|
|
2445
|
+
if (!isEngineTransformExtension(file)) return false;
|
|
2446
|
+
const { extractFacts } = this.engine();
|
|
2447
|
+
if (extractFacts === void 0) return true;
|
|
2448
|
+
const path = relative(this.rootDir, file);
|
|
2449
|
+
try {
|
|
2450
|
+
const facts = parseInternalWire(extractFacts(JSON.stringify([{
|
|
2451
|
+
path,
|
|
2452
|
+
source: readFileSync(file, "utf-8")
|
|
2453
|
+
}])), "extractFacts").files[path];
|
|
2454
|
+
return facts === void 0 || facts.parsePanicked || facts.chains.length > 0;
|
|
2455
|
+
} catch {
|
|
2456
|
+
return true;
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* An import the host resolved while bundling (spec §2.2 A4), reported as
|
|
2461
|
+
* the comparison reports it: webpack resolves each module's requests with
|
|
2462
|
+
* the resolve options of the rules that module matches, which its
|
|
2463
|
+
* resolver, asked outside a compilation, does not apply. `importer` and
|
|
2464
|
+
* `resolved` are absolute. A finding the comparison already reported is
|
|
2465
|
+
* not repeated; an error-level one throws in a build.
|
|
2466
|
+
*/
|
|
2467
|
+
reportHostResolution(importer, request, resolved) {
|
|
2468
|
+
const record = getSharedPackageReadRecord(this.key);
|
|
2469
|
+
if (record === null) return;
|
|
2470
|
+
const finding = packageInstanceFinding(record, relative(record.rootDir, importer).split(sep).join(posix.sep), request, resolved);
|
|
2471
|
+
if (finding === null) return;
|
|
2472
|
+
const key = `${finding.file}\0${finding.component}`;
|
|
2473
|
+
if (record.reported.has(key)) return;
|
|
2474
|
+
record.reported.add(key);
|
|
2475
|
+
surfaceManifestDiagnostics({ diagnostics: [finding] }, (message) => this.warn(message), {
|
|
2476
|
+
levels: this.options.diagnostics,
|
|
2477
|
+
strict: this.options.strict,
|
|
2478
|
+
reportErrors: this.reportErrors()
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
1602
2481
|
writeAnalysisStatus(state, pending, diagnostic) {
|
|
1603
2482
|
const status = {
|
|
1604
2483
|
schema: 2,
|
|
@@ -1708,6 +2587,11 @@ var ExtractionSession = class {
|
|
|
1708
2587
|
/** Maintain the session's epoch witness, rewritten ONLY when the value
|
|
1709
2588
|
* changes, then expose it through the singleton. */
|
|
1710
2589
|
publishReplacementEpoch(epoch) {
|
|
2590
|
+
if (!this.persistArtifacts) {
|
|
2591
|
+
this.lastEpochValue = epoch;
|
|
2592
|
+
setReplacementEpoch(this.key, epoch);
|
|
2593
|
+
return;
|
|
2594
|
+
}
|
|
1711
2595
|
const onDisk = this.diskEpochValue();
|
|
1712
2596
|
if (this.lastEpochValue === null) this.lastEpochValue = onDisk;
|
|
1713
2597
|
if (epoch !== onDisk) this.writeSessionArtifact(REPLACEMENT_EPOCH_ARTIFACT, JSON.stringify({
|
|
@@ -1719,7 +2603,7 @@ var ExtractionSession = class {
|
|
|
1719
2603
|
this.lastEpochValue = epoch;
|
|
1720
2604
|
this.reconcileSiblingEpochs(epoch);
|
|
1721
2605
|
}
|
|
1722
|
-
setReplacementEpoch(epoch);
|
|
2606
|
+
setReplacementEpoch(this.key, epoch);
|
|
1723
2607
|
}
|
|
1724
2608
|
/** sessions-root listing memo, keyed by the root dir's mtime — a new or
|
|
1725
2609
|
* pruned sibling DIRECTORY moves it; agreeing siblings stay listed. */
|
|
@@ -1764,10 +2648,14 @@ var ExtractionSession = class {
|
|
|
1764
2648
|
}
|
|
1765
2649
|
}
|
|
1766
2650
|
/** The pid of `siblingDir`'s live owner, or null when nothing proves one.
|
|
1767
|
-
*
|
|
1768
|
-
*
|
|
1769
|
-
*
|
|
2651
|
+
* A tree whose build is registered in this process is ours and live,
|
|
2652
|
+
* claim or no claim: a publisher's close() releases the claim while the
|
|
2653
|
+
* build's other participants still serve from it. Otherwise a missing,
|
|
2654
|
+
* undecodable or unreadable claim, or one naming our own pid, means no
|
|
2655
|
+
* owner: the opposite default from the CLI lock check on purpose, so do
|
|
2656
|
+
* not unify the two. */
|
|
1770
2657
|
liveSiblingOwnerPid(siblingDir) {
|
|
2658
|
+
if (findSession(sessionKey(basename(siblingDir), this.rootDir)) !== void 0) return process.pid;
|
|
1771
2659
|
let claim;
|
|
1772
2660
|
try {
|
|
1773
2661
|
claim = readCliLockRecord(siblingDir);
|
|
@@ -1798,7 +2686,7 @@ var ExtractionSession = class {
|
|
|
1798
2686
|
/** Delete legacy flat artifacts and prune sibling session directories past
|
|
1799
2687
|
* the retention window — never this session's own dir. */
|
|
1800
2688
|
runSessionStartHygiene() {
|
|
1801
|
-
if (this.sessionStartHygieneDone) return;
|
|
2689
|
+
if (this.sessionStartHygieneDone || !this.persistArtifacts) return;
|
|
1802
2690
|
this.sessionStartHygieneDone = true;
|
|
1803
2691
|
const animusDir = join(this.rootDir, ANIMUS_ARTIFACT_DIR);
|
|
1804
2692
|
const isCliPublishedSet = this.cliWriterHoldsLock(animusDir) || verifyCommitRecord(animusDir).length === 0;
|
|
@@ -1839,13 +2727,29 @@ var ExtractionSession = class {
|
|
|
1839
2727
|
/** Write one artifact write-then-rename, so a cross-process reader never
|
|
1840
2728
|
* sees a torn file; the tmp name carries the pid to keep writers apart. */
|
|
1841
2729
|
writeSessionArtifact(name, content) {
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
2730
|
+
if (this.persistArtifacts) {
|
|
2731
|
+
const dir = this.sessionDir;
|
|
2732
|
+
mkdirSync(dir, { recursive: true });
|
|
2733
|
+
const tmpPath = join(dir, `.${name}.${process.pid}.tmp`);
|
|
2734
|
+
writeFileSync(tmpPath, content);
|
|
2735
|
+
renameSync(tmpPath, join(dir, name));
|
|
2736
|
+
}
|
|
1847
2737
|
this.onArtifactWrite?.(name, content);
|
|
1848
2738
|
}
|
|
2739
|
+
/** How an asset's bytes are fingerprinted, of a file or of bytes read:
|
|
2740
|
+
* the engine's fast fingerprint where it has both, the content hash
|
|
2741
|
+
* otherwise, so the two always agree. */
|
|
2742
|
+
assetFingerprints() {
|
|
2743
|
+
const { fingerprintFile, fingerprintBytes } = this.engine();
|
|
2744
|
+
if (fingerprintFile && fingerprintBytes) return {
|
|
2745
|
+
ofFile: (path) => fingerprintFile(path) ?? contentHash(readFileSync(path)),
|
|
2746
|
+
ofBytes: fingerprintBytes
|
|
2747
|
+
};
|
|
2748
|
+
return {
|
|
2749
|
+
ofFile: (path) => contentHash(readFileSync(path)),
|
|
2750
|
+
ofBytes: contentHash
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
1849
2753
|
/** Copy each asset() specifier's bytes, from every sheet, into `assets/`
|
|
1850
2754
|
* under a content-hashed name and substitute a url relative to
|
|
1851
2755
|
* styles.css. */
|
|
@@ -1855,12 +2759,12 @@ var ExtractionSession = class {
|
|
|
1855
2759
|
const expected = /* @__PURE__ */ new Set();
|
|
1856
2760
|
this.assetDependencyPaths.clear();
|
|
1857
2761
|
this.assetDependencyKeys.clear();
|
|
2762
|
+
if (this.hostSubstitutesAssets) return sheets;
|
|
1858
2763
|
const urlBySpecifier = /* @__PURE__ */ new Map();
|
|
1859
2764
|
for (const specifier of specifiers) {
|
|
1860
2765
|
const cached = this.assetCopyCache.get(specifier);
|
|
1861
2766
|
if (cached && existsSync(join(assetsDir, cached.fileName))) try {
|
|
1862
|
-
|
|
1863
|
-
if (current.mtimeMs === cached.mtimeMs && current.size === cached.size) {
|
|
2767
|
+
if (this.assetFingerprints().ofFile(cached.sourcePath) === cached.fingerprint) {
|
|
1864
2768
|
this.trackAssetDependency(cached.sourcePath);
|
|
1865
2769
|
expected.add(cached.fileName);
|
|
1866
2770
|
urlBySpecifier.set(specifier, cached.url);
|
|
@@ -1869,27 +2773,18 @@ var ExtractionSession = class {
|
|
|
1869
2773
|
} catch {}
|
|
1870
2774
|
const resolvedPath = this.resolveAssetSpecifier(specifier);
|
|
1871
2775
|
if (!resolvedPath) {
|
|
1872
|
-
|
|
1873
|
-
if (this.options.strict) this.strictFailure(`[${this.driverLabel}] ${message}`);
|
|
1874
|
-
else this.warn(message);
|
|
2776
|
+
this.reportUnresolvableAsset(specifier);
|
|
1875
2777
|
urlBySpecifier.set(specifier, specifier);
|
|
1876
2778
|
continue;
|
|
1877
2779
|
}
|
|
1878
|
-
const bytes =
|
|
1879
|
-
const sourceStat = statSync(resolvedPath);
|
|
2780
|
+
const { fileName, bytes } = writeAssetCopy(resolvedPath, assetsDir);
|
|
1880
2781
|
this.trackAssetDependency(resolvedPath);
|
|
1881
|
-
const ext = extname(resolvedPath);
|
|
1882
|
-
const fileName = `${basename(resolvedPath, ext)}.${contentHash(bytes).slice(0, 8)}${ext}`;
|
|
1883
2782
|
expected.add(fileName);
|
|
1884
|
-
if (!existsSync(assetsDir)) mkdirSync(assetsDir, { recursive: true });
|
|
1885
|
-
const assetPath = join(assetsDir, fileName);
|
|
1886
|
-
if (!existsSync(assetPath)) writeFileSync(assetPath, bytes);
|
|
1887
2783
|
const url = `./${SESSION_ASSETS_DIR}/${fileName}`;
|
|
1888
2784
|
urlBySpecifier.set(specifier, url);
|
|
1889
2785
|
this.assetCopyCache.set(specifier, {
|
|
1890
2786
|
sourcePath: resolvedPath,
|
|
1891
|
-
|
|
1892
|
-
size: sourceStat.size,
|
|
2787
|
+
fingerprint: this.assetFingerprints().ofBytes(bytes),
|
|
1893
2788
|
fileName,
|
|
1894
2789
|
url
|
|
1895
2790
|
});
|
|
@@ -1897,6 +2792,10 @@ var ExtractionSession = class {
|
|
|
1897
2792
|
if (pruneSuperseded) pruneStaleAssets(assetsDir, expected);
|
|
1898
2793
|
return substituteSheetAssets(sheets, urlBySpecifier);
|
|
1899
2794
|
}
|
|
2795
|
+
reportUnresolvableAsset(specifier) {
|
|
2796
|
+
const message = `unresolvable asset() specifier: ${specifier}`;
|
|
2797
|
+
this.strictOrWarn(message, `[${this.driverLabel}] ${message}`);
|
|
2798
|
+
}
|
|
1900
2799
|
trackAssetDependency(path) {
|
|
1901
2800
|
this.assetDependencyPaths.add(path);
|
|
1902
2801
|
for (const key of toWatchKeys(path)) this.assetDependencyKeys.add(key);
|
|
@@ -1918,23 +2817,6 @@ var ExtractionSession = class {
|
|
|
1918
2817
|
return null;
|
|
1919
2818
|
}
|
|
1920
2819
|
};
|
|
1921
|
-
/** Sync `assets/` to the current build's file set; per-entry failures are
|
|
1922
|
-
* tolerated — a concurrent session may have removed the same file. */
|
|
1923
|
-
function pruneStaleAssets(assetsDir, expected) {
|
|
1924
|
-
if (!existsSync(assetsDir)) return;
|
|
1925
|
-
let entries;
|
|
1926
|
-
try {
|
|
1927
|
-
entries = readdirSync(assetsDir);
|
|
1928
|
-
} catch {
|
|
1929
|
-
return;
|
|
1930
|
-
}
|
|
1931
|
-
for (const entry of entries) {
|
|
1932
|
-
if (expected.has(entry)) continue;
|
|
1933
|
-
try {
|
|
1934
|
-
unlinkSync(join(assetsDir, entry));
|
|
1935
|
-
} catch {}
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
2820
|
//#endregion
|
|
1939
2821
|
//#region session/turbopack-orchestrator.ts
|
|
1940
2822
|
async function runSessionPipeline(session) {
|
|
@@ -1942,6 +2824,7 @@ async function runSessionPipeline(session) {
|
|
|
1942
2824
|
session.persistAnalysisInputs = true;
|
|
1943
2825
|
await session.runFullPipeline();
|
|
1944
2826
|
}
|
|
2827
|
+
/** Each build's watched root: another build of the root watches it too. */
|
|
1945
2828
|
const activeWatcherRoots = /* @__PURE__ */ new Set();
|
|
1946
2829
|
const IGNORED_SEGMENTS = /* @__PURE__ */ new Set([
|
|
1947
2830
|
ANIMUS_ARTIFACT_DIR,
|
|
@@ -1968,17 +2851,18 @@ function isIntrinsicString(value) {
|
|
|
1968
2851
|
}
|
|
1969
2852
|
function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
1970
2853
|
const { debounceMs = 75, watchFn = watch, holdEvents = false } = options;
|
|
1971
|
-
|
|
1972
|
-
activeWatcherRoots.
|
|
2854
|
+
const watched = JSON.stringify([session.sessionId, rootDir]);
|
|
2855
|
+
if (activeWatcherRoots.has(watched)) return { kind: "already-watched" };
|
|
2856
|
+
activeWatcherRoots.add(watched);
|
|
1973
2857
|
session.debounceCeilingMs = debounceMs;
|
|
1974
2858
|
const pendingPaths = /* @__PURE__ */ new Set();
|
|
1975
2859
|
const watchers = /* @__PURE__ */ new Map();
|
|
1976
|
-
let timer = null;
|
|
1977
2860
|
let updateChain = Promise.resolve();
|
|
1978
2861
|
let closed = false;
|
|
1979
2862
|
let died = false;
|
|
1980
2863
|
let holdingEvents = holdEvents;
|
|
1981
2864
|
const externalWatchers = /* @__PURE__ */ new Map();
|
|
2865
|
+
const dependencyWatchers = /* @__PURE__ */ new Map();
|
|
1982
2866
|
let pendingOpened = /* @__PURE__ */ new Map();
|
|
1983
2867
|
let capturedDuringSnapshot = [];
|
|
1984
2868
|
const externalDiagnosticKey = (root) => `external-watch:${root}`;
|
|
@@ -1997,24 +2881,28 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
1997
2881
|
session.stickyDiagnostics?.set(externalDiagnosticKey(root), message);
|
|
1998
2882
|
console.warn(`[animus-extract] ${message}`);
|
|
1999
2883
|
};
|
|
2884
|
+
let cyclesInFlight = 0;
|
|
2000
2885
|
const flush = () => {
|
|
2001
|
-
timer = null;
|
|
2002
2886
|
const modifiedFiles = /* @__PURE__ */ new Set();
|
|
2003
2887
|
const removedFiles = /* @__PURE__ */ new Set();
|
|
2004
2888
|
for (const path of pendingPaths) (existsSync(path) ? modifiedFiles : removedFiles).add(path);
|
|
2005
2889
|
pendingPaths.clear();
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2890
|
+
if (closed) return;
|
|
2891
|
+
cyclesInFlight++;
|
|
2892
|
+
const cycle = session.handleWatchUpdate({
|
|
2893
|
+
modifiedFiles,
|
|
2894
|
+
removedFiles
|
|
2895
|
+
}).catch((err) => {
|
|
2896
|
+
console.warn(`[animus-extract] watch update failed: ${String(err)}`);
|
|
2897
|
+
}).finally(() => {
|
|
2898
|
+
cyclesInFlight--;
|
|
2899
|
+
if (cyclesInFlight > 0) return;
|
|
2900
|
+
if (pendingOpened.size > 0 || capturedDuringSnapshot.length > 0) rollbackPendingExternal();
|
|
2901
|
+
syncDependencyWatchers();
|
|
2016
2902
|
});
|
|
2903
|
+
updateChain = updateChain.then(() => cycle);
|
|
2017
2904
|
};
|
|
2905
|
+
const coalescing = new CoalescingWindow(flush, debounceMs);
|
|
2018
2906
|
const rollbackPendingExternal = () => {
|
|
2019
2907
|
for (const watcher of pendingOpened.values()) watcher.close();
|
|
2020
2908
|
pendingOpened = /* @__PURE__ */ new Map();
|
|
@@ -2023,16 +2911,17 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
2023
2911
|
const closeAll = () => {
|
|
2024
2912
|
if (closed) return;
|
|
2025
2913
|
closed = true;
|
|
2026
|
-
|
|
2027
|
-
timer = null;
|
|
2914
|
+
coalescing.cancel();
|
|
2028
2915
|
for (const watcher of watchers.values()) watcher.close();
|
|
2029
2916
|
watchers.clear();
|
|
2917
|
+
for (const { watcher } of dependencyWatchers.values()) watcher.close();
|
|
2918
|
+
dependencyWatchers.clear();
|
|
2030
2919
|
for (const watcher of externalWatchers.values()) watcher.close();
|
|
2031
2920
|
externalWatchers.clear();
|
|
2032
2921
|
rollbackPendingExternal();
|
|
2033
2922
|
session.onExternalRootResolved = null;
|
|
2034
2923
|
session.onExternalRootsCommitted = null;
|
|
2035
|
-
activeWatcherRoots.delete(
|
|
2924
|
+
activeWatcherRoots.delete(watched);
|
|
2036
2925
|
};
|
|
2037
2926
|
const onWatcherError = (err) => {
|
|
2038
2927
|
died = true;
|
|
@@ -2048,10 +2937,7 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
2048
2937
|
} catch (err) {
|
|
2049
2938
|
console.warn(`[animus-extract] Turbopack debounce status update failed: ${String(err)}`);
|
|
2050
2939
|
}
|
|
2051
|
-
|
|
2052
|
-
timer = setTimeout(flush, debounceMs);
|
|
2053
|
-
timer.unref?.();
|
|
2054
|
-
}
|
|
2940
|
+
coalescing.note();
|
|
2055
2941
|
};
|
|
2056
2942
|
const onEvent = (baseDir, filename) => {
|
|
2057
2943
|
if (closed || !filename) return;
|
|
@@ -2095,6 +2981,59 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
2095
2981
|
degradeExternalRoot(root, err);
|
|
2096
2982
|
}
|
|
2097
2983
|
};
|
|
2984
|
+
/** Whether the root or an external root watcher already reports `path`. */
|
|
2985
|
+
const watchedByRoot = (path) => {
|
|
2986
|
+
if (isPathWithinRoot(rootDir, path) && !relative(rootDir, path).split(/[\\/]/).some((segment) => IGNORED_SEGMENTS.has(segment))) return true;
|
|
2987
|
+
return [...externalWatchers.keys()].some((root) => isPathWithinRoot(root, path));
|
|
2988
|
+
};
|
|
2989
|
+
/** Watches the system, asset and configuration dependencies no root
|
|
2990
|
+
* watcher reports, by their directories, for those files only. */
|
|
2991
|
+
const syncDependencyWatchers = () => {
|
|
2992
|
+
if (closed) return;
|
|
2993
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
2994
|
+
for (const path of [
|
|
2995
|
+
...session.systemDependencyPaths,
|
|
2996
|
+
...session.assetDependencyPaths,
|
|
2997
|
+
...session.configInputPaths
|
|
2998
|
+
]) {
|
|
2999
|
+
if (watchedByRoot(path)) continue;
|
|
3000
|
+
const files = wanted.get(dirname(path)) ?? /* @__PURE__ */ new Set();
|
|
3001
|
+
files.add(path);
|
|
3002
|
+
wanted.set(dirname(path), files);
|
|
3003
|
+
}
|
|
3004
|
+
for (const [dir, { watcher }] of [...dependencyWatchers]) {
|
|
3005
|
+
if (wanted.has(dir)) continue;
|
|
3006
|
+
watcher.close();
|
|
3007
|
+
dependencyWatchers.delete(dir);
|
|
3008
|
+
}
|
|
3009
|
+
for (const [dir, files] of wanted) {
|
|
3010
|
+
const existing = dependencyWatchers.get(dir);
|
|
3011
|
+
if (existing) {
|
|
3012
|
+
existing.files = files;
|
|
3013
|
+
continue;
|
|
3014
|
+
}
|
|
3015
|
+
try {
|
|
3016
|
+
const watcher = watchFn(dir, { recursive: false }, (_event, name) => {
|
|
3017
|
+
if (closed || !name) return;
|
|
3018
|
+
const abs = join(dir, name.toString());
|
|
3019
|
+
if (dependencyWatchers.get(dir)?.files.has(abs)) enqueuePath(abs);
|
|
3020
|
+
});
|
|
3021
|
+
watcher.on("error", (err) => {
|
|
3022
|
+
watcher.close();
|
|
3023
|
+
dependencyWatchers.delete(dir);
|
|
3024
|
+
console.warn(`[animus-extract] dependency watch on ${dir} failed (${String(err)}); its changes require a dev-server restart`);
|
|
3025
|
+
});
|
|
3026
|
+
watcher.unref?.();
|
|
3027
|
+
dependencyWatchers.set(dir, {
|
|
3028
|
+
watcher,
|
|
3029
|
+
files
|
|
3030
|
+
});
|
|
3031
|
+
} catch (err) {
|
|
3032
|
+
if (errnoCode(err) === "ENOENT") continue;
|
|
3033
|
+
console.warn(`[animus-extract] dependency watch on ${dir} unavailable (${String(err)}); its changes require a dev-server restart`);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
2098
3037
|
const addWatcher = (dir, recursive) => {
|
|
2099
3038
|
const watcher = watchFn(dir, { recursive }, (_event, filename) => onEvent(dir, filename));
|
|
2100
3039
|
watcher.on("error", onWatcherError);
|
|
@@ -2113,6 +3052,7 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
2113
3052
|
return { kind: "unavailable" };
|
|
2114
3053
|
}
|
|
2115
3054
|
for (const root of session.externalWatchRoots ?? []) openExternalWatcher(root, externalWatchers);
|
|
3055
|
+
syncDependencyWatchers();
|
|
2116
3056
|
session.onExternalRootResolved = (root) => {
|
|
2117
3057
|
if (closed) return;
|
|
2118
3058
|
if (externalWatchers.has(root) || pendingOpened.has(root)) return;
|
|
@@ -2137,7 +3077,8 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
2137
3077
|
onDied: null,
|
|
2138
3078
|
deliverHeldEvents: () => {
|
|
2139
3079
|
holdingEvents = false;
|
|
2140
|
-
|
|
3080
|
+
syncDependencyWatchers();
|
|
3081
|
+
if (pendingPaths.size > 0) coalescing.flush();
|
|
2141
3082
|
return updateChain;
|
|
2142
3083
|
},
|
|
2143
3084
|
settle: () => updateChain
|
|
@@ -2148,4 +3089,4 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
|
|
|
2148
3089
|
};
|
|
2149
3090
|
}
|
|
2150
3091
|
//#endregion
|
|
2151
|
-
export { ANIMUS_ARTIFACT_DIR, ANIMUS_CSS_MODULE_ID, CLI_COMMIT_ARTIFACT, CLI_LOCK_ARTIFACT, CLI_LOCK_HEARTBEAT_INTERVAL_MS, CLI_LOCK_STALE_AFTER_MS, ExtractionSession, MANIFEST_ARTIFACT, SESSION_ASSETS_DIR, STYLES_ARTIFACT, SYSTEM_PROPS_ARTIFACT, TURBOPACK_SYSTEM_PROPS_ID, analysisCommitPath, analysisInputsPath, analysisStatusPath, checkLockLiveness, collectSessionAssets, decodeCommitRecord, engineApi, getAnalysisStartedPromise, getAnalyzedHashes, getManifestJson, getReplacementEpoch, getSessionArtifactDir, getSharedCss, getSharedExternalDirs, getSharedExternalEntries, getSharedExternalSideEffects, getSharedSystemProps, holdDirectoryClaim, isLockHolderAlive, lockRecordBytes, manifestPath, pruneStaleAssets, readCliLockRecord, readJsonEnvelope, replacementEpochPath, resetAnalysisStartedPromise, runSessionPipeline, sessionArtifactDir,
|
|
3092
|
+
export { ANIMUS_ARTIFACT_DIR, ANIMUS_CSS_MODULE_ID, CLI_COMMIT_ARTIFACT, CLI_LOCK_ARTIFACT, CLI_LOCK_HEARTBEAT_INTERVAL_MS, CLI_LOCK_STALE_AFTER_MS, COALESCING_WINDOW_MS, CoalescingWindow, EnvironmentFailure, ExtractionSession, MANIFEST_ARTIFACT, SESSION_ASSETS_DIR, STYLES_ARTIFACT, SYSTEM_PROPS_ARTIFACT, SessionConfigurationConflict, TURBOPACK_SYSTEM_PROPS_ID, analysisCommitPath, analysisInputsPath, analysisStatusPath, checkLockLiveness, collectSessionAssets, createBuildId, decodeCommitRecord, engineApi, engineFactory, engineHandle, findSession, getAnalysisStartedPromise, getAnalyzedHashes, getManifestJson, getReplacementEpoch, getSessionArtifactDir, getSharedCss, getSharedExternalDirs, getSharedExternalEntries, getSharedExternalSideEffects, getSharedSystemProps, holdDirectoryClaim, isLockHolderAlive, joinSession, lockRecordBytes, manifestPath, pruneStaleAssets, readCliLockRecord, readJsonEnvelope, releaseEngineHandle, replacementEpochPath, requireEngine, resetAnalysisStartedPromise, runSessionPipeline, sessionArtifactDir, sessionKey, setAnalysisStartedPromise, startTurbopackWatcher, stylesPath, systemPropsPath, verifyCommitRecord };
|