@invariant-ui/cli 0.0.0-stage → 0.2.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 +105 -0
- package/README.md +250 -2
- package/dist/agent-kit/apply.js +232 -0
- package/dist/agent-kit/guidance.js +236 -0
- package/dist/agent-kit/index.js +5 -0
- package/dist/agent-kit/integrations.js +121 -0
- package/dist/agent-kit/plugin.js +115 -0
- package/dist/artifact-generator/index.js +75 -0
- package/dist/browser-verify/driver.js +2 -0
- package/dist/browser-verify/index.js +4 -0
- package/dist/browser-verify/playwright.js +82 -0
- package/dist/browser-verify/runner.js +175 -0
- package/dist/browser-verify/spec.js +103 -0
- package/dist/cli/args.js +77 -0
- package/dist/cli/baseline.js +64 -0
- package/dist/cli/cli.js +121 -0
- package/dist/cli/commands-browser.js +104 -0
- package/dist/cli/commands-discover.js +312 -0
- package/dist/cli/commands-enforcement.js +35 -0
- package/dist/cli/commands-governance.js +179 -0
- package/dist/cli/commands-hook.js +269 -0
- package/dist/cli/commands-patterns.js +324 -0
- package/dist/cli/commands-setup.js +485 -0
- package/dist/cli/commands-validate.js +157 -0
- package/dist/cli/commands.js +517 -0
- package/dist/cli/config.js +197 -0
- package/dist/cli/diff.js +66 -0
- package/dist/cli/enforcement-log.js +83 -0
- package/dist/cli/enforcement-report.js +96 -0
- package/dist/cli/errors.js +10 -0
- package/dist/cli/format.js +22 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/io.js +2 -0
- package/dist/cli/main.js +31 -0
- package/dist/cli/pipeline.js +262 -0
- package/dist/cli/publish.js +77 -0
- package/dist/cli/report.js +127 -0
- package/dist/cli/starter-rules.js +57 -0
- package/dist/cli/store.js +60 -0
- package/dist/cli/version.js +5 -0
- package/dist/cli/watch.js +68 -0
- package/dist/cli/workflow.js +52 -0
- package/dist/compiler-angular/adapter.js +115 -0
- package/dist/compiler-angular/analyze.js +222 -0
- package/dist/compiler-angular/classes.js +446 -0
- package/dist/compiler-angular/declared.js +285 -0
- package/dist/compiler-angular/emit.js +183 -0
- package/dist/compiler-angular/index.js +4 -0
- package/dist/compiler-angular/template.js +142 -0
- package/dist/compiler-core/adapter.js +2 -0
- package/dist/compiler-core/adapters/inventory.js +312 -0
- package/dist/compiler-core/compile.js +148 -0
- package/dist/compiler-core/component-facts.js +123 -0
- package/dist/compiler-core/discovery/docs.js +66 -0
- package/dist/compiler-core/discovery/entries.js +270 -0
- package/dist/compiler-core/discovery/exports.js +207 -0
- package/dist/compiler-core/discovery/graph.js +59 -0
- package/dist/compiler-core/discovery/index.js +103 -0
- package/dist/compiler-core/discovery/packages.js +148 -0
- package/dist/compiler-core/discovery/schema.js +144 -0
- package/dist/compiler-core/discovery/storybook.js +232 -0
- package/dist/compiler-core/discovery/support.js +82 -0
- package/dist/compiler-core/discovery/tokens.js +186 -0
- package/dist/compiler-core/discovery/tooling.js +146 -0
- package/dist/compiler-core/fs.js +89 -0
- package/dist/compiler-core/glob.js +3 -0
- package/dist/compiler-core/index.js +16 -0
- package/dist/compiler-core/ir-builder.js +68 -0
- package/dist/compiler-core/json-schema.js +11 -0
- package/dist/compiler-core/testing/index.js +81 -0
- package/dist/compiler-core/ts/ast.js +166 -0
- package/dist/compiler-core/ts/members.js +163 -0
- package/dist/compiler-core/ts/program.js +81 -0
- package/dist/compiler-core/ts/static-eval.js +145 -0
- package/dist/compiler-core/ts/tsconfig-paths.js +60 -0
- package/dist/compiler-core/walk.js +46 -0
- package/dist/compiler-ir/index.js +4 -0
- package/dist/compiler-ir/ir.js +67 -0
- package/dist/compiler-ir/json-schema.js +6 -0
- package/dist/compiler-ir/validate.js +116 -0
- package/dist/compiler-react/adapter.js +147 -0
- package/dist/compiler-react/analyze.js +199 -0
- package/dist/compiler-react/behavior.js +75 -0
- package/dist/compiler-react/detect.js +558 -0
- package/dist/compiler-react/emit.js +188 -0
- package/dist/compiler-react/index.js +2 -0
- package/dist/compiler-react/props.js +157 -0
- package/dist/compiler-react/styling.js +138 -0
- package/dist/compiler-react/usage.js +116 -0
- package/dist/compiler-react/variants.js +111 -0
- package/dist/compiler-storybook/adapter.js +253 -0
- package/dist/compiler-storybook/csf.js +521 -0
- package/dist/compiler-storybook/emit.js +202 -0
- package/dist/compiler-storybook/index-json.js +41 -0
- package/dist/compiler-storybook/index.js +5 -0
- package/dist/compiler-storybook/mdx.js +120 -0
- package/dist/compiler-tokens/adapter.js +158 -0
- package/dist/compiler-tokens/css.js +59 -0
- package/dist/compiler-tokens/index.js +5 -0
- package/dist/compiler-tokens/json-lines.js +106 -0
- package/dist/compiler-tokens/json-tokens.js +52 -0
- package/dist/compiler-vue/adapter.js +107 -0
- package/dist/compiler-vue/analyze.js +344 -0
- package/dist/compiler-vue/declared.js +343 -0
- package/dist/compiler-vue/emit.js +129 -0
- package/dist/compiler-vue/index.js +5 -0
- package/dist/compiler-vue/script.js +472 -0
- package/dist/compiler-vue/sfc.js +44 -0
- package/dist/compiler-vue/template.js +73 -0
- package/dist/contract/archetype-checks.js +153 -0
- package/dist/contract/components.js +102 -0
- package/dist/contract/conflicts.js +39 -0
- package/dist/contract/contract.js +46 -0
- package/dist/contract/evidence.js +84 -0
- package/dist/contract/fact-path.js +39 -0
- package/dist/contract/facts.js +62 -0
- package/dist/contract/index.js +16 -0
- package/dist/contract/integrity.js +21 -0
- package/dist/contract/json-schema.js +11 -0
- package/dist/contract/knowledge.js +95 -0
- package/dist/contract/pattern-checks.js +254 -0
- package/dist/contract/patterns.js +225 -0
- package/dist/contract/primitives.js +81 -0
- package/dist/contract/sources.js +30 -0
- package/dist/contract/tokens.js +41 -0
- package/dist/contract/validate.js +253 -0
- package/dist/contract-query/archetype.js +188 -0
- package/dist/contract-query/index.js +6 -0
- package/dist/contract-query/patterns.js +298 -0
- package/dist/contract-query/search.js +132 -0
- package/dist/contract-query/system.js +148 -0
- package/dist/contract-query/views.js +288 -0
- package/dist/governance/decisions.js +229 -0
- package/dist/governance/index.js +5 -0
- package/dist/governance/patterns-file.js +156 -0
- package/dist/governance/patterns.js +510 -0
- package/dist/governance/policies.js +148 -0
- package/dist/mcp/index.js +7 -0
- package/dist/mcp/loader.js +70 -0
- package/dist/mcp/protocol.js +27 -0
- package/dist/mcp/resources.js +138 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/stdio.js +28 -0
- package/dist/mcp/tools.js +267 -0
- package/dist/reconciliation/code.js +62 -0
- package/dist/reconciliation/components.js +401 -0
- package/dist/reconciliation/conflicts.js +126 -0
- package/dist/reconciliation/facts.js +41 -0
- package/dist/reconciliation/index.js +7 -0
- package/dist/reconciliation/reconcile.js +134 -0
- package/dist/reconciliation/resolve.js +158 -0
- package/dist/reconciliation/review.js +81 -0
- package/dist/reconciliation/storybook.js +370 -0
- package/dist/reconciliation/tokens.js +179 -0
- package/dist/reconciliation/util.js +55 -0
- package/dist/semantic-engine/additive.js +51 -0
- package/dist/semantic-engine/compounds.js +91 -0
- package/dist/semantic-engine/documents.js +157 -0
- package/dist/semantic-engine/enrich.js +42 -0
- package/dist/semantic-engine/index.js +7 -0
- package/dist/semantic-engine/infer.js +38 -0
- package/dist/semantic-engine/tokens.js +120 -0
- package/dist/shared/canonical.js +65 -0
- package/dist/shared/diagnostic.js +78 -0
- package/dist/shared/glob.js +98 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/json.js +2 -0
- package/dist/validation/card.js +50 -0
- package/dist/validation/discovery/arrangements.js +162 -0
- package/dist/validation/discovery/discover.js +70 -0
- package/dist/validation/discovery/index.js +8 -0
- package/dist/validation/discovery/model.js +127 -0
- package/dist/validation/discovery/promote.js +24 -0
- package/dist/validation/discovery/reviews.js +63 -0
- package/dist/validation/discovery/shapes.js +47 -0
- package/dist/validation/discovery/similar-files.js +146 -0
- package/dist/validation/discovery/util.js +47 -0
- package/dist/validation/index.js +11 -0
- package/dist/validation/interaction-facts.js +341 -0
- package/dist/validation/interaction-workflows.js +633 -0
- package/dist/validation/literals.js +251 -0
- package/dist/validation/pattern-rules.js +608 -0
- package/dist/validation/policy.js +241 -0
- package/dist/validation/report.js +163 -0
- package/dist/validation/rules.js +269 -0
- package/dist/validation/scan.js +295 -0
- package/dist/validation/text.js +34 -0
- package/dist/validation/validate-code.js +513 -0
- package/dist/validation/validate-usage.js +196 -0
- package/package.json +38 -4
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { jsonValueSchema, TOKEN_CATEGORIES } from "../contract/index.js";
|
|
2
|
+
import { archetypeView, componentView, compositionView, guidelinesView, overview, patternRelationships, patternsView, patternView, search, tokensView, usageView } from "../contract-query/index.js";
|
|
3
|
+
import { enforcementCard, MAX_CODE_CHARS, passCard, validateCode, validateUsage } from "../validation/index.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const ok = (data, text) => ({
|
|
6
|
+
isError: false,
|
|
7
|
+
data,
|
|
8
|
+
...(text === undefined ? {} : { text })
|
|
9
|
+
});
|
|
10
|
+
const fail = (message, extra = {}) => ({
|
|
11
|
+
isError: true,
|
|
12
|
+
data: { error: message, ...extra }
|
|
13
|
+
});
|
|
14
|
+
const name = z
|
|
15
|
+
.string()
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(200)
|
|
18
|
+
.describe("Component name or id, for example Button or component:button");
|
|
19
|
+
const paging = {
|
|
20
|
+
offset: z.number().int().min(0).max(100000).optional().describe("Items to skip"),
|
|
21
|
+
limit: z.number().int().min(1).max(200).optional().describe("Items to return (default 50, at most 200)")
|
|
22
|
+
};
|
|
23
|
+
const framework = z.enum(["react", "vue", "angular", "html"]);
|
|
24
|
+
function resolve(ds, query) {
|
|
25
|
+
const found = ds.findComponent(query);
|
|
26
|
+
if (found.match)
|
|
27
|
+
return { component: found.match };
|
|
28
|
+
return fail(found.candidates.length > 1
|
|
29
|
+
? `"${query}" matches several components; use the id.`
|
|
30
|
+
: `No component matches "${query}".`, { candidates: found.candidates.map((c) => ({ id: c.id, name: c.name })) });
|
|
31
|
+
}
|
|
32
|
+
function resolvePattern(ds, query) {
|
|
33
|
+
const found = ds.findPattern(query);
|
|
34
|
+
if (found.match)
|
|
35
|
+
return { pattern: found.match };
|
|
36
|
+
return fail(found.candidates.length > 1
|
|
37
|
+
? `"${query}" matches several patterns; use the id.`
|
|
38
|
+
: `No pattern matches "${query}".`, { candidates: found.candidates.map((p) => ({ id: p.id, name: p.name })) });
|
|
39
|
+
}
|
|
40
|
+
const component = (fn) => (ds, args) => {
|
|
41
|
+
const r = resolve(ds, args.name);
|
|
42
|
+
return "component" in r ? ok(fn(ds, r.component)) : r;
|
|
43
|
+
};
|
|
44
|
+
export const TOOLS = [
|
|
45
|
+
{
|
|
46
|
+
name: "get_design_system_overview",
|
|
47
|
+
title: "Design system overview",
|
|
48
|
+
description: "Start here. Returns the design system's name, frameworks, sources, counts, open conflicts between sources, how much is inferred, and what the contract does not cover.",
|
|
49
|
+
schema: z.strictObject({}),
|
|
50
|
+
run: (ds) => ok(overview(ds))
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "search_design_system",
|
|
54
|
+
title: "Search components, tokens, guidelines and patterns",
|
|
55
|
+
description: "Lexical search over component names, props, variants, slots, token names and values, guideline titles, and pattern names, intents, parts, regions and states. Matches plurals, prefixes and one-letter typos. Ranked by fixed rules; results say what matched. Use it to find the component or pattern for a need before writing UI.",
|
|
56
|
+
schema: z.strictObject({
|
|
57
|
+
query: z.string().min(1).max(200),
|
|
58
|
+
kinds: z
|
|
59
|
+
.array(z.enum(["component", "token", "guideline", "pattern"]))
|
|
60
|
+
.max(4)
|
|
61
|
+
.optional(),
|
|
62
|
+
limit: z.number().int().min(1).max(100).optional()
|
|
63
|
+
}),
|
|
64
|
+
run: (ds, a) => {
|
|
65
|
+
const r = search(ds, a.query, a.kinds, a.limit);
|
|
66
|
+
return ok({ total: r.total, hits: r.hits });
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "get_component",
|
|
71
|
+
title: "Get a component",
|
|
72
|
+
description: "The full contract entry for one component: implementations per framework, props with type, default, allowed values and where each is declared, events, slots, variants, accessibility, conflicts between sources, and notes about what is incomplete.",
|
|
73
|
+
schema: z.strictObject({ name }),
|
|
74
|
+
run: component((ds, c) => componentView(ds, c))
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "get_component_usage",
|
|
78
|
+
title: "How to use a component",
|
|
79
|
+
description: "What is needed to use a component correctly: how to import it, required props, variants and defaults, deprecated props, source-written examples, and observed prop combinations when available.",
|
|
80
|
+
schema: z.strictObject({ name }),
|
|
81
|
+
run: component((ds, c) => usageView(ds, c))
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "get_component_composition",
|
|
85
|
+
title: "Component composition",
|
|
86
|
+
description: "What a component contains and what contains it (with whether each link was discovered or inferred), plus its slots. Use it to build correct compound structures.",
|
|
87
|
+
schema: z.strictObject({ name }),
|
|
88
|
+
run: component((ds, c) => compositionView(ds, c))
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "get_design_tokens",
|
|
92
|
+
title: "Design tokens",
|
|
93
|
+
description: "Design tokens with their resolved values and per-theme values. Filter by category, text, or theme. Always prefer a token over a literal value.",
|
|
94
|
+
schema: z.strictObject({
|
|
95
|
+
category: z.enum(TOKEN_CATEGORIES).optional(),
|
|
96
|
+
query: z.string().max(200).optional(),
|
|
97
|
+
theme: z.string().max(64).optional().describe("Theme name such as dark"),
|
|
98
|
+
...paging
|
|
99
|
+
}),
|
|
100
|
+
run: (ds, a) => ok(tokensView(ds, a))
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "get_design_patterns",
|
|
104
|
+
title: "Design patterns",
|
|
105
|
+
description: "Layouts, interactions, page archetypes and compositions the contract defines. With no name: lists patterns, filterable by category (layout, interaction, page, composition and others), status and text. With a name or id: that pattern in full, with its parts, regions, states, constraints, relationships, status and evidence. With a name and resolve true (or a variation): the pattern read as a page blueprint, with the patterns it composes expanded to any depth, its variations, the interaction states it requires, responsive expectations, prohibited combinations, and which of it is approved. Every result says whether the pattern is approved; treat anything else as a proposal. An empty list means none is defined, not that none applies.",
|
|
106
|
+
schema: z.strictObject({
|
|
107
|
+
name: z
|
|
108
|
+
.string()
|
|
109
|
+
.min(1)
|
|
110
|
+
.max(200)
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("Pattern name or id, for example page.data-management"),
|
|
113
|
+
category: z
|
|
114
|
+
.enum([
|
|
115
|
+
"layout",
|
|
116
|
+
"navigation",
|
|
117
|
+
"form",
|
|
118
|
+
"data-table",
|
|
119
|
+
"card",
|
|
120
|
+
"dialog",
|
|
121
|
+
"workflow",
|
|
122
|
+
"composition",
|
|
123
|
+
"interaction",
|
|
124
|
+
"page",
|
|
125
|
+
"other"
|
|
126
|
+
])
|
|
127
|
+
.optional(),
|
|
128
|
+
status: z
|
|
129
|
+
.enum(["approved", "documented", "discovered", "inferred", "mixed", "none"])
|
|
130
|
+
.optional()
|
|
131
|
+
.describe("Derived from the pattern's facts; only approved means every fact is approved"),
|
|
132
|
+
query: z.string().max(200).optional(),
|
|
133
|
+
resolve: z
|
|
134
|
+
.boolean()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe("With a name: return the resolved blueprint, following composed patterns to any depth"),
|
|
137
|
+
variation: z
|
|
138
|
+
.string()
|
|
139
|
+
.min(1)
|
|
140
|
+
.max(64)
|
|
141
|
+
.optional()
|
|
142
|
+
.describe("With a name: apply this named variation to the blueprint (implies resolve)"),
|
|
143
|
+
...paging
|
|
144
|
+
}),
|
|
145
|
+
run: (ds, a) => {
|
|
146
|
+
if (a.name === undefined) {
|
|
147
|
+
if (a.resolve || a.variation)
|
|
148
|
+
return fail("resolve and variation need a pattern name");
|
|
149
|
+
return ok(patternsView(ds, a));
|
|
150
|
+
}
|
|
151
|
+
const r = resolvePattern(ds, a.name);
|
|
152
|
+
if (!("pattern" in r))
|
|
153
|
+
return r;
|
|
154
|
+
if (!a.resolve && a.variation === undefined)
|
|
155
|
+
return ok(patternView(ds, r.pattern));
|
|
156
|
+
const blueprint = archetypeView(ds, r.pattern, { variation: a.variation });
|
|
157
|
+
return blueprint.ok ? ok(blueprint.view) : fail(blueprint.message, { variations: blueprint.variations });
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "get_pattern_relationships",
|
|
162
|
+
title: "Pattern relationships",
|
|
163
|
+
description: "What a pattern composes, contains, requires, uses, extends, replaces or conflicts with, and which patterns point at it, walked to a chosen depth. Composition parts appear as part edges with their role. Only stated relationships are returned; none is inferred from names. Each edge shows the status of the fact behind it.",
|
|
164
|
+
schema: z.strictObject({
|
|
165
|
+
name: z.string().min(1).max(200).describe("Pattern name or id"),
|
|
166
|
+
direction: z.enum(["out", "in", "both"]).optional().describe("Default both"),
|
|
167
|
+
depth: z.number().int().min(1).max(5).optional().describe("How many steps to follow (default 1)"),
|
|
168
|
+
types: z
|
|
169
|
+
.array(z.enum([
|
|
170
|
+
"contains",
|
|
171
|
+
"requires",
|
|
172
|
+
"uses",
|
|
173
|
+
"extends",
|
|
174
|
+
"composes",
|
|
175
|
+
"alternative-to",
|
|
176
|
+
"prohibited-with",
|
|
177
|
+
"supersedes",
|
|
178
|
+
"part"
|
|
179
|
+
]))
|
|
180
|
+
.max(9)
|
|
181
|
+
.optional()
|
|
182
|
+
}),
|
|
183
|
+
run: (ds, a) => {
|
|
184
|
+
const r = resolvePattern(ds, a.name);
|
|
185
|
+
return "pattern" in r ? ok(patternRelationships(ds, r.pattern, a)) : r;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: "get_design_guidelines",
|
|
190
|
+
title: "Design guidelines",
|
|
191
|
+
description: "Guideline documents known to the contract, filterable by kind, component, or text. Returns titles and the documents to read; page bodies are not included.",
|
|
192
|
+
schema: z.strictObject({
|
|
193
|
+
kind: z
|
|
194
|
+
.enum(["usage", "accessibility", "composition", "visual-principle", "do-dont", "reference"])
|
|
195
|
+
.optional(),
|
|
196
|
+
component: z.string().max(200).optional(),
|
|
197
|
+
query: z.string().max(200).optional(),
|
|
198
|
+
...paging
|
|
199
|
+
}),
|
|
200
|
+
run: (ds, a) => ok(guidelinesView(ds, a))
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: "validate_component_usage",
|
|
204
|
+
title: "Validate a component usage",
|
|
205
|
+
description: 'Checks one intended use of a component against the contract: unknown component or prop, value outside the declared values, wrong type, deprecated use, missing required props. A prop is only called unknown when the component\'s API listing is complete. For a value you cannot evaluate, pass {"expression": "..."}.',
|
|
206
|
+
schema: z.strictObject({
|
|
207
|
+
component: name,
|
|
208
|
+
framework: framework.optional(),
|
|
209
|
+
props: z
|
|
210
|
+
.record(z.string().max(100), jsonValueSchema)
|
|
211
|
+
.optional()
|
|
212
|
+
.describe('Prop values. Use {"expression":"text"} for dynamic values.'),
|
|
213
|
+
hasChildren: z.boolean().optional().describe("Whether children or default slot content are present")
|
|
214
|
+
}),
|
|
215
|
+
run: (ds, a) => {
|
|
216
|
+
const r = validateUsage(ds, {
|
|
217
|
+
component: a.component,
|
|
218
|
+
framework: a.framework === "html" ? undefined : a.framework,
|
|
219
|
+
props: a.props,
|
|
220
|
+
hasChildren: a.hasChildren
|
|
221
|
+
});
|
|
222
|
+
const errors = r.findings.filter((f) => f.severity === "error").length;
|
|
223
|
+
return ok({
|
|
224
|
+
valid: errors === 0,
|
|
225
|
+
component: r.component ?? null,
|
|
226
|
+
findings: r.findings,
|
|
227
|
+
unverifiedValues: r.unverifiedValues
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: "validate_design_system_compliance",
|
|
233
|
+
title: "Validate code against the design system",
|
|
234
|
+
description: `Statically checks a code snippet (JSX/TSX, Vue, Angular or HTML template; at most ${MAX_CODE_CHARS} characters) against the contract: component props and values, literal colors, spacing and typography against tokens, and the structural rules and required interaction states of approved patterns (React only). Interaction results say how much they establish (structural or static-inferred); none is runtime verified. Nothing is executed. Only literal values are verified and the response lists what was not. Pass filename (project-relative) so path-scoped pattern rules can apply; the result's evaluations list every pattern check as pass, fail, warning, not-verifiable or skipped, and a check that cannot be established is never a pass.`,
|
|
235
|
+
schema: z.strictObject({
|
|
236
|
+
code: z.string().min(1).max(MAX_CODE_CHARS),
|
|
237
|
+
framework: framework
|
|
238
|
+
.optional()
|
|
239
|
+
.describe("Defaults from the file name, else the contract's only framework, else react"),
|
|
240
|
+
filename: z
|
|
241
|
+
.string()
|
|
242
|
+
.max(200)
|
|
243
|
+
.optional()
|
|
244
|
+
.describe("Project-relative path, for example src/pages/Settings.tsx. Needed for path-scoped pattern rules.")
|
|
245
|
+
}),
|
|
246
|
+
run: (ds, a) => {
|
|
247
|
+
const result = validateCode(ds, a);
|
|
248
|
+
const name = ds.contract.metadata.name;
|
|
249
|
+
// The same card the hook shows in the chat, so a fix asked for here reads identically there.
|
|
250
|
+
const card = result.findings.length > 0
|
|
251
|
+
? enforcementCard({
|
|
252
|
+
findings: result.findings,
|
|
253
|
+
contractName: name,
|
|
254
|
+
file: a.filename,
|
|
255
|
+
next: "Fix these, then validate again.",
|
|
256
|
+
more: (n) => `…and ${n} more findings follow in the JSON below.`
|
|
257
|
+
})
|
|
258
|
+
: passCard({
|
|
259
|
+
contractName: name,
|
|
260
|
+
file: a.filename,
|
|
261
|
+
componentsChecked: result.summary.componentsChecked
|
|
262
|
+
});
|
|
263
|
+
return ok(result, card);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
];
|
|
267
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { FactIndex } from "./facts.js";
|
|
2
|
+
const FILE = /^implementations\.([^.]+)\.extensions\.\1\.file$/;
|
|
3
|
+
/**
|
|
4
|
+
* Components from any framework adapter that publish the neutral link key
|
|
5
|
+
* `implementations.<fw>.extensions.<fw>.{file,localName}`. Sources are matched on that key, never on a
|
|
6
|
+
* display name, so renamed or aliased components still link correctly.
|
|
7
|
+
*/
|
|
8
|
+
export function codeComponents(docs) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const doc of docs) {
|
|
11
|
+
const index = new FactIndex(doc);
|
|
12
|
+
for (const entity of doc.entities.filter((e) => e.kind === "component")) {
|
|
13
|
+
const filePath = [...doc.facts.filter((f) => f.subject === entity.ref).map((f) => f.path)].find((p) => FILE.test(p));
|
|
14
|
+
const framework = filePath ? FILE.exec(filePath)?.[1] : undefined;
|
|
15
|
+
if (!filePath || !framework)
|
|
16
|
+
continue;
|
|
17
|
+
const prefix = `implementations.${framework}.extensions.${framework}`;
|
|
18
|
+
const file = index.value(entity.ref, `${prefix}.file`);
|
|
19
|
+
const localName = index.value(entity.ref, `${prefix}.localName`);
|
|
20
|
+
if (!file || !localName)
|
|
21
|
+
continue;
|
|
22
|
+
const props = new Map();
|
|
23
|
+
for (const name of index.children(entity.ref, "props")) {
|
|
24
|
+
const base = `props.${name}`;
|
|
25
|
+
const role = doc.facts.find((f) => f.subject === entity.ref && f.path.startsWith(`${base}.extensions.`) && f.path.endsWith(".role"))?.value;
|
|
26
|
+
const required = index.value(entity.ref, `${base}.required`);
|
|
27
|
+
const allowed = index.value(entity.ref, `${base}.allowedValues`);
|
|
28
|
+
const defaultValue = index.get(entity.ref, `${base}.default`);
|
|
29
|
+
props.set(name, {
|
|
30
|
+
name,
|
|
31
|
+
...(required === undefined ? {} : { required }),
|
|
32
|
+
...(defaultValue ? { default: defaultValue.value } : {}),
|
|
33
|
+
...(allowed ? { allowedValues: allowed } : {}),
|
|
34
|
+
deprecated: index.get(entity.ref, `${base}.deprecated`) !== undefined,
|
|
35
|
+
...(typeof role === "string" ? { role } : {}),
|
|
36
|
+
evidence: {
|
|
37
|
+
default: index.evidenceIds(entity.ref, `${base}.default`),
|
|
38
|
+
allowedValues: index.evidenceIds(entity.ref, `${base}.allowedValues`),
|
|
39
|
+
deprecated: index.evidenceIds(entity.ref, `${base}.deprecated`),
|
|
40
|
+
declared: index.evidenceIds(entity.ref, `${base}.type.text`)
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
out.push({
|
|
45
|
+
ref: entity.ref,
|
|
46
|
+
sourceId: doc.source.id,
|
|
47
|
+
framework,
|
|
48
|
+
file,
|
|
49
|
+
localName,
|
|
50
|
+
name: index.value(entity.ref, "name") ?? entity.name,
|
|
51
|
+
props,
|
|
52
|
+
propsComplete: index.value(entity.ref, `${prefix}.propsComplete`) === true,
|
|
53
|
+
variantNames: new Set(index.children(entity.ref, "variants")),
|
|
54
|
+
slotNames: new Set(index.children(entity.ref, "slots")),
|
|
55
|
+
deprecated: index.value(entity.ref, "lifecycle") === "deprecated",
|
|
56
|
+
index
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=code.js.map
|