@uniweb/build 0.16.4 → 0.16.6

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.16.4",
3
+ "version": "0.16.6",
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/theming": "0.1.15",
63
62
  "@uniweb/content-writer": "0.3.3",
64
- "@uniweb/projections": "0.2.3"
63
+ "@uniweb/projections": "0.2.3",
64
+ "@uniweb/theming": "0.1.15"
65
65
  },
66
66
  "optionalDependencies": {
67
67
  "@uniweb/content-reader": "1.2.2",
68
- "@uniweb/semantic-parser": "1.2.0",
69
- "@uniweb/runtime": "0.9.0",
70
- "@uniweb/schemas": "0.2.4"
68
+ "@uniweb/runtime": "0.9.1",
69
+ "@uniweb/schemas": "0.2.4",
70
+ "@uniweb/semantic-parser": "1.2.0"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -359,6 +359,7 @@ export function extractAllRuntimeSchemas(componentsMeta, dataSchemaMap = {}) {
359
359
  * this overrides per region, or `false` opts the layout out)
360
360
  * - defaults: Param default values
361
361
  * - scroll: Scroll management mode ('self' or CSS selector)
362
+ * - layers: Stacking order of the area wrappers (object, or false to opt out)
362
363
  *
363
364
  * @param {Object} fullMeta - The full meta.js default export for a layout
364
365
  * @returns {Object|null} - Lean layout runtime schema or null if empty
@@ -374,10 +375,21 @@ export function extractLayoutRuntimeSchema(fullMeta) {
374
375
  runtime.areas = fullMeta.areas
375
376
  }
376
377
 
377
- if (fullMeta.transitions && typeof fullMeta.transitions === 'object') {
378
+ // `false` is a value, not an absence: it is the documented way a layout opts
379
+ // out of per-area view transitions. The previous guard was
380
+ // `fullMeta.transitions && typeof … === 'object'`, which is false for `false`
381
+ // — so the opt-out was dropped here and never reached the runtime, even
382
+ // though `resolveLayoutTransitions` has always handled it. Same for `layers`.
383
+ if (fullMeta.transitions === false || (fullMeta.transitions && typeof fullMeta.transitions === 'object')) {
378
384
  runtime.transitions = fullMeta.transitions
379
385
  }
380
386
 
387
+ // Stacking order of the area wrappers. Carried whether or not the layout
388
+ // declares transitions, because an explicit layer is itself a reason to wrap.
389
+ if (fullMeta.layers === false || (fullMeta.layers && typeof fullMeta.layers === 'object')) {
390
+ runtime.layers = fullMeta.layers
391
+ }
392
+
381
393
  if (fullMeta.scroll !== undefined) {
382
394
  runtime.scroll = fullMeta.scroll
383
395
  }
package/src/schema.js CHANGED
@@ -120,6 +120,63 @@ export async function loadPackageJson(srcDir) {
120
120
  * - props: Foundation-wide props
121
121
  * - Future: providers, middleware, etc.
122
122
  */
123
+ /**
124
+ * Capability keys that only work as keys of the DEFAULT export.
125
+ *
126
+ * The list is `cli/partials/agents.md`'s ("A single `export default { … }` whose
127
+ * top-level keys are the capabilities the foundation provides"). `vars` is
128
+ * deliberately absent: it is the one capability that also works named, because
129
+ * `generate-entry.js` reads it explicitly.
130
+ */
131
+ const DEFAULT_ONLY_CAPABILITIES = [
132
+ 'name',
133
+ 'description',
134
+ 'defaultLayout',
135
+ 'defaultSection',
136
+ 'viewTransitions',
137
+ 'props',
138
+ 'defaultInsets',
139
+ 'xref',
140
+ 'outputs',
141
+ 'handlers',
142
+ 'extension',
143
+ ]
144
+
145
+ /**
146
+ * Warn when a capability was written as a named export.
147
+ *
148
+ * `generate-entry.js` builds `capabilities` as `{ ..._foundationModule.default,
149
+ * vars: … }` — it spreads only the DEFAULT export. A named `export const xref =
150
+ * …` is therefore dropped with no error, no warning, and a build that succeeds.
151
+ * Whatever the capability did simply does not happen, which reads as "the
152
+ * feature is not implemented" rather than "it is declared in the wrong place".
153
+ *
154
+ * Real incident (2026-07-31): cross-references were wired onto uniweb.io as
155
+ * named `xref` and `defaultInsets` exports. The build passed, the site ran, and
156
+ * every `[#id]` rendered as its own literal text — indistinguishable from a
157
+ * foundation that had never opted in. Found only by reading generate-entry.js.
158
+ *
159
+ * A warning rather than an error: a foundation may legitimately export a name
160
+ * that collides for its own use, and failing someone's build over a naming
161
+ * coincidence is worse than telling them what we ignored.
162
+ */
163
+ function warnMisplacedCapabilities(module, filePath) {
164
+ const onDefault = module.default && typeof module.default === 'object' ? module.default : {}
165
+ const misplaced = DEFAULT_ONLY_CAPABILITIES.filter(
166
+ key => module[key] !== undefined && onDefault[key] === undefined,
167
+ )
168
+ if (misplaced.length === 0) return
169
+
170
+ const list = misplaced.map(k => `\`${k}\``).join(', ')
171
+ console.warn(
172
+ `Warning: ${filePath} exports ${list} as named export${misplaced.length > 1 ? 's' : ''}, ` +
173
+ `which the build ignores.\n` +
174
+ ` Capabilities are read from the default export only — move ${misplaced.length > 1 ? 'them' : 'it'} into ` +
175
+ `\`export default { … }\`.\n` +
176
+ ` (\`vars\` is the exception and may stay a named export.)`,
177
+ )
178
+ }
179
+
123
180
  export async function loadFoundationConfig(srcDir) {
124
181
  let filePath = null
125
182
  for (const name of FOUNDATION_FILE_NAMES) {
@@ -133,6 +190,7 @@ export async function loadFoundationConfig(srcDir) {
133
190
 
134
191
  try {
135
192
  const module = await import(pathToFileURL(filePath).href)
193
+ warnMisplacedCapabilities(module, filePath)
136
194
  // Support both default export and named exports
137
195
  return {
138
196
  ...module.default,