/** * Heading-anchor slug utilities — a pure-TypeScript port of the Rust * `slugify` / `next_slug` / `SlugAllocator` in * `crates/zfb-content/src/plugins/heading_links.rs`. * * These functions produce the `id` attribute values that appear on * `

`–`

` elements in the rendered HTML. They are intentionally * **not** compatible with npm `github-slugger`: stripped punctuation * collapses to a `-` separator (`"a,b"` → `"a-b"`), and leading/trailing * whitespace / stripped chars emit nothing rather than a stray dash. * * ⚠️ These functions produce heading-anchor slugs (e.g. `"hello-world"` * for `

`). They are **different** from * `_relPathToSlug` in `content.ts`, which converts a file-system relative * path into a URL slug for `CollectionEntry.slug`. * * Parity is enforced by the shared fixture at * `crates/zfb-content/tests/fixtures/slugify-parity.json`, consumed by * both a Rust integration test and the `slugify.test.ts` vitest suite. */ /** * Produce a heading-anchor slug from `input`, matching the Rust * `slugify()` in `crates/zfb-content/src/plugins/heading_links.rs`. * * Algorithm (per Unicode code point): * - whitespace or stripped punctuation → emit ONE `-` unless the last * emitted character was already a `-` (leading separators are skipped * because `lastDash` starts `true`). * - anything else → push `ch.toLowerCase()` (per-code-point, not * whole-string, to avoid Greek final-sigma context collapsing). * - finally pop ONE trailing `-` if present. * * Divergence from npm github-slugger (intentional — parity target is * the Rust function, not npm): * - `"a,b"` → `"a-b"` (stripped punctuation emits a dash, not nothing) * - `" --weird-- "` → `"--weird--"` (existing dashes/underscores pass * through unchanged) */ export declare function slugify(input: string): string; /** * Strategy-aware slug allocator for a single document. * * Mirrors Rust `SlugAllocator` in heading_links.rs:70-118. * * @param strategy `"flat"` (default) — per-document dedup counter, mirrors * github-slugger numbering. `"hierarchical"` — each slug is prefixed with * its ancestor chain and deduped on the full candidate path. * * Depth contract: callers pass `depth` values 2–6 (h2–h6). h1 is never * allocated — it is handled by the page layout, not the markdown body. */ export declare class SlugAllocator { private readonly strategy; private seen; /** Hierarchical ancestor stack of `[depth, finalId]` pairs. Unused in flat mode. */ private stack; constructor(strategy?: "flat" | "hierarchical"); /** * Allocate the slug for a heading of `depth` (2–6) whose slugified text * is `base`. Returns `""` for an empty `base` without mutating state. */ allocate(depth: number, base: string): string; /** * Clear all per-document state (dedup counters AND the hierarchical * ancestor stack). Call between documents to avoid slug counter leakage. */ reset(): void; }