@heroiclands/package-build 20.3.0 → 20.4.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 +97 -0
- package/CONTENT.md +111 -92
- package/README.md +2 -9
- package/bin/content-build.mjs +70 -61
- package/bin/package-build.mjs +2 -2
- package/config.mjs +6 -8
- package/content-config.mjs +187 -64
- package/docs/content-format.md +57 -68
- package/e2e.mjs +4 -4
- package/engine/actor-compiler.mjs +36 -36
- package/engine/address-charset.mjs +6 -6
- package/engine/address-diff.mjs +12 -11
- package/engine/anchored-sections.mjs +1 -1
- package/engine/anchors.mjs +1 -1
- package/engine/base-compiler.mjs +36 -38
- package/engine/bundle-notes.mjs +4 -4
- package/engine/bundles.mjs +8 -8
- package/engine/code-fences.mjs +3 -3
- package/engine/compendiums.mjs +8 -8
- package/engine/compile-corpus.mjs +4 -5
- package/engine/content-address.mjs +15 -15
- package/engine/content-charset.mjs +1 -1
- package/engine/content-format-check.mjs +24 -25
- package/engine/content-format.mjs +8 -8
- package/engine/content-html.mjs +202 -0
- package/engine/content-icons.mjs +225 -98
- package/engine/content-index.mjs +17 -17
- package/engine/content-links.mjs +30 -30
- package/engine/content-lint.mjs +20 -24
- package/engine/content-package.mjs +7 -9
- package/engine/content-slug.mjs +2 -2
- package/engine/content-tables.mjs +7 -8
- package/engine/content-tree.mjs +1 -1
- package/engine/derived-fields.mjs +174 -0
- package/engine/diagnostics.mjs +3 -4
- package/engine/document-subtypes.mjs +6 -7
- package/engine/field-reference.mjs +8 -8
- package/engine/field-spec.mjs +29 -30
- package/engine/folder-notes.mjs +14 -14
- package/engine/foreign-catalog.mjs +8 -9
- package/engine/foundry-entries.mjs +19 -20
- package/engine/frontmatter-lint.mjs +64 -69
- package/engine/frontmatter.mjs +11 -11
- package/engine/generate.mjs +39 -39
- package/engine/helpers.mjs +63 -54
- package/engine/homepage.mjs +20 -22
- package/engine/ids.mjs +15 -15
- package/engine/index-records.mjs +4 -4
- package/engine/index.mjs +14 -8
- package/engine/item-compiler.mjs +54 -29
- package/engine/item-docs.mjs +11 -13
- package/engine/item-registry.mjs +13 -13
- package/engine/journals.mjs +15 -15
- package/engine/macros.mjs +3 -3
- package/engine/map-notes.mjs +6 -6
- package/engine/metadata-index.mjs +5 -5
- package/engine/note-claims.mjs +36 -34
- package/engine/note-ids.mjs +5 -5
- package/engine/note-package.mjs +4 -4
- package/engine/note-renames.mjs +3 -3
- package/engine/note-schemas.mjs +3 -3
- package/engine/note-vocabulary.mjs +27 -26
- package/engine/pack-config.mjs +13 -13
- package/engine/pack-router.mjs +0 -0
- package/engine/prose-config.mjs +9 -9
- package/engine/prose-lint.mjs +12 -13
- package/engine/region-events.mjs +2 -2
- package/engine/retired-fields.mjs +24 -22
- package/engine/runtime-only-fields.mjs +1 -1
- package/engine/scene-levels.mjs +1 -1
- package/engine/scenes.mjs +19 -20
- package/engine/schema-check.mjs +20 -20
- package/engine/schema-extract.mjs +1 -1
- package/engine/site-build.mjs +45 -47
- package/engine/site-index.mjs +17 -18
- package/engine/sql-tables.mjs +21 -13
- package/engine/subtype-registry.mjs +5 -4
- package/engine/system-block.mjs +18 -19
- package/engine/systems.mjs +2 -2
- package/engine/web-wikilinks.mjs +35 -35
- package/engine/wikilink-syntax.mjs +16 -16
- package/engine/wikilinks.mjs +39 -39
- package/hm3/actors.mjs +22 -22
- package/hm3/document-subtypes.mjs +5 -5
- package/hm3/index.mjs +2 -2
- package/hm3/item-builders.mjs +1 -1
- package/hm3/item-fields.mjs +3 -3
- package/hm3/items.mjs +20 -8
- package/hm3/template-priority.mjs +2 -2
- package/lang.mjs +3 -3
- package/manifest.mjs +17 -20
- package/package.json +1 -2
- package/release.mjs +3 -3
- package/sohl/actors.mjs +28 -28
- package/sohl/affiliation-standings.mjs +2 -2
- package/sohl/being-info.mjs +5 -5
- package/sohl/default-item-art.mjs +5 -5
- package/sohl/document-subtypes.mjs +5 -5
- package/sohl/index.mjs +3 -3
- package/sohl/item-builders.mjs +7 -7
- package/sohl/item-fields.mjs +8 -9
- package/sohl/items.mjs +20 -6
- package/sohl/kb-passes.mjs +5 -5
- package/sohl/note-schemas.mjs +7 -7
- package/sohl/skill-base.mjs +1 -1
- package/types/content-config.d.mts +25 -24
- package/types/e2e.d.mts +3 -3
- package/types/engine/actor-compiler.d.mts +14 -13
- package/types/engine/address-charset.d.mts +6 -6
- package/types/engine/address-diff.d.mts +3 -3
- package/types/engine/base-compiler.d.mts +17 -19
- package/types/engine/bundle-notes.d.mts +3 -3
- package/types/engine/bundles.d.mts +1 -1
- package/types/engine/code-fences.d.mts +3 -3
- package/types/engine/compendiums.d.mts +3 -3
- package/types/engine/compile-corpus.d.mts +1 -1
- package/types/engine/content-address.d.mts +11 -11
- package/types/engine/content-format-check.d.mts +6 -6
- package/types/engine/content-format.d.mts +2 -2
- package/types/engine/content-html.d.mts +78 -0
- package/types/engine/content-icons.d.mts +150 -62
- package/types/engine/content-index.d.mts +2 -2
- package/types/engine/content-links.d.mts +8 -8
- package/types/engine/content-lint.d.mts +2 -2
- package/types/engine/content-package.d.mts +6 -8
- package/types/engine/derived-fields.d.mts +101 -0
- package/types/engine/diagnostics.d.mts +2 -2
- package/types/engine/document-subtypes.d.mts +3 -3
- package/types/engine/field-spec.d.mts +37 -39
- package/types/engine/folder-notes.d.mts +4 -5
- package/types/engine/foreign-catalog.d.mts +3 -3
- package/types/engine/foundry-entries.d.mts +6 -7
- package/types/engine/frontmatter-lint.d.mts +7 -7
- package/types/engine/frontmatter.d.mts +7 -7
- package/types/engine/generate.d.mts +7 -7
- package/types/engine/helpers.d.mts +25 -27
- package/types/engine/homepage.d.mts +16 -18
- package/types/engine/ids.d.mts +13 -13
- package/types/engine/index-records.d.mts +3 -3
- package/types/engine/index.d.mts +2 -0
- package/types/engine/item-compiler.d.mts +21 -5
- package/types/engine/item-docs.d.mts +2 -2
- package/types/engine/item-registry.d.mts +6 -6
- package/types/engine/journals.d.mts +3 -3
- package/types/engine/map-notes.d.mts +2 -2
- package/types/engine/metadata-index.d.mts +4 -4
- package/types/engine/note-claims.d.mts +16 -15
- package/types/engine/note-ids.d.mts +4 -4
- package/types/engine/note-package.d.mts +1 -1
- package/types/engine/note-renames.d.mts +3 -3
- package/types/engine/note-vocabulary.d.mts +9 -8
- package/types/engine/pack-config.d.mts +3 -3
- package/types/engine/pack-router.d.mts +1 -1
- package/types/engine/prose-config.d.mts +9 -9
- package/types/engine/prose-lint.d.mts +3 -4
- package/types/engine/region-events.d.mts +2 -2
- package/types/engine/retired-fields.d.mts +10 -9
- package/types/engine/schema-check.d.mts +11 -11
- package/types/engine/site-build.d.mts +18 -19
- package/types/engine/site-index.d.mts +3 -4
- package/types/engine/sql-tables.d.mts +11 -5
- package/types/engine/subtype-registry.d.mts +3 -3
- package/types/engine/system-block.d.mts +3 -3
- package/types/engine/web-wikilinks.d.mts +7 -7
- package/types/engine/wikilink-syntax.d.mts +17 -17
- package/types/engine/wikilinks.d.mts +13 -12
- package/types/hm3/actors.d.mts +1 -1
- package/types/hm3/document-subtypes.d.mts +1 -1
- package/types/hm3/items.d.mts +1 -2
- package/types/hm3/template-priority.d.mts +1 -1
- package/types/manifest.d.mts +8 -8
- package/types/sohl/actors.d.mts +2 -2
- package/types/sohl/affiliation-standings.d.mts +2 -2
- package/types/sohl/being-info.d.mts +2 -2
- package/types/sohl/document-subtypes.d.mts +1 -1
- package/types/sohl/items.d.mts +1 -2
- package/types/sohl/note-schemas.d.mts +1 -1
- package/MIGRATING.md +0 -608
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `aliases:`, `section:` and `traits:` have no such home — there is no
|
|
27
27
|
* surviving concept any of them was part of — so they are refused here.
|
|
28
28
|
*
|
|
29
|
-
* **What `draft:` did
|
|
29
|
+
* **What `draft:` did.** It excluded a note from the compiled packs, from
|
|
30
30
|
* the link manifest and from a consuming site build. Nothing reported the
|
|
31
31
|
* consequence: `content-links.mjs`, `site-index.mjs` and `content-lint.mjs`
|
|
32
32
|
* never read the field, so a link into a drafted note was indistinguishable
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
* *unresolvable*, silently — and it also suppressed real build failures, since
|
|
36
36
|
* a note the compilers never reached could not fail on the defects it carried.
|
|
37
37
|
*
|
|
38
|
-
* **What `aliases:` did
|
|
38
|
+
* **What `aliases:` did.** It fed the alias index, which is what a bare
|
|
39
39
|
* `[[Alias]]` was looked up in. That form resolved to nothing anywhere in the
|
|
40
40
|
* corpus, while the collision rule guarding it folded in every note's
|
|
41
|
-
* `name.full` and so decided what a note could be named
|
|
41
|
+
* `name.full` and so decided what a note could be named. The form and
|
|
42
42
|
* the index are retired together, leaving the field with no reader at all.
|
|
43
43
|
*
|
|
44
|
-
* **What `section:` did
|
|
44
|
+
* **What `section:` did.** It named the section a `collection` note
|
|
45
45
|
* headed, under the `collection` landing rule — its only reader anywhere. That
|
|
46
46
|
* rule is retired, a section being landed by the `README.md` in its directory,
|
|
47
47
|
* so the field has none. No schema or vocabulary ever declared it either, and
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
* reserved.test.ts` pins that equivalence so a future reader cannot be added
|
|
57
57
|
* by accident.
|
|
58
58
|
*
|
|
59
|
-
* **What `traits:` did
|
|
59
|
+
* **What `traits:` did.** It held a being's own description — gender,
|
|
60
60
|
* species, age, birthday, height, weight, frame and `appearance.*` — at the
|
|
61
61
|
* note's top level. The content format gives those a home: `data:`, the closed
|
|
62
62
|
* container for a subject's type-specific facts, which `being` declares every
|
|
63
|
-
* one of them in.
|
|
63
|
+
* one of them in. Every note that carried one has been moved, across four
|
|
64
64
|
* repositories, and this is the third step of that retirement.
|
|
65
65
|
*
|
|
66
66
|
* Refusing it matters more than refusing an ordinary dead key, because top
|
|
@@ -73,19 +73,19 @@
|
|
|
73
73
|
* declares one, and the theme's gear sidebar reads it — so the refusal is
|
|
74
74
|
* anchored at column 1 and never reaches inside a system block.
|
|
75
75
|
*
|
|
76
|
-
* **A field retired in favour of another is a third case
|
|
76
|
+
* **A field retired in favour of another is a third case.** `draft:` and
|
|
77
77
|
* `package:` were retired outright: nothing replaced them, so no value made
|
|
78
78
|
* writing one right and refusal was the only honest answer. A *renamed* field
|
|
79
79
|
* has a replacement, and the two spellings mean the same thing — so the note
|
|
80
80
|
* still compiles, correctly, and refusing it would fail a build over a document
|
|
81
|
-
* that is not wrong. Those retire in the three steps `package:` took
|
|
81
|
+
* that is not wrong. Those retire in the three steps `package:` took, and
|
|
82
82
|
* this module carries the **first**: both spellings are read, the current one
|
|
83
83
|
* wins, and the retired one is *reported* rather than refused. See
|
|
84
84
|
* {@link RETIRED_FIELD_ALIASES}.
|
|
85
85
|
*
|
|
86
|
-
* **The third step is deletion, and it needs no code
|
|
86
|
+
* **The third step is deletion, and it needs no code.** `image`, a map's
|
|
87
87
|
* background art, is the first rename to have run all three: reported (#142),
|
|
88
|
-
* swept
|
|
88
|
+
* swept, then dropped from the
|
|
89
89
|
* table. Removing the entry is the whole of it — with no alias, the spelling is
|
|
90
90
|
* an ordinary unknown key in the `sohl:` block, which the frontmatter lint
|
|
91
91
|
* already refuses as an error alongside the required field it failed to supply.
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
* the record, and a retirement that needed a standing refusal would mean the
|
|
94
94
|
* replacement never arrived. Do not keep a tombstone for one.
|
|
95
95
|
*
|
|
96
|
-
* **A retired *position* is the same case, and reads the same
|
|
96
|
+
* **A retired *position* is the same case, and reads the same.** A field
|
|
97
97
|
* whose shared source moved under `data:` is not renamed — `data.species` and
|
|
98
98
|
* `hm3.species` are one field written in two places — but the retirement has
|
|
99
99
|
* the identical shape: both are read, the one the note carries wins, and the
|
|
@@ -102,8 +102,9 @@
|
|
|
102
102
|
* {@link module:engine/system-block.resolveFieldValue}'s answer; this module
|
|
103
103
|
* only says what an author is told about it.
|
|
104
104
|
*
|
|
105
|
-
* **A field has two retiring positions, not one
|
|
106
|
-
* the obvious one; the other is the note's **top level**, because
|
|
105
|
+
* **A field has two retiring positions, not one.** The in-block key is
|
|
106
|
+
* the obvious one; the other is the note's **top level**, because the sweep
|
|
107
|
+
* did not
|
|
107
108
|
* invent the facts `data:` holds — it gathered them from exactly there. So
|
|
108
109
|
* `portrait:` beside `img:` is the pre-`data:` spelling of `data.portrait`,
|
|
109
110
|
* read for the same reason and reported by {@link retiredTopLevelMessage}. Both
|
|
@@ -184,11 +185,11 @@ export function assertNoDraftField(fm, { file, absPath } = {}) {
|
|
|
184
185
|
* It says what the field fed and what to write instead, rather than which value
|
|
185
186
|
* to correct: no value makes declaring it right.
|
|
186
187
|
*
|
|
187
|
-
* **What it did
|
|
188
|
+
* **What it did.** It was the authored half of the alias index — the
|
|
188
189
|
* namespace a bare `[[Alias]]` was looked up in. Across the three content trees
|
|
189
190
|
* not one bare link resolved through it, while the collision rule that kept it
|
|
190
191
|
* unambiguous folded in every note's `name.full` and so dictated what a note
|
|
191
|
-
* could be named
|
|
192
|
+
* could be named. The form is retired, so the list has no reader.
|
|
192
193
|
*
|
|
193
194
|
* **`name.aliases` is a different field and is not retired.** It fed the same
|
|
194
195
|
* index, but unlike the top-level list it is being kept — reserved, unread,
|
|
@@ -275,10 +276,10 @@ export function declaresRetiredAliasesField(fm) {
|
|
|
275
276
|
* It names what lands a section now rather than a value to correct: no value
|
|
276
277
|
* makes declaring the field right.
|
|
277
278
|
*
|
|
278
|
-
* **What it did
|
|
279
|
+
* **What it did.** It named the section a `collection` note headed,
|
|
279
280
|
* under the `collection` landing rule — the only reader it ever had, in the
|
|
280
281
|
* second branch of `landingOf` (`engine/content-address.mjs`). That rule went
|
|
281
|
-
* first, and the whole mechanism went with it
|
|
282
|
+
* first, and the whole mechanism went with it: a section is a Hugo
|
|
282
283
|
* directory the note format does not carry, so no note lands one and a page
|
|
283
284
|
* that introduces a type is an ordinary note addressed `doc-<type>`. Nothing
|
|
284
285
|
* else read the field, and no schema or vocabulary declared it, so left in
|
|
@@ -438,14 +439,14 @@ export function locateFrontmatterKey(absPath, key, value = undefined, { topLevel
|
|
|
438
439
|
* `relation` is retired on an affiliation — which declares `relations` — and
|
|
439
440
|
* remains an unknown key anywhere else.
|
|
440
441
|
*
|
|
441
|
-
* **`templatePriority
|
|
442
|
+
* **`templatePriority`.** The number that decides which of several
|
|
442
443
|
* competing templates the Create dialog offers was called `archetype`, and
|
|
443
444
|
* `archetypes` — one letter apart — is a list of what *sort* a character is.
|
|
444
445
|
* A priority and a taxonomy cannot be told apart by a plural `s`, so the
|
|
445
446
|
* priority takes the name that says what it is. The specification already
|
|
446
447
|
* called it `templatePriority` on two of its three sides.
|
|
447
448
|
*
|
|
448
|
-
* **`relations
|
|
449
|
+
* **`relations`.** The field holds a *map* of standings, one per
|
|
449
450
|
* affiliation — its own description says so, and `resolveRelation` has always
|
|
450
451
|
* read it that way. `relation` named the many as one, which every author had to
|
|
451
452
|
* read past. Only `affiliation` declares the field, so the alias is reported
|
|
@@ -488,7 +489,7 @@ export function retiredAliasMessage(retired, current, file) {
|
|
|
488
489
|
* What a note writing a field at its **legacy in-block position** is told.
|
|
489
490
|
*
|
|
490
491
|
* The same three-step retirement `retiredAliasMessage` announces, applied to a
|
|
491
|
-
* *position* rather than a spelling
|
|
492
|
+
* *position* rather than a spelling. A field whose shared source moved
|
|
492
493
|
* under `data:` keeps reading the key its block still carries, that read wins,
|
|
493
494
|
* and it is reported here so a sweep has something to count down — without it,
|
|
494
495
|
* moving a field into `data:` would be a flag day across every repository that
|
|
@@ -518,9 +519,10 @@ export function legacyKeyMessage(block, field, file) {
|
|
|
518
519
|
|
|
519
520
|
/**
|
|
520
521
|
* What a note writing a field at the **top-level key `data:` gathered it off**
|
|
521
|
-
* is told
|
|
522
|
+
* is told.
|
|
522
523
|
*
|
|
523
|
-
* {@link legacyKeyMessage}'s counterpart for the other retiring position.
|
|
524
|
+
* {@link legacyKeyMessage}'s counterpart for the other retiring position. The
|
|
525
|
+
* sweep
|
|
524
526
|
* did not invent the facts `data:` holds — it collected them out of the note's
|
|
525
527
|
* open top level — so `portrait:` beside `img:` is the *pre-`data:`* spelling
|
|
526
528
|
* of `data.portrait`, and both are read for the same reason both in-block
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Schema fields a note may **never** author, because the document writes them
|
|
16
|
-
* in play
|
|
16
|
+
* in play.
|
|
17
17
|
*
|
|
18
18
|
* `retired-fields.mjs` refuses a field a note may no longer declare; this
|
|
19
19
|
* refuses one it never could. The two read alike deliberately — a note says one
|
package/engine/scene-levels.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* **Scene ↔ Level integrity** for a compiled compendium pack
|
|
15
|
+
* **Scene ↔ Level integrity** for a compiled compendium pack.
|
|
16
16
|
*
|
|
17
17
|
* A v14 Scene keeps its map image on an embedded `Level`, and a compiled pack
|
|
18
18
|
* stores the two in *separate* LevelDB keys: the Scene at `!scenes!<id>`
|
package/engine/scenes.mjs
CHANGED
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Scenes pack compiler — map notes in `assets/content/` → Foundry `Scene`
|
|
16
|
-
* documents, and the `Adventure` bundles that make their references resolve
|
|
17
|
-
* (issue #1525).
|
|
16
|
+
* documents, and the `Adventure` bundles that make their references resolve.
|
|
18
17
|
*
|
|
19
18
|
* The translation itself lives in the framework-free `map-notes.mjs`; this
|
|
20
19
|
* module is the pass that walks the tree, resolves what one note says about
|
|
@@ -44,7 +43,7 @@
|
|
|
44
43
|
*
|
|
45
44
|
* The walk itself — filtering by type, expanding tables, converting
|
|
46
45
|
* wikilinks, writing the JSON and counting errors — belongs to {@link sohl.utils.packs.BasePackCompiler}; this module
|
|
47
|
-
* states only what makes this pass its own
|
|
46
|
+
* states only what makes this pass its own.
|
|
48
47
|
*/
|
|
49
48
|
|
|
50
49
|
import fs from "fs";
|
|
@@ -62,12 +61,12 @@ import {
|
|
|
62
61
|
import { BasePackCompiler } from "./base-compiler.mjs";
|
|
63
62
|
// What an Adventure member may carry is one rule, and the module that owns the
|
|
64
63
|
// Adventure states it: the scenes pass bundles its pinned places, and the
|
|
65
|
-
// bundles pass compiles a note into one
|
|
64
|
+
// bundles pass compiles a note into one.
|
|
66
65
|
import { stripAdventureKeys } from "./bundle-notes.mjs";
|
|
67
66
|
import { buildJournalEntry, splitPages, journalPageId } from "./journals.mjs";
|
|
68
67
|
import { compendiumUuid, makeId, packForType } from "./ids.mjs";
|
|
69
68
|
// The record accessors only — see `engine/index-records.mjs` for why they live
|
|
70
|
-
// apart from the index that builds them
|
|
69
|
+
// apart from the index that builds them.
|
|
71
70
|
import { authoredFrontmatter, isNoteRecord, noteFile } from "./index-records.mjs";
|
|
72
71
|
import { packRouter } from "./pack-router.mjs";
|
|
73
72
|
import { foundryPackageId } from "./content-package.mjs";
|
|
@@ -124,8 +123,8 @@ export class Scenes extends BasePackCompiler {
|
|
|
124
123
|
* A map note's `img` is its background art, and it is **required**: the map
|
|
125
124
|
* compiler refuses a note without one. It lands on the scene's level rather
|
|
126
125
|
* than on a property spelled `img`, which makes no difference to the
|
|
127
|
-
* question this declaration answers — the authored path reaches the output
|
|
128
|
-
*
|
|
126
|
+
* question this declaration answers — the authored path reaches the output.
|
|
127
|
+
* The place Adventure this pass bundles carries it too.
|
|
129
128
|
*
|
|
130
129
|
* @type {readonly string[]}
|
|
131
130
|
*/
|
|
@@ -182,7 +181,7 @@ export class Scenes extends BasePackCompiler {
|
|
|
182
181
|
* `generatePack` hands every pass the one router the compile resolved, and
|
|
183
182
|
* that is the answer whenever a real compile is running — a second router
|
|
184
183
|
* is a second answer to where a document landed, built from whichever
|
|
185
|
-
* configuration the working directory offers
|
|
184
|
+
* configuration the working directory offers. A compiler
|
|
186
185
|
* constructed directly, as a consumer's or a test's is, has none, and falls
|
|
187
186
|
* back exactly as `prepare` falls back to deriving its own corpus.
|
|
188
187
|
*
|
|
@@ -196,19 +195,19 @@ export class Scenes extends BasePackCompiler {
|
|
|
196
195
|
const maps = [];
|
|
197
196
|
const effectsByAddress = new Map();
|
|
198
197
|
// The corpus this compile derived once, not a walk of this pass's own
|
|
199
|
-
//
|
|
198
|
+
// — and a note is opened only when this pass needs its *prose*,
|
|
200
199
|
// which for a map note means three files in `sohl` rather than 1,685.
|
|
201
200
|
for (const record of this.corpus.records) {
|
|
202
201
|
if (!isNoteRecord(record)) continue;
|
|
203
202
|
// No retired-field test: this pass's own walk — the shared compile
|
|
204
|
-
// loop — is where a note still declaring `package:`
|
|
205
|
-
// `draft:`
|
|
203
|
+
// loop — is where a note still declaring `package:` or
|
|
204
|
+
// `draft:` is reported, once. Repeating either check here
|
|
206
205
|
// would double the diagnostic or throw past it. A refused note is
|
|
207
206
|
// indexed and then never compiled, so it reaches no document.
|
|
208
207
|
const fm = authoredFrontmatter(record);
|
|
209
208
|
const absPath = noteFile(this.contentBase, record);
|
|
210
209
|
// The id is the index's, derived against the configuration this
|
|
211
|
-
// build resolved
|
|
210
|
+
// build resolved — it was derived here through
|
|
212
211
|
// `resolveNoteId(fm)` with no package, which falls back to the
|
|
213
212
|
// ambient one. What remains unset is a file with no address.
|
|
214
213
|
if (!fm || !fm.id) continue;
|
|
@@ -218,10 +217,10 @@ export class Scenes extends BasePackCompiler {
|
|
|
218
217
|
type: fm.type,
|
|
219
218
|
// Where the owning item landed, so a region behaviour's
|
|
220
219
|
// effect reference addresses the right pack when a
|
|
221
|
-
// repository ships several of one type
|
|
220
|
+
// repository ships several of one type.
|
|
222
221
|
// This compile's router, not a freshly built one: a
|
|
223
222
|
// second router is a second answer to where the document
|
|
224
|
-
// landed, resolved from the working directory
|
|
223
|
+
// landed, resolved from the working directory.
|
|
225
224
|
pack: this.#packRouter.resolveOrNull(fm, packForType(fm.type).docType),
|
|
226
225
|
effects: fm.effects,
|
|
227
226
|
});
|
|
@@ -409,7 +408,7 @@ export class Scenes extends BasePackCompiler {
|
|
|
409
408
|
const name = resolveName(fm);
|
|
410
409
|
const hasBody = Boolean(String(markdown).trim());
|
|
411
410
|
// The same doc-entry id the journals pass derives, from the
|
|
412
|
-
// shared `docEntryTypes` arrangement
|
|
411
|
+
// shared `docEntryTypes` arrangement — so neither
|
|
413
412
|
// pass has to read the other's output.
|
|
414
413
|
const entryId = hasBody ? itemDocEntryId(fm.id) : undefined;
|
|
415
414
|
const { value: authoredFolder } = folderField(fm);
|
|
@@ -423,8 +422,8 @@ export class Scenes extends BasePackCompiler {
|
|
|
423
422
|
journalEntryId: entryId,
|
|
424
423
|
// A map note's prose is a derived JournalEntry: it lands in the
|
|
425
424
|
// default JournalEntry pack, not in whichever Scene pack the map
|
|
426
|
-
// itself was routed to
|
|
427
|
-
// This compile's router, as everywhere else in this pass
|
|
425
|
+
// itself was routed to.
|
|
426
|
+
// This compile's router, as everywhere else in this pass.
|
|
428
427
|
journalPack: this.#packRouter.defaultOf("JournalEntry"),
|
|
429
428
|
pageIds: hasBody ? this.#pageIds(markdown, entryId, name) : new Map(),
|
|
430
429
|
knownActions: this.knownActions,
|
|
@@ -432,7 +431,7 @@ export class Scenes extends BasePackCompiler {
|
|
|
432
431
|
...this.#resolvers(this.index, this.effectsByAddress, fm.shortcode),
|
|
433
432
|
});
|
|
434
433
|
for (const message of warnings) {
|
|
435
|
-
// Named by file, like every other note diagnostic
|
|
434
|
+
// Named by file, like every other note diagnostic. A map
|
|
436
435
|
// warning is about the note's frontmatter, which carries no
|
|
437
436
|
// offset, so it names the file and stops there rather than
|
|
438
437
|
// pointing at a line it cannot establish.
|
|
@@ -452,8 +451,8 @@ export class Scenes extends BasePackCompiler {
|
|
|
452
451
|
leadName: name,
|
|
453
452
|
// As in the journals pass: an address resolves in the
|
|
454
453
|
// pack that emits it, which is what makes the folder
|
|
455
|
-
// materialise there too
|
|
456
|
-
// to cross packs verbatim is retired
|
|
454
|
+
// materialise there too. The id spelling that used
|
|
455
|
+
// to cross packs verbatim is retired.
|
|
457
456
|
folder: this.folderResolver(authoredFolder, { isAddress: true }),
|
|
458
457
|
flags: fm.flags,
|
|
459
458
|
})
|
package/engine/schema-check.mjs
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* What a builder **emits** into `system`, against what the receiving DataModel
|
|
16
|
-
* **declares
|
|
16
|
+
* **declares**.
|
|
17
17
|
*
|
|
18
18
|
* Foundry discards an unknown `system` key when a document is constructed, and
|
|
19
19
|
* says nothing: the value is simply absent at load, while the build that wrote
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* - **Emitted, not declared.** `mysticalability` emitted `assocMysteryCode`,
|
|
24
24
|
* which no DataModel defined — 0.8.x had replaced it with
|
|
25
|
-
* `assocAffiliationCode
|
|
25
|
+
* `assocAffiliationCode`. And `affiliation.subType`, authored on all 21
|
|
26
26
|
* of `sohl-kethira-basic`'s deities, is not defined at the version that module
|
|
27
27
|
* targets, so the divine/arcane split evaporates on load.
|
|
28
28
|
* - **Declared, not emitted.** The mirror image, fixed by hand in
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
*
|
|
40
40
|
* **The rest of the emission is only observable.** A compiler writes keys of
|
|
41
41
|
* its own alongside the declared fields — `shortcode`, `actionDefs`, `notes`,
|
|
42
|
-
* `docHtml
|
|
43
|
-
* {@link compareFields} compares, so nothing compared them at all
|
|
42
|
+
* `docHtml` and `templatePriority` — and those appear in neither set
|
|
43
|
+
* {@link compareFields} compares, so nothing compared them at all. They
|
|
44
44
|
* cannot be listed here without the list going stale the next time a compiler
|
|
45
45
|
* grows a key, so they are read off the `system` object the compiler produced:
|
|
46
46
|
* {@link compareEmittedSystem} takes the assembled block and asks what the
|
|
@@ -69,7 +69,7 @@ import { cachedSchemaPath, SCHEMA_ARTIFACT_FILE } from "./foreign-catalog.mjs";
|
|
|
69
69
|
import { loadPackConfig } from "./pack-config.mjs";
|
|
70
70
|
import { systemData, systemDataPaths, undeclaredPaths } from "./system-block.mjs";
|
|
71
71
|
// A field the document writes for itself in play: declared by the schema,
|
|
72
|
-
// emitted by no builder, and authored by no note
|
|
72
|
+
// emitted by no builder, and authored by no note.
|
|
73
73
|
import { runtimeOnlyFields } from "./field-spec.mjs";
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -77,7 +77,7 @@ import { runtimeOnlyFields } from "./field-spec.mjs";
|
|
|
77
77
|
*
|
|
78
78
|
* A mismatch stops the check rather than resolving anyway: a schema read under
|
|
79
79
|
* the wrong shape would report confident nonsense in both directions, and a
|
|
80
|
-
* silently skipped check is the state
|
|
80
|
+
* silently skipped check is the state this exists to leave.
|
|
81
81
|
*
|
|
82
82
|
* @type {number}
|
|
83
83
|
*/
|
|
@@ -136,7 +136,7 @@ export function declaredFields(artifact, documentType, subtype) {
|
|
|
136
136
|
* the path beneath it separately, so a comparison that knew only the leaf would
|
|
137
137
|
* report the container as unemitted and the leaf as undeclared.
|
|
138
138
|
*
|
|
139
|
-
* **A runtime-only field is not in it
|
|
139
|
+
* **A runtime-only field is not in it**. It declares a `to` in order to
|
|
140
140
|
* *claim* the path — so the verbatim passthrough leaves it alone and the
|
|
141
141
|
* refusal has something to name — and `buildFromFields` deliberately skips it,
|
|
142
142
|
* because the document writes that field in play. Counting it here would make
|
|
@@ -196,7 +196,7 @@ function coveredByAncestor(path, emitted) {
|
|
|
196
196
|
* compile into.
|
|
197
197
|
* @param {(type: string) => string} [opts.subtypeOf] - Maps a builder's type to
|
|
198
198
|
* the document subtype it emits. Defaults to identity, which is what the
|
|
199
|
-
* coincidence of names amounts to today
|
|
199
|
+
* coincidence of names amounts to today — stated as a seam so that the
|
|
200
200
|
* explicit map replaces a default rather than a hard-coded assumption.
|
|
201
201
|
* @returns {{undeclared: object[], unemitted: object[], skipped: string[]}}
|
|
202
202
|
* `undeclared` fails a build; `unemitted` is reported; `skipped` names the
|
|
@@ -226,14 +226,14 @@ export function compareFields({
|
|
|
226
226
|
const declared = declaredFields(artifact, documentType, subtype);
|
|
227
227
|
if (!declared) {
|
|
228
228
|
// Not a finding: a builder may compile into a type this system does
|
|
229
|
-
// not define at all, which is a routing question
|
|
229
|
+
// not define at all, which is a routing question rather than a
|
|
230
230
|
// field one. Named so the count is never mistaken for coverage.
|
|
231
231
|
skipped.push(type);
|
|
232
232
|
continue;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
const emitted = emittedFields(fields);
|
|
236
|
-
// Paths the declaration says the *document* writes in play
|
|
236
|
+
// Paths the declaration says the *document* writes in play. They
|
|
237
237
|
// are neither emitted nor a defect, so they answer the unemitted
|
|
238
238
|
// question below rather than appearing in it: "every compiled document
|
|
239
239
|
// will carry the field's initial value" is exactly what a runtime-only
|
|
@@ -373,7 +373,7 @@ function undeclaredEmittedPaths(data, declared, enumerated, prefix = "") {
|
|
|
373
373
|
|
|
374
374
|
/**
|
|
375
375
|
* What a **compiled document** carries in `system`, against what the receiving
|
|
376
|
-
* subtype declares
|
|
376
|
+
* subtype declares.
|
|
377
377
|
*
|
|
378
378
|
* The third of the three checks, and the only one whose emitted set is
|
|
379
379
|
* *observed*. {@link compareFields} reads the `itemBuilders` declarations and
|
|
@@ -430,7 +430,7 @@ export function compareEmittedSystem({
|
|
|
430
430
|
|
|
431
431
|
const declared = declaredFields(artifact, documentType, subtype);
|
|
432
432
|
// Not a finding, for the same reason `compareFields` skips one: a subtype
|
|
433
|
-
// the artifact says nothing about is a routing question
|
|
433
|
+
// the artifact says nothing about is a routing question, not a field
|
|
434
434
|
// one, and guessing at it would report every key on the document.
|
|
435
435
|
if (!declared) return [];
|
|
436
436
|
|
|
@@ -457,7 +457,7 @@ export function compareEmittedSystem({
|
|
|
457
457
|
* The published schema this build should check itself against, or `null`.
|
|
458
458
|
*
|
|
459
459
|
* **Which system, and which version, are already settled.** `stats.systemId`
|
|
460
|
-
* and `stats.systemVersion` are derived rather than authored
|
|
460
|
+
* and `stats.systemVersion` are derived rather than authored — a system
|
|
461
461
|
* package is its own system, and a module takes the one it requires — and the
|
|
462
462
|
* version is the `compatibility.verified` it pins. So the question "whose
|
|
463
463
|
* schema, at what version" has one answer here rather than a second set of
|
|
@@ -477,12 +477,12 @@ export function compareEmittedSystem({
|
|
|
477
477
|
* stamps no system at all, and a system that has not adopted the artifact yet
|
|
478
478
|
* is simply unchecked. Neither is an error, and the caller says which it was.
|
|
479
479
|
*
|
|
480
|
-
* **A build may have more than one system, and then the caller names it
|
|
480
|
+
* **A build may have more than one system, and then the caller names it.**
|
|
481
481
|
* `stats.systemId` is the package-wide answer, and a repository shipping content
|
|
482
482
|
* for two systems has no package-wide answer — it is deliberately `null` there,
|
|
483
483
|
* because a module feeding both `sohl` and `hm3` targets neither. Left at that,
|
|
484
484
|
* every schema check in such a build would be skipped in silence, which is the
|
|
485
|
-
* state
|
|
485
|
+
* state this exists to remove: the five type names the two systems *share* are
|
|
486
486
|
* exactly the ones a wrong-system emission hides in. So a pass supplies the
|
|
487
487
|
* system its pack declares, and the version comes from that system's own
|
|
488
488
|
* `systems:` entry rather than from a package-wide stamp.
|
|
@@ -606,7 +606,7 @@ const artifacts = new WeakMap();
|
|
|
606
606
|
* The per-note check below runs thousands of times in a build and an artifact
|
|
607
607
|
* never changes inside one, so reading and parsing it per note would be a
|
|
608
608
|
* megabyte of JSON per hundred documents for an answer that is already known.
|
|
609
|
-
* Keyed by system as well as by configuration
|
|
609
|
+
* Keyed by system as well as by configuration: a build with two
|
|
610
610
|
* systems has two artifacts, and caching one of them under the configuration
|
|
611
611
|
* alone would hand every pass whichever system asked first.
|
|
612
612
|
*
|
|
@@ -624,7 +624,7 @@ function schemaFor(config, system = undefined) {
|
|
|
624
624
|
|
|
625
625
|
/**
|
|
626
626
|
* What a note authors under `<system>.system`, against what the receiving
|
|
627
|
-
* subtype declares
|
|
627
|
+
* subtype declares.
|
|
628
628
|
*
|
|
629
629
|
* The **note-side** half of the check `compareFields` performs on the
|
|
630
630
|
* declarations. A field list is checked once for the whole build because it is
|
|
@@ -649,7 +649,7 @@ function schemaFor(config, system = undefined) {
|
|
|
649
649
|
* @param {string} opts.documentType - `Item`, `Actor`, …
|
|
650
650
|
* @param {string} opts.subType - The document subtype the note compiles into.
|
|
651
651
|
* @param {string} [opts.system] - The system whose published schema to read,
|
|
652
|
-
* where a build has more than one
|
|
652
|
+
* where a build has more than one. Defaults to the package-wide
|
|
653
653
|
* `stats.systemId`.
|
|
654
654
|
* @param {object} [opts.config] - The resolved build configuration.
|
|
655
655
|
* @returns {{path: string, message: string}[]} One finding per undeclared path,
|
|
@@ -680,7 +680,7 @@ export function checkAuthoredSystemData(
|
|
|
680
680
|
|
|
681
681
|
/**
|
|
682
682
|
* The `system` block a compiler just assembled, against what the receiving
|
|
683
|
-
* subtype declares
|
|
683
|
+
* subtype declares.
|
|
684
684
|
*
|
|
685
685
|
* The build-time face of {@link compareEmittedSystem}: it resolves the schema
|
|
686
686
|
* the way every other check here does — the system's own committed artifact, or
|
|
@@ -703,7 +703,7 @@ export function checkAuthoredSystemData(
|
|
|
703
703
|
* @param {readonly {to?: string}[]} [opts.fields] - The type's field
|
|
704
704
|
* declaration, which decides each finding's origin.
|
|
705
705
|
* @param {string} [opts.system] - The system whose published schema to read,
|
|
706
|
-
* where a build has more than one
|
|
706
|
+
* where a build has more than one. Defaults to the package-wide
|
|
707
707
|
* `stats.systemId`.
|
|
708
708
|
* @param {object} [opts.config] - The resolved build configuration.
|
|
709
709
|
* @returns {(EmissionFinding & {message: string})[]} One per undeclared path.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* The consuming half of this contract already lives in `schema-check.mjs`: a
|
|
18
18
|
* content build subtracts what its builders emit from what a document will
|
|
19
19
|
* actually receive, because Foundry discards an unknown `system` key at
|
|
20
|
-
* construction and says nothing about it
|
|
20
|
+
* construction and says nothing about it. What was missing is the
|
|
21
21
|
* producing half — until now each system carried its own extractor, and the
|
|
22
22
|
* first one to exist hardcoded {@link SCHEMA_ARTIFACT_VERSION}, a constant this
|
|
23
23
|
* package owns. Two producers stamping a third repository's constant by hand is
|