@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.
- package/LICENSE +21 -0
- package/dist/chunk-243QYRUF.js +2145 -0
- package/dist/chunk-243QYRUF.js.map +1 -0
- package/dist/chunk-3LLRNCPX.js +111 -0
- package/dist/chunk-3LLRNCPX.js.map +1 -0
- package/dist/chunk-EIYNNS77.js +48 -0
- package/dist/chunk-EIYNNS77.js.map +1 -0
- package/dist/chunk-JNBFJ34I.js +326 -0
- package/dist/chunk-JNBFJ34I.js.map +1 -0
- package/dist/chunk-R3X7UBHU.js +228 -0
- package/dist/chunk-R3X7UBHU.js.map +1 -0
- package/dist/chunk-SH4KPIYH.js +393 -0
- package/dist/chunk-SH4KPIYH.js.map +1 -0
- package/dist/chunk-V4VQB57N.js +56 -0
- package/dist/chunk-V4VQB57N.js.map +1 -0
- package/dist/chunk-X34IA4LR.js +319 -0
- package/dist/chunk-X34IA4LR.js.map +1 -0
- package/dist/chunk-YF65VYRY.js +493 -0
- package/dist/chunk-YF65VYRY.js.map +1 -0
- package/dist/codes/index.d.ts +40 -0
- package/dist/codes/index.js +23 -0
- package/dist/codes/index.js.map +1 -0
- package/dist/compiled-types/index.d.ts +5 -0
- package/dist/compiled-types/index.js +1 -0
- package/dist/compiled-types/index.js.map +1 -0
- package/dist/generate/index.d.ts +47 -0
- package/dist/generate/index.js +11 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/governance-BOa3KyiJ.d.ts +3279 -0
- package/dist/graph/index.d.ts +66 -0
- package/dist/graph/index.js +17 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/index.d.ts +11388 -0
- package/dist/index.js +8711 -0
- package/dist/index.js.map +1 -0
- package/dist/package-identity.d.ts +42 -0
- package/dist/package-identity.js +23 -0
- package/dist/package-identity.js.map +1 -0
- package/dist/preview/index.d.ts +484 -0
- package/dist/preview/index.js +1129 -0
- package/dist/preview/index.js.map +1 -0
- package/dist/react-types.d.ts +22 -0
- package/dist/react-types.js +1 -0
- package/dist/react-types.js.map +1 -0
- package/dist/registry.d.ts +2367 -0
- package/dist/registry.js +62 -0
- package/dist/registry.js.map +1 -0
- package/dist/schemas/index.d.ts +2584 -0
- package/dist/schemas/index.js +55 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/severity.d.ts +18 -0
- package/dist/severity.js +27 -0
- package/dist/severity.js.map +1 -0
- package/dist/test-utils.d.ts +14 -0
- package/dist/test-utils.js +63 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/topology/index.d.ts +48 -0
- package/dist/topology/index.js +7 -0
- package/dist/topology/index.js.map +1 -0
- package/dist/types-xJ2xyp_G.d.ts +119 -0
- package/package.json +120 -0
- package/src/__tests__/contract-parser.test.ts +614 -0
- package/src/__tests__/dtcg-generators.test.ts +439 -0
- package/src/__tests__/dtcg-parser.test.ts +884 -0
- package/src/__tests__/preview-runtime.test.tsx +111 -0
- package/src/__tests__/schema.test.ts +31 -0
- package/src/__tests__/severity.test.ts +34 -0
- package/src/__tests__/style-comparison.test.ts +662 -0
- package/src/__tests__/tokens-compat.test.ts +51 -0
- package/src/agent-format.test.ts +105 -0
- package/src/agent-format.ts +141 -0
- package/src/bundle.ts +149 -0
- package/src/codes/__tests__/codes.test.ts +73 -0
- package/src/codes/codes.ts +463 -0
- package/src/codes/index.ts +7 -0
- package/src/codes/source-finding-bridge.ts +113 -0
- package/src/compiled-types/index.ts +293 -0
- package/src/component-contract.ts +231 -0
- package/src/component-discovery.ts +80 -0
- package/src/composition.test.ts +262 -0
- package/src/composition.ts +318 -0
- package/src/config-paths.test.ts +78 -0
- package/src/config-paths.ts +47 -0
- package/src/config.ts +18 -0
- package/src/conform-prove.test.ts +274 -0
- package/src/conform-prove.ts +326 -0
- package/src/conform.ts +160 -0
- package/src/constants.ts +114 -0
- package/src/context.ts +2 -0
- package/src/contract/fixture.ts +110 -0
- package/src/contract/hash.test.ts +86 -0
- package/src/contract/hash.ts +195 -0
- package/src/contract/index.ts +43 -0
- package/src/contract/preimage.test.ts +254 -0
- package/src/contract/preimage.ts +365 -0
- package/src/contract/stamp.test.ts +100 -0
- package/src/contract/stamp.ts +105 -0
- package/src/contract-parser.ts +141 -0
- package/src/defineFragment.test.ts +257 -0
- package/src/defineFragment.ts +293 -0
- package/src/dtcg-generators.ts +324 -0
- package/src/dtcg-parser.ts +1 -0
- package/src/dtcg.ts +237 -0
- package/src/facts/__snapshots__/facts.test.ts.snap +124 -0
- package/src/facts/builders.ts +835 -0
- package/src/facts/compile.ts +422 -0
- package/src/facts/fact-index.ts +394 -0
- package/src/facts/facts.test.ts +494 -0
- package/src/facts/ids.ts +125 -0
- package/src/facts/index.ts +119 -0
- package/src/facts/types.ts +614 -0
- package/src/figma.ts +263 -0
- package/src/fragment-types.ts +214 -0
- package/src/generate/generate.test.ts +594 -0
- package/src/generate/index.ts +438 -0
- package/src/governance-integrity.test.ts +186 -0
- package/src/governance-integrity.ts +282 -0
- package/src/governance.test.ts +300 -0
- package/src/governance.ts +605 -0
- package/src/governance.type-test.ts +75 -0
- package/src/graph/engine.ts +446 -0
- package/src/graph/graph.test.ts +746 -0
- package/src/graph/index.ts +32 -0
- package/src/graph/serialization.ts +55 -0
- package/src/graph/types.ts +178 -0
- package/src/index.ts +891 -0
- package/src/local-canonical.ts +102 -0
- package/src/mcp-snapshot.ts +222 -0
- package/src/package-identity-match.ts +33 -0
- package/src/package-identity.generated.ts +233 -0
- package/src/package-identity.test.ts +99 -0
- package/src/package-identity.ts +157 -0
- package/src/performance-presets.ts +142 -0
- package/src/preview/comparison-artifact.test.ts +228 -0
- package/src/preview/comparison-artifact.ts +181 -0
- package/src/preview/comparison-context.ts +93 -0
- package/src/preview/comparison-evidence.ts +112 -0
- package/src/preview/comparison-format.ts +21 -0
- package/src/preview/comparison-presentation.ts +187 -0
- package/src/preview/comparison-references.test.ts +430 -0
- package/src/preview/comparison-references.ts +72 -0
- package/src/preview/comparison-score.ts +59 -0
- package/src/preview/comparison-styles.ts +197 -0
- package/src/preview/comparison.test.ts +559 -0
- package/src/preview/comparison.ts +488 -0
- package/src/preview/index.ts +10 -0
- package/src/preview/types.ts +309 -0
- package/src/preview/validation.test.ts +290 -0
- package/src/preview/validation.ts +356 -0
- package/src/preview-runtime.tsx +144 -0
- package/src/raw-html-canonical.test.ts +41 -0
- package/src/raw-html-canonical.ts +179 -0
- package/src/react-types.ts +21 -0
- package/src/registry-install-plan.ts +344 -0
- package/src/registry.test.ts +245 -0
- package/src/registry.ts +369 -0
- package/src/rules/a11y-required-accessible-name.ts +93 -0
- package/src/rules/color-math.test.ts +72 -0
- package/src/rules/color-math.ts +192 -0
- package/src/rules/components-forbidden-prop-value.ts +108 -0
- package/src/rules/components-prefer-library.ts +943 -0
- package/src/rules/components-unknown-prop.ts +94 -0
- package/src/rules/composition-pattern-schema.ts +125 -0
- package/src/rules/composition-pattern.test.ts +320 -0
- package/src/rules/composition-pattern.ts +271 -0
- package/src/rules/emit-gate.test.ts +42 -0
- package/src/rules/emit-gate.ts +60 -0
- package/src/rules/finding.ts +54 -0
- package/src/rules/index.ts +235 -0
- package/src/rules/jsx-preferred-component.ts +68 -0
- package/src/rules/jsx-preferred-import-path.ts +67 -0
- package/src/rules/presets.ts +57 -0
- package/src/rules/props-invalid-value.ts +115 -0
- package/src/rules/rules.test.ts +3636 -0
- package/src/rules/spacing-resolution.ts +184 -0
- package/src/rules/styles-no-raw-color.ts +329 -0
- package/src/rules/styles-no-raw-dimensions.ts +357 -0
- package/src/rules/styles-no-raw-spacing.ts +236 -0
- package/src/rules/styles-no-raw-typography.ts +237 -0
- package/src/rules/tailwind-arbitrary-color.test.ts +128 -0
- package/src/rules/tailwind-arbitrary-color.ts +93 -0
- package/src/rules/tailwind-arbitrary-spacing.test.ts +157 -0
- package/src/rules/tailwind-arbitrary-spacing.ts +120 -0
- package/src/rules/tailwind-forbidden-palette.test.ts +116 -0
- package/src/rules/tailwind-forbidden-palette.ts +107 -0
- package/src/rules/tailwind-off-scale-spacing-token.test.ts +100 -0
- package/src/rules/tailwind-off-scale-spacing-token.ts +108 -0
- package/src/rules/tailwind-raw-color-via-token.test.ts +108 -0
- package/src/rules/tailwind-raw-color-via-token.ts +82 -0
- package/src/rules/tailwind-rule-utils.ts +106 -0
- package/src/rules/tailwind-unknown-class.test.ts +157 -0
- package/src/rules/tailwind-unknown-class.ts +121 -0
- package/src/rules/taxonomy.test.ts +238 -0
- package/src/rules/theme-no-theme-coupled-literal.ts +132 -0
- package/src/rules/tiers.ts +111 -0
- package/src/rules/tokens-css-vars-must-be-defined.test.ts +244 -0
- package/src/rules/tokens-css-vars-must-be-defined.ts +156 -0
- package/src/rules/tokens-require-dual-fallback.ts +78 -0
- package/src/rules/types.ts +27 -0
- package/src/rules/utils.test.ts +110 -0
- package/src/rules/utils.ts +599 -0
- package/src/schema.ts +427 -0
- package/src/schemas/index.ts +275 -0
- package/src/schemas/schemas.test.ts +124 -0
- package/src/severity.ts +54 -0
- package/src/storyAdapter.test.ts +571 -0
- package/src/storyAdapter.ts +761 -0
- package/src/storyFilters.test.ts +350 -0
- package/src/storyFilters.ts +253 -0
- package/src/storybook-csf.ts +11 -0
- package/src/style-comparison.ts +423 -0
- package/src/test-utils.ts +68 -0
- package/src/token-parser.ts +2 -0
- package/src/token-types.ts +287 -0
- package/src/tokens/categories.ts +131 -0
- package/src/tokens/color.ts +193 -0
- package/src/tokens/design-token-parser.test.ts +159 -0
- package/src/tokens/design-token-parser.ts +402 -0
- package/src/tokens/dtcg.ts +428 -0
- package/src/tokens/index.ts +130 -0
- package/src/tokens/lookup.ts +19 -0
- package/src/tokens/scss.ts +171 -0
- package/src/tokens/tailwind-v4.ts +187 -0
- package/src/tokens/types.ts +43 -0
- package/src/topology/index.ts +9 -0
- package/src/topology/resolve-area.test.ts +174 -0
- package/src/topology/resolve-area.ts +215 -0
- 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 }>;
|