@uniweb/build 0.16.7 → 0.16.9
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 +6 -6
- package/src/resolve-data-schema.js +26 -3
- package/src/uwx/site-project.js +5 -0
- package/src/uwx/site.js +7 -0
- package/src/validate-data.js +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/build",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.9",
|
|
4
4
|
"description": "Build tooling for the Uniweb Component Web Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"js-yaml": "^4.1.0",
|
|
60
60
|
"sharp": "^0.35.3",
|
|
61
61
|
"yaml": "^2.5.0",
|
|
62
|
-
"@uniweb/
|
|
62
|
+
"@uniweb/theming": "0.1.15",
|
|
63
63
|
"@uniweb/projections": "0.2.4",
|
|
64
|
-
"@uniweb/
|
|
64
|
+
"@uniweb/content-writer": "0.3.3"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
67
|
"@uniweb/content-reader": "1.2.2",
|
|
68
|
-
"@uniweb/runtime": "0.9.
|
|
69
|
-
"@uniweb/
|
|
70
|
-
"@uniweb/
|
|
68
|
+
"@uniweb/runtime": "0.9.3",
|
|
69
|
+
"@uniweb/schemas": "0.2.5",
|
|
70
|
+
"@uniweb/semantic-parser": "1.2.1"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
@@ -600,10 +600,32 @@ function normalizeField(field, ref, path) {
|
|
|
600
600
|
|
|
601
601
|
// Structural kinds.
|
|
602
602
|
if (out.type === 'object') {
|
|
603
|
-
|
|
604
|
-
|
|
603
|
+
// Two ways to describe an object, and they answer different questions:
|
|
604
|
+
//
|
|
605
|
+
// fields the object's KNOWN keys — `{ street, city }`
|
|
606
|
+
// values an OPEN MAP whose keys belong to the author and whose values all
|
|
607
|
+
// conform to one shape — `{ <anything>: <a field spec> }`
|
|
608
|
+
//
|
|
609
|
+
// `values` is to an object what `items` is to an array, and it exists for
|
|
610
|
+
// the same reason: a form's `fields` is a map keyed by author-chosen names
|
|
611
|
+
// (see `@std/form`), which could not be described at all until this landed.
|
|
612
|
+
// Requested by the editor team 2026-07-31 — the shape they needed and could
|
|
613
|
+
// not state in this vocabulary either.
|
|
614
|
+
if (field.values !== undefined && field.fields !== undefined) {
|
|
615
|
+
throw new Error(
|
|
616
|
+
`Data schema '${ref}': object field '${path}' declares both 'fields' and 'values'. ` +
|
|
617
|
+
`Use 'fields' for known keys, 'values' for an open map — not both.`
|
|
618
|
+
)
|
|
619
|
+
}
|
|
620
|
+
if (field.values !== undefined) {
|
|
621
|
+
out.values = normalizeField(field.values, ref, `${path}{}`)
|
|
622
|
+
} else if (field.fields === undefined) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
`Data schema '${ref}': object field '${path}' must declare nested 'fields' (known keys) or 'values' (an open map).`
|
|
625
|
+
)
|
|
626
|
+
} else {
|
|
627
|
+
out.fields = normalizeFields(field.fields, ref, path)
|
|
605
628
|
}
|
|
606
|
-
out.fields = normalizeFields(field.fields, ref, path)
|
|
607
629
|
} else if (out.type === 'array') {
|
|
608
630
|
// `items` (the element type) is recommended but optional — an array with
|
|
609
631
|
// no declared element type is an untyped list.
|
|
@@ -637,6 +659,7 @@ export function collectNestedRefs(schema) {
|
|
|
637
659
|
if (typeof field.options === 'string') found.add(field.options)
|
|
638
660
|
if (field.fields) walkFields(field.fields)
|
|
639
661
|
if (field.items) walkFields({ _: field.items })
|
|
662
|
+
if (field.values) walkFields({ _: field.values })
|
|
640
663
|
}
|
|
641
664
|
}
|
|
642
665
|
const walkSections = (sections) => {
|
package/src/uwx/site-project.js
CHANGED
|
@@ -100,6 +100,11 @@ const INFO_TO_SITE_YML = {
|
|
|
100
100
|
fetcher: 'fetcher',
|
|
101
101
|
build: 'build',
|
|
102
102
|
search: 'search',
|
|
103
|
+
// Safe to project back because nothing STAMPS it: `submit` is authored-only,
|
|
104
|
+
// so a pull can never launder a deploy-derived value into authored config the
|
|
105
|
+
// way a key carried by both would. A host-supplied destination is resolved at
|
|
106
|
+
// render time and never enters `info`.
|
|
107
|
+
submit: 'submit',
|
|
103
108
|
agents: 'agents',
|
|
104
109
|
paths: 'paths',
|
|
105
110
|
data: 'data',
|
package/src/uwx/site.js
CHANGED
|
@@ -629,6 +629,13 @@ export async function siteProjectToDocument(siteRoot, opts = {}) {
|
|
|
629
629
|
setIf(info, 'fetcher', siteYml.fetcher)
|
|
630
630
|
setIf(info, 'build', siteYml.build)
|
|
631
631
|
setIf(info, 'search', siteYml.search)
|
|
632
|
+
// `submit` — where this site's forms send submissions. Same family as
|
|
633
|
+
// `fetcher`/`search`: the site declares it, the runtime reads it, and it
|
|
634
|
+
// round-trips verbatim. It has to be listed HERE because this lane is an
|
|
635
|
+
// explicit allowlist while the bundle lane spreads all of site.yml — without
|
|
636
|
+
// the line a `submit:` block works on a static host and vanishes silently on
|
|
637
|
+
// the synced lane, which is the worst shape a config bug can take.
|
|
638
|
+
setIf(info, 'submit', siteYml.submit)
|
|
632
639
|
// `agents` — the projections opt-out + route exclusions. Carried because the
|
|
633
640
|
// app is a second PUBLISHER of projections and derives them from stored
|
|
634
641
|
// content: without this block it cannot see `agents: false` or
|
package/src/validate-data.js
CHANGED
|
@@ -118,6 +118,21 @@ function validateValue(def, value, path) {
|
|
|
118
118
|
out.push(violation(path, 'type', `expected object, got ${typeName(value)}`))
|
|
119
119
|
} else if (def.fields) {
|
|
120
120
|
out.push(...validateFields(def.fields, value, path))
|
|
121
|
+
} else if (def.values) {
|
|
122
|
+
// An OPEN MAP: the keys are the author's, every value conforms to one
|
|
123
|
+
// shape. `values` is to an object what `items` is to an array.
|
|
124
|
+
//
|
|
125
|
+
// Note what this deliberately does NOT do: reject a key. It cannot — the
|
|
126
|
+
// keys are the whole point — and it must not reject unexpected keys
|
|
127
|
+
// WITHIN a value either, which falls out of `validateFields` walking the
|
|
128
|
+
// schema's fields rather than the data's. That tolerance is load-bearing
|
|
129
|
+
// for `@std/form`: a form definition may carry per-field keys the current
|
|
130
|
+
// builder cannot author (hand-written, or from a newer editor), and the
|
|
131
|
+
// editor's boundary passes them through untouched. A stricter check here
|
|
132
|
+
// would fail builds on good content.
|
|
133
|
+
for (const [key, item] of Object.entries(value)) {
|
|
134
|
+
out.push(...validateValue(def.values, item, `${path}.${key}`))
|
|
135
|
+
}
|
|
121
136
|
}
|
|
122
137
|
return out
|
|
123
138
|
}
|