/** * Versioned-docs domain logic. Pure and framework-agnostic: the vite plugin * resolves the author's versions against the docs URL base at build time and * emits the manifest; `DocsShell` and the switcher read it at runtime. * * The current version is served unprefixed at the docs root and is the only one * anyone edits; superseded releases are frozen copies under their own prefix. * See `docs/adr/0001-unprefixed-current-docs.md`. All of it is a no-op when a * site declares no versions. * * **Experimental.** The versioning API sits outside the 1.0 stability promise * and may change in a minor until authors have used it for real. An archive * freezes content, not dependencies — see * `docs/adr/0005-an-archive-freezes-content-not-dependencies.md`. */ import type { DocsContentItem } from './content.js'; /** * One documentation version, declared in the `docsmith()` vite plugin. * * @experimental Outside the 1.0 stability promise. May change in a minor. */ export type DocsVersion = { /** Stable id. Also the URL/directory segment for an archived version. */ id: string; /** Label shown in the switcher and banner, e.g. `'v2'`. */ label: string; /** Keep this version out of search engines. Defaults to `false`. */ noindex?: boolean; }; /** * A site's versions. `current` is the docs for the latest release: it lives at * the docs root, is served unprefixed, and is the folder you edit. `archived` * holds frozen copies of superseded releases, each in `//`, in * the order they should appear in the switcher (newest first). * * Freezes content, not dependencies: prose, samples and URLs stay that * version's, while imports keep resolving to whatever the app has installed. * * @experimental Outside the 1.0 stability promise. May change in a minor until * authors have used versioning for real. */ export type DocsVersions = { current: DocsVersion; archived?: DocsVersion[]; }; /** * A {@link DocsVersion} with the URL fields the runtime needs, computed at build time. * * @experimental Outside the 1.0 stability promise. May change in a minor. */ export type ResolvedVersion = DocsVersion & { /** Absolute URL base: the docs root for `current`, `/docs/` for an archive. */ basePath: string; /** The version's first page in sidebar order, for the switcher's fallback. */ landing: string; /** Whether this is the current version (as opposed to an archived one). */ current: boolean; /** Whether search engines should skip this version. */ noindex: boolean; }; /** * Throw unless `id` is a legal version id. Shared by the vite plugin, which * checks the ids in `docsmith({ versions })`, and by `archive-version`, which * checks the id it is about to turn into a directory. One rule, so an id the * command accepts is one the build accepts. */ export declare function assertValidVersionId(id: unknown): asserts id is string; /** What the docs root actually contains, for {@link checkVersions} to reconcile. */ export type ArchivesOnDisk = { /** Ids of directories carrying the archive marker. */ marked: string[]; /** Names of every directory directly under the docs root. */ directories: string[]; }; /** * Check the declared versions against the docs root, and throw if they disagree. * Called by the vite plugin before {@link resolveVersions}, and by * `archive-version` before it writes. * * Versions are declared by hand in `docsmith()` while archives are directories * on disk, so the config and the tree are two independent claims about which * versions exist. Neither mismatch is visible in the output: an undeclared * archive is merged into the current version and its pages take current-version * URLs, and a section folder wrongly declared as an archive drops out of the * current sidebar entirely. Both are silent corruption of the content index, * which is why this throws rather than warns. * * The marker file is what tells the two apart. A page is assigned to a version * by its first directory segment, so `docs/guides/…` and `docs/v1/…` are the * same shape and no name-based rule can distinguish them. See * `docs/adr/0003-the-archive-marker-defines-an-archive.md`. * * Pure: the caller does the filesystem work and passes the result in. A no-op * for an unversioned site. */ export declare function checkVersions(versions: DocsVersions | undefined, disk: ArchivesOnDisk, markerName: string): void; /** * Resolve author versions against the docs URL base (e.g. `/docs`) and the * collected content: compute each version's `basePath` and its `landing` (first * page in sidebar reading order). Emitted as the `versions` manifest in * `svelte-docsmith/content`, current first, then archives in declared order. * * Returns an empty manifest for an unversioned site, which makes every * downstream scoping, switcher and banner step a no-op. */ export declare function resolveVersions(versions: DocsVersions | undefined, docsBase: string, content: DocsContentItem[]): ResolvedVersion[]; /** * The resolved version owning `pathname`, by longest matching `basePath`. An * archive's base is longer than the current version's, so `/docs/v1/x` picks * `v1` while `/docs/x` falls to the current version. `undefined` off the docs * tree entirely, or on an unversioned site. */ export declare function activeVersion(versions: ResolvedVersion[], pathname: string): ResolvedVersion | undefined; /** The current version: the docs for the latest release. */ export declare function currentVersion(versions: ResolvedVersion[]): ResolvedVersion | undefined; /** * Keep only the current version's pages, for `sitemap.xml` and `llms.txt`, so * search engines and LLMs index one canonical set. A no-op when the site * declares no versions. Works over any record carrying `version`. * * @experimental Outside the 1.0 stability promise. May change in a minor until * authors have used versioning for real. */ export declare function currentOnly(items: T[], versions: ResolvedVersion[]): T[]; /** * Content scoped to one version. With no version id (unversioned site) the * content passes through unchanged, so every caller stays a no-op off the * versioned path. */ export declare function scopeContent(content: DocsContentItem[], versionId: string | undefined): DocsContentItem[]; /** * Map the current page to its equivalent under `to`: swap the version base, and * fall back to the target's landing page when that doc doesn't exist there. * `targetPaths` is the set of the target version's page URLs. */ export declare function mapPathToVersion(pathname: string, from: ResolvedVersion, to: ResolvedVersion, targetPaths: Iterable): string;