@heroiclands/package-build 0.6.0 → 3.0.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-content-build.md +965 -0
- package/CHANGELOG.md +95 -0
- package/CONTENT.md +824 -0
- package/MIGRATING.md +127 -0
- package/README.md +29 -17
- package/bin/content-build.mjs +1082 -0
- package/bin/package-build.mjs +2 -2
- package/bin/report.mjs +2 -2
- package/config.mjs +21 -18
- package/content-config.mjs +1424 -0
- package/coverage.mjs +1 -1
- package/e2e.mjs +1 -1
- package/engine/abbreviations.mjs +0 -0
- package/engine/base-compiler.mjs +608 -0
- package/engine/code-fences.mjs +311 -0
- package/engine/compendiums.mjs +353 -0
- package/engine/content-address.mjs +141 -0
- package/engine/content-links.mjs +438 -0
- package/engine/content-lint.mjs +204 -0
- package/engine/content-package.mjs +67 -0
- package/engine/content-slug.mjs +169 -0
- package/engine/content-tables.mjs +1216 -0
- package/engine/content-tree.mjs +56 -0
- package/engine/diagnostics.mjs +270 -0
- package/engine/field-reference.mjs +242 -0
- package/engine/field-spec.mjs +218 -0
- package/engine/foreign-catalog.mjs +450 -0
- package/engine/foreign-manifests.mjs +129 -0
- package/engine/frontmatter-lint.mjs +343 -0
- package/engine/frontmatter.mjs +258 -0
- package/engine/generate.mjs +305 -0
- package/engine/helpers.mjs +809 -0
- package/engine/ids.mjs +192 -0
- package/engine/index.mjs +142 -0
- package/engine/item-docs.mjs +153 -0
- package/engine/item-registry.mjs +129 -0
- package/engine/journals.mjs +374 -0
- package/engine/kb-manifest.mjs +473 -0
- package/engine/macros.mjs +333 -0
- package/engine/manifest-emit.mjs +339 -0
- package/engine/map-notes.mjs +1302 -0
- package/engine/pack-config.mjs +479 -0
- package/engine/pack-router.mjs +254 -0
- package/engine/prose-config.mjs +238 -0
- package/engine/prose-lint.mjs +294 -0
- package/engine/region-events.mjs +79 -0
- package/engine/scene-levels.mjs +420 -0
- package/engine/scenes.mjs +528 -0
- package/engine/site-build.mjs +778 -0
- package/engine/site-index.mjs +332 -0
- package/engine/web-wikilinks.mjs +330 -0
- package/engine/wikilink-syntax.mjs +105 -0
- package/engine/wikilinks.mjs +645 -0
- package/index.mjs +42 -25
- package/lang.mjs +1 -1
- package/manifest.mjs +79 -5
- package/markdownlint-config.mjs +45 -0
- package/package.json +78 -34
- package/prettier-config.mjs +34 -0
- package/sohl/actors.mjs +581 -0
- package/sohl/affiliation-standings.mjs +44 -0
- package/sohl/being-info.mjs +173 -0
- package/sohl/default-item-art.mjs +82 -0
- package/sohl/index.mjs +55 -0
- package/sohl/item-builders.mjs +114 -0
- package/sohl/item-fields.mjs +867 -0
- package/sohl/items.mjs +197 -0
- package/sohl/kb-passes.mjs +207 -0
- package/sohl/note-schemas.mjs +322 -0
- package/templates.mjs +1 -1
- package/types/config.d.mts +1 -1
- package/types/content-config.d.mts +571 -0
- package/types/engine/abbreviations.d.mts +44 -0
- package/types/engine/base-compiler.d.mts +320 -0
- package/types/engine/code-fences.d.mts +102 -0
- package/types/engine/compendiums.d.mts +77 -0
- package/types/engine/content-address.d.mts +61 -0
- package/types/engine/content-links.d.mts +87 -0
- package/types/engine/content-lint.d.mts +47 -0
- package/types/engine/content-package.d.mts +36 -0
- package/types/engine/content-slug.d.mts +59 -0
- package/types/engine/content-tables.d.mts +131 -0
- package/types/engine/content-tree.d.mts +12 -0
- package/types/engine/diagnostics.d.mts +152 -0
- package/types/engine/field-reference.d.mts +20 -0
- package/types/engine/field-spec.d.mts +181 -0
- package/types/engine/foreign-catalog.d.mts +103 -0
- package/types/engine/foreign-manifests.d.mts +43 -0
- package/types/engine/frontmatter-lint.d.mts +74 -0
- package/types/engine/frontmatter.d.mts +99 -0
- package/types/engine/generate.d.mts +56 -0
- package/types/engine/helpers.d.mts +348 -0
- package/types/engine/ids.d.mts +126 -0
- package/types/engine/index.d.mts +33 -0
- package/types/engine/item-docs.d.mts +73 -0
- package/types/engine/item-registry.d.mts +57 -0
- package/types/engine/journals.d.mts +121 -0
- package/types/engine/kb-manifest.d.mts +214 -0
- package/types/engine/macros.d.mts +201 -0
- package/types/engine/manifest-emit.d.mts +137 -0
- package/types/engine/map-notes.d.mts +283 -0
- package/types/engine/pack-config.d.mts +77 -0
- package/types/engine/pack-router.d.mts +53 -0
- package/types/engine/prose-config.d.mts +121 -0
- package/types/engine/prose-lint.d.mts +59 -0
- package/types/engine/region-events.d.mts +43 -0
- package/types/engine/scene-levels.d.mts +36 -0
- package/types/engine/scenes.d.mts +48 -0
- package/types/engine/site-build.d.mts +214 -0
- package/types/engine/site-index.d.mts +141 -0
- package/types/engine/web-wikilinks.d.mts +67 -0
- package/types/engine/wikilink-syntax.d.mts +101 -0
- package/types/engine/wikilinks.d.mts +172 -0
- package/types/index.d.mts +3 -0
- package/types/manifest.d.mts +52 -4
- package/types/markdownlint-config.d.mts +8 -0
- package/types/prettier-config.d.mts +1 -0
- package/types/sohl/actors.d.mts +65 -0
- package/types/sohl/affiliation-standings.d.mts +22 -0
- package/types/sohl/being-info.d.mts +78 -0
- package/types/sohl/default-item-art.d.mts +28 -0
- package/types/sohl/index.d.mts +7 -0
- package/types/sohl/item-builders.d.mts +11 -0
- package/types/sohl/item-fields.d.mts +20 -0
- package/types/sohl/items.d.mts +19 -0
- package/types/sohl/kb-passes.d.mts +71 -0
- package/types/sohl/note-schemas.d.mts +7 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
3
|
+
* Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
|
|
4
|
+
*
|
|
5
|
+
* This work is licensed under the GNU General Public License v3.0 (GPLv3).
|
|
6
|
+
* You may copy, modify, and distribute it under the terms of that license.
|
|
7
|
+
*
|
|
8
|
+
* For full terms, see the LICENSE.md file in the project root or visit:
|
|
9
|
+
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Journals pack compiler — produces JSON pack files for the "journals"
|
|
16
|
+
* Foundry compendium from markdown notes in the `assets/content/` tree.
|
|
17
|
+
*
|
|
18
|
+
* The content root (`contentBase`) is walked recursively; any `.md` file
|
|
19
|
+
* whose frontmatter declares `package: sohl` and either `type: doc` or a
|
|
20
|
+
* **doc-carrying type** ({@link sohl.utils.packs.docEntryTypes} — every item
|
|
21
|
+
* type, plus `macro`) is compiled into one JournalEntry document. Each note's
|
|
22
|
+
* body is split on top-level H1 headings; the optional content before the
|
|
23
|
+
* first H1 becomes a lead page, and each subsequent H1 starts a new page named
|
|
24
|
+
* after its heading text. All page bodies are rendered to HTML.
|
|
25
|
+
*
|
|
26
|
+
* A doc-carrying note compiles into that document's **documentation** — the
|
|
27
|
+
* same prose and pages, filed in the same folder as the document itself, which
|
|
28
|
+
* keeps only a pointer to it. See `item-docs.mjs` for why, and for the ids the
|
|
29
|
+
* two passes agree on. A macro note's `{#script}` page is compiled here like
|
|
30
|
+
* any other: the macro pass reads the same page independently, and withholds
|
|
31
|
+
* nothing from the journal (#1514).
|
|
32
|
+
*
|
|
33
|
+
* Folder placement is identical to the items pack: `sohl.folder` in
|
|
34
|
+
* frontmatter is the target folder's id (from folders.yaml), resolved
|
|
35
|
+
* against a folders.yaml list via the constructor's `folderResolver`. A
|
|
36
|
+
* documentation entry reuses its document's folder id verbatim.
|
|
37
|
+
*
|
|
38
|
+
* Not a standalone script — exports the `Journals` compiler class, imported
|
|
39
|
+
* and driven by `packages/content-build/engine/generate.mjs` (via `npm run build:compiledb`).
|
|
40
|
+
*
|
|
41
|
+
* The walk itself — filtering by package and type, skipping drafts,
|
|
42
|
+
* expanding tables, converting wikilinks, writing the JSON and counting
|
|
43
|
+
* errors — belongs to {@link sohl.utils.packs.BasePackCompiler}; this module
|
|
44
|
+
* states only what makes this pass its own (#1509).
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
import log from "loglevel";
|
|
48
|
+
|
|
49
|
+
import {
|
|
50
|
+
sohlField,
|
|
51
|
+
makeId,
|
|
52
|
+
resolveName,
|
|
53
|
+
defaultStats,
|
|
54
|
+
md,
|
|
55
|
+
} from "./helpers.mjs";
|
|
56
|
+
import { BasePackCompiler } from "./base-compiler.mjs";
|
|
57
|
+
import { contentPackage } from "./content-package.mjs";
|
|
58
|
+
import { anchorPageId } from "./wikilinks.mjs";
|
|
59
|
+
import { hasDocEntry, itemDocEntryId } from "./item-docs.mjs";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Splits a markdown body into pages by top-level H1 headings. Fenced
|
|
63
|
+
* code blocks are respected so `# foo` inside ``` blocks doesn't trigger
|
|
64
|
+
* a split. Content before the first H1 (if non-empty) becomes a leading
|
|
65
|
+
* page. Each H1 yields a page whose name is the heading
|
|
66
|
+
* text (with any `{#anchor-id}` suffix stripped out and surfaced as
|
|
67
|
+
* `anchorId`).
|
|
68
|
+
*
|
|
69
|
+
* `leadName` names that leading page. A journal note's is "Introduction",
|
|
70
|
+
* because it introduces the pages that follow. An item doc's is the item — a
|
|
71
|
+
* note with no headings at all is one page holding the whole description, and
|
|
72
|
+
* calling that page "Introduction" would label the description as a preamble to
|
|
73
|
+
* nothing.
|
|
74
|
+
*
|
|
75
|
+
* Returns an array of `{ name, anchorId, markdown }` in document order.
|
|
76
|
+
*/
|
|
77
|
+
export function splitPages(body, leadName = "Introduction") {
|
|
78
|
+
const lines = body.split("\n");
|
|
79
|
+
const pages = [];
|
|
80
|
+
const beforeFirstH1 = [];
|
|
81
|
+
let current = null;
|
|
82
|
+
let inCodeBlock = false;
|
|
83
|
+
|
|
84
|
+
const closeCurrent = () => {
|
|
85
|
+
if (!current) return;
|
|
86
|
+
pages.push({
|
|
87
|
+
name: current.name,
|
|
88
|
+
anchorSlug: current.anchorSlug,
|
|
89
|
+
level: current.level,
|
|
90
|
+
markdown: current.lines.join("\n").trim(),
|
|
91
|
+
});
|
|
92
|
+
current = null;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
if (line.trim().startsWith("```")) {
|
|
97
|
+
inCodeBlock = !inCodeBlock;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// An H1 starts a page, as does any heading carrying an `{#slug}`
|
|
101
|
+
// anchor: a Foundry UUID can only address a page, so a linkable
|
|
102
|
+
// section has to be one.
|
|
103
|
+
const headingMatch =
|
|
104
|
+
!inCodeBlock ? line.match(/^\s*(#{1,6})\s+(.+?)\s*#*\s*$/) : null;
|
|
105
|
+
const rawHeading = headingMatch?.[2]?.trim();
|
|
106
|
+
const anchorMatch = rawHeading?.match(/^(.*?)\s*\{#([^}]+)\}\s*$/);
|
|
107
|
+
const startsPage =
|
|
108
|
+
headingMatch && (headingMatch[1].length === 1 || anchorMatch);
|
|
109
|
+
if (startsPage) {
|
|
110
|
+
closeCurrent();
|
|
111
|
+
current = {
|
|
112
|
+
name: (anchorMatch ? anchorMatch[1] : rawHeading).trim(),
|
|
113
|
+
anchorSlug: anchorMatch?.[2]?.trim() || null,
|
|
114
|
+
level: headingMatch[1].length,
|
|
115
|
+
lines: [],
|
|
116
|
+
};
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (current) {
|
|
121
|
+
current.lines.push(line);
|
|
122
|
+
} else {
|
|
123
|
+
beforeFirstH1.push(line);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
closeCurrent();
|
|
127
|
+
|
|
128
|
+
const intro = beforeFirstH1.join("\n").trim();
|
|
129
|
+
if (intro) {
|
|
130
|
+
pages.unshift({
|
|
131
|
+
name: leadName,
|
|
132
|
+
anchorSlug: null,
|
|
133
|
+
level: 1,
|
|
134
|
+
markdown: intro,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return pages;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Two headings in one note sharing an `{#anchor}` derive the same page id, which
|
|
143
|
+
* the LevelDB packer reports only as an opaque duplicate-key collision. Catch it
|
|
144
|
+
* here, where the note and the slug can be named.
|
|
145
|
+
*
|
|
146
|
+
* @param {Array<{anchorSlug: string|null}>} rawPages - From {@link splitPages}.
|
|
147
|
+
* @param {string} noteName - The note, for the error message.
|
|
148
|
+
* @throws {Error} When an anchor is declared twice in the same note.
|
|
149
|
+
*/
|
|
150
|
+
export function assertUniqueAnchors(rawPages, noteName) {
|
|
151
|
+
const seen = new Set();
|
|
152
|
+
for (const page of rawPages) {
|
|
153
|
+
if (!page.anchorSlug) continue;
|
|
154
|
+
if (seen.has(page.anchorSlug)) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`note "${noteName}" declares the anchor {#${page.anchorSlug}} on more than one heading; an anchor must be unique within its note`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
seen.add(page.anchorSlug);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The id of one page within its entry.
|
|
165
|
+
*
|
|
166
|
+
* An anchored page takes the id its inbound links compute from the note id and
|
|
167
|
+
* the slug, so link and page agree without shared state. Every other page is
|
|
168
|
+
* keyed by its position and name, which is what lets the items pass address an
|
|
169
|
+
* item doc's first page without having compiled it (see
|
|
170
|
+
* {@link sohl.utils.packs.itemDocPointer}).
|
|
171
|
+
*
|
|
172
|
+
* @param {string} entryId - The owning JournalEntry's `_id`.
|
|
173
|
+
* @param {{anchorSlug: string|null, name: string}} page - From {@link splitPages}.
|
|
174
|
+
* @param {number} index - The page's position in the entry.
|
|
175
|
+
* @returns {string} A 16-character Foundry id.
|
|
176
|
+
*/
|
|
177
|
+
export function journalPageId(entryId, page, index) {
|
|
178
|
+
return page.anchorSlug ?
|
|
179
|
+
anchorPageId(entryId, page.anchorSlug)
|
|
180
|
+
: makeId("journal-page", `${entryId}:${index}:${page.name}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Compile split pages into JournalEntryPage documents.
|
|
185
|
+
*
|
|
186
|
+
* @param {Array<object>} rawPages - From {@link splitPages}.
|
|
187
|
+
* @param {string} entryId - The owning JournalEntry's `_id`.
|
|
188
|
+
* @param {string} noteName - The note, for error messages.
|
|
189
|
+
* @returns {Array<{_id: string, name: string, type: string,
|
|
190
|
+
* title: {show: boolean, level: number},
|
|
191
|
+
* text: {format: number, content: string}, _key: string}>} The page
|
|
192
|
+
* documents, in order.
|
|
193
|
+
* @throws {Error} When the note has no content at all, or repeats an anchor.
|
|
194
|
+
*/
|
|
195
|
+
export function buildPages(rawPages, entryId, noteName) {
|
|
196
|
+
if (rawPages.length === 0) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`note "${noteName}" has no Introduction content and no H1 headings — nothing to compile`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
assertUniqueAnchors(rawPages, noteName);
|
|
202
|
+
return rawPages.map((page, index) => {
|
|
203
|
+
const pageId = journalPageId(entryId, page, index);
|
|
204
|
+
return {
|
|
205
|
+
_id: pageId,
|
|
206
|
+
name: page.name,
|
|
207
|
+
type: "text",
|
|
208
|
+
title: { show: true, level: page.level ?? 1 },
|
|
209
|
+
text: {
|
|
210
|
+
format: 1,
|
|
211
|
+
content: page.markdown ? md.render(page.markdown) : "",
|
|
212
|
+
},
|
|
213
|
+
_key: `!journal.pages!${entryId}.${pageId}`,
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Assemble one JournalEntry document from a note's converted markdown.
|
|
220
|
+
*
|
|
221
|
+
* Shared with the scenes pass, which needs the *same* entry a map note's prose
|
|
222
|
+
* compiles into so it can bundle it into an Adventure alongside the Scene. Two
|
|
223
|
+
* passes deriving the same document from the same body is what keeps a map
|
|
224
|
+
* pin's `pageId` pointing at a page that actually exists.
|
|
225
|
+
*
|
|
226
|
+
* @param {object} params
|
|
227
|
+
* @param {string} params.id - The entry's `_id`.
|
|
228
|
+
* @param {string} params.name - The entry's name.
|
|
229
|
+
* @param {string} params.markdown - The body, tables expanded and wikilinks
|
|
230
|
+
* resolved.
|
|
231
|
+
* @param {string} [params.leadName] - Name for the page before the first
|
|
232
|
+
* heading; see {@link splitPages}.
|
|
233
|
+
* @param {string|null} [params.folder] - The folder id, or `null`.
|
|
234
|
+
* @param {object} [params.flags] - Document flags.
|
|
235
|
+
* @returns {object} The JournalEntry document, keyed for the pack.
|
|
236
|
+
*/
|
|
237
|
+
export function buildJournalEntry({
|
|
238
|
+
id,
|
|
239
|
+
name,
|
|
240
|
+
markdown,
|
|
241
|
+
leadName,
|
|
242
|
+
folder = null,
|
|
243
|
+
flags,
|
|
244
|
+
}) {
|
|
245
|
+
const rawPages = splitPages(markdown, leadName);
|
|
246
|
+
const pages = buildPages(rawPages, id, name);
|
|
247
|
+
return {
|
|
248
|
+
name,
|
|
249
|
+
pages,
|
|
250
|
+
folder,
|
|
251
|
+
sort: 0,
|
|
252
|
+
ownership: { default: 0 },
|
|
253
|
+
flags: flags || {},
|
|
254
|
+
_id: id,
|
|
255
|
+
_stats: defaultStats(),
|
|
256
|
+
_key: `!journal!${id}`,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export class Journals extends BasePackCompiler {
|
|
261
|
+
static id = "journals";
|
|
262
|
+
static label = "journal";
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* A note with no id is skipped with a warning rather than failing the
|
|
266
|
+
* build: unlike an item or a macro, an unidentified journal note is prose
|
|
267
|
+
* that simply never became an entry.
|
|
268
|
+
*/
|
|
269
|
+
static requiresId = false;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* How many of the compiled entries were documentation for a document
|
|
273
|
+
* compiled elsewhere, for the summary.
|
|
274
|
+
*
|
|
275
|
+
* @type {number}
|
|
276
|
+
*/
|
|
277
|
+
docEntries = 0;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Journal notes, plus every doc-carrying note — an item's prose is its
|
|
281
|
+
* documentation, so it compiles here and the item keeps a pointer to it
|
|
282
|
+
* (#1348); a macro's is the same arrangement (#1514), and so is a map's,
|
|
283
|
+
* whose prose is the place description its pins point at (#1525).
|
|
284
|
+
*
|
|
285
|
+
* The membership is {@link sohl.utils.packs.docEntryTypes}, read through
|
|
286
|
+
* {@link sohl.utils.packs.hasDocEntry} — the one set the link manifest also
|
|
287
|
+
* reads, so what compiles and what is published cannot drift apart.
|
|
288
|
+
*
|
|
289
|
+
* @param {object} fm - The note's frontmatter.
|
|
290
|
+
* @returns {boolean} True for a `doc` note or a doc-carrying note.
|
|
291
|
+
*/
|
|
292
|
+
selects(fm) {
|
|
293
|
+
return fm.type === "doc" || hasDocEntry(fm.type);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* An item with no prose gets no doc, and the items pass leaves its
|
|
298
|
+
* description empty rather than pointing at nothing; a map with no prose
|
|
299
|
+
* gets no entry and no pin target. The two passes apply the same rule to
|
|
300
|
+
* the same body, so they agree.
|
|
301
|
+
*
|
|
302
|
+
* @param {object} fm - The note's frontmatter.
|
|
303
|
+
* @param {string} body - The note body, frontmatter stripped.
|
|
304
|
+
* @returns {boolean} True to skip the note.
|
|
305
|
+
*/
|
|
306
|
+
skipNote(fm, body) {
|
|
307
|
+
return hasDocEntry(fm.type) && !String(body).trim();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Compile one note into a JournalEntry.
|
|
312
|
+
*
|
|
313
|
+
* A `doc` note becomes the entry its frontmatter describes. A
|
|
314
|
+
* **doc-carrying note** — every item note, and every macro note — becomes
|
|
315
|
+
* that document's documentation instead: the same prose, the same pages,
|
|
316
|
+
* in the same folder, under an id derived from the note's, so the pointer
|
|
317
|
+
* the items pass wrote resolves to it (see
|
|
318
|
+
* {@link sohl.utils.packs.itemDocPointer}). A macro's `{#script}` page is
|
|
319
|
+
* compiled here like any other; nothing is withheld from the journal
|
|
320
|
+
* because the macro pass also reads it (#1514).
|
|
321
|
+
*
|
|
322
|
+
* @param {object} fm - The note's frontmatter.
|
|
323
|
+
* @param {string} markdown - The body, tables expanded and wikilinks
|
|
324
|
+
* resolved. The links are resolved from the note as authored — against
|
|
325
|
+
* the note's own id, not the entry's.
|
|
326
|
+
* @returns {object} The JournalEntry document.
|
|
327
|
+
*/
|
|
328
|
+
buildEntry(fm, markdown) {
|
|
329
|
+
const name = resolveName(fm);
|
|
330
|
+
const ownsDoc = hasDocEntry(fm.type);
|
|
331
|
+
const id = ownsDoc ? itemDocEntryId(fm.id) : fm.id;
|
|
332
|
+
|
|
333
|
+
// A documentation entry is filed exactly where the document it
|
|
334
|
+
// describes is, so the journals pack mirrors the items pack and a doc
|
|
335
|
+
// sits under the same heading a reader found the item under. The id is
|
|
336
|
+
// taken verbatim rather than through `folderResolver`, which validates
|
|
337
|
+
// against this pack's own folders.yaml — an item folder is declared in
|
|
338
|
+
// the items one, a macro folder in the macros one, and a map's in the
|
|
339
|
+
// scenes one.
|
|
340
|
+
const folderId = sohlField(fm, "folder", null);
|
|
341
|
+
const folder = ownsDoc ? folderId : this.folderResolver(folderId);
|
|
342
|
+
|
|
343
|
+
return buildJournalEntry({
|
|
344
|
+
id,
|
|
345
|
+
name,
|
|
346
|
+
markdown,
|
|
347
|
+
// A doc-carrying note's lead page is the document itself, not an
|
|
348
|
+
// "Introduction" — see {@link splitPages}.
|
|
349
|
+
leadName: ownsDoc ? name : undefined,
|
|
350
|
+
folder,
|
|
351
|
+
flags: fm.flags,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** @inheritdoc */
|
|
356
|
+
onCompiled(fm) {
|
|
357
|
+
if (hasDocEntry(fm.type)) this.docEntries++;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** @inheritdoc */
|
|
361
|
+
reportCompiled(stats) {
|
|
362
|
+
log.info(
|
|
363
|
+
`Compiled ${stats.compiled} journal entr${stats.compiled === 1 ? "y" : "ies"} (${this.docEntries} documentation entr${this.docEntries === 1 ? "y" : "ies"})`,
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** @inheritdoc */
|
|
368
|
+
reportDetail(stats) {
|
|
369
|
+
log.debug(
|
|
370
|
+
`Skipped ${stats.skippedOther} non-doc file(s) ` +
|
|
371
|
+
`(not type:doc package:${contentPackage()})`,
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
}
|