@usefragments/core 1.2.0 → 1.3.0
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/dist/{chunk-BQQTMGLA.js → chunk-57QDBEHQ.js} +79 -6
- package/dist/chunk-57QDBEHQ.js.map +1 -0
- package/dist/{chunk-DBVTSUMT.js → chunk-MLRDNSSA.js} +20 -6
- package/dist/chunk-MLRDNSSA.js.map +1 -0
- package/dist/codes/index.d.ts +1 -1
- package/dist/codes/index.js +2 -2
- package/dist/index-h_yWj15D.d.ts +6981 -0
- package/dist/index.d.ts +106 -92
- package/dist/index.js +235 -98
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts +36 -36
- package/dist/schemas/index.d.ts +3 -3377
- package/dist/schemas/index.js +1 -1
- package/package.json +1 -1
- package/src/agent-format.test.ts +75 -3
- package/src/agent-format.ts +28 -6
- package/src/evidence.ts +27 -0
- package/src/facts/builders.ts +2 -0
- package/src/facts/fact-index.ts +22 -2
- package/src/facts/facts.test.ts +1 -1
- package/src/facts/types.ts +2 -0
- package/src/index.ts +4 -0
- package/src/rules/__tests__/fix-emission-invariant.test.ts +174 -0
- package/src/rules/__tests__/tokens-require-dual-fallback.test.ts +90 -0
- package/src/rules/emit-gate.test.ts +16 -0
- package/src/rules/emit-gate.ts +6 -3
- package/src/rules/finding.ts +3 -0
- package/src/rules/rules.test.ts +2 -1
- package/src/rules/spacing-resolution.ts +5 -8
- package/src/rules/styles-no-raw-color.ts +32 -23
- package/src/rules/styles-no-raw-dimensions.ts +31 -12
- package/src/rules/styles-no-raw-spacing.ts +33 -11
- package/src/rules/styles-no-raw-typography.ts +37 -15
- package/src/rules/taxonomy.test.ts +13 -0
- package/src/rules/tokens-require-dual-fallback.ts +54 -17
- package/src/rules/utils.ts +51 -0
- package/src/schemas/index.ts +81 -3
- package/src/token-types.ts +6 -0
- package/src/tokens/__tests__/source-names.test.ts +42 -0
- package/src/tokens/design-token-parser.test.ts +24 -5
- package/src/tokens/design-token-parser.ts +40 -8
- package/dist/chunk-BQQTMGLA.js.map +0 -1
- package/dist/chunk-DBVTSUMT.js.map +0 -1
package/src/rules/utils.ts
CHANGED
|
@@ -18,6 +18,57 @@ import type {
|
|
|
18
18
|
UsagePropResolvedFact,
|
|
19
19
|
UsageTextChildFact,
|
|
20
20
|
} from "../facts/index.js";
|
|
21
|
+
import type { FindingFix } from "./types.js";
|
|
22
|
+
|
|
23
|
+
export interface FixProof {
|
|
24
|
+
symbols: readonly string[];
|
|
25
|
+
editKind: FindingFix["kind"];
|
|
26
|
+
valuePreserving: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface FixEmission<F extends FindingFix = FindingFix> {
|
|
30
|
+
fix: F;
|
|
31
|
+
downgradeReason?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Gate token-substitution fixes on explicit proof. Callers attach any returned
|
|
36
|
+
* downgradeReason to the finding attributes so machine consumers can explain
|
|
37
|
+
* why a suggestion was not auto-applicable.
|
|
38
|
+
*/
|
|
39
|
+
export function emitFix<F extends FindingFix>(
|
|
40
|
+
fix: F,
|
|
41
|
+
proof: FixProof,
|
|
42
|
+
ix: FactIndex
|
|
43
|
+
): FixEmission<F> {
|
|
44
|
+
const reasons: string[] = [];
|
|
45
|
+
if (proof.editKind !== fix.kind) reasons.push("edit kind does not match proof");
|
|
46
|
+
if (!proof.valuePreserving) reasons.push("value-preservation proof missing");
|
|
47
|
+
if (proof.symbols.length === 0) reasons.push("token-symbol proof missing");
|
|
48
|
+
|
|
49
|
+
const missingSymbols = proof.symbols.filter((symbol) => !ix.tokens.symbolExists(symbol));
|
|
50
|
+
if (missingSymbols.length > 0) {
|
|
51
|
+
reasons.push(`absent token symbol: ${missingSymbols.join(", ")}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const inapplicableSymbols = proof.symbols.filter((symbol) => {
|
|
55
|
+
const definition = ix.tokens.definitionForSymbol(symbol);
|
|
56
|
+
return definition !== undefined && !isApplicableTokenReference(definition.referenceFormat);
|
|
57
|
+
});
|
|
58
|
+
if (inapplicableSymbols.length > 0) {
|
|
59
|
+
reasons.push(`token reference is not directly applicable: ${inapplicableSymbols.join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
fix: { ...fix, deterministic: reasons.length === 0 },
|
|
64
|
+
...(reasons.length > 0 ? { downgradeReason: reasons.join("; ") } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Extract authored token symbols from a replacement string, preserving order. */
|
|
69
|
+
export function tokenSymbolsInText(value: string): string[] {
|
|
70
|
+
return [...new Set(value.match(/\$[A-Za-z0-9_-]+|--[A-Za-z0-9_-]+/g) ?? [])];
|
|
71
|
+
}
|
|
21
72
|
|
|
22
73
|
export interface LengthScale {
|
|
23
74
|
unit: "px" | "rem";
|
package/src/schemas/index.ts
CHANGED
|
@@ -8,6 +8,15 @@ import {
|
|
|
8
8
|
severitySchema,
|
|
9
9
|
} from "../severity.js";
|
|
10
10
|
import type { LegacySeverityLevel, Severity } from "../severity.js";
|
|
11
|
+
import type { EvidenceGrade } from "../evidence.js";
|
|
12
|
+
|
|
13
|
+
const evidenceGradeSchema: z.ZodType<EvidenceGrade> = z.enum([
|
|
14
|
+
"none",
|
|
15
|
+
"runtime_advisory",
|
|
16
|
+
"provenance_bound",
|
|
17
|
+
"source_backed",
|
|
18
|
+
"receipt_backed",
|
|
19
|
+
]);
|
|
11
20
|
|
|
12
21
|
export { legacySeverityLevelSchema, severityLevelSchema, severitySchema };
|
|
13
22
|
export type { LegacySeverityLevel, Severity, SeverityLevel } from "../severity.js";
|
|
@@ -108,6 +117,7 @@ export const findingSchema = z.object({
|
|
|
108
117
|
fingerprint: z.string(),
|
|
109
118
|
location: factLocationSchema,
|
|
110
119
|
evidence: z.array(factEvidenceSchema).min(1),
|
|
120
|
+
evidenceGrade: evidenceGradeSchema.optional(),
|
|
111
121
|
fix: findingFixSchema.optional(),
|
|
112
122
|
attributes: z.record(z.unknown()).optional(),
|
|
113
123
|
/**
|
|
@@ -224,6 +234,7 @@ export const agentFindingSchema = z.object({
|
|
|
224
234
|
severity: severitySchema,
|
|
225
235
|
level: severityLevelSchema,
|
|
226
236
|
message: z.string(),
|
|
237
|
+
evidenceGrade: evidenceGradeSchema.optional(),
|
|
227
238
|
evidence: z.array(factEvidenceSchema),
|
|
228
239
|
plan: agentPlanSchema,
|
|
229
240
|
});
|
|
@@ -238,10 +249,34 @@ export const agentIntegritySchema = z.object({
|
|
|
238
249
|
reasons: z.array(z.string()),
|
|
239
250
|
});
|
|
240
251
|
|
|
241
|
-
|
|
252
|
+
const agentRunProvenanceSchema = z.object({
|
|
253
|
+
runId: z.string().regex(/^run_[a-f0-9]{12}$/),
|
|
254
|
+
fcid: z.string().min(1),
|
|
255
|
+
baselineId: z.string().min(1).optional(),
|
|
256
|
+
scope: z.object({
|
|
257
|
+
method: z.enum([
|
|
258
|
+
"three-dot",
|
|
259
|
+
"tree-diff",
|
|
260
|
+
"status",
|
|
261
|
+
"fallback-full",
|
|
262
|
+
"explicit",
|
|
263
|
+
"full",
|
|
264
|
+
]),
|
|
265
|
+
gitOk: z.boolean(),
|
|
266
|
+
}),
|
|
267
|
+
engineVersion: z.string().min(1),
|
|
268
|
+
scopeHash: z.string().regex(/^[a-f0-9]{64}$/),
|
|
269
|
+
inputFilesHash: z.string().regex(/^[a-f0-9]{64}$/),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const agentRunVerdictSchema = z.object({
|
|
273
|
+
exitCode: z.union([z.literal(0), z.literal(1)]),
|
|
274
|
+
reasons: z.array(z.string()),
|
|
275
|
+
gatingFindingCount: z.number().int().nonnegative(),
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const agentFormatBaseSchema = z.object({
|
|
242
279
|
schemaVersion: z.literal(AGENT_FORMAT_SCHEMA_VERSION),
|
|
243
|
-
passed: z.boolean(),
|
|
244
|
-
score: z.number(),
|
|
245
280
|
summary: z.string(),
|
|
246
281
|
integrity: agentIntegritySchema,
|
|
247
282
|
fix_first: z.array(agentFindingSchema),
|
|
@@ -258,7 +293,45 @@ export const agentFormatSchema = z.object({
|
|
|
258
293
|
}),
|
|
259
294
|
findings: z.array(findingSchema).optional(),
|
|
260
295
|
suppressions: z.array(suppressionDirectiveSchema).optional(),
|
|
296
|
+
provenance: agentRunProvenanceSchema.optional(),
|
|
297
|
+
verdict: agentRunVerdictSchema.optional(),
|
|
261
298
|
});
|
|
299
|
+
|
|
300
|
+
export const agentFormatSchema = z.union([
|
|
301
|
+
agentFormatBaseSchema.extend({
|
|
302
|
+
passed: z.boolean(),
|
|
303
|
+
score: z.number(),
|
|
304
|
+
status: z.never().optional(),
|
|
305
|
+
reasons: z.never().optional(),
|
|
306
|
+
integrity: agentIntegritySchema.extend({
|
|
307
|
+
rulesLoaded: z.number().int().positive(),
|
|
308
|
+
}),
|
|
309
|
+
}),
|
|
310
|
+
agentFormatBaseSchema.extend({
|
|
311
|
+
passed: z.literal(false),
|
|
312
|
+
score: z.never().optional(),
|
|
313
|
+
status: z.literal("indeterminate"),
|
|
314
|
+
reasons: z.tuple([z.literal("zero_rules_loaded")]),
|
|
315
|
+
integrity: agentIntegritySchema.extend({
|
|
316
|
+
rulesLoaded: z.literal(0),
|
|
317
|
+
}),
|
|
318
|
+
}),
|
|
319
|
+
// A finalized Run can explicitly allow inert governance. Preserve the
|
|
320
|
+
// indeterminate integrity truth while making `passed` match that Run's sole
|
|
321
|
+
// verdict; requiring Run pins prevents generic zero-rule envelopes from
|
|
322
|
+
// accidentally becoming green.
|
|
323
|
+
agentFormatBaseSchema.extend({
|
|
324
|
+
passed: z.literal(true),
|
|
325
|
+
score: z.never().optional(),
|
|
326
|
+
status: z.literal("indeterminate"),
|
|
327
|
+
reasons: z.tuple([z.literal("zero_rules_loaded")]),
|
|
328
|
+
integrity: agentIntegritySchema.extend({
|
|
329
|
+
rulesLoaded: z.literal(0),
|
|
330
|
+
}),
|
|
331
|
+
provenance: agentRunProvenanceSchema,
|
|
332
|
+
verdict: agentRunVerdictSchema.extend({ exitCode: z.literal(0) }),
|
|
333
|
+
}),
|
|
334
|
+
]);
|
|
262
335
|
export type AgentFormat = z.infer<typeof agentFormatSchema>;
|
|
263
336
|
|
|
264
337
|
export const agentErrorEnvelopeSchema = z.object({
|
|
@@ -268,6 +341,10 @@ export const agentErrorEnvelopeSchema = z.object({
|
|
|
268
341
|
code: z.string().min(1),
|
|
269
342
|
message: z.string().min(1),
|
|
270
343
|
}),
|
|
344
|
+
provenance: agentRunProvenanceSchema.optional(),
|
|
345
|
+
verdict: agentRunVerdictSchema.optional(),
|
|
346
|
+
cloudReport: z.enum(["reported", "failed", "skipped"]).optional(),
|
|
347
|
+
notices: z.array(z.string()).optional(),
|
|
271
348
|
});
|
|
272
349
|
export type AgentErrorEnvelope = z.infer<typeof agentErrorEnvelopeSchema>;
|
|
273
350
|
|
|
@@ -285,6 +362,7 @@ export function normalizeFinding(
|
|
|
285
362
|
): Finding {
|
|
286
363
|
return {
|
|
287
364
|
...input,
|
|
365
|
+
evidenceGrade: input.evidenceGrade ?? "source_backed",
|
|
288
366
|
level: input.level ?? severityLevel(input.severity),
|
|
289
367
|
};
|
|
290
368
|
}
|
package/src/token-types.ts
CHANGED
|
@@ -59,6 +59,12 @@ export interface DesignToken {
|
|
|
59
59
|
/** Source file where this token was defined */
|
|
60
60
|
sourceFile: string;
|
|
61
61
|
|
|
62
|
+
/** Authored reference form, when the parser can prove it from the source. */
|
|
63
|
+
referenceFormat?: "css-var" | "scss-var" | "scss-map" | "dtcg";
|
|
64
|
+
|
|
65
|
+
/** Authored spellings preserved before normalization (for example `$x` and `--x`). */
|
|
66
|
+
sourceNames?: string[];
|
|
67
|
+
|
|
62
68
|
/** Line number in source file */
|
|
63
69
|
lineNumber?: number;
|
|
64
70
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { FactIndex, makeTokenDefinitionFact } from "../../facts/index.js";
|
|
7
|
+
import { parseDesignTokenContent } from "../design-token-parser.js";
|
|
8
|
+
|
|
9
|
+
const tokenFile = fileURLToPath(
|
|
10
|
+
new URL("../../../../../libs/ui/src/tokens/_variables.scss", import.meta.url)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
describe("SCSS source-name provenance", () => {
|
|
14
|
+
it("preserves both authored spellings through parser, facts, and rule-time lookup", () => {
|
|
15
|
+
const parsed = parseDesignTokenContent(readFileSync(tokenFile, "utf8"), {
|
|
16
|
+
filePath: tokenFile,
|
|
17
|
+
});
|
|
18
|
+
const token = parsed.tokens.find((candidate) => candidate.name === "--fui-space-2");
|
|
19
|
+
|
|
20
|
+
expect(token?.sourceNames).toEqual(expect.arrayContaining(["--fui-space-2", "$fui-space-2"]));
|
|
21
|
+
|
|
22
|
+
const ix = new FactIndex();
|
|
23
|
+
ix.addMany(
|
|
24
|
+
parsed.tokens.map((candidate) =>
|
|
25
|
+
makeTokenDefinitionFact({
|
|
26
|
+
name: candidate.name,
|
|
27
|
+
value: candidate.resolvedValue,
|
|
28
|
+
category: candidate.category === "spacing" ? "spacing" : "other",
|
|
29
|
+
referenceFormat: candidate.referenceFormat,
|
|
30
|
+
sourceNames: candidate.sourceNames,
|
|
31
|
+
})
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(ix.tokens.symbolExists("$fui-space-2")).toBe(true);
|
|
36
|
+
expect(ix.tokens.symbolExists("--fui-space-2")).toBe(true);
|
|
37
|
+
expect(ix.tokens.symbolExists("$fui-space-99")).toBe(false);
|
|
38
|
+
expect(ix.tokens.definitionForSymbol("$fui-space-2")?.sourceNames).toEqual(
|
|
39
|
+
expect.arrayContaining(["--fui-space-2", "$fui-space-2"])
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -67,15 +67,34 @@ describe("parseDesignTokenContent — DTCG/JSON format dispatch (#10)", () => {
|
|
|
67
67
|
describe("parseDesignTokenContent — SCSS $-variable format dispatch (#32)", () => {
|
|
68
68
|
it("parses SCSS $vars, normalizing $name to --name", () => {
|
|
69
69
|
const content = "$fui-color-accent: #fff;\n$fui-space-2: 8px;";
|
|
70
|
-
const tokens =
|
|
71
|
-
expect(tokens).
|
|
72
|
-
|
|
70
|
+
const tokens = parseDesignTokenContent(content, { filePath: "tokens.scss" }).tokens;
|
|
71
|
+
expect(tokens).toEqual(
|
|
72
|
+
expect.arrayContaining([
|
|
73
|
+
expect.objectContaining({
|
|
74
|
+
name: "--fui-color-accent",
|
|
75
|
+
referenceFormat: "scss-var",
|
|
76
|
+
}),
|
|
77
|
+
expect.objectContaining({ name: "--fui-space-2", referenceFormat: "scss-var" }),
|
|
78
|
+
])
|
|
79
|
+
);
|
|
73
80
|
});
|
|
74
81
|
|
|
75
82
|
it("dedupes a file declaring BOTH --fui-x and $fui-x to one --fui-x", () => {
|
|
76
83
|
const content = ":root {\n --fui-x: red;\n}\n$fui-x: red;";
|
|
77
|
-
const tokens =
|
|
78
|
-
|
|
84
|
+
const tokens = parseDesignTokenContent(content, { filePath: "tokens.scss" }).tokens.filter(
|
|
85
|
+
(token) => token.name === "--fui-x"
|
|
86
|
+
);
|
|
87
|
+
expect(tokens).toHaveLength(1);
|
|
88
|
+
expect(tokens[0].referenceFormat).toBe("scss-var");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("marks a CSS-only declaration in SCSS as css-var", () => {
|
|
92
|
+
const content = ":root {\n --fui-color-accent: red;\n}";
|
|
93
|
+
const token = parseDesignTokenContent(content, { filePath: "tokens.scss" }).tokens.find(
|
|
94
|
+
(candidate) => candidate.name === "--fui-color-accent"
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
expect(token?.referenceFormat).toBe("css-var");
|
|
79
98
|
});
|
|
80
99
|
|
|
81
100
|
it("surfaces a NON-SILENT warning for a comment-only SCSS file (#32)", () => {
|
|
@@ -193,21 +193,51 @@ function parsedOutputToDesignTokens(output: TokenParseOutput, filePath: string):
|
|
|
193
193
|
* and `$fui-x` yields one `--fui-x`.
|
|
194
194
|
*/
|
|
195
195
|
function scssOutputToDesignTokens(output: TokenParseOutput, filePath: string): DesignToken[] {
|
|
196
|
-
const
|
|
197
|
-
|
|
196
|
+
const tokensByName = new Map<
|
|
197
|
+
string,
|
|
198
|
+
{
|
|
199
|
+
parsed: ParsedToken;
|
|
200
|
+
referenceFormat: "css-var" | "scss-var";
|
|
201
|
+
sourceNames: Set<string>;
|
|
202
|
+
}
|
|
203
|
+
>();
|
|
198
204
|
for (const cat of Object.values(output.categories)) {
|
|
199
205
|
for (const t of cat) {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
const isScssVariable = t.name.startsWith("$");
|
|
207
|
+
const cssName = isScssVariable ? `--${t.name.slice(1)}` : t.name;
|
|
208
|
+
if (!cssName.startsWith("--")) continue;
|
|
209
|
+
|
|
210
|
+
const existing = tokensByName.get(cssName);
|
|
211
|
+
if (!existing) {
|
|
212
|
+
tokensByName.set(cssName, {
|
|
213
|
+
parsed: t,
|
|
214
|
+
referenceFormat: isScssVariable ? "scss-var" : "css-var",
|
|
215
|
+
sourceNames: new Set([t.name]),
|
|
216
|
+
});
|
|
217
|
+
} else {
|
|
218
|
+
existing.sourceNames.add(t.name);
|
|
219
|
+
if (isScssVariable) {
|
|
220
|
+
existing.parsed = t;
|
|
221
|
+
existing.referenceFormat = "scss-var";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
204
224
|
}
|
|
205
225
|
}
|
|
206
|
-
return
|
|
226
|
+
return [...tokensByName].map(([name, token]) =>
|
|
227
|
+
designTokenFromParsed(name, token.parsed, filePath, token.referenceFormat, [
|
|
228
|
+
...token.sourceNames,
|
|
229
|
+
])
|
|
230
|
+
);
|
|
207
231
|
}
|
|
208
232
|
|
|
209
233
|
/** Build a `DesignToken` from a sibling-parser `ParsedToken` under a CSS name. */
|
|
210
|
-
function designTokenFromParsed(
|
|
234
|
+
function designTokenFromParsed(
|
|
235
|
+
name: string,
|
|
236
|
+
parsed: ParsedToken,
|
|
237
|
+
filePath: string,
|
|
238
|
+
referenceFormat?: DesignToken["referenceFormat"],
|
|
239
|
+
sourceNames?: string[]
|
|
240
|
+
): DesignToken {
|
|
211
241
|
return {
|
|
212
242
|
name,
|
|
213
243
|
rawValue: parsed.value ?? "",
|
|
@@ -220,6 +250,8 @@ function designTokenFromParsed(name: string, parsed: ParsedToken, filePath: stri
|
|
|
220
250
|
level: 1,
|
|
221
251
|
referenceChain: [],
|
|
222
252
|
sourceFile: filePath,
|
|
253
|
+
referenceFormat,
|
|
254
|
+
...(sourceNames?.length ? { sourceNames } : {}),
|
|
223
255
|
theme: "default",
|
|
224
256
|
selector: ":root",
|
|
225
257
|
description: parsed.description,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schemas/index.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport {\n legacySeverityLevelSchema,\n severityFromLevel,\n severityLevel,\n severityLevelSchema,\n severitySchema,\n} from \"../severity.js\";\nimport type { LegacySeverityLevel, Severity } from \"../severity.js\";\n\nexport { legacySeverityLevelSchema, severityLevelSchema, severitySchema };\nexport type { LegacySeverityLevel, Severity, SeverityLevel } from \"../severity.js\";\n\nexport const factLocationSchema = z.object({\n file: z.string(),\n line: z.number().int().nonnegative(),\n column: z.number().int().nonnegative(),\n endLine: z.number().int().nonnegative().optional(),\n endColumn: z.number().int().nonnegative().optional(),\n});\nexport type FactLocation = z.infer<typeof factLocationSchema>;\n\nexport const findingReplacePropValueFixSchema = z.object({\n kind: z.literal(\"replacePropValue\"),\n title: z.string(),\n prop: z.string(),\n value: z.unknown(),\n deterministic: z.boolean().optional(),\n});\n\nexport const findingReplaceStyleValueFixSchema = z.object({\n kind: z.literal(\"replaceStyleValue\"),\n title: z.string(),\n property: z.string(),\n value: z.string(),\n deterministic: z.boolean().optional(),\n});\n\nexport const findingReplaceImportFixSchema = z.object({\n kind: z.literal(\"replaceImport\"),\n title: z.string(),\n from: z.string(),\n to: z.string(),\n deterministic: z.boolean().optional(),\n});\n\nexport const findingReplaceComponentFixSchema = z.object({\n kind: z.literal(\"replaceComponent\"),\n title: z.string(),\n from: z.string(),\n to: z.string(),\n deterministic: z.boolean().optional(),\n});\n\nexport const findingReplaceClassTokenFixSchema = z.object({\n kind: z.literal(\"replaceClassToken\"),\n title: z.string(),\n from: z.string(),\n to: z.string().nullable(),\n utility: z.string(),\n deterministic: z.boolean().optional(),\n});\n\nexport const findingFixSchema = z.discriminatedUnion(\"kind\", [\n findingReplacePropValueFixSchema,\n findingReplaceStyleValueFixSchema,\n findingReplaceImportFixSchema,\n findingReplaceComponentFixSchema,\n findingReplaceClassTokenFixSchema,\n]);\nexport type FindingFix = z.infer<typeof findingFixSchema>;\nexport type FindingReplacePropValueFix = z.infer<typeof findingReplacePropValueFixSchema>;\nexport type FindingReplaceStyleValueFix = z.infer<typeof findingReplaceStyleValueFixSchema>;\nexport type FindingReplaceImportFix = z.infer<typeof findingReplaceImportFixSchema>;\nexport type FindingReplaceComponentFix = z.infer<typeof findingReplaceComponentFixSchema>;\nexport type FindingReplaceClassTokenFix = z.infer<typeof findingReplaceClassTokenFixSchema>;\n\nexport interface FactEvidence {\n factId: string;\n fact: {\n kind: string;\n location?: FactLocation;\n };\n}\n\nexport const factEvidenceSchema: z.ZodType<FactEvidence> = z.object({\n factId: z.string(),\n fact: z\n .object({\n kind: z.string(),\n location: factLocationSchema.optional(),\n })\n .passthrough(),\n});\n\nexport const findingSchema = z.object({\n ruleId: z.string(),\n ruleVersion: z.string(),\n severity: severitySchema,\n level: severityLevelSchema,\n code: z\n .string()\n .regex(/^FUI\\d{4}$/)\n .optional(),\n helpUrl: z.string().url().optional(),\n message: z.string(),\n fingerprint: z.string(),\n location: factLocationSchema,\n evidence: z.array(factEvidenceSchema).min(1),\n fix: findingFixSchema.optional(),\n attributes: z.record(z.unknown()).optional(),\n /**\n * Product area this finding's file resolved to (topology layer). Optional —\n * absent when the repo has no `topology` config. See `topology/resolve-area`.\n */\n area: z\n .object({\n areaId: z.string(),\n areaName: z.string(),\n criticality: z.enum([\"low\", \"medium\", \"high\", \"revenue\", \"regulated\"]),\n owners: z.array(z.string()),\n matchedGlob: z.string(),\n })\n .optional(),\n});\nexport type Finding = z.infer<typeof findingSchema>;\n\nexport const violationSchema = z.object({\n nodeId: z.string(),\n nodeType: z.string(),\n rule: z.string(),\n severity: severitySchema,\n level: severityLevelSchema.optional(),\n code: z\n .string()\n .regex(/^FUI\\d{4}$/)\n .optional(),\n helpUrl: z.string().url().optional(),\n message: z.string(),\n path: z.string().optional(),\n suggestion: z.string().optional(),\n prop: z.string().optional(),\n filePath: z.string().optional(),\n line: z.number().int().nonnegative().optional(),\n column: z.number().int().nonnegative().optional(),\n rawValue: z.string().optional(),\n extra: z.record(z.unknown()).optional(),\n});\nexport type Violation = z.infer<typeof violationSchema>;\n\nexport const fixSchema = z.object({\n nodeId: z.string(),\n prop: z.string().optional(),\n action: z.enum([\"remove\", \"replace\", \"add\"]),\n value: z.unknown().optional(),\n description: z.string(),\n});\nexport type Fix = z.infer<typeof fixSchema>;\n\nexport const validatorResultSchema = z.object({\n validator: z.string(),\n severity: severitySchema,\n passed: z.boolean(),\n violations: z.array(violationSchema),\n findings: z.array(findingSchema).optional(),\n suggestions: z.array(fixSchema).optional(),\n});\nexport type ValidatorResult = z.infer<typeof validatorResultSchema>;\n\nexport const governanceVerdictMetadataSchema = z.object({\n runner: z.string(),\n policyVersion: z.string().optional(),\n duration: z.number().nonnegative(),\n nodeCount: z.number().int().nonnegative(),\n componentTypes: z.array(z.string()),\n});\nexport type GovernanceVerdictMetadata = z.infer<typeof governanceVerdictMetadataSchema>;\n\nexport const governanceVerdictSchema = z.object({\n verdict: z.enum([\"pass\", \"warn\", \"fail\"]).optional(),\n passed: z.boolean(),\n score: z.number(),\n results: z.array(validatorResultSchema),\n metadata: governanceVerdictMetadataSchema,\n});\nexport type GovernanceVerdict = z.infer<typeof governanceVerdictSchema>;\n\nexport const suppressionDirectiveSchema = z.object({\n ruleId: z.string().optional(),\n reason: z.string().min(1),\n expiresAt: z.string().datetime().optional(),\n expiresOn: z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/)\n .optional(),\n scope: z.enum([\"line\", \"block\", \"file\"]).default(\"line\"),\n code: z\n .string()\n .regex(/^FUI\\d{4}$/)\n .optional(),\n});\nexport type SuppressionDirective = z.infer<typeof suppressionDirectiveSchema>;\n\nexport const agentPlanSchema = z.object({\n tool: z.enum([\n \"design_system/list_primitives\",\n \"design_system/conform\",\n \"design_system/prove_compliant\",\n ]),\n args: z.record(z.unknown()),\n confidence: z.number().min(0).max(1),\n});\n\nexport const agentFindingSchema = z.object({\n code: z\n .string()\n .regex(/^FUI\\d{4}$/)\n .optional(),\n ruleId: z.string(),\n filePath: z.string(),\n line: z.number().int().nonnegative(),\n col: z.number().int().nonnegative(),\n severity: severitySchema,\n level: severityLevelSchema,\n message: z.string(),\n evidence: z.array(factEvidenceSchema),\n plan: agentPlanSchema,\n});\n\nexport const AGENT_FORMAT_SCHEMA_VERSION = \"typestyle.agent.v2\" as const;\n\nexport const agentIntegritySchema = z.object({\n rulesLoaded: z.number().int().nonnegative(),\n status: z.enum([\"healthy\", \"degraded\", \"inert\"]),\n healthy: z.boolean(),\n inert: z.boolean(),\n reasons: z.array(z.string()),\n});\n\nexport const agentFormatSchema = z.object({\n schemaVersion: z.literal(AGENT_FORMAT_SCHEMA_VERSION),\n passed: z.boolean(),\n score: z.number(),\n summary: z.string(),\n integrity: agentIntegritySchema,\n fix_first: z.array(agentFindingSchema),\n remaining: z.array(agentFindingSchema),\n suppression_template: z.object({\n directive: z.string(),\n requiredFields: z.array(z.string()),\n example: z.string(),\n }),\n budget: z.object({\n iteration: z.number().int().nonnegative(),\n maxIterations: z.number().int().positive(),\n scoreDelta: z.number(),\n }),\n findings: z.array(findingSchema).optional(),\n suppressions: z.array(suppressionDirectiveSchema).optional(),\n});\nexport type AgentFormat = z.infer<typeof agentFormatSchema>;\n\nexport const agentErrorEnvelopeSchema = z.object({\n schemaVersion: z.literal(AGENT_FORMAT_SCHEMA_VERSION),\n passed: z.literal(false),\n error: z.object({\n code: z.string().min(1),\n message: z.string().min(1),\n }),\n});\nexport type AgentErrorEnvelope = z.infer<typeof agentErrorEnvelopeSchema>;\n\nexport const agentOutputSchema = z.union([agentFormatSchema, agentErrorEnvelopeSchema]);\nexport type AgentOutput = z.infer<typeof agentOutputSchema>;\n\nexport function normalizeSeverity(severity: Severity | LegacySeverityLevel): Severity {\n return severitySchema.safeParse(severity).success\n ? (severity as Severity)\n : severityFromLevel(legacySeverityLevelSchema.parse(severity));\n}\n\nexport function normalizeFinding(\n input: Omit<Finding, \"level\"> & { level?: Finding[\"level\"] }\n): Finding {\n return {\n ...input,\n level: input.level ?? severityLevel(input.severity),\n };\n}\n\nexport function normalizeViolation(\n input: Omit<Violation, \"level\"> & { level?: Violation[\"level\"] }\n): Violation {\n return {\n ...input,\n level: input.level ?? severityLevel(input.severity),\n };\n}\n"],"mappings":"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","names":[]}
|