@contentful/experience-design-system-cli 2.30.1-dev-build-e7a9959.0 → 2.30.1-dev-build-87c8cf1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -9574,6 +9574,26 @@ function loadRawComponents(db, sessionId2, allowedNames) {
|
|
|
9574
9574
|
})
|
|
9575
9575
|
);
|
|
9576
9576
|
}
|
|
9577
|
+
function rewrittenSourcePaths(basePath) {
|
|
9578
|
+
for (const [emitted, sources] of TS_ESM_EXTENSION_REWRITES) {
|
|
9579
|
+
if (!basePath.endsWith(emitted)) continue;
|
|
9580
|
+
const stem = basePath.slice(0, -emitted.length);
|
|
9581
|
+
return sources.map((ext) => `${stem}${ext}`);
|
|
9582
|
+
}
|
|
9583
|
+
return [];
|
|
9584
|
+
}
|
|
9585
|
+
function identifiersIn(propTypes) {
|
|
9586
|
+
const names = /* @__PURE__ */ new Set();
|
|
9587
|
+
for (const propType of propTypes) {
|
|
9588
|
+
for (const match2 of propType.matchAll(IDENTIFIER_PATTERN)) names.add(match2[0]);
|
|
9589
|
+
}
|
|
9590
|
+
return [...names];
|
|
9591
|
+
}
|
|
9592
|
+
function declaresAnyType(text, typeNames) {
|
|
9593
|
+
return typeNames.some(
|
|
9594
|
+
(name) => new RegExp(`\\b(?:type|interface|enum|const|class)\\s+${escapeForRegExp(name)}\\b`).test(text)
|
|
9595
|
+
);
|
|
9596
|
+
}
|
|
9577
9597
|
function extractRelativeImportPaths(sourceText) {
|
|
9578
9598
|
const specifiers = /* @__PURE__ */ new Set();
|
|
9579
9599
|
for (const match2 of sourceText.matchAll(RELATIVE_IMPORT_PATTERN)) {
|
|
@@ -9585,6 +9605,7 @@ async function resolveRelativeImport(specifier, fromDir) {
|
|
|
9585
9605
|
const basePath = resolve7(fromDir, specifier);
|
|
9586
9606
|
const candidates = [
|
|
9587
9607
|
basePath,
|
|
9608
|
+
...rewrittenSourcePaths(basePath),
|
|
9588
9609
|
...SIBLING_FILE_EXTENSIONS.map((ext) => `${basePath}${ext}`),
|
|
9589
9610
|
...SIBLING_FILE_EXTENSIONS.map((ext) => resolve7(basePath, `index${ext}`))
|
|
9590
9611
|
];
|
|
@@ -9605,7 +9626,7 @@ async function resolveImportSpecifiers(sourceText, fromDir) {
|
|
|
9605
9626
|
}
|
|
9606
9627
|
return resolvedPaths;
|
|
9607
9628
|
}
|
|
9608
|
-
async function loadSiblingFiles(sourceText, sourcePath, propNames) {
|
|
9629
|
+
async function loadSiblingFiles(sourceText, sourcePath, propNames, candidateTypeNames = []) {
|
|
9609
9630
|
const visited = /* @__PURE__ */ new Set([resolve7(sourcePath)]);
|
|
9610
9631
|
const discovered = [];
|
|
9611
9632
|
let frontier = [{ text: sourceText, dir: dirname7(sourcePath) }];
|
|
@@ -9630,9 +9651,16 @@ async function loadSiblingFiles(sourceText, sourcePath, propNames) {
|
|
|
9630
9651
|
}
|
|
9631
9652
|
frontier = nextFrontier;
|
|
9632
9653
|
}
|
|
9654
|
+
const inHand = [sourceText, ...discovered.map((d) => d.content)];
|
|
9655
|
+
const declaredTypeNames = candidateTypeNames.filter((name) => inHand.some((text) => declaresAnyType(text, [name])));
|
|
9633
9656
|
const usesNotShown = /* @__PURE__ */ new Set();
|
|
9657
|
+
const searchNames = [.../* @__PURE__ */ new Set([...propNames, ...declaredTypeNames])];
|
|
9658
|
+
let enlarged = 0;
|
|
9634
9659
|
const siblings = discovered.slice(0, MAX_SIBLING_FILES).map((d) => {
|
|
9635
|
-
const
|
|
9660
|
+
const enlarge = enlarged < MAX_ENLARGED_SIBLINGS && declaresAnyType(d.content, declaredTypeNames);
|
|
9661
|
+
if (enlarge) enlarged++;
|
|
9662
|
+
const budget = enlarge ? MAX_TYPE_DECLARING_SIBLING_CHARS : MAX_SIBLING_SNIPPET_CHARS;
|
|
9663
|
+
const excerpt = excerptAroundNames(d.content, searchNames, budget);
|
|
9636
9664
|
for (const name of excerpt.usesNotShown) usesNotShown.add(name);
|
|
9637
9665
|
return { path: d.path, content: excerpt.content };
|
|
9638
9666
|
});
|
|
@@ -9640,25 +9668,32 @@ async function loadSiblingFiles(sourceText, sourcePath, propNames) {
|
|
|
9640
9668
|
return {
|
|
9641
9669
|
siblings,
|
|
9642
9670
|
truncatedCount,
|
|
9643
|
-
usesNotShown: propNames.filter((name) => usesNotShown.has(name))
|
|
9671
|
+
usesNotShown: propNames.filter((name) => usesNotShown.has(name)),
|
|
9672
|
+
declaredTypeNames
|
|
9644
9673
|
};
|
|
9645
9674
|
}
|
|
9646
|
-
async function loadComponentSourceRef(name, sourcePath, propNames = []) {
|
|
9675
|
+
async function loadComponentSourceRef(name, sourcePath, propNames = [], propTypes = []) {
|
|
9647
9676
|
let content = null;
|
|
9648
9677
|
let siblingFiles = [];
|
|
9649
9678
|
let truncatedSiblingCount = 0;
|
|
9650
9679
|
const usesNotShown = /* @__PURE__ */ new Set();
|
|
9651
9680
|
try {
|
|
9652
9681
|
const rawText = await readFile7(sourcePath, "utf8");
|
|
9653
|
-
const mainExcerpt = excerptAroundNames(rawText, propNames, MAX_COMPONENT_SOURCE_CHARS);
|
|
9654
|
-
content = mainExcerpt.content;
|
|
9655
|
-
for (const name2 of mainExcerpt.usesNotShown) usesNotShown.add(name2);
|
|
9656
9682
|
let siblingUsesNotShown;
|
|
9683
|
+
let declaredTypeNames;
|
|
9657
9684
|
({
|
|
9658
9685
|
siblings: siblingFiles,
|
|
9659
9686
|
truncatedCount: truncatedSiblingCount,
|
|
9660
|
-
usesNotShown: siblingUsesNotShown
|
|
9661
|
-
|
|
9687
|
+
usesNotShown: siblingUsesNotShown,
|
|
9688
|
+
declaredTypeNames
|
|
9689
|
+
} = await loadSiblingFiles(rawText, sourcePath, propNames, identifiersIn(propTypes)));
|
|
9690
|
+
const mainExcerpt = excerptAroundNames(
|
|
9691
|
+
rawText,
|
|
9692
|
+
[.../* @__PURE__ */ new Set([...propNames, ...declaredTypeNames])],
|
|
9693
|
+
MAX_COMPONENT_SOURCE_CHARS
|
|
9694
|
+
);
|
|
9695
|
+
content = mainExcerpt.content;
|
|
9696
|
+
for (const name2 of mainExcerpt.usesNotShown) usesNotShown.add(name2);
|
|
9662
9697
|
for (const name2 of siblingUsesNotShown) usesNotShown.add(name2);
|
|
9663
9698
|
} catch {
|
|
9664
9699
|
}
|
|
@@ -9673,13 +9708,18 @@ async function loadComponentSourceRefs(db, sessionId2) {
|
|
|
9673
9708
|
const rows = db.prepare(
|
|
9674
9709
|
`SELECT component_id, name, source, source_path FROM raw_components WHERE session_id = ? AND status = 'generated' ORDER BY rowid`
|
|
9675
9710
|
).all(sessionId2);
|
|
9676
|
-
const
|
|
9677
|
-
`SELECT name FROM raw_props WHERE session_id = ? AND component_id = ? ORDER BY position`
|
|
9711
|
+
const propsFor = db.prepare(
|
|
9712
|
+
`SELECT name, type FROM raw_props WHERE session_id = ? AND component_id = ? ORDER BY position`
|
|
9678
9713
|
);
|
|
9679
9714
|
return Promise.all(
|
|
9680
9715
|
rows.map((r) => {
|
|
9681
|
-
const
|
|
9682
|
-
return loadComponentSourceRef(
|
|
9716
|
+
const props = propsFor.all(sessionId2, r.component_id);
|
|
9717
|
+
return loadComponentSourceRef(
|
|
9718
|
+
r.name,
|
|
9719
|
+
r.source_path ?? r.source,
|
|
9720
|
+
props.map((p) => p.name),
|
|
9721
|
+
props.map((p) => p.type)
|
|
9722
|
+
);
|
|
9683
9723
|
})
|
|
9684
9724
|
);
|
|
9685
9725
|
}
|
|
@@ -10562,7 +10602,7 @@ function lookupSelectCache(db, componentHash, promptHash, cliVersion2) {
|
|
|
10562
10602
|
updatedAt: row.updated_at
|
|
10563
10603
|
};
|
|
10564
10604
|
}
|
|
10565
|
-
var SCHEMA, MAX_COMPONENT_SOURCE_CHARS, MAX_SIBLING_FILES, MAX_SIBLING_SNIPPET_CHARS, MAX_SIBLING_DEPTH, MAX_SIBLING_CANDIDATES_EXPLORED, RELATIVE_IMPORT_PATTERN, SIBLING_FILE_EXTENSIONS, _cliCacheVersionCache;
|
|
10605
|
+
var SCHEMA, MAX_COMPONENT_SOURCE_CHARS, MAX_SIBLING_FILES, MAX_SIBLING_SNIPPET_CHARS, MAX_TYPE_DECLARING_SIBLING_CHARS, MAX_ENLARGED_SIBLINGS, MAX_SIBLING_DEPTH, MAX_SIBLING_CANDIDATES_EXPLORED, RELATIVE_IMPORT_PATTERN, SIBLING_FILE_EXTENSIONS, TS_ESM_EXTENSION_REWRITES, IDENTIFIER_PATTERN, _cliCacheVersionCache;
|
|
10566
10606
|
var init_db = __esm({
|
|
10567
10607
|
"packages/experience-design-system-cli/src/session/db.ts"() {
|
|
10568
10608
|
"use strict";
|
|
@@ -10748,10 +10788,19 @@ CREATE INDEX IF NOT EXISTS idx_scanned_files_session ON scanned_files(session
|
|
|
10748
10788
|
MAX_COMPONENT_SOURCE_CHARS = 8e3;
|
|
10749
10789
|
MAX_SIBLING_FILES = 5;
|
|
10750
10790
|
MAX_SIBLING_SNIPPET_CHARS = 1200;
|
|
10791
|
+
MAX_TYPE_DECLARING_SIBLING_CHARS = 4e3;
|
|
10792
|
+
MAX_ENLARGED_SIBLINGS = 2;
|
|
10751
10793
|
MAX_SIBLING_DEPTH = 2;
|
|
10752
10794
|
MAX_SIBLING_CANDIDATES_EXPLORED = 25;
|
|
10753
10795
|
RELATIVE_IMPORT_PATTERN = /from\s+['"](\.[^'"]+)['"]/g;
|
|
10754
10796
|
SIBLING_FILE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
|
|
10797
|
+
TS_ESM_EXTENSION_REWRITES = [
|
|
10798
|
+
[".js", [".ts", ".tsx", ".js", ".jsx"]],
|
|
10799
|
+
[".jsx", [".tsx", ".jsx"]],
|
|
10800
|
+
[".mjs", [".mts", ".mjs"]],
|
|
10801
|
+
[".cjs", [".cts", ".cjs"]]
|
|
10802
|
+
];
|
|
10803
|
+
IDENTIFIER_PATTERN = /[A-Za-z_$][A-Za-z0-9_$]*/g;
|
|
10755
10804
|
_cliCacheVersionCache = null;
|
|
10756
10805
|
}
|
|
10757
10806
|
});
|
|
@@ -32468,7 +32517,8 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
32468
32517
|
const sourceRef = await loadComponentSourceRef(
|
|
32469
32518
|
component.name,
|
|
32470
32519
|
component.sourcePath ?? component.source,
|
|
32471
|
-
component.props.map((p) => p.name)
|
|
32520
|
+
component.props.map((p) => p.name),
|
|
32521
|
+
component.props.map((p) => p.type)
|
|
32472
32522
|
);
|
|
32473
32523
|
const prompt2 = await buildPrompt({
|
|
32474
32524
|
skill: "components",
|
|
@@ -32709,7 +32759,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
32709
32759
|
const sampleSourceRef = sampleComponent ? await loadComponentSourceRef(
|
|
32710
32760
|
sampleComponent.name,
|
|
32711
32761
|
sampleComponent.sourcePath ?? sampleComponent.source,
|
|
32712
|
-
sampleComponent.props.map((p) => p.name)
|
|
32762
|
+
sampleComponent.props.map((p) => p.name),
|
|
32763
|
+
sampleComponent.props.map((p) => p.type)
|
|
32713
32764
|
) : void 0;
|
|
32714
32765
|
const prompt2 = await buildPrompt({
|
|
32715
32766
|
skill,
|
package/dist/src/session/db.d.ts
CHANGED
|
@@ -107,7 +107,7 @@ export type RawComponentWithId = RawComponentDefinition & {
|
|
|
107
107
|
component_id: string;
|
|
108
108
|
};
|
|
109
109
|
export declare function loadRawComponents(db: DatabaseSync, sessionId: string, allowedNames?: Set<string>): RawComponentWithId[];
|
|
110
|
-
export declare function loadComponentSourceRef(name: string, sourcePath: string, propNames?: string[]): Promise<ComponentSourceRef>;
|
|
110
|
+
export declare function loadComponentSourceRef(name: string, sourcePath: string, propNames?: string[], propTypes?: string[]): Promise<ComponentSourceRef>;
|
|
111
111
|
export declare function loadComponentSourceRefs(db: DatabaseSync, sessionId: string): Promise<ComponentSourceRef[]>;
|
|
112
112
|
export declare function renameEmptySlots(db: DatabaseSync, sessionId: string, componentId: string, componentName: string, slotCount: number): {
|
|
113
113
|
renames: Array<{
|
|
@@ -16,6 +16,7 @@ export interface SourceExcerpt {
|
|
|
16
16
|
*/
|
|
17
17
|
usesNotShown: string[];
|
|
18
18
|
}
|
|
19
|
+
export declare function escapeForRegExp(value: string): string;
|
|
19
20
|
/**
|
|
20
21
|
* Returns `text` whole when it fits `maxChars`. Otherwise returns windows of
|
|
21
22
|
* `contextLines` lines around every line that mentions one of `names`, merged
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.30.1-dev-build-
|
|
3
|
+
"version": "2.30.1-dev-build-87c8cf1.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"svelte": "^5.56.4",
|
|
40
40
|
"ts-morph": "^27.0.2",
|
|
41
41
|
"typescript": "^5.9.3",
|
|
42
|
-
"@contentful/experience-design-system-cli-v2": "2.30.1-dev-build-
|
|
43
|
-
"@contentful/experience-design-system-types": "2.30.1-dev-build-
|
|
42
|
+
"@contentful/experience-design-system-cli-v2": "2.30.1-dev-build-87c8cf1.0",
|
|
43
|
+
"@contentful/experience-design-system-types": "2.30.1-dev-build-87c8cf1.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@tsconfig/node24": "^24.0.4",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"ink-testing-library": "^4.0.0",
|
|
53
53
|
"typescript-eslint": "^8.67.0",
|
|
54
54
|
"vitest": "^4.0.16",
|
|
55
|
-
"@contentful/experience-design-system-client": "2.30.1-dev-build-
|
|
56
|
-
"@contentful/experience-design-system-
|
|
57
|
-
"@contentful/experience-design-system-
|
|
55
|
+
"@contentful/experience-design-system-client": "2.30.1-dev-build-87c8cf1.0",
|
|
56
|
+
"@contentful/experience-design-system-extraction": "2.30.1-dev-build-87c8cf1.0",
|
|
57
|
+
"@contentful/experience-design-system-generation": "2.30.1-dev-build-87c8cf1.0"
|
|
58
58
|
},
|
|
59
59
|
"repository": {
|
|
60
60
|
"type": "git",
|
|
@@ -91,7 +91,7 @@ Emit one JSON object per line. The CLI parses lines starting with `{`. Lines not
|
|
|
91
91
|
- Every prop in the input must produce exactly one call: `classify_prop` OR `exclude_prop`.
|
|
92
92
|
- Every slot must produce exactly one `classify_slot` call.
|
|
93
93
|
- Emit `classify_component` once at the start (required). The `description` field is **required** — always provide a brief description of the component's purpose.
|
|
94
|
-
- `values` is required for `cdf_type: "enum"` — must be a non-empty string array of the variant names the prop accepts.
|
|
94
|
+
- `values` is required for `cdf_type: "enum"` — must be a non-empty string array of the variant names the prop accepts. **There is no legal `enum` with a guessed list.** If the value set is shown to you anywhere in the material below — the type's own declaration, an `allowedValues` list on the raw prop, a variant/lookup map, a default, a sibling excerpt — copy it and emit `enum`. If it is shown nowhere, emit `cdf_type: "string"` and leave `values` off. `string` is an unrestricted enum: the author can still pass the real value. A guessed list silently rejects it.
|
|
95
95
|
- **Do NOT include `values` for `cdf_type: "token"`.** The two property types carry different kinds of list. An `enum` prop's list holds *variant names* the component accepts (`"primary"`, `"secondary"`). A `token` prop's list holds *design token paths* (`"color.brand.primary"`), produced by the separate token-mapping step (`$token.allowed`) — never by you. Emitting `values` on a token prop makes the definition invalid.
|
|
96
96
|
- `token_kind` is required for `cdf_type: "token"` — must be a DTCG `$type` string, e.g. `"color"`.
|
|
97
97
|
- `required` must be a JSON boolean (`true`/`false`), not a string.
|
|
@@ -208,12 +208,14 @@ the default "could be overridden" (every default can), or because the tie-break
|
|
|
208
208
|
below exists. Nothing downstream re-derives, corrects, or second-guesses this —
|
|
209
209
|
what you emit is what ships.
|
|
210
210
|
|
|
211
|
-
**Ambiguity resolves to `enum` — but only when Q1–Q3 cannot be answered
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
the use sits in a file you cannot see, or
|
|
215
|
-
of use (the "uses not shown" line). In those
|
|
216
|
-
|
|
211
|
+
**Ambiguity resolves to `enum` — but only when Q1–Q3 cannot be answered, and only
|
|
212
|
+
when you can still cite its values.** The tie-break applies solely when the source
|
|
213
|
+
shown does not let you answer the three questions: the property is interpolated
|
|
214
|
+
in one place and looked up in another, the use sits in a file you cannot see, or
|
|
215
|
+
the source is truncated at the point of use (the "uses not shown" line). In those
|
|
216
|
+
cases emit `enum` if a value set is citable from the source shown, else `cdf_type:
|
|
217
|
+
"string"` per "no legal `enum` with a guessed list" — either way, record the
|
|
218
|
+
ambiguity in `reason`. When the three
|
|
217
219
|
questions *can* be answered from the source shown, they are answered and the
|
|
218
220
|
tie-break does not apply: a clear Q1-yes is `enum`, a clear Q2-yes + Q3-yes is
|
|
219
221
|
`token`, and a type annotation does not create ambiguity. An `enum` is delivered
|
|
@@ -297,7 +299,7 @@ A prop with a complex TypeScript type is **not automatically excluded**. Many pr
|
|
|
297
299
|
| Raw type pattern | How to resolve |
|
|
298
300
|
|---|---|
|
|
299
301
|
| `'primary' \| 'secondary' \| 'ghost'` (union of literals) | → `enum`, extract `values` |
|
|
300
|
-
| `HeadingSize` / `ButtonVariant` / any named type that is clearly a finite set of visual options | → `enum
|
|
302
|
+
| `HeadingSize` / `ButtonVariant` / any named type that is clearly a finite set of visual options | → `enum` if you can cite its values from the source shown (the type's own declaration, a lookup table, a default) — copy them, never invent them. If the source shown does not enumerate the values, this is not the Q1–Q3 ambiguity tie-break — it is the "no legal `enum` with a guessed list" rule: emit `cdf_type: "string"` instead, with the missing evidence noted in `reason`. Do not default to a generic guess like `['sm', 'md', 'lg']` or `['primary', 'secondary']` — those are one design system's vocabulary, not a fallback for missing evidence. |
|
|
301
303
|
| `Variant` / `variant` prop | Usually a visual design variant. → `enum`, `cdf_category: "design"`. Same evidence rule as above — cite values from the source shown; do not invent them. |
|
|
302
304
|
| `Section[]` / array of custom items where the structure is unclear | → `exclude_prop` only if the array elements are complex objects with no obvious flat representation. If items are simple (title, label, id), consider representing as `string` (a comma-separated IDs or keys) or note in `description` why. |
|
|
303
305
|
| `ExperienceConfiguration<Variant>` / deep generic | Personalization config — → `exclude_prop`, reason: `"personalization configuration — framework internal"` |
|
|
@@ -462,14 +464,30 @@ footer is supplementary and optional
|
|
|
462
464
|
{"tool":"classify_slot","slot":"footer","required":false,"description":"Optional footer area for actions or metadata","rationale":"Footer is a supplementary region typically used for actions or metadata. Optional because most cards do not need one and the card renders correctly without it."}
|
|
463
465
|
```
|
|
464
466
|
|
|
465
|
-
### Named type (HeadingSize, ButtonVariant, etc.)
|
|
467
|
+
### Named type (HeadingSize, ButtonVariant, etc.) — do NOT infer the values
|
|
466
468
|
|
|
467
|
-
When a prop has a named TypeScript type that is not inlined as a union literal,
|
|
469
|
+
When a prop has a named TypeScript type that is not inlined as a union literal,
|
|
470
|
+
the value set is whatever that type's declaration says. A type *name* is not
|
|
471
|
+
evidence of its members: `HeadingSize` could be `h1`–`h6`, `sm|md|lg`, or
|
|
472
|
+
`s|m|l|xl`. Guessing picks one design system's vocabulary and is wrong more
|
|
473
|
+
often than it is right, and a wrong name matches no style rule — the author's
|
|
474
|
+
setting silently does nothing.
|
|
468
475
|
|
|
476
|
+
So: look for the declaration in the source shown. If it is there, copy it. If it
|
|
477
|
+
is not, **emit `string`** — `string` is an unrestricted enum, so the author stays
|
|
478
|
+
unrestricted but correct.
|
|
479
|
+
|
|
480
|
+
Members visible in the source shown — copy them, do not paraphrase:
|
|
481
|
+
```
|
|
482
|
+
titleSize has type HeadingSize; HeadingSize is declared in the excerpt as 'sm' | 'md' | 'lg'
|
|
483
|
+
{"tool":"classify_prop","prop":"titleSize","cdf_type":"enum","cdf_category":"design","required":false,"values":["sm","md","lg"],"description":"Heading size","reason":"Copied from the HeadingSize declaration shown in the excerpt."}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Members NOT visible in the source shown — degrade to `string`:
|
|
469
487
|
```
|
|
470
|
-
titleSize has type HeadingSize
|
|
471
|
-
|
|
472
|
-
{"tool":"classify_prop","prop":"titleSize","cdf_type":"
|
|
488
|
+
titleSize has type HeadingSize; HeadingSize is not declared anywhere in the source shown
|
|
489
|
+
no evidence for its members, so no values list — string, not a guess
|
|
490
|
+
{"tool":"classify_prop","prop":"titleSize","cdf_type":"string","cdf_category":"design","required":false,"description":"Heading size","reason":"HeadingSize is not declared in the source shown, so its members cannot be cited. Emitted as string rather than inventing a value list."}
|
|
473
491
|
```
|
|
474
492
|
|
|
475
493
|
### href prop
|
|
@@ -495,7 +513,7 @@ Before emitting any tool calls, verify:
|
|
|
495
513
|
1. Every prop in the input has exactly one `classify_prop` or `exclude_prop` call
|
|
496
514
|
2. Every slot has exactly one `classify_slot` call
|
|
497
515
|
3. `classify_component` is emitted exactly once
|
|
498
|
-
4. Every `cdf_type: "enum"` has a non-empty `values` array
|
|
516
|
+
4. Every `cdf_type: "enum"` has a non-empty `values` array taken from the material shown. A prop whose value set was shown nowhere is `cdf_type: "string"` with no `values` — never an `enum` with a plausible-looking list, and never an `exclude_prop`.
|
|
499
517
|
5. Every `cdf_type: "token"` has `token_kind` (or a warning in `description` if lookup failed) and does **not** have `values` set
|
|
500
518
|
6. No `cdf_type: "link"` — all href/url props use `string`
|
|
501
519
|
7. `required` values are JSON booleans, not strings
|
|
@@ -507,7 +525,7 @@ Before emitting any tool calls, verify:
|
|
|
507
525
|
13. `rationale.description` follows the same "Description content rules" as `description` — no internal initiative names (`INTEG-*`, `EDSI`, `DSI`, `M1`, `M2`, wave/phase references, etc.).
|
|
508
526
|
14. Every `cdf_type: "token"` prop cites a line that interpolates its value into a style **and** a token reference at that use (Q2 yes, Q3 yes), and carries no `values`. If you cannot cite both, it is `enum` or `string`; if you can, it is `token` — its type annotation is not a reason to emit `string`.
|
|
509
527
|
15. Every prop whose values are friendly names is `enum` with a non-empty `values` array, even when each name resolves to a design token internally; every prop for which Q1–Q3 could not be answered was emitted as `enum` (or `string`) with the ambiguity stated in `reason`, and no answerable prop was called ambiguous.
|
|
510
|
-
16. Every `enum`'s `values` array is copied from evidence in the
|
|
528
|
+
16. Every `enum`'s `values` array is copied from evidence in the material shown — a type declaration, an `allowedValues` list on the raw prop, a variant or lookup map, a default, in the component's own file or in any sibling excerpt — and none of it was invented. Where the value set appears nowhere, the prop is `cdf_type: "string"`, with the reason recorded in `reason`. Do not drop a prop merely because you could not enumerate its values.
|
|
511
529
|
|
|
512
530
|
After the run completes, the developer can validate the pipeline output with:
|
|
513
531
|
|
|
@@ -528,4 +546,6 @@ properties — this is never acceptable.
|
|
|
528
546
|
If you are genuinely uncertain about every prop, classify each as:
|
|
529
547
|
{"tool":"classify_prop","prop":"<name>","cdf_type":"string","cdf_category":"content","required":false,"description":"Uncertain classification — review recommended"}
|
|
530
548
|
|
|
531
|
-
An imperfect classification is infinitely better than no classification.
|
|
549
|
+
An imperfect classification is infinitely better than no classification. That is
|
|
550
|
+
about **classifying a prop rather than dropping it** — it is not a licence to
|
|
551
|
+
invent a `values` list. The uncertain answer is `cdf_type: "string"`, every time.
|