@animus-ui/extract 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/crates/extract-v2/animus-extract-v2.darwin-arm64.node +0 -0
- package/crates/extract-v2/animus-extract-v2.linux-arm64-gnu.node +0 -0
- package/crates/extract-v2/animus-extract-v2.linux-x64-gnu.node +0 -0
- package/crates/extract-v2/index.d.ts +16 -5
- package/dist/engine-adapter.d.ts +2 -0
- package/dist/engine-adapter.d.ts.map +1 -1
- package/dist/external-keyframes.d.ts +23 -0
- package/dist/external-keyframes.d.ts.map +1 -0
- package/dist/index.cjs +147 -8
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +145 -9
- package/dist/manifest-diagnostics.d.ts +36 -4
- package/dist/manifest-diagnostics.d.ts.map +1 -1
- package/dist/run-analysis.d.ts +5 -0
- package/dist/run-analysis.d.ts.map +1 -1
- package/package.json +3 -3
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -58,7 +58,7 @@ export interface EngineOptions {
|
|
|
58
58
|
/** Selector aliases JSON (v1 `selector_aliases_json`). */
|
|
59
59
|
selectorAliasesJson?: string
|
|
60
60
|
/**
|
|
61
|
-
* Condition aliases JSON (
|
|
61
|
+
* Condition aliases JSON (the `conditionAliases` manifest field):
|
|
62
62
|
* `{ "_motionReduce": { "value": "@media …", "order": 500, "kind":
|
|
63
63
|
* "media" } }`. Absent = no registrations.
|
|
64
64
|
*/
|
|
@@ -98,10 +98,10 @@ export interface EngineOptions {
|
|
|
98
98
|
export declare function engineVersion(): string
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Full per-file fact extraction
|
|
101
|
+
* Full per-file fact extraction: chains + eagerly evaluated
|
|
102
102
|
* stages + statics + raw usage facts + compose families — one parse per
|
|
103
103
|
* file. The store (and every AST) is dropped when this call returns; the
|
|
104
|
-
*
|
|
104
|
+
* invariant is that no program() read happens after
|
|
105
105
|
* cross-file facts resolve.
|
|
106
106
|
*/
|
|
107
107
|
export declare function extractFacts(fileEntriesJson: string): string
|
|
@@ -118,8 +118,8 @@ export interface NapiSystemConfig {
|
|
|
118
118
|
selectorAliases?: string
|
|
119
119
|
selectorOrder?: string
|
|
120
120
|
/**
|
|
121
|
-
* Condition alias map JSON (
|
|
122
|
-
* `{ value, order, kind }`. Absent when the system registers none.
|
|
121
|
+
* Condition alias map JSON (the `conditionAliases` manifest field):
|
|
122
|
+
* alias → `{ value, order, kind }`. Absent when the system registers none.
|
|
123
123
|
*/
|
|
124
124
|
conditionAliases?: string
|
|
125
125
|
globalStyleBlocks?: string
|
|
@@ -138,3 +138,14 @@ export interface NapiSystemConfig {
|
|
|
138
138
|
*/
|
|
139
139
|
sourceThemeManifests?: string
|
|
140
140
|
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Scan one module entry for named `Keyframes` collection exports — the
|
|
144
|
+
* keyframes-only carve-out for external package entries. The
|
|
145
|
+
* entry evaluates through the same loader pipeline as a system module, but
|
|
146
|
+
* nothing except `__brand === 'Keyframes'` exports is read from it; the
|
|
147
|
+
* consumer's configured system remains the singular config authority.
|
|
148
|
+
* Returns the `{ exportName: { keyName: { name, frames } } }` JSON, or None
|
|
149
|
+
* when the entry exports no collections.
|
|
150
|
+
*/
|
|
151
|
+
export declare function scanKeyframesExports(entryPath: string, rootDir: string): string | null
|
package/dist/engine-adapter.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface TransformFileResult {
|
|
|
40
40
|
*/
|
|
41
41
|
export interface EngineApi {
|
|
42
42
|
loadSystemModule: (...args: unknown[]) => any;
|
|
43
|
+
/** Keyframes-only scan of an external package entry. */
|
|
44
|
+
scanKeyframesExports: (entryPath: string, rootDir: string) => string | null;
|
|
43
45
|
analyzeProject: (filesJson: string, scalesJson: string, variableMapJson: string, contextualVarsJson: string | null, propConfigJson: string, groupRegistryJson: string, packageResolutionJson: string, devMode: boolean, emitterConfigJson: string | null, selectorAliasesJson: string | null, selectorOrderJson: string | null, globalStyleBlocksJson: string | null, pathAliasesJson: string | null, keyframesJson: string | null, staticCssJson: string | null, conditionAliasesJson: string | null, externalDirsJson: string | null) => string;
|
|
44
46
|
transformFile: (source: string, path: string, manifest: string) => TransformFileResult;
|
|
45
47
|
clearAnalysisCache: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-adapter.d.ts","sourceRoot":"","sources":["../pipeline/engine-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,6DAA6D;AAC7D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IAIxB,gBAAgB,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC;IAC9C,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,kBAAkB,EAAE,MAAM,GAAG,IAAI,EACjC,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,EACzB,qBAAqB,EAAE,MAAM,EAC7B,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,mBAAmB,EAAE,MAAM,GAAG,IAAI,EAClC,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,qBAAqB,EAAE,MAAM,GAAG,IAAI,EACpC,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,gBAAgB,EAAE,MAAM,GAAG,IAAI,KAC5B,MAAM,CAAC;IACZ,aAAa,EAAE,CACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,KACb,mBAAmB,CAAC;IACzB,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,IAAI,eAAe,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IAChD,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1D,cAAc,IAAI,OAAO,CAAC;IAC1B,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACtC;AAED,4EAA4E;AAE5E,KAAK,kBAAkB,GAAG,GAAG,CAAC;AA2B9B,MAAM,WAAW,mBAAmB;IAClC;kDAC8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd;;2DAEuD;IACvD,IAAI,IAAI,OAAO,CAAC;IAChB;qDACiD;IACjD,gBAAgB,IAAI,kBAAkB,CAAC;IACvC,qEAAqE;IACrE,KAAK,EAAE,kBAAkB,CAAC;IAC1B;;;;gBAIY;IACZ,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;+CAG2C;IAC3C,kBAAkB,CAAC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"engine-adapter.d.ts","sourceRoot":"","sources":["../pipeline/engine-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,6DAA6D;AAC7D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IAIxB,gBAAgB,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC;IAC9C,wDAAwD;IACxD,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC5E,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,kBAAkB,EAAE,MAAM,GAAG,IAAI,EACjC,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,EACzB,qBAAqB,EAAE,MAAM,EAC7B,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,mBAAmB,EAAE,MAAM,GAAG,IAAI,EAClC,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,qBAAqB,EAAE,MAAM,GAAG,IAAI,EACpC,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,gBAAgB,EAAE,MAAM,GAAG,IAAI,KAC5B,MAAM,CAAC;IACZ,aAAa,EAAE,CACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,KACb,mBAAmB,CAAC;IACzB,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,IAAI,eAAe,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IAChD,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1D,cAAc,IAAI,OAAO,CAAC;IAC1B,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACtC;AAED,4EAA4E;AAE5E,KAAK,kBAAkB,GAAG,GAAG,CAAC;AA2B9B,MAAM,WAAW,mBAAmB;IAClC;kDAC8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd;;2DAEuD;IACvD,IAAI,IAAI,OAAO,CAAC;IAChB;qDACiD;IACjD,gBAAgB,IAAI,kBAAkB,CAAC;IACvC,qEAAqE;IACrE,KAAK,EAAE,kBAAkB,CAAC;IAC1B;;;;gBAIY;IACZ,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;+CAG2C;IAC3C,kBAAkB,CAAC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,SAAS,CAsH5E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ManifestDiagnostic } from './manifest-diagnostics';
|
|
2
|
+
/** Stable codes for external keyframes discovery. */
|
|
3
|
+
export declare const KEYFRAMES_EXTERNAL_ENTRY_FAILED = "animus.keyframes.external-entry-failed";
|
|
4
|
+
export declare const KEYFRAMES_EXPORT_COLLISION = "animus.keyframes.export-collision";
|
|
5
|
+
export interface ExternalKeyframesMerge {
|
|
6
|
+
/** Consumer collections merged with every discovered external collection
|
|
7
|
+
* (consumer wins on name collisions); `null` when nothing exists. */
|
|
8
|
+
keyframesJson: string | null;
|
|
9
|
+
/** Warn-severity diagnostics for failed entries and name collisions —
|
|
10
|
+
* surfaced through the shared manifest-diagnostics policy point. */
|
|
11
|
+
diagnostics: ManifestDiagnostic[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Merge `Keyframes` collections discovered from external package entries into
|
|
15
|
+
* the consumer system's collections. Keyframes are the sole carve-out from
|
|
16
|
+
* the consumer-config singular-authority rule: nothing but branded
|
|
17
|
+
* collections is read from an entry, an entry that fails to evaluate
|
|
18
|
+
* degrades to a coded diagnostic naming it, and a collection whose export
|
|
19
|
+
* name collides keeps the earlier (consumer-first) collection with a coded
|
|
20
|
+
* diagnostic instead of silently reordering names.
|
|
21
|
+
*/
|
|
22
|
+
export declare function mergeExternalKeyframes(scan: (entryPath: string, rootDir: string) => string | null, consumerKeyframesJson: string | null | undefined, externalEntries: Iterable<string>, rootDir: string): ExternalKeyframesMerge;
|
|
23
|
+
//# sourceMappingURL=external-keyframes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-keyframes.d.ts","sourceRoot":"","sources":["../pipeline/external-keyframes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,qDAAqD;AACrD,eAAO,MAAM,+BAA+B,2CACF,CAAC;AAC3C,eAAO,MAAM,0BAA0B,sCAAsC,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC;0EACsE;IACtE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;yEACqE;IACrE,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,EAC3D,qBAAqB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChD,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,EACjC,OAAO,EAAE,MAAM,GACd,sBAAsB,CAoExB"}
|
package/dist/index.cjs
CHANGED
|
@@ -141,6 +141,7 @@ function createV2EngineApi(deps) {
|
|
|
141
141
|
const native = loadNativeEngine();
|
|
142
142
|
return {
|
|
143
143
|
loadSystemModule: (...args) => native.loadSystemModule(...args),
|
|
144
|
+
scanKeyframesExports: (entryPath, rootDir) => native.scanKeyframesExports(entryPath, rootDir) ?? null,
|
|
144
145
|
analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson) => {
|
|
145
146
|
const filesJson = deps.rehydrateFilesJson ? deps.rehydrateFilesJson(filesJsonRaw) : filesJsonRaw;
|
|
146
147
|
const sent = /* @__PURE__ */ new Map();
|
|
@@ -232,6 +233,77 @@ function contentHash(source) {
|
|
|
232
233
|
return (0, crypto.createHash)("md5").update(source).digest("hex");
|
|
233
234
|
}
|
|
234
235
|
//#endregion
|
|
236
|
+
//#region pipeline/external-keyframes.ts
|
|
237
|
+
/** Stable codes for external keyframes discovery. */
|
|
238
|
+
const KEYFRAMES_EXTERNAL_ENTRY_FAILED = "animus.keyframes.external-entry-failed";
|
|
239
|
+
const KEYFRAMES_EXPORT_COLLISION = "animus.keyframes.export-collision";
|
|
240
|
+
/**
|
|
241
|
+
* Merge `Keyframes` collections discovered from external package entries into
|
|
242
|
+
* the consumer system's collections. Keyframes are the sole carve-out from
|
|
243
|
+
* the consumer-config singular-authority rule: nothing but branded
|
|
244
|
+
* collections is read from an entry, an entry that fails to evaluate
|
|
245
|
+
* degrades to a coded diagnostic naming it, and a collection whose export
|
|
246
|
+
* name collides keeps the earlier (consumer-first) collection with a coded
|
|
247
|
+
* diagnostic instead of silently reordering names.
|
|
248
|
+
*/
|
|
249
|
+
function mergeExternalKeyframes(scan, consumerKeyframesJson, externalEntries, rootDir) {
|
|
250
|
+
const merged = {};
|
|
251
|
+
if (consumerKeyframesJson) try {
|
|
252
|
+
Object.assign(merged, JSON.parse(consumerKeyframesJson));
|
|
253
|
+
} catch {
|
|
254
|
+
return {
|
|
255
|
+
keyframesJson: consumerKeyframesJson,
|
|
256
|
+
diagnostics: []
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const diagnostics = [];
|
|
260
|
+
const seenEntries = /* @__PURE__ */ new Set();
|
|
261
|
+
for (const entryPath of externalEntries) {
|
|
262
|
+
if (seenEntries.has(entryPath)) continue;
|
|
263
|
+
seenEntries.add(entryPath);
|
|
264
|
+
let scanned;
|
|
265
|
+
try {
|
|
266
|
+
scanned = scan(entryPath, rootDir);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
diagnostics.push({
|
|
269
|
+
file: entryPath,
|
|
270
|
+
component: "keyframes",
|
|
271
|
+
kind: "warn",
|
|
272
|
+
message: `external package entry failed the keyframes scan — its collections are invisible to extraction: ${String(error)}. Keyframe collections must be reachable from the package's definition entry without evaluating framework re-exports: export them (directly or as a named re-export) from the definition entry, and avoid \`export *\` of framework packages there (${KEYFRAMES_EXTERNAL_ENTRY_FAILED})`,
|
|
273
|
+
code: KEYFRAMES_EXTERNAL_ENTRY_FAILED,
|
|
274
|
+
severity: "warn"
|
|
275
|
+
});
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (!scanned) continue;
|
|
279
|
+
let collections;
|
|
280
|
+
try {
|
|
281
|
+
collections = JSON.parse(scanned);
|
|
282
|
+
} catch {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
for (const [exportName, collection] of Object.entries(collections)) {
|
|
286
|
+
const existing = merged[exportName];
|
|
287
|
+
if (existing !== void 0) {
|
|
288
|
+
if (JSON.stringify(existing) !== JSON.stringify(collection)) diagnostics.push({
|
|
289
|
+
file: entryPath,
|
|
290
|
+
component: exportName,
|
|
291
|
+
kind: "warn",
|
|
292
|
+
message: `keyframes collection export '${exportName}' collides with an earlier collection of the same name — the earlier one wins (${KEYFRAMES_EXPORT_COLLISION})`,
|
|
293
|
+
code: KEYFRAMES_EXPORT_COLLISION,
|
|
294
|
+
severity: "warn"
|
|
295
|
+
});
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
merged[exportName] = collection;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
keyframesJson: Object.keys(merged).length > 0 ? JSON.stringify(merged) : null,
|
|
303
|
+
diagnostics
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
//#endregion
|
|
235
307
|
//#region pipeline/discover-files.ts
|
|
236
308
|
/**
|
|
237
309
|
* Recursively discover source files under `dir`, skipping any path that
|
|
@@ -1007,17 +1079,78 @@ function postProcessCss(css, opts) {
|
|
|
1007
1079
|
}
|
|
1008
1080
|
//#endregion
|
|
1009
1081
|
//#region pipeline/manifest-diagnostics.ts
|
|
1082
|
+
/** Stable code for selector forms with no substitutable subject.
|
|
1083
|
+
* Mirrors the Rust constant in `extract-v2/src/eval.rs`. */
|
|
1084
|
+
const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
1085
|
+
/** True when the selector string carries at least one substitutable `&`
|
|
1086
|
+
* subject outside quoted text (mirrors the Rust `selector_subject` walk —
|
|
1087
|
+
* ancestor, leading, and repeated subjects all count; a `&` inside a
|
|
1088
|
+
* quoted attribute value does not). */
|
|
1089
|
+
function hasSelectorSubject(value) {
|
|
1090
|
+
let quote = null;
|
|
1091
|
+
for (const c of value) if (quote !== null) {
|
|
1092
|
+
if (c === quote) quote = null;
|
|
1093
|
+
} else if (c === "\"" || c === "'") quote = c;
|
|
1094
|
+
else if (c === "&") return true;
|
|
1095
|
+
return false;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Synthesize coded diagnostics for registered selector-alias values that
|
|
1099
|
+
* look selector-shaped (`&` present) but carry no substitutable subject —
|
|
1100
|
+
* every `&` sits inside quoted text, so there is nothing to anchor the
|
|
1101
|
+
* class to. Ancestor-prefixed and repeated subjects are supported and pass
|
|
1102
|
+
* validation. The system-config boundary is where these must fail loud
|
|
1103
|
+
* (alias values never reach the evaluator's key guard).
|
|
1104
|
+
*/
|
|
1105
|
+
function collectSelectorAliasDiagnostics(selectorAliasesJson) {
|
|
1106
|
+
if (!selectorAliasesJson) return [];
|
|
1107
|
+
let aliases;
|
|
1108
|
+
try {
|
|
1109
|
+
aliases = JSON.parse(selectorAliasesJson);
|
|
1110
|
+
} catch {
|
|
1111
|
+
return [];
|
|
1112
|
+
}
|
|
1113
|
+
const diagnostics = [];
|
|
1114
|
+
for (const [name, value] of Object.entries(aliases)) {
|
|
1115
|
+
if (typeof value !== "string") continue;
|
|
1116
|
+
if (value.includes("&") && !hasSelectorSubject(value)) diagnostics.push({
|
|
1117
|
+
file: "system",
|
|
1118
|
+
component: name,
|
|
1119
|
+
kind: "warn",
|
|
1120
|
+
message: `selector alias '${name}' value '${value}' has no substitutable '&' subject outside quoted text (${SELECTOR_UNSUPPORTED_SUBJECT})`,
|
|
1121
|
+
code: SELECTOR_UNSUPPORTED_SUBJECT,
|
|
1122
|
+
severity: "error"
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
return diagnostics;
|
|
1126
|
+
}
|
|
1010
1127
|
/**
|
|
1011
1128
|
* Surface extraction-manifest diagnostics through a plugin's warn channel.
|
|
1012
1129
|
*
|
|
1013
|
-
* Single authoritative copy for both extraction plugins
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1130
|
+
* Single authoritative copy for both extraction plugins — and the single
|
|
1131
|
+
* strict-escalation policy point: error-severity diagnostics throw one
|
|
1132
|
+
* Error naming every offender when `policy.strict`, and print as warnings
|
|
1133
|
+
* otherwise. Surfaces `bail` (component not extracted), `skip` (component
|
|
1134
|
+
* skipped), and `warn` kinds; unknown kinds stay silent. Printed lines
|
|
1135
|
+
* include the diagnostic code when the message doesn't already carry it.
|
|
1016
1136
|
*/
|
|
1017
|
-
function surfaceManifestDiagnostics(manifest, warn) {
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1137
|
+
function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
1138
|
+
const errors = [];
|
|
1139
|
+
const diagnostics = policy.prepend?.length ? [...policy.prepend, ...manifest.diagnostics ?? []] : manifest.diagnostics ?? [];
|
|
1140
|
+
for (const diagnostic of diagnostics) {
|
|
1141
|
+
let line = null;
|
|
1142
|
+
if (diagnostic.kind === "bail") line = `⚠ ${diagnostic.component} not extracted: ${diagnostic.message}`;
|
|
1143
|
+
else if (diagnostic.kind === "skip") line = `⚠ ${diagnostic.component}: skipped ${diagnostic.message}`;
|
|
1144
|
+
else if (diagnostic.kind === "warn") line = `⚠ ${diagnostic.file}: ${diagnostic.component}: ${diagnostic.message}`;
|
|
1145
|
+
if (line === null) continue;
|
|
1146
|
+
if (diagnostic.code && !diagnostic.message.includes(diagnostic.code)) line += ` [${diagnostic.code}]`;
|
|
1147
|
+
if (policy.strict && diagnostic.severity === "error") {
|
|
1148
|
+
errors.push(`${diagnostic.code ?? "error"} — ${diagnostic.component}: ${diagnostic.message}`);
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
warn(line);
|
|
1152
|
+
}
|
|
1153
|
+
if (errors.length > 0) throw new Error(`[animus] strict: ${errors.length} error diagnostic(s):\n${errors.join("\n")}`);
|
|
1021
1154
|
}
|
|
1022
1155
|
//#endregion
|
|
1023
1156
|
//#region pipeline/unit-fallback.ts
|
|
@@ -1113,7 +1246,10 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
1113
1246
|
const extractMs = Math.round(performance.now() - t);
|
|
1114
1247
|
t = performance.now();
|
|
1115
1248
|
const manifest = JSON.parse(manifestJson);
|
|
1116
|
-
surfaceManifestDiagnostics(manifest, opts.warn
|
|
1249
|
+
surfaceManifestDiagnostics(manifest, opts.warn, {
|
|
1250
|
+
strict: opts.strict,
|
|
1251
|
+
prepend: [...collectSelectorAliasDiagnostics(opts.system.selectorAliasesJson), ...opts.extraDiagnostics ?? []]
|
|
1252
|
+
});
|
|
1117
1253
|
const parseMs = Math.round(performance.now() - t);
|
|
1118
1254
|
return {
|
|
1119
1255
|
manifest,
|
|
@@ -1581,6 +1717,8 @@ function realpathThroughNearestExistingAncestor(path) {
|
|
|
1581
1717
|
//#endregion
|
|
1582
1718
|
exports.ANIMUS_LAYERS = ANIMUS_LAYERS;
|
|
1583
1719
|
exports.DEFAULT_EXTENSIONS = DEFAULT_EXTENSIONS;
|
|
1720
|
+
exports.KEYFRAMES_EXPORT_COLLISION = KEYFRAMES_EXPORT_COLLISION;
|
|
1721
|
+
exports.KEYFRAMES_EXTERNAL_ENTRY_FAILED = KEYFRAMES_EXTERNAL_ENTRY_FAILED;
|
|
1584
1722
|
exports.RETIRED_ENGINE_MESSAGE = RETIRED_ENGINE_MESSAGE;
|
|
1585
1723
|
exports.applyPrefix = applyPrefix;
|
|
1586
1724
|
exports.applyUnitFallback = applyUnitFallback;
|
|
@@ -1603,6 +1741,7 @@ exports.findAssetSpecifiers = findAssetSpecifiers;
|
|
|
1603
1741
|
exports.findPackageRoot = findPackageRoot;
|
|
1604
1742
|
exports.formatRustTimingWaterfall = formatRustTimingWaterfall;
|
|
1605
1743
|
exports.loadSystemConfig = loadSystemConfig;
|
|
1744
|
+
exports.mergeExternalKeyframes = mergeExternalKeyframes;
|
|
1606
1745
|
exports.postProcessCss = postProcessCss;
|
|
1607
1746
|
exports.preprocessMdx = preprocessMdx;
|
|
1608
1747
|
exports.readTsconfigAliasPairs = readTsconfigAliasPairs;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type { EngineApi, TransformFileResult, V2EngineAdapterDeps, V2EngineState
|
|
|
6
6
|
export { createV2EngineApi } from './engine-adapter';
|
|
7
7
|
export { assertNoRetiredEngineSelection, RETIRED_ENGINE_MESSAGE, } from './engine-retirement';
|
|
8
8
|
export { contentHash } from './content-hash';
|
|
9
|
+
export { KEYFRAMES_EXPORT_COLLISION, KEYFRAMES_EXTERNAL_ENTRY_FAILED, mergeExternalKeyframes, } from './external-keyframes';
|
|
10
|
+
export type { ExternalKeyframesMerge } from './external-keyframes';
|
|
9
11
|
export { discoverFiles } from './discover-files';
|
|
10
12
|
export type { CollectedExternalPackages, ExternalPackageOutcome, } from './discover-packages';
|
|
11
13
|
export { collectExternalPackageSources, extractSystemFilePackages, findPackageRoot, staleDistIncludesMessage, unresolvableIncludesMessage, } from './discover-packages';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../pipeline/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,8BAA8B,EAC9B,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EACV,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,6BAA6B,EAC7B,yBAAyB,EACzB,eAAe,EACf,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,YAAY,EACV,eAAe,EACf,aAAa,EACb,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EACV,sBAAsB,EACtB,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../pipeline/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -121,6 +121,7 @@ function createV2EngineApi(deps) {
|
|
|
121
121
|
const native = loadNativeEngine();
|
|
122
122
|
return {
|
|
123
123
|
loadSystemModule: (...args) => native.loadSystemModule(...args),
|
|
124
|
+
scanKeyframesExports: (entryPath, rootDir) => native.scanKeyframesExports(entryPath, rootDir) ?? null,
|
|
124
125
|
analyzeProject: (filesJsonRaw, scalesJson, variableMapJson, contextualVarsJson, propConfigJson, groupRegistryJson, packageResolutionJson, devMode, emitterConfigJson, selectorAliasesJson, _selectorOrderJson, globalStyleBlocksJson, pathAliasesJson, keyframesJson, staticCssJson, conditionAliasesJson, externalDirsJson) => {
|
|
125
126
|
const filesJson = deps.rehydrateFilesJson ? deps.rehydrateFilesJson(filesJsonRaw) : filesJsonRaw;
|
|
126
127
|
const sent = /* @__PURE__ */ new Map();
|
|
@@ -212,6 +213,77 @@ function contentHash(source) {
|
|
|
212
213
|
return createHash("md5").update(source).digest("hex");
|
|
213
214
|
}
|
|
214
215
|
//#endregion
|
|
216
|
+
//#region pipeline/external-keyframes.ts
|
|
217
|
+
/** Stable codes for external keyframes discovery. */
|
|
218
|
+
const KEYFRAMES_EXTERNAL_ENTRY_FAILED = "animus.keyframes.external-entry-failed";
|
|
219
|
+
const KEYFRAMES_EXPORT_COLLISION = "animus.keyframes.export-collision";
|
|
220
|
+
/**
|
|
221
|
+
* Merge `Keyframes` collections discovered from external package entries into
|
|
222
|
+
* the consumer system's collections. Keyframes are the sole carve-out from
|
|
223
|
+
* the consumer-config singular-authority rule: nothing but branded
|
|
224
|
+
* collections is read from an entry, an entry that fails to evaluate
|
|
225
|
+
* degrades to a coded diagnostic naming it, and a collection whose export
|
|
226
|
+
* name collides keeps the earlier (consumer-first) collection with a coded
|
|
227
|
+
* diagnostic instead of silently reordering names.
|
|
228
|
+
*/
|
|
229
|
+
function mergeExternalKeyframes(scan, consumerKeyframesJson, externalEntries, rootDir) {
|
|
230
|
+
const merged = {};
|
|
231
|
+
if (consumerKeyframesJson) try {
|
|
232
|
+
Object.assign(merged, JSON.parse(consumerKeyframesJson));
|
|
233
|
+
} catch {
|
|
234
|
+
return {
|
|
235
|
+
keyframesJson: consumerKeyframesJson,
|
|
236
|
+
diagnostics: []
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const diagnostics = [];
|
|
240
|
+
const seenEntries = /* @__PURE__ */ new Set();
|
|
241
|
+
for (const entryPath of externalEntries) {
|
|
242
|
+
if (seenEntries.has(entryPath)) continue;
|
|
243
|
+
seenEntries.add(entryPath);
|
|
244
|
+
let scanned;
|
|
245
|
+
try {
|
|
246
|
+
scanned = scan(entryPath, rootDir);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
diagnostics.push({
|
|
249
|
+
file: entryPath,
|
|
250
|
+
component: "keyframes",
|
|
251
|
+
kind: "warn",
|
|
252
|
+
message: `external package entry failed the keyframes scan — its collections are invisible to extraction: ${String(error)}. Keyframe collections must be reachable from the package's definition entry without evaluating framework re-exports: export them (directly or as a named re-export) from the definition entry, and avoid \`export *\` of framework packages there (${KEYFRAMES_EXTERNAL_ENTRY_FAILED})`,
|
|
253
|
+
code: KEYFRAMES_EXTERNAL_ENTRY_FAILED,
|
|
254
|
+
severity: "warn"
|
|
255
|
+
});
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (!scanned) continue;
|
|
259
|
+
let collections;
|
|
260
|
+
try {
|
|
261
|
+
collections = JSON.parse(scanned);
|
|
262
|
+
} catch {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
for (const [exportName, collection] of Object.entries(collections)) {
|
|
266
|
+
const existing = merged[exportName];
|
|
267
|
+
if (existing !== void 0) {
|
|
268
|
+
if (JSON.stringify(existing) !== JSON.stringify(collection)) diagnostics.push({
|
|
269
|
+
file: entryPath,
|
|
270
|
+
component: exportName,
|
|
271
|
+
kind: "warn",
|
|
272
|
+
message: `keyframes collection export '${exportName}' collides with an earlier collection of the same name — the earlier one wins (${KEYFRAMES_EXPORT_COLLISION})`,
|
|
273
|
+
code: KEYFRAMES_EXPORT_COLLISION,
|
|
274
|
+
severity: "warn"
|
|
275
|
+
});
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
merged[exportName] = collection;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
keyframesJson: Object.keys(merged).length > 0 ? JSON.stringify(merged) : null,
|
|
283
|
+
diagnostics
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
215
287
|
//#region pipeline/discover-files.ts
|
|
216
288
|
/**
|
|
217
289
|
* Recursively discover source files under `dir`, skipping any path that
|
|
@@ -987,17 +1059,78 @@ function postProcessCss(css, opts) {
|
|
|
987
1059
|
}
|
|
988
1060
|
//#endregion
|
|
989
1061
|
//#region pipeline/manifest-diagnostics.ts
|
|
1062
|
+
/** Stable code for selector forms with no substitutable subject.
|
|
1063
|
+
* Mirrors the Rust constant in `extract-v2/src/eval.rs`. */
|
|
1064
|
+
const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
1065
|
+
/** True when the selector string carries at least one substitutable `&`
|
|
1066
|
+
* subject outside quoted text (mirrors the Rust `selector_subject` walk —
|
|
1067
|
+
* ancestor, leading, and repeated subjects all count; a `&` inside a
|
|
1068
|
+
* quoted attribute value does not). */
|
|
1069
|
+
function hasSelectorSubject(value) {
|
|
1070
|
+
let quote = null;
|
|
1071
|
+
for (const c of value) if (quote !== null) {
|
|
1072
|
+
if (c === quote) quote = null;
|
|
1073
|
+
} else if (c === "\"" || c === "'") quote = c;
|
|
1074
|
+
else if (c === "&") return true;
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Synthesize coded diagnostics for registered selector-alias values that
|
|
1079
|
+
* look selector-shaped (`&` present) but carry no substitutable subject —
|
|
1080
|
+
* every `&` sits inside quoted text, so there is nothing to anchor the
|
|
1081
|
+
* class to. Ancestor-prefixed and repeated subjects are supported and pass
|
|
1082
|
+
* validation. The system-config boundary is where these must fail loud
|
|
1083
|
+
* (alias values never reach the evaluator's key guard).
|
|
1084
|
+
*/
|
|
1085
|
+
function collectSelectorAliasDiagnostics(selectorAliasesJson) {
|
|
1086
|
+
if (!selectorAliasesJson) return [];
|
|
1087
|
+
let aliases;
|
|
1088
|
+
try {
|
|
1089
|
+
aliases = JSON.parse(selectorAliasesJson);
|
|
1090
|
+
} catch {
|
|
1091
|
+
return [];
|
|
1092
|
+
}
|
|
1093
|
+
const diagnostics = [];
|
|
1094
|
+
for (const [name, value] of Object.entries(aliases)) {
|
|
1095
|
+
if (typeof value !== "string") continue;
|
|
1096
|
+
if (value.includes("&") && !hasSelectorSubject(value)) diagnostics.push({
|
|
1097
|
+
file: "system",
|
|
1098
|
+
component: name,
|
|
1099
|
+
kind: "warn",
|
|
1100
|
+
message: `selector alias '${name}' value '${value}' has no substitutable '&' subject outside quoted text (${SELECTOR_UNSUPPORTED_SUBJECT})`,
|
|
1101
|
+
code: SELECTOR_UNSUPPORTED_SUBJECT,
|
|
1102
|
+
severity: "error"
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
return diagnostics;
|
|
1106
|
+
}
|
|
990
1107
|
/**
|
|
991
1108
|
* Surface extraction-manifest diagnostics through a plugin's warn channel.
|
|
992
1109
|
*
|
|
993
|
-
* Single authoritative copy for both extraction plugins
|
|
994
|
-
*
|
|
995
|
-
*
|
|
1110
|
+
* Single authoritative copy for both extraction plugins — and the single
|
|
1111
|
+
* strict-escalation policy point: error-severity diagnostics throw one
|
|
1112
|
+
* Error naming every offender when `policy.strict`, and print as warnings
|
|
1113
|
+
* otherwise. Surfaces `bail` (component not extracted), `skip` (component
|
|
1114
|
+
* skipped), and `warn` kinds; unknown kinds stay silent. Printed lines
|
|
1115
|
+
* include the diagnostic code when the message doesn't already carry it.
|
|
996
1116
|
*/
|
|
997
|
-
function surfaceManifestDiagnostics(manifest, warn) {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1117
|
+
function surfaceManifestDiagnostics(manifest, warn, policy = {}) {
|
|
1118
|
+
const errors = [];
|
|
1119
|
+
const diagnostics = policy.prepend?.length ? [...policy.prepend, ...manifest.diagnostics ?? []] : manifest.diagnostics ?? [];
|
|
1120
|
+
for (const diagnostic of diagnostics) {
|
|
1121
|
+
let line = null;
|
|
1122
|
+
if (diagnostic.kind === "bail") line = `⚠ ${diagnostic.component} not extracted: ${diagnostic.message}`;
|
|
1123
|
+
else if (diagnostic.kind === "skip") line = `⚠ ${diagnostic.component}: skipped ${diagnostic.message}`;
|
|
1124
|
+
else if (diagnostic.kind === "warn") line = `⚠ ${diagnostic.file}: ${diagnostic.component}: ${diagnostic.message}`;
|
|
1125
|
+
if (line === null) continue;
|
|
1126
|
+
if (diagnostic.code && !diagnostic.message.includes(diagnostic.code)) line += ` [${diagnostic.code}]`;
|
|
1127
|
+
if (policy.strict && diagnostic.severity === "error") {
|
|
1128
|
+
errors.push(`${diagnostic.code ?? "error"} — ${diagnostic.component}: ${diagnostic.message}`);
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
warn(line);
|
|
1132
|
+
}
|
|
1133
|
+
if (errors.length > 0) throw new Error(`[animus] strict: ${errors.length} error diagnostic(s):\n${errors.join("\n")}`);
|
|
1001
1134
|
}
|
|
1002
1135
|
//#endregion
|
|
1003
1136
|
//#region pipeline/unit-fallback.ts
|
|
@@ -1093,7 +1226,10 @@ function runProjectAnalysis(engineApi, opts) {
|
|
|
1093
1226
|
const extractMs = Math.round(performance.now() - t);
|
|
1094
1227
|
t = performance.now();
|
|
1095
1228
|
const manifest = JSON.parse(manifestJson);
|
|
1096
|
-
surfaceManifestDiagnostics(manifest, opts.warn
|
|
1229
|
+
surfaceManifestDiagnostics(manifest, opts.warn, {
|
|
1230
|
+
strict: opts.strict,
|
|
1231
|
+
prepend: [...collectSelectorAliasDiagnostics(opts.system.selectorAliasesJson), ...opts.extraDiagnostics ?? []]
|
|
1232
|
+
});
|
|
1097
1233
|
const parseMs = Math.round(performance.now() - t);
|
|
1098
1234
|
return {
|
|
1099
1235
|
manifest,
|
|
@@ -1559,4 +1695,4 @@ function realpathThroughNearestExistingAncestor(path) {
|
|
|
1559
1695
|
}
|
|
1560
1696
|
}
|
|
1561
1697
|
//#endregion
|
|
1562
|
-
export { ANIMUS_LAYERS, DEFAULT_EXTENSIONS, RETIRED_ENGINE_MESSAGE, applyPrefix, applyUnitFallback, assembleStylesheet, assertNoRetiredEngineSelection, buildAnalysisInputs, buildAnalyzeProjectArgs, buildDynamicPropConfig, buildPathAliasesJson, buildSystemPropsModule, camelToKebab, clearEngineCache, collectExternalPackageSources, contentHash, createV2EngineApi, discoverFiles, enforceExternalTokenContracts, extractSystemFilePackages, findAssetSpecifiers, findPackageRoot, formatRustTimingWaterfall, loadSystemConfig, postProcessCss, preprocessMdx, readTsconfigAliasPairs, resolveAssetFile, resolveLightningTargets, resolveThroughPathAliases, runProjectAnalysis, serializeStaticCss, staleDistIncludesMessage, stripLeadingLayerDeclaration, substituteAssetPlaceholders, surfaceManifestDiagnostics, toWatchKeys, unresolvableIncludesMessage, validateLayerOrder };
|
|
1698
|
+
export { ANIMUS_LAYERS, DEFAULT_EXTENSIONS, KEYFRAMES_EXPORT_COLLISION, KEYFRAMES_EXTERNAL_ENTRY_FAILED, RETIRED_ENGINE_MESSAGE, applyPrefix, applyUnitFallback, assembleStylesheet, assertNoRetiredEngineSelection, buildAnalysisInputs, buildAnalyzeProjectArgs, buildDynamicPropConfig, buildPathAliasesJson, buildSystemPropsModule, camelToKebab, clearEngineCache, collectExternalPackageSources, contentHash, createV2EngineApi, discoverFiles, enforceExternalTokenContracts, extractSystemFilePackages, findAssetSpecifiers, findPackageRoot, formatRustTimingWaterfall, loadSystemConfig, mergeExternalKeyframes, postProcessCss, preprocessMdx, readTsconfigAliasPairs, resolveAssetFile, resolveLightningTargets, resolveThroughPathAliases, runProjectAnalysis, serializeStaticCss, staleDistIncludesMessage, stripLeadingLayerDeclaration, substituteAssetPlaceholders, surfaceManifestDiagnostics, toWatchKeys, unresolvableIncludesMessage, validateLayerOrder };
|
|
@@ -6,15 +6,47 @@ export type ManifestDiagnostic = {
|
|
|
6
6
|
/** Structured token path (`scale.key`) — present only on
|
|
7
7
|
* `external-token-candidate` diagnostics (cross-source correlation). */
|
|
8
8
|
token?: string;
|
|
9
|
+
/** Stable diagnostic code (`animus.<namespace>.<slug>`). */
|
|
10
|
+
code?: string;
|
|
11
|
+
/** `"error"` fails strict builds at this policy point; `"warn"`/absent
|
|
12
|
+
* never does. */
|
|
13
|
+
severity?: string;
|
|
9
14
|
};
|
|
15
|
+
/** Stable code for selector forms with no substitutable subject.
|
|
16
|
+
* Mirrors the Rust constant in `extract-v2/src/eval.rs`. */
|
|
17
|
+
export declare const SELECTOR_UNSUPPORTED_SUBJECT = "animus.selector.unsupported-subject";
|
|
18
|
+
export interface DiagnosticPolicy {
|
|
19
|
+
/** When true, error-severity diagnostics throw instead of warning. */
|
|
20
|
+
strict?: boolean;
|
|
21
|
+
/** System-level diagnostics (e.g. selector-alias validation) surfaced
|
|
22
|
+
* ahead of the manifest's own, through the same policy. */
|
|
23
|
+
prepend?: ManifestDiagnostic[];
|
|
24
|
+
}
|
|
25
|
+
/** True when the selector string carries at least one substitutable `&`
|
|
26
|
+
* subject outside quoted text (mirrors the Rust `selector_subject` walk —
|
|
27
|
+
* ancestor, leading, and repeated subjects all count; a `&` inside a
|
|
28
|
+
* quoted attribute value does not). */
|
|
29
|
+
export declare function hasSelectorSubject(value: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Synthesize coded diagnostics for registered selector-alias values that
|
|
32
|
+
* look selector-shaped (`&` present) but carry no substitutable subject —
|
|
33
|
+
* every `&` sits inside quoted text, so there is nothing to anchor the
|
|
34
|
+
* class to. Ancestor-prefixed and repeated subjects are supported and pass
|
|
35
|
+
* validation. The system-config boundary is where these must fail loud
|
|
36
|
+
* (alias values never reach the evaluator's key guard).
|
|
37
|
+
*/
|
|
38
|
+
export declare function collectSelectorAliasDiagnostics(selectorAliasesJson: string | null | undefined): ManifestDiagnostic[];
|
|
10
39
|
/**
|
|
11
40
|
* Surface extraction-manifest diagnostics through a plugin's warn channel.
|
|
12
41
|
*
|
|
13
|
-
* Single authoritative copy for both extraction plugins
|
|
14
|
-
*
|
|
15
|
-
*
|
|
42
|
+
* Single authoritative copy for both extraction plugins — and the single
|
|
43
|
+
* strict-escalation policy point: error-severity diagnostics throw one
|
|
44
|
+
* Error naming every offender when `policy.strict`, and print as warnings
|
|
45
|
+
* otherwise. Surfaces `bail` (component not extracted), `skip` (component
|
|
46
|
+
* skipped), and `warn` kinds; unknown kinds stay silent. Printed lines
|
|
47
|
+
* include the diagnostic code when the message doesn't already carry it.
|
|
16
48
|
*/
|
|
17
49
|
export declare function surfaceManifestDiagnostics(manifest: {
|
|
18
50
|
diagnostics?: ManifestDiagnostic[];
|
|
19
|
-
}, warn: (message: string) => void): void;
|
|
51
|
+
}, warn: (message: string) => void, policy?: DiagnosticPolicy): void;
|
|
20
52
|
//# sourceMappingURL=manifest-diagnostics.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-diagnostics.d.ts","sourceRoot":"","sources":["../pipeline/manifest-diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB;6EACyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest-diagnostics.d.ts","sourceRoot":"","sources":["../pipeline/manifest-diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB;6EACyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;sBACkB;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;6DAC6D;AAC7D,eAAO,MAAM,4BAA4B,wCACF,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;gEAC4D;IAC5D,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED;;;wCAGwC;AACxC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAYzD;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,mBAAmB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7C,kBAAkB,EAAE,CAuBtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE;IAAE,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAAE,EAChD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAC/B,MAAM,GAAE,gBAAqB,GAC5B,IAAI,CA+BN"}
|
package/dist/run-analysis.d.ts
CHANGED
|
@@ -42,6 +42,10 @@ export interface AnalysisOptions {
|
|
|
42
42
|
/** rootDir-relative external package dirs (external-token candidates). */
|
|
43
43
|
externalDirs?: string[];
|
|
44
44
|
devMode: boolean;
|
|
45
|
+
/** System-level diagnostics gathered outside analysis (e.g. external
|
|
46
|
+
* keyframes discovery) — surfaced through the single shared policy
|
|
47
|
+
* point alongside the manifest's own. */
|
|
48
|
+
extraDiagnostics?: import('./manifest-diagnostics').ManifestDiagnostic[];
|
|
45
49
|
}
|
|
46
50
|
/**
|
|
47
51
|
* Build the named `analyzeProject` input set from analysis options. Also
|
|
@@ -59,6 +63,7 @@ export declare function buildAnalysisInputs(opts: AnalysisOptions): AnalyzeProje
|
|
|
59
63
|
*/
|
|
60
64
|
export declare function runProjectAnalysis(engineApi: () => any, opts: AnalysisOptions & {
|
|
61
65
|
warn: (message: string) => void;
|
|
66
|
+
strict?: boolean;
|
|
62
67
|
}): ProjectAnalysisResult;
|
|
63
68
|
/**
|
|
64
69
|
* Clear the engine's per-file analysis cache so stale results from a prior
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-analysis.d.ts","sourceRoot":"","sources":["../pipeline/run-analysis.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-analysis.d.ts","sourceRoot":"","sources":["../pipeline/run-analysis.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IAEpC,QAAQ,EAAE,GAAG,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB;6EACyE;IACzE,MAAM,EAAE,oBAAoB,CAAC;IAC7B,4DAA4D;IAC5D,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACtE;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB;;8CAE0C;IAC1C,gBAAgB,CAAC,EAAE,OAAO,wBAAwB,EAAE,kBAAkB,EAAE,CAAC;CAC1E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,eAAe,GACpB,oBAAoB,CAiCtB;AAQD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAEhC,SAAS,EAAE,MAAM,GAAG,EACpB,IAAI,EAAE,eAAe,GAAG;IAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5E,qBAAqB,CAgCvB;AAED;;;;GAIG;AAEH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,IAAI,CAQ3D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@animus-ui/extract",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Animus static CSS extraction pipeline (Rust/NAPI)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"animus",
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"build:v2:debug": "cd crates/extract-v2 && bunx napi build --platform"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@animus-ui/properties": "0.1.
|
|
54
|
+
"@animus-ui/properties": "0.1.7",
|
|
55
55
|
"browserslist": "^4.24.0",
|
|
56
56
|
"lightningcss": "^1.29.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@animus-ui/system": "0.1.
|
|
59
|
+
"@animus-ui/system": "0.1.7",
|
|
60
60
|
"@mdx-js/mdx": "3.1.1",
|
|
61
61
|
"@napi-rs/cli": "^3.7.3"
|
|
62
62
|
},
|