@animus-ui/extract 0.1.17 → 0.1.19
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/README.md +2 -2
- 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 +5 -0
- package/dist/index.cjs +6 -2
- package/dist/index.mjs +2 -2
- package/dist/pipeline/asset-placeholders.d.ts +19 -0
- package/dist/pipeline/asset-placeholders.d.ts.map +1 -1
- package/dist/pipeline/engine-retirement.d.ts.map +1 -1
- package/dist/pipeline/index.d.ts +3 -3
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/manifest-diagnostics.d.ts +32 -1
- package/dist/pipeline/manifest-diagnostics.d.ts.map +1 -1
- package/dist/pipeline/manifest-schema.d.ts +5 -2
- package/dist/pipeline/manifest-schema.d.ts.map +1 -1
- package/dist/pipeline/property-diagnostics.d.ts +17 -0
- package/dist/pipeline/property-diagnostics.d.ts.map +1 -0
- package/dist/pipeline/property-registrations.d.ts +23 -0
- package/dist/pipeline/property-registrations.d.ts.map +1 -0
- package/dist/pipeline/run-analysis.d.ts +2 -0
- package/dist/pipeline/run-analysis.d.ts.map +1 -1
- package/dist/pipeline/system-config.d.ts +6 -0
- package/dist/pipeline/system-config.d.ts.map +1 -1
- package/dist/{pipeline-D7TdVERQ.mjs → pipeline-BuiItKT-.mjs} +393 -31
- package/dist/{pipeline-OMz1HGqU.cjs → pipeline-CD2qmEEn.cjs} +420 -34
- package/dist/session/extraction-session.d.ts +3 -5
- package/dist/session/extraction-session.d.ts.map +1 -1
- package/dist/session/timing.d.ts.map +1 -1
- package/dist/session.cjs +20 -20
- package/dist/session.mjs +20 -20
- package/index-v2.js +1 -1
- package/package.json +4 -4
- package/dist/pipeline/timing-waterfall.d.ts +0 -6
- package/dist/pipeline/timing-waterfall.d.ts.map +0 -1
|
@@ -1166,7 +1166,7 @@ function createV2EngineApi(deps) {
|
|
|
1166
1166
|
}
|
|
1167
1167
|
//#endregion
|
|
1168
1168
|
//#region pipeline/engine-retirement.ts
|
|
1169
|
-
const RETIRED_ENGINE_MESSAGE = "animus:
|
|
1169
|
+
const RETIRED_ENGINE_MESSAGE = "animus: the 'v1' extraction engine is no longer supported, and v2 is the only engine. Remove the engine option from your Animus config and unset the ANIMUS_ENGINE environment variable.";
|
|
1170
1170
|
function assertNoRetiredEngineSelection(engineOption) {
|
|
1171
1171
|
if (engineOption === "v1" || process.env.ANIMUS_ENGINE === "v1") throw new Error(RETIRED_ENGINE_MESSAGE);
|
|
1172
1172
|
}
|
|
@@ -2023,6 +2023,31 @@ function substituteAssetPlaceholders(css, urlBySpecifier) {
|
|
|
2023
2023
|
}
|
|
2024
2024
|
return out;
|
|
2025
2025
|
}
|
|
2026
|
+
function findSheetAssetSpecifiers(sheets) {
|
|
2027
|
+
return [.../* @__PURE__ */ new Set([
|
|
2028
|
+
...findAssetSpecifiers(sheets.variableCss),
|
|
2029
|
+
...findAssetSpecifiers(sheets.globalCss),
|
|
2030
|
+
...findAssetSpecifiers(sheets.componentCss)
|
|
2031
|
+
])];
|
|
2032
|
+
}
|
|
2033
|
+
/** The one substitution step every emitted sheet passes through. */
|
|
2034
|
+
function substituteSheetAssets(sheets, urlBySpecifier) {
|
|
2035
|
+
return {
|
|
2036
|
+
variableCss: substituteAssetPlaceholders(sheets.variableCss, urlBySpecifier),
|
|
2037
|
+
globalCss: substituteAssetPlaceholders(sheets.globalCss, urlBySpecifier),
|
|
2038
|
+
componentCss: substituteAssetPlaceholders(sheets.componentCss, urlBySpecifier)
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
const UNSUBSTITUTED_ASSET_CODE = "animus.asset.unsubstituted-placeholder";
|
|
2042
|
+
/** A placeholder in emitted CSS is a broken URL in the browser: it fails a
|
|
2043
|
+
* strict build and warns otherwise. */
|
|
2044
|
+
function reportSurvivingAssetPlaceholders(css, report) {
|
|
2045
|
+
const specifiers = findAssetSpecifiers(css);
|
|
2046
|
+
if (specifiers.length === 0) return;
|
|
2047
|
+
const message = `${report.prefix} asset() placeholders reached emitted CSS unsubstituted: ${specifiers.join(", ")} (${UNSUBSTITUTED_ASSET_CODE})`;
|
|
2048
|
+
if (report.strict) throw new Error(message);
|
|
2049
|
+
report.warn(message);
|
|
2050
|
+
}
|
|
2026
2051
|
//#endregion
|
|
2027
2052
|
//#region pipeline/resolve-asset.ts
|
|
2028
2053
|
/**
|
|
@@ -2315,14 +2340,35 @@ function unreadableSourceDiagnostic(relPath, error) {
|
|
|
2315
2340
|
}
|
|
2316
2341
|
/** The collision entry code minted by the system package's merge. */
|
|
2317
2342
|
const VOCABULARY_COLLISION = "animus.vocabulary.collision";
|
|
2343
|
+
/** A theme `@property` registration browsers would ignore; it is not emitted. */
|
|
2344
|
+
const INVALID_PROPERTY_REGISTRATION = "animus.theme.invalid-property-registration";
|
|
2318
2345
|
/** Minted when a sealed kit with registered vocabulary is consumed through
|
|
2319
2346
|
* the deprecated `from()`/`includes:` verbs. */
|
|
2320
2347
|
const VOCABULARY_LEGACY_VERB = "animus.vocabulary.legacy-verb";
|
|
2348
|
+
/** A `var()` fallback that never applies: the property is registered with an
|
|
2349
|
+
* initial value. */
|
|
2350
|
+
const PROPERTY_FALLBACK_SUPPRESSED = "animus.property.fallback-suppressed";
|
|
2351
|
+
/** The same, where the fallback heads a chain of further `var()` reads. */
|
|
2352
|
+
const PROPERTY_FALLBACK_CHAIN_SUPPRESSED = "animus.property.fallback-chain-suppressed";
|
|
2353
|
+
/** A declared property set in keyframes or transitioned without a typed
|
|
2354
|
+
* registration, so it does not interpolate. */
|
|
2355
|
+
const PROPERTY_UNREGISTERED_ANIMATION = "animus.property.unregistered-animation";
|
|
2356
|
+
/** The same, where `allow-discrete` shows interpolation was intended. */
|
|
2357
|
+
const PROPERTY_DISCRETE_ANIMATION = "animus.property.discrete-animation";
|
|
2358
|
+
/** A custom property whose resolved value is `var()` of itself, which makes
|
|
2359
|
+
* it invalid at computed-value time. */
|
|
2360
|
+
const PROPERTY_SELF_REFERENCE = "animus.property.self-reference";
|
|
2321
2361
|
const DIAGNOSTIC_SEVERITY = /* @__PURE__ */ new Map([
|
|
2322
2362
|
[SELECTOR_UNSUPPORTED_SUBJECT, "error"],
|
|
2323
2363
|
[UNREADABLE_SOURCE_FILE, "error"],
|
|
2324
2364
|
[VOCABULARY_COLLISION, "warn"],
|
|
2325
|
-
[VOCABULARY_LEGACY_VERB, "warn"]
|
|
2365
|
+
[VOCABULARY_LEGACY_VERB, "warn"],
|
|
2366
|
+
[INVALID_PROPERTY_REGISTRATION, "error"],
|
|
2367
|
+
[PROPERTY_FALLBACK_SUPPRESSED, "info"],
|
|
2368
|
+
[PROPERTY_FALLBACK_CHAIN_SUPPRESSED, "warn"],
|
|
2369
|
+
[PROPERTY_UNREGISTERED_ANIMATION, "info"],
|
|
2370
|
+
[PROPERTY_DISCRETE_ANIMATION, "warn"],
|
|
2371
|
+
[PROPERTY_SELF_REFERENCE, "warn"]
|
|
2326
2372
|
]);
|
|
2327
2373
|
/** An unlisted code is `warn`: a witness kind from a newer system package
|
|
2328
2374
|
* must not fail the strict build of a host that predates its writer. */
|
|
@@ -2363,6 +2409,19 @@ function vocabularyWitnessDiagnostics(vocabularyWitnessesJson) {
|
|
|
2363
2409
|
});
|
|
2364
2410
|
return diagnostics;
|
|
2365
2411
|
}
|
|
2412
|
+
/** The diagnostics a loaded system's own records carry: vocabulary
|
|
2413
|
+
* witnesses and invalid `@property` registrations. */
|
|
2414
|
+
function systemLoadDiagnostics(system) {
|
|
2415
|
+
const registrations = (system.invalidPropertyRegistrations ?? []).map(({ name, reason }) => ({
|
|
2416
|
+
file: "system",
|
|
2417
|
+
component: name,
|
|
2418
|
+
kind: "warn",
|
|
2419
|
+
message: `@property ${name} was not emitted: ${reason}. Browsers ignore an invalid registration and minifying it fails; fix it where the theme declares ${name} (${INVALID_PROPERTY_REGISTRATION})`,
|
|
2420
|
+
code: INVALID_PROPERTY_REGISTRATION,
|
|
2421
|
+
severity: severityFor(INVALID_PROPERTY_REGISTRATION)
|
|
2422
|
+
}));
|
|
2423
|
+
return [...vocabularyWitnessDiagnostics(system.vocabularyWitnessesJson), ...registrations];
|
|
2424
|
+
}
|
|
2366
2425
|
/**
|
|
2367
2426
|
* The single strict-escalation policy point for both extraction plugins:
|
|
2368
2427
|
* error-severity diagnostics throw together under `strict`, else warn.
|
|
@@ -2374,9 +2433,13 @@ function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
|
2374
2433
|
let line = null;
|
|
2375
2434
|
if (diagnostic.kind === "bail") line = `⚠ ${diagnostic.component} not extracted: ${diagnostic.message}`;
|
|
2376
2435
|
else if (diagnostic.kind === "skip") line = `⚠ ${diagnostic.component}: skipped ${diagnostic.message}`;
|
|
2377
|
-
else if (diagnostic.kind === "warn") line =
|
|
2436
|
+
else if (diagnostic.kind === "warn") line = `${diagnostic.severity === "info" ? "ℹ" : "⚠"} ${diagnostic.file}: ${diagnostic.component}: ${diagnostic.message}`;
|
|
2378
2437
|
if (line === null) continue;
|
|
2379
2438
|
if (diagnostic.code && !diagnostic.message.includes(diagnostic.code)) line += ` [${diagnostic.code}]`;
|
|
2439
|
+
if (diagnostic.severity === "info") {
|
|
2440
|
+
policy.info?.(line);
|
|
2441
|
+
continue;
|
|
2442
|
+
}
|
|
2380
2443
|
if (policy.strict && diagnostic.severity === "error") {
|
|
2381
2444
|
errors.push(`${diagnostic.code ?? "error"} — ${diagnostic.component}: ${diagnostic.message}`);
|
|
2382
2445
|
continue;
|
|
@@ -2386,6 +2449,315 @@ function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
|
2386
2449
|
if (errors.length > 0) throw new Error(`[animus] strict: ${errors.length} error diagnostic(s):\n${errors.join("\n")}`);
|
|
2387
2450
|
}
|
|
2388
2451
|
//#endregion
|
|
2452
|
+
//#region pipeline/property-registrations.ts
|
|
2453
|
+
const PROPERTY_RULE = /@property\s+(--[\w-]+)\s*\{[^}]*\}\n?/g;
|
|
2454
|
+
/** The data types a registration's `syntax` may name. */
|
|
2455
|
+
const SYNTAX_TYPES = /* @__PURE__ */ new Set([
|
|
2456
|
+
"angle",
|
|
2457
|
+
"color",
|
|
2458
|
+
"custom-ident",
|
|
2459
|
+
"image",
|
|
2460
|
+
"integer",
|
|
2461
|
+
"length",
|
|
2462
|
+
"length-percentage",
|
|
2463
|
+
"number",
|
|
2464
|
+
"percentage",
|
|
2465
|
+
"resolution",
|
|
2466
|
+
"string",
|
|
2467
|
+
"time",
|
|
2468
|
+
"transform-function",
|
|
2469
|
+
"transform-list",
|
|
2470
|
+
"url"
|
|
2471
|
+
]);
|
|
2472
|
+
const SYNTAX_COMPONENT = /^(?:<([a-z-]+)>[+#]?|-?[a-zA-Z_][\w-]*)$/;
|
|
2473
|
+
/** The syntax types whose values can carry a font- or container-relative
|
|
2474
|
+
* unit, which makes a typed initial value depend on context. */
|
|
2475
|
+
const DIMENSION_TYPES = /* @__PURE__ */ new Set([
|
|
2476
|
+
"image",
|
|
2477
|
+
"length",
|
|
2478
|
+
"length-percentage",
|
|
2479
|
+
"transform-function",
|
|
2480
|
+
"transform-list"
|
|
2481
|
+
]);
|
|
2482
|
+
const RELATIVE_UNIT = /(?:\d|\.)(?:r?em|r?ex|r?cap|r?ch|r?ic|r?lh|cq(?:w|h|i|b|min|max))\b/i;
|
|
2483
|
+
const SUBSTITUTION = /\b(?:var|env|attr)\(/i;
|
|
2484
|
+
/** Quoted strings and `url()` hold text, never units or substitutions. */
|
|
2485
|
+
const LITERAL_TEXT = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|url\([^)]*\)/gi;
|
|
2486
|
+
/**
|
|
2487
|
+
* Removes the `@property` rules browsers would ignore — an unknown syntax
|
|
2488
|
+
* component, a syntax other than `*` without an initial value, an initial
|
|
2489
|
+
* value that depends on context, or one the syntax does not accept.
|
|
2490
|
+
* Minifying a stylesheet that contains such a rule can also fail.
|
|
2491
|
+
*/
|
|
2492
|
+
function splitInvalidPropertyRegistrations(css) {
|
|
2493
|
+
const invalid = [];
|
|
2494
|
+
return {
|
|
2495
|
+
css: css.replace(PROPERTY_RULE, (rule, name) => {
|
|
2496
|
+
const reason = registrationFailure(rule);
|
|
2497
|
+
if (reason === null) return rule;
|
|
2498
|
+
invalid.push({
|
|
2499
|
+
name,
|
|
2500
|
+
reason
|
|
2501
|
+
});
|
|
2502
|
+
return "";
|
|
2503
|
+
}),
|
|
2504
|
+
invalid
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
/** The registrations in `css`, by custom-property name. */
|
|
2508
|
+
function propertyRegistrations(css) {
|
|
2509
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
2510
|
+
for (const match of css.matchAll(PROPERTY_RULE)) registrations.set(match[1], readRegistration(match[0]));
|
|
2511
|
+
return registrations;
|
|
2512
|
+
}
|
|
2513
|
+
function readRegistration(rule) {
|
|
2514
|
+
return {
|
|
2515
|
+
syntax: /syntax:\s*"([^"]*)"/.exec(rule)?.[1]?.trim() ?? "",
|
|
2516
|
+
initialValue: /initial-value\s*:\s*([^;}]*)/.exec(rule)?.[1]?.trim()
|
|
2517
|
+
};
|
|
2518
|
+
}
|
|
2519
|
+
function registrationFailure(rule) {
|
|
2520
|
+
const { syntax, initialValue } = readRegistration(rule);
|
|
2521
|
+
if (syntax !== "*") {
|
|
2522
|
+
const components = syntax.split("|").map((component) => ({
|
|
2523
|
+
text: component.trim(),
|
|
2524
|
+
match: SYNTAX_COMPONENT.exec(component.trim())
|
|
2525
|
+
}));
|
|
2526
|
+
const unknown = components.find(({ match }) => match === null || match[1] !== void 0 && !SYNTAX_TYPES.has(match[1]));
|
|
2527
|
+
if (unknown !== void 0) return `syntax "${syntax}" has the unknown component "${unknown.text}"`;
|
|
2528
|
+
if (initialValue === void 0) return `syntax "${syntax}" needs an initialValue`;
|
|
2529
|
+
const dimensional = components.some(({ match }) => match?.[1] !== void 0 && DIMENSION_TYPES.has(match[1]));
|
|
2530
|
+
const value = initialValue.replace(LITERAL_TEXT, "");
|
|
2531
|
+
if (SUBSTITUTION.test(value) || dimensional && RELATIVE_UNIT.test(value)) return `initialValue "${initialValue}" depends on context; font- and container-relative units and var(), env() and attr() are not allowed`;
|
|
2532
|
+
}
|
|
2533
|
+
try {
|
|
2534
|
+
transform({
|
|
2535
|
+
filename: "animus-registrations.css",
|
|
2536
|
+
code: Buffer.from(rule)
|
|
2537
|
+
});
|
|
2538
|
+
return null;
|
|
2539
|
+
} catch (error) {
|
|
2540
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2541
|
+
return `the CSS parser rejects \`${rule.trim()}\` (${detail})`;
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
//#endregion
|
|
2545
|
+
//#region pipeline/property-diagnostics.ts
|
|
2546
|
+
/**
|
|
2547
|
+
* Reports custom properties that will not behave as their CSS suggests: a
|
|
2548
|
+
* property that refers to itself and, once the system emits an `@property`
|
|
2549
|
+
* rule, a fallback an initial value suppresses and an animated property that
|
|
2550
|
+
* cannot interpolate. The CSS itself is never changed.
|
|
2551
|
+
*/
|
|
2552
|
+
function checkCustomProperties(input) {
|
|
2553
|
+
const registered = propertyRegistrations(input.system.variableCss);
|
|
2554
|
+
const declared = declaredProperties(input.system.contextualVarsJson);
|
|
2555
|
+
const findings = [];
|
|
2556
|
+
const sheets = [{
|
|
2557
|
+
css: input.componentCss,
|
|
2558
|
+
owner: componentOwner(input.manifest)
|
|
2559
|
+
}, {
|
|
2560
|
+
css: input.globalCss,
|
|
2561
|
+
owner: globalOwner
|
|
2562
|
+
}];
|
|
2563
|
+
for (const { css, owner } of sheets) {
|
|
2564
|
+
const parsed = declarations(css);
|
|
2565
|
+
const discreteRules = new Set(parsed.filter((d) => d.property === "transition-behavior" && /\ballow-discrete\b/.test(d.value)).map((d) => d.rule));
|
|
2566
|
+
for (const declaration of parsed) {
|
|
2567
|
+
const found = (code, property, message) => findings.push({
|
|
2568
|
+
code,
|
|
2569
|
+
property,
|
|
2570
|
+
message,
|
|
2571
|
+
owner: owner(declaration)
|
|
2572
|
+
});
|
|
2573
|
+
if (isSelfReference(declaration)) {
|
|
2574
|
+
found(PROPERTY_SELF_REFERENCE, declaration.property, `${declaration.property} resolves to var(${declaration.property}), a reference to itself, so it is invalid at computed-value time. Give it a value other than its own name`);
|
|
2575
|
+
continue;
|
|
2576
|
+
}
|
|
2577
|
+
if (registered.size === 0) continue;
|
|
2578
|
+
for (const read of varReads(declaration.value)) {
|
|
2579
|
+
const registration = registered.get(read.name);
|
|
2580
|
+
if (read.fallback === void 0 || registration?.initialValue === void 0) continue;
|
|
2581
|
+
const chain = read.fallback.startsWith("var(");
|
|
2582
|
+
found(chain ? PROPERTY_FALLBACK_CHAIN_SUPPRESSED : PROPERTY_FALLBACK_SUPPRESSED, read.name, chain ? `var(${read.name}, ${read.fallback}) never reads its fallback chain: ${read.name} is registered with initial-value ${registration.initialValue}, which applies whenever it is unset. Remove the initial value or reorder the chain` : `var(${read.name}, ${read.fallback}) never uses its fallback: ${read.name} is registered with initial-value ${registration.initialValue}, which applies whenever it is unset`);
|
|
2583
|
+
}
|
|
2584
|
+
for (const animated of animatedProperties(declaration, discreteRules)) {
|
|
2585
|
+
if (!declared.has(animated.name)) continue;
|
|
2586
|
+
const reason = interpolationGap(registered.get(animated.name));
|
|
2587
|
+
if (reason === null) continue;
|
|
2588
|
+
if (animated.discrete) found(PROPERTY_DISCRETE_ANIMATION, animated.name, `${animated.name} is transitioned with allow-discrete but ${reason}, so it flips at the midpoint instead of interpolating. Register it with a typed syntax`);
|
|
2589
|
+
else found(PROPERTY_UNREGISTERED_ANIMATION, animated.name, `${animated.name} is ${animated.how} but ${reason}, so it changes in one step instead of interpolating. Register it with a typed syntax to animate it`);
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
return toDiagnostics(findings);
|
|
2594
|
+
}
|
|
2595
|
+
function declaredProperties(contextualVarsJson) {
|
|
2596
|
+
if (!contextualVarsJson) return /* @__PURE__ */ new Set();
|
|
2597
|
+
const byScale = parseInternalWire(contextualVarsJson, "contextualVarsJson (the theme's contextual variable names)");
|
|
2598
|
+
return new Set(Object.values(byScale).flatMap((names) => names.map((name) => `--${name}`)));
|
|
2599
|
+
}
|
|
2600
|
+
/** Declarations in engine-emitted CSS: one `property: value` per `;`. */
|
|
2601
|
+
function declarations(css) {
|
|
2602
|
+
const found = [];
|
|
2603
|
+
const stack = [];
|
|
2604
|
+
let rules = 0;
|
|
2605
|
+
let segment = 0;
|
|
2606
|
+
let parens = 0;
|
|
2607
|
+
let quote = null;
|
|
2608
|
+
const take = (end) => {
|
|
2609
|
+
const text = css.slice(segment, end);
|
|
2610
|
+
const colon = text.indexOf(":");
|
|
2611
|
+
const current = stack[stack.length - 1];
|
|
2612
|
+
if (current === void 0 || colon <= 0) return;
|
|
2613
|
+
found.push({
|
|
2614
|
+
property: text.slice(0, colon).trim(),
|
|
2615
|
+
value: text.slice(colon + 1).replace(/;$/, "").trim(),
|
|
2616
|
+
start: segment + (text.length - text.trimStart().length),
|
|
2617
|
+
end,
|
|
2618
|
+
rule: current.rule,
|
|
2619
|
+
context: stack.map((entry) => entry.prelude)
|
|
2620
|
+
});
|
|
2621
|
+
};
|
|
2622
|
+
for (let i = 0; i < css.length; i += 1) {
|
|
2623
|
+
const c = css[i];
|
|
2624
|
+
if (quote !== null) {
|
|
2625
|
+
if (c === "\\") i += 1;
|
|
2626
|
+
else if (c === quote) quote = null;
|
|
2627
|
+
continue;
|
|
2628
|
+
}
|
|
2629
|
+
if (c === "\"" || c === "'") quote = c;
|
|
2630
|
+
else if (c === "(") parens += 1;
|
|
2631
|
+
else if (c === ")") parens -= 1;
|
|
2632
|
+
else if (parens === 0 && c === "{") {
|
|
2633
|
+
stack.push({
|
|
2634
|
+
prelude: css.slice(segment, i).trim(),
|
|
2635
|
+
rule: rules
|
|
2636
|
+
});
|
|
2637
|
+
rules += 1;
|
|
2638
|
+
segment = i + 1;
|
|
2639
|
+
} else if (parens === 0 && c === ";") {
|
|
2640
|
+
take(i + 1);
|
|
2641
|
+
segment = i + 1;
|
|
2642
|
+
} else if (parens === 0 && c === "}") {
|
|
2643
|
+
take(i);
|
|
2644
|
+
stack.pop();
|
|
2645
|
+
segment = i + 1;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
return found;
|
|
2649
|
+
}
|
|
2650
|
+
function isSelfReference(declaration) {
|
|
2651
|
+
return declaration.property.startsWith("--") && declaration.value.replace(/\s+/g, "") === `var(${declaration.property})`;
|
|
2652
|
+
}
|
|
2653
|
+
/** Every `var()` read in `value`, nested fallbacks included. */
|
|
2654
|
+
function varReads(value) {
|
|
2655
|
+
const reads = [];
|
|
2656
|
+
for (const match of value.matchAll(/var\(\s*(--[\w-]+)\s*/g)) {
|
|
2657
|
+
const after = (match.index ?? 0) + match[0].length;
|
|
2658
|
+
if (value[after] !== ",") {
|
|
2659
|
+
reads.push({
|
|
2660
|
+
name: match[1],
|
|
2661
|
+
fallback: void 0
|
|
2662
|
+
});
|
|
2663
|
+
continue;
|
|
2664
|
+
}
|
|
2665
|
+
let depth = 1;
|
|
2666
|
+
let close = after + 1;
|
|
2667
|
+
for (; close < value.length && depth > 0; close += 1) if (value[close] === "(") depth += 1;
|
|
2668
|
+
else if (value[close] === ")") depth -= 1;
|
|
2669
|
+
reads.push({
|
|
2670
|
+
name: match[1],
|
|
2671
|
+
fallback: value.slice(after + 1, close - 1).trim()
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
return reads;
|
|
2675
|
+
}
|
|
2676
|
+
/** Custom properties this declaration sets in a keyframe or names in a
|
|
2677
|
+
* transition. */
|
|
2678
|
+
function animatedProperties(declaration, discreteRules) {
|
|
2679
|
+
const keyframes = declaration.context.find((prelude) => prelude.startsWith("@keyframes"));
|
|
2680
|
+
if (keyframes !== void 0 && declaration.property.startsWith("--")) return [{
|
|
2681
|
+
name: declaration.property,
|
|
2682
|
+
how: `set in ${keyframes}`,
|
|
2683
|
+
discrete: false
|
|
2684
|
+
}];
|
|
2685
|
+
if (declaration.property !== "transition" && declaration.property !== "transition-property") return [];
|
|
2686
|
+
return topLevelItems(declaration.value).flatMap((item) => {
|
|
2687
|
+
const property = item.trim().split(/\s+/)[0] ?? "";
|
|
2688
|
+
return property.startsWith("--") ? [{
|
|
2689
|
+
name: property,
|
|
2690
|
+
how: "transitioned",
|
|
2691
|
+
discrete: /\ballow-discrete\b/.test(item) || discreteRules.has(declaration.rule)
|
|
2692
|
+
}] : [];
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
function topLevelItems(value) {
|
|
2696
|
+
const items = [];
|
|
2697
|
+
let depth = 0;
|
|
2698
|
+
let start = 0;
|
|
2699
|
+
for (let i = 0; i < value.length; i += 1) if (value[i] === "(") depth += 1;
|
|
2700
|
+
else if (value[i] === ")") depth -= 1;
|
|
2701
|
+
else if (value[i] === "," && depth === 0) {
|
|
2702
|
+
items.push(value.slice(start, i));
|
|
2703
|
+
start = i + 1;
|
|
2704
|
+
}
|
|
2705
|
+
items.push(value.slice(start));
|
|
2706
|
+
return items;
|
|
2707
|
+
}
|
|
2708
|
+
/** Why a property cannot interpolate, or `null` when it can. */
|
|
2709
|
+
function interpolationGap(registration) {
|
|
2710
|
+
if (registration === void 0) return "it is not registered";
|
|
2711
|
+
if (registration.syntax === "*") return "it is registered with the universal syntax \"*\"";
|
|
2712
|
+
return null;
|
|
2713
|
+
}
|
|
2714
|
+
function componentOwner(manifest) {
|
|
2715
|
+
const components = Object.values(manifest.components);
|
|
2716
|
+
return (declaration) => {
|
|
2717
|
+
const selector = [...declaration.context].reverse().find((prelude) => !prelude.startsWith("@"));
|
|
2718
|
+
const classes = (selector ?? "").match(/\.-?[_a-zA-Z][\w-]*/g) ?? [];
|
|
2719
|
+
for (const dotted of classes) {
|
|
2720
|
+
const name = dotted.slice(1);
|
|
2721
|
+
const owner = components.find((component) => name === component.class_name || name.startsWith(`${component.class_name}--`) || component.replacement.includes(`"${name}"`));
|
|
2722
|
+
if (owner) return {
|
|
2723
|
+
file: owner.file,
|
|
2724
|
+
component: owner.binding
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
return {
|
|
2728
|
+
file: "styles",
|
|
2729
|
+
component: selector ?? "stylesheet"
|
|
2730
|
+
};
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
function globalOwner(declaration) {
|
|
2734
|
+
const keyframes = declaration.context.find((prelude) => prelude.startsWith("@keyframes"));
|
|
2735
|
+
const selector = [...declaration.context].reverse().find((prelude) => !prelude.startsWith("@"));
|
|
2736
|
+
return {
|
|
2737
|
+
file: "system",
|
|
2738
|
+
component: keyframes ?? selector ?? "global styles"
|
|
2739
|
+
};
|
|
2740
|
+
}
|
|
2741
|
+
/** One diagnostic per code, property and owner. */
|
|
2742
|
+
function toDiagnostics(findings) {
|
|
2743
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2744
|
+
const diagnostics = [];
|
|
2745
|
+
for (const finding of findings) {
|
|
2746
|
+
const key = `${finding.code}|${finding.property}|${finding.owner.file}|${finding.owner.component}`;
|
|
2747
|
+
if (seen.has(key)) continue;
|
|
2748
|
+
seen.add(key);
|
|
2749
|
+
diagnostics.push({
|
|
2750
|
+
file: finding.owner.file,
|
|
2751
|
+
component: finding.owner.component,
|
|
2752
|
+
kind: "warn",
|
|
2753
|
+
message: `${finding.message} (${finding.code})`,
|
|
2754
|
+
code: finding.code,
|
|
2755
|
+
severity: severityFor(finding.code)
|
|
2756
|
+
});
|
|
2757
|
+
}
|
|
2758
|
+
return diagnostics;
|
|
2759
|
+
}
|
|
2760
|
+
//#endregion
|
|
2389
2761
|
//#region pipeline/unit-fallback.ts
|
|
2390
2762
|
/** A digit run after one of these continues a word (`#b1b1b7`, `ss01`,
|
|
2391
2763
|
* `U+0025`), so it is not a bare number. The extractor predicts this pass
|
|
@@ -2482,9 +2854,21 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
2482
2854
|
const extractMs = Math.round(performance.now() - t);
|
|
2483
2855
|
t = performance.now();
|
|
2484
2856
|
const manifest = JSON.parse(manifestJson);
|
|
2857
|
+
const propertyDiagnostics = checkCustomProperties({
|
|
2858
|
+
system: opts.system,
|
|
2859
|
+
manifest,
|
|
2860
|
+
componentCss: applyUnitFallback(manifest.css),
|
|
2861
|
+
globalCss: manifest.sheets.global
|
|
2862
|
+
});
|
|
2485
2863
|
surfaceManifestDiagnostics(manifest, opts.warn, {
|
|
2486
2864
|
strict: opts.strict,
|
|
2487
|
-
|
|
2865
|
+
info: opts.info,
|
|
2866
|
+
prepend: [
|
|
2867
|
+
...collectSelectorAliasDiagnostics(opts.system.selectorAliasesJson),
|
|
2868
|
+
...systemLoadDiagnostics(opts.system),
|
|
2869
|
+
...propertyDiagnostics,
|
|
2870
|
+
...opts.extraDiagnostics ?? []
|
|
2871
|
+
]
|
|
2488
2872
|
});
|
|
2489
2873
|
const parseMs = Math.round(performance.now() - t);
|
|
2490
2874
|
return {
|
|
@@ -2587,7 +2971,8 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
2587
2971
|
const config = loadSystemModule(opts.systemPath, opts.rootDir);
|
|
2588
2972
|
let scalesJson = config.scalesJson;
|
|
2589
2973
|
let variableMapJson = config.variableMapJson;
|
|
2590
|
-
|
|
2974
|
+
const registrations = splitInvalidPropertyRegistrations(config.variableCss);
|
|
2975
|
+
let variableCss = registrations.css;
|
|
2591
2976
|
let contextualVarsJson = config.contextualVarsJson || null;
|
|
2592
2977
|
let declarationScalesJson = config.declarationScalesJson || null;
|
|
2593
2978
|
if (opts.prefix) {
|
|
@@ -2616,6 +3001,8 @@ function loadSystemConfig(engineApi, opts) {
|
|
|
2616
3001
|
sourceThemeManifestsJson: config.sourceThemeManifests || null
|
|
2617
3002
|
};
|
|
2618
3003
|
if (declarationScalesJson) system.declarationScalesJson = declarationScalesJson;
|
|
3004
|
+
if (config.propertyRecordsJson) system.propertyRecordsJson = config.propertyRecordsJson;
|
|
3005
|
+
if (registrations.invalid.length > 0) system.invalidPropertyRegistrations = registrations.invalid;
|
|
2619
3006
|
return system;
|
|
2620
3007
|
}
|
|
2621
3008
|
//#endregion
|
|
@@ -2699,31 +3086,6 @@ function buildSystemPropsModule(opts) {
|
|
|
2699
3086
|
return `export const systemPropMap = ${opts.systemPropMapJson};\nexport const systemPropGroups = ${opts.groupRegistryJson};\nexport const dynamicPropConfig = ${JSON.stringify(dynamicPropConfig)};\nexport const transforms = ${transformsSource(opts.admittedTransforms)};\n` + (opts.typedSystemProps.length > 0 ? `export const typedSystemProps = ${JSON.stringify(opts.typedSystemProps)};\n` : "");
|
|
2700
3087
|
}
|
|
2701
3088
|
//#endregion
|
|
2702
|
-
//#region pipeline/timing-waterfall.ts
|
|
2703
|
-
const RUST_TIMING_PHASES = [
|
|
2704
|
-
["parseAndWalk", "parse+walk"],
|
|
2705
|
-
["importResolution", "imports"],
|
|
2706
|
-
["extensionProvenance", "provenance"],
|
|
2707
|
-
["topologicalSort", "topo-sort"],
|
|
2708
|
-
["chainEvaluation", "chains"],
|
|
2709
|
-
["jsxScanning", "jsx-scan"],
|
|
2710
|
-
["systemPropAggregation", "sys-props"],
|
|
2711
|
-
["usageLedger", "usage"],
|
|
2712
|
-
["reconciliation", "reconcile"],
|
|
2713
|
-
["cssGeneration", "css-gen"],
|
|
2714
|
-
["manifestSerialization", "serialize"]
|
|
2715
|
-
];
|
|
2716
|
-
function formatRustTimingWaterfall(timing, opts) {
|
|
2717
|
-
const lines = [];
|
|
2718
|
-
for (const [key, label] of RUST_TIMING_PHASES) {
|
|
2719
|
-
const ms = timing[key] ?? 0;
|
|
2720
|
-
const pad = " ".repeat(Math.max(0, opts.labelWidth - label.length));
|
|
2721
|
-
const extra = key === "parseAndWalk" ? ` (${timing.fileCount ?? 0} files, ${timing.cacheHits ?? 0} cached)` : "";
|
|
2722
|
-
lines.push(`${opts.indent}${label}${pad}${String(ms).padStart(5)}ms${extra}`);
|
|
2723
|
-
}
|
|
2724
|
-
return lines;
|
|
2725
|
-
}
|
|
2726
|
-
//#endregion
|
|
2727
3089
|
//#region pipeline/tsconfig-paths.ts
|
|
2728
3090
|
/**
|
|
2729
3091
|
* tsconfig `paths` → alias pairs, for drivers with no live bundler config.
|
|
@@ -2990,4 +3352,4 @@ function realpathThroughNearestExistingAncestor(path) {
|
|
|
2990
3352
|
}
|
|
2991
3353
|
}
|
|
2992
3354
|
//#endregion
|
|
2993
|
-
export {
|
|
3355
|
+
export { compareDiscoveryOrder as $, buildPathAliasesJson as A, collectExternalPackageSources as B, surfaceManifestDiagnostics as C, contentHash as Ct, vocabularyWitnessDiagnostics as D, stripLeadingLayerDeclaration as Dt, unresolvedParentName as E, assembleStylesheet as Et, findSheetAssetSpecifiers as F, isExcludedPackageRelativePath as G, extractSystemFilePackages as H, reportSurvivingAssetPlaceholders as I, unresolvableIncludesMessage as J, resolveAbsolutePathSpecifier as K, substituteAssetPlaceholders as L, resolveAssetFile as M, resolveThroughPathAliases as N, postProcessCss as O, validateLayerOrder as Ot, findAssetSpecifiers as P, sharesVolumeRoot as Q, substituteSheetAssets as R, isUnresolvedParentDrop as S, preprocessMdx as St, unreadableSourceDiagnostic as T, ANIMUS_LAYERS as Tt, findPackageRoot as U, excludeCollectedPackages as V, firstOwners as W, createSourceIdentity as X, walkPackageSources as Y, isPathWithinRoot as Z, runProjectAnalysis as _, projectExternalFileOwners as _t, assertNoErrorDiagnostics as a, REPLACEABLE_DEFAULT_EXCLUDE as at, VOCABULARY_COLLISION as b, ENGINE_TRANSFORM_EXTENSIONS as bt, buildDynamicPropConfig as c, createExcludeMatcher as ct, applyPrefix as d, RETIRED_ENGINE_MESSAGE as dt, discoverFiles as et, serializeStaticCss as f, assertNoRetiredEngineSelection as ft, clearEngineCache as g, parseFilesJson as gt, buildAnalysisInputs as h, isAdvisorySourceDiagnostic as ht, snapshotFilePlans as i, DRIVER_NAMESPACES as it, enforceExternalTokenContracts as j, resolveLightningTargets as k, __require as kt, runStructuralSelfCheck as l, resolveMode as lt, stableStringify as m, ingestSourceEntries as mt, diffFilePlans as n, CORE_OPTION_KEYS as nt, readTsconfigAliasPairs as o, STRUCTURAL_EXCLUDE as ot, camelToKebab as p, createV2EngineApi as pt, staleDistIncludesMessage as q, hashReplacementPlans as r, DEFAULT_EXCLUDE as rt, buildSystemPropsModule as s, assertKnownOptionKeys as st, toWatchKeys as t, AnimusConfigError as tt, loadSystemConfig as u, resolveVerbosity as ut, applyUnitFallback as v, adaptSvelteSource as vt, systemLoadDiagnostics as w, buildAnalyzeProjectArgs as wt, VOCABULARY_LEGACY_VERB as x, isEngineTransformExtension as xt, INVALID_PROPERTY_REGISTRATION as y, DEFAULT_EXTENSIONS as yt, createSourceCorpus as z };
|