@heroiclands/package-build 22.3.1 → 22.4.1

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.
@@ -1,18 +1,3 @@
1
- /**
2
- * The file a homepage is written to, relative to the package's site root.
3
- *
4
- * Its **address**, flat at the package root, and stated in the page's own `url`
5
- * — the same separation every other page has, where the directory
6
- * decides the Hugo section and the front matter decides the URL. Flat rather
7
- * than inside a `homepage/` section directory, because a homepage is not one of
8
- * a kind: a section holding exactly one page would publish a landing at
9
- * `/<package>/kb/homepage/` that nothing links to and nobody wrote.
10
- *
11
- * @param {object} fm - Parsed frontmatter.
12
- * @returns {string} The destination filename, e.g. `homepage-root.md`.
13
- * @throws {Error} When the note declares no shortcode, and so has no address.
14
- */
15
- export function homepageDestination(fm: object): string;
16
1
  /**
17
2
  * Whether a note's frontmatter declares the homepage type.
18
3
  *
@@ -24,7 +9,7 @@ export function isHomepage(fm: object | null | undefined): boolean;
24
9
  * What the address rule says about one note's top-level fields.
25
10
  *
26
11
  * Two statements about the same thing, so they are made together: the field a
27
- * homepage **owes** and the field it may **not** write.
12
+ * homepage **owes** and the fields it may **not** write.
28
13
  *
29
14
  * The missing `shortcode` comes first, and is located at `type:` rather than at
30
15
  * a key that is not there — the `homepage` value is what makes the field
@@ -34,8 +19,9 @@ export function isHomepage(fm: object | null | undefined): boolean;
34
19
  * diagnostic per finding walks down the file.
35
20
  *
36
21
  * Presence is the whole test for a refused field, and absence-or-blank for the
37
- * required one: `shortcode:` authored empty is no address, and a value cannot
38
- * make `id` mean something on a page that compiles to no document.
22
+ * required one: `shortcode:` authored empty is no address, and no value can
23
+ * make `id` or `landing` mean something on a page that compiles to no document
24
+ * and renders as its body.
39
25
  *
40
26
  * Each finding carries the `locator` key to position it at, because the two
41
27
  * things that would resolve one — the raw note text and the position helper —
@@ -79,13 +65,11 @@ export function checkHomepageAddressFields(fm: object | null | undefined, { isAu
79
65
  * this exists to prevent, and it is silent — the site build reports `wrote 0
80
66
  * homepage(s)` and exits 0.
81
67
  * - _Two_ and it serves a page nobody chose. **This is a cardinality rule, and
82
- * only that.** A homepage is written at its own address, so two of them
83
- * publish two pages and collide over nothing; the
84
- * duplicate-address check catches only the pair that happen to share a
85
- * shortcode, and says nothing at all about a `homepage-root` beside a
86
- * `homepage-front`. Which of the two the redirect at `/<package>/` should
87
- * name is a question nothing here can answer, and both being reachable is
88
- * not an answer to it.
68
+ * only that.** Both are written to the mount's `_index.md`, so the second
69
+ * silently overwrites the first; the duplicate-address check catches only
70
+ * the pair that happen to share a shortcode, and says nothing at all about
71
+ * a `homepage-root` beside a `homepage-front`. Which of the two should be
72
+ * the front page is a question nothing here can answer.
89
73
  *
90
74
  * Neither has a safe default, so neither is a warning. A warning is the right
91
75
  * severity for something a build can proceed past correctly, and a build that
@@ -149,24 +133,15 @@ export function homepageTitle(fm: object | null | undefined, config: object): st
149
133
  /**
150
134
  * The frontmatter a homepage publishes with.
151
135
  *
152
- * The note's own, plus the derived values every emitted page carries: the
153
- * resolved `title`, the package the build derived — no note declares one
136
+ * The note's own, plus the two derived values every emitted page carries: the
137
+ * resolved `title`, and the package the build derived — no note declares one
154
138
  * (`package:` is retired) and the theme's breadcrumb partial reads
155
- * `.Params.package` — and its **address**.
156
- *
157
- * The address is stated as `url` for the same reason every other page states
158
- * one: Hugo publishes a page where its file sits unless told otherwise,
159
- * and a homepage's file sits at the package's site root. `slug` is written
160
- * beside it because it is the last segment of that address and Hugo's own key
161
- * for one; it decides nothing while `url` is present, but a page carrying only
162
- * `url` would report a slug Hugo had inferred from the filename.
163
- *
164
- * **Site-root relative, and so carrying no package base**, exactly as
165
- * `pageFrontmatter` states a content page's: Hugo resolves a `url`
166
- * against `baseURL`, whose path is already where the package is served, so a
167
- * stated base was written twice and published the landing at
168
- * `/<package>/<package>/homepage-root/`. Where the package is served is what
169
- * every *href* is composed from and it reaches this page's address not at all.
139
+ * `.Params.package`.
140
+ *
141
+ * **No `url` and no `slug`.** Hugo publishes the `home` kind at `baseURL`,
142
+ * whose path is already where the package is served, so the page has no
143
+ * address to state; a content page states one because its file sits under the
144
+ * mount and its address does not.
170
145
  *
171
146
  * An authored `aliases` is dropped for the same reason it is on every other
172
147
  * page: Hugo reads it as URL redirects, so passing it through would publish a
@@ -178,43 +153,33 @@ export function homepageTitle(fm: object | null | undefined, config: object): st
178
153
  * @param {string} options.contentPackage - The package this build publishes.
179
154
  * @param {string} options.title - The resolved title.
180
155
  * @returns {object} The frontmatter to write.
181
- * @throws {Error} When the note declares no shortcode, and so has no address.
182
156
  */
183
157
  export function homepageFrontmatter(fm: object, { contentPackage, title }: {
184
158
  contentPackage: string;
185
159
  title: string;
186
160
  }): object;
187
161
  /**
188
- * Every address a homepage carries, wherever it is written.
189
- *
190
- * **Both halves of the page are in scope, and that is the finding rather than
191
- * the assumption.** Of the six homepages authored today, four carry every link
192
- * in the body as ordinary markdown and two carry them in `landing:` — and the
193
- * one whose dead links prompted the check has an *empty body*, so a body-only
194
- * reading would have found nothing at all on it. A dead link in a card is
195
- * exactly as broken as one in a paragraph.
162
+ * Every address a homepage carries: the markdown links in its body.
196
163
  *
197
- * Three shapes are gathered, and the caller needs to tell them apart because
198
- * the rules differ:
164
+ * Nowhere else: the frontmatter holds no address, because a homepage is a
165
+ * page with a body and the card block that once carried links is refused.
166
+ * Top-level `title` and `description` are not walked — they are set as text,
167
+ * never rendered as markdown — and `banner:` is not an address: it is an image
168
+ * path resolved through the CDN base, and `banner: none` is a sentinel rather
169
+ * than a target.
199
170
  *
200
- * - **`url`** package-relative, resolved against the site by the theme.
201
- * - **`href`** already resolved, used verbatim.
202
- * - **prose and body markdown links** — emitted as written and resolved by the
203
- * browser against the landing's own address, which *is* the package root, so
204
- * a relative one means the same thing a `url` does.
171
+ * A body link is emitted as written and resolved by the browser against the
172
+ * homepage's own address, which *is* the package root, so a package-relative
173
+ * one (`kb/rules/`) lands where a reader expects.
205
174
  *
206
- * `banner:` is not an address: it is an image path resolved through the CDN
207
- * base, and `banner: none` is a sentinel rather than a target. Top-level
208
- * `title` and `description` are not walked either — they are set as text, never
209
- * rendered as markdown.
175
+ * Links inside code are ignored, so an example in a fenced block is not
176
+ * reported as a dead address.
210
177
  *
211
- * @param {object|null|undefined} fm - The note's frontmatter.
212
178
  * @param {string} [body] - The note's markdown body.
213
179
  * @returns {Array<{field: string, url: string, kind: string}>} Every address,
214
- * frontmatter first and then the body, each with the dotted path it was
215
- * written at.
180
+ * in body order, each recorded at `field: "body"` with `kind: "body"`.
216
181
  */
217
- export function homepageAddresses(fm: object | null | undefined, body?: string): Array<{
182
+ export function homepageAddresses(body?: string): Array<{
218
183
  field: string;
219
184
  url: string;
220
185
  kind: string;
@@ -250,17 +215,28 @@ export const HOMEPAGE_FIELDS: readonly import("./field-spec.mjs").FieldSpec[];
250
215
  */
251
216
  export const HOMEPAGE_SHORTCODE: string;
252
217
  /**
253
- * The top-level field a homepage refuses, and what it would decide.
218
+ * The file a homepage is written to, relative to the package's site root.
254
219
  *
255
- * **One field rather than three.** `name` and `shortcode` are
256
- * refused because a page's URL derived from `name.full` while a homepage's
257
- * destination was fixed, so the address a `shortcode` computed named a page the
258
- * site build never wrote. A page's URL is its address now and a homepage
259
- * publishes at its own, so both fields decide exactly what they decide
260
- * everywhere else and are permitted.
220
+ * The mount's own `_index.md`: Hugo renders it as the `home` kind, at
221
+ * `baseURL` which is `/<package>/`, the package's own address. One fixed
222
+ * destination rather than one derived from the note's address, because the
223
+ * homepage's address *is* the package root; the note's `shortcode` names the
224
+ * page in links and decides no file.
261
225
  *
262
- * `id` is untouched by that, and stays: it is the Foundry document id a
263
- * compendium UUID is built from, and a homepage compiles into no document.
226
+ * @type {string}
227
+ */
228
+ export const HOMEPAGE_DESTINATION: string;
229
+ /**
230
+ * The top-level fields a homepage refuses, and what each would decide.
231
+ *
232
+ * `id` is the Foundry document id a compendium UUID is built from, and a
233
+ * homepage compiles into no document. `landing` is a card block; the homepage
234
+ * is a page with a body, rendered as one, so nothing reads it — and an index
235
+ * of what the package publishes is a `doc` note carrying a content table,
236
+ * authored where every other page is.
237
+ *
238
+ * `name` and `shortcode` are permitted: the shortcode is what a link is
239
+ * written with, and `name` titles the page like every other note's.
264
240
  *
265
241
  * **A named class, not an allow-list, and that boundary is the decision.** A
266
242
  * homepage's frontmatter is *emitted into the published page*
@@ -276,19 +252,3 @@ export const HOMEPAGE_SHORTCODE: string;
276
252
  * @type {ReadonlyMap<string, string>}
277
253
  */
278
254
  export const HOMEPAGE_REFUSED_FIELDS: ReadonlyMap<string, string>;
279
- /**
280
- * The two frontmatter keys that hold an address, and what each one means.
281
- *
282
- * They are **not** interchangeable, and a check that treated them as one would
283
- * be wrong about both. The theme resolves a `url` against the site with
284
- * `relURL`, so a package writes `kb/rules/` and is served `/sohl/kb/rules/`
285
- * without ever naming its own prefix. An `href` is an address that is *already*
286
- * resolved and is used verbatim — which is what `cards.source: sections` fills
287
- * in, since a section's permalink already carries the prefix.
288
- *
289
- * So a leading `/` is a defect in a `url` (it is prefixed a second time) and
290
- * correct in an `href`.
291
- *
292
- * @type {ReadonlySet<string>}
293
- */
294
- export const HOMEPAGE_ADDRESS_KEYS: ReadonlySet<string>;
@@ -50,18 +50,6 @@ export function exclusiveTagGroups(type: string, groups?: object): {
50
50
  * @returns {boolean} Whether the note carries it.
51
51
  */
52
52
  export function hasTag(fm: object | null | undefined, tag: string): boolean;
53
- /**
54
- * Whether a note carries any `tags:` at all, however authored.
55
- *
56
- * The one question the site build asks of tags in aggregate — whether the
57
- * tree publishes taxonomy pages — rather than about a particular tag. Reads
58
- * `tags` and `tag` exactly as {@link hasTag} does, and treats an empty list
59
- * or a blank string as carrying none.
60
- *
61
- * @param {object|null|undefined} fm - Parsed frontmatter.
62
- * @returns {boolean} Whether the note carries at least one tag.
63
- */
64
- export function hasAnyTag(fm: object | null | undefined): boolean;
65
53
  /**
66
54
  * Whether a note is tagged as an unfinished **draft**.
67
55
  *
@@ -46,25 +46,24 @@ export function collectHomepages(contentBase: string, ctx: object): {
46
46
  addressFindings: object[];
47
47
  };
48
48
  /**
49
- * Writes each homepage at its address, below the package's own root.
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, no section landing and no link resolution — so
53
- * routing it through {@link renderPages} would buy it a pipeline it has no input
54
- * for, and would make homepage-only mode depend on the index, the foreign
55
- * manifests and the table universe that mode exists to not build.
56
- *
57
- * **Verbatim is the answer, not a gap.** A landing's links
58
- * could not be *resolved* here without giving `homepage` mode the index its
59
- * licensing fence exists to not build, so they are **checked** instead:
60
- * {@link auditHomepageLinks} reads the `landing:` addresses and the body's
61
- * markdown links, and reports a wikilink on the page rather than resolving one.
62
- *
63
- * **Its destination is no longer fixed**. The file is written at the
64
- * note's address, flat at the package's site root, and the page states that
65
- * address as its `url` — the same separation of file from URL every other page
66
- * has. Nothing is written at `/<package>/` itself: that becomes a redirect the
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, or no section to be filed under — would silently drop a page.
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
- * theme reads: `breadcrumbs.html` builds its middle crumb from
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 now named
213
- * the same way, so the two agree. Filing it into `<section>/` so that
214
- * Hugo would read a section off its path; a section appears in no address, and
215
- * a directory chosen only to satisfy a rendering engine's idea of what a
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 rather than a section-relative half of it, so
219
- * two types cannot fight over one file: a `doc` note's `subType` may be spelled
220
- * the same as another note's `type`, and `doc-gear.md` and `weapongear-gear.md`
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, hasTags }: {
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, { hasTags }?: {
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 a site with no tagged notes renders.
163
+ * The kinds no site renders.
175
164
  *
176
- * A section exists only where `site.sections` declares one, so a tree holding
177
- * only the homepage emits nothing beyond it; a taxonomy nobody's notes fill
178
- * and a feed would be empty shells. A site whose notes carry `tags:` emits
179
- * `taxonomy` and `term` after all see {@link hugoConfig} but `RSS` is
180
- * disabled either way: nothing here publishes a feed.
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 lifetime pinned on the prefix-root redirect, and why it is pinned.
21
+ * The `_headers` file's contents: the `noindex` rules, and nothing else.
32
22
  *
33
- * Cloudflare Pages sets no `Cache-Control` on a redirect it generates those
34
- * responses carry `location` and nothing else and a 301 with no lifetime is
35
- * cached by a browser indefinitely, on the most-linked URL there is. An hour
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(pkg: string): string;
29
+ export function headers(): string;
60
30
  /**
61
- * Write `_headers` and `_redirects` beside the rendered site.
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