@usefragments/core 1.0.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 (228) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-243QYRUF.js +2145 -0
  3. package/dist/chunk-243QYRUF.js.map +1 -0
  4. package/dist/chunk-3LLRNCPX.js +111 -0
  5. package/dist/chunk-3LLRNCPX.js.map +1 -0
  6. package/dist/chunk-EIYNNS77.js +48 -0
  7. package/dist/chunk-EIYNNS77.js.map +1 -0
  8. package/dist/chunk-JNBFJ34I.js +326 -0
  9. package/dist/chunk-JNBFJ34I.js.map +1 -0
  10. package/dist/chunk-R3X7UBHU.js +228 -0
  11. package/dist/chunk-R3X7UBHU.js.map +1 -0
  12. package/dist/chunk-SH4KPIYH.js +393 -0
  13. package/dist/chunk-SH4KPIYH.js.map +1 -0
  14. package/dist/chunk-V4VQB57N.js +56 -0
  15. package/dist/chunk-V4VQB57N.js.map +1 -0
  16. package/dist/chunk-X34IA4LR.js +319 -0
  17. package/dist/chunk-X34IA4LR.js.map +1 -0
  18. package/dist/chunk-YF65VYRY.js +493 -0
  19. package/dist/chunk-YF65VYRY.js.map +1 -0
  20. package/dist/codes/index.d.ts +40 -0
  21. package/dist/codes/index.js +23 -0
  22. package/dist/codes/index.js.map +1 -0
  23. package/dist/compiled-types/index.d.ts +5 -0
  24. package/dist/compiled-types/index.js +1 -0
  25. package/dist/compiled-types/index.js.map +1 -0
  26. package/dist/generate/index.d.ts +47 -0
  27. package/dist/generate/index.js +11 -0
  28. package/dist/generate/index.js.map +1 -0
  29. package/dist/governance-BOa3KyiJ.d.ts +3279 -0
  30. package/dist/graph/index.d.ts +66 -0
  31. package/dist/graph/index.js +17 -0
  32. package/dist/graph/index.js.map +1 -0
  33. package/dist/index.d.ts +11388 -0
  34. package/dist/index.js +8711 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/package-identity.d.ts +42 -0
  37. package/dist/package-identity.js +23 -0
  38. package/dist/package-identity.js.map +1 -0
  39. package/dist/preview/index.d.ts +484 -0
  40. package/dist/preview/index.js +1129 -0
  41. package/dist/preview/index.js.map +1 -0
  42. package/dist/react-types.d.ts +22 -0
  43. package/dist/react-types.js +1 -0
  44. package/dist/react-types.js.map +1 -0
  45. package/dist/registry.d.ts +2367 -0
  46. package/dist/registry.js +62 -0
  47. package/dist/registry.js.map +1 -0
  48. package/dist/schemas/index.d.ts +2584 -0
  49. package/dist/schemas/index.js +55 -0
  50. package/dist/schemas/index.js.map +1 -0
  51. package/dist/severity.d.ts +18 -0
  52. package/dist/severity.js +27 -0
  53. package/dist/severity.js.map +1 -0
  54. package/dist/test-utils.d.ts +14 -0
  55. package/dist/test-utils.js +63 -0
  56. package/dist/test-utils.js.map +1 -0
  57. package/dist/topology/index.d.ts +48 -0
  58. package/dist/topology/index.js +7 -0
  59. package/dist/topology/index.js.map +1 -0
  60. package/dist/types-xJ2xyp_G.d.ts +119 -0
  61. package/package.json +120 -0
  62. package/src/__tests__/contract-parser.test.ts +614 -0
  63. package/src/__tests__/dtcg-generators.test.ts +439 -0
  64. package/src/__tests__/dtcg-parser.test.ts +884 -0
  65. package/src/__tests__/preview-runtime.test.tsx +111 -0
  66. package/src/__tests__/schema.test.ts +31 -0
  67. package/src/__tests__/severity.test.ts +34 -0
  68. package/src/__tests__/style-comparison.test.ts +662 -0
  69. package/src/__tests__/tokens-compat.test.ts +51 -0
  70. package/src/agent-format.test.ts +105 -0
  71. package/src/agent-format.ts +141 -0
  72. package/src/bundle.ts +149 -0
  73. package/src/codes/__tests__/codes.test.ts +73 -0
  74. package/src/codes/codes.ts +463 -0
  75. package/src/codes/index.ts +7 -0
  76. package/src/codes/source-finding-bridge.ts +113 -0
  77. package/src/compiled-types/index.ts +293 -0
  78. package/src/component-contract.ts +231 -0
  79. package/src/component-discovery.ts +80 -0
  80. package/src/composition.test.ts +262 -0
  81. package/src/composition.ts +318 -0
  82. package/src/config-paths.test.ts +78 -0
  83. package/src/config-paths.ts +47 -0
  84. package/src/config.ts +18 -0
  85. package/src/conform-prove.test.ts +274 -0
  86. package/src/conform-prove.ts +326 -0
  87. package/src/conform.ts +160 -0
  88. package/src/constants.ts +114 -0
  89. package/src/context.ts +2 -0
  90. package/src/contract/fixture.ts +110 -0
  91. package/src/contract/hash.test.ts +86 -0
  92. package/src/contract/hash.ts +195 -0
  93. package/src/contract/index.ts +43 -0
  94. package/src/contract/preimage.test.ts +254 -0
  95. package/src/contract/preimage.ts +365 -0
  96. package/src/contract/stamp.test.ts +100 -0
  97. package/src/contract/stamp.ts +105 -0
  98. package/src/contract-parser.ts +141 -0
  99. package/src/defineFragment.test.ts +257 -0
  100. package/src/defineFragment.ts +293 -0
  101. package/src/dtcg-generators.ts +324 -0
  102. package/src/dtcg-parser.ts +1 -0
  103. package/src/dtcg.ts +237 -0
  104. package/src/facts/__snapshots__/facts.test.ts.snap +124 -0
  105. package/src/facts/builders.ts +835 -0
  106. package/src/facts/compile.ts +422 -0
  107. package/src/facts/fact-index.ts +394 -0
  108. package/src/facts/facts.test.ts +494 -0
  109. package/src/facts/ids.ts +125 -0
  110. package/src/facts/index.ts +119 -0
  111. package/src/facts/types.ts +614 -0
  112. package/src/figma.ts +263 -0
  113. package/src/fragment-types.ts +214 -0
  114. package/src/generate/generate.test.ts +594 -0
  115. package/src/generate/index.ts +438 -0
  116. package/src/governance-integrity.test.ts +186 -0
  117. package/src/governance-integrity.ts +282 -0
  118. package/src/governance.test.ts +300 -0
  119. package/src/governance.ts +605 -0
  120. package/src/governance.type-test.ts +75 -0
  121. package/src/graph/engine.ts +446 -0
  122. package/src/graph/graph.test.ts +746 -0
  123. package/src/graph/index.ts +32 -0
  124. package/src/graph/serialization.ts +55 -0
  125. package/src/graph/types.ts +178 -0
  126. package/src/index.ts +891 -0
  127. package/src/local-canonical.ts +102 -0
  128. package/src/mcp-snapshot.ts +222 -0
  129. package/src/package-identity-match.ts +33 -0
  130. package/src/package-identity.generated.ts +233 -0
  131. package/src/package-identity.test.ts +99 -0
  132. package/src/package-identity.ts +157 -0
  133. package/src/performance-presets.ts +142 -0
  134. package/src/preview/comparison-artifact.test.ts +228 -0
  135. package/src/preview/comparison-artifact.ts +181 -0
  136. package/src/preview/comparison-context.ts +93 -0
  137. package/src/preview/comparison-evidence.ts +112 -0
  138. package/src/preview/comparison-format.ts +21 -0
  139. package/src/preview/comparison-presentation.ts +187 -0
  140. package/src/preview/comparison-references.test.ts +430 -0
  141. package/src/preview/comparison-references.ts +72 -0
  142. package/src/preview/comparison-score.ts +59 -0
  143. package/src/preview/comparison-styles.ts +197 -0
  144. package/src/preview/comparison.test.ts +559 -0
  145. package/src/preview/comparison.ts +488 -0
  146. package/src/preview/index.ts +10 -0
  147. package/src/preview/types.ts +309 -0
  148. package/src/preview/validation.test.ts +290 -0
  149. package/src/preview/validation.ts +356 -0
  150. package/src/preview-runtime.tsx +144 -0
  151. package/src/raw-html-canonical.test.ts +41 -0
  152. package/src/raw-html-canonical.ts +179 -0
  153. package/src/react-types.ts +21 -0
  154. package/src/registry-install-plan.ts +344 -0
  155. package/src/registry.test.ts +245 -0
  156. package/src/registry.ts +369 -0
  157. package/src/rules/a11y-required-accessible-name.ts +93 -0
  158. package/src/rules/color-math.test.ts +72 -0
  159. package/src/rules/color-math.ts +192 -0
  160. package/src/rules/components-forbidden-prop-value.ts +108 -0
  161. package/src/rules/components-prefer-library.ts +943 -0
  162. package/src/rules/components-unknown-prop.ts +94 -0
  163. package/src/rules/composition-pattern-schema.ts +125 -0
  164. package/src/rules/composition-pattern.test.ts +320 -0
  165. package/src/rules/composition-pattern.ts +271 -0
  166. package/src/rules/emit-gate.test.ts +42 -0
  167. package/src/rules/emit-gate.ts +60 -0
  168. package/src/rules/finding.ts +54 -0
  169. package/src/rules/index.ts +235 -0
  170. package/src/rules/jsx-preferred-component.ts +68 -0
  171. package/src/rules/jsx-preferred-import-path.ts +67 -0
  172. package/src/rules/presets.ts +57 -0
  173. package/src/rules/props-invalid-value.ts +115 -0
  174. package/src/rules/rules.test.ts +3636 -0
  175. package/src/rules/spacing-resolution.ts +184 -0
  176. package/src/rules/styles-no-raw-color.ts +329 -0
  177. package/src/rules/styles-no-raw-dimensions.ts +357 -0
  178. package/src/rules/styles-no-raw-spacing.ts +236 -0
  179. package/src/rules/styles-no-raw-typography.ts +237 -0
  180. package/src/rules/tailwind-arbitrary-color.test.ts +128 -0
  181. package/src/rules/tailwind-arbitrary-color.ts +93 -0
  182. package/src/rules/tailwind-arbitrary-spacing.test.ts +157 -0
  183. package/src/rules/tailwind-arbitrary-spacing.ts +120 -0
  184. package/src/rules/tailwind-forbidden-palette.test.ts +116 -0
  185. package/src/rules/tailwind-forbidden-palette.ts +107 -0
  186. package/src/rules/tailwind-off-scale-spacing-token.test.ts +100 -0
  187. package/src/rules/tailwind-off-scale-spacing-token.ts +108 -0
  188. package/src/rules/tailwind-raw-color-via-token.test.ts +108 -0
  189. package/src/rules/tailwind-raw-color-via-token.ts +82 -0
  190. package/src/rules/tailwind-rule-utils.ts +106 -0
  191. package/src/rules/tailwind-unknown-class.test.ts +157 -0
  192. package/src/rules/tailwind-unknown-class.ts +121 -0
  193. package/src/rules/taxonomy.test.ts +238 -0
  194. package/src/rules/theme-no-theme-coupled-literal.ts +132 -0
  195. package/src/rules/tiers.ts +111 -0
  196. package/src/rules/tokens-css-vars-must-be-defined.test.ts +244 -0
  197. package/src/rules/tokens-css-vars-must-be-defined.ts +156 -0
  198. package/src/rules/tokens-require-dual-fallback.ts +78 -0
  199. package/src/rules/types.ts +27 -0
  200. package/src/rules/utils.test.ts +110 -0
  201. package/src/rules/utils.ts +599 -0
  202. package/src/schema.ts +427 -0
  203. package/src/schemas/index.ts +275 -0
  204. package/src/schemas/schemas.test.ts +124 -0
  205. package/src/severity.ts +54 -0
  206. package/src/storyAdapter.test.ts +571 -0
  207. package/src/storyAdapter.ts +761 -0
  208. package/src/storyFilters.test.ts +350 -0
  209. package/src/storyFilters.ts +253 -0
  210. package/src/storybook-csf.ts +11 -0
  211. package/src/style-comparison.ts +423 -0
  212. package/src/test-utils.ts +68 -0
  213. package/src/token-parser.ts +2 -0
  214. package/src/token-types.ts +287 -0
  215. package/src/tokens/categories.ts +131 -0
  216. package/src/tokens/color.ts +193 -0
  217. package/src/tokens/design-token-parser.test.ts +159 -0
  218. package/src/tokens/design-token-parser.ts +402 -0
  219. package/src/tokens/dtcg.ts +428 -0
  220. package/src/tokens/index.ts +130 -0
  221. package/src/tokens/lookup.ts +19 -0
  222. package/src/tokens/scss.ts +171 -0
  223. package/src/tokens/tailwind-v4.ts +187 -0
  224. package/src/tokens/types.ts +43 -0
  225. package/src/topology/index.ts +9 -0
  226. package/src/topology/resolve-area.test.ts +174 -0
  227. package/src/topology/resolve-area.ts +215 -0
  228. package/src/types.ts +1057 -0
@@ -0,0 +1,614 @@
1
+ /**
2
+ * Fact IR — discriminated union of governance facts.
3
+ *
4
+ * Facts are content-addressed records. Their ID is a deterministic hash of a
5
+ * canonical identity tuple (kind + identity fields), never the source location
6
+ * — moving a line in a source file does not perturb component or policy fact
7
+ * IDs. Usage facts include source location for evidence display, but their ID
8
+ * is derived only from structural identity (file + node path + element).
9
+ *
10
+ * This module owns only the types. Hashing lives in `./ids.ts`, builders in
11
+ * `./builders.ts`, the in-memory store in `./fact-index.ts`, and conversion
12
+ * from compiled fragments + governance config in `./compile.ts`.
13
+ */
14
+
15
+ import type { GovernanceSeverity } from "../governance.js";
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Branded IDs
19
+ // ---------------------------------------------------------------------------
20
+
21
+ declare const componentIdBrand: unique symbol;
22
+ declare const factIdBrand: unique symbol;
23
+
24
+ export type ComponentId = string & { readonly [componentIdBrand]: void };
25
+ export type FactId = string & { readonly [factIdBrand]: void };
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Source location (carried by usage facts; never part of fact identity)
29
+ // ---------------------------------------------------------------------------
30
+
31
+ export interface FactLocation {
32
+ file: string;
33
+ line: number;
34
+ column: number;
35
+ endLine?: number;
36
+ endColumn?: number;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Component facts
41
+ // ---------------------------------------------------------------------------
42
+
43
+ interface BaseFact {
44
+ id: FactId;
45
+ }
46
+
47
+ export interface ComponentMetadataFact extends BaseFact {
48
+ kind: "component";
49
+ componentId: ComponentId;
50
+ name: string;
51
+ description?: string;
52
+ category?: string;
53
+ filePath?: string;
54
+ }
55
+
56
+ export interface ComponentCapabilityFact extends BaseFact {
57
+ kind: "component_capability";
58
+ componentId: ComponentId;
59
+ capability: string;
60
+ }
61
+
62
+ export interface PropMetadataFact extends BaseFact {
63
+ kind: "prop_metadata";
64
+ componentId: ComponentId;
65
+ prop: string;
66
+ type: string;
67
+ values?: string[];
68
+ required: boolean;
69
+ default?: unknown;
70
+ description?: string;
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Policy facts (component-scoped)
75
+ // ---------------------------------------------------------------------------
76
+
77
+ export interface PropValueAvoidedFact extends BaseFact {
78
+ kind: "prop_value_avoided";
79
+ componentId: ComponentId;
80
+ prop: string;
81
+ value: unknown;
82
+ because: string;
83
+ suggest?: string;
84
+ severity: GovernanceSeverity;
85
+ }
86
+
87
+ export interface PropValueForbiddenFact extends BaseFact {
88
+ kind: "prop_value_forbidden";
89
+ componentId: ComponentId;
90
+ prop: string;
91
+ value: unknown;
92
+ pathPattern?: string;
93
+ because: string;
94
+ replaceWith?: unknown;
95
+ severity: GovernanceSeverity;
96
+ }
97
+
98
+ export interface A11yNameRequiredFact extends BaseFact {
99
+ kind: "a11y_name_required";
100
+ componentId: ComponentId;
101
+ because: string;
102
+ severity: GovernanceSeverity;
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Policy facts (global)
107
+ // ---------------------------------------------------------------------------
108
+
109
+ export interface ScaleFact extends BaseFact {
110
+ kind: "scale";
111
+ name: string;
112
+ unit: "px" | "rem";
113
+ rootFontSizePx?: number;
114
+ emBasePx?: number;
115
+ }
116
+
117
+ export interface ScaleValueFact extends BaseFact {
118
+ kind: "scale_value";
119
+ scale: string;
120
+ value: number;
121
+ }
122
+
123
+ export interface StyleRawColorForbiddenFact extends BaseFact {
124
+ kind: "style_raw_color_forbidden";
125
+ except: string[];
126
+ prefer: "token" | "css-variable";
127
+ severity: GovernanceSeverity;
128
+ }
129
+
130
+ export interface StyleRawDimensionForbiddenFact extends BaseFact {
131
+ kind: "style_raw_dimension_forbidden";
132
+ appliesTo: string[];
133
+ prefer: "token" | "css-variable";
134
+ severity: GovernanceSeverity;
135
+ }
136
+
137
+ export interface StylePropertyScaleFact extends BaseFact {
138
+ kind: "style_property_scale";
139
+ property: string;
140
+ scale: string;
141
+ severity: GovernanceSeverity;
142
+ }
143
+
144
+ export interface StyleFontSizeScaleFact extends BaseFact {
145
+ kind: "style_font_size_scale";
146
+ scale: string;
147
+ severity: GovernanceSeverity;
148
+ }
149
+
150
+ export interface StyleCssVarsMustBeDefinedFact extends BaseFact {
151
+ kind: "style_css_vars_must_be_defined";
152
+ severity: GovernanceSeverity;
153
+ }
154
+
155
+ /**
156
+ * A token name in the contract vocabulary (from the user's selected token source
157
+ * files). A DEDICATED channel — separate from `token_definition` — so the
158
+ * off-contract-drift rule (FUI2015) judges `var(--x)` against the CONTRACT
159
+ * vocabulary, while the raw-* rules + scale detection keep reading the project's
160
+ * local `token_definition` tokens unchanged.
161
+ */
162
+ export interface ContractTokenFact extends BaseFact {
163
+ kind: "contract_token";
164
+ /** Custom-property name, normalized to `--`-prefixed form. */
165
+ name: string;
166
+ }
167
+
168
+ export interface JsxUnknownPropsForbiddenFact extends BaseFact {
169
+ kind: "jsx_unknown_props_forbidden";
170
+ severity: GovernanceSeverity;
171
+ }
172
+
173
+ export interface JsxInlineStyleForbiddenRawFact extends BaseFact {
174
+ kind: "jsx_inline_style_forbidden_raw";
175
+ property: string;
176
+ severity: GovernanceSeverity;
177
+ }
178
+
179
+ export interface JsxImportPathPreferredFact extends BaseFact {
180
+ kind: "jsx_import_path_preferred";
181
+ from: string;
182
+ to: string;
183
+ imported?: string;
184
+ because?: string;
185
+ severity: GovernanceSeverity;
186
+ }
187
+
188
+ export interface JsxComponentPreferredFact extends BaseFact {
189
+ kind: "jsx_component_preferred";
190
+ from: ComponentId;
191
+ to: ComponentId;
192
+ because?: string;
193
+ severity: GovernanceSeverity;
194
+ }
195
+
196
+ /**
197
+ * A design token from the system. Used by fixes (e.g., raw color → token
198
+ * substitution) and rules that need to know the token vocabulary. Identity is
199
+ * the token `name`; two scans of the same token registry produce the same ID.
200
+ */
201
+ export interface TokenDefinitionFact extends BaseFact {
202
+ kind: "token_definition";
203
+ /** Token identifier, e.g., "fui-color-accent" or "--fui-color-accent". */
204
+ name: string;
205
+ /** Resolved value, e.g., "#2563eb". */
206
+ value: string;
207
+ /** Loose category bucket. Phase 6 only differentiates `color` from others. */
208
+ category?: "color" | "spacing" | "typography" | "radius" | "shadow" | "other";
209
+ /**
210
+ * How the token is referenced from authored styles, inferred from its source.
211
+ * Governs whether a "use the token" fix can be *applied* automatically: a
212
+ * `css-var`/`scss-var` reference resolves verbatim, but a `scss-map` member
213
+ * (`$colors-primary` minted from a Sass map) or a `dtcg` JSON token (no CSS
214
+ * custom property emitted) does not — those are surfaced as suggestions, not
215
+ * deterministic rewrites, so the fixer never writes non-compiling output.
216
+ * Absent on legacy/hand-built facts, which are treated as safe.
217
+ */
218
+ referenceFormat?: "css-var" | "scss-var" | "scss-map" | "dtcg";
219
+ }
220
+
221
+ export interface TailwindPaletteAllowFact extends BaseFact {
222
+ kind: "tailwind_palette_allow";
223
+ patterns: string[];
224
+ severity: GovernanceSeverity;
225
+ }
226
+
227
+ export interface TailwindPaletteDenyFact extends BaseFact {
228
+ kind: "tailwind_palette_deny";
229
+ patterns: string[];
230
+ severity: GovernanceSeverity;
231
+ }
232
+
233
+ export interface TailwindUnknownClassEnabledFact extends BaseFact {
234
+ kind: "tailwind_unknown_class_enabled";
235
+ severity: GovernanceSeverity;
236
+ }
237
+
238
+ export interface GovernanceRuleConfigFact extends BaseFact {
239
+ kind: "governance_rule_config";
240
+ ruleId: string;
241
+ enabled: boolean;
242
+ severity?: GovernanceSeverity;
243
+ options?: Record<string, unknown>;
244
+ }
245
+
246
+ // ---------------------------------------------------------------------------
247
+ // Usage facts (Phase 4 will populate these; types live here so the index and
248
+ // rules can reference them already).
249
+ // ---------------------------------------------------------------------------
250
+
251
+ export interface UsageNodeFact extends BaseFact {
252
+ kind: "usage_node";
253
+ file: string;
254
+ /**
255
+ * Stable structural path: a `rootIndex:` token (the root tree's index within
256
+ * the file) then `/`-joined opaque segments, e.g. `"0:2/1"`. Segments are
257
+ * emitted by the framework adapter (`computeNodePath`) and compared whole —
258
+ * never parsed inside (see the usage-node-fact contract); `regionsByPrefix`
259
+ * relies on this grammar.
260
+ */
261
+ nodePath: string;
262
+ element: string;
263
+ /**
264
+ * Normalized ARIA role of the element when statically declared (a
265
+ * `role="status"` attribute or equivalent). Framework-neutral: every adapter
266
+ * populates it from its own markup (JSX attribute, Vue/Svelte template
267
+ * binding, …) so semantic rules can reason over roles without knowing the
268
+ * framework. Never part of fact identity.
269
+ */
270
+ role?: string;
271
+ /**
272
+ * Normalized interactivity signal: true when the element carries an
273
+ * interaction handler (click/key/pointer/…) or is intrinsically interactive.
274
+ * Framework-neutral — the adapter decides how to detect it. Never part of
275
+ * fact identity.
276
+ */
277
+ interactive?: boolean;
278
+ location: FactLocation;
279
+ }
280
+
281
+ export interface UsageComponentFact extends BaseFact {
282
+ kind: "usage_component";
283
+ nodeId: FactId;
284
+ componentId: ComponentId;
285
+ }
286
+
287
+ export interface UsageImportFact extends BaseFact {
288
+ kind: "usage_import";
289
+ file: string;
290
+ local: string;
291
+ imported: string;
292
+ source: string;
293
+ namespace?: boolean;
294
+ location: FactLocation;
295
+ }
296
+
297
+ export interface UsagePropResolvedFact extends BaseFact {
298
+ kind: "usage_prop_resolved";
299
+ nodeId: FactId;
300
+ prop: string;
301
+ resolution: "static" | "dynamic" | "spread" | "jsx";
302
+ value?: unknown;
303
+ location?: FactLocation;
304
+ }
305
+
306
+ export interface UsageInlineStyleFact extends BaseFact {
307
+ kind: "usage_inline_style";
308
+ nodeId: FactId;
309
+ property: string;
310
+ valueKind: "static" | "number" | "css-variable";
311
+ value: string;
312
+ }
313
+
314
+ export interface UsageTextChildFact extends BaseFact {
315
+ kind: "usage_text_child";
316
+ nodeId: FactId;
317
+ text: string;
318
+ index: number;
319
+ }
320
+
321
+ // ---------------------------------------------------------------------------
322
+ // Tailwind className facts.
323
+ //
324
+ // `classname_literal` carries fully-bounded class tokens parsed out of a JSX
325
+ // `className` attribute. `classname_dynamic` records a piece of the
326
+ // attribute that could not be statically resolved (variables, unknown helper
327
+ // calls, template interpolations, spread props, …). Both join back to the
328
+ // parent JSX element via `nodeId`.
329
+ //
330
+ // Identity is `{nodeId, attr, origin/reason, originPath}` — `originPath`
331
+ // disambiguates multiple sibling facts on a single element so the FactIndex
332
+ // never sees a collision when one element produces many className facts.
333
+ // ---------------------------------------------------------------------------
334
+
335
+ export type ClassNameOrigin =
336
+ | "attribute"
337
+ | "clsx"
338
+ | "cn"
339
+ | "classnames"
340
+ | "twMerge"
341
+ | "tw"
342
+ | "cva-arg"
343
+ | "template";
344
+
345
+ export interface ClassNameLiteralFact extends BaseFact {
346
+ kind: "classname_literal";
347
+ file: string;
348
+ nodeId: FactId;
349
+ attr: string;
350
+ classes: string[];
351
+ origin: ClassNameOrigin;
352
+ originPath: string;
353
+ location: FactLocation;
354
+ }
355
+
356
+ export type ClassNameDynamicReason =
357
+ | "identifier"
358
+ | "computed"
359
+ | "spread"
360
+ | "unknown_helper"
361
+ | "template_interpolation"
362
+ | "cva-arg";
363
+
364
+ export interface ClassNameDynamicFact extends BaseFact {
365
+ kind: "classname_dynamic";
366
+ file: string;
367
+ nodeId: FactId;
368
+ attr: string;
369
+ reason: ClassNameDynamicReason;
370
+ snippet: string;
371
+ originPath: string;
372
+ location: FactLocation;
373
+ }
374
+
375
+ export type ClassNameFact = ClassNameLiteralFact | ClassNameDynamicFact;
376
+
377
+ export type TailwindModifierKind =
378
+ | "media"
379
+ | "state"
380
+ | "dark"
381
+ | "aria"
382
+ | "data"
383
+ | "selector"
384
+ | "container"
385
+ | "unknown";
386
+
387
+ export interface TailwindModifier {
388
+ raw: string;
389
+ kind: TailwindModifierKind;
390
+ }
391
+
392
+ export type TailwindValue =
393
+ | { kind: "token"; token: string; opacity?: string }
394
+ | { kind: "arbitrary"; raw: string }
395
+ | { kind: "css-variable"; ref: string }
396
+ | { kind: "none" };
397
+
398
+ export interface TailwindClassFact extends BaseFact {
399
+ kind: "tailwind_class";
400
+ file: string;
401
+ /** Joins to the parent JSX element and originating classname_literal. */
402
+ nodeId: FactId;
403
+ /** Original class token, e.g. `dark:hover:!bg-red-500/50`. */
404
+ raw: string;
405
+ /** Stable path from the originating classname_literal plus class index. */
406
+ originPath: string;
407
+ prefix: string | null;
408
+ modifiers: TailwindModifier[];
409
+ important: boolean;
410
+ negative: boolean;
411
+ utility: string;
412
+ value: TailwindValue;
413
+ location: FactLocation;
414
+ }
415
+
416
+ export interface ThemeDeclarationFact extends BaseFact {
417
+ kind: "theme_declaration";
418
+ file: string;
419
+ name: string;
420
+ value: string;
421
+ declarationPath: string;
422
+ inline: boolean;
423
+ flavor: "default" | "inline" | "reference" | "static" | "unknown";
424
+ location: FactLocation;
425
+ }
426
+
427
+ export interface SuppressionDirectiveFact extends BaseFact {
428
+ kind: "suppression_directive";
429
+ file: string;
430
+ line: number;
431
+ column: number;
432
+ code: string;
433
+ reason: string;
434
+ expiresOn?: string;
435
+ attachedLine?: number;
436
+ attachedTo?: FactId;
437
+ /**
438
+ * Which authoring syntax produced the directive. Absent (legacy facts) means
439
+ * `@fragments-expect-error`; `"allow"` is the `fragments-allow FUI####: reason`
440
+ * flavor, which carries no expiry syntax and is reported to Cloud as a bypass
441
+ * event when it matches a finding.
442
+ */
443
+ directive?: "expect-error" | "allow";
444
+ }
445
+
446
+ export type TailwindResolvedKind =
447
+ | "color"
448
+ | "length"
449
+ | "shadow"
450
+ | "font-family"
451
+ | "font-size"
452
+ | "radius"
453
+ | "duration"
454
+ | "unknown";
455
+
456
+ export type TailwindResolutionSource = "theme-css" | "default" | "unknown";
457
+
458
+ export type TailwindResolvedValue =
459
+ | {
460
+ kind: Exclude<TailwindResolvedKind, "unknown">;
461
+ value: string;
462
+ source: Exclude<TailwindResolutionSource, "unknown">;
463
+ inline?: boolean;
464
+ }
465
+ | { kind: "unknown"; source: "unknown" };
466
+
467
+ export interface TailwindTokenResolvedFact extends BaseFact {
468
+ kind: "tailwind_token_resolved";
469
+ utility: string;
470
+ token: string;
471
+ resolved: TailwindResolvedValue;
472
+ }
473
+
474
+ /**
475
+ * A raw declaration extracted from a CSS/SCSS file. Distinct from
476
+ * `usage_inline_style` because there is no JSX node — declarations live in a
477
+ * selector chain. Identity is `{ file, selector, declarationPath, property }`
478
+ * so the ID stays stable when other lines move.
479
+ */
480
+ export interface StyleDeclarationFact extends BaseFact {
481
+ kind: "style_declaration";
482
+ file: string;
483
+ /** Full selector chain (e.g., ".button .icon") or "" for root-level. */
484
+ selector: string;
485
+ /** Stable structural index within the parent selector (e.g., "0", "0/2"). */
486
+ declarationPath: string;
487
+ property: string;
488
+ value: string;
489
+ location: FactLocation;
490
+ /**
491
+ * True when the declaration came from a configured token source file. Raw
492
+ * value rules use this to allow token registries to mint values while still
493
+ * flagging ad hoc custom properties in product code.
494
+ */
495
+ declaredTokenSource?: boolean;
496
+ }
497
+
498
+ export type UnsupportedStyleReason =
499
+ | "dynamic-template-expression"
500
+ | "dynamic-object-value"
501
+ | "object-spread"
502
+ | "unsupported-array-element";
503
+
504
+ export interface StyleUnsupportedFact extends BaseFact {
505
+ kind: "style_unsupported";
506
+ file: string;
507
+ source: "css-in-js";
508
+ syntax: string;
509
+ selector: string;
510
+ declarationPath: string;
511
+ property?: string;
512
+ reason: UnsupportedStyleReason;
513
+ location: FactLocation;
514
+ }
515
+
516
+ // ---------------------------------------------------------------------------
517
+ // Classifier facts
518
+ // ---------------------------------------------------------------------------
519
+
520
+ export interface CanonicalCandidateFact extends BaseFact {
521
+ kind: "canonical_candidate";
522
+ componentId: ComponentId;
523
+ canonical: string;
524
+ confidence: number;
525
+ band: "auto" | "suggested" | "possible" | "tie" | "unknown";
526
+ location?: FactLocation;
527
+ classifierVersion: string;
528
+ vocabVersion: string;
529
+ evidence: unknown[];
530
+ userConfirmed?: boolean;
531
+ }
532
+
533
+ export interface CanonicalMappingFact extends BaseFact {
534
+ kind: "canonical_mapping";
535
+ componentId: ComponentId;
536
+ canonical: string;
537
+ status: "confirmed" | "proposed" | "unknown";
538
+ confidence: number;
539
+ location?: FactLocation;
540
+ }
541
+
542
+ export interface StructuralConfidenceFact extends BaseFact {
543
+ kind: "structural_confidence";
544
+ componentId: ComponentId;
545
+ canonical: string;
546
+ confidence: number;
547
+ signalCount: number;
548
+ location?: FactLocation;
549
+ }
550
+
551
+ export interface CanonicalReplacementFact extends BaseFact {
552
+ kind: "canonical_replacement";
553
+ componentId: ComponentId;
554
+ canonical: string;
555
+ importPath?: string;
556
+ componentName?: string;
557
+ confidence: number;
558
+ location?: FactLocation;
559
+ }
560
+
561
+ // ---------------------------------------------------------------------------
562
+ // Discriminated unions
563
+ // ---------------------------------------------------------------------------
564
+
565
+ export type ComponentLevelFact = ComponentMetadataFact | ComponentCapabilityFact | PropMetadataFact;
566
+
567
+ export type PolicyFact =
568
+ | PropValueAvoidedFact
569
+ | PropValueForbiddenFact
570
+ | A11yNameRequiredFact
571
+ | ScaleFact
572
+ | ScaleValueFact
573
+ | StyleRawColorForbiddenFact
574
+ | StyleRawDimensionForbiddenFact
575
+ | StylePropertyScaleFact
576
+ | StyleFontSizeScaleFact
577
+ | StyleCssVarsMustBeDefinedFact
578
+ | ContractTokenFact
579
+ | JsxUnknownPropsForbiddenFact
580
+ | JsxInlineStyleForbiddenRawFact
581
+ | JsxImportPathPreferredFact
582
+ | JsxComponentPreferredFact
583
+ | TokenDefinitionFact
584
+ | TailwindPaletteAllowFact
585
+ | TailwindPaletteDenyFact
586
+ | TailwindUnknownClassEnabledFact
587
+ | GovernanceRuleConfigFact;
588
+
589
+ export type UsageFact =
590
+ | UsageNodeFact
591
+ | UsageComponentFact
592
+ | UsageImportFact
593
+ | UsagePropResolvedFact
594
+ | UsageInlineStyleFact
595
+ | UsageTextChildFact
596
+ | StyleDeclarationFact
597
+ | StyleUnsupportedFact
598
+ | ClassNameLiteralFact
599
+ | ClassNameDynamicFact
600
+ | TailwindClassFact
601
+ | ThemeDeclarationFact
602
+ | SuppressionDirectiveFact
603
+ | TailwindTokenResolvedFact
604
+ | CanonicalCandidateFact
605
+ | CanonicalMappingFact
606
+ | StructuralConfidenceFact
607
+ | CanonicalReplacementFact;
608
+
609
+ export type Fact = ComponentLevelFact | PolicyFact | UsageFact;
610
+
611
+ export type FactKind = Fact["kind"];
612
+
613
+ /** Narrows a Fact union by kind. */
614
+ export type FactOfKind<K extends FactKind> = Extract<Fact, { kind: K }>;