@heroiclands/package-build 22.5.0 → 22.6.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 +23 -0
- package/CONTENT.md +30 -12
- package/docs/api.md +13 -9
- package/docs/content-format.md +115 -23
- package/engine/actor-compiler.mjs +12 -0
- package/engine/base-compiler.mjs +51 -36
- package/engine/content-index.mjs +21 -12
- package/engine/foundry-entries.mjs +50 -16
- package/engine/generate.mjs +81 -10
- package/engine/infobox-registry.mjs +14 -13
- package/engine/item-compiler.mjs +12 -0
- package/engine/journals.mjs +13 -5
- package/engine/note-claims.mjs +98 -2
- package/engine/note-state.mjs +29 -0
- package/engine/subtype-registry.mjs +42 -5
- package/package.json +1 -1
- package/types/engine/actor-compiler.d.mts +11 -0
- package/types/engine/base-compiler.d.mts +46 -16
- package/types/engine/content-index.d.mts +4 -3
- package/types/engine/generate.d.mts +29 -0
- package/types/engine/infobox-registry.d.mts +11 -12
- package/types/engine/item-compiler.d.mts +11 -0
- package/types/engine/note-claims.d.mts +6 -1
- package/types/engine/note-state.d.mts +26 -0
- package/types/engine/subtype-registry.d.mts +32 -5
|
@@ -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
|
|
85
|
+
* only notes that carry the block this pass reads.
|
|
86
86
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* nothing to say about
|
|
91
|
-
* document**: a subtype, and none of the fields the subtype exists
|
|
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
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
* documents
|
|
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
|
|
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
|
/**
|
|
@@ -104,9 +104,10 @@ export function asciiAliases(aliases: unknown): Array<string>;
|
|
|
104
104
|
* @returns {Record<string, any>} The record, keys sorted at every depth. A
|
|
105
105
|
* **stub** — a note with an empty body, on a type an empty body suppresses —
|
|
106
106
|
* carries `address` and `anchors` as `null`: it publishes no page, so it
|
|
107
|
-
* holds no address and offers no anchor. It keeps
|
|
108
|
-
*
|
|
109
|
-
* derived from `data
|
|
107
|
+
* holds no address and offers no anchor. It keeps its `id`, and a `foundry`
|
|
108
|
+
* block naming every document that was made — which is every document
|
|
109
|
+
* derived from `data:`, and no journal, because a journal of an empty body
|
|
110
|
+
* would be empty and is not created.
|
|
110
111
|
* @throws {Error} When the note carries a key this module derives, which would
|
|
111
112
|
* otherwise be overwritten without a word. `file` and, where the file was
|
|
112
113
|
* read, `position` ride on the error.
|
|
@@ -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
|
/**
|
|
@@ -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.
|
|
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
|
|
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
|
-
*
|
|
25
|
-
* list this build is driven by
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
*
|
|
@@ -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
|
|
@@ -59,6 +59,32 @@ export function isStubbableType(type: string | null | undefined, vocabulary?: Re
|
|
|
59
59
|
export function isStubNote(frontmatter: Record<string, any> | null | undefined, body: string | null | undefined, vocabulary?: Readonly<Record<string, {
|
|
60
60
|
stubbable?: boolean;
|
|
61
61
|
}>>): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether a note's body compiles into a JournalEntry that holds anything.
|
|
64
|
+
*
|
|
65
|
+
* > **A document that would be empty is not created.** Nothing names one
|
|
66
|
+
* > either: the index records the note with every field that names an artefact
|
|
67
|
+
* > set to `null`.
|
|
68
|
+
*
|
|
69
|
+
* The question is about the **output**, not the input, and that is what makes
|
|
70
|
+
* one rule serve every caller: a note's own journal, and the documentation
|
|
71
|
+
* journal an item's prose compiles into beside it, are the same document asked
|
|
72
|
+
* the same question.
|
|
73
|
+
*
|
|
74
|
+
* A JournalEntry's content is its pages, and a page comes from
|
|
75
|
+
* {@link module:engine/journals.splitPages} — a lead page of the prose before
|
|
76
|
+
* the first heading, and one page per heading after it. A body of whitespace
|
|
77
|
+
* yields neither, so an empty body is exactly an empty journal.
|
|
78
|
+
*
|
|
79
|
+
* **An infobox does not count.** The panel is a rendering of `data:`, which the
|
|
80
|
+
* index already publishes; an entry holding nothing else gives a consumer
|
|
81
|
+
* nothing it cannot read from the record.
|
|
82
|
+
*
|
|
83
|
+
* @param {string|null|undefined} body - The note body, frontmatter stripped.
|
|
84
|
+
* @returns {boolean} Whether a JournalEntry compiled from this body holds
|
|
85
|
+
* anything.
|
|
86
|
+
*/
|
|
87
|
+
export function journalHasContent(body: string | null | undefined): boolean;
|
|
62
88
|
/**
|
|
63
89
|
* The placeholder phrases a body reduces to, or an empty list.
|
|
64
90
|
*
|
|
@@ -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
|
-
*
|
|
54
|
-
*
|
|
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
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
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
|
*
|