@takazudo/zfb 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -74,8 +74,8 @@ surface. Today it covers:
74
74
  - `clientScript(name)` — SSR helper that returns the stable URL for a
75
75
  named client-script asset.
76
76
  - `slugify(input)` and `SlugAllocator` — exported from the root barrel and
77
- the `zfb/slugify` subpath for heading-id parity with the Rust content
78
- pipeline.
77
+ the `zfb/slugify` compatibility subpath for heading-id parity with the Rust content
78
+ pipeline. For a lightweight direct import, use `@takazudo/zfb-slugify`.
79
79
 
80
80
  The package uses the owned `@takazudo/zfb/zudo-react` runtime for island
81
81
  rendering and hydration. Consumers do not install a separate JSX runtime.
package/dist/runtime.js CHANGED
@@ -210,6 +210,9 @@ const ISLAND_REMOUNT_ATTR = "data-zfb-island-remount";
210
210
  * - bundle re-import: dispose the old symbol handle before render mode replaces it.
211
211
  */
212
212
  export const ISLAND_MOUNTED_ATTR = "data-zfb-island-mounted";
213
+ // Retained SSR DOM may already have incoming props while its first mount is
214
+ // deferred. Keep the render operation across swaps, retries, and dev re-imports.
215
+ const ISLAND_PENDING_RENDER_ATTR = "data-zfb-island-pending-render";
213
216
  const COMPOSITION_KEY = Symbol.for("@takazudo/zfb/zudo-react/composition-v1");
214
217
  const TRACKER_KEY = Symbol.for("@takazudo/zfb/zudo-react/composition-tracker-v1");
215
218
  // A fresh bundle instance replaces roots installed by a previous instance.
@@ -237,6 +240,9 @@ function reportIslandError(element, phase, error) {
237
240
  }
238
241
  }
239
242
  function disposeIsland(element, phase) {
243
+ pendingCancels.get(element)?.();
244
+ pendingCancels.delete(element);
245
+ element.removeAttribute(ISLAND_PENDING_RENDER_ATTR);
240
246
  const handle = rootHandle(element);
241
247
  try {
242
248
  handle?.dispose();
@@ -320,8 +326,10 @@ export function mountIslands(manifest) {
320
326
  const name = el.getAttribute("data-zfb-island");
321
327
  if (!name)
322
328
  continue;
329
+ const hadLiveRoot = !!rootHandle(el);
330
+ const flagged = !hadLiveRoot && !replacing && clearMountedForRemount(el);
323
331
  warnIfNestedIsland(el, name);
324
- scheduleMount(manifest, el, name, replacing ? "render" : "hydrate", { force: replacing });
332
+ scheduleMount(manifest, el, name, replacing || flagged || el.hasAttribute(ISLAND_PENDING_RENDER_ATTR) ? "render" : "hydrate", { force: hadLiveRoot || replacing });
325
333
  }
326
334
  const skipSsrIslands = document.querySelectorAll("[data-zfb-island-skip-ssr]");
327
335
  for (const el of Array.from(skipSsrIslands)) {
@@ -329,8 +337,11 @@ export function mountIslands(manifest) {
329
337
  const name = el.getAttribute("data-zfb-island-skip-ssr");
330
338
  if (!name)
331
339
  continue;
340
+ const hadLiveRoot = !!rootHandle(el);
341
+ if (!hadLiveRoot && !replacing)
342
+ clearMountedForRemount(el);
332
343
  warnIfNestedIsland(el, name);
333
- scheduleMount(manifest, el, name, "render", { force: replacing });
344
+ scheduleMount(manifest, el, name, "render", { force: hadLiveRoot || replacing });
334
345
  }
335
346
  }
336
347
  /**
@@ -357,9 +368,10 @@ export function mountNewIslands() {
357
368
  if (!name)
358
369
  continue;
359
370
  // The router marks changed persisted identity/props on the surviving node.
360
- const forceRemount = clearMountedForRemount(el) || replacing;
371
+ const hadLiveRoot = !!rootHandle(el);
372
+ const flagged = clearMountedForRemount(el);
361
373
  warnIfNestedIsland(el, name);
362
- scheduleMount(manifest, el, name, forceRemount ? "render" : "hydrate", { force: forceRemount });
374
+ scheduleMount(manifest, el, name, replacing || flagged || el.hasAttribute(ISLAND_PENDING_RENDER_ATTR) ? "render" : "hydrate", { force: hadLiveRoot || replacing });
363
375
  }
364
376
  const skipSsrIslands = document.querySelectorAll("[data-zfb-island-skip-ssr]");
365
377
  for (const el of Array.from(skipSsrIslands)) {
@@ -368,8 +380,9 @@ export function mountNewIslands() {
368
380
  if (!name)
369
381
  continue;
370
382
  warnIfNestedIsland(el, name);
371
- const forceRemount = clearMountedForRemount(el) || replacing;
372
- scheduleMount(manifest, el, name, "render", { force: forceRemount });
383
+ const hadLiveRoot = !!rootHandle(el);
384
+ clearMountedForRemount(el);
385
+ scheduleMount(manifest, el, name, "render", { force: hadLiveRoot || replacing });
373
386
  }
374
387
  }
375
388
  /** Consume a persisted root's remount flag and dispose its previous resources. */
@@ -379,14 +392,17 @@ function clearMountedForRemount(el) {
379
392
  el.removeAttribute(ISLAND_REMOUNT_ATTR);
380
393
  if (rootHandle(el))
381
394
  disposeIsland(el, "remount disposal");
382
- else
395
+ else {
383
396
  el.removeAttribute(ISLAND_MOUNTED_ATTR);
397
+ el.setAttribute(ISLAND_PENDING_RENDER_ATTR, "");
398
+ }
384
399
  return true;
385
400
  }
386
401
  function prepareMount(el) {
387
402
  let replacing = false;
388
403
  if (rootHandle(el) && !owned.has(el)) {
389
404
  disposeIsland(el, "dev replacement disposal");
405
+ el.removeAttribute(ISLAND_REMOUNT_ATTR);
390
406
  replacing = true;
391
407
  }
392
408
  if (!rootHandle(el))
@@ -444,6 +460,9 @@ function warnIfNestedIsland(el, componentName) {
444
460
  function scheduleMount(manifest, element, componentName, mode, options = {}) {
445
461
  if (rootHandle(element))
446
462
  return;
463
+ // A later scan may change hydrate into render after a retained props update.
464
+ pendingCancels.get(element)?.();
465
+ pendingCancels.delete(element);
447
466
  const entry = manifest[componentName];
448
467
  if (entry == null) {
449
468
  if (typeof process !== "undefined" && process.env && process.env["NODE_ENV"] !== "production") {
@@ -499,6 +518,7 @@ function fireInlineMount(element, mod, mode, options = {}) {
499
518
  setRootHandle(element, handle);
500
519
  owned.add(element);
501
520
  element.setAttribute(ISLAND_MOUNTED_ATTR, "");
521
+ element.removeAttribute(ISLAND_PENDING_RENDER_ATTR);
502
522
  }
503
523
  catch (error) {
504
524
  element.removeAttribute(ISLAND_MOUNTED_ATTR);
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// Hydration scheduling helper consumed by the hydration runtime (Sub 3).\n//\n// Sub 3 owns the hydration runtime that walks the DOM, finds elements\n// marked with `data-zfb-island`, and dispatches each one through this\n// helper to decide *when* to fire the actual hydrate() call. The helper\n// itself does not know how to hydrate — it only schedules the supplied\n// `fire` callback.\n//\n// The branching matches the `When` union exactly:\n// \"visible\" → IntersectionObserver, threshold 0.0, hydrate on first\n// intersection, then disconnect.\n// \"idle\" → requestIdleCallback if available, otherwise setTimeout(0).\n// \"media\" → matchMedia(target's data-media), hydrate when the query\n// first matches (now or on a later change event), then\n// remove the listener.\n// \"load\" → immediate, synchronous fire.\n//\n// Anything else is treated as \"load\" (with a console.warn in development).\n// The helper is environment-tolerant: callers can run it in jsdom /\n// happy-dom or bare Node, and the absence of `IntersectionObserver` /\n// `requestIdleCallback` / `matchMedia` is handled gracefully.\n\nimport { resolveWhen, type When } from \"./types.js\";\nimport { ROOT_KEY, type RootHandle } from \"./zudo-react/root.js\";\nimport { parseProps as parseOwnedProps } from \"./zudo-react/props-transport.js\";\n\n/**\n * Subset of the global object that this module touches. Cast once at the\n * module top so individual scheduler functions don't repeat the inline\n * widening.\n */\ntype SchedulerGlobal = typeof globalThis & {\n requestIdleCallback?: (\n cb: (deadline: { didTimeout: boolean; timeRemaining: () => number }) => void,\n options?: { timeout?: number },\n ) => number;\n cancelIdleCallback?: (handle: number) => void;\n IntersectionObserver?: typeof IntersectionObserver;\n matchMedia?: typeof matchMedia;\n};\n\nconst g = globalThis as SchedulerGlobal;\n\n/**\n * Internal variant of `scheduleHydrate` that also reports whether the fire\n * callback was invoked synchronously. Unexported — call sites in this module\n * use this to decide whether to register a `pendingCancels` entry.\n */\nfunction scheduleHydrateInternal(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const resolved = resolveWhen(when);\n\n if (resolved === \"load\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n if (resolved === \"idle\") {\n return { fired: false, cancel: scheduleIdle(fire) };\n }\n\n if (resolved === \"media\") {\n return scheduleMedia(target, fire);\n }\n\n // \"visible\"\n return scheduleVisible(target, fire);\n}\n\n/**\n * Schedule a hydration `fire` callback for `target` according to `when`.\n *\n * Returns a `cancel` function that aborts the scheduling if it has not\n * fired yet. After firing, calling `cancel` is a no-op. If the helper\n * cannot find the relevant browser API (e.g. running in pure Node with no\n * polyfill), it falls back to firing synchronously so server-side smoke\n * tests still observe the call.\n */\nexport function scheduleHydrate(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): () => void {\n return scheduleHydrateInternal(target, when, fire).cancel;\n}\n\nfunction noop(): void {\n // intentionally empty\n}\n\n/**\n * Build a one-shot gate around `fn`. The returned `run` invokes `fn`\n * exactly once provided `cancel` has not been called first; `cancel`\n * marks the gate as cancelled (later `run` invocations become no-ops)\n * and reports whether the gate had already fired.\n */\nfunction oneShot(fn: () => void): {\n run: () => void;\n cancel: () => boolean;\n} {\n let fired = false;\n let cancelled = false;\n return {\n run(): void {\n if (cancelled || fired) return;\n fired = true;\n fn();\n },\n cancel(): boolean {\n if (fired) return true;\n cancelled = true;\n return false;\n },\n };\n}\n\nfunction scheduleIdle(fire: () => void): () => void {\n const gate = oneShot(fire);\n\n if (typeof g.requestIdleCallback === \"function\") {\n const handle = g.requestIdleCallback(gate.run);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n if (typeof g.cancelIdleCallback === \"function\") g.cancelIdleCallback(handle);\n };\n }\n\n const handle = setTimeout(gate.run, 0);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n clearTimeout(handle);\n };\n}\n\nfunction scheduleVisible(\n target: Element,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const Observer = g.IntersectionObserver;\n\n // No IntersectionObserver (e.g. very old browsers, bare Node) — fail\n // open and hydrate immediately so the island is at least functional.\n if (typeof Observer !== \"function\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n const observer = new Observer(\n (entries, obs) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n obs.disconnect();\n gate.run();\n return;\n }\n }\n },\n { threshold: 0 },\n );\n\n observer.observe(target);\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n observer.disconnect();\n },\n };\n}\n\nfunction scheduleMedia(target: Element, fire: () => void): { fired: boolean; cancel: () => void } {\n const query = target.getAttribute(\"data-media\");\n\n // No matchMedia API (e.g. bare Node, very old browser) or missing/empty\n // query — fail open and hydrate immediately so the island is at least\n // functional.\n if (typeof g.matchMedia !== \"function\" || !query) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const mql = g.matchMedia(query);\n\n // Already matches — fire synchronously (no pending listener needed).\n if (mql.matches) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n\n let removeListener = noop;\n\n // Listen for the first change event where the query matches.\n // We do NOT use `{once:true}` because we must ignore un-match events\n // (e.g. viewport widens back above breakpoint) and only fire on the\n // first match event — `{once:true}` would consume any change, including\n // un-match changes.\n const handler = (e: MediaQueryListEvent): void => {\n if (!e.matches) return; // ignore un-match changes\n removeListener();\n gate.run();\n };\n\n // Modern browsers expose the EventTarget API on MediaQueryList; older\n // Safari (<14) only has the deprecated addListener/removeListener pair\n // and throws on addEventListener. Prefer modern, fall back to legacy,\n // and fail open when neither exists (mirrors the missing-matchMedia case).\n if (typeof mql.addEventListener === \"function\") {\n mql.addEventListener(\"change\", handler);\n removeListener = () => mql.removeEventListener(\"change\", handler);\n } else if (typeof mql.addListener === \"function\") {\n mql.addListener(handler);\n removeListener = () => mql.removeListener(handler);\n } else {\n fire();\n return { fired: true, cancel: noop };\n }\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n removeListener();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// mountIslands — DOM walk + dynamic-import dispatcher.\n//\n// `mountIslands` is the entry point the generated `islands-runtime-<hash>.js`\n// bundle calls at script load time. It walks the DOM for the two island\n// markers emitted by the server-side hydration step and the `<Island>`\n// JSX wrapper:\n//\n// 1. `[data-zfb-island]` — adopt server-rendered owned DOM.\n// 2. `[data-zfb-island-skip-ssr]` — mount over the fallback when scheduled.\n//\n// The generated shared bundle supplies strict identity and a RootHandle.\n// ---------------------------------------------------------------------------\n\n/**\n * The mount function supplied by a shared-bundle island module.\n *\n * `mode === \"hydrate\"` is used for SSR'd islands, `\"render\"` for\n * SSR-skip islands.\n */\ntype IslandMount = (\n props: Record<string, unknown>,\n element: Element,\n mode: \"hydrate\" | \"render\",\n) => RootHandle | null;\n\ninterface IslandModule {\n identity: { component: string; build: string };\n mount: IslandMount;\n}\n\n/**\n * Map of `componentName → island descriptor` baked into the runtime entry.\n *\n * Each manifest value is an inline module with `mount` or `default`.\n * The shared bundle imports island sources at build time.\n */\nexport type IslandManifestValue = IslandModule;\nexport type IslandManifest = Readonly<Record<string, IslandManifestValue>>;\n\n// data-zfb-transition-persist marker attribute — the client-router's persist\n// contract. Mirrored from client-router/swap-functions.ts: that package owns the\n// body swap (lifting persisted nodes into the incoming body), this package owns\n// island mount/unmount. Both must agree on the literal string. See the port\n// spec at packages/zfb-runtime/docs/client-router/port-spec.md §12.3.\nconst PERSIST_ATTR = \"data-zfb-transition-persist\";\n\n// Cross-package \"needs-remount\" flag set by client-router/swap-functions.ts on a\n// persisted island whose props changed across a body swap. Mirrored literal (same\n// cross-package contract as PERSIST_ATTR above — both packages must agree on the\n// string). Consumed by clearMountedForRemount(). See #1389.\nconst ISLAND_REMOUNT_ATTR = \"data-zfb-island-remount\";\n\n/**\n * Public observation marker; the symbol handle is the live-root guard.\n *\n * State table:\n * - initial/deferred/missing entry/failed mount: marker and handle absent;\n * - successful mount: both present;\n * - discarded root: disposal leaves DOM for the body swap, then clears both;\n * - unchanged island inside a retained persist boundary: handle and marker survive;\n * - changed island inside a retained boundary: metadata and remount flag are set,\n * then the post-swap scan disposes once and mounts in render mode;\n * - removed island inside a retained boundary: dispose and detach before swap;\n * - bundle re-import: dispose the old symbol handle before render mode replaces it.\n */\nexport const ISLAND_MOUNTED_ATTR = \"data-zfb-island-mounted\";\nconst COMPOSITION_KEY = Symbol.for(\"@takazudo/zfb/zudo-react/composition-v1\");\nconst TRACKER_KEY = Symbol.for(\"@takazudo/zfb/zudo-react/composition-tracker-v1\");\n\n// A fresh bundle instance replaces roots installed by a previous instance.\n// Ordinary repeat scans in the same instance keep their live handles.\nconst owned = new WeakSet<Element>();\nfunction rootHandle(element: Element): RootHandle | undefined {\n return (element as unknown as Record<symbol, RootHandle | undefined>)[ROOT_KEY];\n}\nfunction setRootHandle(element: Element, handle: RootHandle | undefined): void {\n const target = element as unknown as Record<symbol, RootHandle | undefined>;\n if (handle) target[ROOT_KEY] = handle;\n else delete target[ROOT_KEY];\n}\nfunction reportIslandError(element: Element, phase: string, error: unknown): void {\n const name =\n element.getAttribute(\"data-zfb-island\") ??\n element.getAttribute(\"data-zfb-island-skip-ssr\") ??\n \"unknown\";\n try {\n console.error(`[zfb] island \"${name}\" ${phase} failed`, error);\n } catch {\n // A broken reporter must not stop other roots.\n }\n}\nfunction disposeIsland(element: Element, phase: string): void {\n const handle = rootHandle(element);\n try {\n handle?.dispose();\n } catch (error) {\n reportIslandError(element, phase, error);\n } finally {\n if (rootHandle(element) === handle) setRootHandle(element, undefined);\n element.removeAttribute(ISLAND_MOUNTED_ATTR);\n }\n}\nfunction installCompositionTracker(doc: Document): void {\n const target = doc as unknown as Record<symbol, (() => void) | undefined>;\n if (target[TRACKER_KEY]) return;\n const set = (event: Event, value: \"active\" | \"idle\") => {\n if (event.target instanceof Element) {\n (event.target as unknown as Record<symbol, string>)[COMPOSITION_KEY] = value;\n }\n };\n const start = (event: Event) => set(event, \"active\");\n const end = (event: Event) => set(event, \"idle\");\n const input = (event: Event) => {\n if ((event as InputEvent).isComposing) set(event, \"active\");\n };\n doc.addEventListener(\"compositionstart\", start, true);\n doc.addEventListener(\"compositionend\", end, true);\n doc.addEventListener(\"input\", input, true);\n doc.addEventListener(\"blur\", end, true);\n target[TRACKER_KEY] = () => {\n doc.removeEventListener(\"compositionstart\", start, true);\n doc.removeEventListener(\"compositionend\", end, true);\n doc.removeEventListener(\"input\", input, true);\n doc.removeEventListener(\"blur\", end, true);\n delete target[TRACKER_KEY];\n };\n}\n\n// Elements for which the nested-island self-wrap warning has already been\n// emitted. Guards against repeated warn spam across re-walks (e.g. SPA swaps).\nconst warnedNested = new WeakSet<Element>();\n// Module-level captured manifest — set by the first `mountIslands` call and reused by\n// `mountNewIslands()` so the client-router does not need to know the manifest directly.\n// Named technical cause (W1B §12.1): the router lives in @takazudo/zfb-runtime; the\n// islands manifest lives in @takazudo/zfb. Passing the manifest through the swap event\n// would require widening the event API or threading manifest into router options. The\n// captured-manifest pattern keeps the package boundary clean.\nlet capturedManifest: IslandManifest | null = null;\n\n// Map of element → cancel-function for deferred-hydration islands\n// (data-when=\"idle\"|\"visible\"|\"media\").\n// Populated in scheduleMount; consulted on `zfb:before-swap` so deferred fires do not run\n// against orphan elements after a body swap. (W1B §12.5)\nconst pendingCancels = new Map<Element, () => void>();\n\n/**\n * Walk the DOM and mount every `[data-zfb-island]` / `[data-zfb-island-skip-ssr]`\n * element using `manifest`.\n *\n * No-op when `document` is undefined (SSR, edge runtime). Safe to call\n * multiple times: each element is mounted at most once thanks to the\n * symbol-handle guard.\n *\n * The manifest is captured at module level so `mountNewIslands()` can re-use\n * it after an SPA body swap without needing the caller to re-supply it.\n */\nexport function mountIslands(manifest: IslandManifest): void {\n if (typeof document === \"undefined\") return;\n\n // Capture the manifest for post-swap re-walks via mountNewIslands().\n capturedManifest = manifest;\n installCompositionTracker(document);\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n const replacing = prepareMount(el);\n // Skip the empty-skeleton case left behind when the server-side\n // rewriter has not run yet (data-zfb-island=\"\" with no component\n // name). The hydration emit step is expected to fill this in\n // before the page reaches the browser; if it didn't, we cannot\n // dispatch.\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, replacing ? \"render\" : \"hydrate\", { force: replacing });\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"render\", { force: replacing });\n }\n}\n\n/**\n * Re-walk the current document body and mount any new island markers introduced\n * by an SPA body swap. Uses the manifest captured by the previous `mountIslands`\n * call — no manifest arg required.\n *\n * The caller (client-router `router.ts`) invokes this after `swap()` + `runScripts()`\n * and before dispatching `zfb:page-load`, per W1B §12.2 contract.\n *\n * No-op when called before `mountIslands` (capturedManifest is null) or when\n * `document` is undefined.\n */\nexport function mountNewIslands(): void {\n if (typeof document === \"undefined\") return;\n if (capturedManifest === null) return;\n\n const manifest = capturedManifest;\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n // The router marks changed persisted identity/props on the surviving node.\n const forceRemount = clearMountedForRemount(el) || replacing;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, forceRemount ? \"render\" : \"hydrate\", { force: forceRemount });\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n const forceRemount = clearMountedForRemount(el) || replacing;\n scheduleMount(manifest, el, name, \"render\", { force: forceRemount });\n }\n}\n\n/** Consume a persisted root's remount flag and dispose its previous resources. */\nfunction clearMountedForRemount(el: Element): boolean {\n if (!el.hasAttribute(ISLAND_REMOUNT_ATTR)) return false;\n el.removeAttribute(ISLAND_REMOUNT_ATTR);\n if (rootHandle(el)) disposeIsland(el, \"remount disposal\");\n else el.removeAttribute(ISLAND_MOUNTED_ATTR);\n return true;\n}\n\nfunction prepareMount(el: Element): boolean {\n let replacing = false;\n if (rootHandle(el) && !owned.has(el)) {\n disposeIsland(el, \"dev replacement disposal\");\n replacing = true;\n }\n if (!rootHandle(el)) el.removeAttribute(ISLAND_MOUNTED_ATTR);\n return replacing;\n}\n\n/**\n * Cancel deferred-hydration callbacks for all islands in the old body before a\n * swap. Prevents idle / visibility callbacks from running against orphan elements\n * after `swapBodyElement` removes them from the live document. (W1B §12.5)\n *\n * Call this on `zfb:before-swap` (or equivalently, in the router's swap sequence\n * before `swap()` mutates the DOM). Fire-and-forget; safe to call if nothing is\n * pending.\n */\nexport function cancelPendingIslands(): void {\n for (const [el, cancel] of pendingCancels) {\n cancel();\n pendingCancels.delete(el);\n }\n}\n\n/**\n * Warn (once per element, dev-only) when an island marker element is found\n * nested inside another island marker. Self-wrapping an island — emitting a\n * `data-zfb-island` or `data-zfb-island-skip-ssr` container *inside* another\n * island component's render output — mis-hydrates because the runtime will\n * try to mount both the outer and inner islands independently. The outer\n * island's framework instance owns the inner DOM, so a second `hydrate()` /\n * `render()` call against the inner element races with the outer render and\n * produces undefined behaviour.\n *\n * The fix is to author the inner component bare (no `<Island>` in its own\n * render output) and apply the `<Island when=\"...\">` wrapper at the call site.\n */\nfunction warnIfNestedIsland(el: Element, componentName: string): void {\n if (typeof process === \"undefined\" || !process.env || process.env[\"NODE_ENV\"] === \"production\") {\n return;\n }\n if (warnedNested.has(el)) return;\n const parent = el.parentElement;\n if (!parent || typeof parent.closest !== \"function\") return;\n const ancestor = parent.closest(\"[data-zfb-island],[data-zfb-island-skip-ssr]\");\n if (!ancestor) return;\n warnedNested.add(el);\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] Island \"${componentName}\" is nested inside another island marker. ` +\n `Self-wrapping an island mis-hydrates: the outer framework instance owns ` +\n `the inner DOM, causing a conflicting mount. ` +\n `Fix: author \"${componentName}\" bare (remove <Island> from its own render output) ` +\n `and apply <Island when=\"...\"> at the call site instead.`,\n );\n}\n\nfunction scheduleMount(\n manifest: IslandManifest,\n element: Element,\n componentName: string,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n if (rootHandle(element)) return;\n\n const entry = manifest[componentName];\n if (entry == null) {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] no island manifest entry for component \"${componentName}\" — ` +\n `the runtime manifest is out of sync with the rendered HTML.`,\n );\n }\n return;\n }\n\n fireInlineMount(element, entry, mode, options);\n}\n\n/**\n * Run the mount step for the inline-module manifest shape used by the\n * shared-bundle path. The module is already in memory (it was imported\n * into the bundle at build time), so there is no async window to\n * coordinate around — we just call `mount` / `default` directly,\n * gated by `data-when` semantics.\n */\nfunction fireInlineMount(\n element: Element,\n mod: IslandModule,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n const fn = mod.mount;\n if (typeof fn !== \"function\") {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\"[zfb] owned island manifest entry did not export mount()\");\n }\n return;\n }\n\n const fire = (): void => {\n // Re-check the guard in case `fire` is invoked from a deferred\n // scheduler (rIC/rAF/visibility) after a sibling caller already\n // mounted this element.\n if (rootHandle(element)) return;\n // When the deferred fire actually runs, the cancel handle is no longer\n // needed — remove it so pendingCancels doesn't hold stale entries.\n pendingCancels.delete(element);\n // Stale-mount race guard for deferred inline mounts: skip if the element\n // was detached (e.g. body swap) while the idle/visible callback was queued.\n if (!element.isConnected) return;\n // Lazy props parse: read and parse data-props only at mount time.\n // For deferred strategies (media, visible, idle) this avoids JSON.parse\n // work at boot time for islands that may never hydrate.\n try {\n const props = readProps(element, mod.identity);\n const result = fn(props, element, mode);\n if (result === null) return;\n if (!result || typeof result.dispose !== \"function\" || typeof result.unmount !== \"function\") {\n throw new TypeError(\n `ZR_ROOT_HANDLE: island ${mod.identity.component} returned no root handle`,\n );\n }\n const handle: RootHandle = result;\n setRootHandle(element, handle);\n owned.add(element);\n element.setAttribute(ISLAND_MOUNTED_ATTR, \"\");\n } catch (error) {\n element.removeAttribute(ISLAND_MOUNTED_ATTR);\n reportIslandError(element, \"mount\", error);\n }\n };\n\n if (options.force) {\n fire();\n return;\n }\n\n const when = element.getAttribute(\"data-when\") ?? undefined;\n const { fired, cancel } = scheduleHydrateInternal(element, when, fire);\n // Track deferred-hydration cancel handle so cancelPendingIslands() can abort\n // idle / visibility callbacks before a body swap. (W1B §12.5)\n // Only register when the scheduler did NOT fire synchronously — a synchronous\n // fire means the island is already handling its mount and there is no\n // deferred callback to cancel. Registering noop after a sync fire would leave\n // a stale pendingCancels entry for an already-handled element. (#743)\n if (when && when !== \"load\" && !fired) {\n pendingCancels.set(element, cancel);\n }\n}\n\n/**\n * Snapshot persistence and island pairings before changing any old-body node.\n * The router lifts only matched persist nodes whose incoming targets are not\n * nested inside another matched target. Their descendants survive that lift.\n */\nexport function unmountIslands(\n root: ParentNode = document.body,\n incomingBody?: ParentNode | null,\n): void {\n const islandSelector = \"[data-zfb-island],[data-zfb-island-skip-ssr]\";\n const oldIslands = Array.from(root.querySelectorAll<HTMLElement>(islandSelector));\n if (!incomingBody) {\n for (const island of oldIslands) disposeIsland(island, \"disposal\");\n return;\n }\n\n const persistSelector = `[${PERSIST_ATTR}]`;\n const oldPersist = Array.from(root.querySelectorAll(persistSelector));\n const incomingPersist = Array.from(incomingBody.querySelectorAll(persistSelector));\n const incomingById = new Map<string, Element>();\n for (const element of incomingPersist) {\n const id = element.getAttribute(PERSIST_ATTR);\n if (id !== null && !incomingById.has(id)) incomingById.set(id, element);\n }\n\n const targets = new Map<Element, Element>();\n for (const element of oldPersist) {\n const id = element.getAttribute(PERSIST_ATTR);\n const target = id === null ? undefined : incomingById.get(id);\n if (target) targets.set(element, target);\n }\n const matchedTargets = new Set(targets.values());\n const lifted = new Set<Element>();\n for (const [element, target] of targets) {\n let ancestor = target.parentElement;\n while (ancestor && !matchedTargets.has(ancestor)) ancestor = ancestor.parentElement;\n if (!ancestor) lifted.add(element);\n }\n const retained = new Set<Element>(lifted);\n for (const element of oldPersist) {\n if (!targets.has(element)) continue;\n let ancestor = element.parentElement;\n while (ancestor && !lifted.has(ancestor)) ancestor = ancestor.parentElement;\n if (ancestor) retained.add(element);\n }\n\n const boundaryById = new Map<string, Element>();\n for (const element of oldPersist) {\n if (!retained.has(element)) continue;\n const id = element.getAttribute(PERSIST_ATTR);\n if (id !== null && !boundaryById.has(id)) boundaryById.set(id, element);\n }\n const oldByBoundary = new Map<Element, Element[]>();\n const incomingByBoundary = new Map<Element, Element[]>();\n const withoutBoundary: Element[] = [];\n for (const island of oldIslands) {\n let ancestor: Element | null = island;\n while (ancestor && !retained.has(ancestor)) ancestor = ancestor.parentElement;\n if (!ancestor) {\n withoutBoundary.push(island);\n continue;\n }\n const group = oldByBoundary.get(ancestor) ?? [];\n group.push(island);\n oldByBoundary.set(ancestor, group);\n }\n for (const island of incomingBody.querySelectorAll(islandSelector)) {\n let ancestor: Element | null = island;\n let boundary: Element | undefined;\n while (ancestor && !boundary) {\n const id = ancestor.getAttribute(PERSIST_ATTR);\n if (id !== null) boundary = boundaryById.get(id);\n ancestor = ancestor.parentElement;\n }\n if (!boundary) continue;\n const group = incomingByBoundary.get(boundary) ?? [];\n group.push(island);\n incomingByBoundary.set(boundary, group);\n }\n\n const pairs: Array<{ old: Element; incoming: Element }> = [];\n const removed: Element[] = [];\n for (const [boundary, oldGroup] of oldByBoundary) {\n const incomingGroup = incomingByBoundary.get(boundary) ?? [];\n const pairedOld = new Set<Element>();\n const pairedIncoming = new Set<Element>();\n // A persisted island root always maps to its own target, even when the\n // target changes component or ceases to be an island.\n if (oldGroup.includes(boundary)) {\n pairedOld.add(boundary);\n const target = targets.get(boundary);\n if (target && incomingGroup.includes(target)) {\n pairs.push({ old: boundary, incoming: target });\n pairedIncoming.add(target);\n } else {\n removed.push(boundary);\n }\n }\n for (const old of oldGroup) {\n if (pairedOld.has(old)) continue;\n const name = islandName(old);\n const incoming = incomingGroup.find(\n (candidate) => !pairedIncoming.has(candidate) && islandName(candidate) === name,\n );\n if (!incoming) continue;\n pairs.push({ old, incoming });\n pairedOld.add(old);\n pairedIncoming.add(incoming);\n }\n const remainingIncoming = incomingGroup.filter((island) => !pairedIncoming.has(island));\n let next = 0;\n for (const old of oldGroup) {\n if (pairedOld.has(old)) continue;\n const incoming = remainingIncoming[next++];\n if (incoming) pairs.push({ old, incoming });\n else removed.push(old);\n }\n }\n\n // Apply only after all boundaries and pairings have been computed. An old\n // descendant removed from a lifted wrapper must be detached as well as\n // disposed, or the post-swap walk could hydrate its mutated DOM.\n for (const island of withoutBoundary) disposeIsland(island, \"disposal\");\n for (const { old, incoming } of pairs) {\n const copyProps =\n !old.hasAttribute(\"data-zfb-transition-persist-props\") ||\n old.getAttribute(\"data-zfb-transition-persist-props\") === \"false\";\n const identityChanged = ISLAND_IDENTITY_ATTRS.some(\n (attribute) => old.getAttribute(attribute) !== incoming.getAttribute(attribute),\n );\n if (\n !old.hasAttribute(ISLAND_REMOUNT_ATTR) &&\n !identityChanged &&\n (!copyProps || old.getAttribute(\"data-props\") === incoming.getAttribute(\"data-props\"))\n )\n continue;\n for (const attribute of ISLAND_IDENTITY_ATTRS) copyAttribute(incoming, old, attribute);\n if (copyProps) copyAttribute(incoming, old, \"data-props\");\n old.setAttribute(ISLAND_REMOUNT_ATTR, \"\");\n }\n for (const island of removed) {\n disposeIsland(island, \"disposal\");\n island.remove();\n }\n}\n\nconst ISLAND_IDENTITY_ATTRS = [\n \"data-zfb-island\",\n \"data-zfb-island-skip-ssr\",\n \"data-zfb-transport\",\n \"data-zfb-protocol\",\n \"data-zfb-build\",\n] as const;\n\nfunction islandName(element: Element): string | null {\n return (\n element.getAttribute(\"data-zfb-island\") ?? element.getAttribute(\"data-zfb-island-skip-ssr\")\n );\n}\n\nfunction copyAttribute(from: Element, to: Element, attribute: string): void {\n const value = from.getAttribute(attribute);\n if (value === null) to.removeAttribute(attribute);\n else to.setAttribute(attribute, value);\n}\n\nfunction readProps(\n element: Element,\n identity: { component: string; build: string },\n): Record<string, unknown> {\n const raw = element.getAttribute(\"data-props\");\n const hasHydrate = element.hasAttribute(\"data-zfb-island\");\n const hasSkipSsr = element.hasAttribute(\"data-zfb-island-skip-ssr\");\n const component =\n element.getAttribute(\"data-zfb-island\") ?? element.getAttribute(\"data-zfb-island-skip-ssr\");\n if (\n hasHydrate === hasSkipSsr ||\n component !== identity.component ||\n element.getAttribute(\"data-zfb-transport\") !== \"json/1\" ||\n element.getAttribute(\"data-zfb-protocol\") !== \"zudo-react/1\" ||\n element.getAttribute(\"data-zfb-build\") !== identity.build ||\n raw === null\n ) {\n throw new TypeError(`ZR_IDENTITY: island ${identity.component} has invalid transport identity`);\n }\n if (element.querySelector(\"[data-zfb-island],[data-zfb-island-skip-ssr]\")) {\n throw new TypeError(`ZR_NESTED_ISLAND: island ${identity.component} contains another island`);\n }\n try {\n return parseOwnedProps(raw);\n } catch (error) {\n throw new TypeError(`ZR_PROPS: island ${identity.component}: ${String(error)}`);\n }\n}\n\n/**\n * Test-only seam. Returns whether the given element has an entry in the\n * module-private `pendingCancels` Map. Used to assert that a synchronous\n * scheduler fire does not leave a stale entry behind. (#743)\n */\nexport function __hasPendingCancelForTests(element: Element): boolean {\n return pendingCancels.has(element);\n}\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// Hydration scheduling helper consumed by the hydration runtime (Sub 3).\n//\n// Sub 3 owns the hydration runtime that walks the DOM, finds elements\n// marked with `data-zfb-island`, and dispatches each one through this\n// helper to decide *when* to fire the actual hydrate() call. The helper\n// itself does not know how to hydrate — it only schedules the supplied\n// `fire` callback.\n//\n// The branching matches the `When` union exactly:\n// \"visible\" → IntersectionObserver, threshold 0.0, hydrate on first\n// intersection, then disconnect.\n// \"idle\" → requestIdleCallback if available, otherwise setTimeout(0).\n// \"media\" → matchMedia(target's data-media), hydrate when the query\n// first matches (now or on a later change event), then\n// remove the listener.\n// \"load\" → immediate, synchronous fire.\n//\n// Anything else is treated as \"load\" (with a console.warn in development).\n// The helper is environment-tolerant: callers can run it in jsdom /\n// happy-dom or bare Node, and the absence of `IntersectionObserver` /\n// `requestIdleCallback` / `matchMedia` is handled gracefully.\n\nimport { resolveWhen, type When } from \"./types.js\";\nimport { ROOT_KEY, type RootHandle } from \"./zudo-react/root.js\";\nimport { parseProps as parseOwnedProps } from \"./zudo-react/props-transport.js\";\n\n/**\n * Subset of the global object that this module touches. Cast once at the\n * module top so individual scheduler functions don't repeat the inline\n * widening.\n */\ntype SchedulerGlobal = typeof globalThis & {\n requestIdleCallback?: (\n cb: (deadline: { didTimeout: boolean; timeRemaining: () => number }) => void,\n options?: { timeout?: number },\n ) => number;\n cancelIdleCallback?: (handle: number) => void;\n IntersectionObserver?: typeof IntersectionObserver;\n matchMedia?: typeof matchMedia;\n};\n\nconst g = globalThis as SchedulerGlobal;\n\n/**\n * Internal variant of `scheduleHydrate` that also reports whether the fire\n * callback was invoked synchronously. Unexported — call sites in this module\n * use this to decide whether to register a `pendingCancels` entry.\n */\nfunction scheduleHydrateInternal(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const resolved = resolveWhen(when);\n\n if (resolved === \"load\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n if (resolved === \"idle\") {\n return { fired: false, cancel: scheduleIdle(fire) };\n }\n\n if (resolved === \"media\") {\n return scheduleMedia(target, fire);\n }\n\n // \"visible\"\n return scheduleVisible(target, fire);\n}\n\n/**\n * Schedule a hydration `fire` callback for `target` according to `when`.\n *\n * Returns a `cancel` function that aborts the scheduling if it has not\n * fired yet. After firing, calling `cancel` is a no-op. If the helper\n * cannot find the relevant browser API (e.g. running in pure Node with no\n * polyfill), it falls back to firing synchronously so server-side smoke\n * tests still observe the call.\n */\nexport function scheduleHydrate(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): () => void {\n return scheduleHydrateInternal(target, when, fire).cancel;\n}\n\nfunction noop(): void {\n // intentionally empty\n}\n\n/**\n * Build a one-shot gate around `fn`. The returned `run` invokes `fn`\n * exactly once provided `cancel` has not been called first; `cancel`\n * marks the gate as cancelled (later `run` invocations become no-ops)\n * and reports whether the gate had already fired.\n */\nfunction oneShot(fn: () => void): {\n run: () => void;\n cancel: () => boolean;\n} {\n let fired = false;\n let cancelled = false;\n return {\n run(): void {\n if (cancelled || fired) return;\n fired = true;\n fn();\n },\n cancel(): boolean {\n if (fired) return true;\n cancelled = true;\n return false;\n },\n };\n}\n\nfunction scheduleIdle(fire: () => void): () => void {\n const gate = oneShot(fire);\n\n if (typeof g.requestIdleCallback === \"function\") {\n const handle = g.requestIdleCallback(gate.run);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n if (typeof g.cancelIdleCallback === \"function\") g.cancelIdleCallback(handle);\n };\n }\n\n const handle = setTimeout(gate.run, 0);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n clearTimeout(handle);\n };\n}\n\nfunction scheduleVisible(\n target: Element,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const Observer = g.IntersectionObserver;\n\n // No IntersectionObserver (e.g. very old browsers, bare Node) — fail\n // open and hydrate immediately so the island is at least functional.\n if (typeof Observer !== \"function\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n const observer = new Observer(\n (entries, obs) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n obs.disconnect();\n gate.run();\n return;\n }\n }\n },\n { threshold: 0 },\n );\n\n observer.observe(target);\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n observer.disconnect();\n },\n };\n}\n\nfunction scheduleMedia(target: Element, fire: () => void): { fired: boolean; cancel: () => void } {\n const query = target.getAttribute(\"data-media\");\n\n // No matchMedia API (e.g. bare Node, very old browser) or missing/empty\n // query — fail open and hydrate immediately so the island is at least\n // functional.\n if (typeof g.matchMedia !== \"function\" || !query) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const mql = g.matchMedia(query);\n\n // Already matches — fire synchronously (no pending listener needed).\n if (mql.matches) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n\n let removeListener = noop;\n\n // Listen for the first change event where the query matches.\n // We do NOT use `{once:true}` because we must ignore un-match events\n // (e.g. viewport widens back above breakpoint) and only fire on the\n // first match event — `{once:true}` would consume any change, including\n // un-match changes.\n const handler = (e: MediaQueryListEvent): void => {\n if (!e.matches) return; // ignore un-match changes\n removeListener();\n gate.run();\n };\n\n // Modern browsers expose the EventTarget API on MediaQueryList; older\n // Safari (<14) only has the deprecated addListener/removeListener pair\n // and throws on addEventListener. Prefer modern, fall back to legacy,\n // and fail open when neither exists (mirrors the missing-matchMedia case).\n if (typeof mql.addEventListener === \"function\") {\n mql.addEventListener(\"change\", handler);\n removeListener = () => mql.removeEventListener(\"change\", handler);\n } else if (typeof mql.addListener === \"function\") {\n mql.addListener(handler);\n removeListener = () => mql.removeListener(handler);\n } else {\n fire();\n return { fired: true, cancel: noop };\n }\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n removeListener();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// mountIslands — DOM walk + dynamic-import dispatcher.\n//\n// `mountIslands` is the entry point the generated `islands-runtime-<hash>.js`\n// bundle calls at script load time. It walks the DOM for the two island\n// markers emitted by the server-side hydration step and the `<Island>`\n// JSX wrapper:\n//\n// 1. `[data-zfb-island]` — adopt server-rendered owned DOM.\n// 2. `[data-zfb-island-skip-ssr]` — mount over the fallback when scheduled.\n//\n// The generated shared bundle supplies strict identity and a RootHandle.\n// ---------------------------------------------------------------------------\n\n/**\n * The mount function supplied by a shared-bundle island module.\n *\n * `mode === \"hydrate\"` is used for SSR'd islands, `\"render\"` for\n * SSR-skip islands.\n */\ntype IslandMount = (\n props: Record<string, unknown>,\n element: Element,\n mode: \"hydrate\" | \"render\",\n) => RootHandle | null;\n\ninterface IslandModule {\n identity: { component: string; build: string };\n mount: IslandMount;\n}\n\n/**\n * Map of `componentName → island descriptor` baked into the runtime entry.\n *\n * Each manifest value is an inline module with `mount` or `default`.\n * The shared bundle imports island sources at build time.\n */\nexport type IslandManifestValue = IslandModule;\nexport type IslandManifest = Readonly<Record<string, IslandManifestValue>>;\n\n// data-zfb-transition-persist marker attribute — the client-router's persist\n// contract. Mirrored from client-router/swap-functions.ts: that package owns the\n// body swap (lifting persisted nodes into the incoming body), this package owns\n// island mount/unmount. Both must agree on the literal string. See the port\n// spec at packages/zfb-runtime/docs/client-router/port-spec.md §12.3.\nconst PERSIST_ATTR = \"data-zfb-transition-persist\";\n\n// Cross-package \"needs-remount\" flag set by client-router/swap-functions.ts on a\n// persisted island whose props changed across a body swap. Mirrored literal (same\n// cross-package contract as PERSIST_ATTR above — both packages must agree on the\n// string). Consumed by clearMountedForRemount(). See #1389.\nconst ISLAND_REMOUNT_ATTR = \"data-zfb-island-remount\";\n\n/**\n * Public observation marker; the symbol handle is the live-root guard.\n *\n * State table:\n * - initial/deferred/missing entry/failed mount: marker and handle absent;\n * - successful mount: both present;\n * - discarded root: disposal leaves DOM for the body swap, then clears both;\n * - unchanged island inside a retained persist boundary: handle and marker survive;\n * - changed island inside a retained boundary: metadata and remount flag are set,\n * then the post-swap scan disposes once and mounts in render mode;\n * - removed island inside a retained boundary: dispose and detach before swap;\n * - bundle re-import: dispose the old symbol handle before render mode replaces it.\n */\nexport const ISLAND_MOUNTED_ATTR = \"data-zfb-island-mounted\";\n// Retained SSR DOM may already have incoming props while its first mount is\n// deferred. Keep the render operation across swaps, retries, and dev re-imports.\nconst ISLAND_PENDING_RENDER_ATTR = \"data-zfb-island-pending-render\";\nconst COMPOSITION_KEY = Symbol.for(\"@takazudo/zfb/zudo-react/composition-v1\");\nconst TRACKER_KEY = Symbol.for(\"@takazudo/zfb/zudo-react/composition-tracker-v1\");\n\n// A fresh bundle instance replaces roots installed by a previous instance.\n// Ordinary repeat scans in the same instance keep their live handles.\nconst owned = new WeakSet<Element>();\nfunction rootHandle(element: Element): RootHandle | undefined {\n return (element as unknown as Record<symbol, RootHandle | undefined>)[ROOT_KEY];\n}\nfunction setRootHandle(element: Element, handle: RootHandle | undefined): void {\n const target = element as unknown as Record<symbol, RootHandle | undefined>;\n if (handle) target[ROOT_KEY] = handle;\n else delete target[ROOT_KEY];\n}\nfunction reportIslandError(element: Element, phase: string, error: unknown): void {\n const name =\n element.getAttribute(\"data-zfb-island\") ??\n element.getAttribute(\"data-zfb-island-skip-ssr\") ??\n \"unknown\";\n try {\n console.error(`[zfb] island \"${name}\" ${phase} failed`, error);\n } catch {\n // A broken reporter must not stop other roots.\n }\n}\nfunction disposeIsland(element: Element, phase: string): void {\n pendingCancels.get(element)?.();\n pendingCancels.delete(element);\n element.removeAttribute(ISLAND_PENDING_RENDER_ATTR);\n const handle = rootHandle(element);\n try {\n handle?.dispose();\n } catch (error) {\n reportIslandError(element, phase, error);\n } finally {\n if (rootHandle(element) === handle) setRootHandle(element, undefined);\n element.removeAttribute(ISLAND_MOUNTED_ATTR);\n }\n}\nfunction installCompositionTracker(doc: Document): void {\n const target = doc as unknown as Record<symbol, (() => void) | undefined>;\n if (target[TRACKER_KEY]) return;\n const set = (event: Event, value: \"active\" | \"idle\") => {\n if (event.target instanceof Element) {\n (event.target as unknown as Record<symbol, string>)[COMPOSITION_KEY] = value;\n }\n };\n const start = (event: Event) => set(event, \"active\");\n const end = (event: Event) => set(event, \"idle\");\n const input = (event: Event) => {\n if ((event as InputEvent).isComposing) set(event, \"active\");\n };\n doc.addEventListener(\"compositionstart\", start, true);\n doc.addEventListener(\"compositionend\", end, true);\n doc.addEventListener(\"input\", input, true);\n doc.addEventListener(\"blur\", end, true);\n target[TRACKER_KEY] = () => {\n doc.removeEventListener(\"compositionstart\", start, true);\n doc.removeEventListener(\"compositionend\", end, true);\n doc.removeEventListener(\"input\", input, true);\n doc.removeEventListener(\"blur\", end, true);\n delete target[TRACKER_KEY];\n };\n}\n\n// Elements for which the nested-island self-wrap warning has already been\n// emitted. Guards against repeated warn spam across re-walks (e.g. SPA swaps).\nconst warnedNested = new WeakSet<Element>();\n// Module-level captured manifest — set by the first `mountIslands` call and reused by\n// `mountNewIslands()` so the client-router does not need to know the manifest directly.\n// Named technical cause (W1B §12.1): the router lives in @takazudo/zfb-runtime; the\n// islands manifest lives in @takazudo/zfb. Passing the manifest through the swap event\n// would require widening the event API or threading manifest into router options. The\n// captured-manifest pattern keeps the package boundary clean.\nlet capturedManifest: IslandManifest | null = null;\n\n// Map of element → cancel-function for deferred-hydration islands\n// (data-when=\"idle\"|\"visible\"|\"media\").\n// Populated in scheduleMount; consulted on `zfb:before-swap` so deferred fires do not run\n// against orphan elements after a body swap. (W1B §12.5)\nconst pendingCancels = new Map<Element, () => void>();\n\n/**\n * Walk the DOM and mount every `[data-zfb-island]` / `[data-zfb-island-skip-ssr]`\n * element using `manifest`.\n *\n * No-op when `document` is undefined (SSR, edge runtime). Safe to call\n * multiple times: each element is mounted at most once thanks to the\n * symbol-handle guard.\n *\n * The manifest is captured at module level so `mountNewIslands()` can re-use\n * it after an SPA body swap without needing the caller to re-supply it.\n */\nexport function mountIslands(manifest: IslandManifest): void {\n if (typeof document === \"undefined\") return;\n\n // Capture the manifest for post-swap re-walks via mountNewIslands().\n capturedManifest = manifest;\n installCompositionTracker(document);\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n const replacing = prepareMount(el);\n // Skip the empty-skeleton case left behind when the server-side\n // rewriter has not run yet (data-zfb-island=\"\" with no component\n // name). The hydration emit step is expected to fill this in\n // before the page reaches the browser; if it didn't, we cannot\n // dispatch.\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n const hadLiveRoot = !!rootHandle(el);\n const flagged = !hadLiveRoot && !replacing && clearMountedForRemount(el);\n warnIfNestedIsland(el, name);\n scheduleMount(\n manifest,\n el,\n name,\n replacing || flagged || el.hasAttribute(ISLAND_PENDING_RENDER_ATTR) ? \"render\" : \"hydrate\",\n { force: hadLiveRoot || replacing },\n );\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n const hadLiveRoot = !!rootHandle(el);\n if (!hadLiveRoot && !replacing) clearMountedForRemount(el);\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"render\", { force: hadLiveRoot || replacing });\n }\n}\n\n/**\n * Re-walk the current document body and mount any new island markers introduced\n * by an SPA body swap. Uses the manifest captured by the previous `mountIslands`\n * call — no manifest arg required.\n *\n * The caller (client-router `router.ts`) invokes this after `swap()` + `runScripts()`\n * and before dispatching `zfb:page-load`, per W1B §12.2 contract.\n *\n * No-op when called before `mountIslands` (capturedManifest is null) or when\n * `document` is undefined.\n */\nexport function mountNewIslands(): void {\n if (typeof document === \"undefined\") return;\n if (capturedManifest === null) return;\n\n const manifest = capturedManifest;\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n // The router marks changed persisted identity/props on the surviving node.\n const hadLiveRoot = !!rootHandle(el);\n const flagged = clearMountedForRemount(el);\n warnIfNestedIsland(el, name);\n scheduleMount(\n manifest,\n el,\n name,\n replacing || flagged || el.hasAttribute(ISLAND_PENDING_RENDER_ATTR) ? \"render\" : \"hydrate\",\n { force: hadLiveRoot || replacing },\n );\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n const hadLiveRoot = !!rootHandle(el);\n clearMountedForRemount(el);\n scheduleMount(manifest, el, name, \"render\", { force: hadLiveRoot || replacing });\n }\n}\n\n/** Consume a persisted root's remount flag and dispose its previous resources. */\nfunction clearMountedForRemount(el: Element): boolean {\n if (!el.hasAttribute(ISLAND_REMOUNT_ATTR)) return false;\n el.removeAttribute(ISLAND_REMOUNT_ATTR);\n if (rootHandle(el)) disposeIsland(el, \"remount disposal\");\n else {\n el.removeAttribute(ISLAND_MOUNTED_ATTR);\n el.setAttribute(ISLAND_PENDING_RENDER_ATTR, \"\");\n }\n return true;\n}\n\nfunction prepareMount(el: Element): boolean {\n let replacing = false;\n if (rootHandle(el) && !owned.has(el)) {\n disposeIsland(el, \"dev replacement disposal\");\n el.removeAttribute(ISLAND_REMOUNT_ATTR);\n replacing = true;\n }\n if (!rootHandle(el)) el.removeAttribute(ISLAND_MOUNTED_ATTR);\n return replacing;\n}\n\n/**\n * Cancel deferred-hydration callbacks for all islands in the old body before a\n * swap. Prevents idle / visibility callbacks from running against orphan elements\n * after `swapBodyElement` removes them from the live document. (W1B §12.5)\n *\n * Call this on `zfb:before-swap` (or equivalently, in the router's swap sequence\n * before `swap()` mutates the DOM). Fire-and-forget; safe to call if nothing is\n * pending.\n */\nexport function cancelPendingIslands(): void {\n for (const [el, cancel] of pendingCancels) {\n cancel();\n pendingCancels.delete(el);\n }\n}\n\n/**\n * Warn (once per element, dev-only) when an island marker element is found\n * nested inside another island marker. Self-wrapping an island — emitting a\n * `data-zfb-island` or `data-zfb-island-skip-ssr` container *inside* another\n * island component's render output — mis-hydrates because the runtime will\n * try to mount both the outer and inner islands independently. The outer\n * island's framework instance owns the inner DOM, so a second `hydrate()` /\n * `render()` call against the inner element races with the outer render and\n * produces undefined behaviour.\n *\n * The fix is to author the inner component bare (no `<Island>` in its own\n * render output) and apply the `<Island when=\"...\">` wrapper at the call site.\n */\nfunction warnIfNestedIsland(el: Element, componentName: string): void {\n if (typeof process === \"undefined\" || !process.env || process.env[\"NODE_ENV\"] === \"production\") {\n return;\n }\n if (warnedNested.has(el)) return;\n const parent = el.parentElement;\n if (!parent || typeof parent.closest !== \"function\") return;\n const ancestor = parent.closest(\"[data-zfb-island],[data-zfb-island-skip-ssr]\");\n if (!ancestor) return;\n warnedNested.add(el);\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] Island \"${componentName}\" is nested inside another island marker. ` +\n `Self-wrapping an island mis-hydrates: the outer framework instance owns ` +\n `the inner DOM, causing a conflicting mount. ` +\n `Fix: author \"${componentName}\" bare (remove <Island> from its own render output) ` +\n `and apply <Island when=\"...\"> at the call site instead.`,\n );\n}\n\nfunction scheduleMount(\n manifest: IslandManifest,\n element: Element,\n componentName: string,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n if (rootHandle(element)) return;\n\n // A later scan may change hydrate into render after a retained props update.\n pendingCancels.get(element)?.();\n pendingCancels.delete(element);\n\n const entry = manifest[componentName];\n if (entry == null) {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] no island manifest entry for component \"${componentName}\" — ` +\n `the runtime manifest is out of sync with the rendered HTML.`,\n );\n }\n return;\n }\n\n fireInlineMount(element, entry, mode, options);\n}\n\n/**\n * Run the mount step for the inline-module manifest shape used by the\n * shared-bundle path. The module is already in memory (it was imported\n * into the bundle at build time), so there is no async window to\n * coordinate around — we just call `mount` / `default` directly,\n * gated by `data-when` semantics.\n */\nfunction fireInlineMount(\n element: Element,\n mod: IslandModule,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n const fn = mod.mount;\n if (typeof fn !== \"function\") {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\"[zfb] owned island manifest entry did not export mount()\");\n }\n return;\n }\n\n const fire = (): void => {\n // Re-check the guard in case `fire` is invoked from a deferred\n // scheduler (rIC/rAF/visibility) after a sibling caller already\n // mounted this element.\n if (rootHandle(element)) return;\n // When the deferred fire actually runs, the cancel handle is no longer\n // needed — remove it so pendingCancels doesn't hold stale entries.\n pendingCancels.delete(element);\n // Stale-mount race guard for deferred inline mounts: skip if the element\n // was detached (e.g. body swap) while the idle/visible callback was queued.\n if (!element.isConnected) return;\n // Lazy props parse: read and parse data-props only at mount time.\n // For deferred strategies (media, visible, idle) this avoids JSON.parse\n // work at boot time for islands that may never hydrate.\n try {\n const props = readProps(element, mod.identity);\n const result = fn(props, element, mode);\n if (result === null) return;\n if (!result || typeof result.dispose !== \"function\" || typeof result.unmount !== \"function\") {\n throw new TypeError(\n `ZR_ROOT_HANDLE: island ${mod.identity.component} returned no root handle`,\n );\n }\n const handle: RootHandle = result;\n setRootHandle(element, handle);\n owned.add(element);\n element.setAttribute(ISLAND_MOUNTED_ATTR, \"\");\n element.removeAttribute(ISLAND_PENDING_RENDER_ATTR);\n } catch (error) {\n element.removeAttribute(ISLAND_MOUNTED_ATTR);\n reportIslandError(element, \"mount\", error);\n }\n };\n\n if (options.force) {\n fire();\n return;\n }\n\n const when = element.getAttribute(\"data-when\") ?? undefined;\n const { fired, cancel } = scheduleHydrateInternal(element, when, fire);\n // Track deferred-hydration cancel handle so cancelPendingIslands() can abort\n // idle / visibility callbacks before a body swap. (W1B §12.5)\n // Only register when the scheduler did NOT fire synchronously — a synchronous\n // fire means the island is already handling its mount and there is no\n // deferred callback to cancel. Registering noop after a sync fire would leave\n // a stale pendingCancels entry for an already-handled element. (#743)\n if (when && when !== \"load\" && !fired) {\n pendingCancels.set(element, cancel);\n }\n}\n\n/**\n * Snapshot persistence and island pairings before changing any old-body node.\n * The router lifts only matched persist nodes whose incoming targets are not\n * nested inside another matched target. Their descendants survive that lift.\n */\nexport function unmountIslands(\n root: ParentNode = document.body,\n incomingBody?: ParentNode | null,\n): void {\n const islandSelector = \"[data-zfb-island],[data-zfb-island-skip-ssr]\";\n const oldIslands = Array.from(root.querySelectorAll<HTMLElement>(islandSelector));\n if (!incomingBody) {\n for (const island of oldIslands) disposeIsland(island, \"disposal\");\n return;\n }\n\n const persistSelector = `[${PERSIST_ATTR}]`;\n const oldPersist = Array.from(root.querySelectorAll(persistSelector));\n const incomingPersist = Array.from(incomingBody.querySelectorAll(persistSelector));\n const incomingById = new Map<string, Element>();\n for (const element of incomingPersist) {\n const id = element.getAttribute(PERSIST_ATTR);\n if (id !== null && !incomingById.has(id)) incomingById.set(id, element);\n }\n\n const targets = new Map<Element, Element>();\n for (const element of oldPersist) {\n const id = element.getAttribute(PERSIST_ATTR);\n const target = id === null ? undefined : incomingById.get(id);\n if (target) targets.set(element, target);\n }\n const matchedTargets = new Set(targets.values());\n const lifted = new Set<Element>();\n for (const [element, target] of targets) {\n let ancestor = target.parentElement;\n while (ancestor && !matchedTargets.has(ancestor)) ancestor = ancestor.parentElement;\n if (!ancestor) lifted.add(element);\n }\n const retained = new Set<Element>(lifted);\n for (const element of oldPersist) {\n if (!targets.has(element)) continue;\n let ancestor = element.parentElement;\n while (ancestor && !lifted.has(ancestor)) ancestor = ancestor.parentElement;\n if (ancestor) retained.add(element);\n }\n\n const boundaryById = new Map<string, Element>();\n for (const element of oldPersist) {\n if (!retained.has(element)) continue;\n const id = element.getAttribute(PERSIST_ATTR);\n if (id !== null && !boundaryById.has(id)) boundaryById.set(id, element);\n }\n const oldByBoundary = new Map<Element, Element[]>();\n const incomingByBoundary = new Map<Element, Element[]>();\n const withoutBoundary: Element[] = [];\n for (const island of oldIslands) {\n let ancestor: Element | null = island;\n while (ancestor && !retained.has(ancestor)) ancestor = ancestor.parentElement;\n if (!ancestor) {\n withoutBoundary.push(island);\n continue;\n }\n const group = oldByBoundary.get(ancestor) ?? [];\n group.push(island);\n oldByBoundary.set(ancestor, group);\n }\n for (const island of incomingBody.querySelectorAll(islandSelector)) {\n let ancestor: Element | null = island;\n let boundary: Element | undefined;\n while (ancestor && !boundary) {\n const id = ancestor.getAttribute(PERSIST_ATTR);\n if (id !== null) boundary = boundaryById.get(id);\n ancestor = ancestor.parentElement;\n }\n if (!boundary) continue;\n const group = incomingByBoundary.get(boundary) ?? [];\n group.push(island);\n incomingByBoundary.set(boundary, group);\n }\n\n const pairs: Array<{ old: Element; incoming: Element }> = [];\n const removed: Element[] = [];\n for (const [boundary, oldGroup] of oldByBoundary) {\n const incomingGroup = incomingByBoundary.get(boundary) ?? [];\n const pairedOld = new Set<Element>();\n const pairedIncoming = new Set<Element>();\n // A persisted island root always maps to its own target, even when the\n // target changes component or ceases to be an island.\n if (oldGroup.includes(boundary)) {\n pairedOld.add(boundary);\n const target = targets.get(boundary);\n if (target && incomingGroup.includes(target)) {\n pairs.push({ old: boundary, incoming: target });\n pairedIncoming.add(target);\n } else {\n removed.push(boundary);\n }\n }\n for (const old of oldGroup) {\n if (pairedOld.has(old)) continue;\n const name = islandName(old);\n const incoming = incomingGroup.find(\n (candidate) => !pairedIncoming.has(candidate) && islandName(candidate) === name,\n );\n if (!incoming) continue;\n pairs.push({ old, incoming });\n pairedOld.add(old);\n pairedIncoming.add(incoming);\n }\n const remainingIncoming = incomingGroup.filter((island) => !pairedIncoming.has(island));\n let next = 0;\n for (const old of oldGroup) {\n if (pairedOld.has(old)) continue;\n const incoming = remainingIncoming[next++];\n if (incoming) pairs.push({ old, incoming });\n else removed.push(old);\n }\n }\n\n // Apply only after all boundaries and pairings have been computed. An old\n // descendant removed from a lifted wrapper must be detached as well as\n // disposed, or the post-swap walk could hydrate its mutated DOM.\n for (const island of withoutBoundary) disposeIsland(island, \"disposal\");\n for (const { old, incoming } of pairs) {\n const copyProps =\n !old.hasAttribute(\"data-zfb-transition-persist-props\") ||\n old.getAttribute(\"data-zfb-transition-persist-props\") === \"false\";\n const identityChanged = ISLAND_IDENTITY_ATTRS.some(\n (attribute) => old.getAttribute(attribute) !== incoming.getAttribute(attribute),\n );\n if (\n !old.hasAttribute(ISLAND_REMOUNT_ATTR) &&\n !identityChanged &&\n (!copyProps || old.getAttribute(\"data-props\") === incoming.getAttribute(\"data-props\"))\n )\n continue;\n for (const attribute of ISLAND_IDENTITY_ATTRS) copyAttribute(incoming, old, attribute);\n if (copyProps) copyAttribute(incoming, old, \"data-props\");\n old.setAttribute(ISLAND_REMOUNT_ATTR, \"\");\n }\n for (const island of removed) {\n disposeIsland(island, \"disposal\");\n island.remove();\n }\n}\n\nconst ISLAND_IDENTITY_ATTRS = [\n \"data-zfb-island\",\n \"data-zfb-island-skip-ssr\",\n \"data-zfb-transport\",\n \"data-zfb-protocol\",\n \"data-zfb-build\",\n] as const;\n\nfunction islandName(element: Element): string | null {\n return (\n element.getAttribute(\"data-zfb-island\") ?? element.getAttribute(\"data-zfb-island-skip-ssr\")\n );\n}\n\nfunction copyAttribute(from: Element, to: Element, attribute: string): void {\n const value = from.getAttribute(attribute);\n if (value === null) to.removeAttribute(attribute);\n else to.setAttribute(attribute, value);\n}\n\nfunction readProps(\n element: Element,\n identity: { component: string; build: string },\n): Record<string, unknown> {\n const raw = element.getAttribute(\"data-props\");\n const hasHydrate = element.hasAttribute(\"data-zfb-island\");\n const hasSkipSsr = element.hasAttribute(\"data-zfb-island-skip-ssr\");\n const component =\n element.getAttribute(\"data-zfb-island\") ?? element.getAttribute(\"data-zfb-island-skip-ssr\");\n if (\n hasHydrate === hasSkipSsr ||\n component !== identity.component ||\n element.getAttribute(\"data-zfb-transport\") !== \"json/1\" ||\n element.getAttribute(\"data-zfb-protocol\") !== \"zudo-react/1\" ||\n element.getAttribute(\"data-zfb-build\") !== identity.build ||\n raw === null\n ) {\n throw new TypeError(`ZR_IDENTITY: island ${identity.component} has invalid transport identity`);\n }\n if (element.querySelector(\"[data-zfb-island],[data-zfb-island-skip-ssr]\")) {\n throw new TypeError(`ZR_NESTED_ISLAND: island ${identity.component} contains another island`);\n }\n try {\n return parseOwnedProps(raw);\n } catch (error) {\n throw new TypeError(`ZR_PROPS: island ${identity.component}: ${String(error)}`);\n }\n}\n\n/**\n * Test-only seam. Returns whether the given element has an entry in the\n * module-private `pendingCancels` Map. Used to assert that a synchronous\n * scheduler fire does not leave a stale entry behind. (#743)\n */\nexport function __hasPendingCancelForTests(element: Element): boolean {\n return pendingCancels.has(element);\n}\n"]}
package/dist/slugify.d.ts CHANGED
@@ -1,68 +1 @@
1
- /**
2
- * Heading-anchor slug utilities — a pure-TypeScript port of the Rust
3
- * `slugify` / `next_slug` / `SlugAllocator` in
4
- * `crates/zfb-content/src/plugins/heading_links.rs`.
5
- *
6
- * These functions produce the `id` attribute values that appear on
7
- * `<h2>`–`<h6>` elements in the rendered HTML. They are intentionally
8
- * **not** compatible with npm `github-slugger`: stripped punctuation
9
- * collapses to a `-` separator (`"a,b"` → `"a-b"`), and leading/trailing
10
- * whitespace / stripped chars emit nothing rather than a stray dash.
11
- *
12
- * ⚠️ These functions produce heading-anchor slugs (e.g. `"hello-world"`
13
- * for `<h2 id="hello-world">`). They are **different** from
14
- * `_relPathToSlug` in `content.ts`, which converts a file-system relative
15
- * path into a URL slug for `CollectionEntry.slug`.
16
- *
17
- * Parity is enforced by the shared fixture at
18
- * `crates/zfb-content/tests/fixtures/slugify-parity.json`, consumed by
19
- * both a Rust integration test and the `slugify.test.ts` vitest suite.
20
- */
21
- /**
22
- * Produce a heading-anchor slug from `input`, matching the Rust
23
- * `slugify()` in `crates/zfb-content/src/plugins/heading_links.rs`.
24
- *
25
- * Algorithm (per Unicode code point):
26
- * - whitespace or stripped punctuation → emit ONE `-` unless the last
27
- * emitted character was already a `-` (leading separators are skipped
28
- * because `lastDash` starts `true`).
29
- * - anything else → push `ch.toLowerCase()` (per-code-point, not
30
- * whole-string, to avoid Greek final-sigma context collapsing).
31
- * - finally pop ONE trailing `-` if present.
32
- *
33
- * Divergence from npm github-slugger (intentional — parity target is
34
- * the Rust function, not npm):
35
- * - `"a,b"` → `"a-b"` (stripped punctuation emits a dash, not nothing)
36
- * - `" --weird-- "` → `"--weird--"` (existing dashes/underscores pass
37
- * through unchanged)
38
- */
39
- export declare function slugify(input: string): string;
40
- /**
41
- * Strategy-aware slug allocator for a single document.
42
- *
43
- * Mirrors Rust `SlugAllocator` in heading_links.rs:70-118.
44
- *
45
- * @param strategy `"flat"` (default) — per-document dedup counter, mirrors
46
- * github-slugger numbering. `"hierarchical"` — each slug is prefixed with
47
- * its ancestor chain and deduped on the full candidate path.
48
- *
49
- * Depth contract: callers pass `depth` values 2–6 (h2–h6). h1 is never
50
- * allocated — it is handled by the page layout, not the markdown body.
51
- */
52
- export declare class SlugAllocator {
53
- private readonly strategy;
54
- private seen;
55
- /** Hierarchical ancestor stack of `[depth, finalId]` pairs. Unused in flat mode. */
56
- private stack;
57
- constructor(strategy?: "flat" | "hierarchical");
58
- /**
59
- * Allocate the slug for a heading of `depth` (2–6) whose slugified text
60
- * is `base`. Returns `""` for an empty `base` without mutating state.
61
- */
62
- allocate(depth: number, base: string): string;
63
- /**
64
- * Clear all per-document state (dedup counters AND the hierarchical
65
- * ancestor stack). Call between documents to avoid slug counter leakage.
66
- */
67
- reset(): void;
68
- }
1
+ export { slugify, SlugAllocator } from "@takazudo/zfb-slugify";
package/dist/slugify.js CHANGED
@@ -1,197 +1,2 @@
1
- /**
2
- * Heading-anchor slug utilities — a pure-TypeScript port of the Rust
3
- * `slugify` / `next_slug` / `SlugAllocator` in
4
- * `crates/zfb-content/src/plugins/heading_links.rs`.
5
- *
6
- * These functions produce the `id` attribute values that appear on
7
- * `<h2>`–`<h6>` elements in the rendered HTML. They are intentionally
8
- * **not** compatible with npm `github-slugger`: stripped punctuation
9
- * collapses to a `-` separator (`"a,b"` → `"a-b"`), and leading/trailing
10
- * whitespace / stripped chars emit nothing rather than a stray dash.
11
- *
12
- * ⚠️ These functions produce heading-anchor slugs (e.g. `"hello-world"`
13
- * for `<h2 id="hello-world">`). They are **different** from
14
- * `_relPathToSlug` in `content.ts`, which converts a file-system relative
15
- * path into a URL slug for `CollectionEntry.slug`.
16
- *
17
- * Parity is enforced by the shared fixture at
18
- * `crates/zfb-content/tests/fixtures/slugify-parity.json`, consumed by
19
- * both a Rust integration test and the `slugify.test.ts` vitest suite.
20
- */
21
- // ---------------------------------------------------------------------------
22
- // Helpers — mirrors the Rust `is_stripped` predicate
23
- // ---------------------------------------------------------------------------
24
- /** Unicode General Category Cc (control characters). */
25
- function isCc(ch) {
26
- // \p{Cc} = general category "Control" (C0 + C1 blocks: U+0000–U+001F, U+007F–U+009F)
27
- return /^\p{Cc}$/u.test(ch);
28
- }
29
- /**
30
- * Returns true when the character should be stripped (maps to a dash
31
- * separator in the output). Mirrors Rust's `is_stripped`:
32
- * - Unicode Cc control characters
33
- * - Explicit ASCII punctuation set: `! " # $ % & ' ( ) * + , . / : ; < = > ? @ [ \ ] ^ ` { | } ~`
34
- */
35
- function isStripped(ch) {
36
- if (isCc(ch))
37
- return true;
38
- return (ch === "!" ||
39
- ch === '"' ||
40
- ch === "#" ||
41
- ch === "$" ||
42
- ch === "%" ||
43
- ch === "&" ||
44
- ch === "'" ||
45
- ch === "(" ||
46
- ch === ")" ||
47
- ch === "*" ||
48
- ch === "+" ||
49
- ch === "," ||
50
- ch === "." ||
51
- ch === "/" ||
52
- ch === ":" ||
53
- ch === ";" ||
54
- ch === "<" ||
55
- ch === "=" ||
56
- ch === ">" ||
57
- ch === "?" ||
58
- ch === "@" ||
59
- ch === "[" ||
60
- ch === "\\" ||
61
- ch === "]" ||
62
- ch === "^" ||
63
- ch === "`" ||
64
- ch === "{" ||
65
- ch === "|" ||
66
- ch === "}" ||
67
- ch === "~");
68
- }
69
- /**
70
- * Returns true when `ch` is a Unicode whitespace character.
71
- *
72
- * Mirrors Rust `char::is_whitespace` which is `\p{White_Space}/u` — NOT
73
- * the JS `\s` class (`\s` wrongly matches U+FEFF BYTE ORDER MARK and
74
- * misses U+0085 NEXT LINE).
75
- */
76
- function isWhitespace(ch) {
77
- return /^\p{White_Space}$/u.test(ch);
78
- }
79
- // ---------------------------------------------------------------------------
80
- // slugify
81
- // ---------------------------------------------------------------------------
82
- /**
83
- * Produce a heading-anchor slug from `input`, matching the Rust
84
- * `slugify()` in `crates/zfb-content/src/plugins/heading_links.rs`.
85
- *
86
- * Algorithm (per Unicode code point):
87
- * - whitespace or stripped punctuation → emit ONE `-` unless the last
88
- * emitted character was already a `-` (leading separators are skipped
89
- * because `lastDash` starts `true`).
90
- * - anything else → push `ch.toLowerCase()` (per-code-point, not
91
- * whole-string, to avoid Greek final-sigma context collapsing).
92
- * - finally pop ONE trailing `-` if present.
93
- *
94
- * Divergence from npm github-slugger (intentional — parity target is
95
- * the Rust function, not npm):
96
- * - `"a,b"` → `"a-b"` (stripped punctuation emits a dash, not nothing)
97
- * - `" --weird-- "` → `"--weird--"` (existing dashes/underscores pass
98
- * through unchanged)
99
- */
100
- export function slugify(input) {
101
- let out = "";
102
- let lastDash = true;
103
- for (const ch of input) {
104
- if (isWhitespace(ch) || isStripped(ch)) {
105
- if (!lastDash) {
106
- out += "-";
107
- lastDash = true;
108
- }
109
- }
110
- else {
111
- // Per-code-point lowercase — avoids Greek final-sigma context:
112
- // "ΦΟΣ" → "φοσ" not "φος".
113
- out += ch.toLowerCase();
114
- lastDash = false;
115
- }
116
- }
117
- if (out.endsWith("-")) {
118
- out = out.slice(0, -1);
119
- }
120
- return out;
121
- }
122
- // ---------------------------------------------------------------------------
123
- // next_slug
124
- // ---------------------------------------------------------------------------
125
- /**
126
- * Allocate the next deduplicated slug for `base` against a per-document
127
- * counter map.
128
- *
129
- * Mirrors Rust `next_slug`: first occurrence returns `base`, second
130
- * returns `base-1`, third `base-2`, … Empty `base` short-circuits to
131
- * `""` without mutating the map.
132
- */
133
- function nextSlug(seen, base) {
134
- if (base === "")
135
- return "";
136
- const count = seen.get(base) ?? 0;
137
- const slug = count === 0 ? base : `${base}-${count}`;
138
- seen.set(base, count + 1);
139
- return slug;
140
- }
141
- // ---------------------------------------------------------------------------
142
- // SlugAllocator
143
- // ---------------------------------------------------------------------------
144
- /**
145
- * Strategy-aware slug allocator for a single document.
146
- *
147
- * Mirrors Rust `SlugAllocator` in heading_links.rs:70-118.
148
- *
149
- * @param strategy `"flat"` (default) — per-document dedup counter, mirrors
150
- * github-slugger numbering. `"hierarchical"` — each slug is prefixed with
151
- * its ancestor chain and deduped on the full candidate path.
152
- *
153
- * Depth contract: callers pass `depth` values 2–6 (h2–h6). h1 is never
154
- * allocated — it is handled by the page layout, not the markdown body.
155
- */
156
- export class SlugAllocator {
157
- strategy;
158
- seen;
159
- /** Hierarchical ancestor stack of `[depth, finalId]` pairs. Unused in flat mode. */
160
- stack;
161
- constructor(strategy = "flat") {
162
- this.strategy = strategy;
163
- this.seen = new Map();
164
- this.stack = [];
165
- }
166
- /**
167
- * Allocate the slug for a heading of `depth` (2–6) whose slugified text
168
- * is `base`. Returns `""` for an empty `base` without mutating state.
169
- */
170
- allocate(depth, base) {
171
- if (this.strategy === "flat") {
172
- return nextSlug(this.seen, base);
173
- }
174
- // Hierarchical mode
175
- if (base === "")
176
- return "";
177
- // Pop ancestors whose depth >= this heading's depth
178
- let top = this.stack.at(-1);
179
- while (top !== undefined && top[0] >= depth) {
180
- this.stack.pop();
181
- top = this.stack.at(-1);
182
- }
183
- const candidate = top !== undefined ? `${top[1]}-${base}` : base;
184
- const slug = nextSlug(this.seen, candidate);
185
- this.stack.push([depth, slug]);
186
- return slug;
187
- }
188
- /**
189
- * Clear all per-document state (dedup counters AND the hierarchical
190
- * ancestor stack). Call between documents to avoid slug counter leakage.
191
- */
192
- reset() {
193
- this.seen.clear();
194
- this.stack = [];
195
- }
196
- }
1
+ export { slugify, SlugAllocator } from "@takazudo/zfb-slugify";
197
2
  //# sourceMappingURL=slugify.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"slugify.js","sourceRoot":"","sources":["../src/slugify.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Heading-anchor slug utilities — a pure-TypeScript port of the Rust\n * `slugify` / `next_slug` / `SlugAllocator` in\n * `crates/zfb-content/src/plugins/heading_links.rs`.\n *\n * These functions produce the `id` attribute values that appear on\n * `<h2>`–`<h6>` elements in the rendered HTML. They are intentionally\n * **not** compatible with npm `github-slugger`: stripped punctuation\n * collapses to a `-` separator (`\"a,b\"` → `\"a-b\"`), and leading/trailing\n * whitespace / stripped chars emit nothing rather than a stray dash.\n *\n * ⚠️ These functions produce heading-anchor slugs (e.g. `\"hello-world\"`\n * for `<h2 id=\"hello-world\">`). They are **different** from\n * `_relPathToSlug` in `content.ts`, which converts a file-system relative\n * path into a URL slug for `CollectionEntry.slug`.\n *\n * Parity is enforced by the shared fixture at\n * `crates/zfb-content/tests/fixtures/slugify-parity.json`, consumed by\n * both a Rust integration test and the `slugify.test.ts` vitest suite.\n */\n\n// ---------------------------------------------------------------------------\n// Helpers — mirrors the Rust `is_stripped` predicate\n// ---------------------------------------------------------------------------\n\n/** Unicode General Category Cc (control characters). */\nfunction isCc(ch: string): boolean {\n // \\p{Cc} = general category \"Control\" (C0 + C1 blocks: U+0000–U+001F, U+007F–U+009F)\n return /^\\p{Cc}$/u.test(ch);\n}\n\n/**\n * Returns true when the character should be stripped (maps to a dash\n * separator in the output). Mirrors Rust's `is_stripped`:\n * - Unicode Cc control characters\n * - Explicit ASCII punctuation set: `! \" # $ % & ' ( ) * + , . / : ; < = > ? @ [ \\ ] ^ ` { | } ~`\n */\nfunction isStripped(ch: string): boolean {\n if (isCc(ch)) return true;\n return (\n ch === \"!\" ||\n ch === '\"' ||\n ch === \"#\" ||\n ch === \"$\" ||\n ch === \"%\" ||\n ch === \"&\" ||\n ch === \"'\" ||\n ch === \"(\" ||\n ch === \")\" ||\n ch === \"*\" ||\n ch === \"+\" ||\n ch === \",\" ||\n ch === \".\" ||\n ch === \"/\" ||\n ch === \":\" ||\n ch === \";\" ||\n ch === \"<\" ||\n ch === \"=\" ||\n ch === \">\" ||\n ch === \"?\" ||\n ch === \"@\" ||\n ch === \"[\" ||\n ch === \"\\\\\" ||\n ch === \"]\" ||\n ch === \"^\" ||\n ch === \"`\" ||\n ch === \"{\" ||\n ch === \"|\" ||\n ch === \"}\" ||\n ch === \"~\"\n );\n}\n\n/**\n * Returns true when `ch` is a Unicode whitespace character.\n *\n * Mirrors Rust `char::is_whitespace` which is `\\p{White_Space}/u` — NOT\n * the JS `\\s` class (`\\s` wrongly matches U+FEFF BYTE ORDER MARK and\n * misses U+0085 NEXT LINE).\n */\nfunction isWhitespace(ch: string): boolean {\n return /^\\p{White_Space}$/u.test(ch);\n}\n\n// ---------------------------------------------------------------------------\n// slugify\n// ---------------------------------------------------------------------------\n\n/**\n * Produce a heading-anchor slug from `input`, matching the Rust\n * `slugify()` in `crates/zfb-content/src/plugins/heading_links.rs`.\n *\n * Algorithm (per Unicode code point):\n * - whitespace or stripped punctuation → emit ONE `-` unless the last\n * emitted character was already a `-` (leading separators are skipped\n * because `lastDash` starts `true`).\n * - anything else → push `ch.toLowerCase()` (per-code-point, not\n * whole-string, to avoid Greek final-sigma context collapsing).\n * - finally pop ONE trailing `-` if present.\n *\n * Divergence from npm github-slugger (intentional — parity target is\n * the Rust function, not npm):\n * - `\"a,b\"` → `\"a-b\"` (stripped punctuation emits a dash, not nothing)\n * - `\" --weird-- \"` → `\"--weird--\"` (existing dashes/underscores pass\n * through unchanged)\n */\nexport function slugify(input: string): string {\n let out = \"\";\n let lastDash = true;\n\n for (const ch of input) {\n if (isWhitespace(ch) || isStripped(ch)) {\n if (!lastDash) {\n out += \"-\";\n lastDash = true;\n }\n } else {\n // Per-code-point lowercase — avoids Greek final-sigma context:\n // \"ΦΟΣ\" → \"φοσ\" not \"φος\".\n out += ch.toLowerCase();\n lastDash = false;\n }\n }\n\n if (out.endsWith(\"-\")) {\n out = out.slice(0, -1);\n }\n\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// next_slug\n// ---------------------------------------------------------------------------\n\n/**\n * Allocate the next deduplicated slug for `base` against a per-document\n * counter map.\n *\n * Mirrors Rust `next_slug`: first occurrence returns `base`, second\n * returns `base-1`, third `base-2`, … Empty `base` short-circuits to\n * `\"\"` without mutating the map.\n */\nfunction nextSlug(seen: Map<string, number>, base: string): string {\n if (base === \"\") return \"\";\n const count = seen.get(base) ?? 0;\n const slug = count === 0 ? base : `${base}-${count}`;\n seen.set(base, count + 1);\n return slug;\n}\n\n// ---------------------------------------------------------------------------\n// SlugAllocator\n// ---------------------------------------------------------------------------\n\n/**\n * Strategy-aware slug allocator for a single document.\n *\n * Mirrors Rust `SlugAllocator` in heading_links.rs:70-118.\n *\n * @param strategy `\"flat\"` (default) — per-document dedup counter, mirrors\n * github-slugger numbering. `\"hierarchical\"` — each slug is prefixed with\n * its ancestor chain and deduped on the full candidate path.\n *\n * Depth contract: callers pass `depth` values 2–6 (h2–h6). h1 is never\n * allocated — it is handled by the page layout, not the markdown body.\n */\nexport class SlugAllocator {\n private readonly strategy: \"flat\" | \"hierarchical\";\n private seen: Map<string, number>;\n /** Hierarchical ancestor stack of `[depth, finalId]` pairs. Unused in flat mode. */\n private stack: Array<[number, string]>;\n\n constructor(strategy: \"flat\" | \"hierarchical\" = \"flat\") {\n this.strategy = strategy;\n this.seen = new Map();\n this.stack = [];\n }\n\n /**\n * Allocate the slug for a heading of `depth` (2–6) whose slugified text\n * is `base`. Returns `\"\"` for an empty `base` without mutating state.\n */\n allocate(depth: number, base: string): string {\n if (this.strategy === \"flat\") {\n return nextSlug(this.seen, base);\n }\n\n // Hierarchical mode\n if (base === \"\") return \"\";\n\n // Pop ancestors whose depth >= this heading's depth\n let top = this.stack.at(-1);\n while (top !== undefined && top[0] >= depth) {\n this.stack.pop();\n top = this.stack.at(-1);\n }\n\n const candidate = top !== undefined ? `${top[1]}-${base}` : base;\n const slug = nextSlug(this.seen, candidate);\n this.stack.push([depth, slug]);\n return slug;\n }\n\n /**\n * Clear all per-document state (dedup counters AND the hierarchical\n * ancestor stack). Call between documents to avoid slug counter leakage.\n */\n reset(): void {\n this.seen.clear();\n this.stack = [];\n }\n}\n"]}
1
+ {"version":3,"file":"slugify.js","sourceRoot":"","sources":["../src/slugify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export { slugify, SlugAllocator } from \"@takazudo/zfb-slugify\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zfb",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Content-site engine on the web's Request/Response model — prerender to static HTML, serve on Cloudflare Workers, or run as a local content server inside your app. One Rust binary. SDK with islands, content collections, pagination, and config helpers.",
@@ -95,12 +95,15 @@
95
95
  "CHANGELOG.md",
96
96
  "LICENSE"
97
97
  ],
98
+ "dependencies": {
99
+ "@takazudo/zfb-slugify": "4.3.0"
100
+ },
98
101
  "optionalDependencies": {
99
- "@takazudo/zfb-darwin-arm64": "4.2.0",
100
- "@takazudo/zfb-darwin-x64": "4.2.0",
101
- "@takazudo/zfb-linux-arm64-gnu": "4.2.0",
102
- "@takazudo/zfb-linux-x64-gnu": "4.2.0",
103
- "@takazudo/zfb-win32-x64-msvc": "4.2.0"
102
+ "@takazudo/zfb-darwin-arm64": "4.3.0",
103
+ "@takazudo/zfb-darwin-x64": "4.3.0",
104
+ "@takazudo/zfb-linux-arm64-gnu": "4.3.0",
105
+ "@takazudo/zfb-linux-x64-gnu": "4.3.0",
106
+ "@takazudo/zfb-win32-x64-msvc": "4.3.0"
104
107
  },
105
108
  "publishConfig": {
106
109
  "access": "public"