@heroiclands/package-build 22.21.0 → 22.23.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 +223 -0
- package/assets/styles/content-base.css +162 -0
- package/bin/content-commands.mjs +77 -17
- package/bin/package-build.mjs +15 -2
- package/ci/content-format-reference.mjs +68 -1
- package/config.mjs +26 -0
- package/content-config.mjs +153 -6
- package/docs/api.md +120 -89
- package/docs/authoring/assets.md +14 -0
- package/docs/authoring/dates-and-calendars.md +41 -3
- package/docs/authoring/frontmatter.md +2 -2
- package/docs/authoring/links-and-markup.md +325 -35
- package/docs/commands.md +12 -10
- package/docs/configuration.md +117 -14
- package/docs/content-format.md +4 -2
- package/docs/guides/book.md +5 -4
- package/docs/guides/reference-pages.md +15 -0
- package/docs/reference/format-details.md +545 -104
- package/docs/reference/note-types.md +30 -13
- package/engine/actor-compiler.mjs +23 -0
- package/engine/anchored-sections.mjs +35 -4
- package/engine/anchors.mjs +26 -30
- package/engine/art-fields.mjs +118 -0
- package/engine/art-slots.mjs +7 -1
- package/engine/asset-index.mjs +160 -10
- package/engine/asset-replacement.mjs +93 -0
- package/engine/asset-types.mjs +240 -0
- package/engine/base-compiler.mjs +139 -22
- package/engine/base-styles.mjs +149 -0
- package/engine/bundles.mjs +13 -2
- package/engine/compendiums.mjs +8 -1
- package/engine/content-blocks.mjs +410 -0
- package/engine/content-embeds.mjs +19 -0
- package/engine/content-figures.mjs +468 -0
- package/engine/content-footnotes.mjs +197 -0
- package/engine/content-format-check.mjs +15 -12
- package/engine/content-format.yaml +1 -1
- package/engine/content-images.mjs +126 -25
- package/engine/content-index.mjs +38 -12
- package/engine/content-links.mjs +14 -6
- package/engine/content-tables.mjs +45 -4
- package/engine/content-tasklists.mjs +189 -0
- package/engine/docs-checks.mjs +4 -4
- package/engine/extension-attributes.mjs +48 -2
- package/engine/field-reference.mjs +31 -10
- package/engine/field-spec.mjs +10 -8
- package/engine/foreign-catalog.mjs +143 -18
- package/engine/frontmatter-lint.mjs +120 -65
- package/engine/frontmatter.mjs +3 -3
- package/engine/heading-attributes.mjs +321 -0
- package/engine/helpers.mjs +109 -41
- package/engine/homepage.mjs +8 -8
- package/engine/index.mjs +3 -0
- package/engine/infobox-registry.mjs +4 -1
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +129 -15
- package/engine/itinerary-scenes.mjs +4 -10
- package/engine/journals.mjs +294 -50
- package/engine/lore-events.mjs +197 -0
- package/engine/macros.mjs +1 -1
- package/engine/markdown-expressions.mjs +434 -59
- package/engine/note-dates.mjs +354 -12
- package/engine/note-frontmatter.mjs +7 -16
- package/engine/note-vocabulary.mjs +183 -42
- package/engine/page-lists.mjs +358 -0
- package/engine/pathnames.mjs +36 -0
- package/engine/pdf-build.mjs +431 -74
- package/engine/pdf-images.mjs +64 -0
- package/engine/pdf-render.mjs +563 -66
- package/engine/rank-ladder.mjs +198 -0
- package/engine/reckoning-markers.mjs +1 -1
- package/engine/retired-fields.mjs +8 -13
- package/engine/scenes.mjs +26 -7
- package/engine/site-build.mjs +166 -23
- package/engine/site-config.mjs +10 -1
- package/engine/site-index.mjs +90 -3
- package/engine/site-preview.mjs +20 -7
- package/engine/social-ties.mjs +52 -14
- package/engine/sql-tables.mjs +66 -9
- package/engine/standings.mjs +89 -6
- package/engine/system-block.mjs +56 -30
- package/engine/web-wikilinks.mjs +48 -1
- package/hm3/actors.mjs +8 -5
- package/manifest.mjs +43 -24
- package/package.json +1 -1
- package/packagebuild-metadata.jsonl +13 -13
- package/sohl/actors.mjs +22 -99
- package/sohl/item-fields.mjs +5 -5
- package/sohl/items.mjs +1 -1
- package/sohl/note-schemas.mjs +11 -21
- package/types/config.d.mts +9 -0
- package/types/content-config.d.mts +48 -1
- package/types/engine/actor-compiler.d.mts +11 -0
- package/types/engine/anchored-sections.d.mts +24 -0
- package/types/engine/anchors.d.mts +9 -4
- package/types/engine/art-fields.d.mts +64 -0
- package/types/engine/asset-index.d.mts +43 -0
- package/types/engine/asset-replacement.d.mts +22 -0
- package/types/engine/asset-types.d.mts +18 -0
- package/types/engine/base-compiler.d.mts +19 -17
- package/types/engine/base-styles.d.mts +93 -0
- package/types/engine/content-blocks.d.mts +87 -0
- package/types/engine/content-embeds.d.mts +16 -0
- package/types/engine/content-figures.d.mts +101 -0
- package/types/engine/content-footnotes.d.mts +80 -0
- package/types/engine/content-format-check.d.mts +8 -6
- package/types/engine/content-images.d.mts +78 -12
- package/types/engine/content-index.d.mts +8 -2
- package/types/engine/content-tables.d.mts +12 -4
- package/types/engine/content-tasklists.d.mts +72 -0
- package/types/engine/extension-attributes.d.mts +22 -1
- package/types/engine/field-reference.d.mts +21 -0
- package/types/engine/field-spec.d.mts +20 -16
- package/types/engine/foreign-catalog.d.mts +39 -0
- package/types/engine/frontmatter.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +179 -0
- package/types/engine/helpers.d.mts +29 -10
- package/types/engine/homepage.d.mts +7 -7
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox-registry.d.mts +4 -1
- package/types/engine/infobox-render.d.mts +6 -1
- package/types/engine/infobox.d.mts +6 -0
- package/types/engine/journals.d.mts +41 -12
- package/types/engine/lore-events.d.mts +14 -0
- package/types/engine/markdown-expressions.d.mts +46 -2
- package/types/engine/note-dates.d.mts +64 -1
- package/types/engine/note-frontmatter.d.mts +1 -4
- package/types/engine/note-vocabulary.d.mts +82 -6
- package/types/engine/page-lists.d.mts +126 -0
- package/types/engine/pathnames.d.mts +26 -0
- package/types/engine/pdf-build.d.mts +28 -6
- package/types/engine/pdf-images.d.mts +52 -0
- package/types/engine/pdf-render.d.mts +84 -2
- package/types/engine/rank-ladder.d.mts +32 -0
- package/types/engine/retired-fields.d.mts +4 -6
- package/types/engine/site-build.d.mts +27 -4
- package/types/engine/site-config.d.mts +9 -0
- package/types/engine/site-index.d.mts +67 -1
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -7
- package/types/engine/standings.d.mts +21 -3
- package/types/engine/system-block.d.mts +37 -14
- package/types/engine/web-wikilinks.d.mts +3 -1
- package/types/hm3/actors.d.mts +21 -3
- package/types/manifest.d.mts +19 -23
- package/types/sohl/actors.d.mts +6 -7
- package/engine/content-admonitions.mjs +0 -114
- package/engine/content-captions.mjs +0 -181
- package/engine/content-secrets.mjs +0 -112
- package/types/engine/content-admonitions.d.mts +0 -24
- package/types/engine/content-captions.d.mts +0 -45
- package/types/engine/content-secrets.d.mts +0 -17
|
@@ -0,0 +1,198 @@
|
|
|
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
|
+
* What a **rung** of an affiliation's rank ladder has to state.
|
|
16
|
+
*
|
|
17
|
+
* A rung is a map of `level`, `title` and `description`, all three required,
|
|
18
|
+
* plus an optional `lore` Address for a standing that needs more said about it
|
|
19
|
+
* than a description can hold. Those three keys together are a complete
|
|
20
|
+
* statement of a rung; nothing further is needed for a ladder to be correct.
|
|
21
|
+
*
|
|
22
|
+
* **A level belongs to one rung.** The ladder is read by level, so two rungs
|
|
23
|
+
* claiming one level leave a member's `rank` answering to whichever is written
|
|
24
|
+
* first — a standing whose name changes when two lines swap places. A body that
|
|
25
|
+
* confers two titles at one standing writes them as one rung, or gives each its
|
|
26
|
+
* own level.
|
|
27
|
+
*
|
|
28
|
+
* **The severity is error**, because the ladder is what a being's `rank`
|
|
29
|
+
* indexes into: a rung missing its `title` makes a standing that resolves to
|
|
30
|
+
* nothing, and one missing its `description` ships a rung that says nothing on
|
|
31
|
+
* a sheet or a page.
|
|
32
|
+
*
|
|
33
|
+
* Two things are deliberately **not** checked here, because something else
|
|
34
|
+
* already does and a finding reported twice is a finding read once and fixed
|
|
35
|
+
* neither time:
|
|
36
|
+
*
|
|
37
|
+
* - **that `ranks` is a list at all** — the field declares `kind: "list"`, and
|
|
38
|
+
* the shape check names it;
|
|
39
|
+
* - **that `lore` resolves** — the reference checker reads every Address in the
|
|
40
|
+
* note, this one included.
|
|
41
|
+
*
|
|
42
|
+
* @module
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
46
|
+
|
|
47
|
+
/** The keys a rung may carry. */
|
|
48
|
+
const RUNG_KEYS = Object.freeze(["level", "title", "description", "lore"]);
|
|
49
|
+
|
|
50
|
+
/** The keys a rung must carry a value for. */
|
|
51
|
+
const REQUIRED_TEXT = Object.freeze(["title", "description"]);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether a value is a YAML mapping rather than a list or a scalar.
|
|
55
|
+
*
|
|
56
|
+
* @param {unknown} value - What was authored.
|
|
57
|
+
* @returns {boolean} True for a mapping.
|
|
58
|
+
*/
|
|
59
|
+
function mapping(value) {
|
|
60
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Whether a value states a whole number.
|
|
65
|
+
*
|
|
66
|
+
* A quoted `"3"` counts, because YAML hands a quoted scalar back as a string
|
|
67
|
+
* and the ladder reads it as a number either way — `3.5` does not, because a
|
|
68
|
+
* rung sits on a rung and there is nothing between two of them.
|
|
69
|
+
*
|
|
70
|
+
* @param {unknown} value - The authored `level`.
|
|
71
|
+
* @returns {boolean} True when it is an integer.
|
|
72
|
+
*/
|
|
73
|
+
function integer(value) {
|
|
74
|
+
if (typeof value === "number") return Number.isInteger(value);
|
|
75
|
+
if (typeof value !== "string" || value.trim() === "") return false;
|
|
76
|
+
return Number.isInteger(Number(value));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Whether a value states something rather than nothing.
|
|
81
|
+
*
|
|
82
|
+
* @param {unknown} value - The authored `title` or `description`.
|
|
83
|
+
* @returns {boolean} True for a non-empty string.
|
|
84
|
+
*/
|
|
85
|
+
function stated(value) {
|
|
86
|
+
return typeof value === "string" && value.trim() !== "";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check one affiliation's `data.governance.ranks` against the rung contract.
|
|
91
|
+
*
|
|
92
|
+
* Each problem is its own finding, so a rung missing all three of its required
|
|
93
|
+
* keys reports three rather than the first: a reader fixing a ladder wants the
|
|
94
|
+
* whole of it in one pass.
|
|
95
|
+
*
|
|
96
|
+
* **A finding is located by the node it is about**, through the frontmatter's
|
|
97
|
+
* own YAML tree — a present-but-wrong value points at that value, and an absent
|
|
98
|
+
* key points at the rung that should have carried it, since a key that was
|
|
99
|
+
* never written has no position of its own. Where even the rung cannot be
|
|
100
|
+
* located the position is dropped rather than guessed, and the finding names
|
|
101
|
+
* the file alone.
|
|
102
|
+
*
|
|
103
|
+
* @param {object} note - The note being checked.
|
|
104
|
+
* @param {string} note.file - Its path, as a diagnostic spells it.
|
|
105
|
+
* @param {string} [note.raw] - Its source, for the position.
|
|
106
|
+
* @param {object} [note.fm] - Its parsed frontmatter.
|
|
107
|
+
* @returns {Array<{file: string, line?: number, column?: number,
|
|
108
|
+
* severity: string, message: string}>} The findings, in authored order.
|
|
109
|
+
*/
|
|
110
|
+
export function checkRankLadder(note) {
|
|
111
|
+
const ranks = note.fm?.data?.governance?.ranks;
|
|
112
|
+
// Absent is the ordinary case: most bodies confer no ranks at all. A value
|
|
113
|
+
// that is not a list is the shape check's finding, not this one's.
|
|
114
|
+
if (!Array.isArray(ranks)) return [];
|
|
115
|
+
|
|
116
|
+
const findings = [];
|
|
117
|
+
const base = ["data", "governance", "ranks"];
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* One finding, located at the first of the given paths that resolves.
|
|
121
|
+
*
|
|
122
|
+
* @param {Array<Array<string|number>>} paths - Candidates, most specific
|
|
123
|
+
* first.
|
|
124
|
+
* @param {string} message - What is wrong.
|
|
125
|
+
* @returns {void}
|
|
126
|
+
*/
|
|
127
|
+
const at = (paths, message) => {
|
|
128
|
+
let position = {};
|
|
129
|
+
for (const path of paths) {
|
|
130
|
+
position = positionOfFrontmatterPath(note.raw ?? "", path);
|
|
131
|
+
if (position.line !== undefined) break;
|
|
132
|
+
}
|
|
133
|
+
findings.push({ file: note.file, ...position, severity: "error", message });
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Level → how the rung holding it is named, so a repeat can say which rung
|
|
137
|
+
// already holds the level rather than only that something does.
|
|
138
|
+
const held = new Map();
|
|
139
|
+
|
|
140
|
+
ranks.forEach((rung, index) => {
|
|
141
|
+
const rungPath = [...base, index];
|
|
142
|
+
// Named by its level where it states one, because a reader scanning a
|
|
143
|
+
// ladder of fifteen rungs knows them by level and not by position.
|
|
144
|
+
const which =
|
|
145
|
+
integer(rung?.level) ? `rank ${rung.level}` : `rank ${index + 1} of the ladder`;
|
|
146
|
+
|
|
147
|
+
if (!mapping(rung)) {
|
|
148
|
+
at([rungPath, base], `${which} must be a map of level, title and description`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const key of Object.keys(rung)) {
|
|
153
|
+
if (RUNG_KEYS.includes(key)) continue;
|
|
154
|
+
at(
|
|
155
|
+
[[...rungPath, key], rungPath],
|
|
156
|
+
`${which} has unknown key ${key}; a rung takes ${RUNG_KEYS.join(", ")}`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!integer(rung.level)) {
|
|
161
|
+
at(
|
|
162
|
+
[[...rungPath, "level"], rungPath],
|
|
163
|
+
rung.level === undefined || rung.level === null ?
|
|
164
|
+
`${which} needs a level — the rung's position on this body's own ladder`
|
|
165
|
+
: `${which} has a level that is not a whole number`,
|
|
166
|
+
);
|
|
167
|
+
} else {
|
|
168
|
+
// A level belongs to one rung. Two rungs claiming it leave a
|
|
169
|
+
// member's `rank` answering to the one written first, so the
|
|
170
|
+
// ladder's own order decides what the standing is called and
|
|
171
|
+
// moving two lines renames it. Reported on the second rung,
|
|
172
|
+
// naming the first, because the first is the one a reader has to
|
|
173
|
+
// find to tell the two apart.
|
|
174
|
+
const level = Number(rung.level);
|
|
175
|
+
const named = stated(rung.title) ? JSON.stringify(rung.title) : which;
|
|
176
|
+
const first = held.get(level);
|
|
177
|
+
if (first === undefined) held.set(level, named);
|
|
178
|
+
else
|
|
179
|
+
at(
|
|
180
|
+
[[...rungPath, "level"], rungPath],
|
|
181
|
+
`rank ${level} is declared twice, as ${first} and ${named}; a level ` +
|
|
182
|
+
`is a rung's identity and a member's rank indexes into it, so ` +
|
|
183
|
+
`each rung states its own`,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
for (const key of REQUIRED_TEXT) {
|
|
188
|
+
if (stated(rung[key])) continue;
|
|
189
|
+
at(
|
|
190
|
+
[[...rungPath, key], rungPath],
|
|
191
|
+
`${which} needs a ${key}: ` +
|
|
192
|
+
(key === "title" ? "what the standing is called" : "what the standing is"),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return findings;
|
|
198
|
+
}
|
|
@@ -54,7 +54,7 @@ export function resolveReckoningMarkers(index, daysPerYear) {
|
|
|
54
54
|
1,
|
|
55
55
|
daysPerYear,
|
|
56
56
|
);
|
|
57
|
-
const pkg =
|
|
57
|
+
const pkg = note.package ?? index?.contentPackage;
|
|
58
58
|
const declared = [];
|
|
59
59
|
for (const [position, era] of rows.entries()) {
|
|
60
60
|
if (!era || typeof era.shortcode !== "string" || !era.shortcode || !fm.shortcode)
|
|
@@ -58,11 +58,9 @@
|
|
|
58
58
|
* one of them in. Every note that carried one has been moved, across four
|
|
59
59
|
* repositories, and this is the third step of that retirement.
|
|
60
60
|
*
|
|
61
|
-
* Refusing it
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* the page as a theme parameter, checked by nothing. The whole argument for
|
|
65
|
-
* `data:` being closed is the argument for refusing this.
|
|
61
|
+
* Refusing it by name rather than as an unknown key is what names the home the
|
|
62
|
+
* facts have: the finding says which `data:` key each one becomes, which an
|
|
63
|
+
* author cannot read off a list of the keys the region declares.
|
|
66
64
|
*
|
|
67
65
|
* `sohl.traits` is a different field that shares the name — `projectilegear`
|
|
68
66
|
* declares one, and the theme's gear sidebar reads it — so the refusal is
|
|
@@ -350,8 +348,7 @@ export function traitsRetiredMessage(file) {
|
|
|
350
348
|
(file ? ` — ${file}` : "") +
|
|
351
349
|
". A being's own description belongs in the closed container the " +
|
|
352
350
|
"content format declares, where `being` declares every one of its " +
|
|
353
|
-
"keys
|
|
354
|
-
"so a misspelling became a theme parameter rather than a finding. " +
|
|
351
|
+
"keys. " +
|
|
355
352
|
"`gender`, `species`, `age` and `appearance.*` move unchanged; " +
|
|
356
353
|
"`traits.birthday` becomes `data.born`; three reshape — " +
|
|
357
354
|
"`traits.height.m` becomes `data.height` " +
|
|
@@ -526,12 +523,10 @@ export function legacyKeyMessage(block, field, file) {
|
|
|
526
523
|
* What a note writing a field at the **top-level key `data:` gathered it off**
|
|
527
524
|
* is told.
|
|
528
525
|
*
|
|
529
|
-
* {@link legacyKeyMessage}'s counterpart for the other retiring position.
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* of `data.portrait`, and both are read for the same reason both in-block
|
|
534
|
-
* spellings are: a package moves its corpus when it is ready, not on a flag day.
|
|
526
|
+
* {@link legacyKeyMessage}'s counterpart for the other retiring position.
|
|
527
|
+
* `portrait:` beside `img:` is the bare spelling of `data.portrait`, and both
|
|
528
|
+
* are read for the same reason both in-block spellings are: a package moves its
|
|
529
|
+
* corpus when it is ready, not on a flag day.
|
|
535
530
|
*
|
|
536
531
|
* It says nothing about which value is emitted, because that is not what an
|
|
537
532
|
* author needs from it. The value is the same either way; what the finding
|
package/engine/scenes.mjs
CHANGED
|
@@ -50,6 +50,10 @@ import fs from "fs";
|
|
|
50
50
|
import path from "path";
|
|
51
51
|
import log from "loglevel";
|
|
52
52
|
|
|
53
|
+
// The one reader of a system block's own properties, so a scene's effect
|
|
54
|
+
// references resolve from the same position the item compiler emits from.
|
|
55
|
+
import { blockProperty } from "./system-block.mjs";
|
|
56
|
+
|
|
53
57
|
import {
|
|
54
58
|
parseMarkdownFile,
|
|
55
59
|
sohlField,
|
|
@@ -76,7 +80,7 @@ import { behaviorDocId, buildScene, isMapType, regionDocId } from "./map-notes.m
|
|
|
76
80
|
import { buildItineraryScenes } from "./itinerary-scenes.mjs";
|
|
77
81
|
import { emitDiagnostic } from "./diagnostics.mjs";
|
|
78
82
|
import { rasterizeMapSvg } from "./map-raster.mjs";
|
|
79
|
-
import { artPathname, artSlot } from "./art-fields.mjs";
|
|
83
|
+
import { artPathname, artSlot, pathnameRoles } from "./art-fields.mjs";
|
|
80
84
|
import { buildExportedScene } from "./exported-scene.mjs";
|
|
81
85
|
|
|
82
86
|
/**
|
|
@@ -235,7 +239,11 @@ export class Scenes extends BasePackCompiler {
|
|
|
235
239
|
// `resolveNoteId(fm)` with no package, which falls back to the
|
|
236
240
|
// ambient one. What remains unset is a file with no address.
|
|
237
241
|
if (!fm || !fm.id) continue;
|
|
238
|
-
|
|
242
|
+
// The Active Effects a region behaviour may point at, read from
|
|
243
|
+
// the block that carries them onto the document — the one position
|
|
244
|
+
// the format accepts for them.
|
|
245
|
+
const effects = blockProperty(fm, "sohl", "effects");
|
|
246
|
+
if (fm.shortcode && Array.isArray(effects) && effects.length) {
|
|
239
247
|
effectsByAddress.set(`${fm.type}-${fm.shortcode}`, {
|
|
240
248
|
id: fm.id,
|
|
241
249
|
type: fm.type,
|
|
@@ -246,7 +254,7 @@ export class Scenes extends BasePackCompiler {
|
|
|
246
254
|
// second router is a second answer to where the document
|
|
247
255
|
// landed, resolved from the working directory.
|
|
248
256
|
pack: this.#packRouter.resolveOrNull(fm, packForType(fm.type).docType),
|
|
249
|
-
effects
|
|
257
|
+
effects,
|
|
250
258
|
});
|
|
251
259
|
}
|
|
252
260
|
if (!isMapType(fm.type)) continue;
|
|
@@ -387,11 +395,15 @@ export class Scenes extends BasePackCompiler {
|
|
|
387
395
|
* @param {string} markdown - The converted body.
|
|
388
396
|
* @param {string} entryId - The JournalEntry's id.
|
|
389
397
|
* @param {string} name - The map's name (its lead page).
|
|
398
|
+
* @param {(address: string) => string|undefined} resolveRole - See
|
|
399
|
+
* {@link module:engine/journals.splitPages}; threaded through so an
|
|
400
|
+
* unanchored map figure's page key agrees with the journal this pass
|
|
401
|
+
* derives it against.
|
|
390
402
|
* @returns {Map<string, string>} heading key → page id.
|
|
391
403
|
*/
|
|
392
|
-
#pageIds(markdown, entryId, name) {
|
|
404
|
+
#pageIds(markdown, entryId, name, resolveRole) {
|
|
393
405
|
const pageIds = new Map();
|
|
394
|
-
splitPages(markdown, name).forEach((page) => {
|
|
406
|
+
splitPages(markdown, name, resolveRole).forEach((page) => {
|
|
395
407
|
const id = journalPageId(entryId, page);
|
|
396
408
|
if (page.anchorSlug) pageIds.set(page.anchorSlug, id);
|
|
397
409
|
const slug = slugify(page.name);
|
|
@@ -431,6 +443,12 @@ export class Scenes extends BasePackCompiler {
|
|
|
431
443
|
compileNote(fm, markdown) {
|
|
432
444
|
const name = resolveName(fm);
|
|
433
445
|
const hasBody = Boolean(String(markdown).trim());
|
|
446
|
+
// The markdown this pass reads has already had its embeds rewritten
|
|
447
|
+
// into ordinary images, each `src` the pathname `pathnameRoles` keys
|
|
448
|
+
// its roles by — see {@link module:engine/journals.Journals#buildEntry},
|
|
449
|
+
// which derives this same journal's pages the same way.
|
|
450
|
+
const roles = pathnameRoles(this.linkIndex);
|
|
451
|
+
const resolveRole = (pathname) => roles.get(pathname);
|
|
434
452
|
// The same doc-entry id the journals pass derives, from the
|
|
435
453
|
// shared `docEntryTypes` arrangement — so neither
|
|
436
454
|
// pass has to read the other's output.
|
|
@@ -503,7 +521,8 @@ export class Scenes extends BasePackCompiler {
|
|
|
503
521
|
hasBody ?
|
|
504
522
|
this.#packRouter.resolve(fm, "JournalEntry")
|
|
505
523
|
: this.#packRouter.defaultOf("JournalEntry"),
|
|
506
|
-
pageIds:
|
|
524
|
+
pageIds:
|
|
525
|
+
hasBody ? this.#pageIds(markdown, entryId, name, resolveRole) : new Map(),
|
|
507
526
|
knownActions: this.knownActions,
|
|
508
527
|
warnings,
|
|
509
528
|
...this.#resolvers(this.index, this.effectsByAddress, fm.shortcode),
|
|
@@ -527,12 +546,12 @@ export class Scenes extends BasePackCompiler {
|
|
|
527
546
|
name,
|
|
528
547
|
markdown,
|
|
529
548
|
leadName: name,
|
|
549
|
+
resolveRole,
|
|
530
550
|
// As in the journals pass: an address resolves in the
|
|
531
551
|
// pack that emits it, which is what makes the folder
|
|
532
552
|
// materialise there too. The id spelling that used
|
|
533
553
|
// to cross packs verbatim is retired.
|
|
534
554
|
folder: this.folderResolver(authoredFolder, { isAddress: true }),
|
|
535
|
-
flags: fm.flags,
|
|
536
555
|
})
|
|
537
556
|
: null;
|
|
538
557
|
|