@objectstack/sdui-parser 11.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/dist/index.mjs ADDED
@@ -0,0 +1,489 @@
1
+ // src/parse.ts
2
+ var EVENT_ATTR = /^on[A-Z]/;
3
+ var FORBIDDEN_ATTRS = /* @__PURE__ */ new Set(["dangerouslySetInnerHTML", "ref", "key"]);
4
+ function parseJsx(source, options = {}) {
5
+ return new Parser(source, options).parseDocument();
6
+ }
7
+ var isNameStart = (c) => /[A-Za-z]/.test(c);
8
+ var isNameChar = (c) => /[A-Za-z0-9:_-]/.test(c);
9
+ var Parser = class {
10
+ constructor(src, opts) {
11
+ this.src = src;
12
+ this.opts = opts;
13
+ this.pos = 0;
14
+ this.diagnostics = [];
15
+ }
16
+ parseDocument() {
17
+ this.skipTrivia();
18
+ if (this.peek() !== "<") {
19
+ this.error("no-root", "Expected a single root element");
20
+ return { tree: null, diagnostics: this.diagnostics };
21
+ }
22
+ const tree = this.parseElement();
23
+ this.skipTrivia();
24
+ if (tree && this.pos < this.src.length) {
25
+ this.error("multiple-roots", "A page must have exactly one root element", this.pos);
26
+ }
27
+ return { tree, diagnostics: this.diagnostics };
28
+ }
29
+ parseElement() {
30
+ const start = this.pos;
31
+ if (!this.eat("<")) {
32
+ this.error("expected-element", 'Expected "<"', start);
33
+ return null;
34
+ }
35
+ const tag = this.readName();
36
+ if (!tag) {
37
+ this.error("bad-tag", 'Expected a tag name after "<"', start);
38
+ return null;
39
+ }
40
+ if (this.opts.allowedTags && !this.opts.allowedTags.has(tag)) {
41
+ this.error("forbidden-tag", `<${tag}> is not an allowed component`, start, tag);
42
+ }
43
+ const props = {};
44
+ for (; ; ) {
45
+ this.skipWs();
46
+ const c = this.peek();
47
+ if (c === "" || c === ">" || c === "/") break;
48
+ const attr = this.parseAttr(start, tag);
49
+ if (!attr) break;
50
+ props[attr.name] = attr.value;
51
+ }
52
+ this.skipWs();
53
+ let children;
54
+ if (this.eat("/")) {
55
+ if (!this.eat(">")) this.error("bad-self-close", `Malformed self-closing <${tag}>`, this.pos, tag);
56
+ } else if (this.eat(">")) {
57
+ children = this.parseChildren(tag);
58
+ } else {
59
+ this.error("unterminated-open-tag", `Unterminated <${tag}> open tag`, start, tag);
60
+ }
61
+ const node = { type: tag, ...props };
62
+ if (children && children.length) node.children = children;
63
+ return node;
64
+ }
65
+ parseAttr(elStart, tag) {
66
+ const name = this.readName();
67
+ if (!name) {
68
+ this.error("bad-attr", `Malformed attribute on <${tag}>`, this.pos, tag);
69
+ this.pos++;
70
+ return null;
71
+ }
72
+ this.skipWs();
73
+ let value = true;
74
+ if (this.eat("=")) {
75
+ this.skipWs();
76
+ value = this.parseAttrValue(tag);
77
+ }
78
+ if (EVENT_ATTR.test(name) || FORBIDDEN_ATTRS.has(name)) {
79
+ this.error("forbidden-attr", `Attribute "${name}" is not allowed on <${tag}>`, elStart, tag);
80
+ return { name: `__forbidden_${name}`, value: void 0 };
81
+ }
82
+ return { name, value };
83
+ }
84
+ parseAttrValue(tag) {
85
+ const c = this.peek();
86
+ if (c === '"' || c === "'") return this.readString(c);
87
+ if (c === "{") return interpretBrace(this.readBraced());
88
+ this.error("bad-attr-value", `Expected an attribute value on <${tag}>`, this.pos, tag);
89
+ return void 0;
90
+ }
91
+ parseChildren(parentTag) {
92
+ const children = [];
93
+ for (; ; ) {
94
+ if (this.pos >= this.src.length) {
95
+ this.error("unclosed-element", `Unclosed <${parentTag}>`, this.pos, parentTag);
96
+ break;
97
+ }
98
+ if (this.src.startsWith("</", this.pos)) {
99
+ this.pos += 2;
100
+ this.skipWs();
101
+ const close = this.readName();
102
+ this.skipWs();
103
+ this.eat(">");
104
+ if (close !== parentTag) {
105
+ this.error("mismatched-tag", `Expected </${parentTag}> but found </${close}>`, this.pos, parentTag);
106
+ }
107
+ break;
108
+ }
109
+ if (this.src.startsWith("{/*", this.pos)) {
110
+ const end = this.src.indexOf("*/}", this.pos);
111
+ if (end === -1) {
112
+ this.error("unclosed-comment", "Unclosed comment", this.pos);
113
+ this.pos = this.src.length;
114
+ } else {
115
+ this.pos = end + 3;
116
+ }
117
+ continue;
118
+ }
119
+ if (this.peek() === "<") {
120
+ const el = this.parseElement();
121
+ if (el) children.push(el);
122
+ continue;
123
+ }
124
+ if (this.peek() === "{") {
125
+ const start = this.pos;
126
+ this.readBraced();
127
+ this.error(
128
+ "expression-child",
129
+ "Inline {expression} children are not supported yet \u2014 bind via a component prop",
130
+ start
131
+ );
132
+ continue;
133
+ }
134
+ const text = this.readTextRun();
135
+ const trimmed = text.replace(/\s+/g, " ").trim();
136
+ if (trimmed) children.push(trimmed);
137
+ }
138
+ return children;
139
+ }
140
+ /* ----------------------------- lexing ----------------------------- */
141
+ peek() {
142
+ return this.pos < this.src.length ? this.src[this.pos] : "";
143
+ }
144
+ eat(ch) {
145
+ if (this.src[this.pos] === ch) {
146
+ this.pos++;
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+ readName() {
152
+ if (!isNameStart(this.peek())) return "";
153
+ const start = this.pos;
154
+ this.pos++;
155
+ while (this.pos < this.src.length && isNameChar(this.src[this.pos])) this.pos++;
156
+ return this.src.slice(start, this.pos);
157
+ }
158
+ readString(quote) {
159
+ this.pos++;
160
+ const start = this.pos;
161
+ while (this.pos < this.src.length && this.src[this.pos] !== quote) this.pos++;
162
+ const value = this.src.slice(start, this.pos);
163
+ if (!this.eat(quote)) this.error("unterminated-string", "Unterminated string literal", start);
164
+ return value;
165
+ }
166
+ /** Reads a balanced `{ ... }` run and returns the inner text (no outer braces). */
167
+ readBraced() {
168
+ const start = this.pos;
169
+ let depth = 0;
170
+ let inStr = null;
171
+ for (; this.pos < this.src.length; this.pos++) {
172
+ const ch = this.src[this.pos];
173
+ if (inStr) {
174
+ if (ch === inStr && this.src[this.pos - 1] !== "\\") inStr = null;
175
+ continue;
176
+ }
177
+ if (ch === '"' || ch === "'") inStr = ch;
178
+ else if (ch === "{") depth++;
179
+ else if (ch === "}") {
180
+ depth--;
181
+ if (depth === 0) {
182
+ const inner = this.src.slice(start + 1, this.pos);
183
+ this.pos++;
184
+ return inner;
185
+ }
186
+ }
187
+ }
188
+ this.error("unterminated-brace", 'Unterminated "{"', start);
189
+ return this.src.slice(start + 1);
190
+ }
191
+ readTextRun() {
192
+ const start = this.pos;
193
+ while (this.pos < this.src.length && this.src[this.pos] !== "<" && this.src[this.pos] !== "{") this.pos++;
194
+ return this.src.slice(start, this.pos);
195
+ }
196
+ skipWs() {
197
+ while (this.pos < this.src.length && /\s/.test(this.src[this.pos])) this.pos++;
198
+ }
199
+ /** whitespace + top-level JSX comments */
200
+ skipTrivia() {
201
+ for (; ; ) {
202
+ this.skipWs();
203
+ if (this.src.startsWith("{/*", this.pos)) {
204
+ const end = this.src.indexOf("*/}", this.pos);
205
+ this.pos = end === -1 ? this.src.length : end + 3;
206
+ continue;
207
+ }
208
+ break;
209
+ }
210
+ }
211
+ error(code, message, start, tag) {
212
+ this.diagnostics.push({ severity: "error", code, message, start: start ?? this.pos, tag });
213
+ }
214
+ };
215
+ function interpretBrace(raw) {
216
+ const trimmed = raw.trim();
217
+ try {
218
+ return JSON.parse(trimmed);
219
+ } catch {
220
+ return { $expr: trimmed };
221
+ }
222
+ }
223
+
224
+ // src/validate.ts
225
+ var BASE_PROPS = /* @__PURE__ */ new Set([
226
+ "type",
227
+ "id",
228
+ "className",
229
+ "style",
230
+ "visible",
231
+ "visibleOn",
232
+ "disabled",
233
+ "disabledOn",
234
+ "children"
235
+ ]);
236
+ var isExpr = (v) => typeof v === "object" && v !== null && "$expr" in v;
237
+ function validateTree(tree, manifest) {
238
+ const diagnostics = [];
239
+ const requires = /* @__PURE__ */ new Set();
240
+ const bindings = [];
241
+ const visit = (node) => {
242
+ if (typeof node === "string") return;
243
+ const comp = manifest.components[node.type];
244
+ if (!comp) {
245
+ diagnostics.push({
246
+ severity: "error",
247
+ code: "unknown-component",
248
+ message: `<${node.type}> is not a known component`,
249
+ tag: node.type
250
+ });
251
+ } else {
252
+ if (comp.namespace) requires.add(comp.namespace);
253
+ const byName = new Map(comp.inputs.map((i) => [i.name, i]));
254
+ for (const input of comp.inputs) {
255
+ if (input.required && !(input.name in node)) {
256
+ diagnostics.push({
257
+ severity: "error",
258
+ code: "missing-required-prop",
259
+ message: `<${node.type}> is missing required prop "${input.name}"`,
260
+ tag: node.type
261
+ });
262
+ }
263
+ }
264
+ for (const [key, value] of Object.entries(node)) {
265
+ if (BASE_PROPS.has(key)) continue;
266
+ const input = byName.get(key);
267
+ if (!input) {
268
+ diagnostics.push({
269
+ severity: "warning",
270
+ code: "unknown-prop",
271
+ message: `<${node.type}> has no prop "${key}"`,
272
+ tag: node.type
273
+ });
274
+ continue;
275
+ }
276
+ if (input.binding) {
277
+ bindings.push({ tag: node.type, input: key, kind: input.binding, value });
278
+ }
279
+ if (!isExpr(value)) {
280
+ const typeDiag = checkType(node.type, input, value);
281
+ if (typeDiag) diagnostics.push(typeDiag);
282
+ }
283
+ }
284
+ if (node.children?.length && !comp.isContainer) {
285
+ diagnostics.push({
286
+ severity: "warning",
287
+ code: "not-a-container",
288
+ message: `<${node.type}> does not accept children`,
289
+ tag: node.type
290
+ });
291
+ }
292
+ }
293
+ if (node.children) node.children.forEach(visit);
294
+ };
295
+ if (tree) visit(tree);
296
+ return { diagnostics, requires: [...requires], bindings };
297
+ }
298
+ function checkType(tag, input, value) {
299
+ const mismatch = (expected) => ({
300
+ severity: "warning",
301
+ code: "type-mismatch",
302
+ message: `<${tag}> prop "${input.name}" expected ${expected}`,
303
+ tag
304
+ });
305
+ switch (input.type) {
306
+ case "number":
307
+ return typeof value === "number" ? null : mismatch("a number");
308
+ case "boolean":
309
+ return typeof value === "boolean" ? null : mismatch("a boolean");
310
+ case "string":
311
+ case "color":
312
+ case "date":
313
+ case "code":
314
+ case "file":
315
+ return typeof value === "string" ? null : mismatch("a string");
316
+ case "array":
317
+ return Array.isArray(value) ? null : mismatch("an array");
318
+ case "object":
319
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? null : mismatch("an object");
320
+ case "enum": {
321
+ const allowed = (input.enum ?? []).map((e) => typeof e === "object" ? e.value : e);
322
+ return allowed.includes(value) ? null : {
323
+ severity: "error",
324
+ code: "invalid-enum",
325
+ message: `<${tag}> prop "${input.name}"=${JSON.stringify(value)} is not one of ${JSON.stringify(allowed)}`,
326
+ tag
327
+ };
328
+ }
329
+ default:
330
+ return null;
331
+ }
332
+ }
333
+
334
+ // src/codegen.ts
335
+ function generateDts(manifest, options = {}) {
336
+ const { standaloneJsx = true } = options;
337
+ const comps = Object.values(manifest.components).sort((a, b) => a.type.localeCompare(b.type));
338
+ const interfaces = comps.map(emitInterface).join("\n\n");
339
+ const intrinsics = comps.map((c) => ` ${JSON.stringify(c.type)}: ${propsName(c.type)};`).join("\n");
340
+ const baseElement = standaloneJsx ? `
341
+ // minimal, so the surface type-checks without pulling React types
342
+ type Element = unknown;
343
+ interface ElementClass {}
344
+ interface ElementAttributesProperty {}
345
+ interface ElementChildrenAttribute { children: object; }` : "";
346
+ return `// AUTO-GENERATED by @object-ui/sdui-parser \u2014 DO NOT EDIT.
347
+ // Source of truth: ComponentRegistry inputs (ADR-0080 \xA73). Regenerate via codegen.
348
+ /* eslint-disable */
349
+
350
+ export interface SduiBaseProps {
351
+ id?: string;
352
+ className?: string;
353
+ style?: Record<string, unknown>;
354
+ visible?: boolean;
355
+ visibleOn?: string;
356
+ disabled?: boolean;
357
+ disabledOn?: string;
358
+ children?: unknown;
359
+ }
360
+
361
+ ${interfaces}
362
+
363
+ declare global {
364
+ namespace JSX {
365
+ interface IntrinsicElements {
366
+ ${intrinsics}
367
+ }${baseElement}
368
+ }
369
+ }
370
+
371
+ export {};
372
+ `;
373
+ }
374
+ function emitInterface(comp) {
375
+ const lines = comp.inputs.filter((i) => i.type !== "slot").map((i) => ` ${propLine(i)}`).join("\n");
376
+ return `export interface ${propsName(comp.type)} extends SduiBaseProps {
377
+ ${lines}
378
+ }`;
379
+ }
380
+ function propLine(input) {
381
+ const opt = input.required ? "" : "?";
382
+ return `${quoteKeyIfNeeded(input.name)}${opt}: ${tsType(input)};`;
383
+ }
384
+ function tsType(input) {
385
+ switch (input.type) {
386
+ case "number":
387
+ return "number";
388
+ case "boolean":
389
+ return "boolean";
390
+ case "array":
391
+ return "unknown[]";
392
+ case "object":
393
+ return "Record<string, unknown>";
394
+ case "enum": {
395
+ const vals = (input.enum ?? []).map((e) => typeof e === "object" ? e.value : e);
396
+ return vals.length ? vals.map((v) => JSON.stringify(v)).join(" | ") : "string";
397
+ }
398
+ case "string":
399
+ case "color":
400
+ case "date":
401
+ case "code":
402
+ case "file":
403
+ default:
404
+ return "string";
405
+ }
406
+ }
407
+ var IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
408
+ var quoteKeyIfNeeded = (name) => IDENT.test(name) ? name : JSON.stringify(name);
409
+ function propsName(type) {
410
+ const pascal = type.split(/[^A-Za-z0-9]+/).filter(Boolean).map((s) => s[0].toUpperCase() + s.slice(1)).join("");
411
+ return `${pascal}Props`;
412
+ }
413
+ function generateBlockList(manifest) {
414
+ const rows = Object.values(manifest.components).sort((a, b) => a.type.localeCompare(b.type)).map((c) => {
415
+ const req = c.inputs.filter((i) => i.required).map((i) => i.name);
416
+ const binds = c.inputs.filter((i) => i.binding).map((i) => `${i.name}:${i.binding}`);
417
+ return `| \`${c.type}\` | ${c.namespace ?? "\u2014"} | ${c.isContainer ? "\u2713" : ""} | ${req.join(", ") || "\u2014"} | ${binds.join(", ") || "\u2014"} |`;
418
+ });
419
+ return [
420
+ `# SDUI public blocks (${Object.keys(manifest.components).length})`,
421
+ "",
422
+ "> Auto-generated from the registry `tier:'public'` set (ADR-0080). Do not edit by hand.",
423
+ "",
424
+ "| block | plugin | container | required props | bindings |",
425
+ "|---|---|---|---|---|",
426
+ ...rows,
427
+ ""
428
+ ].join("\n");
429
+ }
430
+
431
+ // src/index.ts
432
+ function compile(source, manifest) {
433
+ const allowedTags = new Set(Object.keys(manifest.components));
434
+ const parsed = parseJsx(source, { allowedTags });
435
+ const validated = validateTree(parsed.tree, manifest);
436
+ const diagnostics = [...parsed.diagnostics, ...validated.diagnostics];
437
+ return {
438
+ tree: parsed.tree,
439
+ diagnostics,
440
+ requires: validated.requires,
441
+ bindings: validated.bindings,
442
+ ok: !diagnostics.some((d) => d.severity === "error")
443
+ };
444
+ }
445
+ var INPUT_TYPES = /* @__PURE__ */ new Set([
446
+ "string",
447
+ "number",
448
+ "boolean",
449
+ "enum",
450
+ "array",
451
+ "object",
452
+ "color",
453
+ "date",
454
+ "code",
455
+ "file",
456
+ "slot"
457
+ ]);
458
+ function manifestFromConfigs(configs, opts = {}) {
459
+ const components = {};
460
+ for (const c of configs) {
461
+ if (opts.only && !opts.only.has(c.type)) continue;
462
+ if (opts.publicOnly && c.tier !== "public") continue;
463
+ components[c.type] = {
464
+ type: c.type,
465
+ namespace: c.namespace,
466
+ isContainer: c.isContainer,
467
+ inputs: (c.inputs ?? []).map((i) => ({
468
+ name: i.name,
469
+ type: INPUT_TYPES.has(i.type) ? i.type : "string",
470
+ required: i.required,
471
+ enum: i.enum,
472
+ binding: i.binding,
473
+ description: i.description
474
+ }))
475
+ };
476
+ }
477
+ return { components };
478
+ }
479
+ export {
480
+ compile,
481
+ generateBlockList,
482
+ generateDts,
483
+ interpretBrace,
484
+ manifestFromConfigs,
485
+ parseJsx,
486
+ propsName,
487
+ validateTree
488
+ };
489
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/parse.ts","../src/validate.ts","../src/codegen.ts","../src/index.ts"],"sourcesContent":["/**\n * ObjectUI — SDUI JSX-source parser (ADR-0080)\n *\n * A small recursive-descent parser for a CONSTRAINED JSX subset. It is\n * deliberately not a full JS/JSX parser: a bounded grammar is the point\n * (Markdoc model) — it shrinks the attack surface and the expressible-but-wrong\n * space. Output is the existing SDUI `SchemaNode` tree. Nothing is executed.\n *\n * Grammar (informal):\n * document := element (exactly one root)\n * element := openTag child-star closeTag, or a self-closing tag\n * attr := name '=' (string | braced), or a bare name meaning true\n * child := element | text | jsx-block-comment\n * tag := [A-Za-z][A-Za-z0-9:_-]star (matches registry keys)\n */\n\nimport type { Diagnostic, ParseOptions, ParseResult, SchemaElement, SchemaNode } from './types.js';\n\n/** Event handlers and raw-HTML injection are never allowed (parse ≠ execute). */\nconst EVENT_ATTR = /^on[A-Z]/;\nconst FORBIDDEN_ATTRS = new Set(['dangerouslySetInnerHTML', 'ref', 'key']);\n\nexport function parseJsx(source: string, options: ParseOptions = {}): ParseResult {\n return new Parser(source, options).parseDocument();\n}\n\nconst isNameStart = (c: string) => /[A-Za-z]/.test(c);\nconst isNameChar = (c: string) => /[A-Za-z0-9:_-]/.test(c);\n\nclass Parser {\n private pos = 0;\n private readonly diagnostics: Diagnostic[] = [];\n\n constructor(private readonly src: string, private readonly opts: ParseOptions) {}\n\n parseDocument(): ParseResult {\n this.skipTrivia();\n if (this.peek() !== '<') {\n this.error('no-root', 'Expected a single root element');\n return { tree: null, diagnostics: this.diagnostics };\n }\n const tree = this.parseElement();\n this.skipTrivia();\n if (tree && this.pos < this.src.length) {\n this.error('multiple-roots', 'A page must have exactly one root element', this.pos);\n }\n return { tree, diagnostics: this.diagnostics };\n }\n\n private parseElement(): SchemaElement | null {\n const start = this.pos;\n if (!this.eat('<')) {\n this.error('expected-element', 'Expected \"<\"', start);\n return null;\n }\n const tag = this.readName();\n if (!tag) {\n this.error('bad-tag', 'Expected a tag name after \"<\"', start);\n return null;\n }\n if (this.opts.allowedTags && !this.opts.allowedTags.has(tag)) {\n this.error('forbidden-tag', `<${tag}> is not an allowed component`, start, tag);\n }\n\n const props: Record<string, unknown> = {};\n for (;;) {\n this.skipWs();\n const c = this.peek();\n if (c === '' || c === '>' || c === '/') break;\n const attr = this.parseAttr(start, tag);\n if (!attr) break;\n props[attr.name] = attr.value;\n }\n\n this.skipWs();\n let children: SchemaNode[] | undefined;\n if (this.eat('/')) {\n if (!this.eat('>')) this.error('bad-self-close', `Malformed self-closing <${tag}>`, this.pos, tag);\n } else if (this.eat('>')) {\n children = this.parseChildren(tag);\n } else {\n this.error('unterminated-open-tag', `Unterminated <${tag}> open tag`, start, tag);\n }\n\n const node: SchemaElement = { type: tag, ...props };\n if (children && children.length) node.children = children;\n return node;\n }\n\n private parseAttr(elStart: number, tag: string): { name: string; value: unknown } | null {\n const name = this.readName();\n if (!name) {\n this.error('bad-attr', `Malformed attribute on <${tag}>`, this.pos, tag);\n // skip one char to avoid an infinite loop on garbage\n this.pos++;\n return null;\n }\n this.skipWs();\n let value: unknown = true; // bare attribute => boolean true\n if (this.eat('=')) {\n this.skipWs();\n value = this.parseAttrValue(tag);\n }\n if (EVENT_ATTR.test(name) || FORBIDDEN_ATTRS.has(name)) {\n this.error('forbidden-attr', `Attribute \"${name}\" is not allowed on <${tag}>`, elStart, tag);\n return { name: `__forbidden_${name}`, value: undefined };\n }\n return { name, value };\n }\n\n private parseAttrValue(tag: string): unknown {\n const c = this.peek();\n if (c === '\"' || c === \"'\") return this.readString(c);\n if (c === '{') return interpretBrace(this.readBraced());\n this.error('bad-attr-value', `Expected an attribute value on <${tag}>`, this.pos, tag);\n return undefined;\n }\n\n private parseChildren(parentTag: string): SchemaNode[] {\n const children: SchemaNode[] = [];\n for (;;) {\n if (this.pos >= this.src.length) {\n this.error('unclosed-element', `Unclosed <${parentTag}>`, this.pos, parentTag);\n break;\n }\n // closing tag\n if (this.src.startsWith('</', this.pos)) {\n this.pos += 2;\n this.skipWs();\n const close = this.readName();\n this.skipWs();\n this.eat('>');\n if (close !== parentTag) {\n this.error('mismatched-tag', `Expected </${parentTag}> but found </${close}>`, this.pos, parentTag);\n }\n break;\n }\n // JSX comment {/* ... */}\n if (this.src.startsWith('{/*', this.pos)) {\n const end = this.src.indexOf('*/}', this.pos);\n if (end === -1) {\n this.error('unclosed-comment', 'Unclosed comment', this.pos);\n this.pos = this.src.length;\n } else {\n this.pos = end + 3;\n }\n continue;\n }\n // nested element\n if (this.peek() === '<') {\n const el = this.parseElement();\n if (el) children.push(el);\n continue;\n }\n // expression child {expr} — out of grammar for v1: skip with a warning\n if (this.peek() === '{') {\n const start = this.pos;\n this.readBraced();\n this.error(\n 'expression-child',\n 'Inline {expression} children are not supported yet — bind via a component prop',\n start,\n );\n continue;\n }\n // text\n const text = this.readTextRun();\n const trimmed = text.replace(/\\s+/g, ' ').trim();\n if (trimmed) children.push(trimmed);\n }\n return children;\n }\n\n /* ----------------------------- lexing ----------------------------- */\n\n private peek(): string {\n return this.pos < this.src.length ? this.src[this.pos] : '';\n }\n\n private eat(ch: string): boolean {\n if (this.src[this.pos] === ch) {\n this.pos++;\n return true;\n }\n return false;\n }\n\n private readName(): string {\n if (!isNameStart(this.peek())) return '';\n const start = this.pos;\n this.pos++;\n while (this.pos < this.src.length && isNameChar(this.src[this.pos])) this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private readString(quote: string): string {\n this.pos++; // opening quote\n const start = this.pos;\n while (this.pos < this.src.length && this.src[this.pos] !== quote) this.pos++;\n const value = this.src.slice(start, this.pos);\n if (!this.eat(quote)) this.error('unterminated-string', 'Unterminated string literal', start);\n return value;\n }\n\n /** Reads a balanced `{ ... }` run and returns the inner text (no outer braces). */\n private readBraced(): string {\n const start = this.pos;\n let depth = 0;\n let inStr: string | null = null;\n for (; this.pos < this.src.length; this.pos++) {\n const ch = this.src[this.pos];\n if (inStr) {\n if (ch === inStr && this.src[this.pos - 1] !== '\\\\') inStr = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") inStr = ch;\n else if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const inner = this.src.slice(start + 1, this.pos);\n this.pos++; // consume closing brace\n return inner;\n }\n }\n }\n this.error('unterminated-brace', 'Unterminated \"{\"', start);\n return this.src.slice(start + 1);\n }\n\n private readTextRun(): string {\n const start = this.pos;\n while (this.pos < this.src.length && this.src[this.pos] !== '<' && this.src[this.pos] !== '{') this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private skipWs(): void {\n while (this.pos < this.src.length && /\\s/.test(this.src[this.pos])) this.pos++;\n }\n\n /** whitespace + top-level JSX comments */\n private skipTrivia(): void {\n for (;;) {\n this.skipWs();\n if (this.src.startsWith('{/*', this.pos)) {\n const end = this.src.indexOf('*/}', this.pos);\n this.pos = end === -1 ? this.src.length : end + 3;\n continue;\n }\n break;\n }\n }\n\n private error(code: string, message: string, start?: number, tag?: string): void {\n this.diagnostics.push({ severity: 'error', code, message, start: start ?? this.pos, tag });\n }\n}\n\n/**\n * Interpret a braced attribute value `{...}`.\n * JSON-literal values (numbers, booleans, null, strings, arrays, objects with\n * quoted keys) are materialized. Anything else is kept as a deferred expression\n * marker `{ $expr }` — typed and validated later, NEVER evaluated here.\n */\nexport function interpretBrace(raw: string): unknown {\n const trimmed = raw.trim();\n try {\n return JSON.parse(trimmed);\n } catch {\n return { $expr: trimmed };\n }\n}\n","/**\n * ObjectUI — SDUI tree validation against the registry manifest (ADR-0080 §3/§6)\n *\n * Shallow, author-time validation: unknown component, unknown/missing prop,\n * wrong coarse type, illegal enum value. Collects `requires` (plugin provenance)\n * and binding sites the SERVER must resolve against object schema (we cannot\n * resolve objects/fields here — that check is framework-side by design).\n */\n\nimport type {\n Diagnostic,\n Manifest,\n ManifestInput,\n SchemaElement,\n SchemaNode,\n ValidationResult,\n} from './types.js';\n\n/** Base props every node may carry (mirrors BaseSchema) — never \"unknown prop\". */\nconst BASE_PROPS = new Set([\n 'type',\n 'id',\n 'className',\n 'style',\n 'visible',\n 'visibleOn',\n 'disabled',\n 'disabledOn',\n 'children',\n]);\n\nconst isExpr = (v: unknown): boolean =>\n typeof v === 'object' && v !== null && '$expr' in (v as Record<string, unknown>);\n\nexport function validateTree(tree: SchemaElement | null, manifest: Manifest): ValidationResult {\n const diagnostics: Diagnostic[] = [];\n const requires = new Set<string>();\n const bindings: ValidationResult['bindings'] = [];\n\n const visit = (node: SchemaNode): void => {\n if (typeof node === 'string') return;\n const comp = manifest.components[node.type];\n if (!comp) {\n diagnostics.push({\n severity: 'error',\n code: 'unknown-component',\n message: `<${node.type}> is not a known component`,\n tag: node.type,\n });\n } else {\n if (comp.namespace) requires.add(comp.namespace);\n const byName = new Map(comp.inputs.map((i) => [i.name, i]));\n\n // required present?\n for (const input of comp.inputs) {\n if (input.required && !(input.name in node)) {\n diagnostics.push({\n severity: 'error',\n code: 'missing-required-prop',\n message: `<${node.type}> is missing required prop \"${input.name}\"`,\n tag: node.type,\n });\n }\n }\n\n // each provided prop\n for (const [key, value] of Object.entries(node)) {\n if (BASE_PROPS.has(key)) continue;\n const input = byName.get(key);\n if (!input) {\n diagnostics.push({\n severity: 'warning',\n code: 'unknown-prop',\n message: `<${node.type}> has no prop \"${key}\"`,\n tag: node.type,\n });\n continue;\n }\n if (input.binding) {\n bindings.push({ tag: node.type, input: key, kind: input.binding, value });\n }\n if (!isExpr(value)) {\n const typeDiag = checkType(node.type, input, value);\n if (typeDiag) diagnostics.push(typeDiag);\n }\n }\n\n // containment\n if (node.children?.length && !comp.isContainer) {\n diagnostics.push({\n severity: 'warning',\n code: 'not-a-container',\n message: `<${node.type}> does not accept children`,\n tag: node.type,\n });\n }\n }\n\n if (node.children) node.children.forEach(visit);\n };\n\n if (tree) visit(tree);\n return { diagnostics, requires: [...requires], bindings };\n}\n\nfunction checkType(tag: string, input: ManifestInput, value: unknown): Diagnostic | null {\n const mismatch = (expected: string): Diagnostic => ({\n severity: 'warning',\n code: 'type-mismatch',\n message: `<${tag}> prop \"${input.name}\" expected ${expected}`,\n tag,\n });\n switch (input.type) {\n case 'number':\n return typeof value === 'number' ? null : mismatch('a number');\n case 'boolean':\n return typeof value === 'boolean' ? null : mismatch('a boolean');\n case 'string':\n case 'color':\n case 'date':\n case 'code':\n case 'file':\n return typeof value === 'string' ? null : mismatch('a string');\n case 'array':\n return Array.isArray(value) ? null : mismatch('an array');\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? null\n : mismatch('an object');\n case 'enum': {\n const allowed = (input.enum ?? []).map((e) => (typeof e === 'object' ? e.value : e));\n return allowed.includes(value as never)\n ? null\n : {\n severity: 'error',\n code: 'invalid-enum',\n message: `<${tag}> prop \"${input.name}\"=${JSON.stringify(value)} is not one of ${JSON.stringify(allowed)}`,\n tag,\n };\n }\n default:\n return null;\n }\n}\n","/**\n * ObjectUI — codegen the JSX type surface from the registry manifest (ADR-0080 §3)\n *\n * Emits a `.d.ts` that augments `JSX.IntrinsicElements` so a constrained\n * JSX-source page type-checks in `.tsx`: tag name === registry `type` key,\n * attributes === the component's manifest `inputs`. This is a TYPE-CHECKING\n * fiction — no real React intrinsic named `flex` exists; the interpreter\n * fulfills it via the registry at render time.\n */\n\nimport type { Manifest, ManifestComponent, ManifestInput } from './types.js';\n\nexport interface CodegenOptions {\n /** include a self-contained minimal JSX namespace so the d.ts type-checks\n * standalone (no React types needed). Default true. */\n standaloneJsx?: boolean;\n}\n\nexport function generateDts(manifest: Manifest, options: CodegenOptions = {}): string {\n const { standaloneJsx = true } = options;\n const comps = Object.values(manifest.components).sort((a, b) => a.type.localeCompare(b.type));\n\n const interfaces = comps.map(emitInterface).join('\\n\\n');\n const intrinsics = comps\n .map((c) => ` ${JSON.stringify(c.type)}: ${propsName(c.type)};`)\n .join('\\n');\n\n const baseElement = standaloneJsx\n ? `\n // minimal, so the surface type-checks without pulling React types\n type Element = unknown;\n interface ElementClass {}\n interface ElementAttributesProperty {}\n interface ElementChildrenAttribute { children: object; }`\n : '';\n\n return `// AUTO-GENERATED by @object-ui/sdui-parser — DO NOT EDIT.\n// Source of truth: ComponentRegistry inputs (ADR-0080 §3). Regenerate via codegen.\n/* eslint-disable */\n\nexport interface SduiBaseProps {\n id?: string;\n className?: string;\n style?: Record<string, unknown>;\n visible?: boolean;\n visibleOn?: string;\n disabled?: boolean;\n disabledOn?: string;\n children?: unknown;\n}\n\n${interfaces}\n\ndeclare global {\n namespace JSX {\n interface IntrinsicElements {\n${intrinsics}\n }${baseElement}\n }\n}\n\nexport {};\n`;\n}\n\nfunction emitInterface(comp: ManifestComponent): string {\n const lines = comp.inputs\n .filter((i) => i.type !== 'slot')\n .map((i) => ` ${propLine(i)}`)\n .join('\\n');\n return `export interface ${propsName(comp.type)} extends SduiBaseProps {\\n${lines}\\n}`;\n}\n\nfunction propLine(input: ManifestInput): string {\n const opt = input.required ? '' : '?';\n return `${quoteKeyIfNeeded(input.name)}${opt}: ${tsType(input)};`;\n}\n\nfunction tsType(input: ManifestInput): string {\n switch (input.type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'array':\n return 'unknown[]';\n case 'object':\n return 'Record<string, unknown>';\n case 'enum': {\n const vals = (input.enum ?? []).map((e) => (typeof e === 'object' ? e.value : e));\n return vals.length ? vals.map((v) => JSON.stringify(v)).join(' | ') : 'string';\n }\n case 'string':\n case 'color':\n case 'date':\n case 'code':\n case 'file':\n default:\n return 'string';\n }\n}\n\nconst IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst quoteKeyIfNeeded = (name: string): string => (IDENT.test(name) ? name : JSON.stringify(name));\n\n/** 'object-grid' -> 'ObjectGrid', 'record:details' -> 'RecordDetails' */\nexport function propsName(type: string): string {\n const pascal = type\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((s) => s[0].toUpperCase() + s.slice(1))\n .join('');\n return `${pascal}Props`;\n}\n\n/**\n * Generate the human-facing PUBLIC block list (the curated \"清单\") from a\n * manifest — a Markdown table. Derived, never hand-maintained (ADR-0046).\n */\nexport function generateBlockList(manifest: Manifest): string {\n const rows = Object.values(manifest.components)\n .sort((a, b) => a.type.localeCompare(b.type))\n .map((c) => {\n const req = c.inputs.filter((i) => i.required).map((i) => i.name);\n const binds = c.inputs.filter((i) => i.binding).map((i) => `${i.name}:${i.binding}`);\n return `| \\`${c.type}\\` | ${c.namespace ?? '—'} | ${c.isContainer ? '✓' : ''} | ${req.join(', ') || '—'} | ${binds.join(', ') || '—'} |`;\n });\n return [\n `# SDUI public blocks (${Object.keys(manifest.components).length})`,\n '',\n '> Auto-generated from the registry `tier:\\'public\\'` set (ADR-0080). Do not edit by hand.',\n '',\n '| block | plugin | container | required props | bindings |',\n '|---|---|---|---|---|',\n ...rows,\n '',\n ].join('\\n');\n}\n","/**\n * @object-ui/sdui-parser — constrained JSX-source → SDUI SchemaNode tree (ADR-0080)\n *\n * Isomorphic, zero React. Run server-side as the authoritative save-time gate;\n * may also run client-side for live edit preview (re-validated on the server —\n * never the trust boundary). It PARSES; it never executes.\n */\n\nexport * from './types.js';\nexport { parseJsx, interpretBrace } from './parse.js';\nexport { validateTree } from './validate.js';\nexport { generateDts, propsName, generateBlockList } from './codegen.js';\nexport type { CodegenOptions } from './codegen.js';\n\nimport { parseJsx } from './parse.js';\nimport { validateTree } from './validate.js';\nimport type { Diagnostic, Manifest, SchemaElement, ValidationResult } from './types.js';\n\nexport interface CompileResult {\n tree: SchemaElement | null;\n diagnostics: Diagnostic[];\n requires: string[];\n bindings: ValidationResult['bindings'];\n /** true when there are no error-severity diagnostics — the save gate's pass/fail */\n ok: boolean;\n}\n\n/**\n * The authoritative pipeline: parse (with the manifest's tags as the whitelist)\n * → validate against the manifest → derive `requires` + binding sites.\n */\nexport function compile(source: string, manifest: Manifest): CompileResult {\n const allowedTags = new Set(Object.keys(manifest.components));\n const parsed = parseJsx(source, { allowedTags });\n const validated = validateTree(parsed.tree, manifest);\n const diagnostics = [...parsed.diagnostics, ...validated.diagnostics];\n return {\n tree: parsed.tree,\n diagnostics,\n requires: validated.requires,\n bindings: validated.bindings,\n ok: !diagnostics.some((d) => d.severity === 'error'),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Registry → manifest adapter. Structural input (no @object-ui/core\n * dependency) so the package stays pure and hoistable to framework.\n * Feed it `ComponentRegistry.getAllConfigs()` (optionally filtered to\n * the `tier:'public'` set).\n * ------------------------------------------------------------------ */\n\nexport interface RegistryConfigLike {\n type: string;\n namespace?: string;\n isContainer?: boolean;\n /** ADR-0080 contract tier — only 'public' configs form the AI/contract surface. */\n tier?: 'public' | 'internal';\n label?: string;\n category?: string;\n inputs?: Array<{\n name: string;\n type: string;\n required?: boolean;\n enum?: Array<string | { value: unknown; label?: string }>;\n binding?: 'object' | 'field';\n description?: string;\n }>;\n}\n\nconst INPUT_TYPES = new Set([\n 'string',\n 'number',\n 'boolean',\n 'enum',\n 'array',\n 'object',\n 'color',\n 'date',\n 'code',\n 'file',\n 'slot',\n]);\n\nexport function manifestFromConfigs(\n configs: RegistryConfigLike[],\n opts: { only?: Set<string>; publicOnly?: boolean } = {},\n): Manifest {\n const components: Manifest['components'] = {};\n for (const c of configs) {\n if (opts.only && !opts.only.has(c.type)) continue;\n if (opts.publicOnly && c.tier !== 'public') continue;\n components[c.type] = {\n type: c.type,\n namespace: c.namespace,\n isContainer: c.isContainer,\n inputs: (c.inputs ?? []).map((i) => ({\n name: i.name,\n type: (INPUT_TYPES.has(i.type) ? i.type : 'string') as Manifest['components'][string]['inputs'][number]['type'],\n required: i.required,\n enum: i.enum,\n binding: i.binding,\n description: i.description,\n })),\n };\n }\n return { components };\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@objectstack/sdui-parser",
3
+ "version": "11.2.0",
4
+ "license": "Apache-2.0",
5
+ "description": "ObjectStack constrained JSX-source → SDUI SchemaNode tree compiler (parse, never execute). Isomorphic, zero React. ADR-0080.",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^6.0.3",
17
+ "vitest": "^4.1.9"
18
+ },
19
+ "keywords": [
20
+ "objectstack",
21
+ "sdui",
22
+ "jsx",
23
+ "parser",
24
+ "adr-0080"
25
+ ],
26
+ "author": "ObjectStack",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/objectstack-ai/framework.git",
30
+ "directory": "packages/sdui-parser"
31
+ },
32
+ "homepage": "https://objectstack.ai/docs",
33
+ "bugs": "https://github.com/objectstack-ai/framework/issues",
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsup --config ../../tsup.config.ts",
39
+ "test": "vitest run"
40
+ }
41
+ }