@usefragments/core 1.0.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.
Files changed (59) hide show
  1. package/dist/{chunk-R3X7UBHU.js → chunk-57QDBEHQ.js} +101 -6
  2. package/dist/chunk-57QDBEHQ.js.map +1 -0
  3. package/dist/{chunk-243QYRUF.js → chunk-MLRDNSSA.js} +88 -47
  4. package/dist/chunk-MLRDNSSA.js.map +1 -0
  5. package/dist/codes/index.d.ts +2 -2
  6. package/dist/codes/index.js +2 -2
  7. package/dist/compiled-types/index.d.ts +1 -1
  8. package/dist/generate/index.d.ts +1 -1
  9. package/dist/{governance-BOa3KyiJ.d.ts → governance-DYSirwJu.d.ts} +22 -1
  10. package/dist/index-h_yWj15D.d.ts +6981 -0
  11. package/dist/index.d.ts +113 -97
  12. package/dist/index.js +387 -113
  13. package/dist/index.js.map +1 -1
  14. package/dist/react-types.d.ts +1 -1
  15. package/dist/registry.d.ts +36 -36
  16. package/dist/schemas/index.d.ts +3 -2584
  17. package/dist/schemas/index.js +9 -1
  18. package/dist/test-utils.d.ts +1 -1
  19. package/package.json +1 -1
  20. package/src/agent-format.test.ts +144 -2
  21. package/src/agent-format.ts +34 -7
  22. package/src/codes/__tests__/codes.test.ts +57 -7
  23. package/src/codes/codes.ts +44 -42
  24. package/src/conform-prove.ts +4 -8
  25. package/src/contract/index.ts +3 -0
  26. package/src/contract/preimage.test.ts +50 -0
  27. package/src/contract/preimage.ts +56 -0
  28. package/src/evidence.ts +27 -0
  29. package/src/facts/builders.ts +4 -0
  30. package/src/facts/fact-index.ts +25 -1
  31. package/src/facts/facts.test.ts +49 -0
  32. package/src/facts/types.ts +3 -0
  33. package/src/governance-integrity.test.ts +2 -0
  34. package/src/governance-integrity.ts +7 -1
  35. package/src/index.ts +13 -0
  36. package/src/rules/__tests__/fix-emission-invariant.test.ts +174 -0
  37. package/src/rules/__tests__/tokens-require-dual-fallback.test.ts +90 -0
  38. package/src/rules/components-prefer-library.ts +165 -7
  39. package/src/rules/emit-gate.test.ts +40 -2
  40. package/src/rules/emit-gate.ts +21 -10
  41. package/src/rules/finding.ts +3 -0
  42. package/src/rules/fix-availability.ts +33 -0
  43. package/src/rules/rules.test.ts +180 -24
  44. package/src/rules/spacing-resolution.ts +5 -8
  45. package/src/rules/styles-no-raw-color.ts +32 -23
  46. package/src/rules/styles-no-raw-dimensions.ts +31 -12
  47. package/src/rules/styles-no-raw-spacing.ts +33 -11
  48. package/src/rules/styles-no-raw-typography.ts +37 -15
  49. package/src/rules/taxonomy.test.ts +19 -3
  50. package/src/rules/tiers.ts +1 -1
  51. package/src/rules/tokens-require-dual-fallback.ts +54 -17
  52. package/src/rules/utils.ts +51 -0
  53. package/src/schemas/index.ts +106 -4
  54. package/src/token-types.ts +6 -0
  55. package/src/tokens/__tests__/source-names.test.ts +42 -0
  56. package/src/tokens/design-token-parser.test.ts +24 -5
  57. package/src/tokens/design-token-parser.ts +40 -8
  58. package/dist/chunk-243QYRUF.js.map +0 -1
  59. package/dist/chunk-R3X7UBHU.js.map +0 -1
@@ -1,6 +1,10 @@
1
1
  import {
2
+ AGENT_FORMAT_SCHEMA_VERSION,
3
+ agentErrorEnvelopeSchema,
2
4
  agentFindingSchema,
3
5
  agentFormatSchema,
6
+ agentIntegritySchema,
7
+ agentOutputSchema,
4
8
  agentPlanSchema,
5
9
  factEvidenceSchema,
6
10
  factLocationSchema,
@@ -20,15 +24,19 @@ import {
20
24
  suppressionDirectiveSchema,
21
25
  validatorResultSchema,
22
26
  violationSchema
23
- } from "../chunk-R3X7UBHU.js";
27
+ } from "../chunk-57QDBEHQ.js";
24
28
  import {
25
29
  legacySeverityLevelSchema,
26
30
  severityLevelSchema,
27
31
  severitySchema
28
32
  } from "../chunk-V4VQB57N.js";
29
33
  export {
34
+ AGENT_FORMAT_SCHEMA_VERSION,
35
+ agentErrorEnvelopeSchema,
30
36
  agentFindingSchema,
31
37
  agentFormatSchema,
38
+ agentIntegritySchema,
39
+ agentOutputSchema,
32
40
  agentPlanSchema,
33
41
  factEvidenceSchema,
34
42
  factLocationSchema,
@@ -1,4 +1,4 @@
1
- import { C as CompiledBlock, b as CompiledFragment } from './governance-BOa3KyiJ.js';
1
+ import { C as CompiledBlock, b as CompiledFragment } from './governance-DYSirwJu.js';
2
2
  import 'zod';
3
3
  import 'react';
4
4
  import './topology/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefragments/core",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "license": "MIT",
5
5
  "description": "Core types, schemas, and runtime API for Fragments component definitions",
6
6
  "author": "Conan McNicholl",
@@ -1,9 +1,22 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
 
3
3
  import { buildAgentFormat } from "./agent-format.js";
4
- import { agentFormatSchema, type Finding } from "./schemas/index.js";
4
+ import {
5
+ AGENT_FORMAT_SCHEMA_VERSION,
6
+ agentFormatSchema,
7
+ agentOutputSchema,
8
+ type AgentFormat,
9
+ type Finding,
10
+ } from "./schemas/index.js";
5
11
 
6
12
  const DEAD_TOOL_NAMES = ["apply_fix", "swap_to_canonical", "tokens.suggest"];
13
+ const HEALTHY_INTEGRITY = {
14
+ rulesLoaded: 1,
15
+ status: "healthy",
16
+ healthy: true,
17
+ inert: false,
18
+ reasons: [],
19
+ } satisfies AgentFormat["integrity"];
7
20
 
8
21
  function finding(overrides: Partial<Finding> = {}): Finding {
9
22
  return {
@@ -32,6 +45,7 @@ describe("buildAgentFormat", () => {
32
45
  it("names only hosted MCP tools in fix plans", () => {
33
46
  const agentFormat = buildAgentFormat({
34
47
  filesScanned: 1,
48
+ integrity: HEALTHY_INTEGRITY,
35
49
  findings: [
36
50
  finding({
37
51
  fix: {
@@ -69,6 +83,7 @@ describe("buildAgentFormat", () => {
69
83
  it("keeps warn-only scans passed when the report summary passed", () => {
70
84
  const agentFormat = buildAgentFormat({
71
85
  filesScanned: 1,
86
+ integrity: HEALTHY_INTEGRITY,
72
87
  passed: true,
73
88
  findings: [
74
89
  finding({
@@ -84,6 +99,7 @@ describe("buildAgentFormat", () => {
84
99
  it("omits full findings and evidence by default", () => {
85
100
  const agentFormat = buildAgentFormat({
86
101
  filesScanned: 1,
102
+ integrity: HEALTHY_INTEGRITY,
87
103
  findings: [finding()],
88
104
  });
89
105
 
@@ -100,6 +116,132 @@ describe("buildAgentFormat", () => {
100
116
  })
101
117
  );
102
118
 
103
- expect(buildAgentFormat({ filesScanned: 3, findings }).score).toBeGreaterThan(0);
119
+ expect(
120
+ buildAgentFormat({ filesScanned: 3, findings, integrity: HEALTHY_INTEGRITY }).score
121
+ ).toBeGreaterThan(0);
122
+ });
123
+
124
+ it("keeps a healthy empty scan passed with a perfect score", () => {
125
+ const agentFormat = buildAgentFormat({
126
+ filesScanned: 1,
127
+ findings: [],
128
+ integrity: HEALTHY_INTEGRITY,
129
+ });
130
+
131
+ expect(agentFormat).toMatchObject({
132
+ schemaVersion: AGENT_FORMAT_SCHEMA_VERSION,
133
+ passed: true,
134
+ score: 100,
135
+ integrity: HEALTHY_INTEGRITY,
136
+ });
137
+ });
138
+
139
+ it("marks an inert zero-rule scan indeterminate without inventing a score", () => {
140
+ const agentFormat = buildAgentFormat({
141
+ filesScanned: 1,
142
+ findings: [],
143
+ integrity: {
144
+ rulesLoaded: 0,
145
+ status: "inert",
146
+ healthy: false,
147
+ inert: true,
148
+ reasons: ["no_enforceable_rules"],
149
+ },
150
+ });
151
+
152
+ expect(agentFormat).toMatchObject({
153
+ passed: false,
154
+ status: "indeterminate",
155
+ reasons: ["zero_rules_loaded"],
156
+ integrity: {
157
+ rulesLoaded: 0,
158
+ healthy: false,
159
+ inert: true,
160
+ reasons: ["no_enforceable_rules"],
161
+ },
162
+ });
163
+ expect(agentFormat).not.toHaveProperty("score");
164
+ expect(agentFormat.summary).toContain("zero_rules_loaded");
165
+ expect(() => agentFormatSchema.parse(agentFormat)).not.toThrow();
166
+ });
167
+
168
+ it("rejects invalid determinate and indeterminate field combinations", () => {
169
+ const determinate = buildAgentFormat({
170
+ filesScanned: 1,
171
+ findings: [],
172
+ integrity: HEALTHY_INTEGRITY,
173
+ });
174
+ const indeterminate = buildAgentFormat({
175
+ filesScanned: 1,
176
+ findings: [],
177
+ integrity: {
178
+ rulesLoaded: 0,
179
+ status: "inert",
180
+ healthy: false,
181
+ inert: true,
182
+ reasons: ["no_enforceable_rules"],
183
+ },
184
+ });
185
+
186
+ expect(agentFormatSchema.safeParse({ ...determinate, score: undefined }).success).toBe(false);
187
+ expect(
188
+ agentFormatSchema.safeParse({
189
+ ...determinate,
190
+ status: "indeterminate",
191
+ reasons: ["zero_rules_loaded"],
192
+ }).success
193
+ ).toBe(false);
194
+ expect(agentFormatSchema.safeParse({ ...determinate, reasons: [] }).success).toBe(false);
195
+ expect(agentFormatSchema.safeParse({ ...indeterminate, passed: true }).success).toBe(false);
196
+ expect(agentFormatSchema.safeParse({ ...indeterminate, score: 0 }).success).toBe(false);
197
+ expect(
198
+ agentFormatSchema.safeParse({ ...indeterminate, reasons: ["no_enforceable_rules"] }).success
199
+ ).toBe(false);
200
+ expect(
201
+ agentFormatSchema.safeParse({
202
+ ...determinate,
203
+ integrity: { ...determinate.integrity, rulesLoaded: 0 },
204
+ }).success
205
+ ).toBe(false);
206
+ expect(
207
+ agentFormatSchema.safeParse({
208
+ ...indeterminate,
209
+ integrity: { ...indeterminate.integrity, rulesLoaded: 1 },
210
+ }).success
211
+ ).toBe(false);
212
+ });
213
+
214
+ it("validates the structured error envelope against the shared agent output schema", () => {
215
+ expect(() =>
216
+ agentOutputSchema.parse({
217
+ schemaVersion: AGENT_FORMAT_SCHEMA_VERSION,
218
+ passed: false,
219
+ error: { code: "check_failed", message: "Scan failed." },
220
+ })
221
+ ).not.toThrow();
222
+ });
223
+
224
+ it("preserves additive Run provenance and verdict through typed parsing", () => {
225
+ const agentFormat = buildAgentFormat({
226
+ filesScanned: 1,
227
+ findings: [],
228
+ integrity: HEALTHY_INTEGRITY,
229
+ provenance: {
230
+ runId: "run_0123456789ab",
231
+ fcid: "a".repeat(64),
232
+ scope: { method: "full", gitOk: true },
233
+ engineVersion: `sha256:${"b".repeat(64)}`,
234
+ scopeHash: "c".repeat(64),
235
+ inputFilesHash: "d".repeat(64),
236
+ },
237
+ verdict: { exitCode: 0, reasons: [], gatingFindingCount: 0 },
238
+ });
239
+
240
+ const parsed = agentOutputSchema.parse(agentFormat);
241
+
242
+ expect(parsed).toMatchObject({
243
+ provenance: { runId: "run_0123456789ab", scope: { method: "full", gitOk: true } },
244
+ verdict: { exitCode: 0, reasons: [], gatingFindingCount: 0 },
245
+ });
104
246
  });
105
247
  });
@@ -1,10 +1,11 @@
1
1
  import { severityLevel } from "./severity.js";
2
- import type { AgentFormat, Finding } from "./schemas/index.js";
2
+ import { AGENT_FORMAT_SCHEMA_VERSION, type AgentFormat, type Finding } from "./schemas/index.js";
3
3
  import type { SuppressionDirectiveFact } from "./facts/index.js";
4
4
 
5
5
  export interface BuildAgentFormatInput {
6
6
  findings: readonly Finding[];
7
7
  filesScanned: number;
8
+ integrity: AgentFormat["integrity"];
8
9
  passed?: boolean;
9
10
  suppressions?: readonly SuppressionDirectiveFact[];
10
11
  iteration?: number;
@@ -13,10 +14,14 @@ export interface BuildAgentFormatInput {
13
14
  maxFindings?: number;
14
15
  includeEvidence?: boolean;
15
16
  includeFindings?: boolean;
17
+ provenance?: NonNullable<AgentFormat["provenance"]>;
18
+ verdict?: NonNullable<AgentFormat["verdict"]>;
16
19
  }
17
20
 
18
21
  export function buildAgentFormat(input: BuildAgentFormatInput): AgentFormat {
19
- const score = scoreFindings(input.findings);
22
+ const zeroRulesLoaded = input.integrity.rulesLoaded === 0;
23
+ const integrityFailed = !input.integrity.healthy || input.integrity.inert;
24
+ const score = integrityFailed ? 0 : scoreFindings(input.findings);
20
25
  const visibleFindings = uniqueFindings(input.findings).slice(0, input.maxFindings ?? 50);
21
26
  const agentFindings = visibleFindings.map((finding) => ({
22
27
  code: finding.code,
@@ -27,6 +32,7 @@ export function buildAgentFormat(input: BuildAgentFormatInput): AgentFormat {
27
32
  severity: finding.severity,
28
33
  level: severityLevel(finding.severity),
29
34
  message: finding.message,
35
+ evidenceGrade: finding.evidenceGrade,
30
36
  evidence: input.includeEvidence ? finding.evidence : [],
31
37
  plan: planForFinding(finding),
32
38
  }));
@@ -36,11 +42,14 @@ export function buildAgentFormat(input: BuildAgentFormatInput): AgentFormat {
36
42
  // `passed:false`.
37
43
  const hasErrors = input.findings.some((finding) => severityLevel(finding.severity) === "error");
38
44
 
39
- return {
40
- schemaVersion: "typestyle.agent.v1",
41
- passed: (input.passed ?? true) && !hasErrors,
42
- score,
43
- summary: agentSummary(input.findings.length, input.filesScanned, score),
45
+ const shared = {
46
+ schemaVersion: AGENT_FORMAT_SCHEMA_VERSION,
47
+ summary: zeroRulesLoaded
48
+ ? "indeterminate; zero_rules_loaded"
49
+ : integrityFailed
50
+ ? `failed with score ${score}; ${input.integrity.reasons.join("; ") || "governance integrity is unhealthy"}`
51
+ : agentSummary(input.findings.length, input.filesScanned, score),
52
+ integrity: input.integrity,
44
53
  fix_first: agentFindings.filter((finding) => finding.plan.confidence >= 0.8),
45
54
  remaining: agentFindings.filter((finding) => finding.plan.confidence < 0.8),
46
55
  suppression_template: {
@@ -65,6 +74,24 @@ export function buildAgentFormat(input: BuildAgentFormatInput): AgentFormat {
65
74
  })),
66
75
  }
67
76
  : {}),
77
+ ...(input.provenance ? { provenance: input.provenance } : {}),
78
+ ...(input.verdict ? { verdict: input.verdict } : {}),
79
+ };
80
+
81
+ if (zeroRulesLoaded) {
82
+ return {
83
+ ...shared,
84
+ integrity: { ...input.integrity, rulesLoaded: 0 },
85
+ passed: false,
86
+ status: "indeterminate",
87
+ reasons: ["zero_rules_loaded"],
88
+ };
89
+ }
90
+
91
+ return {
92
+ ...shared,
93
+ passed: !integrityFailed && (input.passed ?? true) && !hasErrors,
94
+ score,
68
95
  };
69
96
  }
70
97
 
@@ -3,18 +3,36 @@ import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { describe, expect, it } from "vitest";
5
5
 
6
- import {
7
- CODES,
8
- EXPLAIN_URL_BASE,
9
- bridgeSourceViolation,
10
- byCode,
11
- byRuleId,
12
- } from "../index.js";
6
+ import { CODES, EXPLAIN_URL_BASE, bridgeSourceViolation, byCode, byRuleId } from "../index.js";
7
+ import { RULE_FIX_AVAILABLE, type RuleWithFixAvailability } from "../../rules/fix-availability.js";
8
+ import { RULES } from "../../rules/index.js";
13
9
 
14
10
  const __filename = fileURLToPath(import.meta.url);
15
11
  const __dirname = path.dirname(__filename);
16
12
  const registryPath = path.resolve(__dirname, "../../../../../docs/codes/registry.json");
17
13
 
14
+ const SUBSYSTEM_EMITTED_CODES = ["FUI9001", "FUI9002", "FUI9003"] as const;
15
+
16
+ const RESERVED_CODES = {
17
+ FUI1001: "Reserved for canonical primitive findings; no core rule emits it.",
18
+ FUI1005: "Reserved for component allow-set policy; no core rule emits it.",
19
+ FUI1006: "Reserved for component deny-set policy; no core rule emits it.",
20
+ FUI2001: "Reserved for generic design-token requirements; no core rule emits it.",
21
+ FUI2002: "Reserved for token-prefix policy; no core rule emits it.",
22
+ FUI2013: "Reserved for brand-seed enforcement; no core rule emits it.",
23
+ FUI3002: "Reserved for general accessibility standards; no core rule emits it.",
24
+ FUI5001: "Reserved for required-child composition; no core rule emits it.",
25
+ FUI5002: "Deprecated canonical-composition alias; no active core rule emits it.",
26
+ FUI6001: "Reserved for generic unknown props; no core rule emits it.",
27
+ FUI6003: "Reserved for banned prop patterns; no core rule emits it.",
28
+ FUI8001: "Reserved for event-handler safety policy; no core rule emits it.",
29
+ FUI8002: "Reserved for dangerous-prop safety policy; no core rule emits it.",
30
+ FUI8003: "Reserved for controlled-prop safety policy; no core rule emits it.",
31
+ FUI8004: "Reserved for function-prop safety policy; no core rule emits it.",
32
+ FUI8005: "Reserved for internal-prop safety policy; no core rule emits it.",
33
+ FUI8006: "Reserved for href-sanitization safety policy; no core rule emits it.",
34
+ } as const;
35
+
18
36
  describe("FUI code registry", () => {
19
37
  it("does not contain duplicate codes", () => {
20
38
  expect(new Set(CODES.map((entry) => entry.code)).size).toBe(CODES.length);
@@ -32,6 +50,38 @@ describe("FUI code registry", () => {
32
50
  }
33
51
  });
34
52
 
53
+ it("maps every implemented rule to a code", () => {
54
+ const unmappedRuleIds = RULES.filter((rule) => !byRuleId.has(rule.id)).map((rule) => rule.id);
55
+ expect(unmappedRuleIds).toEqual([]);
56
+ });
57
+
58
+ it("partitions every code into exactly one implementation state", () => {
59
+ const ruleBackedCodes = RULES.map((rule) => byRuleId.get(rule.id)?.code).filter(
60
+ (code): code is string => code !== undefined
61
+ );
62
+ const classifiedCodes = [
63
+ ...ruleBackedCodes,
64
+ ...SUBSYSTEM_EMITTED_CODES,
65
+ ...Object.keys(RESERVED_CODES),
66
+ ];
67
+
68
+ expect(new Set(classifiedCodes).size).toBe(classifiedCodes.length);
69
+ expect(classifiedCodes.sort()).toEqual(CODES.map((entry) => entry.code).sort());
70
+ expect(
71
+ Object.values(RESERVED_CODES).every((reason) => reason.length > 0 && !reason.includes("\n"))
72
+ ).toBe(true);
73
+ });
74
+
75
+ it("keeps rule fix capability in lock-step with RULES and rule-backed codes", () => {
76
+ const ruleIds = RULES.map((rule) => rule.id).sort();
77
+ expect(Object.keys(RULE_FIX_AVAILABLE).sort()).toEqual(ruleIds);
78
+
79
+ for (const rule of RULES) {
80
+ const fixAvailable = RULE_FIX_AVAILABLE[rule.id as RuleWithFixAvailability];
81
+ expect(byRuleId.get(rule.id)?.fixAvailable, rule.id).toBe(fixAvailable);
82
+ }
83
+ });
84
+
35
85
  it("matches the committed docs registry snapshot", () => {
36
86
  const snapshot = JSON.parse(readFileSync(registryPath, "utf8"));
37
87
  expect(snapshot).toEqual(CODES);
@@ -1,4 +1,5 @@
1
1
  import type { Severity } from "../severity.js";
2
+ import { RULE_FIX_AVAILABLE, type RuleWithFixAvailability } from "../rules/fix-availability.js";
2
3
  export type { Severity } from "../severity.js";
3
4
 
4
5
  export const EXPLAIN_URL_BASE = "https://usefragments.com/errors/";
@@ -36,6 +37,19 @@ function code(entry: Omit<FuiCode, "explainUrl"> & { explainUrl?: never }): FuiC
36
37
  };
37
38
  }
38
39
 
40
+ type RuleCodeEntry = Omit<FuiCode, "explainUrl" | "fixAvailable" | "ruleId"> & {
41
+ ruleId: RuleWithFixAvailability;
42
+ };
43
+
44
+ function ruleCode(entry: RuleCodeEntry): FuiCode {
45
+ const { evidenceRequired, ...metadata } = entry;
46
+ return code({
47
+ ...metadata,
48
+ fixAvailable: RULE_FIX_AVAILABLE[entry.ruleId],
49
+ evidenceRequired,
50
+ });
51
+ }
52
+
39
53
  export const CODES = [
40
54
  code({
41
55
  code: "FUI1001",
@@ -47,34 +61,31 @@ export const CODES = [
47
61
  fixAvailable: true,
48
62
  evidenceRequired: true,
49
63
  }),
50
- code({
64
+ ruleCode({
51
65
  code: "FUI1002",
52
66
  ruleId: "components/preferred-component",
53
67
  category: "canonical-usage",
54
68
  defaultSeverity: "serious",
55
69
  title: "Preferred component should be used",
56
70
  lifecycle: "experimental",
57
- fixAvailable: true,
58
71
  evidenceRequired: true,
59
72
  }),
60
- code({
73
+ ruleCode({
61
74
  code: "FUI1003",
62
75
  ruleId: "imports/preferred-path",
63
76
  category: "canonical-usage",
64
77
  defaultSeverity: "moderate",
65
78
  title: "Import should use the preferred path",
66
79
  lifecycle: "experimental",
67
- fixAvailable: true,
68
80
  evidenceRequired: true,
69
81
  }),
70
- code({
82
+ ruleCode({
71
83
  code: "FUI1004",
72
84
  ruleId: "components/prefer-library",
73
85
  category: "canonical-usage",
74
86
  defaultSeverity: "moderate",
75
87
  title: "Library component should be preferred",
76
88
  lifecycle: "experimental",
77
- fixAvailable: true,
78
89
  evidenceRequired: true,
79
90
  }),
80
91
  code({
@@ -117,104 +128,94 @@ export const CODES = [
117
128
  fixAvailable: true,
118
129
  evidenceRequired: true,
119
130
  }),
120
- code({
131
+ ruleCode({
121
132
  code: "FUI2003",
122
133
  ruleId: "tokens/require-dual-fallback",
123
134
  category: "tokens",
124
135
  defaultSeverity: "serious",
125
136
  title: "Token fallback is required",
126
137
  lifecycle: "experimental",
127
- fixAvailable: true,
128
138
  evidenceRequired: true,
129
139
  }),
130
- code({
140
+ ruleCode({
131
141
  code: "FUI2004",
132
142
  ruleId: "styles/no-raw-dimensions",
133
143
  category: "tokens",
134
144
  defaultSeverity: "serious",
135
145
  title: "Raw dimension should use a token",
136
146
  lifecycle: "experimental",
137
- fixAvailable: true,
138
147
  evidenceRequired: true,
139
148
  }),
140
- code({
149
+ ruleCode({
141
150
  code: "FUI2005",
142
151
  ruleId: "styles/no-raw-color",
143
152
  category: "tokens",
144
153
  defaultSeverity: "serious",
145
154
  title: "Raw color should use a token",
146
155
  lifecycle: "experimental",
147
- fixAvailable: true,
148
156
  evidenceRequired: true,
149
157
  }),
150
- code({
158
+ ruleCode({
151
159
  code: "FUI2006",
152
160
  ruleId: "styles/no-raw-spacing",
153
161
  category: "tokens",
154
162
  defaultSeverity: "serious",
155
163
  title: "Raw spacing should use the scale",
156
164
  lifecycle: "experimental",
157
- fixAvailable: true,
158
165
  evidenceRequired: true,
159
166
  }),
160
- code({
167
+ ruleCode({
161
168
  code: "FUI2007",
162
169
  ruleId: "tailwind/arbitrary-color",
163
170
  category: "tokens",
164
171
  defaultSeverity: "moderate",
165
172
  title: "Tailwind arbitrary color should use a token",
166
173
  lifecycle: "experimental",
167
- fixAvailable: true,
168
174
  evidenceRequired: true,
169
175
  }),
170
- code({
176
+ ruleCode({
171
177
  code: "FUI2008",
172
178
  ruleId: "tailwind/arbitrary-spacing",
173
179
  category: "tokens",
174
180
  defaultSeverity: "moderate",
175
181
  title: "Tailwind arbitrary spacing should use the scale",
176
182
  lifecycle: "experimental",
177
- fixAvailable: true,
178
183
  evidenceRequired: true,
179
184
  }),
180
- code({
185
+ ruleCode({
181
186
  code: "FUI2009",
182
187
  ruleId: "tailwind/forbidden-palette",
183
188
  category: "tokens",
184
189
  defaultSeverity: "moderate",
185
190
  title: "Tailwind palette is forbidden",
186
191
  lifecycle: "experimental",
187
- fixAvailable: false,
188
192
  evidenceRequired: true,
189
193
  }),
190
- code({
194
+ ruleCode({
191
195
  code: "FUI2010",
192
196
  ruleId: "tailwind/raw-color-via-token",
193
197
  category: "tokens",
194
198
  defaultSeverity: "moderate",
195
199
  title: "Tailwind color should use a resolved token",
196
200
  lifecycle: "experimental",
197
- fixAvailable: true,
198
201
  evidenceRequired: true,
199
202
  }),
200
- code({
203
+ ruleCode({
201
204
  code: "FUI2011",
202
205
  ruleId: "tailwind/off-scale-spacing-token",
203
206
  category: "tokens",
204
207
  defaultSeverity: "moderate",
205
208
  title: "Tailwind spacing token is off scale",
206
209
  lifecycle: "experimental",
207
- fixAvailable: true,
208
210
  evidenceRequired: true,
209
211
  }),
210
- code({
212
+ ruleCode({
211
213
  code: "FUI2012",
212
214
  ruleId: "tailwind/unknown-class",
213
215
  category: "tokens",
214
216
  defaultSeverity: "moderate",
215
217
  title: "Tailwind class is unknown",
216
218
  lifecycle: "experimental",
217
- fixAvailable: false,
218
219
  evidenceRequired: true,
219
220
  }),
220
221
  code({
@@ -227,34 +228,40 @@ export const CODES = [
227
228
  fixAvailable: true,
228
229
  evidenceRequired: true,
229
230
  }),
230
- code({
231
+ ruleCode({
231
232
  code: "FUI2014",
232
233
  ruleId: "theme/no-theme-coupled-literal",
233
234
  category: "tokens",
234
235
  defaultSeverity: "moderate",
235
236
  title: "Theme-coupled literal should use a semantic token",
236
237
  lifecycle: "experimental",
237
- fixAvailable: false,
238
238
  evidenceRequired: true,
239
239
  }),
240
- code({
240
+ ruleCode({
241
241
  code: "FUI2015",
242
242
  ruleId: "tokens/css-vars-must-be-defined",
243
243
  category: "tokens",
244
244
  defaultSeverity: "moderate",
245
245
  title: "CSS variable is not in the contract vocabulary",
246
246
  lifecycle: "experimental",
247
- fixAvailable: false,
248
247
  evidenceRequired: true,
249
248
  }),
250
- code({
249
+ ruleCode({
250
+ code: "FUI2016",
251
+ ruleId: "styles/no-raw-typography",
252
+ category: "tokens",
253
+ defaultSeverity: "serious",
254
+ title: "Raw typography should use a token",
255
+ lifecycle: "experimental",
256
+ evidenceRequired: true,
257
+ }),
258
+ ruleCode({
251
259
  code: "FUI3001",
252
260
  ruleId: "a11y/required-accessible-name",
253
261
  category: "a11y",
254
262
  defaultSeverity: "serious",
255
263
  title: "Accessible name is required",
256
264
  lifecycle: "experimental",
257
- fixAvailable: false,
258
265
  evidenceRequired: true,
259
266
  }),
260
267
  code({
@@ -288,24 +295,22 @@ export const CODES = [
288
295
  fixAvailable: true,
289
296
  evidenceRequired: true,
290
297
  }),
291
- code({
298
+ ruleCode({
292
299
  code: "FUI5003",
293
300
  ruleId: "composition/cardinality",
294
301
  category: "composition",
295
302
  defaultSeverity: "moderate",
296
303
  title: "Too many of a component in one region",
297
304
  lifecycle: "experimental",
298
- fixAvailable: false,
299
305
  evidenceRequired: true,
300
306
  }),
301
- code({
307
+ ruleCode({
302
308
  code: "FUI5004",
303
309
  ruleId: "composition/co-occurrence",
304
310
  category: "composition",
305
311
  defaultSeverity: "moderate",
306
312
  title: "Required companion component is missing from the region",
307
313
  lifecycle: "experimental",
308
- fixAvailable: false,
309
314
  evidenceRequired: true,
310
315
  }),
311
316
  code({
@@ -318,14 +323,13 @@ export const CODES = [
318
323
  fixAvailable: false,
319
324
  evidenceRequired: true,
320
325
  }),
321
- code({
326
+ ruleCode({
322
327
  code: "FUI6002",
323
328
  ruleId: "props/invalid-value",
324
329
  category: "props",
325
330
  defaultSeverity: "serious",
326
331
  title: "Prop value is invalid",
327
332
  lifecycle: "experimental",
328
- fixAvailable: true,
329
333
  evidenceRequired: true,
330
334
  }),
331
335
  code({
@@ -338,24 +342,22 @@ export const CODES = [
338
342
  fixAvailable: false,
339
343
  evidenceRequired: true,
340
344
  }),
341
- code({
345
+ ruleCode({
342
346
  code: "FUI6004",
343
347
  ruleId: "components/forbidden-prop-value",
344
348
  category: "props",
345
349
  defaultSeverity: "serious",
346
350
  title: "Prop value is forbidden",
347
351
  lifecycle: "experimental",
348
- fixAvailable: true,
349
352
  evidenceRequired: true,
350
353
  }),
351
- code({
354
+ ruleCode({
352
355
  code: "FUI6005",
353
356
  ruleId: "components/unknown-prop",
354
357
  category: "props",
355
358
  defaultSeverity: "moderate",
356
359
  title: "Component prop is unknown",
357
360
  lifecycle: "experimental",
358
- fixAvailable: false,
359
361
  evidenceRequired: true,
360
362
  }),
361
363
  code({