/**
* 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;
}