@animus-ui/extract 0.1.23 → 0.1.25
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 +22 -3
- package/dist/index.cjs +11 -1
- package/dist/index.mjs +2 -2
- package/dist/pipeline/analyze-project-args.d.ts +9 -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-B3JzXiSY.cjs → pipeline-DOgKR4VZ.cjs} +1066 -302
- package/dist/{pipeline-kA3VEMgt.mjs → pipeline-YGWpNr_Z.mjs} +1024 -321
- 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
|
@@ -31,6 +31,8 @@ let browserslist = require("browserslist");
|
|
|
31
31
|
browserslist = __toESM(browserslist);
|
|
32
32
|
let lightningcss = require("lightningcss");
|
|
33
33
|
let _animus_ui_properties = require("@animus-ui/properties");
|
|
34
|
+
let node_child_process = require("node:child_process");
|
|
35
|
+
let node_module = require("node:module");
|
|
34
36
|
//#region pipeline/assemble-stylesheet.ts
|
|
35
37
|
/**
|
|
36
38
|
* The cascade layer order, outermost first: its one definition. The engine
|
|
@@ -110,8 +112,14 @@ function buildAnalyzeProjectArgs(inputs) {
|
|
|
110
112
|
inputs.transformSourcesJson,
|
|
111
113
|
inputs.transformProvenanceJson ?? null
|
|
112
114
|
];
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
const tail = [
|
|
116
|
+
inputs.declarationScalesJson,
|
|
117
|
+
inputs.analysisContextJson,
|
|
118
|
+
inputs.generatedNamesJson,
|
|
119
|
+
inputs.propertyRecordsJson
|
|
120
|
+
];
|
|
121
|
+
const last = tail.findLastIndex((slot) => slot !== void 0 && slot !== "");
|
|
122
|
+
for (const slot of tail.slice(0, last + 1)) args.push(slot || void 0);
|
|
115
123
|
return args;
|
|
116
124
|
}
|
|
117
125
|
//#endregion
|
|
@@ -257,13 +265,17 @@ function substituteSheetAssets(sheets, urlBySpecifier) {
|
|
|
257
265
|
}
|
|
258
266
|
const UNSUBSTITUTED_ASSET_CODE = "animus.asset.unsubstituted-placeholder";
|
|
259
267
|
/** A placeholder in emitted CSS is a broken URL in the browser: it fails a
|
|
260
|
-
* strict build and warns otherwise. */
|
|
268
|
+
* strict build, strict development reports it, and it warns otherwise. */
|
|
261
269
|
function reportSurvivingAssetPlaceholders(css, report) {
|
|
262
270
|
const specifiers = placeholdersInAssetCalls(css);
|
|
263
271
|
if (specifiers.length === 0) return;
|
|
264
272
|
const message = `${report.prefix} asset() placeholders reached ${report.surface ?? "emitted CSS"} unsubstituted: ${specifiers.join(", ")} (${UNSUBSTITUTED_ASSET_CODE})`;
|
|
265
|
-
if (report.strict)
|
|
266
|
-
|
|
273
|
+
if (!report.strict) {
|
|
274
|
+
report.warn(message);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (!report.reportErrors) throw new Error(message);
|
|
278
|
+
report.reportErrors(message);
|
|
267
279
|
}
|
|
268
280
|
/**
|
|
269
281
|
* The runtime code an analysis generates: each dynamic prop config, which the
|
|
@@ -292,6 +304,15 @@ function locatedPrefix(diagnostic) {
|
|
|
292
304
|
function droppedSuffix(diagnostic) {
|
|
293
305
|
return diagnostic.dropped && !diagnostic.message.includes(diagnostic.dropped) ? ` — dropped: ${diagnostic.dropped}` : "";
|
|
294
306
|
}
|
|
307
|
+
/** The record's code, when its message does not already quote it. */
|
|
308
|
+
function codeSuffix(diagnostic) {
|
|
309
|
+
return diagnostic.code && !diagnostic.message.includes(diagnostic.code) ? ` [${diagnostic.code}]` : "";
|
|
310
|
+
}
|
|
311
|
+
/** A warn-kind record's line after its mark:
|
|
312
|
+
* `file:line:column: component: message [code]`. */
|
|
313
|
+
function warnLine(diagnostic) {
|
|
314
|
+
return `${locationOf(diagnostic)}: ${diagnostic.component}: ${diagnostic.message}${droppedSuffix(diagnostic)}${codeSuffix(diagnostic)}`;
|
|
315
|
+
}
|
|
295
316
|
/** Stable code for selector forms with no substitutable subject; the
|
|
296
317
|
* extraction engine mints the same string. */
|
|
297
318
|
const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
@@ -310,10 +331,19 @@ const DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set([
|
|
|
310
331
|
"warn",
|
|
311
332
|
"error"
|
|
312
333
|
]);
|
|
334
|
+
/** A key that selects every record of a kind: `kind:bail`, `kind:skip`,
|
|
335
|
+
* `kind:warn` or `kind:error`. */
|
|
336
|
+
const KIND_KEY = "kind:";
|
|
337
|
+
const DIAGNOSTIC_KINDS = /* @__PURE__ */ new Set([
|
|
338
|
+
"bail",
|
|
339
|
+
"skip",
|
|
340
|
+
"warn",
|
|
341
|
+
"error"
|
|
342
|
+
]);
|
|
313
343
|
/** The level `levels` sets for `code`: its exact entry, else the entry of
|
|
314
344
|
* the longest prefix it starts with. */
|
|
315
|
-
function
|
|
316
|
-
if (code === void 0
|
|
345
|
+
function codeLevel(code, levels) {
|
|
346
|
+
if (code === void 0) return void 0;
|
|
317
347
|
if (Object.hasOwn(levels, code)) return levels[code];
|
|
318
348
|
let longest;
|
|
319
349
|
for (const [key, level] of Object.entries(levels)) {
|
|
@@ -326,11 +356,19 @@ function levelFor(code, levels) {
|
|
|
326
356
|
}
|
|
327
357
|
return longest?.level;
|
|
328
358
|
}
|
|
359
|
+
/** The level `levels` sets for a record: its code's level, else its kind's. */
|
|
360
|
+
function levelFor({ code, kind }, levels) {
|
|
361
|
+
if (levels === void 0) return void 0;
|
|
362
|
+
const kindKey = `${KIND_KEY}${kind}`;
|
|
363
|
+
return codeLevel(code, levels) ?? (Object.hasOwn(levels, kindKey) ? levels[kindKey] : void 0);
|
|
364
|
+
}
|
|
329
365
|
/** The level a record prints at: the option's entry for its code, else
|
|
330
|
-
* `error` for
|
|
366
|
+
* `error` for a hard error (an `error`-kind record) or an error-severity
|
|
367
|
+
* record under `strict`, else its own. */
|
|
331
368
|
function effectiveLevel(diagnostic, policy) {
|
|
332
|
-
const level = levelFor(diagnostic
|
|
369
|
+
const level = levelFor(diagnostic, policy.levels);
|
|
333
370
|
if (level !== void 0) return level;
|
|
371
|
+
if (diagnostic.kind === "error") return "error";
|
|
334
372
|
if (diagnostic.severity === "info") return "info";
|
|
335
373
|
return policy.strict && diagnostic.severity === "error" ? "error" : "warn";
|
|
336
374
|
}
|
|
@@ -349,6 +387,7 @@ function knownDiagnosticCodes(engineCodesJson) {
|
|
|
349
387
|
/** The keys of `levels` that name no known code, exactly or as a prefix. */
|
|
350
388
|
function unknownDiagnosticKeys(levels, known) {
|
|
351
389
|
return Object.keys(levels).filter((key) => {
|
|
390
|
+
if (key.startsWith(KIND_KEY)) return !DIAGNOSTIC_KINDS.has(key.slice(5));
|
|
352
391
|
if (!key.endsWith(".*")) return !known.has(key);
|
|
353
392
|
const prefix = key.slice(0, -1);
|
|
354
393
|
return ![...known].some((code) => code.startsWith(prefix));
|
|
@@ -403,9 +442,22 @@ function collectSelectorAliasDiagnostics(selectorAliasesJson) {
|
|
|
403
442
|
const UNREADABLE_SOURCE_FILE = "animus.ingestion.unreadable-source-file";
|
|
404
443
|
/** A kit the system extends resolved, yet discovery found none of its files. */
|
|
405
444
|
const NO_KIT_FILES = "animus.discovery.no-kit-files";
|
|
445
|
+
/** A kit with no `animus` export condition whose exports do not all target
|
|
446
|
+
* TypeScript source: discovery guesses its source from `src/`. */
|
|
447
|
+
const KIT_WITHOUT_SOURCE_CONDITION = "animus.discovery.kit-without-source-condition";
|
|
448
|
+
/** A kit's `animus` export condition names a file that is missing or outside
|
|
449
|
+
* its package, so that entry is not read from source. */
|
|
450
|
+
const INVALID_KIT_SOURCE_CONDITION = "animus.discovery.invalid-source-condition";
|
|
451
|
+
/** A kit the application imports whose system the application's system
|
|
452
|
+
* does not include: its components are not extracted. */
|
|
453
|
+
const KIT_SYSTEM_NOT_INCLUDED = "animus.kit.system-not-included";
|
|
406
454
|
/** A system file's `createSystem` binding that discovery could not follow to
|
|
407
455
|
* Animus's factory, so it is no root. */
|
|
408
456
|
const UNPROVEN_ROOT_BINDING = "animus.discovery.unproven-root-binding";
|
|
457
|
+
/** A system file calls `createSystem` with no import or local binding. The
|
|
458
|
+
* system loader evaluates the file without auto-imports, where the name is
|
|
459
|
+
* undefined, so the call is no root. */
|
|
460
|
+
const UNIMPORTED_CREATE_SYSTEM = "animus.discovery.unimported-create-system";
|
|
409
461
|
/** What a skipped source file costs: the analysis never sees what it
|
|
410
462
|
* renders. */
|
|
411
463
|
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";
|
|
@@ -441,6 +493,11 @@ function noKitFilesDiagnostics(outcomes) {
|
|
|
441
493
|
severity: severityFor(NO_KIT_FILES)
|
|
442
494
|
}));
|
|
443
495
|
}
|
|
496
|
+
/** A kit's descriptor declares a format this Animus does not read. */
|
|
497
|
+
const KIT_UNSUPPORTED_FORMAT = "animus.kit.unsupported-format";
|
|
498
|
+
/** A kit's descriptor records a definition its shipped source no longer
|
|
499
|
+
* declares. */
|
|
500
|
+
const KIT_STALE_DESCRIPTOR = "animus.kit.stale-descriptor";
|
|
444
501
|
/** The collision entry code minted by the system package's merge. */
|
|
445
502
|
const VOCABULARY_COLLISION = "animus.vocabulary.collision";
|
|
446
503
|
/** A theme `@property` registration browsers would ignore; it is not emitted. */
|
|
@@ -466,9 +523,6 @@ const PROPERTY_FALLBACK_SELF_REFERENCE = "animus.property.fallback-self-referenc
|
|
|
466
523
|
* another directly, so every property in the cycle is invalid at
|
|
467
524
|
* computed-value time. */
|
|
468
525
|
const PROPERTY_CURRENT_VAR_CYCLE = "animus.property.current-var-cycle";
|
|
469
|
-
/** A prefix renamed contextual variables without `prefixContextualVars`, so
|
|
470
|
-
* their declared names no longer resolve. */
|
|
471
|
-
const PREFIX_CONTEXTUAL_VARS_UNPREFIXED = "animus.prefix.contextual-vars-unprefixed";
|
|
472
526
|
/** Under `prefixContextualVars`, a final name that collides with a runtime
|
|
473
527
|
* transport variable or a theme variable of the same spelling. */
|
|
474
528
|
const PREFIX_NAME_CONFLICT = "animus.prefix.name-conflict";
|
|
@@ -482,7 +536,13 @@ const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
|
|
|
482
536
|
[SELECTOR_UNSUPPORTED_SUBJECT, "error"],
|
|
483
537
|
[UNREADABLE_SOURCE_FILE, "error"],
|
|
484
538
|
[NO_KIT_FILES, "warn"],
|
|
539
|
+
[KIT_WITHOUT_SOURCE_CONDITION, "warn"],
|
|
540
|
+
[INVALID_KIT_SOURCE_CONDITION, "error"],
|
|
541
|
+
[KIT_SYSTEM_NOT_INCLUDED, "error"],
|
|
542
|
+
[KIT_UNSUPPORTED_FORMAT, "error"],
|
|
543
|
+
[KIT_STALE_DESCRIPTOR, "warn"],
|
|
485
544
|
[UNPROVEN_ROOT_BINDING, "warn"],
|
|
545
|
+
[UNIMPORTED_CREATE_SYSTEM, "warn"],
|
|
486
546
|
[VOCABULARY_COLLISION, "warn"],
|
|
487
547
|
[VOCABULARY_LEGACY_VERB, "warn"],
|
|
488
548
|
[INVALID_PROPERTY_REGISTRATION, "error"],
|
|
@@ -492,7 +552,6 @@ const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
|
|
|
492
552
|
[PROPERTY_SELF_REFERENCE, "warn"],
|
|
493
553
|
[PROPERTY_FALLBACK_SELF_REFERENCE, "warn"],
|
|
494
554
|
[PROPERTY_CURRENT_VAR_CYCLE, "warn"],
|
|
495
|
-
[PREFIX_CONTEXTUAL_VARS_UNPREFIXED, "warn"],
|
|
496
555
|
[PREFIX_NAME_CONFLICT, "error"],
|
|
497
556
|
[PROPERTY_LEGACY_TOKEN_COLLISION, "warn"],
|
|
498
557
|
[PROPERTY_TOKEN_COLLISION, "error"]
|
|
@@ -547,15 +606,6 @@ function systemLoadDiagnostics(system) {
|
|
|
547
606
|
code: INVALID_PROPERTY_REGISTRATION,
|
|
548
607
|
severity: severityFor(INVALID_PROPERTY_REGISTRATION)
|
|
549
608
|
}));
|
|
550
|
-
const prefixed = system.legacyPrefixedContextualVars ?? [];
|
|
551
|
-
const unprefixed = prefixed.length === 0 ? [] : [{
|
|
552
|
-
file: "system",
|
|
553
|
-
component: "prefix",
|
|
554
|
-
kind: "warn",
|
|
555
|
-
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})`,
|
|
556
|
-
code: PREFIX_CONTEXTUAL_VARS_UNPREFIXED,
|
|
557
|
-
severity: severityFor(PREFIX_CONTEXTUAL_VARS_UNPREFIXED)
|
|
558
|
-
}];
|
|
559
609
|
const conflicts = (system.prefixNameConflicts ?? []).map(({ name, final, reason }) => ({
|
|
560
610
|
file: "system",
|
|
561
611
|
component: `--${name}`,
|
|
@@ -567,7 +617,6 @@ function systemLoadDiagnostics(system) {
|
|
|
567
617
|
return [
|
|
568
618
|
...vocabularyWitnessDiagnostics(system.vocabularyWitnessesJson),
|
|
569
619
|
...registrations,
|
|
570
|
-
...unprefixed,
|
|
571
620
|
...conflicts,
|
|
572
621
|
...tokenCollisionDiagnostics(system)
|
|
573
622
|
];
|
|
@@ -603,13 +652,14 @@ function tokenCollisionDiagnostics(system) {
|
|
|
603
652
|
}
|
|
604
653
|
/**
|
|
605
654
|
* The single strict-escalation policy point for both extraction plugins:
|
|
606
|
-
* error-severity diagnostics throw together under `strict`, else warn.
|
|
655
|
+
* error-severity diagnostics throw together under `strict`, else warn. A
|
|
656
|
+
* development session reports them through `reportErrors` instead.
|
|
607
657
|
*/
|
|
608
658
|
function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
609
|
-
const errors =
|
|
659
|
+
const errors = /* @__PURE__ */ new Set();
|
|
610
660
|
if (policy.levels && policy.knownCodes && !checkedLevels.has(policy.levels)) {
|
|
611
661
|
checkedLevels.add(policy.levels);
|
|
612
|
-
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)`);
|
|
662
|
+
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)`);
|
|
613
663
|
}
|
|
614
664
|
const diagnostics = policy.prepend?.length ? [...policy.prepend, ...manifest.diagnostics ?? []] : manifest.diagnostics ?? [];
|
|
615
665
|
for (const diagnostic of diagnostics) {
|
|
@@ -618,22 +668,28 @@ function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
|
618
668
|
let line = null;
|
|
619
669
|
const mark = level === "info" ? "ℹ" : "⚠";
|
|
620
670
|
const message = `${diagnostic.message}${droppedSuffix(diagnostic)}`;
|
|
621
|
-
if (diagnostic.kind === "bail") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component} not extracted: ${message}`;
|
|
622
|
-
else if (diagnostic.kind === "skip") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component}: skipped ${message}`;
|
|
623
|
-
else if (diagnostic.kind === "warn") line = `${mark} ${
|
|
671
|
+
if (diagnostic.kind === "bail") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component} not extracted: ${message}${codeSuffix(diagnostic)}`;
|
|
672
|
+
else if (diagnostic.kind === "skip") line = `${mark} ${locatedPrefix(diagnostic)}${diagnostic.component}: skipped ${message}${codeSuffix(diagnostic)}`;
|
|
673
|
+
else if (diagnostic.kind === "warn" || diagnostic.kind === "error") line = `${mark} ${warnLine(diagnostic)}`;
|
|
624
674
|
if (line === null) continue;
|
|
625
|
-
if (diagnostic.code && !diagnostic.message.includes(diagnostic.code)) line += ` [${diagnostic.code}]`;
|
|
626
675
|
if (level === "info") {
|
|
627
676
|
policy.info?.(line);
|
|
628
677
|
continue;
|
|
629
678
|
}
|
|
630
679
|
if (level === "error") {
|
|
631
|
-
|
|
680
|
+
const subject = diagnostic.kind === "warn" || diagnostic.kind === "error" ? `${locationOf(diagnostic)}: ` : locatedPrefix(diagnostic);
|
|
681
|
+
errors.add(`${diagnostic.code ?? "error"} — ${subject}${diagnostic.component}: ${message}`);
|
|
632
682
|
continue;
|
|
633
683
|
}
|
|
634
684
|
warn(line);
|
|
635
685
|
}
|
|
636
|
-
if (errors.
|
|
686
|
+
if (errors.size === 0) return;
|
|
687
|
+
const message = `[animus] strict: ${errors.size} error diagnostic(s):\n${[...errors].join("\n")}`;
|
|
688
|
+
if (policy.reportErrors) {
|
|
689
|
+
policy.reportErrors(message);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
throw new DiagnosticFailure(message);
|
|
637
693
|
}
|
|
638
694
|
//#endregion
|
|
639
695
|
//#region pipeline/mdx-preprocessor.ts
|
|
@@ -1600,7 +1656,8 @@ function createSourceIngestor(host) {
|
|
|
1600
1656
|
const fatal = diagnostics.filter((diagnostic) => !isAdvisorySourceDiagnostic(diagnostic));
|
|
1601
1657
|
const invalidOriginals = new Set(fatal.map((diagnostic) => diagnostic.originalPath));
|
|
1602
1658
|
if (diagnostics.length === 0) return invalidOriginals;
|
|
1603
|
-
|
|
1659
|
+
const reportError = host.strict() ? host.reportErrors?.() : void 0;
|
|
1660
|
+
if (host.strict() && fatal.length > 0 && !reportError) {
|
|
1604
1661
|
const lines = fatal.map((diagnostic) => `${diagnostic.code} ${diagnostic.originalPath}: ${diagnostic.message} (${SKIPPED_SOURCE_COST})`);
|
|
1605
1662
|
throw new Error(`${host.prefix} ${lines.join(`\n${host.prefix} `)}`);
|
|
1606
1663
|
}
|
|
@@ -1614,7 +1671,8 @@ function createSourceIngestor(host) {
|
|
|
1614
1671
|
}
|
|
1615
1672
|
if (warned.has(line)) continue;
|
|
1616
1673
|
warned.add(line);
|
|
1617
|
-
|
|
1674
|
+
if (reportError && skipped) reportError(`${host.prefix} ${line}`);
|
|
1675
|
+
else host.warn(`${host.prefix} ${line}`);
|
|
1618
1676
|
}
|
|
1619
1677
|
return invalidOriginals;
|
|
1620
1678
|
},
|
|
@@ -1641,8 +1699,9 @@ function createV2EngineApi(deps) {
|
|
|
1641
1699
|
return {
|
|
1642
1700
|
loadSystemModule: (...args) => native.loadSystemModule(...args),
|
|
1643
1701
|
extractFacts: (filesJson) => native.extractFacts(filesJson),
|
|
1702
|
+
moduleSpecifiers: (filesJson) => native.moduleSpecifiers(filesJson),
|
|
1644
1703
|
diagnosticCodes: () => native.diagnosticCodes(),
|
|
1645
|
-
analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson, transformSourcesJson, transformProvenanceJson, declarationScalesJson, analysisContextJson) => {
|
|
1704
|
+
analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson, transformSourcesJson, transformProvenanceJson, declarationScalesJson, analysisContextJson, generatedNamesJson, propertyRecordsJson) => {
|
|
1646
1705
|
const filesJson = deps.rehydrateFilesJson ? deps.rehydrateFilesJson(filesJsonRaw) : filesJsonRaw;
|
|
1647
1706
|
const sent = /* @__PURE__ */ new Map();
|
|
1648
1707
|
for (const entry of parseFilesJson(filesJson, label)) sent.set(entry.path, entry.source);
|
|
@@ -1670,6 +1729,8 @@ function createV2EngineApi(deps) {
|
|
|
1670
1729
|
transformProvenanceJson: transformProvenanceJson ?? void 0,
|
|
1671
1730
|
declarationScalesJson,
|
|
1672
1731
|
analysisContextJson,
|
|
1732
|
+
generatedNamesJson,
|
|
1733
|
+
propertyRecordsJson,
|
|
1673
1734
|
devMode
|
|
1674
1735
|
};
|
|
1675
1736
|
const engine = new native.ExtractEngine(config);
|
|
@@ -2005,114 +2066,6 @@ function walkFiles(dir, rootDir, exclude, extensionsSet) {
|
|
|
2005
2066
|
return results;
|
|
2006
2067
|
}
|
|
2007
2068
|
//#endregion
|
|
2008
|
-
//#region pipeline/source-identity.ts
|
|
2009
|
-
/**
|
|
2010
|
-
* One derivation of source identity for discovery, watch ingestion, ownership
|
|
2011
|
-
* and deletion: event paths are lookup INPUTS only and never fork identity.
|
|
2012
|
-
*/
|
|
2013
|
-
/**
|
|
2014
|
-
* True when `target` is `root` or a descendant, decided by `relative()`
|
|
2015
|
-
* shape: string prefixing would let `/ui` claim `/ui-old`.
|
|
2016
|
-
*/
|
|
2017
|
-
function isPathWithinRoot(root, target, pathApi = node_path.default) {
|
|
2018
|
-
const rel = pathApi.relative(root, target);
|
|
2019
|
-
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
2020
|
-
}
|
|
2021
|
-
/**
|
|
2022
|
-
* True when two paths share a platform root (win32 drive letter or UNC
|
|
2023
|
-
* share; always true on posix). Drive letters compare case-insensitively.
|
|
2024
|
-
*/
|
|
2025
|
-
function sharesVolumeRoot(a, b, pathApi = node_path.default) {
|
|
2026
|
-
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
2027
|
-
return volumeOf(a) === volumeOf(b);
|
|
2028
|
-
}
|
|
2029
|
-
function canonicalize(p) {
|
|
2030
|
-
try {
|
|
2031
|
-
return (0, node_fs.realpathSync)(p);
|
|
2032
|
-
} catch {
|
|
2033
|
-
return null;
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
function createSourceIdentity(rootDir) {
|
|
2037
|
-
const normalizedRootDir = node_path.default.normalize(rootDir);
|
|
2038
|
-
const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
|
|
2039
|
-
const roots = [];
|
|
2040
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
2041
|
-
const owningRecord = (canonicalPath) => {
|
|
2042
|
-
let owner = null;
|
|
2043
|
-
for (const record of roots) {
|
|
2044
|
-
if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
|
|
2045
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2046
|
-
}
|
|
2047
|
-
return owner;
|
|
2048
|
-
};
|
|
2049
|
-
return {
|
|
2050
|
-
rootDir: normalizedRootDir,
|
|
2051
|
-
canonicalRootDir,
|
|
2052
|
-
registerExternalRoot(root) {
|
|
2053
|
-
const asRegistered = node_path.default.normalize(root);
|
|
2054
|
-
const canonical = canonicalize(asRegistered) ?? asRegistered;
|
|
2055
|
-
const existing = roots.find((record) => record.canonical === canonical);
|
|
2056
|
-
if (existing) return existing.canonical;
|
|
2057
|
-
roots.push({
|
|
2058
|
-
asRegistered,
|
|
2059
|
-
canonical
|
|
2060
|
-
});
|
|
2061
|
-
return canonical;
|
|
2062
|
-
},
|
|
2063
|
-
externalRoots() {
|
|
2064
|
-
return roots.map((record) => record.canonical);
|
|
2065
|
-
},
|
|
2066
|
-
resolveSourceId(inputPath) {
|
|
2067
|
-
const lexical = node_path.default.normalize(inputPath);
|
|
2068
|
-
const canonical = canonicalize(lexical);
|
|
2069
|
-
if (canonical === null) return null;
|
|
2070
|
-
const owner = owningRecord(canonical);
|
|
2071
|
-
const ownedBy = (record) => {
|
|
2072
|
-
const pathInRoot = node_path.default.relative(record.canonical, canonical);
|
|
2073
|
-
return {
|
|
2074
|
-
sourceKey: node_path.default.relative(normalizedRootDir, node_path.default.join(record.asRegistered, pathInRoot)),
|
|
2075
|
-
owningRoot: record.canonical,
|
|
2076
|
-
pathInRoot
|
|
2077
|
-
};
|
|
2078
|
-
};
|
|
2079
|
-
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
2080
|
-
let resolved;
|
|
2081
|
-
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
2082
|
-
const key = node_path.default.relative(canonicalRootDir, canonical);
|
|
2083
|
-
resolved = {
|
|
2084
|
-
sourceKey: key,
|
|
2085
|
-
owningRoot: null,
|
|
2086
|
-
pathInRoot: key
|
|
2087
|
-
};
|
|
2088
|
-
} else if (owner) resolved = ownedBy(owner);
|
|
2089
|
-
else return null;
|
|
2090
|
-
aliases.set(lexical, resolved);
|
|
2091
|
-
aliases.set(canonical, resolved);
|
|
2092
|
-
return resolved;
|
|
2093
|
-
},
|
|
2094
|
-
resolveDeletedSourceId(inputPath) {
|
|
2095
|
-
return aliases.get(node_path.default.normalize(inputPath)) ?? null;
|
|
2096
|
-
},
|
|
2097
|
-
containingExternalRoot(inputPath) {
|
|
2098
|
-
const lexical = node_path.default.normalize(inputPath);
|
|
2099
|
-
let owner = null;
|
|
2100
|
-
for (const record of roots) {
|
|
2101
|
-
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
2102
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2103
|
-
}
|
|
2104
|
-
if (owner) return owner.canonical;
|
|
2105
|
-
const canonical = canonicalize(lexical);
|
|
2106
|
-
if (canonical === null) return null;
|
|
2107
|
-
for (const record of roots) {
|
|
2108
|
-
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
2109
|
-
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2110
|
-
}
|
|
2111
|
-
return owner?.canonical ?? null;
|
|
2112
|
-
}
|
|
2113
|
-
};
|
|
2114
|
-
}
|
|
2115
|
-
//#endregion
|
|
2116
2069
|
//#region pipeline/tsconfig-paths.ts
|
|
2117
2070
|
/**
|
|
2118
2071
|
* tsconfig `paths` → alias pairs, for drivers with no live bundler config.
|
|
@@ -2196,10 +2149,10 @@ function decodePaths(value) {
|
|
|
2196
2149
|
function decodeExtends(value) {
|
|
2197
2150
|
return (Array.isArray(value) ? value : [value]).filter(isJsonString);
|
|
2198
2151
|
}
|
|
2199
|
-
function readConfig(path$
|
|
2152
|
+
function readConfig(path$8) {
|
|
2200
2153
|
let raw;
|
|
2201
2154
|
try {
|
|
2202
|
-
raw = (0, fs.readFileSync)(path$
|
|
2155
|
+
raw = (0, fs.readFileSync)(path$8, "utf-8");
|
|
2203
2156
|
} catch {
|
|
2204
2157
|
return null;
|
|
2205
2158
|
}
|
|
@@ -2212,7 +2165,7 @@ function readConfig(path$4) {
|
|
|
2212
2165
|
const root = isJsonBlock(parsed) ? parsed : {};
|
|
2213
2166
|
const compilerOptions = isJsonBlock(root.compilerOptions) ? root.compilerOptions : {};
|
|
2214
2167
|
return {
|
|
2215
|
-
dir: (0, path.dirname)(path$
|
|
2168
|
+
dir: (0, path.dirname)(path$8),
|
|
2216
2169
|
baseUrl: isJsonString(compilerOptions.baseUrl) ? compilerOptions.baseUrl : null,
|
|
2217
2170
|
paths: decodePaths(compilerOptions.paths),
|
|
2218
2171
|
extends: decodeExtends(root.extends)
|
|
@@ -2244,8 +2197,8 @@ function loadChain(entryPath) {
|
|
|
2244
2197
|
const visited = /* @__PURE__ */ new Set();
|
|
2245
2198
|
const queue = [entryPath];
|
|
2246
2199
|
while (queue.length > 0) {
|
|
2247
|
-
const path$
|
|
2248
|
-
const key = (0, path.resolve)(path$
|
|
2200
|
+
const path$9 = queue.shift();
|
|
2201
|
+
const key = (0, path.resolve)(path$9);
|
|
2249
2202
|
if (visited.has(key)) continue;
|
|
2250
2203
|
visited.add(key);
|
|
2251
2204
|
const node = readConfig(key);
|
|
@@ -2295,6 +2248,216 @@ function readTsconfigAliasPairs(rootDir) {
|
|
|
2295
2248
|
return pairs;
|
|
2296
2249
|
}
|
|
2297
2250
|
//#endregion
|
|
2251
|
+
//#region pipeline/kit-descriptor.ts
|
|
2252
|
+
/** A kit's description, which `animus build --kit` writes at its package
|
|
2253
|
+
* root and the kit exports as `./animus.json`. */
|
|
2254
|
+
const KIT_DESCRIPTOR_FILE = "animus.json";
|
|
2255
|
+
/** A path with `/` separators, as descriptors key their components. */
|
|
2256
|
+
function posixPath$1(path) {
|
|
2257
|
+
return path.split(node_path.sep).join("/");
|
|
2258
|
+
}
|
|
2259
|
+
/** The descriptor of the kit a build analysed. */
|
|
2260
|
+
function buildKitDescriptor(manifest) {
|
|
2261
|
+
const components = {};
|
|
2262
|
+
for (const id of Object.keys(manifest.components).sort()) {
|
|
2263
|
+
const component = manifest.components[id];
|
|
2264
|
+
components[posixPath$1(id)] = {
|
|
2265
|
+
definition: component.definition_fingerprint,
|
|
2266
|
+
runtimeProps: [...new Set(component.system_prop_names)].sort()
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
return {
|
|
2270
|
+
format: 1,
|
|
2271
|
+
system: manifest.system_fingerprint,
|
|
2272
|
+
components
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
/** Reads the descriptor at a kit's package root; `null` when it has none. */
|
|
2276
|
+
function readKitDescriptor(pkgRoot, rootDir) {
|
|
2277
|
+
const path = (0, node_path.join)(pkgRoot, KIT_DESCRIPTOR_FILE);
|
|
2278
|
+
if (!(0, node_fs.existsSync)(path)) return null;
|
|
2279
|
+
const packageRoot = posixPath$1((0, node_path.relative)(rootDir, pkgRoot));
|
|
2280
|
+
let wire;
|
|
2281
|
+
try {
|
|
2282
|
+
wire = JSON.parse((0, node_fs.readFileSync)(path, "utf-8"));
|
|
2283
|
+
} catch {
|
|
2284
|
+
return {
|
|
2285
|
+
packageRoot,
|
|
2286
|
+
unreadable: "is not valid JSON: rebuild it with animus build --kit"
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
const block = isJsonBlock(wire) ? wire : {};
|
|
2290
|
+
if (block.format !== 1) return {
|
|
2291
|
+
packageRoot,
|
|
2292
|
+
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`
|
|
2293
|
+
};
|
|
2294
|
+
const definitions = {};
|
|
2295
|
+
const components = isJsonBlock(block.components) ? block.components : {};
|
|
2296
|
+
for (const [id, component] of Object.entries(components)) {
|
|
2297
|
+
const definition = isJsonBlock(component) ? component.definition : null;
|
|
2298
|
+
if (isJsonString(definition)) definitions[posixPath$1(id)] = definition;
|
|
2299
|
+
}
|
|
2300
|
+
return {
|
|
2301
|
+
packageRoot,
|
|
2302
|
+
definitions
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
/**
|
|
2306
|
+
* A descriptor in a format this Animus cannot read fails the build; one
|
|
2307
|
+
* whose component definitions differ from the kit's shipped source, as the
|
|
2308
|
+
* analysis read it, or that describes a component its analysed file no
|
|
2309
|
+
* longer declares, was built from other source and is stale.
|
|
2310
|
+
*/
|
|
2311
|
+
function kitDescriptorDiagnostics(records, manifest) {
|
|
2312
|
+
if (records.length === 0) return [];
|
|
2313
|
+
const diagnostics = [];
|
|
2314
|
+
const analysedById = new Map(Object.entries(manifest.components).map(([id, component]) => [posixPath$1(id), component]));
|
|
2315
|
+
const analysedFiles = new Set(Object.keys(manifest.fileFacts).map(posixPath$1));
|
|
2316
|
+
const declared = new Set(Object.entries(manifest.fileFacts).flatMap(([file, facts]) => facts.chains.map((chain) => `${posixPath$1(file)}::${chain.descriptor.binding}`)));
|
|
2317
|
+
for (const record of records) {
|
|
2318
|
+
const file = `${record.packageRoot}/${KIT_DESCRIPTOR_FILE}`;
|
|
2319
|
+
if ("unreadable" in record) {
|
|
2320
|
+
diagnostics.push({
|
|
2321
|
+
file,
|
|
2322
|
+
component: "kit",
|
|
2323
|
+
kind: "error",
|
|
2324
|
+
message: record.unreadable,
|
|
2325
|
+
code: KIT_UNSUPPORTED_FORMAT,
|
|
2326
|
+
severity: severityFor(KIT_UNSUPPORTED_FORMAT)
|
|
2327
|
+
});
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
for (const [id, definition] of Object.entries(record.definitions)) {
|
|
2331
|
+
const key = `${record.packageRoot}/${id}`;
|
|
2332
|
+
const analysed = analysedById.get(key);
|
|
2333
|
+
const fileAnalysed = analysedFiles.has(key.slice(0, key.lastIndexOf("::")));
|
|
2334
|
+
let stale;
|
|
2335
|
+
if (analysed) {
|
|
2336
|
+
if (analysed.definition_fingerprint === definition) continue;
|
|
2337
|
+
stale = `describes ${id} with a definition other than the one its shipped source declares`;
|
|
2338
|
+
} else if (fileAnalysed && !declared.has(key)) stale = `describes ${id}, which its shipped source no longer declares`;
|
|
2339
|
+
else continue;
|
|
2340
|
+
diagnostics.push({
|
|
2341
|
+
file,
|
|
2342
|
+
component: analysed?.binding ?? id.slice(id.lastIndexOf("::") + 2),
|
|
2343
|
+
kind: "warn",
|
|
2344
|
+
message: `${stale}, so the descriptor is stale: rebuild it with animus build --kit`,
|
|
2345
|
+
code: KIT_STALE_DESCRIPTOR,
|
|
2346
|
+
severity: severityFor(KIT_STALE_DESCRIPTOR)
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return diagnostics;
|
|
2351
|
+
}
|
|
2352
|
+
//#endregion
|
|
2353
|
+
//#region pipeline/source-identity.ts
|
|
2354
|
+
/**
|
|
2355
|
+
* One derivation of source identity for discovery, watch ingestion, ownership
|
|
2356
|
+
* and deletion: event paths are lookup INPUTS only and never fork identity.
|
|
2357
|
+
*/
|
|
2358
|
+
/**
|
|
2359
|
+
* True when `target` is `root` or a descendant, decided by `relative()`
|
|
2360
|
+
* shape: string prefixing would let `/ui` claim `/ui-old`.
|
|
2361
|
+
*/
|
|
2362
|
+
function isPathWithinRoot(root, target, pathApi = node_path.default) {
|
|
2363
|
+
const rel = pathApi.relative(root, target);
|
|
2364
|
+
return rel === "" || !pathApi.isAbsolute(rel) && rel !== ".." && !rel.startsWith(".." + pathApi.sep);
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* True when two paths share a platform root (win32 drive letter or UNC
|
|
2368
|
+
* share; always true on posix). Drive letters compare case-insensitively.
|
|
2369
|
+
*/
|
|
2370
|
+
function sharesVolumeRoot(a, b, pathApi = node_path.default) {
|
|
2371
|
+
const volumeOf = (p) => pathApi.parse(pathApi.resolve(p)).root.toLowerCase();
|
|
2372
|
+
return volumeOf(a) === volumeOf(b);
|
|
2373
|
+
}
|
|
2374
|
+
function canonicalize(p) {
|
|
2375
|
+
try {
|
|
2376
|
+
return (0, node_fs.realpathSync)(p);
|
|
2377
|
+
} catch {
|
|
2378
|
+
return null;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
function createSourceIdentity(rootDir) {
|
|
2382
|
+
const normalizedRootDir = node_path.default.normalize(rootDir);
|
|
2383
|
+
const canonicalRootDir = canonicalize(normalizedRootDir) ?? normalizedRootDir;
|
|
2384
|
+
const roots = [];
|
|
2385
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
2386
|
+
const owningRecord = (canonicalPath) => {
|
|
2387
|
+
let owner = null;
|
|
2388
|
+
for (const record of roots) {
|
|
2389
|
+
if (!isPathWithinRoot(record.canonical, canonicalPath)) continue;
|
|
2390
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2391
|
+
}
|
|
2392
|
+
return owner;
|
|
2393
|
+
};
|
|
2394
|
+
return {
|
|
2395
|
+
rootDir: normalizedRootDir,
|
|
2396
|
+
canonicalRootDir,
|
|
2397
|
+
registerExternalRoot(root) {
|
|
2398
|
+
const asRegistered = node_path.default.normalize(root);
|
|
2399
|
+
const canonical = canonicalize(asRegistered) ?? asRegistered;
|
|
2400
|
+
const existing = roots.find((record) => record.canonical === canonical);
|
|
2401
|
+
if (existing) return existing.canonical;
|
|
2402
|
+
roots.push({
|
|
2403
|
+
asRegistered,
|
|
2404
|
+
canonical
|
|
2405
|
+
});
|
|
2406
|
+
return canonical;
|
|
2407
|
+
},
|
|
2408
|
+
externalRoots() {
|
|
2409
|
+
return roots.map((record) => record.canonical);
|
|
2410
|
+
},
|
|
2411
|
+
resolveSourceId(inputPath) {
|
|
2412
|
+
const lexical = node_path.default.normalize(inputPath);
|
|
2413
|
+
const canonical = canonicalize(lexical);
|
|
2414
|
+
if (canonical === null) return null;
|
|
2415
|
+
const owner = owningRecord(canonical);
|
|
2416
|
+
const ownedBy = (record) => {
|
|
2417
|
+
const pathInRoot = node_path.default.relative(record.canonical, canonical);
|
|
2418
|
+
return {
|
|
2419
|
+
sourceKey: node_path.default.relative(normalizedRootDir, node_path.default.join(record.asRegistered, pathInRoot)),
|
|
2420
|
+
owningRoot: record.canonical,
|
|
2421
|
+
pathInRoot
|
|
2422
|
+
};
|
|
2423
|
+
};
|
|
2424
|
+
const ownerIsMoreSpecific = owner !== null && owner.canonical.length > canonicalRootDir.length;
|
|
2425
|
+
let resolved;
|
|
2426
|
+
if (!ownerIsMoreSpecific && isPathWithinRoot(canonicalRootDir, canonical)) {
|
|
2427
|
+
const key = node_path.default.relative(canonicalRootDir, canonical);
|
|
2428
|
+
resolved = {
|
|
2429
|
+
sourceKey: key,
|
|
2430
|
+
owningRoot: null,
|
|
2431
|
+
pathInRoot: key
|
|
2432
|
+
};
|
|
2433
|
+
} else if (owner) resolved = ownedBy(owner);
|
|
2434
|
+
else return null;
|
|
2435
|
+
aliases.set(lexical, resolved);
|
|
2436
|
+
aliases.set(canonical, resolved);
|
|
2437
|
+
return resolved;
|
|
2438
|
+
},
|
|
2439
|
+
resolveDeletedSourceId(inputPath) {
|
|
2440
|
+
return aliases.get(node_path.default.normalize(inputPath)) ?? null;
|
|
2441
|
+
},
|
|
2442
|
+
containingExternalRoot(inputPath) {
|
|
2443
|
+
const lexical = node_path.default.normalize(inputPath);
|
|
2444
|
+
let owner = null;
|
|
2445
|
+
for (const record of roots) {
|
|
2446
|
+
if (!(isPathWithinRoot(record.canonical, lexical) || isPathWithinRoot(record.asRegistered, lexical))) continue;
|
|
2447
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2448
|
+
}
|
|
2449
|
+
if (owner) return owner.canonical;
|
|
2450
|
+
const canonical = canonicalize(lexical);
|
|
2451
|
+
if (canonical === null) return null;
|
|
2452
|
+
for (const record of roots) {
|
|
2453
|
+
if (!isPathWithinRoot(record.canonical, canonical)) continue;
|
|
2454
|
+
if (!owner || record.canonical.length > owner.canonical.length) owner = record;
|
|
2455
|
+
}
|
|
2456
|
+
return owner?.canonical ?? null;
|
|
2457
|
+
}
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
//#endregion
|
|
2298
2461
|
//#region pipeline/discover-packages.ts
|
|
2299
2462
|
function findPackageRoot(absEntryPath) {
|
|
2300
2463
|
let pkgRoot = (0, path.dirname)(absEntryPath);
|
|
@@ -2320,7 +2483,7 @@ const PACKAGE_OUTPUT_EXCLUDES = [
|
|
|
2320
2483
|
".d.ts",
|
|
2321
2484
|
".map"
|
|
2322
2485
|
];
|
|
2323
|
-
const isFile = (path$2) => {
|
|
2486
|
+
const isFile$1 = (path$2) => {
|
|
2324
2487
|
try {
|
|
2325
2488
|
return (0, fs.statSync)(path$2).isFile();
|
|
2326
2489
|
} catch {
|
|
@@ -2332,8 +2495,9 @@ function resolveAbsolutePathSpecifier(absSpecifier, extensionsSet) {
|
|
|
2332
2495
|
absSpecifier,
|
|
2333
2496
|
...Array.from(extensionsSet, (ext) => absSpecifier + ext),
|
|
2334
2497
|
...Array.from(extensionsSet, (ext) => (0, path.join)(absSpecifier, `index${ext}`))
|
|
2335
|
-
].find(isFile) ?? null;
|
|
2498
|
+
].find(isFile$1) ?? null;
|
|
2336
2499
|
}
|
|
2500
|
+
/** The package a bare specifier names: `@scope/name` or `name`. */
|
|
2337
2501
|
function bareSpecifierPackageName(specifier) {
|
|
2338
2502
|
const segments = specifier.split("/");
|
|
2339
2503
|
return specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0];
|
|
@@ -2348,6 +2512,103 @@ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
|
2348
2512
|
const subpath = specifier.slice(packageName.length + 1);
|
|
2349
2513
|
return resolveAbsolutePathSpecifier((0, path.join)(srcDir, subpath || "index"), extensionsSet);
|
|
2350
2514
|
}
|
|
2515
|
+
/** The package's parsed `package.json`, or null when it cannot be read. */
|
|
2516
|
+
function readPackageManifest(pkgRoot) {
|
|
2517
|
+
try {
|
|
2518
|
+
return JSON.parse((0, fs.readFileSync)((0, path.join)(pkgRoot, "package.json"), "utf-8"));
|
|
2519
|
+
} catch {
|
|
2520
|
+
return null;
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
/** Each `exports` subpath and its value; a bare target or condition object
|
|
2524
|
+
* is the `.` entry. */
|
|
2525
|
+
function exportsSubpaths(manifest) {
|
|
2526
|
+
const exports = isJsonBlock(manifest) ? manifest.exports : void 0;
|
|
2527
|
+
if (exports === void 0 || exports === null) return [];
|
|
2528
|
+
const subpaths = isJsonBlock(exports) && Object.keys(exports).some((k) => k.startsWith(".")) ? exports : { ".": exports };
|
|
2529
|
+
return Object.entries(subpaths).filter(([subpath]) => subpath.startsWith("."));
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* The export condition a kit gives each public entry's original source:
|
|
2533
|
+
* `{ "types": …, "animus": "./src/system.ts", "import": …, "default": … }`.
|
|
2534
|
+
* Hosts never resolve through it; discovery reads it, redirects the entry to
|
|
2535
|
+
* its source in every host, and the system loader prefers it.
|
|
2536
|
+
*/
|
|
2537
|
+
const KIT_SOURCE_CONDITION = "animus";
|
|
2538
|
+
/** The package's kit source condition, or null when no exact `exports`
|
|
2539
|
+
* entry declares it: the package is no source kit. */
|
|
2540
|
+
function readKitSourceCondition(pkgRoot) {
|
|
2541
|
+
const condition = {
|
|
2542
|
+
entries: [],
|
|
2543
|
+
invalid: [],
|
|
2544
|
+
root: null
|
|
2545
|
+
};
|
|
2546
|
+
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2547
|
+
if (subpath.includes("*") || !isJsonBlock(value)) continue;
|
|
2548
|
+
const target = value[KIT_SOURCE_CONDITION];
|
|
2549
|
+
if (!isJsonString(target)) continue;
|
|
2550
|
+
const file = (0, path.resolve)(pkgRoot, target);
|
|
2551
|
+
if (isPathWithinRoot(pkgRoot, file) && isFile$1(file)) condition.entries.push([subpath, file]);
|
|
2552
|
+
else condition.invalid.push([subpath, target]);
|
|
2553
|
+
}
|
|
2554
|
+
if (condition.entries.length === 0 && condition.invalid.length === 0) return null;
|
|
2555
|
+
condition.root = sourceRoot(condition.entries);
|
|
2556
|
+
return condition;
|
|
2557
|
+
}
|
|
2558
|
+
/** The deepest directory holding every entry's file. */
|
|
2559
|
+
function sourceRoot(entries) {
|
|
2560
|
+
return entries.reduce((root, [, file]) => root === null ? (0, path.dirname)(file) : commonDirectory(root, (0, path.dirname)(file)), null);
|
|
2561
|
+
}
|
|
2562
|
+
/** A TypeScript source file; compiled output and declarations are not. */
|
|
2563
|
+
const TS_SOURCE = /(?<!\.d)\.[cm]?tsx?$/;
|
|
2564
|
+
/** A kit with no source condition whose every exact `exports` entry already
|
|
2565
|
+
* targets TypeScript source in the package under `import` or `default`:
|
|
2566
|
+
* those targets are its source, as the condition would name them. Null
|
|
2567
|
+
* when any exact entry has no such target, such as one only `require` or
|
|
2568
|
+
* `types` reaches, or there is no exact entry. */
|
|
2569
|
+
function sourceExportsCondition(pkgRoot) {
|
|
2570
|
+
const entries = [];
|
|
2571
|
+
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2572
|
+
if (subpath.includes("*")) continue;
|
|
2573
|
+
const target = exportTarget(value);
|
|
2574
|
+
const file = target === null ? null : (0, path.resolve)(pkgRoot, target);
|
|
2575
|
+
if (file === null || !TS_SOURCE.test(file) || !isPathWithinRoot(pkgRoot, file) || !isFile$1(file)) return null;
|
|
2576
|
+
entries.push([subpath, file]);
|
|
2577
|
+
}
|
|
2578
|
+
if (entries.length === 0) return null;
|
|
2579
|
+
return {
|
|
2580
|
+
entries,
|
|
2581
|
+
invalid: [],
|
|
2582
|
+
root: sourceRoot(entries)
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
function commonDirectory(a, b) {
|
|
2586
|
+
let dir = a;
|
|
2587
|
+
while (!isPathWithinRoot(dir, b)) dir = (0, path.dirname)(dir);
|
|
2588
|
+
return dir;
|
|
2589
|
+
}
|
|
2590
|
+
/** Whether the manifest at `dir` names the package `name`. */
|
|
2591
|
+
function isPackageNamed(dir, name) {
|
|
2592
|
+
const manifest = readPackageManifest(dir);
|
|
2593
|
+
return isJsonBlock(manifest) && manifest.name === name;
|
|
2594
|
+
}
|
|
2595
|
+
function realPath(path$3) {
|
|
2596
|
+
try {
|
|
2597
|
+
return (0, fs.realpathSync)(path$3);
|
|
2598
|
+
} catch {
|
|
2599
|
+
return path$3;
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
/** The root of the installed package `name` as Node finds it from `fromDir`,
|
|
2603
|
+
* the first `node_modules/<name>` up the directory tree, at its real path,
|
|
2604
|
+
* as host resolvers report a linked package. */
|
|
2605
|
+
function locatePackageRoot(name, fromDir) {
|
|
2606
|
+
for (let dir = fromDir;; dir = (0, path.dirname)(dir)) {
|
|
2607
|
+
const candidate = (0, path.join)(dir, "node_modules", name);
|
|
2608
|
+
if ((0, fs.existsSync)((0, path.join)(candidate, "package.json"))) return realPath(candidate);
|
|
2609
|
+
if (dir === (0, path.dirname)(dir)) return null;
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2351
2612
|
/**
|
|
2352
2613
|
* A package's `sideEffects` field, decoded the way Vite reads it: a boolean
|
|
2353
2614
|
* as written, or the list's globs, one with no `/` matching the basename
|
|
@@ -2356,12 +2617,7 @@ function sourceEntryForSpecifier(specifier, srcDir, extensionsSet) {
|
|
|
2356
2617
|
* extglobs), which leaves the bundler's side-effectful default.
|
|
2357
2618
|
*/
|
|
2358
2619
|
function readPackageSideEffects(pkgRoot) {
|
|
2359
|
-
|
|
2360
|
-
try {
|
|
2361
|
-
manifest = JSON.parse((0, fs.readFileSync)((0, path.join)(pkgRoot, "package.json"), "utf-8"));
|
|
2362
|
-
} catch {
|
|
2363
|
-
return;
|
|
2364
|
-
}
|
|
2620
|
+
const manifest = readPackageManifest(pkgRoot);
|
|
2365
2621
|
const field = isJsonBlock(manifest) ? manifest.sideEffects : void 0;
|
|
2366
2622
|
if (field === true || field === false) return field;
|
|
2367
2623
|
if (!Array.isArray(field)) return void 0;
|
|
@@ -2369,6 +2625,77 @@ function readPackageSideEffects(pkgRoot) {
|
|
|
2369
2625
|
if (globs.some((glob) => /[{}[\]()!+@]/.test(glob))) return void 0;
|
|
2370
2626
|
return globs.map((glob) => globToRegExp(glob.includes("/") ? glob.replace(/^\.?\//, "") : `**/${glob}`));
|
|
2371
2627
|
}
|
|
2628
|
+
/** Whether a bundler that reads the nearest `package.json`'s `sideEffects`
|
|
2629
|
+
* against the file's own path keeps `absFile`; undefined without a field
|
|
2630
|
+
* it reads, which keeps the bundler's side-effectful default. */
|
|
2631
|
+
function fileSideEffects(absFile) {
|
|
2632
|
+
const pkgRoot = findPackageRoot(absFile);
|
|
2633
|
+
const field = readPackageSideEffects(pkgRoot);
|
|
2634
|
+
if (field === void 0 || field === true || field === false) return field;
|
|
2635
|
+
return matchesSideEffects(field, pkgRoot, [absFile]);
|
|
2636
|
+
}
|
|
2637
|
+
/** Whether a `sideEffects` glob can name a code file: a last segment with
|
|
2638
|
+
* no extension can name any file, and an extension with glob syntax or of
|
|
2639
|
+
* a script can name code; `*.css` cannot. Brace alternatives are each read,
|
|
2640
|
+
* and braces this reading cannot expand count as naming code. */
|
|
2641
|
+
function globNamesCode(glob) {
|
|
2642
|
+
const alternatives = expandBraces(glob);
|
|
2643
|
+
if (alternatives === null) return true;
|
|
2644
|
+
return alternatives.some((alternative) => {
|
|
2645
|
+
const last = alternative.split("/").at(-1) ?? "";
|
|
2646
|
+
const dot = last.lastIndexOf(".");
|
|
2647
|
+
if (dot === -1) return true;
|
|
2648
|
+
const extension = last.slice(dot + 1);
|
|
2649
|
+
return /[*?[]/.test(extension) || /^[cm]?[jt]sx?$/.test(extension);
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
/** Every alternative a glob's `{a,b}` groups spell, nested groups included;
|
|
2653
|
+
* null when its braces do not balance. */
|
|
2654
|
+
function expandBraces(glob) {
|
|
2655
|
+
const open = glob.indexOf("{");
|
|
2656
|
+
if (open === -1) return glob.includes("}") ? null : [glob];
|
|
2657
|
+
let depth = 0;
|
|
2658
|
+
const commas = [];
|
|
2659
|
+
for (let at = open; at < glob.length; at++) if (glob[at] === "{") depth++;
|
|
2660
|
+
else if (glob[at] === "," && depth === 1) commas.push(at);
|
|
2661
|
+
else if (glob[at] === "}" && --depth === 0) {
|
|
2662
|
+
const bounds = [
|
|
2663
|
+
open,
|
|
2664
|
+
...commas,
|
|
2665
|
+
at
|
|
2666
|
+
];
|
|
2667
|
+
const rest = expandBraces(glob.slice(at + 1));
|
|
2668
|
+
if (rest === null) return null;
|
|
2669
|
+
const expanded = [];
|
|
2670
|
+
for (let i = 0; i < bounds.length - 1; i++) {
|
|
2671
|
+
const inner = expandBraces(glob.slice(bounds[i] + 1, bounds[i + 1]));
|
|
2672
|
+
if (inner === null) return null;
|
|
2673
|
+
for (const middle of inner) for (const tail of rest) expanded.push(glob.slice(0, open) + middle + tail);
|
|
2674
|
+
}
|
|
2675
|
+
return expanded;
|
|
2676
|
+
}
|
|
2677
|
+
return null;
|
|
2678
|
+
}
|
|
2679
|
+
/**
|
|
2680
|
+
* True when a source module of the package that owns `absFile` must stay
|
|
2681
|
+
* side-effectful: its `sideEffects` list names shipped code, and no proven
|
|
2682
|
+
* map takes a shipped file to its source module, so a bundler that reads
|
|
2683
|
+
* the list against the source path can drop a listed effect. Undefined
|
|
2684
|
+
* leaves the bundler's own reading, which no list naming code can mislead.
|
|
2685
|
+
*/
|
|
2686
|
+
function kitSourceModuleSideEffects(absFile) {
|
|
2687
|
+
const manifest = readPackageManifest(findPackageRoot(absFile));
|
|
2688
|
+
const field = isJsonBlock(manifest) ? manifest.sideEffects : void 0;
|
|
2689
|
+
if (!Array.isArray(field)) return void 0;
|
|
2690
|
+
return field.some((glob) => isJsonString(glob) && globNamesCode(glob)) ? true : void 0;
|
|
2691
|
+
}
|
|
2692
|
+
/** Whether a host keeps the module at `file` side-effectful: it lies under
|
|
2693
|
+
* one of the discovered kit source directories, and its package's list
|
|
2694
|
+
* could misread it (see `kitSourceModuleSideEffects`). A host asks this of
|
|
2695
|
+
* the resolved module, never of its importer alone. */
|
|
2696
|
+
function keepsKitSourceEffects(file, kitDirs) {
|
|
2697
|
+
return kitDirs.some((dir) => isPathWithinRoot(dir, file)) && kitSourceModuleSideEffects(file) === true;
|
|
2698
|
+
}
|
|
2372
2699
|
function matchesSideEffects(globs, pkgRoot, absFiles) {
|
|
2373
2700
|
return absFiles.some((file) => {
|
|
2374
2701
|
const relPath = (0, path.relative)(pkgRoot, file).split(path.sep).join("/");
|
|
@@ -2392,18 +2719,9 @@ function exportTarget(value) {
|
|
|
2392
2719
|
/** Each exact `exports` entry of the package at `pkgRoot`, as its subpath
|
|
2393
2720
|
* and absolute target; `*` patterns name no single file and are skipped. */
|
|
2394
2721
|
function packageExportEntries(pkgRoot) {
|
|
2395
|
-
let manifest;
|
|
2396
|
-
try {
|
|
2397
|
-
manifest = JSON.parse((0, fs.readFileSync)((0, path.join)(pkgRoot, "package.json"), "utf-8"));
|
|
2398
|
-
} catch {
|
|
2399
|
-
return [];
|
|
2400
|
-
}
|
|
2401
|
-
const exports = isJsonBlock(manifest) ? manifest.exports : void 0;
|
|
2402
|
-
if (exports === void 0 || exports === null) return [];
|
|
2403
|
-
const subpaths = isJsonBlock(exports) && Object.keys(exports).some((k) => k.startsWith(".")) ? exports : { ".": exports };
|
|
2404
2722
|
const entries = [];
|
|
2405
|
-
for (const [subpath, value] of
|
|
2406
|
-
if (
|
|
2723
|
+
for (const [subpath, value] of exportsSubpaths(readPackageManifest(pkgRoot))) {
|
|
2724
|
+
if (subpath.includes("*")) continue;
|
|
2407
2725
|
const target = exportTarget(value);
|
|
2408
2726
|
if (target !== null) entries.push([subpath, (0, path.resolve)(pkgRoot, target)]);
|
|
2409
2727
|
}
|
|
@@ -2442,6 +2760,16 @@ async function collectExternalPackageSources(opts) {
|
|
|
2442
2760
|
const sourceEntrySideEffects = /* @__PURE__ */ new Map();
|
|
2443
2761
|
/** `replaced` names the entry the redirect stands in for; it is only
|
|
2444
2762
|
* needed, and so only resolved, for a glob list. */
|
|
2763
|
+
/** The entry `subpath` of the package resolves to without the redirect.
|
|
2764
|
+
* A resolver with no `import` condition, as Node's `require` has none,
|
|
2765
|
+
* finds no ESM-only entry, so the manifest's own target answers then. */
|
|
2766
|
+
const shippedEntry = async (specifier, pkgRoot, subpath) => {
|
|
2767
|
+
try {
|
|
2768
|
+
const resolved = await resolveSpecifier(specifier);
|
|
2769
|
+
if (resolved) return resolved;
|
|
2770
|
+
} catch {}
|
|
2771
|
+
return packageExportEntries(pkgRoot).find(([entry]) => entry === subpath)?.[1] ?? null;
|
|
2772
|
+
};
|
|
2445
2773
|
const redirect = async (specifier, srcEntry, pkgRoot, replaced) => {
|
|
2446
2774
|
sourceEntries.set(specifier, srcEntry);
|
|
2447
2775
|
const field = readPackageSideEffects(pkgRoot);
|
|
@@ -2454,6 +2782,8 @@ async function collectExternalPackageSources(opts) {
|
|
|
2454
2782
|
sourceEntrySideEffects.set(specifier, replacedEntry === null || matchesSideEffects(field, pkgRoot, [srcEntry, replacedEntry]));
|
|
2455
2783
|
};
|
|
2456
2784
|
const packageDirs = [];
|
|
2785
|
+
const linkedDirs = [];
|
|
2786
|
+
const outputDirs = [];
|
|
2457
2787
|
const dirOwnerSets = {};
|
|
2458
2788
|
const dirExtensions = {};
|
|
2459
2789
|
const fileOwners = {};
|
|
@@ -2462,6 +2792,31 @@ async function collectExternalPackageSources(opts) {
|
|
|
2462
2792
|
(dirOwnerSets[dir] ??= []).push(specifier);
|
|
2463
2793
|
};
|
|
2464
2794
|
const alreadyIngested = (relPath) => hasEntry(relPath) || pushed.has(relPath);
|
|
2795
|
+
/** Adds `file` to the analysis set unless it is there; false when it
|
|
2796
|
+
* cannot be read. */
|
|
2797
|
+
const ingest = (file, specifier) => {
|
|
2798
|
+
const relPath = (0, path.relative)(rootDir, file);
|
|
2799
|
+
if (alreadyIngested(relPath)) return true;
|
|
2800
|
+
let source;
|
|
2801
|
+
try {
|
|
2802
|
+
source = (0, fs.readFileSync)(file, "utf-8");
|
|
2803
|
+
} catch (err) {
|
|
2804
|
+
onUnreadable(relPath, err);
|
|
2805
|
+
return false;
|
|
2806
|
+
}
|
|
2807
|
+
onSourceRead?.(source, relPath, file);
|
|
2808
|
+
entries.push({
|
|
2809
|
+
path: relPath,
|
|
2810
|
+
source
|
|
2811
|
+
});
|
|
2812
|
+
pushed.add(relPath);
|
|
2813
|
+
fileOwners[relPath] ??= specifier;
|
|
2814
|
+
return true;
|
|
2815
|
+
};
|
|
2816
|
+
const diagnostics = [];
|
|
2817
|
+
const reportedPackages = /* @__PURE__ */ new Set();
|
|
2818
|
+
const kitDescriptors = [];
|
|
2819
|
+
const describedRoots = /* @__PURE__ */ new Set();
|
|
2465
2820
|
for (const specifier of specifiers) {
|
|
2466
2821
|
let absEntry;
|
|
2467
2822
|
try {
|
|
@@ -2470,7 +2825,14 @@ async function collectExternalPackageSources(opts) {
|
|
|
2470
2825
|
absEntry = null;
|
|
2471
2826
|
}
|
|
2472
2827
|
if (!absEntry && (0, path.isAbsolute)(specifier)) absEntry = resolveAbsolutePathSpecifier(specifier, extensionsSet);
|
|
2473
|
-
|
|
2828
|
+
const packageName = (0, path.isAbsolute)(specifier) ? null : bareSpecifierPackageName(specifier);
|
|
2829
|
+
const resolvedRoot = absEntry ? findPackageRoot(absEntry) : null;
|
|
2830
|
+
const locatedRoot = packageName && locatePackageRoot(packageName, rootDir);
|
|
2831
|
+
const pkgRoot = resolvedRoot && (!locatedRoot || isPackageNamed(resolvedRoot, packageName) || realPath(resolvedRoot) === locatedRoot) ? resolvedRoot : locatedRoot || resolvedRoot;
|
|
2832
|
+
const condition = packageName && pkgRoot ? readKitSourceCondition(pkgRoot) ?? sourceExportsCondition(pkgRoot) : null;
|
|
2833
|
+
const entryKey = packageName && `.${specifier.slice(packageName.length)}`;
|
|
2834
|
+
absEntry ??= condition?.entries.find(([entry]) => entry === entryKey)?.[1] ?? null;
|
|
2835
|
+
if (!absEntry || !pkgRoot) {
|
|
2474
2836
|
outcomes.push({
|
|
2475
2837
|
specifier,
|
|
2476
2838
|
outcome: "unresolvable",
|
|
@@ -2478,12 +2840,38 @@ async function collectExternalPackageSources(opts) {
|
|
|
2478
2840
|
});
|
|
2479
2841
|
continue;
|
|
2480
2842
|
}
|
|
2481
|
-
const
|
|
2843
|
+
const realRoot = realPath(pkgRoot);
|
|
2844
|
+
if (!describedRoots.has(realRoot)) {
|
|
2845
|
+
describedRoots.add(realRoot);
|
|
2846
|
+
const described = readKitDescriptor(pkgRoot, rootDir);
|
|
2847
|
+
if (described) kitDescriptors.push(described);
|
|
2848
|
+
}
|
|
2849
|
+
const linked = !isInstalledPackage(pkgRoot);
|
|
2482
2850
|
const srcDir = (0, path.join)(pkgRoot, "src");
|
|
2483
2851
|
let fileCount = 0;
|
|
2484
2852
|
let staleDist = false;
|
|
2485
|
-
if (
|
|
2853
|
+
if (packageName && !reportedPackages.has(packageName)) {
|
|
2854
|
+
reportedPackages.add(packageName);
|
|
2855
|
+
diagnostics.push(...sourceConditionDiagnostics(packageName, condition));
|
|
2856
|
+
}
|
|
2857
|
+
if (condition && packageName) {
|
|
2858
|
+
for (const [entry, target] of condition.entries) {
|
|
2859
|
+
const entrySpecifier = packageName + entry.slice(1);
|
|
2860
|
+
packageMap[entrySpecifier] = (0, path.relative)(rootDir, target);
|
|
2861
|
+
await redirect(entrySpecifier, target, pkgRoot, () => shippedEntry(entrySpecifier, pkgRoot, entry));
|
|
2862
|
+
}
|
|
2863
|
+
packageMap[specifier] ??= (0, path.relative)(rootDir, absEntry);
|
|
2864
|
+
if (condition.root) {
|
|
2865
|
+
packageDirs.push(condition.root);
|
|
2866
|
+
if (linked) linkedDirs.push(condition.root);
|
|
2867
|
+
claimDir(condition.root, specifier);
|
|
2868
|
+
dirExtensions[condition.root] = [...extensionsSet];
|
|
2869
|
+
onPackageResolved?.(specifier, condition.root);
|
|
2870
|
+
for (const file of walkPackageSources(condition.root, extensionsSet)) if (ingest(file, specifier)) fileCount++;
|
|
2871
|
+
}
|
|
2872
|
+
} else if ((0, fs.existsSync)(srcDir)) {
|
|
2486
2873
|
packageDirs.push(srcDir);
|
|
2874
|
+
if (linked) linkedDirs.push(srcDir);
|
|
2487
2875
|
claimDir(srcDir, specifier);
|
|
2488
2876
|
dirExtensions[srcDir] = [...extensionsSet];
|
|
2489
2877
|
onPackageResolved?.(specifier, srcDir);
|
|
@@ -2493,49 +2881,23 @@ async function collectExternalPackageSources(opts) {
|
|
|
2493
2881
|
const replaced = absEntry;
|
|
2494
2882
|
await redirect(specifier, srcEntry, pkgRoot, async () => replaced);
|
|
2495
2883
|
} else packageMap[specifier] = (0, path.relative)(rootDir, absEntry);
|
|
2496
|
-
if (
|
|
2497
|
-
const packageName = bareSpecifierPackageName(specifier);
|
|
2884
|
+
if (packageName) {
|
|
2498
2885
|
if (packageName !== specifier && !(packageName in packageMap)) {
|
|
2499
2886
|
const rootEntry = sourceEntryForSpecifier(packageName, srcDir, extensionsSet);
|
|
2500
2887
|
if (rootEntry) {
|
|
2501
2888
|
packageMap[packageName] = (0, path.relative)(rootDir, rootEntry);
|
|
2502
|
-
await redirect(packageName, rootEntry, pkgRoot,
|
|
2503
|
-
try {
|
|
2504
|
-
return await resolveSpecifier(packageName);
|
|
2505
|
-
} catch {
|
|
2506
|
-
return null;
|
|
2507
|
-
}
|
|
2508
|
-
});
|
|
2889
|
+
await redirect(packageName, rootEntry, pkgRoot, () => shippedEntry(packageName, pkgRoot, "."));
|
|
2509
2890
|
}
|
|
2510
2891
|
}
|
|
2511
2892
|
}
|
|
2512
2893
|
const pkgFiles = walkPackageSources(srcDir, extensionsSet);
|
|
2513
|
-
staleDist =
|
|
2514
|
-
for (const pkgFile of pkgFiles)
|
|
2515
|
-
const relPath = (0, path.relative)(rootDir, pkgFile);
|
|
2516
|
-
if (alreadyIngested(relPath)) {
|
|
2517
|
-
fileCount++;
|
|
2518
|
-
continue;
|
|
2519
|
-
}
|
|
2520
|
-
let source;
|
|
2521
|
-
try {
|
|
2522
|
-
source = (0, fs.readFileSync)(pkgFile, "utf-8");
|
|
2523
|
-
} catch (err) {
|
|
2524
|
-
onUnreadable(relPath, err);
|
|
2525
|
-
continue;
|
|
2526
|
-
}
|
|
2527
|
-
onSourceRead?.(source, relPath, pkgFile);
|
|
2528
|
-
entries.push({
|
|
2529
|
-
path: relPath,
|
|
2530
|
-
source
|
|
2531
|
-
});
|
|
2532
|
-
pushed.add(relPath);
|
|
2533
|
-
fileOwners[relPath] ??= specifier;
|
|
2534
|
-
fileCount++;
|
|
2535
|
-
}
|
|
2894
|
+
staleDist = linked && distEntryIsStale(absEntry, srcDir, pkgFiles);
|
|
2895
|
+
for (const pkgFile of pkgFiles) if (ingest(pkgFile, specifier)) fileCount++;
|
|
2536
2896
|
} else {
|
|
2537
2897
|
const outputDir = (0, path.dirname)(absEntry);
|
|
2538
2898
|
packageDirs.push(outputDir);
|
|
2899
|
+
if (linked) linkedDirs.push(outputDir);
|
|
2900
|
+
outputDirs.push(outputDir);
|
|
2539
2901
|
claimDir(outputDir, specifier);
|
|
2540
2902
|
onPackageResolved?.(specifier, outputDir);
|
|
2541
2903
|
packageMap[specifier] = (0, path.relative)(rootDir, absEntry);
|
|
@@ -2547,37 +2909,13 @@ async function collectExternalPackageSources(opts) {
|
|
|
2547
2909
|
return !PACKAGE_OUTPUT_EXCLUDES.some((pattern) => relToOutput.includes(pattern));
|
|
2548
2910
|
});
|
|
2549
2911
|
if (!outputFiles.includes(absEntry)) outputFiles.unshift(absEntry);
|
|
2550
|
-
for (const outputFile of outputFiles)
|
|
2551
|
-
const outputRelPath = (0, path.relative)(rootDir, outputFile);
|
|
2552
|
-
if (alreadyIngested(outputRelPath)) {
|
|
2553
|
-
fileCount++;
|
|
2554
|
-
continue;
|
|
2555
|
-
}
|
|
2556
|
-
let source;
|
|
2557
|
-
try {
|
|
2558
|
-
source = (0, fs.readFileSync)(outputFile, "utf-8");
|
|
2559
|
-
} catch (err) {
|
|
2560
|
-
onUnreadable(outputRelPath, err);
|
|
2561
|
-
continue;
|
|
2562
|
-
}
|
|
2563
|
-
onSourceRead?.(source, outputRelPath, outputFile);
|
|
2564
|
-
entries.push({
|
|
2565
|
-
path: outputRelPath,
|
|
2566
|
-
source
|
|
2567
|
-
});
|
|
2568
|
-
pushed.add(outputRelPath);
|
|
2569
|
-
fileOwners[outputRelPath] ??= specifier;
|
|
2570
|
-
fileCount++;
|
|
2571
|
-
}
|
|
2912
|
+
for (const outputFile of outputFiles) if (ingest(outputFile, specifier)) fileCount++;
|
|
2572
2913
|
}
|
|
2573
|
-
if (
|
|
2574
|
-
const
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
if (entrySpecifier in packageMap || !alreadyIngested(targetRelPath)) continue;
|
|
2579
|
-
packageMap[entrySpecifier] = targetRelPath;
|
|
2580
|
-
}
|
|
2914
|
+
if (packageName) for (const [subpath, target] of packageExportEntries(pkgRoot)) {
|
|
2915
|
+
const entrySpecifier = packageName + subpath.slice(1);
|
|
2916
|
+
const targetRelPath = (0, path.relative)(rootDir, target);
|
|
2917
|
+
if (entrySpecifier in packageMap || !alreadyIngested(targetRelPath)) continue;
|
|
2918
|
+
packageMap[entrySpecifier] = targetRelPath;
|
|
2581
2919
|
}
|
|
2582
2920
|
outcomes.push({
|
|
2583
2921
|
specifier,
|
|
@@ -2591,12 +2929,112 @@ async function collectExternalPackageSources(opts) {
|
|
|
2591
2929
|
sourceEntries,
|
|
2592
2930
|
sourceEntrySideEffects,
|
|
2593
2931
|
packageDirs,
|
|
2932
|
+
linkedDirs,
|
|
2933
|
+
outputDirs,
|
|
2594
2934
|
dirOwnerSets,
|
|
2595
2935
|
dirExtensions,
|
|
2596
2936
|
fileOwners,
|
|
2597
|
-
outcomes
|
|
2937
|
+
outcomes,
|
|
2938
|
+
diagnostics: [...diagnostics, ...noKitFilesDiagnostics(outcomes)],
|
|
2939
|
+
kitDescriptors
|
|
2598
2940
|
};
|
|
2599
2941
|
}
|
|
2942
|
+
/** The dependency names a manifest lists in `fields`. */
|
|
2943
|
+
function dependencyNames(manifest, fields) {
|
|
2944
|
+
if (!isJsonBlock(manifest)) return [];
|
|
2945
|
+
const names = /* @__PURE__ */ new Set();
|
|
2946
|
+
for (const field of fields) {
|
|
2947
|
+
const deps = manifest[field];
|
|
2948
|
+
if (isJsonBlock(deps)) for (const name of Object.keys(deps)) names.add(name);
|
|
2949
|
+
}
|
|
2950
|
+
return [...names];
|
|
2951
|
+
}
|
|
2952
|
+
/** The source kits the application at `rootDir` declares as dependencies.
|
|
2953
|
+
* A bundler serves an installed one as compiled code unless told
|
|
2954
|
+
* otherwise: Next keeps it external on the server unless it is in
|
|
2955
|
+
* `transpilePackages`, and Vite's optimizer prebundles it. */
|
|
2956
|
+
function sourceKitDependencies(rootDir) {
|
|
2957
|
+
return dependencyNames(readPackageManifest(rootDir), ["dependencies", "devDependencies"]).flatMap((name) => {
|
|
2958
|
+
const pkgRoot = locatePackageRoot(name, rootDir);
|
|
2959
|
+
if (pkgRoot === null || readKitSourceCondition(pkgRoot) === null) return [];
|
|
2960
|
+
return [{
|
|
2961
|
+
name,
|
|
2962
|
+
installed: isInstalledPackage(pkgRoot),
|
|
2963
|
+
dependencies: dependencyNames(readPackageManifest(pkgRoot), ["dependencies"])
|
|
2964
|
+
}];
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
/** A specifier that names a package: not relative or absolute, and no URL,
|
|
2968
|
+
* scheme (`node:`, `virtual:`), subpath import or virtual id. */
|
|
2969
|
+
function isPackageSpecifier(specifier) {
|
|
2970
|
+
return /^(?:@[^/\\:]+\/)?[^./\\#\0:][^:]*$/.test(specifier);
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* An error for each kit the application's own `files` import or re-export
|
|
2974
|
+
* whose system the application's system does not include: a package that
|
|
2975
|
+
* declares the kit source condition, with no kit the system extends
|
|
2976
|
+
* (`systemKits`) in that package. One app build has exactly one system, and
|
|
2977
|
+
* every kit's system is part of it, so such a kit is not extracted against
|
|
2978
|
+
* a system it was not built for. One batch parse reads the imports of every
|
|
2979
|
+
* file the engine parses as it is; an adapted source (`.svelte`, `.mdx`)
|
|
2980
|
+
* reaches the engine only as its generated children.
|
|
2981
|
+
*/
|
|
2982
|
+
function importedKitDiagnostics(files, engine, rootDir, systemKits) {
|
|
2983
|
+
const { extractFacts } = engine;
|
|
2984
|
+
const parsed = files.filter(({ path: path$4 }) => isEngineTransformExtension(path$4));
|
|
2985
|
+
if (!extractFacts || parsed.length === 0) return [];
|
|
2986
|
+
let facts;
|
|
2987
|
+
try {
|
|
2988
|
+
facts = parseInternalWire(extractFacts(JSON.stringify(parsed.map(({ path: path$5, source }) => ({
|
|
2989
|
+
path: path$5,
|
|
2990
|
+
source
|
|
2991
|
+
})))), "extractFacts");
|
|
2992
|
+
} catch {
|
|
2993
|
+
return [];
|
|
2994
|
+
}
|
|
2995
|
+
const seen = new Set(systemKits.filter((specifier) => !(0, path.isAbsolute)(specifier)).map(bareSpecifierPackageName));
|
|
2996
|
+
const diagnostics = [];
|
|
2997
|
+
for (const [path$6, file] of Object.entries(facts.files)) {
|
|
2998
|
+
if (file.parsePanicked) continue;
|
|
2999
|
+
const specifiers = [...file.imports.map((fact) => fact.source), ...file.exports.flatMap((fact) => fact.source === null ? [] : [fact.source])];
|
|
3000
|
+
for (const specifier of specifiers) {
|
|
3001
|
+
if (!isPackageSpecifier(specifier)) continue;
|
|
3002
|
+
const name = bareSpecifierPackageName(specifier);
|
|
3003
|
+
if (seen.has(name)) continue;
|
|
3004
|
+
seen.add(name);
|
|
3005
|
+
const pkgRoot = locatePackageRoot(name, (0, path.dirname)((0, path.resolve)(rootDir, path$6)));
|
|
3006
|
+
if (pkgRoot && readKitSourceCondition(pkgRoot)) diagnostics.push({
|
|
3007
|
+
file: path$6,
|
|
3008
|
+
component: name,
|
|
3009
|
+
kind: "warn",
|
|
3010
|
+
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>)`,
|
|
3011
|
+
code: KIT_SYSTEM_NOT_INCLUDED,
|
|
3012
|
+
severity: severityFor(KIT_SYSTEM_NOT_INCLUDED)
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
return diagnostics;
|
|
3017
|
+
}
|
|
3018
|
+
/** A kit without the source condition, warned once, or each condition entry
|
|
3019
|
+
* whose target is missing or outside the package. */
|
|
3020
|
+
function sourceConditionDiagnostics(packageName, condition) {
|
|
3021
|
+
if (condition === null) return [{
|
|
3022
|
+
file: packageName,
|
|
3023
|
+
component: "kit",
|
|
3024
|
+
kind: "warn",
|
|
3025
|
+
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`,
|
|
3026
|
+
code: KIT_WITHOUT_SOURCE_CONDITION,
|
|
3027
|
+
severity: severityFor(KIT_WITHOUT_SOURCE_CONDITION)
|
|
3028
|
+
}];
|
|
3029
|
+
return condition.invalid.map(([subpath, target]) => ({
|
|
3030
|
+
file: packageName,
|
|
3031
|
+
component: "kit",
|
|
3032
|
+
kind: "warn",
|
|
3033
|
+
message: `exports["${subpath}"].${KIT_SOURCE_CONDITION} names ${target}, which is missing or outside the package, so that entry is not read from source`,
|
|
3034
|
+
code: INVALID_KIT_SOURCE_CONDITION,
|
|
3035
|
+
severity: severityFor(INVALID_KIT_SOURCE_CONDITION)
|
|
3036
|
+
}));
|
|
3037
|
+
}
|
|
2600
3038
|
function firstOwners(dirOwnerSets) {
|
|
2601
3039
|
const owners = {};
|
|
2602
3040
|
for (const [dir, specifiers] of Object.entries(dirOwnerSets)) if (specifiers.length > 0) owners[dir] = specifiers[0];
|
|
@@ -2642,10 +3080,14 @@ function excludeCollectedPackages(collected, rejectedSpecifiers, rootDir) {
|
|
|
2642
3080
|
sourceEntries,
|
|
2643
3081
|
sourceEntrySideEffects,
|
|
2644
3082
|
packageDirs: collected.packageDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
3083
|
+
linkedDirs: collected.linkedDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
3084
|
+
outputDirs: collected.outputDirs.filter((dir) => !rejectedDirs.includes(dir)),
|
|
2645
3085
|
dirOwnerSets,
|
|
2646
3086
|
dirExtensions,
|
|
2647
3087
|
fileOwners,
|
|
2648
|
-
outcomes: collected.outcomes
|
|
3088
|
+
outcomes: collected.outcomes,
|
|
3089
|
+
diagnostics: collected.diagnostics,
|
|
3090
|
+
kitDescriptors: collected.kitDescriptors.filter((record) => !rejectedDirs.some((dir) => isPathWithinRoot((0, path.resolve)(rootDir, record.packageRoot), dir)))
|
|
2649
3091
|
};
|
|
2650
3092
|
}
|
|
2651
3093
|
function unresolvableIncludesMessage(outcomes) {
|
|
@@ -2666,15 +3108,16 @@ function staleDistIncludesMessage(outcomes) {
|
|
|
2666
3108
|
function engineModuleParser(engine) {
|
|
2667
3109
|
const { extractFacts } = engine;
|
|
2668
3110
|
if (!extractFacts) return void 0;
|
|
2669
|
-
return (source, path$
|
|
3111
|
+
return (source, path$7) => {
|
|
2670
3112
|
try {
|
|
2671
3113
|
const facts = parseInternalWire(extractFacts(JSON.stringify([{
|
|
2672
|
-
path: path$
|
|
3114
|
+
path: path$7,
|
|
2673
3115
|
source
|
|
2674
|
-
}])), "extractFacts").files[path$
|
|
3116
|
+
}])), "extractFacts").files[path$7];
|
|
2675
3117
|
return facts && !facts.parsePanicked ? {
|
|
2676
3118
|
imports: facts.imports,
|
|
2677
|
-
exports: facts.exports
|
|
3119
|
+
exports: facts.exports,
|
|
3120
|
+
unboundCreateSystemCalls: facts.unboundCreateSystemCalls ?? []
|
|
2678
3121
|
} : null;
|
|
2679
3122
|
} catch {
|
|
2680
3123
|
return null;
|
|
@@ -2685,7 +3128,7 @@ const ANIMUS_SYSTEM_SPECIFIER = /^@animus-ui\/system(?:\/.*)?$/;
|
|
|
2685
3128
|
/** The file a specifier names from `importer`: a relative one by the
|
|
2686
3129
|
* ingestion's probe order, a bare one by the host's package resolution. */
|
|
2687
3130
|
async function resolveModuleFile(importer, specifier, resolvePackage) {
|
|
2688
|
-
if (specifier.startsWith(".")) return relativeSourceCandidates(importer, specifier).find(isFile) ?? null;
|
|
3131
|
+
if (specifier.startsWith(".")) return relativeSourceCandidates(importer, specifier).find(isFile$1) ?? null;
|
|
2689
3132
|
try {
|
|
2690
3133
|
return await resolvePackage?.(specifier) ?? null;
|
|
2691
3134
|
} catch {
|
|
@@ -2770,13 +3213,15 @@ const NAMESPACE_IMPORT = /\bimport\s+(?:[a-zA-Z_$][a-zA-Z0-9_$]*\s*,\s*)?\*\s*as
|
|
|
2770
3213
|
* `import()` of a module. A binding named `createSystem` shown to be
|
|
2771
3214
|
* something else is no root. One whose identity discovery cannot follow
|
|
2772
3215
|
* keeps the admission spelling gave it, so a resolution limit never drops a
|
|
2773
|
-
* kit. Both are reported.
|
|
2774
|
-
* the
|
|
3216
|
+
* kit. Both are reported. A call of the bare name, which the file neither
|
|
3217
|
+
* imports nor declares, is no root: the system loader evaluates the file
|
|
3218
|
+
* without auto-imports, where the name is undefined. It is reported once.
|
|
2775
3219
|
*/
|
|
2776
|
-
async function systemRoots(systemFilePath, source,
|
|
3220
|
+
async function systemRoots(systemFilePath, source, record, following) {
|
|
3221
|
+
const { imports } = record;
|
|
2777
3222
|
const roots = /* @__PURE__ */ new Set();
|
|
2778
3223
|
const identityOf = (specifier, name) => exportIdentity(systemFilePath, specifier, name, following, /* @__PURE__ */ new Set());
|
|
2779
|
-
const called = (callee) =>
|
|
3224
|
+
const called = (callee) => callOf(callee).test(source);
|
|
2780
3225
|
/** Admits a binding named `createSystem` by its identity: an unknown one
|
|
2781
3226
|
* keeps `spellingAdmits`, and every unproven one is reported. */
|
|
2782
3227
|
const admit = (local, offset, identity, spellingAdmits) => {
|
|
@@ -2796,11 +3241,8 @@ async function systemRoots(systemFilePath, source, imports, following) {
|
|
|
2796
3241
|
...locationIn(source, offset)
|
|
2797
3242
|
});
|
|
2798
3243
|
};
|
|
2799
|
-
let bindsName = false;
|
|
2800
3244
|
for (const binding of imports) {
|
|
2801
|
-
|
|
2802
|
-
if (binding.local === "createSystem") bindsName = true;
|
|
2803
|
-
if (named) {
|
|
3245
|
+
if (binding.imported === "createSystem" || binding.local === "createSystem") {
|
|
2804
3246
|
const statement = new RegExp(`\\bimport\\b[^;]*?\\bfrom\\s*['"]${escapeRegExp$1(binding.source)}['"]`, "g");
|
|
2805
3247
|
let offset = 0;
|
|
2806
3248
|
for (const match of source.matchAll(statement)) {
|
|
@@ -2831,19 +3273,47 @@ async function systemRoots(systemFilePath, source, imports, following) {
|
|
|
2831
3273
|
why: `it is destructured from '${initializer}', which is not a module namespace`
|
|
2832
3274
|
});
|
|
2833
3275
|
};
|
|
3276
|
+
for (const { local, offset, initializer } of destructuredCreateSystems(source)) admit(local, offset, await destructuredFrom(initializer), local === "createSystem");
|
|
3277
|
+
const unimported = unimportedCreateSystemCall(systemFilePath, record);
|
|
3278
|
+
if (unimported) following.report?.(unimported);
|
|
3279
|
+
return roots;
|
|
3280
|
+
}
|
|
3281
|
+
/** A call of `callee` as a whole name, not a member. */
|
|
3282
|
+
function callOf(callee) {
|
|
3283
|
+
return new RegExp(`(?<![a-zA-Z0-9_$.])${escapeRegExp$1(callee)}\\s*\\(`);
|
|
3284
|
+
}
|
|
3285
|
+
/** Each `createSystem` property a declaration destructures: its local name,
|
|
3286
|
+
* its offset in `source`, and the destructured initializer. */
|
|
3287
|
+
function* destructuredCreateSystems(source) {
|
|
2834
3288
|
for (const match of source.matchAll(/\b(?:const|let|var)\s*\{([^}]*)\}\s*=\s*([^;\n]+)/g)) {
|
|
2835
3289
|
const [whole, pattern, initializer] = match;
|
|
2836
3290
|
for (const property of pattern.split(",")) {
|
|
2837
3291
|
const binding = /^\s*createSystem\s*(?::\s*([a-zA-Z_$][a-zA-Z0-9_$]*))?\s*(?:=[\s\S]*)?$/.exec(property);
|
|
2838
3292
|
if (!binding) continue;
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
3293
|
+
yield {
|
|
3294
|
+
local: binding[1] ?? "createSystem",
|
|
3295
|
+
offset: match.index + whole.indexOf("createSystem"),
|
|
3296
|
+
initializer: initializer.trim()
|
|
3297
|
+
};
|
|
2842
3298
|
}
|
|
2843
3299
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
3300
|
+
}
|
|
3301
|
+
/** The warning for a `createSystem` call that the parser's scopes leave
|
|
3302
|
+
* unbound: no import, declaration or parameter names it. Null when there is
|
|
3303
|
+
* none, or when the parser reports no scopes. */
|
|
3304
|
+
function unimportedCreateSystemCall(systemFilePath, record) {
|
|
3305
|
+
const call = record.unboundCreateSystemCalls?.[0];
|
|
3306
|
+
if (!call) return null;
|
|
3307
|
+
return {
|
|
3308
|
+
file: systemFilePath,
|
|
3309
|
+
component: "createSystem",
|
|
3310
|
+
kind: "warn",
|
|
3311
|
+
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'`,
|
|
3312
|
+
code: UNIMPORTED_CREATE_SYSTEM,
|
|
3313
|
+
severity: severityFor(UNIMPORTED_CREATE_SYSTEM),
|
|
3314
|
+
line: call[0],
|
|
3315
|
+
column: call[1]
|
|
3316
|
+
};
|
|
2847
3317
|
}
|
|
2848
3318
|
/** A pattern matching a call of any of `callees` as a whole name, or null
|
|
2849
3319
|
* when there is none to anchor on. */
|
|
@@ -2859,9 +3329,8 @@ async function extractSystemFilePackages(systemFilePath, parseModule, report, re
|
|
|
2859
3329
|
return [];
|
|
2860
3330
|
}
|
|
2861
3331
|
const parsed = parseModule?.(source, systemFilePath) ?? null;
|
|
2862
|
-
const parsedImports = parsed && parsed.imports.length > 0 ? parsed.imports : null;
|
|
2863
3332
|
let rootCall = "createSystem";
|
|
2864
|
-
if (parseModule &&
|
|
3333
|
+
if (parseModule && parsed) rootCall = rootCallPattern([...await systemRoots(systemFilePath, source, parsed, {
|
|
2865
3334
|
parseModule,
|
|
2866
3335
|
resolvePackage,
|
|
2867
3336
|
report
|
|
@@ -3033,9 +3502,9 @@ async function extractSystemFilePackages(systemFilePath, parseModule, report, re
|
|
|
3033
3502
|
}
|
|
3034
3503
|
if (identifiers.size === 0) return [];
|
|
3035
3504
|
const importMap = /* @__PURE__ */ new Map();
|
|
3036
|
-
for (const binding of
|
|
3505
|
+
for (const binding of parsed?.imports ?? []) importMap.set(binding.local, binding.source);
|
|
3037
3506
|
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;
|
|
3038
|
-
if (!
|
|
3507
|
+
if (!parsed) {
|
|
3039
3508
|
let importMatch;
|
|
3040
3509
|
while ((importMatch = importRegex.exec(source)) !== null) {
|
|
3041
3510
|
const [, comboDefault, namedImports, defaultImport, specifier] = importMatch;
|
|
@@ -3287,8 +3756,13 @@ function enforceExternalTokenContracts(opts) {
|
|
|
3287
3756
|
sourceTokens
|
|
3288
3757
|
});
|
|
3289
3758
|
if (messages.length === 0) return;
|
|
3290
|
-
if (opts.strict)
|
|
3291
|
-
|
|
3759
|
+
if (!opts.strict) {
|
|
3760
|
+
for (const message of messages) opts.warn(message);
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
const message = `${opts.prefix} ${messages.join("\n")}`;
|
|
3764
|
+
if (!opts.reportErrors) throw new Error(message);
|
|
3765
|
+
opts.reportErrors(message);
|
|
3292
3766
|
}
|
|
3293
3767
|
//#endregion
|
|
3294
3768
|
//#region pipeline/path-aliases.ts
|
|
@@ -3900,11 +4374,15 @@ function buildAnalysisInputs(opts) {
|
|
|
3900
4374
|
externalDirsJson: opts.externalDirs?.length && hasSourceThemeManifests(opts.system) ? JSON.stringify(opts.externalDirs) : null
|
|
3901
4375
|
};
|
|
3902
4376
|
if (opts.system.declarationScalesJson) inputs.declarationScalesJson = opts.system.declarationScalesJson;
|
|
4377
|
+
if (opts.system.generatedNamesJson) inputs.generatedNamesJson = opts.system.generatedNamesJson;
|
|
4378
|
+
if (opts.system.propertyRecordsJson) inputs.propertyRecordsJson = opts.system.propertyRecordsJson;
|
|
3903
4379
|
const context = opts.analysisContext;
|
|
3904
4380
|
if (context?.skippedSources?.length || context?.unbundledComputedImports || context?.packageDirs?.length) inputs.analysisContextJson = JSON.stringify({
|
|
3905
4381
|
skippedSources: context.skippedSources ?? [],
|
|
3906
4382
|
unbundledComputedImports: context.unbundledComputedImports ?? false,
|
|
3907
|
-
packageDirs: context.packageDirs ?? []
|
|
4383
|
+
packageDirs: context.packageDirs ?? [],
|
|
4384
|
+
linkedDirs: context.linkedDirs ?? [],
|
|
4385
|
+
outputDirs: context.outputDirs ?? []
|
|
3908
4386
|
});
|
|
3909
4387
|
return inputs;
|
|
3910
4388
|
}
|
|
@@ -3945,7 +4423,12 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
3945
4423
|
t = performance.now();
|
|
3946
4424
|
const manifest = JSON.parse(manifestJson);
|
|
3947
4425
|
const systemErrors = systemLoadDiagnostics(opts.system).filter((diagnostic) => diagnostic.kind === "error");
|
|
3948
|
-
|
|
4426
|
+
const kitDiagnostics = kitDescriptorDiagnostics(opts.kitDescriptors ?? [], manifest);
|
|
4427
|
+
if (systemErrors.length > 0 || kitDiagnostics.length > 0) manifest.diagnostics = [
|
|
4428
|
+
...systemErrors,
|
|
4429
|
+
...kitDiagnostics,
|
|
4430
|
+
...manifest.diagnostics ?? []
|
|
4431
|
+
];
|
|
3949
4432
|
const componentCss = applyUnitFallback(manifest.css);
|
|
3950
4433
|
const propertyDiagnostics = checkCustomProperties({
|
|
3951
4434
|
system: opts.system,
|
|
@@ -3956,6 +4439,7 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
3956
4439
|
surfaceManifestDiagnostics(manifest, opts.warn, {
|
|
3957
4440
|
strict: opts.strict,
|
|
3958
4441
|
info: opts.info,
|
|
4442
|
+
reportErrors: opts.reportErrors,
|
|
3959
4443
|
levels: opts.diagnostics,
|
|
3960
4444
|
knownCodes: opts.diagnostics ? knownDiagnosticCodes(diagnosticCodes?.()) : void 0,
|
|
3961
4445
|
prepend: [
|
|
@@ -4063,36 +4547,34 @@ function renameCustomProperties(css, names) {
|
|
|
4063
4547
|
}
|
|
4064
4548
|
//#endregion
|
|
4065
4549
|
//#region pipeline/prefix.ts
|
|
4066
|
-
/**
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4550
|
+
/**
|
|
4551
|
+
* The prefix without `prefixContextualVars`: every name Animus generates (a
|
|
4552
|
+
* variable the theme's map or variable CSS defines) takes `--${prefix}-`
|
|
4553
|
+
* wherever it is defined, registered or read, `var()` fallbacks at any depth
|
|
4554
|
+
* included. Every other name stays as written: each declared contextual
|
|
4555
|
+
* variable, and any custom property an author writes.
|
|
4556
|
+
*/
|
|
4557
|
+
function applyPrefix(prefix, variableMapJson, variableCss, themeJson, contextualVarsJson, declarationScalesJson) {
|
|
4072
4558
|
if (!prefix) return {
|
|
4073
4559
|
variableMapJson,
|
|
4074
4560
|
variableCss,
|
|
4075
4561
|
themeJson,
|
|
4076
|
-
contextualVarsJson
|
|
4562
|
+
contextualVarsJson,
|
|
4563
|
+
declarationScalesJson
|
|
4077
4564
|
};
|
|
4078
|
-
const
|
|
4079
|
-
const
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
css = prefixVariableReferences(prefix, css);
|
|
4084
|
-
css = css.replace(/@property(\s+)--([a-zA-Z][\w-]*)/g, `@property$1--${prefix}-$2`);
|
|
4565
|
+
const contextual = new Set(contextualVarsJson ? Object.values(parseInternalWire(contextualVarsJson, "contextualVarsJson (the theme's contextual variable names)")).flat() : []);
|
|
4566
|
+
const variableMap = parseInternalWire(variableMapJson, "variableMapJson (the theme's token variables)");
|
|
4567
|
+
const generated = [...Object.values(variableMap).map((name) => name.replace(/^--/, "")), ...themeDefinitions(variableCss)].filter((name) => !contextual.has(name));
|
|
4568
|
+
const names = createPropertyNames([], prefix, generated);
|
|
4569
|
+
const rename = (value) => renameCustomProperties(value, names);
|
|
4085
4570
|
const result = {
|
|
4086
|
-
variableMapJson: JSON.stringify(
|
|
4087
|
-
variableCss:
|
|
4571
|
+
variableMapJson: JSON.stringify(Object.fromEntries(Object.entries(variableMap).map(([key, name]) => [key, rename(name)]))),
|
|
4572
|
+
variableCss: rename(variableCss)
|
|
4088
4573
|
};
|
|
4089
|
-
if (themeJson) result.themeJson =
|
|
4090
|
-
if (contextualVarsJson)
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
for (const [scale, names] of Object.entries(ctxVars)) prefixedCtx[scale] = names.map((name) => `${prefix}-${name}`);
|
|
4094
|
-
result.contextualVarsJson = JSON.stringify(prefixedCtx);
|
|
4095
|
-
}
|
|
4574
|
+
if (themeJson) result.themeJson = renameTokenValues(themeJson, rename);
|
|
4575
|
+
if (contextualVarsJson) result.contextualVarsJson = contextualVarsJson;
|
|
4576
|
+
if (generated.length > 0) result.generatedNamesJson = JSON.stringify(Object.fromEntries(generated.map((name) => [name, `${prefix}-${name}`])));
|
|
4577
|
+
if (declarationScalesJson) result.declarationScalesJson = renameDeclarationRecords(declarationScalesJson, rename);
|
|
4096
4578
|
return result;
|
|
4097
4579
|
}
|
|
4098
4580
|
/** The runtime's transport variables are `--animus-<prop>`. */
|
|
@@ -4108,7 +4590,8 @@ function applyPropertyNames(prefix, artifacts) {
|
|
|
4108
4590
|
const byScale = artifacts.contextualVarsJson ? parseInternalWire(artifacts.contextualVarsJson, "contextualVarsJson (the theme's contextual variable names)") : null;
|
|
4109
4591
|
const declared = Object.values(byScale ?? {}).flat();
|
|
4110
4592
|
const variableMap = parseInternalWire(artifacts.variableMapJson, "variableMapJson (the theme's token variables)");
|
|
4111
|
-
const
|
|
4593
|
+
const themeDefined = [...Object.values(variableMap).map((name) => name.replace(/^--/, "")), ...themeDefinitions(artifacts.variableCss)];
|
|
4594
|
+
const managed = createPropertyNames(declared, prefix, themeDefined);
|
|
4112
4595
|
const nameConflicts = [...[...new Set(declared)].flatMap((name) => {
|
|
4113
4596
|
const final = managed.finalName(name) ?? name;
|
|
4114
4597
|
return final.startsWith(TRANSPORT_NAMESPACE) ? [{
|
|
@@ -4132,11 +4615,30 @@ function applyPropertyNames(prefix, artifacts) {
|
|
|
4132
4615
|
}))]))),
|
|
4133
4616
|
declarationScalesJson: artifacts.declarationScalesJson === null ? null : renameDeclarationRecords(artifacts.declarationScalesJson, rename),
|
|
4134
4617
|
nameConflicts,
|
|
4135
|
-
contextualProperties: [...new Set(declared)].map((name) => `--${managed.finalName(name) ?? name}`)
|
|
4618
|
+
contextualProperties: [...new Set(declared)].map((name) => `--${managed.finalName(name) ?? name}`),
|
|
4619
|
+
generatedNamesJson: generatedNamesJson(themeDefined.filter((name) => !declared.includes(name)), managed)
|
|
4136
4620
|
};
|
|
4137
4621
|
}
|
|
4138
|
-
/**
|
|
4139
|
-
|
|
4622
|
+
/** The generated names' final names, for authored component styles. */
|
|
4623
|
+
function generatedNamesJson(names, managed) {
|
|
4624
|
+
const entries = [...new Set(names)].flatMap((name) => {
|
|
4625
|
+
const final = managed.finalName(name);
|
|
4626
|
+
return final === void 0 ? [] : [[name, final]];
|
|
4627
|
+
});
|
|
4628
|
+
return entries.length === 0 ? null : JSON.stringify(Object.fromEntries(entries));
|
|
4629
|
+
}
|
|
4630
|
+
/** The custom properties the theme's CSS declares or `@property` registers,
|
|
4631
|
+
* read as CSS tokenizes it: a name in a string or comment defines nothing. */
|
|
4632
|
+
function themeDefinitions(variableCss) {
|
|
4633
|
+
const tokens = (0, _animus_ui_properties.tokenize)(variableCss).filter((token) => token.type !== "whitespace");
|
|
4634
|
+
return tokens.flatMap((token, index) => {
|
|
4635
|
+
if (token.type !== "ident" || !token.value.startsWith("--")) return [];
|
|
4636
|
+
const previous = tokens[index - 1];
|
|
4637
|
+
const declared = (previous === void 0 || previous.type === "{" || previous.type === ";") && tokens[index + 1]?.type === ":";
|
|
4638
|
+
const registered = previous?.type === "at-keyword" && previous.value.toLowerCase() === "property";
|
|
4639
|
+
return declared || registered ? [token.value.slice(2)] : [];
|
|
4640
|
+
});
|
|
4641
|
+
}
|
|
4140
4642
|
/** Renames inside the token map's values. */
|
|
4141
4643
|
function renameTokenValues(themeJson, rename) {
|
|
4142
4644
|
const tokens = parseInternalWire(themeJson, "themeJson (the theme's flattened token values)");
|
|
@@ -4152,23 +4654,40 @@ function renameDeclarationRecords(declarationScalesJson, rename) {
|
|
|
4152
4654
|
}
|
|
4153
4655
|
//#endregion
|
|
4154
4656
|
//#region pipeline/system-config.ts
|
|
4657
|
+
/** The loader's evaluation of the system file. A failure on a file that
|
|
4658
|
+
* calls `createSystem` with no binding leads with discovery's warning line
|
|
4659
|
+
* for it, then keeps the loader's own error. */
|
|
4660
|
+
function evaluateSystemModule(engine, systemPath, rootDir, conditions) {
|
|
4661
|
+
try {
|
|
4662
|
+
return engine.loadSystemModule(systemPath, rootDir, void 0, conditions);
|
|
4663
|
+
} catch (error) {
|
|
4664
|
+
let source;
|
|
4665
|
+
try {
|
|
4666
|
+
source = (0, fs.readFileSync)(systemPath, "utf-8");
|
|
4667
|
+
} catch {
|
|
4668
|
+
throw error;
|
|
4669
|
+
}
|
|
4670
|
+
const record = engineModuleParser(engine)?.(source, systemPath);
|
|
4671
|
+
const call = record && unimportedCreateSystemCall(systemPath, record);
|
|
4672
|
+
if (!call) throw error;
|
|
4673
|
+
throw new Error(`${warnLine(call)}\n${String(error)}`, { cause: error });
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4155
4676
|
/**
|
|
4156
4677
|
* Load and normalize a SystemInstance; `prefix` namespaces every CSS
|
|
4157
4678
|
* variable name. Error handling stays at the call site.
|
|
4158
4679
|
*/
|
|
4159
4680
|
function loadSystemConfig(engineApi, opts) {
|
|
4160
|
-
const
|
|
4161
|
-
const config = loadSystemModule(opts.systemPath, opts.rootDir);
|
|
4681
|
+
const config = evaluateSystemModule(engineApi(), opts.systemPath, opts.rootDir, opts.conditions);
|
|
4162
4682
|
let scalesJson = config.scalesJson;
|
|
4163
4683
|
let variableMapJson = config.variableMapJson;
|
|
4164
4684
|
const registrations = splitInvalidPropertyRegistrations(config.variableCss);
|
|
4165
4685
|
let variableCss = registrations.css;
|
|
4166
4686
|
let contextualVarsJson = config.contextualVarsJson || null;
|
|
4167
4687
|
let declarationScalesJson = config.declarationScalesJson || null;
|
|
4168
|
-
|
|
4169
|
-
let contextualProperties = declaredNames.map((name) => `--${name}`);
|
|
4170
|
-
let legacyPrefixedContextualVars = [];
|
|
4688
|
+
let contextualProperties = Object.values(parseInternalWire(contextualVarsJson ?? "{}", "contextualVarsJson (the theme's contextual variable names)")).flat().map((name) => `--${name}`);
|
|
4171
4689
|
let prefixNameConflicts = [];
|
|
4690
|
+
let generatedNamesJson;
|
|
4172
4691
|
if (opts.prefix && opts.prefixContextualVars) {
|
|
4173
4692
|
const resolved = applyPropertyNames(opts.prefix, {
|
|
4174
4693
|
variableMapJson,
|
|
@@ -4184,15 +4703,14 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
4184
4703
|
contextualProperties = resolved.contextualProperties;
|
|
4185
4704
|
prefixNameConflicts = resolved.nameConflicts;
|
|
4186
4705
|
declarationScalesJson = resolved.declarationScalesJson;
|
|
4706
|
+
generatedNamesJson = resolved.generatedNamesJson;
|
|
4187
4707
|
} else if (opts.prefix) {
|
|
4188
|
-
|
|
4189
|
-
contextualProperties = declaredNames.map((name) => `--${opts.prefix}-${name}`);
|
|
4190
|
-
const prefixed = applyPrefix(opts.prefix, variableMapJson, variableCss, scalesJson, contextualVarsJson || void 0);
|
|
4708
|
+
const prefixed = applyPrefix(opts.prefix, variableMapJson, variableCss, scalesJson, contextualVarsJson || void 0, declarationScalesJson || void 0);
|
|
4191
4709
|
variableMapJson = prefixed.variableMapJson;
|
|
4192
4710
|
variableCss = prefixed.variableCss;
|
|
4193
4711
|
if (prefixed.themeJson) scalesJson = prefixed.themeJson;
|
|
4194
|
-
if (prefixed.
|
|
4195
|
-
|
|
4712
|
+
if (prefixed.declarationScalesJson) declarationScalesJson = prefixed.declarationScalesJson;
|
|
4713
|
+
generatedNamesJson = prefixed.generatedNamesJson;
|
|
4196
4714
|
}
|
|
4197
4715
|
const system = {
|
|
4198
4716
|
propConfigJson: config.propConfig,
|
|
@@ -4216,7 +4734,7 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
4216
4734
|
if (config.propertyRecordsJson) system.propertyRecordsJson = config.propertyRecordsJson;
|
|
4217
4735
|
if (registrations.invalid.length > 0) system.invalidPropertyRegistrations = registrations.invalid;
|
|
4218
4736
|
if (prefixNameConflicts.length > 0) system.prefixNameConflicts = prefixNameConflicts;
|
|
4219
|
-
if (
|
|
4737
|
+
if (generatedNamesJson) system.generatedNamesJson = generatedNamesJson;
|
|
4220
4738
|
return system;
|
|
4221
4739
|
}
|
|
4222
4740
|
//#endregion
|
|
@@ -4225,8 +4743,7 @@ function runStructuralSelfCheck(input) {
|
|
|
4225
4743
|
const failures = [];
|
|
4226
4744
|
if (input.componentCount === 0) failures.push("No component CSS produced — check the system file and its includes list");
|
|
4227
4745
|
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`);
|
|
4228
|
-
for (const { specifier, outcome } of input.externalOutcomes ?? []) if (outcome === "
|
|
4229
|
-
else if (outcome === "unresolvable") failures.push(`include '${specifier}' could not be resolved`);
|
|
4746
|
+
for (const { specifier, outcome } of input.externalOutcomes ?? []) if (outcome === "unresolvable") failures.push(`include '${specifier}' could not be resolved`);
|
|
4230
4747
|
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");
|
|
4231
4748
|
if ((input.assembledCss ?? `${input.variableCss}\n${input.globalCss}\n${input.componentCss}`).includes("__TRANSFORM__")) failures.push("Unresolved __TRANSFORM__ placeholders found in CSS output");
|
|
4232
4749
|
if (input.componentCount > 0 && (input.componentCss.length > 0 || input.assembledCss !== void 0)) {
|
|
@@ -4260,7 +4777,8 @@ function buildDynamicPropConfig(dynamicProps) {
|
|
|
4260
4777
|
kind: meta.kind,
|
|
4261
4778
|
slotClass: meta.slotClass,
|
|
4262
4779
|
memberVars: meta.memberVars,
|
|
4263
|
-
declarationScaleValues: meta.declarationScaleValues
|
|
4780
|
+
declarationScaleValues: meta.declarationScaleValues,
|
|
4781
|
+
...meta.productionConditions && { productionConditions: meta.productionConditions }
|
|
4264
4782
|
};
|
|
4265
4783
|
continue;
|
|
4266
4784
|
}
|
|
@@ -4278,6 +4796,7 @@ function buildDynamicPropConfig(dynamicProps) {
|
|
|
4278
4796
|
if (meta.strict) entry.strict = true;
|
|
4279
4797
|
if (meta.keywords?.length) entry.keywords = meta.keywords;
|
|
4280
4798
|
if (meta.currentVar) entry.currentVar = meta.currentVar;
|
|
4799
|
+
if (meta.productionConditions) entry.productionConditions = meta.productionConditions;
|
|
4281
4800
|
configEntries[propName] = entry;
|
|
4282
4801
|
}
|
|
4283
4802
|
return configEntries;
|
|
@@ -4316,6 +4835,191 @@ function assertNoErrorDiagnostics(diagnostics) {
|
|
|
4316
4835
|
throw new Error(lines.join("\n"));
|
|
4317
4836
|
}
|
|
4318
4837
|
//#endregion
|
|
4838
|
+
//#region pipeline/kit-publication.ts
|
|
4839
|
+
/** Source a kit publishes and the loader or a bundler parses for imports. */
|
|
4840
|
+
const CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4841
|
+
".ts",
|
|
4842
|
+
".tsx",
|
|
4843
|
+
".mts",
|
|
4844
|
+
".cts",
|
|
4845
|
+
".js",
|
|
4846
|
+
".jsx",
|
|
4847
|
+
".mjs",
|
|
4848
|
+
".cjs"
|
|
4849
|
+
]);
|
|
4850
|
+
const isFile = (path) => {
|
|
4851
|
+
try {
|
|
4852
|
+
return (0, node_fs.statSync)(path).isFile();
|
|
4853
|
+
} catch {
|
|
4854
|
+
return false;
|
|
4855
|
+
}
|
|
4856
|
+
};
|
|
4857
|
+
const posixPath = (path) => path.split(node_path.sep).join("/");
|
|
4858
|
+
/**
|
|
4859
|
+
* The package-relative files `npm pack` publishes, read with npm's own rules
|
|
4860
|
+
* (`files`, `.npmignore`, `.gitignore` and the files npm always includes)
|
|
4861
|
+
* through a dry run that runs no scripts and needs no network.
|
|
4862
|
+
*/
|
|
4863
|
+
function npmPublishedFiles(pkgRoot) {
|
|
4864
|
+
const windows = process.platform === "win32";
|
|
4865
|
+
const run = (0, node_child_process.spawnSync)(windows ? "npm.cmd" : "npm", [
|
|
4866
|
+
"pack",
|
|
4867
|
+
"--dry-run",
|
|
4868
|
+
"--json",
|
|
4869
|
+
"--ignore-scripts"
|
|
4870
|
+
], {
|
|
4871
|
+
cwd: pkgRoot,
|
|
4872
|
+
encoding: "utf-8",
|
|
4873
|
+
shell: windows,
|
|
4874
|
+
env: {
|
|
4875
|
+
...process.env,
|
|
4876
|
+
npm_config_update_notifier: "false"
|
|
4877
|
+
}
|
|
4878
|
+
});
|
|
4879
|
+
if (run.error || run.status !== 0) return {
|
|
4880
|
+
kind: "failed",
|
|
4881
|
+
reason: `npm pack --dry-run could not list the published files: ${String(run.error ?? run.stderr.trim())}`
|
|
4882
|
+
};
|
|
4883
|
+
let output;
|
|
4884
|
+
try {
|
|
4885
|
+
output = JSON.parse(run.stdout);
|
|
4886
|
+
} catch (error) {
|
|
4887
|
+
return {
|
|
4888
|
+
kind: "failed",
|
|
4889
|
+
reason: `npm pack --dry-run printed no JSON: ${String(error)}`
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
const pack = Array.isArray(output) ? output[0] : void 0;
|
|
4893
|
+
const files = isJsonBlock(pack) ? pack.files : void 0;
|
|
4894
|
+
if (!Array.isArray(files)) return {
|
|
4895
|
+
kind: "failed",
|
|
4896
|
+
reason: "npm pack --dry-run printed no file list"
|
|
4897
|
+
};
|
|
4898
|
+
return {
|
|
4899
|
+
kind: "listed",
|
|
4900
|
+
files: new Set(files.flatMap((file) => isJsonBlock(file) && isJsonString(file.path) ? [posixPath(file.path)] : []))
|
|
4901
|
+
};
|
|
4902
|
+
}
|
|
4903
|
+
function animusTargets(manifest) {
|
|
4904
|
+
const targets = [];
|
|
4905
|
+
const unreadable = [];
|
|
4906
|
+
const visit = (subpath, value, underAnimus) => {
|
|
4907
|
+
if (isJsonString(value)) {
|
|
4908
|
+
if (underAnimus) targets.push([subpath, value]);
|
|
4909
|
+
} else if (Array.isArray(value)) for (const entry of value) visit(subpath, entry, underAnimus);
|
|
4910
|
+
else if (isJsonBlock(value)) for (const [key, entry] of Object.entries(value)) visit(subpath, entry, underAnimus || key === "animus");
|
|
4911
|
+
else if (underAnimus && value !== null) unreadable.push([subpath, JSON.stringify(value)]);
|
|
4912
|
+
};
|
|
4913
|
+
for (const [subpath, value] of exportsSubpaths(manifest)) visit(subpath, value, false);
|
|
4914
|
+
return {
|
|
4915
|
+
targets,
|
|
4916
|
+
unreadable
|
|
4917
|
+
};
|
|
4918
|
+
}
|
|
4919
|
+
/** Every file in the package outside `node_modules` and `.git`,
|
|
4920
|
+
* package-relative. */
|
|
4921
|
+
function packageFiles(pkgRoot, dir = "") {
|
|
4922
|
+
return (0, node_fs.readdirSync)((0, node_path.join)(pkgRoot, dir), { withFileTypes: true }).flatMap((entry) => {
|
|
4923
|
+
const path = dir === "" ? entry.name : `${dir}/${entry.name}`;
|
|
4924
|
+
if (entry.isDirectory()) return entry.name === "node_modules" || entry.name === ".git" ? [] : packageFiles(pkgRoot, path);
|
|
4925
|
+
return entry.isFile() ? [path] : [];
|
|
4926
|
+
});
|
|
4927
|
+
}
|
|
4928
|
+
/** A `*` target pattern as a matcher of package-relative files. Node puts
|
|
4929
|
+
* one subpath into every `*`, so each later `*` repeats the first match. */
|
|
4930
|
+
function targetPattern(target) {
|
|
4931
|
+
const body = posixPath(target).replace(/^\.\//, "").split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).reduce((pattern, part, index) => index === 0 ? part : `${pattern}${index === 1 ? "(.+)" : "\\1"}${part}`);
|
|
4932
|
+
return new RegExp(`^${body}$`);
|
|
4933
|
+
}
|
|
4934
|
+
/**
|
|
4935
|
+
* Why the kit at `pkgRoot` would fail an installed consumer: each `animus`
|
|
4936
|
+
* source target, at any condition depth or as a pattern, and each file its
|
|
4937
|
+
* relative imports reach, must be in the package and among the files `npm
|
|
4938
|
+
* pack` publishes, and each bare package import a declared dependency.
|
|
4939
|
+
* Each line names the file, the import and the cause; none means the
|
|
4940
|
+
* published source is complete. With `artifactDir`, a build's artifact
|
|
4941
|
+
* directory inside the package that `npm pack` would publish is a line too.
|
|
4942
|
+
*/
|
|
4943
|
+
function kitPublicationFailures(pkgRoot, engine, artifactDir) {
|
|
4944
|
+
let manifest;
|
|
4945
|
+
try {
|
|
4946
|
+
manifest = JSON.parse((0, node_fs.readFileSync)((0, node_path.join)(pkgRoot, "package.json"), "utf-8"));
|
|
4947
|
+
} catch (error) {
|
|
4948
|
+
return [`package.json: cannot be read: ${String(error)}`];
|
|
4949
|
+
}
|
|
4950
|
+
const { targets, unreadable } = animusTargets(manifest);
|
|
4951
|
+
if (targets.length === 0 && unreadable.length === 0) return [];
|
|
4952
|
+
const { moduleSpecifiers } = engine;
|
|
4953
|
+
if (moduleSpecifiers === void 0) throw new Error("the native engine does not expose moduleSpecifiers, which the kit publication check needs — rebuild @animus-ui/extract");
|
|
4954
|
+
const publication = npmPublishedFiles(pkgRoot);
|
|
4955
|
+
if (publication.kind === "failed") return [`package.json: ${publication.reason}`];
|
|
4956
|
+
const published = (packageRelative) => publication.files.has(packageRelative);
|
|
4957
|
+
const declared = new Set([
|
|
4958
|
+
"dependencies",
|
|
4959
|
+
"peerDependencies",
|
|
4960
|
+
"optionalDependencies"
|
|
4961
|
+
].flatMap((field) => {
|
|
4962
|
+
const block = isJsonBlock(manifest) ? manifest[field] : void 0;
|
|
4963
|
+
return isJsonBlock(block) ? Object.keys(block) : [];
|
|
4964
|
+
}));
|
|
4965
|
+
const ownName = isJsonBlock(manifest) && isJsonString(manifest.name) ? manifest.name : null;
|
|
4966
|
+
const failures = [];
|
|
4967
|
+
const rel = (file) => posixPath((0, node_path.relative)(pkgRoot, file));
|
|
4968
|
+
const outside = (relPath) => relPath.startsWith("../") || (0, node_path.isAbsolute)(relPath);
|
|
4969
|
+
for (const [subpath, value] of unreadable) failures.push(`package.json: exports["${subpath}"] has an "animus" value, ${value}, that is no target path`);
|
|
4970
|
+
const queue = [];
|
|
4971
|
+
const admit = (subpath, relPath) => {
|
|
4972
|
+
if (published(relPath)) queue.push((0, node_path.resolve)(pkgRoot, relPath));
|
|
4973
|
+
else failures.push(`package.json: the "animus" target of exports["${subpath}"], ${relPath}, is not in the published files`);
|
|
4974
|
+
};
|
|
4975
|
+
let files = null;
|
|
4976
|
+
for (const [subpath, target] of targets) {
|
|
4977
|
+
const relPath = rel((0, node_path.resolve)(pkgRoot, target));
|
|
4978
|
+
if (outside(relPath)) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, is outside the package`);
|
|
4979
|
+
else if (target.includes("*")) {
|
|
4980
|
+
files ??= packageFiles(pkgRoot);
|
|
4981
|
+
const pattern = targetPattern(target);
|
|
4982
|
+
const matched = files.filter((file) => pattern.test(file));
|
|
4983
|
+
if (matched.length === 0) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, matches no file in the package`);
|
|
4984
|
+
for (const file of matched) admit(subpath, file);
|
|
4985
|
+
} else if (!isFile((0, node_path.resolve)(pkgRoot, target))) failures.push(`package.json: the "animus" target of exports["${subpath}"], ${target}, does not exist in the package`);
|
|
4986
|
+
else admit(subpath, relPath);
|
|
4987
|
+
}
|
|
4988
|
+
const visited = /* @__PURE__ */ new Set();
|
|
4989
|
+
while (queue.length > 0) {
|
|
4990
|
+
const file = queue.shift();
|
|
4991
|
+
if (visited.has(file)) continue;
|
|
4992
|
+
visited.add(file);
|
|
4993
|
+
const specifiers = parseInternalWire(moduleSpecifiers(JSON.stringify([{
|
|
4994
|
+
path: file,
|
|
4995
|
+
source: (0, node_fs.readFileSync)(file, "utf-8")
|
|
4996
|
+
}])), "moduleSpecifiers").files[file] ?? [];
|
|
4997
|
+
for (const specifier of specifiers) {
|
|
4998
|
+
if (specifier.startsWith(".")) {
|
|
4999
|
+
const target = relativeSourceCandidates(file, specifier).find(isFile);
|
|
5000
|
+
if (target === void 0) failures.push(`${rel(file)}: import '${specifier}' resolves to no file in the package`);
|
|
5001
|
+
else if (outside(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, outside the package`);
|
|
5002
|
+
else if (!published(rel(target))) failures.push(`${rel(file)}: import '${specifier}' resolves to ${rel(target)}, which is not in the published files`);
|
|
5003
|
+
else if (CODE_EXTENSIONS.has((0, node_path.extname)(target))) queue.push(target);
|
|
5004
|
+
continue;
|
|
5005
|
+
}
|
|
5006
|
+
if (specifier.startsWith("/") || /^[a-z][\w+.-]*:/i.test(specifier)) {
|
|
5007
|
+
if (!(0, node_module.isBuiltin)(specifier)) failures.push(`${rel(file)}: import '${specifier}' is not a package or relative import, so an installed consumer cannot resolve it`);
|
|
5008
|
+
continue;
|
|
5009
|
+
}
|
|
5010
|
+
const name = bareSpecifierPackageName(specifier);
|
|
5011
|
+
if ((0, node_module.isBuiltin)(name) || name === ownName || declared.has(name)) continue;
|
|
5012
|
+
failures.push(`${rel(file)}: import '${specifier}' names the package ${name}, which package.json does not declare in dependencies, peerDependencies or optionalDependencies`);
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
const artifacts = artifactDir === void 0 ? "" : rel(artifactDir);
|
|
5016
|
+
if (artifacts !== "" && !outside(artifacts)) {
|
|
5017
|
+
const shipped = [...publication.files].filter((file) => file.startsWith(`${artifacts}/`));
|
|
5018
|
+
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"`);
|
|
5019
|
+
}
|
|
5020
|
+
return failures;
|
|
5021
|
+
}
|
|
5022
|
+
//#endregion
|
|
4319
5023
|
//#region pipeline/replacement-plans.ts
|
|
4320
5024
|
const snapshotByManifest = /* @__PURE__ */ new WeakMap();
|
|
4321
5025
|
/** `null` (a context before its first analysis) snapshots to the empty plan
|
|
@@ -4452,6 +5156,12 @@ Object.defineProperty(exports, "INVALID_PROPERTY_REGISTRATION", {
|
|
|
4452
5156
|
return INVALID_PROPERTY_REGISTRATION;
|
|
4453
5157
|
}
|
|
4454
5158
|
});
|
|
5159
|
+
Object.defineProperty(exports, "KIT_DESCRIPTOR_FILE", {
|
|
5160
|
+
enumerable: true,
|
|
5161
|
+
get: function() {
|
|
5162
|
+
return KIT_DESCRIPTOR_FILE;
|
|
5163
|
+
}
|
|
5164
|
+
});
|
|
4455
5165
|
Object.defineProperty(exports, "REPLACEABLE_DEFAULT_EXCLUDE", {
|
|
4456
5166
|
enumerable: true,
|
|
4457
5167
|
get: function() {
|
|
@@ -4542,6 +5252,12 @@ Object.defineProperty(exports, "buildDynamicPropConfig", {
|
|
|
4542
5252
|
return buildDynamicPropConfig;
|
|
4543
5253
|
}
|
|
4544
5254
|
});
|
|
5255
|
+
Object.defineProperty(exports, "buildKitDescriptor", {
|
|
5256
|
+
enumerable: true,
|
|
5257
|
+
get: function() {
|
|
5258
|
+
return buildKitDescriptor;
|
|
5259
|
+
}
|
|
5260
|
+
});
|
|
4545
5261
|
Object.defineProperty(exports, "buildPathAliasesJson", {
|
|
4546
5262
|
enumerable: true,
|
|
4547
5263
|
get: function() {
|
|
@@ -4644,6 +5360,12 @@ Object.defineProperty(exports, "extractSystemFilePackages", {
|
|
|
4644
5360
|
return extractSystemFilePackages;
|
|
4645
5361
|
}
|
|
4646
5362
|
});
|
|
5363
|
+
Object.defineProperty(exports, "fileSideEffects", {
|
|
5364
|
+
enumerable: true,
|
|
5365
|
+
get: function() {
|
|
5366
|
+
return fileSideEffects;
|
|
5367
|
+
}
|
|
5368
|
+
});
|
|
4647
5369
|
Object.defineProperty(exports, "findAssetSpecifiers", {
|
|
4648
5370
|
enumerable: true,
|
|
4649
5371
|
get: function() {
|
|
@@ -4680,6 +5402,12 @@ Object.defineProperty(exports, "hashReplacementPlans", {
|
|
|
4680
5402
|
return hashReplacementPlans;
|
|
4681
5403
|
}
|
|
4682
5404
|
});
|
|
5405
|
+
Object.defineProperty(exports, "importedKitDiagnostics", {
|
|
5406
|
+
enumerable: true,
|
|
5407
|
+
get: function() {
|
|
5408
|
+
return importedKitDiagnostics;
|
|
5409
|
+
}
|
|
5410
|
+
});
|
|
4683
5411
|
Object.defineProperty(exports, "ingestSourceEntries", {
|
|
4684
5412
|
enumerable: true,
|
|
4685
5413
|
get: function() {
|
|
@@ -4734,6 +5462,30 @@ Object.defineProperty(exports, "isUnresolvedParentDrop", {
|
|
|
4734
5462
|
return isUnresolvedParentDrop;
|
|
4735
5463
|
}
|
|
4736
5464
|
});
|
|
5465
|
+
Object.defineProperty(exports, "keepsKitSourceEffects", {
|
|
5466
|
+
enumerable: true,
|
|
5467
|
+
get: function() {
|
|
5468
|
+
return keepsKitSourceEffects;
|
|
5469
|
+
}
|
|
5470
|
+
});
|
|
5471
|
+
Object.defineProperty(exports, "kitDescriptorDiagnostics", {
|
|
5472
|
+
enumerable: true,
|
|
5473
|
+
get: function() {
|
|
5474
|
+
return kitDescriptorDiagnostics;
|
|
5475
|
+
}
|
|
5476
|
+
});
|
|
5477
|
+
Object.defineProperty(exports, "kitPublicationFailures", {
|
|
5478
|
+
enumerable: true,
|
|
5479
|
+
get: function() {
|
|
5480
|
+
return kitPublicationFailures;
|
|
5481
|
+
}
|
|
5482
|
+
});
|
|
5483
|
+
Object.defineProperty(exports, "kitSourceModuleSideEffects", {
|
|
5484
|
+
enumerable: true,
|
|
5485
|
+
get: function() {
|
|
5486
|
+
return kitSourceModuleSideEffects;
|
|
5487
|
+
}
|
|
5488
|
+
});
|
|
4737
5489
|
Object.defineProperty(exports, "loadSystemConfig", {
|
|
4738
5490
|
enumerable: true,
|
|
4739
5491
|
get: function() {
|
|
@@ -4776,6 +5528,12 @@ Object.defineProperty(exports, "projectExternalFileOwners", {
|
|
|
4776
5528
|
return projectExternalFileOwners;
|
|
4777
5529
|
}
|
|
4778
5530
|
});
|
|
5531
|
+
Object.defineProperty(exports, "readKitDescriptor", {
|
|
5532
|
+
enumerable: true,
|
|
5533
|
+
get: function() {
|
|
5534
|
+
return readKitDescriptor;
|
|
5535
|
+
}
|
|
5536
|
+
});
|
|
4779
5537
|
Object.defineProperty(exports, "readTsconfigAliasPairs", {
|
|
4780
5538
|
enumerable: true,
|
|
4781
5539
|
get: function() {
|
|
@@ -4854,6 +5612,12 @@ Object.defineProperty(exports, "snapshotFilePlans", {
|
|
|
4854
5612
|
return snapshotFilePlans;
|
|
4855
5613
|
}
|
|
4856
5614
|
});
|
|
5615
|
+
Object.defineProperty(exports, "sourceKitDependencies", {
|
|
5616
|
+
enumerable: true,
|
|
5617
|
+
get: function() {
|
|
5618
|
+
return sourceKitDependencies;
|
|
5619
|
+
}
|
|
5620
|
+
});
|
|
4857
5621
|
Object.defineProperty(exports, "stableStringify", {
|
|
4858
5622
|
enumerable: true,
|
|
4859
5623
|
get: function() {
|