@heroiclands/package-build 22.3.1 → 22.4.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/CHANGELOG.md +47 -0
- package/CONTENT.md +182 -306
- package/bin/content-build.mjs +15 -20
- package/bin/package-build.mjs +4 -3
- package/content-config.mjs +70 -179
- package/docs/api.md +27 -32
- package/docs/commands.md +31 -19
- package/docs/configuration.md +90 -126
- package/docs/content-format.md +25 -15
- package/docs/getting-started.md +5 -4
- package/docs/project-setup.md +1 -1
- package/engine/content-links.mjs +25 -60
- package/engine/diagnostics.mjs +2 -2
- package/engine/field-reference.mjs +7 -1
- package/engine/homepage.mjs +91 -172
- package/engine/metadata-index.mjs +7 -3
- package/engine/note-vocabulary.mjs +0 -20
- package/engine/pdf-build.mjs +2 -2
- package/engine/site-build.mjs +64 -225
- package/engine/site-config.mjs +15 -53
- package/engine/site-root.mjs +26 -70
- package/package.json +1 -1
- package/types/content-config.d.mts +6 -8
- package/types/engine/content-links.d.mts +12 -23
- package/types/engine/diagnostics.d.mts +2 -2
- package/types/engine/homepage.d.mts +51 -91
- package/types/engine/note-vocabulary.d.mts +0 -12
- package/types/engine/site-build.d.mts +28 -129
- package/types/engine/site-config.d.mts +10 -19
- package/types/engine/site-root.d.mts +11 -36
|
@@ -46,25 +46,24 @@ export function collectHomepages(contentBase: string, ctx: object): {
|
|
|
46
46
|
addressFindings: object[];
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
|
-
* Writes each homepage
|
|
49
|
+
* Writes each homepage as the package root's `_index.md`.
|
|
50
50
|
*
|
|
51
51
|
* Its own writer, deliberately small. A homepage is authored markdown published
|
|
52
|
-
* verbatim — no table expansion
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* **Verbatim is the answer, not a gap.** A
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* {@link auditHomepageLinks} reads the
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* **Its destination is
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* package's own repository authors, which is a routing fact rather than a page.
|
|
52
|
+
* verbatim — no table expansion and no link resolution — so routing it through
|
|
53
|
+
* {@link renderPages} would buy it a pipeline it has no input for, and would
|
|
54
|
+
* make homepage-only mode depend on the index, the foreign manifests and the
|
|
55
|
+
* table universe that mode exists to not build.
|
|
56
|
+
*
|
|
57
|
+
* **Verbatim is the answer, not a gap.** A homepage's links could not be
|
|
58
|
+
* *resolved* here without giving `homepage` mode the index its licensing fence
|
|
59
|
+
* exists to not build, so they are **checked** instead:
|
|
60
|
+
* {@link auditHomepageLinks} reads the body's markdown links, and reports a
|
|
61
|
+
* wikilink on the page rather than resolving one.
|
|
62
|
+
*
|
|
63
|
+
* **Its destination is fixed**: {@link HOMEPAGE_DESTINATION}, at the package's
|
|
64
|
+
* site root, which Hugo renders as the `home` kind at `/<package>/`. The page
|
|
65
|
+
* states no `url` — the home kind has none to state — and the mount below it
|
|
66
|
+
* holds pages and nothing else, so this is the only `_index.md` in the tree.
|
|
68
67
|
*
|
|
69
68
|
* @param {string} outRoot - The package's site root — the content mount's
|
|
70
69
|
* root, `build/hugo/content`, one level above the mount itself.
|
|
@@ -84,7 +83,7 @@ export function writeHomepages(outRoot: string, pages: readonly object[], config
|
|
|
84
83
|
* - **Frontmatter wikilinks** first, because frontmatter is copied to the page
|
|
85
84
|
* verbatim and a link written in one reaches the reader as literal `[[…]]`.
|
|
86
85
|
* - **Addresses** next: a note that has no address — no shortcode to be
|
|
87
|
-
* addressed by
|
|
86
|
+
* addressed by — would silently drop a page.
|
|
88
87
|
* There is no collision gate beside it: an address is `(type, shortcode)`,
|
|
89
88
|
* which is unique within a package by rule, so two pages cannot claim one URL.
|
|
90
89
|
* - **Foreign manifests** last, in two steps. *Unusable* is a file this build
|
|
@@ -125,31 +124,6 @@ export function gatesFailed(gates: any): boolean;
|
|
|
125
124
|
* @returns {Map<string, object[]>} Package → the notes it may tabulate.
|
|
126
125
|
*/
|
|
127
126
|
export function tableUniverse(pages: object[]): Map<string, object[]>;
|
|
128
|
-
/**
|
|
129
|
-
* The front matter a section's landing states about itself.
|
|
130
|
-
*
|
|
131
|
-
* The section metadata a configuration resolved, ready to be written or merged
|
|
132
|
-
* onto a page. Two things happen here and nothing else does:
|
|
133
|
-
*
|
|
134
|
-
* - **`title` leads.** It is the one key every landing has carried since the
|
|
135
|
-
* first one, and a landing whose block opened with `banner:` would be a
|
|
136
|
-
* gratuitous diff on every consumer's tree.
|
|
137
|
-
* - **An absent value is left off**, not written as `undefined` — which is not
|
|
138
|
-
* a value YAML can carry, and would abort the serializer.
|
|
139
|
-
*
|
|
140
|
-
* Everything else the section declared is passed through. That is the point of
|
|
141
|
-
* the function: two writers transcribing `title` and `banner` by
|
|
142
|
-
* name, so the vocabulary lived in three places — the schema that admits a key
|
|
143
|
-
* and the two writers that copy it — and a key added to the schema alone
|
|
144
|
-
* validated cleanly and then reached no page. The *schema* is the bound worth
|
|
145
|
-
* keeping (see `normalizeSectionMeta`, which refuses a key it does not know and
|
|
146
|
-
* names it); a second, silent bound in the writers is not.
|
|
147
|
-
*
|
|
148
|
-
* @param {object} meta - A resolved `site.sections` / `site.readmeSections`
|
|
149
|
-
* entry.
|
|
150
|
-
* @returns {object} Its front matter, `title` first.
|
|
151
|
-
*/
|
|
152
|
-
export function sectionFrontmatter(meta: object): object;
|
|
153
127
|
/**
|
|
154
128
|
* The frontmatter a page publishes with.
|
|
155
129
|
*
|
|
@@ -180,10 +154,8 @@ export function sectionFrontmatter(meta: object): object;
|
|
|
180
154
|
* A content page carries the package the build **derived**. No note
|
|
181
155
|
* declares one — `package:` is retired — so the note's frontmatter alone
|
|
182
156
|
* would publish a page that does not say which package it belongs to. The
|
|
183
|
-
* emitted page is what a
|
|
184
|
-
*
|
|
185
|
-
* `.Params.package`, so without it that crumb degrades from a linked, labelled
|
|
186
|
-
* section to a bare type slug. Writing the derived value keeps a page
|
|
157
|
+
* emitted page is what a theme reads: `breadcrumbs.html` reads
|
|
158
|
+
* `.Params.package`. Writing the derived value keeps a page
|
|
187
159
|
* self-describing and makes sweeping the field out of a content tree
|
|
188
160
|
* output-preserving for a site as it already is for the packs.
|
|
189
161
|
*
|
|
@@ -209,16 +181,15 @@ export function pageFrontmatter(page: object, { decorate, webSrc, artSrc }: {
|
|
|
209
181
|
* Where a page is written, relative to the output root.
|
|
210
182
|
*
|
|
211
183
|
* **Flat, under the mount, named by its address**. A content page's URL
|
|
212
|
-
* is its address — `/<package>/<type>-<shortcode>/` — and the file is
|
|
213
|
-
* the same way, so the two agree.
|
|
214
|
-
* Hugo
|
|
215
|
-
* a directory chosen only to satisfy a rendering engine's idea
|
|
216
|
-
* section is has no business in the note format.
|
|
184
|
+
* is its address — `/<package>/<type>-<shortcode>/` — and the file is named
|
|
185
|
+
* the same way, so the two agree. No page creates a directory: a section is
|
|
186
|
+
* a Hugo listing over a content directory, the `section` kind is disabled on
|
|
187
|
+
* every site, and a directory chosen only to satisfy a rendering engine's idea
|
|
188
|
+
* of what a section is has no business in the note format.
|
|
217
189
|
*
|
|
218
|
-
* The name is the *whole* address
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* are distinct whatever the sections.
|
|
190
|
+
* The name is the *whole* address, so two types cannot fight over one file: a
|
|
191
|
+
* `doc` note's `subType` may be spelled the same as another note's `type`, and
|
|
192
|
+
* `doc-gear.md` and `weapongear-gear.md` are distinct.
|
|
222
193
|
*
|
|
223
194
|
* @param {object} page - The page.
|
|
224
195
|
* @returns {string} The file, relative to the mount.
|
|
@@ -251,74 +222,6 @@ export function renderPages(pages: object[], options: object): {
|
|
|
251
222
|
wikiErrors: object[];
|
|
252
223
|
imageErrors: object[];
|
|
253
224
|
};
|
|
254
|
-
/**
|
|
255
|
-
* Writes the Hugo sections a published tree declares.
|
|
256
|
-
*
|
|
257
|
-
* **This is where a section lives now, and the only place**. A content
|
|
258
|
-
* note carries none: it is addressed by `(type, shortcode)` and emitted flat
|
|
259
|
-
* under the mount, so nothing a page does creates a directory. A site that wants
|
|
260
|
-
* `/<package>/<prefix><section>/` to answer — with a title, a hero, and whatever
|
|
261
|
-
* listing its layout builds — says so here, in configuration, and this writes
|
|
262
|
-
* the `_index.md` that makes Hugo agree it is a section.
|
|
263
|
-
*
|
|
264
|
-
* Three jobs, all of them Hugo's directory semantics rather than the note
|
|
265
|
-
* format's:
|
|
266
|
-
*
|
|
267
|
-
* - **The mount's own landing**, so `/<package>/<prefix>` is a page rather than
|
|
268
|
-
* a directory listing. It carries a `type` of its own: Hugo's template lookup
|
|
269
|
-
* walks up a page's path, so an untyped landing template at the mount would
|
|
270
|
-
* also serve every section below it that has none.
|
|
271
|
-
* - **Declared sections** get a titled `_index.md` with their hero, so a landing
|
|
272
|
-
* matches the card that links to it instead of showing Hugo's auto-humanised
|
|
273
|
-
* directory name. The body is empty, which lets the theme decide what to list.
|
|
274
|
-
* - **Every other directory directly under the mount** gets a bare `_index.md`,
|
|
275
|
-
* or its own address publishes nothing. Hugo generates a section page
|
|
276
|
-
* automatically only for a *top-level* content directory; below that, a
|
|
277
|
-
* directory without an `_index.md` is not a section, so its URL 404s while its
|
|
278
|
-
* children publish normally. With content pages flat, no note creates a
|
|
279
|
-
* directory below the mount, so this reaches only what something else
|
|
280
|
-
* placed there.
|
|
281
|
-
*
|
|
282
|
-
* **A section listing is not a page listing any more.** A layout that reads
|
|
283
|
-
* `.Pages` off a section it declares here will find nothing, because no file is
|
|
284
|
-
* filed into it; one that queries `site.RegularPages` by `Params.type` — which
|
|
285
|
-
* is how `sohl`'s eleven catalog layouts already work — is unaffected. That is a
|
|
286
|
-
* consumer's layout to choose, and it is stated here because the choice is no
|
|
287
|
-
* longer free.
|
|
288
|
-
*
|
|
289
|
-
* Scoped to one level on purpose. A directory further down was not a section
|
|
290
|
-
* before either, and giving it one here would silently re-scope the prev/next
|
|
291
|
-
* navigation of every page inside it.
|
|
292
|
-
*
|
|
293
|
-
* @param {string} outRoot - The mount directory.
|
|
294
|
-
* @param {object} options
|
|
295
|
-
* @param {Record<string, object>} [options.sections] - The declared sections,
|
|
296
|
-
* each written as a titled `_index.md` carrying its own frontmatter.
|
|
297
|
-
* @param {object} [options.landing] - The mount's own landing frontmatter.
|
|
298
|
-
* Omitted, the mount gets no `_index.md` of its own.
|
|
299
|
-
* @param {((name: string) => string)|null} [options.sectionTitle] - Titles a
|
|
300
|
-
* directory below the mount that declared no section. `null` leaves such a
|
|
301
|
-
* directory without an `_index.md`.
|
|
302
|
-
* @returns {number} How many landings were written.
|
|
303
|
-
*/
|
|
304
|
-
export function writeSectionLandings(outRoot: string, { sections, landing, sectionTitle }: {
|
|
305
|
-
sections?: Record<string, object> | undefined;
|
|
306
|
-
landing?: object | undefined;
|
|
307
|
-
sectionTitle?: ((name: string) => string) | null | undefined;
|
|
308
|
-
}): number;
|
|
309
|
-
/**
|
|
310
|
-
* A section landing's title, from its directory name — `macro` → `Macros`.
|
|
311
|
-
*
|
|
312
|
-
* Hugo derives exactly this for a section page it generates itself, but not for
|
|
313
|
-
* one backed by an `_index.md`: an explicit file with no `title` renders a blank
|
|
314
|
-
* heading. So a backfilled landing states its own, in plain English
|
|
315
|
-
* pluralisation rather than Hugo's inflector, which spells that section
|
|
316
|
-
* "Macroes".
|
|
317
|
-
*
|
|
318
|
-
* @param {string} name - The directory name.
|
|
319
|
-
* @returns {string} The display title.
|
|
320
|
-
*/
|
|
321
|
-
export function pluralTitle(name: string): string;
|
|
322
225
|
/**
|
|
323
226
|
* Resolves `site.pass` to its bundle.
|
|
324
227
|
*
|
|
@@ -346,10 +249,7 @@ export function resolveSitePass(name: string | undefined, options: object): {
|
|
|
346
249
|
* `sql` directive with none prepared is a table error: nothing here runs a
|
|
347
250
|
* query.
|
|
348
251
|
* @returns {{gates: object, stats: object|null, tableErrors: object[],
|
|
349
|
-
* wikiErrors: object[], imageErrors: object[], manifests: object|null
|
|
350
|
-
* hasTags: boolean}} `hasTags` is whether any note the walk read carries
|
|
351
|
-
* `tags:` — what {@link module:engine/site-config.hugoConfig} reads to
|
|
352
|
-
* decide whether the site emits taxonomy pages.
|
|
252
|
+
* wikiErrors: object[], imageErrors: object[], manifests: object|null}}
|
|
353
253
|
*/
|
|
354
254
|
export function buildSite({ config, sqlTables }?: {
|
|
355
255
|
config?: object | undefined;
|
|
@@ -361,7 +261,6 @@ export function buildSite({ config, sqlTables }?: {
|
|
|
361
261
|
wikiErrors: object[];
|
|
362
262
|
imageErrors: object[];
|
|
363
263
|
manifests: object | null;
|
|
364
|
-
hasTags: boolean;
|
|
365
264
|
};
|
|
366
265
|
export { formatUnaddressableFinding };
|
|
367
266
|
import { formatUnaddressableFinding } from "./metadata-index.mjs";
|
|
@@ -91,19 +91,15 @@ export function resolveThemesDir(rootDir: string): string;
|
|
|
91
91
|
* @param {object} options.config - The resolved build configuration.
|
|
92
92
|
* @param {readonly NavigationEntry[]} options.navigation - The navigation.
|
|
93
93
|
* @param {string} options.themesDir - From {@link resolveThemesDir}.
|
|
94
|
-
* @param {boolean} [options.hasTags] - Whether any note the site build walked
|
|
95
|
-
* carries `tags:`, from {@link module:engine/site-build.buildSite}'s
|
|
96
|
-
* `hasTags`. Defaults to `false` — no tagged note, no taxonomy pages.
|
|
97
94
|
* @returns {Record<string, any>} The configuration Hugo reads.
|
|
98
95
|
* @throws {TypeError} When `homepage` fails `checkHomepage`, or the
|
|
99
96
|
* configuration declares no `packageBuild.manifest.title`, no
|
|
100
97
|
* `site.description`, or no `site.assets`.
|
|
101
98
|
*/
|
|
102
|
-
export function hugoConfig({ config, navigation, themesDir
|
|
99
|
+
export function hugoConfig({ config, navigation, themesDir }: {
|
|
103
100
|
config: object;
|
|
104
101
|
navigation: readonly NavigationEntry[];
|
|
105
102
|
themesDir: string;
|
|
106
|
-
hasTags?: boolean | undefined;
|
|
107
103
|
}): Record<string, any>;
|
|
108
104
|
/**
|
|
109
105
|
* The configuration as the TOML Hugo reads.
|
|
@@ -120,17 +116,10 @@ export function hugoToml(generated: Record<string, unknown>): string;
|
|
|
120
116
|
* run this before touching the output tree and fail with it intact.
|
|
121
117
|
*
|
|
122
118
|
* @param {object} config - The resolved build configuration.
|
|
123
|
-
* @param {object} [options] - Options.
|
|
124
|
-
* @param {boolean} [options.hasTags] - Whether any note the site build walked
|
|
125
|
-
* carries `tags:`. Defaults to `false`, so a caller generating the
|
|
126
|
-
* configuration before the walk (to fail fast on a missing source) gets the
|
|
127
|
-
* untagged shape; pass the site build's own `hasTags` once it is known.
|
|
128
119
|
* @returns {Record<string, any>} The configuration Hugo reads.
|
|
129
120
|
* @throws {Error} When any source is missing or wrong.
|
|
130
121
|
*/
|
|
131
|
-
export function generateHugoConfig(config: object,
|
|
132
|
-
hasTags?: boolean | undefined;
|
|
133
|
-
}): Record<string, any>;
|
|
122
|
+
export function generateHugoConfig(config: object): Record<string, any>;
|
|
134
123
|
/**
|
|
135
124
|
* Write `build/hugo/hugo.toml`.
|
|
136
125
|
*
|
|
@@ -171,13 +160,15 @@ export const BRAND: Readonly<{
|
|
|
171
160
|
discordURL: "https://discord.gg/EwMfkNd3az";
|
|
172
161
|
}>;
|
|
173
162
|
/**
|
|
174
|
-
* The kinds
|
|
163
|
+
* The kinds no site renders.
|
|
175
164
|
*
|
|
176
|
-
* A
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
165
|
+
* A site is its homepage and its pages: `home` and `page` are the only kinds,
|
|
166
|
+
* for every package and whatever its notes carry. A `section` is a listing
|
|
167
|
+
* Hugo would generate from a content directory; `taxonomy` and `term` are
|
|
168
|
+
* listings it would generate from `tags:`; `RSS` is a feed. Every structure
|
|
169
|
+
* between the homepage and the pages is authored instead, as a `doc` note
|
|
170
|
+
* carrying a content table — a tag is a field such a table filters on, not a
|
|
171
|
+
* page of its own.
|
|
181
172
|
*/
|
|
182
173
|
export const DISABLE_KINDS: readonly string[];
|
|
183
174
|
/**
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where a package's landing is served, now that it is an addressed page.
|
|
3
|
-
*
|
|
4
|
-
* The site build emits the homepage at its own address rather than as the
|
|
5
|
-
* site root's `_index.md`, so the prefix root is a redirect to it.
|
|
6
|
-
*
|
|
7
|
-
* @param {string} pkg - The content package name.
|
|
8
|
-
* @returns {string} The landing's path.
|
|
9
|
-
*/
|
|
10
|
-
export function landingPath(pkg: string): string;
|
|
11
1
|
/**
|
|
12
2
|
* Suppress indexing of every address a deployment answers on but nobody
|
|
13
3
|
* advertises.
|
|
@@ -28,37 +18,22 @@ export function landingPath(pkg: string): string;
|
|
|
28
18
|
*/
|
|
29
19
|
export function noindexHeaders(): string[];
|
|
30
20
|
/**
|
|
31
|
-
* The
|
|
21
|
+
* The `_headers` file's contents: the `noindex` rules, and nothing else.
|
|
32
22
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* keeps the 301's canonical signal without the permanence.
|
|
23
|
+
* No `Cache-Control` is pinned on the prefix root. It is the homepage, and a
|
|
24
|
+
* lifetime on it would hold a stale copy at the most-linked address after a
|
|
25
|
+
* deploy; Pages' own defaults for a page apply.
|
|
37
26
|
*
|
|
38
|
-
* @param {string} pkg - The content package name.
|
|
39
|
-
* @returns {string[]} The header block's lines.
|
|
40
|
-
*/
|
|
41
|
-
export function cacheHeaders(pkg: string): string[];
|
|
42
|
-
/**
|
|
43
|
-
* Both forms of the prefix root, because Pages matches the raw path.
|
|
44
|
-
*
|
|
45
|
-
* Redirect matching runs before any trailing-slash or `index.html` handling, so
|
|
46
|
-
* `/<pkg>` and `/<pkg>/` are distinct keys and a rule on one does not catch the
|
|
47
|
-
* other.
|
|
48
|
-
*
|
|
49
|
-
* @param {string} pkg - The content package name.
|
|
50
|
-
* @returns {string} The `_redirects` file's contents.
|
|
51
|
-
*/
|
|
52
|
-
export function redirects(pkg: string): string;
|
|
53
|
-
/**
|
|
54
|
-
* The `_headers` file's contents.
|
|
55
|
-
*
|
|
56
|
-
* @param {string} pkg - The content package name.
|
|
57
27
|
* @returns {string} The file's contents.
|
|
58
28
|
*/
|
|
59
|
-
export function headers(
|
|
29
|
+
export function headers(): string;
|
|
60
30
|
/**
|
|
61
|
-
* Write `_headers`
|
|
31
|
+
* Write `_headers` beside the rendered site, and remove any `_redirects`.
|
|
32
|
+
*
|
|
33
|
+
* The removal is part of owning the root: a `_redirects` this build did not
|
|
34
|
+
* write is one an earlier build left, and Cloudflare Pages applies whatever
|
|
35
|
+
* sits there. Left in place it would redirect the prefix root — the homepage —
|
|
36
|
+
* to an address nothing publishes.
|
|
62
37
|
*
|
|
63
38
|
* @param {object} options - Options.
|
|
64
39
|
* @param {string} options.pkg - The content package name, which is also the
|