create-kerf-component 5.0.0-beta.18 → 5.0.0-beta.21

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.
@@ -0,0 +1,246 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/brianwestphal/kerf/main/ui/ai/component-catalog-v2.schema.json",
4
+ "title": "Kerf UI composition catalog v2",
5
+ "type": "object",
6
+ "required": ["schemaVersion", "package", "compatibility", "entries"],
7
+ "properties": {
8
+ "$schema": { "type": "string" },
9
+ "schemaVersion": { "const": 2 },
10
+ "package": { "type": "string", "minLength": 1 },
11
+ "compatibility": {
12
+ "type": "object",
13
+ "required": ["v1Catalog", "identity"],
14
+ "properties": {
15
+ "v1Catalog": { "type": "string", "minLength": 1 },
16
+ "identity": { "const": "package:id" }
17
+ },
18
+ "additionalProperties": false
19
+ },
20
+ "entries": { "type": "array", "items": { "$ref": "#/$defs/entry" } }
21
+ },
22
+ "additionalProperties": false,
23
+ "$defs": {
24
+ "stringList": {
25
+ "type": "array",
26
+ "items": { "type": "string", "minLength": 1 },
27
+ "uniqueItems": true
28
+ },
29
+ "cardinality": {
30
+ "type": "object",
31
+ "required": ["min", "max"],
32
+ "properties": {
33
+ "min": { "type": "integer", "minimum": 0 },
34
+ "max": {
35
+ "anyOf": [
36
+ { "type": "integer", "minimum": 1 },
37
+ { "const": "unbounded" }
38
+ ]
39
+ }
40
+ },
41
+ "additionalProperties": false
42
+ },
43
+ "zone": {
44
+ "type": "object",
45
+ "required": ["id", "accepts", "cardinality", "exclusiveWith"],
46
+ "properties": {
47
+ "id": { "type": "string", "minLength": 1 },
48
+ "accepts": { "$ref": "#/$defs/stringList" },
49
+ "cardinality": { "$ref": "#/$defs/cardinality" },
50
+ "exclusiveWith": { "$ref": "#/$defs/stringList" }
51
+ },
52
+ "additionalProperties": false
53
+ },
54
+ "state": {
55
+ "type": "object",
56
+ "required": ["id", "owner", "required"],
57
+ "properties": {
58
+ "id": { "type": "string", "minLength": 1 },
59
+ "owner": { "enum": ["application", "controlled", "component"] },
60
+ "required": { "type": "boolean" }
61
+ },
62
+ "additionalProperties": false
63
+ },
64
+ "diagnostic": {
65
+ "type": "object",
66
+ "required": ["id", "severity", "when", "message"],
67
+ "properties": {
68
+ "id": { "type": "string", "pattern": "^KUI-C[0-9]{3}$" },
69
+ "severity": { "enum": ["error", "warning"] },
70
+ "when": { "type": "string", "minLength": 1 },
71
+ "message": { "type": "string", "minLength": 1 }
72
+ },
73
+ "additionalProperties": false
74
+ },
75
+ "entry": {
76
+ "type": "object",
77
+ "required": [
78
+ "key",
79
+ "package",
80
+ "id",
81
+ "name",
82
+ "kind",
83
+ "source",
84
+ "parents",
85
+ "contexts",
86
+ "zones",
87
+ "children",
88
+ "state",
89
+ "wiring",
90
+ "responsive",
91
+ "layout",
92
+ "accessibility",
93
+ "boundaries",
94
+ "diagnostics",
95
+ "provenance"
96
+ ],
97
+ "properties": {
98
+ "key": { "type": "string", "minLength": 3 },
99
+ "package": { "type": "string", "minLength": 1 },
100
+ "id": { "type": "string", "minLength": 1 },
101
+ "name": { "type": "string", "minLength": 1 },
102
+ "kind": { "enum": ["component", "composition", "recipe"] },
103
+ "purpose": { "type": "string", "minLength": 1 },
104
+ "publicExports": {
105
+ "type": "array",
106
+ "items": {
107
+ "type": "object",
108
+ "required": ["name", "subpath"],
109
+ "properties": {
110
+ "name": { "type": "string", "minLength": 1 },
111
+ "subpath": { "type": "string", "pattern": "^\\." }
112
+ },
113
+ "additionalProperties": false
114
+ },
115
+ "minItems": 1
116
+ },
117
+ "sourceLinks": { "$ref": "#/$defs/stringList" },
118
+ "source": { "type": "string", "minLength": 1 },
119
+ "parents": {
120
+ "type": "object",
121
+ "required": ["mode", "entries"],
122
+ "properties": {
123
+ "mode": { "enum": ["any", "root", "listed"] },
124
+ "entries": { "$ref": "#/$defs/stringList" }
125
+ },
126
+ "additionalProperties": false
127
+ },
128
+ "contexts": { "$ref": "#/$defs/stringList" },
129
+ "zones": { "type": "array", "items": { "$ref": "#/$defs/zone" } },
130
+ "children": {
131
+ "type": "object",
132
+ "required": ["mode", "concepts", "requiredConcepts"],
133
+ "properties": {
134
+ "mode": { "enum": ["any", "none", "listed"] },
135
+ "concepts": { "$ref": "#/$defs/stringList" },
136
+ "requiredConcepts": { "$ref": "#/$defs/stringList" }
137
+ },
138
+ "additionalProperties": false
139
+ },
140
+ "state": { "type": "array", "items": { "$ref": "#/$defs/state" } },
141
+ "wiring": {
142
+ "type": "object",
143
+ "required": ["required", "helpers", "obligations"],
144
+ "properties": {
145
+ "required": { "type": "boolean" },
146
+ "helpers": { "$ref": "#/$defs/stringList" },
147
+ "obligations": { "$ref": "#/$defs/stringList" }
148
+ },
149
+ "additionalProperties": false
150
+ },
151
+ "responsive": {
152
+ "type": "object",
153
+ "required": ["owner", "behaviors"],
154
+ "properties": {
155
+ "owner": {
156
+ "enum": ["application", "component", "shared", "not-applicable"]
157
+ },
158
+ "behaviors": { "$ref": "#/$defs/stringList" }
159
+ },
160
+ "additionalProperties": false
161
+ },
162
+ "layout": {
163
+ "type": "object",
164
+ "required": ["roles", "geometry"],
165
+ "properties": {
166
+ "roles": { "$ref": "#/$defs/stringList" },
167
+ "geometry": {
168
+ "type": "object",
169
+ "required": ["margin", "border", "padding"],
170
+ "properties": {
171
+ "margin": {
172
+ "enum": [
173
+ "self",
174
+ "parent",
175
+ "child",
176
+ "none",
177
+ "conditional",
178
+ "composed"
179
+ ]
180
+ },
181
+ "border": {
182
+ "enum": [
183
+ "self",
184
+ "parent",
185
+ "child",
186
+ "none",
187
+ "conditional",
188
+ "composed"
189
+ ]
190
+ },
191
+ "padding": {
192
+ "enum": [
193
+ "self",
194
+ "parent",
195
+ "child",
196
+ "none",
197
+ "conditional",
198
+ "composed"
199
+ ]
200
+ },
201
+ "notes": { "$ref": "#/$defs/stringList" }
202
+ },
203
+ "additionalProperties": false
204
+ }
205
+ },
206
+ "additionalProperties": false
207
+ },
208
+ "accessibility": {
209
+ "type": "object",
210
+ "required": ["obligations"],
211
+ "properties": { "obligations": { "$ref": "#/$defs/stringList" } },
212
+ "additionalProperties": false
213
+ },
214
+ "boundaries": {
215
+ "type": "object",
216
+ "required": ["rootClass", "publicClasses", "publicTokens"],
217
+ "properties": {
218
+ "rootClass": {
219
+ "oneOf": [
220
+ { "type": "string", "minLength": 1 },
221
+ { "type": "null" }
222
+ ]
223
+ },
224
+ "publicClasses": { "$ref": "#/$defs/stringList" },
225
+ "publicTokens": { "$ref": "#/$defs/stringList" }
226
+ },
227
+ "additionalProperties": false
228
+ },
229
+ "diagnostics": {
230
+ "type": "array",
231
+ "items": { "$ref": "#/$defs/diagnostic" }
232
+ },
233
+ "provenance": {
234
+ "type": "object",
235
+ "required": ["selection", "composition"],
236
+ "properties": {
237
+ "selection": { "type": "string", "minLength": 1 },
238
+ "composition": { "type": "string", "minLength": 1 }
239
+ },
240
+ "additionalProperties": false
241
+ }
242
+ },
243
+ "additionalProperties": false
244
+ }
245
+ }
246
+ }
@@ -0,0 +1,229 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/brianwestphal/kerf/main/create-kerf-component/component-metadata.schema.json",
4
+ "title": "Kerf consumer component metadata source",
5
+ "type": "object",
6
+ "required": ["schemaVersion", "components"],
7
+ "properties": {
8
+ "$schema": { "type": "string" },
9
+ "schemaVersion": { "const": 1 },
10
+ "v1Catalog": { "type": "string", "minLength": 1 },
11
+ "components": {
12
+ "type": "array",
13
+ "items": { "$ref": "#/$defs/component" }
14
+ }
15
+ },
16
+ "additionalProperties": false,
17
+ "$defs": {
18
+ "stringList": {
19
+ "type": "array",
20
+ "items": { "type": "string", "minLength": 1 },
21
+ "uniqueItems": true
22
+ },
23
+ "cardinality": {
24
+ "type": "object",
25
+ "required": ["min", "max"],
26
+ "properties": {
27
+ "min": { "type": "integer", "minimum": 0 },
28
+ "max": {
29
+ "anyOf": [
30
+ { "type": "integer", "minimum": 1 },
31
+ { "const": "unbounded" }
32
+ ]
33
+ }
34
+ },
35
+ "additionalProperties": false
36
+ },
37
+ "diagnostic": {
38
+ "type": "object",
39
+ "required": ["id", "severity", "when", "message"],
40
+ "properties": {
41
+ "id": { "type": "string", "pattern": "^KUI-C[0-9]{3}$" },
42
+ "severity": { "enum": ["error", "warning"] },
43
+ "when": { "type": "string", "minLength": 1 },
44
+ "message": { "type": "string", "minLength": 1 }
45
+ },
46
+ "additionalProperties": false
47
+ },
48
+ "component": {
49
+ "type": "object",
50
+ "required": [
51
+ "id",
52
+ "name",
53
+ "kind",
54
+ "purpose",
55
+ "source",
56
+ "publicExports",
57
+ "sourceLinks",
58
+ "composition",
59
+ "boundaries",
60
+ "accessibility",
61
+ "diagnostics",
62
+ "provenance"
63
+ ],
64
+ "properties": {
65
+ "id": { "type": "string", "minLength": 1 },
66
+ "name": { "type": "string", "minLength": 1 },
67
+ "kind": { "enum": ["component", "composition", "recipe"] },
68
+ "purpose": { "type": "string", "minLength": 1 },
69
+ "source": { "type": "string", "minLength": 1 },
70
+ "publicExports": {
71
+ "type": "array",
72
+ "minItems": 1,
73
+ "items": {
74
+ "type": "object",
75
+ "required": ["name", "subpath"],
76
+ "properties": {
77
+ "name": { "type": "string", "minLength": 1 },
78
+ "subpath": { "type": "string", "pattern": "^\\." }
79
+ },
80
+ "additionalProperties": false
81
+ }
82
+ },
83
+ "sourceLinks": { "$ref": "#/$defs/stringList" },
84
+ "composition": { "$ref": "#/$defs/composition" },
85
+ "boundaries": {
86
+ "type": "object",
87
+ "required": ["rootClass", "publicClasses", "publicTokens"],
88
+ "properties": {
89
+ "rootClass": {
90
+ "oneOf": [
91
+ { "type": "string", "minLength": 1 },
92
+ { "type": "null" }
93
+ ]
94
+ },
95
+ "publicClasses": { "$ref": "#/$defs/stringList" },
96
+ "publicTokens": { "$ref": "#/$defs/stringList" }
97
+ },
98
+ "additionalProperties": false
99
+ },
100
+ "accessibility": {
101
+ "type": "object",
102
+ "required": ["obligations"],
103
+ "properties": { "obligations": { "$ref": "#/$defs/stringList" } },
104
+ "additionalProperties": false
105
+ },
106
+ "diagnostics": {
107
+ "type": "array",
108
+ "items": { "$ref": "#/$defs/diagnostic" }
109
+ },
110
+ "provenance": {
111
+ "type": "object",
112
+ "required": ["selection", "composition"],
113
+ "properties": {
114
+ "selection": { "type": "string", "minLength": 1 },
115
+ "composition": { "type": "string", "minLength": 1 }
116
+ },
117
+ "additionalProperties": false
118
+ }
119
+ },
120
+ "additionalProperties": false
121
+ },
122
+ "composition": {
123
+ "type": "object",
124
+ "required": [
125
+ "parents",
126
+ "contexts",
127
+ "zones",
128
+ "children",
129
+ "state",
130
+ "wiring",
131
+ "responsive",
132
+ "layout"
133
+ ],
134
+ "properties": {
135
+ "parents": {
136
+ "type": "object",
137
+ "required": ["mode", "entries"],
138
+ "properties": {
139
+ "mode": { "enum": ["any", "root", "listed"] },
140
+ "entries": { "$ref": "#/$defs/stringList" }
141
+ },
142
+ "additionalProperties": false
143
+ },
144
+ "contexts": { "$ref": "#/$defs/stringList" },
145
+ "zones": {
146
+ "type": "array",
147
+ "items": {
148
+ "type": "object",
149
+ "required": ["id", "accepts", "cardinality", "exclusiveWith"],
150
+ "properties": {
151
+ "id": { "type": "string", "minLength": 1 },
152
+ "accepts": { "$ref": "#/$defs/stringList" },
153
+ "cardinality": { "$ref": "#/$defs/cardinality" },
154
+ "exclusiveWith": { "$ref": "#/$defs/stringList" }
155
+ },
156
+ "additionalProperties": false
157
+ }
158
+ },
159
+ "children": {
160
+ "type": "object",
161
+ "required": ["mode", "concepts", "requiredConcepts"],
162
+ "properties": {
163
+ "mode": { "enum": ["any", "none", "listed"] },
164
+ "concepts": { "$ref": "#/$defs/stringList" },
165
+ "requiredConcepts": { "$ref": "#/$defs/stringList" }
166
+ },
167
+ "additionalProperties": false
168
+ },
169
+ "state": {
170
+ "type": "array",
171
+ "items": {
172
+ "type": "object",
173
+ "required": ["id", "owner", "required"],
174
+ "properties": {
175
+ "id": { "type": "string", "minLength": 1 },
176
+ "owner": { "enum": ["application", "controlled", "component"] },
177
+ "required": { "type": "boolean" }
178
+ },
179
+ "additionalProperties": false
180
+ }
181
+ },
182
+ "wiring": {
183
+ "type": "object",
184
+ "required": ["required", "helpers", "obligations"],
185
+ "properties": {
186
+ "required": { "type": "boolean" },
187
+ "helpers": { "$ref": "#/$defs/stringList" },
188
+ "obligations": { "$ref": "#/$defs/stringList" }
189
+ },
190
+ "additionalProperties": false
191
+ },
192
+ "responsive": {
193
+ "type": "object",
194
+ "required": ["owner", "behaviors"],
195
+ "properties": {
196
+ "owner": {
197
+ "enum": ["application", "component", "shared", "not-applicable"]
198
+ },
199
+ "behaviors": { "$ref": "#/$defs/stringList" }
200
+ },
201
+ "additionalProperties": false
202
+ },
203
+ "layout": {
204
+ "type": "object",
205
+ "required": ["roles", "geometry"],
206
+ "properties": {
207
+ "roles": { "$ref": "#/$defs/stringList" },
208
+ "geometry": {
209
+ "type": "object",
210
+ "required": ["margin", "border", "padding"],
211
+ "properties": {
212
+ "margin": { "$ref": "#/$defs/geometryOwner" },
213
+ "border": { "$ref": "#/$defs/geometryOwner" },
214
+ "padding": { "$ref": "#/$defs/geometryOwner" },
215
+ "notes": { "$ref": "#/$defs/stringList" }
216
+ },
217
+ "additionalProperties": false
218
+ }
219
+ },
220
+ "additionalProperties": false
221
+ }
222
+ },
223
+ "additionalProperties": false
224
+ },
225
+ "geometryOwner": {
226
+ "enum": ["self", "parent", "child", "none", "conditional", "composed"]
227
+ }
228
+ }
229
+ }
package/index.js CHANGED
@@ -18,6 +18,7 @@
18
18
  // initializer is plain Node so `npm create` runs it with zero install latency.
19
19
 
20
20
  import {
21
+ copyFileSync,
21
22
  cpSync,
22
23
  existsSync,
23
24
  mkdirSync,
@@ -27,6 +28,7 @@ import {
27
28
  writeFileSync,
28
29
  } from 'node:fs';
29
30
  import { basename, dirname, join, resolve } from 'node:path';
31
+ import process from 'node:process';
30
32
  import { createInterface } from 'node:readline/promises';
31
33
  import { fileURLToPath } from 'node:url';
32
34
 
@@ -127,6 +129,19 @@ async function main(argv) {
127
129
  // verbatim (`_gitignore` → `.gitignore`).
128
130
  mkdirSync(targetDir, { recursive: true });
129
131
  cpSync(TEMPLATE_DIR, targetDir, { recursive: true });
132
+ mkdirSync(join(targetDir, 'scripts'), { recursive: true });
133
+ copyFileSync(
134
+ join(dirname(fileURLToPath(import.meta.url)), 'catalog.js'),
135
+ join(targetDir, 'scripts', 'kerf-component-catalog.mjs'),
136
+ );
137
+ for (const schema of [
138
+ 'component-metadata.schema.json',
139
+ 'component-catalog-v2.schema.json',
140
+ ])
141
+ copyFileSync(
142
+ join(dirname(fileURLToPath(import.meta.url)), schema),
143
+ join(targetDir, 'scripts', schema),
144
+ );
130
145
 
131
146
  for (const file of walk(targetDir)) {
132
147
  const text = readFileSync(file, 'utf8');
@@ -146,8 +161,9 @@ async function main(argv) {
146
161
  cdHint +
147
162
  ' npm install\n' +
148
163
  ' npm run build # tsup → ESM + .d.ts (kerfjs stays external)\n' +
164
+ ' npm run catalog:check # verify AI metadata and public exports\n' +
149
165
  ' npm run typecheck\n\n' +
150
- 'Edit src/counter.tsx, then publish with `npm publish --access public`.\n',
166
+ 'Edit src/counter.tsx and kerf.components.json, then publish with `npm publish --access public`.\n',
151
167
  );
152
168
  }
153
169
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kerf-component",
3
- "version": "5.0.0-beta.18",
3
+ "version": "5.0.0-beta.21",
4
4
  "description": "Scaffold a publishable kerf component package that already follows kerf's hard packaging rules.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,15 +26,22 @@
26
26
  "node": ">=18.0.0"
27
27
  },
28
28
  "bin": {
29
- "create-kerf-component": "index.js"
29
+ "create-kerf-component": "index.js",
30
+ "kerf-component-catalog": "catalog.js"
30
31
  },
31
32
  "files": [
32
33
  "index.js",
34
+ "catalog.js",
35
+ "component-metadata.schema.json",
36
+ "component-catalog-v2.schema.json",
33
37
  "template",
34
38
  "README.md",
35
39
  "LICENSE"
36
40
  ],
37
41
  "scripts": {
38
42
  "test": "node --test tests/*.test.js"
43
+ },
44
+ "dependencies": {
45
+ "typescript": "^5.0.0 || ^6.0.0"
39
46
  }
40
47
  }
@@ -9,6 +9,7 @@ scaffolded with `create-kerf-component`.
9
9
  npm install
10
10
  npm run build # tsup → dist/ (ESM + .d.ts); kerfjs stays external
11
11
  npm run typecheck
12
+ npm run catalog:check # verify component-catalog-v2.json is current
12
13
  ```
13
14
 
14
15
  ## Use it
@@ -56,4 +57,29 @@ have to:
56
57
  npm publish --access public
57
58
  ```
58
59
 
59
- `prepublishOnly` runs the build first; `files` ships only `dist/` + docs.
60
+ `prepublishOnly` checks the catalog and runs the build; `files` ships `dist/`,
61
+ the metadata/catalog pair, the README, and the license.
62
+
63
+ ## AI component metadata
64
+
65
+ `kerf.components.json` is the author-owned source for the component's purpose,
66
+ public exports, composition rules, geometry ownership, tokens, accessibility,
67
+ and source links. `boundaries.rootClass` explicitly names the public class that
68
+ owns runtime geometry (or is `null` when none does); `publicClasses` order has no
69
+ semantic meaning. Keep decisions explicit: the generator deliberately does not
70
+ derive semantic or geometry ownership from rendered appearance. It validates
71
+ both this source and the generated catalog against the schema copies beside the
72
+ checker, including rejection of unknown fields. Named exports must exist in
73
+ the TypeScript/TSX syntax tree; JSX text, nested scopes, comments, and literals
74
+ are not exports. The checker uses this package's installed TypeScript compiler,
75
+ so run `npm install` before the first local catalog command.
76
+
77
+ ```bash
78
+ npm run catalog:generate # write component-catalog-v2.json
79
+ npm run catalog:check # no writes; fail when metadata, source, or output drift
80
+ ```
81
+
82
+ The generated catalog ships with the package. AI tools join each entry to
83
+ Kerf's catalog by its `package:id` key, search this package first for
84
+ application-specific concepts, and retain both packages' identities when
85
+ following cross-catalog composition references.