unoverse 0.1.187 → 0.1.189
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/package.json
CHANGED
|
@@ -399,8 +399,16 @@ function lintFile(file) {
|
|
|
399
399
|
// ONE REQUIREMENT SHAPE (2026-08-29): a kind declares its tree (`states:`) OR
|
|
400
400
|
// its drawing (`root` — flat components/atoms). A tree component's root is
|
|
401
401
|
// SYNTHESIZED by the compiler, never required.
|
|
402
|
+
// A BLOCK is a template that declares a DRAWING instead of a tree (2026-08-31): a flat
|
|
403
|
+
// file, no manifest, one `root:` — `pair`, `feature`, `single`, `rail`, `stack`. It has
|
|
404
|
+
// no states because it is not a screen: it is a shape a page imports by `Ref`, inlined
|
|
405
|
+
// before the page's sections compile. Requiring `states:` of it would be demanding a
|
|
406
|
+
// state machine from a fragment, which is the same mistake as demanding a manifest:
|
|
407
|
+
// both are what a PAGE has, and a block is not a page.
|
|
408
|
+
const isBlock = declared === "template" && json.states === undefined && json.root !== undefined;
|
|
402
409
|
const envelopeRequired =
|
|
403
|
-
|
|
410
|
+
isBlock ? ["name", "root"]
|
|
411
|
+
: declared === "app" || declared === "template" ? ["name", "states"]
|
|
404
412
|
: declared === "component" ? ["name", ...(json.states !== undefined || json.state?.view !== undefined ? [] : ["root"])]
|
|
405
413
|
: ["name", "root"];
|
|
406
414
|
if (declared === "template" && json.states === undefined && (json.parts !== undefined || json.shapes !== undefined)) envelopeRequired.pop();
|
|
@@ -45,7 +45,7 @@ export const UNIVERSAL_PROPS = new Set([
|
|
|
45
45
|
*/
|
|
46
46
|
export const PROP_KEYS = [
|
|
47
47
|
"type", "input", "description", "maxLength", "minItems", "maxItems",
|
|
48
|
-
"hydrate", "optional", "enum", "preview", "default", "items",
|
|
48
|
+
"hydrate", "override", "optional", "enum", "preview", "default", "items",
|
|
49
49
|
];
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -86,7 +86,7 @@ export const PRIMITIVE_PROPS = {
|
|
|
86
86
|
Input: ["placeholder", "inputType", "disabledWhen", "maxLength", "multiline", "rows",
|
|
87
87
|
"inputMode", "autoComplete", "advanceOnFill"],
|
|
88
88
|
Select: ["placeholder", "options", "disabledWhen"],
|
|
89
|
-
Each: ["
|
|
89
|
+
Each: ["item", "app", "items"],
|
|
90
90
|
Switch: ["on", "cases", "fallback"],
|
|
91
91
|
Ref: ["ref", "props", "with", "children", "name"],
|
|
92
92
|
ComponentSlot: ["select", "frame", "fallback", "pinned", "appWidth"],
|
|
@@ -121,7 +121,7 @@ export const STYLE_KEYS = new Set([
|
|
|
121
121
|
// exact regex from server/src/runtime/definition-tokens.test.ts
|
|
122
122
|
export const RAW_VALUE = /#[0-9a-fA-F]{3,8}\b|\b\d*\.?\d+(px|rem|em)\b/;
|
|
123
123
|
// nodes reachable through these keys (data keys like `items`/`cases` handled explicitly)
|
|
124
|
-
export const CHILD_NODE_KEYS = ["children", "
|
|
124
|
+
export const CHILD_NODE_KEYS = ["children", "item", "fallback", "user", "assistant"];
|
|
125
125
|
// folders that hold BARE PARTIALS one level under the definition root
|
|
126
126
|
export const PARTIAL_DIRS = new Set(["layouts", "states", "components", "blocks"]);
|
|
127
127
|
|
|
@@ -68,16 +68,19 @@ function walkNode(node, file, root, widthCap = null, isLayoutRoot = false) {
|
|
|
68
68
|
report("error", file, `director.preview names unknown component "${c}". No match in the design system or this org's components (lookup is case-insensitive)`);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
71
|
+
// A PLACE NEEDS NO NAME (§9d, ruled 2026-08-31). A layout may hold several director
|
|
72
|
+
// places — one mind, arranged — and each needs a DISTINCT address or the surface is
|
|
73
|
+
// ambiguous (the reaction contract's one-view-one-surface rule). But the ADDRESS is
|
|
74
|
+
// the compiler's to hand out, by position, and an author writes places and a brief,
|
|
75
|
+
// never a face name. This rule used to demand `state:` on every place after the
|
|
76
|
+
// first; that was config in the layout, saying nothing the one mind did not already
|
|
77
|
+
// know from the page's brief.
|
|
78
|
+
//
|
|
79
|
+
// An AUTHORED `state:` still stands (the flat-email pin, §9b rule 4), so two places
|
|
80
|
+
// pinned to the SAME face remains an error — that one is genuinely ambiguous.
|
|
76
81
|
const seen = directorsSeen.get(file) ?? [];
|
|
77
82
|
const face = typeof d?.state === "string" ? d.state : null;
|
|
78
|
-
if (
|
|
79
|
-
report("error", file, `a second "director:" in this layout declares no "state:". Several bands are allowed — one mind, arranged — but each must claim a DISTINCT face, so every one of them names it (§9b rule 3)`);
|
|
80
|
-
else if (face && seen.includes(face))
|
|
83
|
+
if (face && seen.includes(face))
|
|
81
84
|
report("error", file, `two directed bands claim the face "${face}". A face has exactly one surface, or the active one is ambiguous (§9b rule 3, the reaction contract)`);
|
|
82
85
|
directorsSeen.set(file, [...seen, face]);
|
|
83
86
|
} else if (typeof node[word] !== "string") {
|
|
@@ -151,12 +154,12 @@ function walkNode(node, file, root, widthCap = null, isLayoutRoot = false) {
|
|
|
151
154
|
report("error", file, `Switch on "${node.on}" → case "${caseKey}" re-guards its own discriminant. A layer never guards itself; delete the visibleWhen (docs.unoverse.ai/design/components)`);
|
|
152
155
|
}
|
|
153
156
|
}
|
|
154
|
-
// Each:
|
|
157
|
+
// Each: an `item` + a list — EITHER a literal `items:[]` (hardcoded content,
|
|
155
158
|
// the microapp default) OR `bind.items` (a workflow-fed array).
|
|
156
159
|
if (t === "Each") {
|
|
157
160
|
const hasList = Array.isArray(node.items) || (node.bind && typeof node.bind === "object" && node.bind.items);
|
|
158
|
-
if (!node.
|
|
159
|
-
report("error", file, `Each needs "
|
|
161
|
+
if (!node.item || !hasList)
|
|
162
|
+
report("error", file, `Each needs "item" + a list. Literal "items": [...] or "bind": { "items": "<field>" } (docs.unoverse.ai/design/components)`);
|
|
160
163
|
}
|
|
161
164
|
if (t === "Ref") {
|
|
162
165
|
if (typeof node.ref !== "string")
|