@uniweb/build 0.70.1 → 0.71.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.70.1",
3
+ "version": "0.71.0",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
@@ -58,14 +58,14 @@
58
58
  "sharp": "^0.35.3",
59
59
  "yaml": "^2.5.0",
60
60
  "@uniweb/content-writer": "^0.3.4",
61
- "@uniweb/projections": "^0.7.9",
62
- "@uniweb/content-reader": "^1.2.7",
63
- "@uniweb/schemas": "^0.9.0",
64
61
  "@uniweb/semantic-parser": "^1.4.1",
65
- "@uniweb/theming": "^0.1.16"
62
+ "@uniweb/projections": "^0.7.10",
63
+ "@uniweb/theming": "^0.1.16",
64
+ "@uniweb/content-reader": "^1.2.7",
65
+ "@uniweb/schemas": "^0.9.1"
66
66
  },
67
67
  "optionalDependencies": {
68
- "@uniweb/runtime": "^0.28.0"
68
+ "@uniweb/runtime": "^0.28.1"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -74,8 +74,8 @@
74
74
  "@tailwindcss/vite": "^4.0.0",
75
75
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
76
76
  "vite-plugin-svgr": "^4.0.0",
77
- "@uniweb/runtime": "^0.28.0",
78
- "@uniweb/core": "^0.33.0"
77
+ "@uniweb/core": "^0.34.0",
78
+ "@uniweb/runtime": "^0.28.1"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "vite": {
@@ -32,7 +32,7 @@ export function sameMarkdownDocument(markdown, doc) {
32
32
  }
33
33
 
34
34
  // A document without the attributes that only restate a default: an inset's `embedKind: 'visual'`,
35
- // which the parser writes and the pull's re-inlining leaves out (`reinlineInsets`) — so a body holding
35
+ // which the parser writes and the pull's re-inlining (retired 2026-09-28) left out — so a body holding
36
36
  // an inset never compared as unchanged (measured 2026-09-26 on the `marketing` template's hero).
37
37
  function withoutDefaults(doc) {
38
38
  return JSON.parse(JSON.stringify(doc), (_, v) => {
@@ -29,8 +29,8 @@
29
29
  // It needs TWO bases, and that is the non-obvious part.
30
30
  //
31
31
  // Our document and the backend's are not byte-comparable renderings of the same
32
- // unit: the backend's copy carries fields we don't emit (`params`,
33
- // `theme_override`, its own `$uuid`) and serializes in its own key order. So a hash
32
+ // unit: the backend's copy carries fields we don't emit (its own `$uuid`, for
33
+ // one) and serializes in its own key order. So a hash
34
34
  // taken on our side and one taken on theirs differ for a unit NEITHER side touched.
35
35
  // A single base therefore validates exactly one comparison and silently corrupts
36
36
  // the other — with a local-representation base every unit looks "changed
@@ -383,50 +383,12 @@ export function siteInfoToConfig({ document, siteRoot, backend = null, sourceLoc
383
383
  // Section records → section .md files
384
384
  // ---------------------------------------------------------------------------
385
385
 
386
- /**
387
- * Re-inline a section's extracted insets back into its ProseMirror content —
388
- * the exact inverse of content-collector's `extractInsets`. The producer pulls
389
- * each `![alt](@Component){params}` ref out of the body into an `insets[]` array
390
- * and leaves an `inset_placeholder` behind; content-writer only serializes
391
- * `inset_ref` nodes, so we restore them before serializing or the inset would
392
- * be reported as unmappable and dropped.
393
- *
394
- * @param {object} content - the section's ProseMirror document (placeholders in)
395
- * @param {Array} insets - `[{ refId, type, params, title, embedKind }]`
396
- * @returns {object} a content document with `inset_ref` nodes restored
397
- */
398
- function reinlineInsets(content, insets) {
399
- if (!content || !Array.isArray(content.content) || !Array.isArray(insets) || insets.length === 0) {
400
- return content
401
- }
402
- const byRef = new Map(insets.map((i) => [i.refId, i]))
403
-
404
- const visit = (nodes) =>
405
- nodes.map((node) => {
406
- if (!node) return node
407
- if (node.type === 'inset_placeholder') {
408
- const inset = byRef.get(node.attrs?.refId)
409
- if (!inset) return node // no match → leave the placeholder (the guard reports it)
410
- const attrs = { component: inset.type, ...(inset.params || {}) }
411
- if (inset.title != null) attrs.alt = inset.title
412
- // `visual` is the extractor's default — omit it so the projected markdown
413
- // doesn't gain a spurious `{embedKind=visual}` the source never had.
414
- if (inset.embedKind && inset.embedKind !== 'visual') attrs.embedKind = inset.embedKind
415
- return { type: 'inset_ref', attrs }
416
- }
417
- if (Array.isArray(node.content)) return { ...node, content: visit(node.content) }
418
- return node
419
- })
420
-
421
- return { ...content, content: visit(content.content) }
422
- }
423
-
424
386
  /**
425
387
  * Project one section `$`-record (from `page_sections` / `layout_sections`) to a
426
388
  * section `.md` file — the inverse of site.js `mapSectionData`. Frontmatter is
427
- * `type` + the flat `params` + `background` / `theme` (`theme_override`) /
428
- * `fetch` / `id` (`stable_id`); the body is the section's
429
- * content (insets re-inlined) serialized to markdown. Idempotent.
389
+ * `type` + `hidden` + the flat `params` (`background` and `theme` among them) +
390
+ * the data declaration (`params.fetch`, else the `fetch` field) + `id` (`stable_id`);
391
+ * the body is the section's content serialized to markdown. Idempotent.
430
392
  *
431
393
  * Note: `$children` (a section's child sections) are NOT written here — the page
432
394
  * walk (`pageSectionsToFiles`) writes each to its own file and nests it under its
@@ -444,7 +406,10 @@ function reinlineInsets(content, insets) {
444
406
  export function sectionRecordToFile({ filePath, record, sourceLocale = LOCALIZED_FIELD_ASSUMPTION.defaultSourceLocale, collector, freeformRelPath, freeformCandidates = null, writeId = true, context = null }) {
445
407
  // ⛔ A stored `preset` or `input` is not written back: neither has an effect, and the build
446
408
  // would only warn about it (2026-09-27).
447
- const { type, stable_id, hidden, params, content, insets, fetch, background, theme_override } = record || {}
409
+ // ⛔ No `background` / `theme_override` / `insets`: the site-content Model dropped all three
410
+ // (2026-09-28), with a stored background and theme copied into `params`. Until then a field
411
+ // filled in where `params` lacked the key, and a stored `insets[]` was re-inlined into the body.
412
+ const { type, stable_id, hidden, params, content, fetch } = record || {}
448
413
 
449
414
  // A localized `content` field unwraps to the source-locale doc for the body; its
450
415
  // target-locale structural maps are captured into the locales/ collector, and any
@@ -452,7 +417,7 @@ export function sectionRecordToFile({ filePath, record, sourceLocale = LOCALIZED
452
417
  // locales/freeform/. A bare doc (source-only / pre-localization) passes through.
453
418
  const sourceContent = unwrapLocalizedContent(content, sourceLocale, collector, freeformRelPath, freeformCandidates, context)
454
419
 
455
- const { hidden: paramHidden, ...paramsRest } = params && typeof params === 'object' ? params : {}
420
+ const { hidden: paramHidden, fetch: paramFetch, ...paramsRest } = params && typeof params === 'object' ? params : {}
456
421
  const frontmatter = {}
457
422
  if (type !== undefined) frontmatter.type = type
458
423
  // ⭐ `hidden:` says what the store says: written for a hidden section, and removed from the
@@ -461,25 +426,22 @@ export function sectionRecordToFile({ filePath, record, sourceLocale = LOCALIZED
461
426
  // `params`, so one stored there counts when the field is absent.
462
427
  frontmatter.hidden = (typeof hidden === 'boolean' ? hidden : paramHidden === true) ? true : undefined
463
428
  Object.assign(frontmatter, paramsRest)
464
- // ⚠️ A stored `background` / `theme_override` field wins over the same key in `params` while
465
- // one is stored: an editor may still write the fields rather than `params` (2026-09-28;
466
- // uwx-format.md § A page section's fields, Order).
467
- if (background !== undefined) frontmatter.background = background
468
- if (theme_override !== undefined) frontmatter.theme = theme_override
469
429
  // Invert the build's resolution rather than copy it — see fetch-shapes.js. A new
470
430
  // file gets `query:` for a declaration of names alone; a section that declares
471
431
  // its data locally keeps it (`writeSectionFile`, the declaration keys).
472
- if (fetch !== undefined) {
473
- const { key, value } = authorableDeclaration(fetch)
432
+ // ⭐ From `params.fetch` when present — where a section carries its data since 2026-09-28 —
433
+ // else the stored field.
434
+ const ownFetch = paramFetch !== undefined ? paramFetch : fetch
435
+ if (ownFetch !== undefined) {
436
+ const { key, value } = authorableDeclaration(ownFetch)
474
437
  frontmatter[key] = value
475
438
  }
476
439
  // `id:` only where the file's name does not already give it (`writeId`, `pageSectionsToFiles`).
477
440
  if (stable_id !== undefined && writeId) frontmatter.id = stable_id
478
441
 
479
- const body = insets ? reinlineInsets(sourceContent, insets) : sourceContent
480
442
  // ⛔ Not `type: Content` into a file that names no type: it is what the push sent for it, and
481
443
  // absent, the foundation's `defaultSection` renders it. Until 2026-09-26 a pull wrote it back.
482
- return writeSectionFile({ filePath, content: body, params: frontmatter, implied: { type: FILLED_SECTION_TYPE } })
444
+ return writeSectionFile({ filePath, content: sourceContent, params: frontmatter, implied: { type: FILLED_SECTION_TYPE } })
483
445
  }
484
446
 
485
447
  // ---------------------------------------------------------------------------
package/src/uwx/site.js CHANGED
@@ -302,6 +302,10 @@ function localizePageMeta(page, route, sourceLocale, translations) {
302
302
 
303
303
  function mapSectionData(section) {
304
304
  const params = { ...section.params }
305
+ // ⭐ The section's own data rides in `params.fetch` [Diego, 2026-09-28] — nothing on a store's
306
+ // side acts on it by name. ⚠️ Also sent as the `fetch` field it had until then, until an
307
+ // editor's reader looks in `params.fetch` (uwx-format.md § A page section's fields).
308
+ if (section.fetch) params.fetch = section.fetch
305
309
  const data = { type: section.type || FILLED_SECTION_TYPE } // entity type requires `type`
306
310
  setIf(data, 'stable_id', section.stableId ?? undefined)
307
311
  // ⭐ A draft section — the store's own `hidden`, which an editor also writes [2026-09-28].