@uniweb/runtime 1.5.4 → 1.5.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/dist/ssr.js CHANGED
@@ -15,6 +15,8 @@ import { jsonForScript } from "@uniweb/core/data-script";
15
15
  import { dataScript, jsonForScript as jsonForScript2 } from "@uniweb/core/data-script";
16
16
  import DataStore, { deriveCacheKey as deriveCacheKey$1 } from "@uniweb/core/datastore";
17
17
  import { RESOLUTION_STATUS, carryQuery, localeOfPath, localeUrl, resolveRoute, routeIndex } from "@uniweb/core/resolve-route";
18
+ import { declaredKeys } from "@uniweb/core/data-keys";
19
+ import { heldPageRecord, blockRouteQuery, blockFillsOf, fillIsPageRecord } from "@uniweb/core/page-data";
18
20
  import { resolveFetchConfigs } from "@uniweb/core/fetch-config";
19
21
  import { resolveRecordsService } from "@uniweb/core/records-service";
20
22
  function guaranteeItemStructure(item) {
@@ -99,7 +101,16 @@ function applyDefaults(params, defaults) {
99
101
  };
100
102
  }
101
103
  function assembleData(block, meta, entityData) {
102
- const declared = block.website?.declaredKeys ? block.website.declaredKeys(meta) : [];
104
+ const declared = declaredOf(block, meta);
105
+ const data = collectDeclared(block, declared, entityData);
106
+ warnUndeclaredBlocks(block, Object.keys(block.heldData || {}).filter((key) => !Object.hasOwn(data, key)));
107
+ block.parsedContent.data = data;
108
+ return declared;
109
+ }
110
+ function declaredOf(block, meta) {
111
+ return block.website?.declaredKeys ? block.website.declaredKeys(meta) : [];
112
+ }
113
+ function collectDeclared(block, declared, entityData) {
103
114
  const held = block.heldData || {};
104
115
  const data = {};
105
116
  for (const [key] of declared) {
@@ -107,19 +118,25 @@ function assembleData(block, meta, entityData) {
107
118
  else if (entityData && entityData[key] !== void 0) data[key] = entityData[key];
108
119
  else data[key] = null;
109
120
  }
110
- warnUndeclaredBlocks(block, Object.keys(held).filter((key) => !Object.hasOwn(data, key)));
111
- block.parsedContent.data = data;
112
- return declared;
121
+ return data;
122
+ }
123
+ function receivedData(block, meta, entityData = null) {
124
+ const declared = declaredOf(block, meta);
125
+ const probe = { parsedContent: { data: collectDeclared(block, declared, entityData) }, fetch: block.fetch, website: block.website };
126
+ block.website?.entityStore?.linkOwnRecords?.(probe);
127
+ return { declared, data: oneRecordEach(probe.parsedContent.data, declared) };
113
128
  }
114
129
  function holdOneRecord(block, declared) {
115
- const data = block.parsedContent.data;
130
+ block.parsedContent.data = oneRecordEach(block.parsedContent.data, declared);
131
+ }
132
+ function oneRecordEach(data, declared) {
116
133
  let out = null;
117
134
  for (const [key, , , single] of declared) {
118
135
  if (single !== true || !Array.isArray(data?.[key])) continue;
119
136
  out = out || { ...data };
120
137
  out[key] = data[key][0] ?? null;
121
138
  }
122
- if (out) block.parsedContent.data = out;
139
+ return out || data;
123
140
  }
124
141
  const warnedBlocks = /* @__PURE__ */ new Set();
125
142
  function warnUndeclaredBlocks(block, leftOut) {
@@ -1260,14 +1277,14 @@ function iconValue(value) {
1260
1277
  const ref = parseIconReference(value);
1261
1278
  return ref && ICON_FAMILY_MAP[ref.library.toLowerCase()] && ICON_NAME.test(ref.name) ? ref : null;
1262
1279
  }
1263
- function visit(node, found) {
1280
+ function visit$1(node, found) {
1264
1281
  if (!node || typeof node !== "object") return;
1265
1282
  if (node.type === "image" && node.attrs?.role === "icon") found.push(node.attrs);
1266
1283
  for (const mark of node.marks || []) {
1267
1284
  const ref = parseIconReference(mark?.attrs?.icon);
1268
1285
  if (ref) found.push(ref);
1269
1286
  }
1270
- if (Array.isArray(node.content)) for (const child of node.content) visit(child, found);
1287
+ if (Array.isArray(node.content)) for (const child of node.content) visit$1(child, found);
1271
1288
  }
1272
1289
  function visitValue(value, found, seen = /* @__PURE__ */ new WeakSet()) {
1273
1290
  if (typeof value === "string") {
@@ -1290,7 +1307,7 @@ function addressed(named) {
1290
1307
  }
1291
1308
  function pageIcons(blocks) {
1292
1309
  const named = [];
1293
- for (const block of blocks) visit(block.rawContent?.doc ?? block.rawContent, named);
1310
+ for (const block of blocks) visit$1(block.rawContent?.doc ?? block.rawContent, named);
1294
1311
  for (const block of blocks) {
1295
1312
  visitValue(block.properties, named);
1296
1313
  visitValue(getComponentMeta(block.type)?.defaults, named);
@@ -1412,10 +1429,93 @@ async function loadPageData({ website, route, fetch: fetch2, dev = false, locale
1412
1429
  if (askIcons) await askIcons(dataIcons([...entries.values()].map((entry) => entry.data)));
1413
1430
  return [...entries.values()];
1414
1431
  }
1432
+ function sectionRecords(page) {
1433
+ const sections = [];
1434
+ const shown = [];
1435
+ for (const block of page?.getBodyBlocks?.() ?? []) visit(block, sectionDomId(block), sections, shown);
1436
+ return { sections, record: pageRecordOf(page, shown) };
1437
+ }
1438
+ function visit(block, id, sections, shown) {
1439
+ if (!block) return;
1440
+ const data = recordsOf(block, shown);
1441
+ if (data) sections.push({ id, data });
1442
+ for (const inset of block.insets || []) visit(inset, id, sections, shown);
1443
+ for (const child of block.childBlocks || []) visit(child, sectionDomId(child), sections, shown);
1444
+ }
1445
+ function pageRecordOf(page, shown) {
1446
+ if (!page?.dynamicContext) return void 0;
1447
+ const one = (value) => Array.isArray(value) ? value[0] ?? null : value;
1448
+ const whole = shown.find((s) => s.whole && one(s.value));
1449
+ if (whole) return one(whole.value);
1450
+ const website = page.website;
1451
+ const fetcher = website?.fetcher;
1452
+ const own = heldPageRecord(page, {
1453
+ website,
1454
+ peek: (request) => fetcher?.peek?.(request, { website, page, block: null }),
1455
+ peekRecord: (id2) => fetcher?.peekRecord?.(id2)
1456
+ });
1457
+ const seen = shown.map((s) => one(s.value)).find(Boolean) ?? null;
1458
+ const id = (own ?? seen)?.$uuid;
1459
+ const held = typeof id === "string" && id ? fetcher?.peekRecord?.(id) : null;
1460
+ if (held?.whole === true && held.record) return held.record;
1461
+ return seen ?? own;
1462
+ }
1463
+ function recordsOf(block, shown) {
1464
+ if (!globalThis.uniweb?.getComponent?.(block.type)) return null;
1465
+ const meta = getComponentMeta(block.type);
1466
+ const own = declaredKeys(meta?.data);
1467
+ if (own.length === 0) return null;
1468
+ const resolved = block.website?.entityStore?.resolve(block, meta);
1469
+ const { data } = receivedData(block, meta, resolved?.status === "ready" ? resolved.data : null);
1470
+ const held = block.heldData || {};
1471
+ let fills = null;
1472
+ let route = null;
1473
+ let tagged = null;
1474
+ const out = {};
1475
+ for (const [key] of own) {
1476
+ const value = data[key];
1477
+ if (value === void 0 || value === null) continue;
1478
+ let name;
1479
+ if (held[key] !== void 0) {
1480
+ tagged ??= taggedKeys(block);
1481
+ if (tagged.has(key)) continue;
1482
+ name = key;
1483
+ } else {
1484
+ if (!fills) {
1485
+ route = blockRouteQuery(block);
1486
+ fills = blockFillsOf(block, meta, route);
1487
+ }
1488
+ const fill = fills.get(key);
1489
+ const cfg = fill?.cfg;
1490
+ if (!cfg?.as) continue;
1491
+ if (fillIsPageRecord(block, cfg, route)) {
1492
+ shown.push({ value, whole: fill.whole === true });
1493
+ continue;
1494
+ }
1495
+ name = cfg.as;
1496
+ }
1497
+ if (Object.hasOwn(out, name) && !sameValue(out[name], value)) name = key;
1498
+ if (Object.hasOwn(out, name) && !sameValue(out[name], value)) continue;
1499
+ out[name] = value;
1500
+ }
1501
+ return Object.keys(out).length ? out : null;
1502
+ }
1503
+ function taggedKeys(block) {
1504
+ const parsed = typeof block.parseContent === "function" && block.rawContent ? block.parseContent(block.rawContent) : null;
1505
+ return new Set(Object.keys(parsed?.data || {}));
1506
+ }
1507
+ function sameValue(a, b) {
1508
+ if (a === b) return true;
1509
+ try {
1510
+ return JSON.stringify(a) === JSON.stringify(b);
1511
+ } catch {
1512
+ return false;
1513
+ }
1514
+ }
1415
1515
  function createPageRenderer({ website, shell }) {
1416
1516
  if (!website) throw new Error("createPageRenderer: `website` is required");
1417
1517
  if (typeof shell !== "string") throw new Error("createPageRenderer: `shell` must be an HTML string");
1418
- function render(target, { inject = {}, fetchedData } = {}) {
1518
+ function render(target, { inject = {}, fetchedData, sectionData = false } = {}) {
1419
1519
  if (fetchedData !== void 0 && !Array.isArray(fetchedData)) {
1420
1520
  throw new Error("createPageRenderer: `fetchedData` must be the array of entries the page carries");
1421
1521
  }
@@ -1442,7 +1542,13 @@ function createPageRenderer({ website, shell }) {
1442
1542
  sectionOverrideCSS: result.sectionOverrideCSS,
1443
1543
  icons
1444
1544
  });
1445
- return { outcome: missing ? "notFound" : "rendered", html, page, error: null };
1545
+ const rendered = { outcome: missing ? "notFound" : "rendered", html, page, error: null };
1546
+ if (sectionData) {
1547
+ const shown = sectionRecords(page);
1548
+ rendered.sections = shown.sections;
1549
+ if (shown.record !== void 0) rendered.record = shown.record;
1550
+ }
1551
+ return rendered;
1446
1552
  }
1447
1553
  return { website, render, failingSection: (page, message) => failingSectionOf(page, message) };
1448
1554
  }