@heroiclands/package-build 22.4.2 → 22.4.4

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.
@@ -148,15 +148,22 @@ export function homepageTitle(fm: object | null | undefined, config: object): st
148
148
  * redirect stub at each one. The field is retired and refused before a
149
149
  * build reaches here, which makes this a guard rather than a working path.
150
150
  *
151
+ * `related` is derived like every other page's — what links to the homepage
152
+ * is a fact about the rest of the tree — so an authored value is dropped and
153
+ * the caller's block, where it has one, is written in its place.
154
+ *
151
155
  * @param {object} fm - The note's frontmatter.
152
156
  * @param {object} options - Options.
153
157
  * @param {string} options.contentPackage - The package this build publishes.
154
158
  * @param {string} options.title - The resolved title.
159
+ * @param {object} [options.related] - The homepage's backlinks and mentions,
160
+ * where the site build found either.
155
161
  * @returns {object} The frontmatter to write.
156
162
  */
157
- export function homepageFrontmatter(fm: object, { contentPackage, title }: {
163
+ export function homepageFrontmatter(fm: object, { contentPackage, title, related }: {
158
164
  contentPackage: string;
159
165
  title: string;
166
+ related?: object | undefined;
160
167
  }): object;
161
168
  /**
162
169
  * Every address a homepage carries: the markdown links in its body.
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Inverts a link graph into each page's backlinks and mentions.
3
+ *
4
+ * An edge is `(source URL, target URL)`, and a URL that is not in `entries` is
5
+ * not a page of this site, so an edge touching one is dropped. A self-link says
6
+ * nothing a reader is not already looking at, and a page that links another
7
+ * three times is connected to it once, so both collapse.
8
+ *
9
+ * The result holds only pages with at least one connection, so the caller can
10
+ * write nothing on a page with none — the theme's silent-disappear convention,
11
+ * kept at the source rather than papered over with an empty block.
12
+ *
13
+ * @param {Iterable<readonly [string, string]>} edges - Every resolved link, as
14
+ * the source page's URL and the target page's.
15
+ * @param {ReadonlyMap<string, RelatedEntry>} entries - Every page of this
16
+ * site, keyed by URL.
17
+ * @returns {Map<string, Related>} URL → the page's `related` block, both lists
18
+ * sorted, for every page with at least one entry in either.
19
+ */
20
+ export function relatedPages(edges: Iterable<readonly [string, string]>, entries: ReadonlyMap<string, RelatedEntry>): Map<string, Related>;
21
+ /**
22
+ * The pages a homepage's body links to, as URLs.
23
+ *
24
+ * A homepage is published verbatim — no wikilink on it resolves, and its links
25
+ * are ordinary markdown the browser resolves against the page's own address,
26
+ * which is the package root. So its edges are read the same way: each target
27
+ * resolved against `base`, the way a browser would. A package-relative
28
+ * `being-x/`, a root-relative `/pkg/being-x/` and a `./being-x/#anchor` all
29
+ * name the same page; a bare `#anchor` names the homepage itself.
30
+ *
31
+ * A link that names a host or a scheme leaves the site, whatever path it
32
+ * carries, and yields nothing: the site's own pages are addressed without one.
33
+ *
34
+ * @param {string} body - The homepage's markdown body.
35
+ * @param {string} base - Where the package is served — the homepage's own URL.
36
+ * @returns {string[]} The targets' URLs, in body order, repeats included.
37
+ */
38
+ export function homepageLinkTargets(body: string, base: string): string[];
39
+ /**
40
+ * One entry in a `related` list — the page a reader is pointed at.
41
+ */
42
+ export type RelatedEntry = {
43
+ /**
44
+ * The page's published title.
45
+ */
46
+ title: string;
47
+ /**
48
+ * `<base><slug>/` — the page's address as every href
49
+ * this build renders composes it, never the
50
+ * site-root-relative form the page states for itself.
51
+ */
52
+ url: string;
53
+ /**
54
+ * The note's `type`, which the theme groups by.
55
+ */
56
+ type: string;
57
+ };
58
+ /**
59
+ * The `related` block one page publishes.
60
+ */
61
+ export type Related = {
62
+ /**
63
+ * Pages that link to this one.
64
+ */
65
+ backlinks: RelatedEntry[];
66
+ /**
67
+ * Pages this one links to.
68
+ */
69
+ mentions: RelatedEntry[];
70
+ };
@@ -65,14 +65,27 @@ export function collectHomepages(contentBase: string, ctx: object): {
65
65
  * states no `url` — the home kind has none to state — and the mount below it
66
66
  * holds pages and nothing else, so this is the only `_index.md` in the tree.
67
67
  *
68
+ * **Verbatim, but not unconnected.** The homepage is a page like any other on
69
+ * both sides of the link graph: a content page reaches it through
70
+ * `[[homepage-root|Text]]`, and its own markdown links name content pages. So
71
+ * it carries the same `related` block every content page does — handed in by
72
+ * the caller, since the graph is read off the content render and homepage-only
73
+ * mode has none.
74
+ *
68
75
  * @param {string} outRoot - The package's site root — the content mount's
69
76
  * root, `build/hugo/content`, one level above the mount itself.
70
77
  * @param {readonly object[]} pages - From {@link collectHomepages}.
71
78
  * @param {object} config - The resolved configuration, for the package name and
72
79
  * the default title.
80
+ * @param {object} [options] - Options.
81
+ * @param {import("./related-pages.mjs").Related} [options.related] - The
82
+ * homepage's backlinks and mentions. Absent where nothing connects to it,
83
+ * and in homepage-only mode, where no link resolves.
73
84
  * @returns {number} How many pages were written.
74
85
  */
75
- export function writeHomepages(outRoot: string, pages: readonly object[], config: object): number;
86
+ export function writeHomepages(outRoot: string, pages: readonly object[], config: object, { related }?: {
87
+ related?: import("./related-pages.mjs").Related | undefined;
88
+ }): number;
76
89
  /**
77
90
  * The integrity gates a site build runs before it writes anything.
78
91
  *
@@ -159,6 +172,12 @@ export function tableUniverse(pages: object[]): Map<string, object[]>;
159
172
  * self-describing and makes sweeping the field out of a content tree
160
173
  * output-preserving for a site as it already is for the packs.
161
174
  *
175
+ * **`related` is derived, never authored.** What links to a page is a fact
176
+ * about every other page, known only once the whole tree has resolved — see
177
+ * {@link module:engine/related-pages} — so an authored value is dropped the
178
+ * way `aliases` is, and {@link renderPages} writes the derived block once it
179
+ * holds the graph.
180
+ *
162
181
  * @param {object} page - The page.
163
182
  * @param {object} options
164
183
  * @param {(data: object, page: object) => void} [options.decorate] - Called
@@ -210,10 +229,23 @@ export function pageDestination(page: object): string;
210
229
  * touches, so the repository's own rewrite runs before the shared one
211
230
  * rather than replacing it.
212
231
  *
232
+ * **Every page is rendered before any is written.** What links *to* a page is
233
+ * known only once every other page has resolved, and it is written into the
234
+ * page's own front matter, so the render is one pass over the tree and the
235
+ * write is a second — with the link graph read off the first, at the one
236
+ * point the resolver answers, and inverted once between them. Nothing is
237
+ * resolved twice.
238
+ *
213
239
  * @param {object[]} pages - Every page.
214
- * @param {object} options - Everything the render needs.
240
+ * @param {object} options - Everything the render needs. `homepages` is the
241
+ * homepage as the index knows it — `{ fm, body, url, title }` — which takes
242
+ * no part in the render and every part in the graph: a content page links
243
+ * it by wikilink, and its own markdown links name content pages.
215
244
  * @returns {{written: number, byKind: Record<string, number>, tableErrors: object[],
216
- * wikiErrors: object[], imageErrors: object[]}}
245
+ * wikiErrors: object[], imageErrors: object[],
246
+ * related: Map<string, import("./related-pages.mjs").Related>}} `related`
247
+ * is keyed by page URL, and holds the homepage's block beside every content
248
+ * page's, so the caller can write it on the page this render does not.
217
249
  */
218
250
  export function renderPages(pages: object[], options: object): {
219
251
  written: number;
@@ -221,6 +253,7 @@ export function renderPages(pages: object[], options: object): {
221
253
  tableErrors: object[];
222
254
  wikiErrors: object[];
223
255
  imageErrors: object[];
256
+ related: Map<string, import("./related-pages.mjs").Related>;
224
257
  };
225
258
  /**
226
259
  * Resolves `site.pass` to its bundle.
@@ -41,6 +41,9 @@ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, no
41
41
  * resolvers that distinguish a foreign hit from a local one.
42
42
  * @param {object} [options.assets] - The address space an `![[…]]` embed
43
43
  * resolves against, shaped as every asset resolver reads one.
44
+ * @param {object[]} [options.resolved] - Collector the resolver appends every
45
+ * resolved target's index entry to — the page's outbound edges, read off
46
+ * the one pass that resolves them.
44
47
  * @returns {object} The resolver context.
45
48
  *
46
49
  * There is deliberately **no `manifestsComplete`**. It used to let a resolver
@@ -49,13 +52,14 @@ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, no
49
52
  * checker never had it and one authored link must not get two verdicts. A
50
53
  * caller still passing it is ignored rather than obeyed.
51
54
  */
52
- export function wikiContext(built: SiteIndex, { src, file, type, errors, foreignIndex, assets }: {
55
+ export function wikiContext(built: SiteIndex, { src, file, type, errors, foreignIndex, assets, resolved }: {
53
56
  src: string;
54
57
  type?: string | null | undefined;
55
58
  errors: object[];
56
59
  file?: string | undefined;
57
60
  foreignIndex?: Map<string, object> | undefined;
58
61
  assets?: object | undefined;
62
+ resolved?: object[] | undefined;
59
63
  }): object;
60
64
  /**
61
65
  * Resolve one infobox reference against a site index.
@@ -76,9 +76,17 @@ export function frontmatterWikilinks(fm: unknown): Array<{
76
76
  * {@link module:engine/content-images.renderImageFigures} turns into a figure
77
77
  * for the website, and what the book reads its staging list out of.
78
78
  *
79
+ * ## Every hit is recorded, so the page's edges come out of one pass
80
+ *
81
+ * A caller that hands in `ctx.resolved` is given every index entry a link on
82
+ * the page resolved to, in body order, repeats included. That is the link
83
+ * graph, read at the one point where it exists: the build never has to walk a
84
+ * page a second time to learn what it links to. Nothing is recorded for a
85
+ * same-page anchor or for a target that resolved nowhere.
86
+ *
79
87
  * @param {string} body - The markdown body.
80
88
  * @param {object} ctx - `{ index, assets, collide, contentTypes,
81
- * packages, noIndexPackages, foreign, type, errors, src, file }`.
89
+ * packages, noIndexPackages, foreign, type, errors, src, file, resolved }`.
82
90
  * `packages` is every package an address may name, without which the leading
83
91
  * package segment of a canonical address reads as an unknown type;
84
92
  * `noIndexPackages` is every package declared `contentIndex: false`, so a
@@ -87,7 +95,8 @@ export function frontmatterWikilinks(fm: unknown): Array<{
87
95
  * is the cross-package manifest index; `assets` is the address space an embed
88
96
  * resolves against. `src` is the page's display
89
97
  * path and `file` the source file a diagnostic should name — absent, `src`
90
- * stands in.
98
+ * stands in. `resolved`, when supplied, is the array every resolved
99
+ * target's index entry is appended to.
91
100
  * @returns {string} The body with embeds and wikilinks rewritten.
92
101
  */
93
102
  export function resolveWebWikilinks(body: string, ctx: object): string;