/** * -------------------------------------------------------------------- * docmd : the zero-config documentation engine. * * @package @docmd/parser * @website https://docmd.io * @repository https://github.com/docmd-io/docmd * @license MIT * @copyright Copyright (c) 2025-present docmd.io * * [docmd-source] - Please do not remove this header. * -------------------------------------------------------------------- */ /** * Centralised URL Utilities * ========================= * * This module is the **single source of truth** for all URL transformations * in the docmd ecosystem. Every plugin, template, and engine component * MUST use these utilities instead of rolling their own URL logic. * * Architecture: * * User Input (markdown, config) * │ * ▼ * resolveHref() ← normalize-href.ts (user-facing href → clean path) * │ * ▼ * Build Engine ← generator.ts produces outputPath per page * │ * ▼ * URL Utilities ← THIS FILE * │ * ├── outputPathToSlug() → "guide/" * ├── outputPathToCanonical() → "https://site.com/guide/" * ├── buildContextualUrl() → "../de/guide/" (relative, context-aware) * ├── sanitizeUrl() → collapse //, enforce trailing / * └── createUrlContext() → factory for page-level context * * Plugins receive pre-computed URLs via the page object, OR can import * these utilities directly for custom URL generation. */ import { sanitizeUrl } from './normalize-href.js'; export { sanitizeUrl }; /** * Immutable context object that captures all the environmental factors * needed to resolve a URL for a specific page render. * * Created once per page in generator.ts and passed to all templates * and plugin hooks. */ export interface UrlContext { /** Relative path from current page back to site root, e.g. `../../` or `./` */ readonly relativePathToRoot: string; /** Locale + version prefix for the current build pass, e.g. `de/v1/` or `` */ readonly outputPrefix: string; /** Whether we're generating for offline/file:// browsing */ readonly offline: boolean; /** The site base path from config, e.g. `/docs/` or `/` */ readonly base: string; /** The full site URL from config, e.g. `https://docmd.io` (no trailing slash) */ readonly siteUrl: string; } /** * Pre-computed URL data attached to every page object. * Plugins can read these directly - zero computation needed. */ export interface PageUrls { /** Clean directory-style slug, e.g. `guide/` or `/` for root */ readonly slug: string; /** Full canonical URL, e.g. `https://docmd.io/guide/` (only if siteUrl is set) */ readonly canonical: string; /** Relative path from site root, e.g. `/guide/` or `/` */ readonly pathname: string; } /** * Collapse consecutive slashes (except after protocol `:`), enforce * consistent formatting. This is the **last-resort safety net** - if * the upstream logic is correct, this should be a no-op. * * Note: This function is imported from normalize-href.ts to ensure * single source of truth for URL sanitization logic. */ /** * Convert a build-engine outputPath to a clean directory-style slug. * * This is the **single canonical conversion** from the internal file path * representation to a URL path segment. Every consumer that previously * did its own `outputPath.replace('/index.html', '/')` MUST use this. * * @param outputPath - e.g. `guide/index.html`, `index.html`, `de/v1/api/index.html` * @returns Clean slug, e.g. `guide/`, `/`, `de/v1/api/` * * @example * outputPathToSlug('guide/index.html') → 'guide/' * outputPathToSlug('index.html') → '/' * outputPathToSlug('de/v1/api/index.html') → 'de/v1/api/' * outputPathToSlug('about.html') → 'about/' */ export declare function outputPathToSlug(outputPath: string): string; /** * Convert an outputPath to a root-relative pathname (always starts with `/`). * * @param outputPath - e.g. `guide/index.html` * @returns e.g. `/guide/` */ export declare function outputPathToPathname(outputPath: string): string; /** * Convert an outputPath to a full canonical URL. * * @param outputPath - e.g. `guide/index.html` * @param siteUrl - e.g. `https://docmd.io` (no trailing slash) * @returns e.g. `https://docmd.io/guide/` */ export declare function outputPathToCanonical(outputPath: string, siteUrl: string): string; /** * Build a context-aware relative URL from a clean href. * * This replaces ALL inline URL building in EJS templates and the * `buildRelativeUrl` function in generator.ts. It is the single * function that understands relativePathToRoot, outputPrefix, * offline mode, and base path. * * @param href - A clean, normalised href (output of resolveHref), e.g. `guide/`, `#section`, `https://...` * @param context - The UrlContext for the current page * @returns A fully resolved relative URL safe for use in `` * * @example * // Page at /de/v1/getting-started/index.html * buildContextualUrl('guide/', ctx) * // → '../../de/v1/guide/' (relative, with locale+version prefix) * * buildContextualUrl('#section', ctx) * // → '#section' (hash-only, untouched) * * buildContextualUrl('https://github.com', ctx) * // → 'https://github.com' (external, untouched) */ export declare function buildContextualUrl(href: string, context: UrlContext): string; /** * Create a UrlContext for a specific page render. * * Called once per page in generator.ts. The resulting context is then * passed to all templates and can be forwarded to plugin hooks. * * @param options - Configuration for this page's URL context */ export declare function createUrlContext(options: { relativePathToRoot: string; outputPrefix?: string; offline?: boolean; base?: string; siteUrl?: string; }): UrlContext; /** * Compute pre-built URL data for a page. * * Called once per page in generator.ts. The resulting PageUrls object * is attached to the page object and available to all post-build plugins. * * @param outputPath - The page's output path, e.g. `guide/index.html` * @param siteUrl - The site URL from config, e.g. `https://docmd.io` */ export declare function computePageUrls(outputPath: string, siteUrl: string): PageUrls; /** * Build an absolute URL from config.base + optional locale + optional version + page path. * * Used by version-dropdown.ejs and language-switcher.ejs for absolute navigation. * Replaces the inline JS computations in those templates. * * @param base - config.base, e.g. `/docs/` or `/` * @param localePrefix - e.g. `de/` or `` for default locale * @param versionPrefix - e.g. `v1/` or `` for current version * @param pagePath - e.g. `guide/` or `` * @returns Absolute path, e.g. `/docs/de/v1/guide/` */ export declare function buildAbsoluteUrl(base: string, localePrefix?: string, versionPrefix?: string, pagePath?: string): string;