@animus-ui/extract 0.1.23 → 0.1.24
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 +16 -3
- package/dist/index.cjs +11 -1
- package/dist/index.mjs +2 -2
- package/dist/pipeline/analyze-project-args.d.ts +5 -1
- package/dist/pipeline/analyze-project-args.d.ts.map +1 -1
- package/dist/pipeline/asset-placeholders.d.ts +4 -1
- package/dist/pipeline/asset-placeholders.d.ts.map +1 -1
- package/dist/pipeline/core-options.d.ts +13 -7
- package/dist/pipeline/core-options.d.ts.map +1 -1
- package/dist/pipeline/correlate-external-tokens.d.ts +3 -0
- package/dist/pipeline/correlate-external-tokens.d.ts.map +1 -1
- package/dist/pipeline/discover-packages.d.ts +89 -0
- package/dist/pipeline/discover-packages.d.ts.map +1 -1
- package/dist/pipeline/dynamic-prop-config.d.ts +13 -2
- package/dist/pipeline/dynamic-prop-config.d.ts.map +1 -1
- package/dist/pipeline/engine-adapter.d.ts +3 -1
- package/dist/pipeline/engine-adapter.d.ts.map +1 -1
- package/dist/pipeline/index.d.ts +5 -2
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/kit-descriptor.d.ts +44 -0
- package/dist/pipeline/kit-descriptor.d.ts.map +1 -0
- package/dist/pipeline/kit-publication.d.ts +15 -0
- package/dist/pipeline/kit-publication.d.ts.map +1 -0
- package/dist/pipeline/manifest-diagnostics.d.ts +32 -7
- package/dist/pipeline/manifest-diagnostics.d.ts.map +1 -1
- package/dist/pipeline/manifest-schema.d.ts +4 -0
- package/dist/pipeline/manifest-schema.d.ts.map +1 -1
- package/dist/pipeline/prefix.d.ts +14 -3
- package/dist/pipeline/prefix.d.ts.map +1 -1
- package/dist/pipeline/run-analysis.d.ts +13 -2
- package/dist/pipeline/run-analysis.d.ts.map +1 -1
- package/dist/pipeline/source-ingestion.d.ts +9 -2
- package/dist/pipeline/source-ingestion.d.ts.map +1 -1
- package/dist/pipeline/structural-self-check.d.ts.map +1 -1
- package/dist/pipeline/system-config.d.ts +6 -3
- package/dist/pipeline/system-config.d.ts.map +1 -1
- package/dist/{pipeline-kA3VEMgt.mjs → pipeline-Bl20tbu_.mjs} +994 -321
- package/dist/{pipeline-B3JzXiSY.cjs → pipeline-CAH9mxnK.cjs} +1036 -302
- package/dist/session/extraction-session.d.ts +17 -4
- package/dist/session/extraction-session.d.ts.map +1 -1
- package/dist/session.cjs +54 -19
- package/dist/session.mjs +54 -19
- package/package.json +4 -4
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import path, { basename, dirname, join, normalize, posix } from "node:path";
|
|
1
|
+
import { createRequire, isBuiltin } from "node:module";
|
|
2
|
+
import path, { basename, dirname, extname, isAbsolute, join, normalize, posix, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { createHash } from "crypto";
|
|
4
4
|
import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "fs";
|
|
5
|
-
import { dirname as dirname$1, extname, isAbsolute, join as join$1, relative, resolve, sep } from "path";
|
|
6
|
-
import { realpathSync as realpathSync$1 } from "node:fs";
|
|
5
|
+
import { dirname as dirname$1, extname as extname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
|
|
6
|
+
import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, statSync as statSync$1 } from "node:fs";
|
|
7
7
|
import { createRequire as createRequire$1 } from "module";
|
|
8
8
|
import browserslist from "browserslist";
|
|
9
9
|
import { browserslistToTargets, transform } from "lightningcss";
|
|
10
10
|
import { componentValues, dependsOnContext, foldInitialValue, identifierAt, isSpace, isUnitlessProperty, someValue, substitutesValue, tokenize, variableReads } from "@animus-ui/properties";
|
|
11
|
+
import { spawnSync } from "node:child_process";
|
|
11
12
|
//#region \0rolldown/runtime.js
|
|
12
13
|
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
13
14
|
//#endregion
|
|
@@ -90,8 +91,13 @@ function buildAnalyzeProjectArgs(inputs) {
|
|
|
90
91
|
inputs.transformSourcesJson,
|
|
91
92
|
inputs.transformProvenanceJson ?? null
|
|
92
93
|
];
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
const tail = [
|
|
95
|
+
inputs.declarationScalesJson,
|
|
96
|
+
inputs.analysisContextJson,
|
|
97
|
+
inputs.generatedNamesJson
|
|
98
|
+
];
|
|
99
|
+
const last = tail.findLastIndex((slot) => slot !== void 0 && slot !== "");
|
|
100
|
+
for (const slot of tail.slice(0, last + 1)) args.push(slot || void 0);
|
|
95
101
|
return args;
|
|
96
102
|
}
|
|
97
103
|
//#endregion
|
|
@@ -237,13 +243,17 @@ function substituteSheetAssets(sheets, urlBySpecifier) {
|
|
|
237
243
|
}
|
|
238
244
|
const UNSUBSTITUTED_ASSET_CODE = "animus.asset.unsubstituted-placeholder";
|
|
239
245
|
/** A placeholder in emitted CSS is a broken URL in the browser: it fails a
|
|
240
|
-
* strict build and warns otherwise. */
|
|
246
|
+
* strict build, strict development reports it, and it warns otherwise. */
|
|
241
247
|
function reportSurvivingAssetPlaceholders(css, report) {
|
|
242
248
|
const specifiers = placeholdersInAssetCalls(css);
|
|
243
249
|
if (specifiers.length === 0) return;
|
|
244
250
|
const message = `${report.prefix} asset() placeholders reached ${report.surface ?? "emitted CSS"} unsubstituted: ${specifiers.join(", ")} (${UNSUBSTITUTED_ASSET_CODE})`;
|
|
245
|
-
if (report.strict)
|
|
246
|
-
|
|
251
|
+
if (!report.strict) {
|
|
252
|
+
report.warn(message);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (!report.reportErrors) throw new Error(message);
|
|
256
|
+
report.reportErrors(message);
|
|
247
257
|
}
|
|
248
258
|
/**
|
|
249
259
|
* The runtime code an analysis generates: each dynamic prop config, which the
|
|
@@ -272,6 +282,15 @@ function locatedPrefix(diagnostic) {
|
|
|
272
282
|
function droppedSuffix(diagnostic) {
|
|
273
283
|
return diagnostic.dropped && !diagnostic.message.includes(diagnostic.dropped) ? ` — dropped: ${diagnostic.dropped}` : "";
|
|
274
284
|
}
|
|
285
|
+
/** The record's code, when its message does not already quote it. */
|
|
286
|
+
function codeSuffix(diagnostic) {
|
|
287
|
+
return diagnostic.code && !diagnostic.message.includes(diagnostic.code) ? ` [${diagnostic.code}]` : "";
|
|
288
|
+
}
|
|
289
|
+
/** A warn-kind record's line after its mark:
|
|
290
|
+
* `file:line:column: component: message [code]`. */
|
|
291
|
+
function warnLine(diagnostic) {
|
|
292
|
+
return `${locationOf(diagnostic)}: ${diagnostic.component}: ${diagnostic.message}${droppedSuffix(diagnostic)}${codeSuffix(diagnostic)}`;
|
|
293
|
+
}
|
|
275
294
|
/** Stable code for selector forms with no substitutable subject; the
|
|
276
295
|
* extraction engine mints the same string. */
|
|
277
296
|
const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
@@ -290,10 +309,19 @@ const DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set([
|
|
|
290
309
|
"warn",
|
|
291
310
|
"error"
|
|
292
311
|
]);
|
|
312
|
+
/** A key that selects every record of a kind: `kind:bail`, `kind:skip`,
|
|
313
|
+
* `kind:warn` or `kind:error`. */
|
|
314
|
+
const KIND_KEY = "kind:";
|
|
315
|
+
const DIAGNOSTIC_KINDS = /* @__PURE__ */ new Set([
|
|
316
|
+
"bail",
|
|
317
|
+
"skip",
|
|
318
|
+
"warn",
|
|
319
|
+
"error"
|
|
320
|
+
]);
|
|
293
321
|
/** The level `levels` sets for `code`: its exact entry, else the entry of
|
|
294
322
|
* the longest prefix it starts with. */
|
|
295
|
-
function
|
|
296
|
-
if (code === void 0
|
|
323
|
+
function codeLevel(code, levels) {
|
|
324
|
+
if (code === void 0) return void 0;
|
|
297
325
|
if (Object.hasOwn(levels, code)) return levels[code];
|
|
298
326
|
let longest;
|
|
299
327
|
for (const [key, level] of Object.entries(levels)) {
|
|
@@ -306,11 +334,19 @@ function levelFor(code, levels) {
|
|
|
306
334
|
}
|
|
307
335
|
return longest?.level;
|
|
308
336
|
}
|
|
337
|
+
/** The level `levels` sets for a record: its code's level, else its kind's. */
|
|
338
|
+
function levelFor({ code, kind }, levels) {
|
|
339
|
+
if (levels === void 0) return void 0;
|
|
340
|
+
const kindKey = `${KIND_KEY}${kind}`;
|
|
341
|
+
return codeLevel(code, levels) ?? (Object.hasOwn(levels, kindKey) ? levels[kindKey] : void 0);
|
|
342
|
+
}
|
|
309
343
|
/** The level a record prints at: the option's entry for its code, else
|
|
310
|
-
* `error` for
|
|
344
|
+
* `error` for a hard error (an `error`-kind record) or an error-severity
|
|
345
|
+
* record under `strict`, else its own. */
|
|
311
346
|
function effectiveLevel(diagnostic, policy) {
|
|
312
|
-
const level = levelFor(diagnostic
|
|
347
|
+
const level = levelFor(diagnostic, policy.levels);
|
|
313
348
|
if (level !== void 0) return level;
|
|
349
|
+
if (diagnostic.kind === "error") return "error";
|
|
314
350
|
if (diagnostic.severity === "info") return "info";
|
|
315
351
|
return policy.strict && diagnostic.severity === "error" ? "error" : "warn";
|
|
316
352
|
}
|
|
@@ -329,6 +365,7 @@ function knownDiagnosticCodes(engineCodesJson) {
|
|
|
329
365
|
/** The keys of `levels` that name no known code, exactly or as a prefix. */
|
|
330
366
|
function unknownDiagnosticKeys(levels, known) {
|
|
331
367
|
return Object.keys(levels).filter((key) => {
|
|
368
|
+
if (key.startsWith(KIND_KEY)) return !DIAGNOSTIC_KINDS.has(key.slice(5));
|
|
332
369
|
if (!key.endsWith(".*")) return !known.has(key);
|
|
333
370
|
const prefix = key.slice(0, -1);
|
|
334
371
|
return ![...known].some((code) => code.startsWith(prefix));
|
|
@@ -383,9 +420,22 @@ function collectSelectorAliasDiagnostics(selectorAliasesJson) {
|
|
|
383
420
|
const UNREADABLE_SOURCE_FILE = "animus.ingestion.unreadable-source-file";
|
|
384
421
|
/** A kit the system extends resolved, yet discovery found none of its files. */
|
|
385
422
|
const NO_KIT_FILES = "animus.discovery.no-kit-files";
|
|
423
|
+
/** A kit with no `animus` export condition: discovery guesses its source
|
|
424
|
+
* from `src/`. */
|
|
425
|
+
const KIT_WITHOUT_SOURCE_CONDITION = "animus.discovery.kit-without-source-condition";
|
|
426
|
+
/** A kit's `animus` export condition names a file that is missing or outside
|
|
427
|
+
* its package, so that entry is not read from source. */
|
|
428
|
+
const INVALID_KIT_SOURCE_CONDITION = "animus.discovery.invalid-source-condition";
|
|
429
|
+
/** A kit the application imports whose system the application's system
|
|
430
|
+
* does not include: its components are not extracted. */
|
|
431
|
+
const KIT_SYSTEM_NOT_INCLUDED = "animus.kit.system-not-included";
|
|
386
432
|
/** A system file's `createSystem` binding that discovery could not follow to
|
|
387
433
|
* Animus's factory, so it is no root. */
|
|
388
434
|
const UNPROVEN_ROOT_BINDING = "animus.discovery.unproven-root-binding";
|
|
435
|
+
/** A system file calls `createSystem` with no import or local binding. The
|
|
436
|
+
* system loader evaluates the file without auto-imports, where the name is
|
|
437
|
+
* undefined, so the call is no root. */
|
|
438
|
+
const UNIMPORTED_CREATE_SYSTEM = "animus.discovery.unimported-create-system";
|
|
389
439
|
/** What a skipped source file costs: the analysis never sees what it
|
|
390
440
|
* renders. */
|
|
391
441
|
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";
|
|
@@ -421,6 +471,11 @@ function noKitFilesDiagnostics(outcomes) {
|
|
|
421
471
|
severity: severityFor(NO_KIT_FILES)
|
|
422
472
|
}));
|
|
423
473
|
}
|
|
474
|
+
/** A kit's descriptor declares a format this Animus does not read. */
|
|
475
|
+
const KIT_UNSUPPORTED_FORMAT = "animus.kit.unsupported-format";
|
|
476
|
+
/** A kit's descriptor records a definition its shipped source no longer
|
|
477
|
+
* declares. */
|
|
478
|
+
const KIT_STALE_DESCRIPTOR = "animus.kit.stale-descriptor";
|
|
424
479
|
/** The collision entry code minted by the system package's merge. */
|
|
425
480
|
const VOCABULARY_COLLISION = "animus.vocabulary.collision";
|
|
426
481
|
/** A theme `@property` registration browsers would ignore; it is not emitted. */
|
|
@@ -446,9 +501,6 @@ const PROPERTY_FALLBACK_SELF_REFERENCE = "animus.property.fallback-self-referenc
|
|
|
446
501
|
* another directly, so every property in the cycle is invalid at
|
|
447
502
|
* computed-value time. */
|
|
448
503
|
const PROPERTY_CURRENT_VAR_CYCLE = "animus.property.current-var-cycle";
|
|
449
|
-
/** A prefix renamed contextual variables without `prefixContextualVars`, so
|
|
450
|
-
* their declared names no longer resolve. */
|
|
451
|
-
const PREFIX_CONTEXTUAL_VARS_UNPREFIXED = "animus.prefix.contextual-vars-unprefixed";
|
|
452
504
|
/** Under `prefixContextualVars`, a final name that collides with a runtime
|
|
453
505
|
* transport variable or a theme variable of the same spelling. */
|
|
454
506
|
const PREFIX_NAME_CONFLICT = "animus.prefix.name-conflict";
|
|
@@ -462,7 +514,13 @@ const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
|
|
|
462
514
|
[SELECTOR_UNSUPPORTED_SUBJECT, "error"],
|
|
463
515
|
[UNREADABLE_SOURCE_FILE, "error"],
|
|
464
516
|
[NO_KIT_FILES, "warn"],
|
|
517
|
+
[KIT_WITHOUT_SOURCE_CONDITION, "warn"],
|
|
518
|
+
[INVALID_KIT_SOURCE_CONDITION, "error"],
|
|
519
|
+
[KIT_SYSTEM_NOT_INCLUDED, "error"],
|
|
520
|
+
[KIT_UNSUPPORTED_FORMAT, "error"],
|
|
521
|
+
[KIT_STALE_DESCRIPTOR, "warn"],
|
|
465
522
|
[UNPROVEN_ROOT_BINDING, "warn"],
|
|
523
|
+
[UNIMPORTED_CREATE_SYSTEM, "warn"],
|
|
466
524
|
[VOCABULARY_COLLISION, "warn"],
|
|
467
525
|
[VOCABULARY_LEGACY_VERB, "warn"],
|
|
468
526
|
[INVALID_PROPERTY_REGISTRATION, "error"],
|
|
@@ -472,7 +530,6 @@ const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
|
|
|
472
530
|
[PROPERTY_SELF_REFERENCE, "warn"],
|
|
473
531
|
[PROPERTY_FALLBACK_SELF_REFERENCE, "warn"],
|
|
474
532
|
[PROPERTY_CURRENT_VAR_CYCLE, "warn"],
|
|
475
|
-
[PREFIX_CONTEXTUAL_VARS_UNPREFIXED, "warn"],
|
|
476
533
|
[PREFIX_NAME_CONFLICT, "error"],
|
|
477
534
|
[PROPERTY_LEGACY_TOKEN_COLLISION, "warn"],
|
|
478
535
|
[PROPERTY_TOKEN_COLLISION, "error"]
|
|
@@ -527,15 +584,6 @@ function systemLoadDiagnostics(system) {
|
|
|
527
584
|
code: INVALID_PROPERTY_REGISTRATION,
|
|
528
585
|
severity: severityFor(INVALID_PROPERTY_REGISTRATION)
|
|
529
586
|
}));
|
|
530
|
-
const prefixed = system.legacyPrefixedContextualVars ?? [];
|
|
531
|
-
const unprefixed = prefixed.length === 0 ? [] : [{
|
|
532
|
-
file: "system",
|
|
533
|
-
component: "prefix",
|
|
534
|
-
kind: "warn",
|
|
535
|
-
message: `the prefix renames the contextual variables ${prefixed.join(", ")}, but their declared names are still read and written as written, so scale reads of them fail and their writes miss. Set prefixContextualVars: true to resolve them under the prefix (${PREFIX_CONTEXTUAL_VARS_UNPREFIXED})`,
|
|
536
|
-
code: PREFIX_CONTEXTUAL_VARS_UNPREFIXED,
|
|
537
|
-
severity: severityFor(PREFIX_CONTEXTUAL_VARS_UNPREFIXED)
|
|
538
|
-
}];
|
|
539
587
|
const conflicts = (system.prefixNameConflicts ?? []).map(({ name, final, reason }) => ({
|
|
540
588
|
file: "system",
|
|
541
589
|
component: `--${name}`,
|
|
@@ -547,7 +595,6 @@ function systemLoadDiagnostics(system) {
|
|
|
547
595
|
return [
|
|
548
596
|
...vocabularyWitnessDiagnostics(system.vocabularyWitnessesJson),
|
|
549
597
|
...registrations,
|
|
550
|
-
...unprefixed,
|
|
551
598
|
...conflicts,
|
|
552
599
|
...tokenCollisionDiagnostics(system)
|
|
553
600
|
];
|
|
@@ -583,13 +630,14 @@ function tokenCollisionDiagnostics(system) {
|
|
|
583
630
|
}
|
|
584
631
|
/**
|
|
585
632
|
* The single strict-escalation policy point for both extraction plugins:
|
|
586
|
-
* error-severity diagnostics throw together under `strict`, else warn.
|
|
633
|
+
* error-severity diagnostics throw together under `strict`, else warn. A
|
|
634
|
+
* development session reports them through `reportErrors` instead.
|
|
587
635
|
*/
|
|
588
636
|
function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
589
|
-
const errors =
|
|
637
|
+
const errors = /* @__PURE__ */ new Set();
|
|
590
638
|
if (policy.levels && policy.knownCodes && !checkedLevels.has(policy.levels)) {
|
|
591
639
|
checkedLevels.add(policy.levels);
|
|
592
|
-
for (const key of unknownDiagnosticKeys(policy.levels, policy.knownCodes)) warn(`⚠ diagnostics option: '${key}' matches no Animus diagnostic code — check its spelling (a code the system package mints at run time is known only once it is reported)`);
|
|
640
|
+
for (const key of unknownDiagnosticKeys(policy.levels, policy.knownCodes)) warn(key.startsWith(KIND_KEY) ? `⚠ diagnostics option: '${key}' names no diagnostic kind — use kind:bail, kind:skip, kind:warn or kind:error` : `⚠ diagnostics option: '${key}' matches no Animus diagnostic code — check its spelling (a code the system package mints at run time is known only once it is reported)`);
|
|
593
641
|
}
|
|
594
642
|
const diagnostics = policy.prepend?.length ? [...policy.prepend, ...manifest.diagnostics ?? []] : manifest.diagnostics ?? [];
|
|
595
643
|
for (const diagnostic of diagnostics) {
|
|
@@ -598,22 +646,28 @@ function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
|
598
646
|
let line = null;
|
|
599
647
|
const mark = level === "info" ? "ℹ" : "⚠";
|
|
600
648
|
const message = `${diagnostic.message}${droppedSuffix(diagnostic)}`;
|
|
601
|
-
if (diagnostic.kind === "bail") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component} not extracted: ${message}`;
|
|
602
|
-
else if (diagnostic.kind === "skip") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component}: skipped ${message}`;
|
|
603
|
-
else if (diagnostic.kind === "warn") line = `${mark} ${
|
|
649
|
+
if (diagnostic.kind === "bail") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component} not extracted: ${message}${codeSuffix(diagnostic)}`;
|
|
650
|
+
else if (diagnostic.kind === "skip") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component}: skipped ${message}${codeSuffix(diagnostic)}`;
|
|
651
|
+
else if (diagnostic.kind === "warn" || diagnostic.kind === "error") line = `${mark} ${warnLine(diagnostic)}`;
|
|
604
652
|
if (line === null) continue;
|
|
605
|
-
if (diagnostic.code && !diagnostic.message.includes(diagnostic.code)) line += ` [${diagnostic.code}]`;
|
|
606
653
|
if (level === "info") {
|
|
607
654
|
policy.info?.(line);
|
|
608
655
|
continue;
|
|
609
656
|
}
|
|
610
657
|
if (level === "error") {
|
|
611
|
-
|
|
658
|
+
const subject = diagnostic.kind === "warn" || diagnostic.kind === "error" ? `${locationOf(diagnostic)}: ` : locatedPrefix(diagnostic);
|
|
659
|
+
errors.add(`${diagnostic.code ?? "error"} — ${subject}${diagnostic.component}: ${message}`);
|
|
612
660
|
continue;
|
|
613
661
|
}
|
|
614
662
|
warn(line);
|
|
615
663
|
}
|
|
616
|
-
if (errors.
|
|
664
|
+
if (errors.size === 0) return;
|
|
665
|
+
const message = `[animus] strict: ${errors.size} error diagnostic(s):\n${[...errors].join("\n")}`;
|
|
666
|
+
if (policy.reportErrors) {
|
|
667
|
+
policy.reportErrors(message);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
throw new DiagnosticFailure(message);
|
|
617
671
|
}
|
|
618
672
|
//#endregion
|
|
619
673
|
//#region pipeline/mdx-preprocessor.ts
|
|
@@ -1580,7 +1634,8 @@ function createSourceIngestor(host) {
|
|
|
1580
1634
|
const fatal = diagnostics.filter((diagnostic) => !isAdvisorySourceDiagnostic(diagnostic));
|
|
1581
1635
|
const invalidOriginals = new Set(fatal.map((diagnostic) => diagnostic.originalPath));
|
|
1582
1636
|
if (diagnostics.length === 0) return invalidOriginals;
|
|
1583
|
-
|
|
1637
|
+
const reportError = host.strict() ? host.reportErrors?.() : void 0;
|
|
1638
|
+
if (host.strict() && fatal.length > 0 && !reportError) {
|
|
1584
1639
|
const lines = fatal.map((diagnostic) => `${diagnostic.code} ${diagnostic.originalPath}: ${diagnostic.message} (${SKIPPED_SOURCE_COST})`);
|
|
1585
1640
|
throw new Error(`${host.prefix} ${lines.join(`\n${host.prefix} `)}`);
|
|
1586
1641
|
}
|
|
@@ -1594,7 +1649,8 @@ function createSourceIngestor(host) {
|
|
|
1594
1649
|
}
|
|
1595
1650
|
if (warned.has(line)) continue;
|
|
1596
1651
|
warned.add(line);
|
|
1597
|
-
|
|
1652
|
+
if (reportError && skipped) reportError(`${host.prefix} ${line}`);
|
|
1653
|
+
else host.warn(`${host.prefix} ${line}`);
|
|
1598
1654
|
}
|
|
1599
1655
|
return invalidOriginals;
|
|
1600
1656
|
},
|
|
@@ -1621,8 +1677,9 @@ function createV2EngineApi(deps) {
|
|
|
1621
1677
|
return {
|
|
1622
1678
|
loadSystemModule: (...args) => native.loadSystemModule(...args),
|
|
1623
1679
|
extractFacts: (filesJson) => native.extractFacts(filesJson),
|
|
1680
|
+
moduleSpecifiers: (filesJson) => native.moduleSpecifiers(filesJson),
|
|
1624
1681
|
diagnosticCodes: () => native.diagnosticCodes(),
|
|
1625
|
-
analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson, transformSourcesJson, transformProvenanceJson, declarationScalesJson, analysisContextJson) => {
|
|
1682
|
+
analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson, transformSourcesJson, transformProvenanceJson, declarationScalesJson, analysisContextJson, generatedNamesJson) => {
|
|
1626
1683
|
const filesJson = deps.rehydrateFilesJson ? deps.rehydrateFilesJson(filesJsonRaw) : filesJsonRaw;
|
|
1627
1684
|
const sent = /* @__PURE__ */ new Map();
|
|
1628
1685
|
for (const entry of parseFilesJson(filesJson, label)) sent.set(entry.path, entry.source);
|
|
@@ -1650,6 +1707,7 @@ function createV2EngineApi(deps) {
|
|
|
1650
1707
|
transformProvenanceJson: transformProvenanceJson ?? void 0,
|
|
1651
1708
|
declarationScalesJson,
|
|
1652
1709
|
analysisContextJson,
|
|
1710
|
+
generatedNamesJson,
|
|
1653
1711
|
devMode
|
|
1654
1712
|
};
|
|
1655
1713
|
const engine = new native.ExtractEngine(config);
|
|
@@ -1972,7 +2030,7 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
|
|
|
1972
2030
|
const isExcluded = exclude ? (full, rel) => exclude.matches(full, rel) : () => false;
|
|
1973
2031
|
for (const entry of entries) {
|
|
1974
2032
|
const fullPath = join$1(dir, entry);
|
|
1975
|
-
if (isExcluded(fullPath, relative(rootDir, fullPath))) continue;
|
|
2033
|
+
if (isExcluded(fullPath, relative$1(rootDir, fullPath))) continue;
|
|
1976
2034
|
let stat;
|
|
1977
2035
|
try {
|
|
1978
2036
|
stat = statSync(fullPath);
|
|
@@ -1980,119 +2038,11 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
|
|
|
1980
2038
|
continue;
|
|
1981
2039
|
}
|
|
1982
2040
|
if (stat.isDirectory()) results.push(...walkFiles(fullPath, rootDir, exclude, extensionsSet));
|
|
1983
|
-
else if (extensionsSet.has(extname(entry))) results.push(fullPath);
|
|
2041
|
+
else if (extensionsSet.has(extname$1(entry))) results.push(fullPath);
|
|
1984
2042
|
}
|
|
1985
2043
|
return results;
|
|
1986
2044
|
}
|
|
1987
2045
|
//#endregion
|
|
1988
|
-
//#region pipeline/source-identity.ts
|
|
1989
|
-
/**
|
|
1990
|
-
* One derivation of source identity for discovery, watch ingestion, ownership
|
|
1991
|
-
* and deletion: event paths are lookup INPUTS only and never fork identity.
|
|
1992
|
-
*/
|
|
1993
|
-
/**
|
|
1994
|
-
* True when `target` is `root` or a descendant, decided by `relative()`
|
|
1995
|
-
* shape: string prefixing would let `/ui` claim `/ui-old`.
|
|
1996
|
-
*/
|
|
1997
|
-
function isPathWithinRoot(root, target, pathApi = path) {
|
|
1998
|
-
const rel = pathApi.relative(root, target);
|
|
1999
|
-
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
2000
|
-
}
|
|
2001
|
-
/**
|
|
2002
|
-
* True when two paths share a platform root (win32 drive letter or UNC
|
|
2003
|
-
* share; always true on posix). Drive letters compare case-insensitively.
|
|
2004
|
-
*/
|
|
2005
|
-
function sharesVolumeRoot(a, b, pathApi = path) {
|
|
2006
|
-
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
2007
|
-
return volumeOf(a) === volumeOf(b);
|
|
2008
|
-
}
|
|
2009
|
-
function canonicalize(p) {
|
|
2010
|
-
try {
|
|
2011
|
-
return realpathSync$1(p);
|
|
2012
|
-
} catch {
|
|
2013
|
-
return null;
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
function createSourceIdentity(rootDir) {
|
|
2017
|
-
const normalizedRootDir = path.normalize(rootDir);
|
|
2018
|
-
const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
|
|
2019
|
-
const roots = [];
|
|
2020
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
2021
|
-
const owningRecord = (canonicalPath) => {
|
|
2022
|
-
let owner = null;
|
|
2023
|
-
for (const record of roots) {
|
|
2024
|
-
if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
|
|
2025
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2026
|
-
}
|
|
2027
|
-
return owner;
|
|
2028
|
-
};
|
|
2029
|
-
return {
|
|
2030
|
-
rootDir: normalizedRootDir,
|
|
2031
|
-
canonicalRootDir,
|
|
2032
|
-
registerExternalRoot(root) {
|
|
2033
|
-
const asRegistered = path.normalize(root);
|
|
2034
|
-
const canonical = canonicalize(asRegistered) ?? asRegistered;
|
|
2035
|
-
const existing = roots.find((record) => record.canonical === canonical);
|
|
2036
|
-
if (existing) return existing.canonical;
|
|
2037
|
-
roots.push({
|
|
2038
|
-
asRegistered,
|
|
2039
|
-
canonical
|
|
2040
|
-
});
|
|
2041
|
-
return canonical;
|
|
2042
|
-
},
|
|
2043
|
-
externalRoots() {
|
|
2044
|
-
return roots.map((record) => record.canonical);
|
|
2045
|
-
},
|
|
2046
|
-
resolveSourceId(inputPath) {
|
|
2047
|
-
const lexical = path.normalize(inputPath);
|
|
2048
|
-
const canonical = canonicalize(lexical);
|
|
2049
|
-
if (canonical === null) return null;
|
|
2050
|
-
const owner = owningRecord(canonical);
|
|
2051
|
-
const ownedBy = (record) => {
|
|
2052
|
-
const pathInRoot = path.relative(record.canonical, canonical);
|
|
2053
|
-
return {
|
|
2054
|
-
sourceKey: path.relative(normalizedRootDir, path.join(record.asRegistered, pathInRoot)),
|
|
2055
|
-
owningRoot: record.canonical,
|
|
2056
|
-
pathInRoot
|
|
2057
|
-
};
|
|
2058
|
-
};
|
|
2059
|
-
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
2060
|
-
let resolved;
|
|
2061
|
-
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
2062
|
-
const key = path.relative(canonicalRootDir, canonical);
|
|
2063
|
-
resolved = {
|
|
2064
|
-
sourceKey: key,
|
|
2065
|
-
owningRoot: null,
|
|
2066
|
-
pathInRoot: key
|
|
2067
|
-
};
|
|
2068
|
-
} else if (owner) resolved = ownedBy(owner);
|
|
2069
|
-
else return null;
|
|
2070
|
-
aliases.set(lexical, resolved);
|
|
2071
|
-
aliases.set(canonical, resolved);
|
|
2072
|
-
return resolved;
|
|
2073
|
-
},
|
|
2074
|
-
resolveDeletedSourceId(inputPath) {
|
|
2075
|
-
return aliases.get(path.normalize(inputPath)) ?? null;
|
|
2076
|
-
},
|
|
2077
|
-
containingExternalRoot(inputPath) {
|
|
2078
|
-
const lexical = path.normalize(inputPath);
|
|
2079
|
-
let owner = null;
|
|
2080
|
-
for (const record of roots) {
|
|
2081
|
-
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
2082
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2083
|
-
}
|
|
2084
|
-
if (owner) return owner.canonical;
|
|
2085
|
-
const canonical = canonicalize(lexical);
|
|
2086
|
-
if (canonical === null) return null;
|
|
2087
|
-
for (const record of roots) {
|
|
2088
|
-
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
2089
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2090
|
-
}
|
|
2091
|
-
return owner?.canonical ?? null;
|
|
2092
|
-
}
|
|
2093
|
-
};
|
|
2094
|
-
}
|
|
2095
|
-
//#endregion
|
|
2096
2046
|
//#region pipeline/tsconfig-paths.ts
|
|
2097
2047
|
/**
|
|
2098
2048
|
* tsconfig `paths` → alias pairs, for drivers with no live bundler config.
|
|
@@ -2199,8 +2149,8 @@ function readConfig(path) {
|
|
|
2199
2149
|
};
|
|
2200
2150
|
}
|
|
2201
2151
|
function resolveExtendsTarget(specifier, fromDir) {
|
|
2202
|
-
if (specifier.startsWith(".") || isAbsolute(specifier)) {
|
|
2203
|
-
const base = resolve(fromDir, specifier);
|
|
2152
|
+
if (specifier.startsWith(".") || isAbsolute$1(specifier)) {
|
|
2153
|
+
const base = resolve$1(fromDir, specifier);
|
|
2204
2154
|
for (const candidate of [
|
|
2205
2155
|
base,
|
|
2206
2156
|
`${base}.json`,
|
|
@@ -2225,7 +2175,7 @@ function loadChain(entryPath) {
|
|
|
2225
2175
|
const queue = [entryPath];
|
|
2226
2176
|
while (queue.length > 0) {
|
|
2227
2177
|
const path = queue.shift();
|
|
2228
|
-
const key = resolve(path);
|
|
2178
|
+
const key = resolve$1(path);
|
|
2229
2179
|
if (visited.has(key)) continue;
|
|
2230
2180
|
visited.add(key);
|
|
2231
2181
|
const node = readConfig(key);
|
|
@@ -2250,7 +2200,7 @@ function readTsconfigAliasPairs(rootDir) {
|
|
|
2250
2200
|
if (pathsOwner === void 0 || paths === null) return [];
|
|
2251
2201
|
const baseOwner = chain.find((node) => node.baseUrl !== null);
|
|
2252
2202
|
const baseUrl = baseOwner?.baseUrl ?? null;
|
|
2253
|
-
const base = baseOwner !== void 0 && baseUrl !== null ? resolve(baseOwner.dir, baseUrl) : pathsOwner.dir;
|
|
2203
|
+
const base = baseOwner !== void 0 && baseUrl !== null ? resolve$1(baseOwner.dir, baseUrl) : pathsOwner.dir;
|
|
2254
2204
|
const pairs = [];
|
|
2255
2205
|
for (const [pattern, target] of paths) {
|
|
2256
2206
|
const patternStars = pattern.split("*").length - 1;
|
|
@@ -2260,7 +2210,7 @@ function readTsconfigAliasPairs(rootDir) {
|
|
|
2260
2210
|
if (!target.endsWith("/*")) continue;
|
|
2261
2211
|
pairs.push({
|
|
2262
2212
|
pattern: pattern.slice(0, -2),
|
|
2263
|
-
target: resolve(base, target.slice(0, -2)),
|
|
2213
|
+
target: resolve$1(base, target.slice(0, -2)),
|
|
2264
2214
|
kind: "prefix"
|
|
2265
2215
|
});
|
|
2266
2216
|
continue;
|
|
@@ -2268,13 +2218,223 @@ function readTsconfigAliasPairs(rootDir) {
|
|
|
2268
2218
|
if (patternStars > 0 || targetStars > 0) continue;
|
|
2269
2219
|
pairs.push({
|
|
2270
2220
|
pattern,
|
|
2271
|
-
target: resolve(base, target),
|
|
2221
|
+
target: resolve$1(base, target),
|
|
2272
2222
|
kind: "exact"
|
|
2273
2223
|
});
|
|
2274
2224
|
}
|
|
2275
2225
|
return pairs;
|
|
2276
2226
|
}
|
|
2277
2227
|
//#endregion
|
|
2228
|
+
//#region pipeline/kit-descriptor.ts
|
|
2229
|
+
/** A kit's description, which `animus build --kit` writes at its package
|
|
2230
|
+
* root and the kit exports as `./animus.json`. */
|
|
2231
|
+
const KIT_DESCRIPTOR_FILE = "animus.json";
|
|
2232
|
+
/** A path with `/` separators, as descriptors key their components. */
|
|
2233
|
+
function posixPath$1(path) {
|
|
2234
|
+
return path.split(sep).join("/");
|
|
2235
|
+
}
|
|
2236
|
+
/** The descriptor of the kit a build analysed. */
|
|
2237
|
+
function buildKitDescriptor(manifest) {
|
|
2238
|
+
const components = {};
|
|
2239
|
+
for (const id of Object.keys(manifest.components).sort()) {
|
|
2240
|
+
const component = manifest.components[id];
|
|
2241
|
+
components[posixPath$1(id)] = {
|
|
2242
|
+
definition: component.definition_fingerprint,
|
|
2243
|
+
runtimeProps: [...new Set(component.system_prop_names)].sort()
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
2246
|
+
return {
|
|
2247
|
+
format: 1,
|
|
2248
|
+
system: manifest.system_fingerprint,
|
|
2249
|
+
components
|
|
2250
|
+
};
|
|
2251
|
+
}
|
|
2252
|
+
/** Reads the descriptor at a kit's package root; `null` when it has none. */
|
|
2253
|
+
function readKitDescriptor(pkgRoot, rootDir) {
|
|
2254
|
+
const path = join(pkgRoot, KIT_DESCRIPTOR_FILE);
|
|
2255
|
+
if (!existsSync$1(path)) return null;
|
|
2256
|
+
const packageRoot = posixPath$1(relative(rootDir, pkgRoot));
|
|
2257
|
+
let wire;
|
|
2258
|
+
try {
|
|
2259
|
+
wire = JSON.parse(readFileSync$1(path, "utf-8"));
|
|
2260
|
+
} catch {
|
|
2261
|
+
return {
|
|
2262
|
+
packageRoot,
|
|
2263
|
+
unreadable: "is not valid JSON: rebuild it with animus build --kit"
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2266
|
+
const block = isJsonBlock(wire) ? wire : {};
|
|
2267
|
+
if (block.format !== 1) return {
|
|
2268
|
+
packageRoot,
|
|
2269
|
+
unreadable: `declares descriptor format ${JSON.stringify(block.format ?? null)}, which this Animus does not read (it reads format 1): upgrade Animus, or install a kit built for this version`
|
|
2270
|
+
};
|
|
2271
|
+
const definitions = {};
|
|
2272
|
+
const components = isJsonBlock(block.components) ? block.components : {};
|
|
2273
|
+
for (const [id, component] of Object.entries(components)) {
|
|
2274
|
+
const definition = isJsonBlock(component) ? component.definition : null;
|
|
2275
|
+
if (isJsonString(definition)) definitions[posixPath$1(id)] = definition;
|
|
2276
|
+
}
|
|
2277
|
+
return {
|
|
2278
|
+
packageRoot,
|
|
2279
|
+
definitions
|
|
2280
|
+
};
|
|
2281
|
+
}
|
|
2282
|
+
/**
|
|
2283
|
+
* A descriptor in a format this Animus cannot read fails the build; one
|
|
2284
|
+
* whose component definitions differ from the kit's shipped source, as the
|
|
2285
|
+
* analysis read it, or that describes a component its analysed file no
|
|
2286
|
+
* longer declares, was built from other source and is stale.
|
|
2287
|
+
*/
|
|
2288
|
+
function kitDescriptorDiagnostics(records, manifest) {
|
|
2289
|
+
if (records.length === 0) return [];
|
|
2290
|
+
const diagnostics = [];
|
|
2291
|
+
const analysedById = new Map(Object.entries(manifest.components).map(([id, component]) => [posixPath$1(id), component]));
|
|
2292
|
+
const analysedFiles = new Set(Object.keys(manifest.fileFacts).map(posixPath$1));
|
|
2293
|
+
const declared = new Set(Object.entries(manifest.fileFacts).flatMap(([file, facts]) => facts.chains.map((chain) => `${posixPath$1(file)}::${chain.descriptor.binding}`)));
|
|
2294
|
+
for (const record of records) {
|
|
2295
|
+
const file = `${record.packageRoot}/${KIT_DESCRIPTOR_FILE}`;
|
|
2296
|
+
if ("unreadable" in record) {
|
|
2297
|
+
diagnostics.push({
|
|
2298
|
+
file,
|
|
2299
|
+
component: "kit",
|
|
2300
|
+
kind: "error",
|
|
2301
|
+
message: record.unreadable,
|
|
2302
|
+
code: KIT_UNSUPPORTED_FORMAT,
|
|
2303
|
+
severity: severityFor(KIT_UNSUPPORTED_FORMAT)
|
|
2304
|
+
});
|
|
2305
|
+
continue;
|
|
2306
|
+
}
|
|
2307
|
+
for (const [id, definition] of Object.entries(record.definitions)) {
|
|
2308
|
+
const key = `${record.packageRoot}/${id}`;
|
|
2309
|
+
const analysed = analysedById.get(key);
|
|
2310
|
+
const fileAnalysed = analysedFiles.has(key.slice(0, key.lastIndexOf("::")));
|
|
2311
|
+
let stale;
|
|
2312
|
+
if (analysed) {
|
|
2313
|
+
if (analysed.definition_fingerprint === definition) continue;
|
|
2314
|
+
stale = `describes ${id} with a definition other than the one its shipped source declares`;
|
|
2315
|
+
} else if (fileAnalysed && !declared.has(key)) stale = `describes ${id}, which its shipped source no longer declares`;
|
|
2316
|
+
else continue;
|
|
2317
|
+
diagnostics.push({
|
|
2318
|
+
file,
|
|
2319
|
+
component: analysed?.binding ?? id.slice(id.lastIndexOf("::") + 2),
|
|
2320
|
+
kind: "warn",
|
|
2321
|
+
message: `${stale}, so the descriptor is stale: rebuild it with animus build --kit`,
|
|
2322
|
+
code: KIT_STALE_DESCRIPTOR,
|
|
2323
|
+
severity: severityFor(KIT_STALE_DESCRIPTOR)
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
return diagnostics;
|
|
2328
|
+
}
|
|
2329
|
+
//#endregion
|
|
2330
|
+
//#region pipeline/source-identity.ts
|
|
2331
|
+
/**
|
|
2332
|
+
* One derivation of source identity for discovery, watch ingestion, ownership
|
|
2333
|
+
* and deletion: event paths are lookup INPUTS only and never fork identity.
|
|
2334
|
+
*/
|
|
2335
|
+
/**
|
|
2336
|
+
* True when `target` is `root` or a descendant, decided by `relative()`
|
|
2337
|
+
* shape: string prefixing would let `/ui` claim `/ui-old`.
|
|
2338
|
+
*/
|
|
2339
|
+
function isPathWithinRoot(root, target, pathApi = path) {
|
|
2340
|
+
const rel = pathApi.relative(root, target);
|
|
2341
|
+
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
2342
|
+
}
|
|
2343
|
+
/**
|
|
2344
|
+
* True when two paths share a platform root (win32 drive letter or UNC
|
|
2345
|
+
* share; always true on posix). Drive letters compare case-insensitively.
|
|
2346
|
+
*/
|
|
2347
|
+
function sharesVolumeRoot(a, b, pathApi = path) {
|
|
2348
|
+
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
2349
|
+
return volumeOf(a) === volumeOf(b);
|
|
2350
|
+
}
|
|
2351
|
+
function canonicalize(p) {
|
|
2352
|
+
try {
|
|
2353
|
+
return realpathSync$1(p);
|
|
2354
|
+
} catch {
|
|
2355
|
+
return null;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
function createSourceIdentity(rootDir) {
|
|
2359
|
+
const normalizedRootDir = path.normalize(rootDir);
|
|
2360
|
+
const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
|
|
2361
|
+
const roots = [];
|
|
2362
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
2363
|
+
const owningRecord = (canonicalPath) => {
|
|
2364
|
+
let owner = null;
|
|
2365
|
+
for (const record of roots) {
|
|
2366
|
+
if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
|
|
2367
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2368
|
+
}
|
|
2369
|
+
return owner;
|
|
2370
|
+
};
|
|
2371
|
+
return {
|
|
2372
|
+
rootDir: normalizedRootDir,
|
|
2373
|
+
canonicalRootDir,
|
|
2374
|
+
registerExternalRoot(root) {
|
|
2375
|
+
const asRegistered = path.normalize(root);
|
|
2376
|
+
const canonical = canonicalize(asRegistered) ?? asRegistered;
|
|
2377
|
+
const existing = roots.find((record) => record.canonical === canonical);
|
|
2378
|
+
if (existing) return existing.canonical;
|
|
2379
|
+
roots.push({
|
|
2380
|
+
asRegistered,
|
|
2381
|
+
canonical
|
|
2382
|
+
});
|
|
2383
|
+
return canonical;
|
|
2384
|
+
},
|
|
2385
|
+
externalRoots() {
|
|
2386
|
+
return roots.map((record) => record.canonical);
|
|
2387
|
+
},
|
|
2388
|
+
resolveSourceId(inputPath) {
|
|
2389
|
+
const lexical = path.normalize(inputPath);
|
|
2390
|
+
const canonical = canonicalize(lexical);
|
|
2391
|
+
if (canonical === null) return null;
|
|
2392
|
+
const owner = owningRecord(canonical);
|
|
2393
|
+
const ownedBy = (record) => {
|
|
2394
|
+
const pathInRoot = path.relative(record.canonical, canonical);
|
|
2395
|
+
return {
|
|
2396
|
+
sourceKey: path.relative(normalizedRootDir, path.join(record.asRegistered, pathInRoot)),
|
|
2397
|
+
owningRoot: record.canonical,
|
|
2398
|
+
pathInRoot
|
|
2399
|
+
};
|
|
2400
|
+
};
|
|
2401
|
+
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
2402
|
+
let resolved;
|
|
2403
|
+
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
2404
|
+
const key = path.relative(canonicalRootDir, canonical);
|
|
2405
|
+
resolved = {
|
|
2406
|
+
sourceKey: key,
|
|
2407
|
+
owningRoot: null,
|
|
2408
|
+
pathInRoot: key
|
|
2409
|
+
};
|
|
2410
|
+
} else if (owner) resolved = ownedBy(owner);
|
|
2411
|
+
else return null;
|
|
2412
|
+
aliases.set(lexical, resolved);
|
|
2413
|
+
aliases.set(canonical, resolved);
|
|
2414
|
+
return resolved;
|
|
2415
|
+
},
|
|
2416
|
+
resolveDeletedSourceId(inputPath) {
|
|
2417
|
+
return aliases.get(path.normalize(inputPath)) ?? null;
|
|
2418
|
+
},
|
|
2419
|
+
containingExternalRoot(inputPath) {
|
|
2420
|
+
const lexical = path.normalize(inputPath);
|
|
2421
|
+
let owner = null;
|
|
2422
|
+
for (const record of roots) {
|
|
2423
|
+
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
2424
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2425
|
+
}
|
|
2426
|
+
if (owner) return owner.canonical;
|
|
2427
|
+
const canonical = canonicalize(lexical);
|
|
2428
|
+
if (canonical === null) return null;
|
|
2429
|
+
for (const record of roots) {
|
|
2430
|
+
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
2431
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2432
|
+
}
|
|
2433
|
+
return owner?.canonical ?? null;
|
|
2434
|
+
}
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
//#endregion
|
|
2278
2438
|
//#region pipeline/discover-packages.ts
|
|
2279
2439
|
function findPackageRoot(absEntryPath) {
|
|
2280
2440
|
let pkgRoot = dirname$1(absEntryPath);
|
|
@@ -2291,7 +2451,7 @@ function isExcludedPackageRelativePath(rel) {
|
|
|
2291
2451
|
return PACKAGE_SRC_EXCLUDES.some((pattern) => rel.includes(pattern));
|
|
2292
2452
|
}
|
|
2293
2453
|
function walkPackageSources(packageDir, extensionsSet) {
|
|
2294
|
-
return discoverFiles(packageDir, packageDir, void 0, extensionsSet).filter((absPath) => !isExcludedPackageRelativePath(relative(packageDir, absPath)));
|
|
2454
|
+
return discoverFiles(packageDir, packageDir, void 0, extensionsSet).filter((absPath) => !isExcludedPackageRelativePath(relative$1(packageDir, absPath)));
|
|
2295
2455
|
}
|
|
2296
2456
|
const PACKAGE_OUTPUT_EXCLUDES = [
|
|
2297
2457
|
"node_modules",
|
|
@@ -2300,7 +2460,7 @@ const PACKAGE_OUTPUT_EXCLUDES = [
|
|
|
2300
2460
|
".d.ts",
|
|
2301
2461
|
".map"
|
|
2302
2462
|
];
|
|
2303
|
-
const isFile = (path) => {
|
|
2463
|
+
const isFile$1 = (path) => {
|
|
2304
2464
|
try {
|
|
2305
2465
|
return statSync(path).isFile();
|
|
2306
2466
|
} catch {
|
|
@@ -2312,14 +2472,15 @@ function resolveAbsolutePathSpecifier(absSpecifier, extensionsSet) {
|
|
|
2312
2472
|
absSpecifier,
|
|
2313
2473
|
...Array.from(extensionsSet, (ext) => absSpecifier + ext),
|
|
2314
2474
|
...Array.from(extensionsSet, (ext) => join$1(absSpecifier, `index${ext}`))
|
|
2315
|
-
].find(isFile) ?? null;
|
|
2475
|
+
].find(isFile$1) ?? null;
|
|
2316
2476
|
}
|
|
2477
|
+
/** The package a bare specifier names: `@scope/name` or `name`. */
|
|
2317
2478
|
function bareSpecifierPackageName(specifier) {
|
|
2318
2479
|
const segments = specifier.split("/");
|
|
2319
2480
|
return specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0];
|
|
2320
2481
|
}
|
|
2321
2482
|
function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
2322
|
-
if (isAbsolute(specifier)) {
|
|
2483
|
+
if (isAbsolute$1(specifier)) {
|
|
2323
2484
|
const resolved = resolveAbsolutePathSpecifier(specifier, extensionsSet);
|
|
2324
2485
|
if (!resolved) return null;
|
|
2325
2486
|
return isPathWithinRoot(srcDir, resolved) ? resolved : null;
|
|
@@ -2328,6 +2489,76 @@ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
|
2328
2489
|
const subpath = specifier.slice(packageName.length + 1);
|
|
2329
2490
|
return resolveAbsolutePathSpecifier(join$1(srcDir, subpath || "index"), extensionsSet);
|
|
2330
2491
|
}
|
|
2492
|
+
/** The package's parsed `package.json`, or null when it cannot be read. */
|
|
2493
|
+
function readPackageManifest(pkgRoot) {
|
|
2494
|
+
try {
|
|
2495
|
+
return JSON.parse(readFileSync(join$1(pkgRoot, "package.json"), "utf-8"));
|
|
2496
|
+
} catch {
|
|
2497
|
+
return null;
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
/** Each `exports` subpath and its value; a bare target or condition object
|
|
2501
|
+
* is the `.` entry. */
|
|
2502
|
+
function exportsSubpaths(manifest) {
|
|
2503
|
+
const exports = isJsonBlock(manifest) ? manifest.exports : void 0;
|
|
2504
|
+
if (exports === void 0 || exports === null) return [];
|
|
2505
|
+
const subpaths = isJsonBlock(exports) && Object.keys(exports).some((k) => k.startsWith(".")) ? exports : { ".": exports };
|
|
2506
|
+
return Object.entries(subpaths).filter(([subpath]) => subpath.startsWith("."));
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* The export condition a kit gives each public entry's original source:
|
|
2510
|
+
* `{ "types": …, "animus": "./src/system.ts", "import": …, "default": … }`.
|
|
2511
|
+
* Hosts never resolve through it; discovery reads it, redirects the entry to
|
|
2512
|
+
* its source in every host, and the system loader prefers it.
|
|
2513
|
+
*/
|
|
2514
|
+
const KIT_SOURCE_CONDITION = "animus";
|
|
2515
|
+
/** The package's kit source condition, or null when no exact `exports`
|
|
2516
|
+
* entry declares it: the package is no source kit. */
|
|
2517
|
+
function readKitSourceCondition(pkgRoot) {
|
|
2518
|
+
const condition = {
|
|
2519
|
+
entries: [],
|
|
2520
|
+
invalid: [],
|
|
2521
|
+
root: null
|
|
2522
|
+
};
|
|
2523
|
+
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2524
|
+
if (subpath.includes("*") || !isJsonBlock(value)) continue;
|
|
2525
|
+
const target = value[KIT_SOURCE_CONDITION];
|
|
2526
|
+
if (!isJsonString(target)) continue;
|
|
2527
|
+
const file = resolve$1(pkgRoot, target);
|
|
2528
|
+
if (isPathWithinRoot(pkgRoot, file) && isFile$1(file)) condition.entries.push([subpath, file]);
|
|
2529
|
+
else condition.invalid.push([subpath, target]);
|
|
2530
|
+
}
|
|
2531
|
+
if (condition.entries.length === 0 && condition.invalid.length === 0) return null;
|
|
2532
|
+
condition.root = condition.entries.reduce((root, [, file]) => root === null ? dirname$1(file) : commonDirectory(root, dirname$1(file)), null);
|
|
2533
|
+
return condition;
|
|
2534
|
+
}
|
|
2535
|
+
function commonDirectory(a, b) {
|
|
2536
|
+
let dir = a;
|
|
2537
|
+
while (!isPathWithinRoot(dir, b)) dir = dirname$1(dir);
|
|
2538
|
+
return dir;
|
|
2539
|
+
}
|
|
2540
|
+
/** Whether the manifest at `dir` names the package `name`. */
|
|
2541
|
+
function isPackageNamed(dir, name) {
|
|
2542
|
+
const manifest = readPackageManifest(dir);
|
|
2543
|
+
return isJsonBlock(manifest) && manifest.name === name;
|
|
2544
|
+
}
|
|
2545
|
+
function realPath(path) {
|
|
2546
|
+
try {
|
|
2547
|
+
return realpathSync(path);
|
|
2548
|
+
} catch {
|
|
2549
|
+
return path;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
/** The root of the installed package `name` as Node finds it from `fromDir`,
|
|
2553
|
+
* the first `node_modules/<name>` up the directory tree, at its real path,
|
|
2554
|
+
* as host resolvers report a linked package. */
|
|
2555
|
+
function locatePackageRoot(name, fromDir) {
|
|
2556
|
+
for (let dir = fromDir;; dir = dirname$1(dir)) {
|
|
2557
|
+
const candidate = join$1(dir, "node_modules", name);
|
|
2558
|
+
if (existsSync(join$1(candidate, "package.json"))) return realPath(candidate);
|
|
2559
|
+
if (dir === dirname$1(dir)) return null;
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2331
2562
|
/**
|
|
2332
2563
|
* A package's `sideEffects` field, decoded the way Vite reads it: a boolean
|
|
2333
2564
|
* as written, or the list's globs, one with no `/` matching the basename
|
|
@@ -2336,12 +2567,7 @@ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
|
2336
2567
|
* extglobs), which leaves the bundler's side-effectful default.
|
|
2337
2568
|
*/
|
|
2338
2569
|
function readPackageSideEffects(pkgRoot) {
|
|
2339
|
-
|
|
2340
|
-
try {
|
|
2341
|
-
manifest = JSON.parse(readFileSync(join$1(pkgRoot, "package.json"), "utf-8"));
|
|
2342
|
-
} catch {
|
|
2343
|
-
return;
|
|
2344
|
-
}
|
|
2570
|
+
const manifest = readPackageManifest(pkgRoot);
|
|
2345
2571
|
const field = isJsonBlock(manifest) ? manifest.sideEffects : void 0;
|
|
2346
2572
|
if (field === true || field === false) return field;
|
|
2347
2573
|
if (!Array.isArray(field)) return void 0;
|
|
@@ -2349,9 +2575,80 @@ function readPackageSideEffects(pkgRoot) {
|
|
|
2349
2575
|
if (globs.some((glob) => /[{}[\]()!+@]/.test(glob))) return void 0;
|
|
2350
2576
|
return globs.map((glob) => globToRegExp(glob.includes("/") ? glob.replace(/^\.?\//, "") : `**/${glob}`));
|
|
2351
2577
|
}
|
|
2578
|
+
/** Whether a bundler that reads the nearest `package.json`'s `sideEffects`
|
|
2579
|
+
* against the file's own path keeps `absFile`; undefined without a field
|
|
2580
|
+
* it reads, which keeps the bundler's side-effectful default. */
|
|
2581
|
+
function fileSideEffects(absFile) {
|
|
2582
|
+
const pkgRoot = findPackageRoot(absFile);
|
|
2583
|
+
const field = readPackageSideEffects(pkgRoot);
|
|
2584
|
+
if (field === void 0 || field === true || field === false) return field;
|
|
2585
|
+
return matchesSideEffects(field, pkgRoot, [absFile]);
|
|
2586
|
+
}
|
|
2587
|
+
/** Whether a `sideEffects` glob can name a code file: a last segment with
|
|
2588
|
+
* no extension can name any file, and an extension with glob syntax or of
|
|
2589
|
+
* a script can name code; `*.css` cannot. Brace alternatives are each read,
|
|
2590
|
+
* and braces this reading cannot expand count as naming code. */
|
|
2591
|
+
function globNamesCode(glob) {
|
|
2592
|
+
const alternatives = expandBraces(glob);
|
|
2593
|
+
if (alternatives === null) return true;
|
|
2594
|
+
return alternatives.some((alternative) => {
|
|
2595
|
+
const last = alternative.split("/").at(-1) ?? "";
|
|
2596
|
+
const dot = last.lastIndexOf(".");
|
|
2597
|
+
if (dot === -1) return true;
|
|
2598
|
+
const extension = last.slice(dot + 1);
|
|
2599
|
+
return /[*?[]/.test(extension) || /^[cm]?[jt]sx?$/.test(extension);
|
|
2600
|
+
});
|
|
2601
|
+
}
|
|
2602
|
+
/** Every alternative a glob's `{a,b}` groups spell, nested groups included;
|
|
2603
|
+
* null when its braces do not balance. */
|
|
2604
|
+
function expandBraces(glob) {
|
|
2605
|
+
const open = glob.indexOf("{");
|
|
2606
|
+
if (open === -1) return glob.includes("}") ? null : [glob];
|
|
2607
|
+
let depth = 0;
|
|
2608
|
+
const commas = [];
|
|
2609
|
+
for (let at = open; at < glob.length; at++) if (glob[at] === "{") depth++;
|
|
2610
|
+
else if (glob[at] === "," && depth === 1) commas.push(at);
|
|
2611
|
+
else if (glob[at] === "}" && --depth === 0) {
|
|
2612
|
+
const bounds = [
|
|
2613
|
+
open,
|
|
2614
|
+
...commas,
|
|
2615
|
+
at
|
|
2616
|
+
];
|
|
2617
|
+
const rest = expandBraces(glob.slice(at + 1));
|
|
2618
|
+
if (rest === null) return null;
|
|
2619
|
+
const expanded = [];
|
|
2620
|
+
for (let i = 0; i < bounds.length - 1; i++) {
|
|
2621
|
+
const inner = expandBraces(glob.slice(bounds[i] + 1, bounds[i + 1]));
|
|
2622
|
+
if (inner === null) return null;
|
|
2623
|
+
for (const middle of inner) for (const tail of rest) expanded.push(glob.slice(0, open) + middle + tail);
|
|
2624
|
+
}
|
|
2625
|
+
return expanded;
|
|
2626
|
+
}
|
|
2627
|
+
return null;
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* True when a source module of the package that owns `absFile` must stay
|
|
2631
|
+
* side-effectful: its `sideEffects` list names shipped code, and no proven
|
|
2632
|
+
* map takes a shipped file to its source module, so a bundler that reads
|
|
2633
|
+
* the list against the source path can drop a listed effect. Undefined
|
|
2634
|
+
* leaves the bundler's own reading, which no list naming code can mislead.
|
|
2635
|
+
*/
|
|
2636
|
+
function kitSourceModuleSideEffects(absFile) {
|
|
2637
|
+
const manifest = readPackageManifest(findPackageRoot(absFile));
|
|
2638
|
+
const field = isJsonBlock(manifest) ? manifest.sideEffects : void 0;
|
|
2639
|
+
if (!Array.isArray(field)) return void 0;
|
|
2640
|
+
return field.some((glob) => isJsonString(glob) && globNamesCode(glob)) ? true : void 0;
|
|
2641
|
+
}
|
|
2642
|
+
/** Whether a host keeps the module at `file` side-effectful: it lies under
|
|
2643
|
+
* one of the discovered kit source directories, and its package's list
|
|
2644
|
+
* could misread it (see `kitSourceModuleSideEffects`). A host asks this of
|
|
2645
|
+
* the resolved module, never of its importer alone. */
|
|
2646
|
+
function keepsKitSourceEffects(file, kitDirs) {
|
|
2647
|
+
return kitDirs.some((dir) => isPathWithinRoot(dir, file)) && kitSourceModuleSideEffects(file) === true;
|
|
2648
|
+
}
|
|
2352
2649
|
function matchesSideEffects(globs, pkgRoot, absFiles) {
|
|
2353
2650
|
return absFiles.some((file) => {
|
|
2354
|
-
const relPath = relative(pkgRoot, file).split(sep).join("/");
|
|
2651
|
+
const relPath = relative$1(pkgRoot, file).split(sep$1).join("/");
|
|
2355
2652
|
return globs.some((glob) => glob.test(relPath));
|
|
2356
2653
|
});
|
|
2357
2654
|
}
|
|
@@ -2372,20 +2669,11 @@ function exportTarget(value) {
|
|
|
2372
2669
|
/** Each exact `exports` entry of the package at `pkgRoot`, as its subpath
|
|
2373
2670
|
* and absolute target; `*` patterns name no single file and are skipped. */
|
|
2374
2671
|
function packageExportEntries(pkgRoot) {
|
|
2375
|
-
let manifest;
|
|
2376
|
-
try {
|
|
2377
|
-
manifest = JSON.parse(readFileSync(join$1(pkgRoot, "package.json"), "utf-8"));
|
|
2378
|
-
} catch {
|
|
2379
|
-
return [];
|
|
2380
|
-
}
|
|
2381
|
-
const exports = isJsonBlock(manifest) ? manifest.exports : void 0;
|
|
2382
|
-
if (exports === void 0 || exports === null) return [];
|
|
2383
|
-
const subpaths = isJsonBlock(exports) && Object.keys(exports).some((k) => k.startsWith(".")) ? exports : { ".": exports };
|
|
2384
2672
|
const entries = [];
|
|
2385
|
-
for (const [subpath, value] of
|
|
2386
|
-
if (
|
|
2673
|
+
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2674
|
+
if (subpath.includes("*")) continue;
|
|
2387
2675
|
const target = exportTarget(value);
|
|
2388
|
-
if (target !== null) entries.push([subpath, resolve(pkgRoot, target)]);
|
|
2676
|
+
if (target !== null) entries.push([subpath, resolve$1(pkgRoot, target)]);
|
|
2389
2677
|
}
|
|
2390
2678
|
return entries;
|
|
2391
2679
|
}
|
|
@@ -2422,6 +2710,16 @@ async function collectExternalPackageSources(opts) {
|
|
|
2422
2710
|
const sourceEntrySideEffects = /* @__PURE__ */ new Map();
|
|
2423
2711
|
/** `replaced` names the entry the redirect stands in for; it is only
|
|
2424
2712
|
* needed, and so only resolved, for a glob list. */
|
|
2713
|
+
/** The entry `subpath` of the package resolves to without the redirect.
|
|
2714
|
+
* A resolver with no `import` condition, as Node's `require` has none,
|
|
2715
|
+
* finds no ESM-only entry, so the manifest's own target answers then. */
|
|
2716
|
+
const shippedEntry = async (specifier, pkgRoot, subpath) => {
|
|
2717
|
+
try {
|
|
2718
|
+
const resolved = await resolveSpecifier(specifier);
|
|
2719
|
+
if (resolved) return resolved;
|
|
2720
|
+
} catch {}
|
|
2721
|
+
return packageExportEntries(pkgRoot).find(([entry]) => entry === subpath)?.[1] ?? null;
|
|
2722
|
+
};
|
|
2425
2723
|
const redirect = async (specifier, srcEntry, pkgRoot, replaced) => {
|
|
2426
2724
|
sourceEntries.set(specifier, srcEntry);
|
|
2427
2725
|
const field = readPackageSideEffects(pkgRoot);
|
|
@@ -2434,6 +2732,8 @@ async function collectExternalPackageSources(opts) {
|
|
|
2434
2732
|
sourceEntrySideEffects.set(specifier, replacedEntry === null || matchesSideEffects(field, pkgRoot, [srcEntry, replacedEntry]));
|
|
2435
2733
|
};
|
|
2436
2734
|
const packageDirs = [];
|
|
2735
|
+
const linkedDirs = [];
|
|
2736
|
+
const outputDirs = [];
|
|
2437
2737
|
const dirOwnerSets = {};
|
|
2438
2738
|
const dirExtensions = {};
|
|
2439
2739
|
const fileOwners = {};
|
|
@@ -2442,6 +2742,31 @@ async function collectExternalPackageSources(opts) {
|
|
|
2442
2742
|
(dirOwnerSets[dir] ??= []).push(specifier);
|
|
2443
2743
|
};
|
|
2444
2744
|
const alreadyIngested = (relPath) => hasEntry(relPath) || pushed.has(relPath);
|
|
2745
|
+
/** Adds `file` to the analysis set unless it is there; false when it
|
|
2746
|
+
* cannot be read. */
|
|
2747
|
+
const ingest = (file, specifier) => {
|
|
2748
|
+
const relPath = relative$1(rootDir, file);
|
|
2749
|
+
if (alreadyIngested(relPath)) return true;
|
|
2750
|
+
let source;
|
|
2751
|
+
try {
|
|
2752
|
+
source = readFileSync(file, "utf-8");
|
|
2753
|
+
} catch (err) {
|
|
2754
|
+
onUnreadable(relPath, err);
|
|
2755
|
+
return false;
|
|
2756
|
+
}
|
|
2757
|
+
onSourceRead?.(source, relPath, file);
|
|
2758
|
+
entries.push({
|
|
2759
|
+
path: relPath,
|
|
2760
|
+
source
|
|
2761
|
+
});
|
|
2762
|
+
pushed.add(relPath);
|
|
2763
|
+
fileOwners[relPath] ??= specifier;
|
|
2764
|
+
return true;
|
|
2765
|
+
};
|
|
2766
|
+
const diagnostics = [];
|
|
2767
|
+
const reportedPackages = /* @__PURE__ */ new Set();
|
|
2768
|
+
const kitDescriptors = [];
|
|
2769
|
+
const describedRoots = /* @__PURE__ */ new Set();
|
|
2445
2770
|
for (const specifier of specifiers) {
|
|
2446
2771
|
let absEntry;
|
|
2447
2772
|
try {
|
|
@@ -2449,8 +2774,15 @@ async function collectExternalPackageSources(opts) {
|
|
|
2449
2774
|
} catch {
|
|
2450
2775
|
absEntry = null;
|
|
2451
2776
|
}
|
|
2452
|
-
if (!absEntry && isAbsolute(specifier)) absEntry = resolveAbsolutePathSpecifier(specifier, extensionsSet);
|
|
2453
|
-
|
|
2777
|
+
if (!absEntry && isAbsolute$1(specifier)) absEntry = resolveAbsolutePathSpecifier(specifier, extensionsSet);
|
|
2778
|
+
const packageName = isAbsolute$1(specifier) ? null : bareSpecifierPackageName(specifier);
|
|
2779
|
+
const resolvedRoot = absEntry ? findPackageRoot(absEntry) : null;
|
|
2780
|
+
const locatedRoot = packageName && locatePackageRoot(packageName, rootDir);
|
|
2781
|
+
const pkgRoot = resolvedRoot && (!locatedRoot || isPackageNamed(resolvedRoot, packageName) || realPath(resolvedRoot) === locatedRoot) ? resolvedRoot : locatedRoot || resolvedRoot;
|
|
2782
|
+
const condition = packageName && pkgRoot ? readKitSourceCondition(pkgRoot) : null;
|
|
2783
|
+
const entryKey = packageName && `.${specifier.slice(packageName.length)}`;
|
|
2784
|
+
absEntry ??= condition?.entries.find(([entry]) => entry === entryKey)?.[1] ?? null;
|
|
2785
|
+
if (!absEntry || !pkgRoot) {
|
|
2454
2786
|
outcomes.push({
|
|
2455
2787
|
specifier,
|
|
2456
2788
|
outcome: "unresolvable",
|
|
@@ -2458,106 +2790,82 @@ async function collectExternalPackageSources(opts) {
|
|
|
2458
2790
|
});
|
|
2459
2791
|
continue;
|
|
2460
2792
|
}
|
|
2461
|
-
const
|
|
2793
|
+
const realRoot = realPath(pkgRoot);
|
|
2794
|
+
if (!describedRoots.has(realRoot)) {
|
|
2795
|
+
describedRoots.add(realRoot);
|
|
2796
|
+
const described = readKitDescriptor(pkgRoot, rootDir);
|
|
2797
|
+
if (described) kitDescriptors.push(described);
|
|
2798
|
+
}
|
|
2799
|
+
const linked = !isInstalledPackage(pkgRoot);
|
|
2462
2800
|
const srcDir = join$1(pkgRoot, "src");
|
|
2463
2801
|
let fileCount = 0;
|
|
2464
2802
|
let staleDist = false;
|
|
2465
|
-
if (
|
|
2803
|
+
if (packageName && !reportedPackages.has(packageName)) {
|
|
2804
|
+
reportedPackages.add(packageName);
|
|
2805
|
+
diagnostics.push(...sourceConditionDiagnostics(packageName, condition));
|
|
2806
|
+
}
|
|
2807
|
+
if (condition && packageName) {
|
|
2808
|
+
for (const [entry, target] of condition.entries) {
|
|
2809
|
+
const entrySpecifier = packageName + entry.slice(1);
|
|
2810
|
+
packageMap[entrySpecifier] = relative$1(rootDir, target);
|
|
2811
|
+
await redirect(entrySpecifier, target, pkgRoot, () => shippedEntry(entrySpecifier, pkgRoot, entry));
|
|
2812
|
+
}
|
|
2813
|
+
packageMap[specifier] ??= relative$1(rootDir, absEntry);
|
|
2814
|
+
if (condition.root) {
|
|
2815
|
+
packageDirs.push(condition.root);
|
|
2816
|
+
if (linked) linkedDirs.push(condition.root);
|
|
2817
|
+
claimDir(condition.root, specifier);
|
|
2818
|
+
dirExtensions[condition.root] = [...extensionsSet];
|
|
2819
|
+
onPackageResolved?.(specifier, condition.root);
|
|
2820
|
+
for (const file of walkPackageSources(condition.root, extensionsSet)) if (ingest(file, specifier)) fileCount++;
|
|
2821
|
+
}
|
|
2822
|
+
} else if (existsSync(srcDir)) {
|
|
2466
2823
|
packageDirs.push(srcDir);
|
|
2824
|
+
if (linked) linkedDirs.push(srcDir);
|
|
2467
2825
|
claimDir(srcDir, specifier);
|
|
2468
2826
|
dirExtensions[srcDir] = [...extensionsSet];
|
|
2469
2827
|
onPackageResolved?.(specifier, srcDir);
|
|
2470
2828
|
const srcEntry = sourceEntryForSpecifier(specifier, srcDir, extensionsSet);
|
|
2471
2829
|
if (srcEntry) {
|
|
2472
|
-
packageMap[specifier] = relative(rootDir, srcEntry);
|
|
2830
|
+
packageMap[specifier] = relative$1(rootDir, srcEntry);
|
|
2473
2831
|
const replaced = absEntry;
|
|
2474
2832
|
await redirect(specifier, srcEntry, pkgRoot, async () => replaced);
|
|
2475
|
-
} else packageMap[specifier] = relative(rootDir, absEntry);
|
|
2476
|
-
if (
|
|
2477
|
-
const packageName = bareSpecifierPackageName(specifier);
|
|
2833
|
+
} else packageMap[specifier] = relative$1(rootDir, absEntry);
|
|
2834
|
+
if (packageName) {
|
|
2478
2835
|
if (packageName !== specifier && !(packageName in packageMap)) {
|
|
2479
2836
|
const rootEntry = sourceEntryForSpecifier(packageName, srcDir, extensionsSet);
|
|
2480
2837
|
if (rootEntry) {
|
|
2481
|
-
packageMap[packageName] = relative(rootDir, rootEntry);
|
|
2482
|
-
await redirect(packageName, rootEntry, pkgRoot,
|
|
2483
|
-
try {
|
|
2484
|
-
return await resolveSpecifier(packageName);
|
|
2485
|
-
} catch {
|
|
2486
|
-
return null;
|
|
2487
|
-
}
|
|
2488
|
-
});
|
|
2838
|
+
packageMap[packageName] = relative$1(rootDir, rootEntry);
|
|
2839
|
+
await redirect(packageName, rootEntry, pkgRoot, () => shippedEntry(packageName, pkgRoot, "."));
|
|
2489
2840
|
}
|
|
2490
2841
|
}
|
|
2491
2842
|
}
|
|
2492
2843
|
const pkgFiles = walkPackageSources(srcDir, extensionsSet);
|
|
2493
|
-
staleDist =
|
|
2494
|
-
for (const pkgFile of pkgFiles)
|
|
2495
|
-
const relPath = relative(rootDir, pkgFile);
|
|
2496
|
-
if (alreadyIngested(relPath)) {
|
|
2497
|
-
fileCount++;
|
|
2498
|
-
continue;
|
|
2499
|
-
}
|
|
2500
|
-
let source;
|
|
2501
|
-
try {
|
|
2502
|
-
source = readFileSync(pkgFile, "utf-8");
|
|
2503
|
-
} catch (err) {
|
|
2504
|
-
onUnreadable(relPath, err);
|
|
2505
|
-
continue;
|
|
2506
|
-
}
|
|
2507
|
-
onSourceRead?.(source, relPath, pkgFile);
|
|
2508
|
-
entries.push({
|
|
2509
|
-
path: relPath,
|
|
2510
|
-
source
|
|
2511
|
-
});
|
|
2512
|
-
pushed.add(relPath);
|
|
2513
|
-
fileOwners[relPath] ??= specifier;
|
|
2514
|
-
fileCount++;
|
|
2515
|
-
}
|
|
2844
|
+
staleDist = linked && distEntryIsStale(absEntry, srcDir, pkgFiles);
|
|
2845
|
+
for (const pkgFile of pkgFiles) if (ingest(pkgFile, specifier)) fileCount++;
|
|
2516
2846
|
} else {
|
|
2517
2847
|
const outputDir = dirname$1(absEntry);
|
|
2518
2848
|
packageDirs.push(outputDir);
|
|
2849
|
+
if (linked) linkedDirs.push(outputDir);
|
|
2850
|
+
outputDirs.push(outputDir);
|
|
2519
2851
|
claimDir(outputDir, specifier);
|
|
2520
2852
|
onPackageResolved?.(specifier, outputDir);
|
|
2521
|
-
packageMap[specifier] = relative(rootDir, absEntry);
|
|
2853
|
+
packageMap[specifier] = relative$1(rootDir, absEntry);
|
|
2522
2854
|
const outputExtensions = new Set(extensionsSet);
|
|
2523
|
-
outputExtensions.add(extname(absEntry));
|
|
2855
|
+
outputExtensions.add(extname$1(absEntry));
|
|
2524
2856
|
dirExtensions[outputDir] = [...outputExtensions];
|
|
2525
2857
|
const outputFiles = discoverFiles(outputDir, outputDir, void 0, outputExtensions).filter((file) => {
|
|
2526
|
-
const relToOutput = relative(outputDir, file);
|
|
2858
|
+
const relToOutput = relative$1(outputDir, file);
|
|
2527
2859
|
return !PACKAGE_OUTPUT_EXCLUDES.some((pattern) => relToOutput.includes(pattern));
|
|
2528
2860
|
});
|
|
2529
2861
|
if (!outputFiles.includes(absEntry)) outputFiles.unshift(absEntry);
|
|
2530
|
-
for (const outputFile of outputFiles)
|
|
2531
|
-
const outputRelPath = relative(rootDir, outputFile);
|
|
2532
|
-
if (alreadyIngested(outputRelPath)) {
|
|
2533
|
-
fileCount++;
|
|
2534
|
-
continue;
|
|
2535
|
-
}
|
|
2536
|
-
let source;
|
|
2537
|
-
try {
|
|
2538
|
-
source = readFileSync(outputFile, "utf-8");
|
|
2539
|
-
} catch (err) {
|
|
2540
|
-
onUnreadable(outputRelPath, err);
|
|
2541
|
-
continue;
|
|
2542
|
-
}
|
|
2543
|
-
onSourceRead?.(source, outputRelPath, outputFile);
|
|
2544
|
-
entries.push({
|
|
2545
|
-
path: outputRelPath,
|
|
2546
|
-
source
|
|
2547
|
-
});
|
|
2548
|
-
pushed.add(outputRelPath);
|
|
2549
|
-
fileOwners[outputRelPath] ??= specifier;
|
|
2550
|
-
fileCount++;
|
|
2551
|
-
}
|
|
2862
|
+
for (const outputFile of outputFiles) if (ingest(outputFile, specifier)) fileCount++;
|
|
2552
2863
|
}
|
|
2553
|
-
if (
|
|
2554
|
-
const
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
if (entrySpecifier in packageMap || !alreadyIngested(targetRelPath)) continue;
|
|
2559
|
-
packageMap[entrySpecifier] = targetRelPath;
|
|
2560
|
-
}
|
|
2864
|
+
if (packageName) for (const [subpath, target] of packageExportEntries(pkgRoot)) {
|
|
2865
|
+
const entrySpecifier = packageName + subpath.slice(1);
|
|
2866
|
+
const targetRelPath = relative$1(rootDir, target);
|
|
2867
|
+
if (entrySpecifier in packageMap || !alreadyIngested(targetRelPath)) continue;
|
|
2868
|
+
packageMap[entrySpecifier] = targetRelPath;
|
|
2561
2869
|
}
|
|
2562
2870
|
outcomes.push({
|
|
2563
2871
|
specifier,
|
|
@@ -2571,12 +2879,112 @@ async function collectExternalPackageSources(opts) {
|
|
|
2571
2879
|
sourceEntries,
|
|
2572
2880
|
sourceEntrySideEffects,
|
|
2573
2881
|
packageDirs,
|
|
2882
|
+
linkedDirs,
|
|
2883
|
+
outputDirs,
|
|
2574
2884
|
dirOwnerSets,
|
|
2575
2885
|
dirExtensions,
|
|
2576
2886
|
fileOwners,
|
|
2577
|
-
outcomes
|
|
2887
|
+
outcomes,
|
|
2888
|
+
diagnostics: [...diagnostics, ...noKitFilesDiagnostics(outcomes)],
|
|
2889
|
+
kitDescriptors
|
|
2578
2890
|
};
|
|
2579
2891
|
}
|
|
2892
|
+
/** The dependency names a manifest lists in `fields`. */
|
|
2893
|
+
function dependencyNames(manifest, fields) {
|
|
2894
|
+
if (!isJsonBlock(manifest)) return [];
|
|
2895
|
+
const names = /* @__PURE__ */ new Set();
|
|
2896
|
+
for (const field of fields) {
|
|
2897
|
+
const deps = manifest[field];
|
|
2898
|
+
if (isJsonBlock(deps)) for (const name of Object.keys(deps)) names.add(name);
|
|
2899
|
+
}
|
|
2900
|
+
return [...names];
|
|
2901
|
+
}
|
|
2902
|
+
/** The source kits the application at `rootDir` declares as dependencies.
|
|
2903
|
+
* A bundler serves an installed one as compiled code unless told
|
|
2904
|
+
* otherwise: Next keeps it external on the server unless it is in
|
|
2905
|
+
* `transpilePackages`, and Vite's optimizer prebundles it. */
|
|
2906
|
+
function sourceKitDependencies(rootDir) {
|
|
2907
|
+
return dependencyNames(readPackageManifest(rootDir), ["dependencies", "devDependencies"]).flatMap((name) => {
|
|
2908
|
+
const pkgRoot = locatePackageRoot(name, rootDir);
|
|
2909
|
+
if (pkgRoot === null || readKitSourceCondition(pkgRoot) === null) return [];
|
|
2910
|
+
return [{
|
|
2911
|
+
name,
|
|
2912
|
+
installed: isInstalledPackage(pkgRoot),
|
|
2913
|
+
dependencies: dependencyNames(readPackageManifest(pkgRoot), ["dependencies"])
|
|
2914
|
+
}];
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
/** A specifier that names a package: not relative or absolute, and no URL,
|
|
2918
|
+
* scheme (`node:`, `virtual:`), subpath import or virtual id. */
|
|
2919
|
+
function isPackageSpecifier(specifier) {
|
|
2920
|
+
return /^(?:@[^/\\:]+\/)?[^./\\#\0:][^:]*$/.test(specifier);
|
|
2921
|
+
}
|
|
2922
|
+
/**
|
|
2923
|
+
* An error for each kit the application's own `files` import or re-export
|
|
2924
|
+
* whose system the application's system does not include: a package that
|
|
2925
|
+
* declares the kit source condition, with no kit the system extends
|
|
2926
|
+
* (`systemKits`) in that package. One app build has exactly one system, and
|
|
2927
|
+
* every kit's system is part of it, so such a kit is not extracted against
|
|
2928
|
+
* a system it was not built for. One batch parse reads the imports of every
|
|
2929
|
+
* file the engine parses as it is; an adapted source (`.svelte`, `.mdx`)
|
|
2930
|
+
* reaches the engine only as its generated children.
|
|
2931
|
+
*/
|
|
2932
|
+
function importedKitDiagnostics(files, engine, rootDir, systemKits) {
|
|
2933
|
+
const { extractFacts } = engine;
|
|
2934
|
+
const parsed = files.filter(({ path }) => isEngineTransformExtension(path));
|
|
2935
|
+
if (!extractFacts || parsed.length === 0) return [];
|
|
2936
|
+
let facts;
|
|
2937
|
+
try {
|
|
2938
|
+
facts = parseInternalWire(extractFacts(JSON.stringify(parsed.map(({ path, source }) => ({
|
|
2939
|
+
path,
|
|
2940
|
+
source
|
|
2941
|
+
})))), "extractFacts");
|
|
2942
|
+
} catch {
|
|
2943
|
+
return [];
|
|
2944
|
+
}
|
|
2945
|
+
const seen = new Set(systemKits.filter((specifier) => !isAbsolute$1(specifier)).map(bareSpecifierPackageName));
|
|
2946
|
+
const diagnostics = [];
|
|
2947
|
+
for (const [path, file] of Object.entries(facts.files)) {
|
|
2948
|
+
if (file.parsePanicked) continue;
|
|
2949
|
+
const specifiers = [...file.imports.map((fact) => fact.source), ...file.exports.flatMap((fact) => fact.source === null ? [] : [fact.source])];
|
|
2950
|
+
for (const specifier of specifiers) {
|
|
2951
|
+
if (!isPackageSpecifier(specifier)) continue;
|
|
2952
|
+
const name = bareSpecifierPackageName(specifier);
|
|
2953
|
+
if (seen.has(name)) continue;
|
|
2954
|
+
seen.add(name);
|
|
2955
|
+
const pkgRoot = locatePackageRoot(name, dirname$1(resolve$1(rootDir, path)));
|
|
2956
|
+
if (pkgRoot && readKitSourceCondition(pkgRoot)) diagnostics.push({
|
|
2957
|
+
file: path,
|
|
2958
|
+
component: name,
|
|
2959
|
+
kind: "warn",
|
|
2960
|
+
message: `the application imports this kit, but its system is not included in the application's system, so its components are not extracted — include the kit's system in the application's system: createSystem().extend(<the kit's system>)`,
|
|
2961
|
+
code: KIT_SYSTEM_NOT_INCLUDED,
|
|
2962
|
+
severity: severityFor(KIT_SYSTEM_NOT_INCLUDED)
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
return diagnostics;
|
|
2967
|
+
}
|
|
2968
|
+
/** A kit without the source condition, warned once, or each condition entry
|
|
2969
|
+
* whose target is missing or outside the package. */
|
|
2970
|
+
function sourceConditionDiagnostics(packageName, condition) {
|
|
2971
|
+
if (condition === null) return [{
|
|
2972
|
+
file: packageName,
|
|
2973
|
+
component: "kit",
|
|
2974
|
+
kind: "warn",
|
|
2975
|
+
message: `declares no "${KIT_SOURCE_CONDITION}" export condition, so discovery guesses its source from src/ — give each public exports entry an "${KIT_SOURCE_CONDITION}" condition naming its original source`,
|
|
2976
|
+
code: KIT_WITHOUT_SOURCE_CONDITION,
|
|
2977
|
+
severity: severityFor(KIT_WITHOUT_SOURCE_CONDITION)
|
|
2978
|
+
}];
|
|
2979
|
+
return condition.invalid.map(([subpath, target]) => ({
|
|
2980
|
+
file: packageName,
|
|
2981
|
+
component: "kit",
|
|
2982
|
+
kind: "warn",
|
|
2983
|
+
message: `exports["${subpath}"].${KIT_SOURCE_CONDITION} names ${target}, which is missing or outside the package, so that entry is not read from source`,
|
|
2984
|
+
code: INVALID_KIT_SOURCE_CONDITION,
|
|
2985
|
+
severity: severityFor(INVALID_KIT_SOURCE_CONDITION)
|
|
2986
|
+
}));
|
|
2987
|
+
}
|
|
2580
2988
|
function firstOwners(dirOwnerSets) {
|
|
2581
2989
|
const owners = {};
|
|
2582
2990
|
for (const [dir, specifiers] of Object.entries(dirOwnerSets)) if (specifiers.length > 0) owners[dir] = specifiers[0];
|
|
@@ -2589,7 +2997,7 @@ function excludeCollectedPackages(collected, rejectedSpecifiers, rootDir) {
|
|
|
2589
2997
|
const targetRejected = (specifier, absTarget) => rejectedSpecifiers.has(specifier) || underRejectedDir(absTarget);
|
|
2590
2998
|
const packageMap = {};
|
|
2591
2999
|
for (const [specifier, relTarget] of Object.entries(collected.packageMap)) {
|
|
2592
|
-
if (targetRejected(specifier, resolve(rootDir, relTarget))) continue;
|
|
3000
|
+
if (targetRejected(specifier, resolve$1(rootDir, relTarget))) continue;
|
|
2593
3001
|
packageMap[specifier] = relTarget;
|
|
2594
3002
|
}
|
|
2595
3003
|
const sourceEntries = /* @__PURE__ */ new Map();
|
|
@@ -2622,10 +3030,14 @@ function excludeCollectedPackages(collected, rejectedSpecifiers, rootDir) {
|
|
|
2622
3030
|
sourceEntries,
|
|
2623
3031
|
sourceEntrySideEffects,
|
|
2624
3032
|
packageDirs: collected.packageDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
3033
|
+
linkedDirs: collected.linkedDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
3034
|
+
outputDirs: collected.outputDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
2625
3035
|
dirOwnerSets,
|
|
2626
3036
|
dirExtensions,
|
|
2627
3037
|
fileOwners,
|
|
2628
|
-
outcomes: collected.outcomes
|
|
3038
|
+
outcomes: collected.outcomes,
|
|
3039
|
+
diagnostics: collected.diagnostics,
|
|
3040
|
+
kitDescriptors: collected.kitDescriptors.filter((record) => !rejectedDirs.some((dir) => isPathWithinRoot(resolve$1(rootDir, record.packageRoot), dir)))
|
|
2629
3041
|
};
|
|
2630
3042
|
}
|
|
2631
3043
|
function unresolvableIncludesMessage(outcomes) {
|
|
@@ -2654,7 +3066,8 @@ function engineModuleParser(engine) {
|
|
|
2654
3066
|
}])), "extractFacts").files[path];
|
|
2655
3067
|
return facts && !facts.parsePanicked ? {
|
|
2656
3068
|
imports: facts.imports,
|
|
2657
|
-
exports: facts.exports
|
|
3069
|
+
exports: facts.exports,
|
|
3070
|
+
unboundCreateSystemCalls: facts.unboundCreateSystemCalls ?? []
|
|
2658
3071
|
} : null;
|
|
2659
3072
|
} catch {
|
|
2660
3073
|
return null;
|
|
@@ -2665,7 +3078,7 @@ const ANIMUS_SYSTEM_SPECIFIER = /^@animus-ui\/system(?:\/.*)?$/;
|
|
|
2665
3078
|
/** The file a specifier names from `importer`: a relative one by the
|
|
2666
3079
|
* ingestion's probe order, a bare one by the host's package resolution. */
|
|
2667
3080
|
async function resolveModuleFile(importer, specifier, resolvePackage) {
|
|
2668
|
-
if (specifier.startsWith(".")) return relativeSourceCandidates(importer, specifier).find(isFile) ?? null;
|
|
3081
|
+
if (specifier.startsWith(".")) return relativeSourceCandidates(importer, specifier).find(isFile$1) ?? null;
|
|
2669
3082
|
try {
|
|
2670
3083
|
return await resolvePackage?.(specifier) ?? null;
|
|
2671
3084
|
} catch {
|
|
@@ -2750,13 +3163,15 @@ const NAMESPACE_IMPORT = /\bimport\s+(?:[a-zA-Z_$][a-zA-Z0-9_$]*\s*,\s*)?\*\s*as
|
|
|
2750
3163
|
* `import()` of a module. A binding named `createSystem` shown to be
|
|
2751
3164
|
* something else is no root. One whose identity discovery cannot follow
|
|
2752
3165
|
* keeps the admission spelling gave it, so a resolution limit never drops a
|
|
2753
|
-
* kit. Both are reported.
|
|
2754
|
-
* the
|
|
3166
|
+
* kit. Both are reported. A call of the bare name, which the file neither
|
|
3167
|
+
* imports nor declares, is no root: the system loader evaluates the file
|
|
3168
|
+
* without auto-imports, where the name is undefined. It is reported once.
|
|
2755
3169
|
*/
|
|
2756
|
-
async function systemRoots(systemFilePath, source,
|
|
3170
|
+
async function systemRoots(systemFilePath, source, record, following) {
|
|
3171
|
+
const { imports } = record;
|
|
2757
3172
|
const roots = /* @__PURE__ */ new Set();
|
|
2758
3173
|
const identityOf = (specifier, name) => exportIdentity(systemFilePath, specifier, name, following, /* @__PURE__ */ new Set());
|
|
2759
|
-
const called = (callee) =>
|
|
3174
|
+
const called = (callee) => callOf(callee).test(source);
|
|
2760
3175
|
/** Admits a binding named `createSystem` by its identity: an unknown one
|
|
2761
3176
|
* keeps `spellingAdmits`, and every unproven one is reported. */
|
|
2762
3177
|
const admit = (local, offset, identity, spellingAdmits) => {
|
|
@@ -2776,11 +3191,8 @@ async function systemRoots(systemFilePath, source, imports, following) {
|
|
|
2776
3191
|
...locationIn(source, offset)
|
|
2777
3192
|
});
|
|
2778
3193
|
};
|
|
2779
|
-
let bindsName = false;
|
|
2780
3194
|
for (const binding of imports) {
|
|
2781
|
-
|
|
2782
|
-
if (binding.local === "createSystem") bindsName = true;
|
|
2783
|
-
if (named) {
|
|
3195
|
+
if (binding.imported === "createSystem" || binding.local === "createSystem") {
|
|
2784
3196
|
const statement = new RegExp(`\\bimport\\b[^;]*?\\bfrom\\s*['"]${escapeRegExp$1(binding.source)}['"]`, "g");
|
|
2785
3197
|
let offset = 0;
|
|
2786
3198
|
for (const match of source.matchAll(statement)) {
|
|
@@ -2811,19 +3223,47 @@ async function systemRoots(systemFilePath, source, imports, following) {
|
|
|
2811
3223
|
why: `it is destructured from '${initializer}', which is not a module namespace`
|
|
2812
3224
|
});
|
|
2813
3225
|
};
|
|
3226
|
+
for (const { local, offset, initializer } of destructuredCreateSystems(source)) admit(local, offset, await destructuredFrom(initializer), local === "createSystem");
|
|
3227
|
+
const unimported = unimportedCreateSystemCall(systemFilePath, record);
|
|
3228
|
+
if (unimported) following.report?.(unimported);
|
|
3229
|
+
return roots;
|
|
3230
|
+
}
|
|
3231
|
+
/** A call of `callee` as a whole name, not a member. */
|
|
3232
|
+
function callOf(callee) {
|
|
3233
|
+
return new RegExp(`(?<![a-zA-Z0-9_$.])${escapeRegExp$1(callee)}\\s*\\(`);
|
|
3234
|
+
}
|
|
3235
|
+
/** Each `createSystem` property a declaration destructures: its local name,
|
|
3236
|
+
* its offset in `source`, and the destructured initializer. */
|
|
3237
|
+
function* destructuredCreateSystems(source) {
|
|
2814
3238
|
for (const match of source.matchAll(/\b(?:const|let|var)\s*\{([^}]*)\}\s*=\s*([^;\n]+)/g)) {
|
|
2815
3239
|
const [whole, pattern, initializer] = match;
|
|
2816
3240
|
for (const property of pattern.split(",")) {
|
|
2817
3241
|
const binding = /^\s*createSystem\s*(?::\s*([a-zA-Z_$][a-zA-Z0-9_$]*))?\s*(?:=[\s\S]*)?$/.exec(property);
|
|
2818
3242
|
if (!binding) continue;
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
3243
|
+
yield {
|
|
3244
|
+
local: binding[1] ?? "createSystem",
|
|
3245
|
+
offset: match.index + whole.indexOf("createSystem"),
|
|
3246
|
+
initializer: initializer.trim()
|
|
3247
|
+
};
|
|
2822
3248
|
}
|
|
2823
3249
|
}
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
3250
|
+
}
|
|
3251
|
+
/** The warning for a `createSystem` call that the parser's scopes leave
|
|
3252
|
+
* unbound: no import, declaration or parameter names it. Null when there is
|
|
3253
|
+
* none, or when the parser reports no scopes. */
|
|
3254
|
+
function unimportedCreateSystemCall(systemFilePath, record) {
|
|
3255
|
+
const call = record.unboundCreateSystemCalls?.[0];
|
|
3256
|
+
if (!call) return null;
|
|
3257
|
+
return {
|
|
3258
|
+
file: systemFilePath,
|
|
3259
|
+
component: "createSystem",
|
|
3260
|
+
kind: "warn",
|
|
3261
|
+
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'`,
|
|
3262
|
+
code: UNIMPORTED_CREATE_SYSTEM,
|
|
3263
|
+
severity: severityFor(UNIMPORTED_CREATE_SYSTEM),
|
|
3264
|
+
line: call[0],
|
|
3265
|
+
column: call[1]
|
|
3266
|
+
};
|
|
2827
3267
|
}
|
|
2828
3268
|
/** A pattern matching a call of any of `callees` as a whole name, or null
|
|
2829
3269
|
* when there is none to anchor on. */
|
|
@@ -2839,9 +3279,8 @@ async function extractSystemFilePackages(systemFilePath, parseModule, report, re
|
|
|
2839
3279
|
return [];
|
|
2840
3280
|
}
|
|
2841
3281
|
const parsed = parseModule?.(source, systemFilePath) ?? null;
|
|
2842
|
-
const parsedImports = parsed && parsed.imports.length > 0 ? parsed.imports : null;
|
|
2843
3282
|
let rootCall = "createSystem";
|
|
2844
|
-
if (parseModule &&
|
|
3283
|
+
if (parseModule && parsed) rootCall = rootCallPattern([...await systemRoots(systemFilePath, source, parsed, {
|
|
2845
3284
|
parseModule,
|
|
2846
3285
|
resolvePackage,
|
|
2847
3286
|
report
|
|
@@ -3013,9 +3452,9 @@ async function extractSystemFilePackages(systemFilePath, parseModule, report, re
|
|
|
3013
3452
|
}
|
|
3014
3453
|
if (identifiers.size === 0) return [];
|
|
3015
3454
|
const importMap = /* @__PURE__ */ new Map();
|
|
3016
|
-
for (const binding of
|
|
3455
|
+
for (const binding of parsed?.imports ?? []) importMap.set(binding.local, binding.source);
|
|
3017
3456
|
const importRegex = /^\s*import\s+(?:([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,\s*)?(?:\{([^}]*)\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\s+from\s+['"]([^'"]+)['"]/gm;
|
|
3018
|
-
if (!
|
|
3457
|
+
if (!parsed) {
|
|
3019
3458
|
let importMatch;
|
|
3020
3459
|
while ((importMatch = importRegex.exec(source)) !== null) {
|
|
3021
3460
|
const [, comboDefault, namedImports, defaultImport, specifier] = importMatch;
|
|
@@ -3045,7 +3484,7 @@ async function extractSystemFilePackages(systemFilePath, parseModule, report, re
|
|
|
3045
3484
|
for (const id of identifiers) {
|
|
3046
3485
|
const specifier = importMap.get(throughAliases(id));
|
|
3047
3486
|
if (!specifier) continue;
|
|
3048
|
-
if (specifier.startsWith(".")) packages.add(resolve(systemFileDir, specifier));
|
|
3487
|
+
if (specifier.startsWith(".")) packages.add(resolve$1(systemFileDir, specifier));
|
|
3049
3488
|
else packages.add(specifier);
|
|
3050
3489
|
}
|
|
3051
3490
|
return Array.from(packages);
|
|
@@ -3148,7 +3587,7 @@ function resolveThroughPathAliases(specifier, rootDir, pathAliasesJson) {
|
|
|
3148
3587
|
if (alias.pattern === specifier) mapped = alias.replacement;
|
|
3149
3588
|
} else if (specifier.startsWith(alias.pattern)) mapped = alias.replacement + specifier.slice(alias.pattern.length);
|
|
3150
3589
|
if (mapped === null) continue;
|
|
3151
|
-
const absolute = isAbsolute(mapped) ? mapped : join$1(rootDir, mapped);
|
|
3590
|
+
const absolute = isAbsolute$1(mapped) ? mapped : join$1(rootDir, mapped);
|
|
3152
3591
|
if (existsSync(absolute)) return absolute;
|
|
3153
3592
|
}
|
|
3154
3593
|
return null;
|
|
@@ -3267,8 +3706,13 @@ function enforceExternalTokenContracts(opts) {
|
|
|
3267
3706
|
sourceTokens
|
|
3268
3707
|
});
|
|
3269
3708
|
if (messages.length === 0) return;
|
|
3270
|
-
if (opts.strict)
|
|
3271
|
-
|
|
3709
|
+
if (!opts.strict) {
|
|
3710
|
+
for (const message of messages) opts.warn(message);
|
|
3711
|
+
return;
|
|
3712
|
+
}
|
|
3713
|
+
const message = `${opts.prefix} ${messages.join("\n")}`;
|
|
3714
|
+
if (!opts.reportErrors) throw new Error(message);
|
|
3715
|
+
opts.reportErrors(message);
|
|
3272
3716
|
}
|
|
3273
3717
|
//#endregion
|
|
3274
3718
|
//#region pipeline/path-aliases.ts
|
|
@@ -3880,11 +4324,14 @@ function buildAnalysisInputs(opts) {
|
|
|
3880
4324
|
externalDirsJson: opts.externalDirs?.length && hasSourceThemeManifests(opts.system) ? JSON.stringify(opts.externalDirs) : null
|
|
3881
4325
|
};
|
|
3882
4326
|
if (opts.system.declarationScalesJson) inputs.declarationScalesJson = opts.system.declarationScalesJson;
|
|
4327
|
+
if (opts.system.generatedNamesJson) inputs.generatedNamesJson = opts.system.generatedNamesJson;
|
|
3883
4328
|
const context = opts.analysisContext;
|
|
3884
4329
|
if (context?.skippedSources?.length || context?.unbundledComputedImports || context?.packageDirs?.length) inputs.analysisContextJson = JSON.stringify({
|
|
3885
4330
|
skippedSources: context.skippedSources ?? [],
|
|
3886
4331
|
unbundledComputedImports: context.unbundledComputedImports ?? false,
|
|
3887
|
-
packageDirs: context.packageDirs ?? []
|
|
4332
|
+
packageDirs: context.packageDirs ?? [],
|
|
4333
|
+
linkedDirs: context.linkedDirs ?? [],
|
|
4334
|
+
outputDirs: context.outputDirs ?? []
|
|
3888
4335
|
});
|
|
3889
4336
|
return inputs;
|
|
3890
4337
|
}
|
|
@@ -3925,7 +4372,12 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
3925
4372
|
t = performance.now();
|
|
3926
4373
|
const manifest = JSON.parse(manifestJson);
|
|
3927
4374
|
const systemErrors = systemLoadDiagnostics(opts.system).filter((diagnostic) => diagnostic.kind === "error");
|
|
3928
|
-
|
|
4375
|
+
const kitDiagnostics = kitDescriptorDiagnostics(opts.kitDescriptors ?? [], manifest);
|
|
4376
|
+
if (systemErrors.length > 0 || kitDiagnostics.length > 0) manifest.diagnostics = [
|
|
4377
|
+
...systemErrors,
|
|
4378
|
+
...kitDiagnostics,
|
|
4379
|
+
...manifest.diagnostics ?? []
|
|
4380
|
+
];
|
|
3929
4381
|
const componentCss = applyUnitFallback(manifest.css);
|
|
3930
4382
|
const propertyDiagnostics = checkCustomProperties({
|
|
3931
4383
|
system: opts.system,
|
|
@@ -3936,6 +4388,7 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
3936
4388
|
surfaceManifestDiagnostics(manifest, opts.warn, {
|
|
3937
4389
|
strict: opts.strict,
|
|
3938
4390
|
info: opts.info,
|
|
4391
|
+
reportErrors: opts.reportErrors,
|
|
3939
4392
|
levels: opts.diagnostics,
|
|
3940
4393
|
knownCodes: opts.diagnostics ? knownDiagnosticCodes(diagnosticCodes?.()) : void 0,
|
|
3941
4394
|
prepend: [
|
|
@@ -4043,36 +4496,34 @@ function renameCustomProperties(css, names) {
|
|
|
4043
4496
|
}
|
|
4044
4497
|
//#endregion
|
|
4045
4498
|
//#region pipeline/prefix.ts
|
|
4046
|
-
/**
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4499
|
+
/**
|
|
4500
|
+
* The prefix without `prefixContextualVars`: every name Animus generates (a
|
|
4501
|
+
* variable the theme's map or variable CSS defines) takes `--${prefix}-`
|
|
4502
|
+
* wherever it is defined, registered or read, `var()` fallbacks at any depth
|
|
4503
|
+
* included. Every other name stays as written: each declared contextual
|
|
4504
|
+
* variable, and any custom property an author writes.
|
|
4505
|
+
*/
|
|
4506
|
+
function applyPrefix(prefix, variableMapJson, variableCss, themeJson, contextualVarsJson, declarationScalesJson) {
|
|
4052
4507
|
if (!prefix) return {
|
|
4053
4508
|
variableMapJson,
|
|
4054
4509
|
variableCss,
|
|
4055
4510
|
themeJson,
|
|
4056
|
-
contextualVarsJson
|
|
4511
|
+
contextualVarsJson,
|
|
4512
|
+
declarationScalesJson
|
|
4057
4513
|
};
|
|
4058
|
-
const
|
|
4059
|
-
const
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
css = prefixVariableReferences(prefix, css);
|
|
4064
|
-
css = css.replace(/@property(\s+)--([a-zA-Z][\w-]*)/g, `@property$1--${prefix}-$2`);
|
|
4514
|
+
const contextual = new Set(contextualVarsJson ? Object.values(parseInternalWire(contextualVarsJson, "contextualVarsJson (the theme's contextual variable names)")).flat() : []);
|
|
4515
|
+
const variableMap = parseInternalWire(variableMapJson, "variableMapJson (the theme's token variables)");
|
|
4516
|
+
const generated = [...Object.values(variableMap).map((name) => name.replace(/^--/, "")), ...themeDefinitions(variableCss)].filter((name) => !contextual.has(name));
|
|
4517
|
+
const names = createPropertyNames([], prefix, generated);
|
|
4518
|
+
const rename = (value) => renameCustomProperties(value, names);
|
|
4065
4519
|
const result = {
|
|
4066
|
-
variableMapJson: JSON.stringify(
|
|
4067
|
-
variableCss:
|
|
4520
|
+
variableMapJson: JSON.stringify(Object.fromEntries(Object.entries(variableMap).map(([key, name]) => [key, rename(name)]))),
|
|
4521
|
+
variableCss: rename(variableCss)
|
|
4068
4522
|
};
|
|
4069
|
-
if (themeJson) result.themeJson =
|
|
4070
|
-
if (contextualVarsJson)
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
for (const [scale, names] of Object.entries(ctxVars)) prefixedCtx[scale] = names.map((name) => `${prefix}-${name}`);
|
|
4074
|
-
result.contextualVarsJson = JSON.stringify(prefixedCtx);
|
|
4075
|
-
}
|
|
4523
|
+
if (themeJson) result.themeJson = renameTokenValues(themeJson, rename);
|
|
4524
|
+
if (contextualVarsJson) result.contextualVarsJson = contextualVarsJson;
|
|
4525
|
+
if (generated.length > 0) result.generatedNamesJson = JSON.stringify(Object.fromEntries(generated.map((name) => [name, `${prefix}-${name}`])));
|
|
4526
|
+
if (declarationScalesJson) result.declarationScalesJson = renameDeclarationRecords(declarationScalesJson, rename);
|
|
4076
4527
|
return result;
|
|
4077
4528
|
}
|
|
4078
4529
|
/** The runtime's transport variables are `--animus-<prop>`. */
|
|
@@ -4088,7 +4539,8 @@ function applyPropertyNames(prefix, artifacts) {
|
|
|
4088
4539
|
const byScale = artifacts.contextualVarsJson ? parseInternalWire(artifacts.contextualVarsJson, "contextualVarsJson (the theme's contextual variable names)") : null;
|
|
4089
4540
|
const declared = Object.values(byScale ?? {}).flat();
|
|
4090
4541
|
const variableMap = parseInternalWire(artifacts.variableMapJson, "variableMapJson (the theme's token variables)");
|
|
4091
|
-
const
|
|
4542
|
+
const themeDefined = [...Object.values(variableMap).map((name) => name.replace(/^--/, "")), ...themeDefinitions(artifacts.variableCss)];
|
|
4543
|
+
const managed = createPropertyNames(declared, prefix, themeDefined);
|
|
4092
4544
|
const nameConflicts = [...[...new Set(declared)].flatMap((name) => {
|
|
4093
4545
|
const final = managed.finalName(name) ?? name;
|
|
4094
4546
|
return final.startsWith(TRANSPORT_NAMESPACE) ? [{
|
|
@@ -4112,11 +4564,30 @@ function applyPropertyNames(prefix, artifacts) {
|
|
|
4112
4564
|
}))]))),
|
|
4113
4565
|
declarationScalesJson: artifacts.declarationScalesJson === null ? null : renameDeclarationRecords(artifacts.declarationScalesJson, rename),
|
|
4114
4566
|
nameConflicts,
|
|
4115
|
-
contextualProperties: [...new Set(declared)].map((name) => `--${managed.finalName(name) ?? name}`)
|
|
4567
|
+
contextualProperties: [...new Set(declared)].map((name) => `--${managed.finalName(name) ?? name}`),
|
|
4568
|
+
generatedNamesJson: generatedNamesJson(themeDefined.filter((name) => !declared.includes(name)), managed)
|
|
4116
4569
|
};
|
|
4117
4570
|
}
|
|
4118
|
-
/**
|
|
4119
|
-
|
|
4571
|
+
/** The generated names' final names, for authored component styles. */
|
|
4572
|
+
function generatedNamesJson(names, managed) {
|
|
4573
|
+
const entries = [...new Set(names)].flatMap((name) => {
|
|
4574
|
+
const final = managed.finalName(name);
|
|
4575
|
+
return final === void 0 ? [] : [[name, final]];
|
|
4576
|
+
});
|
|
4577
|
+
return entries.length === 0 ? null : JSON.stringify(Object.fromEntries(entries));
|
|
4578
|
+
}
|
|
4579
|
+
/** The custom properties the theme's CSS declares or `@property` registers,
|
|
4580
|
+
* read as CSS tokenizes it: a name in a string or comment defines nothing. */
|
|
4581
|
+
function themeDefinitions(variableCss) {
|
|
4582
|
+
const tokens = tokenize(variableCss).filter((token) => token.type !== "whitespace");
|
|
4583
|
+
return tokens.flatMap((token, index) => {
|
|
4584
|
+
if (token.type !== "ident" || !token.value.startsWith("--")) return [];
|
|
4585
|
+
const previous = tokens[index - 1];
|
|
4586
|
+
const declared = (previous === void 0 || previous.type === "{" || previous.type === ";") && tokens[index + 1]?.type === ":";
|
|
4587
|
+
const registered = previous?.type === "at-keyword" && previous.value.toLowerCase() === "property";
|
|
4588
|
+
return declared || registered ? [token.value.slice(2)] : [];
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4120
4591
|
/** Renames inside the token map's values. */
|
|
4121
4592
|
function renameTokenValues(themeJson, rename) {
|
|
4122
4593
|
const tokens = parseInternalWire(themeJson, "themeJson (the theme's flattened token values)");
|
|
@@ -4132,23 +4603,40 @@ function renameDeclarationRecords(declarationScalesJson, rename) {
|
|
|
4132
4603
|
}
|
|
4133
4604
|
//#endregion
|
|
4134
4605
|
//#region pipeline/system-config.ts
|
|
4606
|
+
/** The loader's evaluation of the system file. A failure on a file that
|
|
4607
|
+
* calls `createSystem` with no binding leads with discovery's warning line
|
|
4608
|
+
* for it, then keeps the loader's own error. */
|
|
4609
|
+
function evaluateSystemModule(engine, systemPath, rootDir, conditions) {
|
|
4610
|
+
try {
|
|
4611
|
+
return engine.loadSystemModule(systemPath, rootDir, void 0, conditions);
|
|
4612
|
+
} catch (error) {
|
|
4613
|
+
let source;
|
|
4614
|
+
try {
|
|
4615
|
+
source = readFileSync(systemPath, "utf-8");
|
|
4616
|
+
} catch {
|
|
4617
|
+
throw error;
|
|
4618
|
+
}
|
|
4619
|
+
const record = engineModuleParser(engine)?.(source, systemPath);
|
|
4620
|
+
const call = record && unimportedCreateSystemCall(systemPath, record);
|
|
4621
|
+
if (!call) throw error;
|
|
4622
|
+
throw new Error(`${warnLine(call)}\n${String(error)}`, { cause: error });
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4135
4625
|
/**
|
|
4136
4626
|
* Load and normalize a SystemInstance; `prefix` namespaces every CSS
|
|
4137
4627
|
* variable name. Error handling stays at the call site.
|
|
4138
4628
|
*/
|
|
4139
4629
|
function loadSystemConfig(engineApi, opts) {
|
|
4140
|
-
const
|
|
4141
|
-
const config = loadSystemModule(opts.systemPath, opts.rootDir);
|
|
4630
|
+
const config = evaluateSystemModule(engineApi(), opts.systemPath, opts.rootDir, opts.conditions);
|
|
4142
4631
|
let scalesJson = config.scalesJson;
|
|
4143
4632
|
let variableMapJson = config.variableMapJson;
|
|
4144
4633
|
const registrations = splitInvalidPropertyRegistrations(config.variableCss);
|
|
4145
4634
|
let variableCss = registrations.css;
|
|
4146
4635
|
let contextualVarsJson = config.contextualVarsJson || null;
|
|
4147
4636
|
let declarationScalesJson = config.declarationScalesJson || null;
|
|
4148
|
-
|
|
4149
|
-
let contextualProperties = declaredNames.map((name) => `--${name}`);
|
|
4150
|
-
let legacyPrefixedContextualVars = [];
|
|
4637
|
+
let contextualProperties = Object.values(parseInternalWire(contextualVarsJson ?? "{}", "contextualVarsJson (the theme's contextual variable names)")).flat().map((name) => `--${name}`);
|
|
4151
4638
|
let prefixNameConflicts = [];
|
|
4639
|
+
let generatedNamesJson;
|
|
4152
4640
|
if (opts.prefix && opts.prefixContextualVars) {
|
|
4153
4641
|
const resolved = applyPropertyNames(opts.prefix, {
|
|
4154
4642
|
variableMapJson,
|
|
@@ -4164,15 +4652,14 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
4164
4652
|
contextualProperties = resolved.contextualProperties;
|
|
4165
4653
|
prefixNameConflicts = resolved.nameConflicts;
|
|
4166
4654
|
declarationScalesJson = resolved.declarationScalesJson;
|
|
4655
|
+
generatedNamesJson = resolved.generatedNamesJson;
|
|
4167
4656
|
} else if (opts.prefix) {
|
|
4168
|
-
|
|
4169
|
-
contextualProperties = declaredNames.map((name) => `--${opts.prefix}-${name}`);
|
|
4170
|
-
const prefixed = applyPrefix(opts.prefix, variableMapJson, variableCss, scalesJson, contextualVarsJson || void 0);
|
|
4657
|
+
const prefixed = applyPrefix(opts.prefix, variableMapJson, variableCss, scalesJson, contextualVarsJson || void 0, declarationScalesJson || void 0);
|
|
4171
4658
|
variableMapJson = prefixed.variableMapJson;
|
|
4172
4659
|
variableCss = prefixed.variableCss;
|
|
4173
4660
|
if (prefixed.themeJson) scalesJson = prefixed.themeJson;
|
|
4174
|
-
if (prefixed.
|
|
4175
|
-
|
|
4661
|
+
if (prefixed.declarationScalesJson) declarationScalesJson = prefixed.declarationScalesJson;
|
|
4662
|
+
generatedNamesJson = prefixed.generatedNamesJson;
|
|
4176
4663
|
}
|
|
4177
4664
|
const system = {
|
|
4178
4665
|
propConfigJson: config.propConfig,
|
|
@@ -4196,7 +4683,7 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
4196
4683
|
if (config.propertyRecordsJson) system.propertyRecordsJson = config.propertyRecordsJson;
|
|
4197
4684
|
if (registrations.invalid.length > 0) system.invalidPropertyRegistrations = registrations.invalid;
|
|
4198
4685
|
if (prefixNameConflicts.length > 0) system.prefixNameConflicts = prefixNameConflicts;
|
|
4199
|
-
if (
|
|
4686
|
+
if (generatedNamesJson) system.generatedNamesJson = generatedNamesJson;
|
|
4200
4687
|
return system;
|
|
4201
4688
|
}
|
|
4202
4689
|
//#endregion
|
|
@@ -4205,8 +4692,7 @@ function runStructuralSelfCheck(input) {
|
|
|
4205
4692
|
const failures = [];
|
|
4206
4693
|
if (input.componentCount === 0) failures.push("No component CSS produced — check the system file and its includes list");
|
|
4207
4694
|
else if (input.assembledCss !== void 0 ? !/@layer\s+anm-base\s*\{/.test(input.assembledCss) : input.componentCss.trim().length === 0) failures.push(`${input.componentCount} component(s) discovered but the emitted component CSS is empty`);
|
|
4208
|
-
for (const { specifier, outcome } of input.externalOutcomes ?? []) if (outcome === "
|
|
4209
|
-
else if (outcome === "unresolvable") failures.push(`include '${specifier}' could not be resolved`);
|
|
4695
|
+
for (const { specifier, outcome } of input.externalOutcomes ?? []) if (outcome === "unresolvable") failures.push(`include '${specifier}' could not be resolved`);
|
|
4210
4696
|
if ((input.variableMapJson == null || Object.keys(parseInternalWire(input.variableMapJson, "variableMapJson (the theme's token → variable map)")).length > 0) && !input.variableCss.includes(":root")) failures.push("No :root variable block found in variable CSS");
|
|
4211
4697
|
if ((input.assembledCss ?? `${input.variableCss}\n${input.globalCss}\n${input.componentCss}`).includes("__TRANSFORM__")) failures.push("Unresolved __TRANSFORM__ placeholders found in CSS output");
|
|
4212
4698
|
if (input.componentCount > 0 && (input.componentCss.length > 0 || input.assembledCss !== void 0)) {
|
|
@@ -4240,7 +4726,8 @@ function buildDynamicPropConfig(dynamicProps) {
|
|
|
4240
4726
|
kind: meta.kind,
|
|
4241
4727
|
slotClass: meta.slotClass,
|
|
4242
4728
|
memberVars: meta.memberVars,
|
|
4243
|
-
declarationScaleValues: meta.declarationScaleValues
|
|
4729
|
+
declarationScaleValues: meta.declarationScaleValues,
|
|
4730
|
+
...meta.productionConditions && { productionConditions: meta.productionConditions }
|
|
4244
4731
|
};
|
|
4245
4732
|
continue;
|
|
4246
4733
|
}
|
|
@@ -4258,6 +4745,7 @@ function buildDynamicPropConfig(dynamicProps) {
|
|
|
4258
4745
|
if (meta.strict) entry.strict = true;
|
|
4259
4746
|
if (meta.keywords?.length) entry.keywords = meta.keywords;
|
|
4260
4747
|
if (meta.currentVar) entry.currentVar = meta.currentVar;
|
|
4748
|
+
if (meta.productionConditions) entry.productionConditions = meta.productionConditions;
|
|
4261
4749
|
configEntries[propName] = entry;
|
|
4262
4750
|
}
|
|
4263
4751
|
return configEntries;
|
|
@@ -4296,6 +4784,191 @@ function assertNoErrorDiagnostics(diagnostics) {
|
|
|
4296
4784
|
throw new Error(lines.join("\n"));
|
|
4297
4785
|
}
|
|
4298
4786
|
//#endregion
|
|
4787
|
+
//#region pipeline/kit-publication.ts
|
|
4788
|
+
/** Source a kit publishes and the loader or a bundler parses for imports. */
|
|
4789
|
+
const CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4790
|
+
".ts",
|
|
4791
|
+
".tsx",
|
|
4792
|
+
".mts",
|
|
4793
|
+
".cts",
|
|
4794
|
+
".js",
|
|
4795
|
+
".jsx",
|
|
4796
|
+
".mjs",
|
|
4797
|
+
".cjs"
|
|
4798
|
+
]);
|
|
4799
|
+
const isFile = (path) => {
|
|
4800
|
+
try {
|
|
4801
|
+
return statSync$1(path).isFile();
|
|
4802
|
+
} catch {
|
|
4803
|
+
return false;
|
|
4804
|
+
}
|
|
4805
|
+
};
|
|
4806
|
+
const posixPath = (path) => path.split(sep).join("/");
|
|
4807
|
+
/**
|
|
4808
|
+
* The package-relative files `npm pack` publishes, read with npm's own rules
|
|
4809
|
+
* (`files`, `.npmignore`, `.gitignore` and the files npm always includes)
|
|
4810
|
+
* through a dry run that runs no scripts and needs no network.
|
|
4811
|
+
*/
|
|
4812
|
+
function npmPublishedFiles(pkgRoot) {
|
|
4813
|
+
const windows = process.platform === "win32";
|
|
4814
|
+
const run = spawnSync(windows ? "npm.cmd" : "npm", [
|
|
4815
|
+
"pack",
|
|
4816
|
+
"--dry-run",
|
|
4817
|
+
"--json",
|
|
4818
|
+
"--ignore-scripts"
|
|
4819
|
+
], {
|
|
4820
|
+
cwd: pkgRoot,
|
|
4821
|
+
encoding: "utf-8",
|
|
4822
|
+
shell: windows,
|
|
4823
|
+
env: {
|
|
4824
|
+
...process.env,
|
|
4825
|
+
npm_config_update_notifier: "false"
|
|
4826
|
+
}
|
|
4827
|
+
});
|
|
4828
|
+
if (run.error || run.status !== 0) return {
|
|
4829
|
+
kind: "failed",
|
|
4830
|
+
reason: `npm pack --dry-run could not list the published files: ${String(run.error ?? run.stderr.trim())}`
|
|
4831
|
+
};
|
|
4832
|
+
let output;
|
|
4833
|
+
try {
|
|
4834
|
+
output = JSON.parse(run.stdout);
|
|
4835
|
+
} catch (error) {
|
|
4836
|
+
return {
|
|
4837
|
+
kind: "failed",
|
|
4838
|
+
reason: `npm pack --dry-run printed no JSON: ${String(error)}`
|
|
4839
|
+
};
|
|
4840
|
+
}
|
|
4841
|
+
const pack = Array.isArray(output) ? output[0] : void 0;
|
|
4842
|
+
const files = isJsonBlock(pack) ? pack.files : void 0;
|
|
4843
|
+
if (!Array.isArray(files)) return {
|
|
4844
|
+
kind: "failed",
|
|
4845
|
+
reason: "npm pack --dry-run printed no file list"
|
|
4846
|
+
};
|
|
4847
|
+
return {
|
|
4848
|
+
kind: "listed",
|
|
4849
|
+
files: new Set(files.flatMap((file) => isJsonBlock(file) && isJsonString(file.path) ? [posixPath(file.path)] : []))
|
|
4850
|
+
};
|
|
4851
|
+
}
|
|
4852
|
+
function animusTargets(manifest) {
|
|
4853
|
+
const targets = [];
|
|
4854
|
+
const unreadable = [];
|
|
4855
|
+
const visit = (subpath, value, underAnimus) => {
|
|
4856
|
+
if (isJsonString(value)) {
|
|
4857
|
+
if (underAnimus) targets.push([subpath, value]);
|
|
4858
|
+
} else if (Array.isArray(value)) for (const entry of value) visit(subpath, entry, underAnimus);
|
|
4859
|
+
else if (isJsonBlock(value)) for (const [key, entry] of Object.entries(value)) visit(subpath, entry, underAnimus || key === "animus");
|
|
4860
|
+
else if (underAnimus && value !== null) unreadable.push([subpath, JSON.stringify(value)]);
|
|
4861
|
+
};
|
|
4862
|
+
for (const [subpath, value] of exportsSubpaths(manifest)) visit(subpath, value, false);
|
|
4863
|
+
return {
|
|
4864
|
+
targets,
|
|
4865
|
+
unreadable
|
|
4866
|
+
};
|
|
4867
|
+
}
|
|
4868
|
+
/** Every file in the package outside `node_modules` and `.git`,
|
|
4869
|
+
* package-relative. */
|
|
4870
|
+
function packageFiles(pkgRoot, dir = "") {
|
|
4871
|
+
return readdirSync$1(join(pkgRoot, dir), { withFileTypes: true }).flatMap((entry) => {
|
|
4872
|
+
const path = dir === "" ? entry.name : `${dir}/${entry.name}`;
|
|
4873
|
+
if (entry.isDirectory()) return entry.name === "node_modules" || entry.name === ".git" ? [] : packageFiles(pkgRoot, path);
|
|
4874
|
+
return entry.isFile() ? [path] : [];
|
|
4875
|
+
});
|
|
4876
|
+
}
|
|
4877
|
+
/** A `*` target pattern as a matcher of package-relative files. Node puts
|
|
4878
|
+
* one subpath into every `*`, so each later `*` repeats the first match. */
|
|
4879
|
+
function targetPattern(target) {
|
|
4880
|
+
const body = posixPath(target).replace(/^\.\//, "").split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).reduce((pattern, part, index) => index === 0 ? part : `${pattern}${index === 1 ? "(.+)" : "\\1"}${part}`);
|
|
4881
|
+
return new RegExp(`^${body}$`);
|
|
4882
|
+
}
|
|
4883
|
+
/**
|
|
4884
|
+
* Why the kit at `pkgRoot` would fail an installed consumer: each `animus`
|
|
4885
|
+
* source target, at any condition depth or as a pattern, and each file its
|
|
4886
|
+
* relative imports reach, must be in the package and among the files `npm
|
|
4887
|
+
* pack` publishes, and each bare package import a declared dependency.
|
|
4888
|
+
* Each line names the file, the import and the cause; none means the
|
|
4889
|
+
* published source is complete. With `artifactDir`, a build's artifact
|
|
4890
|
+
* directory inside the package that `npm pack` would publish is a line too.
|
|
4891
|
+
*/
|
|
4892
|
+
function kitPublicationFailures(pkgRoot, engine, artifactDir) {
|
|
4893
|
+
let manifest;
|
|
4894
|
+
try {
|
|
4895
|
+
manifest = JSON.parse(readFileSync$1(join(pkgRoot, "package.json"), "utf-8"));
|
|
4896
|
+
} catch (error) {
|
|
4897
|
+
return [`package.json: cannot be read: ${String(error)}`];
|
|
4898
|
+
}
|
|
4899
|
+
const { targets, unreadable } = animusTargets(manifest);
|
|
4900
|
+
if (targets.length === 0 && unreadable.length === 0) return [];
|
|
4901
|
+
const { moduleSpecifiers } = engine;
|
|
4902
|
+
if (moduleSpecifiers === void 0) throw new Error("the native engine does not expose moduleSpecifiers, which the kit publication check needs — rebuild @animus-ui/extract");
|
|
4903
|
+
const publication = npmPublishedFiles(pkgRoot);
|
|
4904
|
+
if (publication.kind === "failed") return [`package.json: ${publication.reason}`];
|
|
4905
|
+
const published = (packageRelative) => publication.files.has(packageRelative);
|
|
4906
|
+
const declared = new Set([
|
|
4907
|
+
"dependencies",
|
|
4908
|
+
"peerDependencies",
|
|
4909
|
+
"optionalDependencies"
|
|
4910
|
+
].flatMap((field) => {
|
|
4911
|
+
const block = isJsonBlock(manifest) ? manifest[field] : void 0;
|
|
4912
|
+
return isJsonBlock(block) ? Object.keys(block) : [];
|
|
4913
|
+
}));
|
|
4914
|
+
const ownName = isJsonBlock(manifest) && isJsonString(manifest.name) ? manifest.name : null;
|
|
4915
|
+
const failures = [];
|
|
4916
|
+
const rel = (file) => posixPath(relative(pkgRoot, file));
|
|
4917
|
+
const outside = (relPath) => relPath.startsWith("../") || isAbsolute(relPath);
|
|
4918
|
+
for (const [subpath, value] of unreadable) failures.push(`package.json: exports["${subpath}"] has an "animus" value, ${value}, that is no target path`);
|
|
4919
|
+
const queue = [];
|
|
4920
|
+
const admit = (subpath, relPath) => {
|
|
4921
|
+
if (published(relPath)) queue.push(resolve(pkgRoot, relPath));
|
|
4922
|
+
else failures.push(`package.json: the "animus" target of exports["${subpath}"], ${relPath}, is not in the published files`);
|
|
4923
|
+
};
|
|
4924
|
+
let files = null;
|
|
4925
|
+
for (const [subpath, target] of targets) {
|
|
4926
|
+
const relPath = rel(resolve(pkgRoot, target));
|
|
4927
|
+
if (outside(relPath)) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, is outside the package`);
|
|
4928
|
+
else if (target.includes("*")) {
|
|
4929
|
+
files ??= packageFiles(pkgRoot);
|
|
4930
|
+
const pattern = targetPattern(target);
|
|
4931
|
+
const matched = files.filter((file) => pattern.test(file));
|
|
4932
|
+
if (matched.length === 0) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, matches no file in the package`);
|
|
4933
|
+
for (const file of matched) admit(subpath, file);
|
|
4934
|
+
} else if (!isFile(resolve(pkgRoot, target))) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, does not exist in the package`);
|
|
4935
|
+
else admit(subpath, relPath);
|
|
4936
|
+
}
|
|
4937
|
+
const visited = /* @__PURE__ */ new Set();
|
|
4938
|
+
while (queue.length > 0) {
|
|
4939
|
+
const file = queue.shift();
|
|
4940
|
+
if (visited.has(file)) continue;
|
|
4941
|
+
visited.add(file);
|
|
4942
|
+
const specifiers = parseInternalWire(moduleSpecifiers(JSON.stringify([{
|
|
4943
|
+
path: file,
|
|
4944
|
+
source: readFileSync$1(file, "utf-8")
|
|
4945
|
+
}])), "moduleSpecifiers").files[file] ?? [];
|
|
4946
|
+
for (const specifier of specifiers) {
|
|
4947
|
+
if (specifier.startsWith(".")) {
|
|
4948
|
+
const target = relativeSourceCandidates(file, specifier).find(isFile);
|
|
4949
|
+
if (target === void 0) failures.push(`${rel(file)}: import '${specifier}' resolves to no file in the package`);
|
|
4950
|
+
else if (outside(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, outside the package`);
|
|
4951
|
+
else if (!published(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, which is not in the published files`);
|
|
4952
|
+
else if (CODE_EXTENSIONS.has(extname(target))) queue.push(target);
|
|
4953
|
+
continue;
|
|
4954
|
+
}
|
|
4955
|
+
if (specifier.startsWith("/") || /^[a-z][\w+.-]*:/i.test(specifier)) {
|
|
4956
|
+
if (!isBuiltin(specifier)) failures.push(`${rel(file)}: import '${specifier}' is not a package or relative import, so an installed consumer cannot resolve it`);
|
|
4957
|
+
continue;
|
|
4958
|
+
}
|
|
4959
|
+
const name = bareSpecifierPackageName(specifier);
|
|
4960
|
+
if (isBuiltin(name) || name === ownName || declared.has(name)) continue;
|
|
4961
|
+
failures.push(`${rel(file)}: import '${specifier}' names the package ${name}, which package.json does not declare in dependencies, peerDependencies or optionalDependencies`);
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
const artifacts = artifactDir === void 0 ? "" : rel(artifactDir);
|
|
4965
|
+
if (artifacts !== "" && !outside(artifacts)) {
|
|
4966
|
+
const shipped = [...publication.files].filter((file) => file.startsWith(`${artifacts}/`));
|
|
4967
|
+
if (shipped.length > 0) failures.push(`${artifacts}/: npm pack would publish this build-artifact directory (${shipped.length} files) — add "${artifacts}/" to .npmignore or .gitignore, or list the published files in package.json "files"`);
|
|
4968
|
+
}
|
|
4969
|
+
return failures;
|
|
4970
|
+
}
|
|
4971
|
+
//#endregion
|
|
4299
4972
|
//#region pipeline/replacement-plans.ts
|
|
4300
4973
|
const snapshotByManifest = /* @__PURE__ */ new WeakMap();
|
|
4301
4974
|
/** `null` (a context before its first analysis) snapshots to the empty plan
|
|
@@ -4372,4 +5045,4 @@ function realpathThroughNearestExistingAncestor(path) {
|
|
|
4372
5045
|
}
|
|
4373
5046
|
}
|
|
4374
5047
|
//#endregion
|
|
4375
|
-
export {
|
|
5048
|
+
export { discoverFiles as $, fileSideEffects as A, surfaceManifestDiagnostics as At, unresolvableIncludesMessage as B, substituteSheetAssets as Bt, resolveAssetFile as C, DiagnosticFailure as Ct, engineModuleParser as D, isDeletedSource as Dt, collectExternalPackageSources as E, VOCABULARY_LEGACY_VERB as Et, keepsKitSourceEffects as F, findAssetSpecifiers as Ft, KIT_DESCRIPTOR_FILE as G, assembleStylesheet as Gt, createSourceIdentity as H, contentHash as Ht, kitSourceModuleSideEffects as I, findSheetAssetSpecifiers as It, readKitDescriptor as J, __require as Jt, buildKitDescriptor as K, stripLeadingLayerDeclaration as Kt, resolveAbsolutePathSpecifier as L, generatedModuleCode as Lt, firstOwners as M, unreadableSourceDiagnostic as Mt, importedKitDiagnostics as N, unresolvedParentName as Nt, excludeCollectedPackages as O, isUnresolvedParentDrop as Ot, isExcludedPackageRelativePath as P, vocabularyWitnessDiagnostics as Pt, compareDiscoveryOrder as Q, sourceKitDependencies as R, reportSurvivingAssetPlaceholders as Rt, enforceExternalTokenContracts as S, DIAGNOSTIC_LEVELS as St, createSourceCorpus as T, VOCABULARY_COLLISION as Tt, isPathWithinRoot as U, buildAnalyzeProjectArgs as Ut, walkPackageSources as V, parseInternalWire as Vt, sharesVolumeRoot as W, ANIMUS_LAYERS as Wt, isJsonString as X, isJsonBlock as Y, readTsconfigAliasPairs as Z, runProjectAnalysis as _, adaptSvelteSource as _t, kitPublicationFailures as a, STRUCTURAL_EXCLUDE as at, resolveLightningTargets as b, isEngineTransformExtension as bt, buildDynamicPropConfig as c, resolveMode as ct, applyPrefix as d, assertNoRetiredEngineSelection as dt, AnimusConfigError as et, serializeStaticCss as f, createV2EngineApi as ft, clearEngineCache as g, projectExternalFileOwners as gt, buildAnalysisInputs as h, parseFilesJson as ht, snapshotFilePlans as i, REPLACEABLE_DEFAULT_EXCLUDE as it, findPackageRoot as j, systemLoadDiagnostics as jt, extractSystemFilePackages as k, noKitFilesDiagnostics as kt, runStructuralSelfCheck as l, resolveVerbosity as lt, stableStringify as m, isAdvisorySourceDiagnostic as mt, diffFilePlans as n, DEFAULT_EXCLUDE as nt, assertNoErrorDiagnostics as o, assertKnownOptionKeys as ot, camelToKebab as p, ingestSourceEntries as pt, kitDescriptorDiagnostics as q, validateLayerOrder as qt, hashReplacementPlans as r, DRIVER_NAMESPACES as rt, buildSystemPropsModule as s, createExcludeMatcher as st, toWatchKeys as t, CORE_OPTION_KEYS as tt, loadSystemConfig as u, RETIRED_ENGINE_MESSAGE as ut, applyUnitFallback as v, DEFAULT_EXTENSIONS as vt, resolveThroughPathAliases as w, INVALID_PROPERTY_REGISTRATION as wt, buildPathAliasesJson as x, preprocessMdx as xt, postProcessCss as y, ENGINE_TRANSFORM_EXTENSIONS as yt, staleDistIncludesMessage as z, substituteAssetPlaceholders as zt };
|