@heroiclands/package-build 22.5.1 → 22.7.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.
@@ -199,6 +199,17 @@ export function loadItemsMap(itemsSourceDirs: readonly string[], foreignSourceDi
199
199
  * becomes embedded items. Nothing above that line is a system's business.
200
200
  */
201
201
  export class SystemActorCompiler extends BasePackCompiler {
202
+ /**
203
+ * The Foundry document class this pass writes.
204
+ *
205
+ * Declared by the class that does the writing, so the table pairing a
206
+ * system with its passes is derived from the passes themselves rather than
207
+ * written out a second time — see
208
+ * {@link module:engine/generate.systemCompilers}.
209
+ *
210
+ * @type {string}
211
+ */
212
+ static documentClass: string;
202
213
  /**
203
214
  * The note-type → document-subtype map this pass compiles against.
204
215
  *
@@ -82,13 +82,16 @@ export class BasePackCompiler {
82
82
  static readsPackOutputOf: readonly string[];
83
83
  /**
84
84
  * Whether this pass's document **is** a system's data, and therefore takes
85
- * only notes that carry that system's block.
85
+ * only notes that carry the block this pass reads.
86
86
  *
87
- * A pack may declare a `system:` — `harn-ensemble` ships an `actors-hm3`
88
- * and an `actors-sohl` from one tree — and the note-side half of that is
89
- * the block named after the system. A note carrying no such block has
90
- * nothing to say about it, so compiling it there would emit a **hollow
91
- * document**: a subtype, and none of the fields the subtype exists for.
87
+ * The question is asked of {@link BasePackCompiler#system} — the pass's own
88
+ * system, which an Actor or Item pass always has — rather than of the
89
+ * pack's `system:`, which a pack need not declare. A note carrying no such
90
+ * block has nothing to say about that system, so compiling it would emit a
91
+ * **hollow document**: a subtype, and none of the fields the subtype exists
92
+ * for. `harn-ensemble` ships an `actors-hm3` and an `actors-sohl` from one
93
+ * tree, and `sohl-thalorna` ships one `actors` declaring nothing; the rule
94
+ * is the same in both, because it is the pass that reads a block.
92
95
  *
93
96
  * False by default, because most passes write documents that are not
94
97
  * system data at all. A JournalEntry of prose is the same document under
@@ -265,22 +268,49 @@ export class BasePackCompiler {
265
268
  * routes to no pack at all — a build failure, never a silent drop.
266
269
  */
267
270
  routesHere(fm: object): boolean;
271
+ /**
272
+ * The system block this pass reads, where it reads one.
273
+ *
274
+ * `undefined` on the base class, because most passes read none: a
275
+ * JournalEntry, a Macro, a Scene and an Adventure are Foundry's documents
276
+ * rather than any system's. The Actor and Item passes answer with the
277
+ * block their {@link SystemActorCompiler.documentSubtypes} names, which is
278
+ * the same declaration that says which notes they claim and what each
279
+ * becomes.
280
+ *
281
+ * Stated here so {@link BasePackCompiler#eligibleFor} is total: a pass
282
+ * declaring `requiresSystemBlock` without a system reads no block, and a
283
+ * note can carry nothing for it.
284
+ *
285
+ * @returns {string|undefined} The block key, or `undefined`.
286
+ */
287
+ get system(): string | undefined;
268
288
  /**
269
289
  * Whether a claimed, routed note may become this pack's document at all.
270
290
  *
271
- * The pack-eligibility gate, and it fails rather than skipping: a note that
272
- * routed *here* and carries nothing for this pack's system is an authoring
273
- * mistake with a hollow document at the end of it, not a note that belongs
274
- * to another pass. Skipping it quietly is how a whole tree compiles to
275
- * documents nobody can use.
291
+ * **A system block is what makes a game document.** A pass whose document
292
+ * *is* a system's data compiles a note only where the note carries the
293
+ * block that pass reads, so a note saying nothing about any system becomes
294
+ * no Actor and no Item anywhere — its prose still compiles into a page, a
295
+ * PDF leaf and a JournalEntry, which are documents no system defines.
296
+ *
297
+ * Asked of this pass's own {@link BasePackCompiler#system}, never of the
298
+ * pack's `system:`. A pack declaring none is a single-system convenience
299
+ * compiled by the fallback pass for its document type, and that pass still
300
+ * reads exactly one block — so the note-side question is the same one
301
+ * whether or not the pack answered it.
302
+ *
303
+ * A note this pass has nothing to compile is **skipped**, counted like any
304
+ * other note the pack does not own. A deliberately unstatted person is the
305
+ * ordinary case, and a block deleted by accident shows in the diff that
306
+ * deleted it; what would otherwise be discarded in silence is the block
307
+ * written for a system no pack of the class serves, and that is reported by
308
+ * {@link module:engine/note-claims.unclaimedNoteFindings} rather than here,
309
+ * where a pass can see only its own half of the configuration.
276
310
  *
277
311
  * @param {object} fm - The note's frontmatter.
278
312
  * @returns {boolean} True when the note may be compiled here; `false` when
279
- * it belongs to another system's pass of the same document type, which is
280
- * skipped as quietly as any other note this pack does not own.
281
- * @throws {Error} When this pack's system is absent from the note and no
282
- * other configured system claims it. The error carries a `position` where
283
- * the note's own file can be read.
313
+ * it carries nothing for this pass's system.
284
314
  */
285
315
  eligibleFor(fm: object): boolean;
286
316
  /**
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The notice as HTML, for a JournalEntry page and for an Actor's prose field.
3
+ *
4
+ * A `blockquote` because that is the element Foundry already sets apart —
5
+ * `body.game .app blockquote` carries a left rule and an indent — so the
6
+ * treatment survives with no stylesheet of this package's own. The mark is a
7
+ * Font Awesome element, which Foundry bundles; `aria-hidden` keeps it out of a
8
+ * screen reader, where the label reads it.
9
+ *
10
+ * @returns {string} The notice's HTML.
11
+ */
12
+ export function draftNoticeHtml(): string;
13
+ /**
14
+ * The notice a note has earned, or nothing.
15
+ *
16
+ * The one place the tag is asked about on a compiled document, so the packs and
17
+ * the book cannot answer it differently. It reads {@link
18
+ * module:engine/note-vocabulary.isDraftNote}, which is the single reader of the
19
+ * tag itself.
20
+ *
21
+ * @param {object|null|undefined} fm - Parsed frontmatter.
22
+ * @returns {string} The notice's HTML, or `""` for a note that is settled.
23
+ */
24
+ export function draftNoticeFor(fm: object | null | undefined): string;
25
+ /**
26
+ * Prose led by the notice, where the note is a draft.
27
+ *
28
+ * **Which field a system leads is the system's decision, and it makes it
29
+ * once.** A referee at the table opens an actor sheet rather than the
30
+ * documentation beside it, so the prose a sheet draws says it too — on one
31
+ * field, since a document showing the same statement twice teaches a reader to
32
+ * skip it. Both systems put it on the dossier: SoHL's `dossier` and HM3's
33
+ * `biography` read the same authored section, so the notice lands on the same
34
+ * prose whichever system compiles it.
35
+ *
36
+ * @param {object|null|undefined} fm - Parsed frontmatter.
37
+ * @param {string} html - The rendered prose.
38
+ * @returns {string} The prose, led by the notice where one is due.
39
+ */
40
+ export function withDraftNotice(fm: object | null | undefined, html: string): string;
41
+ /**
42
+ * The `#let` the book's notice is drawn by.
43
+ *
44
+ * Emitted with the rest of the book's preamble. The mark is a circle with an
45
+ * exclamation set inside it: two primitives and the face already setting the
46
+ * page, so there is no font to resolve and nothing that can come out as a box.
47
+ *
48
+ * @returns {string} The Typst definition.
49
+ */
50
+ export function bookDraftNoticePreamble(): string;
51
+ /**
52
+ * The notice as Typst, for a leaf of the book.
53
+ *
54
+ * @returns {string} The call, ready to sit between the entry's plate and its
55
+ * infobox panel.
56
+ */
57
+ export function draftNoticeTypst(): string;
58
+ /** The word that opens the notice, and the only part a reader reads as a label. */
59
+ export const DRAFT_NOTICE_LABEL: "Draft.";
60
+ /**
61
+ * The sentence, which states the fact and stops.
62
+ *
63
+ * It says the content may change rather than that the writing is rough,
64
+ * because that is the difference between a reader who treats the entry as
65
+ * provisional and one who builds on it. It gives no instruction: a notice that
66
+ * reaches one page in seven wears better as a statement than as a direction,
67
+ * and the fact carries the consequence for anyone who can act on it.
68
+ *
69
+ * @type {string}
70
+ */
71
+ export const DRAFT_NOTICE: string;
72
+ /** The Font Awesome mark: a notice, not a hazard. */
73
+ export const DRAFT_NOTICE_ICON: "fa-circle-exclamation";
74
+ /** The class a package may style the HTML notice against. */
75
+ export const DRAFT_NOTICE_CLASS: "sohl-draft-notice";
76
+ /** The Typst function the book's notice calls. */
77
+ export const BOOK_DRAFT_NOTICE: "book-draft-notice";
@@ -1,11 +1,40 @@
1
+ /**
2
+ * The system-specific compilers, derived from the passes themselves.
3
+ *
4
+ * A repository feeding two systems declares one Item pack and one Actor pack
5
+ * per system — `harn-ensemble` has `actors-hm3` and `actors-sohl` — and each
6
+ * pack's `system:` is what says whose data model its documents are shaped for.
7
+ * That is the same field the `_stats` stamp, the item-catalogue scope and the
8
+ * `itemBuilders` lookup already read, so nothing new is declared to make the
9
+ * compiler follow it.
10
+ *
11
+ * @param {readonly Function[]} passes - The system passes to table.
12
+ * @returns {Readonly<Record<string, Readonly<Record<string, Function>>>>}
13
+ * System id → document class → pass.
14
+ * @throws {Error} When a pass declares no system or no document class, which is
15
+ * a pass that cannot be addressed by either question this table answers.
16
+ */
17
+ export function systemCompilers(passes: readonly Function[]): Readonly<Record<string, Readonly<Record<string, Function>>>>;
1
18
  /**
2
19
  * The compiler class a pack of one document type and one system gets.
3
20
  *
21
+ * A pack declaring **no** system takes the fallback pass for its document
22
+ * class, which reads
23
+ * {@link module:engine/subtype-registry.DEFAULT_DOCUMENT_SUBTYPES} — the
24
+ * single-system convenience every tree shipping for one system is built on.
25
+ *
26
+ * A pack declaring a system this toolchain has no pass for is **refused by
27
+ * name**. Falling through to the fallback would compile that pack out of
28
+ * another system's blocks and ship it stamped with the system it asked for,
29
+ * which is the quiet failure the refusal exists to replace.
30
+ *
4
31
  * @param {string} docType - The Foundry document type the pack holds.
5
32
  * @param {string|null} [system] - The system the pack declares, if any.
6
33
  * @returns {Function|undefined} The compiler class, or `undefined` for a
7
34
  * document type nothing here compiles — which {@link generatePack} reports
8
35
  * rather than defaulting past.
36
+ * @throws {Error} When a system-bearing document class is asked for a system
37
+ * this toolchain ships no pass for.
9
38
  */
10
39
  export function compilerFor(docType: string, system?: string | null): Function | undefined;
11
40
  /**
@@ -16,6 +16,7 @@ export * as homepage from "./homepage.mjs";
16
16
  export * as noteSchemas from "./note-schemas.mjs";
17
17
  export * as noteVocabulary from "./note-vocabulary.mjs";
18
18
  export * as noteState from "./note-state.mjs";
19
+ export * as draftNotice from "./draft-notice.mjs";
19
20
  export * as stubLint from "./stub-lint.mjs";
20
21
  export * as placeRelations from "./place-relations.mjs";
21
22
  export * as holdings from "./holdings.mjs";
@@ -10,24 +10,23 @@ export function infoboxFor(system: string | undefined): object | undefined;
10
10
  * Whether one system compiles a document for one note.
11
11
  *
12
12
  * This is what a system box's _available_ asserts, and it is the compile's own
13
- * question rather than a reading of the frontmatter. A note carrying no block
14
- * is not a note a system has nothing for: where the pack compiling its document
15
- * declares no `system:`, the document is built from `data:` and the field
16
- * defaults and ships exactly like any other.
13
+ * question rather than a reading of the frontmatter.
17
14
  *
18
15
  * Three statements answer it, and they are the three the compile itself
19
16
  * follows:
20
17
  *
21
- * 1. **The map** says which document class this system makes of the note's
18
+ * 1. **The note's block.** A system block is what makes a game document, so a
19
+ * note carrying nothing for this system compiles into no document of it
20
+ * anywhere — the rule
21
+ * {@link module:engine/base-compiler.BasePackCompiler#eligibleFor} applies,
22
+ * asked here from outside.
23
+ * 2. **The map** says which document class this system makes of the note's
22
24
  * type. No row, no document — and no box either, which is why a caller
23
25
  * reaching here already has one.
24
- * 2. **The router** says which pack that document goes to, read from the pack
25
- * list this build is driven by.
26
- * 3. **That pack's `system:`** decides the rest. Declaring one, it writes that
27
- * system's data and takes only notes that say something about it — the rule
28
- * {@link module:engine/base-compiler.BasePackCompiler#eligibleFor} applies,
29
- * asked here from outside. Declaring none, it is compiled by the fallback
30
- * pass, which needs no block and answers for
26
+ * 3. **The router** says which pack that document goes to, read from the pack
27
+ * list this build is driven by, and **that pack's `system:`** decides whose
28
+ * it is. Declaring one, it writes that system's data. Declaring none, it is
29
+ * compiled by the fallback pass, which reads
31
30
  * {@link module:engine/subtype-registry.DEFAULT_DOCUMENT_SUBTYPES} alone —
32
31
  * so a tree with no HM3 pack ships no HM3 document however a note is
33
32
  * written.
@@ -29,6 +29,17 @@ export function itemDescription(markdown: string, fm: object, name: string): str
29
29
  * a configuration one.
30
30
  */
31
31
  export class SystemItemCompiler extends BasePackCompiler {
32
+ /**
33
+ * The Foundry document class this pass writes.
34
+ *
35
+ * Declared by the class that does the writing, so the table pairing a
36
+ * system with its passes is derived from the passes themselves rather than
37
+ * written out a second time — see
38
+ * {@link module:engine/generate.systemCompilers}.
39
+ *
40
+ * @type {string}
41
+ */
42
+ static documentClass: string;
32
43
  /**
33
44
  * The note-type → document-subtype map this pass compiles against.
34
45
  *
@@ -2,10 +2,10 @@
2
2
  * Every content type whose **prose compiles into a JournalEntry of its own**,
3
3
  * addressed by the virtual `doc<type>` qualifier.
4
4
  *
5
- * Every item type, plus `macro` — a macro note's body documents the script the
6
- * note also compiles into a Macro, which is the same shape as an item
7
- * and its description: one note, two documents, the prose living in the
8
- * journals pack.
5
+ * Every item type, every actor type, every map type, plus `macro` — a macro
6
+ * note's body documents the script the note also compiles into a Macro, which
7
+ * is the same shape as an item and its description: one note, two documents,
8
+ * the prose living in the journals pack.
9
9
  *
10
10
  * **One set, read by the compiler and the emitter alike.** The journals pass
11
11
  * decides what to compile from it, and the link manifest decides what to
@@ -14,8 +14,9 @@
14
14
  * consumer can address. It is composed exactly once, in `defineConfig`, and
15
15
  * read from there — never recomposed at a call site.
16
16
  *
17
- * `doc` notes and actors are absent: each is a single document, so it has no
18
- * separate documentation to address.
17
+ * `doc` notes are absent, for the reason that applies to them alone: a `doc`
18
+ * note's single document *is* its prose, so there is no second document for a
19
+ * `doc<type>` address to name.
19
20
  *
20
21
  * An accessor rather than a hoisted constant, so that importing this module
21
22
  * needs no configuration (#2).
@@ -28,8 +29,8 @@ export function docEntryTypes(): ReadonlySet<string>;
28
29
  * its own.
29
30
  *
30
31
  * @param {string} type - The note's `type` frontmatter.
31
- * @returns {boolean} True for an item type, for `macro` and for a map type;
32
- * false for `doc` and for actors.
32
+ * @returns {boolean} True for an item type, an actor type, a map type and
33
+ * `macro`; false for `doc`.
33
34
  */
34
35
  export function hasDocEntry(type: string): boolean;
35
36
  /**
@@ -143,9 +143,14 @@ export function buildPages(rawPages: Array<object>, entryId: string, noteName: s
143
143
  * that reads. It is **not** a page of its own — a page is what a UUID
144
144
  * addresses, and a summary a reader has to navigate to is a summary they do
145
145
  * not see.
146
+ * @param {string} [params.notice] - A statement about the entry rather than
147
+ * about its subject, already rendered to HTML — see {@link
148
+ * module:engine/draft-notice}. It leads the first page, ahead of the infobox,
149
+ * because a reader deciding whether to rely on the entry has to be told
150
+ * before they read it rather than after.
146
151
  * @returns {object} The JournalEntry document, keyed for the pack.
147
152
  */
148
- export function buildJournalEntry({ id, name, markdown, leadName, folder, flags, stats, infobox, }: {
153
+ export function buildJournalEntry({ id, name, markdown, leadName, folder, flags, stats, infobox, notice, }: {
149
154
  id: string;
150
155
  name: string;
151
156
  markdown: string;
@@ -154,6 +159,7 @@ export function buildJournalEntry({ id, name, markdown, leadName, folder, flags,
154
159
  flags?: object | undefined;
155
160
  stats?: object | undefined;
156
161
  infobox?: string | undefined;
162
+ notice?: string | undefined;
157
163
  }): object;
158
164
  /**
159
165
  * Journals pack compiler.
@@ -102,7 +102,12 @@ export function claimedNoteTypes(config?: object, sources?: ClaimSources): Reado
102
102
  */
103
103
  export function noteTypeVocabulary(sources?: ClaimSources): ReadonlySet<string>;
104
104
  /**
105
- * Every note in the content tree that no configured pack would compile.
105
+ * Every note in the content tree that no configured pack would compile, and
106
+ * every system block no configured pack would read.
107
+ *
108
+ * Two questions of one walk, because they are the same question asked of a
109
+ * note's type and of a note's systems, and a note can fail either while passing
110
+ * the other — see {@link discardedSystemBlockFindings}.
106
111
  *
107
112
  * Read-only: it walks the tree and reports, and writes nothing. Three kinds of
108
113
  * note are passed over, each for a stated reason rather than by omission — a
@@ -50,12 +50,15 @@ export const KNOWN_DOCUMENT_SUBTYPE_MAPS: readonly import("./document-subtypes.m
50
50
  /**
51
51
  * The map a pack declaring no `system:` compiles its documents against.
52
52
  *
53
- * A pack names the system its documents are shaped for, and one declaring none
54
- * is compiled by the fallback pass for its document type — a single-system
53
+ * **The single-system fallback, and not a default any system inherits.** A pack
54
+ * names the system its documents are shaped for, and one declaring none is
55
+ * compiled by the fallback pass for its document type — a single-system
55
56
  * package's ordinary arrangement, and the one `sohl-thalorna` ships. That pass
56
- * follows one map whatever a note carries, which makes this the answer to "a
57
- * document compiled here belongs to *which* system?" wherever a pack has not
58
- * said.
57
+ * reads this map's block and no other, so a note carrying nothing for this
58
+ * system compiles into no document there; a note carrying another system's
59
+ * block reaches that system's pass or nothing at all, never this one. This is
60
+ * the answer to "a document compiled here belongs to *which* system?" wherever
61
+ * a pack has not said, and it answers nothing about a system that has said.
59
62
  *
60
63
  * Stated here rather than read off the compiler classes because those are not
61
64
  * reachable from a leaf: `engine/item-compiler.mjs` imports the journals pass,
@@ -67,6 +70,30 @@ export const KNOWN_DOCUMENT_SUBTYPE_MAPS: readonly import("./document-subtypes.m
67
70
  * @type {import("./document-subtypes.mjs").DocumentSubtypeMap}
68
71
  */
69
72
  export const DEFAULT_DOCUMENT_SUBTYPES: import("./document-subtypes.mjs").DocumentSubtypeMap;
73
+ /**
74
+ * Every system this toolchain ships a map for, by id.
75
+ *
76
+ * Derived from {@link KNOWN_DOCUMENT_SUBTYPE_MAPS}, so registering a map is the
77
+ * whole of adding a system to every reader that asks "which systems are there?"
78
+ * — the per-system findings among them.
79
+ *
80
+ * @type {readonly string[]}
81
+ */
82
+ export const SHIPPED_SYSTEMS: readonly string[];
83
+ /**
84
+ * The Foundry document classes a system compiles its own data into.
85
+ *
86
+ * Derived from the shipped maps' rows, so it is the set of classes for which
87
+ * "which system?" is a question with consequences: a pack of one of these
88
+ * classes is compiled by one system's pass reading one system's block, and a
89
+ * note carrying no such block produces nothing there. Every other class — a
90
+ * JournalEntry, a Macro, a Scene, an Adventure — has one implementation
91
+ * whatever a pack declares, because it is Foundry's document rather than any
92
+ * system's.
93
+ *
94
+ * @type {ReadonlySet<string>}
95
+ */
96
+ export const SYSTEM_DOCUMENT_CLASSES: ReadonlySet<string>;
70
97
  /**
71
98
  * Every note type any shipped map compiles into an **Actor**.
72
99
  *