@docpensieve/core 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 +21 -0
- package/README.md +38 -0
- package/package.json +58 -0
- package/src/compiler.js +415 -0
- package/src/config.js +265 -0
- package/src/generator.js +517 -0
- package/src/index.js +35 -0
- package/src/loader.js +260 -0
- package/src/sidebar.js +105 -0
- package/src/structured-data.js +334 -0
- package/templates/layout.hbs +94 -0
- package/templates/nav-items.hbs +14 -0
- package/templates/toc-items.hbs +10 -0
- package/types/compiler.d.ts +108 -0
- package/types/config.d.ts +149 -0
- package/types/generator.d.ts +82 -0
- package/types/index.d.ts +34 -0
- package/types/loader.d.ts +66 -0
- package/types/sidebar.d.ts +60 -0
- package/types/structured-data.d.ts +51 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="{{lang}}"{{#if darkModeClass}} class="{{darkModeClass}}"{{/if}}>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
{{#if description}}
|
|
8
|
+
<meta name="description" content="{{description}}" />
|
|
9
|
+
{{/if}}
|
|
10
|
+
{{#if noindex}}
|
|
11
|
+
<meta name="robots" content="noindex, follow" />
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{#if canonical}}
|
|
14
|
+
<link rel="canonical" href="{{canonical}}" />
|
|
15
|
+
{{/if}}
|
|
16
|
+
{{#each preloads}}
|
|
17
|
+
<link rel="preload" as="{{as}}" href="{{href}}" />
|
|
18
|
+
{{/each}}
|
|
19
|
+
<link rel="stylesheet" href="{{cssHref}}" />
|
|
20
|
+
{{{jsonld}}}
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<a class="{{{cls.skip}}}" href="#content">Skip to content</a>
|
|
24
|
+
|
|
25
|
+
{{!-- Target of the back-to-top link: bring the focus back, not only the view. --}}
|
|
26
|
+
<header class="{{{cls.header}}}" id="top" tabindex="-1">
|
|
27
|
+
<a class="{{{cls.brand}}}" href="{{homeUrl}}">{{projectName}}</a>
|
|
28
|
+
{{#if showVersions}}
|
|
29
|
+
<details class="{{{cls.versions}}}">
|
|
30
|
+
{{!-- The accessible name contains the visible label: when dictated by
|
|
31
|
+
voice, what is read on screen must find this button. --}}
|
|
32
|
+
<summary aria-label="Version {{versionName}}, switch version">{{versionName}}</summary>
|
|
33
|
+
<ul class="{{{cls.versionsList}}}">
|
|
34
|
+
{{#each versions}}
|
|
35
|
+
<li><a href="{{url}}"{{#if current}} aria-current="true"{{/if}}>{{name}}</a></li>
|
|
36
|
+
{{/each}}
|
|
37
|
+
</ul>
|
|
38
|
+
</details>
|
|
39
|
+
{{/if}}
|
|
40
|
+
</header>
|
|
41
|
+
|
|
42
|
+
<div class="{{#if wide}}{{{cls.shellWide}}}{{else}}{{{cls.shell}}}{{/if}}">
|
|
43
|
+
{{#if sidebar.length}}
|
|
44
|
+
<nav class="{{{cls.sidebar}}}" aria-label="Documentation navigation">
|
|
45
|
+
{{> navItems sidebar}}
|
|
46
|
+
</nav>
|
|
47
|
+
{{/if}}
|
|
48
|
+
|
|
49
|
+
<main class="{{{cls.main}}}" id="content" tabindex="-1">
|
|
50
|
+
{{#if notice}}
|
|
51
|
+
<aside class="{{{cls.notice}}}" role="note">
|
|
52
|
+
{{#if notice.prerelease}}
|
|
53
|
+
This version is in preparation and may change.
|
|
54
|
+
{{else}}
|
|
55
|
+
This version is no longer maintained.
|
|
56
|
+
{{/if}}
|
|
57
|
+
The current version is <a href="{{notice.url}}">{{notice.name}}</a>.
|
|
58
|
+
</aside>
|
|
59
|
+
{{/if}}
|
|
60
|
+
<article class="{{{cls.article}}}">{{{content}}}</article>
|
|
61
|
+
</main>
|
|
62
|
+
|
|
63
|
+
{{#if toc.length}}
|
|
64
|
+
<nav class="{{{cls.toc}}}" aria-label="On this page">
|
|
65
|
+
<p class="{{{cls.tocTitle}}}">On this page</p>
|
|
66
|
+
{{> tocItems toc}}
|
|
67
|
+
</nav>
|
|
68
|
+
{{/if}}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<footer class="{{{cls.footer}}}">
|
|
72
|
+
<p>{{projectName}} — version {{versionName}}</p>
|
|
73
|
+
</footer>
|
|
74
|
+
|
|
75
|
+
{{#if scrollToTop}}
|
|
76
|
+
<a class="{{{cls.scrollTop}}}" href="#top" aria-label="Back to top">
|
|
77
|
+
<svg
|
|
78
|
+
class="{{{cls.scrollTopIcon}}}"
|
|
79
|
+
viewBox="0 0 24 24"
|
|
80
|
+
fill="none"
|
|
81
|
+
stroke="currentColor"
|
|
82
|
+
stroke-width="2"
|
|
83
|
+
stroke-linecap="round"
|
|
84
|
+
stroke-linejoin="round"
|
|
85
|
+
aria-hidden="true"
|
|
86
|
+
focusable="false"
|
|
87
|
+
>
|
|
88
|
+
<path d="M12 19V5" />
|
|
89
|
+
<path d="m5 12 7-7 7 7" />
|
|
90
|
+
</svg>
|
|
91
|
+
</a>
|
|
92
|
+
{{/if}}
|
|
93
|
+
</body>
|
|
94
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<ul class="{{{@root.cls.nav}}}">
|
|
2
|
+
{{#each this}}
|
|
3
|
+
<li class="{{{@root.cls.navItem}}}{{#if items.length}} {{{@root.cls.navItemParent}}}{{/if}}">
|
|
4
|
+
{{#if url}}
|
|
5
|
+
<a class="{{{@root.cls.navLink}}}" href="{{url}}"{{#if (eq url @root.currentUrl)}} aria-current="page"{{/if}}>{{label}}</a>
|
|
6
|
+
{{else}}
|
|
7
|
+
<span class="{{{@root.cls.navLabel}}}">{{label}}</span>
|
|
8
|
+
{{/if}}
|
|
9
|
+
{{#if items.length}}
|
|
10
|
+
{{> navItems items}}
|
|
11
|
+
{{/if}}
|
|
12
|
+
</li>
|
|
13
|
+
{{/each}}
|
|
14
|
+
</ul>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiles Markdown/MDX content into static HTML.
|
|
3
|
+
*
|
|
4
|
+
* Chosen pipeline: `.md` and `.mdx` both go through @mdx-js/mdx, then the
|
|
5
|
+
* resulting component is rendered by `react-dom/server`. React only serves
|
|
6
|
+
* the build; the HTML produced contains no React runtime.
|
|
7
|
+
*
|
|
8
|
+
* @module @docpensieve/core/compiler
|
|
9
|
+
*/
|
|
10
|
+
export type TocEntry = {
|
|
11
|
+
/**
|
|
12
|
+
* Heading anchor (`'installation'`).
|
|
13
|
+
*/
|
|
14
|
+
id: string;
|
|
15
|
+
/**
|
|
16
|
+
* Heading text, tags removed.
|
|
17
|
+
*/
|
|
18
|
+
text: string;
|
|
19
|
+
/**
|
|
20
|
+
* Heading level (2 for `h2`).
|
|
21
|
+
*/
|
|
22
|
+
depth: number;
|
|
23
|
+
/**
|
|
24
|
+
* Nested sub-headings.
|
|
25
|
+
*/
|
|
26
|
+
children: TocEntry[];
|
|
27
|
+
};
|
|
28
|
+
export type Preload = {
|
|
29
|
+
/**
|
|
30
|
+
* Resource to preload.
|
|
31
|
+
*/
|
|
32
|
+
href: string;
|
|
33
|
+
/**
|
|
34
|
+
* Resource type (`'image'`).
|
|
35
|
+
*/
|
|
36
|
+
as: string;
|
|
37
|
+
};
|
|
38
|
+
export type CompileResult = {
|
|
39
|
+
/**
|
|
40
|
+
* HTML fragment of the content alone.
|
|
41
|
+
*/
|
|
42
|
+
html: string;
|
|
43
|
+
/**
|
|
44
|
+
* Nested table of contents.
|
|
45
|
+
*/
|
|
46
|
+
toc: TocEntry[];
|
|
47
|
+
/**
|
|
48
|
+
* Resources to preload, meant for the `<head>`.
|
|
49
|
+
*/
|
|
50
|
+
preloads: Preload[];
|
|
51
|
+
};
|
|
52
|
+
/** Compiles an MDX/Markdown source into an HTML fragment. */
|
|
53
|
+
export declare class Compiler {
|
|
54
|
+
#private;
|
|
55
|
+
options: {
|
|
56
|
+
components?: Record<string, Function>;
|
|
57
|
+
remarkPlugins?: any[];
|
|
58
|
+
rehypePlugins?: any[];
|
|
59
|
+
highlight?: false | Record<string, any>;
|
|
60
|
+
tocDepth?: [number, number];
|
|
61
|
+
};
|
|
62
|
+
components: Record<string, Function>;
|
|
63
|
+
remarkPlugins: any[];
|
|
64
|
+
rehypePlugins: any[];
|
|
65
|
+
highlight: false | Record<string, any> | {
|
|
66
|
+
themes: {
|
|
67
|
+
light: string;
|
|
68
|
+
dark: string;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
tocDepth: number[];
|
|
72
|
+
/**
|
|
73
|
+
* @param {{
|
|
74
|
+
* components?: Record<string, Function>,
|
|
75
|
+
* remarkPlugins?: any[],
|
|
76
|
+
* rehypePlugins?: any[],
|
|
77
|
+
* highlight?: false | Record<string, any>,
|
|
78
|
+
* tocDepth?: [number, number],
|
|
79
|
+
* }} [options]
|
|
80
|
+
* `components` is the table of global components injected into MDX: it is
|
|
81
|
+
* what lets a page write `<Card>` without an import. `highlight` takes the
|
|
82
|
+
* @shikijs/rehype options, or `false` to turn highlighting off. `tocDepth`
|
|
83
|
+
* bounds the headings kept in the table of contents.
|
|
84
|
+
*/
|
|
85
|
+
constructor(options?: {
|
|
86
|
+
components?: Record<string, Function>;
|
|
87
|
+
remarkPlugins?: any[];
|
|
88
|
+
rehypePlugins?: any[];
|
|
89
|
+
highlight?: false | Record<string, any>;
|
|
90
|
+
tocDepth?: [number, number];
|
|
91
|
+
});
|
|
92
|
+
/**
|
|
93
|
+
* Compiles a source into an HTML fragment and a table of contents.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} source Markdown/MDX content, frontmatter already removed.
|
|
96
|
+
* @param {{ filepath?: string, url?: string, dirUrl?: string, basePath?: string }} [context]
|
|
97
|
+
* `filepath` locates errors, `dirUrl` is the base of relative targets and
|
|
98
|
+
* `basePath` prefixes absolute targets (the version root).
|
|
99
|
+
* @returns {Promise<CompileResult>}
|
|
100
|
+
* @throws {CompileError} Invalid syntax, or a component unknown at use.
|
|
101
|
+
*/
|
|
102
|
+
compile(source: string, context?: {
|
|
103
|
+
filepath?: string;
|
|
104
|
+
url?: string;
|
|
105
|
+
dirUrl?: string;
|
|
106
|
+
basePath?: string;
|
|
107
|
+
}): Promise<CompileResult>;
|
|
108
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading and normalisation of `docpensieve.config.js`.
|
|
3
|
+
* @module @docpensieve/core/config
|
|
4
|
+
*/
|
|
5
|
+
export type Version = {
|
|
6
|
+
/**
|
|
7
|
+
* URL and branch identifier (`'v1.0'`).
|
|
8
|
+
*/
|
|
9
|
+
slug: string;
|
|
10
|
+
/**
|
|
11
|
+
* Label shown in the version switcher (`'1.0'`).
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Source folder, relative to the root.
|
|
16
|
+
*/
|
|
17
|
+
folder: string;
|
|
18
|
+
/**
|
|
19
|
+
* Version served by default. At most one.
|
|
20
|
+
*/
|
|
21
|
+
current?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Version kept but no longer maintained.
|
|
24
|
+
*/
|
|
25
|
+
archived?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Version in preparation, not yet the
|
|
28
|
+
* reference one. Its pages carry a notice and are not indexed.
|
|
29
|
+
*/
|
|
30
|
+
prerelease?: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type DocPensieveConfig = {
|
|
33
|
+
/**
|
|
34
|
+
* Name shown in the header and in the JSON-LD.
|
|
35
|
+
*/
|
|
36
|
+
projectName: string;
|
|
37
|
+
/**
|
|
38
|
+
* Public URL, empty when unknown.
|
|
39
|
+
*/
|
|
40
|
+
siteUrl: string;
|
|
41
|
+
/**
|
|
42
|
+
* Deployment prefix, slashes included.
|
|
43
|
+
*/
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
/**
|
|
46
|
+
* Output folder, relative to the root.
|
|
47
|
+
*/
|
|
48
|
+
outDir: string;
|
|
49
|
+
/**
|
|
50
|
+
* At least one.
|
|
51
|
+
*/
|
|
52
|
+
versions: Version[];
|
|
53
|
+
theme: {
|
|
54
|
+
framework: string;
|
|
55
|
+
darkMode?: string;
|
|
56
|
+
tokens?: Record<string, string>;
|
|
57
|
+
css?: string;
|
|
58
|
+
source?: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* `'auto'`, or the path of a description.
|
|
62
|
+
*/
|
|
63
|
+
sidebar: string;
|
|
64
|
+
globalComponents: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Back-to-top button on every page.
|
|
67
|
+
*/
|
|
68
|
+
scrollToTop: boolean;
|
|
69
|
+
jsonld: {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Project root, set by `loadConfig`.
|
|
74
|
+
*/
|
|
75
|
+
rootDir?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Document language, `'en'` by default.
|
|
78
|
+
*/
|
|
79
|
+
lang?: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {object} Version
|
|
83
|
+
* @property {string} slug URL and branch identifier (`'v1.0'`).
|
|
84
|
+
* @property {string} name Label shown in the version switcher (`'1.0'`).
|
|
85
|
+
* @property {string} folder Source folder, relative to the root.
|
|
86
|
+
* @property {boolean} [current] Version served by default. At most one.
|
|
87
|
+
* @property {boolean} [archived] Version kept but no longer maintained.
|
|
88
|
+
* @property {boolean} [prerelease] Version in preparation, not yet the
|
|
89
|
+
* reference one. Its pages carry a notice and are not indexed.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* @typedef {object} DocPensieveConfig
|
|
93
|
+
* @property {string} projectName Name shown in the header and in the JSON-LD.
|
|
94
|
+
* @property {string} siteUrl Public URL, empty when unknown.
|
|
95
|
+
* @property {string} baseUrl Deployment prefix, slashes included.
|
|
96
|
+
* @property {string} outDir Output folder, relative to the root.
|
|
97
|
+
* @property {Version[]} versions At least one.
|
|
98
|
+
* @property {{ framework: string, darkMode?: string, tokens?: Record<string, string>, css?: string, source?: string }} theme
|
|
99
|
+
* @property {string} sidebar `'auto'`, or the path of a description.
|
|
100
|
+
* @property {boolean} globalComponents
|
|
101
|
+
* @property {boolean} scrollToTop Back-to-top button on every page.
|
|
102
|
+
* @property {{ enabled: boolean }} jsonld
|
|
103
|
+
* @property {string} [rootDir] Project root, set by `loadConfig`.
|
|
104
|
+
* @property {string} [lang] Document language, `'en'` by default.
|
|
105
|
+
*/
|
|
106
|
+
/**
|
|
107
|
+
* Values applied when the user config leaves them out.
|
|
108
|
+
*
|
|
109
|
+
* The type is spelled out: without it, TypeScript would infer
|
|
110
|
+
* `versions: never[]` from the empty array and refuse every read of its
|
|
111
|
+
* elements elsewhere in the file.
|
|
112
|
+
*
|
|
113
|
+
* @type {Readonly<DocPensieveConfig>}
|
|
114
|
+
*/
|
|
115
|
+
export declare const DEFAULT_CONFIG: Readonly<DocPensieveConfig>;
|
|
116
|
+
/**
|
|
117
|
+
* Identity over the config, used only for autocompletion and type checking
|
|
118
|
+
* in the editor.
|
|
119
|
+
*
|
|
120
|
+
* @template T
|
|
121
|
+
* @param {T} config
|
|
122
|
+
* @returns {T}
|
|
123
|
+
*/
|
|
124
|
+
export declare function defineConfig<T>(config: T): T;
|
|
125
|
+
/**
|
|
126
|
+
* Merges the user config with the defaults and validates it.
|
|
127
|
+
*
|
|
128
|
+
* @param {Record<string, unknown>} userConfig
|
|
129
|
+
* @returns {DocPensieveConfig} Normalised config.
|
|
130
|
+
* @throws {ConfigError} When the config is structurally invalid.
|
|
131
|
+
*/
|
|
132
|
+
export declare function normalizeConfig(userConfig: Record<string, unknown>): DocPensieveConfig;
|
|
133
|
+
/**
|
|
134
|
+
* Loads `docpensieve.config.js` from a project folder.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} [cwd] Project root. Default: `process.cwd()`.
|
|
137
|
+
* @returns {Promise<DocPensieveConfig>} Normalised config.
|
|
138
|
+
* @throws {ConfigError} When the file is missing or exports no object.
|
|
139
|
+
*/
|
|
140
|
+
export declare function loadConfig(cwd?: string): Promise<DocPensieveConfig>;
|
|
141
|
+
/**
|
|
142
|
+
* Finds a declared version by its slug.
|
|
143
|
+
*
|
|
144
|
+
* @param {DocPensieveConfig} config Normalised config.
|
|
145
|
+
* @param {string} [slug] Slug to look for. Omitted: the "current" version.
|
|
146
|
+
* @returns {Version} The requested version.
|
|
147
|
+
* @throws {ConfigError} When the slug does not exist.
|
|
148
|
+
*/
|
|
149
|
+
export declare function resolveVersion(config: DocPensieveConfig, slug?: string): Version;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestration: loader → compiler → Handlebars shell → disk.
|
|
3
|
+
*
|
|
4
|
+
* @module @docpensieve/core/generator
|
|
5
|
+
*/
|
|
6
|
+
import { Compiler } from './compiler.js';
|
|
7
|
+
import { DocLoader } from './loader.js';
|
|
8
|
+
/** Generates the static site of one or more versions. */
|
|
9
|
+
export declare class SiteGenerator {
|
|
10
|
+
#private;
|
|
11
|
+
config: import("./config.js").DocPensieveConfig;
|
|
12
|
+
deps: {
|
|
13
|
+
components?: Record<string, Function>;
|
|
14
|
+
theme?: any;
|
|
15
|
+
loader?: DocLoader;
|
|
16
|
+
compiler?: Compiler;
|
|
17
|
+
onPage?: (page: {
|
|
18
|
+
url: string;
|
|
19
|
+
dirUrl?: string;
|
|
20
|
+
basePath: string;
|
|
21
|
+
filepath?: string;
|
|
22
|
+
sourceDir?: string;
|
|
23
|
+
}) => void;
|
|
24
|
+
};
|
|
25
|
+
loader: DocLoader;
|
|
26
|
+
compiler: Compiler;
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('./config.js').DocPensieveConfig} config Normalised config.
|
|
29
|
+
* @param {{
|
|
30
|
+
* components?: Record<string, Function>,
|
|
31
|
+
* theme?: any,
|
|
32
|
+
* loader?: DocLoader,
|
|
33
|
+
* compiler?: Compiler,
|
|
34
|
+
* onPage?: (page: {
|
|
35
|
+
* url: string, dirUrl?: string, basePath: string,
|
|
36
|
+
* filepath?: string, sourceDir?: string,
|
|
37
|
+
* }) => void,
|
|
38
|
+
* }} [deps]
|
|
39
|
+
* Global components and the theme are injected rather than imported:
|
|
40
|
+
* `core` stays independent of `components` and `theme` (ADR-002). `loader`
|
|
41
|
+
* and `compiler` only serve tests. `onPage` is called before every page:
|
|
42
|
+
* components learn from it the URL they render, which the compiler
|
|
43
|
+
* plugins cannot tell them (ADR-006), and how to find a file of the
|
|
44
|
+
* version.
|
|
45
|
+
*/
|
|
46
|
+
constructor(config: import('./config.js').DocPensieveConfig, deps?: {
|
|
47
|
+
components?: Record<string, Function>;
|
|
48
|
+
theme?: any;
|
|
49
|
+
loader?: DocLoader;
|
|
50
|
+
compiler?: Compiler;
|
|
51
|
+
onPage?: (page: {
|
|
52
|
+
url: string;
|
|
53
|
+
dirUrl?: string;
|
|
54
|
+
basePath: string;
|
|
55
|
+
filepath?: string;
|
|
56
|
+
sourceDir?: string;
|
|
57
|
+
}) => void;
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Generates one version into a folder.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} versionSlug Slug of the version to generate.
|
|
63
|
+
* @param {string} outDir Output folder of that version.
|
|
64
|
+
* @returns {Promise<{ pages: number, outDir: string }>}
|
|
65
|
+
* @throws {GeneratorError} Write failure.
|
|
66
|
+
*/
|
|
67
|
+
buildVersion(versionSlug: string, outDir: string): Promise<{
|
|
68
|
+
pages: number;
|
|
69
|
+
outDir: string;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Generates every declared version, plus `versions.json` and a root that
|
|
73
|
+
* redirects to the current version.
|
|
74
|
+
*
|
|
75
|
+
* @returns {Promise<{ versions: number, pages: number, outDir: string }>}
|
|
76
|
+
*/
|
|
77
|
+
buildAll(): Promise<{
|
|
78
|
+
versions: number;
|
|
79
|
+
pages: number;
|
|
80
|
+
outDir: string;
|
|
81
|
+
}>;
|
|
82
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @docpensieve/core — the generation engine.
|
|
3
|
+
*
|
|
4
|
+
* Depends on `@docpensieve/shared` only. Global components and the theme are
|
|
5
|
+
* injected by the caller (the CLI), which keeps the engine testable without
|
|
6
|
+
* React or CSS.
|
|
7
|
+
*
|
|
8
|
+
* @module @docpensieve/core
|
|
9
|
+
*/
|
|
10
|
+
export type DocPensieveConfig = import('./config.js').DocPensieveConfig;
|
|
11
|
+
export type Version = import('./config.js').Version;
|
|
12
|
+
export type Doc = import('./loader.js').Doc;
|
|
13
|
+
export type CompileResult = import('./compiler.js').CompileResult;
|
|
14
|
+
export type TocEntry = import('./compiler.js').TocEntry;
|
|
15
|
+
export type Preload = import('./compiler.js').Preload;
|
|
16
|
+
export type SidebarNode = import('./sidebar.js').SidebarNode;
|
|
17
|
+
/**
|
|
18
|
+
* Engine types, re-exported for consumers of the published package: without
|
|
19
|
+
* this they would only be reachable through an internal path.
|
|
20
|
+
*
|
|
21
|
+
* @typedef {import('./config.js').DocPensieveConfig} DocPensieveConfig
|
|
22
|
+
* @typedef {import('./config.js').Version} Version
|
|
23
|
+
* @typedef {import('./loader.js').Doc} Doc
|
|
24
|
+
* @typedef {import('./compiler.js').CompileResult} CompileResult
|
|
25
|
+
* @typedef {import('./compiler.js').TocEntry} TocEntry
|
|
26
|
+
* @typedef {import('./compiler.js').Preload} Preload
|
|
27
|
+
* @typedef {import('./sidebar.js').SidebarNode} SidebarNode
|
|
28
|
+
*/
|
|
29
|
+
export { DEFAULT_CONFIG, defineConfig, loadConfig, normalizeConfig, resolveVersion, } from './config.js';
|
|
30
|
+
export { DocLoader } from './loader.js';
|
|
31
|
+
export { Compiler } from './compiler.js';
|
|
32
|
+
export { StructuredDataBuilder } from './structured-data.js';
|
|
33
|
+
export { SiteGenerator } from './generator.js';
|
|
34
|
+
export { buildSidebar, collectSectionTitles } from './sidebar.js';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the Markdown/MDX sources of a version.
|
|
3
|
+
*
|
|
4
|
+
* @module @docpensieve/core/loader
|
|
5
|
+
*/
|
|
6
|
+
export type Doc = {
|
|
7
|
+
/**
|
|
8
|
+
* Page slug (`'guide/install'`).
|
|
9
|
+
*/
|
|
10
|
+
slug: string;
|
|
11
|
+
/**
|
|
12
|
+
* Absolute path of the source file.
|
|
13
|
+
*/
|
|
14
|
+
path: string;
|
|
15
|
+
/**
|
|
16
|
+
* Site URL (`'/guide/install/'`).
|
|
17
|
+
*/
|
|
18
|
+
url: string;
|
|
19
|
+
/**
|
|
20
|
+
* Frontmatter parsed by gray-matter.
|
|
21
|
+
*/
|
|
22
|
+
frontmatter: Record<string, any>;
|
|
23
|
+
/**
|
|
24
|
+
* Raw Markdown/MDX body, frontmatter removed.
|
|
25
|
+
*/
|
|
26
|
+
content: string;
|
|
27
|
+
/**
|
|
28
|
+
* Ordering weight for the sidebar.
|
|
29
|
+
*/
|
|
30
|
+
order: number;
|
|
31
|
+
};
|
|
32
|
+
/** Walks a version folder and produces the list of documents. */
|
|
33
|
+
export declare class DocLoader {
|
|
34
|
+
#private;
|
|
35
|
+
options: {
|
|
36
|
+
extensions?: string[];
|
|
37
|
+
includeDrafts?: boolean;
|
|
38
|
+
};
|
|
39
|
+
extensions: string[];
|
|
40
|
+
includeDrafts: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* @param {{ extensions?: string[], includeDrafts?: boolean }} [options]
|
|
43
|
+
* `extensions` replaces the default list (`.md`, `.mdx`);
|
|
44
|
+
* `includeDrafts` keeps the pages marked `draft: true`.
|
|
45
|
+
*/
|
|
46
|
+
constructor(options?: {
|
|
47
|
+
extensions?: string[];
|
|
48
|
+
includeDrafts?: boolean;
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Recursively loads every document of a folder.
|
|
52
|
+
*
|
|
53
|
+
* Documents come back in the site's reading order: at each level, the index
|
|
54
|
+
* page first, then numeric prefixes, then alphabetical. That is the order
|
|
55
|
+
* the sidebar needs, hence sorting during the walk rather than a flat sort
|
|
56
|
+
* of the result.
|
|
57
|
+
*
|
|
58
|
+
* The URLs produced carry no version prefix: the loader does not know which
|
|
59
|
+
* version it works on, the generator adds it.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} dir Version folder (e.g. `docs/v1.0`).
|
|
62
|
+
* @returns {Promise<Doc[]>}
|
|
63
|
+
* @throws {LoaderError} Missing folder, invalid frontmatter, colliding slugs.
|
|
64
|
+
*/
|
|
65
|
+
load(dir: string): Promise<Doc[]>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the sidebar from the loaded documents.
|
|
3
|
+
*
|
|
4
|
+
* @module @docpensieve/core/sidebar
|
|
5
|
+
*/
|
|
6
|
+
export type SidebarNode = {
|
|
7
|
+
/**
|
|
8
|
+
* Displayed title.
|
|
9
|
+
*/
|
|
10
|
+
label: string;
|
|
11
|
+
/**
|
|
12
|
+
* Page URL, or `null` for a folder without an
|
|
13
|
+
* index page — the category is then a mere grouping.
|
|
14
|
+
*/
|
|
15
|
+
url: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Child entries.
|
|
18
|
+
*/
|
|
19
|
+
items: SidebarNode[];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {object} SidebarNode
|
|
23
|
+
* @property {string} label Displayed title.
|
|
24
|
+
* @property {string | null} url Page URL, or `null` for a folder without an
|
|
25
|
+
* index page — the category is then a mere grouping.
|
|
26
|
+
* @property {SidebarNode[]} items Child entries.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Builds the navigation tree of a version.
|
|
30
|
+
*
|
|
31
|
+
* The order is the `DocLoader`'s, which has already sorted: index page first,
|
|
32
|
+
* then numeric prefixes, then alphabetical. Nothing is re-sorted here, which
|
|
33
|
+
* guarantees that the sidebar follows the reading order of the files exactly.
|
|
34
|
+
*
|
|
35
|
+
* That order has a useful consequence: since `guide/index.md` is loaded
|
|
36
|
+
* before `guide/installation.md`, the “guide” category receives its real
|
|
37
|
+
* title before a child page creates it with a default one.
|
|
38
|
+
*
|
|
39
|
+
* @param {import('./loader.js').Doc[]} docs Documents in loader order.
|
|
40
|
+
* @param {(doc: import('./loader.js').Doc) => string} [toUrl] Turns a
|
|
41
|
+
* document into a URL. By default, the document's URL as is.
|
|
42
|
+
* @param {{ brand?: string }} [options] `brand` is the name shown in the
|
|
43
|
+
* header: a root entry carrying exactly that title is dropped, since the
|
|
44
|
+
* brand already leads to that page. The same word twice, an inch apart,
|
|
45
|
+
* tells the reader nothing.
|
|
46
|
+
* @returns {SidebarNode[]}
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildSidebar(docs: import('./loader.js').Doc[], toUrl?: (doc: import('./loader.js').Doc) => string, options?: {
|
|
49
|
+
brand?: string;
|
|
50
|
+
}): SidebarNode[];
|
|
51
|
+
/**
|
|
52
|
+
* Collects folder titles, for the breadcrumb.
|
|
53
|
+
*
|
|
54
|
+
* Only folders with an index page have a known title; the others will be
|
|
55
|
+
* humanised from their slug by `StructuredDataBuilder`.
|
|
56
|
+
*
|
|
57
|
+
* @param {import('./loader.js').Doc[]} docs
|
|
58
|
+
* @returns {Record<string, string>} Full folder slug to title.
|
|
59
|
+
*/
|
|
60
|
+
export declare function collectSectionTitles(docs: import('./loader.js').Doc[]): Record<string, string>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the JSON-LD from the frontmatter.
|
|
3
|
+
*
|
|
4
|
+
* @module @docpensieve/core/structured-data
|
|
5
|
+
*/
|
|
6
|
+
/** Assembles a schema.org graph for a page. */
|
|
7
|
+
export declare class StructuredDataBuilder {
|
|
8
|
+
#private;
|
|
9
|
+
frontmatter: Record<string, any>;
|
|
10
|
+
url: string;
|
|
11
|
+
config: Record<string, any>;
|
|
12
|
+
options: {
|
|
13
|
+
breadcrumbTitles?: Record<string, string>;
|
|
14
|
+
basePath?: string;
|
|
15
|
+
dirUrl?: string;
|
|
16
|
+
};
|
|
17
|
+
breadcrumbTitles: Record<string, string>;
|
|
18
|
+
basePath: string;
|
|
19
|
+
dirUrl: string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* @param {Record<string, any>} frontmatter Page frontmatter.
|
|
22
|
+
* @param {string} url Page URL on the site (`'/guide/install/'`).
|
|
23
|
+
* @param {Record<string, any>} config Normalised project config.
|
|
24
|
+
* @param {{ breadcrumbTitles?: Record<string, string>, basePath?: string, dirUrl?: string }} [options]
|
|
25
|
+
* `breadcrumbTitles` maps a folder slug to its real title, so that the
|
|
26
|
+
* breadcrumb shows “Café Guide” rather than “Cafe guide”. `basePath` is
|
|
27
|
+
* the site root from which crumbs are counted: the generator sets
|
|
28
|
+
* `/versions/v1.0/`, otherwise the breadcrumb would show “Versions” and
|
|
29
|
+
* “V1.0”, which are neither pages nor titles. `dirUrl` is the source
|
|
30
|
+
* file's folder as a URL: the base of the frontmatter's relative targets.
|
|
31
|
+
*/
|
|
32
|
+
constructor(frontmatter: Record<string, any>, url: string, config: Record<string, any>, options?: {
|
|
33
|
+
breadcrumbTitles?: Record<string, string>;
|
|
34
|
+
basePath?: string;
|
|
35
|
+
dirUrl?: string;
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Builds the page's schema.org graph.
|
|
39
|
+
*
|
|
40
|
+
* @returns {Record<string, any> | null} Object ready to serialise, or
|
|
41
|
+
* `null` when structured data is turned off in the configuration.
|
|
42
|
+
* @throws {StructuredDataError} Unknown article type, or malformed FAQ.
|
|
43
|
+
*/
|
|
44
|
+
build(): Record<string, any> | null;
|
|
45
|
+
/**
|
|
46
|
+
* Serialises the graph into a tag ready for the `<head>`.
|
|
47
|
+
*
|
|
48
|
+
* @returns {string} `<script>` tag, or an empty string when disabled.
|
|
49
|
+
*/
|
|
50
|
+
toScriptTag(): string;
|
|
51
|
+
}
|