@reddoorla/maintenance 0.68.0 → 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.
Files changed (136) hide show
  1. package/dist/airtable-2PJ4NSAV.js +9 -0
  2. package/dist/{announce-72R3LRNT.js → announce-3JE5FKW7.js} +6 -6
  3. package/dist/blux-FKZYMKLF.js +2205 -0
  4. package/dist/blux-FKZYMKLF.js.map +1 -0
  5. package/dist/{bump-deps-QNM3H4GI.js → bump-deps-K3JMLMBB.js} +3 -2
  6. package/dist/bump-deps-K3JMLMBB.js.map +1 -0
  7. package/dist/{chunk-RINXPU3H.js → chunk-2PWQ6MPG.js} +2 -2
  8. package/dist/{chunk-H6YZBXBQ.js → chunk-52TDNN7K.js} +37 -15
  9. package/dist/chunk-52TDNN7K.js.map +1 -0
  10. package/dist/{chunk-XWPZ46IN.js → chunk-5QC5KJHR.js} +2 -2
  11. package/dist/{chunk-O6G4HHMF.js → chunk-6J25IIAI.js} +162 -42
  12. package/dist/chunk-6J25IIAI.js.map +1 -0
  13. package/dist/chunk-7MJBTV2R.js +145 -0
  14. package/dist/chunk-7MJBTV2R.js.map +1 -0
  15. package/dist/{chunk-6JFOAPW4.js → chunk-AYM2EFSK.js} +38 -6
  16. package/dist/chunk-AYM2EFSK.js.map +1 -0
  17. package/dist/{chunk-GKSXZIMX.js → chunk-CMQMNFFJ.js} +77 -3
  18. package/dist/chunk-CMQMNFFJ.js.map +1 -0
  19. package/dist/{chunk-6MT5W6UF.js → chunk-F6OE6MGQ.js} +6 -3
  20. package/dist/chunk-F6OE6MGQ.js.map +1 -0
  21. package/dist/{chunk-OTBA7DON.js → chunk-J2SHWT2O.js} +1 -1
  22. package/dist/chunk-J2SHWT2O.js.map +1 -0
  23. package/dist/{chunk-XVR7UM6Z.js → chunk-JNXCDUYB.js} +4 -4
  24. package/dist/{chunk-2E2X5BCG.js → chunk-KOAGMTRI.js} +3 -3
  25. package/dist/chunk-KRDLHAKK.js +17 -0
  26. package/dist/chunk-KRDLHAKK.js.map +1 -0
  27. package/dist/{chunk-LYCKN7ZR.js → chunk-LPMQXS2N.js} +8 -4
  28. package/dist/chunk-LPMQXS2N.js.map +1 -0
  29. package/dist/{chunk-WCN54744.js → chunk-M7HOQ4W7.js} +388 -8
  30. package/dist/chunk-M7HOQ4W7.js.map +1 -0
  31. package/dist/{chunk-LCKKIJ22.js → chunk-MPRLMGJU.js} +11 -3
  32. package/dist/chunk-MPRLMGJU.js.map +1 -0
  33. package/dist/chunk-PKVZMFEB.js +315 -0
  34. package/dist/chunk-PKVZMFEB.js.map +1 -0
  35. package/dist/{chunk-A5KYRGQA.js → chunk-PSJQE6T6.js} +4 -4
  36. package/dist/chunk-SL24DCGC.js +41 -0
  37. package/dist/chunk-SL24DCGC.js.map +1 -0
  38. package/dist/{chunk-MAYHLXCS.js → chunk-VR246V3G.js} +25 -5
  39. package/dist/chunk-VR246V3G.js.map +1 -0
  40. package/dist/{chunk-45AUGDFR.js → chunk-WN4NEHE7.js} +2 -7
  41. package/dist/chunk-WN4NEHE7.js.map +1 -0
  42. package/dist/{chunk-YQMYQAJX.js → chunk-Y7LZHPDF.js} +2 -2
  43. package/dist/{chunk-C3PDS623.js → chunk-YWRQEDB3.js} +53 -3
  44. package/dist/chunk-YWRQEDB3.js.map +1 -0
  45. package/dist/cli/bin.js +63 -19
  46. package/dist/cli/bin.js.map +1 -1
  47. package/dist/cli/commands/audit.d.ts +1 -1
  48. package/dist/cli/commands/audit.js +13 -11
  49. package/dist/cli/commands/audit.js.map +1 -1
  50. package/dist/client/index.d.ts +84 -0
  51. package/dist/client/index.js +47 -0
  52. package/dist/client/index.js.map +1 -0
  53. package/dist/configs/playwright-a11y.js +1 -1
  54. package/dist/{convert-to-pnpm-XH7NYRVK.js → convert-to-pnpm-6F4RAFEJ.js} +3 -2
  55. package/dist/convert-to-pnpm-6F4RAFEJ.js.map +1 -0
  56. package/dist/{digest-J7TDG62Q.js → digest-GZCZYJKC.js} +11 -11
  57. package/dist/{ensure-site-2PF522VL.js → ensure-site-H5VMBPLF.js} +2 -2
  58. package/dist/forms/index.d.ts +2 -0
  59. package/dist/forms/index.js +7 -1
  60. package/dist/forms/index.js.map +1 -1
  61. package/dist/{github-signals-PP7GWYIY.js → github-signals-SQECQNST.js} +8 -8
  62. package/dist/health-endpoint-QXWM6GW2.js +54 -0
  63. package/dist/health-endpoint-QXWM6GW2.js.map +1 -0
  64. package/dist/index.d.ts +132 -17
  65. package/dist/index.js +213 -70
  66. package/dist/index.js.map +1 -1
  67. package/dist/{init-WLR35YGN.js → init-KQOIPLVT.js} +12 -8
  68. package/dist/init-KQOIPLVT.js.map +1 -0
  69. package/dist/{launch-2HPQXWII.js → launch-RX4VI7F2.js} +13 -13
  70. package/dist/{lighthouse-airtable-UBSXKHAQ.js → lighthouse-airtable-TTXULEGU.js} +3 -3
  71. package/dist/{onboard-X6KJ5Z2V.js → onboard-TFBL62J3.js} +2 -2
  72. package/dist/{orchestrate-PVCGBH4K.js → orchestrate-DYA4XAQJ.js} +6 -6
  73. package/dist/{preflight-KWVYJ2DU.js → preflight-S3GYME3Q.js} +8 -8
  74. package/dist/probe-DJAMLVTT.js +46 -0
  75. package/dist/probe-DJAMLVTT.js.map +1 -0
  76. package/dist/recipes/sync-configs.d.ts +1 -1
  77. package/dist/recipes/sync-configs.js +2 -2
  78. package/dist/{renovate-dispatch-LG4RJGDY.js → renovate-dispatch-MZPAWVBL.js} +2 -2
  79. package/dist/{report-ZBFMTT76.js → report-BLZ67QAQ.js} +12 -12
  80. package/dist/run-migration-LJNNZWIV.js +205 -0
  81. package/dist/run-migration-LJNNZWIV.js.map +1 -0
  82. package/dist/{self-updating-JTTFOJ7Q.js → self-updating-GSH427XP.js} +2 -2
  83. package/dist/{selftest-LFZPZRJP.js → selftest-KPTL6KC4.js} +11 -11
  84. package/dist/smoke-suite-GP3W57JP.js +54 -0
  85. package/dist/smoke-suite-GP3W57JP.js.map +1 -0
  86. package/dist/{svelte-codemods-KJLNH6FQ.js → svelte-codemods-GYZZX742.js} +3 -2
  87. package/dist/svelte-codemods-GYZZX742.js.map +1 -0
  88. package/dist/{sync-configs-6GBZLGRQ.js → sync-configs-CQNOTJ2B.js} +5 -4
  89. package/dist/sync-configs-CQNOTJ2B.js.map +1 -0
  90. package/dist/{types-Dg4mHvyf.d.ts → types-0jreMCF5.d.ts} +2 -2
  91. package/dist/{upgrade-TPTE26FG.js → upgrade-RTAJZD56.js} +3 -2
  92. package/dist/upgrade-RTAJZD56.js.map +1 -0
  93. package/dist/{websites-6YTT5ZTO.js → websites-SVI4KYSH.js} +8 -2
  94. package/dist/{write-audits-to-airtable-IWOO4FFH.js → write-audits-to-airtable-3XFNWMUE.js} +4 -4
  95. package/package.json +8 -1
  96. package/dist/airtable-WGQQ3KAD.js +0 -9
  97. package/dist/bump-deps-QNM3H4GI.js.map +0 -1
  98. package/dist/chunk-45AUGDFR.js.map +0 -1
  99. package/dist/chunk-6JFOAPW4.js.map +0 -1
  100. package/dist/chunk-6MT5W6UF.js.map +0 -1
  101. package/dist/chunk-C3PDS623.js.map +0 -1
  102. package/dist/chunk-GKSXZIMX.js.map +0 -1
  103. package/dist/chunk-H6YZBXBQ.js.map +0 -1
  104. package/dist/chunk-LCKKIJ22.js.map +0 -1
  105. package/dist/chunk-LYCKN7ZR.js.map +0 -1
  106. package/dist/chunk-MAYHLXCS.js.map +0 -1
  107. package/dist/chunk-O6G4HHMF.js.map +0 -1
  108. package/dist/chunk-OTBA7DON.js.map +0 -1
  109. package/dist/chunk-WCN54744.js.map +0 -1
  110. package/dist/convert-to-pnpm-XH7NYRVK.js.map +0 -1
  111. package/dist/init-WLR35YGN.js.map +0 -1
  112. package/dist/svelte-codemods-KJLNH6FQ.js.map +0 -1
  113. package/dist/sync-configs-6GBZLGRQ.js.map +0 -1
  114. package/dist/upgrade-TPTE26FG.js.map +0 -1
  115. /package/dist/{airtable-WGQQ3KAD.js.map → airtable-2PJ4NSAV.js.map} +0 -0
  116. /package/dist/{announce-72R3LRNT.js.map → announce-3JE5FKW7.js.map} +0 -0
  117. /package/dist/{chunk-RINXPU3H.js.map → chunk-2PWQ6MPG.js.map} +0 -0
  118. /package/dist/{chunk-XWPZ46IN.js.map → chunk-5QC5KJHR.js.map} +0 -0
  119. /package/dist/{chunk-XVR7UM6Z.js.map → chunk-JNXCDUYB.js.map} +0 -0
  120. /package/dist/{chunk-2E2X5BCG.js.map → chunk-KOAGMTRI.js.map} +0 -0
  121. /package/dist/{chunk-A5KYRGQA.js.map → chunk-PSJQE6T6.js.map} +0 -0
  122. /package/dist/{chunk-YQMYQAJX.js.map → chunk-Y7LZHPDF.js.map} +0 -0
  123. /package/dist/{digest-J7TDG62Q.js.map → digest-GZCZYJKC.js.map} +0 -0
  124. /package/dist/{ensure-site-2PF522VL.js.map → ensure-site-H5VMBPLF.js.map} +0 -0
  125. /package/dist/{github-signals-PP7GWYIY.js.map → github-signals-SQECQNST.js.map} +0 -0
  126. /package/dist/{launch-2HPQXWII.js.map → launch-RX4VI7F2.js.map} +0 -0
  127. /package/dist/{lighthouse-airtable-UBSXKHAQ.js.map → lighthouse-airtable-TTXULEGU.js.map} +0 -0
  128. /package/dist/{onboard-X6KJ5Z2V.js.map → onboard-TFBL62J3.js.map} +0 -0
  129. /package/dist/{orchestrate-PVCGBH4K.js.map → orchestrate-DYA4XAQJ.js.map} +0 -0
  130. /package/dist/{preflight-KWVYJ2DU.js.map → preflight-S3GYME3Q.js.map} +0 -0
  131. /package/dist/{renovate-dispatch-LG4RJGDY.js.map → renovate-dispatch-MZPAWVBL.js.map} +0 -0
  132. /package/dist/{report-ZBFMTT76.js.map → report-BLZ67QAQ.js.map} +0 -0
  133. /package/dist/{self-updating-JTTFOJ7Q.js.map → self-updating-GSH427XP.js.map} +0 -0
  134. /package/dist/{selftest-LFZPZRJP.js.map → selftest-KPTL6KC4.js.map} +0 -0
  135. /package/dist/{websites-6YTT5ZTO.js.map → websites-SVI4KYSH.js.map} +0 -0
  136. /package/dist/{write-audits-to-airtable-IWOO4FFH.js.map → write-audits-to-airtable-3XFNWMUE.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/blux.ts","../src/blux/parse.ts","../src/blux/archetype.ts","../src/blux/normalize.ts","../src/blux/collections.ts","../src/blux/assemble.ts","../src/blux/emit/plan.ts","../src/blux/emit/custom-types.ts","../src/blux/emit/coerce-html.ts","../src/blux/emit/slices.ts","../src/blux/emit/flatten.ts","../src/blux/emit/migration-plan.ts","../src/blux/emit/theme.ts","../src/blux/emit/review.ts","../src/blux/validate.ts","../src/blux/grid/parse-grid.ts","../src/blux/grid/token.ts","../src/blux/grid/leaf.ts","../src/blux/grid/classify-band.ts","../src/blux/grid/extract-map.ts","../src/blux/emit/block-styles.ts","../src/blux/emit/grid-slice.ts","../src/blux/emit/grid-plan.ts","../src/blux/emit/presentation.ts","../src/blux/emit/convert.ts","../src/blux/emit/validate-layout.ts","../src/blux/emit/rewrite-manifest.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { glob } from \"tinyglobby\";\nimport { assembleIR } from \"../../blux/assemble.js\";\nimport { buildMigrationPlan } from \"../../blux/emit/migration-plan.js\";\nimport { emitThemeCss, emitRolesCss } from \"../../blux/emit/theme.js\";\nimport { buildReviewManifest } from \"../../blux/emit/review.js\";\nimport { validateCoverage } from \"../../blux/validate.js\";\nimport { parseGridBands, extractMapConfig } from \"../../blux/grid/index.js\";\nimport { convertExport } from \"../../blux/emit/convert.js\";\nimport { validateLayout, formatLayoutReport } from \"../../blux/emit/validate-layout.js\";\nimport { rewriteManifestUrls } from \"../../blux/emit/rewrite-manifest.js\";\nimport type { Presentation } from \"../../blux/emit/presentation.js\";\nimport type { MigrationPlan } from \"../../blux/emit/plan.js\";\n\nexport type BluxCommandOptions = {\n /** Output directory for emit (default: <exportDir>/blux-out). */\n out?: string;\n /** Base URL of the converted site for the review manifest. */\n convertedBase?: string;\n /** Base URL of the original Blux site (default: https://<site.json domain>). */\n bluxBase?: string;\n /** Reconstruct + HEAD-probe CDN URLs for used assets the HTML scrape missed (network). */\n probe?: boolean;\n /** validate: the converted site's rendered HTML — a file path or http(s) URL. */\n against?: string;\n /** Test seam for --probe; defaults to global fetch. */\n fetchImpl?: typeof fetch;\n cwd?: string;\n verbose?: boolean;\n};\n\n/** `blux <action> [dir]` — emit: Blux export dir → migration plan + custom-type\n * schemas + theme CSS + review manifest, all deterministic and offline.\n * migrate: a previously emitted plan → live Prismic (creds-gated; the runner\n * is imported lazily so emit runs never touch @prismicio).\n * validate: offline layout-fidelity gate (parse+classify index.html, diff the\n * emitted manifest vs the source answer key) — exits non-zero on drift.\n * --against <file|url> additionally runs content coverage of a rendered page.\n * grid: parse rendered index.html → grid-tree.json (layout tree).\n * convert: parse+classify index.html + assemble IR from site.json → the grid\n * migration-plan.json (page doc) + blux-presentation.json (render manifest) +\n * theme.css (+ map-config.json when a map is present), all offline, no creds. */\nexport async function runBluxCommand(\n action: string,\n dir: string | undefined,\n opts: BluxCommandOptions,\n): Promise<{ output: string; code: number }> {\n if (action === \"emit\") {\n if (!dir) return { output: \"blux emit needs a Blux export directory.\", code: 1 };\n let siteJson: unknown;\n try {\n siteJson = JSON.parse(await readFile(join(dir, \"site.json\"), \"utf-8\"));\n } catch (err) {\n return {\n output: `could not read site.json in ${dir}: ${(err as Error).message}`,\n code: 1,\n };\n }\n const out = opts.out ?? join(dir, \"blux-out\");\n const htmlPaths = (\n await glob([\"**/*.html\"], { cwd: dir, absolute: true, ignore: [\"blux-out/**\"] })\n ).sort();\n const htmls = await Promise.all(htmlPaths.map((p) => readFile(p, \"utf-8\")));\n\n const ir = assembleIR({ siteJson, htmls });\n\n let probeLine = \"\";\n if (opts.probe) {\n const { probeAssetUrls } = await import(\"../../blux/emit/probe.js\");\n // derive \"used\" from the plan's own __asset_id markers — the single\n // source of truth for which assets documents actually reference\n const used = new Set<string>();\n const collect = (v: unknown): void => {\n if (!v || typeof v !== \"object\") return;\n if (\"__asset_id\" in v) used.add((v as { __asset_id: string }).__asset_id);\n else if (Array.isArray(v)) v.forEach(collect);\n else Object.values(v).forEach(collect);\n };\n buildMigrationPlan(ir).documents.forEach((d) => collect(d.data));\n\n const targets = ir.assets.filter((a) => used.has(a.id) && !a.sourceUrl);\n const probed = await probeAssetUrls(targets, ir.meta.bluxSiteId, opts.fetchImpl ?? fetch);\n let hits = 0;\n for (const a of ir.assets) {\n const url = probed.get(a.id);\n if (url) {\n a.sourceUrl = url;\n hits++;\n }\n }\n ir.diagnostics = ir.diagnostics.filter(\n (d) => !(d.kind === \"unresolved-asset\" && probed.get(d.where)),\n );\n probeLine = `probe resolved ${hits}/${targets.length} used assets`;\n }\n\n const plan = buildMigrationPlan(ir);\n const manifest = buildReviewManifest(ir, {\n convertedBase: opts.convertedBase ?? \"http://localhost:5173\",\n bluxBase: opts.bluxBase ?? `https://${ir.meta.domain}`,\n });\n\n await mkdir(join(out, \"customtypes\"), { recursive: true });\n await writeFile(join(out, \"ir.json\"), JSON.stringify(ir, null, 2));\n await writeFile(join(out, \"migration-plan.json\"), JSON.stringify(plan, null, 2));\n const rolesCss = emitRolesCss(ir.theme);\n await writeFile(\n join(out, \"theme.css\"),\n emitThemeCss(ir.theme) + (rolesCss ? \"\\n\" + rolesCss : \"\"),\n );\n await writeFile(join(out, \"review-manifest.json\"), JSON.stringify(manifest, null, 2));\n await writeFile(\n join(out, \"styles-manifest.json\"),\n JSON.stringify(plan.stylesManifest, null, 2),\n );\n for (const ct of plan.customTypes) {\n await writeFile(join(out, \"customtypes\", `${ct.id}.json`), JSON.stringify(ct.json, null, 2));\n }\n\n const resolved = ir.assets.filter((a) => a.sourceUrl !== null).length;\n const diagnostics = [...ir.diagnostics, ...plan.diagnostics];\n const lines = [\n `site: ${ir.meta.name} (${ir.meta.domain})`,\n ...(probeLine ? [probeLine] : []),\n `pages: ${ir.pages.length} | custom types: ${plan.customTypes.length} | documents: ${plan.documents.length} | assets: ${resolved}/${ir.assets.length} resolved`,\n `diagnostics: ${diagnostics.length}`,\n ...diagnostics.map((d) => ` - [${d.kind}] ${d.where}: ${d.message}`),\n `wrote ${out}`,\n ];\n return { output: lines.join(\"\\n\"), code: 0 };\n }\n\n if (action === \"migrate\") {\n if (!dir) {\n return {\n output: \"blux migrate needs an emitted output directory (or a plan .json path).\",\n code: 1,\n };\n }\n if (!process.env.PRISMIC_REPOSITORY_NAME || !process.env.PRISMIC_WRITE_TOKEN) {\n return {\n output: \"Set PRISMIC_REPOSITORY_NAME and PRISMIC_WRITE_TOKEN to run a live migration.\",\n code: 1,\n };\n }\n const planPath = dir.endsWith(\".json\") ? dir : join(dir, \"migration-plan.json\");\n const plan = JSON.parse(await readFile(planPath, \"utf-8\")) as MigrationPlan;\n const { pushCustomTypes, runMigration } = await import(\"../../blux/emit/run-migration.js\");\n const pushed = await pushCustomTypes(plan.customTypes);\n // stream progress to stderr — a throttled run over many assets/docs takes\n // minutes and silence reads as a hang; stdout stays the result summary\n const r = await runMigration(plan, (line) => process.stderr.write(`${line}\\n`));\n const missing = r.missingAssets.length\n ? `\\nWARNING missing assets: ${r.missingAssets.join(\", \")}`\n : \"\";\n // Rewrite the render manifest's media urls from the CDN url the export\n // carries → the durable Prismic url we just uploaded to. Skipped silently\n // when no manifest sits beside the plan (e.g. an archetype-only emit).\n let manifestNote = \"\";\n const manifestPath = join(dirname(planPath), \"blux-presentation.json\");\n try {\n const manifest = JSON.parse(await readFile(manifestPath, \"utf-8\")) as Presentation;\n const rewritten = rewriteManifestUrls(manifest, r.assetUrlByCdn);\n await writeFile(manifestPath, JSON.stringify(rewritten, null, 2) + \"\\n\");\n manifestNote = \"\\nmanifest media rewritten to Prismic urls\";\n } catch {\n /* no manifest beside the plan (e.g. archetype emit) — skip silently */\n }\n return {\n output:\n `custom types pushed: ${pushed.join(\", \") || \"none\"}\\n` +\n `assets: ${r.assetsUploaded} uploaded, ${r.assetsReused} reused | ` +\n `documents: ${r.docsCreated} created, ${r.docsUpdated} updated → ` +\n `${process.env.PRISMIC_REPOSITORY_NAME} (publish the migration release in the dashboard)` +\n missing +\n manifestNote,\n code: 0,\n };\n }\n\n if (action === \"validate\") {\n if (!dir) return { output: \"blux validate needs a Blux export directory.\", code: 1 };\n let exportHtml: string;\n try {\n exportHtml = await readFile(join(dir, \"index.html\"), \"utf-8\");\n } catch (err) {\n return { output: `could not read index.html in ${dir}: ${(err as Error).message}`, code: 1 };\n }\n\n // Resolve the optional --against render FIRST so a bad target hard-fails\n // before we spend the convert pipeline (and so its error message wins).\n let rendered: string | null = null;\n if (opts.against) {\n try {\n if (/^https?:\\/\\//.test(opts.against)) {\n const res = await (opts.fetchImpl ?? fetch)(opts.against);\n if (!res.ok) {\n return {\n output: `could not fetch --against ${opts.against}: HTTP ${res.status}`,\n code: 1,\n };\n }\n rendered = await res.text();\n } else {\n rendered = await readFile(opts.against, \"utf-8\");\n }\n } catch (err) {\n return {\n output: `could not read --against ${opts.against}: ${(err as Error).message}`,\n code: 1,\n };\n }\n }\n\n let siteJson: unknown;\n try {\n siteJson = JSON.parse(await readFile(join(dir, \"site.json\"), \"utf-8\"));\n } catch (err) {\n return { output: `could not read site.json in ${dir}: ${(err as Error).message}`, code: 1 };\n }\n\n const { specs, presentation } = convertExport({ html: exportHtml, siteJson });\n const layout = validateLayout(specs, presentation);\n const lines = [formatLayoutReport(layout)];\n\n // Content coverage is informational only — it names export text the render\n // dropped, but layout fidelity alone gates the exit code below. A coverage\n // gap never flips a faithful layout to a non-zero exit.\n if (rendered !== null) {\n const report = validateCoverage(exportHtml, rendered);\n lines.push(\n \"\",\n `content coverage: ${report.covered}/${report.total} runs (${report.coveragePct}%)`,\n ...(report.missing.length\n ? [\n \"missing runs — export text absent from the render:\",\n ...report.missing.map((m) => ` - ${m}`),\n ]\n : [\"all export text runs present in the render\"]),\n );\n }\n\n return { output: lines.join(\"\\n\"), code: layout.faithful ? 0 : 1 };\n }\n\n if (action === \"grid\") {\n if (!dir) return { output: \"blux grid needs a Blux export directory.\", code: 1 };\n let html: string;\n try {\n html = await readFile(join(dir, \"index.html\"), \"utf-8\");\n } catch (err) {\n return {\n output: `could not read index.html in ${dir}: ${(err as Error).message}`,\n code: 1,\n };\n }\n const bands = parseGridBands(html);\n const outDir = opts.out ?? join(dir, \"blux-out\");\n await mkdir(outDir, { recursive: true });\n await writeFile(join(outDir, \"grid-tree.json\"), JSON.stringify(bands, null, 2));\n const mapConfig = extractMapConfig(html);\n if (mapConfig) {\n await writeFile(\n join(outDir, \"map-config.json\"),\n JSON.stringify(mapConfig, null, 2) + \"\\n\",\n \"utf-8\",\n );\n }\n return {\n output:\n `Parsed ${bands.length} bands → ${join(outDir, \"grid-tree.json\")}` +\n (mapConfig ? \", map config extracted\" : \"\"),\n code: 0,\n };\n }\n\n if (action === \"convert\") {\n if (!dir) return { output: \"blux convert needs a Blux export directory.\", code: 1 };\n let html: string;\n let siteJson: unknown;\n try {\n html = await readFile(join(dir, \"index.html\"), \"utf-8\");\n siteJson = JSON.parse(await readFile(join(dir, \"site.json\"), \"utf-8\"));\n } catch (err) {\n return { output: `could not read export in ${dir}: ${(err as Error).message}`, code: 1 };\n }\n const { bands, mapConfig, plan, presentation, ir, specs } = convertExport({ html, siteJson });\n\n const outDir = opts.out ?? join(dir, \"blux-out\");\n await mkdir(outDir, { recursive: true });\n await writeFile(join(outDir, \"migration-plan.json\"), JSON.stringify(plan, null, 2));\n await writeFile(\n join(outDir, \"blux-presentation.json\"),\n JSON.stringify(presentation, null, 2) + \"\\n\",\n );\n await writeFile(\n join(outDir, \"theme.css\"),\n emitThemeCss(ir.theme) + \"\\n\" + emitRolesCss(ir.theme),\n );\n if (mapConfig) {\n await writeFile(join(outDir, \"map-config.json\"), JSON.stringify(mapConfig, null, 2) + \"\\n\");\n }\n const layout = validateLayout(specs, presentation);\n await writeFile(join(outDir, \"layout-report.json\"), JSON.stringify(layout, null, 2) + \"\\n\");\n const sliceCount = (plan.documents[0]?.data.slices as unknown[] | undefined)?.length ?? 0;\n return {\n output:\n `Converted ${bands.length} bands → ${outDir} ` +\n `(${Object.keys(presentation.bands).length} manifest bands, ${sliceCount} slices` +\n (mapConfig ? \", map config extracted\" : \"\") +\n \")\\n\" +\n formatLayoutReport(layout),\n code: 0,\n };\n }\n\n return {\n output: `unknown blux action '${action}'. Use: emit, migrate, validate, grid, convert.`,\n code: 1,\n };\n}\n","/** Style config for a block's title/body. `class: \"disable\"` (or the bare\n * string \"disable\") hides that element on the rendered site. */\nexport type BluxTextStyle = string | { class?: string; [key: string]: unknown };\n\nexport type BluxBlock = {\n title?: string;\n _title?: BluxTextStyle;\n body?: string;\n _body?: BluxTextStyle;\n media?: { media?: string };\n backgroundMedia?: { media?: string };\n class?: string;\n ratio?: string;\n loadEffect?: string;\n items?: BluxBlock[];\n styles?: Record<string, unknown>;\n};\n\nconst hasDisable = (cls: unknown) =>\n typeof cls === \"string\" && cls.split(/\\s+/).includes(\"disable\");\n\n/** Display text of a Blux title/body pair, or undefined when the element is\n * hidden. Blux stores the text itself in `title`/`body`; the underscore twin\n * (`_title`/`_body`) is style config whose `class: \"disable\"` hides the\n * element, so its text must not be migrated. */\nexport function visibleText(text: unknown, style: BluxTextStyle | undefined): string | undefined {\n const s = typeof text === \"number\" && Number.isFinite(text) ? String(text) : text;\n if (typeof s !== \"string\" || s.trim() === \"\") return undefined;\n if (hasDisable(style)) return undefined;\n if (typeof style === \"object\" && style !== null && hasDisable(style.class)) return undefined;\n return s.trim();\n}\nexport type BluxPage = { title?: string; description?: string; items?: BluxBlock[] };\nexport type BluxFeed = {\n name?: string;\n source?: string;\n publish?: string;\n fields?: { title?: string; field?: string; type?: string }[];\n items?: Record<string, unknown>[];\n};\nexport type BluxMedia = { name?: string; type?: string; size?: unknown; siteID?: string };\nexport type BluxRaw = {\n meta: { name: string; domain: string; bluxSiteId: string };\n pages: BluxPage[];\n feeds: Record<string, BluxFeed>;\n media: Record<string, BluxMedia>;\n styles: {\n colors?: Record<string, string>;\n text?: Record<string, unknown>;\n buttons?: Record<string, unknown>;\n };\n nav: { title?: string; url?: string }[];\n settings: { fonts?: { heading?: string; body?: string } };\n};\n\nfunction asObject(v: unknown): Record<string, unknown> {\n if (!v || typeof v !== \"object\" || Array.isArray(v)) {\n throw new Error(\"Invalid site.json: expected an object\");\n }\n return v as Record<string, unknown>;\n}\n\nexport function parseBluxSite(input: unknown): BluxRaw {\n const j = asObject(input);\n const content = (j.content ?? {}) as { pages?: BluxPage[] };\n const styles = (j.styles ?? {}) as BluxRaw[\"styles\"];\n const nav = ((j.navigation as { items?: unknown }[] | undefined)?.[0]?.items ?? []) as {\n title?: string;\n url?: string;\n }[];\n return {\n meta: {\n name: String(j.name ?? \"\"),\n domain: String(j.domain ?? \"\"),\n bluxSiteId: String(j.id ?? \"\"),\n },\n pages: Array.isArray(content.pages) ? content.pages : [],\n feeds: (j.feeds ?? {}) as Record<string, BluxFeed>,\n media: (j.media ?? {}) as Record<string, BluxMedia>,\n styles,\n nav,\n settings: (j.settings ?? {}) as BluxRaw[\"settings\"],\n };\n}\n","import { visibleText, type BluxBlock } from \"./parse.js\";\n\nconst nonEmpty = (v: unknown): boolean =>\n v != null &&\n v !== \"\" &&\n !(Array.isArray(v) && v.length === 0) &&\n !(typeof v === \"object\" && !Array.isArray(v) && Object.keys(v as object).length === 0);\n\nexport type ArchetypeResult = {\n sliceType: \"hero\" | \"media_text\" | \"rich_text\" | \"grid\" | \"slider\" | \"collection_list\";\n variation: string;\n confidence: number;\n};\n\nexport function archetype(b: BluxBlock): ArchetypeResult {\n const heading = visibleText(b.title, b._title) !== undefined;\n const text = visibleText(b.body, b._body) !== undefined;\n const media = nonEmpty(b.media?.media);\n const bg = nonEmpty(b.backgroundMedia?.media);\n const kids = Array.isArray(b.items) && b.items.length > 0;\n const cls = nonEmpty(b.class) ? String(b.class) : null;\n\n // Slides keep their grouping even under a background — exploding a\n // carousel into siblings loses more than dropping its backdrop does.\n if (kids && cls === \"slides\")\n return { sliceType: \"slider\", variation: \"default\", confidence: 0.85 };\n // A background image/video makes a hero even with no visible copy — Blux\n // uses text-less full-bleed banners (e.g. a hero video with a disabled label).\n if (bg)\n return { sliceType: \"hero\", variation: \"default\", confidence: heading || text ? 0.9 : 0.7 };\n if (kids)\n return { sliceType: \"grid\", variation: \"default\", confidence: cls === \"grid\" ? 0.9 : 0.7 };\n // Any visible copy next to media is a media_text; media alone still is,\n // just with less certainty.\n if (media && heading && text)\n return { sliceType: \"media_text\", variation: \"imageRight\", confidence: 0.9 };\n if (media && (heading || text))\n return { sliceType: \"media_text\", variation: \"imageRight\", confidence: 0.75 };\n if (media) return { sliceType: \"media_text\", variation: \"imageRight\", confidence: 0.6 };\n if (heading && text) return { sliceType: \"rich_text\", variation: \"default\", confidence: 0.85 };\n if (heading || text) return { sliceType: \"rich_text\", variation: \"default\", confidence: 0.6 };\n return { sliceType: \"rich_text\", variation: \"default\", confidence: 0.2 };\n}\n","import { visibleText, type BluxBlock, type BluxRaw, type BluxTextStyle } from \"./parse.js\";\nimport { archetype } from \"./archetype.js\";\nimport type { FontLoad, PageIR, SectionIR, TextStyleIR, ThemeIR, Diagnostic } from \"./ir.js\";\n\n/** The styles.text role (\"text5\") a block's _title/_body class points at. */\nfunction textRole(style: BluxTextStyle | undefined): string | undefined {\n const cls = typeof style === \"object\" && style !== null ? style.class : style;\n if (typeof cls !== \"string\") return undefined;\n return cls.split(/\\s+/).find((c) => /^text\\d+$/.test(c));\n}\n\nconst str = (x: unknown): string =>\n typeof x === \"string\" ? x : typeof x === \"number\" ? String(x) : \"\";\n\n/** A cleaned CSS value, or \"\" when the export left a malformed one. Blux emits\n * degenerate placeholders — \"\" and \"px\" for unset lengths, \"0.px\" for a zeroed\n * one — which would poison a Tailwind custom property (an invalid `var()` value\n * collapses the whole declaration). Those are always single tokens, so the\n * numeric-prefix guard runs only on a lone length; multi-value shorthands\n * (\"10px 40px 10px 40px\"), colors, \"0\", and keywords all pass through. */\nexport function cleanCssValue(x: unknown): string {\n const s = str(x).trim();\n if (s === \"\" || s === \"px\") return \"\";\n if (!/\\s/.test(s) && /px$/.test(s) && !/^-?(\\d+(\\.\\d+)?|\\.\\d+)px$/.test(s)) return \"\";\n return s;\n}\n\n/** Per-element inline style overrides on a _title/_body element (color,\n * font-size, margin, …) minus the `class` token, cleaned. undefined when none\n * survive — e.g. a hero title's `{ class: \"text0\", color: \"#fff\" }` white\n * override that a role reference alone would lose. */\nfunction inlineStyle(style: BluxTextStyle | undefined): Record<string, string> | undefined {\n if (typeof style !== \"object\" || style === null) return undefined;\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(style)) {\n if (k === \"class\") continue;\n const cleaned = cleanCssValue(v);\n if (cleaned) out[k] = cleaned;\n }\n return Object.keys(out).length ? out : undefined;\n}\n\n/** Parse `settings.fonts.google` (\"Scope+One:regular|Montserrat:300,500,regular\")\n * into families + numeric weights (\"regular\" → \"400\"). */\nfunction parseGoogleFonts(google: string): FontLoad[] {\n if (!google.trim()) return [];\n return google\n .split(\"|\")\n .map((spec) => {\n const [rawFamily = \"\", rawWeights = \"\"] = spec.split(\":\");\n const family = rawFamily.replace(/\\+/g, \" \").trim();\n const weights = rawWeights\n .split(\",\")\n .map((w) => w.trim())\n .filter(Boolean)\n .map((w) => (w === \"regular\" ? \"400\" : w));\n return { family, weights: weights.length ? weights : [\"400\"] };\n })\n .filter((f) => f.family);\n}\n\n/** The real font-family for a text style. A Typekit `font-ident`\n * (`T:Family:variant:obfuscated`) carries the true family in segment 2 while\n * `font-family` holds the obfuscated id (e.g. `ysxc`); Google idents (`G:…`) and\n * missing idents already have the true family in `font-family`. */\nfunction fontFamilyFromStyle(m: Record<string, unknown>): string {\n const ident = str(m[\"font-ident\"]);\n if (ident.startsWith(\"T:\")) {\n const fam = ident.split(\":\")[1]?.trim();\n if (fam) return fam;\n }\n return str(m[\"font-family\"]).replace(/['\"]/g, \"\");\n}\n\n/** Typekit fonts to preload, parsed from the comma-separated `settings.fonts.string`\n * idents (`T:Montserrat:n6:ysxc`). `fonts.google` omits Typekit faces, so the page's\n * Montserrat 600 would otherwise never be requested. Variant `nN`/`iN` → weight N×100. */\nfunction typekitFontLoads(fontString: string): FontLoad[] {\n const byFamily = new Map<string, string[]>();\n for (const ident of fontString.split(\",\").map((s) => s.trim())) {\n if (!ident.startsWith(\"T:\")) continue;\n const [, family = \"\", variant = \"\"] = ident.split(\":\");\n const fam = family.trim();\n if (!fam) continue;\n const v = variant.trim();\n const digit = /^[ni](\\d)$/.exec(v);\n const weight = digit ? `${Number(digit[1]) * 100}` : v === \"regular\" ? \"400\" : v;\n if (!weight) continue;\n const ws = byFamily.get(fam) ?? [];\n if (!ws.includes(weight)) ws.push(weight);\n byFamily.set(fam, ws);\n }\n return [...byFamily].map(([family, weights]) => ({ family, weights }));\n}\n\n/** Union `extra` font-loads into `base`, preserving `base` order and folding new\n * weights into an existing family (so Montserrat gains 600 instead of duplicating). */\nfunction mergeFontLoads(base: FontLoad[], extra: FontLoad[]): FontLoad[] {\n const out = base.map((f) => ({ family: f.family, weights: [...f.weights] }));\n for (const e of extra) {\n const existing = out.find((f) => f.family === e.family);\n if (existing) {\n for (const w of e.weights) if (!existing.weights.includes(w)) existing.weights.push(w);\n } else {\n out.push({ family: e.family, weights: [...e.weights] });\n }\n }\n return out;\n}\n\nconst CONFIDENCE_MIN = 0.5;\n\nfunction sectionFromBlock(b: BluxBlock, pageUid: string, diagnostics: Diagnostic[]): SectionIR {\n const a = archetype(b);\n if (a.confidence < CONFIDENCE_MIN) {\n diagnostics.push({\n kind: \"low-confidence-block\",\n where: pageUid,\n message: `block mapped to ${a.sliceType} at ${a.confidence}`,\n });\n }\n const heading = visibleText(b.title, b._title);\n const body = visibleText(b.body, b._body);\n const headingRole = heading !== undefined ? textRole(b._title) : undefined;\n const bodyRole = body !== undefined ? textRole(b._body) : undefined;\n const headingStyle = heading !== undefined ? inlineStyle(b._title) : undefined;\n const bodyStyle = body !== undefined ? inlineStyle(b._body) : undefined;\n // Route every value through cleanCssValue (as inlineStyle does) so numeric\n // block styles (a JSON `\"z-index\": 10`) are kept, not silently dropped.\n const block: Record<string, string> = {};\n for (const [k, v] of Object.entries(b.styles ?? {})) {\n const cleaned = cleanCssValue(v);\n if (cleaned) block[k] = cleaned;\n }\n const presentation = {\n ...(headingRole ? { headingRole } : {}),\n ...(bodyRole ? { bodyRole } : {}),\n ...(headingStyle ? { headingStyle } : {}),\n ...(bodyStyle ? { bodyStyle } : {}),\n ...(Object.keys(block).length ? { block } : {}),\n };\n const section: SectionIR = {\n sliceType: a.sliceType,\n variation: a.variation,\n confidence: a.confidence,\n fields: {\n ...(heading !== undefined ? { heading } : {}),\n ...(body !== undefined ? { body } : {}),\n ...(b.media?.media ? { media: b.media.media } : {}),\n ...(b.backgroundMedia?.media ? { backgroundMedia: b.backgroundMedia.media } : {}),\n ...(b.ratio ? { ratio: String(b.ratio) } : {}),\n ...(b.loadEffect ? { anim: String(b.loadEffect) } : {}),\n },\n ...(Object.keys(presentation).length ? { presentation } : {}),\n };\n if (Array.isArray(b.items) && b.items.length > 0) {\n section.children = b.items.map((child) => sectionFromBlock(child, pageUid, diagnostics));\n }\n return section;\n}\n\nfunction slugify(s: string): string {\n return (\n s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\") || \"page\"\n );\n}\n\nexport function normalizePages(raw: BluxRaw): { pages: PageIR[]; diagnostics: Diagnostic[] } {\n const diagnostics: Diagnostic[] = [];\n const pages = raw.pages.map((p) => {\n const uid = slugify(String(p.title ?? \"\"));\n return {\n uid,\n title: String(p.title ?? \"\"),\n description: String(p.description ?? \"\"),\n sections: (p.items ?? []).map((b) => sectionFromBlock(b, uid, diagnostics)),\n };\n });\n return { pages, diagnostics };\n}\n\nexport function normalizeTheme(raw: BluxRaw): ThemeIR {\n const colors = Object.entries(raw.styles.colors ?? {}).map(([role, value]) => ({\n role,\n value: String(value),\n }));\n // styles.text is a position-stable array whose slots are { _label,\n // \".textN\": { css props incl font-ident } }. A deleted style leaves a\n // { removed: true } tombstone with no \".textN\" key — the role name comes\n // from that inner key (not the array index), so tombstones drop out and\n // roles never renumber if the array is ever compacted.\n const textStyles: TextStyleIR[] = [];\n for (const v of Object.values(raw.styles.text ?? {})) {\n const entry = (v ?? {}) as Record<string, unknown>;\n const innerKey = Object.keys(entry).find((k) => /^\\.text\\d+$/.test(k));\n if (!innerKey) continue;\n const m = (entry[innerKey] ?? {}) as Record<string, unknown>;\n const transform = cleanCssValue(m[\"text-transform\"]);\n const tracking = cleanCssValue(m[\"letter-spacing\"]);\n const mobileSize = cleanCssValue(m[\"__media_mobile_font-size\"]);\n const mobileLineHeight = cleanCssValue(m[\"__media_mobile_line-height\"]);\n textStyles.push({\n role: innerKey.slice(1), // \".text11\" -> \"text11\"\n label: str(entry._label),\n fontFamily: fontFamilyFromStyle(m),\n size: cleanCssValue(m[\"font-size\"]) || \"16px\",\n weight:\n typeof m[\"font-weight\"] === \"number\" ? m[\"font-weight\"] : str(m[\"font-weight\"]) || 400,\n lineHeight: cleanCssValue(m[\"line-height\"]) || \"1.5\",\n ...(transform && transform !== \"none\" ? { transform } : {}),\n ...(tracking ? { letterSpacing: tracking } : {}),\n ...(mobileSize ? { mobileSize } : {}),\n ...(mobileLineHeight ? { mobileLineHeight } : {}),\n });\n }\n // Fonts: explicit settings win; otherwise Blux's own default roles —\n // text0 \"Title (Default)\" and text1 \"Body (Default)\".\n const fonts = (raw.settings.fonts ?? {}) as Record<string, unknown>;\n const roleFont = (r: string) => textStyles.find((t) => t.role === r)?.fontFamily ?? \"\";\n return {\n colors,\n fonts: {\n heading: str(fonts.heading) || roleFont(\"text0\"),\n body: str(fonts.body) || roleFont(\"text1\"),\n },\n fontLoad: mergeFontLoads(\n parseGoogleFonts(str(fonts.google)),\n typekitFontLoads(str(fonts.string)),\n ),\n textStyles,\n };\n}\n","import type { BluxFeed, BluxRaw } from \"./parse.js\";\nimport type { CollectionIR, FieldDef, RecordIR } from \"./ir.js\";\n\nfunction singularSlug(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_|_$/g, \"\");\n return slug.replace(/s$/, \"\") || \"item\";\n}\n\nconst RICHTEXT_KEYS = new Set([\"body\", \"description\"]);\n\nfunction fieldType(key: string, value: unknown): FieldDef[\"type\"] {\n if (RICHTEXT_KEYS.has(key)) return \"richtext\";\n if (value && typeof value === \"object\" && \"media\" in (value as object)) return \"image\";\n if (Array.isArray(value)) return \"group\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"number\") return \"number\";\n if (key === \"date\") return \"date\";\n if (/^(url|link)/.test(key)) return \"link\";\n return \"text\";\n}\n\n/** Underscore-prefixed keys are per-element style config (same convention as\n * page blocks' _title/_body), not content — never model or migrate them. */\nconst isStyleKey = (key: string) => key.startsWith(\"_\");\n\nfunction deriveFields(feed: BluxFeed): FieldDef[] {\n const seen = new Map<string, FieldDef[\"type\"]>();\n // Declared custom fields first (Blux feed.fields), then observed item keys.\n for (const d of feed.fields ?? []) {\n if (d.field) seen.set(d.field, \"text\");\n }\n for (const item of feed.items ?? []) {\n for (const [key, value] of Object.entries(item)) {\n if (isStyleKey(key)) continue;\n if (!seen.has(key) || seen.get(key) === \"text\") seen.set(key, fieldType(key, value));\n }\n }\n return [...seen.entries()].map(([key, type]) => ({ key, type }));\n}\n\nfunction recordUid(values: Record<string, unknown>, i: number): string {\n const title = typeof values.title === \"string\" ? values.title : \"\";\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n return slug || `item-${i}`;\n}\n\nexport function modelCollections(raw: BluxRaw): CollectionIR[] {\n const out: CollectionIR[] = [];\n for (const feed of Object.values(raw.feeds)) {\n const label = String(feed.name ?? \"\");\n const items = feed.items ?? [];\n const records: RecordIR[] = items.map((item, i) => {\n const mediaRefs: string[] = [];\n for (const value of Object.values(item)) {\n if (\n value &&\n typeof value === \"object\" &&\n typeof (value as { media?: string }).media === \"string\"\n ) {\n mediaRefs.push((value as { media: string }).media);\n }\n }\n const values = Object.fromEntries(Object.entries(item).filter(([key]) => !isStyleKey(key)));\n return { uid: recordUid(item, i), values, mediaRefs };\n });\n out.push({\n apiId: singularSlug(label),\n label,\n publishRoute: feed.publish ? String(feed.publish) : null,\n fields: deriveFields(feed),\n records,\n });\n }\n return out;\n}\n","import { parseBluxSite } from \"./parse.js\";\nimport { normalizePages, normalizeTheme } from \"./normalize.js\";\nimport { modelCollections } from \"./collections.js\";\nimport { collectAssetUrls } from \"./assets.js\";\nimport type { AssetRef, Diagnostic, SiteIR } from \"./ir.js\";\n\nexport function assembleIR(input: { siteJson: unknown; htmls: string[] }): SiteIR {\n const raw = parseBluxSite(input.siteJson);\n const { pages, diagnostics: pageDiags } = normalizePages(raw);\n const theme = normalizeTheme(raw);\n const collections = modelCollections(raw);\n const urlMap = collectAssetUrls(input.htmls);\n\n const diagnostics: Diagnostic[] = [...pageDiags];\n const assets: AssetRef[] = Object.entries(raw.media).map(([id, m]) => {\n const sourceUrl = urlMap.get(id) ?? null;\n if (!sourceUrl) {\n diagnostics.push({\n kind: \"unresolved-asset\",\n where: id,\n message: `no CDN url for ${m.name ?? id}`,\n });\n }\n return {\n id,\n sourceUrl,\n name: String(m.name ?? \"\"),\n mime: String(m.type ?? \"\"),\n alt: String(m.name ?? \"\"),\n };\n });\n\n return {\n meta: raw.meta,\n theme,\n pages,\n collections,\n assets,\n diagnostics,\n };\n}\n","import type { Diagnostic, SectionIR } from \"../ir.js\";\n\nexport type RichTextMarker = { __richtext_html: string };\nexport type AssetMarker = { __asset_id: string };\nexport const richText = (html: string): RichTextMarker => ({ __richtext_html: html });\nexport const assetRef = (id: string): AssetMarker => ({ __asset_id: id });\n\nexport type PlanSlice = {\n slice_type: string;\n variation: string;\n primary: Record<string, unknown>;\n items: Record<string, unknown>[];\n};\nexport type PlanDocument = { type: string; uid: string; data: Record<string, unknown> };\nexport type PlanCustomType = { id: string; label: string; repeatable: true; json: unknown };\nexport type PlanAsset = { id: string; url: string; alt: string };\n/** Presentation hints for one emitted slice; `index` is its position in the\n * document's slice zone (after empty-slice filtering). `items` aligns with a\n * kept section_grid's items. */\nexport type SliceStyleEntry = {\n index: number;\n sliceType: string;\n presentation?: NonNullable<SectionIR[\"presentation\"]>;\n items?: (NonNullable<SectionIR[\"presentation\"]> | null)[];\n};\n\nexport type MigrationPlan = {\n customTypes: PlanCustomType[];\n documents: PlanDocument[];\n assets: PlanAsset[];\n /** Per-page presentation hints (block styles + text roles) — design-pass\n * reference only, never pushed to Prismic. */\n stylesManifest: { pageUid: string; slices: SliceStyleEntry[] }[];\n /** Plan-time findings (skipped empty pages, dropped non-image assets, …). */\n diagnostics: Diagnostic[];\n};\n","import type { CollectionIR, FieldDef } from \"../ir.js\";\nimport type { PlanCustomType } from \"./plan.js\";\n\nconst FIELD_CONFIG: Record<\n FieldDef[\"type\"],\n () => { type: string; config: Record<string, unknown> }\n> = {\n text: () => ({ type: \"Text\", config: {} }),\n richtext: () => ({\n type: \"StructuredText\",\n config: { multi: \"paragraph,strong,em,hyperlink,list-item,o-list-item\" },\n }),\n image: () => ({ type: \"Image\", config: { constraint: {}, thumbnails: [] } }),\n group: () => ({ type: \"Group\", config: { fields: { value: { type: \"Text\", config: {} } } } }),\n date: () => ({ type: \"Date\", config: {} }),\n boolean: () => ({ type: \"Boolean\", config: {} }),\n number: () => ({ type: \"Number\", config: {} }),\n link: () => ({ type: \"Link\", config: { allowTargetBlank: true } }),\n};\n\nexport function buildCustomType(c: CollectionIR): PlanCustomType {\n const Main: Record<string, unknown> = {};\n for (const f of c.fields) {\n const spec = FIELD_CONFIG[f.type]();\n Main[f.key] = { ...spec, config: { ...spec.config, label: f.key } };\n }\n return {\n id: c.apiId,\n label: c.label,\n repeatable: true,\n json: { id: c.apiId, label: c.label, repeatable: true, status: true, json: { Main } },\n };\n}\n","/** HTML-level rich-text coercion so emitted plans validate against the slice\n * models' StructuredText restrictions (heading slots are `single` and\n * heading-restricted; body slots allow no headings — see Plan 4's field-type\n * table). Blux markup is simple generated HTML, so tag rewriting is reliable. */\n\nconst BLOCK_RE = /<(h[1-6]|p|div)(\\s[^>]*)?>[\\s\\S]*?<\\/\\1>/i;\n\n/** Coerce a heading-slot HTML fragment to a single block whose tag is in\n * `allowed` (e.g. [\"h2\",\"h3\"]): keep an allowed tag, clamp other headings to\n * the nearest allowed level, promote paragraphs/bare text to the LOWEST\n * allowed heading. Only the first block survives (the fields are `single`). */\nexport function coerceHeadingHtml(html: string, allowed: string[]): string {\n const m = html.match(BLOCK_RE);\n const block = m ? m[0] : html;\n const tagMatch = block.match(/^<(h[1-6]|p|div)(\\s[^>]*)?>/i);\n const tag = tagMatch?.[1]?.toLowerCase();\n if (tag && allowed.includes(tag)) return block;\n\n const levels = allowed.filter((t) => /^h[1-6]$/.test(t)).map((t) => Number(t[1]));\n const target =\n tag && tag.startsWith(\"h\")\n ? `h${levels.reduce((b, l) => (Math.abs(l - Number(tag[1])) < Math.abs(b - Number(tag[1])) ? l : b))}`\n : `h${Math.max(...levels)}`;\n\n if (!tag) return `<${target}>${block}</${target}>`;\n return block\n .replace(new RegExp(`^<${tag}`, \"i\"), `<${target}`)\n .replace(new RegExp(`</${tag}>$`, \"i\"), `</${target}>`);\n}\n\n/** Demote all headings in a body-slot fragment to paragraphs (body fields\n * allow no heading blocks). Attributes and inline markup pass through. */\nexport function demoteHeadingsHtml(html: string): string {\n return html.replace(/<(\\/?)h[1-6](\\s[^>]*)?>/gi, \"<$1p$2>\");\n}\n","import type { SectionIR } from \"../ir.js\";\nimport { richText, assetRef, type PlanSlice } from \"./plan.js\";\nimport { coerceHeadingHtml, demoteHeadingsHtml } from \"./coerce-html.js\";\n\n/** Allowed heading tags per slice heading slot — MUST mirror the\n * StructuredText configs in reddoor-starter/src/lib/slices/<Slice>/model.json. */\nconst HEADING_TAGS = {\n hero: [\"h1\", \"h2\"],\n media_text: [\"h2\", \"h3\"],\n section_grid: [\"h2\", \"h3\"],\n section_grid_item: [\"h3\", \"h4\"],\n} satisfies Record<string, string[]>;\n\nfunction rt(html?: string) {\n return html ? richText(html) : undefined;\n}\nfunction rtHeading(html: string | undefined, slot: keyof typeof HEADING_TAGS) {\n return html ? richText(coerceHeadingHtml(html, HEADING_TAGS[slot])) : undefined;\n}\nfunction rtBody(html?: string) {\n return html ? richText(demoteHeadingsHtml(html)) : undefined;\n}\nfunction img(id?: string) {\n return id ? assetRef(id) : undefined;\n}\nfunction compact(o: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));\n}\n\nexport function sectionToSlice(s: SectionIR): PlanSlice {\n const f = s.fields;\n switch (s.sliceType) {\n case \"hero\":\n return {\n slice_type: \"hero\",\n variation: \"default\",\n primary: compact({\n heading: rtHeading(f.heading, \"hero\"),\n body: rtBody(f.body),\n background_image: img(f.backgroundMedia ?? f.media),\n }),\n items: [],\n };\n case \"media_text\":\n return {\n slice_type: \"media_text\",\n variation: s.variation === \"imageLeft\" ? \"imageLeft\" : \"imageRight\",\n primary: compact({\n heading: rtHeading(f.heading, \"media_text\"),\n body: rtBody(f.body),\n media: img(f.media),\n }),\n items: [],\n };\n case \"collection_list\":\n return {\n slice_type: \"collection_list\",\n variation: s.variation === \"list\" ? \"list\" : \"grid\",\n primary: compact({\n heading: rtHeading(f.heading, \"section_grid\"),\n collection_type: s.collectionRef?.apiId ?? \"\",\n max_items: 24,\n }),\n items: [],\n };\n case \"grid\":\n case \"slider\":\n return {\n slice_type: \"section_grid\",\n variation: \"default\",\n primary: compact({\n heading: rtHeading(f.heading, \"section_grid\"),\n columns: f.columns ?? 3,\n }),\n items: (s.children ?? [])\n .map((c) =>\n compact({\n item_heading: rtHeading(c.fields.heading, \"section_grid_item\"),\n item_body: rtBody(c.fields.body),\n item_media: img(c.fields.media),\n }),\n )\n // a child whose only content was hidden text has nothing to show\n .filter((item) => Object.keys(item).length > 0),\n };\n case \"rich_text\":\n default:\n // rich_text content allows every block type — no coercion needed\n return {\n slice_type: \"rich_text\",\n variation: \"default\",\n primary: compact({ content: rt(f.heading ? `${f.heading}${f.body ?? \"\"}` : f.body) }),\n items: [],\n };\n }\n}\n","import type { SectionIR } from \"../ir.js\";\n\nconst isContainer = (s: SectionIR) => s.sliceType === \"grid\" || s.sliceType === \"slider\";\nconst isFlatLeaf = (s: SectionIR) =>\n (s.sliceType === \"media_text\" || s.sliceType === \"rich_text\") && !(s.children ?? []).length;\n\n/** Depth-first flatten: Prismic slices cannot nest, so a container survives\n * as a section_grid-with-items only when every child is representable as a\n * flat item (childless media_text/rich_text). Anything richer — nested\n * containers, heroes with backgrounds — explodes into sequential sibling\n * sections, and the container's OWN content (heading/body/media) survives\n * as a leading media_text or rich_text section. Proven need: thePointe's\n * depth-4 tree kept only 7/53 images under one-level flattening. */\nexport function flattenSections(sections: SectionIR[]): SectionIR[] {\n const out: SectionIR[] = [];\n for (const s of sections) {\n const children = s.children ?? [];\n\n if (s.sliceType === \"hero\" && s.fields.media && s.fields.backgroundMedia) {\n // the hero slice only models the background image — surface the\n // foreground image (a logo/overlay in Blux) as a sibling media_text\n const { media, ...heroFields } = s.fields;\n const { children: _heroKids, ...heroSelf } = s;\n out.push({ ...heroSelf, fields: heroFields });\n out.push({\n sliceType: \"media_text\",\n variation: \"imageRight\",\n confidence: s.confidence,\n fields: { media },\n });\n out.push(...flattenSections(children));\n continue;\n }\n\n // a container may keep its items form only when it has no content of its\n // own beyond a heading — section_grid's primary cannot carry media/body\n const keepable = isContainer(s) && !s.fields.media && !s.fields.body;\n if (!children.length) {\n if (isContainer(s) && !keepable) {\n out.push({ ...s, sliceType: s.fields.media ? \"media_text\" : \"rich_text\" });\n } else {\n out.push(s);\n }\n } else if (keepable && children.every(isFlatLeaf)) {\n out.push(s);\n } else if (isContainer(s)) {\n // the container's own content leads its exploded children: with media\n // it is a media_text-shaped section that merely carries a subtree,\n // otherwise its heading/body become a rich_text grouping label\n const { children: _kids, ...self } = s;\n if (self.fields.media) {\n out.push({ ...self, sliceType: \"media_text\" });\n } else if (self.fields.heading || self.fields.body) {\n out.push({ ...self, sliceType: \"rich_text\" });\n }\n out.push(...flattenSections(children));\n } else {\n // normalize attaches `children` to ANY block with items — a hero or\n // media_text can carry a subtree. Its own slice mapping ignores\n // children, so hoist them as following siblings instead of losing them.\n const { children: _hoisted, ...self } = s;\n out.push(self);\n out.push(...flattenSections(children));\n }\n }\n return out;\n}\n","import type { SiteIR, RecordIR, PageIR, AssetRef, Diagnostic } from \"../ir.js\";\nimport {\n richText,\n assetRef,\n type MigrationPlan,\n type PlanDocument,\n type SliceStyleEntry,\n} from \"./plan.js\";\nimport { buildCustomType } from \"./custom-types.js\";\nimport { sectionToSlice } from \"./slices.js\";\nimport { coerceHeadingHtml, demoteHeadingsHtml } from \"./coerce-html.js\";\nimport { flattenSections } from \"./flatten.js\";\n\n/** Slice fields modeled as Prismic Image fields — only image assets may land here. */\nconst IMAGE_FIELDS = new Set([\"background_image\", \"media\", \"item_media\"]);\n\nconst RICHTEXT = new Set([\"body\", \"description\"]);\n\n/** A page with no title and no sections emits no document (and no review pair). */\nexport function isEmptyPage(p: PageIR): boolean {\n return !p.sections.length && !p.title.trim();\n}\n\n/** True when the asset may occupy a Prismic Image field. A known non-image\n * mime is disqualifying; a MISSING mime (exports often omit `type`) falls\n * back to the filename extension and keeps the asset unless it is clearly\n * not an image. */\nconst NON_IMAGE_EXT = /\\.(mp4|mov|webm|avi|mp3|wav|pdf|zip)$/i;\nfunction isImageAsset(a: AssetRef | undefined): boolean {\n if (!a) return true; // unknown asset id: leave it; migrate reports the miss\n if (a.mime) return a.mime.startsWith(\"image/\");\n return !NON_IMAGE_EXT.test(a.name);\n}\n\nfunction recordData(rec: RecordIR): Record<string, unknown> {\n const data: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(rec.values)) {\n if (\n value &&\n typeof value === \"object\" &&\n typeof (value as { media?: string }).media === \"string\"\n ) {\n data[key] = assetRef((value as { media: string }).media);\n } else if (RICHTEXT.has(key) && typeof value === \"string\") {\n // record rich-text models allow no heading blocks (see buildCustomType)\n data[key] = richText(demoteHeadingsHtml(value));\n } else {\n data[key] = value;\n }\n }\n return data;\n}\n\nexport function buildMigrationPlan(ir: SiteIR): MigrationPlan {\n const diagnostics: Diagnostic[] = [];\n const customTypes = ir.collections.map(buildCustomType);\n const assetById = new Map(ir.assets.map((a) => [a.id, a]));\n\n /** Drop non-image assets referenced by an Image field, with a diagnostic. */\n const dropNonImages = (rec: Record<string, unknown>, keys: Set<string> | null, where: string) => {\n for (const [key, val] of Object.entries(rec)) {\n if ((keys && !keys.has(key)) || !val || typeof val !== \"object\" || !(\"__asset_id\" in val))\n continue;\n const asset = assetById.get((val as { __asset_id: string }).__asset_id);\n if (!isImageAsset(asset)) {\n diagnostics.push({\n kind: \"non-image-in-image-field\",\n where: `${where}.${key}`,\n message: `${asset?.mime || \"unknown mime\"} asset dropped from image field`,\n });\n delete rec[key];\n }\n }\n };\n\n const documents: PlanDocument[] = [];\n const stylesManifest: MigrationPlan[\"stylesManifest\"] = [];\n for (const page of ir.pages) {\n if (isEmptyPage(page)) {\n diagnostics.push({\n kind: \"empty-page\",\n where: page.uid,\n message: \"page has no title and no sections; skipped\",\n });\n continue;\n }\n const slices: ReturnType<typeof sectionToSlice>[] = [];\n const styleEntries: SliceStyleEntry[] = [];\n for (const section of flattenSections(page.sections)) {\n const slice = sectionToSlice(section);\n for (const rec of [slice.primary, ...slice.items]) {\n dropNonImages(rec, IMAGE_FIELDS, `${page.uid}/${slice.slice_type}`);\n }\n // Structural defaults aren't content — a slice with nothing else to\n // show (e.g. a block whose only content was hidden text, or whose\n // sole video was dropped from an image field) is invisible; skip it.\n const STRUCTURAL = new Set([\"columns\", \"collection_type\", \"max_items\"]);\n const hasContent =\n Object.keys(slice.primary).some((k) => !STRUCTURAL.has(k)) || slice.items.length > 0;\n if (!hasContent) {\n diagnostics.push({\n kind: \"empty-slice\",\n where: `${page.uid}/${slice.slice_type}`,\n message: \"slice has no content after filtering; dropped\",\n });\n continue;\n }\n // Presentation hints ride beside the slice, keyed by its final index.\n // Grid items mirror sectionToSlice's emptiness rule so they stay aligned.\n const itemPresentations = (section.children ?? [])\n .filter((c) => c.fields.heading || c.fields.body || c.fields.media)\n .map((c) => c.presentation ?? null);\n const entry: SliceStyleEntry = {\n index: slices.length,\n sliceType: slice.slice_type,\n ...(section.presentation ? { presentation: section.presentation } : {}),\n ...(slice.slice_type === \"section_grid\" && itemPresentations.some(Boolean)\n ? { items: itemPresentations }\n : {}),\n };\n if (entry.presentation || entry.items) styleEntries.push(entry);\n slices.push(slice);\n }\n stylesManifest.push({ pageUid: page.uid, slices: styleEntries });\n documents.push({\n type: \"page\",\n uid: page.uid,\n // the page type's title is StructuredText(single heading1)\n data: {\n title: richText(coerceHeadingHtml(page.title || page.uid, [\"h1\"])),\n slices,\n },\n });\n }\n for (const c of ir.collections) {\n for (const rec of c.records) {\n const data = recordData(rec);\n // record asset markers only ever occupy Image fields — check them all\n dropNonImages(data, null, `${c.apiId}/${rec.uid}`);\n documents.push({ type: c.apiId, uid: rec.uid, data });\n }\n }\n\n const assets = ir.assets\n .filter((a) => a.sourceUrl !== null)\n .map((a) => ({ id: a.id, url: a.sourceUrl as string, alt: a.alt }));\n\n return { customTypes, documents, assets, stylesManifest, diagnostics };\n}\n","import type { ThemeIR } from \"../ir.js\";\n\n/** ThemeIR → a Tailwind v4 `@theme` block of CSS custom properties. Deterministic.\n * A leading comment lists the exact web-font weights the export loads, so the\n * design pass can install them without measuring the rendered site. */\nexport function emitThemeCss(theme: ThemeIR): string {\n const lines: string[] = [];\n if (theme.fontLoad.length) {\n const spec = theme.fontLoad.map((f) => `${f.family} ${f.weights.join(\",\")}`).join(\"; \");\n lines.push(`/* Fonts to load — ${spec} */`);\n }\n lines.push(\"@theme {\");\n for (const c of theme.colors) lines.push(` --color-${c.role}: ${c.value};`);\n lines.push(` --font-heading: ${theme.fonts.heading || \"sans-serif\"};`);\n lines.push(` --font-body: ${theme.fonts.body || \"sans-serif\"};`);\n for (const t of theme.textStyles) {\n if (t.label) lines.push(` /* ${t.role} — ${t.label} */`);\n lines.push(` --text-${t.role}: ${t.size};`);\n lines.push(` --text-${t.role}--line-height: ${t.lineHeight};`);\n lines.push(` --text-${t.role}--font-weight: ${t.weight};`);\n if (t.fontFamily) lines.push(` --text-${t.role}--font-family: ${t.fontFamily};`);\n if (t.transform) lines.push(` --text-${t.role}--text-transform: ${t.transform};`);\n if (t.letterSpacing) lines.push(` --text-${t.role}--letter-spacing: ${t.letterSpacing};`);\n if (t.mobileSize) lines.push(` --text-${t.role}--mobile-font-size: ${t.mobileSize};`);\n if (t.mobileLineHeight)\n lines.push(` --text-${t.role}--mobile-line-height: ${t.mobileLineHeight};`);\n }\n lines.push(\"}\");\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/** ThemeIR → the `.txt-role-textN` utility layer: one rule per text style that\n * maps the role's `@theme` vars (emitted by {@link emitThemeCss}) onto the\n * h1–h6/p it wraps. A slice applies `txt-role-textN` to a block and its\n * headings/paragraphs pick up that role's type — the same mechanism the\n * per-site `gen-blux-theme.mjs` script used to hand-generate, now owned by\n * `blux emit` so a converted site consumes it with zero hand-tuning.\n *\n * letter-spacing and text-transform fall back through `var(…, default)` so a\n * role that omits them is inert for that property. font-family is set only when\n * the role declares one — a family-less role (a body default) keeps the natural\n * cascade (headings stay heading font, paragraphs stay body font) rather than\n * being forced onto either. Returns \"\" when the theme has no text styles. */\nexport function emitRolesCss(theme: ThemeIR): string {\n if (!theme.textStyles.length) return \"\";\n const lines: string[] = [\n \"/* Role utilities — one .txt-role-textN per Blux text style, mapping its\",\n \" @theme vars onto the heading/paragraph it wraps. Generated by blux emit. */\",\n ];\n for (const t of theme.textStyles) {\n const r = t.role;\n lines.push(`.txt-role-${r} :is(h1, h2, h3, h4, h5, h6, p) {`);\n if (t.fontFamily) lines.push(` font-family: var(--text-${r}--font-family);`);\n lines.push(\n ` font-size: var(--text-${r});`,\n ` font-weight: var(--text-${r}--font-weight);`,\n ` line-height: var(--text-${r}--line-height);`,\n ` letter-spacing: var(--text-${r}--letter-spacing, normal);`,\n ` text-transform: var(--text-${r}--text-transform, none);`,\n ` margin: 0;`,\n `}`,\n );\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n","import type { SiteIR, Diagnostic } from \"../ir.js\";\nimport { isEmptyPage } from \"./migration-plan.js\";\n\nexport type ReviewPair = { uid: string; converted: string; original: string };\nexport type ReviewManifest = { pairs: ReviewPair[]; diagnostics: Diagnostic[] };\n\nexport function buildReviewManifest(\n ir: SiteIR,\n opts: { convertedBase: string; bluxBase: string },\n): ReviewManifest {\n // empty pages emit no document (see buildMigrationPlan) — nothing to review\n const pairs = ir.pages\n .filter((p) => !isEmptyPage(p))\n .map((p) => ({\n uid: p.uid,\n converted: `${opts.convertedBase}/${p.uid}`,\n // The home page maps to the site root; other pages to /uid.\n original: p.uid === \"home\" ? `${opts.bluxBase}/` : `${opts.bluxBase}/${p.uid}`,\n }));\n return { pairs, diagnostics: ir.diagnostics };\n}\n","/** Content-coverage validation: does a converted site actually render every\n * piece of text the Blux export shows? The export's rendered `index.html` is\n * the answer key; we extract its visible text runs and check each appears in\n * the converted site's rendered HTML. A missing run is a content gap the\n * deterministic transform left behind (e.g. a hero title that never mapped\n * onto a slice field) — surfaced without spending a token eyeballing pages. */\n\nconst DROP_ELEMENTS = /<(script|style|head|noscript|svg|template)[\\s\\S]*?<\\/\\1>/gi;\nconst COMMENTS = /<!--[\\s\\S]*?-->/g;\n\n/** Decode the entity forms an export mixes in so they match the raw characters\n * a Prismic render emits. Numeric first, then the common named ones. */\nfunction decodeEntities(s: string): string {\n return (\n s\n .replace(/&#(\\d+);/g, (_, n) => codePoint(Number(n)))\n .replace(/&#x([0-9a-f]+);/gi, (_, h) => codePoint(parseInt(h, 16)))\n .replace(/&nbsp;/gi, \" \")\n .replace(/&(?:amp);/gi, \"&\")\n .replace(/&(?:lt);/gi, \"<\")\n .replace(/&(?:gt);/gi, \">\")\n .replace(/&(?:quot);/gi, '\"')\n .replace(/&(?:apos|#39);/gi, \"'\")\n // any remaining named entity (&mdash; &rsquo; &copy; …) becomes a space,\n // not the literal token \"mdash\"/\"rsquo\" — a phantom word would break the\n // substring match and report otherwise-present text as a false gap\n .replace(/&[a-z][a-z0-9]*;/gi, \" \")\n );\n}\n\nfunction codePoint(n: number): string {\n try {\n return String.fromCodePoint(n);\n } catch {\n return \" \";\n }\n}\n\n/** Fold text to a matchable form: decode, lowercase, and reduce every run of\n * non-alphanumeric characters (punctuation, smart quotes, em-dashes, symbols)\n * to a single space. Coverage then compares words, not typography — so\n * \"CBRE & Co. — Leasing\" and \"cbre co leasing\" are the same content. */\nexport function normalizeText(s: string): string {\n return decodeEntities(s)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim();\n}\n\n/** A normalized run counts as content only if it carries a real word — at least\n * three alphanumeric characters together. Filters whitespace, lone punctuation,\n * and single/double-letter fragments left by inline tags. */\nfunction hasWord(run: string): boolean {\n return /[a-z0-9]{3,}/.test(run);\n}\n\n/** Strip the non-content elements and all tags from an HTML string, leaving\n * one normalized text blob (used for the render side of a coverage check). */\nexport function flattenText(html: string): string {\n const text = html\n .replace(DROP_ELEMENTS, \" \")\n .replace(COMMENTS, \" \")\n .replace(/<[^>]+>/g, \" \");\n return normalizeText(text);\n}\n\n/** Split an HTML string into de-duplicated, normalized visible text runs — the\n * text between tags, once script/style/head are removed. Inline tags fragment a\n * sentence into several runs; each must still appear in the render to count. */\nexport function extractTextRuns(html: string): string[] {\n const stripped = html.replace(DROP_ELEMENTS, \" \").replace(COMMENTS, \" \");\n const seen = new Set<string>();\n for (const piece of stripped.split(/<[^>]+>/)) {\n const run = normalizeText(piece);\n if (hasWord(run)) seen.add(run);\n }\n return [...seen];\n}\n\nexport type CoverageReport = {\n total: number;\n covered: number;\n missing: string[];\n coveragePct: number;\n};\n\n/** Compare the export's rendered HTML (answer key) against the converted site's\n * rendered HTML. Every text run in the export should appear somewhere in the\n * render; the ones that don't are the content the transform dropped. */\nexport function validateCoverage(exportHtml: string, renderedHtml: string): CoverageReport {\n const runs = extractTextRuns(exportHtml);\n // Pad with spaces and match a space-bounded run so a short label (\"art\")\n // isn't counted as covered because it sits inside a longer word\n // (\"apartments\") — that would silently hide a real content gap.\n const blob = ` ${flattenText(renderedHtml)} `;\n const missing = runs.filter((run) => !blob.includes(` ${run} `));\n const covered = runs.length - missing.length;\n const coveragePct = runs.length === 0 ? 100 : Math.round((covered / runs.length) * 100);\n return { total: runs.length, covered, missing, coveragePct };\n}\n","import { parse } from \"node-html-parser\";\nimport type { HTMLElement, Node as HTMLNode } from \"node-html-parser\";\nimport type { Band, Cell, GridToken, Media, Node } from \"./types.js\";\nimport { parseGridToken } from \"./token.js\";\nimport {\n textRoleFromClass,\n headingLevel,\n mediaFromElement,\n stripAssetExt,\n blockPlainText,\n readBgSizing,\n} from \"./leaf.js\";\n\nconst DEFAULT_TOKEN: GridToken = { cols: 1, raw: \"grid-1\" };\n\nconst isElement = (n: HTMLNode): n is HTMLElement =>\n (n as HTMLElement).tagName !== undefined && (n as HTMLElement).tagName !== null;\n\nconst hasClass = (el: HTMLElement, c: string) => el.classNames.split(/\\s+/).includes(c);\n\n/** A foreground media holder: a `block-media-holder`, a bare\n * `camediaload[data-media]`, or a `<video>`. */\nconst isMediaHolder = (el: HTMLElement): boolean =>\n hasClass(el, \"block-media-holder\") ||\n (hasClass(el, \"camediaload\") && !!el.getAttribute(\"data-media\")) ||\n el.tagName === \"VIDEO\";\n\nconst isLeafElement = (el: HTMLElement): boolean =>\n hasClass(el, \"block-title\") ||\n hasClass(el, \"block-body\") ||\n hasClass(el, \"block-subtitle\") ||\n isMediaHolder(el);\n\n/** A leaf `<a>`: a CTA button / text link with no structural descendants. Such\n * an anchor is not a wrapper — peeling through it (its inner text/spans are not\n * structural) would drop the link entirely — so it is treated as a structural\n * leaf. A linked media/grid wrapper (`<a>` containing a camediaload/grid) is NOT\n * a leaf anchor: it keeps peeling so the inner media parses normally. */\nconst isLeafAnchor = (el: HTMLElement): boolean =>\n el.tagName === \"A\" && collectStructuralChildren(el).length === 0;\n\n/** Is this element a structural boundary (a leaf, a grid row, or a token-bearing\n * cell/holder), as opposed to a pure wrapper div we should peel through? */\nconst isStructural = (el: HTMLElement): boolean =>\n isLeafElement(el) ||\n el.hasAttribute(\"data-exec\") || // Blux custom-code embed (e.g. map mount)\n hasClass(el, \"cagrid\") ||\n isLeafAnchor(el) ||\n parseGridToken(el.classNames) !== null;\n\n/** The child elements that carry structure, peeling pure wrapper divs. */\nexport function collectStructuralChildren(el: HTMLElement): HTMLElement[] {\n const out: HTMLElement[] = [];\n for (const child of el.childNodes) {\n if (!isElement(child)) continue;\n if (isStructural(child)) out.push(child);\n else out.push(...collectStructuralChildren(child));\n }\n return out;\n}\n\n/** Does a parsed leaf node carry real text (not just empty markup)? Gates caption\n * capture so an empty `.block-*` inside a media holder adds nothing. Routes\n * heading/body through `blockPlainText` (same as the subtitle path) so an\n * entity- or `&nbsp;`-only block reads as empty, not as text. */\nfunction nodeHasText(n: Node): boolean {\n if (n.kind === \"heading\" || n.kind === \"body\") return blockPlainText(n.html) !== \"\";\n if (n.kind === \"subtitle\") return n.text.trim() !== \"\";\n return false;\n}\n\n/** Is a caption element (or an ancestor up to and including the media holder)\n * marked `class:\"disable\"`? Blux omits disabled blocks from the rendered HTML,\n * but guard anyway so hidden copy is never leaked into a caption. */\nfunction isDisabledWithin(caption: HTMLElement, holder: HTMLElement): boolean {\n let a: HTMLElement | null | undefined = caption;\n while (a) {\n if (hasClass(a, \"disable\")) return true;\n if (a === holder) return false;\n a = a.parentNode as HTMLElement | null | undefined;\n }\n return false;\n}\n\n/** Parse one element into a grid Node. Leaves dispatch by role; everything else\n * becomes a row / stack / single / raw via parseContainer. */\nexport function parseNode(el: HTMLElement): Node {\n if (hasClass(el, \"block-title\") && /^H[1-6]$/.test(el.tagName ?? \"\")) {\n const role = textRoleFromClass(el.classNames);\n return {\n kind: \"heading\",\n ...(role ? { role } : {}),\n level: headingLevel(el),\n html: el.innerHTML,\n };\n }\n if (hasClass(el, \"block-body\")) {\n const role = textRoleFromClass(el.classNames);\n return { kind: \"body\", ...(role ? { role } : {}), html: el.innerHTML };\n }\n if (hasClass(el, \"block-subtitle\")) {\n const role = textRoleFromClass(el.classNames);\n // Route through blockPlainText (not raw `.text`): a `<br>` in a display\n // subtitle survives as a newline while insignificant source whitespace\n // collapses — `.text` alone can't tell a hard break from source formatting.\n return { kind: \"subtitle\", ...(role ? { role } : {}), text: blockPlainText(el.innerHTML) };\n }\n if (isMediaHolder(el)) {\n const media = mediaFromElement(el);\n if (media) {\n // Blux slider tiles nest the slide's CAPTION inside the media holder (the\n // holder is `data-bgmedia` and the copy overlays it). The holder is an\n // opaque media leaf, so those captions would be dropped. When one carries\n // block-title/body/subtitle text, emit the media PLUS the caption(s) as a\n // stack so the copy survives. Pure-media holders — the vast majority —\n // stay a bare media node, byte-identical (no `.block-*` descendant → no\n // extra work). This does NOT change the peel boundary: the holder is still\n // a structural leaf; only its own internal text is recovered here.\n const captions = el\n .querySelectorAll(\".block-title, .block-body, .block-subtitle\")\n .filter((c) => !isDisabledWithin(c, el))\n .map((c) => parseNode(c))\n .filter(nodeHasText);\n if (captions.length) {\n return { kind: \"stack\", children: [{ kind: \"media\", media }, ...captions] };\n }\n return { kind: \"media\", media };\n }\n }\n if (el.hasAttribute(\"data-exec\")) {\n // Custom-code embed (map, third-party widget). Keep the whole subtree —\n // including id=\"burbank_map\" and any inline initMap/KmlLayer scripts — so\n // extract-map can read it and Grid.svelte can render it verbatim.\n return { kind: \"raw\", html: el.outerHTML };\n }\n if (el.tagName === \"A\") {\n // A leaf CTA button / text link (isLeafAnchor). Preserve the whole anchor —\n // href + label — verbatim so the render layer keeps the clickable link.\n return { kind: \"raw\", html: el.outerHTML };\n }\n return parseContainer(el);\n}\n\n/** Parse a wrapper/cell/band-body element: a row when it is a grid or holds\n * ≥2 token-bearing children, else a stack / single / raw. */\nexport function parseContainer(el: HTMLElement): Node {\n const kids = collectStructuralChildren(el);\n // Parse each structural child up front, then drop any that collapse to an\n // EMPTY raw — an empty `.caslider`/wrapper (no static slides, JS-hydrated)\n // yields `raw:\"\"`, which would otherwise survive as a phantom sibling (e.g.\n // turning a lone poster image into `[media, empty-block]`). A non-empty raw\n // (a `[data-exec]` embed, a leaf `<a>`) always has real html, so it is kept.\n const parsed = kids\n .map((k) => ({ token: parseGridToken(k.classNames), node: parseNode(k) }))\n .filter((p) => !(p.node.kind === \"raw\" && p.node.html.trim() === \"\"));\n const isGrid = hasClass(el, \"cagrid\");\n const tokenCount = parsed.filter((p) => p.token).length;\n\n if ((isGrid || tokenCount >= 2) && parsed.length > 0) {\n const cells: Cell[] = parsed.map((p) => ({ token: p.token ?? DEFAULT_TOKEN, node: p.node }));\n if (hasClass(el, \"caslider\")) {\n // A source slider row. `data-columns` = slides visible at a time; only a\n // positive integer is meaningful (conditional build keeps `columns`\n // absent, not undefined, under exactOptionalPropertyTypes).\n const cols = Number(el.getAttribute(\"data-columns\"));\n const slider = Number.isInteger(cols) && cols > 0 ? { columns: cols } : {};\n return { kind: \"row\", cells, slider };\n }\n return { kind: \"row\", cells };\n }\n const [only] = parsed;\n if (parsed.length === 1 && only) return only.node;\n if (parsed.length === 0) return { kind: \"raw\", html: el.innerHTML };\n return { kind: \"stack\", children: parsed.map((p) => p.node) };\n}\n\nconst BAND_ID_RE = /^page-block-(\\d+)$/;\n\n/** Read the band-level background media off a `camediaload` band wrapper. */\nfunction bandBackground(el: HTMLElement): Media | undefined {\n if (!hasClass(el, \"camediaload\")) return undefined;\n const rawId = el.getAttribute(\"data-media\");\n if (!rawId) return undefined;\n const ext = el.getAttribute(\"data-ext\") ?? undefined;\n const base = el.getAttribute(\"data-base\") ?? undefined;\n return {\n kind: \"image\",\n assetId: stripAssetExt(rawId, ext),\n ...(ext ? { ext } : {}),\n ...(base ? { base } : {}),\n // A band background carries its own render sizing (background-size/position);\n // a corner-anchored `auto` accent must not be centered + full-bleed.\n ...readBgSizing(el),\n };\n}\n\n/** Parse the rendered Blux index.html into the page's top-level band tree. */\nexport function parseGridBands(html: string): Band[] {\n const root = parse(html);\n const content = root.querySelector(\"#page-content\");\n if (!content) return [];\n const bands: Band[] = [];\n for (const child of content.childNodes) {\n if (!isElement(child)) continue;\n const m = BAND_ID_RE.exec(child.getAttribute(\"id\") ?? \"\");\n if (!m) continue;\n const idStr = m[1];\n if (idStr === undefined) continue;\n const background = bandBackground(child);\n bands.push({\n index: Number(idStr),\n ...(background ? { background } : {}),\n root: parseContainer(child),\n });\n }\n return bands;\n}\n","import type { GridToken } from \"./types.js\";\n\nconst TOKEN_RE = /\\bgrid-(\\d+|any)(?:-(r|s)(\\d+))?\\b/;\n\n/** Parse the `grid-*` layout token out of an element's class string.\n * `grid-2` -> equal 2-col; `grid-2-r60` -> 60% of a 2-col row; `grid-1-s40` ->\n * 1-col with 40px inter-cell spacing (the `s` suffix is the grid's gap, matching\n * `data-spacing`, NOT a width — width comes from the column count). Returns null\n * when the class has no grid token (e.g. `grid-container`, no column count). */\nexport function parseGridToken(className: string): GridToken | null {\n const m = TOKEN_RE.exec(className);\n if (!m) return null;\n const cols = m[1] === \"any\" ? \"any\" : Number(m[1]);\n const token: GridToken = { cols, raw: m[0] };\n if (m[2] === \"r\") token.ratio = Number(m[3]);\n if (m[2] === \"s\") token.spacing = Number(m[3]);\n return token;\n}\n","import { parse } from \"node-html-parser\";\nimport type { HTMLElement } from \"node-html-parser\";\nimport type { Media, VideoPlayback } from \"./types.js\";\n\nconst ROLE_RE = /\\btext\\d+\\b/;\n\n/** The Blux text role (`text5`, `text11`, …) carried on a block-title/body/subtitle\n * element's class in the rendered HTML, or undefined when none is present. */\nexport function textRoleFromClass(className: string): string | undefined {\n return ROLE_RE.exec(className)?.[0];\n}\n\n/** The heading level (1..6) for an h1..h6 element. */\nexport function headingLevel(el: HTMLElement): number {\n const m = /^H([1-6])$/.exec(el.tagName ?? \"\");\n return m ? Number(m[1]) : 2;\n}\n\n/** Plain text of a block's inner HTML for a title field: a hard line break\n * (`<br>`, with or without attributes/self-close) becomes a newline; every other\n * tag drops and HTML entities decode (`Bar &amp; Grill` → `Bar & Grill`); all\n * source-formatting whitespace collapses to single spaces. Robust to\n * pretty-printed exports — insignificant newlines in the markup are NOT mistaken\n * for hard breaks — by routing `<br>` through a sentinel that survives the\n * whitespace collapse. */\nexport function blockPlainText(html: string): string {\n const BR = \"\\uE000\";\n // node-html-parser `.text` strips tags AND decodes entities; the <br>→BR swap\n // runs first so hard breaks survive as the sentinel through the collapse below.\n const text = parse(html.replace(/<br\\b[^>]*>/gi, BR)).text;\n return text\n .replace(/\\s+/g, \" \")\n .replace(/ *\\uE000 */g, \"\\n\")\n .trim();\n}\n\n/** The last path segment of a CDN url, sans extension (the Blux asset uuid). */\nfunction uuidFromUrl(url: string): { id: string; ext?: string } {\n const base = url.split(/[?#]/)[0] ?? \"\";\n const file = base.split(\"/\").pop() ?? \"\";\n const dot = file.lastIndexOf(\".\");\n return dot > 0 ? { id: file.slice(0, dot), ext: file.slice(dot + 1) } : { id: file };\n}\n\n/** Blux `data-media` is sometimes `uuid.ext` and sometimes a bare `uuid`; the\n * existing asset pipeline keys on the bare uuid (extension stripped), matching the\n * video path. Strip a trailing `.<ext>` when `data-ext` names it. */\nexport function stripAssetExt(rawId: string, ext?: string): string {\n return ext && rawId.endsWith(`.${ext}`) ? rawId.slice(0, -(ext.length + 1)) : rawId;\n}\n\n/** Read a single CSS declaration's value out of an inline `style` string. */\nexport function cssProp(style: string, prop: string): string | undefined {\n const m = new RegExp(`(?:^|;|\\\\s)${prop}\\\\s*:\\\\s*([^;]+)`, \"i\").exec(style);\n return m?.[1]?.trim();\n}\n\nconst CENTERED = new Set([\"center\", \"center center\", \"50% 50%\", \"50%\"]);\n\n/** Background sizing off a BAND-background wrapper's inline style: its\n * `background-size` → `fit` (a background's `auto`/`contain` is meaningful — a\n * native-size decorative accent, not a full-bleed `cover`) and its\n * `background-position` → `position` (e.g. \"right bottom\"). Unlike `readImgSizing`\n * (foreground), `auto` is kept; `cover` and a centered position are the render\n * defaults, so they are left absent to keep the manifest to deviations only. */\nexport function readBgSizing(el: HTMLElement): Pick<Media, \"fit\" | \"position\"> {\n const style = el.getAttribute(\"style\") ?? \"\";\n const out: Pick<Media, \"fit\" | \"position\"> = {};\n const size = cssProp(style, \"background-size\")?.toLowerCase();\n if (size === \"auto\" || size === \"contain\") out.fit = size;\n const pos = cssProp(style, \"background-position\");\n if (pos && !CENTERED.has(pos.toLowerCase())) out.position = pos;\n return out;\n}\n\n/** Intrinsic render sizing off a foreground image holder: the inline pixel\n * `width`, the `.mediaRatio` `data-og-ratio` (→ `aspect`), and the\n * `background-size` (→ `fit`, only when contain/cover — a background's `auto`\n * is not foreground sizing). Each field is present only when the source has it,\n * so a plain holder still yields a bare `Media`. */\nfunction readImgSizing(holder: HTMLElement): Pick<Media, \"width\" | \"aspect\" | \"fit\" | \"minHeight\"> {\n const style = holder.getAttribute(\"style\") ?? \"\";\n const out: Pick<Media, \"width\" | \"aspect\" | \"fit\" | \"minHeight\"> = {};\n // Only a pixel width is a faithful intrinsic size. A `%`/`vw`/`em`/`calc()`\n // width is relative to context and must NOT be mistaken for px (which the\n // render layer would then apply literally) — skip it, leaving `width` absent.\n const w = cssProp(style, \"width\");\n const wpx = w ? /^(\\d+(?:\\.\\d+)?)px$/i.exec(w) : null;\n if (wpx?.[1]) out.width = Math.round(parseFloat(wpx[1]));\n const ogr = holder.querySelector(\".mediaRatio\")?.getAttribute(\"data-og-ratio\");\n if (ogr) {\n const n = Number(ogr);\n if (Number.isFinite(n)) out.aspect = Math.round(n * 1000) / 1000;\n }\n const fit = cssProp(style, \"background-size\")?.toLowerCase();\n if (fit === \"contain\" || fit === \"cover\") out.fit = fit;\n // The holder's inline min-height (e.g. \"80vh\" on a slider slide) is the\n // height the export reserves for a cover-rendered frame — keep it.\n const mh = cssProp(style, \"min-height\");\n if (mh) out.minHeight = mh;\n return out;\n}\n\n/** Playback semantics from a `<video>`'s boolean attributes — only those PRESENT\n * are set (an absent field = attribute absent). Undefined when none is present. */\nfunction readVideoPlayback(video: HTMLElement): VideoPlayback | undefined {\n const flags = [\"controls\", \"playsinline\", \"autoplay\", \"loop\", \"muted\"] as const;\n const pb: VideoPlayback = {};\n for (const f of flags) if (video.hasAttribute(f)) pb[f] = true;\n return Object.keys(pb).length ? pb : undefined;\n}\n\n/** Intrinsic aspect for a foreground `<video>`, reserved on a nearby\n * `.ib[data-og-ratio]` holder OR a `.mediaRatio` (inline `padding-bottom:NN%`).\n * Values are percent-suffixed strings (e.g. \"56.25%\") — strip the `%` (raw\n * `Number()` NaNs), then reuse the `aspect` = height-%-of-width convention.\n * Fail-safe: no parseable ratio → undefined (video keeps its bare shape). */\nfunction readVideoAspect(video: HTMLElement): number | undefined {\n let raw: string | undefined;\n let anc: HTMLElement | null | undefined = video.parentNode;\n for (let i = 0; i < 3 && anc && !raw; i++) {\n raw = anc.getAttribute?.(\"data-og-ratio\") ?? undefined;\n if (!raw) {\n const mr = anc.querySelector?.(\".mediaRatio\");\n raw = mr ? cssProp(mr.getAttribute(\"style\") ?? \"\", \"padding-bottom\") : undefined;\n }\n anc = anc.parentNode as HTMLElement | null | undefined;\n }\n if (!raw) return undefined;\n const n = parseFloat(raw.replace(/%\\s*$/, \"\"));\n return Number.isFinite(n) ? Math.round(n * 1000) / 1000 : undefined;\n}\n\n/** Resolve the media an element carries: a `.camediaload` descendant (image, via\n * `data-media`) or a `<video>` (via its src uuid). Returns null when there is none. */\nexport function mediaFromElement(el: HTMLElement): Media | null {\n if (el.tagName === \"VIDEO\") {\n const src = el.getAttribute(\"src\") ?? \"\";\n const { id, ext } = uuidFromUrl(src);\n if (!id) return null;\n // The full CDN url sits on `<video src>`; capture its prefix as `base` (the\n // same field an image carries from `data-base`) so `mediaCdnUrl` rebuilds it\n // OFFLINE. Without this a video resolves only via the IR sourceUrl, i.e. it\n // depends on site.json listing the asset — breaking convert's offline\n // invariant even though the url is right here in the markup.\n const clean = src.split(/[?#]/)[0] ?? \"\";\n const slash = clean.lastIndexOf(\"/\");\n const base = slash >= 0 ? clean.slice(0, slash + 1) : undefined;\n const aspect = readVideoAspect(el);\n const playback = readVideoPlayback(el);\n return {\n kind: \"video\",\n assetId: id,\n ...(ext ? { ext } : {}),\n ...(base ? { base } : {}),\n ...(aspect !== undefined ? { aspect } : {}),\n ...(playback ? { playback } : {}),\n };\n }\n const img =\n el.classList.contains(\"camediaload\") && el.getAttribute(\"data-media\")\n ? el\n : el.querySelector(\".camediaload[data-media]\");\n if (img) {\n const rawId = img.getAttribute(\"data-media\");\n if (rawId) {\n const ext = img.getAttribute(\"data-ext\") ?? undefined;\n const base = img.getAttribute(\"data-base\") ?? undefined;\n return {\n kind: \"image\",\n assetId: stripAssetExt(rawId, ext),\n ...(ext ? { ext } : {}),\n ...(base ? { base } : {}),\n ...readImgSizing(img),\n };\n }\n }\n const video = el.querySelector(\"video\");\n if (video) return mediaFromElement(video);\n return null;\n}\n","import type { Band, Cell, Media, Node, Widget } from \"./types.js\";\nimport type { CarouselSlide, CarouselSpec, SliceSpec } from \"./slice-spec.js\";\nimport { blockPlainText } from \"./leaf.js\";\n\n/** Depth-first collect of every `media` node's `Media` in a subtree. */\nexport function collectMedia(node: Node): Media[] {\n switch (node.kind) {\n case \"media\":\n return [node.media];\n case \"row\":\n return node.cells.flatMap((c) => collectMedia(c.node));\n case \"stack\":\n return node.children.flatMap(collectMedia);\n case \"heading\":\n case \"body\":\n case \"subtitle\":\n case \"widget\":\n case \"raw\":\n return [];\n }\n}\n\n/** Depth-first collect of text nodes (heading/body/subtitle). */\nexport function collectText(node: Node): Node[] {\n switch (node.kind) {\n case \"heading\":\n case \"body\":\n case \"subtitle\":\n return [node];\n case \"row\":\n return node.cells.flatMap((c) => collectText(c.node));\n case \"stack\":\n return node.children.flatMap(collectText);\n case \"media\":\n case \"widget\":\n case \"raw\":\n return [];\n }\n}\n\n/** Depth-first collect of every widget in a subtree. */\nexport function collectWidgets(node: Node): Widget[] {\n switch (node.kind) {\n case \"widget\":\n return [node.widget];\n case \"row\":\n return node.cells.flatMap((c) => collectWidgets(c.node));\n case \"stack\":\n return node.children.flatMap(collectWidgets);\n case \"heading\":\n case \"body\":\n case \"subtitle\":\n case \"media\":\n case \"raw\":\n return [];\n }\n}\n\n/** Depth-first collect of every `raw` node in a subtree. */\nfunction collectRaws(node: Node): Node[] {\n switch (node.kind) {\n case \"raw\":\n return [node];\n case \"row\":\n return node.cells.flatMap((c) => collectRaws(c.node));\n case \"stack\":\n return node.children.flatMap(collectRaws);\n case \"heading\":\n case \"body\":\n case \"subtitle\":\n case \"media\":\n case \"widget\":\n return [];\n }\n}\n\n/** The root row NODE, or null when the root is not a single row. A `stack`\n * whose only child is a row also counts (Blux wraps rows in holders). */\nexport function topRowNode(node: Node): Extract<Node, { kind: \"row\" }> | null {\n if (node.kind === \"row\") return node;\n if (node.kind === \"stack\" && node.children.length === 1) {\n const [only] = node.children;\n if (only && only.kind === \"row\") return only;\n }\n return null;\n}\n\n/** The cells of the root row, or null when the root is not a single row. */\nexport function topRow(node: Node): Cell[] | null {\n return topRowNode(node)?.cells ?? null;\n}\n\n/** A `raw` node carrying no rendered text or nested block — the shape a\n * client-injected mount (e.g. the map container) parses to. */\nexport function isEmptyRaw(node: Node): boolean {\n if (node.kind !== \"raw\") return false;\n const text = node.html.replace(/<[^>]*>/g, \"\").trim();\n return text.length === 0;\n}\n\n/** Options for the classifier. `isMapMount` is injected by plan 4\n * (`extract-map.ts`); by default nothing is recognized as a map. */\nexport type ClassifyOptions = {\n isMapMount?: (node: Node) => boolean;\n};\n\n/** The band's slice-zone base carried onto every spec (conditional spread keeps\n * `background` absent, not `undefined`, under exactOptionalPropertyTypes). */\nfunction base(band: Band): { index: number; background?: Media } {\n return { index: band.index, ...(band.background ? { background: band.background } : {}) };\n}\n\n/** Plain text of a heading/subtitle/body node. Hard line breaks (Blux `<br>`)\n * survive as newlines so the render layer can split a display title back into\n * lines; all other tags and source whitespace collapse to single spaces. */\nfunction nodeText(node: Node): string {\n switch (node.kind) {\n case \"heading\":\n case \"body\":\n // Raw markup — `<br>` → newline, other tags + source formatting → spaces.\n return blockPlainText(node.html);\n case \"subtitle\":\n // Already normalized at parse via blockPlainText (entities decoded, hard\n // breaks as newlines, source whitespace collapsed) — pass it through.\n return node.text.trim();\n case \"row\":\n case \"stack\":\n case \"media\":\n case \"widget\":\n case \"raw\":\n return \"\";\n }\n}\n\n/** The single media of a pure-media cell, or null if the cell isn't pure media. */\nfunction pureCellMedia(cell: Cell): Media | null {\n return cell.node.kind === \"media\" ? cell.node.media : null;\n}\n\n/** TitleBand/Hero presentation metadata: the heading's textN role + h-level and\n * the subtitle's role. Carried alongside the plain-string text (page-doc) so the\n * render applies the right display font/tag — band 15's script accent heading\n * (`h2.text11`) must not render like a plain `text5` title. */\nfunction textRoleMeta(\n heading: Node | undefined,\n subtitle: Node | undefined,\n): { headingRole?: string; headingLevel?: number; subtitleRole?: string } {\n return {\n ...(heading?.kind === \"heading\" && heading.role ? { headingRole: heading.role } : {}),\n ...(heading?.kind === \"heading\" ? { headingLevel: heading.level } : {}),\n ...(subtitle?.kind === \"subtitle\" && subtitle.role ? { subtitleRole: subtitle.role } : {}),\n };\n}\n\n/** A cell's effective column share as a percentage, from its grid token.\n *\n * Width comes from the explicit `ratio` (`grid-2-r60` → 60) or, absent that,\n * an equal split of the column count. `spacing` (the `s` suffix) is a gap, not\n * a width, so it never factors in here. The `\"any\"` → 50 fallback assumes a\n * 2-cell row — the only shape that reaches here today (SplitFeature requires\n * exactly two cells); a bare-`any` cell in a wider row would need real division. */\nfunction cellRatio(cell: Cell): number {\n const t = cell.token;\n if (typeof t.ratio === \"number\") return t.ratio;\n if (t.cols === \"any\") return 50;\n return Math.round(100 / t.cols);\n}\n\n/** The carousel slides of a slider row, or null when any cell isn't a media\n * slide. A slide is a bare `media` cell or a `stack[media, heading]` captioned\n * slide (the band-8 archetype); ≥2 qualifying slides required. */\nfunction carouselSlides(cells: Cell[]): CarouselSlide[] | null {\n const out: CarouselSlide[] = [];\n for (const c of cells) {\n const n = c.node;\n if (n.kind === \"media\") {\n out.push({ media: n.media });\n continue;\n }\n if (n.kind === \"stack\" && n.children.length === 2) {\n const [m, h] = n.children;\n if (m?.kind === \"media\" && h?.kind === \"heading\") {\n out.push({\n media: m.media,\n caption: { html: h.html, level: h.level, ...(h.role ? { role: h.role } : {}) },\n });\n continue;\n }\n }\n return null;\n }\n return out.length >= 2 ? out : null;\n}\n\n/** If every cell of a row is exactly one media node, return them in order. */\nfunction galleryMedia(cells: Cell[]): Media[] | null {\n const out: Media[] = [];\n for (const c of cells) {\n const m = pureCellMedia(c);\n if (!m) return null;\n out.push(m);\n }\n return out.length >= 2 ? out : null;\n}\n\n/** Return a copy of the tree with every node matching `isMapMount` replaced by a\n * `widget:map` node. Pure — does not mutate the input. Top-down: a matched\n * container is replaced whole, so its children are never visited. */\nfunction rewriteMapMounts(node: Node, isMapMount: (n: Node) => boolean): Node {\n if (isMapMount(node)) return { kind: \"widget\", widget: { type: \"map\" } };\n switch (node.kind) {\n case \"row\":\n return {\n kind: \"row\",\n cells: node.cells.map((c) => ({\n token: c.token,\n node: rewriteMapMounts(c.node, isMapMount),\n })),\n // Keep the slider marker — dropping it here would silently demote a\n // Carousel to Grid whenever a map config is present.\n ...(node.slider ? { slider: node.slider } : {}),\n };\n case \"stack\":\n return { kind: \"stack\", children: node.children.map((n) => rewriteMapMounts(n, isMapMount)) };\n case \"heading\":\n case \"body\":\n case \"subtitle\":\n case \"media\":\n case \"widget\":\n case \"raw\":\n return node;\n }\n}\n\n/** The single significant child of a container (ignoring empty raw), or the node\n * itself. Used to detect a band whose dominant content is one widget. */\nfunction soleSignificant(node: Node): Node {\n let kids: Node[];\n switch (node.kind) {\n case \"row\":\n kids = node.cells.map((c) => c.node);\n break;\n case \"stack\":\n kids = node.children;\n break;\n case \"heading\":\n case \"body\":\n case \"subtitle\":\n case \"media\":\n case \"widget\":\n case \"raw\":\n kids = [node];\n break;\n }\n const significant = kids.filter((n) => !isEmptyRaw(n));\n return significant.length === 1 && significant[0] ? significant[0] : node;\n}\n\n/** Classify one band into a SliceSpec. Conservative: only unambiguous shapes\n * become pattern slices; everything else is a render-faithful Grid fallback. */\nexport function classifyBand(band: Band, opts: ClassifyOptions = {}): SliceSpec {\n // Widget rewrite runs FIRST, so the pattern branches and the Grid fallback\n // all see `widget` nodes in place of injected mounts.\n const root = opts.isMapMount ? rewriteMapMounts(band.root, opts.isMapMount) : band.root;\n const widgets = collectWidgets(root);\n const media = collectMedia(root);\n const text = collectText(root);\n const rowNode = topRowNode(root);\n const row = rowNode ? rowNode.cells : null;\n // A raw node with real content is text we cannot account for — every\n // promotion must refuse to fire over it (only the Grid fallback keeps it).\n const hasSignificantRaw = collectRaws(root).some((n) => !isEmptyRaw(n));\n\n // Top-level widget promotion (before the structural patterns).\n const sole = soleSignificant(root);\n if (sole.kind === \"widget\" && sole.widget.type === \"map\") {\n return { slice: \"LocationMap\", ...base(band) };\n }\n if (\n media.length === 1 &&\n media[0]?.kind === \"video\" &&\n text.length === 0 &&\n widgets.length === 0 &&\n row === null &&\n !hasSignificantRaw\n ) {\n const v = media[0];\n return { slice: \"VideoFeature\", ...base(band), media: v };\n }\n\n const headings = text.filter((n) => n.kind === \"heading\");\n const subtitles = text.filter((n) => n.kind === \"subtitle\");\n const bodies = text.filter((n) => n.kind === \"body\");\n\n // Text-only bands (no media, no row, no widgets, no significant raw — any\n // co-located content must survive via the Grid fallback, not be swallowed).\n if (media.length === 0 && row === null && widgets.length === 0 && !hasSignificantRaw) {\n // TitleBand: exactly one heading + at most one subtitle, nothing else —\n // TitleBandSpec has nowhere to carry surplus text.\n if (headings.length === 1 && subtitles.length <= 1 && bodies.length === 0 && !band.background) {\n const first = headings[0];\n const sub = subtitles[0];\n return {\n slice: \"TitleBand\",\n ...base(band),\n heading: first ? nodeText(first) : \"\",\n ...(sub ? { subtitle: nodeText(sub) } : {}),\n ...textRoleMeta(first, sub),\n };\n }\n // RichText: body node(s) only — a subtitle would be dropped from the html.\n if (headings.length === 0 && subtitles.length === 0 && bodies.length > 0 && !band.background) {\n return {\n slice: \"RichText\",\n ...base(band),\n html: bodies.map((b) => (b.kind === \"body\" ? b.html : \"\")).join(\"\\n\"),\n };\n }\n }\n\n // Full-bleed hero: a background image with overlay text and no grid row. At\n // most one of each overlay text kind — HeroSpec keeps one heading/subtitle/\n // body, so surplus would be silently dropped.\n if (\n band.background &&\n headings.length === 1 &&\n subtitles.length <= 1 &&\n bodies.length <= 1 &&\n row === null &&\n media.length === 0 &&\n widgets.length === 0 &&\n !hasSignificantRaw\n ) {\n const h = headings[0];\n const sub = subtitles[0];\n const bod = bodies[0];\n return {\n slice: \"Hero\",\n ...base(band),\n ...(h ? { heading: nodeText(h) } : {}),\n ...(sub ? { subtitle: nodeText(sub) } : {}),\n ...(bod && bod.kind === \"body\" ? { body: bod.html } : {}),\n ...textRoleMeta(h, sub),\n };\n }\n\n // Carousel: a source slider row (.caslider) whose every cell is a media\n // slide, optionally captioned (stack[media, heading]). Anything richer\n // falls through to the faithful Grid fallback.\n if (rowNode?.slider) {\n const slides = carouselSlides(rowNode.cells);\n if (slides) {\n const spec: CarouselSpec = { slice: \"Carousel\", ...base(band), slides };\n if (rowNode.slider.columns !== undefined) spec.columns = rowNode.slider.columns;\n return spec;\n }\n }\n\n // Gallery: a row whose cells are all single media.\n if (row) {\n const gm = galleryMedia(row);\n if (gm) return { slice: \"Gallery\", ...base(band), media: gm };\n }\n\n // MediaFull: one media, no text, no top row, no widgets, no significant raw —\n // a row sibling, a co-located widget (e.g. a map mount), or raw prose would\n // be silently dropped, so those stay Grid.\n if (\n media.length === 1 &&\n text.length === 0 &&\n row === null &&\n widgets.length === 0 &&\n !hasSignificantRaw\n ) {\n const m = media[0];\n if (m) return { slice: \"MediaFull\", ...base(band), media: m };\n }\n\n // SplitFeature: exactly two cells, one pure media, one text-bearing.\n if (row && row.length === 2) {\n const [c0, c1] = row;\n if (c0 && c1) {\n const m0 = pureCellMedia(c0);\n const m1 = pureCellMedia(c1);\n const t0 = collectText(c0.node).length > 0;\n const t1 = collectText(c1.node).length > 0;\n if (m0 && !m1 && t1) {\n return {\n slice: \"SplitFeature\",\n ...base(band),\n media: m0,\n mediaSide: \"left\",\n ratio: cellRatio(c0),\n text: c1.node,\n };\n }\n if (m1 && !m0 && t0) {\n return {\n slice: \"SplitFeature\",\n ...base(band),\n media: m1,\n mediaSide: \"right\",\n ratio: cellRatio(c1),\n text: c0.node,\n };\n }\n }\n }\n\n return { slice: \"Grid\", ...base(band), root };\n}\n\nexport function classifyBands(bands: Band[], opts: ClassifyOptions = {}): SliceSpec[] {\n return bands.map((b) => classifyBand(b, opts));\n}\n","// Plan 4 of docs/superpowers/specs/2026-07-08-blux-faithful-grid-slices-design.md:\n// deterministic extraction of the Blux map widget's config from the rendered\n// index.html. The initMap script carries mount/styles/layers; the toggle-chip\n// labels live in the band markup and the group logic in the site's clickMap\n// script. The Google API key lives only in the separate loader URL and is\n// deliberately NOT extracted — render uses VITE_GOOGLE_MAPS_KEY.\n\nimport type { Node } from \"./types.js\";\n\nexport type MapKmlLayer = {\n /** mapLayers key in the source script, e.g. \"Hotels\". */\n name: string;\n lid: string;\n /** Constructed with `map: map` — visible before any toggle. */\n initiallyVisible: boolean;\n /** Absent in source = false = layer fits the viewport to its KML bounds. */\n preserveViewport: boolean;\n};\n\nexport type MapToggleGroup = {\n label: string;\n layers: string[];\n /** The content panel (0-based `cagrid` cell) this chip reveals — chip index\n * `i` shows panel `i`, hiding the others; pairs with `MapConfig.defaultToggle`. */\n panelIndex: number;\n};\n\nexport type MapConfig = {\n mountId: string;\n mid: string;\n layers: MapKmlLayer[];\n toggles: MapToggleGroup[];\n /** Google Maps style rules, verbatim JSON. */\n styles: unknown[];\n center?: { lat: number; lng: number };\n zoom?: number;\n /** The mount div's inline height (e.g. \"600px\"); absent = let the render decide. */\n height?: string;\n /** Which toggle/panel is active on load (source default = the first, 0). Present\n * only when there are toggles. */\n defaultToggle?: number;\n};\n\nconst SCRIPT_RE = /<script\\b[^>]*>([\\s\\S]*?)<\\/script>/g;\n\nfunction findScript(html: string, marker: RegExp): string | null {\n for (const m of html.matchAll(SCRIPT_RE)) {\n const body = m[1];\n if (body !== undefined && marker.test(body)) return body;\n }\n return null;\n}\n\n/** Balanced-bracket slice of the JSON array starting at `styles:[`. */\nfunction extractStyles(script: string): unknown[] {\n const at = script.indexOf(\"styles:[\");\n if (at === -1) return [];\n const start = at + \"styles:\".length;\n let depth = 0;\n for (let i = start; i < script.length; i++) {\n const ch = script[i];\n if (ch === \"[\") depth++;\n else if (ch === \"]\") {\n depth--;\n if (depth === 0) {\n try {\n // The Blux styles literal uses unquoted keys — quote them for JSON.parse.\n const raw = script.slice(start, i + 1);\n const jsonish = raw.replace(/([{,])\\s*([A-Za-z_][A-Za-z0-9_.]*)\\s*:/g, '$1\"$2\":');\n const parsed: unknown = JSON.parse(jsonish);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n }\n }\n return [];\n}\n\nconst LAYER_RE = /(\\w+)\\s*:\\s*new google\\.maps\\.KmlLayer\\(\\{([^}]*)\\}\\)/g;\n\nexport function extractMapConfig(html: string): MapConfig | null {\n const init = findScript(html, /function initMap\\(\\)[\\s\\S]*new google\\.maps\\.Map/);\n if (!init) return null;\n\n const mountId = /getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/.exec(init)?.[1];\n if (!mountId) return null;\n\n const layers: MapKmlLayer[] = [];\n let mid: string | undefined;\n for (const m of init.matchAll(LAYER_RE)) {\n const name = m[1];\n const args = m[2];\n if (!name || args === undefined) continue;\n const layerMid = /[?&]mid=([^&\"']+)/.exec(args)?.[1];\n const lid = /[?&]lid=([^&\"']+)/.exec(args)?.[1];\n if (!layerMid || !lid) continue;\n mid ??= layerMid;\n layers.push({\n name,\n lid,\n initiallyVisible: /\\bmap\\s*:\\s*map\\b/.test(args),\n preserveViewport: /preserveViewport\\s*:\\s*true/.test(args),\n });\n }\n if (!mid || layers.length === 0) return null;\n\n const centerM = /center\\s*:\\s*\\{\\s*lat\\s*:\\s*(-?[\\d.]+)\\s*,\\s*lng\\s*:\\s*(-?[\\d.]+)\\s*\\}/.exec(\n init,\n );\n const zoomM = /zoom\\s*:\\s*(\\d+)/.exec(init);\n\n // The mount div's own inline height (`<div id=\"burbank_map\" style=\"…height:600px\">`)\n // — it lives on the inner mount, not the section, so section-style capture misses it.\n const mountTag = new RegExp(`<[^>]*\\\\bid=[\"']${mountId}[\"'][^>]*>`, \"i\").exec(html)?.[0] ?? \"\";\n const height = /height\\s*:\\s*([\\d.]+(?:px|%|vh|vw|em|rem))/i.exec(mountTag)?.[1];\n\n const toggles = extractToggles(html);\n\n return {\n mountId,\n mid,\n layers,\n toggles,\n styles: extractStyles(init),\n ...(centerM?.[1] && centerM[2]\n ? { center: { lat: Number(centerM[1]), lng: Number(centerM[2]) } }\n : {}),\n ...(zoomM?.[1] ? { zoom: Number(zoomM[1]) } : {}),\n ...(height ? { height } : {}),\n ...(toggles.length ? { defaultToggle: 0 } : {}),\n };\n}\n\n/** The classifier predicate (plan-2 `ClassifyOptions.isMapMount`): matches the\n * raw node carrying the map mount element. Mounts parse to `raw` nodes; the\n * mount id survives verbatim in the serialized html. */\nexport function makeIsMapMount(config: MapConfig): (node: Node) => boolean {\n const marker = `id=\"${config.mountId}\"`;\n return (node) => node.kind === \"raw\" && node.html.includes(marker);\n}\n\n/** Pairs the band's map_icon chip labels (DOM order) with the clickMap\n * groups (index order). Either side missing → no toggles (map still renders\n * its initially-visible layers). */\nfunction extractToggles(html: string): MapToggleGroup[] {\n const labels = [...html.matchAll(/map_icon_text\">([^<]*)</g)]\n .map((m) => m[1])\n .filter((l): l is string => l !== undefined);\n const click = findScript(html, /clickMap\\s*=\\s*\\{\\s*0\\s*:/);\n if (!click || labels.length === 0) return [];\n const bodyM = /clickMap\\s*=\\s*(\\{[\\s\\S]*?\\}\\})\\s*;/.exec(click);\n if (!bodyM?.[1]) return [];\n const groups: MapToggleGroup[] = [];\n for (const g of bodyM[1].matchAll(/(\\d+)\\s*:\\s*function\\s*\\(onoff\\)\\s*\\{([^}]*)\\}/g)) {\n const idx = Number(g[1]);\n const body = g[2] ?? \"\";\n const layerNames = [\n ...new Set(\n [...body.matchAll(/mapLayers\\.(\\w+)\\./g)]\n .map((m) => m[1])\n .filter((n): n is string => n !== undefined),\n ),\n ];\n const label = labels[idx];\n if (label === undefined) return [];\n groups[idx] = { label, layers: layerNames, panelIndex: idx };\n }\n // Non-contiguous clickMap indices would leave holes that serialize as null.\n return groups.length === labels.length && groups.every((g) => g !== undefined) ? groups : [];\n}\n","import { cleanCssValue } from \"../normalize.js\";\n\n/** Per-band block styles (background-color, min-height, text-align, …) sourced\n * from site.json's top-level page blocks, cleaned exactly as normalize.ts does.\n * Keyed by the block's render-order index, which equals the grid `Band.index`\n * (the `page-block-N` number) for a contiguously-rendered page.\n *\n * site.json's page blocks live at `content.pages[0].items` (see\n * `parseBluxSite` in parse.ts, which reads `j.content.pages`, and `BluxPage`,\n * whose blocks field is `items`) — not `pages[0].blocks` as a naive reading\n * of the export's top level might suggest. */\nexport function blockStylesByIndex(siteJson: unknown): Map<number, Record<string, string>> {\n const out = new Map<number, Record<string, string>>();\n const blocks = (siteJson as { content?: { pages?: { items?: unknown[] }[] } })?.content\n ?.pages?.[0]?.items;\n if (!Array.isArray(blocks)) return out;\n blocks.forEach((b, i) => {\n const styles = (b as { styles?: Record<string, unknown> })?.styles ?? {};\n const cleaned: Record<string, string> = {};\n for (const [k, v] of Object.entries(styles)) {\n const c = cleanCssValue(v);\n if (c) cleaned[k] = c;\n }\n if (Object.keys(cleaned).length) out.set(i, cleaned);\n });\n return out;\n}\n","import { blockPlainText, type SliceSpec } from \"../grid/index.js\";\nimport { type PlanSlice, richText } from \"./plan.js\";\n\n/** Strip all tags → the plain text a Prismic \"Text\" (key-text) field holds. */\nfunction stripTags(html: string): string {\n return html\n .replace(/<[^>]*>/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** Map one classified band to its page-doc slice. Text + band index only —\n * media, layout, style and map all live in the presentation manifest. */\nexport function sliceSpecToPlanSlice(spec: SliceSpec): PlanSlice {\n switch (spec.slice) {\n case \"Hero\":\n return {\n slice_type: \"hero\",\n variation: \"band\",\n items: [],\n primary: {\n band: spec.index,\n ...(spec.heading ? { heading: spec.heading } : {}),\n ...(spec.subtitle ? { subtitle: spec.subtitle } : {}),\n ...(spec.body ? { body: stripTags(spec.body) } : {}),\n },\n };\n case \"TitleBand\":\n return {\n slice_type: \"title_band\",\n variation: \"default\",\n items: [],\n primary: {\n band: spec.index,\n heading: spec.heading,\n ...(spec.subtitle ? { subtitle: spec.subtitle } : {}),\n },\n };\n case \"RichText\":\n return {\n slice_type: \"rich_text\",\n variation: \"default\",\n items: [],\n primary: { content: richText(spec.html), band: spec.index },\n };\n case \"SplitFeature\":\n return {\n slice_type: \"split_feature\",\n variation: \"default\",\n items: [],\n primary: { band: spec.index },\n };\n case \"Gallery\":\n return {\n slice_type: \"gallery\",\n variation: \"default\",\n items: [],\n primary: { band: spec.index },\n };\n case \"Carousel\":\n // One item per slide, in slide order (the render zips by index); an\n // uncaptioned slide contributes {} so the alignment holds. Captions are\n // heading nodes, so blockPlainText (entities decoded, <br> kept as a\n // newline) — same as the Hero/TitleBand heading path.\n return {\n slice_type: \"carousel\",\n variation: \"default\",\n items: spec.slides.map((s) =>\n s.caption ? { caption: blockPlainText(s.caption.html) } : {},\n ),\n primary: { band: spec.index },\n };\n case \"MediaFull\":\n case \"VideoFeature\":\n return {\n slice_type: \"media_full\",\n variation: \"default\",\n items: [],\n primary: { band: spec.index },\n };\n case \"LocationMap\":\n return {\n slice_type: \"location_map\",\n variation: \"default\",\n items: [],\n primary: { band: spec.index },\n };\n case \"Grid\":\n return {\n slice_type: \"grid_band\",\n variation: \"default\",\n items: [],\n primary: { band: spec.index },\n };\n }\n}\n","import { type SliceSpec, type Media, collectMedia } from \"../grid/index.js\";\nimport type { Diagnostic, SiteIR } from \"../ir.js\";\nimport { buildCustomType } from \"./custom-types.js\";\nimport { sliceSpecToPlanSlice } from \"./grid-slice.js\";\nimport { type MigrationPlan, type PlanAsset, type PlanDocument, richText } from \"./plan.js\";\n\n/** Build the CDN url for a media from its parser-captured base + uuid + ext.\n * Null when the node carried no `data-base` (the manifest resolver then falls\n * back to the IR asset's sourceUrl — see `buildGridPlan`). Exported so the\n * `blux convert` manifest resolver builds byte-identical urls (a later task\n * rewrites the manifest by matching plan.assets urls). */\nexport function mediaCdnUrl(m: Media): string | null {\n return m.base ? `${m.base}${m.assetId}${m.ext ? `.${m.ext}` : \"\"}` : null;\n}\n\n/** The absolute source url for a media: the parser-captured CDN url\n * (data-base + uuid + ext) if present, else the IR asset's scraped sourceUrl,\n * else null. Shared by the plan's asset list and the manifest resolver so the\n * two url strings are byte-identical (the migrate rewrite keys on that). */\nexport function mediaUrl(\n m: Media,\n sourceUrlById: Map<string, string | null | undefined>,\n): string | null {\n return mediaCdnUrl(m) ?? sourceUrlById.get(m.assetId) ?? null;\n}\n\n/** Every Media referenced across all specs: band backgrounds, direct media\n * fields, and media inside node trees (SplitFeature.text / Grid.root). Deduped\n * by assetId, first occurrence wins, insertion order preserved. `resolve`\n * turns a media into its upload entry (CDN-base url, else IR sourceUrl) or null\n * when neither is available — an unresolvable media is dropped and (if a\n * `diagnostics` sink is passed) recorded once per assetId. */\nexport function collectPlanAssets(\n specs: SliceSpec[],\n resolve: (m: Media) => PlanAsset | null,\n diagnostics?: Diagnostic[],\n): PlanAsset[] {\n const byId = new Map<string, PlanAsset>();\n const seen = new Set<string>();\n const add = (m: Media) => {\n if (seen.has(m.assetId)) return;\n seen.add(m.assetId);\n const asset = resolve(m);\n if (asset) byId.set(m.assetId, asset);\n else\n diagnostics?.push({\n kind: \"unresolved-asset\",\n where: m.assetId,\n message: `media ${m.assetId} has no CDN base nor IR source url — not uploaded`,\n });\n };\n for (const spec of specs) {\n if (spec.background) add(spec.background);\n switch (spec.slice) {\n case \"Gallery\":\n spec.media.forEach(add);\n break;\n case \"Carousel\":\n spec.slides.forEach((s) => add(s.media));\n break;\n case \"MediaFull\":\n case \"VideoFeature\":\n add(spec.media);\n break;\n case \"SplitFeature\":\n add(spec.media);\n collectMedia(spec.text).forEach(add);\n break;\n case \"Grid\":\n collectMedia(spec.root).forEach(add);\n break;\n default:\n break; // Hero/TitleBand/RichText/LocationMap: only background (handled above)\n }\n }\n return [...byId.values()];\n}\n\n/** Build the Prismic migration plan for a grid-converted site: one text-only\n * page document + the assets its manifest references (uploaded so the manifest\n * can be rewritten to Prismic urls at migrate time). Collections flow through\n * `buildCustomType`, unchanged from archetype. */\nexport function buildGridPlan(specs: SliceSpec[], ir: SiteIR): MigrationPlan {\n const page = ir.pages[0];\n const uid = page?.uid ?? \"home\";\n const title = page?.title ?? uid;\n const doc: PlanDocument = {\n type: \"page\",\n uid,\n data: { title: richText(`<h1>${title}</h1>`), slices: specs.map(sliceSpecToPlanSlice) },\n };\n // Upload-url resolution MUST stay identical to the later manifest resolver:\n // CDN-base url first, else the IR asset's sourceUrl. `mediaUrl` is the\n // single shared implementation (see its doc comment above).\n const assetById = new Map(ir.assets.map((a) => [a.id, a] as const));\n const sourceUrlById = new Map(ir.assets.map((a) => [a.id, a.sourceUrl] as const));\n const resolve = (m: Media): PlanAsset | null => {\n const asset = assetById.get(m.assetId);\n const url = mediaUrl(m, sourceUrlById);\n return url ? { id: m.assetId, url, alt: asset?.alt ?? \"\" } : null;\n };\n const diagnostics: Diagnostic[] = [...(ir.diagnostics ?? [])];\n const assets = collectPlanAssets(specs, resolve, diagnostics);\n const customTypes = ir.collections.map(buildCustomType);\n return { customTypes, documents: [doc], assets, stylesManifest: [], diagnostics };\n}\n","// Render-faithful presentation manifest (plan 5). Transforms the source\n// node tree (src/blux/grid/types.ts `Node`) and the classified `SliceSpec[]`\n// into `blux-presentation.json`, the render-side contract the-pointe's\n// Svelte layer loads (src/lib/blux/presentation.ts — that file is the fixed\n// target; these mirror types must match it exactly). Media/style/map are\n// resolved via injected `deps` so this builder stays pure and offline.\nimport type {\n Media,\n Node,\n GridToken as SrcToken,\n SliceSpec,\n VideoPlayback,\n} from \"../grid/index.js\";\n\n// ---------------------------------------------------------------------------\n// Render-side mirror types (must match the-pointe's src/lib/blux/presentation.ts)\n// ---------------------------------------------------------------------------\n\nexport type RenderMedia = {\n kind: \"image\" | \"video\";\n url: string;\n alt?: string;\n // Intrinsic sizing carried from the source. `width`/`aspect` size a foreground\n // graphic (capped to its cell) so rules/logos keep their true size. `fit` +\n // `position` carry a band background's `background-size`/`-position` so a\n // corner-anchored `auto` accent isn't centered full-bleed. `playback` carries a\n // video's source `<video>` attributes. Mirrors the-pointe's src/lib/blux/presentation.ts.\n width?: number;\n aspect?: number;\n fit?: \"contain\" | \"cover\" | \"auto\";\n position?: string;\n /** The source holder's inline min-height (e.g. \"80vh\" on slider slides), so\n * a cover-frame carousel reserves the original's height. */\n minHeight?: string;\n playback?: VideoPlayback;\n};\n\nexport type RenderToken = { cols: number | \"any\"; ratio?: number; spacing?: number };\n\nexport type RenderNode =\n | { kind: \"row\"; cells: RenderCell[] }\n | { kind: \"stack\"; children: RenderNode[] }\n | { kind: \"heading\"; level: number; html: string; role?: string }\n | { kind: \"body\"; html: string; role?: string }\n | { kind: \"subtitle\"; text: string; role?: string }\n | { kind: \"media\"; media: RenderMedia }\n | { kind: \"raw\"; html: string }\n | { kind: \"widget\"; widget: { type: \"map\" } };\n\nexport type RenderCell = { token: RenderToken; node: RenderNode };\n\nexport type MapLayer = {\n name: string;\n lid: string;\n initiallyVisible: boolean;\n preserveViewport: boolean;\n};\nexport type MapToggle = { label: string; layers: string[]; panelIndex: number };\nexport type MapRenderConfig = {\n mid: string;\n layers: MapLayer[];\n toggles: MapToggle[];\n styles: unknown[];\n center?: { lat: number; lng: number };\n zoom?: number;\n height?: string;\n defaultToggle?: number;\n};\n\nexport type BandPresentation = {\n style?: Record<string, string>;\n background?: RenderMedia;\n tree?: RenderNode;\n split?: { mediaSide: \"left\" | \"right\"; ratio: number; media: RenderMedia; text: RenderNode };\n gallery?: RenderMedia[];\n /** Carousel payload: the band is a source slider (.caslider). Caption TEXT\n * lives in the page doc's items (Prismic-editable); the manifest carries the\n * media and the caption's role metadata. `columns` = slides visible at once\n * (source data-columns). */\n carousel?: {\n slides: {\n media: RenderMedia;\n caption?: { level?: number; role?: string };\n }[];\n columns?: number;\n };\n media?: RenderMedia;\n map?: MapRenderConfig;\n /** Hero/TitleBand heading textN role + h-level and subtitle role, so the\n * render applies the right display font/tag. The text itself is the Prismic\n * page-doc string; this is presentation metadata only. */\n text?: { headingRole?: string; headingLevel?: number; subtitleRole?: string };\n};\n\nexport type Presentation = { bands: Record<string, BandPresentation> };\n\nexport type PresentationDeps = {\n resolveMedia: (media: Media) => RenderMedia | null;\n styleFor: (index: number) => Record<string, string> | undefined;\n map?: MapRenderConfig | null;\n};\n\n// ---------------------------------------------------------------------------\n// Node-tree serializer: source Node → RenderNode\n// ---------------------------------------------------------------------------\n\n/** Drop the source-only `raw` field from a grid token; keep only cols/ratio/spacing. */\nfunction renderToken(t: SrcToken): RenderToken {\n return {\n cols: t.cols,\n ...(t.ratio !== undefined ? { ratio: t.ratio } : {}),\n ...(t.spacing !== undefined ? { spacing: t.spacing } : {}),\n };\n}\n\n/** Recursively serialize a source Node → RenderNode: resolve media (dropping\n * unresolved media nodes), strip token.raw. Never mutates the input. */\nfunction renderNode(node: Node, resolve: PresentationDeps[\"resolveMedia\"]): RenderNode | null {\n switch (node.kind) {\n case \"row\": {\n const cells: RenderCell[] = [];\n for (const c of node.cells) {\n const rn = renderNode(c.node, resolve);\n if (rn) cells.push({ token: renderToken(c.token), node: rn });\n }\n return { kind: \"row\", cells };\n }\n case \"stack\": {\n const children: RenderNode[] = [];\n for (const c of node.children) {\n const rn = renderNode(c, resolve);\n if (rn) children.push(rn);\n }\n return { kind: \"stack\", children };\n }\n case \"heading\":\n return {\n kind: \"heading\",\n level: node.level,\n html: node.html,\n ...(node.role ? { role: node.role } : {}),\n };\n case \"body\":\n return { kind: \"body\", html: node.html, ...(node.role ? { role: node.role } : {}) };\n case \"subtitle\":\n return { kind: \"subtitle\", text: node.text, ...(node.role ? { role: node.role } : {}) };\n case \"media\": {\n const m = resolve(node.media);\n return m ? { kind: \"media\", media: m } : null; // drop unresolved media\n }\n case \"raw\":\n return { kind: \"raw\", html: node.html };\n case \"widget\":\n return { kind: \"widget\", widget: node.widget };\n }\n}\n\n/** Does a (source) node tree contain a map widget anywhere? */\nexport function hasMapWidget(node: Node): boolean {\n if (node.kind === \"widget\") return node.widget.type === \"map\";\n if (node.kind === \"row\") return node.cells.some((c) => hasMapWidget(c.node));\n if (node.kind === \"stack\") return node.children.some(hasMapWidget);\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Per-variant builder: SliceSpec[] → Presentation\n// ---------------------------------------------------------------------------\n\nexport function buildPresentation(specs: SliceSpec[], deps: PresentationDeps): Presentation {\n const bands: Record<string, BandPresentation> = {};\n for (const spec of specs) {\n const bp: BandPresentation = {};\n const style = deps.styleFor(spec.index);\n if (style) bp.style = style;\n if (spec.background) {\n const bg = deps.resolveMedia(spec.background);\n if (bg) bp.background = bg;\n }\n\n switch (spec.slice) {\n case \"Hero\":\n case \"TitleBand\": {\n // Text lives in the page doc; carry only the role/level metadata so the\n // render picks the right display font + heading tag.\n const meta = {\n ...(spec.headingRole ? { headingRole: spec.headingRole } : {}),\n ...(spec.headingLevel !== undefined ? { headingLevel: spec.headingLevel } : {}),\n ...(spec.subtitleRole ? { subtitleRole: spec.subtitleRole } : {}),\n };\n if (Object.keys(meta).length) bp.text = meta;\n break;\n }\n case \"RichText\":\n break; // content is in the page doc\n case \"Gallery\": {\n const g = spec.media.map(deps.resolveMedia).filter((m): m is RenderMedia => m !== null);\n if (g.length) bp.gallery = g;\n break;\n }\n case \"Carousel\": {\n // Caption TEXT lives in the page doc's items; only its role metadata\n // rides the manifest. An unresolved media TRUNCATES the slide list —\n // splicing it out would shift later slides onto the wrong page-doc\n // caption (the render zips items↔slides by index). Either way the\n // count shrink trips validateLayout's media-dropped finding.\n const slides: { media: RenderMedia; caption?: { level?: number; role?: string } }[] = [];\n for (const s of spec.slides) {\n const media = deps.resolveMedia(s.media);\n if (!media) break;\n const slide: { media: RenderMedia; caption?: { level?: number; role?: string } } = {\n media,\n };\n if (s.caption) {\n const caption: { level?: number; role?: string } = { level: s.caption.level };\n if (s.caption.role !== undefined) caption.role = s.caption.role;\n slide.caption = caption;\n }\n slides.push(slide);\n }\n if (slides.length > 0) {\n bp.carousel = spec.columns !== undefined ? { slides, columns: spec.columns } : { slides };\n }\n break;\n }\n case \"MediaFull\":\n case \"VideoFeature\": {\n const m = deps.resolveMedia(spec.media);\n if (m) bp.media = m;\n break;\n }\n case \"SplitFeature\": {\n const media = deps.resolveMedia(spec.media);\n const text = renderNode(spec.text, deps.resolveMedia);\n if (media && text) bp.split = { mediaSide: spec.mediaSide, ratio: spec.ratio, media, text };\n break;\n }\n case \"LocationMap\":\n if (deps.map) bp.map = deps.map;\n break;\n case \"Grid\": {\n const tree = renderNode(spec.root, deps.resolveMedia);\n if (tree) bp.tree = tree;\n // Co-located map (widget:map inside the tree): attach the map config too.\n if (deps.map && hasMapWidget(spec.root)) bp.map = deps.map;\n break;\n }\n }\n bands[String(spec.index)] = bp;\n }\n return { bands };\n}\n","import {\n parseGridBands,\n extractMapConfig,\n classifyBands,\n makeIsMapMount,\n type Band,\n type MapConfig,\n type SliceSpec,\n} from \"../grid/index.js\";\nimport { assembleIR } from \"../assemble.js\";\nimport type { SiteIR } from \"../ir.js\";\nimport { blockStylesByIndex } from \"./block-styles.js\";\nimport { buildGridPlan, mediaUrl } from \"./grid-plan.js\";\nimport type { MigrationPlan } from \"./plan.js\";\nimport {\n buildPresentation,\n type MapRenderConfig,\n type Presentation,\n type PresentationDeps,\n type RenderMedia,\n} from \"./presentation.js\";\n\nexport type ConvertResult = {\n bands: Band[];\n specs: SliceSpec[];\n ir: SiteIR;\n mapConfig: MapConfig | null;\n plan: MigrationPlan;\n presentation: Presentation;\n};\n\n/** Drop the source-only `mountId` from an extracted MapConfig → the render-side\n * MapRenderConfig the presentation manifest carries. */\nexport function mapRenderFromConfig(c: MapConfig): MapRenderConfig {\n return {\n mid: c.mid,\n layers: c.layers,\n toggles: c.toggles,\n styles: c.styles,\n ...(c.center ? { center: c.center } : {}),\n ...(c.zoom !== undefined ? { zoom: c.zoom } : {}),\n ...(c.height ? { height: c.height } : {}),\n ...(c.defaultToggle !== undefined ? { defaultToggle: c.defaultToggle } : {}),\n };\n}\n\n/** The offline convert pipeline shared by `blux convert` (writes files) and\n * `blux validate` (checks fidelity): parse + classify index.html, assemble the\n * IR from site.json, and build both emit artifacts through a single media\n * resolver (CDN base ?? IR sourceUrl) so plan, manifest, and validation all\n * agree on which media resolve. Pure + offline — no writes, no network. */\nexport function convertExport({\n html,\n siteJson,\n}: {\n html: string;\n siteJson: unknown;\n}): ConvertResult {\n const bands = parseGridBands(html);\n const mapConfig = extractMapConfig(html);\n const specs = classifyBands(bands, mapConfig ? { isMapMount: makeIsMapMount(mapConfig) } : {});\n const ir = assembleIR({ siteJson, htmls: [html] });\n\n const assetsById = new Map(ir.assets.map((a) => [a.id, a] as const));\n const sourceUrlById = new Map(ir.assets.map((a) => [a.id, a.sourceUrl] as const));\n const styles = blockStylesByIndex(siteJson);\n const deps: PresentationDeps = {\n resolveMedia: (m) => {\n const url = mediaUrl(m, sourceUrlById);\n if (!url) return null;\n const alt = assetsById.get(m.assetId)?.alt;\n const rm: RenderMedia = {\n kind: m.kind,\n url,\n ...(alt ? { alt } : {}),\n ...(m.width !== undefined ? { width: m.width } : {}),\n ...(m.aspect !== undefined ? { aspect: m.aspect } : {}),\n ...(m.fit ? { fit: m.fit } : {}),\n ...(m.position ? { position: m.position } : {}),\n ...(m.minHeight ? { minHeight: m.minHeight } : {}),\n ...(m.playback ? { playback: m.playback } : {}),\n };\n return rm;\n },\n styleFor: (i) => styles.get(i),\n map: mapConfig ? mapRenderFromConfig(mapConfig) : null,\n };\n\n const plan = buildGridPlan(specs, ir);\n const presentation = buildPresentation(specs, deps);\n return { bands, specs, ir, mapConfig, plan, presentation };\n}\n","// Offline layout-fidelity gate (plan 6). Diffs the classified source\n// (`SliceSpec[]`, already gated band→spec by grid-classify-golden) against the\n// emitted presentation manifest (plan 5), naming every band whose layout,\n// media, or map drifted. Pure + offline — the render side (Playwright DOM\n// signature) is plan 7's verify. See the plan's \"The comparison, precisely\".\nimport type { Cell, Node, SliceSpec } from \"../grid/index.js\";\nimport {\n hasMapWidget,\n type Presentation,\n type RenderCell,\n type RenderNode,\n} from \"./presentation.js\";\n\n/** Canonical grid-token key — cols + optional ratio/spacing, WITHOUT the\n * source-only `raw` string, so a source token and its render-side twin (which\n * never carries `raw`) compare equal. */\nfunction tokKey(t: { cols: number | \"any\"; ratio?: number; spacing?: number }): string {\n return `${t.cols}${t.ratio !== undefined ? `r${t.ratio}` : \"\"}${t.spacing !== undefined ? `s${t.spacing}` : \"\"}`;\n}\n\n/** Compact structural signature of a node tree, computed identically for a\n * source `Node` and its serialized `RenderNode` twin (they share `kind`s and\n * aligned fields). Prose is excluded; only kinds + grid tokens + media/widget\n * kinds appear — so it snapshots LAYOUT, not content. A source media node the\n * manifest dropped (unresolved url) makes the two signatures diverge, which is\n * exactly the fidelity signal we want. Mirrors `grid/signature.ts`'s exhaustive\n * switch so a new node kind is a compile error, not a silent drop. */\nexport function sigOf(node: Node | RenderNode): string {\n switch (node.kind) {\n case \"row\":\n return `row[${node.cells\n .map((c: Cell | RenderCell) => `${tokKey(c.token)}:${sigOf(c.node)}`)\n .join(\",\")}]`;\n case \"stack\":\n return `stack[${node.children.map(sigOf).join(\",\")}]`;\n case \"heading\":\n return `h${node.level}`;\n case \"body\":\n return \"body\";\n case \"subtitle\":\n return \"subtitle\";\n case \"media\":\n return `media:${node.media.kind}`;\n case \"widget\":\n return `widget:${node.widget.type}`;\n case \"raw\":\n return \"raw\";\n }\n}\n\nexport type LayoutFinding =\n | { kind: \"band-count\"; specs: number; manifest: number }\n | { kind: \"band-missing\"; band: number }\n | { kind: \"tree-drift\"; band: number; expected: string; actual: string }\n | { kind: \"media-dropped\"; band: number; where: string }\n | { kind: \"map-missing\"; band: number };\n\nexport type LayoutRow = {\n band: number;\n slice: SliceSpec[\"slice\"];\n source: string;\n converted: string;\n ok: boolean;\n};\n\nexport type LayoutReport = {\n /** number of source bands (== specs.length) */\n bands: number;\n /** Grid-fallback bands whose tree fidelity was signature-checked */\n gridBands: number;\n faithful: boolean;\n findings: LayoutFinding[];\n rows: LayoutRow[];\n};\n\n/** A short source-side label per slice, used for the report row's `source`\n * column and the missing-band row. Grid uses the full structural signature. */\nfunction sourceLabel(spec: SliceSpec): string {\n switch (spec.slice) {\n case \"Grid\":\n return sigOf(spec.root);\n case \"Gallery\":\n return `gallery(${spec.media.length})`;\n case \"Carousel\":\n return `carousel(${spec.slides.length})`;\n case \"MediaFull\":\n return \"media_full\";\n case \"VideoFeature\":\n return \"video\";\n case \"SplitFeature\":\n return `split(${spec.mediaSide},${spec.ratio})`;\n case \"LocationMap\":\n return \"location_map\";\n case \"Hero\":\n return \"hero\";\n case \"TitleBand\":\n return \"title_band\";\n case \"RichText\":\n return \"rich_text\";\n }\n}\n\n/** Diff the classified source against the emitted manifest. Grid bands must\n * round-trip their structural signature exactly (spec.root vs the serialized\n * tree); smart slices are checked for payload completeness (gallery count,\n * split/media present, background/map present). Returns a structured report;\n * `faithful` is true iff `findings` is empty. */\nexport function validateLayout(specs: SliceSpec[], presentation: Presentation): LayoutReport {\n const findings: LayoutFinding[] = [];\n const rows: LayoutRow[] = [];\n const manifestKeys = Object.keys(presentation.bands);\n let gridBands = 0;\n\n if (specs.length !== manifestKeys.length) {\n findings.push({ kind: \"band-count\", specs: specs.length, manifest: manifestKeys.length });\n }\n\n // We iterate specs (the source answer key): a stray manifest band with no spec surfaces only via the band-count mismatch above, never named — by design.\n for (const spec of specs) {\n const source = sourceLabel(spec);\n const bp = presentation.bands[String(spec.index)];\n if (!bp) {\n findings.push({ kind: \"band-missing\", band: spec.index });\n rows.push({ band: spec.index, slice: spec.slice, source, converted: \"∅\", ok: false });\n continue;\n }\n const before = findings.length;\n let converted = source;\n\n // Band background (any slice) must survive if the source declared one.\n if (spec.background && !bp.background) {\n findings.push({ kind: \"media-dropped\", band: spec.index, where: \"background\" });\n }\n\n switch (spec.slice) {\n case \"Grid\": {\n gridBands++;\n converted = bp.tree ? sigOf(bp.tree) : \"∅\";\n if (source !== converted) {\n findings.push({\n kind: \"tree-drift\",\n band: spec.index,\n expected: source,\n actual: converted,\n });\n }\n if (hasMapWidget(spec.root) && !bp.map) {\n findings.push({ kind: \"map-missing\", band: spec.index });\n }\n break;\n }\n case \"Gallery\": {\n const got = bp.gallery?.length ?? 0;\n converted = `gallery(${got})`;\n if (got < spec.media.length) {\n findings.push({\n kind: \"media-dropped\",\n band: spec.index,\n where: `gallery ${got}/${spec.media.length}`,\n });\n }\n break;\n }\n case \"Carousel\": {\n const got = bp.carousel?.slides.length ?? 0;\n converted = `carousel(${got})`;\n if (got < spec.slides.length) {\n findings.push({\n kind: \"media-dropped\",\n band: spec.index,\n where: `carousel ${got}/${spec.slides.length}`,\n });\n }\n break;\n }\n case \"MediaFull\":\n case \"VideoFeature\": {\n if (!bp.media) {\n converted = \"∅\";\n findings.push({ kind: \"media-dropped\", band: spec.index, where: \"media\" });\n }\n break;\n }\n case \"SplitFeature\": {\n if (!bp.split) {\n converted = \"∅\";\n findings.push({ kind: \"media-dropped\", band: spec.index, where: \"split\" });\n } else {\n converted = `split(${bp.split.mediaSide},${bp.split.ratio})`;\n // Defensive: the current builder copies mediaSide/ratio verbatim, so\n // this can't fire against real convertExport output — it guards a\n // future transforming builder that reshapes the split.\n if (converted !== source) {\n findings.push({\n kind: \"tree-drift\",\n band: spec.index,\n expected: source,\n actual: converted,\n });\n }\n // The split's text side is a full node subtree (band 1 of the-pointe\n // nests media inside it); buildPresentation serializes it via\n // renderNode, which DROPS unresolved media. Signature-check it like a\n // Grid tree so a dropped nested media isn't silently reported faithful.\n const expectedText = sigOf(spec.text);\n const actualText = sigOf(bp.split.text);\n if (expectedText !== actualText) {\n findings.push({\n kind: \"tree-drift\",\n band: spec.index,\n expected: `split.text ${expectedText}`,\n actual: `split.text ${actualText}`,\n });\n }\n }\n break;\n }\n case \"LocationMap\": {\n if (!bp.map) {\n converted = \"∅\";\n findings.push({ kind: \"map-missing\", band: spec.index });\n }\n break;\n }\n case \"Hero\":\n case \"TitleBand\":\n case \"RichText\":\n break; // text lives in the page doc (gated by grid-slice.test.ts); nothing manifest-carried to lose beyond background\n default: {\n // A new slice kind must be handled explicitly, not silently pass as\n // faithful. `sourceLabel` above is also exhaustive, so this is a local\n // belt-and-suspenders guard rather than the sole gate.\n const _exhaustive: never = spec;\n throw new Error(`validateLayout: unhandled slice ${(_exhaustive as SliceSpec).slice}`);\n }\n }\n\n rows.push({\n band: spec.index,\n slice: spec.slice,\n source,\n converted,\n ok: findings.length === before,\n });\n }\n\n return { bands: specs.length, gridBands, faithful: findings.length === 0, findings, rows };\n}\n\nfunction fmtFinding(f: LayoutFinding): string {\n switch (f.kind) {\n case \"band-count\":\n return ` band count mismatch: ${f.specs} source bands vs ${f.manifest} manifest bands`;\n case \"band-missing\":\n return ` band ${f.band}: no manifest entry`;\n case \"tree-drift\":\n return ` band ${f.band}: grid tree drift\\n expected ${f.expected}\\n actual ${f.actual}`;\n case \"media-dropped\":\n return ` band ${f.band}: media dropped (${f.where})`;\n case \"map-missing\":\n return ` band ${f.band}: map config missing`;\n }\n}\n\n/** Render a LayoutReport as a terminal summary: a headline verdict, a per-band\n * signature table (`ok` / `!!` per band), then the findings detail. */\nexport function formatLayoutReport(r: LayoutReport): string {\n const headline = `layout fidelity: ${\n r.faithful ? \"FAITHFUL\" : `${r.findings.length} finding(s)`\n } — ${r.bands} bands (${r.gridBands} grid-tree checked)`;\n const table = r.rows.map((x) => {\n const tag = x.ok ? \"ok\" : \"!!\";\n const sig = x.ok ? x.source : `${x.source} -> ${x.converted}`;\n return ` band ${String(x.band).padStart(2)} ${x.slice.padEnd(13)} ${tag} ${sig}`;\n });\n const detail = r.findings.length ? [\"findings:\", ...r.findings.map(fmtFinding)] : [];\n return [headline, ...table, ...detail].join(\"\\n\");\n}\n","import type { BandPresentation, Presentation, RenderMedia, RenderNode } from \"./presentation.js\";\n\nconst swap = (m: RenderMedia, map: Map<string, string>): RenderMedia => {\n const url = map.get(m.url);\n return url ? { ...m, url } : m;\n};\n\nfunction walkNode(node: RenderNode, map: Map<string, string>): RenderNode {\n switch (node.kind) {\n case \"row\":\n return {\n kind: \"row\",\n cells: node.cells.map((c) => ({ token: c.token, node: walkNode(c.node, map) })),\n };\n case \"stack\":\n return { kind: \"stack\", children: node.children.map((c) => walkNode(c, map)) };\n case \"media\":\n return { kind: \"media\", media: swap(node.media, map) };\n default:\n return node; // heading/body/subtitle/raw/widget carry no media url\n }\n}\n\nfunction walkBand(bp: BandPresentation, map: Map<string, string>): BandPresentation {\n const out: BandPresentation = { ...bp };\n if (bp.background) out.background = swap(bp.background, map);\n if (bp.media) out.media = swap(bp.media, map);\n if (bp.gallery) out.gallery = bp.gallery.map((m) => swap(m, map));\n if (bp.carousel)\n out.carousel = {\n ...bp.carousel,\n slides: bp.carousel.slides.map((s) => ({ ...s, media: swap(s.media, map) })),\n };\n if (bp.tree) out.tree = walkNode(bp.tree, map);\n if (bp.split)\n out.split = {\n ...bp.split,\n media: swap(bp.split.media, map),\n text: walkNode(bp.split.text, map),\n };\n return out; // style / map untouched (no media urls)\n}\n\n/** Deep copy of the manifest with every RenderMedia.url present in `urlMap`\n * replaced by its mapped value. Unknown urls left intact. Pure. */\nexport function rewriteManifestUrls(\n manifest: Presentation,\n urlMap: Map<string, string>,\n): Presentation {\n const bands: Record<string, BandPresentation> = {};\n for (const [k, bp] of Object.entries(manifest.bands)) bands[k] = walkBand(bp, urlMap);\n return { bands };\n}\n"],"mappings":"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","names":["base","parse","base","img","base","parse"]}
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-4NAOR44V.js";
9
9
  import {
10
10
  resolveSites
11
- } from "./chunk-YQMYQAJX.js";
11
+ } from "./chunk-Y7LZHPDF.js";
12
12
  import {
13
13
  bumpDeps
14
14
  } from "./chunk-D3DQFC32.js";
@@ -39,6 +39,7 @@ async function runBumpDepsCommand(site, opts) {
39
39
  let sites = await resolveSites({
40
40
  ...site !== void 0 ? { site } : {},
41
41
  ...opts.fleet !== void 0 ? { fleet: opts.fleet } : {},
42
+ ...opts.workdir !== void 0 ? { workdir: opts.workdir } : {},
42
43
  cwd
43
44
  });
44
45
  let skipped = [];
@@ -56,4 +57,4 @@ async function runBumpDepsCommand(site, opts) {
56
57
  export {
57
58
  runBumpDepsCommand
58
59
  };
59
- //# sourceMappingURL=bump-deps-QNM3H4GI.js.map
60
+ //# sourceMappingURL=bump-deps-K3JMLMBB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/bump-deps.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { bumpDeps, type BumpDepsGroup } from \"../../recipes/bump-deps.js\";\nimport type { RecipeResult } from \"../../types.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\nimport { prepareFleetSites, appendSkipNotice, type SkippedSite } from \"../fleet/prepare-sites.js\";\nimport { runRecipeOverSites } from \"../fleet/run-recipe-over-sites.js\";\nimport { fleetWorkdir } from \"../../util/fleet-workdir.js\";\n\nconst GROUPS: BumpDepsGroup[] = [\"patch\", \"minor\", \"major\"];\n\nexport type BumpDepsCommandOptions = {\n group?: string;\n fleet?: string;\n workdir?: string;\n cwd?: string;\n};\n\nfunction formatResult(r: RecipeResult): string {\n if (r.status === \"noop\") return `[${r.site}] noop: ${r.notes ?? \"\"}`;\n return `[${r.site}] applied: ${r.commits.length} commit(s)\\n${r.notes ?? \"\"}`;\n}\n\nexport async function runBumpDepsCommand(\n site: string | undefined,\n opts: BumpDepsCommandOptions,\n): Promise<{ output: string; code: number }> {\n const group = (opts.group ?? \"minor\") as BumpDepsGroup;\n if (!GROUPS.includes(group)) {\n throw Object.assign(\n new Error(`unknown --group: ${group}. expected one of ${GROUPS.join(\", \")}`),\n { exitCode: 2 },\n );\n }\n\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n\n let sites = await resolveSites({\n ...(site !== undefined ? { site } : {}),\n ...(opts.fleet !== undefined ? { fleet: opts.fleet } : {}),\n ...(opts.workdir !== undefined ? { workdir: opts.workdir } : {}),\n cwd,\n });\n\n let skipped: SkippedSite[] = [];\n if (opts.fleet) {\n const workdir = opts.workdir ?? fleetWorkdir();\n const prep = await prepareFleetSites(sites, { workdir });\n sites = prep.prepared;\n skipped = prep.skipped;\n }\n\n const results = await runRecipeOverSites(\"bump-deps\", sites, (s) => bumpDeps(s, { group }));\n\n const output = results.map(formatResult).join(\"\\n\");\n const code = results.some((r) => r.status === \"failed\") ? 1 : 0;\n return { output: appendSkipNotice(output, skipped), code };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;AAQxB,IAAM,SAA0B,CAAC,SAAS,SAAS,OAAO;AAS1D,SAAS,aAAa,GAAyB;AAC7C,MAAI,EAAE,WAAW,OAAQ,QAAO,IAAI,EAAE,IAAI,WAAW,EAAE,SAAS,EAAE;AAClE,SAAO,IAAI,EAAE,IAAI,cAAc,EAAE,QAAQ,MAAM;AAAA,EAAe,EAAE,SAAS,EAAE;AAC7E;AAEA,eAAsB,mBACpB,MACA,MAC2C;AAC3C,QAAM,QAAS,KAAK,SAAS;AAC7B,MAAI,CAAC,OAAO,SAAS,KAAK,GAAG;AAC3B,UAAM,OAAO;AAAA,MACX,IAAI,MAAM,oBAAoB,KAAK,qBAAqB,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,MAC3E,EAAE,UAAU,EAAE;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,MAAM,KAAK,MAAM,QAAQ,KAAK,GAAG,IAAI,QAAQ,IAAI;AAEvD,MAAI,QAAQ,MAAM,aAAa;AAAA,IAC7B,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACrC,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IACxD,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AAED,MAAI,UAAyB,CAAC;AAC9B,MAAI,KAAK,OAAO;AACd,UAAM,UAAU,KAAK,WAAW,aAAa;AAC7C,UAAM,OAAO,MAAM,kBAAkB,OAAO,EAAE,QAAQ,CAAC;AACvD,YAAQ,KAAK;AACb,cAAU,KAAK;AAAA,EACjB;AAEA,QAAM,UAAU,MAAM,mBAAmB,aAAa,OAAO,CAAC,MAAM,SAAS,GAAG,EAAE,MAAM,CAAC,CAAC;AAE1F,QAAM,SAAS,QAAQ,IAAI,YAAY,EAAE,KAAK,IAAI;AAClD,QAAM,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,IAAI,IAAI;AAC9D,SAAO,EAAE,QAAQ,iBAAiB,QAAQ,OAAO,GAAG,KAAK;AAC3D;","names":[]}
@@ -2,7 +2,7 @@ import {
2
2
  isPendingApproval,
3
3
  listReportsForSite,
4
4
  setDraftReady
5
- } from "./chunk-6JFOAPW4.js";
5
+ } from "./chunk-AYM2EFSK.js";
6
6
 
7
7
  // src/reports/queue.ts
8
8
  var REPORT_TIER = {
@@ -35,4 +35,4 @@ export {
35
35
  reportTier,
36
36
  queueDraft
37
37
  };
38
- //# sourceMappingURL=chunk-RINXPU3H.js.map
38
+ //# sourceMappingURL=chunk-2PWQ6MPG.js.map