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