@animus-ui/extract 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/dist/correlate-external-tokens.d.ts.map +1 -1
- package/dist/discover-packages.d.ts +50 -2
- package/dist/discover-packages.d.ts.map +1 -1
- package/dist/external-keyframes.d.ts.map +1 -1
- package/dist/index.cjs +336 -24
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +319 -21
- package/dist/manifest-diagnostics.d.ts +10 -0
- package/dist/manifest-diagnostics.d.ts.map +1 -1
- package/dist/replacement-plans.d.ts +46 -0
- package/dist/replacement-plans.d.ts.map +1 -0
- package/dist/source-identity.d.ts +93 -0
- package/dist/source-identity.d.ts.map +1 -0
- package/package.json +3 -3
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"correlate-external-tokens.d.ts","sourceRoot":"","sources":["../pipeline/correlate-external-tokens.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"correlate-external-tokens.d.ts","sourceRoot":"","sources":["../pipeline/correlate-external-tokens.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAejE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,wBAAwB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpD,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CA+D3B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,IAAI,EAAE;IACtD,WAAW,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAC;IAC9C,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,yDAAyD;IACzD,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CACxC,GAAG,MAAM,EAAE,CAyBX;AAWD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,WAAW,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAC;IAC9C,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,wBAAwB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpD,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,GAAG,IAAI,CAwBP"}
|
|
@@ -12,6 +12,16 @@ export declare function findPackageRoot(absEntryPath: string): string;
|
|
|
12
12
|
* repo path containing 'dist') must still have its sources discovered.
|
|
13
13
|
*/
|
|
14
14
|
export declare const PACKAGE_SRC_EXCLUDES: string[];
|
|
15
|
+
/** True when a PACKAGE-RELATIVE path matches a package-source exclusion
|
|
16
|
+
* fragment (the "within the package" filter — see PACKAGE_SRC_EXCLUDES). */
|
|
17
|
+
export declare function isExcludedPackageRelativePath(rel: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* THE package-source walk (guardrail G1 — one policy): shared discovery with
|
|
20
|
+
* no consumer patterns, then exclusion by package-relative path so fragments
|
|
21
|
+
* in the package's own location can't blank out its sources. Used by the
|
|
22
|
+
* collector, hosts' dirty-root rewalks, and watch-path classification alike.
|
|
23
|
+
*/
|
|
24
|
+
export declare function walkPackageSources(packageDir: string, extensionsSet: ReadonlySet<string>): string[];
|
|
15
25
|
/**
|
|
16
26
|
* What one declared include specifier produced, so callers can tell a package
|
|
17
27
|
* that contributed sources apart from one that silently contributed nothing.
|
|
@@ -38,6 +48,14 @@ export interface ExternalPackageOutcome {
|
|
|
38
48
|
*/
|
|
39
49
|
fileCount: number;
|
|
40
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve an absolute-path specifier (a relative `includes` entry already
|
|
53
|
+
* resolved against the system file) without a bundler: the path itself when it
|
|
54
|
+
* is a file, otherwise the extension and directory-index candidates built from
|
|
55
|
+
* the caller's extension set. Used only as a fallback — a bundler resolver that
|
|
56
|
+
* answers first still wins, since it also knows aliases and `.js`→`.ts` mapping.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveAbsolutePathSpecifier(absSpecifier: string, extensionsSet: ReadonlySet<string>): string | null;
|
|
41
59
|
export interface CollectedExternalPackages {
|
|
42
60
|
/** New file entries (rootDir-relative, preprocessed) for the analysis set. */
|
|
43
61
|
entries: Array<{
|
|
@@ -48,10 +66,20 @@ export interface CollectedExternalPackages {
|
|
|
48
66
|
packageMap: Record<string, string>;
|
|
49
67
|
/** specifier → absolute src/index.ts path, only for packages with one. */
|
|
50
68
|
sourceEntries: Map<string, string>;
|
|
69
|
+
/** specifier → absolute entry to scan for branded `Keyframes` collections —
|
|
70
|
+
* one per admitted specifier, whatever the package's shape: the redirected
|
|
71
|
+
* source entry when src/ serves it, the resolved (dist) entry otherwise.
|
|
72
|
+
* Keyed separately from `sourceEntries` because that map doubles as the
|
|
73
|
+
* hosts' module-resolution redirect and stays src-only by contract. */
|
|
74
|
+
keyframesScanEntries: Map<string, string>;
|
|
51
75
|
/** Absolute directories for bundler loader allowlisting (src/ or dist entry dir). */
|
|
52
76
|
packageDirs: string[];
|
|
53
|
-
/** Absolute package dir →
|
|
54
|
-
|
|
77
|
+
/** Absolute package dir → EVERY declared specifier that claimed it, in
|
|
78
|
+
* declaration order (set-valued ownership — openspec:
|
|
79
|
+
* external-source-watch-ingestion, design D2). The first-wins
|
|
80
|
+
* single-value view correlation consumers key on derives via
|
|
81
|
+
* `firstOwners`. */
|
|
82
|
+
dirOwnerSets: Record<string, string[]>;
|
|
55
83
|
/** rootDir-relative file path → owning specifier, for files THIS collection
|
|
56
84
|
* pushed (first-contributing specifier wins; files the caller's own set
|
|
57
85
|
* already supplied stay unattributed — they are consumer-owned). */
|
|
@@ -95,7 +123,27 @@ export declare function collectExternalPackageSources(opts: {
|
|
|
95
123
|
} | null>;
|
|
96
124
|
/** Called when a discovered file cannot be read; the file is skipped. */
|
|
97
125
|
onUnreadable: (relPath: string, error: unknown) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Called once per specifier immediately after its package dir is derived
|
|
128
|
+
* and BEFORE that package's sources are walked (openspec:
|
|
129
|
+
* external-source-watch-ingestion, design D4 — a host can open its
|
|
130
|
+
* watcher with no blind gap between scan and watch).
|
|
131
|
+
*/
|
|
132
|
+
onPackageResolved?: (specifier: string, packageDir: string) => void;
|
|
98
133
|
}): Promise<CollectedExternalPackages>;
|
|
134
|
+
/** First-declared specifier per package dir — the single-value ownership
|
|
135
|
+
* view correlation consumers key on, derived from `dirOwnerSets`. */
|
|
136
|
+
export declare function firstOwners(dirOwnerSets: Record<string, string[]>): Record<string, string>;
|
|
137
|
+
/**
|
|
138
|
+
* Excise a set of rejected specifiers from a collection result ATOMICALLY
|
|
139
|
+
* (openspec: external-source-watch-ingestion, design D5): the returned copy
|
|
140
|
+
* carries no entries, package-map targets, source entries, package dirs, or
|
|
141
|
+
* ownership for the rejected packages — a package dir is removed only when
|
|
142
|
+
* EVERY specifier that claimed it is rejected (a dir-level rejection, such
|
|
143
|
+
* as the cross-volume gate, always rejects them together). Outcome records
|
|
144
|
+
* are reporting inputs, not membership, and pass through untouched.
|
|
145
|
+
*/
|
|
146
|
+
export declare function excludeCollectedPackages(collected: CollectedExternalPackages, rejectedSpecifiers: ReadonlySet<string>, rootDir: string): CollectedExternalPackages;
|
|
99
147
|
/**
|
|
100
148
|
* Extract external DS package names from inheritance declarations in the
|
|
101
149
|
* system file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover-packages.d.ts","sourceRoot":"","sources":["../pipeline/discover-packages.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"discover-packages.d.ts","sourceRoot":"","sources":["../pipeline/discover-packages.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-keyframes.d.ts","sourceRoot":"","sources":["../pipeline/external-keyframes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,qDAAqD;AACrD,eAAO,MAAM,+BAA+B,2CACF,CAAC;AAC3C,eAAO,MAAM,0BAA0B,sCAAsC,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC;0EACsE;IACtE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;yEACqE;IACrE,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,EAC3D,qBAAqB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChD,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,EACjC,OAAO,EAAE,MAAM,GACd,sBAAsB,
|
|
1
|
+
{"version":3,"file":"external-keyframes.d.ts","sourceRoot":"","sources":["../pipeline/external-keyframes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,qDAAqD;AACrD,eAAO,MAAM,+BAA+B,2CACF,CAAC;AAC3C,eAAO,MAAM,0BAA0B,sCAAsC,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC;0EACsE;IACtE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;yEACqE;IACrE,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,EAC3D,qBAAqB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChD,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,EACjC,OAAO,EAAE,MAAM,GACd,sBAAsB,CAoExB"}
|
package/dist/index.cjs
CHANGED
|
@@ -24,13 +24,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
let crypto = require("crypto");
|
|
25
25
|
let fs = require("fs");
|
|
26
26
|
let path = require("path");
|
|
27
|
+
let node_fs = require("node:fs");
|
|
28
|
+
let node_path = require("node:path");
|
|
29
|
+
node_path = __toESM(node_path);
|
|
27
30
|
let module$1 = require("module");
|
|
28
31
|
let browserslist = require("browserslist");
|
|
29
32
|
browserslist = __toESM(browserslist);
|
|
30
33
|
let lightningcss = require("lightningcss");
|
|
31
34
|
let _animus_ui_properties = require("@animus-ui/properties");
|
|
32
|
-
let node_fs = require("node:fs");
|
|
33
|
-
let node_path = require("node:path");
|
|
34
35
|
//#region pipeline/assemble-stylesheet.ts
|
|
35
36
|
/**
|
|
36
37
|
* The 7 Animus cascade layers. Always prefixed with `anm-` to avoid
|
|
@@ -269,7 +270,7 @@ function mergeExternalKeyframes(scan, consumerKeyframesJson, externalEntries, ro
|
|
|
269
270
|
file: entryPath,
|
|
270
271
|
component: "keyframes",
|
|
271
272
|
kind: "warn",
|
|
272
|
-
message: `external package entry failed the keyframes scan — its collections are invisible to extraction: ${String(error)} (${KEYFRAMES_EXTERNAL_ENTRY_FAILED})`,
|
|
273
|
+
message: `external package entry failed the keyframes scan — its collections are invisible to extraction: ${String(error)}. Keyframe collections must be reachable from the package's definition entry without evaluating framework re-exports: export them (directly or as a named re-export) from the definition entry, and avoid \`export *\` of framework packages there (${KEYFRAMES_EXTERNAL_ENTRY_FAILED})`,
|
|
273
274
|
code: KEYFRAMES_EXTERNAL_ENTRY_FAILED,
|
|
274
275
|
severity: "warn"
|
|
275
276
|
});
|
|
@@ -337,6 +338,126 @@ function discoverFiles(dir, rootDir, excludePatterns, extensionsSet) {
|
|
|
337
338
|
return results;
|
|
338
339
|
}
|
|
339
340
|
//#endregion
|
|
341
|
+
//#region pipeline/source-identity.ts
|
|
342
|
+
/**
|
|
343
|
+
* SourceId derivation authority + allowlist membership (openspec:
|
|
344
|
+
* external-source-watch-ingestion, design D1/D2/D5).
|
|
345
|
+
*
|
|
346
|
+
* One shared derivation produces the canonical source identity consumed by
|
|
347
|
+
* discovery, watch ingestion, ownership, deletion pruning, and diagnostics
|
|
348
|
+
* — raw event paths are lookup INPUTS only, so event spelling (symlink
|
|
349
|
+
* alias vs canonical, lexical vs realpath) can never fork identity.
|
|
350
|
+
*
|
|
351
|
+
* The containment and volume helpers are pure and path-API-injectable so
|
|
352
|
+
* Windows semantics are unit-testable via `path.win32` on any host; runtime
|
|
353
|
+
* callers use the ambient platform implementation.
|
|
354
|
+
*/
|
|
355
|
+
/**
|
|
356
|
+
* Structural containment: `target` is the root itself or a descendant of it,
|
|
357
|
+
* decided by `relative()` shape — never by string prefixing, so `/ui` can
|
|
358
|
+
* never claim `/ui-old`, and a cross-drive win32 target (whose relative()
|
|
359
|
+
* result is absolute) is never contained.
|
|
360
|
+
*/
|
|
361
|
+
function isPathWithinRoot(root, target, pathApi = node_path.default) {
|
|
362
|
+
const rel = pathApi.relative(root, target);
|
|
363
|
+
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Cross-volume gate (design D5): two paths share a platform path root
|
|
367
|
+
* (win32 drive letter or UNC share; always true on posix). Compared
|
|
368
|
+
* case-insensitively — win32 drive letters are case-insensitive.
|
|
369
|
+
*/
|
|
370
|
+
function sharesVolumeRoot(a, b, pathApi = node_path.default) {
|
|
371
|
+
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
372
|
+
return volumeOf(a) === volumeOf(b);
|
|
373
|
+
}
|
|
374
|
+
function canonicalize(p) {
|
|
375
|
+
try {
|
|
376
|
+
return (0, node_fs.realpathSync)(p);
|
|
377
|
+
} catch {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function createSourceIdentity(rootDir) {
|
|
382
|
+
const normalizedRootDir = node_path.default.normalize(rootDir);
|
|
383
|
+
const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
|
|
384
|
+
const roots = [];
|
|
385
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
386
|
+
const owningRecord = (canonicalPath) => {
|
|
387
|
+
let owner = null;
|
|
388
|
+
for (const record of roots) {
|
|
389
|
+
if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
|
|
390
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
391
|
+
}
|
|
392
|
+
return owner;
|
|
393
|
+
};
|
|
394
|
+
return {
|
|
395
|
+
rootDir: normalizedRootDir,
|
|
396
|
+
canonicalRootDir,
|
|
397
|
+
registerExternalRoot(root) {
|
|
398
|
+
const asRegistered = node_path.default.normalize(root);
|
|
399
|
+
const canonical = canonicalize(asRegistered) ?? asRegistered;
|
|
400
|
+
const existing = roots.find((record) => record.canonical === canonical);
|
|
401
|
+
if (existing) return existing.canonical;
|
|
402
|
+
roots.push({
|
|
403
|
+
asRegistered,
|
|
404
|
+
canonical
|
|
405
|
+
});
|
|
406
|
+
return canonical;
|
|
407
|
+
},
|
|
408
|
+
externalRoots() {
|
|
409
|
+
return roots.map((record) => record.canonical);
|
|
410
|
+
},
|
|
411
|
+
resolveSourceId(inputPath) {
|
|
412
|
+
const lexical = node_path.default.normalize(inputPath);
|
|
413
|
+
const canonical = canonicalize(lexical);
|
|
414
|
+
if (canonical === null) return null;
|
|
415
|
+
const owner = owningRecord(canonical);
|
|
416
|
+
const ownedBy = (record) => {
|
|
417
|
+
const pathInRoot = node_path.default.relative(record.canonical, canonical);
|
|
418
|
+
return {
|
|
419
|
+
sourceKey: node_path.default.relative(normalizedRootDir, node_path.default.join(record.asRegistered, pathInRoot)),
|
|
420
|
+
owningRoot: record.canonical,
|
|
421
|
+
pathInRoot
|
|
422
|
+
};
|
|
423
|
+
};
|
|
424
|
+
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
425
|
+
let resolved;
|
|
426
|
+
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
427
|
+
const key = node_path.default.relative(canonicalRootDir, canonical);
|
|
428
|
+
resolved = {
|
|
429
|
+
sourceKey: key,
|
|
430
|
+
owningRoot: null,
|
|
431
|
+
pathInRoot: key
|
|
432
|
+
};
|
|
433
|
+
} else if (owner) resolved = ownedBy(owner);
|
|
434
|
+
else return null;
|
|
435
|
+
aliases.set(lexical, resolved);
|
|
436
|
+
aliases.set(canonical, resolved);
|
|
437
|
+
return resolved;
|
|
438
|
+
},
|
|
439
|
+
resolveDeletedSourceId(inputPath) {
|
|
440
|
+
return aliases.get(node_path.default.normalize(inputPath)) ?? null;
|
|
441
|
+
},
|
|
442
|
+
containingExternalRoot(inputPath) {
|
|
443
|
+
const lexical = node_path.default.normalize(inputPath);
|
|
444
|
+
let owner = null;
|
|
445
|
+
for (const record of roots) {
|
|
446
|
+
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
447
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
448
|
+
}
|
|
449
|
+
if (owner) return owner.canonical;
|
|
450
|
+
const canonical = canonicalize(lexical);
|
|
451
|
+
if (canonical === null) return null;
|
|
452
|
+
for (const record of roots) {
|
|
453
|
+
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
454
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
455
|
+
}
|
|
456
|
+
return owner?.canonical ?? null;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
//#endregion
|
|
340
461
|
//#region pipeline/discover-packages.ts
|
|
341
462
|
/**
|
|
342
463
|
* Walk up from a resolved package entry file to the nearest directory
|
|
@@ -361,6 +482,20 @@ const PACKAGE_SRC_EXCLUDES = [
|
|
|
361
482
|
".test.",
|
|
362
483
|
".spec."
|
|
363
484
|
];
|
|
485
|
+
/** True when a PACKAGE-RELATIVE path matches a package-source exclusion
|
|
486
|
+
* fragment (the "within the package" filter — see PACKAGE_SRC_EXCLUDES). */
|
|
487
|
+
function isExcludedPackageRelativePath(rel) {
|
|
488
|
+
return PACKAGE_SRC_EXCLUDES.some((pattern) => rel.includes(pattern));
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* THE package-source walk (guardrail G1 — one policy): shared discovery with
|
|
492
|
+
* no consumer patterns, then exclusion by package-relative path so fragments
|
|
493
|
+
* in the package's own location can't blank out its sources. Used by the
|
|
494
|
+
* collector, hosts' dirty-root rewalks, and watch-path classification alike.
|
|
495
|
+
*/
|
|
496
|
+
function walkPackageSources(packageDir, extensionsSet) {
|
|
497
|
+
return discoverFiles(packageDir, packageDir, [], extensionsSet).filter((absPath) => !isExcludedPackageRelativePath((0, path.relative)(packageDir, absPath)));
|
|
498
|
+
}
|
|
364
499
|
/** Exclusions for the compiled-output fallback when a package does not ship src/. */
|
|
365
500
|
const PACKAGE_OUTPUT_EXCLUDES = [
|
|
366
501
|
"node_modules",
|
|
@@ -369,9 +504,9 @@ const PACKAGE_OUTPUT_EXCLUDES = [
|
|
|
369
504
|
".d.ts",
|
|
370
505
|
".map"
|
|
371
506
|
];
|
|
372
|
-
const isFile = (path$
|
|
507
|
+
const isFile = (path$3) => {
|
|
373
508
|
try {
|
|
374
|
-
return (0, fs.statSync)(path$
|
|
509
|
+
return (0, fs.statSync)(path$3).isFile();
|
|
375
510
|
} catch {
|
|
376
511
|
return false;
|
|
377
512
|
}
|
|
@@ -399,7 +534,7 @@ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
|
399
534
|
if ((0, path.isAbsolute)(specifier)) {
|
|
400
535
|
const resolved = resolveAbsolutePathSpecifier(specifier, extensionsSet);
|
|
401
536
|
if (!resolved) return null;
|
|
402
|
-
return
|
|
537
|
+
return isPathWithinRoot(srcDir, resolved) ? resolved : null;
|
|
403
538
|
}
|
|
404
539
|
const packageName = bareSpecifierPackageName(specifier);
|
|
405
540
|
return resolveAbsolutePathSpecifier((0, path.join)(srcDir, specifier.slice(packageName.length + 1) || "index"), extensionsSet);
|
|
@@ -413,7 +548,7 @@ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
|
413
548
|
* file's mtime is readable. Detection only — reporting is the caller's policy.
|
|
414
549
|
*/
|
|
415
550
|
function distEntryIsStale(absEntry, srcDir, srcFiles) {
|
|
416
|
-
if (
|
|
551
|
+
if (isPathWithinRoot(srcDir, absEntry)) return false;
|
|
417
552
|
let distMtime;
|
|
418
553
|
try {
|
|
419
554
|
distMtime = (0, fs.statSync)(absEntry).mtimeMs;
|
|
@@ -445,15 +580,19 @@ function distEntryIsStale(absEntry, srcDir, srcFiles) {
|
|
|
445
580
|
* them — any warning or gate is the caller's policy.
|
|
446
581
|
*/
|
|
447
582
|
async function collectExternalPackageSources(opts) {
|
|
448
|
-
const { specifiers, resolveSpecifier, rootDir, extensionsSet, hasEntry, preprocessFile, onUnreadable } = opts;
|
|
583
|
+
const { specifiers, resolveSpecifier, rootDir, extensionsSet, hasEntry, preprocessFile, onUnreadable, onPackageResolved } = opts;
|
|
449
584
|
const entries = [];
|
|
450
585
|
const pushed = /* @__PURE__ */ new Set();
|
|
451
586
|
const packageMap = {};
|
|
452
587
|
const sourceEntries = /* @__PURE__ */ new Map();
|
|
588
|
+
const keyframesScanEntries = /* @__PURE__ */ new Map();
|
|
453
589
|
const packageDirs = [];
|
|
454
|
-
const
|
|
590
|
+
const dirOwnerSets = {};
|
|
455
591
|
const fileOwners = {};
|
|
456
592
|
const outcomes = [];
|
|
593
|
+
const claimDir = (dir, specifier) => {
|
|
594
|
+
(dirOwnerSets[dir] ??= []).push(specifier);
|
|
595
|
+
};
|
|
457
596
|
const alreadyIngested = (relPath) => hasEntry(relPath) || pushed.has(relPath);
|
|
458
597
|
for (const specifier of specifiers) {
|
|
459
598
|
let absEntry;
|
|
@@ -476,12 +615,14 @@ async function collectExternalPackageSources(opts) {
|
|
|
476
615
|
let staleDist = false;
|
|
477
616
|
if ((0, fs.existsSync)(srcDir)) {
|
|
478
617
|
packageDirs.push(srcDir);
|
|
479
|
-
|
|
618
|
+
claimDir(srcDir, specifier);
|
|
619
|
+
onPackageResolved?.(specifier, srcDir);
|
|
480
620
|
const srcEntry = sourceEntryForSpecifier(specifier, srcDir, extensionsSet);
|
|
481
621
|
if (srcEntry) {
|
|
482
622
|
packageMap[specifier] = (0, path.relative)(rootDir, srcEntry);
|
|
483
623
|
sourceEntries.set(specifier, srcEntry);
|
|
484
624
|
} else packageMap[specifier] = (0, path.relative)(rootDir, absEntry);
|
|
625
|
+
keyframesScanEntries.set(specifier, srcEntry ?? absEntry);
|
|
485
626
|
if (!(0, path.isAbsolute)(specifier)) {
|
|
486
627
|
const packageName = bareSpecifierPackageName(specifier);
|
|
487
628
|
if (packageName !== specifier && !(packageName in packageMap)) {
|
|
@@ -489,13 +630,11 @@ async function collectExternalPackageSources(opts) {
|
|
|
489
630
|
if (rootEntry) {
|
|
490
631
|
packageMap[packageName] = (0, path.relative)(rootDir, rootEntry);
|
|
491
632
|
sourceEntries.set(packageName, rootEntry);
|
|
633
|
+
keyframesScanEntries.set(packageName, rootEntry);
|
|
492
634
|
}
|
|
493
635
|
}
|
|
494
636
|
}
|
|
495
|
-
const pkgFiles =
|
|
496
|
-
const inPkg = (0, path.relative)(srcDir, absPath);
|
|
497
|
-
return !PACKAGE_SRC_EXCLUDES.some((pattern) => inPkg.includes(pattern));
|
|
498
|
-
});
|
|
637
|
+
const pkgFiles = walkPackageSources(srcDir, extensionsSet);
|
|
499
638
|
staleDist = distEntryIsStale(absEntry, srcDir, pkgFiles);
|
|
500
639
|
for (const pkgFile of pkgFiles) {
|
|
501
640
|
const relPath = (0, path.relative)(rootDir, pkgFile);
|
|
@@ -523,8 +662,10 @@ async function collectExternalPackageSources(opts) {
|
|
|
523
662
|
} else {
|
|
524
663
|
const outputDir = (0, path.dirname)(absEntry);
|
|
525
664
|
packageDirs.push(outputDir);
|
|
526
|
-
|
|
665
|
+
claimDir(outputDir, specifier);
|
|
666
|
+
onPackageResolved?.(specifier, outputDir);
|
|
527
667
|
packageMap[specifier] = (0, path.relative)(rootDir, absEntry);
|
|
668
|
+
keyframesScanEntries.set(specifier, absEntry);
|
|
528
669
|
const outputExtensions = new Set(extensionsSet);
|
|
529
670
|
outputExtensions.add((0, path.extname)(absEntry));
|
|
530
671
|
const outputFiles = discoverFiles(outputDir, outputDir, [], outputExtensions).filter((file) => {
|
|
@@ -566,12 +707,71 @@ async function collectExternalPackageSources(opts) {
|
|
|
566
707
|
entries,
|
|
567
708
|
packageMap,
|
|
568
709
|
sourceEntries,
|
|
710
|
+
keyframesScanEntries,
|
|
569
711
|
packageDirs,
|
|
570
|
-
|
|
712
|
+
dirOwnerSets,
|
|
571
713
|
fileOwners,
|
|
572
714
|
outcomes
|
|
573
715
|
};
|
|
574
716
|
}
|
|
717
|
+
/** First-declared specifier per package dir — the single-value ownership
|
|
718
|
+
* view correlation consumers key on, derived from `dirOwnerSets`. */
|
|
719
|
+
function firstOwners(dirOwnerSets) {
|
|
720
|
+
const owners = {};
|
|
721
|
+
for (const [dir, specifiers] of Object.entries(dirOwnerSets)) if (specifiers.length > 0) owners[dir] = specifiers[0];
|
|
722
|
+
return owners;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Excise a set of rejected specifiers from a collection result ATOMICALLY
|
|
726
|
+
* (openspec: external-source-watch-ingestion, design D5): the returned copy
|
|
727
|
+
* carries no entries, package-map targets, source entries, package dirs, or
|
|
728
|
+
* ownership for the rejected packages — a package dir is removed only when
|
|
729
|
+
* EVERY specifier that claimed it is rejected (a dir-level rejection, such
|
|
730
|
+
* as the cross-volume gate, always rejects them together). Outcome records
|
|
731
|
+
* are reporting inputs, not membership, and pass through untouched.
|
|
732
|
+
*/
|
|
733
|
+
function excludeCollectedPackages(collected, rejectedSpecifiers, rootDir) {
|
|
734
|
+
if (rejectedSpecifiers.size === 0) return collected;
|
|
735
|
+
const rejectedDirs = Object.entries(collected.dirOwnerSets).filter(([, specs]) => specs.every((s) => rejectedSpecifiers.has(s))).map(([dir]) => dir);
|
|
736
|
+
const underRejectedDir = (absPath) => rejectedDirs.some((dir) => isPathWithinRoot(dir, absPath));
|
|
737
|
+
const targetRejected = (specifier, absTarget) => rejectedSpecifiers.has(specifier) || underRejectedDir(absTarget);
|
|
738
|
+
const packageMap = {};
|
|
739
|
+
for (const [specifier, relTarget] of Object.entries(collected.packageMap)) {
|
|
740
|
+
if (targetRejected(specifier, (0, path.resolve)(rootDir, relTarget))) continue;
|
|
741
|
+
packageMap[specifier] = relTarget;
|
|
742
|
+
}
|
|
743
|
+
const sourceEntries = /* @__PURE__ */ new Map();
|
|
744
|
+
for (const [specifier, absEntry] of collected.sourceEntries) {
|
|
745
|
+
if (targetRejected(specifier, absEntry)) continue;
|
|
746
|
+
sourceEntries.set(specifier, absEntry);
|
|
747
|
+
}
|
|
748
|
+
const keyframesScanEntries = /* @__PURE__ */ new Map();
|
|
749
|
+
for (const [specifier, absEntry] of collected.keyframesScanEntries) {
|
|
750
|
+
if (targetRejected(specifier, absEntry)) continue;
|
|
751
|
+
keyframesScanEntries.set(specifier, absEntry);
|
|
752
|
+
}
|
|
753
|
+
const dirOwnerSets = {};
|
|
754
|
+
for (const [dir, specs] of Object.entries(collected.dirOwnerSets)) {
|
|
755
|
+
const kept = specs.filter((s) => !rejectedSpecifiers.has(s));
|
|
756
|
+
if (kept.length === 0) continue;
|
|
757
|
+
dirOwnerSets[dir] = kept;
|
|
758
|
+
}
|
|
759
|
+
const fileOwners = {};
|
|
760
|
+
for (const [relPath, owner] of Object.entries(collected.fileOwners)) {
|
|
761
|
+
if (rejectedSpecifiers.has(owner)) continue;
|
|
762
|
+
fileOwners[relPath] = owner;
|
|
763
|
+
}
|
|
764
|
+
return {
|
|
765
|
+
entries: collected.entries.filter((entry) => !rejectedSpecifiers.has(collected.fileOwners[entry.path])),
|
|
766
|
+
packageMap,
|
|
767
|
+
sourceEntries,
|
|
768
|
+
keyframesScanEntries,
|
|
769
|
+
packageDirs: collected.packageDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
770
|
+
dirOwnerSets,
|
|
771
|
+
fileOwners,
|
|
772
|
+
outcomes: collected.outcomes
|
|
773
|
+
};
|
|
774
|
+
}
|
|
575
775
|
/**
|
|
576
776
|
* Extract external DS package names from inheritance declarations in the
|
|
577
777
|
* system file.
|
|
@@ -941,7 +1141,7 @@ function buildSourceTokenIndex(opts) {
|
|
|
941
1141
|
if ((0, fs.existsSync)((0, path.join)(packageRoot, "package.json"))) addOwnerDir(packageRoot, specifier);
|
|
942
1142
|
}
|
|
943
1143
|
for (const [modulePath, exports] of Object.entries(manifests)) {
|
|
944
|
-
const owner = realDirOwners.find(({ dir }) =>
|
|
1144
|
+
const owner = realDirOwners.find(({ dir }) => isPathWithinRoot(dir, modulePath));
|
|
945
1145
|
if (!owner) continue;
|
|
946
1146
|
let tokens = index.get(owner.specifier);
|
|
947
1147
|
if (!tokens) {
|
|
@@ -1082,16 +1282,42 @@ function postProcessCss(css, opts) {
|
|
|
1082
1282
|
/** Stable code for selector forms with no substitutable subject.
|
|
1083
1283
|
* Mirrors the Rust constant in `extract-v2/src/eval.rs`. */
|
|
1084
1284
|
const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
1285
|
+
/** Unresolved-parent chain-drop message (mirrors the Rust diagnostic in
|
|
1286
|
+
* `extract-v2` — the ONE encoding of this message shape; consumers match
|
|
1287
|
+
* through the helpers below, never their own regex copies). */
|
|
1288
|
+
const UNRESOLVED_PARENT_RE = /chain dropped: could not resolve parent component '([^']+)'/;
|
|
1289
|
+
/** True when the diagnostic reports a chain dropped for an unresolved
|
|
1290
|
+
* parent component. */
|
|
1291
|
+
function isUnresolvedParentDrop(diagnostic) {
|
|
1292
|
+
return typeof diagnostic?.message === "string" && UNRESOLVED_PARENT_RE.test(diagnostic.message);
|
|
1293
|
+
}
|
|
1294
|
+
/** The parent binding named by an unresolved-parent drop, or null when the
|
|
1295
|
+
* diagnostic is not one. */
|
|
1296
|
+
function unresolvedParentName(diagnostic) {
|
|
1297
|
+
if (typeof diagnostic?.message !== "string") return null;
|
|
1298
|
+
return UNRESOLVED_PARENT_RE.exec(diagnostic.message)?.[1] ?? null;
|
|
1299
|
+
}
|
|
1085
1300
|
/** True when the selector string carries at least one substitutable `&`
|
|
1086
1301
|
* subject outside quoted text (mirrors the Rust `selector_subject` walk —
|
|
1087
1302
|
* ancestor, leading, and repeated subjects all count; a `&` inside a
|
|
1088
1303
|
* quoted attribute value does not). */
|
|
1089
1304
|
function hasSelectorSubject(value) {
|
|
1090
1305
|
let quote = null;
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1306
|
+
let escaped = false;
|
|
1307
|
+
for (const c of value) {
|
|
1308
|
+
if (escaped) {
|
|
1309
|
+
escaped = false;
|
|
1310
|
+
continue;
|
|
1311
|
+
}
|
|
1312
|
+
if (c === "\\") {
|
|
1313
|
+
escaped = true;
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
if (quote !== null) {
|
|
1317
|
+
if (c === quote) quote = null;
|
|
1318
|
+
} else if (c === "\"" || c === "'") quote = c;
|
|
1319
|
+
else if (c === "&") return true;
|
|
1320
|
+
}
|
|
1095
1321
|
return false;
|
|
1096
1322
|
}
|
|
1097
1323
|
/**
|
|
@@ -1509,17 +1735,17 @@ function stripJsonc(text) {
|
|
|
1509
1735
|
}
|
|
1510
1736
|
return out.replace(/,(\s*[}\]])/g, "$1");
|
|
1511
1737
|
}
|
|
1512
|
-
function readConfig(path$
|
|
1738
|
+
function readConfig(path$2) {
|
|
1513
1739
|
let raw;
|
|
1514
1740
|
try {
|
|
1515
|
-
raw = (0, fs.readFileSync)(path$
|
|
1741
|
+
raw = (0, fs.readFileSync)(path$2, "utf-8");
|
|
1516
1742
|
} catch {
|
|
1517
1743
|
return null;
|
|
1518
1744
|
}
|
|
1519
1745
|
try {
|
|
1520
1746
|
const json = JSON.parse(stripJsonc(raw));
|
|
1521
1747
|
return {
|
|
1522
|
-
dir: (0, path.dirname)(path$
|
|
1748
|
+
dir: (0, path.dirname)(path$2),
|
|
1523
1749
|
compilerOptions: json.compilerOptions ?? {},
|
|
1524
1750
|
extends: json.extends
|
|
1525
1751
|
};
|
|
@@ -1664,6 +1890,79 @@ async function preprocessMdx(source, filename) {
|
|
|
1664
1890
|
}
|
|
1665
1891
|
}
|
|
1666
1892
|
//#endregion
|
|
1893
|
+
//#region pipeline/replacement-plans.ts
|
|
1894
|
+
const snapshotByManifest = /* @__PURE__ */ new WeakMap();
|
|
1895
|
+
function snapshotFilePlans(manifest) {
|
|
1896
|
+
const memoKey = manifest !== null && typeof manifest === "object" ? manifest : null;
|
|
1897
|
+
if (memoKey) {
|
|
1898
|
+
const cached = snapshotByManifest.get(memoKey);
|
|
1899
|
+
if (cached) return cached;
|
|
1900
|
+
}
|
|
1901
|
+
const entriesByFile = /* @__PURE__ */ new Map();
|
|
1902
|
+
for (const [id, desc] of Object.entries(manifest?.components ?? {})) {
|
|
1903
|
+
const file = desc.file;
|
|
1904
|
+
if (!file) continue;
|
|
1905
|
+
const list = entriesByFile.get(file) ?? [];
|
|
1906
|
+
list.push([id, desc.replacement ?? ""]);
|
|
1907
|
+
entriesByFile.set(file, list);
|
|
1908
|
+
}
|
|
1909
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
1910
|
+
for (const [file, entries] of entriesByFile) {
|
|
1911
|
+
entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
1912
|
+
snapshot.set(file, JSON.stringify(entries));
|
|
1913
|
+
}
|
|
1914
|
+
if (memoKey) snapshotByManifest.set(memoKey, snapshot);
|
|
1915
|
+
return snapshot;
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Rel paths whose plan changed between two snapshots: absent→present,
|
|
1919
|
+
* present→absent, and any change to membership or replacement content.
|
|
1920
|
+
* `exclude` drops one path (the changed file itself on the edit path — its
|
|
1921
|
+
* own modules are already in the update set).
|
|
1922
|
+
*/
|
|
1923
|
+
function diffFilePlans(prev, next, opts) {
|
|
1924
|
+
const changed = /* @__PURE__ */ new Set();
|
|
1925
|
+
for (const [file, plan] of next) if (prev.get(file) !== plan) changed.add(file);
|
|
1926
|
+
for (const file of prev.keys()) if (!next.has(file)) changed.add(file);
|
|
1927
|
+
if (opts?.exclude) changed.delete(opts.exclude);
|
|
1928
|
+
return [...changed].sort();
|
|
1929
|
+
}
|
|
1930
|
+
/** Domain prefix keeping the epoch hash disjoint from every other
|
|
1931
|
+
* contentHash use in the pipeline (design D5). */
|
|
1932
|
+
const REPLACEMENT_PLANS_DOMAIN = "animus-replacement-plans-v1\0";
|
|
1933
|
+
/** Section marker for the served-dependency witness. Leads with NUL: every
|
|
1934
|
+
* plan entry ends `…\0` and neither file paths nor plan JSON contain NUL,
|
|
1935
|
+
* so `\0\0` is unreachable from entry serialization alone — a snapshot can
|
|
1936
|
+
* never forge the witness section. */
|
|
1937
|
+
const SERVED_DEPENDENCY_DOMAIN = "\0animus-served-dependency-v1\0";
|
|
1938
|
+
/**
|
|
1939
|
+
* Canonical replacement epoch: contentHash over the domain-prefixed, sorted
|
|
1940
|
+
* canonical serialization of a file-plan snapshot — each entry contributes
|
|
1941
|
+
* `file + '\0' + plan + '\0'` (unambiguous: neither file paths nor the
|
|
1942
|
+
* JSON plan strings contain NUL). Byte-identical plans → identical epoch;
|
|
1943
|
+
* any membership/replacement/absent↔present change moves it.
|
|
1944
|
+
*
|
|
1945
|
+
* `servedDependencyWitness` extends the epoch to content the plans cannot
|
|
1946
|
+
* see but restored modules depend on: transformed modules import the
|
|
1947
|
+
* session's served system-props artifact, so a consumer passes that
|
|
1948
|
+
* artifact's content here and an offline change to it moves the epoch —
|
|
1949
|
+
* invalidating persistent-cache snapshots that reference the old epoch
|
|
1950
|
+
* artifact. Absence and empty-string are distinct values.
|
|
1951
|
+
*
|
|
1952
|
+
* This is THE epoch definition — integrations consume this hash (or the
|
|
1953
|
+
* snapshot diff) and never define their own. Epoch values compare only for
|
|
1954
|
+
* equality (a moved value invalidates), so the serialization is free to
|
|
1955
|
+
* evolve with a domain bump: sessions running different serializations
|
|
1956
|
+
* simply disagree once and rebuild.
|
|
1957
|
+
*/
|
|
1958
|
+
function hashReplacementPlans(snapshot, servedDependencyWitness) {
|
|
1959
|
+
const entries = [...snapshot.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
1960
|
+
let serialized = REPLACEMENT_PLANS_DOMAIN;
|
|
1961
|
+
for (const [file, plan] of entries) serialized += file + "\0" + plan + "\0";
|
|
1962
|
+
if (servedDependencyWitness !== void 0) serialized += SERVED_DEPENDENCY_DOMAIN + servedDependencyWitness;
|
|
1963
|
+
return contentHash(serialized);
|
|
1964
|
+
}
|
|
1965
|
+
//#endregion
|
|
1667
1966
|
//#region pipeline/utils.ts
|
|
1668
1967
|
/** Convert camelCase CSS property names to kebab-case. */
|
|
1669
1968
|
function camelToKebab(str) {
|
|
@@ -1733,27 +2032,40 @@ exports.camelToKebab = camelToKebab;
|
|
|
1733
2032
|
exports.clearEngineCache = clearEngineCache;
|
|
1734
2033
|
exports.collectExternalPackageSources = collectExternalPackageSources;
|
|
1735
2034
|
exports.contentHash = contentHash;
|
|
2035
|
+
exports.createSourceIdentity = createSourceIdentity;
|
|
1736
2036
|
exports.createV2EngineApi = createV2EngineApi;
|
|
2037
|
+
exports.diffFilePlans = diffFilePlans;
|
|
1737
2038
|
exports.discoverFiles = discoverFiles;
|
|
1738
2039
|
exports.enforceExternalTokenContracts = enforceExternalTokenContracts;
|
|
2040
|
+
exports.excludeCollectedPackages = excludeCollectedPackages;
|
|
1739
2041
|
exports.extractSystemFilePackages = extractSystemFilePackages;
|
|
1740
2042
|
exports.findAssetSpecifiers = findAssetSpecifiers;
|
|
1741
2043
|
exports.findPackageRoot = findPackageRoot;
|
|
2044
|
+
exports.firstOwners = firstOwners;
|
|
1742
2045
|
exports.formatRustTimingWaterfall = formatRustTimingWaterfall;
|
|
2046
|
+
exports.hashReplacementPlans = hashReplacementPlans;
|
|
2047
|
+
exports.isExcludedPackageRelativePath = isExcludedPackageRelativePath;
|
|
2048
|
+
exports.isPathWithinRoot = isPathWithinRoot;
|
|
2049
|
+
exports.isUnresolvedParentDrop = isUnresolvedParentDrop;
|
|
1743
2050
|
exports.loadSystemConfig = loadSystemConfig;
|
|
1744
2051
|
exports.mergeExternalKeyframes = mergeExternalKeyframes;
|
|
1745
2052
|
exports.postProcessCss = postProcessCss;
|
|
1746
2053
|
exports.preprocessMdx = preprocessMdx;
|
|
1747
2054
|
exports.readTsconfigAliasPairs = readTsconfigAliasPairs;
|
|
2055
|
+
exports.resolveAbsolutePathSpecifier = resolveAbsolutePathSpecifier;
|
|
1748
2056
|
exports.resolveAssetFile = resolveAssetFile;
|
|
1749
2057
|
exports.resolveLightningTargets = resolveLightningTargets;
|
|
1750
2058
|
exports.resolveThroughPathAliases = resolveThroughPathAliases;
|
|
1751
2059
|
exports.runProjectAnalysis = runProjectAnalysis;
|
|
1752
2060
|
exports.serializeStaticCss = serializeStaticCss;
|
|
2061
|
+
exports.sharesVolumeRoot = sharesVolumeRoot;
|
|
2062
|
+
exports.snapshotFilePlans = snapshotFilePlans;
|
|
1753
2063
|
exports.staleDistIncludesMessage = staleDistIncludesMessage;
|
|
1754
2064
|
exports.stripLeadingLayerDeclaration = stripLeadingLayerDeclaration;
|
|
1755
2065
|
exports.substituteAssetPlaceholders = substituteAssetPlaceholders;
|
|
1756
2066
|
exports.surfaceManifestDiagnostics = surfaceManifestDiagnostics;
|
|
1757
2067
|
exports.toWatchKeys = toWatchKeys;
|
|
1758
2068
|
exports.unresolvableIncludesMessage = unresolvableIncludesMessage;
|
|
2069
|
+
exports.unresolvedParentName = unresolvedParentName;
|
|
1759
2070
|
exports.validateLayerOrder = validateLayerOrder;
|
|
2071
|
+
exports.walkPackageSources = walkPackageSources;
|