@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.
Files changed (83) hide show
  1. package/crates/extract-v2/animus-extract-v2.darwin-arm64.node +0 -0
  2. package/crates/extract-v2/animus-extract-v2.linux-arm64-gnu.node +0 -0
  3. package/crates/extract-v2/animus-extract-v2.linux-x64-gnu.node +0 -0
  4. package/crates/extract-v2/index.d.ts +107 -6
  5. package/dist/index.cjs +48 -5
  6. package/dist/index.mjs +2 -2
  7. package/dist/pipeline/alias-agreement.d.ts +107 -0
  8. package/dist/pipeline/alias-agreement.d.ts.map +1 -0
  9. package/dist/pipeline/analyze-project-args.d.ts +11 -2
  10. package/dist/pipeline/analyze-project-args.d.ts.map +1 -1
  11. package/dist/pipeline/asset-copies.d.ts +20 -0
  12. package/dist/pipeline/asset-copies.d.ts.map +1 -0
  13. package/dist/pipeline/built-in-asset-types.d.ts +9 -0
  14. package/dist/pipeline/built-in-asset-types.d.ts.map +1 -0
  15. package/dist/pipeline/core-options.d.ts +31 -7
  16. package/dist/pipeline/core-options.d.ts.map +1 -1
  17. package/dist/pipeline/discover-packages.d.ts +98 -12
  18. package/dist/pipeline/discover-packages.d.ts.map +1 -1
  19. package/dist/pipeline/engine-adapter.d.ts +41 -3
  20. package/dist/pipeline/engine-adapter.d.ts.map +1 -1
  21. package/dist/pipeline/engine-retirement.d.ts +7 -1
  22. package/dist/pipeline/engine-retirement.d.ts.map +1 -1
  23. package/dist/pipeline/extension-policy.d.ts +95 -0
  24. package/dist/pipeline/extension-policy.d.ts.map +1 -0
  25. package/dist/pipeline/host-assets.d.ts +32 -0
  26. package/dist/pipeline/host-assets.d.ts.map +1 -0
  27. package/dist/pipeline/host-expansions.d.ts +92 -0
  28. package/dist/pipeline/host-expansions.d.ts.map +1 -0
  29. package/dist/pipeline/host-extensions.d.ts +64 -0
  30. package/dist/pipeline/host-extensions.d.ts.map +1 -0
  31. package/dist/pipeline/host-package-resolver.d.ts +40 -0
  32. package/dist/pipeline/host-package-resolver.d.ts.map +1 -0
  33. package/dist/pipeline/index.d.ts +32 -8
  34. package/dist/pipeline/index.d.ts.map +1 -1
  35. package/dist/pipeline/kit-publication.d.ts.map +1 -1
  36. package/dist/pipeline/manifest-diagnostics.d.ts +27 -6
  37. package/dist/pipeline/manifest-diagnostics.d.ts.map +1 -1
  38. package/dist/pipeline/manifest-schema.d.ts +16 -0
  39. package/dist/pipeline/manifest-schema.d.ts.map +1 -1
  40. package/dist/pipeline/output-targets.d.ts +52 -0
  41. package/dist/pipeline/output-targets.d.ts.map +1 -0
  42. package/dist/pipeline/probe-evidence.d.ts +58 -0
  43. package/dist/pipeline/probe-evidence.d.ts.map +1 -0
  44. package/dist/pipeline/run-analysis.d.ts +26 -0
  45. package/dist/pipeline/run-analysis.d.ts.map +1 -1
  46. package/dist/pipeline/runtime-import.d.ts +10 -0
  47. package/dist/pipeline/runtime-import.d.ts.map +1 -0
  48. package/dist/pipeline/served-files.d.ts +16 -0
  49. package/dist/pipeline/served-files.d.ts.map +1 -0
  50. package/dist/pipeline/source-corpus.d.ts +4 -0
  51. package/dist/pipeline/source-corpus.d.ts.map +1 -1
  52. package/dist/pipeline/source-ingestion.d.ts +37 -5
  53. package/dist/pipeline/source-ingestion.d.ts.map +1 -1
  54. package/dist/pipeline/system-config.d.ts +18 -0
  55. package/dist/pipeline/system-config.d.ts.map +1 -1
  56. package/dist/pipeline/system-instances.d.ts +27 -0
  57. package/dist/pipeline/system-instances.d.ts.map +1 -0
  58. package/dist/pipeline/tsconfig-paths.d.ts +4 -0
  59. package/dist/pipeline/tsconfig-paths.d.ts.map +1 -1
  60. package/dist/pipeline/vite-expansions.d.ts +40 -0
  61. package/dist/pipeline/vite-expansions.d.ts.map +1 -0
  62. package/dist/pipeline/webpack-expansions.d.ts +55 -0
  63. package/dist/pipeline/webpack-expansions.d.ts.map +1 -0
  64. package/dist/pipeline/workspace-packages.d.ts +13 -0
  65. package/dist/pipeline/workspace-packages.d.ts.map +1 -0
  66. package/dist/{pipeline-Bl20tbu_.mjs → pipeline-BzMQ_Z0M.mjs} +2293 -751
  67. package/dist/{pipeline-CAH9mxnK.cjs → pipeline-DyUf-eKZ.cjs} +2564 -746
  68. package/dist/session/coalescing-window.d.ts +34 -0
  69. package/dist/session/coalescing-window.d.ts.map +1 -0
  70. package/dist/session/extraction-session.d.ts +297 -35
  71. package/dist/session/extraction-session.d.ts.map +1 -1
  72. package/dist/session/index.d.ts +7 -3
  73. package/dist/session/index.d.ts.map +1 -1
  74. package/dist/session/published-set.d.ts +6 -1
  75. package/dist/session/published-set.d.ts.map +1 -1
  76. package/dist/session/resolve-packages.d.ts +9 -5
  77. package/dist/session/resolve-packages.d.ts.map +1 -1
  78. package/dist/session/singleton.d.ts +218 -53
  79. package/dist/session/singleton.d.ts.map +1 -1
  80. package/dist/session/turbopack-orchestrator.d.ts.map +1 -1
  81. package/dist/session.cjs +1462 -510
  82. package/dist/session.mjs +1430 -489
  83. package/package.json +4 -4
@@ -23,9 +23,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  let node_path = require("node:path");
24
24
  node_path = __toESM(node_path);
25
25
  let crypto = require("crypto");
26
+ let node_fs = require("node:fs");
26
27
  let fs = require("fs");
27
28
  let path = require("path");
28
- let node_fs = require("node:fs");
29
29
  let module$1 = require("module");
30
30
  let browserslist = require("browserslist");
31
31
  browserslist = __toESM(browserslist);
@@ -90,7 +90,7 @@ function assembleStylesheet(options) {
90
90
  //#endregion
91
91
  //#region pipeline/analyze-project-args.ts
92
92
  /** @internal */
93
- function buildAnalyzeProjectArgs(inputs) {
93
+ function buildAnalyzeProjectArgs(inputs, probeEvidence) {
94
94
  const args = [
95
95
  inputs.filesJson,
96
96
  inputs.scalesJson,
@@ -115,18 +115,15 @@ function buildAnalyzeProjectArgs(inputs) {
115
115
  const tail = [
116
116
  inputs.declarationScalesJson,
117
117
  inputs.analysisContextJson,
118
- inputs.generatedNamesJson
118
+ inputs.generatedNamesJson,
119
+ inputs.propertyRecordsJson
119
120
  ];
120
- const last = tail.findLastIndex((slot) => slot !== void 0 && slot !== "");
121
+ const last = probeEvidence === void 0 ? tail.findLastIndex((slot) => slot !== void 0 && slot !== "") : tail.length - 1;
121
122
  for (const slot of tail.slice(0, last + 1)) args.push(slot || void 0);
123
+ if (probeEvidence !== void 0) args.push(probeEvidence);
122
124
  return args;
123
125
  }
124
126
  //#endregion
125
- //#region pipeline/content-hash.ts
126
- function contentHash(source) {
127
- return (0, crypto.createHash)("md5").update(source).digest("hex");
128
- }
129
- //#endregion
130
127
  //#region pipeline/internal-wire.ts
131
128
  function parseInternalWire(json, wire) {
132
129
  let parsed;
@@ -138,6 +135,160 @@ function parseInternalWire(json, wire) {
138
135
  return parsed;
139
136
  }
140
137
  //#endregion
138
+ //#region pipeline/content-hash.ts
139
+ function contentHash(source) {
140
+ return (0, crypto.createHash)("md5").update(source).digest("hex");
141
+ }
142
+ //#endregion
143
+ //#region pipeline/extension-policy.ts
144
+ /**
145
+ * The one extension policy: the order in which a relative or aliased
146
+ * specifier's candidate files are tried. Source ingestion reads it here. The
147
+ * system loader and the extractor read `extension_policy.json`, which
148
+ * `node packages/extract/scripts/extension-policy.ts --write` generates from
149
+ * it, so every resolver tries the same files in the same order.
150
+ *
151
+ * The order: the base itself, the base with each appended extension, its
152
+ * `index` with each, then the sources an emitted NodeNext extension stands
153
+ * for (`./x.js` for `x.ts`), spelled exactly.
154
+ */
155
+ const EXTENSION_POLICY = {
156
+ /** Appended to the base, then to `{base}/index`. */
157
+ appended: [
158
+ ".ts",
159
+ ".tsx",
160
+ ".js",
161
+ ".jsx",
162
+ ".mjs"
163
+ ],
164
+ /** An emitted extension, and the source extensions it names, in order. */
165
+ nodeNext: [
166
+ [".js", [
167
+ ".ts",
168
+ ".tsx",
169
+ ".jsx"
170
+ ]],
171
+ [".jsx", [".tsx"]],
172
+ [".mjs", [".mts"]],
173
+ [".cjs", [".cts"]]
174
+ ]
175
+ };
176
+ const BUILT_IN_ORDER = {
177
+ appended: EXTENSION_POLICY.appended,
178
+ nodeNext: EXTENSION_POLICY.nodeNext,
179
+ alias: []
180
+ };
181
+ /** The files `base` can name, in policy order: itself, with each appended
182
+ * extension, as a directory's index with each, then the sources its
183
+ * emitted NodeNext extension stands for (`x.js` names `x.ts`), spelled
184
+ * exactly. Given `sources`, only extensions in it are tried, and under the
185
+ * built-in order those it lacks (`.mdx`) follow its own. A configured
186
+ * alias of the base's suffix replaces all of these. `index` spells a
187
+ * directory's index path. */
188
+ function policyCandidates(base, options = {}) {
189
+ const { sources, index = (directory, file) => `${directory}/${file}`, policy = BUILT_IN_ORDER } = options;
190
+ const alias = policy.alias.find(([from]) => base.endsWith(from));
191
+ if (alias !== void 0) {
192
+ const [from, sequence] = alias;
193
+ const stem = base.slice(0, base.length - from.length);
194
+ return sequence.map((to) => `${stem}${to}`);
195
+ }
196
+ const admitted = (extension) => !sources || sources.has(extension);
197
+ const appended = [...policy.appended.filter(admitted), ...sources && policy.appended === EXTENSION_POLICY.appended ? [...sources].filter((s) => !policy.appended.includes(s)) : []];
198
+ const name = base.slice(Math.max(base.lastIndexOf("/"), base.lastIndexOf("\\")) + 1);
199
+ const dot = name.lastIndexOf(".");
200
+ const emitted = dot === -1 ? "" : name.slice(dot);
201
+ const stem = base.slice(0, base.length - emitted.length);
202
+ const nodeNext = (policy.nodeNext.find(([from]) => from === emitted)?.[1] ?? []).filter(admitted);
203
+ return [
204
+ base,
205
+ ...appended.map((extension) => `${base}${extension}`),
206
+ ...appended.map((extension) => index(base, `index${extension}`)),
207
+ ...nodeNext.map((source) => `${stem}${source}`)
208
+ ];
209
+ }
210
+ /** The first of `candidates` that `see` finds, in order; a candidate found
211
+ * only under another case ends the probe as a mismatch. */
212
+ function probeCandidates(candidates, see) {
213
+ for (const candidate of candidates) {
214
+ const seen = see(candidate);
215
+ if (seen.kind === "file") return {
216
+ kind: "found",
217
+ path: candidate
218
+ };
219
+ if (seen.kind === "case-only") return {
220
+ kind: "case-mismatch",
221
+ candidate,
222
+ actual: seen.actual
223
+ };
224
+ }
225
+ return { kind: "absent" };
226
+ }
227
+ const isFile = (path) => {
228
+ try {
229
+ return (0, node_fs.statSync)(path).isFile();
230
+ } catch {
231
+ return false;
232
+ }
233
+ };
234
+ /** Whether `directory` lists an entry spelled exactly `name`. */
235
+ function lists(directory, name) {
236
+ try {
237
+ return (0, node_fs.readdirSync)(directory || ".").includes(name);
238
+ } catch {
239
+ return false;
240
+ }
241
+ }
242
+ /** `path`'s real path as the filesystem reports it; as given when it cannot
243
+ * be read. */
244
+ const reported = (path) => {
245
+ try {
246
+ return node_fs.realpathSync.native(path);
247
+ } catch {
248
+ return path;
249
+ }
250
+ };
251
+ /** What the filesystem holds at `candidate`: a file it opens under exactly
252
+ * that spelling, or one it opens although a directory below the one the
253
+ * candidate shares with `within` lists no entry spelled as the candidate
254
+ * spells it (a case- or normalization-insensitive filesystem opening
255
+ * another spelling). Nothing is folded: the filesystem decides what opens,
256
+ * and its listings decide the spelling, so a file a case-sensitive
257
+ * filesystem cannot open is simply missing. The shared directory is
258
+ * spelled as given, as a specifier spells only the path from its
259
+ * importer's directory and a manifest only the paths in its package. `..`
260
+ * is taken back lexically, as Node and the bundlers resolve a specifier
261
+ * before opening it. The system loader reads it alike. */
262
+ function seeOnDisk(candidate, within) {
263
+ const path = (0, node_path.normalize)(candidate);
264
+ if (!isFile(path)) return { kind: "missing" };
265
+ const { root } = (0, node_path.parse)(path);
266
+ const names = path.slice(root.length).split(node_path.sep).filter(Boolean);
267
+ const baseNames = within === void 0 ? [] : (0, node_path.normalize)(within).slice(root.length).split(node_path.sep).filter(Boolean);
268
+ let shared = 0;
269
+ while (shared < baseNames.length && names[shared] === baseNames[shared] && names[shared] !== "..") shared++;
270
+ let directory = (0, node_path.join)(root, ...names.slice(0, shared));
271
+ for (const name of names.slice(shared)) {
272
+ if (!lists(directory, name)) return {
273
+ kind: "case-only",
274
+ actual: reported(path)
275
+ };
276
+ directory = (0, node_path.join)(directory, name);
277
+ }
278
+ return { kind: "file" };
279
+ }
280
+ /** The first of `candidates` the filesystem holds, spelled exactly below
281
+ * `within` when given. */
282
+ function probeOnDisk(candidates, within) {
283
+ return probeCandidates(candidates, (candidate) => seeOnDisk(candidate, within));
284
+ }
285
+ /** Why `subject` names no file: the file it would load is spelled otherwise
286
+ * on disk. `remedy` says what to respell. The system loader words it
287
+ * alike. */
288
+ function caseMismatchReason(subject, mismatch, remedy) {
289
+ return `${subject} names ${mismatch.candidate}, but the file on disk is ${mismatch.actual}, spelled differently: a case- or normalization-insensitive filesystem loads it and a sensitive one does not — ${remedy}`;
290
+ }
291
+ //#endregion
141
292
  //#region pipeline/asset-placeholders.ts
142
293
  const ASSET_PLACEHOLDER_PREFIX = "animus-asset:";
143
294
  const URL_OPEN_RE = /url\(\s*(['"]?)/gi;
@@ -315,15 +466,6 @@ function warnLine(diagnostic) {
315
466
  /** Stable code for selector forms with no substitutable subject; the
316
467
  * extraction engine mints the same string. */
317
468
  const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
318
- /** The one matcher for the engine's unresolved-parent chain-drop message;
319
- * consumers match through the exported helpers, never their own copy. */
320
- const UNRESOLVED_PARENT_RE = /chain dropped: could not resolve parent component '([^']+)'/;
321
- function isUnresolvedParentDrop(diagnostic) {
322
- return UNRESOLVED_PARENT_RE.test(diagnostic.message);
323
- }
324
- function unresolvedParentName(diagnostic) {
325
- return UNRESOLVED_PARENT_RE.exec(diagnostic.message)?.[1] ?? null;
326
- }
327
469
  const DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set([
328
470
  "off",
329
471
  "info",
@@ -441,11 +583,11 @@ function collectSelectorAliasDiagnostics(selectorAliasesJson) {
441
583
  const UNREADABLE_SOURCE_FILE = "animus.ingestion.unreadable-source-file";
442
584
  /** A kit the system extends resolved, yet discovery found none of its files. */
443
585
  const NO_KIT_FILES = "animus.discovery.no-kit-files";
444
- /** A kit with no `animus` export condition: discovery guesses its source
445
- * from `src/`. */
586
+ /** A kit with no `animus` export condition whose exports do not all target
587
+ * TypeScript source: discovery guesses its source from `src/`. */
446
588
  const KIT_WITHOUT_SOURCE_CONDITION = "animus.discovery.kit-without-source-condition";
447
589
  /** A kit's `animus` export condition names a file that is missing or outside
448
- * its package, so that entry is not read from source. */
590
+ * its package, so that entry is read from its runtime target instead. */
449
591
  const INVALID_KIT_SOURCE_CONDITION = "animus.discovery.invalid-source-condition";
450
592
  /** A kit the application imports whose system the application's system
451
593
  * does not include: its components are not extracted. */
@@ -453,10 +595,34 @@ const KIT_SYSTEM_NOT_INCLUDED = "animus.kit.system-not-included";
453
595
  /** A system file's `createSystem` binding that discovery could not follow to
454
596
  * Animus's factory, so it is no root. */
455
597
  const UNPROVEN_ROOT_BINDING = "animus.discovery.unproven-root-binding";
598
+ /** A system builder, a `createSystem` chain not yet built, leaves the
599
+ * bindings and chains discovery follows, so kits extended on it from there
600
+ * are not read as members. */
601
+ const UNFOLLOWED_SYSTEM_BUILDER = "animus.discovery.unfollowed-system-builder";
456
602
  /** A system file calls `createSystem` with no import or local binding. The
457
603
  * system loader evaluates the file without auto-imports, where the name is
458
604
  * undefined, so the call is no root. */
459
605
  const UNIMPORTED_CREATE_SYSTEM = "animus.discovery.unimported-create-system";
606
+ /** A tsconfig path alias the host bundler resolves to another file than
607
+ * analysis does (spec §2.2 A7): report only. */
608
+ const ALIAS_MISMATCH = "animus.discovery.alias-mismatch";
609
+ /** A package the host bundler resolves to a file in no package of its own,
610
+ * where discovery reads the installed package instead (spec §2.2 A4):
611
+ * report only. */
612
+ const PACKAGE_MISMATCH = "animus.discovery.package-mismatch";
613
+ /** A system-file kit whose analysed instance is not the one the system
614
+ * load evaluated (spec §2.2 A4): its components would be extracted
615
+ * against another instance's vocabulary. */
616
+ const SYSTEM_INSTANCE_MISMATCH = "animus.discovery.system-instance-mismatch";
617
+ /** An import the host resolves, from its importer, into another instance
618
+ * of a discovered package whose file is not analysed and that no source
619
+ * redirect covers: the importer would render unextracted builder code
620
+ * (spec §2.2 A4, SA1). */
621
+ const UNREAD_PACKAGE_INSTANCE = "animus.discovery.unread-package-instance";
622
+ /** An import the host resolves, from its importer, into another instance
623
+ * of a discovered package, which a request-keyed source redirect replaces
624
+ * with the instance discovery read (spec §2.2 A4). */
625
+ const REPLACED_PACKAGE_INSTANCE = "animus.discovery.replaced-package-instance";
460
626
  /** What a skipped source file costs: the analysis never sees what it
461
627
  * renders. */
462
628
  const SKIPPED_SOURCE_COST = "skipped: its renders are not seen, so nothing is pruned and every component, variant option and state is kept until it is analyzed";
@@ -542,6 +708,12 @@ const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
542
708
  [KIT_STALE_DESCRIPTOR, "warn"],
543
709
  [UNPROVEN_ROOT_BINDING, "warn"],
544
710
  [UNIMPORTED_CREATE_SYSTEM, "warn"],
711
+ [UNFOLLOWED_SYSTEM_BUILDER, "warn"],
712
+ [ALIAS_MISMATCH, "warn"],
713
+ [PACKAGE_MISMATCH, "warn"],
714
+ [SYSTEM_INSTANCE_MISMATCH, "error"],
715
+ [UNREAD_PACKAGE_INSTANCE, "error"],
716
+ [REPLACED_PACKAGE_INSTANCE, "warn"],
545
717
  [VOCABULARY_COLLISION, "warn"],
546
718
  [VOCABULARY_LEGACY_VERB, "warn"],
547
719
  [INVALID_PROPERTY_REGISTRATION, "error"],
@@ -743,6 +915,135 @@ async function preprocessMdx(source, filename) {
743
915
  }
744
916
  }
745
917
  //#endregion
918
+ //#region pipeline/host-expansions.ts
919
+ /**
920
+ * The host's expansion of each listed load the expander reproduces, with
921
+ * each file read as the analysis and the host read it: a module the
922
+ * analysis holds, loaded as code without a query; a file the host loads as
923
+ * an opaque value (spec §2.2 A8); otherwise a file the analysis does not
924
+ * read. A query can select other code than the module (a plugin's
925
+ * transform), so a queried file that is not opaque is never the analysed
926
+ * module, and it keeps its query.
927
+ */
928
+ function hostExpansions(loads, rootDir, analysed, expander, isAsset) {
929
+ const expansions = [];
930
+ for (const load of loads) {
931
+ const expanded = expander.expand(load, rootDir);
932
+ if (expanded === void 0) continue;
933
+ const files = /* @__PURE__ */ new Map();
934
+ for (const { path, query } of expanded) {
935
+ const opaque = isAsset?.((0, node_path.join)(rootDir, path), query) ?? false;
936
+ const status = query === "" && analysed.has(path) ? "analysed" : opaque ? "opaque" : "unanalysed";
937
+ const key = `${path}${query}`;
938
+ files.set(key, {
939
+ path: status === "analysed" ? path : key,
940
+ status
941
+ });
942
+ }
943
+ expansions.push({
944
+ importer: load.importer,
945
+ start: load.start,
946
+ closed: true,
947
+ files: [...files.values()]
948
+ });
949
+ }
950
+ return expansions;
951
+ }
952
+ //#endregion
953
+ //#region pipeline/probe-evidence.ts
954
+ let generations = 0;
955
+ /** `rootDir` at its real path, where the filesystem reports spellings. */
956
+ function realRoot(rootDir) {
957
+ try {
958
+ return node_fs.realpathSync.native(rootDir);
959
+ } catch {
960
+ return rootDir;
961
+ }
962
+ }
963
+ /**
964
+ * What the host's filesystem opens for `base` (spec §2.2 A2, A8): the first
965
+ * of its candidates, in the host's order, that the host opens. The
966
+ * filesystem decides what opens, and each name below the session root is
967
+ * checked against its own directory's listing (`seeOnDisk`); nothing is
968
+ * folded. Null where no candidate opens.
969
+ *
970
+ * A candidate the analysis holds answers before the filesystem is asked: an
971
+ * adapted original's analysis child need not exist on disk. A file the host
972
+ * opens that the analysis holds no module for is read as an adapted
973
+ * original (analysed as its first later child), an asset, or a file
974
+ * analysis never reads.
975
+ */
976
+ function hostCandidate(rootDir, base, analysed, order, readings = {}, root = realRoot(rootDir)) {
977
+ const at = base.indexOf("?");
978
+ const query = at === -1 ? "" : base.slice(at);
979
+ const candidates = policyCandidates(at === -1 ? base : base.slice(0, at), { policy: order });
980
+ for (const [index, file] of candidates.entries()) {
981
+ const candidate = `${file}${query}`;
982
+ const opaque = () => readings.isAsset?.((0, node_path.join)(rootDir, file), query);
983
+ if (analysed.has(file)) return query !== "" && opaque() ? {
984
+ candidate,
985
+ actual: null,
986
+ analysedAs: null,
987
+ reading: "asset"
988
+ } : {
989
+ candidate,
990
+ actual: null,
991
+ analysedAs: file
992
+ };
993
+ const seen = seeOnDisk((0, node_path.join)(rootDir, file), rootDir);
994
+ if (seen.kind === "missing") continue;
995
+ if (seen.kind === "case-only") return {
996
+ candidate,
997
+ actual: (0, node_path.relative)(root, seen.actual),
998
+ analysedAs: null
999
+ };
1000
+ const children = readings.adapted?.get(file);
1001
+ if (children !== void 0) return {
1002
+ candidate,
1003
+ actual: null,
1004
+ analysedAs: candidates.slice(index + 1).find((later) => children.includes(later)) ?? null,
1005
+ reading: "adapted"
1006
+ };
1007
+ return {
1008
+ candidate,
1009
+ actual: null,
1010
+ analysedAs: null,
1011
+ reading: opaque() ? "asset" : "unanalysed"
1012
+ };
1013
+ }
1014
+ return null;
1015
+ }
1016
+ /**
1017
+ * The session's host-candidate evidence for one analysis (spec §2.3): each
1018
+ * probe base the engine's `prepare` names, as `hostCandidate` reads it, and
1019
+ * the host's expansion of each computed load it lists (spec §6.3). The
1020
+ * evidence carries the input identity `prepare` reported, and each call is a
1021
+ * new ingest generation, so no evidence is read for other files.
1022
+ */
1023
+ function gatherProbeEvidence(rootDir, analysed, order, readings = {}) {
1024
+ const root = realRoot(rootDir);
1025
+ return (bases, identity, loads = []) => {
1026
+ const byBase = {};
1027
+ for (const base of bases) {
1028
+ const host = hostCandidate(rootDir, base, analysed, order, readings, root);
1029
+ if (host !== null) byBase[base] = host;
1030
+ }
1031
+ const expansions = readings.expander === void 0 ? [] : hostExpansions(loads, rootDir, analysed, readings.expander, readings.isAsset);
1032
+ generations += 1;
1033
+ return JSON.stringify({
1034
+ generation: generations,
1035
+ identity,
1036
+ bases: byBase,
1037
+ ...expansions.length > 0 && { expansions }
1038
+ });
1039
+ };
1040
+ }
1041
+ /** Each adapted original and its analysis children, from ingestion's
1042
+ * ownership: an original whose children are other paths than its own. */
1043
+ function adaptedOriginals(ownership) {
1044
+ return new Map(Object.entries(ownership).filter(([original, { analysisPaths }]) => !(analysisPaths.length === 1 && analysisPaths[0] === original)).map(([original, { analysisPaths }]) => [original, analysisPaths]));
1045
+ }
1046
+ //#endregion
746
1047
  //#region pipeline/svelte-source-adapter.ts
747
1048
  const isCompilerReference = (value) => Object(value) === value;
748
1049
  const isCompilerCallable = (value) => {
@@ -840,14 +1141,14 @@ function sourceLocation(source, node) {
840
1141
  function createsNestedBindingScope(node) {
841
1142
  return node.type === "BlockStatement" || node.type === "CatchClause" || node.type === "ClassBody" || node.type === "ClassDeclaration" || node.type === "ClassExpression" || node.type === "ForInStatement" || node.type === "ForOfStatement" || node.type === "ForStatement" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "StaticBlock" || node.type === "SwitchStatement" || node.type === "TSModuleBlock";
842
1143
  }
843
- function walk(node, visit, nestedScopeDepth = 0) {
1144
+ function walk$1(node, visit, nestedScopeDepth = 0) {
844
1145
  visit(node, nestedScopeDepth);
845
1146
  const childScopeDepth = nestedScopeDepth + (createsNestedBindingScope(node) ? 1 : 0);
846
1147
  for (const [key, value] of Object.entries(node)) {
847
1148
  if (key === "loc" || key === "start" || key === "end") continue;
848
1149
  if (Array.isArray(value)) {
849
- for (const item of value) if (isNode(item)) walk(item, visit, childScopeDepth);
850
- } else if (isNode(value)) walk(value, visit, childScopeDepth);
1150
+ for (const item of value) if (isNode(item)) walk$1(item, visit, childScopeDepth);
1151
+ } else if (isNode(value)) walk$1(value, visit, childScopeDepth);
851
1152
  }
852
1153
  }
853
1154
  /**
@@ -1049,7 +1350,7 @@ function isJsxAttributeName(name) {
1049
1350
  }
1050
1351
  function tsxIncompatibleValue(value) {
1051
1352
  let incompatible = null;
1052
- walk(value, (node) => {
1353
+ walk$1(value, (node) => {
1053
1354
  if (incompatible) return;
1054
1355
  if (node.type === "TSTypeAssertion" || node.type === "ArrowFunctionExpression" && childNode(node.typeParameters) !== null) incompatible = node;
1055
1356
  });
@@ -1146,7 +1447,7 @@ function projectScope(script, scope, source, originalPath, options, inherited, p
1146
1447
  const bindings = inherited ? new Map([...inherited.bindings, ...ownBindings]) : ownBindings;
1147
1448
  const witnesses = [];
1148
1449
  const diagnostics = [];
1149
- if (bindings.size > 0) walk(script.content, (node, nestedScopeDepth) => {
1450
+ if (bindings.size > 0) walk$1(script.content, (node, nestedScopeDepth) => {
1150
1451
  const site = resolverCallSite(node, bindings);
1151
1452
  if (!site) return;
1152
1453
  const { access, form } = site;
@@ -1311,17 +1612,6 @@ function parseFilesJson(filesJson, context) {
1311
1612
  function isAdvisorySourceDiagnostic(diagnostic) {
1312
1613
  return diagnostic.code === "SOURCE_NATIVE_PARSE_ERROR";
1313
1614
  }
1314
- const RELATIVE_PROBE_SUFFIXES = [
1315
- "",
1316
- ".ts",
1317
- ".tsx",
1318
- ".js",
1319
- ".jsx",
1320
- "/index.ts",
1321
- "/index.tsx",
1322
- "/index.js",
1323
- "/index.jsx"
1324
- ];
1325
1615
  function extension(path) {
1326
1616
  const basename = node_path.posix.basename(path);
1327
1617
  const dot = basename.lastIndexOf(".");
@@ -1330,27 +1620,40 @@ function extension(path) {
1330
1620
  function canonicalResolverPath(path) {
1331
1621
  return node_path.posix.normalize(path.replaceAll("\\", "/"));
1332
1622
  }
1333
- const NODE_NEXT_EXTENSION_MAP = {
1334
- ".js": [
1335
- ".ts",
1336
- ".tsx",
1337
- ".jsx"
1338
- ],
1339
- ".jsx": [".tsx"],
1340
- ".mjs": [".mts"],
1341
- ".cjs": [".cts"]
1342
- };
1343
- /** The paths a relative specifier can name from `importerPath`, in probe
1344
- * order: as written with each source suffix, then a NodeNext emitted
1345
- * extension's sources. Empty for a non-relative specifier. */
1346
- function relativeSourceCandidates(importerPath, specifier) {
1623
+ /** The paths a relative specifier can name from `importerPath`, in the
1624
+ * extension policy's probe order. Empty for a non-relative specifier. */
1625
+ function relativeSourceCandidates(importerPath, specifier, policy) {
1347
1626
  if (!specifier.startsWith(".")) return [];
1348
- const base = node_path.posix.normalize(node_path.posix.join(node_path.posix.dirname(canonicalResolverPath(importerPath)), specifier));
1349
- const explicitExtension = extension(base);
1350
- return [...RELATIVE_PROBE_SUFFIXES.map((suffix) => `${base}${suffix}`), ...(NODE_NEXT_EXTENSION_MAP[explicitExtension] ?? []).map((sourceExtension) => `${base.slice(0, -explicitExtension.length)}${sourceExtension}`)];
1351
- }
1352
- function resolveRelativeSource(importerPath, specifier, files) {
1353
- for (const candidate of relativeSourceCandidates(importerPath, specifier)) {
1627
+ return policyCandidates(node_path.posix.normalize(node_path.posix.join(node_path.posix.dirname(canonicalResolverPath(importerPath)), specifier)), { policy });
1628
+ }
1629
+ function resolveRelativeSource(importerPath, specifier, files, analysed, opened, policy, host) {
1630
+ if (host !== void 0 && specifier.startsWith(".")) {
1631
+ const first = hostCandidate(host.rootDir, node_path.posix.normalize(node_path.posix.join(node_path.posix.dirname(canonicalResolverPath(importerPath)), specifier)), analysed, policy, { adapted: host.adapted });
1632
+ if (first !== null) {
1633
+ if (first.actual) {
1634
+ opened({
1635
+ candidate: first.candidate,
1636
+ opened: first.actual,
1637
+ why: "case-mismatch"
1638
+ });
1639
+ return null;
1640
+ }
1641
+ if (first.reading === "unanalysed") {
1642
+ const candidates = relativeSourceCandidates(importerPath, specifier, policy);
1643
+ const later = candidates.slice(candidates.indexOf(first.candidate) + 1).find((candidate) => files.has(candidate));
1644
+ const opening = {
1645
+ candidate: first.candidate,
1646
+ opened: first.candidate,
1647
+ why: "skipped"
1648
+ };
1649
+ if (later !== void 0) opening.later = later;
1650
+ opened(opening);
1651
+ return null;
1652
+ }
1653
+ return first.analysedAs === null ? null : files.get(first.analysedAs) ?? null;
1654
+ }
1655
+ }
1656
+ for (const candidate of relativeSourceCandidates(importerPath, specifier, policy)) {
1354
1657
  const actualPath = files.get(candidate);
1355
1658
  if (actualPath !== void 0) return actualPath;
1356
1659
  }
@@ -1358,15 +1661,22 @@ function resolveRelativeSource(importerPath, specifier, files) {
1358
1661
  }
1359
1662
  var ResolverExportIndex = class {
1360
1663
  facts;
1664
+ extensions;
1665
+ host;
1361
1666
  collisions;
1362
1667
  files;
1668
+ analysed;
1669
+ /** Each resolver call that ended Incomplete, once. */
1670
+ openings = /* @__PURE__ */ new Map();
1363
1671
  resolverBindings = /* @__PURE__ */ new Map();
1364
1672
  /** Both memos live for one ingest only — the index is rebuilt per call,
1365
1673
  * so neither needs invalidation. */
1366
1674
  attributionMemo = /* @__PURE__ */ new Map();
1367
1675
  resolveMemo = /* @__PURE__ */ new Map();
1368
- constructor(facts, analysisPaths) {
1676
+ constructor(facts, analysisPaths, extensions, host) {
1369
1677
  this.facts = facts;
1678
+ this.extensions = extensions;
1679
+ this.host = host;
1370
1680
  const pathsByCanonical = /* @__PURE__ */ new Map();
1371
1681
  for (const path of analysisPaths) {
1372
1682
  const canonicalPath = canonicalResolverPath(path);
@@ -1391,6 +1701,7 @@ var ResolverExportIndex = class {
1391
1701
  if (paths.length === 1 && factPaths.length === 1) files.set(canonicalPath, factPaths[0]);
1392
1702
  }
1393
1703
  this.files = files;
1704
+ this.analysed = new Set(files.keys());
1394
1705
  for (const [path, file] of Object.entries(facts.files)) this.resolverBindings.set(path, new Set(file.chains.filter((chain) => chain.descriptor.terminal === "asClass" && chain.descriptor.extractable && chain.fatalError === null).map((chain) => chain.descriptor.binding)));
1395
1706
  }
1396
1707
  attribute(importerPath, request) {
@@ -1411,7 +1722,11 @@ var ResolverExportIndex = class {
1411
1722
  const key = `${importerPath}\0${specifier}`;
1412
1723
  let resolved = this.resolveMemo.get(key);
1413
1724
  if (resolved === void 0) {
1414
- resolved = resolveRelativeSource(importerPath, specifier, this.files);
1725
+ resolved = resolveRelativeSource(importerPath, specifier, this.files, this.analysed, (opening) => this.openings.set(key, {
1726
+ importer: importerPath,
1727
+ specifier,
1728
+ ...opening
1729
+ }), this.extensions, this.host);
1415
1730
  this.resolveMemo.set(key, resolved);
1416
1731
  }
1417
1732
  return resolved;
@@ -1533,7 +1848,10 @@ async function ingestSourceEntries(rawEntries, options) {
1533
1848
  messages: file.parseDiagnostics
1534
1849
  });
1535
1850
  }
1536
- const resolvers = new ResolverExportIndex(facts, analysisEntries.map((entry) => entry.path));
1851
+ const resolvers = new ResolverExportIndex(facts, analysisEntries.map((entry) => entry.path), options.extensions, options.rootDir === void 0 ? void 0 : {
1852
+ rootDir: options.rootDir,
1853
+ adapted: adaptedOriginals(ownership)
1854
+ });
1537
1855
  for (const { canonicalPath, paths } of resolvers.collisions) for (let index = 0; index < paths.length; index += 1) {
1538
1856
  const path = paths[index];
1539
1857
  const conflictingPath = paths[(index + 1) % paths.length];
@@ -1568,13 +1886,14 @@ async function ingestSourceEntries(rawEntries, options) {
1568
1886
  diagnostics
1569
1887
  };
1570
1888
  if (abortedParses.length > 0) result.abortedParses = abortedParses;
1889
+ if (resolvers.openings.size > 0) result.openings = [...resolvers.openings.values()];
1571
1890
  return result;
1572
1891
  }
1573
1892
  /**
1574
1893
  * `parseCount` counts the parses performed by THIS call, so a fully-memoized
1575
1894
  * pass reports zero.
1576
1895
  */
1577
- function collectFileFacts(analysisEntries, options) {
1896
+ function collectFileFacts(analysisEntries, options, evict = true) {
1578
1897
  const cache = options.factsCache;
1579
1898
  if (!cache) return JSON.parse(options.extractFacts(JSON.stringify(analysisEntries)));
1580
1899
  const pending = analysisEntries.filter((entry) => cache.get(entry.path)?.hash !== entry.hash);
@@ -1591,8 +1910,10 @@ function collectFileFacts(analysisEntries, options) {
1591
1910
  else cache.delete(entry.path);
1592
1911
  }
1593
1912
  }
1594
- const currentPaths = new Set(analysisEntries.map((entry) => entry.path));
1595
- for (const path of [...cache.keys()]) if (!currentPaths.has(path)) cache.delete(path);
1913
+ if (evict) {
1914
+ const currentPaths = new Set(analysisEntries.map((entry) => entry.path));
1915
+ for (const path of [...cache.keys()]) if (!currentPaths.has(path)) cache.delete(path);
1916
+ }
1596
1917
  const files = {};
1597
1918
  for (const entry of analysisEntries) {
1598
1919
  const cached = cache.get(entry.path);
@@ -1642,15 +1963,26 @@ function createSourceIngestor(host) {
1642
1963
  /** Non-strict dedupe: a quarantined original re-ingests on every later
1643
1964
  * corpus pass, so re-warning it on each save is noise. */
1644
1965
  const warnedByOriginal = /* @__PURE__ */ new Map();
1966
+ const extractFacts = () => {
1967
+ const extract = host.engineApi().extractFacts;
1968
+ if (extract === void 0) throw new Error(`${host.prefix} native engine does not expose extractFacts required for source adaptation`);
1969
+ return extract;
1970
+ };
1645
1971
  return {
1646
1972
  async ingest(entries) {
1647
- const extractFacts = host.engineApi().extractFacts;
1648
- if (extractFacts === void 0) throw new Error(`${host.prefix} native engine does not expose extractFacts required for source adaptation`);
1649
1973
  return ingestSourceEntries(entries, {
1650
- extractFacts,
1651
- factsCache
1974
+ extractFacts: extractFacts(),
1975
+ factsCache,
1976
+ extensions: host.extensions?.(),
1977
+ rootDir: host.rootDir?.()
1652
1978
  });
1653
1979
  },
1980
+ facts(entries) {
1981
+ return collectFileFacts(entries, {
1982
+ extractFacts: extractFacts(),
1983
+ factsCache
1984
+ }, false);
1985
+ },
1654
1986
  surfaceDiagnostics(diagnostics) {
1655
1987
  const fatal = diagnostics.filter((diagnostic) => !isAdvisorySourceDiagnostic(diagnostic));
1656
1988
  const invalidOriginals = new Set(fatal.map((diagnostic) => diagnostic.originalPath));
@@ -1698,9 +2030,16 @@ function createV2EngineApi(deps) {
1698
2030
  return {
1699
2031
  loadSystemModule: (...args) => native.loadSystemModule(...args),
1700
2032
  extractFacts: (filesJson) => native.extractFacts(filesJson),
1701
- moduleSpecifiers: (filesJson) => native.moduleSpecifiers(filesJson),
2033
+ moduleSpecifiers: (filesJson, pathAliasesJson) => native.moduleSpecifiers(filesJson, pathAliasesJson),
2034
+ systemMembership: (inputsJson) => native.systemMembership(inputsJson),
1702
2035
  diagnosticCodes: () => native.diagnosticCodes(),
1703
- analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson, transformSourcesJson, transformProvenanceJson, declarationScalesJson, analysisContextJson, generatedNamesJson) => {
2036
+ resolveSpecifier: native.resolveSpecifier === void 0 ? void 0 : (specifier, fromDir, conditions, workspaces, extensionPolicyJson) => native.resolveSpecifier(specifier, fromDir, conditions, workspaces, extensionPolicyJson),
2037
+ fingerprintFile: native.fingerprintFile === void 0 ? void 0 : (path) => native.fingerprintFile(path) ?? null,
2038
+ fingerprintBytes: native.fingerprintBytes === void 0 ? void 0 : (bytes) => native.fingerprintBytes(bytes),
2039
+ declaresKitSource: native.declaresKitSource === void 0 ? void 0 : (packageDir) => native.declaresKitSource(packageDir),
2040
+ locatePackage: native.locatePackage === void 0 ? void 0 : (name, fromDir, workspaces) => native.locatePackage(name, fromDir, workspaces) ?? null,
2041
+ resolveKitSourceRoot: native.resolveKitSourceRoot === void 0 ? void 0 : (specifier, fromDir, conditions, workspaces, extensionPolicyJson, hostEntry, packageDir) => native.resolveKitSourceRoot(specifier, fromDir, conditions, workspaces, extensionPolicyJson, hostEntry, packageDir),
2042
+ analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson, transformSourcesJson, transformProvenanceJson, declarationScalesJson, analysisContextJson, generatedNamesJson, propertyRecordsJson, probeEvidence) => {
1704
2043
  const filesJson = deps.rehydrateFilesJson ? deps.rehydrateFilesJson(filesJsonRaw) : filesJsonRaw;
1705
2044
  const sent = /* @__PURE__ */ new Map();
1706
2045
  for (const entry of parseFilesJson(filesJson, label)) sent.set(entry.path, entry.source);
@@ -1729,11 +2068,17 @@ function createV2EngineApi(deps) {
1729
2068
  declarationScalesJson,
1730
2069
  analysisContextJson,
1731
2070
  generatedNamesJson,
2071
+ propertyRecordsJson,
1732
2072
  devMode
1733
2073
  };
1734
2074
  const engine = new native.ExtractEngine(config);
1735
2075
  store.setEngine(engine);
1736
- return engine.analyze(filesJson);
2076
+ let evidence;
2077
+ if (probeEvidence !== void 0) {
2078
+ const prepared = parseInternalWire(engine.prepare(filesJson), "ExtractEngine.prepare");
2079
+ evidence = probeEvidence(prepared.bases, prepared.identity, prepared.loads);
2080
+ }
2081
+ return engine.analyze(filesJson, evidence);
1737
2082
  },
1738
2083
  transformFile: (source, path, _manifest) => {
1739
2084
  const engine = store.getEngine();
@@ -1759,10 +2104,112 @@ function createV2EngineApi(deps) {
1759
2104
  };
1760
2105
  }
1761
2106
  //#endregion
1762
- //#region pipeline/engine-retirement.ts
1763
- const RETIRED_ENGINE_MESSAGE = "animus: the 'v1' extraction engine is no longer supported, and v2 is the only engine. Remove the engine option from your Animus config and unset the ANIMUS_ENGINE environment variable.";
1764
- function assertNoRetiredEngineSelection(engineOption) {
1765
- if (engineOption === "v1" || process.env.ANIMUS_ENGINE === "v1") throw new Error(RETIRED_ENGINE_MESSAGE);
2107
+ //#region pipeline/source-identity.ts
2108
+ /**
2109
+ * One derivation of source identity for discovery, watch ingestion, ownership
2110
+ * and deletion: event paths are lookup INPUTS only and never fork identity.
2111
+ */
2112
+ /**
2113
+ * True when `target` is `root` or a descendant, decided by `relative()`
2114
+ * shape: string prefixing would let `/ui` claim `/ui-old`.
2115
+ */
2116
+ function isPathWithinRoot(root, target, pathApi = node_path.default) {
2117
+ const rel = pathApi.relative(root, target);
2118
+ return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
2119
+ }
2120
+ /**
2121
+ * True when two paths share a platform root (win32 drive letter or UNC
2122
+ * share; always true on posix). Drive letters compare case-insensitively.
2123
+ */
2124
+ function sharesVolumeRoot(a, b, pathApi = node_path.default) {
2125
+ const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
2126
+ return volumeOf(a) === volumeOf(b);
2127
+ }
2128
+ function canonicalize(p) {
2129
+ try {
2130
+ return (0, node_fs.realpathSync)(p);
2131
+ } catch {
2132
+ return null;
2133
+ }
2134
+ }
2135
+ function createSourceIdentity(rootDir) {
2136
+ const normalizedRootDir = node_path.default.normalize(rootDir);
2137
+ const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
2138
+ const roots = [];
2139
+ const aliases = /* @__PURE__ */ new Map();
2140
+ const owningRecord = (canonicalPath) => {
2141
+ let owner = null;
2142
+ for (const record of roots) {
2143
+ if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
2144
+ if (!owner || record.canonical.length > owner.canonical.length) owner = record;
2145
+ }
2146
+ return owner;
2147
+ };
2148
+ return {
2149
+ rootDir: normalizedRootDir,
2150
+ canonicalRootDir,
2151
+ registerExternalRoot(root) {
2152
+ const asRegistered = node_path.default.normalize(root);
2153
+ const canonical = canonicalize(asRegistered) ?? asRegistered;
2154
+ const existing = roots.find((record) => record.canonical === canonical);
2155
+ if (existing) return existing.canonical;
2156
+ roots.push({
2157
+ asRegistered,
2158
+ canonical
2159
+ });
2160
+ return canonical;
2161
+ },
2162
+ externalRoots() {
2163
+ return roots.map((record) => record.canonical);
2164
+ },
2165
+ resolveSourceId(inputPath) {
2166
+ const lexical = node_path.default.normalize(inputPath);
2167
+ const canonical = canonicalize(lexical);
2168
+ if (canonical === null) return null;
2169
+ const owner = owningRecord(canonical);
2170
+ const ownedBy = (record) => {
2171
+ const pathInRoot = node_path.default.relative(record.canonical, canonical);
2172
+ return {
2173
+ sourceKey: node_path.default.relative(normalizedRootDir, node_path.default.join(record.asRegistered, pathInRoot)),
2174
+ owningRoot: record.canonical,
2175
+ pathInRoot
2176
+ };
2177
+ };
2178
+ const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
2179
+ let resolved;
2180
+ if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
2181
+ const key = node_path.default.relative(canonicalRootDir, canonical);
2182
+ resolved = {
2183
+ sourceKey: key,
2184
+ owningRoot: null,
2185
+ pathInRoot: key
2186
+ };
2187
+ } else if (owner) resolved = ownedBy(owner);
2188
+ else return null;
2189
+ aliases.set(lexical, resolved);
2190
+ aliases.set(canonical, resolved);
2191
+ return resolved;
2192
+ },
2193
+ resolveDeletedSourceId(inputPath) {
2194
+ return aliases.get(node_path.default.normalize(inputPath)) ?? null;
2195
+ },
2196
+ containingExternalRoot(inputPath) {
2197
+ const lexical = node_path.default.normalize(inputPath);
2198
+ let owner = null;
2199
+ for (const record of roots) {
2200
+ if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
2201
+ if (!owner || record.canonical.length > owner.canonical.length) owner = record;
2202
+ }
2203
+ if (owner) return owner.canonical;
2204
+ const canonical = canonicalize(lexical);
2205
+ if (canonical === null) return null;
2206
+ for (const record of roots) {
2207
+ if (!isPathWithinRoot(record.canonical, canonical)) continue;
2208
+ if (!owner || record.canonical.length > owner.canonical.length) owner = record;
2209
+ }
2210
+ return owner?.canonical ?? null;
2211
+ }
2212
+ };
1766
2213
  }
1767
2214
  //#endregion
1768
2215
  //#region pipeline/core-options.ts
@@ -1871,6 +2318,11 @@ const CORE_VALUE_GATES = [
1871
2318
  ok: isString,
1872
2319
  expected: "a string path"
1873
2320
  },
2321
+ {
2322
+ key: "root",
2323
+ ok: isString,
2324
+ expected: "a string path"
2325
+ },
1874
2326
  {
1875
2327
  key: "exclude",
1876
2328
  ok: isStringArray,
@@ -1989,30 +2441,101 @@ function globToRegExp(glob) {
1989
2441
  }
1990
2442
  return new RegExp(`^${out}$`);
1991
2443
  }
2444
+ /** Whether a root-relative path is `dir` or lies under it, a literal path
2445
+ * prefix: an output name is never a pattern. */
2446
+ function compileOutputDir(dir) {
2447
+ return (_full, rel) => {
2448
+ const normalized = rel.split("\\").join("/");
2449
+ return normalized === dir || normalized.startsWith(`${dir}/`);
2450
+ };
2451
+ }
1992
2452
  /**
1993
- * A user list replaces only the replaceable defaults. Driver-owned
1994
- * invariants belong in `extraStructural`; a user list would replace those.
2453
+ * A user list replaces only the replaceable defaults. A host's output
2454
+ * directories (`outputExclusion`) always apply, whatever the user's list.
1995
2455
  */
1996
- function createExcludeMatcher(userPatterns, extraStructural = []) {
1997
- const merged = [...STRUCTURAL_EXCLUDE];
1998
- for (const pattern of extraStructural) if (!merged.includes(pattern)) merged.push(pattern);
1999
- for (const pattern of userPatterns ?? REPLACEABLE_DEFAULT_EXCLUDE) if (!merged.includes(pattern)) merged.push(pattern);
2000
- const compiled = merged.map((pattern) => [pattern, compilePattern(pattern)]);
2001
- const hits = new Map(merged.map((p) => [p, 0]));
2456
+ function createExcludeMatcher(userPatterns, outputDirs = []) {
2457
+ const userList = userPatterns ?? REPLACEABLE_DEFAULT_EXCLUDE;
2458
+ const compiled = [];
2459
+ for (const pattern of STRUCTURAL_EXCLUDE) compiled.push({
2460
+ pattern,
2461
+ test: compilePattern(pattern),
2462
+ isUser: userList.includes(pattern)
2463
+ });
2464
+ for (const dir of outputDirs) compiled.push({
2465
+ pattern: dir,
2466
+ test: compileOutputDir(dir),
2467
+ isUser: false
2468
+ });
2469
+ for (const pattern of userList) {
2470
+ if (STRUCTURAL_EXCLUDE.includes(pattern)) continue;
2471
+ compiled.push({
2472
+ pattern,
2473
+ test: compilePattern(pattern),
2474
+ isUser: true
2475
+ });
2476
+ }
2477
+ const hits = new Map(compiled.map((c) => [c.pattern, 0]));
2002
2478
  const explain = (full, rel) => {
2003
- for (const [pattern, test] of compiled) if (test(full, rel)) {
2479
+ let excludedBy = null;
2480
+ for (const { pattern, test, isUser } of compiled) {
2481
+ if (excludedBy !== null && !isUser) continue;
2482
+ if (!test(full, rel)) continue;
2004
2483
  hits.set(pattern, (hits.get(pattern) ?? 0) + 1);
2005
- return pattern;
2484
+ excludedBy ??= pattern;
2006
2485
  }
2007
- return null;
2486
+ return excludedBy;
2008
2487
  };
2009
2488
  return {
2010
- patterns: merged,
2489
+ patterns: compiled.map((c) => c.pattern),
2011
2490
  matches: (full, rel) => explain(full, rel) !== null,
2012
2491
  explain,
2013
- stats: () => hits
2492
+ stats: () => hits,
2493
+ unmatched: () => (userPatterns ?? []).filter((pattern) => hits.get(pattern) === 0)
2494
+ };
2495
+ }
2496
+ /** One line per user pattern that matched nothing, which every host
2497
+ * prints to stderr after its first discovery, as the CLI always has. */
2498
+ function unmatchedExcludeLines(matcher) {
2499
+ return matcher.unmatched().map((pattern) => `[animus] exclude pattern '${pattern}' matched nothing`);
2500
+ }
2501
+ /**
2502
+ * A host's output directory as an exclusion: root-relative with `/`
2503
+ * separators, matched as a literal path prefix, so a user list, which
2504
+ * replaces the defaults, never re-admits output. Null when the directory is
2505
+ * outside the root or is the root itself.
2506
+ */
2507
+ function outputExclusion(root, outDir) {
2508
+ if (!isPathWithinRoot(root, outDir)) return null;
2509
+ const rel = (0, path.relative)(root, outDir);
2510
+ return rel === "" ? null : rel.split(path.sep).join("/");
2511
+ }
2512
+ /**
2513
+ * The output directory a source file's real path lies in, or null. Applied
2514
+ * where a host assembles its analysis inputs: a file reached under another
2515
+ * spelling, through a source-tree link or a package's entry, is output too.
2516
+ */
2517
+ function outputSourceGuard(root, outputDirs) {
2518
+ if (outputDirs.length === 0) return () => null;
2519
+ const realDirs = outputDirs.map((dir) => ({
2520
+ dir,
2521
+ real: realPathOf((0, path.resolve)(root, dir))
2522
+ }));
2523
+ return (absPath) => {
2524
+ const real = realPathOf(absPath);
2525
+ return realDirs.find((o) => isPathWithinRoot(o.real, real))?.dir ?? null;
2014
2526
  };
2015
2527
  }
2528
+ /** The warning for a source a host refused as output. */
2529
+ function outputSourceMessage(relPath, outputDir) {
2530
+ return `${relPath} resolves into the output directory '${outputDir}', which is never source; it is not analysed`;
2531
+ }
2532
+ function realPathOf(path$8) {
2533
+ try {
2534
+ return (0, fs.realpathSync)(path$8);
2535
+ } catch {
2536
+ return path$8;
2537
+ }
2538
+ }
2016
2539
  function resolveMode(explicit, driverDefault) {
2017
2540
  if (explicit === "development" || explicit === "production") return {
2018
2541
  mode: explicit,
@@ -2024,18 +2547,92 @@ function resolveMode(explicit, driverDefault) {
2024
2547
  };
2025
2548
  }
2026
2549
  //#endregion
2027
- //#region pipeline/discover-files.ts
2028
- function pathCharRank(code) {
2029
- return code === 47 || code === 92 ? -1 : code;
2030
- }
2031
- function compareDiscoveryOrder(a, b) {
2032
- const shared = Math.min(a.length, b.length);
2033
- for (let i = 0; i < shared; i++) {
2034
- const left = pathCharRank(a.charCodeAt(i));
2035
- const right = pathCharRank(b.charCodeAt(i));
2036
- if (left !== right) return left - right;
2550
+ //#region pipeline/engine-retirement.ts
2551
+ const RETIRED_ENGINE_MESSAGE = "animus: the 'v1' extraction engine is no longer supported, and v2 is the only engine. Remove the engine option from your Animus config and unset the ANIMUS_ENGINE environment variable.";
2552
+ /**
2553
+ * v2 is the only engine (SA2): the option and `ANIMUS_ENGINE`, a startup
2554
+ * input a worker may pass as captured, accept `v2` or nothing. Hosts call
2555
+ * this before the native module loads, so another selection never reaches
2556
+ * it; either fails as a configuration error naming its source.
2557
+ */
2558
+ function assertSupportedEngine(engineOption, environmentSelection = process.env.ANIMUS_ENGINE) {
2559
+ const selections = [[engineOption, "the engine option"], [environmentSelection || void 0, "ANIMUS_ENGINE"]];
2560
+ for (const [selection, source] of selections) {
2561
+ if (selection === void 0 || selection === "v2") continue;
2562
+ if (selection === "v1") throw new AnimusConfigError(`${RETIRED_ENGINE_MESSAGE} (from ${source})`);
2563
+ throw new AnimusConfigError(`animus: unknown extraction engine "${selection}" from ${source}: v2 is the only engine.`);
2037
2564
  }
2038
- return a.length - b.length;
2565
+ }
2566
+ //#endregion
2567
+ //#region pipeline/asset-copies.ts
2568
+ /**
2569
+ * Immutable asset copies: one binding from an `asset()` source file to a
2570
+ * content-digested name, shared by every host that serves copies.
2571
+ */
2572
+ /** Copies `sourcePath` into `assetsDir` under its content-digested name,
2573
+ * once: a copy is never overwritten, so a URL naming it always serves the
2574
+ * bytes it named. */
2575
+ function writeAssetCopy(sourcePath, assetsDir) {
2576
+ const bytes = (0, fs.readFileSync)(sourcePath);
2577
+ const digest = contentHash(bytes);
2578
+ const ext = (0, path.extname)(sourcePath);
2579
+ const fileName = `${(0, path.basename)(sourcePath, ext)}.${digest.slice(0, 8)}${ext}`;
2580
+ if (!(0, fs.existsSync)(assetsDir)) (0, fs.mkdirSync)(assetsDir, { recursive: true });
2581
+ const copyPath = (0, path.join)(assetsDir, fileName);
2582
+ if (!(0, fs.existsSync)(copyPath)) (0, fs.writeFileSync)(copyPath, bytes);
2583
+ return {
2584
+ fileName,
2585
+ digest,
2586
+ bytes
2587
+ };
2588
+ }
2589
+ /** Sync `assets/` to the current build's file set; per-entry failures are
2590
+ * tolerated — a concurrent session may have removed the same file. */
2591
+ function pruneStaleAssets(assetsDir, expected) {
2592
+ if (!(0, fs.existsSync)(assetsDir)) return;
2593
+ let entries;
2594
+ try {
2595
+ entries = (0, fs.readdirSync)(assetsDir);
2596
+ } catch {
2597
+ return;
2598
+ }
2599
+ for (const entry of entries) {
2600
+ if (expected.has(entry)) continue;
2601
+ try {
2602
+ (0, fs.unlinkSync)((0, path.join)(assetsDir, entry));
2603
+ } catch {}
2604
+ }
2605
+ }
2606
+ //#endregion
2607
+ //#region pipeline/runtime-import.ts
2608
+ /** The runtime every adapter emits by default (spine row 1). */
2609
+ const DEFAULT_RUNTIME_IMPORT = "@animus-ui/system/runtime";
2610
+ /** The entries that supply every terminal: an override naming another must
2611
+ * extract only `.asClass()` terminals. */
2612
+ const FULL_RUNTIME_IMPORTS = /* @__PURE__ */ new Set([DEFAULT_RUNTIME_IMPORT, "@animus-ui/system"]);
2613
+ /** Throws when `runtimeImport` names a module that cannot supply a
2614
+ * terminal the manifest extracted. */
2615
+ function assertRuntimeImportSuppliesTerminals(runtimeImport, manifest) {
2616
+ if (!runtimeImport || FULL_RUNTIME_IMPORTS.has(runtimeImport)) return;
2617
+ const offenders = [];
2618
+ for (const [id, descriptor] of Object.entries(manifest.components)) if (/\bcreateComponent\(|\bcreateComposedFamily\(/.test(descriptor.replacement)) offenders.push(id);
2619
+ if (offenders.length === 0) return;
2620
+ const shown = offenders.slice(0, 5).join(", ");
2621
+ throw new Error(`[animus-extract] runtimeImport '${runtimeImport}' is valid only when every extracted terminal is .asClass(), but ${offenders.length} component(s) need createComponent/createComposedFamily from the default '${DEFAULT_RUNTIME_IMPORT}' runtime: ${shown}` + (offenders.length > 5 ? ", …" : "") + `. Remove the override or convert these terminals to .asClass().`);
2622
+ }
2623
+ //#endregion
2624
+ //#region pipeline/discover-files.ts
2625
+ function pathCharRank(code) {
2626
+ return code === 47 || code === 92 ? -1 : code;
2627
+ }
2628
+ function compareDiscoveryOrder(a, b) {
2629
+ const shared = Math.min(a.length, b.length);
2630
+ for (let i = 0; i < shared; i++) {
2631
+ const left = pathCharRank(a.charCodeAt(i));
2632
+ const right = pathCharRank(b.charCodeAt(i));
2633
+ if (left !== right) return left - right;
2634
+ }
2635
+ return a.length - b.length;
2039
2636
  }
2040
2637
  function discoverFiles(dir, rootDir, exclude, extensionsSet) {
2041
2638
  return walkFiles(dir, rootDir, exclude, extensionsSet).sort(compareDiscoveryOrder);
@@ -2064,6 +2661,161 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
2064
2661
  return results;
2065
2662
  }
2066
2663
  //#endregion
2664
+ //#region pipeline/host-extensions.ts
2665
+ /** Animus's own order, where no host resolver configuration exists. */
2666
+ const BUILT_IN_EXTENSION_POLICY = {
2667
+ appended: EXTENSION_POLICY.appended,
2668
+ nodeNext: EXTENSION_POLICY.nodeNext,
2669
+ alias: [],
2670
+ resolverVersion: "built-in"
2671
+ };
2672
+ /** The TypeScript output a source compiles to, as a host that resolves an
2673
+ * emitted extension to its TypeScript source reads it. */
2674
+ const TYPESCRIPT_OUTPUTS = [
2675
+ [".js", [".ts", ".tsx"]],
2676
+ [".jsx", [".tsx"]],
2677
+ [".mjs", [".mts"]],
2678
+ [".cjs", [".cts"]]
2679
+ ];
2680
+ /** esbuild's rewritten file extensions, which also let `.jsx` name `.ts`. */
2681
+ const ESBUILD_OUTPUTS = [
2682
+ [".js", [".ts", ".tsx"]],
2683
+ [".jsx", [".ts", ".tsx"]],
2684
+ [".mjs", [".mts"]],
2685
+ [".cjs", [".cts"]]
2686
+ ];
2687
+ /** Documented defaults, for a host whose resolved order is not readable. */
2688
+ const HOST_DEFAULT_EXTENSIONS = {
2689
+ vite: [
2690
+ ".mjs",
2691
+ ".js",
2692
+ ".mts",
2693
+ ".ts",
2694
+ ".jsx",
2695
+ ".tsx",
2696
+ ".json"
2697
+ ],
2698
+ webpack: [
2699
+ ".js",
2700
+ ".json",
2701
+ ".wasm"
2702
+ ],
2703
+ /** Rspack 1's documented default; later versions document another. */
2704
+ rspack1: [
2705
+ ".js",
2706
+ ".json",
2707
+ ".wasm"
2708
+ ],
2709
+ turbopack: [
2710
+ ".tsx",
2711
+ ".ts",
2712
+ ".jsx",
2713
+ ".js",
2714
+ ".mjs",
2715
+ ".json"
2716
+ ],
2717
+ esbuild: [
2718
+ ".tsx",
2719
+ ".ts",
2720
+ ".jsx",
2721
+ ".js",
2722
+ ".css",
2723
+ ".json"
2724
+ ]
2725
+ };
2726
+ function label(host, version, how) {
2727
+ return `${version ? `${host}@${version}` : host} ${how}`;
2728
+ }
2729
+ /** Vite's `resolve.extensions`, which `configResolved` holds with its
2730
+ * defaults applied. A TypeScript importer's `./x.js` names `x.ts` too.
2731
+ * Only the default order is captured, as a real build resolves it. A
2732
+ * configured list does not describe Vite's effective resolution: Vite 8's
2733
+ * resolver falls back past it (`['.js']` still loads `./only` as
2734
+ * `only.tsx`), so it is unreadable. */
2735
+ function viteExtensionPolicy(extensions, version) {
2736
+ if (extensions.length !== HOST_DEFAULT_EXTENSIONS.vite.length || extensions.some((ext, i) => ext !== HOST_DEFAULT_EXTENSIONS.vite[i])) return {
2737
+ ...BUILT_IN_EXTENSION_POLICY,
2738
+ resolverVersion: "built-in (hostOptionUnreadable: vite configured extensions)"
2739
+ };
2740
+ return {
2741
+ appended: [...extensions],
2742
+ nodeNext: TYPESCRIPT_OUTPUTS,
2743
+ alias: [],
2744
+ resolverVersion: label("vite", version, "captured")
2745
+ };
2746
+ }
2747
+ /** webpack's or Rspack's resolved order for an ESM import: the root
2748
+ * `resolve` with `byDependency.esm` merged over it as the bundler merges
2749
+ * it, a `...` standing for what it extends. `extensionAlias` is kept whole
2750
+ * and in order. Where neither sets extensions, the bundler's documented
2751
+ * default stands in; for Rspack only version 1's is known. */
2752
+ function webpackExtensionPolicy(host, resolve, version) {
2753
+ const esm = resolve.byDependency?.esm;
2754
+ const unset = resolve.extensions === void 0 && esm?.extensions === void 0;
2755
+ const defaults = !(host === "rspack") ? HOST_DEFAULT_EXTENSIONS.webpack : version?.startsWith("1.") ? HOST_DEFAULT_EXTENSIONS.rspack1 : null;
2756
+ if ([...Object.values(resolve.extensionAlias ?? {}), ...Object.values(esm?.extensionAlias ?? {})].some((value) => !Array.isArray(value))) return {
2757
+ ...BUILT_IN_EXTENSION_POLICY,
2758
+ resolverVersion: "built-in (hostOptionUnreadable: string extensionAlias)"
2759
+ };
2760
+ const extendsBase = (list) => list === void 0 || list.includes("...");
2761
+ if (defaults === null && extendsBase(esm?.extensions) && extendsBase(resolve.extensions)) return {
2762
+ ...BUILT_IN_EXTENSION_POLICY,
2763
+ resolverVersion: `built-in (hostOptionUnreadable: ${host}${version ? `@${version}` : ""} defaults)`
2764
+ };
2765
+ const extend = (list, base) => list === void 0 ? base : list.flatMap((extension) => extension === "..." ? base : [extension]);
2766
+ const root = extend(resolve.extensions, defaults ?? []);
2767
+ const sequence = (value) => Array.isArray(value) ? value : [value];
2768
+ const alias = new Map(Object.entries(resolve.extensionAlias ?? {}).map(([emitted, value]) => [emitted, sequence(value).filter((extension) => extension !== "...")]));
2769
+ for (const [emitted, value] of Object.entries(esm?.extensionAlias ?? {})) {
2770
+ const base = alias.get(emitted) ?? [];
2771
+ alias.set(emitted, sequence(value).flatMap((extension) => extension === "..." ? base : [extension]));
2772
+ }
2773
+ return {
2774
+ appended: [...extend(esm?.extensions, root)],
2775
+ nodeNext: [],
2776
+ alias: [...alias].map(([emitted, extensions]) => [emitted, [...extensions]]),
2777
+ resolverVersion: label(host, version, unset ? "default" : "captured")
2778
+ };
2779
+ }
2780
+ /** Turbopack's `turbopack.resolveExtensions`, or its documented default
2781
+ * when the Next config sets none. It substitutes no source: under Next
2782
+ * 16.3, `./x.js` beside only `x.ts` names no module. */
2783
+ function turbopackExtensionPolicy(resolveExtensions, nextVersion) {
2784
+ return {
2785
+ appended: [...resolveExtensions ?? HOST_DEFAULT_EXTENSIONS.turbopack],
2786
+ nodeNext: [],
2787
+ alias: [],
2788
+ resolverVersion: label("turbopack", nextVersion, resolveExtensions === void 0 ? "default" : "captured")
2789
+ };
2790
+ }
2791
+ /** esbuild's `resolveExtensions`, or its default when the build sets none. */
2792
+ function esbuildExtensionPolicy(resolveExtensions, version) {
2793
+ return {
2794
+ appended: [...resolveExtensions ?? HOST_DEFAULT_EXTENSIONS.esbuild],
2795
+ nodeNext: ESBUILD_OUTPUTS,
2796
+ alias: [],
2797
+ resolverVersion: label("esbuild", version, resolveExtensions === void 0 ? "default" : "captured")
2798
+ };
2799
+ }
2800
+ /** Rollup leaves the extension order to its resolver plugins, which keep
2801
+ * their options private: a TypeScript build sets `@rollup/plugin-node-resolve`'s
2802
+ * `extensions`, which no documented default matches. The built-in policy
2803
+ * answers, with the reason. */
2804
+ function rollupExtensionPolicy(usesNodeResolve) {
2805
+ return {
2806
+ ...BUILT_IN_EXTENSION_POLICY,
2807
+ resolverVersion: usesNodeResolve ? "built-in (hostOptionUnreadable: rollup-node-resolve)" : "built-in (hostOptionUnreadable: rollup resolver plugins)"
2808
+ };
2809
+ }
2810
+ /** The policy as the system loader reads it (`ExtensionPolicy`). */
2811
+ function extensionPolicyJson(policy) {
2812
+ return JSON.stringify({
2813
+ appended: policy.appended,
2814
+ nodeNext: policy.nodeNext,
2815
+ alias: policy.alias
2816
+ });
2817
+ }
2818
+ //#endregion
2067
2819
  //#region pipeline/tsconfig-paths.ts
2068
2820
  /**
2069
2821
  * tsconfig `paths` → alias pairs, for drivers with no live bundler config.
@@ -2147,10 +2899,10 @@ function decodePaths(value) {
2147
2899
  function decodeExtends(value) {
2148
2900
  return (Array.isArray(value) ? value : [value]).filter(isJsonString);
2149
2901
  }
2150
- function readConfig(path$8) {
2902
+ function readConfig(path$6) {
2151
2903
  let raw;
2152
2904
  try {
2153
- raw = (0, fs.readFileSync)(path$8, "utf-8");
2905
+ raw = (0, fs.readFileSync)(path$6, "utf-8");
2154
2906
  } catch {
2155
2907
  return null;
2156
2908
  }
@@ -2163,22 +2915,33 @@ function readConfig(path$8) {
2163
2915
  const root = isJsonBlock(parsed) ? parsed : {};
2164
2916
  const compilerOptions = isJsonBlock(root.compilerOptions) ? root.compilerOptions : {};
2165
2917
  return {
2166
- dir: (0, path.dirname)(path$8),
2918
+ dir: (0, path.dirname)(path$6),
2167
2919
  baseUrl: isJsonString(compilerOptions.baseUrl) ? compilerOptions.baseUrl : null,
2168
2920
  paths: decodePaths(compilerOptions.paths),
2169
2921
  extends: decodeExtends(root.extends)
2170
2922
  };
2171
2923
  }
2172
- function resolveExtendsTarget(specifier, fromDir) {
2924
+ /** Where an `extends` specifier can name a config: a relative one as
2925
+ * written, with `.json`, or as a directory's tsconfig; a package's under
2926
+ * each ancestor's `node_modules`. Resolution takes the first that exists. */
2927
+ function extendsCandidates(specifier, fromDir) {
2173
2928
  if (specifier.startsWith(".") || (0, path.isAbsolute)(specifier)) {
2174
2929
  const base = (0, path.resolve)(fromDir, specifier);
2175
- for (const candidate of [
2930
+ return [
2176
2931
  base,
2177
2932
  `${base}.json`,
2178
2933
  (0, path.join)(base, "tsconfig.json")
2179
- ]) if ((0, fs.existsSync)(candidate)) return candidate;
2180
- return null;
2934
+ ];
2935
+ }
2936
+ const target = specifier.endsWith(".json") ? specifier : `${specifier}/tsconfig.json`;
2937
+ const candidates = [];
2938
+ for (let dir = (0, path.resolve)(fromDir);; dir = (0, path.dirname)(dir)) {
2939
+ candidates.push((0, path.join)(dir, "node_modules", target));
2940
+ if ((0, path.dirname)(dir) === dir) return candidates;
2181
2941
  }
2942
+ }
2943
+ function resolveExtendsTarget(specifier, fromDir) {
2944
+ if (specifier.startsWith(".") || (0, path.isAbsolute)(specifier)) return extendsCandidates(specifier, fromDir).find((candidate) => (0, fs.existsSync)(candidate)) ?? null;
2182
2945
  try {
2183
2946
  return require.resolve(specifier.endsWith(".json") ? specifier : `${specifier}/tsconfig.json`, { paths: [fromDir] });
2184
2947
  } catch {
@@ -2190,13 +2953,12 @@ function resolveExtendsTarget(specifier, fromDir) {
2190
2953
  }
2191
2954
  }
2192
2955
  /** Child-first flattened extends chain starting at `entryPath`. */
2193
- function loadChain(entryPath) {
2956
+ function loadChain(entryPath, visited = /* @__PURE__ */ new Set(), absent = /* @__PURE__ */ new Set()) {
2194
2957
  const chain = [];
2195
- const visited = /* @__PURE__ */ new Set();
2196
2958
  const queue = [entryPath];
2197
2959
  while (queue.length > 0) {
2198
- const path$9 = queue.shift();
2199
- const key = (0, path.resolve)(path$9);
2960
+ const path$7 = queue.shift();
2961
+ const key = (0, path.resolve)(path$7);
2200
2962
  if (visited.has(key)) continue;
2201
2963
  visited.add(key);
2202
2964
  const node = readConfig(key);
@@ -2205,10 +2967,20 @@ function loadChain(entryPath) {
2205
2967
  for (const parent of node.extends) {
2206
2968
  const resolved = resolveExtendsTarget(parent, node.dir);
2207
2969
  if (resolved) queue.push(resolved);
2970
+ else for (const candidate of extendsCandidates(parent, node.dir)) absent.add(candidate);
2208
2971
  }
2209
2972
  }
2210
2973
  return chain;
2211
2974
  }
2975
+ /** Every tsconfig file the project's alias chain reads or looks for, absent
2976
+ * ones included, an unresolved `extends` target's candidates among them:
2977
+ * an edit, creation or deletion of any changes the aliases. */
2978
+ function tsconfigChainPaths(rootDir) {
2979
+ const visited = /* @__PURE__ */ new Set();
2980
+ const absent = /* @__PURE__ */ new Set();
2981
+ loadChain((0, path.join)(rootDir, "tsconfig.json"), visited, absent);
2982
+ return [...visited, ...absent];
2983
+ }
2212
2984
  /**
2213
2985
  * The project's tsconfig path aliases as `buildPathAliasesJson` pairs; empty
2214
2986
  * when no readable tsconfig, or no usable `paths`, exists.
@@ -2348,112 +3120,42 @@ function kitDescriptorDiagnostics(records, manifest) {
2348
3120
  return diagnostics;
2349
3121
  }
2350
3122
  //#endregion
2351
- //#region pipeline/source-identity.ts
2352
- /**
2353
- * One derivation of source identity for discovery, watch ingestion, ownership
2354
- * and deletion: event paths are lookup INPUTS only and never fork identity.
2355
- */
2356
- /**
2357
- * True when `target` is `root` or a descendant, decided by `relative()`
2358
- * shape: string prefixing would let `/ui` claim `/ui-old`.
2359
- */
2360
- function isPathWithinRoot(root, target, pathApi = node_path.default) {
2361
- const rel = pathApi.relative(root, target);
2362
- return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
2363
- }
2364
- /**
2365
- * True when two paths share a platform root (win32 drive letter or UNC
2366
- * share; always true on posix). Drive letters compare case-insensitively.
2367
- */
2368
- function sharesVolumeRoot(a, b, pathApi = node_path.default) {
2369
- const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
2370
- return volumeOf(a) === volumeOf(b);
2371
- }
2372
- function canonicalize(p) {
3123
+ //#region pipeline/workspace-packages.ts
3124
+ /** The parsed `package.json` in `dir`, or null when it cannot be read. */
3125
+ function readManifest(dir) {
2373
3126
  try {
2374
- return (0, node_fs.realpathSync)(p);
3127
+ return JSON.parse((0, fs.readFileSync)((0, path.join)(dir, "package.json"), "utf-8"));
2375
3128
  } catch {
2376
3129
  return null;
2377
3130
  }
2378
3131
  }
2379
- function createSourceIdentity(rootDir) {
2380
- const normalizedRootDir = node_path.default.normalize(rootDir);
2381
- const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
2382
- const roots = [];
2383
- const aliases = /* @__PURE__ */ new Map();
2384
- const owningRecord = (canonicalPath) => {
2385
- let owner = null;
2386
- for (const record of roots) {
2387
- if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
2388
- if (!owner || record.canonical.length > owner.canonical.length) owner = record;
2389
- }
2390
- return owner;
2391
- };
2392
- return {
2393
- rootDir: normalizedRootDir,
2394
- canonicalRootDir,
2395
- registerExternalRoot(root) {
2396
- const asRegistered = node_path.default.normalize(root);
2397
- const canonical = canonicalize(asRegistered) ?? asRegistered;
2398
- const existing = roots.find((record) => record.canonical === canonical);
2399
- if (existing) return existing.canonical;
2400
- roots.push({
2401
- asRegistered,
2402
- canonical
2403
- });
2404
- return canonical;
2405
- },
2406
- externalRoots() {
2407
- return roots.map((record) => record.canonical);
2408
- },
2409
- resolveSourceId(inputPath) {
2410
- const lexical = node_path.default.normalize(inputPath);
2411
- const canonical = canonicalize(lexical);
2412
- if (canonical === null) return null;
2413
- const owner = owningRecord(canonical);
2414
- const ownedBy = (record) => {
2415
- const pathInRoot = node_path.default.relative(record.canonical, canonical);
2416
- return {
2417
- sourceKey: node_path.default.relative(normalizedRootDir, node_path.default.join(record.asRegistered, pathInRoot)),
2418
- owningRoot: record.canonical,
2419
- pathInRoot
2420
- };
2421
- };
2422
- const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
2423
- let resolved;
2424
- if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
2425
- const key = node_path.default.relative(canonicalRootDir, canonical);
2426
- resolved = {
2427
- sourceKey: key,
2428
- owningRoot: null,
2429
- pathInRoot: key
2430
- };
2431
- } else if (owner) resolved = ownedBy(owner);
2432
- else return null;
2433
- aliases.set(lexical, resolved);
2434
- aliases.set(canonical, resolved);
2435
- return resolved;
2436
- },
2437
- resolveDeletedSourceId(inputPath) {
2438
- return aliases.get(node_path.default.normalize(inputPath)) ?? null;
2439
- },
2440
- containingExternalRoot(inputPath) {
2441
- const lexical = node_path.default.normalize(inputPath);
2442
- let owner = null;
2443
- for (const record of roots) {
2444
- if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
2445
- if (!owner || record.canonical.length > owner.canonical.length) owner = record;
2446
- }
2447
- if (owner) return owner.canonical;
2448
- const canonical = canonicalize(lexical);
2449
- if (canonical === null) return null;
2450
- for (const record of roots) {
2451
- if (!isPathWithinRoot(record.canonical, canonical)) continue;
2452
- if (!owner || record.canonical.length > owner.canonical.length) owner = record;
2453
- }
2454
- return owner?.canonical ?? null;
3132
+ /**
3133
+ * The packages the session root's `package.json` declares as workspaces, by
3134
+ * name, at their real directories, so a linked workspace is one package. The
3135
+ * system loader consults them after a `node_modules` lookup misses. Only
3136
+ * literal entries name a package; a glob entry (`packages/*`) names none
3137
+ * yet. None when the manifest is absent or declares none.
3138
+ */
3139
+ function declaredWorkspacePackages(rootDir) {
3140
+ const rootPkg = readManifest(rootDir);
3141
+ if (!isJsonBlock(rootPkg)) return {};
3142
+ const workspaces = rootPkg.workspaces;
3143
+ const declared = isJsonBlock(workspaces) ? workspaces.packages : workspaces;
3144
+ if (!Array.isArray(declared)) return {};
3145
+ const packages = /* @__PURE__ */ new Map();
3146
+ for (const entry of declared) {
3147
+ if (!isJsonString(entry)) continue;
3148
+ let dir;
3149
+ try {
3150
+ dir = (0, fs.realpathSync)((0, path.resolve)(rootDir, entry));
3151
+ } catch {
3152
+ continue;
2455
3153
  }
2456
- };
3154
+ const manifest = readManifest(dir);
3155
+ const name = isJsonBlock(manifest) ? manifest.name : void 0;
3156
+ if (isJsonString(name) && name !== "" && !packages.has(name)) packages.set(name, dir);
3157
+ }
3158
+ return Object.fromEntries(packages);
2457
3159
  }
2458
3160
  //#endregion
2459
3161
  //#region pipeline/discover-packages.ts
@@ -2481,34 +3183,31 @@ const PACKAGE_OUTPUT_EXCLUDES = [
2481
3183
  ".d.ts",
2482
3184
  ".map"
2483
3185
  ];
2484
- const isFile$1 = (path$2) => {
2485
- try {
2486
- return (0, fs.statSync)(path$2).isFile();
2487
- } catch {
2488
- return false;
2489
- }
2490
- };
2491
- function resolveAbsolutePathSpecifier(absSpecifier, extensionsSet) {
2492
- return [
2493
- absSpecifier,
2494
- ...Array.from(extensionsSet, (ext) => absSpecifier + ext),
2495
- ...Array.from(extensionsSet, (ext) => (0, path.join)(absSpecifier, `index${ext}`))
2496
- ].find(isFile$1) ?? null;
3186
+ /** The file an absolute path specifier names, through the extension
3187
+ * policy, spelled exactly below the directory it shares with `within`
3188
+ * when given; a file differing only in case is a mismatch. */
3189
+ function probeAbsolutePathSpecifier(absSpecifier, extensionsSet, within, policy) {
3190
+ return probeOnDisk(policyCandidates((0, path.normalize)(absSpecifier), {
3191
+ sources: extensionsSet,
3192
+ index: path.join,
3193
+ policy
3194
+ }), within);
2497
3195
  }
2498
3196
  /** The package a bare specifier names: `@scope/name` or `name`. */
2499
3197
  function bareSpecifierPackageName(specifier) {
2500
3198
  const segments = specifier.split("/");
2501
3199
  return specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0];
2502
3200
  }
2503
- function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
3201
+ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet, rootDir, policy) {
2504
3202
  if ((0, path.isAbsolute)(specifier)) {
2505
- const resolved = resolveAbsolutePathSpecifier(specifier, extensionsSet);
2506
- if (!resolved) return null;
2507
- return isPathWithinRoot(srcDir, resolved) ? resolved : null;
3203
+ const probed = probeAbsolutePathSpecifier(specifier, extensionsSet, rootDir, policy);
3204
+ if (probed.kind !== "found") return null;
3205
+ return isPathWithinRoot(srcDir, probed.path) ? probed.path : null;
2508
3206
  }
2509
3207
  const packageName = bareSpecifierPackageName(specifier);
2510
3208
  const subpath = specifier.slice(packageName.length + 1);
2511
- return resolveAbsolutePathSpecifier((0, path.join)(srcDir, subpath || "index"), extensionsSet);
3209
+ const probed = probeAbsolutePathSpecifier((0, path.join)(srcDir, subpath || "index"), extensionsSet, srcDir, policy);
3210
+ return probed.kind === "found" ? probed.path : null;
2512
3211
  }
2513
3212
  /** The package's parsed `package.json`, or null when it cannot be read. */
2514
3213
  function readPackageManifest(pkgRoot) {
@@ -2533,51 +3232,50 @@ function exportsSubpaths(manifest) {
2533
3232
  * its source in every host, and the system loader prefers it.
2534
3233
  */
2535
3234
  const KIT_SOURCE_CONDITION = "animus";
2536
- /** The package's kit source condition, or null when no exact `exports`
2537
- * entry declares it: the package is no source kit. */
2538
- function readKitSourceCondition(pkgRoot) {
2539
- const condition = {
2540
- entries: [],
2541
- invalid: [],
2542
- root: null
3235
+ /** The system loader's package locator under the session's declared
3236
+ * `workspaces`: the first `node_modules/<name>` up the tree, then the
3237
+ * workspace of that name. */
3238
+ function nativePackageLocator(engine, workspaces) {
3239
+ const native = engine.locatePackage;
3240
+ return (name, fromDir) => {
3241
+ if (native === void 0) throw new Error("the native engine does not expose locatePackage, which kit discovery needs — rebuild @animus-ui/extract");
3242
+ return native(name, fromDir, workspaces);
2543
3243
  };
2544
- for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
2545
- if (subpath.includes("*") || !isJsonBlock(value)) continue;
2546
- const target = value[KIT_SOURCE_CONDITION];
2547
- if (!isJsonString(target)) continue;
2548
- const file = (0, path.resolve)(pkgRoot, target);
2549
- if (isPathWithinRoot(pkgRoot, file) && isFile$1(file)) condition.entries.push([subpath, file]);
2550
- else condition.invalid.push([subpath, target]);
2551
- }
2552
- if (condition.entries.length === 0 && condition.invalid.length === 0) return null;
2553
- condition.root = condition.entries.reduce((root, [, file]) => root === null ? (0, path.dirname)(file) : commonDirectory(root, (0, path.dirname)(file)), null);
2554
- return condition;
2555
- }
2556
- function commonDirectory(a, b) {
2557
- let dir = a;
2558
- while (!isPathWithinRoot(dir, b)) dir = (0, path.dirname)(dir);
2559
- return dir;
2560
- }
2561
- /** Whether the manifest at `dir` names the package `name`. */
2562
- function isPackageNamed(dir, name) {
3244
+ }
3245
+ /** The native table's kit source roots under one resolution context. */
3246
+ function nativeKitSourceRoot(engine, fromDir, conditions, workspaces, policyJson) {
3247
+ const native = engine.resolveKitSourceRoot;
3248
+ return (specifier, packageDir, hostEntry) => {
3249
+ if (native === void 0) throw new Error("the native engine does not expose resolveKitSourceRoot, which kit discovery needs — rebuild @animus-ui/extract");
3250
+ const answer = parseInternalWire(native(specifier, fromDir, [...conditions], workspaces, policyJson, hostEntry ?? void 0, packageDir), "resolveKitSourceRoot");
3251
+ if (answer.rule === void 0) return null;
3252
+ return {
3253
+ rule: answer.rule,
3254
+ root: answer.root ?? null,
3255
+ entries: answer.entries ?? [],
3256
+ invalid: answer.invalid ?? [],
3257
+ unresolved: answer.unresolved ?? null
3258
+ };
3259
+ };
3260
+ }
3261
+ /**
3262
+ * Whether `dir`, the nearest manifest above a host's answer, is a package
3263
+ * the host resolved into: its manifest names a package, and it is not the
3264
+ * project or a directory holding it. A host answer from a dependency cache
3265
+ * (`node_modules/.vite/deps`), or from a file outside every package, finds
3266
+ * the application's own manifest, which is no package root. The name need
3267
+ * not be the specifier's: a host alias resolves one package to another,
3268
+ * and the host's package is the one the bundle renders (spec §2.2 A4).
3269
+ */
3270
+ function isHostPackageRoot(dir, rootDir) {
2563
3271
  const manifest = readPackageManifest(dir);
2564
- return isJsonBlock(manifest) && manifest.name === name;
3272
+ return isJsonBlock(manifest) && isJsonString(manifest.name) && manifest.name !== "" && !isPathWithinRoot(realPath(dir), realPath(rootDir));
2565
3273
  }
2566
- function realPath(path$3) {
3274
+ function realPath(path$2) {
2567
3275
  try {
2568
- return (0, fs.realpathSync)(path$3);
3276
+ return (0, fs.realpathSync)(path$2);
2569
3277
  } catch {
2570
- return path$3;
2571
- }
2572
- }
2573
- /** The root of the installed package `name` as Node finds it from `fromDir`,
2574
- * the first `node_modules/<name>` up the directory tree, at its real path,
2575
- * as host resolvers report a linked package. */
2576
- function locatePackageRoot(name, fromDir) {
2577
- for (let dir = fromDir;; dir = (0, path.dirname)(dir)) {
2578
- const candidate = (0, path.join)(dir, "node_modules", name);
2579
- if ((0, fs.existsSync)((0, path.join)(candidate, "package.json"))) return realPath(candidate);
2580
- if (dir === (0, path.dirname)(dir)) return null;
3278
+ return path$2;
2581
3279
  }
2582
3280
  }
2583
3281
  /**
@@ -2723,14 +3421,21 @@ function distEntryIsStale(absEntry, srcDir, srcFiles) {
2723
3421
  return distMtime < newestSrcMtime;
2724
3422
  }
2725
3423
  async function collectExternalPackageSources(opts) {
2726
- const { specifiers, resolveSpecifier, rootDir, extensionsSet, hasEntry, onSourceRead, onUnreadable, onPackageResolved } = opts;
3424
+ const { specifiers, unresolvedReason, kitSourceRoot, locatePackage, rootDir, extensionsSet, hasEntry, onSourceRead, onUnreadable, onPackageResolved, requireSourceEntry, extensions, hostOutputDirs = [] } = opts;
3425
+ const answers = /* @__PURE__ */ new Map();
3426
+ const resolveSpecifier = (specifier) => {
3427
+ let answer = answers.get(specifier);
3428
+ if (answer === void 0) {
3429
+ answer = Promise.resolve().then(() => opts.resolveSpecifier(specifier));
3430
+ answers.set(specifier, answer);
3431
+ }
3432
+ return answer;
3433
+ };
2727
3434
  const entries = [];
2728
3435
  const pushed = /* @__PURE__ */ new Set();
2729
3436
  const packageMap = {};
2730
3437
  const sourceEntries = /* @__PURE__ */ new Map();
2731
3438
  const sourceEntrySideEffects = /* @__PURE__ */ new Map();
2732
- /** `replaced` names the entry the redirect stands in for; it is only
2733
- * needed, and so only resolved, for a glob list. */
2734
3439
  /** The entry `subpath` of the package resolves to without the redirect.
2735
3440
  * A resolver with no `import` condition, as Node's `require` has none,
2736
3441
  * finds no ESM-only entry, so the manifest's own target answers then. */
@@ -2741,6 +3446,8 @@ async function collectExternalPackageSources(opts) {
2741
3446
  } catch {}
2742
3447
  return packageExportEntries(pkgRoot).find(([entry]) => entry === subpath)?.[1] ?? null;
2743
3448
  };
3449
+ /** `replaced` names the entry the redirect stands in for; it is only
3450
+ * needed, and so only resolved, for a glob list. */
2744
3451
  const redirect = async (specifier, srcEntry, pkgRoot, replaced) => {
2745
3452
  sourceEntries.set(specifier, srcEntry);
2746
3453
  const field = readPackageSideEffects(pkgRoot);
@@ -2785,8 +3492,18 @@ async function collectExternalPackageSources(opts) {
2785
3492
  return true;
2786
3493
  };
2787
3494
  const diagnostics = [];
2788
- const reportedPackages = /* @__PURE__ */ new Set();
3495
+ const reported = /* @__PURE__ */ new Set();
3496
+ const report = (packageName, pkgRoot, condition) => {
3497
+ const copy = realPath(pkgRoot);
3498
+ for (const finding of sourceConditionDiagnostics(packageName, condition)) {
3499
+ const key = `${copy}\0${finding.code}\0${finding.message}`;
3500
+ if (reported.has(key)) continue;
3501
+ reported.add(key);
3502
+ diagnostics.push(finding);
3503
+ }
3504
+ };
2789
3505
  const kitDescriptors = [];
3506
+ const packageInstances = {};
2790
3507
  const describedRoots = /* @__PURE__ */ new Set();
2791
3508
  for (const specifier of specifiers) {
2792
3509
  let absEntry;
@@ -2795,23 +3512,78 @@ async function collectExternalPackageSources(opts) {
2795
3512
  } catch {
2796
3513
  absEntry = null;
2797
3514
  }
2798
- if (!absEntry && (0, path.isAbsolute)(specifier)) absEntry = resolveAbsolutePathSpecifier(specifier, extensionsSet);
3515
+ let caseMismatch;
3516
+ if ((0, path.isAbsolute)(specifier)) {
3517
+ const own = probeAbsolutePathSpecifier(specifier, extensionsSet, rootDir, extensions);
3518
+ const hosted = absEntry === null ? null : (0, path.normalize)(absEntry);
3519
+ const seen = hosted === null ? null : seeOnDisk(hosted, rootDir);
3520
+ const probed = own.kind === "case-mismatch" || hosted === null || seen === null ? own : seen.kind === "case-only" ? {
3521
+ kind: "case-mismatch",
3522
+ candidate: hosted,
3523
+ actual: seen.actual
3524
+ } : {
3525
+ kind: "found",
3526
+ path: hosted
3527
+ };
3528
+ absEntry = probed.kind === "found" ? probed.path : null;
3529
+ if (probed.kind === "case-mismatch") caseMismatch = caseMismatchReason(`'${specifier}'`, probed, "spell the include as the file is spelled");
3530
+ }
2799
3531
  const packageName = (0, path.isAbsolute)(specifier) ? null : bareSpecifierPackageName(specifier);
2800
- const resolvedRoot = absEntry ? findPackageRoot(absEntry) : null;
2801
- const locatedRoot = packageName && locatePackageRoot(packageName, rootDir);
2802
- const pkgRoot = resolvedRoot && (!locatedRoot || isPackageNamed(resolvedRoot, packageName) || realPath(resolvedRoot) === locatedRoot) ? resolvedRoot : locatedRoot || resolvedRoot;
2803
- const condition = packageName && pkgRoot ? readKitSourceCondition(pkgRoot) : null;
3532
+ let resolvedRoot = absEntry ? findPackageRoot(absEntry) : null;
3533
+ const locatedRoot = packageName && locatePackage(packageName, opts.locateFrom?.(specifier) ?? rootDir);
3534
+ if (resolvedRoot && locatedRoot && absEntry && realPath(resolvedRoot) !== locatedRoot && isPathWithinRoot(locatedRoot, realPath(absEntry))) {
3535
+ while (realPath(resolvedRoot) !== locatedRoot && resolvedRoot !== (0, path.dirname)(resolvedRoot)) resolvedRoot = (0, path.dirname)(resolvedRoot);
3536
+ if (realPath(resolvedRoot) !== locatedRoot) resolvedRoot = locatedRoot;
3537
+ }
3538
+ const pkgRoot = resolvedRoot && (!locatedRoot || isHostPackageRoot(resolvedRoot, rootDir) || realPath(resolvedRoot) === locatedRoot) ? resolvedRoot : locatedRoot || resolvedRoot;
3539
+ if (absEntry && packageName && locatedRoot && pkgRoot === locatedRoot && !isPathWithinRoot(locatedRoot, realPath(absEntry)) && !realPath(absEntry).split(path.sep).includes("node_modules")) diagnostics.push(packageMismatchDiagnostic(specifier, (0, path.relative)(rootDir, absEntry), (0, path.relative)(rootDir, locatedRoot)));
3540
+ const selection = packageName && pkgRoot ? kitSourceRoot(specifier, pkgRoot, absEntry) : null;
3541
+ if (selection?.unresolved) {
3542
+ absEntry = null;
3543
+ caseMismatch = selection.unresolved;
3544
+ }
3545
+ const condition = selection && (selection.rule === "animus" || selection.rule === "source-exports" || selection.invalid.length > 0) ? {
3546
+ entries: selection.entries,
3547
+ invalid: selection.invalid,
3548
+ root: selection.rule === "compiled" ? null : selection.root
3549
+ } : null;
3550
+ if (selection?.unresolved && condition && packageName && pkgRoot) report(packageName, pkgRoot, condition);
2804
3551
  const entryKey = packageName && `.${specifier.slice(packageName.length)}`;
2805
3552
  absEntry ??= condition?.entries.find(([entry]) => entry === entryKey)?.[1] ?? null;
2806
3553
  if (!absEntry || !pkgRoot) {
2807
- outcomes.push({
3554
+ const record = {
2808
3555
  specifier,
2809
3556
  outcome: "unresolvable",
2810
3557
  fileCount: 0
3558
+ };
3559
+ const reason = caseMismatch ?? unresolvedReason?.(specifier);
3560
+ if (reason !== void 0) record.reason = reason;
3561
+ outcomes.push(record);
3562
+ continue;
3563
+ }
3564
+ const hostOutput = hostOutputDirs.find((dir) => isPathWithinRoot(dir, pkgRoot) || isPathWithinRoot(realPath(dir), realPath(pkgRoot)));
3565
+ if (hostOutput !== void 0) {
3566
+ outcomes.push({
3567
+ specifier,
3568
+ outcome: "unresolvable",
3569
+ fileCount: 0,
3570
+ reason: `the package lies inside the host's output directory ${hostOutput}, which is never source`
2811
3571
  });
2812
3572
  continue;
2813
3573
  }
3574
+ if (requireSourceEntry?.(specifier)) {
3575
+ if (!(condition && packageName ? condition.entries.some(([entry]) => entry === entryKey) : selection?.rule === "src" && sourceEntryForSpecifier(specifier, (0, path.join)(pkgRoot, "src"), extensionsSet, rootDir, extensions) !== null)) {
3576
+ outcomes.push({
3577
+ specifier,
3578
+ outcome: "unresolvable",
3579
+ fileCount: 0,
3580
+ reason: "the host does not resolve it, and the system loader finds only compiled output that no source entry redirects to — link the package into node_modules, or give it an \"animus\" source condition"
3581
+ });
3582
+ continue;
3583
+ }
3584
+ }
2814
3585
  const realRoot = realPath(pkgRoot);
3586
+ if (packageName) packageInstances[packageName] ??= realRoot;
2815
3587
  if (!describedRoots.has(realRoot)) {
2816
3588
  describedRoots.add(realRoot);
2817
3589
  const described = readKitDescriptor(pkgRoot, rootDir);
@@ -2821,10 +3593,24 @@ async function collectExternalPackageSources(opts) {
2821
3593
  const srcDir = (0, path.join)(pkgRoot, "src");
2822
3594
  let fileCount = 0;
2823
3595
  let staleDist = false;
2824
- if (packageName && !reportedPackages.has(packageName)) {
2825
- reportedPackages.add(packageName);
2826
- diagnostics.push(...sourceConditionDiagnostics(packageName, condition));
2827
- }
3596
+ if (packageName) report(packageName, pkgRoot, condition);
3597
+ const ingestOutput = (entryFile) => {
3598
+ const outputDir = (0, path.dirname)(entryFile);
3599
+ packageDirs.push(outputDir);
3600
+ if (linked) linkedDirs.push(outputDir);
3601
+ outputDirs.push(outputDir);
3602
+ claimDir(outputDir, specifier);
3603
+ onPackageResolved?.(specifier, outputDir);
3604
+ const outputExtensions = new Set(extensionsSet);
3605
+ outputExtensions.add((0, path.extname)(entryFile));
3606
+ dirExtensions[outputDir] = [...outputExtensions];
3607
+ const outputFiles = discoverFiles(outputDir, outputDir, void 0, outputExtensions).filter((file) => {
3608
+ const relToOutput = (0, path.relative)(outputDir, file);
3609
+ return !PACKAGE_OUTPUT_EXCLUDES.some((pattern) => relToOutput.includes(pattern));
3610
+ });
3611
+ if (!outputFiles.includes(entryFile)) outputFiles.unshift(entryFile);
3612
+ for (const outputFile of outputFiles) if (ingest(outputFile, specifier)) fileCount++;
3613
+ };
2828
3614
  if (condition && packageName) {
2829
3615
  for (const [entry, target] of condition.entries) {
2830
3616
  const entrySpecifier = packageName + entry.slice(1);
@@ -2832,6 +3618,7 @@ async function collectExternalPackageSources(opts) {
2832
3618
  await redirect(entrySpecifier, target, pkgRoot, () => shippedEntry(entrySpecifier, pkgRoot, entry));
2833
3619
  }
2834
3620
  packageMap[specifier] ??= (0, path.relative)(rootDir, absEntry);
3621
+ if (!condition.entries.some(([entry]) => entry === entryKey)) ingestOutput(absEntry);
2835
3622
  if (condition.root) {
2836
3623
  packageDirs.push(condition.root);
2837
3624
  if (linked) linkedDirs.push(condition.root);
@@ -2840,13 +3627,13 @@ async function collectExternalPackageSources(opts) {
2840
3627
  onPackageResolved?.(specifier, condition.root);
2841
3628
  for (const file of walkPackageSources(condition.root, extensionsSet)) if (ingest(file, specifier)) fileCount++;
2842
3629
  }
2843
- } else if ((0, fs.existsSync)(srcDir)) {
3630
+ } else if (selection === null ? (0, fs.existsSync)(srcDir) : selection.rule === "src") {
2844
3631
  packageDirs.push(srcDir);
2845
3632
  if (linked) linkedDirs.push(srcDir);
2846
3633
  claimDir(srcDir, specifier);
2847
3634
  dirExtensions[srcDir] = [...extensionsSet];
2848
3635
  onPackageResolved?.(specifier, srcDir);
2849
- const srcEntry = sourceEntryForSpecifier(specifier, srcDir, extensionsSet);
3636
+ const srcEntry = sourceEntryForSpecifier(specifier, srcDir, extensionsSet, rootDir, extensions);
2850
3637
  if (srcEntry) {
2851
3638
  packageMap[specifier] = (0, path.relative)(rootDir, srcEntry);
2852
3639
  const replaced = absEntry;
@@ -2854,7 +3641,7 @@ async function collectExternalPackageSources(opts) {
2854
3641
  } else packageMap[specifier] = (0, path.relative)(rootDir, absEntry);
2855
3642
  if (packageName) {
2856
3643
  if (packageName !== specifier && !(packageName in packageMap)) {
2857
- const rootEntry = sourceEntryForSpecifier(packageName, srcDir, extensionsSet);
3644
+ const rootEntry = sourceEntryForSpecifier(packageName, srcDir, extensionsSet, rootDir, extensions);
2858
3645
  if (rootEntry) {
2859
3646
  packageMap[packageName] = (0, path.relative)(rootDir, rootEntry);
2860
3647
  await redirect(packageName, rootEntry, pkgRoot, () => shippedEntry(packageName, pkgRoot, "."));
@@ -2865,22 +3652,8 @@ async function collectExternalPackageSources(opts) {
2865
3652
  staleDist = linked && distEntryIsStale(absEntry, srcDir, pkgFiles);
2866
3653
  for (const pkgFile of pkgFiles) if (ingest(pkgFile, specifier)) fileCount++;
2867
3654
  } else {
2868
- const outputDir = (0, path.dirname)(absEntry);
2869
- packageDirs.push(outputDir);
2870
- if (linked) linkedDirs.push(outputDir);
2871
- outputDirs.push(outputDir);
2872
- claimDir(outputDir, specifier);
2873
- onPackageResolved?.(specifier, outputDir);
2874
3655
  packageMap[specifier] = (0, path.relative)(rootDir, absEntry);
2875
- const outputExtensions = new Set(extensionsSet);
2876
- outputExtensions.add((0, path.extname)(absEntry));
2877
- dirExtensions[outputDir] = [...outputExtensions];
2878
- const outputFiles = discoverFiles(outputDir, outputDir, void 0, outputExtensions).filter((file) => {
2879
- const relToOutput = (0, path.relative)(outputDir, file);
2880
- return !PACKAGE_OUTPUT_EXCLUDES.some((pattern) => relToOutput.includes(pattern));
2881
- });
2882
- if (!outputFiles.includes(absEntry)) outputFiles.unshift(absEntry);
2883
- for (const outputFile of outputFiles) if (ingest(outputFile, specifier)) fileCount++;
3656
+ ingestOutput(absEntry);
2884
3657
  }
2885
3658
  if (packageName) for (const [subpath, target] of packageExportEntries(pkgRoot)) {
2886
3659
  const entrySpecifier = packageName + subpath.slice(1);
@@ -2888,6 +3661,16 @@ async function collectExternalPackageSources(opts) {
2888
3661
  if (entrySpecifier in packageMap || !alreadyIngested(targetRelPath)) continue;
2889
3662
  packageMap[entrySpecifier] = targetRelPath;
2890
3663
  }
3664
+ const ownManifest = readPackageManifest(pkgRoot);
3665
+ const hostName = isJsonBlock(ownManifest) ? ownManifest.name : void 0;
3666
+ if (packageName && locatedRoot && realPath(pkgRoot) !== locatedRoot && isJsonString(hostName) && hostName !== "" && hostName !== packageName) for (const [key, entry] of [...sourceEntries]) {
3667
+ if (key !== packageName && !key.startsWith(`${packageName}/`)) continue;
3668
+ const hostKey = hostName + key.slice(packageName.length);
3669
+ if (sourceEntries.has(hostKey)) continue;
3670
+ sourceEntries.set(hostKey, entry);
3671
+ const sideEffects = sourceEntrySideEffects.get(key);
3672
+ if (sideEffects !== void 0) sourceEntrySideEffects.set(hostKey, sideEffects);
3673
+ }
2891
3674
  outcomes.push({
2892
3675
  specifier,
2893
3676
  outcome: staleDist ? "stale-dist" : fileCount > 0 ? "resolved" : "empty",
@@ -2907,7 +3690,8 @@ async function collectExternalPackageSources(opts) {
2907
3690
  fileOwners,
2908
3691
  outcomes,
2909
3692
  diagnostics: [...diagnostics, ...noKitFilesDiagnostics(outcomes)],
2910
- kitDescriptors
3693
+ kitDescriptors,
3694
+ packageInstances
2911
3695
  };
2912
3696
  }
2913
3697
  /** The dependency names a manifest lists in `fields`. */
@@ -2920,14 +3704,22 @@ function dependencyNames(manifest, fields) {
2920
3704
  }
2921
3705
  return [...names];
2922
3706
  }
3707
+ /** Whether the package at `pkgRoot` declares the kit source condition, as
3708
+ * the system loader's table reads its manifest: an `animus` key anywhere in
3709
+ * its `exports`, on any entry, subpath or pattern, valid or not. */
3710
+ function declaresKitSource(engine, pkgRoot) {
3711
+ if (engine.declaresKitSource === void 0) throw new Error("the native engine does not expose declaresKitSource, which kit discovery needs — rebuild @animus-ui/extract");
3712
+ return engine.declaresKitSource(pkgRoot);
3713
+ }
2923
3714
  /** The source kits the application at `rootDir` declares as dependencies.
2924
3715
  * A bundler serves an installed one as compiled code unless told
2925
3716
  * otherwise: Next keeps it external on the server unless it is in
2926
3717
  * `transpilePackages`, and Vite's optimizer prebundles it. */
2927
- function sourceKitDependencies(rootDir) {
3718
+ function sourceKitDependencies(rootDir, engine) {
3719
+ const locatePackage = nativePackageLocator(engine, declaredWorkspacePackages(rootDir));
2928
3720
  return dependencyNames(readPackageManifest(rootDir), ["dependencies", "devDependencies"]).flatMap((name) => {
2929
- const pkgRoot = locatePackageRoot(name, rootDir);
2930
- if (pkgRoot === null || readKitSourceCondition(pkgRoot) === null) return [];
3721
+ const pkgRoot = locatePackage(name, rootDir);
3722
+ if (pkgRoot === null || !declaresKitSource(engine, pkgRoot)) return [];
2931
3723
  return [{
2932
3724
  name,
2933
3725
  installed: isInstalledPackage(pkgRoot),
@@ -2935,6 +3727,34 @@ function sourceKitDependencies(rootDir) {
2935
3727
  }];
2936
3728
  });
2937
3729
  }
3730
+ /**
3731
+ * The installed packages a system's membership reaches: each is a kit,
3732
+ * whether or not it declares the source condition, and so is every kit its
3733
+ * own system extends or includes. Read before any host resolves (a
3734
+ * bundler's config), so the application's modules import as the system
3735
+ * loader resolves them from the root, and a kit's from its own directory.
3736
+ */
3737
+ async function systemKitDependencies(rootDir, systemPath, engine) {
3738
+ const workspaces = declaredWorkspacePackages(rootDir);
3739
+ const resolveSpecifier = engine.resolveSpecifier;
3740
+ const systemPackageRoot = findPackageRoot(systemPath);
3741
+ const kitMembers = /* @__PURE__ */ new Map();
3742
+ const members = await extractSystemFilePackages(systemPath, engine, void 0, (specifier, importer) => resolveSpecifier?.(specifier, findPackageRoot(importer) === systemPackageRoot ? rootDir : (0, path.dirname)(importer), [], workspaces, extensionPolicyJson(BUILT_IN_EXTENSION_POLICY))?.path ?? null, void 0, kitMembers);
3743
+ const locatePackage = nativePackageLocator(engine, workspaces);
3744
+ const roots = /* @__PURE__ */ new Map();
3745
+ for (const member of members) {
3746
+ if (!isPackageSpecifier(member)) continue;
3747
+ const name = bareSpecifierPackageName(member);
3748
+ const file = kitMembers.get(member);
3749
+ const pkgRoot = file ? findPackageRoot(file) : locatePackage(name, rootDir);
3750
+ if (pkgRoot !== null && !roots.has(name)) roots.set(name, pkgRoot);
3751
+ }
3752
+ return [...roots].map(([name, pkgRoot]) => ({
3753
+ name,
3754
+ installed: isInstalledPackage(pkgRoot),
3755
+ dependencies: dependencyNames(readPackageManifest(pkgRoot), ["dependencies"])
3756
+ }));
3757
+ }
2938
3758
  /** A specifier that names a package: not relative or absolute, and no URL,
2939
3759
  * scheme (`node:`, `virtual:`), subpath import or virtual id. */
2940
3760
  function isPackageSpecifier(specifier) {
@@ -2950,22 +3770,19 @@ function isPackageSpecifier(specifier) {
2950
3770
  * file the engine parses as it is; an adapted source (`.svelte`, `.mdx`)
2951
3771
  * reaches the engine only as its generated children.
2952
3772
  */
2953
- function importedKitDiagnostics(files, engine, rootDir, systemKits) {
2954
- const { extractFacts } = engine;
2955
- const parsed = files.filter(({ path: path$4 }) => isEngineTransformExtension(path$4));
2956
- if (!extractFacts || parsed.length === 0) return [];
3773
+ function importedKitDiagnostics(files, engine, rootDir, systemKits, factsOf) {
3774
+ const parsed = files.filter(({ path: path$3 }) => isEngineTransformExtension(path$3));
3775
+ if (parsed.length === 0) return [];
3776
+ const locatePackage = nativePackageLocator(engine, declaredWorkspacePackages(rootDir));
2957
3777
  let facts;
2958
3778
  try {
2959
- facts = parseInternalWire(extractFacts(JSON.stringify(parsed.map(({ path: path$5, source }) => ({
2960
- path: path$5,
2961
- source
2962
- })))), "extractFacts");
3779
+ facts = factsOf(parsed);
2963
3780
  } catch {
2964
3781
  return [];
2965
3782
  }
2966
3783
  const seen = new Set(systemKits.filter((specifier) => !(0, path.isAbsolute)(specifier)).map(bareSpecifierPackageName));
2967
3784
  const diagnostics = [];
2968
- for (const [path$6, file] of Object.entries(facts.files)) {
3785
+ for (const [path$4, file] of Object.entries(facts.files)) {
2969
3786
  if (file.parsePanicked) continue;
2970
3787
  const specifiers = [...file.imports.map((fact) => fact.source), ...file.exports.flatMap((fact) => fact.source === null ? [] : [fact.source])];
2971
3788
  for (const specifier of specifiers) {
@@ -2973,9 +3790,9 @@ function importedKitDiagnostics(files, engine, rootDir, systemKits) {
2973
3790
  const name = bareSpecifierPackageName(specifier);
2974
3791
  if (seen.has(name)) continue;
2975
3792
  seen.add(name);
2976
- const pkgRoot = locatePackageRoot(name, (0, path.dirname)((0, path.resolve)(rootDir, path$6)));
2977
- if (pkgRoot && readKitSourceCondition(pkgRoot)) diagnostics.push({
2978
- file: path$6,
3793
+ const pkgRoot = locatePackage(name, (0, path.dirname)((0, path.resolve)(rootDir, path$4)));
3794
+ if (pkgRoot && declaresKitSource(engine, pkgRoot)) diagnostics.push({
3795
+ file: path$4,
2979
3796
  component: name,
2980
3797
  kind: "warn",
2981
3798
  message: `the application imports this kit, but its system is not included in the application's system, so its components are not extracted — include the kit's system in the application's system: createSystem().extend(<the kit's system>)`,
@@ -2987,7 +3804,19 @@ function importedKitDiagnostics(files, engine, rootDir, systemKits) {
2987
3804
  return diagnostics;
2988
3805
  }
2989
3806
  /** A kit without the source condition, warned once, or each condition entry
2990
- * whose target is missing or outside the package. */
3807
+ * the loader does not read as source: missing, spelled otherwise on disk,
3808
+ * no package target Node accepts (each read from its runtime target), or
3809
+ * percent-escaped (refused, failing the load). */
3810
+ function packageMismatchDiagnostic(specifier, hostEntry, located) {
3811
+ return {
3812
+ file: specifier,
3813
+ component: "kit",
3814
+ kind: "warn",
3815
+ message: `the host bundler resolves '${specifier}' to ${hostEntry}, which lies in no package, so discovery reads the installed package at ${located} instead and the bundle may render another module than the one analysed — make the bundler resolve '${specifier}' to a package`,
3816
+ code: PACKAGE_MISMATCH,
3817
+ severity: severityFor(PACKAGE_MISMATCH)
3818
+ };
3819
+ }
2991
3820
  function sourceConditionDiagnostics(packageName, condition) {
2992
3821
  if (condition === null) return [{
2993
3822
  file: packageName,
@@ -2997,11 +3826,11 @@ function sourceConditionDiagnostics(packageName, condition) {
2997
3826
  code: KIT_WITHOUT_SOURCE_CONDITION,
2998
3827
  severity: severityFor(KIT_WITHOUT_SOURCE_CONDITION)
2999
3828
  }];
3000
- return condition.invalid.map(([subpath, target]) => ({
3829
+ return condition.invalid.map(([subpath, target, why]) => ({
3001
3830
  file: packageName,
3002
3831
  component: "kit",
3003
3832
  kind: "warn",
3004
- message: `exports["${subpath}"].${KIT_SOURCE_CONDITION} names ${target}, which is missing or outside the package, so that entry is not read from source`,
3833
+ message: why.includes("percent-escape unsupported") ? `exports["${subpath}"].${KIT_SOURCE_CONDITION} names ${target}, which ${why}, so the system loader fails to load that entry` : `exports["${subpath}"].${KIT_SOURCE_CONDITION} names ${target}, which ${why}, so that entry is read from its runtime target instead of source`,
3005
3834
  code: INVALID_KIT_SOURCE_CONDITION,
3006
3835
  severity: severityFor(INVALID_KIT_SOURCE_CONDITION)
3007
3836
  }));
@@ -3058,13 +3887,16 @@ function excludeCollectedPackages(collected, rejectedSpecifiers, rootDir) {
3058
3887
  fileOwners,
3059
3888
  outcomes: collected.outcomes,
3060
3889
  diagnostics: collected.diagnostics,
3061
- kitDescriptors: collected.kitDescriptors.filter((record) => !rejectedDirs.some((dir) => isPathWithinRoot((0, path.resolve)(rootDir, record.packageRoot), dir)))
3890
+ kitDescriptors: collected.kitDescriptors.filter((record) => !rejectedDirs.some((dir) => isPathWithinRoot((0, path.resolve)(rootDir, record.packageRoot), dir))),
3891
+ packageInstances: Object.fromEntries(Object.entries(collected.packageInstances).filter(([, root]) => !rejectedDirs.some((dir) => isPathWithinRoot(root, dir))))
3062
3892
  };
3063
3893
  }
3064
- function unresolvableIncludesMessage(outcomes) {
3065
- const unresolvable = outcomes.filter((record) => record.outcome === "unresolvable").map((record) => record.specifier);
3894
+ /** Every unresolvable include, with why where the resolver said, and the
3895
+ * system file that includes them when the caller knows it. */
3896
+ function unresolvableIncludesMessage(outcomes, importer) {
3897
+ const unresolvable = outcomes.filter((record) => record.outcome === "unresolvable").map((record) => record.reason === void 0 ? record.specifier : `${record.specifier} (${record.reason})`);
3066
3898
  if (unresolvable.length === 0) return null;
3067
- return `[animus-extract] unresolvable include specifier(s): ${unresolvable.join(", ")}`;
3899
+ return `[animus-extract] unresolvable include specifier(s)${importer === void 0 ? "" : ` in ${importer}`}: ${unresolvable.join(", ")}`;
3068
3900
  }
3069
3901
  /** A stale dist silently skews merged registry content while discovery
3070
3902
  * compiles the fresh sources; null when no specifier is stale. */
@@ -3079,12 +3911,12 @@ function staleDistIncludesMessage(outcomes) {
3079
3911
  function engineModuleParser(engine) {
3080
3912
  const { extractFacts } = engine;
3081
3913
  if (!extractFacts) return void 0;
3082
- return (source, path$7) => {
3914
+ return (source, path$5) => {
3083
3915
  try {
3084
3916
  const facts = parseInternalWire(extractFacts(JSON.stringify([{
3085
- path: path$7,
3917
+ path: path$5,
3086
3918
  source
3087
- }])), "extractFacts").files[path$7];
3919
+ }])), "extractFacts").files[path$5];
3088
3920
  return facts && !facts.parsePanicked ? {
3089
3921
  imports: facts.imports,
3090
3922
  exports: facts.exports,
@@ -3095,178 +3927,24 @@ function engineModuleParser(engine) {
3095
3927
  }
3096
3928
  };
3097
3929
  }
3098
- const ANIMUS_SYSTEM_SPECIFIER = /^@animus-ui\/system(?:\/.*)?$/;
3099
- /** The file a specifier names from `importer`: a relative one by the
3100
- * ingestion's probe order, a bare one by the host's package resolution. */
3101
- async function resolveModuleFile(importer, specifier, resolvePackage) {
3102
- if (specifier.startsWith(".")) return relativeSourceCandidates(importer, specifier).find(isFile$1) ?? null;
3103
- try {
3104
- return await resolvePackage?.(specifier) ?? null;
3105
- } catch {
3106
- return null;
3930
+ /** The file a specifier names from `importer`, or why it names none: a
3931
+ * relative one by the ingestion's probe order, spelled exactly, a bare one
3932
+ * by the host's package resolution. */
3933
+ async function resolveModuleFile(importer, specifier, resolvePackage, extensions) {
3934
+ const unresolved = { why: `'${specifier}' could not be resolved` };
3935
+ if (specifier.startsWith(".")) {
3936
+ const probed = probeOnDisk(relativeSourceCandidates(importer, specifier, extensions), (0, path.dirname)(importer));
3937
+ if (probed.kind === "found") return { file: probed.path };
3938
+ return probed.kind === "case-mismatch" ? {
3939
+ why: caseMismatchReason(`'${specifier}'`, probed, "spell the import as the file is spelled"),
3940
+ caseMismatch: true
3941
+ } : unresolved;
3107
3942
  }
3108
- }
3109
- const escapeRegExp$1 = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3110
- /**
3111
- * Follows `name`, exported by the module `specifier` names from `importer`,
3112
- * through re-exports to its declaration. It is Animus's factory only when
3113
- * that is `createSystem` of `@animus-ui/system`, and another identity only
3114
- * when a module is shown to declare it; anything discovery cannot follow is
3115
- * unknown.
3116
- */
3117
- async function exportIdentity(importer, specifier, name, following, seen) {
3118
- if (ANIMUS_SYSTEM_SPECIFIER.test(specifier)) return name === "createSystem" ? { kind: "animus" } : {
3119
- kind: "other",
3120
- what: `'${name}' of ${specifier}`
3121
- };
3122
- const file = await resolveModuleFile(importer, specifier, following.resolvePackage);
3123
- if (file === null) return {
3124
- kind: "unknown",
3125
- why: `'${specifier}' could not be resolved`
3126
- };
3127
- const key = `${file}#${name}`;
3128
- if (seen.has(key)) return {
3129
- kind: "unknown",
3130
- why: `'${specifier}' re-exports it in a cycle`
3131
- };
3132
- seen.add(key);
3133
- let source;
3134
3943
  try {
3135
- source = (0, fs.readFileSync)(file, "utf-8");
3944
+ const file = await resolvePackage?.(specifier, importer);
3945
+ return file ? { file: file.split("?")[0] } : unresolved;
3136
3946
  } catch {
3137
- return {
3138
- kind: "unknown",
3139
- why: `'${specifier}' could not be read`
3140
- };
3141
- }
3142
- const record = following.parseModule(source, file);
3143
- if (record === null) return {
3144
- kind: "unknown",
3145
- why: `'${specifier}' could not be parsed`
3146
- };
3147
- const exported = record.exports.find((entry) => entry.exported === name);
3148
- if (exported?.source) return exportIdentity(file, exported.source, exported.original ?? name, following, seen);
3149
- const local = exported?.local ?? name;
3150
- const imported = record.imports.find((entry) => entry.local === local);
3151
- if (exported && imported) return exportIdentity(file, imported.source, imported.imported, following, seen);
3152
- if (exported || new RegExp(`\\bexport\\s+(?:async\\s+)?(?:function\\*?|class|const|let|var)\\s+${escapeRegExp$1(name)}\\b`).test(source)) return {
3153
- kind: "other",
3154
- what: `the '${name}' that '${specifier}' declares`
3155
- };
3156
- const stars = [];
3157
- for (const match of source.matchAll(/\bexport\s*\*\s*from\s*['"]([^'"]+)['"]/g)) stars.push(await exportIdentity(file, match[1], name, following, seen));
3158
- const definite = stars.filter((identity) => identity.kind !== "unknown");
3159
- if (definite.length === 1) return definite[0];
3160
- if (definite.length > 1) return {
3161
- kind: "unknown",
3162
- why: `more than one \`export *\` of '${specifier}' provides '${name}'`
3163
- };
3164
- return stars.find((identity) => identity.kind === "unknown") ?? {
3165
- kind: "unknown",
3166
- why: `'${specifier}' has no export '${name}' discovery can read`
3167
- };
3168
- }
3169
- /** 1-based line and column of `offset` in `source`. */
3170
- function locationIn(source, offset) {
3171
- const before = source.slice(0, offset);
3172
- const lineStart = before.lastIndexOf("\n") + 1;
3173
- return {
3174
- line: before.split("\n").length,
3175
- column: offset - lineStart + 1
3176
- };
3177
- }
3178
- const NAMESPACE_IMPORT = /\bimport\s+(?:[a-zA-Z_$][a-zA-Z0-9_$]*\s*,\s*)?\*\s*as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s+from\s+['"]([^'"]+)['"]/g;
3179
- /**
3180
- * The callees that are Animus's `createSystem` in a parsed system file. A
3181
- * binding counts once its identity is followed to the factory: a named
3182
- * import, through local and package re-exports; a namespace import's
3183
- * member; or a property destructured from a namespace import, `require` or
3184
- * `import()` of a module. A binding named `createSystem` shown to be
3185
- * something else is no root. One whose identity discovery cannot follow
3186
- * keeps the admission spelling gave it, so a resolution limit never drops a
3187
- * kit. Both are reported. A call of the bare name, which the file neither
3188
- * imports nor declares, is no root: the system loader evaluates the file
3189
- * without auto-imports, where the name is undefined. It is reported once.
3190
- */
3191
- async function systemRoots(systemFilePath, source, record, following) {
3192
- const { imports } = record;
3193
- const roots = /* @__PURE__ */ new Set();
3194
- const identityOf = (specifier, name) => exportIdentity(systemFilePath, specifier, name, following, /* @__PURE__ */ new Set());
3195
- const called = (callee) => callOf(callee).test(source);
3196
- /** Admits a binding named `createSystem` by its identity: an unknown one
3197
- * keeps `spellingAdmits`, and every unproven one is reported. */
3198
- const admit = (local, offset, identity, spellingAdmits) => {
3199
- if (identity.kind === "animus") {
3200
- roots.add(local);
3201
- return;
3202
- }
3203
- if (identity.kind === "unknown" && spellingAdmits) roots.add(local);
3204
- const shown = identity.kind === "other" ? `it is ${identity.what}, so it is not read as a system root` : `discovery cannot follow what it is bound to (${identity.why}), so it is ${spellingAdmits ? "still read" : "not read"} as a system root by its name alone`;
3205
- following.report?.({
3206
- file: systemFilePath,
3207
- component: local,
3208
- kind: "warn",
3209
- message: `'${local}' is not proven to be Animus's createSystem: ${shown} — import createSystem from '@animus-ui/system', directly or through a re-export discovery can follow`,
3210
- code: UNPROVEN_ROOT_BINDING,
3211
- severity: severityFor(UNPROVEN_ROOT_BINDING),
3212
- ...locationIn(source, offset)
3213
- });
3214
- };
3215
- for (const binding of imports) {
3216
- if (binding.imported === "createSystem" || binding.local === "createSystem") {
3217
- const statement = new RegExp(`\\bimport\\b[^;]*?\\bfrom\\s*['"]${escapeRegExp$1(binding.source)}['"]`, "g");
3218
- let offset = 0;
3219
- for (const match of source.matchAll(statement)) {
3220
- const at = match[0].search(new RegExp(`(?<![a-zA-Z0-9_$])${escapeRegExp$1(binding.local)}\\b`));
3221
- if (at !== -1) {
3222
- offset = match.index + at;
3223
- break;
3224
- }
3225
- }
3226
- admit(binding.local, offset, await identityOf(binding.source, binding.imported), binding.imported === "createSystem");
3227
- continue;
3228
- }
3229
- if (binding.source.startsWith(".") && called(binding.local) && (await identityOf(binding.source, binding.imported)).kind === "animus") roots.add(binding.local);
3230
- }
3231
- const namespaces = /* @__PURE__ */ new Map();
3232
- for (const [, namespace, specifier] of source.matchAll(NAMESPACE_IMPORT)) {
3233
- namespaces.set(namespace, specifier);
3234
- const member = `${namespace}.createSystem`;
3235
- if (ANIMUS_SYSTEM_SPECIFIER.test(specifier) || specifier.startsWith(".") && called(member) && (await identityOf(specifier, "createSystem")).kind === "animus") roots.add(member);
3236
- }
3237
- const destructuredFrom = (initializer) => {
3238
- const loaded = /^\(?\s*(?:(?:await\s+)?import|require)\(\s*['"]([^'"]+)['"]\s*\)\s*\)?$/.exec(initializer);
3239
- if (loaded) return identityOf(loaded[1], "createSystem");
3240
- const namespace = namespaces.get(initializer);
3241
- if (namespace !== void 0) return identityOf(namespace, "createSystem");
3242
- return Promise.resolve({
3243
- kind: "unknown",
3244
- why: `it is destructured from '${initializer}', which is not a module namespace`
3245
- });
3246
- };
3247
- for (const { local, offset, initializer } of destructuredCreateSystems(source)) admit(local, offset, await destructuredFrom(initializer), local === "createSystem");
3248
- const unimported = unimportedCreateSystemCall(systemFilePath, record);
3249
- if (unimported) following.report?.(unimported);
3250
- return roots;
3251
- }
3252
- /** A call of `callee` as a whole name, not a member. */
3253
- function callOf(callee) {
3254
- return new RegExp(`(?<![a-zA-Z0-9_$.])${escapeRegExp$1(callee)}\\s*\\(`);
3255
- }
3256
- /** Each `createSystem` property a declaration destructures: its local name,
3257
- * its offset in `source`, and the destructured initializer. */
3258
- function* destructuredCreateSystems(source) {
3259
- for (const match of source.matchAll(/\b(?:const|let|var)\s*\{([^}]*)\}\s*=\s*([^;\n]+)/g)) {
3260
- const [whole, pattern, initializer] = match;
3261
- for (const property of pattern.split(",")) {
3262
- const binding = /^\s*createSystem\s*(?::\s*([a-zA-Z_$][a-zA-Z0-9_$]*))?\s*(?:=[\s\S]*)?$/.exec(property);
3263
- if (!binding) continue;
3264
- yield {
3265
- local: binding[1] ?? "createSystem",
3266
- offset: match.index + whole.indexOf("createSystem"),
3267
- initializer: initializer.trim()
3268
- };
3269
- }
3947
+ return unresolved;
3270
3948
  }
3271
3949
  }
3272
3950
  /** The warning for a `createSystem` call that the parser's scopes leave
@@ -3286,229 +3964,427 @@ function unimportedCreateSystemCall(systemFilePath, record) {
3286
3964
  column: call[1]
3287
3965
  };
3288
3966
  }
3289
- /** A pattern matching a call of any of `callees` as a whole name, or null
3290
- * when there is none to anchor on. */
3291
- function rootCallPattern(callees) {
3292
- if (callees.length === 0) return null;
3293
- return `(?<![a-zA-Z0-9_$.])(?:${callees.map((callee) => callee.replace(/[.$]/g, "\\$&")).join("|")})`;
3294
- }
3295
- async function extractSystemFilePackages(systemFilePath, parseModule, report, resolvePackage) {
3296
- let source;
3967
+ /** The rounds a membership read resolves the modules it asks for: each
3968
+ * reads the modules the last one's identities stopped at, one re-export
3969
+ * hop further. Past it, what is still asked for is finalized as
3970
+ * unresolved and read once more, so an identity it could not follow keeps
3971
+ * the admission its name gives it, with a finding. */
3972
+ const MEMBERSHIP_ROUNDS = 256;
3973
+ /**
3974
+ * The packages and local modules a system file's roots extend or include,
3975
+ * from the engine's own read of it (spec §2.3 step 5): a bare specifier as
3976
+ * its import spells it, a relative one resolved against the system file.
3977
+ * The engine follows each root binding's identity through the modules this
3978
+ * supplies on request: a relative one by the host's extension order,
3979
+ * spelled exactly, a bare one by the host's package resolution.
3980
+ */
3981
+ async function extractSystemFilePackages(systemFilePath, engine, report, resolvePackage, extensions, kitMembers) {
3982
+ const { systemMembership } = engine;
3983
+ if (systemMembership === void 0) throw new Error("the native engine does not expose systemMembership, which discovery needs — rebuild @animus-ui/extract");
3984
+ const files = {};
3297
3985
  try {
3298
- source = (0, fs.readFileSync)(systemFilePath, "utf-8");
3986
+ files[systemFilePath] = (0, fs.readFileSync)(systemFilePath, "utf-8");
3299
3987
  } catch {
3300
3988
  return [];
3301
3989
  }
3302
- const parsed = parseModule?.(source, systemFilePath) ?? null;
3303
- let rootCall = "createSystem";
3304
- if (parseModule && parsed) rootCall = rootCallPattern([...await systemRoots(systemFilePath, source, parsed, {
3305
- parseModule,
3306
- resolvePackage,
3307
- report
3308
- })]);
3309
- const identifiers = /* @__PURE__ */ new Set();
3310
- const constructorRegex = rootCall === null ? null : new RegExp(`${rootCall}\\s*\\(\\s*\\{[^}]*?\\bincludes\\s*:\\s*\\[([^\\]]*)\\]`, "gs");
3311
- const chainRegex = /\.includes\s*\(\s*\[([^\]]*)\]\s*\)/gs;
3312
- const collectIdentifiers = (regex) => {
3313
- let match;
3314
- while ((match = regex.exec(source)) !== null) {
3315
- const inner = match[1];
3316
- for (const token of inner.split(",")) {
3317
- const id = token.trim();
3318
- if (id && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(id)) identifiers.add(id);
3319
- }
3990
+ const resolved = {};
3991
+ let answer;
3992
+ for (let round = 0;; round++) {
3993
+ answer = parseInternalWire(systemMembership(JSON.stringify({
3994
+ system: systemFilePath,
3995
+ files,
3996
+ resolved
3997
+ })), "systemMembership");
3998
+ if (answer.needs.length === 0) break;
3999
+ for (const [importer, specifier] of answer.needs) {
4000
+ const key = `${importer}\0${specifier}`;
4001
+ const found = round >= MEMBERSHIP_ROUNDS ? { why: `following '${specifier}' stopped after ${MEMBERSHIP_ROUNDS} re-exports` } : await resolveModuleFile(importer, specifier, resolvePackage, extensions);
4002
+ if ("file" in found) {
4003
+ resolved[key] = { file: found.file };
4004
+ if (!(found.file in files)) try {
4005
+ files[found.file] = (0, fs.readFileSync)(found.file, "utf-8");
4006
+ } catch {}
4007
+ } else resolved[key] = {
4008
+ why: found.why,
4009
+ caseMismatch: found.caseMismatch
4010
+ };
3320
4011
  }
3321
- };
3322
- if (constructorRegex) collectIdentifiers(constructorRegex);
3323
- collectIdentifiers(chainRegex);
3324
- const IDENT_START_RE = /^[a-zA-Z_$][a-zA-Z0-9_$]*/;
3325
- const skipTrivia = (from) => {
3326
- let pos = from;
3327
- for (;;) {
3328
- while (pos < source.length && /\s/.test(source[pos])) pos++;
3329
- if (source.startsWith("//", pos)) {
3330
- const newline = source.indexOf("\n", pos);
3331
- pos = newline === -1 ? source.length : newline + 1;
3332
- continue;
3333
- }
3334
- if (source.startsWith("/*", pos)) {
3335
- const close = source.indexOf("*/", pos + 2);
3336
- pos = close === -1 ? source.length : close + 2;
3337
- continue;
3338
- }
3339
- return pos;
4012
+ }
4013
+ if (!answer.parsed) return [];
4014
+ const reportedUnimported = /* @__PURE__ */ new Set();
4015
+ for (const finding of answer.findings) {
4016
+ if (finding.kind === "unimported") {
4017
+ if (reportedUnimported.has(finding.file)) continue;
4018
+ reportedUnimported.add(finding.file);
4019
+ report?.({
4020
+ file: finding.file,
4021
+ component: "createSystem",
4022
+ kind: "warn",
4023
+ message: `'createSystem' is called with no import or local binding, so it is not read as a system root: the system loader evaluates this file without auto-imports, where the name is undefined — import createSystem from '@animus-ui/system'`,
4024
+ code: UNIMPORTED_CREATE_SYSTEM,
4025
+ severity: severityFor(UNIMPORTED_CREATE_SYSTEM),
4026
+ line: finding.line,
4027
+ column: finding.column
4028
+ });
4029
+ continue;
4030
+ }
4031
+ if (finding.kind === "escapes") {
4032
+ report?.({
4033
+ file: finding.file,
4034
+ component: "createSystem",
4035
+ kind: "warn",
4036
+ message: `a system builder leaves what discovery follows here (${finding.how}), so a kit extended on it from there is not read as a member and its components are not extracted — extend it in the chain that creates it, or through a variable`,
4037
+ code: UNFOLLOWED_SYSTEM_BUILDER,
4038
+ severity: severityFor(UNFOLLOWED_SYSTEM_BUILDER),
4039
+ line: finding.line,
4040
+ column: finding.column
4041
+ });
4042
+ continue;
3340
4043
  }
4044
+ const shown = finding.what !== null ? `it is ${finding.what}, so it is not read as a system root` : `discovery cannot follow what it is bound to (${finding.why}), so it is ${finding.admitted ? "still read" : "not read"} as a system root by its name alone`;
4045
+ report?.({
4046
+ file: finding.file,
4047
+ component: finding.local,
4048
+ kind: "warn",
4049
+ message: `'${finding.local}' is not proven to be Animus's createSystem: ${shown} — import createSystem from '@animus-ui/system', directly or through a re-export discovery can follow`,
4050
+ code: UNPROVEN_ROOT_BINDING,
4051
+ severity: severityFor(UNPROVEN_ROOT_BINDING),
4052
+ line: finding.line,
4053
+ column: finding.column
4054
+ });
4055
+ }
4056
+ const systemPackageRoot = findPackageRoot(systemFilePath);
4057
+ for (const { specifier, importer } of answer.members) {
4058
+ const file = resolved[`${importer}\0${specifier}`]?.file;
4059
+ if (file !== void 0 && !specifier.startsWith(".") && findPackageRoot(importer) !== systemPackageRoot && !kitMembers?.has(specifier)) kitMembers?.set(specifier, file);
4060
+ }
4061
+ return [...new Set(answer.members.map(({ specifier, importer }) => specifier.startsWith(".") ? (0, path.resolve)((0, path.dirname)(importer), specifier) : specifier))];
4062
+ }
4063
+ //#endregion
4064
+ //#region pipeline/alias-agreement.ts
4065
+ /** A file's identity on disk: its real path, which follows links and
4066
+ * takes the case the filesystem lists; the path itself where it is not
4067
+ * there. */
4068
+ function physical(file) {
4069
+ try {
4070
+ return node_fs.realpathSync.native(file);
4071
+ } catch {
4072
+ return (0, node_path.resolve)(file);
4073
+ }
4074
+ }
4075
+ /** What a host's module id names: a file on disk, its query dropped and a
4076
+ * dev server's `/@fs/` prefix removed; a virtual id as written; or no
4077
+ * file, where the id names a path nothing is at (an alias applied to a
4078
+ * missing module). */
4079
+ function hostTarget(id) {
4080
+ const path = id.split("?")[0];
4081
+ const file = path.startsWith("/@fs/") ? path.slice(4) : path;
4082
+ if (id.startsWith("\0") || !(0, node_path.isAbsolute)(file)) return { virtual: id };
4083
+ return (0, node_fs.existsSync)(file) ? { file } : null;
4084
+ }
4085
+ /** What a session's comparisons keep between analyses (spec §2.2 A7):
4086
+ * each file's result by its content hash, while the aliases and the file
4087
+ * set are the same. A new alias set, or a file added or removed, compares
4088
+ * every file again. */
4089
+ var AliasAgreementCache = class {
4090
+ scope = "";
4091
+ byFile = /* @__PURE__ */ new Map();
4092
+ };
4093
+ function packageReadRecord(input) {
4094
+ let analysed = null;
4095
+ const rendered = /* @__PURE__ */ new Map();
4096
+ return {
4097
+ rootDir: input.rootDir,
4098
+ roots: input.roots,
4099
+ redirected: input.redirected,
4100
+ holds(file) {
4101
+ analysed ??= new Set(input.analysed.map((path) => physical((0, node_path.join)(input.rootDir, path))));
4102
+ return analysed.has(file);
4103
+ },
4104
+ rendersBuilder(file) {
4105
+ let renders = rendered.get(file);
4106
+ if (renders === void 0) {
4107
+ renders = input.rendersBuilder(file);
4108
+ rendered.set(file, renders);
4109
+ }
4110
+ return renders;
4111
+ },
4112
+ reported: /* @__PURE__ */ new Set()
3341
4113
  };
3342
- /** The index after the string literal opening at `from`. */
3343
- const skipString = (from) => {
3344
- const quote = source[from];
3345
- let pos = from + 1;
3346
- while (pos < source.length && source[pos] !== quote) pos += source[pos] === "\\" ? 2 : 1;
3347
- return pos + 1;
4114
+ }
4115
+ /**
4116
+ * An import of a discovered package that the host resolves, from its
4117
+ * importer, to `resolved` (spec §2.2 A4). None where the analysis holds
4118
+ * that file, or the request is not a discovered package's. Otherwise the
4119
+ * importer would render a file extraction never read:
4120
+ * - another instance's: unextracted builder code
4121
+ * (`animus.discovery.unread-package-instance`), or, where a source
4122
+ * redirect serves the instance read in its place, that instance
4123
+ * (`animus.discovery.replaced-package-instance`);
4124
+ * - a file of the instance read that the analysis does not hold, and no
4125
+ * redirect covers, which declares builder chains (a compiled subpath):
4126
+ * `animus.discovery.unread-package-instance`.
4127
+ */
4128
+ function packageInstanceFinding(record, importer, specifier, resolved) {
4129
+ const readRoot = isPackageSpecifier(specifier) ? record.roots[bareSpecifierPackageName(specifier)] : void 0;
4130
+ if (readRoot === void 0) return null;
4131
+ const file = physical(resolved);
4132
+ if (record.holds(file)) return null;
4133
+ const instance = physical(findPackageRoot(file));
4134
+ const redirected = record.redirected.has(specifier);
4135
+ const shown = (path) => (0, node_path.relative)(record.rootDir, path).split(node_path.sep).join(node_path.posix.sep);
4136
+ const finding = (code, message) => ({
4137
+ file: importer,
4138
+ component: `import '${specifier}'`,
4139
+ kind: code === "animus.discovery.replaced-package-instance" ? "warn" : "error",
4140
+ message,
4141
+ code,
4142
+ severity: severityFor(code)
4143
+ });
4144
+ if (instance === readRoot) {
4145
+ if (redirected || !record.rendersBuilder(file)) return null;
4146
+ return finding(UNREAD_PACKAGE_INSTANCE, `'${specifier}' in ${importer} resolves through the host bundler to ${shown(file)}, a file of the package extraction reads (${shown(readRoot)}) that it does not analyse, and which declares builder chains, so this importer would render unextracted builder code — import the package by an entry extraction reads, or give this entry an "animus" source condition`);
4147
+ }
4148
+ const where = `'${specifier}' in ${importer} resolves through the host bundler to ${shown(file)}, in another instance of the package (${shown(instance)}) than extraction reads (${shown(readRoot)})`;
4149
+ return redirected ? finding(REPLACED_PACKAGE_INSTANCE, `${where}; the source redirect serves the instance read in its place, so this importer renders that one, not its own — resolve the package to one instance`) : finding(UNREAD_PACKAGE_INSTANCE, `${where}, which is not analysed, so this importer would render unextracted builder code — resolve the package to one instance`);
4150
+ }
4151
+ /**
4152
+ * Where the analysis and the host disagree on a path alias (spec §2.2 A7,
4153
+ * report only: resolution never changes). Each analysed import whose
4154
+ * specifier, as the parser decodes it, an alias the analysis reads names
4155
+ * (tsconfig paths, or the host's own aliases) is resolved as the analysis
4156
+ * resolves it (the alias's expansion through the host's extension order)
4157
+ * and by the host's own resolver. A different physical file, or a file
4158
+ * only one of them finds, is `animus.discovery.alias-mismatch`. A request
4159
+ * the host's resolver fails on is unavailable for that request alone.
4160
+ *
4161
+ * Each import of a discovered package is resolved by the host from its
4162
+ * importer too (spec §2.2 A4): an answer in another instance than the one
4163
+ * read, in a file the analysis does not hold, is
4164
+ * `animus.discovery.unread-package-instance` (the importer would render
4165
+ * unextracted builder code), or `animus.discovery.replaced-package-instance`
4166
+ * where a source redirect serves the instance read in its place.
4167
+ */
4168
+ async function compareAliases(input) {
4169
+ const { cache, packages } = input;
4170
+ const scope = JSON.stringify([
4171
+ input.pathAliasesJson,
4172
+ input.fileEntries.map((entry) => entry.path).sort(),
4173
+ packages?.roots ?? {},
4174
+ [...packages?.redirected ?? []].sort()
4175
+ ]);
4176
+ if (cache.scope !== scope) {
4177
+ cache.scope = scope;
4178
+ cache.byFile.clear();
4179
+ }
4180
+ if (!(input.pathAliasesJson !== null && JSON.parse(input.pathAliasesJson).aliases.length > 0) && Object.keys(packages?.roots ?? {}).length === 0) return {
4181
+ findings: [],
4182
+ unavailable: 0
3348
4183
  };
3349
- /** The index after the bracketed span opening at `from`, balanced across
3350
- * `<>`, `()`, `[]` and `{}`, or -1 when it never closes. An arrow type's
3351
- * `=>` closes nothing. */
3352
- const skipBalanced = (from) => {
3353
- let depth = 0;
3354
- let pos = from;
3355
- while (pos < source.length) {
3356
- const ch = source[pos];
3357
- if (ch === "'" || ch === "\"" || ch === "`") {
3358
- pos = skipString(pos);
3359
- continue;
3360
- }
3361
- if (source.startsWith("//", pos) || source.startsWith("/*", pos)) {
3362
- pos = skipTrivia(pos);
3363
- continue;
3364
- }
3365
- if ("<([{".includes(ch)) depth++;
3366
- else if (")]}".includes(ch) || ch === ">" && source[pos - 1] !== "=") {
3367
- depth--;
3368
- if (depth === 0) return pos + 1;
3369
- }
3370
- pos++;
4184
+ const changed = input.fileEntries.filter((entry) => cache.byFile.get(entry.path)?.hash !== entry.hash);
4185
+ const { files, bases } = changed.length === 0 ? { files: {} } : JSON.parse(input.moduleSpecifiers(JSON.stringify(changed.map(({ path, source }) => ({
4186
+ path,
4187
+ source
4188
+ }))), input.pathAliasesJson ?? void 0));
4189
+ const analysed = new Set(input.fileEntries.map((entry) => entry.path));
4190
+ const packageAnswers = /* @__PURE__ */ new Map();
4191
+ const comparePackage = async (record, importer, specifier) => {
4192
+ const key = `${node_path.posix.dirname(importer)}\0${specifier}`;
4193
+ let answer = packageAnswers.get(key);
4194
+ if (answer === void 0) {
4195
+ answer = input.resolve(specifier, (0, node_path.join)(input.rootDir, importer));
4196
+ packageAnswers.set(key, answer);
3371
4197
  }
3372
- return -1;
3373
- };
3374
- const consumeChainLinks = (from) => {
3375
- let pos = from;
3376
- for (;;) {
3377
- let cursor = skipTrivia(pos);
3378
- if (source[cursor] !== ".") return pos;
3379
- cursor = skipTrivia(cursor + 1);
3380
- const method = IDENT_START_RE.exec(source.slice(cursor))?.[0];
3381
- if (method !== "extend" && method !== "from") return pos;
3382
- cursor = skipTrivia(cursor + method.length);
3383
- if (source[cursor] === "<") {
3384
- const afterTypeArguments = skipBalanced(cursor);
3385
- if (afterTypeArguments === -1) return pos;
3386
- cursor = skipTrivia(afterTypeArguments);
3387
- }
3388
- if (source[cursor] !== "(") return pos;
3389
- cursor = skipTrivia(cursor + 1);
3390
- const base = IDENT_START_RE.exec(source.slice(cursor))?.[0];
3391
- if (!base) return pos;
3392
- cursor = skipTrivia(cursor + base.length);
3393
- while (source[cursor] === ".") {
3394
- const afterDot = skipTrivia(cursor + 1);
3395
- const segment = IDENT_START_RE.exec(source.slice(afterDot))?.[0];
3396
- if (!segment) break;
3397
- cursor = skipTrivia(afterDot + segment.length);
3398
- }
3399
- if (source[cursor] === ",") cursor = skipTrivia(cursor + 1);
3400
- if (source[cursor] !== ")") return pos;
3401
- identifiers.add(base);
3402
- pos = cursor + 1;
4198
+ let id;
4199
+ try {
4200
+ id = await answer;
4201
+ } catch {
4202
+ return "unavailable";
3403
4203
  }
4204
+ const host = id === null ? null : hostTarget(id);
4205
+ if (host === null || "virtual" in host) return null;
4206
+ return packageInstanceFinding(record, importer, specifier, host.file);
3404
4207
  };
3405
- const bindingAt = /* @__PURE__ */ new Map();
3406
- const aliasOf = /* @__PURE__ */ new Map();
3407
- const declarationRe = /\b(?:const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
3408
- let declaration;
3409
- while ((declaration = declarationRe.exec(source)) !== null) {
3410
- const name = declaration[1];
3411
- let cursor = skipTrivia(declaration.index + declaration[0].length);
3412
- if (source[cursor] === ":") {
3413
- cursor++;
3414
- while (cursor < source.length) {
3415
- const ch = source[cursor];
3416
- if (ch === ";" || ch === ",") break;
3417
- if (ch === "\n" && /^\s*(?:export\s+)?(?:const|let|var|function|class|type|interface|import)\b/.test(source.slice(cursor + 1, cursor + 80))) break;
3418
- if (ch === "=" && source[cursor + 1] !== ">") break;
3419
- if ("<([{".includes(ch) || ch === "'" || ch === "\"" || ch === "`") {
3420
- const after = "<([{".includes(ch) ? skipBalanced(cursor) : skipString(cursor);
3421
- if (after === -1) break;
3422
- cursor = after;
3423
- continue;
3424
- }
3425
- cursor = ch === "=" ? cursor + 2 : cursor + 1;
3426
- }
4208
+ const compare = async (importer, specifier, base) => {
4209
+ const candidate = hostCandidate(input.rootDir, base, analysed, input.order, input.readings);
4210
+ const analysis = candidate === null ? null : candidate.analysedAs ?? candidate.candidate.split("?")[0];
4211
+ let id;
4212
+ try {
4213
+ id = await input.resolve(specifier, (0, node_path.join)(input.rootDir, importer));
4214
+ } catch {
4215
+ return "unavailable";
3427
4216
  }
3428
- if (source[cursor] !== "=" || source[cursor + 1] === "=") continue;
3429
- const initializer = skipTrivia(cursor + 1);
3430
- bindingAt.set(initializer, name);
3431
- const target = IDENT_START_RE.exec(source.slice(initializer))?.[0];
3432
- if (!target) continue;
3433
- const rest = source.slice(initializer + target.length);
3434
- if (/^[ \t]*(?:(?:as|satisfies)\s[^;\n]*)?(?:\/\/[^\n]*)?(?:;|\r?\n(?!\s*[.([?`])|$)/.test(rest)) aliasOf.set(name, target);
3435
- }
3436
- const boundIdentifierBefore = (index) => {
3437
- const declared = bindingAt.get(index);
3438
- if (declared) return declared;
3439
- const match = /([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*$/.exec(source.slice(0, index));
3440
- return match ? match[1] : null;
4217
+ const host = id === null ? null : hostTarget(id);
4218
+ if (analysis === null || host === null ? analysis === host : "file" in host && physical((0, node_path.join)(input.rootDir, analysis)) === physical(host.file)) return null;
4219
+ const shown = host === null ? "no file" : "virtual" in host ? host.virtual : (0, node_path.relative)(input.rootDir, host.file).split(node_path.sep).join(node_path.posix.sep);
4220
+ return {
4221
+ file: importer,
4222
+ component: `alias '${specifier}'`,
4223
+ kind: "warn",
4224
+ message: `'${specifier}' in ${importer} resolves to ${analysis ?? "no file"} through the path aliases analysis reads, but the host bundler resolves it to ${shown}, so the analysis may read another module than the one the bundle renders — make the bundler's resolution and the aliases (tsconfig paths) agree`,
4225
+ code: ALIAS_MISMATCH,
4226
+ severity: severityFor(ALIAS_MISMATCH)
4227
+ };
3441
4228
  };
3442
- const chainRootIdentifiers = /* @__PURE__ */ new Set();
3443
- const createSystemAnchor = rootCall === null ? null : new RegExp(`${rootCall}\\s*\\(`, "g");
3444
- let anchorMatch;
3445
- while ((anchorMatch = createSystemAnchor?.exec(source) ?? null) !== null) {
3446
- let pos = anchorMatch.index + anchorMatch[0].length;
3447
- let depth = 1;
3448
- while (pos < source.length && depth > 0) {
3449
- const ch = source[pos];
3450
- if (ch === "(") depth++;
3451
- else if (ch === ")") depth--;
3452
- pos++;
3453
- }
3454
- consumeChainLinks(pos);
3455
- const bound = boundIdentifierBefore(anchorMatch.index);
3456
- if (bound) chainRootIdentifiers.add(bound);
3457
- }
3458
- const scannedRoots = /* @__PURE__ */ new Set();
3459
- for (;;) {
3460
- const pendingRoots = [...chainRootIdentifiers].filter((root) => !scannedRoots.has(root));
3461
- if (pendingRoots.length === 0) break;
3462
- for (const root of pendingRoots) {
3463
- scannedRoots.add(root);
3464
- const rootUse = new RegExp(`(?<![a-zA-Z0-9_$])${root.replace(/\$/g, "\\$")}(?![a-zA-Z0-9_$])`, "g");
3465
- let useMatch;
3466
- while ((useMatch = rootUse.exec(source)) !== null) {
3467
- const afterIdentifier = useMatch.index + useMatch[0].length;
3468
- if (consumeChainLinks(afterIdentifier) === afterIdentifier) continue;
3469
- const bound = boundIdentifierBefore(useMatch.index);
3470
- if (bound) chainRootIdentifiers.add(bound);
3471
- }
3472
- }
4229
+ await Promise.all(changed.map(async ({ path, hash }) => {
4230
+ const results = await Promise.all((files[path] ?? []).flatMap((specifier) => {
4231
+ const base = bases?.[path]?.[specifier];
4232
+ if (base !== void 0) return [compare(path, specifier, base)];
4233
+ return packages !== void 0 && isPackageSpecifier(specifier) && packages.roots[bareSpecifierPackageName(specifier)] !== void 0 ? [comparePackage(packages, path, specifier)] : [];
4234
+ }));
4235
+ cache.byFile.set(path, {
4236
+ hash,
4237
+ findings: results.filter((result) => result !== null && result !== "unavailable"),
4238
+ unavailable: results.filter((result) => result === "unavailable").length
4239
+ });
4240
+ }));
4241
+ const kept = input.fileEntries.flatMap((entry) => cache.byFile.get(entry.path) ?? []);
4242
+ return {
4243
+ findings: kept.flatMap((file) => file.findings),
4244
+ unavailable: kept.reduce((total, file) => total + file.unavailable, 0)
4245
+ };
4246
+ }
4247
+ //#endregion
4248
+ //#region pipeline/host-package-resolver.ts
4249
+ /**
4250
+ * Package resolution for discovery: one resolver, whose answers are the
4251
+ * host's where it resolves imports itself (spec §2.2 A4), and the system
4252
+ * loader's otherwise, and for a declared workspace the host cannot resolve.
4253
+ */
4254
+ /**
4255
+ * A declared workspace that nothing links into `node_modules` is no package
4256
+ * to the host, though the system loader resolves it: where the host finds
4257
+ * nothing, discovery asks the loader.
4258
+ */
4259
+ function discoveryResolver(hostResolve, engine, context) {
4260
+ const load = (specifier, fromDir) => {
4261
+ const native = engine.resolveSpecifier;
4262
+ if (native === void 0) throw new Error("the native engine does not expose resolveSpecifier, which package resolution needs — rebuild @animus-ui/extract");
4263
+ return native(specifier, fromDir, [...context.conditions], context.workspaces, extensionPolicyJson(context.extensions));
4264
+ };
4265
+ const loaderResolve = (specifier, fromDir) => load(specifier, fromDir).path ?? null;
4266
+ if (hostResolve === null) {
4267
+ const unresolved = /* @__PURE__ */ new Map();
4268
+ return {
4269
+ hostFirst: false,
4270
+ async resolveSpecifier(specifier) {
4271
+ const entry = load(specifier, context.rootDir);
4272
+ if (entry.path) return entry.path;
4273
+ unresolved.set(specifier, entry.unresolved ?? "it names no file");
4274
+ return null;
4275
+ },
4276
+ unresolvedReason: (specifier) => unresolved.get(specifier),
4277
+ requireSourceEntry: () => false,
4278
+ loaderResolve
4279
+ };
3473
4280
  }
3474
- if (identifiers.size === 0) return [];
3475
- const importMap = /* @__PURE__ */ new Map();
3476
- for (const binding of parsed?.imports ?? []) importMap.set(binding.local, binding.source);
3477
- const importRegex = /^\s*import\s+(?:([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,\s*)?(?:\{([^}]*)\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\s+from\s+['"]([^'"]+)['"]/gm;
3478
- if (!parsed) {
3479
- let importMatch;
3480
- while ((importMatch = importRegex.exec(source)) !== null) {
3481
- const [, comboDefault, namedImports, defaultImport, specifier] = importMatch;
3482
- if (comboDefault) importMap.set(comboDefault, specifier);
3483
- if (defaultImport) importMap.set(defaultImport, specifier);
3484
- if (namedImports) for (const binding of namedImports.split(",")) {
3485
- const parts = binding.trim().split(/\s+as\s+/);
3486
- const localName = (parts[1] || parts[0]).trim();
3487
- if (localName) importMap.set(localName, specifier);
4281
+ const loaderOnly = /* @__PURE__ */ new Set();
4282
+ const rootImporter = (0, path.join)(context.rootDir, "__animus_discovery__.js");
4283
+ return {
4284
+ hostFirst: true,
4285
+ async resolveSpecifier(specifier) {
4286
+ let hosted;
4287
+ try {
4288
+ hosted = await hostResolve(specifier, rootImporter);
4289
+ } catch {
4290
+ hosted = null;
3488
4291
  }
3489
- }
3490
- }
3491
- const systemFileDir = (0, path.dirname)(systemFilePath);
3492
- const packages = /* @__PURE__ */ new Set();
3493
- /** The import a local alias chain ends at, or the identifier itself. */
3494
- const throughAliases = (id) => {
3495
- const seen = /* @__PURE__ */ new Set();
3496
- let current = id;
3497
- while (!importMap.has(current) && !seen.has(current)) {
3498
- seen.add(current);
3499
- const target = aliasOf.get(current);
3500
- if (!target) break;
3501
- current = target;
3502
- }
3503
- return current;
4292
+ if (hosted !== null || !Object.hasOwn(context.workspaces, bareSpecifierPackageName(specifier))) return hosted;
4293
+ const loaded = loaderResolve(specifier, context.rootDir);
4294
+ if (loaded) loaderOnly.add(specifier);
4295
+ return loaded;
4296
+ },
4297
+ unresolvedReason: () => void 0,
4298
+ requireSourceEntry: (specifier) => loaderOnly.has(specifier),
4299
+ loaderResolve
3504
4300
  };
3505
- for (const id of identifiers) {
3506
- const specifier = importMap.get(throughAliases(id));
3507
- if (!specifier) continue;
3508
- if (specifier.startsWith(".")) packages.add((0, path.resolve)(systemFileDir, specifier));
3509
- else packages.add(specifier);
3510
- }
3511
- return Array.from(packages);
4301
+ }
4302
+ //#endregion
4303
+ //#region pipeline/output-targets.ts
4304
+ /**
4305
+ * Where a bundler writes, as one model: the directories it fills and the
4306
+ * files it writes by exact name. Discovery excludes both, and the Rollup
4307
+ * family's render check reads both, so the two never classify output
4308
+ * differently.
4309
+ */
4310
+ function noOutputTargets() {
4311
+ return {
4312
+ dirs: [],
4313
+ files: []
4314
+ };
4315
+ }
4316
+ /** Each output's named directory or file; one naming neither writes to
4317
+ * `fallbackDir` when there is one. */
4318
+ function targetsOf(base, outputs, fallbackDir) {
4319
+ const targets = noOutputTargets();
4320
+ for (const output of outputs) if (output.dir !== void 0) targets.dirs.push((0, path.resolve)(base, output.dir));
4321
+ else if (output.file !== void 0) targets.files.push((0, path.resolve)(base, output.file));
4322
+ else if (fallbackDir !== void 0) targets.dirs.push((0, path.resolve)(base, fallbackDir));
4323
+ return targets;
4324
+ }
4325
+ /** The targets of Rollup's or Rolldown's output options at render. */
4326
+ function rollupOutputTargets(output) {
4327
+ return targetsOf(process.cwd(), [output]);
4328
+ }
4329
+ /** Every Vite environment's outputs, as Vite's own `getResolvedOutDirs`
4330
+ * reads them: each output's `dir`, else the environment's `outDir`. */
4331
+ function viteOutputTargets(config) {
4332
+ return mergeOutputTargets([config.build, ...Object.values(config.environments ?? {}).flatMap((environment) => environment.build === void 0 ? [] : [environment.build])].map((build) => {
4333
+ const output = build.rolldownOptions?.output ?? build.rollupOptions?.output;
4334
+ const outputs = output === void 0 ? [{}] : Array.isArray(output) ? output : [output];
4335
+ return targetsOf(config.root, outputs, build.outDir);
4336
+ }));
4337
+ }
4338
+ /** esbuild's `outdir`, or its exact `outfile`. */
4339
+ function esbuildOutputTargets(options) {
4340
+ return targetsOf(options.absWorkingDir ?? process.cwd(), [{
4341
+ dir: options.outdir,
4342
+ file: options.outfile
4343
+ }]);
4344
+ }
4345
+ /** webpack's `output.path`, up to its first segment holding a template
4346
+ * placeholder (`out/[fullhash]` writes under `out`). */
4347
+ function webpackOutputTargets(outputPath) {
4348
+ if (outputPath === void 0) return noOutputTargets();
4349
+ const segments = outputPath.split(path.sep);
4350
+ const placeholder = segments.findIndex((segment) => segment.includes("["));
4351
+ const fixed = placeholder === -1 ? outputPath : segments.slice(0, placeholder).join(path.sep);
4352
+ return {
4353
+ dirs: fixed === "" ? [] : [fixed],
4354
+ files: []
4355
+ };
4356
+ }
4357
+ function mergeOutputTargets(all) {
4358
+ return {
4359
+ dirs: [...new Set(all.flatMap((targets) => targets.dirs))],
4360
+ files: [...new Set(all.flatMap((targets) => targets.files))]
4361
+ };
4362
+ }
4363
+ /** The Session's structural exclusions: every target inside the root. A
4364
+ * directory that is the root excludes nothing; its files still can. */
4365
+ function outputExclusions(root, targets) {
4366
+ return [...targets.dirs, ...targets.files].flatMap((target) => {
4367
+ const exclusion = outputExclusion(root, target);
4368
+ return exclusion === null ? [] : [exclusion];
4369
+ });
4370
+ }
4371
+ /** The analysed files a build's targets hold, as the render check reports
4372
+ * them: a file target the analysis read is the build's own earlier
4373
+ * output; a file inside a directory target is earlier output or a source
4374
+ * the bundler writes beside, which the check cannot tell apart. */
4375
+ function analysedOutputs(root, targets, analyzed) {
4376
+ const earlier = analyzed.filter((file) => targets.files.includes(file));
4377
+ const inside = targets.dirs.flatMap((dir) => {
4378
+ const exclusion = outputExclusion(root, dir);
4379
+ const held = analyzed.filter((file) => !earlier.includes(file) && isPathWithinRoot(dir, file));
4380
+ return exclusion === null || held.length === 0 ? [] : [{
4381
+ exclusion,
4382
+ held
4383
+ }];
4384
+ });
4385
+ const rel = (file) => (0, path.relative)(root, file);
4386
+ const parts = [...earlier.length === 0 ? [] : [`it analysed its own earlier output: ${earlier.map(rel).join(", ")}. Add ${earlier.map((file) => `'${rel(file)}'`).join(", ")} to the plugin's \`exclude\` option`], ...inside.map(({ exclusion, held }) => `it analysed files inside its output directory '${exclusion}': ${held.map(rel).join(", ")}. If they are earlier output, add '${exclusion}' to the plugin's \`exclude\` option; if they are sources, write the output outside the source tree`)];
4387
+ return parts.length === 0 ? null : `[animus] this build ${parts.join("; and ")}.`;
3512
4388
  }
3513
4389
  //#endregion
3514
4390
  //#region pipeline/source-corpus.ts
@@ -3529,6 +4405,7 @@ function createSourceCorpus(host, ingestor = createSourceIngestor(host)) {
3529
4405
  ownership: {}
3530
4406
  };
3531
4407
  return {
4408
+ facts: (entries) => ingestor.facts(entries),
3532
4409
  async prepare(input) {
3533
4410
  const rawEntries = "fileCache" in input ? assembleRawEntries(input) : input;
3534
4411
  const ingested = await ingestor.ingest(rawEntries);
@@ -4346,15 +5223,28 @@ function buildAnalysisInputs(opts) {
4346
5223
  };
4347
5224
  if (opts.system.declarationScalesJson) inputs.declarationScalesJson = opts.system.declarationScalesJson;
4348
5225
  if (opts.system.generatedNamesJson) inputs.generatedNamesJson = opts.system.generatedNamesJson;
4349
- const context = opts.analysisContext;
4350
- if (context?.skippedSources?.length || context?.unbundledComputedImports || context?.packageDirs?.length) inputs.analysisContextJson = JSON.stringify({
5226
+ if (opts.system.propertyRecordsJson) inputs.propertyRecordsJson = opts.system.propertyRecordsJson;
5227
+ const context = analysisContextJson(opts.analysisContext);
5228
+ if (context !== void 0) inputs.analysisContextJson = context;
5229
+ return inputs;
5230
+ }
5231
+ /** The engine's wire for what the host knows; present only when the host
5232
+ * knows something, so a host that knows nothing persists unchanged inputs. */
5233
+ function analysisContextJson(context) {
5234
+ if (!(context?.skippedSources?.length || context?.unbundledComputedImports || context?.packageDirs?.length || context?.extensions || context?.openings?.length)) return;
5235
+ return JSON.stringify({
4351
5236
  skippedSources: context.skippedSources ?? [],
4352
5237
  unbundledComputedImports: context.unbundledComputedImports ?? false,
4353
5238
  packageDirs: context.packageDirs ?? [],
4354
5239
  linkedDirs: context.linkedDirs ?? [],
4355
- outputDirs: context.outputDirs ?? []
5240
+ outputDirs: context.outputDirs ?? [],
5241
+ ...context.extensions && { extensions: {
5242
+ appended: context.extensions.appended,
5243
+ nodeNext: context.extensions.nodeNext,
5244
+ alias: context.extensions.alias
5245
+ } },
5246
+ ...context.openings?.length && { openings: context.openings }
4356
5247
  });
4357
- return inputs;
4358
5248
  }
4359
5249
  function hasSourceThemeManifests(system) {
4360
5250
  const json = system.sourceThemeManifestsJson ?? "";
@@ -4388,7 +5278,11 @@ function runProjectAnalysis(engineApi, opts) {
4388
5278
  const inputs = buildAnalysisInputs(opts);
4389
5279
  const serializeMs = Math.round(performance.now() - t);
4390
5280
  t = performance.now();
4391
- const manifestJson = analyzeProject(...buildAnalyzeProjectArgs(inputs));
5281
+ const manifestJson = analyzeProject(...buildAnalyzeProjectArgs(inputs, opts.rootDir === void 0 ? void 0 : gatherProbeEvidence(opts.rootDir, new Set(opts.fileEntries.map((entry) => entry.path)), opts.analysisContext?.extensions, {
5282
+ isAsset: opts.assets?.isAsset,
5283
+ adapted: opts.adapted,
5284
+ expander: opts.loadExpander
5285
+ })));
4392
5286
  const extractMs = Math.round(performance.now() - t);
4393
5287
  t = performance.now();
4394
5288
  const manifest = JSON.parse(manifestJson);
@@ -4624,12 +5518,20 @@ function renameDeclarationRecords(declarationScalesJson, rename) {
4624
5518
  }
4625
5519
  //#endregion
4626
5520
  //#region pipeline/system-config.ts
5521
+ function systemLoadReads(error) {
5522
+ const thrown = error;
5523
+ const carrier = thrown?.dependencies ? thrown : thrown?.cause;
5524
+ return {
5525
+ dependencies: carrier?.dependencies ?? [],
5526
+ missing: carrier?.missing ?? []
5527
+ };
5528
+ }
4627
5529
  /** The loader's evaluation of the system file. A failure on a file that
4628
5530
  * calls `createSystem` with no binding leads with discovery's warning line
4629
5531
  * for it, then keeps the loader's own error. */
4630
- function evaluateSystemModule(engine, systemPath, rootDir, conditions) {
5532
+ function evaluateSystemModule(engine, systemPath, rootDir, conditions, workspaces, extensions) {
4631
5533
  try {
4632
- return engine.loadSystemModule(systemPath, rootDir, void 0, conditions);
5534
+ return engine.loadSystemModule(systemPath, rootDir, void 0, conditions, workspaces, extensions && extensionPolicyJson(extensions));
4633
5535
  } catch (error) {
4634
5536
  let source;
4635
5537
  try {
@@ -4648,7 +5550,7 @@ function evaluateSystemModule(engine, systemPath, rootDir, conditions) {
4648
5550
  * variable name. Error handling stays at the call site.
4649
5551
  */
4650
5552
  function loadSystemConfig(engineApi, opts) {
4651
- const config = evaluateSystemModule(engineApi(), opts.systemPath, opts.rootDir, opts.conditions);
5553
+ const config = evaluateSystemModule(engineApi(), opts.systemPath, opts.rootDir, opts.conditions, opts.workspaces, opts.extensions);
4652
5554
  let scalesJson = config.scalesJson;
4653
5555
  let variableMapJson = config.variableMapJson;
4654
5556
  const registrations = splitInvalidPropertyRegistrations(config.variableCss);
@@ -4698,6 +5600,7 @@ function loadSystemConfig(engineApi, opts) {
4698
5600
  keyframesJson: config.keyframesBlocks || null,
4699
5601
  vocabularyWitnessesJson: config.vocabularyWitnesses || null,
4700
5602
  dependencies: config.dependencies ?? [],
5603
+ missing: config.missing ?? [],
4701
5604
  sourceThemeManifestsJson: config.sourceThemeManifests || null
4702
5605
  };
4703
5606
  if (declarationScalesJson) system.declarationScalesJson = declarationScalesJson;
@@ -4817,13 +5720,6 @@ const CODE_EXTENSIONS = /* @__PURE__ */ new Set([
4817
5720
  ".mjs",
4818
5721
  ".cjs"
4819
5722
  ]);
4820
- const isFile = (path) => {
4821
- try {
4822
- return (0, node_fs.statSync)(path).isFile();
4823
- } catch {
4824
- return false;
4825
- }
4826
- };
4827
5723
  const posixPath = (path) => path.split(node_path.sep).join("/");
4828
5724
  /**
4829
5725
  * The package-relative files `npm pack` publishes, read with npm's own rules
@@ -4952,8 +5848,14 @@ function kitPublicationFailures(pkgRoot, engine, artifactDir) {
4952
5848
  const matched = files.filter((file) => pattern.test(file));
4953
5849
  if (matched.length === 0) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, matches no file in the package`);
4954
5850
  for (const file of matched) admit(subpath, file);
4955
- } else if (!isFile((0, node_path.resolve)(pkgRoot, target))) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, does not exist in the package`);
4956
- else admit(subpath, relPath);
5851
+ } else {
5852
+ const seen = seeOnDisk((0, node_path.resolve)(pkgRoot, target), pkgRoot);
5853
+ if (seen.kind === "file") admit(subpath, relPath);
5854
+ else failures.push(seen.kind === "case-only" ? `package.json: ${caseMismatchReason(`the "animus" target of exports["${subpath}"]`, {
5855
+ candidate: target,
5856
+ actual: rel(seen.actual)
5857
+ }, "spell the target as the file is spelled")}` : `package.json: the "animus" target of exports["${subpath}"], ${target}, does not exist in the package`);
5858
+ }
4957
5859
  }
4958
5860
  const visited = /* @__PURE__ */ new Set();
4959
5861
  while (queue.length > 0) {
@@ -4966,8 +5868,13 @@ function kitPublicationFailures(pkgRoot, engine, artifactDir) {
4966
5868
  }])), "moduleSpecifiers").files[file] ?? [];
4967
5869
  for (const specifier of specifiers) {
4968
5870
  if (specifier.startsWith(".")) {
4969
- const target = relativeSourceCandidates(file, specifier).find(isFile);
4970
- if (target === void 0) failures.push(`${rel(file)}: import '${specifier}' resolves to no file in the package`);
5871
+ const probed = probeOnDisk(relativeSourceCandidates(file, specifier), (0, node_path.dirname)(file));
5872
+ const target = probed.kind === "found" ? probed.path : void 0;
5873
+ if (probed.kind === "case-mismatch") failures.push(`${rel(file)}: ${caseMismatchReason(`import '${specifier}'`, {
5874
+ candidate: rel(probed.candidate),
5875
+ actual: rel(probed.actual)
5876
+ }, "spell the import as the file is spelled")}`);
5877
+ else if (target === void 0) failures.push(`${rel(file)}: import '${specifier}' resolves to no file in the package`);
4971
5878
  else if (outside(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, outside the package`);
4972
5879
  else if (!published(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, which is not in the published files`);
4973
5880
  else if (CODE_EXTENSIONS.has((0, node_path.extname)(target))) queue.push(target);
@@ -5066,18 +5973,665 @@ function realpathThroughNearestExistingAncestor(path) {
5066
5973
  }
5067
5974
  }
5068
5975
  //#endregion
5976
+ //#region pipeline/built-in-asset-types.ts
5977
+ /** The Vite version the built-in types come from. */
5978
+ const BUILT_IN_ASSET_SOURCE = "vite@8.2.2";
5979
+ /** Asset extensions, as regular-expression alternatives, a session with no
5980
+ * readable host classification reads as assets (spec §2.2 A8). */
5981
+ const BUILT_IN_ASSET_TYPES = [
5982
+ "apng",
5983
+ "bmp",
5984
+ "png",
5985
+ "jpe?g",
5986
+ "jfif",
5987
+ "pjpeg",
5988
+ "pjp",
5989
+ "gif",
5990
+ "svg",
5991
+ "ico",
5992
+ "webp",
5993
+ "avif",
5994
+ "cur",
5995
+ "jxl",
5996
+ "mp4",
5997
+ "webm",
5998
+ "ogg",
5999
+ "mp3",
6000
+ "wav",
6001
+ "flac",
6002
+ "aac",
6003
+ "opus",
6004
+ "mov",
6005
+ "m4a",
6006
+ "vtt",
6007
+ "woff2?",
6008
+ "eot",
6009
+ "ttf",
6010
+ "otf",
6011
+ "webmanifest",
6012
+ "pdf",
6013
+ "txt"
6014
+ ];
6015
+ /** Stylesheet extensions, as regular-expression alternatives, a session
6016
+ * with no readable host classification reads as stylesheets. */
6017
+ const BUILT_IN_STYLESHEET_TYPES = [
6018
+ "css",
6019
+ "less",
6020
+ "sass",
6021
+ "scss",
6022
+ "styl",
6023
+ "stylus",
6024
+ "pcss",
6025
+ "postcss",
6026
+ "sss"
6027
+ ];
6028
+ //#endregion
6029
+ //#region pipeline/host-assets.ts
6030
+ const BUILT_IN_ASSET_RE = new RegExp(`\\.(?:${BUILT_IN_ASSET_TYPES.join("|")})$`, "i");
6031
+ /** Vite's stylesheet test (`isCSSRequest`), on the final extension only: a
6032
+ * `x.css.ts` is a module. Exact case, as Vite reads it. */
6033
+ const STYLESHEET_RE = new RegExp(`\\.(?:${BUILT_IN_STYLESHEET_TYPES.join("|")})$`);
6034
+ /** JSON, as Vite's json plugin, webpack's `json` type, esbuild's `json`
6035
+ * loader and Turbopack read it: the final extension, exact case. */
6036
+ const JSON_RE = /\.json$/;
6037
+ /** The queries Vite answers with a string whatever the file holds: `?url`
6038
+ * and `?raw`. Any other query keeps the file's own reading. */
6039
+ const VITE_OPAQUE_QUERY_RE = /[?&](?:url|raw)\b/;
6040
+ /** The built-in classification, where no host's can be read or is not
6041
+ * modelled (webpack's and Rspack's rules, as a conditional rule may never
6042
+ * apply): Vite's known asset types, `svg` included, its CSS languages
6043
+ * (`BUILT_IN_ASSET_SOURCE`) and JSON, read with Vite's queries. */
6044
+ function builtInAssetClassification(reason, detail) {
6045
+ return {
6046
+ isAsset: (file, query) => VITE_OPAQUE_QUERY_RE.test(query) || BUILT_IN_ASSET_RE.test(file) || STYLESHEET_RE.test(file) || JSON_RE.test(file),
6047
+ resolverVersion: `built-in (${reason}${detail ? `: ${detail}` : ""}; ${BUILT_IN_ASSET_SOURCE})`
6048
+ };
6049
+ }
6050
+ /** Vite's own classification: `?url` and `?raw`, its known asset types and
6051
+ * the user's `assetsInclude`, as `ResolvedConfig.assetsInclude` answers,
6052
+ * its CSS languages (`isCSSRequest`), and its json plugin's JSON. */
6053
+ function viteAssetClassification(assetsInclude, version) {
6054
+ return {
6055
+ isAsset: (file, query) => VITE_OPAQUE_QUERY_RE.test(query) || assetsInclude(file) || STYLESHEET_RE.test(file) || JSON_RE.test(file),
6056
+ resolverVersion: `${version ? `vite@${version}` : "vite"} captured`
6057
+ };
6058
+ }
6059
+ /** esbuild's built-in loaders, which a configured `loader` map extends. */
6060
+ const ESBUILD_DEFAULT_LOADERS = {
6061
+ "": "js",
6062
+ ".js": "js",
6063
+ ".mjs": "js",
6064
+ ".cjs": "js",
6065
+ ".jsx": "jsx",
6066
+ ".ts": "ts",
6067
+ ".cts": "ts",
6068
+ ".mts": "ts",
6069
+ ".tsx": "tsx",
6070
+ ".css": "css",
6071
+ ".module.css": "local-css",
6072
+ ".json": "json",
6073
+ ".txt": "text"
6074
+ };
6075
+ /** esbuild loaders whose module is an opaque value: a URL, the file's bytes
6076
+ * or text, a stylesheet, or JSON. `copy` keeps the file as code. */
6077
+ const ESBUILD_OPAQUE_LOADERS = /* @__PURE__ */ new Set([
6078
+ "file",
6079
+ "dataurl",
6080
+ "base64",
6081
+ "binary",
6082
+ "text",
6083
+ "css",
6084
+ "local-css",
6085
+ "global-css",
6086
+ "json"
6087
+ ]);
6088
+ /** esbuild's classification, from its `loader` map: the loader esbuild
6089
+ * picks for a file is the longest extension of its name the map holds,
6090
+ * exact case. */
6091
+ function esbuildAssetClassification(loader) {
6092
+ const loaders = new Map(Object.entries({
6093
+ ...ESBUILD_DEFAULT_LOADERS,
6094
+ ...loader
6095
+ }));
6096
+ return {
6097
+ isAsset: (file) => {
6098
+ let name = file.slice(Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\")) + 1);
6099
+ let picked = name.includes(".") ? void 0 : loaders.get("");
6100
+ for (let dot = name.indexOf("."); dot !== -1; dot = name.indexOf(".")) {
6101
+ picked = loaders.get(name.slice(dot));
6102
+ if (picked !== void 0) break;
6103
+ name = name.slice(dot + 1);
6104
+ }
6105
+ return picked !== void 0 && ESBUILD_OPAQUE_LOADERS.has(picked);
6106
+ },
6107
+ resolverVersion: "esbuild captured"
6108
+ };
6109
+ }
6110
+ /** Turbopack's classification under Next: Next's static-image table
6111
+ * (`nextImageLoaderRegex`), unless `images.disableStaticImages`, and its
6112
+ * stylesheets (`regexLikeCss`), as the installed `next` declares them,
6113
+ * and JSON. Built-in where Next cannot be read. */
6114
+ function nextImageAssetClassification(rootDir, disableStaticImages) {
6115
+ try {
6116
+ const require$1 = (0, node_module.createRequire)(`${rootDir}/package.json`);
6117
+ const { version } = require$1("next/package.json");
6118
+ const { nextImageLoaderRegex } = require$1("next/dist/build/webpack-config");
6119
+ const { regexLikeCss } = require$1("next/dist/build/webpack/config/blocks/css");
6120
+ if (!(nextImageLoaderRegex instanceof RegExp) || !(regexLikeCss instanceof RegExp)) return builtInAssetClassification("hostOptionUnreadable", `next@${version} image and stylesheet types`);
6121
+ return {
6122
+ isAsset: (file) => JSON_RE.test(file) || regexLikeCss.test(file) || !disableStaticImages && nextImageLoaderRegex.test(file),
6123
+ resolverVersion: `from next@${version}`
6124
+ };
6125
+ } catch {
6126
+ return builtInAssetClassification("hostOptionUnreadable", "next");
6127
+ }
6128
+ }
6129
+ //#endregion
6130
+ //#region pipeline/vite-expansions.ts
6131
+ /** The glob syntax read here: literal characters, `*` and a whole-segment
6132
+ * `**`, and a `{a,b}` group of literal alternatives. Anything else (`?`,
6133
+ * classes, extglobs, nested groups) is not reproduced. */
6134
+ const UNREAD_SYNTAX = /[?[\]()!+@\\]/;
6135
+ function segmentOf(text) {
6136
+ if (text === "**") return { kind: "globstar" };
6137
+ if (UNREAD_SYNTAX.test(text) || text.includes("**")) return void 0;
6138
+ let source = "";
6139
+ for (const part of text.split(/(\{[^{}]*\}|\*)/)) if (part === "*") source += "[^/]*";
6140
+ else if (part.startsWith("{") && part.endsWith("}")) {
6141
+ const options = part.slice(1, -1).split(",");
6142
+ if (options.some((option) => /[{}*]/.test(option))) return void 0;
6143
+ source += `(?:${options.map(escape).join("|")})`;
6144
+ } else if (/[{}]/.test(part)) return void 0;
6145
+ else source += escape(part);
6146
+ return {
6147
+ kind: "match",
6148
+ test: new RegExp(`^${source}$`),
6149
+ dotted: text.startsWith(".")
6150
+ };
6151
+ }
6152
+ function escape(text) {
6153
+ return text.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
6154
+ }
6155
+ /**
6156
+ * A pattern as Vite resolves it (`toAbsoluteGlob`): relative to the
6157
+ * importer's directory, or with `/` to the Vite root. A pattern in another
6158
+ * form (an alias, a bare name) or with syntax not read here is undefined.
6159
+ */
6160
+ function resolveGlob(pattern, importerDir, viteRoot) {
6161
+ const negated = pattern.startsWith("!");
6162
+ const body = negated ? pattern.slice(1) : pattern;
6163
+ const start = body.startsWith("/") ? viteRoot : body.startsWith("./") || body.startsWith("../") ? importerDir : void 0;
6164
+ if (start === void 0) return void 0;
6165
+ const parts = body.split("/").filter((part) => part !== "" && part !== ".");
6166
+ let base = start;
6167
+ let index = 0;
6168
+ if (parts.some((part) => part !== ".." && UNREAD_SYNTAX.test(part))) return;
6169
+ while (index < parts.length - 1 && !/[*{}]/.test(parts[index])) {
6170
+ base = parts[index] === ".." ? (0, node_path.dirname)(base) : (0, node_path.resolve)(base, parts[index]);
6171
+ index += 1;
6172
+ }
6173
+ const segments = [];
6174
+ for (const part of parts.slice(index)) {
6175
+ if (part === "..") return void 0;
6176
+ const segment = segmentOf(part);
6177
+ if (segment === void 0) return void 0;
6178
+ segments.push(segment);
6179
+ }
6180
+ return {
6181
+ negated,
6182
+ base,
6183
+ segments
6184
+ };
6185
+ }
6186
+ /** Whether `names`, a path below a glob's base, matches its segments. A
6187
+ * wildcard never matches a dot-led name unless `dot`. */
6188
+ function matches(segments, names, dot) {
6189
+ const [segment, ...rest] = segments;
6190
+ if (segment === void 0) return names.length === 0;
6191
+ if (segment.kind === "globstar") {
6192
+ if (matches(rest, names, dot)) return true;
6193
+ const [name, ...more] = names;
6194
+ if (name === void 0 || !dot && name.startsWith(".")) return false;
6195
+ return matches(segments, more, dot);
6196
+ }
6197
+ const [name, ...more] = names;
6198
+ if (name === void 0) return false;
6199
+ if (!dot && name.startsWith(".") && !segment.dotted) return false;
6200
+ return segment.test.test(name) && matches(rest, more, dot);
6201
+ }
6202
+ /** Every file below `dir`, following symbolic links as Vite does, each
6203
+ * directory once by its real path. A read the walk cannot finish throws:
6204
+ * the expansion would not be every file. */
6205
+ function walk(dir, prefix = [], visited = /* @__PURE__ */ new Set()) {
6206
+ const real = (0, node_fs.realpathSync)(dir);
6207
+ if (visited.has(real)) return [];
6208
+ const inside = new Set(visited).add(real);
6209
+ const files = [];
6210
+ for (const name of (0, node_fs.readdirSync)(dir)) {
6211
+ const path = `${dir}${node_path.sep}${name}`;
6212
+ const names = [...prefix, name];
6213
+ const stat = (0, node_fs.statSync)(path);
6214
+ if (stat.isDirectory()) files.push(...walk(path, names, inside));
6215
+ else if (stat.isFile()) files.push({
6216
+ names,
6217
+ path,
6218
+ real: (0, node_fs.realpathSync)(path)
6219
+ });
6220
+ }
6221
+ return files;
6222
+ }
6223
+ /** The files a set of Vite globs selects: in any affirmed glob and no
6224
+ * negated one, `node_modules` and dot-led names left out unless
6225
+ * `exhaustive`, the importer itself never. */
6226
+ function expandGlobs(globs, importer, exhaustive) {
6227
+ const affirmed = globs.filter((glob) => !glob.negated);
6228
+ const negated = globs.filter((glob) => glob.negated);
6229
+ const inside = (glob, file) => {
6230
+ const rel = (0, node_path.relative)(glob.base, file);
6231
+ if ((0, node_path.isAbsolute)(rel) || rel.split(node_path.sep)[0] === "..") return false;
6232
+ return matches(glob.segments, rel.split(node_path.sep), exhaustive);
6233
+ };
6234
+ const selected = /* @__PURE__ */ new Set();
6235
+ for (const glob of affirmed) for (const { names, path, real } of walk(glob.base)) {
6236
+ if (!exhaustive && names.includes("node_modules")) continue;
6237
+ if (path === importer || !inside(glob, path)) continue;
6238
+ if (negated.some((other) => inside(other, path))) continue;
6239
+ selected.add(real);
6240
+ }
6241
+ return [...selected].sort();
6242
+ }
6243
+ /** The queries a glob's `query` option is read as: Vite's opaque ones,
6244
+ * with or without the `?` it adds. */
6245
+ const GLOB_QUERIES = /* @__PURE__ */ new Map([
6246
+ [void 0, ""],
6247
+ ["raw", "?raw"],
6248
+ ["?raw", "?raw"],
6249
+ ["url", "?url"],
6250
+ ["?url", "?url"]
6251
+ ]);
6252
+ /** The boolean an option is written as; absent, `false`. */
6253
+ const GLOB_FLAGS = /* @__PURE__ */ new Map([
6254
+ [void 0, false],
6255
+ [true, true],
6256
+ [false, false]
6257
+ ]);
6258
+ /** A glob's options as Vite reads them (`parseGlobOptions`): the query each
6259
+ * file is imported with and whether the glob is exhaustive. `import`
6260
+ * selects an export, not files. Undefined for an option set not
6261
+ * reproduced here: another query, `base`, `caseSensitive`, or the
6262
+ * deprecated `as`, which a Vite 8 build does not apply as a query. */
6263
+ function globOptions(options) {
6264
+ if (options === null) return {
6265
+ query: "",
6266
+ exhaustive: false
6267
+ };
6268
+ for (const key of Object.keys(options)) if (![
6269
+ "eager",
6270
+ "import",
6271
+ "exhaustive",
6272
+ "query"
6273
+ ].includes(key)) return;
6274
+ const query = GLOB_QUERIES.get(options.query);
6275
+ const exhaustive = GLOB_FLAGS.get(options.exhaustive);
6276
+ if (query === void 0 || exhaustive === void 0) return void 0;
6277
+ if (!GLOB_FLAGS.has(options.eager)) return void 0;
6278
+ return {
6279
+ query,
6280
+ exhaustive
6281
+ };
6282
+ }
6283
+ /**
6284
+ * The glob a variable `import()` of a template literal becomes under
6285
+ * Vite's dynamic-import-vars (`dynamicImportToGlob`): each substitution one
6286
+ * `*` within a segment. It must start `./` or `../` and name a file
6287
+ * extension in its last static text; Vite leaves any other one, and a
6288
+ * concatenation, a runtime import, which it does not expand.
6289
+ */
6290
+ function importVarsGlob(quasis) {
6291
+ if (quasis.length < 2) return void 0;
6292
+ const head = quasis[0];
6293
+ if (!head.startsWith("./") && !head.startsWith("../")) return void 0;
6294
+ if (quasis.slice(1, -1).some((quasi) => quasi === "")) return void 0;
6295
+ if (quasis.some((quasi) => /[*?{}[\]]/.test(quasi))) return void 0;
6296
+ const last = quasis[quasis.length - 1];
6297
+ if (!/\.[a-z0-9]+$/i.test(last) || last.includes("?")) return void 0;
6298
+ return quasis.join("*");
6299
+ }
6300
+ /**
6301
+ * How a bundled Vite environment (Vite 8, rolldown's native glob and
6302
+ * dynamic-import-vars plugins) expands computed loads (spec §6.3):
6303
+ * `import.meta.glob` and a variable `import()`. `importVars` is false where
6304
+ * the project's `build.dynamicImportVarsOptions` differ from Vite's
6305
+ * default, which transforms every importer outside `node_modules`.
6306
+ * Anything this does not reproduce exactly lists no expansion.
6307
+ */
6308
+ function viteLoadExpander(viteRoot, importVars) {
6309
+ return { expand(load, rootDir) {
6310
+ const importer = (0, node_path.resolve)(rootDir, load.importer);
6311
+ const importerDir = (0, node_path.dirname)(importer);
6312
+ let patterns;
6313
+ let query = "";
6314
+ let exhaustive = false;
6315
+ if (load.kind === "glob" && load.args && "patterns" in load.args) {
6316
+ const read = globOptions(load.args.options);
6317
+ if (read === void 0) return void 0;
6318
+ ({query, exhaustive} = read);
6319
+ patterns = load.args.patterns;
6320
+ } else if (load.kind === "import" && load.args && "quasis" in load.args) {
6321
+ if (!importVars || importer.split(node_path.sep).includes("node_modules") || !load.args.template || load.args.options !== null || load.args.comments.some((comment) => comment.includes("@vite-ignore"))) return;
6322
+ const glob = importVarsGlob(load.args.quasis);
6323
+ if (glob === void 0) return void 0;
6324
+ patterns = [glob];
6325
+ } else return;
6326
+ const globs = [];
6327
+ for (const pattern of patterns) {
6328
+ const glob = resolveGlob(pattern, importerDir, viteRoot);
6329
+ if (glob === void 0) return void 0;
6330
+ globs.push(glob);
6331
+ }
6332
+ if (!globs.some((glob) => !glob.negated)) return void 0;
6333
+ let files;
6334
+ let realRoot;
6335
+ try {
6336
+ files = expandGlobs(globs, importer, exhaustive);
6337
+ realRoot = (0, node_fs.realpathSync)(rootDir);
6338
+ } catch {
6339
+ return;
6340
+ }
6341
+ return files.map((file) => ({
6342
+ path: (0, node_path.relative)(realRoot, file).split(node_path.sep).join(node_path.posix.sep),
6343
+ query
6344
+ }));
6345
+ } };
6346
+ }
6347
+ /** Whether `build.dynamicImportVarsOptions` are Vite's default, which
6348
+ * transforms every importer outside `node_modules`. */
6349
+ function defaultImportVars(options) {
6350
+ const exclude = options?.exclude;
6351
+ return options?.include === void 0 && Array.isArray(exclude) && exclude.length === 1 && exclude[0] instanceof RegExp && exclude[0].source === "node_modules" && exclude[0].flags === "";
6352
+ }
6353
+ /** The aliases Vite adds to every configuration (`clientAlias`), which
6354
+ * name only its own `@vite/` modules. */
6355
+ const VITE_CLIENT_ALIASES = /* @__PURE__ */ new Set(["^\\/?@vite\\/env", "^\\/?@vite\\/client"]);
6356
+ /** Whether an alias could rewrite a relative or root specifier, which the
6357
+ * expander reads without the resolver: a string from `.` or `/`, or a
6358
+ * RegExp other than Vite's own client aliases. */
6359
+ function aliasesRelative(aliases) {
6360
+ return (aliases ?? []).some(({ find }) => find instanceof RegExp ? !(find.flags === "" && VITE_CLIENT_ALIASES.has(find.source)) : find.startsWith(".") || find.startsWith("/"));
6361
+ }
6362
+ /**
6363
+ * The expander for a resolved Vite configuration: only where every
6364
+ * environment is bundled (Vite 8, rolldown's native plugins; an earlier
6365
+ * Vite marks none), and no alias could rewrite a relative or root
6366
+ * specifier. A variable `import()` is expanded only where every environment
6367
+ * keeps Vite's default dynamic-import-vars options.
6368
+ */
6369
+ function viteHostExpander(config) {
6370
+ const environments = Object.values(config.environments ?? {});
6371
+ if (environments.length === 0 || !environments.every((environment) => environment.isBundled === true) || aliasesRelative(config.resolve?.alias)) return;
6372
+ return viteLoadExpander(config.root, environments.every((environment) => defaultImportVars(environment.build?.dynamicImportVarsOptions)));
6373
+ }
6374
+ //#endregion
6375
+ //#region pipeline/webpack-expansions.ts
6376
+ /** Webpack's `quoteMeta`. */
6377
+ function quoteMeta(text) {
6378
+ return text.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
6379
+ }
6380
+ /** A literal as a RegExp, where webpack tests it statelessly: a global or
6381
+ * sticky one carries state between tests, which is not reproduced. */
6382
+ function regex(literal) {
6383
+ if (literal === null) return void 0;
6384
+ if (/[gy]/.test(literal.flags)) return null;
6385
+ try {
6386
+ return new RegExp(literal.source, literal.flags);
6387
+ } catch {
6388
+ return null;
6389
+ }
6390
+ }
6391
+ /** Webpack's `splitContextFromPrefix`. */
6392
+ function splitContextFromPrefix(prefix) {
6393
+ const at = prefix.lastIndexOf("/");
6394
+ return at >= 0 ? {
6395
+ context: prefix.slice(0, at),
6396
+ prefix: `.${prefix.slice(at)}`
6397
+ } : {
6398
+ context: ".",
6399
+ prefix
6400
+ };
6401
+ }
6402
+ /** A context directory webpack resolves relative to the importer; another
6403
+ * form goes through the resolver (aliases, modules), not reproduced. */
6404
+ function contextDir(importerDir, context) {
6405
+ return context === "." || context.startsWith("./") || context.startsWith("../") ? (0, node_path.resolve)(importerDir, context) : void 0;
6406
+ }
6407
+ /** The comments that change which files a webpack context holds. */
6408
+ const SELECTING_COMMENT = /webpack(?:Include|Exclude|Ignore)\b/;
6409
+ /**
6410
+ * The context webpack builds for a template literal or a concatenation
6411
+ * (`ContextDependencyHelpers.create`), with the default wrapped-context
6412
+ * options (`/.*\/`, recursive): a template's inner text joins the
6413
+ * expression pattern; a concatenation keeps its prefix and postfix only.
6414
+ */
6415
+ function specifierContext(load, importerDir) {
6416
+ const { args } = load;
6417
+ if (args === null || !("quasis" in args)) return void 0;
6418
+ if (args.options !== null) return void 0;
6419
+ if (args.comments.some((comment) => SELECTING_COMMENT.test(comment))) return;
6420
+ const { quasis, template } = args;
6421
+ if (quasis.length < 2 || !template && quasis.length > 2) return void 0;
6422
+ const { context, prefix } = splitContextFromPrefix(quasis[0]);
6423
+ const postfixRaw = quasis[quasis.length - 1];
6424
+ if (postfixRaw.includes("#")) return void 0;
6425
+ const at = postfixRaw.indexOf("?");
6426
+ const postfix = at === -1 ? postfixRaw : postfixRaw.slice(0, at);
6427
+ const query = at === -1 ? "" : postfixRaw.slice(at);
6428
+ const inner = template ? quasis.slice(1, -1).map((quasi) => `${quoteMeta(quasi)}.*`).join("") : "";
6429
+ const dir = contextDir(importerDir, context);
6430
+ if (dir === void 0) return void 0;
6431
+ return {
6432
+ dir,
6433
+ recursive: true,
6434
+ regExp: new RegExp(`^${quoteMeta(prefix)}.*${inner}${quoteMeta(postfix)}$`),
6435
+ include: void 0,
6436
+ exclude: void 0,
6437
+ query,
6438
+ category: load.kind === "require" ? "commonjs" : "esm"
6439
+ };
6440
+ }
6441
+ /** `require.context(dir, recursive, regExp, mode)` and
6442
+ * `import.meta.webpackContext(dir, { … })`, with webpack's defaults. */
6443
+ function directContext(load, importerDir) {
6444
+ const { args } = load;
6445
+ if (args === null || !("dir" in args)) return void 0;
6446
+ const regExp = regex(args.regExp);
6447
+ const include = regex(args.include);
6448
+ const exclude = regex(args.exclude);
6449
+ if (regExp === null || include === null || exclude === null) return;
6450
+ const dir = contextDir(importerDir, args.dir);
6451
+ if (dir === void 0) return void 0;
6452
+ return {
6453
+ dir,
6454
+ recursive: args.recursive ?? true,
6455
+ regExp: regExp ?? /^\.\/.*$/,
6456
+ include,
6457
+ exclude,
6458
+ query: "",
6459
+ category: load.kind === "context" ? "commonjs" : "esm"
6460
+ };
6461
+ }
6462
+ /** A group of module directory names, rather than one absolute module
6463
+ * directory. */
6464
+ function isModuleGroup(modules) {
6465
+ return Array.isArray(modules);
6466
+ }
6467
+ /** The requests webpack tests a context file's regExp against
6468
+ * (`RequireContextPlugin`'s `alternativeRequests`). */
6469
+ function alternatives(context, request, reading) {
6470
+ let items = [request];
6471
+ if (!reading.fullySpecified) {
6472
+ const extended = [];
6473
+ for (const item of items) {
6474
+ for (const extension of reading.extensions) if (item.endsWith(extension)) extended.push(item.slice(0, -extension.length));
6475
+ if (!reading.enforceExtension) extended.push(item);
6476
+ }
6477
+ items = [];
6478
+ for (const item of extended) {
6479
+ for (const mainFile of reading.mainFiles) if (item.endsWith(`/${mainFile}`)) {
6480
+ items.push(item.slice(0, -mainFile.length));
6481
+ items.push(item.slice(0, -mainFile.length - 1));
6482
+ }
6483
+ items.push(item);
6484
+ }
6485
+ }
6486
+ const requests = [];
6487
+ for (const item of items) {
6488
+ let hidden = false;
6489
+ for (const modules of reading.modules) if (isModuleGroup(modules)) {
6490
+ for (const name of modules) if (item.startsWith(`./${name}/`)) {
6491
+ requests.push(item.slice(name.length + 3));
6492
+ hidden = true;
6493
+ }
6494
+ } else {
6495
+ const dir = modules.replace(/\\/g, "/");
6496
+ const full = context.replace(/\\/g, "/") + item.slice(1);
6497
+ if (full.startsWith(dir)) requests.push(full.slice(dir.length + 1));
6498
+ }
6499
+ if (!hidden) requests.push(item);
6500
+ }
6501
+ return requests;
6502
+ }
6503
+ /** The files a context holds (`resolveDependencies`): below its directory,
6504
+ * dot-led names skipped, `exclude` and `include` tested on each absolute
6505
+ * path, a file kept when any of its alternative requests matches. */
6506
+ function contextFiles(context, reading) {
6507
+ const files = [];
6508
+ const visit = (dir, visited) => {
6509
+ const real = (0, node_fs.realpathSync)(dir);
6510
+ const names = (0, node_fs.readdirSync)(dir).map((name) => name.normalize("NFC"));
6511
+ if (visited.has(real)) return;
6512
+ const inside = new Set(visited).add(real);
6513
+ for (const name of names) {
6514
+ if (name.startsWith(".")) continue;
6515
+ const path = `${dir}${node_path.sep}${name}`;
6516
+ if (context.exclude?.test(path)) continue;
6517
+ const stat = (0, node_fs.statSync)(path);
6518
+ if (stat.isDirectory()) {
6519
+ if (context.recursive) visit(path, inside);
6520
+ } else if (stat.isFile() && (!context.include || context.include.test(path))) {
6521
+ const request = `.${path.slice(context.dir.length).replace(/\\/g, "/")}`;
6522
+ if (alternatives(context.dir, request, reading).some((alternative) => context.regExp.test(alternative))) files.push((0, node_fs.realpathSync)(path));
6523
+ }
6524
+ }
6525
+ };
6526
+ visit(context.dir, /* @__PURE__ */ new Set());
6527
+ return files.sort();
6528
+ }
6529
+ /**
6530
+ * How a webpack 5 build expands computed loads (spec §6.3): a template or
6531
+ * concatenated `import()` or `require()`, `require.context` and
6532
+ * `import.meta.webpackContext`, each a context module whose files
6533
+ * `ContextModuleFactory` lists. `resolveReading` is the resolver's options
6534
+ * for a dependency category; `wrappedDefaults` is false where the project
6535
+ * changes `wrappedContextRegExp` or `wrappedContextRecursive`. Anything not
6536
+ * reproduced exactly lists no expansion.
6537
+ */
6538
+ function webpackLoadExpander(resolveReading, wrappedDefaults) {
6539
+ return { expand(load, rootDir) {
6540
+ const importerDir = (0, node_path.dirname)((0, node_path.resolve)(rootDir, load.importer));
6541
+ let context;
6542
+ if (load.kind === "import" || load.kind === "require") context = wrappedDefaults ? specifierContext(load, importerDir) : void 0;
6543
+ else if (load.kind === "context" || load.kind === "webpackContext") context = directContext(load, importerDir);
6544
+ if (context === void 0) return void 0;
6545
+ const reading = resolveReading(context.category);
6546
+ if (reading === void 0 || reading.aliasNames.length > 0) return;
6547
+ let files;
6548
+ let realRoot;
6549
+ try {
6550
+ files = contextFiles(context, reading);
6551
+ realRoot = (0, node_fs.realpathSync)(rootDir);
6552
+ } catch {
6553
+ return;
6554
+ }
6555
+ return files.map((file) => ({
6556
+ path: (0, node_path.relative)(realRoot, file).split(node_path.sep).join(node_path.posix.sep),
6557
+ query: context.query
6558
+ }));
6559
+ } };
6560
+ }
6561
+ /** A rule entry, rather than `'...'` or a falsy placeholder. */
6562
+ function isRule(rule) {
6563
+ return rule instanceof Object;
6564
+ }
6565
+ /** Every rule, nested `rules` and `oneOf` included. */
6566
+ function everyRule(rules) {
6567
+ return rules.filter(isRule).flatMap((rule) => [
6568
+ rule,
6569
+ ...everyRule(rule.rules ?? []),
6570
+ ...everyRule(rule.oneOf ?? [])
6571
+ ]);
6572
+ }
6573
+ /**
6574
+ * The expander for a webpack 5 compiler. Each expansion reads the
6575
+ * compiler's options again and lists nothing where a rule carries its own
6576
+ * resolve options or context parser options, `module.defaultRules` is not
6577
+ * webpack's own, or the options cannot be read.
6578
+ */
6579
+ function webpackHostExpander(reading) {
6580
+ return { expand(load, rootDir) {
6581
+ let options;
6582
+ try {
6583
+ options = reading.options();
6584
+ } catch {
6585
+ return;
6586
+ }
6587
+ if (everyRule(options.rules).some((rule) => rule.resolve !== void 0 || Object.keys(rule.parser ?? {}).some((key) => key.includes("Context"))) || !options.defaultRulesAreWebpacks) return void 0;
6588
+ return webpackLoadExpander(reading.resolveReading, options.wrappedDefaults).expand(load, rootDir);
6589
+ } };
6590
+ }
6591
+ //#endregion
6592
+ //#region pipeline/served-files.ts
6593
+ function servedFiles(manifest) {
6594
+ const dropped = /* @__PURE__ */ new Map();
6595
+ for (const input of manifest.missing_inputs ?? []) {
6596
+ if (input.outcome === "failed-parent") continue;
6597
+ if (!dropped.has(input.file)) dropped.set(input.file, input);
6598
+ }
6599
+ return {
6600
+ listed: new Set(Object.entries(manifest.files ?? {}).filter(([, ids]) => ids.length > 0).map(([file]) => file)),
6601
+ dropped
6602
+ };
6603
+ }
6604
+ /** Why a file dropped over its extension parent is not served: its builder
6605
+ * code would render with empty classes. */
6606
+ function droppedExtensionMessage(drop) {
6607
+ const from = drop.specifier === null ? "" : ` from '${drop.specifier}'`;
6608
+ return `[animus-extract] cannot serve ${drop.file}: '${drop.component}' extends '${drop.parent}'${from}, which the analysis could not resolve (${drop.outcome}); serving it untransformed would render it without its styles. Make the parent an analysed Animus component, or remove the extension.`;
6609
+ }
6610
+ //#endregion
5069
6611
  Object.defineProperty(exports, "ANIMUS_LAYERS", {
5070
6612
  enumerable: true,
5071
6613
  get: function() {
5072
6614
  return ANIMUS_LAYERS;
5073
6615
  }
5074
6616
  });
6617
+ Object.defineProperty(exports, "AliasAgreementCache", {
6618
+ enumerable: true,
6619
+ get: function() {
6620
+ return AliasAgreementCache;
6621
+ }
6622
+ });
5075
6623
  Object.defineProperty(exports, "AnimusConfigError", {
5076
6624
  enumerable: true,
5077
6625
  get: function() {
5078
6626
  return AnimusConfigError;
5079
6627
  }
5080
6628
  });
6629
+ Object.defineProperty(exports, "BUILT_IN_EXTENSION_POLICY", {
6630
+ enumerable: true,
6631
+ get: function() {
6632
+ return BUILT_IN_EXTENSION_POLICY;
6633
+ }
6634
+ });
5081
6635
  Object.defineProperty(exports, "CORE_OPTION_KEYS", {
5082
6636
  enumerable: true,
5083
6637
  get: function() {
@@ -5096,6 +6650,12 @@ Object.defineProperty(exports, "DEFAULT_EXTENSIONS", {
5096
6650
  return DEFAULT_EXTENSIONS;
5097
6651
  }
5098
6652
  });
6653
+ Object.defineProperty(exports, "DEFAULT_RUNTIME_IMPORT", {
6654
+ enumerable: true,
6655
+ get: function() {
6656
+ return DEFAULT_RUNTIME_IMPORT;
6657
+ }
6658
+ });
5099
6659
  Object.defineProperty(exports, "DIAGNOSTIC_LEVELS", {
5100
6660
  enumerable: true,
5101
6661
  get: function() {
@@ -5150,6 +6710,12 @@ Object.defineProperty(exports, "STRUCTURAL_EXCLUDE", {
5150
6710
  return STRUCTURAL_EXCLUDE;
5151
6711
  }
5152
6712
  });
6713
+ Object.defineProperty(exports, "SYSTEM_INSTANCE_MISMATCH", {
6714
+ enumerable: true,
6715
+ get: function() {
6716
+ return SYSTEM_INSTANCE_MISMATCH;
6717
+ }
6718
+ });
5153
6719
  Object.defineProperty(exports, "VOCABULARY_COLLISION", {
5154
6720
  enumerable: true,
5155
6721
  get: function() {
@@ -5168,6 +6734,18 @@ Object.defineProperty(exports, "adaptSvelteSource", {
5168
6734
  return adaptSvelteSource;
5169
6735
  }
5170
6736
  });
6737
+ Object.defineProperty(exports, "adaptedOriginals", {
6738
+ enumerable: true,
6739
+ get: function() {
6740
+ return adaptedOriginals;
6741
+ }
6742
+ });
6743
+ Object.defineProperty(exports, "analysedOutputs", {
6744
+ enumerable: true,
6745
+ get: function() {
6746
+ return analysedOutputs;
6747
+ }
6748
+ });
5171
6749
  Object.defineProperty(exports, "applyPrefix", {
5172
6750
  enumerable: true,
5173
6751
  get: function() {
@@ -5198,10 +6776,22 @@ Object.defineProperty(exports, "assertNoErrorDiagnostics", {
5198
6776
  return assertNoErrorDiagnostics;
5199
6777
  }
5200
6778
  });
5201
- Object.defineProperty(exports, "assertNoRetiredEngineSelection", {
6779
+ Object.defineProperty(exports, "assertRuntimeImportSuppliesTerminals", {
6780
+ enumerable: true,
6781
+ get: function() {
6782
+ return assertRuntimeImportSuppliesTerminals;
6783
+ }
6784
+ });
6785
+ Object.defineProperty(exports, "assertSupportedEngine", {
5202
6786
  enumerable: true,
5203
6787
  get: function() {
5204
- return assertNoRetiredEngineSelection;
6788
+ return assertSupportedEngine;
6789
+ }
6790
+ });
6791
+ Object.defineProperty(exports, "bareSpecifierPackageName", {
6792
+ enumerable: true,
6793
+ get: function() {
6794
+ return bareSpecifierPackageName;
5205
6795
  }
5206
6796
  });
5207
6797
  Object.defineProperty(exports, "buildAnalysisInputs", {
@@ -5240,12 +6830,24 @@ Object.defineProperty(exports, "buildSystemPropsModule", {
5240
6830
  return buildSystemPropsModule;
5241
6831
  }
5242
6832
  });
6833
+ Object.defineProperty(exports, "builtInAssetClassification", {
6834
+ enumerable: true,
6835
+ get: function() {
6836
+ return builtInAssetClassification;
6837
+ }
6838
+ });
5243
6839
  Object.defineProperty(exports, "camelToKebab", {
5244
6840
  enumerable: true,
5245
6841
  get: function() {
5246
6842
  return camelToKebab;
5247
6843
  }
5248
6844
  });
6845
+ Object.defineProperty(exports, "caseMismatchReason", {
6846
+ enumerable: true,
6847
+ get: function() {
6848
+ return caseMismatchReason;
6849
+ }
6850
+ });
5249
6851
  Object.defineProperty(exports, "clearEngineCache", {
5250
6852
  enumerable: true,
5251
6853
  get: function() {
@@ -5258,6 +6860,12 @@ Object.defineProperty(exports, "collectExternalPackageSources", {
5258
6860
  return collectExternalPackageSources;
5259
6861
  }
5260
6862
  });
6863
+ Object.defineProperty(exports, "compareAliases", {
6864
+ enumerable: true,
6865
+ get: function() {
6866
+ return compareAliases;
6867
+ }
6868
+ });
5261
6869
  Object.defineProperty(exports, "compareDiscoveryOrder", {
5262
6870
  enumerable: true,
5263
6871
  get: function() {
@@ -5294,6 +6902,12 @@ Object.defineProperty(exports, "createV2EngineApi", {
5294
6902
  return createV2EngineApi;
5295
6903
  }
5296
6904
  });
6905
+ Object.defineProperty(exports, "declaredWorkspacePackages", {
6906
+ enumerable: true,
6907
+ get: function() {
6908
+ return declaredWorkspacePackages;
6909
+ }
6910
+ });
5297
6911
  Object.defineProperty(exports, "diffFilePlans", {
5298
6912
  enumerable: true,
5299
6913
  get: function() {
@@ -5306,6 +6920,18 @@ Object.defineProperty(exports, "discoverFiles", {
5306
6920
  return discoverFiles;
5307
6921
  }
5308
6922
  });
6923
+ Object.defineProperty(exports, "discoveryResolver", {
6924
+ enumerable: true,
6925
+ get: function() {
6926
+ return discoveryResolver;
6927
+ }
6928
+ });
6929
+ Object.defineProperty(exports, "droppedExtensionMessage", {
6930
+ enumerable: true,
6931
+ get: function() {
6932
+ return droppedExtensionMessage;
6933
+ }
6934
+ });
5309
6935
  Object.defineProperty(exports, "enforceExternalTokenContracts", {
5310
6936
  enumerable: true,
5311
6937
  get: function() {
@@ -5318,12 +6944,36 @@ Object.defineProperty(exports, "engineModuleParser", {
5318
6944
  return engineModuleParser;
5319
6945
  }
5320
6946
  });
6947
+ Object.defineProperty(exports, "esbuildAssetClassification", {
6948
+ enumerable: true,
6949
+ get: function() {
6950
+ return esbuildAssetClassification;
6951
+ }
6952
+ });
6953
+ Object.defineProperty(exports, "esbuildExtensionPolicy", {
6954
+ enumerable: true,
6955
+ get: function() {
6956
+ return esbuildExtensionPolicy;
6957
+ }
6958
+ });
6959
+ Object.defineProperty(exports, "esbuildOutputTargets", {
6960
+ enumerable: true,
6961
+ get: function() {
6962
+ return esbuildOutputTargets;
6963
+ }
6964
+ });
5321
6965
  Object.defineProperty(exports, "excludeCollectedPackages", {
5322
6966
  enumerable: true,
5323
6967
  get: function() {
5324
6968
  return excludeCollectedPackages;
5325
6969
  }
5326
6970
  });
6971
+ Object.defineProperty(exports, "extensionPolicyJson", {
6972
+ enumerable: true,
6973
+ get: function() {
6974
+ return extensionPolicyJson;
6975
+ }
6976
+ });
5327
6977
  Object.defineProperty(exports, "extractSystemFilePackages", {
5328
6978
  enumerable: true,
5329
6979
  get: function() {
@@ -5408,16 +7058,10 @@ Object.defineProperty(exports, "isExcludedPackageRelativePath", {
5408
7058
  return isExcludedPackageRelativePath;
5409
7059
  }
5410
7060
  });
5411
- Object.defineProperty(exports, "isJsonBlock", {
5412
- enumerable: true,
5413
- get: function() {
5414
- return isJsonBlock;
5415
- }
5416
- });
5417
- Object.defineProperty(exports, "isJsonString", {
7061
+ Object.defineProperty(exports, "isPackageSpecifier", {
5418
7062
  enumerable: true,
5419
7063
  get: function() {
5420
- return isJsonString;
7064
+ return isPackageSpecifier;
5421
7065
  }
5422
7066
  });
5423
7067
  Object.defineProperty(exports, "isPathWithinRoot", {
@@ -5426,12 +7070,6 @@ Object.defineProperty(exports, "isPathWithinRoot", {
5426
7070
  return isPathWithinRoot;
5427
7071
  }
5428
7072
  });
5429
- Object.defineProperty(exports, "isUnresolvedParentDrop", {
5430
- enumerable: true,
5431
- get: function() {
5432
- return isUnresolvedParentDrop;
5433
- }
5434
- });
5435
7073
  Object.defineProperty(exports, "keepsKitSourceEffects", {
5436
7074
  enumerable: true,
5437
7075
  get: function() {
@@ -5462,12 +7100,78 @@ Object.defineProperty(exports, "loadSystemConfig", {
5462
7100
  return loadSystemConfig;
5463
7101
  }
5464
7102
  });
7103
+ Object.defineProperty(exports, "mergeOutputTargets", {
7104
+ enumerable: true,
7105
+ get: function() {
7106
+ return mergeOutputTargets;
7107
+ }
7108
+ });
7109
+ Object.defineProperty(exports, "nativeKitSourceRoot", {
7110
+ enumerable: true,
7111
+ get: function() {
7112
+ return nativeKitSourceRoot;
7113
+ }
7114
+ });
7115
+ Object.defineProperty(exports, "nativePackageLocator", {
7116
+ enumerable: true,
7117
+ get: function() {
7118
+ return nativePackageLocator;
7119
+ }
7120
+ });
7121
+ Object.defineProperty(exports, "nextImageAssetClassification", {
7122
+ enumerable: true,
7123
+ get: function() {
7124
+ return nextImageAssetClassification;
7125
+ }
7126
+ });
5465
7127
  Object.defineProperty(exports, "noKitFilesDiagnostics", {
5466
7128
  enumerable: true,
5467
7129
  get: function() {
5468
7130
  return noKitFilesDiagnostics;
5469
7131
  }
5470
7132
  });
7133
+ Object.defineProperty(exports, "noOutputTargets", {
7134
+ enumerable: true,
7135
+ get: function() {
7136
+ return noOutputTargets;
7137
+ }
7138
+ });
7139
+ Object.defineProperty(exports, "outputExclusion", {
7140
+ enumerable: true,
7141
+ get: function() {
7142
+ return outputExclusion;
7143
+ }
7144
+ });
7145
+ Object.defineProperty(exports, "outputExclusions", {
7146
+ enumerable: true,
7147
+ get: function() {
7148
+ return outputExclusions;
7149
+ }
7150
+ });
7151
+ Object.defineProperty(exports, "outputSourceGuard", {
7152
+ enumerable: true,
7153
+ get: function() {
7154
+ return outputSourceGuard;
7155
+ }
7156
+ });
7157
+ Object.defineProperty(exports, "outputSourceMessage", {
7158
+ enumerable: true,
7159
+ get: function() {
7160
+ return outputSourceMessage;
7161
+ }
7162
+ });
7163
+ Object.defineProperty(exports, "packageInstanceFinding", {
7164
+ enumerable: true,
7165
+ get: function() {
7166
+ return packageInstanceFinding;
7167
+ }
7168
+ });
7169
+ Object.defineProperty(exports, "packageReadRecord", {
7170
+ enumerable: true,
7171
+ get: function() {
7172
+ return packageReadRecord;
7173
+ }
7174
+ });
5471
7175
  Object.defineProperty(exports, "parseFilesJson", {
5472
7176
  enumerable: true,
5473
7177
  get: function() {
@@ -5492,12 +7196,24 @@ Object.defineProperty(exports, "preprocessMdx", {
5492
7196
  return preprocessMdx;
5493
7197
  }
5494
7198
  });
7199
+ Object.defineProperty(exports, "probeAbsolutePathSpecifier", {
7200
+ enumerable: true,
7201
+ get: function() {
7202
+ return probeAbsolutePathSpecifier;
7203
+ }
7204
+ });
5495
7205
  Object.defineProperty(exports, "projectExternalFileOwners", {
5496
7206
  enumerable: true,
5497
7207
  get: function() {
5498
7208
  return projectExternalFileOwners;
5499
7209
  }
5500
7210
  });
7211
+ Object.defineProperty(exports, "pruneStaleAssets", {
7212
+ enumerable: true,
7213
+ get: function() {
7214
+ return pruneStaleAssets;
7215
+ }
7216
+ });
5501
7217
  Object.defineProperty(exports, "readKitDescriptor", {
5502
7218
  enumerable: true,
5503
7219
  get: function() {
@@ -5516,12 +7232,6 @@ Object.defineProperty(exports, "reportSurvivingAssetPlaceholders", {
5516
7232
  return reportSurvivingAssetPlaceholders;
5517
7233
  }
5518
7234
  });
5519
- Object.defineProperty(exports, "resolveAbsolutePathSpecifier", {
5520
- enumerable: true,
5521
- get: function() {
5522
- return resolveAbsolutePathSpecifier;
5523
- }
5524
- });
5525
7235
  Object.defineProperty(exports, "resolveAssetFile", {
5526
7236
  enumerable: true,
5527
7237
  get: function() {
@@ -5552,6 +7262,18 @@ Object.defineProperty(exports, "resolveVerbosity", {
5552
7262
  return resolveVerbosity;
5553
7263
  }
5554
7264
  });
7265
+ Object.defineProperty(exports, "rollupExtensionPolicy", {
7266
+ enumerable: true,
7267
+ get: function() {
7268
+ return rollupExtensionPolicy;
7269
+ }
7270
+ });
7271
+ Object.defineProperty(exports, "rollupOutputTargets", {
7272
+ enumerable: true,
7273
+ get: function() {
7274
+ return rollupOutputTargets;
7275
+ }
7276
+ });
5555
7277
  Object.defineProperty(exports, "runProjectAnalysis", {
5556
7278
  enumerable: true,
5557
7279
  get: function() {
@@ -5570,6 +7292,18 @@ Object.defineProperty(exports, "serializeStaticCss", {
5570
7292
  return serializeStaticCss;
5571
7293
  }
5572
7294
  });
7295
+ Object.defineProperty(exports, "servedFiles", {
7296
+ enumerable: true,
7297
+ get: function() {
7298
+ return servedFiles;
7299
+ }
7300
+ });
7301
+ Object.defineProperty(exports, "severityFor", {
7302
+ enumerable: true,
7303
+ get: function() {
7304
+ return severityFor;
7305
+ }
7306
+ });
5573
7307
  Object.defineProperty(exports, "sharesVolumeRoot", {
5574
7308
  enumerable: true,
5575
7309
  get: function() {
@@ -5624,18 +7358,48 @@ Object.defineProperty(exports, "surfaceManifestDiagnostics", {
5624
7358
  return surfaceManifestDiagnostics;
5625
7359
  }
5626
7360
  });
7361
+ Object.defineProperty(exports, "systemKitDependencies", {
7362
+ enumerable: true,
7363
+ get: function() {
7364
+ return systemKitDependencies;
7365
+ }
7366
+ });
5627
7367
  Object.defineProperty(exports, "systemLoadDiagnostics", {
5628
7368
  enumerable: true,
5629
7369
  get: function() {
5630
7370
  return systemLoadDiagnostics;
5631
7371
  }
5632
7372
  });
7373
+ Object.defineProperty(exports, "systemLoadReads", {
7374
+ enumerable: true,
7375
+ get: function() {
7376
+ return systemLoadReads;
7377
+ }
7378
+ });
5633
7379
  Object.defineProperty(exports, "toWatchKeys", {
5634
7380
  enumerable: true,
5635
7381
  get: function() {
5636
7382
  return toWatchKeys;
5637
7383
  }
5638
7384
  });
7385
+ Object.defineProperty(exports, "tsconfigChainPaths", {
7386
+ enumerable: true,
7387
+ get: function() {
7388
+ return tsconfigChainPaths;
7389
+ }
7390
+ });
7391
+ Object.defineProperty(exports, "turbopackExtensionPolicy", {
7392
+ enumerable: true,
7393
+ get: function() {
7394
+ return turbopackExtensionPolicy;
7395
+ }
7396
+ });
7397
+ Object.defineProperty(exports, "unmatchedExcludeLines", {
7398
+ enumerable: true,
7399
+ get: function() {
7400
+ return unmatchedExcludeLines;
7401
+ }
7402
+ });
5639
7403
  Object.defineProperty(exports, "unreadableSourceDiagnostic", {
5640
7404
  enumerable: true,
5641
7405
  get: function() {
@@ -5648,16 +7412,40 @@ Object.defineProperty(exports, "unresolvableIncludesMessage", {
5648
7412
  return unresolvableIncludesMessage;
5649
7413
  }
5650
7414
  });
5651
- Object.defineProperty(exports, "unresolvedParentName", {
7415
+ Object.defineProperty(exports, "validateLayerOrder", {
5652
7416
  enumerable: true,
5653
7417
  get: function() {
5654
- return unresolvedParentName;
7418
+ return validateLayerOrder;
5655
7419
  }
5656
7420
  });
5657
- Object.defineProperty(exports, "validateLayerOrder", {
7421
+ Object.defineProperty(exports, "viteAssetClassification", {
5658
7422
  enumerable: true,
5659
7423
  get: function() {
5660
- return validateLayerOrder;
7424
+ return viteAssetClassification;
7425
+ }
7426
+ });
7427
+ Object.defineProperty(exports, "viteExtensionPolicy", {
7428
+ enumerable: true,
7429
+ get: function() {
7430
+ return viteExtensionPolicy;
7431
+ }
7432
+ });
7433
+ Object.defineProperty(exports, "viteHostExpander", {
7434
+ enumerable: true,
7435
+ get: function() {
7436
+ return viteHostExpander;
7437
+ }
7438
+ });
7439
+ Object.defineProperty(exports, "viteLoadExpander", {
7440
+ enumerable: true,
7441
+ get: function() {
7442
+ return viteLoadExpander;
7443
+ }
7444
+ });
7445
+ Object.defineProperty(exports, "viteOutputTargets", {
7446
+ enumerable: true,
7447
+ get: function() {
7448
+ return viteOutputTargets;
5661
7449
  }
5662
7450
  });
5663
7451
  Object.defineProperty(exports, "vocabularyWitnessDiagnostics", {
@@ -5672,3 +7460,33 @@ Object.defineProperty(exports, "walkPackageSources", {
5672
7460
  return walkPackageSources;
5673
7461
  }
5674
7462
  });
7463
+ Object.defineProperty(exports, "webpackExtensionPolicy", {
7464
+ enumerable: true,
7465
+ get: function() {
7466
+ return webpackExtensionPolicy;
7467
+ }
7468
+ });
7469
+ Object.defineProperty(exports, "webpackHostExpander", {
7470
+ enumerable: true,
7471
+ get: function() {
7472
+ return webpackHostExpander;
7473
+ }
7474
+ });
7475
+ Object.defineProperty(exports, "webpackLoadExpander", {
7476
+ enumerable: true,
7477
+ get: function() {
7478
+ return webpackLoadExpander;
7479
+ }
7480
+ });
7481
+ Object.defineProperty(exports, "webpackOutputTargets", {
7482
+ enumerable: true,
7483
+ get: function() {
7484
+ return webpackOutputTargets;
7485
+ }
7486
+ });
7487
+ Object.defineProperty(exports, "writeAssetCopy", {
7488
+ enumerable: true,
7489
+ get: function() {
7490
+ return writeAssetCopy;
7491
+ }
7492
+ });