desen-core 1.0.0-draft.3 → 1.0.0-draft.31

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.
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- export declare const styleSpec: z.ZodObject<{
2
+ export declare const styleSpec: z.ZodEffects<z.ZodObject<{
3
3
  bg_color: z.ZodOptional<z.ZodString>;
4
4
  bg_color_token: z.ZodOptional<z.ZodString>;
5
5
  text_color: z.ZodOptional<z.ZodString>;
@@ -14,6 +14,14 @@ export declare const styleSpec: z.ZodObject<{
14
14
  font_weight_token: z.ZodOptional<z.ZodString>;
15
15
  line_height: z.ZodOptional<z.ZodNumber>;
16
16
  line_height_token: z.ZodOptional<z.ZodString>;
17
+ line_height_percent: z.ZodOptional<z.ZodNumber>;
18
+ letter_spacing: z.ZodOptional<z.ZodNumber>;
19
+ letter_spacing_token: z.ZodOptional<z.ZodString>;
20
+ letter_spacing_percent: z.ZodOptional<z.ZodNumber>;
21
+ text_align: z.ZodOptional<z.ZodString>;
22
+ text_decoration: z.ZodOptional<z.ZodString>;
23
+ text_transform: z.ZodOptional<z.ZodString>;
24
+ text_style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
17
25
  padding: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
18
26
  top: z.ZodOptional<z.ZodNumber>;
19
27
  right: z.ZodOptional<z.ZodNumber>;
@@ -48,10 +56,14 @@ export declare const styleSpec: z.ZodObject<{
48
56
  left?: number | undefined;
49
57
  }>]>>;
50
58
  margin_token: z.ZodOptional<z.ZodString>;
51
- border_radius: z.ZodOptional<z.ZodNumber>;
59
+ border_radius: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodArray<z.ZodNumber, "many">]>>;
52
60
  border_radius_token: z.ZodOptional<z.ZodString>;
53
61
  border_width: z.ZodOptional<z.ZodNumber>;
54
62
  border_width_token: z.ZodOptional<z.ZodString>;
63
+ border_top_width: z.ZodOptional<z.ZodNumber>;
64
+ border_right_width: z.ZodOptional<z.ZodNumber>;
65
+ border_bottom_width: z.ZodOptional<z.ZodNumber>;
66
+ border_left_width: z.ZodOptional<z.ZodNumber>;
55
67
  min_height: z.ZodOptional<z.ZodNumber>;
56
68
  min_height_token: z.ZodOptional<z.ZodString>;
57
69
  min_width: z.ZodOptional<z.ZodNumber>;
@@ -62,6 +74,7 @@ export declare const styleSpec: z.ZodObject<{
62
74
  height_token: z.ZodOptional<z.ZodString>;
63
75
  opacity: z.ZodOptional<z.ZodNumber>;
64
76
  opacity_token: z.ZodOptional<z.ZodString>;
77
+ box_shadow: z.ZodOptional<z.ZodString>;
65
78
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
66
79
  bg_color: z.ZodOptional<z.ZodString>;
67
80
  bg_color_token: z.ZodOptional<z.ZodString>;
@@ -77,6 +90,14 @@ export declare const styleSpec: z.ZodObject<{
77
90
  font_weight_token: z.ZodOptional<z.ZodString>;
78
91
  line_height: z.ZodOptional<z.ZodNumber>;
79
92
  line_height_token: z.ZodOptional<z.ZodString>;
93
+ line_height_percent: z.ZodOptional<z.ZodNumber>;
94
+ letter_spacing: z.ZodOptional<z.ZodNumber>;
95
+ letter_spacing_token: z.ZodOptional<z.ZodString>;
96
+ letter_spacing_percent: z.ZodOptional<z.ZodNumber>;
97
+ text_align: z.ZodOptional<z.ZodString>;
98
+ text_decoration: z.ZodOptional<z.ZodString>;
99
+ text_transform: z.ZodOptional<z.ZodString>;
100
+ text_style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
80
101
  padding: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
81
102
  top: z.ZodOptional<z.ZodNumber>;
82
103
  right: z.ZodOptional<z.ZodNumber>;
@@ -111,10 +132,14 @@ export declare const styleSpec: z.ZodObject<{
111
132
  left?: number | undefined;
112
133
  }>]>>;
113
134
  margin_token: z.ZodOptional<z.ZodString>;
114
- border_radius: z.ZodOptional<z.ZodNumber>;
135
+ border_radius: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodArray<z.ZodNumber, "many">]>>;
115
136
  border_radius_token: z.ZodOptional<z.ZodString>;
116
137
  border_width: z.ZodOptional<z.ZodNumber>;
117
138
  border_width_token: z.ZodOptional<z.ZodString>;
139
+ border_top_width: z.ZodOptional<z.ZodNumber>;
140
+ border_right_width: z.ZodOptional<z.ZodNumber>;
141
+ border_bottom_width: z.ZodOptional<z.ZodNumber>;
142
+ border_left_width: z.ZodOptional<z.ZodNumber>;
118
143
  min_height: z.ZodOptional<z.ZodNumber>;
119
144
  min_height_token: z.ZodOptional<z.ZodString>;
120
145
  min_width: z.ZodOptional<z.ZodNumber>;
@@ -125,6 +150,7 @@ export declare const styleSpec: z.ZodObject<{
125
150
  height_token: z.ZodOptional<z.ZodString>;
126
151
  opacity: z.ZodOptional<z.ZodNumber>;
127
152
  opacity_token: z.ZodOptional<z.ZodString>;
153
+ box_shadow: z.ZodOptional<z.ZodString>;
128
154
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
129
155
  bg_color: z.ZodOptional<z.ZodString>;
130
156
  bg_color_token: z.ZodOptional<z.ZodString>;
@@ -140,6 +166,14 @@ export declare const styleSpec: z.ZodObject<{
140
166
  font_weight_token: z.ZodOptional<z.ZodString>;
141
167
  line_height: z.ZodOptional<z.ZodNumber>;
142
168
  line_height_token: z.ZodOptional<z.ZodString>;
169
+ line_height_percent: z.ZodOptional<z.ZodNumber>;
170
+ letter_spacing: z.ZodOptional<z.ZodNumber>;
171
+ letter_spacing_token: z.ZodOptional<z.ZodString>;
172
+ letter_spacing_percent: z.ZodOptional<z.ZodNumber>;
173
+ text_align: z.ZodOptional<z.ZodString>;
174
+ text_decoration: z.ZodOptional<z.ZodString>;
175
+ text_transform: z.ZodOptional<z.ZodString>;
176
+ text_style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
143
177
  padding: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
144
178
  top: z.ZodOptional<z.ZodNumber>;
145
179
  right: z.ZodOptional<z.ZodNumber>;
@@ -174,10 +208,14 @@ export declare const styleSpec: z.ZodObject<{
174
208
  left?: number | undefined;
175
209
  }>]>>;
176
210
  margin_token: z.ZodOptional<z.ZodString>;
177
- border_radius: z.ZodOptional<z.ZodNumber>;
211
+ border_radius: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodArray<z.ZodNumber, "many">]>>;
178
212
  border_radius_token: z.ZodOptional<z.ZodString>;
179
213
  border_width: z.ZodOptional<z.ZodNumber>;
180
214
  border_width_token: z.ZodOptional<z.ZodString>;
215
+ border_top_width: z.ZodOptional<z.ZodNumber>;
216
+ border_right_width: z.ZodOptional<z.ZodNumber>;
217
+ border_bottom_width: z.ZodOptional<z.ZodNumber>;
218
+ border_left_width: z.ZodOptional<z.ZodNumber>;
181
219
  min_height: z.ZodOptional<z.ZodNumber>;
182
220
  min_height_token: z.ZodOptional<z.ZodString>;
183
221
  min_width: z.ZodOptional<z.ZodNumber>;
@@ -188,5 +226,158 @@ export declare const styleSpec: z.ZodObject<{
188
226
  height_token: z.ZodOptional<z.ZodString>;
189
227
  opacity: z.ZodOptional<z.ZodNumber>;
190
228
  opacity_token: z.ZodOptional<z.ZodString>;
229
+ box_shadow: z.ZodOptional<z.ZodString>;
230
+ }, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{
231
+ bg_color: z.ZodOptional<z.ZodString>;
232
+ bg_color_token: z.ZodOptional<z.ZodString>;
233
+ text_color: z.ZodOptional<z.ZodString>;
234
+ text_color_token: z.ZodOptional<z.ZodString>;
235
+ border_color: z.ZodOptional<z.ZodString>;
236
+ border_color_token: z.ZodOptional<z.ZodString>;
237
+ font_family: z.ZodOptional<z.ZodString>;
238
+ font_family_token: z.ZodOptional<z.ZodString>;
239
+ font_size: z.ZodOptional<z.ZodNumber>;
240
+ font_size_token: z.ZodOptional<z.ZodString>;
241
+ font_weight: z.ZodOptional<z.ZodNumber>;
242
+ font_weight_token: z.ZodOptional<z.ZodString>;
243
+ line_height: z.ZodOptional<z.ZodNumber>;
244
+ line_height_token: z.ZodOptional<z.ZodString>;
245
+ line_height_percent: z.ZodOptional<z.ZodNumber>;
246
+ letter_spacing: z.ZodOptional<z.ZodNumber>;
247
+ letter_spacing_token: z.ZodOptional<z.ZodString>;
248
+ letter_spacing_percent: z.ZodOptional<z.ZodNumber>;
249
+ text_align: z.ZodOptional<z.ZodString>;
250
+ text_decoration: z.ZodOptional<z.ZodString>;
251
+ text_transform: z.ZodOptional<z.ZodString>;
252
+ text_style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
253
+ padding: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
254
+ top: z.ZodOptional<z.ZodNumber>;
255
+ right: z.ZodOptional<z.ZodNumber>;
256
+ bottom: z.ZodOptional<z.ZodNumber>;
257
+ left: z.ZodOptional<z.ZodNumber>;
258
+ }, "strip", z.ZodTypeAny, {
259
+ top?: number | undefined;
260
+ right?: number | undefined;
261
+ bottom?: number | undefined;
262
+ left?: number | undefined;
263
+ }, {
264
+ top?: number | undefined;
265
+ right?: number | undefined;
266
+ bottom?: number | undefined;
267
+ left?: number | undefined;
268
+ }>]>>;
269
+ padding_token: z.ZodOptional<z.ZodString>;
270
+ margin: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
271
+ top: z.ZodOptional<z.ZodNumber>;
272
+ right: z.ZodOptional<z.ZodNumber>;
273
+ bottom: z.ZodOptional<z.ZodNumber>;
274
+ left: z.ZodOptional<z.ZodNumber>;
275
+ }, "strip", z.ZodTypeAny, {
276
+ top?: number | undefined;
277
+ right?: number | undefined;
278
+ bottom?: number | undefined;
279
+ left?: number | undefined;
280
+ }, {
281
+ top?: number | undefined;
282
+ right?: number | undefined;
283
+ bottom?: number | undefined;
284
+ left?: number | undefined;
285
+ }>]>>;
286
+ margin_token: z.ZodOptional<z.ZodString>;
287
+ border_radius: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodArray<z.ZodNumber, "many">]>>;
288
+ border_radius_token: z.ZodOptional<z.ZodString>;
289
+ border_width: z.ZodOptional<z.ZodNumber>;
290
+ border_width_token: z.ZodOptional<z.ZodString>;
291
+ border_top_width: z.ZodOptional<z.ZodNumber>;
292
+ border_right_width: z.ZodOptional<z.ZodNumber>;
293
+ border_bottom_width: z.ZodOptional<z.ZodNumber>;
294
+ border_left_width: z.ZodOptional<z.ZodNumber>;
295
+ min_height: z.ZodOptional<z.ZodNumber>;
296
+ min_height_token: z.ZodOptional<z.ZodString>;
297
+ min_width: z.ZodOptional<z.ZodNumber>;
298
+ min_width_token: z.ZodOptional<z.ZodString>;
299
+ width: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
300
+ width_token: z.ZodOptional<z.ZodString>;
301
+ height: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
302
+ height_token: z.ZodOptional<z.ZodString>;
303
+ opacity: z.ZodOptional<z.ZodNumber>;
304
+ opacity_token: z.ZodOptional<z.ZodString>;
305
+ box_shadow: z.ZodOptional<z.ZodString>;
306
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
307
+ bg_color: z.ZodOptional<z.ZodString>;
308
+ bg_color_token: z.ZodOptional<z.ZodString>;
309
+ text_color: z.ZodOptional<z.ZodString>;
310
+ text_color_token: z.ZodOptional<z.ZodString>;
311
+ border_color: z.ZodOptional<z.ZodString>;
312
+ border_color_token: z.ZodOptional<z.ZodString>;
313
+ font_family: z.ZodOptional<z.ZodString>;
314
+ font_family_token: z.ZodOptional<z.ZodString>;
315
+ font_size: z.ZodOptional<z.ZodNumber>;
316
+ font_size_token: z.ZodOptional<z.ZodString>;
317
+ font_weight: z.ZodOptional<z.ZodNumber>;
318
+ font_weight_token: z.ZodOptional<z.ZodString>;
319
+ line_height: z.ZodOptional<z.ZodNumber>;
320
+ line_height_token: z.ZodOptional<z.ZodString>;
321
+ line_height_percent: z.ZodOptional<z.ZodNumber>;
322
+ letter_spacing: z.ZodOptional<z.ZodNumber>;
323
+ letter_spacing_token: z.ZodOptional<z.ZodString>;
324
+ letter_spacing_percent: z.ZodOptional<z.ZodNumber>;
325
+ text_align: z.ZodOptional<z.ZodString>;
326
+ text_decoration: z.ZodOptional<z.ZodString>;
327
+ text_transform: z.ZodOptional<z.ZodString>;
328
+ text_style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
329
+ padding: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
330
+ top: z.ZodOptional<z.ZodNumber>;
331
+ right: z.ZodOptional<z.ZodNumber>;
332
+ bottom: z.ZodOptional<z.ZodNumber>;
333
+ left: z.ZodOptional<z.ZodNumber>;
334
+ }, "strip", z.ZodTypeAny, {
335
+ top?: number | undefined;
336
+ right?: number | undefined;
337
+ bottom?: number | undefined;
338
+ left?: number | undefined;
339
+ }, {
340
+ top?: number | undefined;
341
+ right?: number | undefined;
342
+ bottom?: number | undefined;
343
+ left?: number | undefined;
344
+ }>]>>;
345
+ padding_token: z.ZodOptional<z.ZodString>;
346
+ margin: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodObject<{
347
+ top: z.ZodOptional<z.ZodNumber>;
348
+ right: z.ZodOptional<z.ZodNumber>;
349
+ bottom: z.ZodOptional<z.ZodNumber>;
350
+ left: z.ZodOptional<z.ZodNumber>;
351
+ }, "strip", z.ZodTypeAny, {
352
+ top?: number | undefined;
353
+ right?: number | undefined;
354
+ bottom?: number | undefined;
355
+ left?: number | undefined;
356
+ }, {
357
+ top?: number | undefined;
358
+ right?: number | undefined;
359
+ bottom?: number | undefined;
360
+ left?: number | undefined;
361
+ }>]>>;
362
+ margin_token: z.ZodOptional<z.ZodString>;
363
+ border_radius: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodArray<z.ZodNumber, "many">]>>;
364
+ border_radius_token: z.ZodOptional<z.ZodString>;
365
+ border_width: z.ZodOptional<z.ZodNumber>;
366
+ border_width_token: z.ZodOptional<z.ZodString>;
367
+ border_top_width: z.ZodOptional<z.ZodNumber>;
368
+ border_right_width: z.ZodOptional<z.ZodNumber>;
369
+ border_bottom_width: z.ZodOptional<z.ZodNumber>;
370
+ border_left_width: z.ZodOptional<z.ZodNumber>;
371
+ min_height: z.ZodOptional<z.ZodNumber>;
372
+ min_height_token: z.ZodOptional<z.ZodString>;
373
+ min_width: z.ZodOptional<z.ZodNumber>;
374
+ min_width_token: z.ZodOptional<z.ZodString>;
375
+ width: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
376
+ width_token: z.ZodOptional<z.ZodString>;
377
+ height: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
378
+ height_token: z.ZodOptional<z.ZodString>;
379
+ opacity: z.ZodOptional<z.ZodNumber>;
380
+ opacity_token: z.ZodOptional<z.ZodString>;
381
+ box_shadow: z.ZodOptional<z.ZodString>;
191
382
  }, z.ZodTypeAny, "passthrough">>;
192
383
  export type StyleSpec = z.infer<typeof styleSpec>;
@@ -28,6 +28,15 @@ exports.styleSpec = zod_1.z.object({
28
28
  font_weight_token: dtcgTokenPath.optional(),
29
29
  line_height: zod_1.z.number().optional(),
30
30
  line_height_token: dtcgTokenPath.optional(),
31
+ line_height_percent: zod_1.z.number().optional(),
32
+ letter_spacing: zod_1.z.number().optional(),
33
+ letter_spacing_token: dtcgTokenPath.optional(),
34
+ letter_spacing_percent: zod_1.z.number().optional(),
35
+ text_align: zod_1.z.string().optional(),
36
+ text_decoration: zod_1.z.string().optional(),
37
+ text_transform: zod_1.z.string().optional(),
38
+ // ── Nested text_style (for composition children) ──
39
+ text_style: zod_1.z.record(zod_1.z.any()).optional(),
31
40
  // ── Spacing Properties ──
32
41
  padding: zod_1.z.union([
33
42
  zod_1.z.number(),
@@ -50,10 +59,14 @@ exports.styleSpec = zod_1.z.object({
50
59
  ]).optional(),
51
60
  margin_token: dtcgTokenPath.optional(),
52
61
  // ── Border Properties ──
53
- border_radius: zod_1.z.number().optional(),
62
+ border_radius: zod_1.z.union([zod_1.z.number(), zod_1.z.array(zod_1.z.number())]).optional(),
54
63
  border_radius_token: dtcgTokenPath.optional(),
55
64
  border_width: zod_1.z.number().optional(),
56
65
  border_width_token: dtcgTokenPath.optional(),
66
+ border_top_width: zod_1.z.number().optional(),
67
+ border_right_width: zod_1.z.number().optional(),
68
+ border_bottom_width: zod_1.z.number().optional(),
69
+ border_left_width: zod_1.z.number().optional(),
57
70
  // ── Dimension Properties ──
58
71
  min_height: zod_1.z.number().optional(),
59
72
  min_height_token: dtcgTokenPath.optional(),
@@ -63,7 +76,69 @@ exports.styleSpec = zod_1.z.object({
63
76
  width_token: dtcgTokenPath.optional(),
64
77
  height: zod_1.z.union([zod_1.z.number(), zod_1.z.string()]).optional(),
65
78
  height_token: dtcgTokenPath.optional(),
66
- // ── Opacity ──
79
+ // ── Visual ──
67
80
  opacity: zod_1.z.number().min(0).max(1).optional(),
68
81
  opacity_token: dtcgTokenPath.optional(),
69
- }).passthrough(); // Allow vendor extensions (§2.9)
82
+ box_shadow: zod_1.z.string().optional(),
83
+ }).passthrough().superRefine((data, ctx) => {
84
+ // Fail-Closed Governance: If a literal style value exists, its corresponding token MUST exist.
85
+ const rules = [
86
+ { literal: 'bg_color', token: 'bg_color_token' },
87
+ { literal: 'text_color', token: 'text_color_token' },
88
+ { literal: 'border_color', token: 'border_color_token' },
89
+ { literal: 'font_family', token: 'font_family_token' },
90
+ { literal: 'font_size', token: 'font_size_token' },
91
+ { literal: 'font_weight', token: 'font_weight_token' },
92
+ { literal: 'line_height', token: 'line_height_token' },
93
+ { literal: 'line_height_percent', token: 'line_height_token' },
94
+ { literal: 'letter_spacing', token: 'letter_spacing_token' },
95
+ { literal: 'letter_spacing_percent', token: 'letter_spacing_token' },
96
+ { literal: 'padding', token: 'padding_token' },
97
+ { literal: 'margin', token: 'margin_token' },
98
+ { literal: 'border_radius', token: 'border_radius_token' },
99
+ { literal: 'border_width', token: 'border_width_token' },
100
+ { literal: 'border_top_width', token: 'border_width_token' },
101
+ { literal: 'border_right_width', token: 'border_width_token' },
102
+ { literal: 'border_bottom_width', token: 'border_width_token' },
103
+ { literal: 'border_left_width', token: 'border_width_token' }
104
+ ];
105
+ rules.forEach(({ literal, token }) => {
106
+ const val = data[literal];
107
+ if (val !== undefined && data[token] === undefined) {
108
+ // EXEMPTION: Border widths of 0 or 1 do not require token binding
109
+ if (literal.includes('border_width') || literal.includes('border_top_width') || literal.includes('border_right_width') || literal.includes('border_bottom_width') || literal.includes('border_left_width')) {
110
+ if (val === 0 || val === 1)
111
+ return;
112
+ }
113
+ ctx.addIssue({
114
+ code: zod_1.z.ZodIssueCode.custom,
115
+ message: `Fail-Closed Governance: Unbound Literal Value. Element declares [${literal}] but is missing [${token}]. Hardcoded visual styles are rejected by the design system.`,
116
+ path: [literal],
117
+ });
118
+ }
119
+ });
120
+ // Also validate nested text_style if present
121
+ if (data.text_style && typeof data.text_style === 'object') {
122
+ const ts = data.text_style;
123
+ const textRules = [
124
+ { literal: 'text_color', token: 'text_color_token' },
125
+ { literal: 'font_family', token: 'font_family_token' },
126
+ { literal: 'font_size', token: 'font_size_token' },
127
+ { literal: 'font_weight', token: 'font_weight_token' },
128
+ { literal: 'line_height', token: 'line_height_token' },
129
+ { literal: 'line_height_percent', token: 'line_height_token' },
130
+ { literal: 'letter_spacing', token: 'letter_spacing_token' },
131
+ { literal: 'letter_spacing_percent', token: 'letter_spacing_token' },
132
+ ];
133
+ textRules.forEach(({ literal, token }) => {
134
+ if (ts[literal] !== undefined && ts[token] === undefined) {
135
+ ctx.addIssue({
136
+ code: zod_1.z.ZodIssueCode.custom,
137
+ message: `Fail-Closed Governance: Unbound Literal Value. text_style declares [${literal}] but is missing [${token}]. Hardcoded visual styles are rejected.`,
138
+ path: ['text_style', literal],
139
+ });
140
+ }
141
+ });
142
+ }
143
+ return true;
144
+ }); // Allow vendor extensions (§2.9)
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  export declare const surfaceSpec: z.ZodObject<{
3
3
  id: z.ZodString;
4
+ name: z.ZodOptional<z.ZodString>;
4
5
  root: z.ZodType<any, z.ZodTypeDef, any>;
5
6
  telemetry: z.ZodObject<{
6
7
  emit: z.ZodArray<z.ZodString, "many">;
@@ -11,29 +12,23 @@ export declare const surfaceSpec: z.ZodObject<{
11
12
  }>;
12
13
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
13
14
  environment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
14
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
15
- id: z.ZodString;
16
- root: z.ZodType<any, z.ZodTypeDef, any>;
17
- telemetry: z.ZodObject<{
18
- emit: z.ZodArray<z.ZodString, "many">;
19
- }, "strip", z.ZodTypeAny, {
20
- emit: string[];
21
- }, {
22
- emit: string[];
23
- }>;
24
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
25
- environment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
26
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
27
- id: z.ZodString;
28
- root: z.ZodType<any, z.ZodTypeDef, any>;
29
- telemetry: z.ZodObject<{
30
- emit: z.ZodArray<z.ZodString, "many">;
31
- }, "strip", z.ZodTypeAny, {
15
+ }, "strict", z.ZodTypeAny, {
16
+ id: string;
17
+ telemetry: {
32
18
  emit: string[];
33
- }, {
19
+ };
20
+ name?: string | undefined;
21
+ root?: any;
22
+ metadata?: Record<string, any> | undefined;
23
+ environment?: Record<string, any> | undefined;
24
+ }, {
25
+ id: string;
26
+ telemetry: {
34
27
  emit: string[];
35
- }>;
36
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
37
- environment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
38
- }, z.ZodTypeAny, "passthrough">>;
28
+ };
29
+ name?: string | undefined;
30
+ root?: any;
31
+ metadata?: Record<string, any> | undefined;
32
+ environment?: Record<string, any> | undefined;
33
+ }>;
39
34
  export type SurfaceSpec = z.infer<typeof surfaceSpec>;
@@ -12,8 +12,9 @@ const telemetry_1 = require("./telemetry");
12
12
  // root level; it must be contained within a Composition.
13
13
  exports.surfaceSpec = zod_1.z.object({
14
14
  id: zod_1.z.string().min(1).regex(/^[A-Za-z][A-Za-z0-9_.:-]{0,127}$/),
15
+ name: zod_1.z.string().optional(),
15
16
  root: composition_1.compositionSpec,
16
17
  telemetry: telemetry_1.telemetrySpec,
17
18
  metadata: zod_1.z.record(zod_1.z.any()).optional(),
18
19
  environment: zod_1.z.record(zod_1.z.any()).optional(),
19
- }).passthrough();
20
+ }).strict();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "desen-core",
3
- "version": "1.0.0-draft.3",
3
+ "version": "1.0.0-draft.31",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -8,6 +8,7 @@ export const bindingSourceEnum = z.enum([
8
8
  "backend",
9
9
  "local",
10
10
  "feature_flag",
11
+ "sensor",
11
12
  ]);
12
13
 
13
14
  // ─── bindingSpec ─────────────────────────────────────────────────
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { modifiersSpec, bindingSpec } from "./binding";
3
3
  import { telemetrySpec } from "./telemetry";
4
+ import { styleSpec } from "./style";
4
5
 
5
6
  // ─── Forward-declare recursive types ─────────────────────────────
6
7
  // TypeScript needs explicit type annotations for circular schemas.
@@ -17,15 +18,58 @@ export const positioningSpec = z.object({
17
18
  type: z.enum(["relative", "sticky", "absolute"]),
18
19
  });
19
20
 
21
+ const dtcgTokenPath = z.string().min(1);
22
+
20
23
  // ─── layoutSpec ──────────────────────────────────────────────────
21
24
  // SPEC.md §2.3: kind REQUIRED, rest optional
22
25
  export const layoutSpec = z.object({
23
26
  kind: z.enum(["stack", "grid"]),
24
27
  direction: z.enum(["vertical", "horizontal"]).optional(),
25
- gap: z.number().min(0).optional(),
28
+ gap: z.number().optional(),
29
+ gap_token: dtcgTokenPath.optional(),
26
30
  columns: z.number().int().min(1).optional(),
27
31
  align: z.enum(["start", "center", "end", "stretch"]).optional(),
32
+ align_content: z.enum(["start", "center", "end", "space-between", "space-around", "stretch"]).optional(),
33
+ align_items: z.enum(["start", "center", "end", "stretch"]).optional(),
34
+ padding: z.object({
35
+ top: z.number().optional(),
36
+ right: z.number().optional(),
37
+ bottom: z.number().optional(),
38
+ left: z.number().optional()
39
+ }).strict().optional(),
40
+ padding_token: dtcgTokenPath.optional(),
41
+ sizing_h: z.enum(["hug", "fill", "fixed"]).optional(),
42
+ sizing_v: z.enum(["hug", "fill", "fixed"]).optional(),
28
43
  positioning: positioningSpec.optional(),
44
+ }).strict().superRefine((data, ctx) => {
45
+ // Fail-Closed Governance: Enforce tokens for spacing values if literal exists and > 0.
46
+ const rules = [
47
+ { literal: 'gap', token: 'gap_token' },
48
+ { literal: 'padding', token: 'padding_token' }
49
+ ];
50
+
51
+ rules.forEach(({ literal, token }) => {
52
+ const literalValue = data[literal as keyof typeof data];
53
+ // Only enforce token if literal is actually providing a >0 spacing value.
54
+ // E.g. gap: 0 or padding: 0 object is generally fine to pass through without tracking.
55
+ let isSignificantValue = false;
56
+
57
+ if (typeof literalValue === 'number') {
58
+ isSignificantValue = literalValue > 0;
59
+ } else if (literalValue && typeof literalValue === 'object') {
60
+ isSignificantValue = Object.values(literalValue).some(v => typeof v === 'number' && v > 0);
61
+ }
62
+
63
+ if (isSignificantValue && data[token as keyof typeof data] === undefined) {
64
+ ctx.addIssue({
65
+ code: z.ZodIssueCode.custom,
66
+ message: `Fail-Closed Governance: Unbound Spacing Value. Layout declares physical [${literal}] but is missing [${token}]. Hardcoded layouts are rejected.`,
67
+ path: [literal],
68
+ });
69
+ }
70
+ });
71
+
72
+ return true;
29
73
  });
30
74
 
31
75
  // ─── Composition types ───────────────────────────────────────────
@@ -84,7 +128,14 @@ export const nodeSpec: z.ZodType<NodeSpec> = z.lazy(() =>
84
128
  const elementSpecInternal = z.object({
85
129
  type: z.string().min(1),
86
130
  id: z.string().min(1),
87
- props: z.record(z.any()),
131
+ name: z.string().optional(),
132
+ props: z.object({
133
+ style: styleSpec.optional(),
134
+ layout: layoutSpec.optional(),
135
+ action: z.any().optional(),
136
+ text: z.string().optional(),
137
+ src: z.string().optional(),
138
+ }).passthrough().optional(),
88
139
  constraints: constraintsSpec,
89
140
  modifiers: modifiersSpec.optional(),
90
141
  telemetry: telemetrySpec.optional(),
@@ -92,10 +143,6 @@ const elementSpecInternal = z.object({
92
143
  .refine(
93
144
  (data) => !("children" in data),
94
145
  { message: "ElementSpec MUST NOT contain 'children'. Use CompositionSpec for containers." }
95
- )
96
- .refine(
97
- (data) => !("layout" in data),
98
- { message: "ElementSpec MUST NOT contain 'layout'. Use CompositionSpec for layout." }
99
146
  );
100
147
 
101
148
  // ─── CompositionSpec ─────────────────────────────────────────────
@@ -104,12 +151,14 @@ export const compositionSpec: z.ZodType<any> = z.lazy(() =>
104
151
  z.object({
105
152
  type: compositionTypeEnum,
106
153
  id: z.string().min(1).regex(/^[A-Za-z][A-Za-z0-9_.:-]{0,127}$/),
154
+ name: z.string().optional(),
107
155
  layout: layoutSpec,
156
+ style: styleSpec.optional(),
108
157
  children: z.array(nodeSpec).min(0),
109
158
  constraints: constraintsSpec,
110
159
  modifiers: modifiersSpec.optional(),
111
160
  telemetry: telemetrySpec,
112
- }).passthrough()
161
+ }).strict()
113
162
  );
114
163
 
115
164
  // ─── RepeaterSpec ────────────────────────────────────────────────
@@ -119,13 +168,14 @@ export const repeaterSpec: z.ZodType<any> = z.lazy(() =>
119
168
  z.object({
120
169
  type: z.literal("Repeater"),
121
170
  id: z.string().min(1),
171
+ name: z.string().optional(),
122
172
  data: z.object({
123
173
  bind: bindingSpec,
124
174
  }),
125
175
  template: nodeSpec,
126
176
  modifiers: modifiersSpec.optional(),
127
177
  telemetry: telemetrySpec,
128
- }).passthrough()
178
+ }).strict()
129
179
  );
130
180
 
131
181
  // ─── Types ───────────────────────────────────────────────────────
@@ -11,6 +11,7 @@ import { telemetrySpec } from "./telemetry";
11
11
  export const elementSpec = z.object({
12
12
  type: z.string().min(1),
13
13
  id: z.string().min(1),
14
+ name: z.string().optional(),
14
15
  props: z.record(z.any()),
15
16
  constraints: z.object({
16
17
  a11y: z.object({