@contentful/experience-design-system-cli 2.11.2-dev-build-003ce84.0 → 2.11.3-dev-build-fef5d82.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
|
@@ -27,6 +27,70 @@ function isNumberType(type) {
|
|
|
27
27
|
function isComplexType(type) {
|
|
28
28
|
return !isSimpleType(type);
|
|
29
29
|
}
|
|
30
|
+
const DOM_PASS_THROUGH_PROPS = new Set([
|
|
31
|
+
// Bare HTML / framework styling pass-through
|
|
32
|
+
'className',
|
|
33
|
+
'class',
|
|
34
|
+
'classes',
|
|
35
|
+
'classNames',
|
|
36
|
+
'rootClassName',
|
|
37
|
+
'prefixCls',
|
|
38
|
+
'style',
|
|
39
|
+
'styles',
|
|
40
|
+
// Bare HTML attributes
|
|
41
|
+
'id',
|
|
42
|
+
'role',
|
|
43
|
+
'tabIndex',
|
|
44
|
+
'tabindex',
|
|
45
|
+
'name',
|
|
46
|
+
'htmlFor',
|
|
47
|
+
'for',
|
|
48
|
+
'slot',
|
|
49
|
+
'is',
|
|
50
|
+
'lang',
|
|
51
|
+
'dir',
|
|
52
|
+
'hidden',
|
|
53
|
+
'draggable',
|
|
54
|
+
'spellCheck',
|
|
55
|
+
'spellcheck',
|
|
56
|
+
'contentEditable',
|
|
57
|
+
'contenteditable',
|
|
58
|
+
'inputMode',
|
|
59
|
+
'inputmode',
|
|
60
|
+
'autoComplete',
|
|
61
|
+
'autocomplete',
|
|
62
|
+
'autoFocus',
|
|
63
|
+
'autofocus',
|
|
64
|
+
'translate',
|
|
65
|
+
'part',
|
|
66
|
+
'exportparts',
|
|
67
|
+
'aria',
|
|
68
|
+
// Framework theming / pass-through escape hatches — dev-facing, never marketer-configurable
|
|
69
|
+
'dt',
|
|
70
|
+
'pt',
|
|
71
|
+
'ptOptions',
|
|
72
|
+
'unstyled',
|
|
73
|
+
// Polymorphic component props — change rendered HTML/component, not marketer-visible behavior
|
|
74
|
+
'as',
|
|
75
|
+
'element',
|
|
76
|
+
'component',
|
|
77
|
+
// QA / vendor test attributes
|
|
78
|
+
'dataQa',
|
|
79
|
+
'data-qa',
|
|
80
|
+
// Vue v-model internals — framework wiring, never marketer-configurable
|
|
81
|
+
'modelValue',
|
|
82
|
+
'modelModifiers',
|
|
83
|
+
]);
|
|
84
|
+
function isDomPassThroughProp(name) {
|
|
85
|
+
if (DOM_PASS_THROUGH_PROPS.has(name))
|
|
86
|
+
return true;
|
|
87
|
+
// aria-label, aria-hidden, ariaLabel, ariaHidden — both kebab and camel forms
|
|
88
|
+
if (/^aria[-A-Z]/.test(name))
|
|
89
|
+
return true;
|
|
90
|
+
if (name.startsWith('data-'))
|
|
91
|
+
return true;
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
30
94
|
/**
|
|
31
95
|
* Deterministic pre-classification rule engine.
|
|
32
96
|
* Applies rules in priority order and returns on the first match.
|
|
@@ -54,9 +118,12 @@ export function preClassifyProp(prop) {
|
|
|
54
118
|
if (type.includes('Dispatch<') || type.includes('SetStateAction')) {
|
|
55
119
|
return { category: 'exclude' };
|
|
56
120
|
}
|
|
57
|
-
// Rule 6:
|
|
58
|
-
|
|
59
|
-
|
|
121
|
+
// Rule 6: DOM / a11y / framework pass-through props
|
|
122
|
+
// These are escape hatches developers use to wire components into the DOM.
|
|
123
|
+
// Marketers should never configure them in the ExO editor; exposing them
|
|
124
|
+
// generates noise that obscures the props that actually carry intent.
|
|
125
|
+
if (isDomPassThroughProp(name)) {
|
|
126
|
+
return { category: 'exclude' };
|
|
60
127
|
}
|
|
61
128
|
// Rule 7: String literal union
|
|
62
129
|
if (isStringLiteralUnion(type)) {
|
|
@@ -13,5 +13,5 @@ export function DoneStep({ componentTypes, designTokens, summary, spaceId, envir
|
|
|
13
13
|
function EntityRows({ entity, label }) {
|
|
14
14
|
return (_jsxs(_Fragment, { children: [entity.created > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "green", children: "\u2713" }), _jsxs(Text, { children: [entity.created, " ", label, entity.created !== 1 ? 's' : '', " created"] })] })), entity.updated > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "green", children: "\u2713" }), _jsxs(Text, { children: [entity.updated, " ", label, entity.updated !== 1 ? 's' : '', " updated"] })] })), entity.failed > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "red", children: "\u2717" }), _jsxs(Text, { color: "red", children: [entity.failed, " ", label, entity.failed !== 1 ? 's' : '', " failed \u2014 check logs above"] })] }))] }));
|
|
15
15
|
}
|
|
16
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [success ? (_jsx(Text, { bold: true, color: "green", children: "Done!" })) : (_jsx(Text, { bold: true, color: "yellow", children: "\u26A0 Finished with errors" })), totalPushed === 0 && totalFailed === 0 && !summary ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Nothing was pushed \u2014 everything was already up to date." }) })) : (_jsxs(Box, { flexDirection: "column", gap: 0, marginTop: 1, children: [_jsx(EntityRows, { entity: componentTypes, label: "Component Type" }), _jsx(EntityRows, { entity: designTokens, label: "Design Token" }), summary && (_jsxs(Box, { gap: 1, marginTop: 1, children: [_jsxs(Text, { dimColor: true, children: ["Server: ", summary.succeeded, "/", summary.total, " succeeded"] }), summary.failed > 0 && _jsxs(Text, { color: "red", children: [", ", summary.failed, " failed"] })] }))] })), _jsxs(Box, { gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Space:" }), _jsx(Text, { children: spaceId }), _jsx(Text, { dimColor: true, children: "/" }), _jsx(Text, { dimColor: true, children: "Environment:" }), _jsx(Text, { children: environmentId })] }), success && totalPushed > 0 && (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Your design system is now in Contentful ExO." }), _jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Text, { dimColor: true, children: "View it here:" }), _jsx(Text, { color: "cyan", children: `https://app.contentful.com/spaces/${spaceId}/environments/${environmentId}/
|
|
16
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [success ? (_jsx(Text, { bold: true, color: "green", children: "Done!" })) : (_jsx(Text, { bold: true, color: "yellow", children: "\u26A0 Finished with errors" })), totalPushed === 0 && totalFailed === 0 && !summary ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Nothing was pushed \u2014 everything was already up to date." }) })) : (_jsxs(Box, { flexDirection: "column", gap: 0, marginTop: 1, children: [_jsx(EntityRows, { entity: componentTypes, label: "Component Type" }), _jsx(EntityRows, { entity: designTokens, label: "Design Token" }), summary && (_jsxs(Box, { gap: 1, marginTop: 1, children: [_jsxs(Text, { dimColor: true, children: ["Server: ", summary.succeeded, "/", summary.total, " succeeded"] }), summary.failed > 0 && _jsxs(Text, { color: "red", children: [", ", summary.failed, " failed"] })] }))] })), _jsxs(Box, { gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Space:" }), _jsx(Text, { children: spaceId }), _jsx(Text, { dimColor: true, children: "/" }), _jsx(Text, { dimColor: true, children: "Environment:" }), _jsx(Text, { children: environmentId })] }), success && totalPushed > 0 && (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Your design system is now in Contentful ExO." }), _jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Text, { dimColor: true, children: "View it here:" }), _jsx(Text, { color: "cyan", children: `https://app.contentful.com/spaces/${spaceId}/environments/${environmentId}/exo/components` })] })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "[Enter / q] Exit" }) })] }));
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.3-dev-build-fef5d82.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"react-dom": "^18.3.1",
|
|
37
37
|
"ts-morph": "^27.0.2",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
|
-
"@contentful/experience-design-system-types": "2.11.
|
|
39
|
+
"@contentful/experience-design-system-types": "2.11.3-dev-build-fef5d82.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@tsconfig/node24": "^24.0.3",
|
|
@@ -131,15 +131,30 @@ The pre-classified `category` in the raw input is a starting point — correct i
|
|
|
131
131
|
|
|
132
132
|
For each `RawPropDefinition`, apply in order:
|
|
133
133
|
|
|
134
|
-
1. **Framework
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
134
|
+
1. **Framework / DOM / accessibility pass-through?** → `exclude_prop`. These are escape hatches for developers, not configurable surfaces for marketers. Exposing them in the ExO editor adds noise that obscures the props that actually carry intent. Always exclude:
|
|
135
|
+
- Framework internals: `ref`, `innerRef`, event handlers (any `onSomething`), `testId`, `data-testid`, `key`
|
|
136
|
+
- DOM pass-through: `className`, `class`, `classes`, `classNames`, `rootClassName`, `prefixCls`, `style`, `styles`, `id`, `role`, `tabIndex`, `name` (the bare HTML form `name` attribute), `htmlFor`, `for`, `slot`, `is`, `lang`, `dir`, `hidden`, `draggable`, `spellCheck`, `contentEditable`, `inputMode`, `autoComplete`, `autoFocus`, `translate`, `part`, `exportparts`
|
|
137
|
+
- Accessibility pass-through: any `aria-*` or `ariaSomething` prop (including bare `aria` as an aria-attributes object), `aria-label`, `aria-hidden`, `aria-describedby`, `aria-controls`
|
|
138
|
+
- Data attributes: any `data-*` prop
|
|
139
|
+
- **Polymorphic component props**: `as`, `element`, `component` (when typed as an HTML tag string or component reference) — these change rendered HTML, not marketer-visible behavior
|
|
140
|
+
- **Framework theming / pass-through escape hatches**: PrimeVue's `dt` / `pt` / `ptOptions` / `unstyled`, MUI/Chakra-style `sx`, anything explicitly typed as a developer "override" / "passthrough" object
|
|
141
|
+
- **Important caveat**: only exclude when the prop is one of these *as the bare HTML attribute or framework-internal pass-through*. Compound names like `fileName`, `displayName`, `dataset`, `dataSource`, `roleDescription`, `idLabel` are not pass-through — classify them normally.
|
|
142
|
+
2. **Common semantic props — DO classify, do not exclude.** The LLM has been over-excluding these because they sound like framework internals; they are not. Classify each per the rest of this tree:
|
|
143
|
+
- `icon` / `leftIcon` / `rightIcon` / `prefixIcon` / `suffixIcon` — slot or `string` (icon name); see slot guidance below
|
|
144
|
+
- `items` / `options` / `actions` / `links` — usually array content; if the element shape is simple, classify as `string` (comma-separated names/IDs) and note in `description`. Only exclude when elements are deep nested objects with no flat representation.
|
|
145
|
+
- `value` (the bare prop, not `modelValue`) — content prop, usually `string` (or `enum` if from a fixed set). Note: Vue's `modelValue` / `modelModifiers` are excluded by pre-classify because they're v-model framework wiring.
|
|
146
|
+
- `form` (when not the literal `<form>` HTML attribute) — typically content; classify as `string` unless it's a complex form-config object
|
|
147
|
+
- `inputId` / `componentId` — these CAN be content (anchor IDs, marketer-set tracking refs). Classify as `string`, `cdf_category: "content"` when the type is a plain string. Only exclude if the prop is clearly internal (e.g. typed as a generated React ID).
|
|
148
|
+
- `accessibleNameRef` / `accessibleDescriptionRef` (web components) — these are ID references for a11y wiring; classify as `string`, `cdf_category: "state"` (behavioral wiring, not design or content).
|
|
149
|
+
- `eventDetails` / similar telemetry props — `cdf_category: "state"`.
|
|
150
|
+
3. **Positional/geometric design prop?** (`top`, `bottom`, `left`, `right`, `rotation`, `offset`, `zIndex`) → `classify_prop`, `cdf_type: "string"`, `cdf_category: "design"`.
|
|
151
|
+
4. **Has `tokenReference`?** → `cdf_type: "token"`, resolve `token_kind` via sidecar lookup (see below). This overrides all other heuristics.
|
|
152
|
+
5. **Union of string literals** (e.g. `'a' | 'b' | 'c'`)? → `cdf_type: "enum"`, extract literals into `values`.
|
|
153
|
+
6. **Raw type is `string`** and prop name is `href`, `url`, or clearly a URL? → `cdf_type: "string"`, `cdf_category: "content"`.
|
|
154
|
+
7. **Raw type is `string` / `number` / `boolean`?** → For `boolean`, use `cdf_type: "boolean"` with `default: true` or `false` (native boolean). For `number`, use `cdf_type: "string"` with `default` as the numeric value as a string (e.g. `"0"`). For `string`, use `cdf_type: "string"`.
|
|
155
|
+
8. **Media/image type** (`ImageProps`, `MediaSource`, asset types)? → `cdf_type: "media"`.
|
|
156
|
+
9. **Rich text / markup** (`ReactNode` used as content, HTML string)? → `cdf_type: "richtext"`.
|
|
157
|
+
10. **Complex type — resolve before excluding** (see below).
|
|
143
158
|
|
|
144
159
|
---
|
|
145
160
|
|
|
@@ -268,7 +283,7 @@ Input:
|
|
|
268
283
|
{"name":"variant","type":"'primary'|'secondary'|'ghost'","category":"design","defaultValue":"'primary'"},
|
|
269
284
|
{"name":"disabled","type":"boolean","category":"design"},
|
|
270
285
|
{"name":"onClick","type":"()=>void","category":"state"},
|
|
271
|
-
{"name":"className","type":"string"
|
|
286
|
+
{"name":"className","type":"string"}
|
|
272
287
|
],
|
|
273
288
|
"slots": [{"name":"icon","description":"Optional leading icon"}]
|
|
274
289
|
}
|
|
@@ -286,8 +301,8 @@ disabled is a boolean state prop — raw category says design, correcting to sta
|
|
|
286
301
|
{"tool":"classify_prop","prop":"disabled","cdf_type":"boolean","cdf_category":"state","required":false,"default":false,"description":"Disables the button"}
|
|
287
302
|
onClick is an event handler — framework internal
|
|
288
303
|
{"tool":"exclude_prop","prop":"onClick","reason":"event handler — framework internal"}
|
|
289
|
-
className is a
|
|
290
|
-
{"tool":"
|
|
304
|
+
className is a DOM pass-through — developers wire CSS, marketers never set this
|
|
305
|
+
{"tool":"exclude_prop","prop":"className","reason":"DOM pass-through — not a marketer-configurable surface"}
|
|
291
306
|
icon slot is clearly optional (decorative leading icon)
|
|
292
307
|
{"tool":"classify_slot","slot":"icon","required":false,"description":"Optional leading icon"}
|
|
293
308
|
```
|
|
@@ -337,7 +352,7 @@ Before emitting any tool calls, verify:
|
|
|
337
352
|
5. Every `cdf_type: "token"` has `token_kind` (or a warning in `description` if lookup failed)
|
|
338
353
|
6. No `cdf_type: "link"` — all href/url props use `string`
|
|
339
354
|
7. `required` values are JSON booleans, not strings
|
|
340
|
-
8. Framework
|
|
355
|
+
8. Framework, DOM, accessibility, and data-* pass-through props are excluded — `className`/`classes`/`classNames`/`rootClassName`/`prefixCls`, `style`, `id`, `role`, `tabIndex`, `name` (bare HTML form attribute), `aria-*` (and bare `aria`), `data-*`, polymorphic `as`/`element`/`component`, framework theming `dt`/`pt`/`ptOptions`/`unstyled`/`sx`. Discrete positional/geometric props (`top`, `bottom`, `left`, `right`, `rotation`, etc.) ARE classified as `string` design props. Common semantic props (`icon`, `items`, `actions`, `options`, `value`, `form`, `inputId`, `componentId`) are NOT excluded — classify them per their content/design/state nature.
|
|
341
356
|
9. No `cdf_type: "link"` used — `link` is reserved and rejected by the CLI parser
|
|
342
357
|
10. No `cdf_type: "number"` used — this is not a supported type; use `"string"` with numeric defaults. `cdf_type: "boolean"` IS valid — use it for boolean toggle props.
|
|
343
358
|
|