@animus-ui/extract 0.1.25 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/crates/extract-v2/animus-extract-v2.darwin-arm64.node +0 -0
- package/crates/extract-v2/animus-extract-v2.linux-arm64-gnu.node +0 -0
- package/crates/extract-v2/animus-extract-v2.linux-x64-gnu.node +0 -0
- package/crates/extract-v2/index.d.ts +101 -6
- package/dist/index.cjs +48 -5
- package/dist/index.mjs +2 -2
- package/dist/pipeline/alias-agreement.d.ts +107 -0
- package/dist/pipeline/alias-agreement.d.ts.map +1 -0
- package/dist/pipeline/analyze-project-args.d.ts +7 -2
- package/dist/pipeline/analyze-project-args.d.ts.map +1 -1
- package/dist/pipeline/asset-copies.d.ts +20 -0
- package/dist/pipeline/asset-copies.d.ts.map +1 -0
- package/dist/pipeline/built-in-asset-types.d.ts +9 -0
- package/dist/pipeline/built-in-asset-types.d.ts.map +1 -0
- package/dist/pipeline/core-options.d.ts +31 -7
- package/dist/pipeline/core-options.d.ts.map +1 -1
- package/dist/pipeline/discover-packages.d.ts +98 -12
- package/dist/pipeline/discover-packages.d.ts.map +1 -1
- package/dist/pipeline/engine-adapter.d.ts +41 -3
- package/dist/pipeline/engine-adapter.d.ts.map +1 -1
- package/dist/pipeline/engine-retirement.d.ts +7 -1
- package/dist/pipeline/engine-retirement.d.ts.map +1 -1
- package/dist/pipeline/extension-policy.d.ts +95 -0
- package/dist/pipeline/extension-policy.d.ts.map +1 -0
- package/dist/pipeline/host-assets.d.ts +32 -0
- package/dist/pipeline/host-assets.d.ts.map +1 -0
- package/dist/pipeline/host-expansions.d.ts +92 -0
- package/dist/pipeline/host-expansions.d.ts.map +1 -0
- package/dist/pipeline/host-extensions.d.ts +64 -0
- package/dist/pipeline/host-extensions.d.ts.map +1 -0
- package/dist/pipeline/host-package-resolver.d.ts +40 -0
- package/dist/pipeline/host-package-resolver.d.ts.map +1 -0
- package/dist/pipeline/index.d.ts +32 -8
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/kit-publication.d.ts.map +1 -1
- package/dist/pipeline/manifest-diagnostics.d.ts +25 -4
- package/dist/pipeline/manifest-diagnostics.d.ts.map +1 -1
- package/dist/pipeline/manifest-schema.d.ts +16 -0
- package/dist/pipeline/manifest-schema.d.ts.map +1 -1
- package/dist/pipeline/output-targets.d.ts +52 -0
- package/dist/pipeline/output-targets.d.ts.map +1 -0
- package/dist/pipeline/probe-evidence.d.ts +58 -0
- package/dist/pipeline/probe-evidence.d.ts.map +1 -0
- package/dist/pipeline/run-analysis.d.ts +26 -0
- package/dist/pipeline/run-analysis.d.ts.map +1 -1
- package/dist/pipeline/runtime-import.d.ts +10 -0
- package/dist/pipeline/runtime-import.d.ts.map +1 -0
- package/dist/pipeline/served-files.d.ts +16 -0
- package/dist/pipeline/served-files.d.ts.map +1 -0
- package/dist/pipeline/source-corpus.d.ts +4 -0
- package/dist/pipeline/source-corpus.d.ts.map +1 -1
- package/dist/pipeline/source-ingestion.d.ts +37 -5
- package/dist/pipeline/source-ingestion.d.ts.map +1 -1
- package/dist/pipeline/system-config.d.ts +18 -0
- package/dist/pipeline/system-config.d.ts.map +1 -1
- package/dist/pipeline/system-instances.d.ts +27 -0
- package/dist/pipeline/system-instances.d.ts.map +1 -0
- package/dist/pipeline/tsconfig-paths.d.ts +4 -0
- package/dist/pipeline/tsconfig-paths.d.ts.map +1 -1
- package/dist/pipeline/vite-expansions.d.ts +40 -0
- package/dist/pipeline/vite-expansions.d.ts.map +1 -0
- package/dist/pipeline/webpack-expansions.d.ts +55 -0
- package/dist/pipeline/webpack-expansions.d.ts.map +1 -0
- package/dist/pipeline/workspace-packages.d.ts +13 -0
- package/dist/pipeline/workspace-packages.d.ts.map +1 -0
- package/dist/{pipeline-YGWpNr_Z.mjs → pipeline-BzMQ_Z0M.mjs} +2285 -773
- package/dist/{pipeline-DOgKR4VZ.cjs → pipeline-DyUf-eKZ.cjs} +2556 -768
- package/dist/session/coalescing-window.d.ts +34 -0
- package/dist/session/coalescing-window.d.ts.map +1 -0
- package/dist/session/extraction-session.d.ts +297 -35
- package/dist/session/extraction-session.d.ts.map +1 -1
- package/dist/session/index.d.ts +7 -3
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/published-set.d.ts +6 -1
- package/dist/session/published-set.d.ts.map +1 -1
- package/dist/session/resolve-packages.d.ts +9 -5
- package/dist/session/resolve-packages.d.ts.map +1 -1
- package/dist/session/singleton.d.ts +218 -53
- package/dist/session/singleton.d.ts.map +1 -1
- package/dist/session/turbopack-orchestrator.d.ts.map +1 -1
- package/dist/session.cjs +1462 -510
- package/dist/session.mjs +1430 -489
- package/package.json +4 -4
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createRequire, isBuiltin } from "node:module";
|
|
2
|
-
import path, { basename, dirname, extname, isAbsolute, join, normalize, posix, relative, resolve, sep } from "node:path";
|
|
2
|
+
import path, { basename, dirname, extname, isAbsolute, join, normalize, parse, posix, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { createHash } from "crypto";
|
|
4
|
-
import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "fs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
5
|
+
import { existsSync as existsSync$1, mkdirSync, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, statSync as statSync$1, unlinkSync, writeFileSync } from "fs";
|
|
6
|
+
import { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute as isAbsolute$1, join as join$1, normalize as normalize$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
|
|
7
7
|
import { createRequire as createRequire$1 } from "module";
|
|
8
8
|
import browserslist from "browserslist";
|
|
9
9
|
import { browserslistToTargets, transform } from "lightningcss";
|
|
@@ -69,7 +69,7 @@ function assembleStylesheet(options) {
|
|
|
69
69
|
//#endregion
|
|
70
70
|
//#region pipeline/analyze-project-args.ts
|
|
71
71
|
/** @internal */
|
|
72
|
-
function buildAnalyzeProjectArgs(inputs) {
|
|
72
|
+
function buildAnalyzeProjectArgs(inputs, probeEvidence) {
|
|
73
73
|
const args = [
|
|
74
74
|
inputs.filesJson,
|
|
75
75
|
inputs.scalesJson,
|
|
@@ -97,16 +97,12 @@ function buildAnalyzeProjectArgs(inputs) {
|
|
|
97
97
|
inputs.generatedNamesJson,
|
|
98
98
|
inputs.propertyRecordsJson
|
|
99
99
|
];
|
|
100
|
-
const last = tail.findLastIndex((slot) => slot !== void 0 && slot !== "");
|
|
100
|
+
const last = probeEvidence === void 0 ? tail.findLastIndex((slot) => slot !== void 0 && slot !== "") : tail.length - 1;
|
|
101
101
|
for (const slot of tail.slice(0, last + 1)) args.push(slot || void 0);
|
|
102
|
+
if (probeEvidence !== void 0) args.push(probeEvidence);
|
|
102
103
|
return args;
|
|
103
104
|
}
|
|
104
105
|
//#endregion
|
|
105
|
-
//#region pipeline/content-hash.ts
|
|
106
|
-
function contentHash(source) {
|
|
107
|
-
return createHash("md5").update(source).digest("hex");
|
|
108
|
-
}
|
|
109
|
-
//#endregion
|
|
110
106
|
//#region pipeline/internal-wire.ts
|
|
111
107
|
function parseInternalWire(json, wire) {
|
|
112
108
|
let parsed;
|
|
@@ -118,6 +114,160 @@ function parseInternalWire(json, wire) {
|
|
|
118
114
|
return parsed;
|
|
119
115
|
}
|
|
120
116
|
//#endregion
|
|
117
|
+
//#region pipeline/content-hash.ts
|
|
118
|
+
function contentHash(source) {
|
|
119
|
+
return createHash("md5").update(source).digest("hex");
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region pipeline/extension-policy.ts
|
|
123
|
+
/**
|
|
124
|
+
* The one extension policy: the order in which a relative or aliased
|
|
125
|
+
* specifier's candidate files are tried. Source ingestion reads it here. The
|
|
126
|
+
* system loader and the extractor read `extension_policy.json`, which
|
|
127
|
+
* `node packages/extract/scripts/extension-policy.ts --write` generates from
|
|
128
|
+
* it, so every resolver tries the same files in the same order.
|
|
129
|
+
*
|
|
130
|
+
* The order: the base itself, the base with each appended extension, its
|
|
131
|
+
* `index` with each, then the sources an emitted NodeNext extension stands
|
|
132
|
+
* for (`./x.js` for `x.ts`), spelled exactly.
|
|
133
|
+
*/
|
|
134
|
+
const EXTENSION_POLICY = {
|
|
135
|
+
/** Appended to the base, then to `{base}/index`. */
|
|
136
|
+
appended: [
|
|
137
|
+
".ts",
|
|
138
|
+
".tsx",
|
|
139
|
+
".js",
|
|
140
|
+
".jsx",
|
|
141
|
+
".mjs"
|
|
142
|
+
],
|
|
143
|
+
/** An emitted extension, and the source extensions it names, in order. */
|
|
144
|
+
nodeNext: [
|
|
145
|
+
[".js", [
|
|
146
|
+
".ts",
|
|
147
|
+
".tsx",
|
|
148
|
+
".jsx"
|
|
149
|
+
]],
|
|
150
|
+
[".jsx", [".tsx"]],
|
|
151
|
+
[".mjs", [".mts"]],
|
|
152
|
+
[".cjs", [".cts"]]
|
|
153
|
+
]
|
|
154
|
+
};
|
|
155
|
+
const BUILT_IN_ORDER = {
|
|
156
|
+
appended: EXTENSION_POLICY.appended,
|
|
157
|
+
nodeNext: EXTENSION_POLICY.nodeNext,
|
|
158
|
+
alias: []
|
|
159
|
+
};
|
|
160
|
+
/** The files `base` can name, in policy order: itself, with each appended
|
|
161
|
+
* extension, as a directory's index with each, then the sources its
|
|
162
|
+
* emitted NodeNext extension stands for (`x.js` names `x.ts`), spelled
|
|
163
|
+
* exactly. Given `sources`, only extensions in it are tried, and under the
|
|
164
|
+
* built-in order those it lacks (`.mdx`) follow its own. A configured
|
|
165
|
+
* alias of the base's suffix replaces all of these. `index` spells a
|
|
166
|
+
* directory's index path. */
|
|
167
|
+
function policyCandidates(base, options = {}) {
|
|
168
|
+
const { sources, index = (directory, file) => `${directory}/${file}`, policy = BUILT_IN_ORDER } = options;
|
|
169
|
+
const alias = policy.alias.find(([from]) => base.endsWith(from));
|
|
170
|
+
if (alias !== void 0) {
|
|
171
|
+
const [from, sequence] = alias;
|
|
172
|
+
const stem = base.slice(0, base.length - from.length);
|
|
173
|
+
return sequence.map((to) => `${stem}${to}`);
|
|
174
|
+
}
|
|
175
|
+
const admitted = (extension) => !sources || sources.has(extension);
|
|
176
|
+
const appended = [...policy.appended.filter(admitted), ...sources && policy.appended === EXTENSION_POLICY.appended ? [...sources].filter((s) => !policy.appended.includes(s)) : []];
|
|
177
|
+
const name = base.slice(Math.max(base.lastIndexOf("/"), base.lastIndexOf("\\")) + 1);
|
|
178
|
+
const dot = name.lastIndexOf(".");
|
|
179
|
+
const emitted = dot === -1 ? "" : name.slice(dot);
|
|
180
|
+
const stem = base.slice(0, base.length - emitted.length);
|
|
181
|
+
const nodeNext = (policy.nodeNext.find(([from]) => from === emitted)?.[1] ?? []).filter(admitted);
|
|
182
|
+
return [
|
|
183
|
+
base,
|
|
184
|
+
...appended.map((extension) => `${base}${extension}`),
|
|
185
|
+
...appended.map((extension) => index(base, `index${extension}`)),
|
|
186
|
+
...nodeNext.map((source) => `${stem}${source}`)
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
/** The first of `candidates` that `see` finds, in order; a candidate found
|
|
190
|
+
* only under another case ends the probe as a mismatch. */
|
|
191
|
+
function probeCandidates(candidates, see) {
|
|
192
|
+
for (const candidate of candidates) {
|
|
193
|
+
const seen = see(candidate);
|
|
194
|
+
if (seen.kind === "file") return {
|
|
195
|
+
kind: "found",
|
|
196
|
+
path: candidate
|
|
197
|
+
};
|
|
198
|
+
if (seen.kind === "case-only") return {
|
|
199
|
+
kind: "case-mismatch",
|
|
200
|
+
candidate,
|
|
201
|
+
actual: seen.actual
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return { kind: "absent" };
|
|
205
|
+
}
|
|
206
|
+
const isFile = (path) => {
|
|
207
|
+
try {
|
|
208
|
+
return statSync(path).isFile();
|
|
209
|
+
} catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
/** Whether `directory` lists an entry spelled exactly `name`. */
|
|
214
|
+
function lists(directory, name) {
|
|
215
|
+
try {
|
|
216
|
+
return readdirSync(directory || ".").includes(name);
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** `path`'s real path as the filesystem reports it; as given when it cannot
|
|
222
|
+
* be read. */
|
|
223
|
+
const reported = (path) => {
|
|
224
|
+
try {
|
|
225
|
+
return realpathSync.native(path);
|
|
226
|
+
} catch {
|
|
227
|
+
return path;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
/** What the filesystem holds at `candidate`: a file it opens under exactly
|
|
231
|
+
* that spelling, or one it opens although a directory below the one the
|
|
232
|
+
* candidate shares with `within` lists no entry spelled as the candidate
|
|
233
|
+
* spells it (a case- or normalization-insensitive filesystem opening
|
|
234
|
+
* another spelling). Nothing is folded: the filesystem decides what opens,
|
|
235
|
+
* and its listings decide the spelling, so a file a case-sensitive
|
|
236
|
+
* filesystem cannot open is simply missing. The shared directory is
|
|
237
|
+
* spelled as given, as a specifier spells only the path from its
|
|
238
|
+
* importer's directory and a manifest only the paths in its package. `..`
|
|
239
|
+
* is taken back lexically, as Node and the bundlers resolve a specifier
|
|
240
|
+
* before opening it. The system loader reads it alike. */
|
|
241
|
+
function seeOnDisk(candidate, within) {
|
|
242
|
+
const path = normalize(candidate);
|
|
243
|
+
if (!isFile(path)) return { kind: "missing" };
|
|
244
|
+
const { root } = parse(path);
|
|
245
|
+
const names = path.slice(root.length).split(sep).filter(Boolean);
|
|
246
|
+
const baseNames = within === void 0 ? [] : normalize(within).slice(root.length).split(sep).filter(Boolean);
|
|
247
|
+
let shared = 0;
|
|
248
|
+
while (shared < baseNames.length && names[shared] === baseNames[shared] && names[shared] !== "..") shared++;
|
|
249
|
+
let directory = join(root, ...names.slice(0, shared));
|
|
250
|
+
for (const name of names.slice(shared)) {
|
|
251
|
+
if (!lists(directory, name)) return {
|
|
252
|
+
kind: "case-only",
|
|
253
|
+
actual: reported(path)
|
|
254
|
+
};
|
|
255
|
+
directory = join(directory, name);
|
|
256
|
+
}
|
|
257
|
+
return { kind: "file" };
|
|
258
|
+
}
|
|
259
|
+
/** The first of `candidates` the filesystem holds, spelled exactly below
|
|
260
|
+
* `within` when given. */
|
|
261
|
+
function probeOnDisk(candidates, within) {
|
|
262
|
+
return probeCandidates(candidates, (candidate) => seeOnDisk(candidate, within));
|
|
263
|
+
}
|
|
264
|
+
/** Why `subject` names no file: the file it would load is spelled otherwise
|
|
265
|
+
* on disk. `remedy` says what to respell. The system loader words it
|
|
266
|
+
* alike. */
|
|
267
|
+
function caseMismatchReason(subject, mismatch, remedy) {
|
|
268
|
+
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}`;
|
|
269
|
+
}
|
|
270
|
+
//#endregion
|
|
121
271
|
//#region pipeline/asset-placeholders.ts
|
|
122
272
|
const ASSET_PLACEHOLDER_PREFIX = "animus-asset:";
|
|
123
273
|
const URL_OPEN_RE = /url\(\s*(['"]?)/gi;
|
|
@@ -295,15 +445,6 @@ function warnLine(diagnostic) {
|
|
|
295
445
|
/** Stable code for selector forms with no substitutable subject; the
|
|
296
446
|
* extraction engine mints the same string. */
|
|
297
447
|
const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
298
|
-
/** The one matcher for the engine's unresolved-parent chain-drop message;
|
|
299
|
-
* consumers match through the exported helpers, never their own copy. */
|
|
300
|
-
const UNRESOLVED_PARENT_RE = /chain dropped: could not resolve parent component '([^']+)'/;
|
|
301
|
-
function isUnresolvedParentDrop(diagnostic) {
|
|
302
|
-
return UNRESOLVED_PARENT_RE.test(diagnostic.message);
|
|
303
|
-
}
|
|
304
|
-
function unresolvedParentName(diagnostic) {
|
|
305
|
-
return UNRESOLVED_PARENT_RE.exec(diagnostic.message)?.[1] ?? null;
|
|
306
|
-
}
|
|
307
448
|
const DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set([
|
|
308
449
|
"off",
|
|
309
450
|
"info",
|
|
@@ -425,7 +566,7 @@ const NO_KIT_FILES = "animus.discovery.no-kit-files";
|
|
|
425
566
|
* TypeScript source: discovery guesses its source from `src/`. */
|
|
426
567
|
const KIT_WITHOUT_SOURCE_CONDITION = "animus.discovery.kit-without-source-condition";
|
|
427
568
|
/** A kit's `animus` export condition names a file that is missing or outside
|
|
428
|
-
* its package, so that entry is
|
|
569
|
+
* its package, so that entry is read from its runtime target instead. */
|
|
429
570
|
const INVALID_KIT_SOURCE_CONDITION = "animus.discovery.invalid-source-condition";
|
|
430
571
|
/** A kit the application imports whose system the application's system
|
|
431
572
|
* does not include: its components are not extracted. */
|
|
@@ -433,10 +574,34 @@ const KIT_SYSTEM_NOT_INCLUDED = "animus.kit.system-not-included";
|
|
|
433
574
|
/** A system file's `createSystem` binding that discovery could not follow to
|
|
434
575
|
* Animus's factory, so it is no root. */
|
|
435
576
|
const UNPROVEN_ROOT_BINDING = "animus.discovery.unproven-root-binding";
|
|
577
|
+
/** A system builder, a `createSystem` chain not yet built, leaves the
|
|
578
|
+
* bindings and chains discovery follows, so kits extended on it from there
|
|
579
|
+
* are not read as members. */
|
|
580
|
+
const UNFOLLOWED_SYSTEM_BUILDER = "animus.discovery.unfollowed-system-builder";
|
|
436
581
|
/** A system file calls `createSystem` with no import or local binding. The
|
|
437
582
|
* system loader evaluates the file without auto-imports, where the name is
|
|
438
583
|
* undefined, so the call is no root. */
|
|
439
584
|
const UNIMPORTED_CREATE_SYSTEM = "animus.discovery.unimported-create-system";
|
|
585
|
+
/** A tsconfig path alias the host bundler resolves to another file than
|
|
586
|
+
* analysis does (spec §2.2 A7): report only. */
|
|
587
|
+
const ALIAS_MISMATCH = "animus.discovery.alias-mismatch";
|
|
588
|
+
/** A package the host bundler resolves to a file in no package of its own,
|
|
589
|
+
* where discovery reads the installed package instead (spec §2.2 A4):
|
|
590
|
+
* report only. */
|
|
591
|
+
const PACKAGE_MISMATCH = "animus.discovery.package-mismatch";
|
|
592
|
+
/** A system-file kit whose analysed instance is not the one the system
|
|
593
|
+
* load evaluated (spec §2.2 A4): its components would be extracted
|
|
594
|
+
* against another instance's vocabulary. */
|
|
595
|
+
const SYSTEM_INSTANCE_MISMATCH = "animus.discovery.system-instance-mismatch";
|
|
596
|
+
/** An import the host resolves, from its importer, into another instance
|
|
597
|
+
* of a discovered package whose file is not analysed and that no source
|
|
598
|
+
* redirect covers: the importer would render unextracted builder code
|
|
599
|
+
* (spec §2.2 A4, SA1). */
|
|
600
|
+
const UNREAD_PACKAGE_INSTANCE = "animus.discovery.unread-package-instance";
|
|
601
|
+
/** An import the host resolves, from its importer, into another instance
|
|
602
|
+
* of a discovered package, which a request-keyed source redirect replaces
|
|
603
|
+
* with the instance discovery read (spec §2.2 A4). */
|
|
604
|
+
const REPLACED_PACKAGE_INSTANCE = "animus.discovery.replaced-package-instance";
|
|
440
605
|
/** What a skipped source file costs: the analysis never sees what it
|
|
441
606
|
* renders. */
|
|
442
607
|
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";
|
|
@@ -522,6 +687,12 @@ const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
|
|
|
522
687
|
[KIT_STALE_DESCRIPTOR, "warn"],
|
|
523
688
|
[UNPROVEN_ROOT_BINDING, "warn"],
|
|
524
689
|
[UNIMPORTED_CREATE_SYSTEM, "warn"],
|
|
690
|
+
[UNFOLLOWED_SYSTEM_BUILDER, "warn"],
|
|
691
|
+
[ALIAS_MISMATCH, "warn"],
|
|
692
|
+
[PACKAGE_MISMATCH, "warn"],
|
|
693
|
+
[SYSTEM_INSTANCE_MISMATCH, "error"],
|
|
694
|
+
[UNREAD_PACKAGE_INSTANCE, "error"],
|
|
695
|
+
[REPLACED_PACKAGE_INSTANCE, "warn"],
|
|
525
696
|
[VOCABULARY_COLLISION, "warn"],
|
|
526
697
|
[VOCABULARY_LEGACY_VERB, "warn"],
|
|
527
698
|
[INVALID_PROPERTY_REGISTRATION, "error"],
|
|
@@ -723,6 +894,135 @@ async function preprocessMdx(source, filename) {
|
|
|
723
894
|
}
|
|
724
895
|
}
|
|
725
896
|
//#endregion
|
|
897
|
+
//#region pipeline/host-expansions.ts
|
|
898
|
+
/**
|
|
899
|
+
* The host's expansion of each listed load the expander reproduces, with
|
|
900
|
+
* each file read as the analysis and the host read it: a module the
|
|
901
|
+
* analysis holds, loaded as code without a query; a file the host loads as
|
|
902
|
+
* an opaque value (spec §2.2 A8); otherwise a file the analysis does not
|
|
903
|
+
* read. A query can select other code than the module (a plugin's
|
|
904
|
+
* transform), so a queried file that is not opaque is never the analysed
|
|
905
|
+
* module, and it keeps its query.
|
|
906
|
+
*/
|
|
907
|
+
function hostExpansions(loads, rootDir, analysed, expander, isAsset) {
|
|
908
|
+
const expansions = [];
|
|
909
|
+
for (const load of loads) {
|
|
910
|
+
const expanded = expander.expand(load, rootDir);
|
|
911
|
+
if (expanded === void 0) continue;
|
|
912
|
+
const files = /* @__PURE__ */ new Map();
|
|
913
|
+
for (const { path, query } of expanded) {
|
|
914
|
+
const opaque = isAsset?.(join(rootDir, path), query) ?? false;
|
|
915
|
+
const status = query === "" && analysed.has(path) ? "analysed" : opaque ? "opaque" : "unanalysed";
|
|
916
|
+
const key = `${path}${query}`;
|
|
917
|
+
files.set(key, {
|
|
918
|
+
path: status === "analysed" ? path : key,
|
|
919
|
+
status
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
expansions.push({
|
|
923
|
+
importer: load.importer,
|
|
924
|
+
start: load.start,
|
|
925
|
+
closed: true,
|
|
926
|
+
files: [...files.values()]
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
return expansions;
|
|
930
|
+
}
|
|
931
|
+
//#endregion
|
|
932
|
+
//#region pipeline/probe-evidence.ts
|
|
933
|
+
let generations = 0;
|
|
934
|
+
/** `rootDir` at its real path, where the filesystem reports spellings. */
|
|
935
|
+
function realRoot(rootDir) {
|
|
936
|
+
try {
|
|
937
|
+
return realpathSync.native(rootDir);
|
|
938
|
+
} catch {
|
|
939
|
+
return rootDir;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* What the host's filesystem opens for `base` (spec §2.2 A2, A8): the first
|
|
944
|
+
* of its candidates, in the host's order, that the host opens. The
|
|
945
|
+
* filesystem decides what opens, and each name below the session root is
|
|
946
|
+
* checked against its own directory's listing (`seeOnDisk`); nothing is
|
|
947
|
+
* folded. Null where no candidate opens.
|
|
948
|
+
*
|
|
949
|
+
* A candidate the analysis holds answers before the filesystem is asked: an
|
|
950
|
+
* adapted original's analysis child need not exist on disk. A file the host
|
|
951
|
+
* opens that the analysis holds no module for is read as an adapted
|
|
952
|
+
* original (analysed as its first later child), an asset, or a file
|
|
953
|
+
* analysis never reads.
|
|
954
|
+
*/
|
|
955
|
+
function hostCandidate(rootDir, base, analysed, order, readings = {}, root = realRoot(rootDir)) {
|
|
956
|
+
const at = base.indexOf("?");
|
|
957
|
+
const query = at === -1 ? "" : base.slice(at);
|
|
958
|
+
const candidates = policyCandidates(at === -1 ? base : base.slice(0, at), { policy: order });
|
|
959
|
+
for (const [index, file] of candidates.entries()) {
|
|
960
|
+
const candidate = `${file}${query}`;
|
|
961
|
+
const opaque = () => readings.isAsset?.(join(rootDir, file), query);
|
|
962
|
+
if (analysed.has(file)) return query !== "" && opaque() ? {
|
|
963
|
+
candidate,
|
|
964
|
+
actual: null,
|
|
965
|
+
analysedAs: null,
|
|
966
|
+
reading: "asset"
|
|
967
|
+
} : {
|
|
968
|
+
candidate,
|
|
969
|
+
actual: null,
|
|
970
|
+
analysedAs: file
|
|
971
|
+
};
|
|
972
|
+
const seen = seeOnDisk(join(rootDir, file), rootDir);
|
|
973
|
+
if (seen.kind === "missing") continue;
|
|
974
|
+
if (seen.kind === "case-only") return {
|
|
975
|
+
candidate,
|
|
976
|
+
actual: relative(root, seen.actual),
|
|
977
|
+
analysedAs: null
|
|
978
|
+
};
|
|
979
|
+
const children = readings.adapted?.get(file);
|
|
980
|
+
if (children !== void 0) return {
|
|
981
|
+
candidate,
|
|
982
|
+
actual: null,
|
|
983
|
+
analysedAs: candidates.slice(index + 1).find((later) => children.includes(later)) ?? null,
|
|
984
|
+
reading: "adapted"
|
|
985
|
+
};
|
|
986
|
+
return {
|
|
987
|
+
candidate,
|
|
988
|
+
actual: null,
|
|
989
|
+
analysedAs: null,
|
|
990
|
+
reading: opaque() ? "asset" : "unanalysed"
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* The session's host-candidate evidence for one analysis (spec §2.3): each
|
|
997
|
+
* probe base the engine's `prepare` names, as `hostCandidate` reads it, and
|
|
998
|
+
* the host's expansion of each computed load it lists (spec §6.3). The
|
|
999
|
+
* evidence carries the input identity `prepare` reported, and each call is a
|
|
1000
|
+
* new ingest generation, so no evidence is read for other files.
|
|
1001
|
+
*/
|
|
1002
|
+
function gatherProbeEvidence(rootDir, analysed, order, readings = {}) {
|
|
1003
|
+
const root = realRoot(rootDir);
|
|
1004
|
+
return (bases, identity, loads = []) => {
|
|
1005
|
+
const byBase = {};
|
|
1006
|
+
for (const base of bases) {
|
|
1007
|
+
const host = hostCandidate(rootDir, base, analysed, order, readings, root);
|
|
1008
|
+
if (host !== null) byBase[base] = host;
|
|
1009
|
+
}
|
|
1010
|
+
const expansions = readings.expander === void 0 ? [] : hostExpansions(loads, rootDir, analysed, readings.expander, readings.isAsset);
|
|
1011
|
+
generations += 1;
|
|
1012
|
+
return JSON.stringify({
|
|
1013
|
+
generation: generations,
|
|
1014
|
+
identity,
|
|
1015
|
+
bases: byBase,
|
|
1016
|
+
...expansions.length > 0 && { expansions }
|
|
1017
|
+
});
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
/** Each adapted original and its analysis children, from ingestion's
|
|
1021
|
+
* ownership: an original whose children are other paths than its own. */
|
|
1022
|
+
function adaptedOriginals(ownership) {
|
|
1023
|
+
return new Map(Object.entries(ownership).filter(([original, { analysisPaths }]) => !(analysisPaths.length === 1 && analysisPaths[0] === original)).map(([original, { analysisPaths }]) => [original, analysisPaths]));
|
|
1024
|
+
}
|
|
1025
|
+
//#endregion
|
|
726
1026
|
//#region pipeline/svelte-source-adapter.ts
|
|
727
1027
|
const isCompilerReference = (value) => Object(value) === value;
|
|
728
1028
|
const isCompilerCallable = (value) => {
|
|
@@ -820,14 +1120,14 @@ function sourceLocation(source, node) {
|
|
|
820
1120
|
function createsNestedBindingScope(node) {
|
|
821
1121
|
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";
|
|
822
1122
|
}
|
|
823
|
-
function walk(node, visit, nestedScopeDepth = 0) {
|
|
1123
|
+
function walk$1(node, visit, nestedScopeDepth = 0) {
|
|
824
1124
|
visit(node, nestedScopeDepth);
|
|
825
1125
|
const childScopeDepth = nestedScopeDepth + (createsNestedBindingScope(node) ? 1 : 0);
|
|
826
1126
|
for (const [key, value] of Object.entries(node)) {
|
|
827
1127
|
if (key === "loc" || key === "start" || key === "end") continue;
|
|
828
1128
|
if (Array.isArray(value)) {
|
|
829
|
-
for (const item of value) if (isNode(item)) walk(item, visit, childScopeDepth);
|
|
830
|
-
} else if (isNode(value)) walk(value, visit, childScopeDepth);
|
|
1129
|
+
for (const item of value) if (isNode(item)) walk$1(item, visit, childScopeDepth);
|
|
1130
|
+
} else if (isNode(value)) walk$1(value, visit, childScopeDepth);
|
|
831
1131
|
}
|
|
832
1132
|
}
|
|
833
1133
|
/**
|
|
@@ -1029,7 +1329,7 @@ function isJsxAttributeName(name) {
|
|
|
1029
1329
|
}
|
|
1030
1330
|
function tsxIncompatibleValue(value) {
|
|
1031
1331
|
let incompatible = null;
|
|
1032
|
-
walk(value, (node) => {
|
|
1332
|
+
walk$1(value, (node) => {
|
|
1033
1333
|
if (incompatible) return;
|
|
1034
1334
|
if (node.type === "TSTypeAssertion" || node.type === "ArrowFunctionExpression" && childNode(node.typeParameters) !== null) incompatible = node;
|
|
1035
1335
|
});
|
|
@@ -1126,7 +1426,7 @@ function projectScope(script, scope, source, originalPath, options, inherited, p
|
|
|
1126
1426
|
const bindings = inherited ? new Map([...inherited.bindings, ...ownBindings]) : ownBindings;
|
|
1127
1427
|
const witnesses = [];
|
|
1128
1428
|
const diagnostics = [];
|
|
1129
|
-
if (bindings.size > 0) walk(script.content, (node, nestedScopeDepth) => {
|
|
1429
|
+
if (bindings.size > 0) walk$1(script.content, (node, nestedScopeDepth) => {
|
|
1130
1430
|
const site = resolverCallSite(node, bindings);
|
|
1131
1431
|
if (!site) return;
|
|
1132
1432
|
const { access, form } = site;
|
|
@@ -1291,17 +1591,6 @@ function parseFilesJson(filesJson, context) {
|
|
|
1291
1591
|
function isAdvisorySourceDiagnostic(diagnostic) {
|
|
1292
1592
|
return diagnostic.code === "SOURCE_NATIVE_PARSE_ERROR";
|
|
1293
1593
|
}
|
|
1294
|
-
const RELATIVE_PROBE_SUFFIXES = [
|
|
1295
|
-
"",
|
|
1296
|
-
".ts",
|
|
1297
|
-
".tsx",
|
|
1298
|
-
".js",
|
|
1299
|
-
".jsx",
|
|
1300
|
-
"/index.ts",
|
|
1301
|
-
"/index.tsx",
|
|
1302
|
-
"/index.js",
|
|
1303
|
-
"/index.jsx"
|
|
1304
|
-
];
|
|
1305
1594
|
function extension(path) {
|
|
1306
1595
|
const basename = posix.basename(path);
|
|
1307
1596
|
const dot = basename.lastIndexOf(".");
|
|
@@ -1310,27 +1599,40 @@ function extension(path) {
|
|
|
1310
1599
|
function canonicalResolverPath(path) {
|
|
1311
1600
|
return posix.normalize(path.replaceAll("\\", "/"));
|
|
1312
1601
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
".tsx",
|
|
1317
|
-
".jsx"
|
|
1318
|
-
],
|
|
1319
|
-
".jsx": [".tsx"],
|
|
1320
|
-
".mjs": [".mts"],
|
|
1321
|
-
".cjs": [".cts"]
|
|
1322
|
-
};
|
|
1323
|
-
/** The paths a relative specifier can name from `importerPath`, in probe
|
|
1324
|
-
* order: as written with each source suffix, then a NodeNext emitted
|
|
1325
|
-
* extension's sources. Empty for a non-relative specifier. */
|
|
1326
|
-
function relativeSourceCandidates(importerPath, specifier) {
|
|
1602
|
+
/** The paths a relative specifier can name from `importerPath`, in the
|
|
1603
|
+
* extension policy's probe order. Empty for a non-relative specifier. */
|
|
1604
|
+
function relativeSourceCandidates(importerPath, specifier, policy) {
|
|
1327
1605
|
if (!specifier.startsWith(".")) return [];
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1606
|
+
return policyCandidates(posix.normalize(posix.join(posix.dirname(canonicalResolverPath(importerPath)), specifier)), { policy });
|
|
1607
|
+
}
|
|
1608
|
+
function resolveRelativeSource(importerPath, specifier, files, analysed, opened, policy, host) {
|
|
1609
|
+
if (host !== void 0 && specifier.startsWith(".")) {
|
|
1610
|
+
const first = hostCandidate(host.rootDir, posix.normalize(posix.join(posix.dirname(canonicalResolverPath(importerPath)), specifier)), analysed, policy, { adapted: host.adapted });
|
|
1611
|
+
if (first !== null) {
|
|
1612
|
+
if (first.actual) {
|
|
1613
|
+
opened({
|
|
1614
|
+
candidate: first.candidate,
|
|
1615
|
+
opened: first.actual,
|
|
1616
|
+
why: "case-mismatch"
|
|
1617
|
+
});
|
|
1618
|
+
return null;
|
|
1619
|
+
}
|
|
1620
|
+
if (first.reading === "unanalysed") {
|
|
1621
|
+
const candidates = relativeSourceCandidates(importerPath, specifier, policy);
|
|
1622
|
+
const later = candidates.slice(candidates.indexOf(first.candidate) + 1).find((candidate) => files.has(candidate));
|
|
1623
|
+
const opening = {
|
|
1624
|
+
candidate: first.candidate,
|
|
1625
|
+
opened: first.candidate,
|
|
1626
|
+
why: "skipped"
|
|
1627
|
+
};
|
|
1628
|
+
if (later !== void 0) opening.later = later;
|
|
1629
|
+
opened(opening);
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
return first.analysedAs === null ? null : files.get(first.analysedAs) ?? null;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
for (const candidate of relativeSourceCandidates(importerPath, specifier, policy)) {
|
|
1334
1636
|
const actualPath = files.get(candidate);
|
|
1335
1637
|
if (actualPath !== void 0) return actualPath;
|
|
1336
1638
|
}
|
|
@@ -1338,15 +1640,22 @@ function resolveRelativeSource(importerPath, specifier, files) {
|
|
|
1338
1640
|
}
|
|
1339
1641
|
var ResolverExportIndex = class {
|
|
1340
1642
|
facts;
|
|
1643
|
+
extensions;
|
|
1644
|
+
host;
|
|
1341
1645
|
collisions;
|
|
1342
1646
|
files;
|
|
1647
|
+
analysed;
|
|
1648
|
+
/** Each resolver call that ended Incomplete, once. */
|
|
1649
|
+
openings = /* @__PURE__ */ new Map();
|
|
1343
1650
|
resolverBindings = /* @__PURE__ */ new Map();
|
|
1344
1651
|
/** Both memos live for one ingest only — the index is rebuilt per call,
|
|
1345
1652
|
* so neither needs invalidation. */
|
|
1346
1653
|
attributionMemo = /* @__PURE__ */ new Map();
|
|
1347
1654
|
resolveMemo = /* @__PURE__ */ new Map();
|
|
1348
|
-
constructor(facts, analysisPaths) {
|
|
1655
|
+
constructor(facts, analysisPaths, extensions, host) {
|
|
1349
1656
|
this.facts = facts;
|
|
1657
|
+
this.extensions = extensions;
|
|
1658
|
+
this.host = host;
|
|
1350
1659
|
const pathsByCanonical = /* @__PURE__ */ new Map();
|
|
1351
1660
|
for (const path of analysisPaths) {
|
|
1352
1661
|
const canonicalPath = canonicalResolverPath(path);
|
|
@@ -1371,6 +1680,7 @@ var ResolverExportIndex = class {
|
|
|
1371
1680
|
if (paths.length === 1 && factPaths.length === 1) files.set(canonicalPath, factPaths[0]);
|
|
1372
1681
|
}
|
|
1373
1682
|
this.files = files;
|
|
1683
|
+
this.analysed = new Set(files.keys());
|
|
1374
1684
|
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)));
|
|
1375
1685
|
}
|
|
1376
1686
|
attribute(importerPath, request) {
|
|
@@ -1391,7 +1701,11 @@ var ResolverExportIndex = class {
|
|
|
1391
1701
|
const key = `${importerPath}\0${specifier}`;
|
|
1392
1702
|
let resolved = this.resolveMemo.get(key);
|
|
1393
1703
|
if (resolved === void 0) {
|
|
1394
|
-
resolved = resolveRelativeSource(importerPath, specifier, this.files)
|
|
1704
|
+
resolved = resolveRelativeSource(importerPath, specifier, this.files, this.analysed, (opening) => this.openings.set(key, {
|
|
1705
|
+
importer: importerPath,
|
|
1706
|
+
specifier,
|
|
1707
|
+
...opening
|
|
1708
|
+
}), this.extensions, this.host);
|
|
1395
1709
|
this.resolveMemo.set(key, resolved);
|
|
1396
1710
|
}
|
|
1397
1711
|
return resolved;
|
|
@@ -1513,7 +1827,10 @@ async function ingestSourceEntries(rawEntries, options) {
|
|
|
1513
1827
|
messages: file.parseDiagnostics
|
|
1514
1828
|
});
|
|
1515
1829
|
}
|
|
1516
|
-
const resolvers = new ResolverExportIndex(facts, analysisEntries.map((entry) => entry.path)
|
|
1830
|
+
const resolvers = new ResolverExportIndex(facts, analysisEntries.map((entry) => entry.path), options.extensions, options.rootDir === void 0 ? void 0 : {
|
|
1831
|
+
rootDir: options.rootDir,
|
|
1832
|
+
adapted: adaptedOriginals(ownership)
|
|
1833
|
+
});
|
|
1517
1834
|
for (const { canonicalPath, paths } of resolvers.collisions) for (let index = 0; index < paths.length; index += 1) {
|
|
1518
1835
|
const path = paths[index];
|
|
1519
1836
|
const conflictingPath = paths[(index + 1) % paths.length];
|
|
@@ -1548,13 +1865,14 @@ async function ingestSourceEntries(rawEntries, options) {
|
|
|
1548
1865
|
diagnostics
|
|
1549
1866
|
};
|
|
1550
1867
|
if (abortedParses.length > 0) result.abortedParses = abortedParses;
|
|
1868
|
+
if (resolvers.openings.size > 0) result.openings = [...resolvers.openings.values()];
|
|
1551
1869
|
return result;
|
|
1552
1870
|
}
|
|
1553
1871
|
/**
|
|
1554
1872
|
* `parseCount` counts the parses performed by THIS call, so a fully-memoized
|
|
1555
1873
|
* pass reports zero.
|
|
1556
1874
|
*/
|
|
1557
|
-
function collectFileFacts(analysisEntries, options) {
|
|
1875
|
+
function collectFileFacts(analysisEntries, options, evict = true) {
|
|
1558
1876
|
const cache = options.factsCache;
|
|
1559
1877
|
if (!cache) return JSON.parse(options.extractFacts(JSON.stringify(analysisEntries)));
|
|
1560
1878
|
const pending = analysisEntries.filter((entry) => cache.get(entry.path)?.hash !== entry.hash);
|
|
@@ -1571,8 +1889,10 @@ function collectFileFacts(analysisEntries, options) {
|
|
|
1571
1889
|
else cache.delete(entry.path);
|
|
1572
1890
|
}
|
|
1573
1891
|
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1892
|
+
if (evict) {
|
|
1893
|
+
const currentPaths = new Set(analysisEntries.map((entry) => entry.path));
|
|
1894
|
+
for (const path of [...cache.keys()]) if (!currentPaths.has(path)) cache.delete(path);
|
|
1895
|
+
}
|
|
1576
1896
|
const files = {};
|
|
1577
1897
|
for (const entry of analysisEntries) {
|
|
1578
1898
|
const cached = cache.get(entry.path);
|
|
@@ -1622,15 +1942,26 @@ function createSourceIngestor(host) {
|
|
|
1622
1942
|
/** Non-strict dedupe: a quarantined original re-ingests on every later
|
|
1623
1943
|
* corpus pass, so re-warning it on each save is noise. */
|
|
1624
1944
|
const warnedByOriginal = /* @__PURE__ */ new Map();
|
|
1945
|
+
const extractFacts = () => {
|
|
1946
|
+
const extract = host.engineApi().extractFacts;
|
|
1947
|
+
if (extract === void 0) throw new Error(`${host.prefix} native engine does not expose extractFacts required for source adaptation`);
|
|
1948
|
+
return extract;
|
|
1949
|
+
};
|
|
1625
1950
|
return {
|
|
1626
1951
|
async ingest(entries) {
|
|
1627
|
-
const extractFacts = host.engineApi().extractFacts;
|
|
1628
|
-
if (extractFacts === void 0) throw new Error(`${host.prefix} native engine does not expose extractFacts required for source adaptation`);
|
|
1629
1952
|
return ingestSourceEntries(entries, {
|
|
1630
|
-
extractFacts,
|
|
1631
|
-
factsCache
|
|
1953
|
+
extractFacts: extractFacts(),
|
|
1954
|
+
factsCache,
|
|
1955
|
+
extensions: host.extensions?.(),
|
|
1956
|
+
rootDir: host.rootDir?.()
|
|
1632
1957
|
});
|
|
1633
1958
|
},
|
|
1959
|
+
facts(entries) {
|
|
1960
|
+
return collectFileFacts(entries, {
|
|
1961
|
+
extractFacts: extractFacts(),
|
|
1962
|
+
factsCache
|
|
1963
|
+
}, false);
|
|
1964
|
+
},
|
|
1634
1965
|
surfaceDiagnostics(diagnostics) {
|
|
1635
1966
|
const fatal = diagnostics.filter((diagnostic) => !isAdvisorySourceDiagnostic(diagnostic));
|
|
1636
1967
|
const invalidOriginals = new Set(fatal.map((diagnostic) => diagnostic.originalPath));
|
|
@@ -1678,9 +2009,16 @@ function createV2EngineApi(deps) {
|
|
|
1678
2009
|
return {
|
|
1679
2010
|
loadSystemModule: (...args) => native.loadSystemModule(...args),
|
|
1680
2011
|
extractFacts: (filesJson) => native.extractFacts(filesJson),
|
|
1681
|
-
moduleSpecifiers: (filesJson) => native.moduleSpecifiers(filesJson),
|
|
2012
|
+
moduleSpecifiers: (filesJson, pathAliasesJson) => native.moduleSpecifiers(filesJson, pathAliasesJson),
|
|
2013
|
+
systemMembership: (inputsJson) => native.systemMembership(inputsJson),
|
|
1682
2014
|
diagnosticCodes: () => native.diagnosticCodes(),
|
|
1683
|
-
|
|
2015
|
+
resolveSpecifier: native.resolveSpecifier === void 0 ? void 0 : (specifier, fromDir, conditions, workspaces, extensionPolicyJson) => native.resolveSpecifier(specifier, fromDir, conditions, workspaces, extensionPolicyJson),
|
|
2016
|
+
fingerprintFile: native.fingerprintFile === void 0 ? void 0 : (path) => native.fingerprintFile(path) ?? null,
|
|
2017
|
+
fingerprintBytes: native.fingerprintBytes === void 0 ? void 0 : (bytes) => native.fingerprintBytes(bytes),
|
|
2018
|
+
declaresKitSource: native.declaresKitSource === void 0 ? void 0 : (packageDir) => native.declaresKitSource(packageDir),
|
|
2019
|
+
locatePackage: native.locatePackage === void 0 ? void 0 : (name, fromDir, workspaces) => native.locatePackage(name, fromDir, workspaces) ?? null,
|
|
2020
|
+
resolveKitSourceRoot: native.resolveKitSourceRoot === void 0 ? void 0 : (specifier, fromDir, conditions, workspaces, extensionPolicyJson, hostEntry, packageDir) => native.resolveKitSourceRoot(specifier, fromDir, conditions, workspaces, extensionPolicyJson, hostEntry, packageDir),
|
|
2021
|
+
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) => {
|
|
1684
2022
|
const filesJson = deps.rehydrateFilesJson ? deps.rehydrateFilesJson(filesJsonRaw) : filesJsonRaw;
|
|
1685
2023
|
const sent = /* @__PURE__ */ new Map();
|
|
1686
2024
|
for (const entry of parseFilesJson(filesJson, label)) sent.set(entry.path, entry.source);
|
|
@@ -1714,7 +2052,12 @@ function createV2EngineApi(deps) {
|
|
|
1714
2052
|
};
|
|
1715
2053
|
const engine = new native.ExtractEngine(config);
|
|
1716
2054
|
store.setEngine(engine);
|
|
1717
|
-
|
|
2055
|
+
let evidence;
|
|
2056
|
+
if (probeEvidence !== void 0) {
|
|
2057
|
+
const prepared = parseInternalWire(engine.prepare(filesJson), "ExtractEngine.prepare");
|
|
2058
|
+
evidence = probeEvidence(prepared.bases, prepared.identity, prepared.loads);
|
|
2059
|
+
}
|
|
2060
|
+
return engine.analyze(filesJson, evidence);
|
|
1718
2061
|
},
|
|
1719
2062
|
transformFile: (source, path, _manifest) => {
|
|
1720
2063
|
const engine = store.getEngine();
|
|
@@ -1740,10 +2083,112 @@ function createV2EngineApi(deps) {
|
|
|
1740
2083
|
};
|
|
1741
2084
|
}
|
|
1742
2085
|
//#endregion
|
|
1743
|
-
//#region pipeline/
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2086
|
+
//#region pipeline/source-identity.ts
|
|
2087
|
+
/**
|
|
2088
|
+
* One derivation of source identity for discovery, watch ingestion, ownership
|
|
2089
|
+
* and deletion: event paths are lookup INPUTS only and never fork identity.
|
|
2090
|
+
*/
|
|
2091
|
+
/**
|
|
2092
|
+
* True when `target` is `root` or a descendant, decided by `relative()`
|
|
2093
|
+
* shape: string prefixing would let `/ui` claim `/ui-old`.
|
|
2094
|
+
*/
|
|
2095
|
+
function isPathWithinRoot(root, target, pathApi = path) {
|
|
2096
|
+
const rel = pathApi.relative(root, target);
|
|
2097
|
+
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* True when two paths share a platform root (win32 drive letter or UNC
|
|
2101
|
+
* share; always true on posix). Drive letters compare case-insensitively.
|
|
2102
|
+
*/
|
|
2103
|
+
function sharesVolumeRoot(a, b, pathApi = path) {
|
|
2104
|
+
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
2105
|
+
return volumeOf(a) === volumeOf(b);
|
|
2106
|
+
}
|
|
2107
|
+
function canonicalize(p) {
|
|
2108
|
+
try {
|
|
2109
|
+
return realpathSync(p);
|
|
2110
|
+
} catch {
|
|
2111
|
+
return null;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
function createSourceIdentity(rootDir) {
|
|
2115
|
+
const normalizedRootDir = path.normalize(rootDir);
|
|
2116
|
+
const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
|
|
2117
|
+
const roots = [];
|
|
2118
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
2119
|
+
const owningRecord = (canonicalPath) => {
|
|
2120
|
+
let owner = null;
|
|
2121
|
+
for (const record of roots) {
|
|
2122
|
+
if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
|
|
2123
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2124
|
+
}
|
|
2125
|
+
return owner;
|
|
2126
|
+
};
|
|
2127
|
+
return {
|
|
2128
|
+
rootDir: normalizedRootDir,
|
|
2129
|
+
canonicalRootDir,
|
|
2130
|
+
registerExternalRoot(root) {
|
|
2131
|
+
const asRegistered = path.normalize(root);
|
|
2132
|
+
const canonical = canonicalize(asRegistered) ?? asRegistered;
|
|
2133
|
+
const existing = roots.find((record) => record.canonical === canonical);
|
|
2134
|
+
if (existing) return existing.canonical;
|
|
2135
|
+
roots.push({
|
|
2136
|
+
asRegistered,
|
|
2137
|
+
canonical
|
|
2138
|
+
});
|
|
2139
|
+
return canonical;
|
|
2140
|
+
},
|
|
2141
|
+
externalRoots() {
|
|
2142
|
+
return roots.map((record) => record.canonical);
|
|
2143
|
+
},
|
|
2144
|
+
resolveSourceId(inputPath) {
|
|
2145
|
+
const lexical = path.normalize(inputPath);
|
|
2146
|
+
const canonical = canonicalize(lexical);
|
|
2147
|
+
if (canonical === null) return null;
|
|
2148
|
+
const owner = owningRecord(canonical);
|
|
2149
|
+
const ownedBy = (record) => {
|
|
2150
|
+
const pathInRoot = path.relative(record.canonical, canonical);
|
|
2151
|
+
return {
|
|
2152
|
+
sourceKey: path.relative(normalizedRootDir, path.join(record.asRegistered, pathInRoot)),
|
|
2153
|
+
owningRoot: record.canonical,
|
|
2154
|
+
pathInRoot
|
|
2155
|
+
};
|
|
2156
|
+
};
|
|
2157
|
+
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
2158
|
+
let resolved;
|
|
2159
|
+
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
2160
|
+
const key = path.relative(canonicalRootDir, canonical);
|
|
2161
|
+
resolved = {
|
|
2162
|
+
sourceKey: key,
|
|
2163
|
+
owningRoot: null,
|
|
2164
|
+
pathInRoot: key
|
|
2165
|
+
};
|
|
2166
|
+
} else if (owner) resolved = ownedBy(owner);
|
|
2167
|
+
else return null;
|
|
2168
|
+
aliases.set(lexical, resolved);
|
|
2169
|
+
aliases.set(canonical, resolved);
|
|
2170
|
+
return resolved;
|
|
2171
|
+
},
|
|
2172
|
+
resolveDeletedSourceId(inputPath) {
|
|
2173
|
+
return aliases.get(path.normalize(inputPath)) ?? null;
|
|
2174
|
+
},
|
|
2175
|
+
containingExternalRoot(inputPath) {
|
|
2176
|
+
const lexical = path.normalize(inputPath);
|
|
2177
|
+
let owner = null;
|
|
2178
|
+
for (const record of roots) {
|
|
2179
|
+
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
2180
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2181
|
+
}
|
|
2182
|
+
if (owner) return owner.canonical;
|
|
2183
|
+
const canonical = canonicalize(lexical);
|
|
2184
|
+
if (canonical === null) return null;
|
|
2185
|
+
for (const record of roots) {
|
|
2186
|
+
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
2187
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2188
|
+
}
|
|
2189
|
+
return owner?.canonical ?? null;
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
1747
2192
|
}
|
|
1748
2193
|
//#endregion
|
|
1749
2194
|
//#region pipeline/core-options.ts
|
|
@@ -1852,6 +2297,11 @@ const CORE_VALUE_GATES = [
|
|
|
1852
2297
|
ok: isString,
|
|
1853
2298
|
expected: "a string path"
|
|
1854
2299
|
},
|
|
2300
|
+
{
|
|
2301
|
+
key: "root",
|
|
2302
|
+
ok: isString,
|
|
2303
|
+
expected: "a string path"
|
|
2304
|
+
},
|
|
1855
2305
|
{
|
|
1856
2306
|
key: "exclude",
|
|
1857
2307
|
ok: isStringArray,
|
|
@@ -1970,30 +2420,101 @@ function globToRegExp(glob) {
|
|
|
1970
2420
|
}
|
|
1971
2421
|
return new RegExp(`^${out}$`);
|
|
1972
2422
|
}
|
|
2423
|
+
/** Whether a root-relative path is `dir` or lies under it, a literal path
|
|
2424
|
+
* prefix: an output name is never a pattern. */
|
|
2425
|
+
function compileOutputDir(dir) {
|
|
2426
|
+
return (_full, rel) => {
|
|
2427
|
+
const normalized = rel.split("\\").join("/");
|
|
2428
|
+
return normalized === dir || normalized.startsWith(`${dir}/`);
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
1973
2431
|
/**
|
|
1974
|
-
* A user list replaces only the replaceable defaults.
|
|
1975
|
-
*
|
|
2432
|
+
* A user list replaces only the replaceable defaults. A host's output
|
|
2433
|
+
* directories (`outputExclusion`) always apply, whatever the user's list.
|
|
1976
2434
|
*/
|
|
1977
|
-
function createExcludeMatcher(userPatterns,
|
|
1978
|
-
const
|
|
1979
|
-
|
|
1980
|
-
for (const pattern of
|
|
1981
|
-
|
|
1982
|
-
|
|
2435
|
+
function createExcludeMatcher(userPatterns, outputDirs = []) {
|
|
2436
|
+
const userList = userPatterns ?? REPLACEABLE_DEFAULT_EXCLUDE;
|
|
2437
|
+
const compiled = [];
|
|
2438
|
+
for (const pattern of STRUCTURAL_EXCLUDE) compiled.push({
|
|
2439
|
+
pattern,
|
|
2440
|
+
test: compilePattern(pattern),
|
|
2441
|
+
isUser: userList.includes(pattern)
|
|
2442
|
+
});
|
|
2443
|
+
for (const dir of outputDirs) compiled.push({
|
|
2444
|
+
pattern: dir,
|
|
2445
|
+
test: compileOutputDir(dir),
|
|
2446
|
+
isUser: false
|
|
2447
|
+
});
|
|
2448
|
+
for (const pattern of userList) {
|
|
2449
|
+
if (STRUCTURAL_EXCLUDE.includes(pattern)) continue;
|
|
2450
|
+
compiled.push({
|
|
2451
|
+
pattern,
|
|
2452
|
+
test: compilePattern(pattern),
|
|
2453
|
+
isUser: true
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
const hits = new Map(compiled.map((c) => [c.pattern, 0]));
|
|
1983
2457
|
const explain = (full, rel) => {
|
|
1984
|
-
|
|
2458
|
+
let excludedBy = null;
|
|
2459
|
+
for (const { pattern, test, isUser } of compiled) {
|
|
2460
|
+
if (excludedBy !== null && !isUser) continue;
|
|
2461
|
+
if (!test(full, rel)) continue;
|
|
1985
2462
|
hits.set(pattern, (hits.get(pattern) ?? 0) + 1);
|
|
1986
|
-
|
|
2463
|
+
excludedBy ??= pattern;
|
|
1987
2464
|
}
|
|
1988
|
-
return
|
|
2465
|
+
return excludedBy;
|
|
1989
2466
|
};
|
|
1990
2467
|
return {
|
|
1991
|
-
patterns:
|
|
2468
|
+
patterns: compiled.map((c) => c.pattern),
|
|
1992
2469
|
matches: (full, rel) => explain(full, rel) !== null,
|
|
1993
2470
|
explain,
|
|
1994
|
-
stats: () => hits
|
|
2471
|
+
stats: () => hits,
|
|
2472
|
+
unmatched: () => (userPatterns ?? []).filter((pattern) => hits.get(pattern) === 0)
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
/** One line per user pattern that matched nothing, which every host
|
|
2476
|
+
* prints to stderr after its first discovery, as the CLI always has. */
|
|
2477
|
+
function unmatchedExcludeLines(matcher) {
|
|
2478
|
+
return matcher.unmatched().map((pattern) => `[animus] exclude pattern '${pattern}' matched nothing`);
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* A host's output directory as an exclusion: root-relative with `/`
|
|
2482
|
+
* separators, matched as a literal path prefix, so a user list, which
|
|
2483
|
+
* replaces the defaults, never re-admits output. Null when the directory is
|
|
2484
|
+
* outside the root or is the root itself.
|
|
2485
|
+
*/
|
|
2486
|
+
function outputExclusion(root, outDir) {
|
|
2487
|
+
if (!isPathWithinRoot(root, outDir)) return null;
|
|
2488
|
+
const rel = relative$1(root, outDir);
|
|
2489
|
+
return rel === "" ? null : rel.split(sep$1).join("/");
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* The output directory a source file's real path lies in, or null. Applied
|
|
2493
|
+
* where a host assembles its analysis inputs: a file reached under another
|
|
2494
|
+
* spelling, through a source-tree link or a package's entry, is output too.
|
|
2495
|
+
*/
|
|
2496
|
+
function outputSourceGuard(root, outputDirs) {
|
|
2497
|
+
if (outputDirs.length === 0) return () => null;
|
|
2498
|
+
const realDirs = outputDirs.map((dir) => ({
|
|
2499
|
+
dir,
|
|
2500
|
+
real: realPathOf(resolve$1(root, dir))
|
|
2501
|
+
}));
|
|
2502
|
+
return (absPath) => {
|
|
2503
|
+
const real = realPathOf(absPath);
|
|
2504
|
+
return realDirs.find((o) => isPathWithinRoot(o.real, real))?.dir ?? null;
|
|
1995
2505
|
};
|
|
1996
2506
|
}
|
|
2507
|
+
/** The warning for a source a host refused as output. */
|
|
2508
|
+
function outputSourceMessage(relPath, outputDir) {
|
|
2509
|
+
return `${relPath} resolves into the output directory '${outputDir}', which is never source; it is not analysed`;
|
|
2510
|
+
}
|
|
2511
|
+
function realPathOf(path) {
|
|
2512
|
+
try {
|
|
2513
|
+
return realpathSync$1(path);
|
|
2514
|
+
} catch {
|
|
2515
|
+
return path;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
1997
2518
|
function resolveMode(explicit, driverDefault) {
|
|
1998
2519
|
if (explicit === "development" || explicit === "production") return {
|
|
1999
2520
|
mode: explicit,
|
|
@@ -2005,18 +2526,92 @@ function resolveMode(explicit, driverDefault) {
|
|
|
2005
2526
|
};
|
|
2006
2527
|
}
|
|
2007
2528
|
//#endregion
|
|
2008
|
-
//#region pipeline/
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2529
|
+
//#region pipeline/engine-retirement.ts
|
|
2530
|
+
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.";
|
|
2531
|
+
/**
|
|
2532
|
+
* v2 is the only engine (SA2): the option and `ANIMUS_ENGINE`, a startup
|
|
2533
|
+
* input a worker may pass as captured, accept `v2` or nothing. Hosts call
|
|
2534
|
+
* this before the native module loads, so another selection never reaches
|
|
2535
|
+
* it; either fails as a configuration error naming its source.
|
|
2536
|
+
*/
|
|
2537
|
+
function assertSupportedEngine(engineOption, environmentSelection = process.env.ANIMUS_ENGINE) {
|
|
2538
|
+
const selections = [[engineOption, "the engine option"], [environmentSelection || void 0, "ANIMUS_ENGINE"]];
|
|
2539
|
+
for (const [selection, source] of selections) {
|
|
2540
|
+
if (selection === void 0 || selection === "v2") continue;
|
|
2541
|
+
if (selection === "v1") throw new AnimusConfigError(`${RETIRED_ENGINE_MESSAGE} (from ${source})`);
|
|
2542
|
+
throw new AnimusConfigError(`animus: unknown extraction engine "${selection}" from ${source}: v2 is the only engine.`);
|
|
2018
2543
|
}
|
|
2019
|
-
|
|
2544
|
+
}
|
|
2545
|
+
//#endregion
|
|
2546
|
+
//#region pipeline/asset-copies.ts
|
|
2547
|
+
/**
|
|
2548
|
+
* Immutable asset copies: one binding from an `asset()` source file to a
|
|
2549
|
+
* content-digested name, shared by every host that serves copies.
|
|
2550
|
+
*/
|
|
2551
|
+
/** Copies `sourcePath` into `assetsDir` under its content-digested name,
|
|
2552
|
+
* once: a copy is never overwritten, so a URL naming it always serves the
|
|
2553
|
+
* bytes it named. */
|
|
2554
|
+
function writeAssetCopy(sourcePath, assetsDir) {
|
|
2555
|
+
const bytes = readFileSync$1(sourcePath);
|
|
2556
|
+
const digest = contentHash(bytes);
|
|
2557
|
+
const ext = extname$1(sourcePath);
|
|
2558
|
+
const fileName = `${basename$1(sourcePath, ext)}.${digest.slice(0, 8)}${ext}`;
|
|
2559
|
+
if (!existsSync$1(assetsDir)) mkdirSync(assetsDir, { recursive: true });
|
|
2560
|
+
const copyPath = join$1(assetsDir, fileName);
|
|
2561
|
+
if (!existsSync$1(copyPath)) writeFileSync(copyPath, bytes);
|
|
2562
|
+
return {
|
|
2563
|
+
fileName,
|
|
2564
|
+
digest,
|
|
2565
|
+
bytes
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
/** Sync `assets/` to the current build's file set; per-entry failures are
|
|
2569
|
+
* tolerated — a concurrent session may have removed the same file. */
|
|
2570
|
+
function pruneStaleAssets(assetsDir, expected) {
|
|
2571
|
+
if (!existsSync$1(assetsDir)) return;
|
|
2572
|
+
let entries;
|
|
2573
|
+
try {
|
|
2574
|
+
entries = readdirSync$1(assetsDir);
|
|
2575
|
+
} catch {
|
|
2576
|
+
return;
|
|
2577
|
+
}
|
|
2578
|
+
for (const entry of entries) {
|
|
2579
|
+
if (expected.has(entry)) continue;
|
|
2580
|
+
try {
|
|
2581
|
+
unlinkSync(join$1(assetsDir, entry));
|
|
2582
|
+
} catch {}
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
//#endregion
|
|
2586
|
+
//#region pipeline/runtime-import.ts
|
|
2587
|
+
/** The runtime every adapter emits by default (spine row 1). */
|
|
2588
|
+
const DEFAULT_RUNTIME_IMPORT = "@animus-ui/system/runtime";
|
|
2589
|
+
/** The entries that supply every terminal: an override naming another must
|
|
2590
|
+
* extract only `.asClass()` terminals. */
|
|
2591
|
+
const FULL_RUNTIME_IMPORTS = /* @__PURE__ */ new Set([DEFAULT_RUNTIME_IMPORT, "@animus-ui/system"]);
|
|
2592
|
+
/** Throws when `runtimeImport` names a module that cannot supply a
|
|
2593
|
+
* terminal the manifest extracted. */
|
|
2594
|
+
function assertRuntimeImportSuppliesTerminals(runtimeImport, manifest) {
|
|
2595
|
+
if (!runtimeImport || FULL_RUNTIME_IMPORTS.has(runtimeImport)) return;
|
|
2596
|
+
const offenders = [];
|
|
2597
|
+
for (const [id, descriptor] of Object.entries(manifest.components)) if (/\bcreateComponent\(|\bcreateComposedFamily\(/.test(descriptor.replacement)) offenders.push(id);
|
|
2598
|
+
if (offenders.length === 0) return;
|
|
2599
|
+
const shown = offenders.slice(0, 5).join(", ");
|
|
2600
|
+
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().`);
|
|
2601
|
+
}
|
|
2602
|
+
//#endregion
|
|
2603
|
+
//#region pipeline/discover-files.ts
|
|
2604
|
+
function pathCharRank(code) {
|
|
2605
|
+
return code === 47 || code === 92 ? -1 : code;
|
|
2606
|
+
}
|
|
2607
|
+
function compareDiscoveryOrder(a, b) {
|
|
2608
|
+
const shared = Math.min(a.length, b.length);
|
|
2609
|
+
for (let i = 0; i < shared; i++) {
|
|
2610
|
+
const left = pathCharRank(a.charCodeAt(i));
|
|
2611
|
+
const right = pathCharRank(b.charCodeAt(i));
|
|
2612
|
+
if (left !== right) return left - right;
|
|
2613
|
+
}
|
|
2614
|
+
return a.length - b.length;
|
|
2020
2615
|
}
|
|
2021
2616
|
function discoverFiles(dir, rootDir, exclude, extensionsSet) {
|
|
2022
2617
|
return walkFiles(dir, rootDir, exclude, extensionsSet).sort(compareDiscoveryOrder);
|
|
@@ -2025,7 +2620,7 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
|
|
|
2025
2620
|
const results = [];
|
|
2026
2621
|
let entries;
|
|
2027
2622
|
try {
|
|
2028
|
-
entries = readdirSync(dir, { encoding: "utf8" });
|
|
2623
|
+
entries = readdirSync$1(dir, { encoding: "utf8" });
|
|
2029
2624
|
} catch {
|
|
2030
2625
|
return results;
|
|
2031
2626
|
}
|
|
@@ -2035,7 +2630,7 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
|
|
|
2035
2630
|
if (isExcluded(fullPath, relative$1(rootDir, fullPath))) continue;
|
|
2036
2631
|
let stat;
|
|
2037
2632
|
try {
|
|
2038
|
-
stat = statSync(fullPath);
|
|
2633
|
+
stat = statSync$1(fullPath);
|
|
2039
2634
|
} catch {
|
|
2040
2635
|
continue;
|
|
2041
2636
|
}
|
|
@@ -2045,6 +2640,161 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
|
|
|
2045
2640
|
return results;
|
|
2046
2641
|
}
|
|
2047
2642
|
//#endregion
|
|
2643
|
+
//#region pipeline/host-extensions.ts
|
|
2644
|
+
/** Animus's own order, where no host resolver configuration exists. */
|
|
2645
|
+
const BUILT_IN_EXTENSION_POLICY = {
|
|
2646
|
+
appended: EXTENSION_POLICY.appended,
|
|
2647
|
+
nodeNext: EXTENSION_POLICY.nodeNext,
|
|
2648
|
+
alias: [],
|
|
2649
|
+
resolverVersion: "built-in"
|
|
2650
|
+
};
|
|
2651
|
+
/** The TypeScript output a source compiles to, as a host that resolves an
|
|
2652
|
+
* emitted extension to its TypeScript source reads it. */
|
|
2653
|
+
const TYPESCRIPT_OUTPUTS = [
|
|
2654
|
+
[".js", [".ts", ".tsx"]],
|
|
2655
|
+
[".jsx", [".tsx"]],
|
|
2656
|
+
[".mjs", [".mts"]],
|
|
2657
|
+
[".cjs", [".cts"]]
|
|
2658
|
+
];
|
|
2659
|
+
/** esbuild's rewritten file extensions, which also let `.jsx` name `.ts`. */
|
|
2660
|
+
const ESBUILD_OUTPUTS = [
|
|
2661
|
+
[".js", [".ts", ".tsx"]],
|
|
2662
|
+
[".jsx", [".ts", ".tsx"]],
|
|
2663
|
+
[".mjs", [".mts"]],
|
|
2664
|
+
[".cjs", [".cts"]]
|
|
2665
|
+
];
|
|
2666
|
+
/** Documented defaults, for a host whose resolved order is not readable. */
|
|
2667
|
+
const HOST_DEFAULT_EXTENSIONS = {
|
|
2668
|
+
vite: [
|
|
2669
|
+
".mjs",
|
|
2670
|
+
".js",
|
|
2671
|
+
".mts",
|
|
2672
|
+
".ts",
|
|
2673
|
+
".jsx",
|
|
2674
|
+
".tsx",
|
|
2675
|
+
".json"
|
|
2676
|
+
],
|
|
2677
|
+
webpack: [
|
|
2678
|
+
".js",
|
|
2679
|
+
".json",
|
|
2680
|
+
".wasm"
|
|
2681
|
+
],
|
|
2682
|
+
/** Rspack 1's documented default; later versions document another. */
|
|
2683
|
+
rspack1: [
|
|
2684
|
+
".js",
|
|
2685
|
+
".json",
|
|
2686
|
+
".wasm"
|
|
2687
|
+
],
|
|
2688
|
+
turbopack: [
|
|
2689
|
+
".tsx",
|
|
2690
|
+
".ts",
|
|
2691
|
+
".jsx",
|
|
2692
|
+
".js",
|
|
2693
|
+
".mjs",
|
|
2694
|
+
".json"
|
|
2695
|
+
],
|
|
2696
|
+
esbuild: [
|
|
2697
|
+
".tsx",
|
|
2698
|
+
".ts",
|
|
2699
|
+
".jsx",
|
|
2700
|
+
".js",
|
|
2701
|
+
".css",
|
|
2702
|
+
".json"
|
|
2703
|
+
]
|
|
2704
|
+
};
|
|
2705
|
+
function label(host, version, how) {
|
|
2706
|
+
return `${version ? `${host}@${version}` : host} ${how}`;
|
|
2707
|
+
}
|
|
2708
|
+
/** Vite's `resolve.extensions`, which `configResolved` holds with its
|
|
2709
|
+
* defaults applied. A TypeScript importer's `./x.js` names `x.ts` too.
|
|
2710
|
+
* Only the default order is captured, as a real build resolves it. A
|
|
2711
|
+
* configured list does not describe Vite's effective resolution: Vite 8's
|
|
2712
|
+
* resolver falls back past it (`['.js']` still loads `./only` as
|
|
2713
|
+
* `only.tsx`), so it is unreadable. */
|
|
2714
|
+
function viteExtensionPolicy(extensions, version) {
|
|
2715
|
+
if (extensions.length !== HOST_DEFAULT_EXTENSIONS.vite.length || extensions.some((ext, i) => ext !== HOST_DEFAULT_EXTENSIONS.vite[i])) return {
|
|
2716
|
+
...BUILT_IN_EXTENSION_POLICY,
|
|
2717
|
+
resolverVersion: "built-in (hostOptionUnreadable: vite configured extensions)"
|
|
2718
|
+
};
|
|
2719
|
+
return {
|
|
2720
|
+
appended: [...extensions],
|
|
2721
|
+
nodeNext: TYPESCRIPT_OUTPUTS,
|
|
2722
|
+
alias: [],
|
|
2723
|
+
resolverVersion: label("vite", version, "captured")
|
|
2724
|
+
};
|
|
2725
|
+
}
|
|
2726
|
+
/** webpack's or Rspack's resolved order for an ESM import: the root
|
|
2727
|
+
* `resolve` with `byDependency.esm` merged over it as the bundler merges
|
|
2728
|
+
* it, a `...` standing for what it extends. `extensionAlias` is kept whole
|
|
2729
|
+
* and in order. Where neither sets extensions, the bundler's documented
|
|
2730
|
+
* default stands in; for Rspack only version 1's is known. */
|
|
2731
|
+
function webpackExtensionPolicy(host, resolve, version) {
|
|
2732
|
+
const esm = resolve.byDependency?.esm;
|
|
2733
|
+
const unset = resolve.extensions === void 0 && esm?.extensions === void 0;
|
|
2734
|
+
const defaults = !(host === "rspack") ? HOST_DEFAULT_EXTENSIONS.webpack : version?.startsWith("1.") ? HOST_DEFAULT_EXTENSIONS.rspack1 : null;
|
|
2735
|
+
if ([...Object.values(resolve.extensionAlias ?? {}), ...Object.values(esm?.extensionAlias ?? {})].some((value) => !Array.isArray(value))) return {
|
|
2736
|
+
...BUILT_IN_EXTENSION_POLICY,
|
|
2737
|
+
resolverVersion: "built-in (hostOptionUnreadable: string extensionAlias)"
|
|
2738
|
+
};
|
|
2739
|
+
const extendsBase = (list) => list === void 0 || list.includes("...");
|
|
2740
|
+
if (defaults === null && extendsBase(esm?.extensions) && extendsBase(resolve.extensions)) return {
|
|
2741
|
+
...BUILT_IN_EXTENSION_POLICY,
|
|
2742
|
+
resolverVersion: `built-in (hostOptionUnreadable: ${host}${version ? `@${version}` : ""} defaults)`
|
|
2743
|
+
};
|
|
2744
|
+
const extend = (list, base) => list === void 0 ? base : list.flatMap((extension) => extension === "..." ? base : [extension]);
|
|
2745
|
+
const root = extend(resolve.extensions, defaults ?? []);
|
|
2746
|
+
const sequence = (value) => Array.isArray(value) ? value : [value];
|
|
2747
|
+
const alias = new Map(Object.entries(resolve.extensionAlias ?? {}).map(([emitted, value]) => [emitted, sequence(value).filter((extension) => extension !== "...")]));
|
|
2748
|
+
for (const [emitted, value] of Object.entries(esm?.extensionAlias ?? {})) {
|
|
2749
|
+
const base = alias.get(emitted) ?? [];
|
|
2750
|
+
alias.set(emitted, sequence(value).flatMap((extension) => extension === "..." ? base : [extension]));
|
|
2751
|
+
}
|
|
2752
|
+
return {
|
|
2753
|
+
appended: [...extend(esm?.extensions, root)],
|
|
2754
|
+
nodeNext: [],
|
|
2755
|
+
alias: [...alias].map(([emitted, extensions]) => [emitted, [...extensions]]),
|
|
2756
|
+
resolverVersion: label(host, version, unset ? "default" : "captured")
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2759
|
+
/** Turbopack's `turbopack.resolveExtensions`, or its documented default
|
|
2760
|
+
* when the Next config sets none. It substitutes no source: under Next
|
|
2761
|
+
* 16.3, `./x.js` beside only `x.ts` names no module. */
|
|
2762
|
+
function turbopackExtensionPolicy(resolveExtensions, nextVersion) {
|
|
2763
|
+
return {
|
|
2764
|
+
appended: [...resolveExtensions ?? HOST_DEFAULT_EXTENSIONS.turbopack],
|
|
2765
|
+
nodeNext: [],
|
|
2766
|
+
alias: [],
|
|
2767
|
+
resolverVersion: label("turbopack", nextVersion, resolveExtensions === void 0 ? "default" : "captured")
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2770
|
+
/** esbuild's `resolveExtensions`, or its default when the build sets none. */
|
|
2771
|
+
function esbuildExtensionPolicy(resolveExtensions, version) {
|
|
2772
|
+
return {
|
|
2773
|
+
appended: [...resolveExtensions ?? HOST_DEFAULT_EXTENSIONS.esbuild],
|
|
2774
|
+
nodeNext: ESBUILD_OUTPUTS,
|
|
2775
|
+
alias: [],
|
|
2776
|
+
resolverVersion: label("esbuild", version, resolveExtensions === void 0 ? "default" : "captured")
|
|
2777
|
+
};
|
|
2778
|
+
}
|
|
2779
|
+
/** Rollup leaves the extension order to its resolver plugins, which keep
|
|
2780
|
+
* their options private: a TypeScript build sets `@rollup/plugin-node-resolve`'s
|
|
2781
|
+
* `extensions`, which no documented default matches. The built-in policy
|
|
2782
|
+
* answers, with the reason. */
|
|
2783
|
+
function rollupExtensionPolicy(usesNodeResolve) {
|
|
2784
|
+
return {
|
|
2785
|
+
...BUILT_IN_EXTENSION_POLICY,
|
|
2786
|
+
resolverVersion: usesNodeResolve ? "built-in (hostOptionUnreadable: rollup-node-resolve)" : "built-in (hostOptionUnreadable: rollup resolver plugins)"
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
/** The policy as the system loader reads it (`ExtensionPolicy`). */
|
|
2790
|
+
function extensionPolicyJson(policy) {
|
|
2791
|
+
return JSON.stringify({
|
|
2792
|
+
appended: policy.appended,
|
|
2793
|
+
nodeNext: policy.nodeNext,
|
|
2794
|
+
alias: policy.alias
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
//#endregion
|
|
2048
2798
|
//#region pipeline/tsconfig-paths.ts
|
|
2049
2799
|
/**
|
|
2050
2800
|
* tsconfig `paths` → alias pairs, for drivers with no live bundler config.
|
|
@@ -2131,7 +2881,7 @@ function decodeExtends(value) {
|
|
|
2131
2881
|
function readConfig(path) {
|
|
2132
2882
|
let raw;
|
|
2133
2883
|
try {
|
|
2134
|
-
raw = readFileSync(path, "utf-8");
|
|
2884
|
+
raw = readFileSync$1(path, "utf-8");
|
|
2135
2885
|
} catch {
|
|
2136
2886
|
return null;
|
|
2137
2887
|
}
|
|
@@ -2150,16 +2900,27 @@ function readConfig(path) {
|
|
|
2150
2900
|
extends: decodeExtends(root.extends)
|
|
2151
2901
|
};
|
|
2152
2902
|
}
|
|
2153
|
-
|
|
2903
|
+
/** Where an `extends` specifier can name a config: a relative one as
|
|
2904
|
+
* written, with `.json`, or as a directory's tsconfig; a package's under
|
|
2905
|
+
* each ancestor's `node_modules`. Resolution takes the first that exists. */
|
|
2906
|
+
function extendsCandidates(specifier, fromDir) {
|
|
2154
2907
|
if (specifier.startsWith(".") || isAbsolute$1(specifier)) {
|
|
2155
2908
|
const base = resolve$1(fromDir, specifier);
|
|
2156
|
-
|
|
2909
|
+
return [
|
|
2157
2910
|
base,
|
|
2158
2911
|
`${base}.json`,
|
|
2159
2912
|
join$1(base, "tsconfig.json")
|
|
2160
|
-
]
|
|
2161
|
-
return null;
|
|
2913
|
+
];
|
|
2162
2914
|
}
|
|
2915
|
+
const target = specifier.endsWith(".json") ? specifier : `${specifier}/tsconfig.json`;
|
|
2916
|
+
const candidates = [];
|
|
2917
|
+
for (let dir = resolve$1(fromDir);; dir = dirname$1(dir)) {
|
|
2918
|
+
candidates.push(join$1(dir, "node_modules", target));
|
|
2919
|
+
if (dirname$1(dir) === dir) return candidates;
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
function resolveExtendsTarget(specifier, fromDir) {
|
|
2923
|
+
if (specifier.startsWith(".") || isAbsolute$1(specifier)) return extendsCandidates(specifier, fromDir).find((candidate) => existsSync$1(candidate)) ?? null;
|
|
2163
2924
|
try {
|
|
2164
2925
|
return __require.resolve(specifier.endsWith(".json") ? specifier : `${specifier}/tsconfig.json`, { paths: [fromDir] });
|
|
2165
2926
|
} catch {
|
|
@@ -2171,9 +2932,8 @@ function resolveExtendsTarget(specifier, fromDir) {
|
|
|
2171
2932
|
}
|
|
2172
2933
|
}
|
|
2173
2934
|
/** Child-first flattened extends chain starting at `entryPath`. */
|
|
2174
|
-
function loadChain(entryPath) {
|
|
2935
|
+
function loadChain(entryPath, visited = /* @__PURE__ */ new Set(), absent = /* @__PURE__ */ new Set()) {
|
|
2175
2936
|
const chain = [];
|
|
2176
|
-
const visited = /* @__PURE__ */ new Set();
|
|
2177
2937
|
const queue = [entryPath];
|
|
2178
2938
|
while (queue.length > 0) {
|
|
2179
2939
|
const path = queue.shift();
|
|
@@ -2186,10 +2946,20 @@ function loadChain(entryPath) {
|
|
|
2186
2946
|
for (const parent of node.extends) {
|
|
2187
2947
|
const resolved = resolveExtendsTarget(parent, node.dir);
|
|
2188
2948
|
if (resolved) queue.push(resolved);
|
|
2949
|
+
else for (const candidate of extendsCandidates(parent, node.dir)) absent.add(candidate);
|
|
2189
2950
|
}
|
|
2190
2951
|
}
|
|
2191
2952
|
return chain;
|
|
2192
2953
|
}
|
|
2954
|
+
/** Every tsconfig file the project's alias chain reads or looks for, absent
|
|
2955
|
+
* ones included, an unresolved `extends` target's candidates among them:
|
|
2956
|
+
* an edit, creation or deletion of any changes the aliases. */
|
|
2957
|
+
function tsconfigChainPaths(rootDir) {
|
|
2958
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2959
|
+
const absent = /* @__PURE__ */ new Set();
|
|
2960
|
+
loadChain(join$1(rootDir, "tsconfig.json"), visited, absent);
|
|
2961
|
+
return [...visited, ...absent];
|
|
2962
|
+
}
|
|
2193
2963
|
/**
|
|
2194
2964
|
* The project's tsconfig path aliases as `buildPathAliasesJson` pairs; empty
|
|
2195
2965
|
* when no readable tsconfig, or no usable `paths`, exists.
|
|
@@ -2254,11 +3024,11 @@ function buildKitDescriptor(manifest) {
|
|
|
2254
3024
|
/** Reads the descriptor at a kit's package root; `null` when it has none. */
|
|
2255
3025
|
function readKitDescriptor(pkgRoot, rootDir) {
|
|
2256
3026
|
const path = join(pkgRoot, KIT_DESCRIPTOR_FILE);
|
|
2257
|
-
if (!existsSync
|
|
3027
|
+
if (!existsSync(path)) return null;
|
|
2258
3028
|
const packageRoot = posixPath$1(relative(rootDir, pkgRoot));
|
|
2259
3029
|
let wire;
|
|
2260
3030
|
try {
|
|
2261
|
-
wire = JSON.parse(readFileSync
|
|
3031
|
+
wire = JSON.parse(readFileSync(path, "utf-8"));
|
|
2262
3032
|
} catch {
|
|
2263
3033
|
return {
|
|
2264
3034
|
packageRoot,
|
|
@@ -2329,118 +3099,48 @@ function kitDescriptorDiagnostics(records, manifest) {
|
|
|
2329
3099
|
return diagnostics;
|
|
2330
3100
|
}
|
|
2331
3101
|
//#endregion
|
|
2332
|
-
//#region pipeline/
|
|
2333
|
-
/**
|
|
2334
|
-
|
|
2335
|
-
* and deletion: event paths are lookup INPUTS only and never fork identity.
|
|
2336
|
-
*/
|
|
2337
|
-
/**
|
|
2338
|
-
* True when `target` is `root` or a descendant, decided by `relative()`
|
|
2339
|
-
* shape: string prefixing would let `/ui` claim `/ui-old`.
|
|
2340
|
-
*/
|
|
2341
|
-
function isPathWithinRoot(root, target, pathApi = path) {
|
|
2342
|
-
const rel = pathApi.relative(root, target);
|
|
2343
|
-
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
2344
|
-
}
|
|
2345
|
-
/**
|
|
2346
|
-
* True when two paths share a platform root (win32 drive letter or UNC
|
|
2347
|
-
* share; always true on posix). Drive letters compare case-insensitively.
|
|
2348
|
-
*/
|
|
2349
|
-
function sharesVolumeRoot(a, b, pathApi = path) {
|
|
2350
|
-
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
2351
|
-
return volumeOf(a) === volumeOf(b);
|
|
2352
|
-
}
|
|
2353
|
-
function canonicalize(p) {
|
|
3102
|
+
//#region pipeline/workspace-packages.ts
|
|
3103
|
+
/** The parsed `package.json` in `dir`, or null when it cannot be read. */
|
|
3104
|
+
function readManifest(dir) {
|
|
2354
3105
|
try {
|
|
2355
|
-
return
|
|
3106
|
+
return JSON.parse(readFileSync$1(join$1(dir, "package.json"), "utf-8"));
|
|
2356
3107
|
} catch {
|
|
2357
3108
|
return null;
|
|
2358
3109
|
}
|
|
2359
3110
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
};
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
roots.push({
|
|
2382
|
-
asRegistered,
|
|
2383
|
-
canonical
|
|
2384
|
-
});
|
|
2385
|
-
return canonical;
|
|
2386
|
-
},
|
|
2387
|
-
externalRoots() {
|
|
2388
|
-
return roots.map((record) => record.canonical);
|
|
2389
|
-
},
|
|
2390
|
-
resolveSourceId(inputPath) {
|
|
2391
|
-
const lexical = path.normalize(inputPath);
|
|
2392
|
-
const canonical = canonicalize(lexical);
|
|
2393
|
-
if (canonical === null) return null;
|
|
2394
|
-
const owner = owningRecord(canonical);
|
|
2395
|
-
const ownedBy = (record) => {
|
|
2396
|
-
const pathInRoot = path.relative(record.canonical, canonical);
|
|
2397
|
-
return {
|
|
2398
|
-
sourceKey: path.relative(normalizedRootDir, path.join(record.asRegistered, pathInRoot)),
|
|
2399
|
-
owningRoot: record.canonical,
|
|
2400
|
-
pathInRoot
|
|
2401
|
-
};
|
|
2402
|
-
};
|
|
2403
|
-
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
2404
|
-
let resolved;
|
|
2405
|
-
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
2406
|
-
const key = path.relative(canonicalRootDir, canonical);
|
|
2407
|
-
resolved = {
|
|
2408
|
-
sourceKey: key,
|
|
2409
|
-
owningRoot: null,
|
|
2410
|
-
pathInRoot: key
|
|
2411
|
-
};
|
|
2412
|
-
} else if (owner) resolved = ownedBy(owner);
|
|
2413
|
-
else return null;
|
|
2414
|
-
aliases.set(lexical, resolved);
|
|
2415
|
-
aliases.set(canonical, resolved);
|
|
2416
|
-
return resolved;
|
|
2417
|
-
},
|
|
2418
|
-
resolveDeletedSourceId(inputPath) {
|
|
2419
|
-
return aliases.get(path.normalize(inputPath)) ?? null;
|
|
2420
|
-
},
|
|
2421
|
-
containingExternalRoot(inputPath) {
|
|
2422
|
-
const lexical = path.normalize(inputPath);
|
|
2423
|
-
let owner = null;
|
|
2424
|
-
for (const record of roots) {
|
|
2425
|
-
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
2426
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2427
|
-
}
|
|
2428
|
-
if (owner) return owner.canonical;
|
|
2429
|
-
const canonical = canonicalize(lexical);
|
|
2430
|
-
if (canonical === null) return null;
|
|
2431
|
-
for (const record of roots) {
|
|
2432
|
-
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
2433
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2434
|
-
}
|
|
2435
|
-
return owner?.canonical ?? null;
|
|
3111
|
+
/**
|
|
3112
|
+
* The packages the session root's `package.json` declares as workspaces, by
|
|
3113
|
+
* name, at their real directories, so a linked workspace is one package. The
|
|
3114
|
+
* system loader consults them after a `node_modules` lookup misses. Only
|
|
3115
|
+
* literal entries name a package; a glob entry (`packages/*`) names none
|
|
3116
|
+
* yet. None when the manifest is absent or declares none.
|
|
3117
|
+
*/
|
|
3118
|
+
function declaredWorkspacePackages(rootDir) {
|
|
3119
|
+
const rootPkg = readManifest(rootDir);
|
|
3120
|
+
if (!isJsonBlock(rootPkg)) return {};
|
|
3121
|
+
const workspaces = rootPkg.workspaces;
|
|
3122
|
+
const declared = isJsonBlock(workspaces) ? workspaces.packages : workspaces;
|
|
3123
|
+
if (!Array.isArray(declared)) return {};
|
|
3124
|
+
const packages = /* @__PURE__ */ new Map();
|
|
3125
|
+
for (const entry of declared) {
|
|
3126
|
+
if (!isJsonString(entry)) continue;
|
|
3127
|
+
let dir;
|
|
3128
|
+
try {
|
|
3129
|
+
dir = realpathSync$1(resolve$1(rootDir, entry));
|
|
3130
|
+
} catch {
|
|
3131
|
+
continue;
|
|
2436
3132
|
}
|
|
2437
|
-
|
|
3133
|
+
const manifest = readManifest(dir);
|
|
3134
|
+
const name = isJsonBlock(manifest) ? manifest.name : void 0;
|
|
3135
|
+
if (isJsonString(name) && name !== "" && !packages.has(name)) packages.set(name, dir);
|
|
3136
|
+
}
|
|
3137
|
+
return Object.fromEntries(packages);
|
|
2438
3138
|
}
|
|
2439
3139
|
//#endregion
|
|
2440
3140
|
//#region pipeline/discover-packages.ts
|
|
2441
3141
|
function findPackageRoot(absEntryPath) {
|
|
2442
3142
|
let pkgRoot = dirname$1(absEntryPath);
|
|
2443
|
-
while (pkgRoot !== dirname$1(pkgRoot) && !existsSync(join$1(pkgRoot, "package.json"))) pkgRoot = dirname$1(pkgRoot);
|
|
3143
|
+
while (pkgRoot !== dirname$1(pkgRoot) && !existsSync$1(join$1(pkgRoot, "package.json"))) pkgRoot = dirname$1(pkgRoot);
|
|
2444
3144
|
return pkgRoot;
|
|
2445
3145
|
}
|
|
2446
3146
|
const PACKAGE_SRC_EXCLUDES = [
|
|
@@ -2462,39 +3162,36 @@ const PACKAGE_OUTPUT_EXCLUDES = [
|
|
|
2462
3162
|
".d.ts",
|
|
2463
3163
|
".map"
|
|
2464
3164
|
];
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
absSpecifier,
|
|
2475
|
-
...Array.from(extensionsSet, (ext) => absSpecifier + ext),
|
|
2476
|
-
...Array.from(extensionsSet, (ext) => join$1(absSpecifier, `index${ext}`))
|
|
2477
|
-
].find(isFile$1) ?? null;
|
|
3165
|
+
/** The file an absolute path specifier names, through the extension
|
|
3166
|
+
* policy, spelled exactly below the directory it shares with `within`
|
|
3167
|
+
* when given; a file differing only in case is a mismatch. */
|
|
3168
|
+
function probeAbsolutePathSpecifier(absSpecifier, extensionsSet, within, policy) {
|
|
3169
|
+
return probeOnDisk(policyCandidates(normalize$1(absSpecifier), {
|
|
3170
|
+
sources: extensionsSet,
|
|
3171
|
+
index: join$1,
|
|
3172
|
+
policy
|
|
3173
|
+
}), within);
|
|
2478
3174
|
}
|
|
2479
3175
|
/** The package a bare specifier names: `@scope/name` or `name`. */
|
|
2480
3176
|
function bareSpecifierPackageName(specifier) {
|
|
2481
3177
|
const segments = specifier.split("/");
|
|
2482
3178
|
return specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0];
|
|
2483
3179
|
}
|
|
2484
|
-
function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
3180
|
+
function sourceEntryForSpecifier(specifier, srcDir, extensionsSet, rootDir, policy) {
|
|
2485
3181
|
if (isAbsolute$1(specifier)) {
|
|
2486
|
-
const
|
|
2487
|
-
if (
|
|
2488
|
-
return isPathWithinRoot(srcDir,
|
|
3182
|
+
const probed = probeAbsolutePathSpecifier(specifier, extensionsSet, rootDir, policy);
|
|
3183
|
+
if (probed.kind !== "found") return null;
|
|
3184
|
+
return isPathWithinRoot(srcDir, probed.path) ? probed.path : null;
|
|
2489
3185
|
}
|
|
2490
3186
|
const packageName = bareSpecifierPackageName(specifier);
|
|
2491
3187
|
const subpath = specifier.slice(packageName.length + 1);
|
|
2492
|
-
|
|
3188
|
+
const probed = probeAbsolutePathSpecifier(join$1(srcDir, subpath || "index"), extensionsSet, srcDir, policy);
|
|
3189
|
+
return probed.kind === "found" ? probed.path : null;
|
|
2493
3190
|
}
|
|
2494
3191
|
/** The package's parsed `package.json`, or null when it cannot be read. */
|
|
2495
3192
|
function readPackageManifest(pkgRoot) {
|
|
2496
3193
|
try {
|
|
2497
|
-
return JSON.parse(readFileSync(join$1(pkgRoot, "package.json"), "utf-8"));
|
|
3194
|
+
return JSON.parse(readFileSync$1(join$1(pkgRoot, "package.json"), "utf-8"));
|
|
2498
3195
|
} catch {
|
|
2499
3196
|
return null;
|
|
2500
3197
|
}
|
|
@@ -2514,80 +3211,52 @@ function exportsSubpaths(manifest) {
|
|
|
2514
3211
|
* its source in every host, and the system loader prefers it.
|
|
2515
3212
|
*/
|
|
2516
3213
|
const KIT_SOURCE_CONDITION = "animus";
|
|
2517
|
-
/** The
|
|
2518
|
-
*
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2526
|
-
if (subpath.includes("*") || !isJsonBlock(value)) continue;
|
|
2527
|
-
const target = value[KIT_SOURCE_CONDITION];
|
|
2528
|
-
if (!isJsonString(target)) continue;
|
|
2529
|
-
const file = resolve$1(pkgRoot, target);
|
|
2530
|
-
if (isPathWithinRoot(pkgRoot, file) && isFile$1(file)) condition.entries.push([subpath, file]);
|
|
2531
|
-
else condition.invalid.push([subpath, target]);
|
|
2532
|
-
}
|
|
2533
|
-
if (condition.entries.length === 0 && condition.invalid.length === 0) return null;
|
|
2534
|
-
condition.root = sourceRoot(condition.entries);
|
|
2535
|
-
return condition;
|
|
2536
|
-
}
|
|
2537
|
-
/** The deepest directory holding every entry's file. */
|
|
2538
|
-
function sourceRoot(entries) {
|
|
2539
|
-
return entries.reduce((root, [, file]) => root === null ? dirname$1(file) : commonDirectory(root, dirname$1(file)), null);
|
|
2540
|
-
}
|
|
2541
|
-
/** A TypeScript source file; compiled output and declarations are not. */
|
|
2542
|
-
const TS_SOURCE = /(?<!\.d)\.[cm]?tsx?$/;
|
|
2543
|
-
/** A kit with no source condition whose every exact `exports` entry already
|
|
2544
|
-
* targets TypeScript source in the package under `import` or `default`:
|
|
2545
|
-
* those targets are its source, as the condition would name them. Null
|
|
2546
|
-
* when any exact entry has no such target, such as one only `require` or
|
|
2547
|
-
* `types` reaches, or there is no exact entry. */
|
|
2548
|
-
function sourceExportsCondition(pkgRoot) {
|
|
2549
|
-
const entries = [];
|
|
2550
|
-
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2551
|
-
if (subpath.includes("*")) continue;
|
|
2552
|
-
const target = exportTarget(value);
|
|
2553
|
-
const file = target === null ? null : resolve$1(pkgRoot, target);
|
|
2554
|
-
if (file === null || !TS_SOURCE.test(file) || !isPathWithinRoot(pkgRoot, file) || !isFile$1(file)) return null;
|
|
2555
|
-
entries.push([subpath, file]);
|
|
2556
|
-
}
|
|
2557
|
-
if (entries.length === 0) return null;
|
|
2558
|
-
return {
|
|
2559
|
-
entries,
|
|
2560
|
-
invalid: [],
|
|
2561
|
-
root: sourceRoot(entries)
|
|
3214
|
+
/** The system loader's package locator under the session's declared
|
|
3215
|
+
* `workspaces`: the first `node_modules/<name>` up the tree, then the
|
|
3216
|
+
* workspace of that name. */
|
|
3217
|
+
function nativePackageLocator(engine, workspaces) {
|
|
3218
|
+
const native = engine.locatePackage;
|
|
3219
|
+
return (name, fromDir) => {
|
|
3220
|
+
if (native === void 0) throw new Error("the native engine does not expose locatePackage, which kit discovery needs — rebuild @animus-ui/extract");
|
|
3221
|
+
return native(name, fromDir, workspaces);
|
|
2562
3222
|
};
|
|
2563
3223
|
}
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
return
|
|
3224
|
+
/** The native table's kit source roots under one resolution context. */
|
|
3225
|
+
function nativeKitSourceRoot(engine, fromDir, conditions, workspaces, policyJson) {
|
|
3226
|
+
const native = engine.resolveKitSourceRoot;
|
|
3227
|
+
return (specifier, packageDir, hostEntry) => {
|
|
3228
|
+
if (native === void 0) throw new Error("the native engine does not expose resolveKitSourceRoot, which kit discovery needs — rebuild @animus-ui/extract");
|
|
3229
|
+
const answer = parseInternalWire(native(specifier, fromDir, [...conditions], workspaces, policyJson, hostEntry ?? void 0, packageDir), "resolveKitSourceRoot");
|
|
3230
|
+
if (answer.rule === void 0) return null;
|
|
3231
|
+
return {
|
|
3232
|
+
rule: answer.rule,
|
|
3233
|
+
root: answer.root ?? null,
|
|
3234
|
+
entries: answer.entries ?? [],
|
|
3235
|
+
invalid: answer.invalid ?? [],
|
|
3236
|
+
unresolved: answer.unresolved ?? null
|
|
3237
|
+
};
|
|
3238
|
+
};
|
|
2568
3239
|
}
|
|
2569
|
-
/**
|
|
2570
|
-
|
|
3240
|
+
/**
|
|
3241
|
+
* Whether `dir`, the nearest manifest above a host's answer, is a package
|
|
3242
|
+
* the host resolved into: its manifest names a package, and it is not the
|
|
3243
|
+
* project or a directory holding it. A host answer from a dependency cache
|
|
3244
|
+
* (`node_modules/.vite/deps`), or from a file outside every package, finds
|
|
3245
|
+
* the application's own manifest, which is no package root. The name need
|
|
3246
|
+
* not be the specifier's: a host alias resolves one package to another,
|
|
3247
|
+
* and the host's package is the one the bundle renders (spec §2.2 A4).
|
|
3248
|
+
*/
|
|
3249
|
+
function isHostPackageRoot(dir, rootDir) {
|
|
2571
3250
|
const manifest = readPackageManifest(dir);
|
|
2572
|
-
return isJsonBlock(manifest) && manifest.name
|
|
3251
|
+
return isJsonBlock(manifest) && isJsonString(manifest.name) && manifest.name !== "" && !isPathWithinRoot(realPath(dir), realPath(rootDir));
|
|
2573
3252
|
}
|
|
2574
3253
|
function realPath(path) {
|
|
2575
3254
|
try {
|
|
2576
|
-
return realpathSync(path);
|
|
3255
|
+
return realpathSync$1(path);
|
|
2577
3256
|
} catch {
|
|
2578
3257
|
return path;
|
|
2579
3258
|
}
|
|
2580
3259
|
}
|
|
2581
|
-
/** The root of the installed package `name` as Node finds it from `fromDir`,
|
|
2582
|
-
* the first `node_modules/<name>` up the directory tree, at its real path,
|
|
2583
|
-
* as host resolvers report a linked package. */
|
|
2584
|
-
function locatePackageRoot(name, fromDir) {
|
|
2585
|
-
for (let dir = fromDir;; dir = dirname$1(dir)) {
|
|
2586
|
-
const candidate = join$1(dir, "node_modules", name);
|
|
2587
|
-
if (existsSync(join$1(candidate, "package.json"))) return realPath(candidate);
|
|
2588
|
-
if (dir === dirname$1(dir)) return null;
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
3260
|
/**
|
|
2592
3261
|
* A package's `sideEffects` field, decoded the way Vite reads it: a boolean
|
|
2593
3262
|
* as written, or the list's globs, one with no `/` matching the basename
|
|
@@ -2712,7 +3381,7 @@ function packageExportEntries(pkgRoot) {
|
|
|
2712
3381
|
function isInstalledPackage(pkgRoot) {
|
|
2713
3382
|
let realRoot = pkgRoot;
|
|
2714
3383
|
try {
|
|
2715
|
-
realRoot = realpathSync(pkgRoot);
|
|
3384
|
+
realRoot = realpathSync$1(pkgRoot);
|
|
2716
3385
|
} catch {}
|
|
2717
3386
|
return realRoot.split(/[\\/]/).includes("node_modules");
|
|
2718
3387
|
}
|
|
@@ -2720,25 +3389,32 @@ function distEntryIsStale(absEntry, srcDir, srcFiles) {
|
|
|
2720
3389
|
if (isPathWithinRoot(srcDir, absEntry)) return false;
|
|
2721
3390
|
let distMtime;
|
|
2722
3391
|
try {
|
|
2723
|
-
distMtime = statSync(absEntry).mtimeMs;
|
|
3392
|
+
distMtime = statSync$1(absEntry).mtimeMs;
|
|
2724
3393
|
} catch {
|
|
2725
3394
|
return false;
|
|
2726
3395
|
}
|
|
2727
3396
|
let newestSrcMtime = -Infinity;
|
|
2728
3397
|
for (const srcFile of srcFiles) try {
|
|
2729
|
-
newestSrcMtime = Math.max(newestSrcMtime, statSync(srcFile).mtimeMs);
|
|
3398
|
+
newestSrcMtime = Math.max(newestSrcMtime, statSync$1(srcFile).mtimeMs);
|
|
2730
3399
|
} catch {}
|
|
2731
3400
|
return distMtime < newestSrcMtime;
|
|
2732
3401
|
}
|
|
2733
3402
|
async function collectExternalPackageSources(opts) {
|
|
2734
|
-
const { specifiers,
|
|
3403
|
+
const { specifiers, unresolvedReason, kitSourceRoot, locatePackage, rootDir, extensionsSet, hasEntry, onSourceRead, onUnreadable, onPackageResolved, requireSourceEntry, extensions, hostOutputDirs = [] } = opts;
|
|
3404
|
+
const answers = /* @__PURE__ */ new Map();
|
|
3405
|
+
const resolveSpecifier = (specifier) => {
|
|
3406
|
+
let answer = answers.get(specifier);
|
|
3407
|
+
if (answer === void 0) {
|
|
3408
|
+
answer = Promise.resolve().then(() => opts.resolveSpecifier(specifier));
|
|
3409
|
+
answers.set(specifier, answer);
|
|
3410
|
+
}
|
|
3411
|
+
return answer;
|
|
3412
|
+
};
|
|
2735
3413
|
const entries = [];
|
|
2736
3414
|
const pushed = /* @__PURE__ */ new Set();
|
|
2737
3415
|
const packageMap = {};
|
|
2738
3416
|
const sourceEntries = /* @__PURE__ */ new Map();
|
|
2739
3417
|
const sourceEntrySideEffects = /* @__PURE__ */ new Map();
|
|
2740
|
-
/** `replaced` names the entry the redirect stands in for; it is only
|
|
2741
|
-
* needed, and so only resolved, for a glob list. */
|
|
2742
3418
|
/** The entry `subpath` of the package resolves to without the redirect.
|
|
2743
3419
|
* A resolver with no `import` condition, as Node's `require` has none,
|
|
2744
3420
|
* finds no ESM-only entry, so the manifest's own target answers then. */
|
|
@@ -2749,6 +3425,8 @@ async function collectExternalPackageSources(opts) {
|
|
|
2749
3425
|
} catch {}
|
|
2750
3426
|
return packageExportEntries(pkgRoot).find(([entry]) => entry === subpath)?.[1] ?? null;
|
|
2751
3427
|
};
|
|
3428
|
+
/** `replaced` names the entry the redirect stands in for; it is only
|
|
3429
|
+
* needed, and so only resolved, for a glob list. */
|
|
2752
3430
|
const redirect = async (specifier, srcEntry, pkgRoot, replaced) => {
|
|
2753
3431
|
sourceEntries.set(specifier, srcEntry);
|
|
2754
3432
|
const field = readPackageSideEffects(pkgRoot);
|
|
@@ -2778,7 +3456,7 @@ async function collectExternalPackageSources(opts) {
|
|
|
2778
3456
|
if (alreadyIngested(relPath)) return true;
|
|
2779
3457
|
let source;
|
|
2780
3458
|
try {
|
|
2781
|
-
source = readFileSync(file, "utf-8");
|
|
3459
|
+
source = readFileSync$1(file, "utf-8");
|
|
2782
3460
|
} catch (err) {
|
|
2783
3461
|
onUnreadable(relPath, err);
|
|
2784
3462
|
return false;
|
|
@@ -2793,8 +3471,18 @@ async function collectExternalPackageSources(opts) {
|
|
|
2793
3471
|
return true;
|
|
2794
3472
|
};
|
|
2795
3473
|
const diagnostics = [];
|
|
2796
|
-
const
|
|
3474
|
+
const reported = /* @__PURE__ */ new Set();
|
|
3475
|
+
const report = (packageName, pkgRoot, condition) => {
|
|
3476
|
+
const copy = realPath(pkgRoot);
|
|
3477
|
+
for (const finding of sourceConditionDiagnostics(packageName, condition)) {
|
|
3478
|
+
const key = `${copy}\0${finding.code}\0${finding.message}`;
|
|
3479
|
+
if (reported.has(key)) continue;
|
|
3480
|
+
reported.add(key);
|
|
3481
|
+
diagnostics.push(finding);
|
|
3482
|
+
}
|
|
3483
|
+
};
|
|
2797
3484
|
const kitDescriptors = [];
|
|
3485
|
+
const packageInstances = {};
|
|
2798
3486
|
const describedRoots = /* @__PURE__ */ new Set();
|
|
2799
3487
|
for (const specifier of specifiers) {
|
|
2800
3488
|
let absEntry;
|
|
@@ -2803,23 +3491,78 @@ async function collectExternalPackageSources(opts) {
|
|
|
2803
3491
|
} catch {
|
|
2804
3492
|
absEntry = null;
|
|
2805
3493
|
}
|
|
2806
|
-
|
|
3494
|
+
let caseMismatch;
|
|
3495
|
+
if (isAbsolute$1(specifier)) {
|
|
3496
|
+
const own = probeAbsolutePathSpecifier(specifier, extensionsSet, rootDir, extensions);
|
|
3497
|
+
const hosted = absEntry === null ? null : normalize$1(absEntry);
|
|
3498
|
+
const seen = hosted === null ? null : seeOnDisk(hosted, rootDir);
|
|
3499
|
+
const probed = own.kind === "case-mismatch" || hosted === null || seen === null ? own : seen.kind === "case-only" ? {
|
|
3500
|
+
kind: "case-mismatch",
|
|
3501
|
+
candidate: hosted,
|
|
3502
|
+
actual: seen.actual
|
|
3503
|
+
} : {
|
|
3504
|
+
kind: "found",
|
|
3505
|
+
path: hosted
|
|
3506
|
+
};
|
|
3507
|
+
absEntry = probed.kind === "found" ? probed.path : null;
|
|
3508
|
+
if (probed.kind === "case-mismatch") caseMismatch = caseMismatchReason(`'${specifier}'`, probed, "spell the include as the file is spelled");
|
|
3509
|
+
}
|
|
2807
3510
|
const packageName = isAbsolute$1(specifier) ? null : bareSpecifierPackageName(specifier);
|
|
2808
|
-
|
|
2809
|
-
const locatedRoot = packageName &&
|
|
2810
|
-
|
|
2811
|
-
|
|
3511
|
+
let resolvedRoot = absEntry ? findPackageRoot(absEntry) : null;
|
|
3512
|
+
const locatedRoot = packageName && locatePackage(packageName, opts.locateFrom?.(specifier) ?? rootDir);
|
|
3513
|
+
if (resolvedRoot && locatedRoot && absEntry && realPath(resolvedRoot) !== locatedRoot && isPathWithinRoot(locatedRoot, realPath(absEntry))) {
|
|
3514
|
+
while (realPath(resolvedRoot) !== locatedRoot && resolvedRoot !== dirname$1(resolvedRoot)) resolvedRoot = dirname$1(resolvedRoot);
|
|
3515
|
+
if (realPath(resolvedRoot) !== locatedRoot) resolvedRoot = locatedRoot;
|
|
3516
|
+
}
|
|
3517
|
+
const pkgRoot = resolvedRoot && (!locatedRoot || isHostPackageRoot(resolvedRoot, rootDir) || realPath(resolvedRoot) === locatedRoot) ? resolvedRoot : locatedRoot || resolvedRoot;
|
|
3518
|
+
if (absEntry && packageName && locatedRoot && pkgRoot === locatedRoot && !isPathWithinRoot(locatedRoot, realPath(absEntry)) && !realPath(absEntry).split(sep$1).includes("node_modules")) diagnostics.push(packageMismatchDiagnostic(specifier, relative$1(rootDir, absEntry), relative$1(rootDir, locatedRoot)));
|
|
3519
|
+
const selection = packageName && pkgRoot ? kitSourceRoot(specifier, pkgRoot, absEntry) : null;
|
|
3520
|
+
if (selection?.unresolved) {
|
|
3521
|
+
absEntry = null;
|
|
3522
|
+
caseMismatch = selection.unresolved;
|
|
3523
|
+
}
|
|
3524
|
+
const condition = selection && (selection.rule === "animus" || selection.rule === "source-exports" || selection.invalid.length > 0) ? {
|
|
3525
|
+
entries: selection.entries,
|
|
3526
|
+
invalid: selection.invalid,
|
|
3527
|
+
root: selection.rule === "compiled" ? null : selection.root
|
|
3528
|
+
} : null;
|
|
3529
|
+
if (selection?.unresolved && condition && packageName && pkgRoot) report(packageName, pkgRoot, condition);
|
|
2812
3530
|
const entryKey = packageName && `.${specifier.slice(packageName.length)}`;
|
|
2813
3531
|
absEntry ??= condition?.entries.find(([entry]) => entry === entryKey)?.[1] ?? null;
|
|
2814
3532
|
if (!absEntry || !pkgRoot) {
|
|
2815
|
-
|
|
3533
|
+
const record = {
|
|
2816
3534
|
specifier,
|
|
2817
3535
|
outcome: "unresolvable",
|
|
2818
3536
|
fileCount: 0
|
|
3537
|
+
};
|
|
3538
|
+
const reason = caseMismatch ?? unresolvedReason?.(specifier);
|
|
3539
|
+
if (reason !== void 0) record.reason = reason;
|
|
3540
|
+
outcomes.push(record);
|
|
3541
|
+
continue;
|
|
3542
|
+
}
|
|
3543
|
+
const hostOutput = hostOutputDirs.find((dir) => isPathWithinRoot(dir, pkgRoot) || isPathWithinRoot(realPath(dir), realPath(pkgRoot)));
|
|
3544
|
+
if (hostOutput !== void 0) {
|
|
3545
|
+
outcomes.push({
|
|
3546
|
+
specifier,
|
|
3547
|
+
outcome: "unresolvable",
|
|
3548
|
+
fileCount: 0,
|
|
3549
|
+
reason: `the package lies inside the host's output directory ${hostOutput}, which is never source`
|
|
2819
3550
|
});
|
|
2820
3551
|
continue;
|
|
2821
3552
|
}
|
|
3553
|
+
if (requireSourceEntry?.(specifier)) {
|
|
3554
|
+
if (!(condition && packageName ? condition.entries.some(([entry]) => entry === entryKey) : selection?.rule === "src" && sourceEntryForSpecifier(specifier, join$1(pkgRoot, "src"), extensionsSet, rootDir, extensions) !== null)) {
|
|
3555
|
+
outcomes.push({
|
|
3556
|
+
specifier,
|
|
3557
|
+
outcome: "unresolvable",
|
|
3558
|
+
fileCount: 0,
|
|
3559
|
+
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"
|
|
3560
|
+
});
|
|
3561
|
+
continue;
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
2822
3564
|
const realRoot = realPath(pkgRoot);
|
|
3565
|
+
if (packageName) packageInstances[packageName] ??= realRoot;
|
|
2823
3566
|
if (!describedRoots.has(realRoot)) {
|
|
2824
3567
|
describedRoots.add(realRoot);
|
|
2825
3568
|
const described = readKitDescriptor(pkgRoot, rootDir);
|
|
@@ -2829,10 +3572,24 @@ async function collectExternalPackageSources(opts) {
|
|
|
2829
3572
|
const srcDir = join$1(pkgRoot, "src");
|
|
2830
3573
|
let fileCount = 0;
|
|
2831
3574
|
let staleDist = false;
|
|
2832
|
-
if (packageName
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
3575
|
+
if (packageName) report(packageName, pkgRoot, condition);
|
|
3576
|
+
const ingestOutput = (entryFile) => {
|
|
3577
|
+
const outputDir = dirname$1(entryFile);
|
|
3578
|
+
packageDirs.push(outputDir);
|
|
3579
|
+
if (linked) linkedDirs.push(outputDir);
|
|
3580
|
+
outputDirs.push(outputDir);
|
|
3581
|
+
claimDir(outputDir, specifier);
|
|
3582
|
+
onPackageResolved?.(specifier, outputDir);
|
|
3583
|
+
const outputExtensions = new Set(extensionsSet);
|
|
3584
|
+
outputExtensions.add(extname$1(entryFile));
|
|
3585
|
+
dirExtensions[outputDir] = [...outputExtensions];
|
|
3586
|
+
const outputFiles = discoverFiles(outputDir, outputDir, void 0, outputExtensions).filter((file) => {
|
|
3587
|
+
const relToOutput = relative$1(outputDir, file);
|
|
3588
|
+
return !PACKAGE_OUTPUT_EXCLUDES.some((pattern) => relToOutput.includes(pattern));
|
|
3589
|
+
});
|
|
3590
|
+
if (!outputFiles.includes(entryFile)) outputFiles.unshift(entryFile);
|
|
3591
|
+
for (const outputFile of outputFiles) if (ingest(outputFile, specifier)) fileCount++;
|
|
3592
|
+
};
|
|
2836
3593
|
if (condition && packageName) {
|
|
2837
3594
|
for (const [entry, target] of condition.entries) {
|
|
2838
3595
|
const entrySpecifier = packageName + entry.slice(1);
|
|
@@ -2840,6 +3597,7 @@ async function collectExternalPackageSources(opts) {
|
|
|
2840
3597
|
await redirect(entrySpecifier, target, pkgRoot, () => shippedEntry(entrySpecifier, pkgRoot, entry));
|
|
2841
3598
|
}
|
|
2842
3599
|
packageMap[specifier] ??= relative$1(rootDir, absEntry);
|
|
3600
|
+
if (!condition.entries.some(([entry]) => entry === entryKey)) ingestOutput(absEntry);
|
|
2843
3601
|
if (condition.root) {
|
|
2844
3602
|
packageDirs.push(condition.root);
|
|
2845
3603
|
if (linked) linkedDirs.push(condition.root);
|
|
@@ -2848,13 +3606,13 @@ async function collectExternalPackageSources(opts) {
|
|
|
2848
3606
|
onPackageResolved?.(specifier, condition.root);
|
|
2849
3607
|
for (const file of walkPackageSources(condition.root, extensionsSet)) if (ingest(file, specifier)) fileCount++;
|
|
2850
3608
|
}
|
|
2851
|
-
} else if (existsSync(srcDir)) {
|
|
3609
|
+
} else if (selection === null ? existsSync$1(srcDir) : selection.rule === "src") {
|
|
2852
3610
|
packageDirs.push(srcDir);
|
|
2853
3611
|
if (linked) linkedDirs.push(srcDir);
|
|
2854
3612
|
claimDir(srcDir, specifier);
|
|
2855
3613
|
dirExtensions[srcDir] = [...extensionsSet];
|
|
2856
3614
|
onPackageResolved?.(specifier, srcDir);
|
|
2857
|
-
const srcEntry = sourceEntryForSpecifier(specifier, srcDir, extensionsSet);
|
|
3615
|
+
const srcEntry = sourceEntryForSpecifier(specifier, srcDir, extensionsSet, rootDir, extensions);
|
|
2858
3616
|
if (srcEntry) {
|
|
2859
3617
|
packageMap[specifier] = relative$1(rootDir, srcEntry);
|
|
2860
3618
|
const replaced = absEntry;
|
|
@@ -2862,7 +3620,7 @@ async function collectExternalPackageSources(opts) {
|
|
|
2862
3620
|
} else packageMap[specifier] = relative$1(rootDir, absEntry);
|
|
2863
3621
|
if (packageName) {
|
|
2864
3622
|
if (packageName !== specifier && !(packageName in packageMap)) {
|
|
2865
|
-
const rootEntry = sourceEntryForSpecifier(packageName, srcDir, extensionsSet);
|
|
3623
|
+
const rootEntry = sourceEntryForSpecifier(packageName, srcDir, extensionsSet, rootDir, extensions);
|
|
2866
3624
|
if (rootEntry) {
|
|
2867
3625
|
packageMap[packageName] = relative$1(rootDir, rootEntry);
|
|
2868
3626
|
await redirect(packageName, rootEntry, pkgRoot, () => shippedEntry(packageName, pkgRoot, "."));
|
|
@@ -2873,22 +3631,8 @@ async function collectExternalPackageSources(opts) {
|
|
|
2873
3631
|
staleDist = linked && distEntryIsStale(absEntry, srcDir, pkgFiles);
|
|
2874
3632
|
for (const pkgFile of pkgFiles) if (ingest(pkgFile, specifier)) fileCount++;
|
|
2875
3633
|
} else {
|
|
2876
|
-
const outputDir = dirname$1(absEntry);
|
|
2877
|
-
packageDirs.push(outputDir);
|
|
2878
|
-
if (linked) linkedDirs.push(outputDir);
|
|
2879
|
-
outputDirs.push(outputDir);
|
|
2880
|
-
claimDir(outputDir, specifier);
|
|
2881
|
-
onPackageResolved?.(specifier, outputDir);
|
|
2882
3634
|
packageMap[specifier] = relative$1(rootDir, absEntry);
|
|
2883
|
-
|
|
2884
|
-
outputExtensions.add(extname$1(absEntry));
|
|
2885
|
-
dirExtensions[outputDir] = [...outputExtensions];
|
|
2886
|
-
const outputFiles = discoverFiles(outputDir, outputDir, void 0, outputExtensions).filter((file) => {
|
|
2887
|
-
const relToOutput = relative$1(outputDir, file);
|
|
2888
|
-
return !PACKAGE_OUTPUT_EXCLUDES.some((pattern) => relToOutput.includes(pattern));
|
|
2889
|
-
});
|
|
2890
|
-
if (!outputFiles.includes(absEntry)) outputFiles.unshift(absEntry);
|
|
2891
|
-
for (const outputFile of outputFiles) if (ingest(outputFile, specifier)) fileCount++;
|
|
3635
|
+
ingestOutput(absEntry);
|
|
2892
3636
|
}
|
|
2893
3637
|
if (packageName) for (const [subpath, target] of packageExportEntries(pkgRoot)) {
|
|
2894
3638
|
const entrySpecifier = packageName + subpath.slice(1);
|
|
@@ -2896,6 +3640,16 @@ async function collectExternalPackageSources(opts) {
|
|
|
2896
3640
|
if (entrySpecifier in packageMap || !alreadyIngested(targetRelPath)) continue;
|
|
2897
3641
|
packageMap[entrySpecifier] = targetRelPath;
|
|
2898
3642
|
}
|
|
3643
|
+
const ownManifest = readPackageManifest(pkgRoot);
|
|
3644
|
+
const hostName = isJsonBlock(ownManifest) ? ownManifest.name : void 0;
|
|
3645
|
+
if (packageName && locatedRoot && realPath(pkgRoot) !== locatedRoot && isJsonString(hostName) && hostName !== "" && hostName !== packageName) for (const [key, entry] of [...sourceEntries]) {
|
|
3646
|
+
if (key !== packageName && !key.startsWith(`${packageName}/`)) continue;
|
|
3647
|
+
const hostKey = hostName + key.slice(packageName.length);
|
|
3648
|
+
if (sourceEntries.has(hostKey)) continue;
|
|
3649
|
+
sourceEntries.set(hostKey, entry);
|
|
3650
|
+
const sideEffects = sourceEntrySideEffects.get(key);
|
|
3651
|
+
if (sideEffects !== void 0) sourceEntrySideEffects.set(hostKey, sideEffects);
|
|
3652
|
+
}
|
|
2899
3653
|
outcomes.push({
|
|
2900
3654
|
specifier,
|
|
2901
3655
|
outcome: staleDist ? "stale-dist" : fileCount > 0 ? "resolved" : "empty",
|
|
@@ -2915,7 +3669,8 @@ async function collectExternalPackageSources(opts) {
|
|
|
2915
3669
|
fileOwners,
|
|
2916
3670
|
outcomes,
|
|
2917
3671
|
diagnostics: [...diagnostics, ...noKitFilesDiagnostics(outcomes)],
|
|
2918
|
-
kitDescriptors
|
|
3672
|
+
kitDescriptors,
|
|
3673
|
+
packageInstances
|
|
2919
3674
|
};
|
|
2920
3675
|
}
|
|
2921
3676
|
/** The dependency names a manifest lists in `fields`. */
|
|
@@ -2928,14 +3683,22 @@ function dependencyNames(manifest, fields) {
|
|
|
2928
3683
|
}
|
|
2929
3684
|
return [...names];
|
|
2930
3685
|
}
|
|
3686
|
+
/** Whether the package at `pkgRoot` declares the kit source condition, as
|
|
3687
|
+
* the system loader's table reads its manifest: an `animus` key anywhere in
|
|
3688
|
+
* its `exports`, on any entry, subpath or pattern, valid or not. */
|
|
3689
|
+
function declaresKitSource(engine, pkgRoot) {
|
|
3690
|
+
if (engine.declaresKitSource === void 0) throw new Error("the native engine does not expose declaresKitSource, which kit discovery needs — rebuild @animus-ui/extract");
|
|
3691
|
+
return engine.declaresKitSource(pkgRoot);
|
|
3692
|
+
}
|
|
2931
3693
|
/** The source kits the application at `rootDir` declares as dependencies.
|
|
2932
3694
|
* A bundler serves an installed one as compiled code unless told
|
|
2933
3695
|
* otherwise: Next keeps it external on the server unless it is in
|
|
2934
3696
|
* `transpilePackages`, and Vite's optimizer prebundles it. */
|
|
2935
|
-
function sourceKitDependencies(rootDir) {
|
|
3697
|
+
function sourceKitDependencies(rootDir, engine) {
|
|
3698
|
+
const locatePackage = nativePackageLocator(engine, declaredWorkspacePackages(rootDir));
|
|
2936
3699
|
return dependencyNames(readPackageManifest(rootDir), ["dependencies", "devDependencies"]).flatMap((name) => {
|
|
2937
|
-
const pkgRoot =
|
|
2938
|
-
if (pkgRoot === null ||
|
|
3700
|
+
const pkgRoot = locatePackage(name, rootDir);
|
|
3701
|
+
if (pkgRoot === null || !declaresKitSource(engine, pkgRoot)) return [];
|
|
2939
3702
|
return [{
|
|
2940
3703
|
name,
|
|
2941
3704
|
installed: isInstalledPackage(pkgRoot),
|
|
@@ -2943,6 +3706,34 @@ function sourceKitDependencies(rootDir) {
|
|
|
2943
3706
|
}];
|
|
2944
3707
|
});
|
|
2945
3708
|
}
|
|
3709
|
+
/**
|
|
3710
|
+
* The installed packages a system's membership reaches: each is a kit,
|
|
3711
|
+
* whether or not it declares the source condition, and so is every kit its
|
|
3712
|
+
* own system extends or includes. Read before any host resolves (a
|
|
3713
|
+
* bundler's config), so the application's modules import as the system
|
|
3714
|
+
* loader resolves them from the root, and a kit's from its own directory.
|
|
3715
|
+
*/
|
|
3716
|
+
async function systemKitDependencies(rootDir, systemPath, engine) {
|
|
3717
|
+
const workspaces = declaredWorkspacePackages(rootDir);
|
|
3718
|
+
const resolveSpecifier = engine.resolveSpecifier;
|
|
3719
|
+
const systemPackageRoot = findPackageRoot(systemPath);
|
|
3720
|
+
const kitMembers = /* @__PURE__ */ new Map();
|
|
3721
|
+
const members = await extractSystemFilePackages(systemPath, engine, void 0, (specifier, importer) => resolveSpecifier?.(specifier, findPackageRoot(importer) === systemPackageRoot ? rootDir : dirname$1(importer), [], workspaces, extensionPolicyJson(BUILT_IN_EXTENSION_POLICY))?.path ?? null, void 0, kitMembers);
|
|
3722
|
+
const locatePackage = nativePackageLocator(engine, workspaces);
|
|
3723
|
+
const roots = /* @__PURE__ */ new Map();
|
|
3724
|
+
for (const member of members) {
|
|
3725
|
+
if (!isPackageSpecifier(member)) continue;
|
|
3726
|
+
const name = bareSpecifierPackageName(member);
|
|
3727
|
+
const file = kitMembers.get(member);
|
|
3728
|
+
const pkgRoot = file ? findPackageRoot(file) : locatePackage(name, rootDir);
|
|
3729
|
+
if (pkgRoot !== null && !roots.has(name)) roots.set(name, pkgRoot);
|
|
3730
|
+
}
|
|
3731
|
+
return [...roots].map(([name, pkgRoot]) => ({
|
|
3732
|
+
name,
|
|
3733
|
+
installed: isInstalledPackage(pkgRoot),
|
|
3734
|
+
dependencies: dependencyNames(readPackageManifest(pkgRoot), ["dependencies"])
|
|
3735
|
+
}));
|
|
3736
|
+
}
|
|
2946
3737
|
/** A specifier that names a package: not relative or absolute, and no URL,
|
|
2947
3738
|
* scheme (`node:`, `virtual:`), subpath import or virtual id. */
|
|
2948
3739
|
function isPackageSpecifier(specifier) {
|
|
@@ -2958,16 +3749,13 @@ function isPackageSpecifier(specifier) {
|
|
|
2958
3749
|
* file the engine parses as it is; an adapted source (`.svelte`, `.mdx`)
|
|
2959
3750
|
* reaches the engine only as its generated children.
|
|
2960
3751
|
*/
|
|
2961
|
-
function importedKitDiagnostics(files, engine, rootDir, systemKits) {
|
|
2962
|
-
const { extractFacts } = engine;
|
|
3752
|
+
function importedKitDiagnostics(files, engine, rootDir, systemKits, factsOf) {
|
|
2963
3753
|
const parsed = files.filter(({ path }) => isEngineTransformExtension(path));
|
|
2964
|
-
if (
|
|
3754
|
+
if (parsed.length === 0) return [];
|
|
3755
|
+
const locatePackage = nativePackageLocator(engine, declaredWorkspacePackages(rootDir));
|
|
2965
3756
|
let facts;
|
|
2966
3757
|
try {
|
|
2967
|
-
facts =
|
|
2968
|
-
path,
|
|
2969
|
-
source
|
|
2970
|
-
})))), "extractFacts");
|
|
3758
|
+
facts = factsOf(parsed);
|
|
2971
3759
|
} catch {
|
|
2972
3760
|
return [];
|
|
2973
3761
|
}
|
|
@@ -2981,8 +3769,8 @@ function importedKitDiagnostics(files, engine, rootDir, systemKits) {
|
|
|
2981
3769
|
const name = bareSpecifierPackageName(specifier);
|
|
2982
3770
|
if (seen.has(name)) continue;
|
|
2983
3771
|
seen.add(name);
|
|
2984
|
-
const pkgRoot =
|
|
2985
|
-
if (pkgRoot &&
|
|
3772
|
+
const pkgRoot = locatePackage(name, dirname$1(resolve$1(rootDir, path)));
|
|
3773
|
+
if (pkgRoot && declaresKitSource(engine, pkgRoot)) diagnostics.push({
|
|
2986
3774
|
file: path,
|
|
2987
3775
|
component: name,
|
|
2988
3776
|
kind: "warn",
|
|
@@ -2995,7 +3783,19 @@ function importedKitDiagnostics(files, engine, rootDir, systemKits) {
|
|
|
2995
3783
|
return diagnostics;
|
|
2996
3784
|
}
|
|
2997
3785
|
/** A kit without the source condition, warned once, or each condition entry
|
|
2998
|
-
*
|
|
3786
|
+
* the loader does not read as source: missing, spelled otherwise on disk,
|
|
3787
|
+
* no package target Node accepts (each read from its runtime target), or
|
|
3788
|
+
* percent-escaped (refused, failing the load). */
|
|
3789
|
+
function packageMismatchDiagnostic(specifier, hostEntry, located) {
|
|
3790
|
+
return {
|
|
3791
|
+
file: specifier,
|
|
3792
|
+
component: "kit",
|
|
3793
|
+
kind: "warn",
|
|
3794
|
+
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`,
|
|
3795
|
+
code: PACKAGE_MISMATCH,
|
|
3796
|
+
severity: severityFor(PACKAGE_MISMATCH)
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
2999
3799
|
function sourceConditionDiagnostics(packageName, condition) {
|
|
3000
3800
|
if (condition === null) return [{
|
|
3001
3801
|
file: packageName,
|
|
@@ -3005,11 +3805,11 @@ function sourceConditionDiagnostics(packageName, condition) {
|
|
|
3005
3805
|
code: KIT_WITHOUT_SOURCE_CONDITION,
|
|
3006
3806
|
severity: severityFor(KIT_WITHOUT_SOURCE_CONDITION)
|
|
3007
3807
|
}];
|
|
3008
|
-
return condition.invalid.map(([subpath, target]) => ({
|
|
3808
|
+
return condition.invalid.map(([subpath, target, why]) => ({
|
|
3009
3809
|
file: packageName,
|
|
3010
3810
|
component: "kit",
|
|
3011
3811
|
kind: "warn",
|
|
3012
|
-
message: `exports["${subpath}"].${KIT_SOURCE_CONDITION} names ${target}, which
|
|
3812
|
+
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`,
|
|
3013
3813
|
code: INVALID_KIT_SOURCE_CONDITION,
|
|
3014
3814
|
severity: severityFor(INVALID_KIT_SOURCE_CONDITION)
|
|
3015
3815
|
}));
|
|
@@ -3066,13 +3866,16 @@ function excludeCollectedPackages(collected, rejectedSpecifiers, rootDir) {
|
|
|
3066
3866
|
fileOwners,
|
|
3067
3867
|
outcomes: collected.outcomes,
|
|
3068
3868
|
diagnostics: collected.diagnostics,
|
|
3069
|
-
kitDescriptors: collected.kitDescriptors.filter((record) => !rejectedDirs.some((dir) => isPathWithinRoot(resolve$1(rootDir, record.packageRoot), dir)))
|
|
3869
|
+
kitDescriptors: collected.kitDescriptors.filter((record) => !rejectedDirs.some((dir) => isPathWithinRoot(resolve$1(rootDir, record.packageRoot), dir))),
|
|
3870
|
+
packageInstances: Object.fromEntries(Object.entries(collected.packageInstances).filter(([, root]) => !rejectedDirs.some((dir) => isPathWithinRoot(root, dir))))
|
|
3070
3871
|
};
|
|
3071
3872
|
}
|
|
3072
|
-
|
|
3073
|
-
|
|
3873
|
+
/** Every unresolvable include, with why where the resolver said, and the
|
|
3874
|
+
* system file that includes them when the caller knows it. */
|
|
3875
|
+
function unresolvableIncludesMessage(outcomes, importer) {
|
|
3876
|
+
const unresolvable = outcomes.filter((record) => record.outcome === "unresolvable").map((record) => record.reason === void 0 ? record.specifier : `${record.specifier} (${record.reason})`);
|
|
3074
3877
|
if (unresolvable.length === 0) return null;
|
|
3075
|
-
return `[animus-extract] unresolvable include specifier(s): ${unresolvable.join(", ")}`;
|
|
3878
|
+
return `[animus-extract] unresolvable include specifier(s)${importer === void 0 ? "" : ` in ${importer}`}: ${unresolvable.join(", ")}`;
|
|
3076
3879
|
}
|
|
3077
3880
|
/** A stale dist silently skews merged registry content while discovery
|
|
3078
3881
|
* compiles the fresh sources; null when no specifier is stale. */
|
|
@@ -3089,192 +3892,38 @@ function engineModuleParser(engine) {
|
|
|
3089
3892
|
if (!extractFacts) return void 0;
|
|
3090
3893
|
return (source, path) => {
|
|
3091
3894
|
try {
|
|
3092
|
-
const facts = parseInternalWire(extractFacts(JSON.stringify([{
|
|
3093
|
-
path,
|
|
3094
|
-
source
|
|
3095
|
-
}])), "extractFacts").files[path];
|
|
3096
|
-
return facts && !facts.parsePanicked ? {
|
|
3097
|
-
imports: facts.imports,
|
|
3098
|
-
exports: facts.exports,
|
|
3099
|
-
unboundCreateSystemCalls: facts.unboundCreateSystemCalls ?? []
|
|
3100
|
-
} : null;
|
|
3101
|
-
} catch {
|
|
3102
|
-
return null;
|
|
3103
|
-
}
|
|
3104
|
-
};
|
|
3105
|
-
}
|
|
3106
|
-
const ANIMUS_SYSTEM_SPECIFIER = /^@animus-ui\/system(?:\/.*)?$/;
|
|
3107
|
-
/** The file a specifier names from `importer`: a relative one by the
|
|
3108
|
-
* ingestion's probe order, a bare one by the host's package resolution. */
|
|
3109
|
-
async function resolveModuleFile(importer, specifier, resolvePackage) {
|
|
3110
|
-
if (specifier.startsWith(".")) return relativeSourceCandidates(importer, specifier).find(isFile$1) ?? null;
|
|
3111
|
-
try {
|
|
3112
|
-
return await resolvePackage?.(specifier) ?? null;
|
|
3113
|
-
} catch {
|
|
3114
|
-
return null;
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
const escapeRegExp$1 = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3118
|
-
/**
|
|
3119
|
-
* Follows `name`, exported by the module `specifier` names from `importer`,
|
|
3120
|
-
* through re-exports to its declaration. It is Animus's factory only when
|
|
3121
|
-
* that is `createSystem` of `@animus-ui/system`, and another identity only
|
|
3122
|
-
* when a module is shown to declare it; anything discovery cannot follow is
|
|
3123
|
-
* unknown.
|
|
3124
|
-
*/
|
|
3125
|
-
async function exportIdentity(importer, specifier, name, following, seen) {
|
|
3126
|
-
if (ANIMUS_SYSTEM_SPECIFIER.test(specifier)) return name === "createSystem" ? { kind: "animus" } : {
|
|
3127
|
-
kind: "other",
|
|
3128
|
-
what: `'${name}' of ${specifier}`
|
|
3129
|
-
};
|
|
3130
|
-
const file = await resolveModuleFile(importer, specifier, following.resolvePackage);
|
|
3131
|
-
if (file === null) return {
|
|
3132
|
-
kind: "unknown",
|
|
3133
|
-
why: `'${specifier}' could not be resolved`
|
|
3134
|
-
};
|
|
3135
|
-
const key = `${file}#${name}`;
|
|
3136
|
-
if (seen.has(key)) return {
|
|
3137
|
-
kind: "unknown",
|
|
3138
|
-
why: `'${specifier}' re-exports it in a cycle`
|
|
3139
|
-
};
|
|
3140
|
-
seen.add(key);
|
|
3141
|
-
let source;
|
|
3142
|
-
try {
|
|
3143
|
-
source = readFileSync(file, "utf-8");
|
|
3144
|
-
} catch {
|
|
3145
|
-
return {
|
|
3146
|
-
kind: "unknown",
|
|
3147
|
-
why: `'${specifier}' could not be read`
|
|
3148
|
-
};
|
|
3149
|
-
}
|
|
3150
|
-
const record = following.parseModule(source, file);
|
|
3151
|
-
if (record === null) return {
|
|
3152
|
-
kind: "unknown",
|
|
3153
|
-
why: `'${specifier}' could not be parsed`
|
|
3154
|
-
};
|
|
3155
|
-
const exported = record.exports.find((entry) => entry.exported === name);
|
|
3156
|
-
if (exported?.source) return exportIdentity(file, exported.source, exported.original ?? name, following, seen);
|
|
3157
|
-
const local = exported?.local ?? name;
|
|
3158
|
-
const imported = record.imports.find((entry) => entry.local === local);
|
|
3159
|
-
if (exported && imported) return exportIdentity(file, imported.source, imported.imported, following, seen);
|
|
3160
|
-
if (exported || new RegExp(`\\bexport\\s+(?:async\\s+)?(?:function\\*?|class|const|let|var)\\s+${escapeRegExp$1(name)}\\b`).test(source)) return {
|
|
3161
|
-
kind: "other",
|
|
3162
|
-
what: `the '${name}' that '${specifier}' declares`
|
|
3163
|
-
};
|
|
3164
|
-
const stars = [];
|
|
3165
|
-
for (const match of source.matchAll(/\bexport\s*\*\s*from\s*['"]([^'"]+)['"]/g)) stars.push(await exportIdentity(file, match[1], name, following, seen));
|
|
3166
|
-
const definite = stars.filter((identity) => identity.kind !== "unknown");
|
|
3167
|
-
if (definite.length === 1) return definite[0];
|
|
3168
|
-
if (definite.length > 1) return {
|
|
3169
|
-
kind: "unknown",
|
|
3170
|
-
why: `more than one \`export *\` of '${specifier}' provides '${name}'`
|
|
3171
|
-
};
|
|
3172
|
-
return stars.find((identity) => identity.kind === "unknown") ?? {
|
|
3173
|
-
kind: "unknown",
|
|
3174
|
-
why: `'${specifier}' has no export '${name}' discovery can read`
|
|
3175
|
-
};
|
|
3176
|
-
}
|
|
3177
|
-
/** 1-based line and column of `offset` in `source`. */
|
|
3178
|
-
function locationIn(source, offset) {
|
|
3179
|
-
const before = source.slice(0, offset);
|
|
3180
|
-
const lineStart = before.lastIndexOf("\n") + 1;
|
|
3181
|
-
return {
|
|
3182
|
-
line: before.split("\n").length,
|
|
3183
|
-
column: offset - lineStart + 1
|
|
3184
|
-
};
|
|
3185
|
-
}
|
|
3186
|
-
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;
|
|
3187
|
-
/**
|
|
3188
|
-
* The callees that are Animus's `createSystem` in a parsed system file. A
|
|
3189
|
-
* binding counts once its identity is followed to the factory: a named
|
|
3190
|
-
* import, through local and package re-exports; a namespace import's
|
|
3191
|
-
* member; or a property destructured from a namespace import, `require` or
|
|
3192
|
-
* `import()` of a module. A binding named `createSystem` shown to be
|
|
3193
|
-
* something else is no root. One whose identity discovery cannot follow
|
|
3194
|
-
* keeps the admission spelling gave it, so a resolution limit never drops a
|
|
3195
|
-
* kit. Both are reported. A call of the bare name, which the file neither
|
|
3196
|
-
* imports nor declares, is no root: the system loader evaluates the file
|
|
3197
|
-
* without auto-imports, where the name is undefined. It is reported once.
|
|
3198
|
-
*/
|
|
3199
|
-
async function systemRoots(systemFilePath, source, record, following) {
|
|
3200
|
-
const { imports } = record;
|
|
3201
|
-
const roots = /* @__PURE__ */ new Set();
|
|
3202
|
-
const identityOf = (specifier, name) => exportIdentity(systemFilePath, specifier, name, following, /* @__PURE__ */ new Set());
|
|
3203
|
-
const called = (callee) => callOf(callee).test(source);
|
|
3204
|
-
/** Admits a binding named `createSystem` by its identity: an unknown one
|
|
3205
|
-
* keeps `spellingAdmits`, and every unproven one is reported. */
|
|
3206
|
-
const admit = (local, offset, identity, spellingAdmits) => {
|
|
3207
|
-
if (identity.kind === "animus") {
|
|
3208
|
-
roots.add(local);
|
|
3209
|
-
return;
|
|
3210
|
-
}
|
|
3211
|
-
if (identity.kind === "unknown" && spellingAdmits) roots.add(local);
|
|
3212
|
-
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`;
|
|
3213
|
-
following.report?.({
|
|
3214
|
-
file: systemFilePath,
|
|
3215
|
-
component: local,
|
|
3216
|
-
kind: "warn",
|
|
3217
|
-
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`,
|
|
3218
|
-
code: UNPROVEN_ROOT_BINDING,
|
|
3219
|
-
severity: severityFor(UNPROVEN_ROOT_BINDING),
|
|
3220
|
-
...locationIn(source, offset)
|
|
3221
|
-
});
|
|
3222
|
-
};
|
|
3223
|
-
for (const binding of imports) {
|
|
3224
|
-
if (binding.imported === "createSystem" || binding.local === "createSystem") {
|
|
3225
|
-
const statement = new RegExp(`\\bimport\\b[^;]*?\\bfrom\\s*['"]${escapeRegExp$1(binding.source)}['"]`, "g");
|
|
3226
|
-
let offset = 0;
|
|
3227
|
-
for (const match of source.matchAll(statement)) {
|
|
3228
|
-
const at = match[0].search(new RegExp(`(?<![a-zA-Z0-9_$])${escapeRegExp$1(binding.local)}\\b`));
|
|
3229
|
-
if (at !== -1) {
|
|
3230
|
-
offset = match.index + at;
|
|
3231
|
-
break;
|
|
3232
|
-
}
|
|
3233
|
-
}
|
|
3234
|
-
admit(binding.local, offset, await identityOf(binding.source, binding.imported), binding.imported === "createSystem");
|
|
3235
|
-
continue;
|
|
3895
|
+
const facts = parseInternalWire(extractFacts(JSON.stringify([{
|
|
3896
|
+
path,
|
|
3897
|
+
source
|
|
3898
|
+
}])), "extractFacts").files[path];
|
|
3899
|
+
return facts && !facts.parsePanicked ? {
|
|
3900
|
+
imports: facts.imports,
|
|
3901
|
+
exports: facts.exports,
|
|
3902
|
+
unboundCreateSystemCalls: facts.unboundCreateSystemCalls ?? []
|
|
3903
|
+
} : null;
|
|
3904
|
+
} catch {
|
|
3905
|
+
return null;
|
|
3236
3906
|
}
|
|
3237
|
-
if (binding.source.startsWith(".") && called(binding.local) && (await identityOf(binding.source, binding.imported)).kind === "animus") roots.add(binding.local);
|
|
3238
|
-
}
|
|
3239
|
-
const namespaces = /* @__PURE__ */ new Map();
|
|
3240
|
-
for (const [, namespace, specifier] of source.matchAll(NAMESPACE_IMPORT)) {
|
|
3241
|
-
namespaces.set(namespace, specifier);
|
|
3242
|
-
const member = `${namespace}.createSystem`;
|
|
3243
|
-
if (ANIMUS_SYSTEM_SPECIFIER.test(specifier) || specifier.startsWith(".") && called(member) && (await identityOf(specifier, "createSystem")).kind === "animus") roots.add(member);
|
|
3244
|
-
}
|
|
3245
|
-
const destructuredFrom = (initializer) => {
|
|
3246
|
-
const loaded = /^\(?\s*(?:(?:await\s+)?import|require)\(\s*['"]([^'"]+)['"]\s*\)\s*\)?$/.exec(initializer);
|
|
3247
|
-
if (loaded) return identityOf(loaded[1], "createSystem");
|
|
3248
|
-
const namespace = namespaces.get(initializer);
|
|
3249
|
-
if (namespace !== void 0) return identityOf(namespace, "createSystem");
|
|
3250
|
-
return Promise.resolve({
|
|
3251
|
-
kind: "unknown",
|
|
3252
|
-
why: `it is destructured from '${initializer}', which is not a module namespace`
|
|
3253
|
-
});
|
|
3254
3907
|
};
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
}
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
offset: match.index + whole.indexOf("createSystem"),
|
|
3275
|
-
initializer: initializer.trim()
|
|
3276
|
-
};
|
|
3277
|
-
}
|
|
3908
|
+
}
|
|
3909
|
+
/** The file a specifier names from `importer`, or why it names none: a
|
|
3910
|
+
* relative one by the ingestion's probe order, spelled exactly, a bare one
|
|
3911
|
+
* by the host's package resolution. */
|
|
3912
|
+
async function resolveModuleFile(importer, specifier, resolvePackage, extensions) {
|
|
3913
|
+
const unresolved = { why: `'${specifier}' could not be resolved` };
|
|
3914
|
+
if (specifier.startsWith(".")) {
|
|
3915
|
+
const probed = probeOnDisk(relativeSourceCandidates(importer, specifier, extensions), dirname$1(importer));
|
|
3916
|
+
if (probed.kind === "found") return { file: probed.path };
|
|
3917
|
+
return probed.kind === "case-mismatch" ? {
|
|
3918
|
+
why: caseMismatchReason(`'${specifier}'`, probed, "spell the import as the file is spelled"),
|
|
3919
|
+
caseMismatch: true
|
|
3920
|
+
} : unresolved;
|
|
3921
|
+
}
|
|
3922
|
+
try {
|
|
3923
|
+
const file = await resolvePackage?.(specifier, importer);
|
|
3924
|
+
return file ? { file: file.split("?")[0] } : unresolved;
|
|
3925
|
+
} catch {
|
|
3926
|
+
return unresolved;
|
|
3278
3927
|
}
|
|
3279
3928
|
}
|
|
3280
3929
|
/** The warning for a `createSystem` call that the parser's scopes leave
|
|
@@ -3294,229 +3943,427 @@ function unimportedCreateSystemCall(systemFilePath, record) {
|
|
|
3294
3943
|
column: call[1]
|
|
3295
3944
|
};
|
|
3296
3945
|
}
|
|
3297
|
-
/**
|
|
3298
|
-
*
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3946
|
+
/** The rounds a membership read resolves the modules it asks for: each
|
|
3947
|
+
* reads the modules the last one's identities stopped at, one re-export
|
|
3948
|
+
* hop further. Past it, what is still asked for is finalized as
|
|
3949
|
+
* unresolved and read once more, so an identity it could not follow keeps
|
|
3950
|
+
* the admission its name gives it, with a finding. */
|
|
3951
|
+
const MEMBERSHIP_ROUNDS = 256;
|
|
3952
|
+
/**
|
|
3953
|
+
* The packages and local modules a system file's roots extend or include,
|
|
3954
|
+
* from the engine's own read of it (spec §2.3 step 5): a bare specifier as
|
|
3955
|
+
* its import spells it, a relative one resolved against the system file.
|
|
3956
|
+
* The engine follows each root binding's identity through the modules this
|
|
3957
|
+
* supplies on request: a relative one by the host's extension order,
|
|
3958
|
+
* spelled exactly, a bare one by the host's package resolution.
|
|
3959
|
+
*/
|
|
3960
|
+
async function extractSystemFilePackages(systemFilePath, engine, report, resolvePackage, extensions, kitMembers) {
|
|
3961
|
+
const { systemMembership } = engine;
|
|
3962
|
+
if (systemMembership === void 0) throw new Error("the native engine does not expose systemMembership, which discovery needs — rebuild @animus-ui/extract");
|
|
3963
|
+
const files = {};
|
|
3305
3964
|
try {
|
|
3306
|
-
|
|
3965
|
+
files[systemFilePath] = readFileSync$1(systemFilePath, "utf-8");
|
|
3307
3966
|
} catch {
|
|
3308
3967
|
return [];
|
|
3309
3968
|
}
|
|
3310
|
-
const
|
|
3311
|
-
let
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
}
|
|
3969
|
+
const resolved = {};
|
|
3970
|
+
let answer;
|
|
3971
|
+
for (let round = 0;; round++) {
|
|
3972
|
+
answer = parseInternalWire(systemMembership(JSON.stringify({
|
|
3973
|
+
system: systemFilePath,
|
|
3974
|
+
files,
|
|
3975
|
+
resolved
|
|
3976
|
+
})), "systemMembership");
|
|
3977
|
+
if (answer.needs.length === 0) break;
|
|
3978
|
+
for (const [importer, specifier] of answer.needs) {
|
|
3979
|
+
const key = `${importer}\0${specifier}`;
|
|
3980
|
+
const found = round >= MEMBERSHIP_ROUNDS ? { why: `following '${specifier}' stopped after ${MEMBERSHIP_ROUNDS} re-exports` } : await resolveModuleFile(importer, specifier, resolvePackage, extensions);
|
|
3981
|
+
if ("file" in found) {
|
|
3982
|
+
resolved[key] = { file: found.file };
|
|
3983
|
+
if (!(found.file in files)) try {
|
|
3984
|
+
files[found.file] = readFileSync$1(found.file, "utf-8");
|
|
3985
|
+
} catch {}
|
|
3986
|
+
} else resolved[key] = {
|
|
3987
|
+
why: found.why,
|
|
3988
|
+
caseMismatch: found.caseMismatch
|
|
3989
|
+
};
|
|
3328
3990
|
}
|
|
3329
|
-
}
|
|
3330
|
-
if (
|
|
3331
|
-
|
|
3332
|
-
const
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3991
|
+
}
|
|
3992
|
+
if (!answer.parsed) return [];
|
|
3993
|
+
const reportedUnimported = /* @__PURE__ */ new Set();
|
|
3994
|
+
for (const finding of answer.findings) {
|
|
3995
|
+
if (finding.kind === "unimported") {
|
|
3996
|
+
if (reportedUnimported.has(finding.file)) continue;
|
|
3997
|
+
reportedUnimported.add(finding.file);
|
|
3998
|
+
report?.({
|
|
3999
|
+
file: finding.file,
|
|
4000
|
+
component: "createSystem",
|
|
4001
|
+
kind: "warn",
|
|
4002
|
+
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'`,
|
|
4003
|
+
code: UNIMPORTED_CREATE_SYSTEM,
|
|
4004
|
+
severity: severityFor(UNIMPORTED_CREATE_SYSTEM),
|
|
4005
|
+
line: finding.line,
|
|
4006
|
+
column: finding.column
|
|
4007
|
+
});
|
|
4008
|
+
continue;
|
|
4009
|
+
}
|
|
4010
|
+
if (finding.kind === "escapes") {
|
|
4011
|
+
report?.({
|
|
4012
|
+
file: finding.file,
|
|
4013
|
+
component: "createSystem",
|
|
4014
|
+
kind: "warn",
|
|
4015
|
+
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`,
|
|
4016
|
+
code: UNFOLLOWED_SYSTEM_BUILDER,
|
|
4017
|
+
severity: severityFor(UNFOLLOWED_SYSTEM_BUILDER),
|
|
4018
|
+
line: finding.line,
|
|
4019
|
+
column: finding.column
|
|
4020
|
+
});
|
|
4021
|
+
continue;
|
|
3348
4022
|
}
|
|
4023
|
+
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`;
|
|
4024
|
+
report?.({
|
|
4025
|
+
file: finding.file,
|
|
4026
|
+
component: finding.local,
|
|
4027
|
+
kind: "warn",
|
|
4028
|
+
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`,
|
|
4029
|
+
code: UNPROVEN_ROOT_BINDING,
|
|
4030
|
+
severity: severityFor(UNPROVEN_ROOT_BINDING),
|
|
4031
|
+
line: finding.line,
|
|
4032
|
+
column: finding.column
|
|
4033
|
+
});
|
|
4034
|
+
}
|
|
4035
|
+
const systemPackageRoot = findPackageRoot(systemFilePath);
|
|
4036
|
+
for (const { specifier, importer } of answer.members) {
|
|
4037
|
+
const file = resolved[`${importer}\0${specifier}`]?.file;
|
|
4038
|
+
if (file !== void 0 && !specifier.startsWith(".") && findPackageRoot(importer) !== systemPackageRoot && !kitMembers?.has(specifier)) kitMembers?.set(specifier, file);
|
|
4039
|
+
}
|
|
4040
|
+
return [...new Set(answer.members.map(({ specifier, importer }) => specifier.startsWith(".") ? resolve$1(dirname$1(importer), specifier) : specifier))];
|
|
4041
|
+
}
|
|
4042
|
+
//#endregion
|
|
4043
|
+
//#region pipeline/alias-agreement.ts
|
|
4044
|
+
/** A file's identity on disk: its real path, which follows links and
|
|
4045
|
+
* takes the case the filesystem lists; the path itself where it is not
|
|
4046
|
+
* there. */
|
|
4047
|
+
function physical(file) {
|
|
4048
|
+
try {
|
|
4049
|
+
return realpathSync.native(file);
|
|
4050
|
+
} catch {
|
|
4051
|
+
return resolve(file);
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
/** What a host's module id names: a file on disk, its query dropped and a
|
|
4055
|
+
* dev server's `/@fs/` prefix removed; a virtual id as written; or no
|
|
4056
|
+
* file, where the id names a path nothing is at (an alias applied to a
|
|
4057
|
+
* missing module). */
|
|
4058
|
+
function hostTarget(id) {
|
|
4059
|
+
const path = id.split("?")[0];
|
|
4060
|
+
const file = path.startsWith("/@fs/") ? path.slice(4) : path;
|
|
4061
|
+
if (id.startsWith("\0") || !isAbsolute(file)) return { virtual: id };
|
|
4062
|
+
return existsSync(file) ? { file } : null;
|
|
4063
|
+
}
|
|
4064
|
+
/** What a session's comparisons keep between analyses (spec §2.2 A7):
|
|
4065
|
+
* each file's result by its content hash, while the aliases and the file
|
|
4066
|
+
* set are the same. A new alias set, or a file added or removed, compares
|
|
4067
|
+
* every file again. */
|
|
4068
|
+
var AliasAgreementCache = class {
|
|
4069
|
+
scope = "";
|
|
4070
|
+
byFile = /* @__PURE__ */ new Map();
|
|
4071
|
+
};
|
|
4072
|
+
function packageReadRecord(input) {
|
|
4073
|
+
let analysed = null;
|
|
4074
|
+
const rendered = /* @__PURE__ */ new Map();
|
|
4075
|
+
return {
|
|
4076
|
+
rootDir: input.rootDir,
|
|
4077
|
+
roots: input.roots,
|
|
4078
|
+
redirected: input.redirected,
|
|
4079
|
+
holds(file) {
|
|
4080
|
+
analysed ??= new Set(input.analysed.map((path) => physical(join(input.rootDir, path))));
|
|
4081
|
+
return analysed.has(file);
|
|
4082
|
+
},
|
|
4083
|
+
rendersBuilder(file) {
|
|
4084
|
+
let renders = rendered.get(file);
|
|
4085
|
+
if (renders === void 0) {
|
|
4086
|
+
renders = input.rendersBuilder(file);
|
|
4087
|
+
rendered.set(file, renders);
|
|
4088
|
+
}
|
|
4089
|
+
return renders;
|
|
4090
|
+
},
|
|
4091
|
+
reported: /* @__PURE__ */ new Set()
|
|
3349
4092
|
};
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
4093
|
+
}
|
|
4094
|
+
/**
|
|
4095
|
+
* An import of a discovered package that the host resolves, from its
|
|
4096
|
+
* importer, to `resolved` (spec §2.2 A4). None where the analysis holds
|
|
4097
|
+
* that file, or the request is not a discovered package's. Otherwise the
|
|
4098
|
+
* importer would render a file extraction never read:
|
|
4099
|
+
* - another instance's: unextracted builder code
|
|
4100
|
+
* (`animus.discovery.unread-package-instance`), or, where a source
|
|
4101
|
+
* redirect serves the instance read in its place, that instance
|
|
4102
|
+
* (`animus.discovery.replaced-package-instance`);
|
|
4103
|
+
* - a file of the instance read that the analysis does not hold, and no
|
|
4104
|
+
* redirect covers, which declares builder chains (a compiled subpath):
|
|
4105
|
+
* `animus.discovery.unread-package-instance`.
|
|
4106
|
+
*/
|
|
4107
|
+
function packageInstanceFinding(record, importer, specifier, resolved) {
|
|
4108
|
+
const readRoot = isPackageSpecifier(specifier) ? record.roots[bareSpecifierPackageName(specifier)] : void 0;
|
|
4109
|
+
if (readRoot === void 0) return null;
|
|
4110
|
+
const file = physical(resolved);
|
|
4111
|
+
if (record.holds(file)) return null;
|
|
4112
|
+
const instance = physical(findPackageRoot(file));
|
|
4113
|
+
const redirected = record.redirected.has(specifier);
|
|
4114
|
+
const shown = (path) => relative(record.rootDir, path).split(sep).join(posix.sep);
|
|
4115
|
+
const finding = (code, message) => ({
|
|
4116
|
+
file: importer,
|
|
4117
|
+
component: `import '${specifier}'`,
|
|
4118
|
+
kind: code === "animus.discovery.replaced-package-instance" ? "warn" : "error",
|
|
4119
|
+
message,
|
|
4120
|
+
code,
|
|
4121
|
+
severity: severityFor(code)
|
|
4122
|
+
});
|
|
4123
|
+
if (instance === readRoot) {
|
|
4124
|
+
if (redirected || !record.rendersBuilder(file)) return null;
|
|
4125
|
+
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`);
|
|
4126
|
+
}
|
|
4127
|
+
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)})`;
|
|
4128
|
+
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`);
|
|
4129
|
+
}
|
|
4130
|
+
/**
|
|
4131
|
+
* Where the analysis and the host disagree on a path alias (spec §2.2 A7,
|
|
4132
|
+
* report only: resolution never changes). Each analysed import whose
|
|
4133
|
+
* specifier, as the parser decodes it, an alias the analysis reads names
|
|
4134
|
+
* (tsconfig paths, or the host's own aliases) is resolved as the analysis
|
|
4135
|
+
* resolves it (the alias's expansion through the host's extension order)
|
|
4136
|
+
* and by the host's own resolver. A different physical file, or a file
|
|
4137
|
+
* only one of them finds, is `animus.discovery.alias-mismatch`. A request
|
|
4138
|
+
* the host's resolver fails on is unavailable for that request alone.
|
|
4139
|
+
*
|
|
4140
|
+
* Each import of a discovered package is resolved by the host from its
|
|
4141
|
+
* importer too (spec §2.2 A4): an answer in another instance than the one
|
|
4142
|
+
* read, in a file the analysis does not hold, is
|
|
4143
|
+
* `animus.discovery.unread-package-instance` (the importer would render
|
|
4144
|
+
* unextracted builder code), or `animus.discovery.replaced-package-instance`
|
|
4145
|
+
* where a source redirect serves the instance read in its place.
|
|
4146
|
+
*/
|
|
4147
|
+
async function compareAliases(input) {
|
|
4148
|
+
const { cache, packages } = input;
|
|
4149
|
+
const scope = JSON.stringify([
|
|
4150
|
+
input.pathAliasesJson,
|
|
4151
|
+
input.fileEntries.map((entry) => entry.path).sort(),
|
|
4152
|
+
packages?.roots ?? {},
|
|
4153
|
+
[...packages?.redirected ?? []].sort()
|
|
4154
|
+
]);
|
|
4155
|
+
if (cache.scope !== scope) {
|
|
4156
|
+
cache.scope = scope;
|
|
4157
|
+
cache.byFile.clear();
|
|
4158
|
+
}
|
|
4159
|
+
if (!(input.pathAliasesJson !== null && JSON.parse(input.pathAliasesJson).aliases.length > 0) && Object.keys(packages?.roots ?? {}).length === 0) return {
|
|
4160
|
+
findings: [],
|
|
4161
|
+
unavailable: 0
|
|
3356
4162
|
};
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
pos = skipTrivia(pos);
|
|
3371
|
-
continue;
|
|
3372
|
-
}
|
|
3373
|
-
if ("<([{".includes(ch)) depth++;
|
|
3374
|
-
else if (")]}".includes(ch) || ch === ">" && source[pos - 1] !== "=") {
|
|
3375
|
-
depth--;
|
|
3376
|
-
if (depth === 0) return pos + 1;
|
|
3377
|
-
}
|
|
3378
|
-
pos++;
|
|
4163
|
+
const changed = input.fileEntries.filter((entry) => cache.byFile.get(entry.path)?.hash !== entry.hash);
|
|
4164
|
+
const { files, bases } = changed.length === 0 ? { files: {} } : JSON.parse(input.moduleSpecifiers(JSON.stringify(changed.map(({ path, source }) => ({
|
|
4165
|
+
path,
|
|
4166
|
+
source
|
|
4167
|
+
}))), input.pathAliasesJson ?? void 0));
|
|
4168
|
+
const analysed = new Set(input.fileEntries.map((entry) => entry.path));
|
|
4169
|
+
const packageAnswers = /* @__PURE__ */ new Map();
|
|
4170
|
+
const comparePackage = async (record, importer, specifier) => {
|
|
4171
|
+
const key = `${posix.dirname(importer)}\0${specifier}`;
|
|
4172
|
+
let answer = packageAnswers.get(key);
|
|
4173
|
+
if (answer === void 0) {
|
|
4174
|
+
answer = input.resolve(specifier, join(input.rootDir, importer));
|
|
4175
|
+
packageAnswers.set(key, answer);
|
|
3379
4176
|
}
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
let cursor = skipTrivia(pos);
|
|
3386
|
-
if (source[cursor] !== ".") return pos;
|
|
3387
|
-
cursor = skipTrivia(cursor + 1);
|
|
3388
|
-
const method = IDENT_START_RE.exec(source.slice(cursor))?.[0];
|
|
3389
|
-
if (method !== "extend" && method !== "from") return pos;
|
|
3390
|
-
cursor = skipTrivia(cursor + method.length);
|
|
3391
|
-
if (source[cursor] === "<") {
|
|
3392
|
-
const afterTypeArguments = skipBalanced(cursor);
|
|
3393
|
-
if (afterTypeArguments === -1) return pos;
|
|
3394
|
-
cursor = skipTrivia(afterTypeArguments);
|
|
3395
|
-
}
|
|
3396
|
-
if (source[cursor] !== "(") return pos;
|
|
3397
|
-
cursor = skipTrivia(cursor + 1);
|
|
3398
|
-
const base = IDENT_START_RE.exec(source.slice(cursor))?.[0];
|
|
3399
|
-
if (!base) return pos;
|
|
3400
|
-
cursor = skipTrivia(cursor + base.length);
|
|
3401
|
-
while (source[cursor] === ".") {
|
|
3402
|
-
const afterDot = skipTrivia(cursor + 1);
|
|
3403
|
-
const segment = IDENT_START_RE.exec(source.slice(afterDot))?.[0];
|
|
3404
|
-
if (!segment) break;
|
|
3405
|
-
cursor = skipTrivia(afterDot + segment.length);
|
|
3406
|
-
}
|
|
3407
|
-
if (source[cursor] === ",") cursor = skipTrivia(cursor + 1);
|
|
3408
|
-
if (source[cursor] !== ")") return pos;
|
|
3409
|
-
identifiers.add(base);
|
|
3410
|
-
pos = cursor + 1;
|
|
4177
|
+
let id;
|
|
4178
|
+
try {
|
|
4179
|
+
id = await answer;
|
|
4180
|
+
} catch {
|
|
4181
|
+
return "unavailable";
|
|
3411
4182
|
}
|
|
4183
|
+
const host = id === null ? null : hostTarget(id);
|
|
4184
|
+
if (host === null || "virtual" in host) return null;
|
|
4185
|
+
return packageInstanceFinding(record, importer, specifier, host.file);
|
|
3412
4186
|
};
|
|
3413
|
-
const
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
cursor++;
|
|
3422
|
-
while (cursor < source.length) {
|
|
3423
|
-
const ch = source[cursor];
|
|
3424
|
-
if (ch === ";" || ch === ",") break;
|
|
3425
|
-
if (ch === "\n" && /^\s*(?:export\s+)?(?:const|let|var|function|class|type|interface|import)\b/.test(source.slice(cursor + 1, cursor + 80))) break;
|
|
3426
|
-
if (ch === "=" && source[cursor + 1] !== ">") break;
|
|
3427
|
-
if ("<([{".includes(ch) || ch === "'" || ch === "\"" || ch === "`") {
|
|
3428
|
-
const after = "<([{".includes(ch) ? skipBalanced(cursor) : skipString(cursor);
|
|
3429
|
-
if (after === -1) break;
|
|
3430
|
-
cursor = after;
|
|
3431
|
-
continue;
|
|
3432
|
-
}
|
|
3433
|
-
cursor = ch === "=" ? cursor + 2 : cursor + 1;
|
|
3434
|
-
}
|
|
4187
|
+
const compare = async (importer, specifier, base) => {
|
|
4188
|
+
const candidate = hostCandidate(input.rootDir, base, analysed, input.order, input.readings);
|
|
4189
|
+
const analysis = candidate === null ? null : candidate.analysedAs ?? candidate.candidate.split("?")[0];
|
|
4190
|
+
let id;
|
|
4191
|
+
try {
|
|
4192
|
+
id = await input.resolve(specifier, join(input.rootDir, importer));
|
|
4193
|
+
} catch {
|
|
4194
|
+
return "unavailable";
|
|
3435
4195
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
const match = /([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*$/.exec(source.slice(0, index));
|
|
3448
|
-
return match ? match[1] : null;
|
|
4196
|
+
const host = id === null ? null : hostTarget(id);
|
|
4197
|
+
if (analysis === null || host === null ? analysis === host : "file" in host && physical(join(input.rootDir, analysis)) === physical(host.file)) return null;
|
|
4198
|
+
const shown = host === null ? "no file" : "virtual" in host ? host.virtual : relative(input.rootDir, host.file).split(sep).join(posix.sep);
|
|
4199
|
+
return {
|
|
4200
|
+
file: importer,
|
|
4201
|
+
component: `alias '${specifier}'`,
|
|
4202
|
+
kind: "warn",
|
|
4203
|
+
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`,
|
|
4204
|
+
code: ALIAS_MISMATCH,
|
|
4205
|
+
severity: severityFor(ALIAS_MISMATCH)
|
|
4206
|
+
};
|
|
3449
4207
|
};
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
4208
|
+
await Promise.all(changed.map(async ({ path, hash }) => {
|
|
4209
|
+
const results = await Promise.all((files[path] ?? []).flatMap((specifier) => {
|
|
4210
|
+
const base = bases?.[path]?.[specifier];
|
|
4211
|
+
if (base !== void 0) return [compare(path, specifier, base)];
|
|
4212
|
+
return packages !== void 0 && isPackageSpecifier(specifier) && packages.roots[bareSpecifierPackageName(specifier)] !== void 0 ? [comparePackage(packages, path, specifier)] : [];
|
|
4213
|
+
}));
|
|
4214
|
+
cache.byFile.set(path, {
|
|
4215
|
+
hash,
|
|
4216
|
+
findings: results.filter((result) => result !== null && result !== "unavailable"),
|
|
4217
|
+
unavailable: results.filter((result) => result === "unavailable").length
|
|
4218
|
+
});
|
|
4219
|
+
}));
|
|
4220
|
+
const kept = input.fileEntries.flatMap((entry) => cache.byFile.get(entry.path) ?? []);
|
|
4221
|
+
return {
|
|
4222
|
+
findings: kept.flatMap((file) => file.findings),
|
|
4223
|
+
unavailable: kept.reduce((total, file) => total + file.unavailable, 0)
|
|
4224
|
+
};
|
|
4225
|
+
}
|
|
4226
|
+
//#endregion
|
|
4227
|
+
//#region pipeline/host-package-resolver.ts
|
|
4228
|
+
/**
|
|
4229
|
+
* Package resolution for discovery: one resolver, whose answers are the
|
|
4230
|
+
* host's where it resolves imports itself (spec §2.2 A4), and the system
|
|
4231
|
+
* loader's otherwise, and for a declared workspace the host cannot resolve.
|
|
4232
|
+
*/
|
|
4233
|
+
/**
|
|
4234
|
+
* A declared workspace that nothing links into `node_modules` is no package
|
|
4235
|
+
* to the host, though the system loader resolves it: where the host finds
|
|
4236
|
+
* nothing, discovery asks the loader.
|
|
4237
|
+
*/
|
|
4238
|
+
function discoveryResolver(hostResolve, engine, context) {
|
|
4239
|
+
const load = (specifier, fromDir) => {
|
|
4240
|
+
const native = engine.resolveSpecifier;
|
|
4241
|
+
if (native === void 0) throw new Error("the native engine does not expose resolveSpecifier, which package resolution needs — rebuild @animus-ui/extract");
|
|
4242
|
+
return native(specifier, fromDir, [...context.conditions], context.workspaces, extensionPolicyJson(context.extensions));
|
|
4243
|
+
};
|
|
4244
|
+
const loaderResolve = (specifier, fromDir) => load(specifier, fromDir).path ?? null;
|
|
4245
|
+
if (hostResolve === null) {
|
|
4246
|
+
const unresolved = /* @__PURE__ */ new Map();
|
|
4247
|
+
return {
|
|
4248
|
+
hostFirst: false,
|
|
4249
|
+
async resolveSpecifier(specifier) {
|
|
4250
|
+
const entry = load(specifier, context.rootDir);
|
|
4251
|
+
if (entry.path) return entry.path;
|
|
4252
|
+
unresolved.set(specifier, entry.unresolved ?? "it names no file");
|
|
4253
|
+
return null;
|
|
4254
|
+
},
|
|
4255
|
+
unresolvedReason: (specifier) => unresolved.get(specifier),
|
|
4256
|
+
requireSourceEntry: () => false,
|
|
4257
|
+
loaderResolve
|
|
4258
|
+
};
|
|
3481
4259
|
}
|
|
3482
|
-
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
if (namedImports) for (const binding of namedImports.split(",")) {
|
|
3493
|
-
const parts = binding.trim().split(/\s+as\s+/);
|
|
3494
|
-
const localName = (parts[1] || parts[0]).trim();
|
|
3495
|
-
if (localName) importMap.set(localName, specifier);
|
|
4260
|
+
const loaderOnly = /* @__PURE__ */ new Set();
|
|
4261
|
+
const rootImporter = join$1(context.rootDir, "__animus_discovery__.js");
|
|
4262
|
+
return {
|
|
4263
|
+
hostFirst: true,
|
|
4264
|
+
async resolveSpecifier(specifier) {
|
|
4265
|
+
let hosted;
|
|
4266
|
+
try {
|
|
4267
|
+
hosted = await hostResolve(specifier, rootImporter);
|
|
4268
|
+
} catch {
|
|
4269
|
+
hosted = null;
|
|
3496
4270
|
}
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
while (!importMap.has(current) && !seen.has(current)) {
|
|
3506
|
-
seen.add(current);
|
|
3507
|
-
const target = aliasOf.get(current);
|
|
3508
|
-
if (!target) break;
|
|
3509
|
-
current = target;
|
|
3510
|
-
}
|
|
3511
|
-
return current;
|
|
4271
|
+
if (hosted !== null || !Object.hasOwn(context.workspaces, bareSpecifierPackageName(specifier))) return hosted;
|
|
4272
|
+
const loaded = loaderResolve(specifier, context.rootDir);
|
|
4273
|
+
if (loaded) loaderOnly.add(specifier);
|
|
4274
|
+
return loaded;
|
|
4275
|
+
},
|
|
4276
|
+
unresolvedReason: () => void 0,
|
|
4277
|
+
requireSourceEntry: (specifier) => loaderOnly.has(specifier),
|
|
4278
|
+
loaderResolve
|
|
3512
4279
|
};
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
4280
|
+
}
|
|
4281
|
+
//#endregion
|
|
4282
|
+
//#region pipeline/output-targets.ts
|
|
4283
|
+
/**
|
|
4284
|
+
* Where a bundler writes, as one model: the directories it fills and the
|
|
4285
|
+
* files it writes by exact name. Discovery excludes both, and the Rollup
|
|
4286
|
+
* family's render check reads both, so the two never classify output
|
|
4287
|
+
* differently.
|
|
4288
|
+
*/
|
|
4289
|
+
function noOutputTargets() {
|
|
4290
|
+
return {
|
|
4291
|
+
dirs: [],
|
|
4292
|
+
files: []
|
|
4293
|
+
};
|
|
4294
|
+
}
|
|
4295
|
+
/** Each output's named directory or file; one naming neither writes to
|
|
4296
|
+
* `fallbackDir` when there is one. */
|
|
4297
|
+
function targetsOf(base, outputs, fallbackDir) {
|
|
4298
|
+
const targets = noOutputTargets();
|
|
4299
|
+
for (const output of outputs) if (output.dir !== void 0) targets.dirs.push(resolve$1(base, output.dir));
|
|
4300
|
+
else if (output.file !== void 0) targets.files.push(resolve$1(base, output.file));
|
|
4301
|
+
else if (fallbackDir !== void 0) targets.dirs.push(resolve$1(base, fallbackDir));
|
|
4302
|
+
return targets;
|
|
4303
|
+
}
|
|
4304
|
+
/** The targets of Rollup's or Rolldown's output options at render. */
|
|
4305
|
+
function rollupOutputTargets(output) {
|
|
4306
|
+
return targetsOf(process.cwd(), [output]);
|
|
4307
|
+
}
|
|
4308
|
+
/** Every Vite environment's outputs, as Vite's own `getResolvedOutDirs`
|
|
4309
|
+
* reads them: each output's `dir`, else the environment's `outDir`. */
|
|
4310
|
+
function viteOutputTargets(config) {
|
|
4311
|
+
return mergeOutputTargets([config.build, ...Object.values(config.environments ?? {}).flatMap((environment) => environment.build === void 0 ? [] : [environment.build])].map((build) => {
|
|
4312
|
+
const output = build.rolldownOptions?.output ?? build.rollupOptions?.output;
|
|
4313
|
+
const outputs = output === void 0 ? [{}] : Array.isArray(output) ? output : [output];
|
|
4314
|
+
return targetsOf(config.root, outputs, build.outDir);
|
|
4315
|
+
}));
|
|
4316
|
+
}
|
|
4317
|
+
/** esbuild's `outdir`, or its exact `outfile`. */
|
|
4318
|
+
function esbuildOutputTargets(options) {
|
|
4319
|
+
return targetsOf(options.absWorkingDir ?? process.cwd(), [{
|
|
4320
|
+
dir: options.outdir,
|
|
4321
|
+
file: options.outfile
|
|
4322
|
+
}]);
|
|
4323
|
+
}
|
|
4324
|
+
/** webpack's `output.path`, up to its first segment holding a template
|
|
4325
|
+
* placeholder (`out/[fullhash]` writes under `out`). */
|
|
4326
|
+
function webpackOutputTargets(outputPath) {
|
|
4327
|
+
if (outputPath === void 0) return noOutputTargets();
|
|
4328
|
+
const segments = outputPath.split(sep$1);
|
|
4329
|
+
const placeholder = segments.findIndex((segment) => segment.includes("["));
|
|
4330
|
+
const fixed = placeholder === -1 ? outputPath : segments.slice(0, placeholder).join(sep$1);
|
|
4331
|
+
return {
|
|
4332
|
+
dirs: fixed === "" ? [] : [fixed],
|
|
4333
|
+
files: []
|
|
4334
|
+
};
|
|
4335
|
+
}
|
|
4336
|
+
function mergeOutputTargets(all) {
|
|
4337
|
+
return {
|
|
4338
|
+
dirs: [...new Set(all.flatMap((targets) => targets.dirs))],
|
|
4339
|
+
files: [...new Set(all.flatMap((targets) => targets.files))]
|
|
4340
|
+
};
|
|
4341
|
+
}
|
|
4342
|
+
/** The Session's structural exclusions: every target inside the root. A
|
|
4343
|
+
* directory that is the root excludes nothing; its files still can. */
|
|
4344
|
+
function outputExclusions(root, targets) {
|
|
4345
|
+
return [...targets.dirs, ...targets.files].flatMap((target) => {
|
|
4346
|
+
const exclusion = outputExclusion(root, target);
|
|
4347
|
+
return exclusion === null ? [] : [exclusion];
|
|
4348
|
+
});
|
|
4349
|
+
}
|
|
4350
|
+
/** The analysed files a build's targets hold, as the render check reports
|
|
4351
|
+
* them: a file target the analysis read is the build's own earlier
|
|
4352
|
+
* output; a file inside a directory target is earlier output or a source
|
|
4353
|
+
* the bundler writes beside, which the check cannot tell apart. */
|
|
4354
|
+
function analysedOutputs(root, targets, analyzed) {
|
|
4355
|
+
const earlier = analyzed.filter((file) => targets.files.includes(file));
|
|
4356
|
+
const inside = targets.dirs.flatMap((dir) => {
|
|
4357
|
+
const exclusion = outputExclusion(root, dir);
|
|
4358
|
+
const held = analyzed.filter((file) => !earlier.includes(file) && isPathWithinRoot(dir, file));
|
|
4359
|
+
return exclusion === null || held.length === 0 ? [] : [{
|
|
4360
|
+
exclusion,
|
|
4361
|
+
held
|
|
4362
|
+
}];
|
|
4363
|
+
});
|
|
4364
|
+
const rel = (file) => relative$1(root, file);
|
|
4365
|
+
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`)];
|
|
4366
|
+
return parts.length === 0 ? null : `[animus] this build ${parts.join("; and ")}.`;
|
|
3520
4367
|
}
|
|
3521
4368
|
//#endregion
|
|
3522
4369
|
//#region pipeline/source-corpus.ts
|
|
@@ -3537,6 +4384,7 @@ function createSourceCorpus(host, ingestor = createSourceIngestor(host)) {
|
|
|
3537
4384
|
ownership: {}
|
|
3538
4385
|
};
|
|
3539
4386
|
return {
|
|
4387
|
+
facts: (entries) => ingestor.facts(entries),
|
|
3540
4388
|
async prepare(input) {
|
|
3541
4389
|
const rawEntries = "fileCache" in input ? assembleRawEntries(input) : input;
|
|
3542
4390
|
const ingested = await ingestor.ingest(rawEntries);
|
|
@@ -3585,7 +4433,7 @@ function requireAnchoredAt(rootDir) {
|
|
|
3585
4433
|
function packageRootFromEntry(entry) {
|
|
3586
4434
|
let current = dirname$1(entry);
|
|
3587
4435
|
while (true) {
|
|
3588
|
-
if (existsSync(join$1(current, "package.json"))) return current;
|
|
4436
|
+
if (existsSync$1(join$1(current, "package.json"))) return current;
|
|
3589
4437
|
const parent = dirname$1(current);
|
|
3590
4438
|
if (parent === current) return null;
|
|
3591
4439
|
current = parent;
|
|
@@ -3617,7 +4465,7 @@ function resolveThroughPathAliases(specifier, rootDir, pathAliasesJson) {
|
|
|
3617
4465
|
} else if (specifier.startsWith(alias.pattern)) mapped = alias.replacement + specifier.slice(alias.pattern.length);
|
|
3618
4466
|
if (mapped === null) continue;
|
|
3619
4467
|
const absolute = isAbsolute$1(mapped) ? mapped : join$1(rootDir, mapped);
|
|
3620
|
-
if (existsSync(absolute)) return absolute;
|
|
4468
|
+
if (existsSync$1(absolute)) return absolute;
|
|
3621
4469
|
}
|
|
3622
4470
|
return null;
|
|
3623
4471
|
}
|
|
@@ -3638,15 +4486,15 @@ function resolveAssetFile(specifier, rootDir, pathAliasesJson) {
|
|
|
3638
4486
|
if (!subpath) return null;
|
|
3639
4487
|
for (const modulesDir of requireFromRoot.resolve.paths(packageName) ?? []) {
|
|
3640
4488
|
const packageRoot = join$1(modulesDir, packageName);
|
|
3641
|
-
if (!existsSync(join$1(packageRoot, "package.json"))) continue;
|
|
4489
|
+
if (!existsSync$1(join$1(packageRoot, "package.json"))) continue;
|
|
3642
4490
|
const candidate = join$1(packageRoot, subpath);
|
|
3643
|
-
if (existsSync(candidate)) return candidate;
|
|
4491
|
+
if (existsSync$1(candidate)) return candidate;
|
|
3644
4492
|
}
|
|
3645
4493
|
try {
|
|
3646
4494
|
const packageRoot = packageRootFromEntry(requireFromRoot.resolve(packageName));
|
|
3647
4495
|
if (!packageRoot) return null;
|
|
3648
4496
|
const candidate = join$1(packageRoot, subpath);
|
|
3649
|
-
return existsSync(candidate) ? candidate : null;
|
|
4497
|
+
return existsSync$1(candidate) ? candidate : null;
|
|
3650
4498
|
} catch {
|
|
3651
4499
|
return null;
|
|
3652
4500
|
}
|
|
@@ -3671,12 +4519,12 @@ function buildSourceTokenIndex(opts) {
|
|
|
3671
4519
|
for (const [dir, specifier] of Object.entries(opts.dirOwners)) {
|
|
3672
4520
|
let real = dir;
|
|
3673
4521
|
try {
|
|
3674
|
-
real = realpathSync(dir);
|
|
4522
|
+
real = realpathSync$1(dir);
|
|
3675
4523
|
} catch {}
|
|
3676
4524
|
addOwnerDir(real, specifier);
|
|
3677
4525
|
let packageRoot = real;
|
|
3678
|
-
while (packageRoot !== dirname$1(packageRoot) && !existsSync(join$1(packageRoot, "package.json"))) packageRoot = dirname$1(packageRoot);
|
|
3679
|
-
if (existsSync(join$1(packageRoot, "package.json"))) addOwnerDir(packageRoot, specifier);
|
|
4526
|
+
while (packageRoot !== dirname$1(packageRoot) && !existsSync$1(join$1(packageRoot, "package.json"))) packageRoot = dirname$1(packageRoot);
|
|
4527
|
+
if (existsSync$1(join$1(packageRoot, "package.json"))) addOwnerDir(packageRoot, specifier);
|
|
3680
4528
|
}
|
|
3681
4529
|
for (const [modulePath, exports] of Object.entries(manifests)) {
|
|
3682
4530
|
const owner = realDirOwners.find(({ dir }) => isPathWithinRoot(dir, modulePath));
|
|
@@ -4355,15 +5203,27 @@ function buildAnalysisInputs(opts) {
|
|
|
4355
5203
|
if (opts.system.declarationScalesJson) inputs.declarationScalesJson = opts.system.declarationScalesJson;
|
|
4356
5204
|
if (opts.system.generatedNamesJson) inputs.generatedNamesJson = opts.system.generatedNamesJson;
|
|
4357
5205
|
if (opts.system.propertyRecordsJson) inputs.propertyRecordsJson = opts.system.propertyRecordsJson;
|
|
4358
|
-
const context = opts.analysisContext;
|
|
4359
|
-
if (context
|
|
5206
|
+
const context = analysisContextJson(opts.analysisContext);
|
|
5207
|
+
if (context !== void 0) inputs.analysisContextJson = context;
|
|
5208
|
+
return inputs;
|
|
5209
|
+
}
|
|
5210
|
+
/** The engine's wire for what the host knows; present only when the host
|
|
5211
|
+
* knows something, so a host that knows nothing persists unchanged inputs. */
|
|
5212
|
+
function analysisContextJson(context) {
|
|
5213
|
+
if (!(context?.skippedSources?.length || context?.unbundledComputedImports || context?.packageDirs?.length || context?.extensions || context?.openings?.length)) return;
|
|
5214
|
+
return JSON.stringify({
|
|
4360
5215
|
skippedSources: context.skippedSources ?? [],
|
|
4361
5216
|
unbundledComputedImports: context.unbundledComputedImports ?? false,
|
|
4362
5217
|
packageDirs: context.packageDirs ?? [],
|
|
4363
5218
|
linkedDirs: context.linkedDirs ?? [],
|
|
4364
|
-
outputDirs: context.outputDirs ?? []
|
|
5219
|
+
outputDirs: context.outputDirs ?? [],
|
|
5220
|
+
...context.extensions && { extensions: {
|
|
5221
|
+
appended: context.extensions.appended,
|
|
5222
|
+
nodeNext: context.extensions.nodeNext,
|
|
5223
|
+
alias: context.extensions.alias
|
|
5224
|
+
} },
|
|
5225
|
+
...context.openings?.length && { openings: context.openings }
|
|
4365
5226
|
});
|
|
4366
|
-
return inputs;
|
|
4367
5227
|
}
|
|
4368
5228
|
function hasSourceThemeManifests(system) {
|
|
4369
5229
|
const json = system.sourceThemeManifestsJson ?? "";
|
|
@@ -4397,7 +5257,11 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
4397
5257
|
const inputs = buildAnalysisInputs(opts);
|
|
4398
5258
|
const serializeMs = Math.round(performance.now() - t);
|
|
4399
5259
|
t = performance.now();
|
|
4400
|
-
const manifestJson = analyzeProject(...buildAnalyzeProjectArgs(inputs))
|
|
5260
|
+
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, {
|
|
5261
|
+
isAsset: opts.assets?.isAsset,
|
|
5262
|
+
adapted: opts.adapted,
|
|
5263
|
+
expander: opts.loadExpander
|
|
5264
|
+
})));
|
|
4401
5265
|
const extractMs = Math.round(performance.now() - t);
|
|
4402
5266
|
t = performance.now();
|
|
4403
5267
|
const manifest = JSON.parse(manifestJson);
|
|
@@ -4633,16 +5497,24 @@ function renameDeclarationRecords(declarationScalesJson, rename) {
|
|
|
4633
5497
|
}
|
|
4634
5498
|
//#endregion
|
|
4635
5499
|
//#region pipeline/system-config.ts
|
|
5500
|
+
function systemLoadReads(error) {
|
|
5501
|
+
const thrown = error;
|
|
5502
|
+
const carrier = thrown?.dependencies ? thrown : thrown?.cause;
|
|
5503
|
+
return {
|
|
5504
|
+
dependencies: carrier?.dependencies ?? [],
|
|
5505
|
+
missing: carrier?.missing ?? []
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
4636
5508
|
/** The loader's evaluation of the system file. A failure on a file that
|
|
4637
5509
|
* calls `createSystem` with no binding leads with discovery's warning line
|
|
4638
5510
|
* for it, then keeps the loader's own error. */
|
|
4639
|
-
function evaluateSystemModule(engine, systemPath, rootDir, conditions) {
|
|
5511
|
+
function evaluateSystemModule(engine, systemPath, rootDir, conditions, workspaces, extensions) {
|
|
4640
5512
|
try {
|
|
4641
|
-
return engine.loadSystemModule(systemPath, rootDir, void 0, conditions);
|
|
5513
|
+
return engine.loadSystemModule(systemPath, rootDir, void 0, conditions, workspaces, extensions && extensionPolicyJson(extensions));
|
|
4642
5514
|
} catch (error) {
|
|
4643
5515
|
let source;
|
|
4644
5516
|
try {
|
|
4645
|
-
source = readFileSync(systemPath, "utf-8");
|
|
5517
|
+
source = readFileSync$1(systemPath, "utf-8");
|
|
4646
5518
|
} catch {
|
|
4647
5519
|
throw error;
|
|
4648
5520
|
}
|
|
@@ -4657,7 +5529,7 @@ function evaluateSystemModule(engine, systemPath, rootDir, conditions) {
|
|
|
4657
5529
|
* variable name. Error handling stays at the call site.
|
|
4658
5530
|
*/
|
|
4659
5531
|
function loadSystemConfig(engineApi, opts) {
|
|
4660
|
-
const config = evaluateSystemModule(engineApi(), opts.systemPath, opts.rootDir, opts.conditions);
|
|
5532
|
+
const config = evaluateSystemModule(engineApi(), opts.systemPath, opts.rootDir, opts.conditions, opts.workspaces, opts.extensions);
|
|
4661
5533
|
let scalesJson = config.scalesJson;
|
|
4662
5534
|
let variableMapJson = config.variableMapJson;
|
|
4663
5535
|
const registrations = splitInvalidPropertyRegistrations(config.variableCss);
|
|
@@ -4707,6 +5579,7 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
4707
5579
|
keyframesJson: config.keyframesBlocks || null,
|
|
4708
5580
|
vocabularyWitnessesJson: config.vocabularyWitnesses || null,
|
|
4709
5581
|
dependencies: config.dependencies ?? [],
|
|
5582
|
+
missing: config.missing ?? [],
|
|
4710
5583
|
sourceThemeManifestsJson: config.sourceThemeManifests || null
|
|
4711
5584
|
};
|
|
4712
5585
|
if (declarationScalesJson) system.declarationScalesJson = declarationScalesJson;
|
|
@@ -4826,13 +5699,6 @@ const CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
4826
5699
|
".mjs",
|
|
4827
5700
|
".cjs"
|
|
4828
5701
|
]);
|
|
4829
|
-
const isFile = (path) => {
|
|
4830
|
-
try {
|
|
4831
|
-
return statSync$1(path).isFile();
|
|
4832
|
-
} catch {
|
|
4833
|
-
return false;
|
|
4834
|
-
}
|
|
4835
|
-
};
|
|
4836
5702
|
const posixPath = (path) => path.split(sep).join("/");
|
|
4837
5703
|
/**
|
|
4838
5704
|
* The package-relative files `npm pack` publishes, read with npm's own rules
|
|
@@ -4898,7 +5764,7 @@ function animusTargets(manifest) {
|
|
|
4898
5764
|
/** Every file in the package outside `node_modules` and `.git`,
|
|
4899
5765
|
* package-relative. */
|
|
4900
5766
|
function packageFiles(pkgRoot, dir = "") {
|
|
4901
|
-
return readdirSync
|
|
5767
|
+
return readdirSync(join(pkgRoot, dir), { withFileTypes: true }).flatMap((entry) => {
|
|
4902
5768
|
const path = dir === "" ? entry.name : `${dir}/${entry.name}`;
|
|
4903
5769
|
if (entry.isDirectory()) return entry.name === "node_modules" || entry.name === ".git" ? [] : packageFiles(pkgRoot, path);
|
|
4904
5770
|
return entry.isFile() ? [path] : [];
|
|
@@ -4922,7 +5788,7 @@ function targetPattern(target) {
|
|
|
4922
5788
|
function kitPublicationFailures(pkgRoot, engine, artifactDir) {
|
|
4923
5789
|
let manifest;
|
|
4924
5790
|
try {
|
|
4925
|
-
manifest = JSON.parse(readFileSync
|
|
5791
|
+
manifest = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf-8"));
|
|
4926
5792
|
} catch (error) {
|
|
4927
5793
|
return [`package.json: cannot be read: ${String(error)}`];
|
|
4928
5794
|
}
|
|
@@ -4961,8 +5827,14 @@ function kitPublicationFailures(pkgRoot, engine, artifactDir) {
|
|
|
4961
5827
|
const matched = files.filter((file) => pattern.test(file));
|
|
4962
5828
|
if (matched.length === 0) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, matches no file in the package`);
|
|
4963
5829
|
for (const file of matched) admit(subpath, file);
|
|
4964
|
-
} else
|
|
4965
|
-
|
|
5830
|
+
} else {
|
|
5831
|
+
const seen = seeOnDisk(resolve(pkgRoot, target), pkgRoot);
|
|
5832
|
+
if (seen.kind === "file") admit(subpath, relPath);
|
|
5833
|
+
else failures.push(seen.kind === "case-only" ? `package.json: ${caseMismatchReason(`the "animus" target of exports["${subpath}"]`, {
|
|
5834
|
+
candidate: target,
|
|
5835
|
+
actual: rel(seen.actual)
|
|
5836
|
+
}, "spell the target as the file is spelled")}` : `package.json: the "animus" target of exports["${subpath}"], ${target}, does not exist in the package`);
|
|
5837
|
+
}
|
|
4966
5838
|
}
|
|
4967
5839
|
const visited = /* @__PURE__ */ new Set();
|
|
4968
5840
|
while (queue.length > 0) {
|
|
@@ -4971,12 +5843,17 @@ function kitPublicationFailures(pkgRoot, engine, artifactDir) {
|
|
|
4971
5843
|
visited.add(file);
|
|
4972
5844
|
const specifiers = parseInternalWire(moduleSpecifiers(JSON.stringify([{
|
|
4973
5845
|
path: file,
|
|
4974
|
-
source: readFileSync
|
|
5846
|
+
source: readFileSync(file, "utf-8")
|
|
4975
5847
|
}])), "moduleSpecifiers").files[file] ?? [];
|
|
4976
5848
|
for (const specifier of specifiers) {
|
|
4977
5849
|
if (specifier.startsWith(".")) {
|
|
4978
|
-
const
|
|
4979
|
-
|
|
5850
|
+
const probed = probeOnDisk(relativeSourceCandidates(file, specifier), dirname(file));
|
|
5851
|
+
const target = probed.kind === "found" ? probed.path : void 0;
|
|
5852
|
+
if (probed.kind === "case-mismatch") failures.push(`${rel(file)}: ${caseMismatchReason(`import '${specifier}'`, {
|
|
5853
|
+
candidate: rel(probed.candidate),
|
|
5854
|
+
actual: rel(probed.actual)
|
|
5855
|
+
}, "spell the import as the file is spelled")}`);
|
|
5856
|
+
else if (target === void 0) failures.push(`${rel(file)}: import '${specifier}' resolves to no file in the package`);
|
|
4980
5857
|
else if (outside(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, outside the package`);
|
|
4981
5858
|
else if (!published(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, which is not in the published files`);
|
|
4982
5859
|
else if (CODE_EXTENSIONS.has(extname(target))) queue.push(target);
|
|
@@ -5060,7 +5937,7 @@ function toWatchKeys(input) {
|
|
|
5060
5937
|
* ancestor. A symlink retargeted after load fails open: no match. */
|
|
5061
5938
|
function realpathThroughNearestExistingAncestor(path) {
|
|
5062
5939
|
try {
|
|
5063
|
-
return realpathSync
|
|
5940
|
+
return realpathSync(path);
|
|
5064
5941
|
} catch {}
|
|
5065
5942
|
const suffix = [];
|
|
5066
5943
|
let current = path;
|
|
@@ -5070,9 +5947,644 @@ function realpathThroughNearestExistingAncestor(path) {
|
|
|
5070
5947
|
suffix.unshift(basename(current));
|
|
5071
5948
|
current = parent;
|
|
5072
5949
|
try {
|
|
5073
|
-
return join(realpathSync
|
|
5950
|
+
return join(realpathSync(current), ...suffix);
|
|
5074
5951
|
} catch {}
|
|
5075
5952
|
}
|
|
5076
5953
|
}
|
|
5077
5954
|
//#endregion
|
|
5078
|
-
|
|
5955
|
+
//#region pipeline/built-in-asset-types.ts
|
|
5956
|
+
/** The Vite version the built-in types come from. */
|
|
5957
|
+
const BUILT_IN_ASSET_SOURCE = "vite@8.2.2";
|
|
5958
|
+
/** Asset extensions, as regular-expression alternatives, a session with no
|
|
5959
|
+
* readable host classification reads as assets (spec §2.2 A8). */
|
|
5960
|
+
const BUILT_IN_ASSET_TYPES = [
|
|
5961
|
+
"apng",
|
|
5962
|
+
"bmp",
|
|
5963
|
+
"png",
|
|
5964
|
+
"jpe?g",
|
|
5965
|
+
"jfif",
|
|
5966
|
+
"pjpeg",
|
|
5967
|
+
"pjp",
|
|
5968
|
+
"gif",
|
|
5969
|
+
"svg",
|
|
5970
|
+
"ico",
|
|
5971
|
+
"webp",
|
|
5972
|
+
"avif",
|
|
5973
|
+
"cur",
|
|
5974
|
+
"jxl",
|
|
5975
|
+
"mp4",
|
|
5976
|
+
"webm",
|
|
5977
|
+
"ogg",
|
|
5978
|
+
"mp3",
|
|
5979
|
+
"wav",
|
|
5980
|
+
"flac",
|
|
5981
|
+
"aac",
|
|
5982
|
+
"opus",
|
|
5983
|
+
"mov",
|
|
5984
|
+
"m4a",
|
|
5985
|
+
"vtt",
|
|
5986
|
+
"woff2?",
|
|
5987
|
+
"eot",
|
|
5988
|
+
"ttf",
|
|
5989
|
+
"otf",
|
|
5990
|
+
"webmanifest",
|
|
5991
|
+
"pdf",
|
|
5992
|
+
"txt"
|
|
5993
|
+
];
|
|
5994
|
+
/** Stylesheet extensions, as regular-expression alternatives, a session
|
|
5995
|
+
* with no readable host classification reads as stylesheets. */
|
|
5996
|
+
const BUILT_IN_STYLESHEET_TYPES = [
|
|
5997
|
+
"css",
|
|
5998
|
+
"less",
|
|
5999
|
+
"sass",
|
|
6000
|
+
"scss",
|
|
6001
|
+
"styl",
|
|
6002
|
+
"stylus",
|
|
6003
|
+
"pcss",
|
|
6004
|
+
"postcss",
|
|
6005
|
+
"sss"
|
|
6006
|
+
];
|
|
6007
|
+
//#endregion
|
|
6008
|
+
//#region pipeline/host-assets.ts
|
|
6009
|
+
const BUILT_IN_ASSET_RE = new RegExp(`\\.(?:${BUILT_IN_ASSET_TYPES.join("|")})$`, "i");
|
|
6010
|
+
/** Vite's stylesheet test (`isCSSRequest`), on the final extension only: a
|
|
6011
|
+
* `x.css.ts` is a module. Exact case, as Vite reads it. */
|
|
6012
|
+
const STYLESHEET_RE = new RegExp(`\\.(?:${BUILT_IN_STYLESHEET_TYPES.join("|")})$`);
|
|
6013
|
+
/** JSON, as Vite's json plugin, webpack's `json` type, esbuild's `json`
|
|
6014
|
+
* loader and Turbopack read it: the final extension, exact case. */
|
|
6015
|
+
const JSON_RE = /\.json$/;
|
|
6016
|
+
/** The queries Vite answers with a string whatever the file holds: `?url`
|
|
6017
|
+
* and `?raw`. Any other query keeps the file's own reading. */
|
|
6018
|
+
const VITE_OPAQUE_QUERY_RE = /[?&](?:url|raw)\b/;
|
|
6019
|
+
/** The built-in classification, where no host's can be read or is not
|
|
6020
|
+
* modelled (webpack's and Rspack's rules, as a conditional rule may never
|
|
6021
|
+
* apply): Vite's known asset types, `svg` included, its CSS languages
|
|
6022
|
+
* (`BUILT_IN_ASSET_SOURCE`) and JSON, read with Vite's queries. */
|
|
6023
|
+
function builtInAssetClassification(reason, detail) {
|
|
6024
|
+
return {
|
|
6025
|
+
isAsset: (file, query) => VITE_OPAQUE_QUERY_RE.test(query) || BUILT_IN_ASSET_RE.test(file) || STYLESHEET_RE.test(file) || JSON_RE.test(file),
|
|
6026
|
+
resolverVersion: `built-in (${reason}${detail ? `: ${detail}` : ""}; ${BUILT_IN_ASSET_SOURCE})`
|
|
6027
|
+
};
|
|
6028
|
+
}
|
|
6029
|
+
/** Vite's own classification: `?url` and `?raw`, its known asset types and
|
|
6030
|
+
* the user's `assetsInclude`, as `ResolvedConfig.assetsInclude` answers,
|
|
6031
|
+
* its CSS languages (`isCSSRequest`), and its json plugin's JSON. */
|
|
6032
|
+
function viteAssetClassification(assetsInclude, version) {
|
|
6033
|
+
return {
|
|
6034
|
+
isAsset: (file, query) => VITE_OPAQUE_QUERY_RE.test(query) || assetsInclude(file) || STYLESHEET_RE.test(file) || JSON_RE.test(file),
|
|
6035
|
+
resolverVersion: `${version ? `vite@${version}` : "vite"} captured`
|
|
6036
|
+
};
|
|
6037
|
+
}
|
|
6038
|
+
/** esbuild's built-in loaders, which a configured `loader` map extends. */
|
|
6039
|
+
const ESBUILD_DEFAULT_LOADERS = {
|
|
6040
|
+
"": "js",
|
|
6041
|
+
".js": "js",
|
|
6042
|
+
".mjs": "js",
|
|
6043
|
+
".cjs": "js",
|
|
6044
|
+
".jsx": "jsx",
|
|
6045
|
+
".ts": "ts",
|
|
6046
|
+
".cts": "ts",
|
|
6047
|
+
".mts": "ts",
|
|
6048
|
+
".tsx": "tsx",
|
|
6049
|
+
".css": "css",
|
|
6050
|
+
".module.css": "local-css",
|
|
6051
|
+
".json": "json",
|
|
6052
|
+
".txt": "text"
|
|
6053
|
+
};
|
|
6054
|
+
/** esbuild loaders whose module is an opaque value: a URL, the file's bytes
|
|
6055
|
+
* or text, a stylesheet, or JSON. `copy` keeps the file as code. */
|
|
6056
|
+
const ESBUILD_OPAQUE_LOADERS = /* @__PURE__ */ new Set([
|
|
6057
|
+
"file",
|
|
6058
|
+
"dataurl",
|
|
6059
|
+
"base64",
|
|
6060
|
+
"binary",
|
|
6061
|
+
"text",
|
|
6062
|
+
"css",
|
|
6063
|
+
"local-css",
|
|
6064
|
+
"global-css",
|
|
6065
|
+
"json"
|
|
6066
|
+
]);
|
|
6067
|
+
/** esbuild's classification, from its `loader` map: the loader esbuild
|
|
6068
|
+
* picks for a file is the longest extension of its name the map holds,
|
|
6069
|
+
* exact case. */
|
|
6070
|
+
function esbuildAssetClassification(loader) {
|
|
6071
|
+
const loaders = new Map(Object.entries({
|
|
6072
|
+
...ESBUILD_DEFAULT_LOADERS,
|
|
6073
|
+
...loader
|
|
6074
|
+
}));
|
|
6075
|
+
return {
|
|
6076
|
+
isAsset: (file) => {
|
|
6077
|
+
let name = file.slice(Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\")) + 1);
|
|
6078
|
+
let picked = name.includes(".") ? void 0 : loaders.get("");
|
|
6079
|
+
for (let dot = name.indexOf("."); dot !== -1; dot = name.indexOf(".")) {
|
|
6080
|
+
picked = loaders.get(name.slice(dot));
|
|
6081
|
+
if (picked !== void 0) break;
|
|
6082
|
+
name = name.slice(dot + 1);
|
|
6083
|
+
}
|
|
6084
|
+
return picked !== void 0 && ESBUILD_OPAQUE_LOADERS.has(picked);
|
|
6085
|
+
},
|
|
6086
|
+
resolverVersion: "esbuild captured"
|
|
6087
|
+
};
|
|
6088
|
+
}
|
|
6089
|
+
/** Turbopack's classification under Next: Next's static-image table
|
|
6090
|
+
* (`nextImageLoaderRegex`), unless `images.disableStaticImages`, and its
|
|
6091
|
+
* stylesheets (`regexLikeCss`), as the installed `next` declares them,
|
|
6092
|
+
* and JSON. Built-in where Next cannot be read. */
|
|
6093
|
+
function nextImageAssetClassification(rootDir, disableStaticImages) {
|
|
6094
|
+
try {
|
|
6095
|
+
const require = createRequire(`${rootDir}/package.json`);
|
|
6096
|
+
const { version } = require("next/package.json");
|
|
6097
|
+
const { nextImageLoaderRegex } = require("next/dist/build/webpack-config");
|
|
6098
|
+
const { regexLikeCss } = require("next/dist/build/webpack/config/blocks/css");
|
|
6099
|
+
if (!(nextImageLoaderRegex instanceof RegExp) || !(regexLikeCss instanceof RegExp)) return builtInAssetClassification("hostOptionUnreadable", `next@${version} image and stylesheet types`);
|
|
6100
|
+
return {
|
|
6101
|
+
isAsset: (file) => JSON_RE.test(file) || regexLikeCss.test(file) || !disableStaticImages && nextImageLoaderRegex.test(file),
|
|
6102
|
+
resolverVersion: `from next@${version}`
|
|
6103
|
+
};
|
|
6104
|
+
} catch {
|
|
6105
|
+
return builtInAssetClassification("hostOptionUnreadable", "next");
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
6108
|
+
//#endregion
|
|
6109
|
+
//#region pipeline/vite-expansions.ts
|
|
6110
|
+
/** The glob syntax read here: literal characters, `*` and a whole-segment
|
|
6111
|
+
* `**`, and a `{a,b}` group of literal alternatives. Anything else (`?`,
|
|
6112
|
+
* classes, extglobs, nested groups) is not reproduced. */
|
|
6113
|
+
const UNREAD_SYNTAX = /[?[\]()!+@\\]/;
|
|
6114
|
+
function segmentOf(text) {
|
|
6115
|
+
if (text === "**") return { kind: "globstar" };
|
|
6116
|
+
if (UNREAD_SYNTAX.test(text) || text.includes("**")) return void 0;
|
|
6117
|
+
let source = "";
|
|
6118
|
+
for (const part of text.split(/(\{[^{}]*\}|\*)/)) if (part === "*") source += "[^/]*";
|
|
6119
|
+
else if (part.startsWith("{") && part.endsWith("}")) {
|
|
6120
|
+
const options = part.slice(1, -1).split(",");
|
|
6121
|
+
if (options.some((option) => /[{}*]/.test(option))) return void 0;
|
|
6122
|
+
source += `(?:${options.map(escape).join("|")})`;
|
|
6123
|
+
} else if (/[{}]/.test(part)) return void 0;
|
|
6124
|
+
else source += escape(part);
|
|
6125
|
+
return {
|
|
6126
|
+
kind: "match",
|
|
6127
|
+
test: new RegExp(`^${source}$`),
|
|
6128
|
+
dotted: text.startsWith(".")
|
|
6129
|
+
};
|
|
6130
|
+
}
|
|
6131
|
+
function escape(text) {
|
|
6132
|
+
return text.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
6133
|
+
}
|
|
6134
|
+
/**
|
|
6135
|
+
* A pattern as Vite resolves it (`toAbsoluteGlob`): relative to the
|
|
6136
|
+
* importer's directory, or with `/` to the Vite root. A pattern in another
|
|
6137
|
+
* form (an alias, a bare name) or with syntax not read here is undefined.
|
|
6138
|
+
*/
|
|
6139
|
+
function resolveGlob(pattern, importerDir, viteRoot) {
|
|
6140
|
+
const negated = pattern.startsWith("!");
|
|
6141
|
+
const body = negated ? pattern.slice(1) : pattern;
|
|
6142
|
+
const start = body.startsWith("/") ? viteRoot : body.startsWith("./") || body.startsWith("../") ? importerDir : void 0;
|
|
6143
|
+
if (start === void 0) return void 0;
|
|
6144
|
+
const parts = body.split("/").filter((part) => part !== "" && part !== ".");
|
|
6145
|
+
let base = start;
|
|
6146
|
+
let index = 0;
|
|
6147
|
+
if (parts.some((part) => part !== ".." && UNREAD_SYNTAX.test(part))) return;
|
|
6148
|
+
while (index < parts.length - 1 && !/[*{}]/.test(parts[index])) {
|
|
6149
|
+
base = parts[index] === ".." ? dirname(base) : resolve(base, parts[index]);
|
|
6150
|
+
index += 1;
|
|
6151
|
+
}
|
|
6152
|
+
const segments = [];
|
|
6153
|
+
for (const part of parts.slice(index)) {
|
|
6154
|
+
if (part === "..") return void 0;
|
|
6155
|
+
const segment = segmentOf(part);
|
|
6156
|
+
if (segment === void 0) return void 0;
|
|
6157
|
+
segments.push(segment);
|
|
6158
|
+
}
|
|
6159
|
+
return {
|
|
6160
|
+
negated,
|
|
6161
|
+
base,
|
|
6162
|
+
segments
|
|
6163
|
+
};
|
|
6164
|
+
}
|
|
6165
|
+
/** Whether `names`, a path below a glob's base, matches its segments. A
|
|
6166
|
+
* wildcard never matches a dot-led name unless `dot`. */
|
|
6167
|
+
function matches(segments, names, dot) {
|
|
6168
|
+
const [segment, ...rest] = segments;
|
|
6169
|
+
if (segment === void 0) return names.length === 0;
|
|
6170
|
+
if (segment.kind === "globstar") {
|
|
6171
|
+
if (matches(rest, names, dot)) return true;
|
|
6172
|
+
const [name, ...more] = names;
|
|
6173
|
+
if (name === void 0 || !dot && name.startsWith(".")) return false;
|
|
6174
|
+
return matches(segments, more, dot);
|
|
6175
|
+
}
|
|
6176
|
+
const [name, ...more] = names;
|
|
6177
|
+
if (name === void 0) return false;
|
|
6178
|
+
if (!dot && name.startsWith(".") && !segment.dotted) return false;
|
|
6179
|
+
return segment.test.test(name) && matches(rest, more, dot);
|
|
6180
|
+
}
|
|
6181
|
+
/** Every file below `dir`, following symbolic links as Vite does, each
|
|
6182
|
+
* directory once by its real path. A read the walk cannot finish throws:
|
|
6183
|
+
* the expansion would not be every file. */
|
|
6184
|
+
function walk(dir, prefix = [], visited = /* @__PURE__ */ new Set()) {
|
|
6185
|
+
const real = realpathSync(dir);
|
|
6186
|
+
if (visited.has(real)) return [];
|
|
6187
|
+
const inside = new Set(visited).add(real);
|
|
6188
|
+
const files = [];
|
|
6189
|
+
for (const name of readdirSync(dir)) {
|
|
6190
|
+
const path = `${dir}${sep}${name}`;
|
|
6191
|
+
const names = [...prefix, name];
|
|
6192
|
+
const stat = statSync(path);
|
|
6193
|
+
if (stat.isDirectory()) files.push(...walk(path, names, inside));
|
|
6194
|
+
else if (stat.isFile()) files.push({
|
|
6195
|
+
names,
|
|
6196
|
+
path,
|
|
6197
|
+
real: realpathSync(path)
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
return files;
|
|
6201
|
+
}
|
|
6202
|
+
/** The files a set of Vite globs selects: in any affirmed glob and no
|
|
6203
|
+
* negated one, `node_modules` and dot-led names left out unless
|
|
6204
|
+
* `exhaustive`, the importer itself never. */
|
|
6205
|
+
function expandGlobs(globs, importer, exhaustive) {
|
|
6206
|
+
const affirmed = globs.filter((glob) => !glob.negated);
|
|
6207
|
+
const negated = globs.filter((glob) => glob.negated);
|
|
6208
|
+
const inside = (glob, file) => {
|
|
6209
|
+
const rel = relative(glob.base, file);
|
|
6210
|
+
if (isAbsolute(rel) || rel.split(sep)[0] === "..") return false;
|
|
6211
|
+
return matches(glob.segments, rel.split(sep), exhaustive);
|
|
6212
|
+
};
|
|
6213
|
+
const selected = /* @__PURE__ */ new Set();
|
|
6214
|
+
for (const glob of affirmed) for (const { names, path, real } of walk(glob.base)) {
|
|
6215
|
+
if (!exhaustive && names.includes("node_modules")) continue;
|
|
6216
|
+
if (path === importer || !inside(glob, path)) continue;
|
|
6217
|
+
if (negated.some((other) => inside(other, path))) continue;
|
|
6218
|
+
selected.add(real);
|
|
6219
|
+
}
|
|
6220
|
+
return [...selected].sort();
|
|
6221
|
+
}
|
|
6222
|
+
/** The queries a glob's `query` option is read as: Vite's opaque ones,
|
|
6223
|
+
* with or without the `?` it adds. */
|
|
6224
|
+
const GLOB_QUERIES = /* @__PURE__ */ new Map([
|
|
6225
|
+
[void 0, ""],
|
|
6226
|
+
["raw", "?raw"],
|
|
6227
|
+
["?raw", "?raw"],
|
|
6228
|
+
["url", "?url"],
|
|
6229
|
+
["?url", "?url"]
|
|
6230
|
+
]);
|
|
6231
|
+
/** The boolean an option is written as; absent, `false`. */
|
|
6232
|
+
const GLOB_FLAGS = /* @__PURE__ */ new Map([
|
|
6233
|
+
[void 0, false],
|
|
6234
|
+
[true, true],
|
|
6235
|
+
[false, false]
|
|
6236
|
+
]);
|
|
6237
|
+
/** A glob's options as Vite reads them (`parseGlobOptions`): the query each
|
|
6238
|
+
* file is imported with and whether the glob is exhaustive. `import`
|
|
6239
|
+
* selects an export, not files. Undefined for an option set not
|
|
6240
|
+
* reproduced here: another query, `base`, `caseSensitive`, or the
|
|
6241
|
+
* deprecated `as`, which a Vite 8 build does not apply as a query. */
|
|
6242
|
+
function globOptions(options) {
|
|
6243
|
+
if (options === null) return {
|
|
6244
|
+
query: "",
|
|
6245
|
+
exhaustive: false
|
|
6246
|
+
};
|
|
6247
|
+
for (const key of Object.keys(options)) if (![
|
|
6248
|
+
"eager",
|
|
6249
|
+
"import",
|
|
6250
|
+
"exhaustive",
|
|
6251
|
+
"query"
|
|
6252
|
+
].includes(key)) return;
|
|
6253
|
+
const query = GLOB_QUERIES.get(options.query);
|
|
6254
|
+
const exhaustive = GLOB_FLAGS.get(options.exhaustive);
|
|
6255
|
+
if (query === void 0 || exhaustive === void 0) return void 0;
|
|
6256
|
+
if (!GLOB_FLAGS.has(options.eager)) return void 0;
|
|
6257
|
+
return {
|
|
6258
|
+
query,
|
|
6259
|
+
exhaustive
|
|
6260
|
+
};
|
|
6261
|
+
}
|
|
6262
|
+
/**
|
|
6263
|
+
* The glob a variable `import()` of a template literal becomes under
|
|
6264
|
+
* Vite's dynamic-import-vars (`dynamicImportToGlob`): each substitution one
|
|
6265
|
+
* `*` within a segment. It must start `./` or `../` and name a file
|
|
6266
|
+
* extension in its last static text; Vite leaves any other one, and a
|
|
6267
|
+
* concatenation, a runtime import, which it does not expand.
|
|
6268
|
+
*/
|
|
6269
|
+
function importVarsGlob(quasis) {
|
|
6270
|
+
if (quasis.length < 2) return void 0;
|
|
6271
|
+
const head = quasis[0];
|
|
6272
|
+
if (!head.startsWith("./") && !head.startsWith("../")) return void 0;
|
|
6273
|
+
if (quasis.slice(1, -1).some((quasi) => quasi === "")) return void 0;
|
|
6274
|
+
if (quasis.some((quasi) => /[*?{}[\]]/.test(quasi))) return void 0;
|
|
6275
|
+
const last = quasis[quasis.length - 1];
|
|
6276
|
+
if (!/\.[a-z0-9]+$/i.test(last) || last.includes("?")) return void 0;
|
|
6277
|
+
return quasis.join("*");
|
|
6278
|
+
}
|
|
6279
|
+
/**
|
|
6280
|
+
* How a bundled Vite environment (Vite 8, rolldown's native glob and
|
|
6281
|
+
* dynamic-import-vars plugins) expands computed loads (spec §6.3):
|
|
6282
|
+
* `import.meta.glob` and a variable `import()`. `importVars` is false where
|
|
6283
|
+
* the project's `build.dynamicImportVarsOptions` differ from Vite's
|
|
6284
|
+
* default, which transforms every importer outside `node_modules`.
|
|
6285
|
+
* Anything this does not reproduce exactly lists no expansion.
|
|
6286
|
+
*/
|
|
6287
|
+
function viteLoadExpander(viteRoot, importVars) {
|
|
6288
|
+
return { expand(load, rootDir) {
|
|
6289
|
+
const importer = resolve(rootDir, load.importer);
|
|
6290
|
+
const importerDir = dirname(importer);
|
|
6291
|
+
let patterns;
|
|
6292
|
+
let query = "";
|
|
6293
|
+
let exhaustive = false;
|
|
6294
|
+
if (load.kind === "glob" && load.args && "patterns" in load.args) {
|
|
6295
|
+
const read = globOptions(load.args.options);
|
|
6296
|
+
if (read === void 0) return void 0;
|
|
6297
|
+
({query, exhaustive} = read);
|
|
6298
|
+
patterns = load.args.patterns;
|
|
6299
|
+
} else if (load.kind === "import" && load.args && "quasis" in load.args) {
|
|
6300
|
+
if (!importVars || importer.split(sep).includes("node_modules") || !load.args.template || load.args.options !== null || load.args.comments.some((comment) => comment.includes("@vite-ignore"))) return;
|
|
6301
|
+
const glob = importVarsGlob(load.args.quasis);
|
|
6302
|
+
if (glob === void 0) return void 0;
|
|
6303
|
+
patterns = [glob];
|
|
6304
|
+
} else return;
|
|
6305
|
+
const globs = [];
|
|
6306
|
+
for (const pattern of patterns) {
|
|
6307
|
+
const glob = resolveGlob(pattern, importerDir, viteRoot);
|
|
6308
|
+
if (glob === void 0) return void 0;
|
|
6309
|
+
globs.push(glob);
|
|
6310
|
+
}
|
|
6311
|
+
if (!globs.some((glob) => !glob.negated)) return void 0;
|
|
6312
|
+
let files;
|
|
6313
|
+
let realRoot;
|
|
6314
|
+
try {
|
|
6315
|
+
files = expandGlobs(globs, importer, exhaustive);
|
|
6316
|
+
realRoot = realpathSync(rootDir);
|
|
6317
|
+
} catch {
|
|
6318
|
+
return;
|
|
6319
|
+
}
|
|
6320
|
+
return files.map((file) => ({
|
|
6321
|
+
path: relative(realRoot, file).split(sep).join(posix.sep),
|
|
6322
|
+
query
|
|
6323
|
+
}));
|
|
6324
|
+
} };
|
|
6325
|
+
}
|
|
6326
|
+
/** Whether `build.dynamicImportVarsOptions` are Vite's default, which
|
|
6327
|
+
* transforms every importer outside `node_modules`. */
|
|
6328
|
+
function defaultImportVars(options) {
|
|
6329
|
+
const exclude = options?.exclude;
|
|
6330
|
+
return options?.include === void 0 && Array.isArray(exclude) && exclude.length === 1 && exclude[0] instanceof RegExp && exclude[0].source === "node_modules" && exclude[0].flags === "";
|
|
6331
|
+
}
|
|
6332
|
+
/** The aliases Vite adds to every configuration (`clientAlias`), which
|
|
6333
|
+
* name only its own `@vite/` modules. */
|
|
6334
|
+
const VITE_CLIENT_ALIASES = /* @__PURE__ */ new Set(["^\\/?@vite\\/env", "^\\/?@vite\\/client"]);
|
|
6335
|
+
/** Whether an alias could rewrite a relative or root specifier, which the
|
|
6336
|
+
* expander reads without the resolver: a string from `.` or `/`, or a
|
|
6337
|
+
* RegExp other than Vite's own client aliases. */
|
|
6338
|
+
function aliasesRelative(aliases) {
|
|
6339
|
+
return (aliases ?? []).some(({ find }) => find instanceof RegExp ? !(find.flags === "" && VITE_CLIENT_ALIASES.has(find.source)) : find.startsWith(".") || find.startsWith("/"));
|
|
6340
|
+
}
|
|
6341
|
+
/**
|
|
6342
|
+
* The expander for a resolved Vite configuration: only where every
|
|
6343
|
+
* environment is bundled (Vite 8, rolldown's native plugins; an earlier
|
|
6344
|
+
* Vite marks none), and no alias could rewrite a relative or root
|
|
6345
|
+
* specifier. A variable `import()` is expanded only where every environment
|
|
6346
|
+
* keeps Vite's default dynamic-import-vars options.
|
|
6347
|
+
*/
|
|
6348
|
+
function viteHostExpander(config) {
|
|
6349
|
+
const environments = Object.values(config.environments ?? {});
|
|
6350
|
+
if (environments.length === 0 || !environments.every((environment) => environment.isBundled === true) || aliasesRelative(config.resolve?.alias)) return;
|
|
6351
|
+
return viteLoadExpander(config.root, environments.every((environment) => defaultImportVars(environment.build?.dynamicImportVarsOptions)));
|
|
6352
|
+
}
|
|
6353
|
+
//#endregion
|
|
6354
|
+
//#region pipeline/webpack-expansions.ts
|
|
6355
|
+
/** Webpack's `quoteMeta`. */
|
|
6356
|
+
function quoteMeta(text) {
|
|
6357
|
+
return text.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
|
|
6358
|
+
}
|
|
6359
|
+
/** A literal as a RegExp, where webpack tests it statelessly: a global or
|
|
6360
|
+
* sticky one carries state between tests, which is not reproduced. */
|
|
6361
|
+
function regex(literal) {
|
|
6362
|
+
if (literal === null) return void 0;
|
|
6363
|
+
if (/[gy]/.test(literal.flags)) return null;
|
|
6364
|
+
try {
|
|
6365
|
+
return new RegExp(literal.source, literal.flags);
|
|
6366
|
+
} catch {
|
|
6367
|
+
return null;
|
|
6368
|
+
}
|
|
6369
|
+
}
|
|
6370
|
+
/** Webpack's `splitContextFromPrefix`. */
|
|
6371
|
+
function splitContextFromPrefix(prefix) {
|
|
6372
|
+
const at = prefix.lastIndexOf("/");
|
|
6373
|
+
return at >= 0 ? {
|
|
6374
|
+
context: prefix.slice(0, at),
|
|
6375
|
+
prefix: `.${prefix.slice(at)}`
|
|
6376
|
+
} : {
|
|
6377
|
+
context: ".",
|
|
6378
|
+
prefix
|
|
6379
|
+
};
|
|
6380
|
+
}
|
|
6381
|
+
/** A context directory webpack resolves relative to the importer; another
|
|
6382
|
+
* form goes through the resolver (aliases, modules), not reproduced. */
|
|
6383
|
+
function contextDir(importerDir, context) {
|
|
6384
|
+
return context === "." || context.startsWith("./") || context.startsWith("../") ? resolve(importerDir, context) : void 0;
|
|
6385
|
+
}
|
|
6386
|
+
/** The comments that change which files a webpack context holds. */
|
|
6387
|
+
const SELECTING_COMMENT = /webpack(?:Include|Exclude|Ignore)\b/;
|
|
6388
|
+
/**
|
|
6389
|
+
* The context webpack builds for a template literal or a concatenation
|
|
6390
|
+
* (`ContextDependencyHelpers.create`), with the default wrapped-context
|
|
6391
|
+
* options (`/.*\/`, recursive): a template's inner text joins the
|
|
6392
|
+
* expression pattern; a concatenation keeps its prefix and postfix only.
|
|
6393
|
+
*/
|
|
6394
|
+
function specifierContext(load, importerDir) {
|
|
6395
|
+
const { args } = load;
|
|
6396
|
+
if (args === null || !("quasis" in args)) return void 0;
|
|
6397
|
+
if (args.options !== null) return void 0;
|
|
6398
|
+
if (args.comments.some((comment) => SELECTING_COMMENT.test(comment))) return;
|
|
6399
|
+
const { quasis, template } = args;
|
|
6400
|
+
if (quasis.length < 2 || !template && quasis.length > 2) return void 0;
|
|
6401
|
+
const { context, prefix } = splitContextFromPrefix(quasis[0]);
|
|
6402
|
+
const postfixRaw = quasis[quasis.length - 1];
|
|
6403
|
+
if (postfixRaw.includes("#")) return void 0;
|
|
6404
|
+
const at = postfixRaw.indexOf("?");
|
|
6405
|
+
const postfix = at === -1 ? postfixRaw : postfixRaw.slice(0, at);
|
|
6406
|
+
const query = at === -1 ? "" : postfixRaw.slice(at);
|
|
6407
|
+
const inner = template ? quasis.slice(1, -1).map((quasi) => `${quoteMeta(quasi)}.*`).join("") : "";
|
|
6408
|
+
const dir = contextDir(importerDir, context);
|
|
6409
|
+
if (dir === void 0) return void 0;
|
|
6410
|
+
return {
|
|
6411
|
+
dir,
|
|
6412
|
+
recursive: true,
|
|
6413
|
+
regExp: new RegExp(`^${quoteMeta(prefix)}.*${inner}${quoteMeta(postfix)}$`),
|
|
6414
|
+
include: void 0,
|
|
6415
|
+
exclude: void 0,
|
|
6416
|
+
query,
|
|
6417
|
+
category: load.kind === "require" ? "commonjs" : "esm"
|
|
6418
|
+
};
|
|
6419
|
+
}
|
|
6420
|
+
/** `require.context(dir, recursive, regExp, mode)` and
|
|
6421
|
+
* `import.meta.webpackContext(dir, { … })`, with webpack's defaults. */
|
|
6422
|
+
function directContext(load, importerDir) {
|
|
6423
|
+
const { args } = load;
|
|
6424
|
+
if (args === null || !("dir" in args)) return void 0;
|
|
6425
|
+
const regExp = regex(args.regExp);
|
|
6426
|
+
const include = regex(args.include);
|
|
6427
|
+
const exclude = regex(args.exclude);
|
|
6428
|
+
if (regExp === null || include === null || exclude === null) return;
|
|
6429
|
+
const dir = contextDir(importerDir, args.dir);
|
|
6430
|
+
if (dir === void 0) return void 0;
|
|
6431
|
+
return {
|
|
6432
|
+
dir,
|
|
6433
|
+
recursive: args.recursive ?? true,
|
|
6434
|
+
regExp: regExp ?? /^\.\/.*$/,
|
|
6435
|
+
include,
|
|
6436
|
+
exclude,
|
|
6437
|
+
query: "",
|
|
6438
|
+
category: load.kind === "context" ? "commonjs" : "esm"
|
|
6439
|
+
};
|
|
6440
|
+
}
|
|
6441
|
+
/** A group of module directory names, rather than one absolute module
|
|
6442
|
+
* directory. */
|
|
6443
|
+
function isModuleGroup(modules) {
|
|
6444
|
+
return Array.isArray(modules);
|
|
6445
|
+
}
|
|
6446
|
+
/** The requests webpack tests a context file's regExp against
|
|
6447
|
+
* (`RequireContextPlugin`'s `alternativeRequests`). */
|
|
6448
|
+
function alternatives(context, request, reading) {
|
|
6449
|
+
let items = [request];
|
|
6450
|
+
if (!reading.fullySpecified) {
|
|
6451
|
+
const extended = [];
|
|
6452
|
+
for (const item of items) {
|
|
6453
|
+
for (const extension of reading.extensions) if (item.endsWith(extension)) extended.push(item.slice(0, -extension.length));
|
|
6454
|
+
if (!reading.enforceExtension) extended.push(item);
|
|
6455
|
+
}
|
|
6456
|
+
items = [];
|
|
6457
|
+
for (const item of extended) {
|
|
6458
|
+
for (const mainFile of reading.mainFiles) if (item.endsWith(`/${mainFile}`)) {
|
|
6459
|
+
items.push(item.slice(0, -mainFile.length));
|
|
6460
|
+
items.push(item.slice(0, -mainFile.length - 1));
|
|
6461
|
+
}
|
|
6462
|
+
items.push(item);
|
|
6463
|
+
}
|
|
6464
|
+
}
|
|
6465
|
+
const requests = [];
|
|
6466
|
+
for (const item of items) {
|
|
6467
|
+
let hidden = false;
|
|
6468
|
+
for (const modules of reading.modules) if (isModuleGroup(modules)) {
|
|
6469
|
+
for (const name of modules) if (item.startsWith(`./${name}/`)) {
|
|
6470
|
+
requests.push(item.slice(name.length + 3));
|
|
6471
|
+
hidden = true;
|
|
6472
|
+
}
|
|
6473
|
+
} else {
|
|
6474
|
+
const dir = modules.replace(/\\/g, "/");
|
|
6475
|
+
const full = context.replace(/\\/g, "/") + item.slice(1);
|
|
6476
|
+
if (full.startsWith(dir)) requests.push(full.slice(dir.length + 1));
|
|
6477
|
+
}
|
|
6478
|
+
if (!hidden) requests.push(item);
|
|
6479
|
+
}
|
|
6480
|
+
return requests;
|
|
6481
|
+
}
|
|
6482
|
+
/** The files a context holds (`resolveDependencies`): below its directory,
|
|
6483
|
+
* dot-led names skipped, `exclude` and `include` tested on each absolute
|
|
6484
|
+
* path, a file kept when any of its alternative requests matches. */
|
|
6485
|
+
function contextFiles(context, reading) {
|
|
6486
|
+
const files = [];
|
|
6487
|
+
const visit = (dir, visited) => {
|
|
6488
|
+
const real = realpathSync(dir);
|
|
6489
|
+
const names = readdirSync(dir).map((name) => name.normalize("NFC"));
|
|
6490
|
+
if (visited.has(real)) return;
|
|
6491
|
+
const inside = new Set(visited).add(real);
|
|
6492
|
+
for (const name of names) {
|
|
6493
|
+
if (name.startsWith(".")) continue;
|
|
6494
|
+
const path = `${dir}${sep}${name}`;
|
|
6495
|
+
if (context.exclude?.test(path)) continue;
|
|
6496
|
+
const stat = statSync(path);
|
|
6497
|
+
if (stat.isDirectory()) {
|
|
6498
|
+
if (context.recursive) visit(path, inside);
|
|
6499
|
+
} else if (stat.isFile() && (!context.include || context.include.test(path))) {
|
|
6500
|
+
const request = `.${path.slice(context.dir.length).replace(/\\/g, "/")}`;
|
|
6501
|
+
if (alternatives(context.dir, request, reading).some((alternative) => context.regExp.test(alternative))) files.push(realpathSync(path));
|
|
6502
|
+
}
|
|
6503
|
+
}
|
|
6504
|
+
};
|
|
6505
|
+
visit(context.dir, /* @__PURE__ */ new Set());
|
|
6506
|
+
return files.sort();
|
|
6507
|
+
}
|
|
6508
|
+
/**
|
|
6509
|
+
* How a webpack 5 build expands computed loads (spec §6.3): a template or
|
|
6510
|
+
* concatenated `import()` or `require()`, `require.context` and
|
|
6511
|
+
* `import.meta.webpackContext`, each a context module whose files
|
|
6512
|
+
* `ContextModuleFactory` lists. `resolveReading` is the resolver's options
|
|
6513
|
+
* for a dependency category; `wrappedDefaults` is false where the project
|
|
6514
|
+
* changes `wrappedContextRegExp` or `wrappedContextRecursive`. Anything not
|
|
6515
|
+
* reproduced exactly lists no expansion.
|
|
6516
|
+
*/
|
|
6517
|
+
function webpackLoadExpander(resolveReading, wrappedDefaults) {
|
|
6518
|
+
return { expand(load, rootDir) {
|
|
6519
|
+
const importerDir = dirname(resolve(rootDir, load.importer));
|
|
6520
|
+
let context;
|
|
6521
|
+
if (load.kind === "import" || load.kind === "require") context = wrappedDefaults ? specifierContext(load, importerDir) : void 0;
|
|
6522
|
+
else if (load.kind === "context" || load.kind === "webpackContext") context = directContext(load, importerDir);
|
|
6523
|
+
if (context === void 0) return void 0;
|
|
6524
|
+
const reading = resolveReading(context.category);
|
|
6525
|
+
if (reading === void 0 || reading.aliasNames.length > 0) return;
|
|
6526
|
+
let files;
|
|
6527
|
+
let realRoot;
|
|
6528
|
+
try {
|
|
6529
|
+
files = contextFiles(context, reading);
|
|
6530
|
+
realRoot = realpathSync(rootDir);
|
|
6531
|
+
} catch {
|
|
6532
|
+
return;
|
|
6533
|
+
}
|
|
6534
|
+
return files.map((file) => ({
|
|
6535
|
+
path: relative(realRoot, file).split(sep).join(posix.sep),
|
|
6536
|
+
query: context.query
|
|
6537
|
+
}));
|
|
6538
|
+
} };
|
|
6539
|
+
}
|
|
6540
|
+
/** A rule entry, rather than `'...'` or a falsy placeholder. */
|
|
6541
|
+
function isRule(rule) {
|
|
6542
|
+
return rule instanceof Object;
|
|
6543
|
+
}
|
|
6544
|
+
/** Every rule, nested `rules` and `oneOf` included. */
|
|
6545
|
+
function everyRule(rules) {
|
|
6546
|
+
return rules.filter(isRule).flatMap((rule) => [
|
|
6547
|
+
rule,
|
|
6548
|
+
...everyRule(rule.rules ?? []),
|
|
6549
|
+
...everyRule(rule.oneOf ?? [])
|
|
6550
|
+
]);
|
|
6551
|
+
}
|
|
6552
|
+
/**
|
|
6553
|
+
* The expander for a webpack 5 compiler. Each expansion reads the
|
|
6554
|
+
* compiler's options again and lists nothing where a rule carries its own
|
|
6555
|
+
* resolve options or context parser options, `module.defaultRules` is not
|
|
6556
|
+
* webpack's own, or the options cannot be read.
|
|
6557
|
+
*/
|
|
6558
|
+
function webpackHostExpander(reading) {
|
|
6559
|
+
return { expand(load, rootDir) {
|
|
6560
|
+
let options;
|
|
6561
|
+
try {
|
|
6562
|
+
options = reading.options();
|
|
6563
|
+
} catch {
|
|
6564
|
+
return;
|
|
6565
|
+
}
|
|
6566
|
+
if (everyRule(options.rules).some((rule) => rule.resolve !== void 0 || Object.keys(rule.parser ?? {}).some((key) => key.includes("Context"))) || !options.defaultRulesAreWebpacks) return void 0;
|
|
6567
|
+
return webpackLoadExpander(reading.resolveReading, options.wrappedDefaults).expand(load, rootDir);
|
|
6568
|
+
} };
|
|
6569
|
+
}
|
|
6570
|
+
//#endregion
|
|
6571
|
+
//#region pipeline/served-files.ts
|
|
6572
|
+
function servedFiles(manifest) {
|
|
6573
|
+
const dropped = /* @__PURE__ */ new Map();
|
|
6574
|
+
for (const input of manifest.missing_inputs ?? []) {
|
|
6575
|
+
if (input.outcome === "failed-parent") continue;
|
|
6576
|
+
if (!dropped.has(input.file)) dropped.set(input.file, input);
|
|
6577
|
+
}
|
|
6578
|
+
return {
|
|
6579
|
+
listed: new Set(Object.entries(manifest.files ?? {}).filter(([, ids]) => ids.length > 0).map(([file]) => file)),
|
|
6580
|
+
dropped
|
|
6581
|
+
};
|
|
6582
|
+
}
|
|
6583
|
+
/** Why a file dropped over its extension parent is not served: its builder
|
|
6584
|
+
* code would render with empty classes. */
|
|
6585
|
+
function droppedExtensionMessage(drop) {
|
|
6586
|
+
const from = drop.specifier === null ? "" : ` from '${drop.specifier}'`;
|
|
6587
|
+
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.`;
|
|
6588
|
+
}
|
|
6589
|
+
//#endregion
|
|
6590
|
+
export { excludeCollectedPackages as $, createSourceIdentity as $t, postProcessCss as A, substituteAssetPlaceholders as An, webpackExtensionPolicy as At, noOutputTargets as B, __require as Bn, CORE_OPTION_KEYS as Bt, serializeStaticCss as C, systemLoadDiagnostics as Cn, tsconfigChainPaths as Ct, clearEngineCache as D, findSheetAssetSpecifiers as Dn, rollupExtensionPolicy as Dt, buildAnalysisInputs as E, findAssetSpecifiers as En, extensionPolicyJson as Et, resolveThroughPathAliases as F, buildAnalyzeProjectArgs as Fn, pruneStaleAssets as Ft, discoveryResolver as G, assertKnownOptionKeys as Gt, rollupOutputTargets as H, DRIVER_NAMESPACES as Ht, createSourceCorpus as I, ANIMUS_LAYERS as In, writeAssetCopy as It, packageInstanceFinding as J, outputSourceGuard as Jt, AliasAgreementCache as K, createExcludeMatcher as Kt, analysedOutputs as L, assembleStylesheet as Ln, RETIRED_ENGINE_MESSAGE as Lt, buildPathAliasesJson as M, caseMismatchReason as Mn, discoverFiles as Mt, enforceExternalTokenContracts as N, contentHash as Nn, DEFAULT_RUNTIME_IMPORT as Nt, runProjectAnalysis as O, generatedModuleCode as On, turbopackExtensionPolicy as Ot, resolveAssetFile as P, parseInternalWire as Pn, assertRuntimeImportSuppliesTerminals as Pt, engineModuleParser as Q, unmatchedExcludeLines as Qt, esbuildOutputTargets as R, stripLeadingLayerDeclaration as Rn, assertSupportedEngine as Rt, applyPrefix as S, surfaceManifestDiagnostics as Sn, readTsconfigAliasPairs as St, stableStringify as T, vocabularyWitnessDiagnostics as Tn, esbuildExtensionPolicy as Tt, viteOutputTargets as U, REPLACEABLE_DEFAULT_EXCLUDE as Ut, outputExclusions as V, DEFAULT_EXCLUDE as Vt, webpackOutputTargets as W, STRUCTURAL_EXCLUDE as Wt, bareSpecifierPackageName as X, resolveMode as Xt, packageReadRecord as Y, outputSourceMessage as Yt, collectExternalPackageSources as Z, resolveVerbosity as Zt, buildSystemPropsModule as _, VOCABULARY_COLLISION as _n, declaredWorkspacePackages as _t, viteHostExpander as a, parseFilesJson as an, isExcludedPackageRelativePath as at, loadSystemConfig as b, noKitFilesDiagnostics as bn, kitDescriptorDiagnostics as bt, esbuildAssetClassification as c, adaptedOriginals as cn, kitSourceModuleSideEffects as ct, toWatchKeys as d, isEngineTransformExtension as dn, probeAbsolutePathSpecifier as dt, isPathWithinRoot as en, extractSystemFilePackages as et, diffFilePlans as f, preprocessMdx as fn, sourceKitDependencies as ft, assertNoErrorDiagnostics as g, SYSTEM_INSTANCE_MISMATCH as gn, walkPackageSources as gt, kitPublicationFailures as h, INVALID_PROPERTY_REGISTRATION as hn, unresolvableIncludesMessage as ht, webpackLoadExpander as i, isAdvisorySourceDiagnostic as in, importedKitDiagnostics as it, resolveLightningTargets as j, substituteSheetAssets as jn, compareDiscoveryOrder as jt, applyUnitFallback as k, reportSurvivingAssetPlaceholders as kn, viteExtensionPolicy as kt, nextImageAssetClassification as l, DEFAULT_EXTENSIONS as ln, nativeKitSourceRoot as lt, snapshotFilePlans as m, DiagnosticFailure as mn, systemKitDependencies as mt, servedFiles as n, createV2EngineApi as nn, findPackageRoot as nt, viteLoadExpander as o, projectExternalFileOwners as on, isPackageSpecifier as ot, hashReplacementPlans as p, DIAGNOSTIC_LEVELS as pn, staleDistIncludesMessage as pt, compareAliases as q, outputExclusion as qt, webpackHostExpander as r, ingestSourceEntries as rn, firstOwners as rt, builtInAssetClassification as s, adaptSvelteSource as sn, keepsKitSourceEffects as st, droppedExtensionMessage as t, sharesVolumeRoot as tn, fileSideEffects as tt, viteAssetClassification as u, ENGINE_TRANSFORM_EXTENSIONS as un, nativePackageLocator as ut, buildDynamicPropConfig as v, VOCABULARY_LEGACY_VERB as vn, KIT_DESCRIPTOR_FILE as vt, camelToKebab as w, unreadableSourceDiagnostic as wn, BUILT_IN_EXTENSION_POLICY as wt, systemLoadReads as x, severityFor as xn, readKitDescriptor as xt, runStructuralSelfCheck as y, isDeletedSource as yn, buildKitDescriptor as yt, mergeOutputTargets as z, validateLayerOrder as zn, AnimusConfigError as zt };
|