@docpensieve/shared 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Valentin Chevoleau
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # @docpensieve/shared
2
+
3
+ > Shared constants, errors and slugs
4
+
5
+ Part of [DocPensieve](https://github.com/Juniors017/docpensieve), a static documentation site generator:
6
+ Markdown and MDX in, static HTML out, one version per orphan branch, JSON-LD
7
+ structured data from the frontmatter.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @docpensieve/shared
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ This package depends on nothing: it is the leaf of DocPensieve's dependency
18
+ graph. Anything two or more packages need lives here.
19
+
20
+ ```js
21
+ import { slugify, filePathToSlug, DocPensieveError } from '@docpensieve/shared';
22
+
23
+ slugify('Crème Brûlée Recipes'); // 'creme-brulee-recipes'
24
+ filePathToSlug('guide/01-install.md'); // 'guide/install'
25
+ ```
26
+
27
+ Accents are stripped from slugs, which keeps URLs readable instead of
28
+ percent-encoded.
29
+
30
+ ## Documentation
31
+
32
+ See the [repository](https://github.com/Juniors017/docpensieve#readme).
33
+
34
+ ## License
35
+
36
+ MIT
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@docpensieve/shared",
3
+ "version": "0.1.0",
4
+ "description": "Utilities, constants and errors shared by the DocPensieve packages",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22.0.0"
9
+ },
10
+ "main": "./src/index.js",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./types/index.d.ts",
14
+ "default": "./src/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "src",
19
+ "types"
20
+ ],
21
+ "keywords": [
22
+ "docpensieve",
23
+ "documentation",
24
+ "slug",
25
+ "utils"
26
+ ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/Juniors017/docpensieve.git",
30
+ "directory": "packages/shared"
31
+ },
32
+ "homepage": "https://github.com/Juniors017/docpensieve#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/Juniors017/docpensieve/issues"
35
+ },
36
+ "author": "Valentin Chevoleau (Juniors017)",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "types": "./types/index.d.ts",
41
+ "scripts": {
42
+ "prepack": "tsc -b tsconfig.build.json"
43
+ }
44
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Constants shared by every DocPensieve package.
3
+ * @module @docpensieve/shared/constants
4
+ */
5
+
6
+ /** File extensions recognised as documentation pages. */
7
+ export const DOC_EXTENSIONS = ['.md', '.mdx'];
8
+
9
+ /** Name of the configuration file at the project root. */
10
+ export const CONFIG_FILENAME = 'docpensieve.config.js';
11
+
12
+ /** Default output directory of a build. */
13
+ export const DEFAULT_OUT_DIR = 'dist';
14
+
15
+ /** Version manifest written by every build. */
16
+ export const VERSIONS_MANIFEST = 'versions.json';
17
+
18
+ /** Page slugs treated as the root of their folder (they take the folder's own URL). */
19
+ export const INDEX_SLUGS = ['index', 'readme'];
20
+
21
+ /** JSON-LD types supported by the `jsonld.type` frontmatter field. */
22
+ export const JSONLD_TYPES = ['Article', 'TechArticle', 'BlogPosting'];
23
+
24
+ /** CSS frameworks known to the ThemeEngine. */
25
+ export const THEME_FRAMEWORKS = ['tailwind', 'custom'];
26
+
27
+ /**
28
+ * Layouts accepted in a page's frontmatter.
29
+ *
30
+ * `doc` is the documentation layout: menu on the left, table of contents on
31
+ * the right, content held to reading width. `home` removes all three, which
32
+ * is what a landing page expects.
33
+ *
34
+ * @type {readonly string[]}
35
+ */
36
+ export const PAGE_LAYOUTS = Object.freeze(['doc', 'home']);
37
+
38
+ /**
39
+ * Class slots of the page shell.
40
+ *
41
+ * Templates hard-code no class: they ask the theme for the class of each
42
+ * slot. A provider only redefines what it wants to change; everything else
43
+ * falls back to these values. That is what lets a single template render
44
+ * either `dp-nav` or a string of Tailwind utilities.
45
+ *
46
+ * This table is shared: `core` reads it in its templates, `theme` extends it
47
+ * in its providers.
48
+ */
49
+ export const DEFAULT_THEME_CLASSES = Object.freeze({
50
+ skip: 'dp-skip',
51
+ header: 'dp-header',
52
+ brand: 'dp-brand',
53
+ versions: 'dp-versions',
54
+ versionsList: 'dp-versions-list',
55
+ shell: 'dp-shell',
56
+ shellWide: 'dp-shell dp-shell--wide',
57
+ sidebar: 'dp-sidebar',
58
+ nav: 'dp-nav',
59
+ navItem: 'dp-nav-item',
60
+ navItemParent: 'dp-nav-item--parent',
61
+ navLink: 'dp-nav-link',
62
+ navLabel: 'dp-nav-label',
63
+ notice: 'dp-notice',
64
+ skillIcon: 'dp-skill-icon',
65
+ main: 'dp-main',
66
+ article: 'dp-article',
67
+ toc: 'dp-toc',
68
+ tocTitle: 'dp-toc-title',
69
+ tocList: 'dp-toc-list',
70
+ tocItem: 'dp-toc-item',
71
+ footer: 'dp-footer',
72
+ scrollTop: 'dp-scroll-top',
73
+ scrollTopIcon: 'dp-scroll-top-icon',
74
+ });
package/src/errors.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * DocPensieve error hierarchy.
3
+ *
4
+ * Every domain error extends `DocPensieveError`: that is how the CLI tells an
5
+ * expected error (a clear message for the user) from a bug (full stack trace).
6
+ *
7
+ * @module @docpensieve/shared/errors
8
+ */
9
+
10
+ /** Expected domain error — the CLI prints it without a stack trace. */
11
+ export class DocPensieveError extends Error {
12
+ /**
13
+ * @param {string} message
14
+ * @param {{ cause?: unknown, hint?: string }} [options] `hint` is printed
15
+ * by the CLI as a suggested fix.
16
+ */
17
+ constructor(message, options = {}) {
18
+ super(message, { cause: options.cause });
19
+ this.name = this.constructor.name;
20
+ this.hint = options.hint;
21
+ }
22
+ }
23
+
24
+ /** Configuration missing, unreadable or invalid. */
25
+ export class ConfigError extends DocPensieveError {}
26
+
27
+ /** A source file could not be read or parsed. */
28
+ export class LoaderError extends DocPensieveError {}
29
+
30
+ /** MDX/Markdown compilation failed. */
31
+ export class CompileError extends DocPensieveError {}
32
+
33
+ /** Invalid `jsonld` frontmatter or inconsistent structured data. */
34
+ export class StructuredDataError extends DocPensieveError {}
35
+
36
+ /** Theme provider missing, invalid, or whose compilation failed. */
37
+ export class ThemeError extends DocPensieveError {}
38
+
39
+ /** The site could not be generated or written. */
40
+ export class GeneratorError extends DocPensieveError {}
41
+
42
+ /** Milestone not implemented yet — points to the roadmap section. */
43
+ export class NotImplementedError extends DocPensieveError {
44
+ /**
45
+ * @param {string} what What is not implemented.
46
+ * @param {string} roadmapSection E.g. `'1.1 DocLoader'`.
47
+ */
48
+ constructor(what, roadmapSection) {
49
+ super(`${what} is not available yet.`, {
50
+ hint: `Planned in section ${roadmapSection} of the roadmap.`,
51
+ });
52
+ this.roadmapSection = roadmapSection;
53
+ }
54
+ }
package/src/index.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @docpensieve/shared — shared utilities, constants and errors.
3
+ *
4
+ * This package depends on no other DocPensieve package: it is the leaf of the
5
+ * dependency graph. Anything useful to two packages or more lives here.
6
+ *
7
+ * @module @docpensieve/shared
8
+ */
9
+
10
+ export * from './constants.js';
11
+ export * from './errors.js';
12
+ export * from './slug.js';
package/src/slug.js ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Slug and URL generation from file paths.
3
+ * @module @docpensieve/shared/slug
4
+ */
5
+
6
+ import { INDEX_SLUGS } from './constants.js';
7
+
8
+ /** Numeric ordering prefix: `01-`, `02_`, `10.` */
9
+ const ORDER_PREFIX = /^\d+[-_.]/;
10
+
11
+ /**
12
+ * Turns free text into a URL-safe slug.
13
+ *
14
+ * Accents are decomposed then dropped (`Crème` → `creme`), which keeps URLs
15
+ * readable instead of percent-encoded.
16
+ *
17
+ * @param {string} input
18
+ * @returns {string} Lowercase slug, dash-separated.
19
+ */
20
+ export function slugify(input) {
21
+ return String(input)
22
+ .normalize('NFD')
23
+ .replace(/[\u0300-\u036f]/g, '')
24
+ .replace(/['’]/g, '')
25
+ .toLowerCase()
26
+ .replace(/[^a-z0-9]+/g, '-')
27
+ .replace(/^-+|-+$/g, '');
28
+ }
29
+
30
+ /**
31
+ * Converts a file path, relative to the version folder, into a page slug.
32
+ *
33
+ * Ordering prefixes are removed from every segment: they sort the sidebar,
34
+ * they do not build the URL.
35
+ *
36
+ * @example
37
+ * filePathToSlug('guide/01-install.md') // 'guide/install'
38
+ * filePathToSlug('intro.mdx') // 'intro'
39
+ * filePathToSlug('guide/index.md') // 'guide'
40
+ * filePathToSlug('index.md') // ''
41
+ *
42
+ * @param {string} relativePath Path relative to the version folder.
43
+ * @returns {string} Slug with no leading or trailing slash.
44
+ */
45
+ export function filePathToSlug(relativePath) {
46
+ const withoutExt = String(relativePath).replace(/\.mdx?$/i, '');
47
+ const segments = withoutExt
48
+ .split(/[/\\]/)
49
+ .filter(Boolean)
50
+ .map((segment) => slugify(segment.replace(ORDER_PREFIX, '')));
51
+
52
+ const last = segments.at(-1);
53
+ if (last !== undefined && INDEX_SLUGS.includes(last)) {
54
+ segments.pop();
55
+ }
56
+
57
+ return segments.filter(Boolean).join('/');
58
+ }
59
+
60
+ /**
61
+ * Maps an asset path into URL space.
62
+ *
63
+ * Folders follow the page rule — ordering prefix removed, segment slugified —
64
+ * so that `02-guide/diagram.png` lands under `/guide/`, where the pages of the
65
+ * same folder expect it. Otherwise the sorting prefix, which never shows in a
66
+ * page URL, would show in the URL of its images.
67
+ *
68
+ * The file name itself stays untouched: it is the one the author writes in
69
+ * their Markdown, and rewriting it would break the reference.
70
+ *
71
+ * @example
72
+ * assetPathToSlug('02-guide/diagram.png') // 'guide/diagram.png'
73
+ * assetPathToSlug('My Notes/a.png') // 'my-notes/a.png'
74
+ *
75
+ * @param {string} relativePath Path relative to the version folder.
76
+ * @returns {string} Output path, slash-separated.
77
+ */
78
+ export function assetPathToSlug(relativePath) {
79
+ const segments = String(relativePath).split(/[/\\]/).filter(Boolean);
80
+
81
+ const file = segments.pop();
82
+ const folders = segments.map((segment) => slugify(segment.replace(ORDER_PREFIX, '')));
83
+
84
+ return [...folders, file].filter(Boolean).join('/');
85
+ }
86
+
87
+ /**
88
+ * Segments of a path that leave nothing behind once slugified.
89
+ *
90
+ * `slugify` only keeps Latin letters and digits: a name made entirely of
91
+ * ideograms, or of punctuation, vanishes. For a page, that meant taking the
92
+ * home page's URL; for a folder, disappearing from the address.
93
+ *
94
+ * @example
95
+ * blankSegments('guide/日本語.md') // ['日本語']
96
+ * blankSegments('02-guide/page.md') // []
97
+ *
98
+ * @param {string} relativePath Path relative to the version folder.
99
+ * @returns {string[]} The offending segments, extension removed.
100
+ */
101
+ export function blankSegments(relativePath) {
102
+ return String(relativePath)
103
+ .replace(/\.mdx?$/i, '')
104
+ .split(/[/\\]/)
105
+ .filter(Boolean)
106
+ .filter((segment) => slugify(segment.replace(ORDER_PREFIX, '')) === '');
107
+ }
108
+
109
+ /**
110
+ * Maps a **folder** path into URL space.
111
+ *
112
+ * Sibling of `assetPathToSlug`, but with no file name to spare: every segment
113
+ * goes through the page rule. Applying `assetPathToSlug` to a folder left its
114
+ * last segment untouched — `02-guide` stayed `02-guide` — and every relative
115
+ * target of a page in that folder missed the file actually copied.
116
+ *
117
+ * @example
118
+ * dirPathToSlug('02-guide/03-sub') // 'guide/sub'
119
+ * dirPathToSlug('My Notes') // 'my-notes'
120
+ * dirPathToSlug('') // ''
121
+ *
122
+ * @param {string} relativePath Path relative to the version folder.
123
+ * @returns {string} Output path, slash-separated.
124
+ */
125
+ export function dirPathToSlug(relativePath) {
126
+ return String(relativePath)
127
+ .split(/[/\\]/)
128
+ .filter(Boolean)
129
+ .map((segment) => slugify(segment.replace(ORDER_PREFIX, '')))
130
+ .filter(Boolean)
131
+ .join('/');
132
+ }
133
+
134
+ /**
135
+ * Converts a page slug into an absolute site URL (trailing slash included).
136
+ *
137
+ * @example
138
+ * slugToUrl('guide/install') // '/guide/install/'
139
+ * slugToUrl('') // '/'
140
+ * slugToUrl('intro', 'v1.0') // '/versions/v1.0/intro/'
141
+ *
142
+ * @param {string} slug Slug produced by {@link filePathToSlug}.
143
+ * @param {string} [versionSlug] When given, prefixes `/versions/<version>`.
144
+ * @returns {string} URL starting and ending with `/`.
145
+ */
146
+ export function slugToUrl(slug, versionSlug) {
147
+ const parts = [];
148
+ if (versionSlug) parts.push('versions', versionSlug);
149
+ if (slug) parts.push(...slug.split('/').filter(Boolean));
150
+ return parts.length ? `/${parts.join('/')}/` : '/';
151
+ }
152
+
153
+ /**
154
+ * Turns a slug segment back into a readable label.
155
+ *
156
+ * A deliberate, imperfect fallback: since `slugify` dropped the accents,
157
+ * `creme-brulee` comes back as “Creme brulee”. Only use it when there is no
158
+ * real title — the sidebar and the breadcrumb prefer the frontmatter title.
159
+ *
160
+ * @example
161
+ * humanizeSlug('getting-started') // 'Getting started'
162
+ *
163
+ * @param {string} segment
164
+ * @returns {string}
165
+ */
166
+ export function humanizeSlug(segment) {
167
+ const words = String(segment).replace(/[-_]+/g, ' ').trim();
168
+ return words.charAt(0).toUpperCase() + words.slice(1);
169
+ }
170
+
171
+ /**
172
+ * Reads the ordering weight of a prefixed file name.
173
+ *
174
+ * @example
175
+ * orderOf('01-install.md') // 1
176
+ * orderOf('install.md') // Infinity
177
+ *
178
+ * @param {string} filename
179
+ * @returns {number} The prefix number, or `Infinity` when absent (sorted last).
180
+ */
181
+ export function orderOf(filename) {
182
+ const match = String(filename).match(/^(\d+)[-_.]/);
183
+ return match ? Number(match[1]) : Infinity;
184
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Constants shared by every DocPensieve package.
3
+ * @module @docpensieve/shared/constants
4
+ */
5
+ /** File extensions recognised as documentation pages. */
6
+ export declare const DOC_EXTENSIONS: string[];
7
+ /** Name of the configuration file at the project root. */
8
+ export declare const CONFIG_FILENAME = "docpensieve.config.js";
9
+ /** Default output directory of a build. */
10
+ export declare const DEFAULT_OUT_DIR = "dist";
11
+ /** Version manifest written by every build. */
12
+ export declare const VERSIONS_MANIFEST = "versions.json";
13
+ /** Page slugs treated as the root of their folder (they take the folder's own URL). */
14
+ export declare const INDEX_SLUGS: string[];
15
+ /** JSON-LD types supported by the `jsonld.type` frontmatter field. */
16
+ export declare const JSONLD_TYPES: string[];
17
+ /** CSS frameworks known to the ThemeEngine. */
18
+ export declare const THEME_FRAMEWORKS: string[];
19
+ /**
20
+ * Layouts accepted in a page's frontmatter.
21
+ *
22
+ * `doc` is the documentation layout: menu on the left, table of contents on
23
+ * the right, content held to reading width. `home` removes all three, which
24
+ * is what a landing page expects.
25
+ *
26
+ * @type {readonly string[]}
27
+ */
28
+ export declare const PAGE_LAYOUTS: readonly string[];
29
+ /**
30
+ * Class slots of the page shell.
31
+ *
32
+ * Templates hard-code no class: they ask the theme for the class of each
33
+ * slot. A provider only redefines what it wants to change; everything else
34
+ * falls back to these values. That is what lets a single template render
35
+ * either `dp-nav` or a string of Tailwind utilities.
36
+ *
37
+ * This table is shared: `core` reads it in its templates, `theme` extends it
38
+ * in its providers.
39
+ */
40
+ export declare const DEFAULT_THEME_CLASSES: Readonly<{
41
+ skip: "dp-skip";
42
+ header: "dp-header";
43
+ brand: "dp-brand";
44
+ versions: "dp-versions";
45
+ versionsList: "dp-versions-list";
46
+ shell: "dp-shell";
47
+ shellWide: "dp-shell dp-shell--wide";
48
+ sidebar: "dp-sidebar";
49
+ nav: "dp-nav";
50
+ navItem: "dp-nav-item";
51
+ navItemParent: "dp-nav-item--parent";
52
+ navLink: "dp-nav-link";
53
+ navLabel: "dp-nav-label";
54
+ notice: "dp-notice";
55
+ skillIcon: "dp-skill-icon";
56
+ main: "dp-main";
57
+ article: "dp-article";
58
+ toc: "dp-toc";
59
+ tocTitle: "dp-toc-title";
60
+ tocList: "dp-toc-list";
61
+ tocItem: "dp-toc-item";
62
+ footer: "dp-footer";
63
+ scrollTop: "dp-scroll-top";
64
+ scrollTopIcon: "dp-scroll-top-icon";
65
+ }>;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * DocPensieve error hierarchy.
3
+ *
4
+ * Every domain error extends `DocPensieveError`: that is how the CLI tells an
5
+ * expected error (a clear message for the user) from a bug (full stack trace).
6
+ *
7
+ * @module @docpensieve/shared/errors
8
+ */
9
+ /** Expected domain error — the CLI prints it without a stack trace. */
10
+ export declare class DocPensieveError extends Error {
11
+ hint: string | undefined;
12
+ /**
13
+ * @param {string} message
14
+ * @param {{ cause?: unknown, hint?: string }} [options] `hint` is printed
15
+ * by the CLI as a suggested fix.
16
+ */
17
+ constructor(message: string, options?: {
18
+ cause?: unknown;
19
+ hint?: string;
20
+ });
21
+ }
22
+ /** Configuration missing, unreadable or invalid. */
23
+ export declare class ConfigError extends DocPensieveError {
24
+ }
25
+ /** A source file could not be read or parsed. */
26
+ export declare class LoaderError extends DocPensieveError {
27
+ }
28
+ /** MDX/Markdown compilation failed. */
29
+ export declare class CompileError extends DocPensieveError {
30
+ }
31
+ /** Invalid `jsonld` frontmatter or inconsistent structured data. */
32
+ export declare class StructuredDataError extends DocPensieveError {
33
+ }
34
+ /** Theme provider missing, invalid, or whose compilation failed. */
35
+ export declare class ThemeError extends DocPensieveError {
36
+ }
37
+ /** The site could not be generated or written. */
38
+ export declare class GeneratorError extends DocPensieveError {
39
+ }
40
+ /** Milestone not implemented yet — points to the roadmap section. */
41
+ export declare class NotImplementedError extends DocPensieveError {
42
+ roadmapSection: string;
43
+ /**
44
+ * @param {string} what What is not implemented.
45
+ * @param {string} roadmapSection E.g. `'1.1 DocLoader'`.
46
+ */
47
+ constructor(what: string, roadmapSection: string);
48
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @docpensieve/shared — shared utilities, constants and errors.
3
+ *
4
+ * This package depends on no other DocPensieve package: it is the leaf of the
5
+ * dependency graph. Anything useful to two packages or more lives here.
6
+ *
7
+ * @module @docpensieve/shared
8
+ */
9
+ export * from './constants.js';
10
+ export * from './errors.js';
11
+ export * from './slug.js';
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Slug and URL generation from file paths.
3
+ * @module @docpensieve/shared/slug
4
+ */
5
+ /**
6
+ * Turns free text into a URL-safe slug.
7
+ *
8
+ * Accents are decomposed then dropped (`Crème` → `creme`), which keeps URLs
9
+ * readable instead of percent-encoded.
10
+ *
11
+ * @param {string} input
12
+ * @returns {string} Lowercase slug, dash-separated.
13
+ */
14
+ export declare function slugify(input: string): string;
15
+ /**
16
+ * Converts a file path, relative to the version folder, into a page slug.
17
+ *
18
+ * Ordering prefixes are removed from every segment: they sort the sidebar,
19
+ * they do not build the URL.
20
+ *
21
+ * @example
22
+ * filePathToSlug('guide/01-install.md') // 'guide/install'
23
+ * filePathToSlug('intro.mdx') // 'intro'
24
+ * filePathToSlug('guide/index.md') // 'guide'
25
+ * filePathToSlug('index.md') // ''
26
+ *
27
+ * @param {string} relativePath Path relative to the version folder.
28
+ * @returns {string} Slug with no leading or trailing slash.
29
+ */
30
+ export declare function filePathToSlug(relativePath: string): string;
31
+ /**
32
+ * Maps an asset path into URL space.
33
+ *
34
+ * Folders follow the page rule — ordering prefix removed, segment slugified —
35
+ * so that `02-guide/diagram.png` lands under `/guide/`, where the pages of the
36
+ * same folder expect it. Otherwise the sorting prefix, which never shows in a
37
+ * page URL, would show in the URL of its images.
38
+ *
39
+ * The file name itself stays untouched: it is the one the author writes in
40
+ * their Markdown, and rewriting it would break the reference.
41
+ *
42
+ * @example
43
+ * assetPathToSlug('02-guide/diagram.png') // 'guide/diagram.png'
44
+ * assetPathToSlug('My Notes/a.png') // 'my-notes/a.png'
45
+ *
46
+ * @param {string} relativePath Path relative to the version folder.
47
+ * @returns {string} Output path, slash-separated.
48
+ */
49
+ export declare function assetPathToSlug(relativePath: string): string;
50
+ /**
51
+ * Segments of a path that leave nothing behind once slugified.
52
+ *
53
+ * `slugify` only keeps Latin letters and digits: a name made entirely of
54
+ * ideograms, or of punctuation, vanishes. For a page, that meant taking the
55
+ * home page's URL; for a folder, disappearing from the address.
56
+ *
57
+ * @example
58
+ * blankSegments('guide/日本語.md') // ['日本語']
59
+ * blankSegments('02-guide/page.md') // []
60
+ *
61
+ * @param {string} relativePath Path relative to the version folder.
62
+ * @returns {string[]} The offending segments, extension removed.
63
+ */
64
+ export declare function blankSegments(relativePath: string): string[];
65
+ /**
66
+ * Maps a **folder** path into URL space.
67
+ *
68
+ * Sibling of `assetPathToSlug`, but with no file name to spare: every segment
69
+ * goes through the page rule. Applying `assetPathToSlug` to a folder left its
70
+ * last segment untouched — `02-guide` stayed `02-guide` — and every relative
71
+ * target of a page in that folder missed the file actually copied.
72
+ *
73
+ * @example
74
+ * dirPathToSlug('02-guide/03-sub') // 'guide/sub'
75
+ * dirPathToSlug('My Notes') // 'my-notes'
76
+ * dirPathToSlug('') // ''
77
+ *
78
+ * @param {string} relativePath Path relative to the version folder.
79
+ * @returns {string} Output path, slash-separated.
80
+ */
81
+ export declare function dirPathToSlug(relativePath: string): string;
82
+ /**
83
+ * Converts a page slug into an absolute site URL (trailing slash included).
84
+ *
85
+ * @example
86
+ * slugToUrl('guide/install') // '/guide/install/'
87
+ * slugToUrl('') // '/'
88
+ * slugToUrl('intro', 'v1.0') // '/versions/v1.0/intro/'
89
+ *
90
+ * @param {string} slug Slug produced by {@link filePathToSlug}.
91
+ * @param {string} [versionSlug] When given, prefixes `/versions/<version>`.
92
+ * @returns {string} URL starting and ending with `/`.
93
+ */
94
+ export declare function slugToUrl(slug: string, versionSlug?: string): string;
95
+ /**
96
+ * Turns a slug segment back into a readable label.
97
+ *
98
+ * A deliberate, imperfect fallback: since `slugify` dropped the accents,
99
+ * `creme-brulee` comes back as “Creme brulee”. Only use it when there is no
100
+ * real title — the sidebar and the breadcrumb prefer the frontmatter title.
101
+ *
102
+ * @example
103
+ * humanizeSlug('getting-started') // 'Getting started'
104
+ *
105
+ * @param {string} segment
106
+ * @returns {string}
107
+ */
108
+ export declare function humanizeSlug(segment: string): string;
109
+ /**
110
+ * Reads the ordering weight of a prefixed file name.
111
+ *
112
+ * @example
113
+ * orderOf('01-install.md') // 1
114
+ * orderOf('install.md') // Infinity
115
+ *
116
+ * @param {string} filename
117
+ * @returns {number} The prefix number, or `Infinity` when absent (sorted last).
118
+ */
119
+ export declare function orderOf(filename: string): number;