@heroiclands/package-build 20.3.1 → 20.5.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 +351 -0
- package/CONTENT.md +322 -110
- package/README.md +21 -10
- package/bin/content-build.mjs +204 -92
- package/bin/package-build.mjs +48 -15
- package/config.mjs +6 -8
- package/content-config.mjs +518 -151
- package/docs/api.md +1352 -0
- package/docs/commands.md +1609 -0
- package/docs/configuration.md +1432 -0
- package/docs/content-format.md +73 -74
- package/docs/diagnostics.md +356 -0
- package/docs/getting-started.md +813 -0
- package/docs/project-setup.md +469 -0
- package/e2e.mjs +4 -4
- package/engine/actor-compiler.mjs +64 -61
- package/engine/address-charset.mjs +6 -6
- package/engine/address-diff.mjs +57 -52
- package/engine/anchored-sections.mjs +1 -1
- package/engine/anchors.mjs +1 -1
- package/engine/base-compiler.mjs +42 -38
- package/engine/bundle-notes.mjs +4 -4
- package/engine/bundles.mjs +17 -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 +24 -24
- 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 +196 -165
- package/engine/content-index.mjs +61 -40
- package/engine/content-links.mjs +74 -41
- package/engine/content-lint.mjs +64 -34
- package/engine/content-package.mjs +7 -9
- package/engine/content-slug.mjs +2 -2
- package/engine/content-tables.mjs +38 -34
- 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 +18 -16
- package/engine/foreign-catalog.mjs +8 -9
- package/engine/foundry-entries.mjs +19 -20
- package/engine/frontmatter-lint.mjs +95 -103
- package/engine/frontmatter.mjs +11 -11
- package/engine/generate.mjs +44 -39
- package/engine/helpers.mjs +147 -84
- package/engine/homepage.mjs +20 -22
- package/engine/ids.mjs +15 -15
- package/engine/index-records.mjs +4 -4
- package/engine/index.mjs +26 -10
- 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 +24 -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 +51 -41
- 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 -8
- package/engine/note-vocabulary.mjs +56 -54
- package/engine/pack-config.mjs +39 -25
- package/engine/pack-router.mjs +0 -0
- package/engine/pdf-build.mjs +464 -0
- package/engine/pdf-fonts.mjs +420 -0
- package/engine/pdf-render.mjs +798 -0
- package/engine/pdf-toc.mjs +525 -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 +33 -25
- package/engine/schema-check.mjs +21 -21
- package/engine/schema-extract.mjs +1 -1
- package/engine/site-build.mjs +66 -50
- 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 +41 -38
- package/engine/wikilink-syntax.mjs +16 -16
- package/engine/wikilinks.mjs +40 -42
- package/hm3/actors.mjs +30 -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 +28 -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 +66 -6
- package/sohl/actors.mjs +36 -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 +28 -6
- package/sohl/kb-passes.mjs +5 -5
- package/sohl/note-schemas.mjs +12 -12
- package/sohl/skill-base.mjs +1 -1
- package/types/content-config.d.mts +91 -39
- package/types/e2e.d.mts +3 -3
- package/types/engine/actor-compiler.d.mts +45 -40
- package/types/engine/address-charset.d.mts +6 -6
- package/types/engine/address-diff.d.mts +60 -6
- package/types/engine/base-compiler.d.mts +27 -21
- package/types/engine/bundle-notes.d.mts +3 -3
- package/types/engine/bundles.d.mts +10 -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 +20 -20
- 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 +139 -92
- package/types/engine/content-index.d.mts +59 -15
- package/types/engine/content-links.d.mts +8 -8
- package/types/engine/content-lint.d.mts +8 -6
- package/types/engine/content-package.d.mts +6 -8
- package/types/engine/content-tables.d.mts +49 -18
- 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 +10 -9
- package/types/engine/frontmatter.d.mts +7 -7
- package/types/engine/generate.d.mts +7 -7
- package/types/engine/helpers.d.mts +128 -56
- 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 +6 -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 +12 -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 +30 -22
- 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 +31 -203
- package/types/engine/pack-config.d.mts +7 -7
- package/types/engine/pack-router.d.mts +1 -1
- package/types/engine/pdf-build.d.mts +42 -0
- package/types/engine/pdf-fonts.d.mts +30 -0
- package/types/engine/pdf-render.d.mts +144 -0
- package/types/engine/pdf-toc.d.mts +114 -0
- 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/scenes.d.mts +10 -1
- package/types/engine/schema-check.d.mts +13 -13
- package/types/engine/site-build.d.mts +52 -25
- 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 +14 -14
- package/types/hm3/actors.d.mts +9 -1
- package/types/hm3/document-subtypes.d.mts +1 -1
- package/types/hm3/items.d.mts +9 -2
- package/types/hm3/template-priority.d.mts +1 -1
- package/types/manifest.d.mts +8 -8
- package/types/release.d.mts +15 -4
- package/types/sohl/actors.d.mts +12 -4
- 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 +9 -2
- package/types/sohl/note-schemas.d.mts +1 -1
- package/MIGRATING.md +0 -608
|
@@ -13,14 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* **The Actor pass, for any system** — the parts of compiling a note into a
|
|
16
|
-
* Foundry Actor that belong to the note format rather than to a game system
|
|
17
|
-
* (#139).
|
|
16
|
+
* Foundry Actor that belong to the note format rather than to a game system.
|
|
18
17
|
*
|
|
19
18
|
* The whole of it lived in `sohl/actors.mjs`, where the system-specific facts
|
|
20
|
-
* were already funnelled through one map (`static documentSubtypes
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* were already funnelled through one map (`static documentSubtypes`) and one
|
|
20
|
+
* block constant. A second system needs everything except the shape of the
|
|
21
|
+
* `system` block itself, so all of it lives here and each half declares what
|
|
22
|
+
* differs:
|
|
24
23
|
*
|
|
25
24
|
* | stated by the subclass | what it decides |
|
|
26
25
|
* | --- | --- |
|
|
@@ -35,7 +34,7 @@
|
|
|
35
34
|
* - **Reference translation.** A being addresses its embedded items in the
|
|
36
35
|
* *note* vocabulary and the catalogue is keyed in the *document's*, so
|
|
37
36
|
* {@link SystemActorCompiler#embeddedSubtype} translates each reference
|
|
38
|
-
* forward through this system's map before the lookup
|
|
37
|
+
* forward through this system's map before the lookup.
|
|
39
38
|
* - **Embedding.** Merging a note's overlay onto a catalogue entry, deriving a
|
|
40
39
|
* stable embedded id from the owning actor and the address, and re-keying the
|
|
41
40
|
* embedded document and its effects for the LevelDB flattening.
|
|
@@ -60,15 +59,15 @@ import { BasePackCompiler } from "./base-compiler.mjs";
|
|
|
60
59
|
import { contentPackage } from "./content-package.mjs";
|
|
61
60
|
// Which Foundry Actor subtype a note's `type` compiles into, and which note
|
|
62
61
|
// types are actors at all. Looked up in the system's declared map, never
|
|
63
|
-
// inferred from the type itself
|
|
62
|
+
// inferred from the type itself.
|
|
64
63
|
import { mapsNoteType, noteTypesFor, referencedSubtype } from "./document-subtypes.mjs";
|
|
65
64
|
import { locateFrontmatterKey } from "./retired-fields.mjs";
|
|
66
65
|
// An `items:` entry's `system:` overlay is merged verbatim, so it reaches the
|
|
67
|
-
// document by a path no field declaration sits on — including
|
|
66
|
+
// document by a path no field declaration sits on — including the
|
|
68
67
|
// fields the document is supposed to write for itself in play.
|
|
69
68
|
import { itemFields } from "./item-registry.mjs";
|
|
70
69
|
import { runtimeOnlyIn, runtimeOnlyMessage } from "./runtime-only-fields.mjs";
|
|
71
|
-
// A `model:` is an address, read by the same grammar every wikilink is
|
|
70
|
+
// A `model:` is an address, read by the same grammar every wikilink is,
|
|
72
71
|
// so an author writes one form and meets one set of messages.
|
|
73
72
|
import { readQualifier } from "./wikilinks.mjs";
|
|
74
73
|
|
|
@@ -132,7 +131,7 @@ export function deepMerge(base, overlay) {
|
|
|
132
131
|
* vocabulary, so a reference is translated forward through the system's map
|
|
133
132
|
* before it reaches this function; see
|
|
134
133
|
* {@link SystemActorCompiler#embeddedSubtype} for why the translation goes that
|
|
135
|
-
* way and not the other
|
|
134
|
+
* way and not the other.
|
|
136
135
|
*
|
|
137
136
|
* @param {string} subType - The Foundry Item subtype.
|
|
138
137
|
* @param {string} shortcode - The item's `system.shortcode`.
|
|
@@ -144,7 +143,7 @@ export function itemAddress(subType, shortcode) {
|
|
|
144
143
|
|
|
145
144
|
/**
|
|
146
145
|
* The key one predefined item is held under **for the package that publishes
|
|
147
|
-
* it** — the address a `model:` naming that package resolves through
|
|
146
|
+
* it** — the address a `model:` naming that package resolves through.
|
|
148
147
|
*
|
|
149
148
|
* The unqualified {@link itemAddress} stays beside it, and the two answer
|
|
150
149
|
* different questions. A `model` that names no package means *this* one and
|
|
@@ -174,11 +173,12 @@ export function packagedItemAddress(pkg, subType, shortcode) {
|
|
|
174
173
|
* A shortcode is case-sensitive and routinely mixed — `Clb`, `LtShoe`,
|
|
175
174
|
* `HsTunic` — while an **address** is not: `readQualifier` normalises what it
|
|
176
175
|
* reads, and every canonical address is lowercase. So the moment a `model:` is
|
|
177
|
-
* read as an address
|
|
178
|
-
* `system.shortcode` is `Clb`, and an exact match cannot
|
|
176
|
+
* read as an address, `weapongear-clb` has to find the document whose
|
|
177
|
+
* `system.shortcode` is `Clb`, and an exact match cannot.
|
|
179
178
|
*
|
|
180
179
|
* Folding is safe because the fold is already the address: no two items in any
|
|
181
|
-
* published tree differ only by the case of their shortcode, and
|
|
180
|
+
* published tree differ only by the case of their shortcode, and the rule
|
|
181
|
+
* makes
|
|
182
182
|
* that impossible rather than merely true.
|
|
183
183
|
*
|
|
184
184
|
* **This is not {@link itemAddress}, and must not become it.** That one seeds
|
|
@@ -229,13 +229,13 @@ export function embeddedIdentity(item) {
|
|
|
229
229
|
* four corpora holds 180 items, at which 64 bits collide with probability
|
|
230
230
|
* around 10⁻¹⁵.
|
|
231
231
|
*
|
|
232
|
-
* **It takes no index
|
|
232
|
+
* **It takes no index**. Keying on a position meant reordering a being's
|
|
233
233
|
* item list renumbered every id after the change, so a re-import created new
|
|
234
234
|
* documents beside the old ones — while nothing about those documents had
|
|
235
235
|
* changed, only their neighbours. The identity always exists or must be stated;
|
|
236
236
|
* see {@link embeddedIdentity}.
|
|
237
237
|
*
|
|
238
|
-
* Keyed by the **document subtype**, so renaming a note type
|
|
238
|
+
* Keyed by the **document subtype**, so renaming a note type leaves every
|
|
239
239
|
* embedded id where it was.
|
|
240
240
|
*
|
|
241
241
|
* @param {string} actorId - The owning actor's id.
|
|
@@ -277,7 +277,7 @@ export function loadItemsMap(itemsSourceDirs, foreignSourceDirs = []) {
|
|
|
277
277
|
const shadowed = [];
|
|
278
278
|
for (const itemsSourceDir of itemsSourceDirs) {
|
|
279
279
|
if (!fs.existsSync(itemsSourceDir)) {
|
|
280
|
-
// The generator orders the actors pass after every Item pass
|
|
280
|
+
// The generator orders the actors pass after every Item pass,
|
|
281
281
|
// so a whole-package build cannot reach this. What can is a run
|
|
282
282
|
// restricted to this one pack, or a caller constructing the
|
|
283
283
|
// compiler itself — neither of which reordering a pack list fixes,
|
|
@@ -321,13 +321,13 @@ export function loadItemsMap(itemsSourceDirs, foreignSourceDirs = []) {
|
|
|
321
321
|
const { _key, ...rest } = doc;
|
|
322
322
|
map.set(address, rest);
|
|
323
323
|
// And under this package's own name, so a `model:` that names this
|
|
324
|
-
// package explicitly resolves to the same item
|
|
324
|
+
// package explicitly resolves to the same item.
|
|
325
325
|
map.set(catalogueKey(doc.type, shortcode, contentPackage()), rest);
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
for (const foreignEntry of foreignSourceDirs) {
|
|
329
329
|
// Each dependency's directory arrives with the package that published
|
|
330
|
-
// it
|
|
330
|
+
// it, so a foreign template gets its own canonical address
|
|
331
331
|
// rather than sharing the local address space.
|
|
332
332
|
const foreignDir = typeof foreignEntry === "string" ? foreignEntry : foreignEntry.dir;
|
|
333
333
|
const foreignPackage = typeof foreignEntry === "string" ? null : foreignEntry.package;
|
|
@@ -352,7 +352,7 @@ export function loadItemsMap(itemsSourceDirs, foreignSourceDirs = []) {
|
|
|
352
352
|
// eslint-disable-next-line no-unused-vars
|
|
353
353
|
const { _key, ...rest } = doc;
|
|
354
354
|
// Its own package-qualified address, which a `model:` naming that
|
|
355
|
-
// package resolves through and nothing local can shadow
|
|
355
|
+
// package resolves through and nothing local can shadow.
|
|
356
356
|
if (foreignPackage) {
|
|
357
357
|
map.set(catalogueKey(doc.type, shortcode, foreignPackage), rest);
|
|
358
358
|
}
|
|
@@ -411,8 +411,8 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
411
411
|
* because {@link SystemActorCompiler#resolveEmbedded} is called per entry
|
|
412
412
|
* and has no note lifecycle of its own.
|
|
413
413
|
*
|
|
414
|
-
* `frontmatter-lint.mjs` makes the same finding from frontmatter alone
|
|
415
|
-
*
|
|
414
|
+
* `frontmatter-lint.mjs` makes the same finding from frontmatter alone,
|
|
415
|
+
* and this does not replace it — the lint is a separate command, so
|
|
416
416
|
* without a check here a colliding pair would compile to two documents with
|
|
417
417
|
* one `_id` and reach the LevelDB packer as an opaque duplicate key.
|
|
418
418
|
*
|
|
@@ -422,12 +422,12 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
422
422
|
|
|
423
423
|
// An actor's embedded items are resolved against the *output* of the item
|
|
424
424
|
// passes, so every Item pack compiles before this one. Declared rather than
|
|
425
|
-
// left to the order `packs:` happens to list
|
|
425
|
+
// left to the order `packs:` happens to list.
|
|
426
426
|
static readsPackOutputOf = Object.freeze(["Item"]);
|
|
427
427
|
|
|
428
428
|
/**
|
|
429
429
|
* An Actor **is** a system's data, so this pack takes only notes carrying
|
|
430
|
-
* this system's block
|
|
430
|
+
* this system's block.
|
|
431
431
|
*/
|
|
432
432
|
static requiresSystemBlock = true;
|
|
433
433
|
|
|
@@ -449,7 +449,7 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
449
449
|
|
|
450
450
|
/**
|
|
451
451
|
* Every package a `model:` may name besides this one — the dependencies
|
|
452
|
-
* whose item catalogues were supplied
|
|
452
|
+
* whose item catalogues were supplied.
|
|
453
453
|
*
|
|
454
454
|
* @returns {Set<string>} The dependency package ids.
|
|
455
455
|
*/
|
|
@@ -465,10 +465,10 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
465
465
|
super(options);
|
|
466
466
|
// Where the items passes wrote their JSON. Stated by the caller rather
|
|
467
467
|
// than assumed to be this pack's sibling: the packs' locations are
|
|
468
|
-
// configuration, and a consumer may put them anywhere
|
|
469
|
-
// Item pack, because a repository may ship more than one
|
|
468
|
+
// configuration, and a consumer may put them anywhere. Every
|
|
469
|
+
// Item pack, because a repository may ship more than one.
|
|
470
470
|
//
|
|
471
|
-
// **Optional, and empty is a legitimate package
|
|
471
|
+
// **Optional, and empty is a legitimate package.** This used to
|
|
472
472
|
// throw unless at least one Item pack was declared, which asked a
|
|
473
473
|
// package to declare the very thing it may exist not to have. An Item
|
|
474
474
|
// pack is system-bound by construction — Foundry requires `system` on
|
|
@@ -560,7 +560,7 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
560
560
|
* The Foundry Item subtype an embedded reference's `type` addresses.
|
|
561
561
|
*
|
|
562
562
|
* **The reference is in the note vocabulary; the address is in the
|
|
563
|
-
* document's
|
|
563
|
+
* document's**. An actor writes `(type, shortcode)` with the type an
|
|
564
564
|
* author authors, while {@link itemAddress} keys the predefined items by
|
|
565
565
|
* the subtype each compiled document carries — so exactly one of the two
|
|
566
566
|
* sides has to translate, and it is this one. The system's map is a
|
|
@@ -576,37 +576,10 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
576
576
|
return referencedSubtype(this.documentSubtypes, type, "Item");
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
/**
|
|
580
|
-
* Resolve one embedded item from a `(type, shortcode?, overlay)`
|
|
581
|
-
* descriptor. If `shortcode` is given, the predefined item is fetched
|
|
582
|
-
* from `itemsMap` and the overlay deep-merged on top. If absent, the
|
|
583
|
-
* descriptor must carry enough fields to stand alone. The embedded
|
|
584
|
-
* item's `_id` is regenerated deterministically from
|
|
585
|
-
* `(actorId, subType, shortcode, indexKey)` so re-exports are stable —
|
|
586
|
-
* from the **document subtype**, so that renaming a note type (#78) leaves
|
|
587
|
-
* every embedded id exactly where it was.
|
|
588
|
-
* Returns null if the descriptor cannot be resolved.
|
|
589
|
-
*
|
|
590
|
-
* @param {Map<string, object>} itemsMap - The predefined items, by address.
|
|
591
|
-
* @param {string} actorId - The owning actor's id, seeding embedded ids.
|
|
592
|
-
* @param {string} type - The **note** type the reference names.
|
|
593
|
-
* @param {string|null} shortcode - The referenced item's shortcode, or
|
|
594
|
-
* `null` for a stand-alone entry.
|
|
595
|
-
* @param {object} [overlay] - The entry's remaining properties.
|
|
596
|
-
* @param {string} indexKey - Where the reference sits, for a diagnostic.
|
|
597
|
-
* It no longer reaches the id (#268) — it names the entry in a message.
|
|
598
|
-
* @param {string} ctx - Diagnostic context (the actor's label).
|
|
599
|
-
* @param {object} [at] - Where to locate a finding.
|
|
600
|
-
* @param {string} [at.fmKey] - The frontmatter key the reference sits
|
|
601
|
-
* under, so an unresolved one is reported at the reference rather than
|
|
602
|
-
* at the note.
|
|
603
|
-
* @returns {object|null} The embedded item, or null when it resolved to
|
|
604
|
-
* nothing — always with a finding emitted.
|
|
605
|
-
*/
|
|
606
579
|
/**
|
|
607
580
|
* Read an entry's `model:` — the address of the item it is a copy of.
|
|
608
581
|
*
|
|
609
|
-
* The address grammar is the wikilink one
|
|
582
|
+
* The address grammar is the wikilink one, so a `model` is written at
|
|
610
583
|
* whatever length says what it means: `skill-wpnc` within this package,
|
|
611
584
|
* `sohl-sohl-skill-wpnc` to reach another. The system segment defaults from
|
|
612
585
|
* the block the entry sits in — `<system>.items` — which is what makes the
|
|
@@ -615,7 +588,7 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
615
588
|
*
|
|
616
589
|
* It replaced a top-level `shortcode:` that meant something different from
|
|
617
590
|
* the `system.shortcode` beside it and could not say which package a
|
|
618
|
-
* template came from
|
|
591
|
+
* template came from.
|
|
619
592
|
*
|
|
620
593
|
* @param {unknown} model - The authored value.
|
|
621
594
|
* @param {number} index - The entry's position, for the message.
|
|
@@ -653,6 +626,36 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
653
626
|
return { type: read.type, shortcode: read.shortcode, package: read.package ?? null };
|
|
654
627
|
}
|
|
655
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Resolve one embedded item from a `(type, shortcode?, overlay)`
|
|
631
|
+
* descriptor. If `shortcode` is given, the predefined item is fetched
|
|
632
|
+
* from `itemsMap` and the overlay deep-merged on top. If absent, the
|
|
633
|
+
* descriptor must carry enough fields to stand alone. The embedded
|
|
634
|
+
* item's `_id` is regenerated deterministically from
|
|
635
|
+
* `(actorId, subType, shortcode, indexKey)` so re-exports are stable —
|
|
636
|
+
* from the **document subtype**, so that renaming a note type leaves
|
|
637
|
+
* every embedded id exactly where it was.
|
|
638
|
+
* Returns null if the descriptor cannot be resolved.
|
|
639
|
+
*
|
|
640
|
+
* @param {Map<string, object>} itemsMap - The predefined items, by address.
|
|
641
|
+
* @param {string} actorId - The owning actor's id, seeding embedded ids.
|
|
642
|
+
* @param {string} type - The **note** type the reference names.
|
|
643
|
+
* @param {string|null} shortcode - The referenced item's shortcode, or
|
|
644
|
+
* `null` for a stand-alone entry.
|
|
645
|
+
* @param {object} overlay - The entry's remaining properties.
|
|
646
|
+
* @param {string} indexKey - Where the reference sits, for a diagnostic.
|
|
647
|
+
* It names the entry in a message and does not reach the id.
|
|
648
|
+
* @param {string} ctx - Diagnostic context (the actor's label).
|
|
649
|
+
* @param {object} [at] - Where to locate a finding.
|
|
650
|
+
* @param {string} [at.fmKey] - The frontmatter key the reference sits
|
|
651
|
+
* under, so an unresolved one is reported at the reference rather than
|
|
652
|
+
* at the note.
|
|
653
|
+
* @param {string|null} [at.modelPackage] - The package a `model:` names,
|
|
654
|
+
* where the template comes from another package's catalogue. Given one,
|
|
655
|
+
* the packaged address is what resolves and nothing local shadows it.
|
|
656
|
+
* @returns {object|null} The embedded item, or null when it resolved to
|
|
657
|
+
* nothing — always with a finding emitted.
|
|
658
|
+
*/
|
|
656
659
|
resolveEmbedded(
|
|
657
660
|
itemsMap,
|
|
658
661
|
actorId,
|
|
@@ -675,7 +678,7 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
675
678
|
this.errorCount++;
|
|
676
679
|
return null;
|
|
677
680
|
}
|
|
678
|
-
// A `model:` may name the package its template comes from
|
|
681
|
+
// A `model:` may name the package its template comes from. Where
|
|
679
682
|
// it does, the packaged address is used and nothing local can shadow
|
|
680
683
|
// it; where it does not, the unqualified one is, and a local definition
|
|
681
684
|
// still wins over a dependency's as it always has.
|
|
@@ -687,7 +690,7 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
687
690
|
|
|
688
691
|
// The entry's `system:` overlay is merged verbatim, so it reaches the
|
|
689
692
|
// document without passing a single field declaration — which left it
|
|
690
|
-
// the one position a runtime-only field
|
|
693
|
+
// the one position a runtime-only field would stay authorable at once
|
|
691
694
|
// closed the item note's own. Asked of the **overlay** rather than of
|
|
692
695
|
// the merged result: the template it merges onto is a compiled
|
|
693
696
|
// document, which by then carries none, and a finding has to name what
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* The one charset every segment of a canonical address is held to
|
|
15
|
+
* The one charset every segment of a canonical address is held to.
|
|
16
16
|
*
|
|
17
17
|
* An address is a hyphen-joined tuple — `package-system-type-shortcode`, so
|
|
18
18
|
* `sohl-none-doc-gear` — and it is read back by **counting segments**, with a
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
* digits only.
|
|
44
44
|
*
|
|
45
45
|
* Case *was* deliberately unconstrained, on the reasoning that case has no
|
|
46
|
-
* bearing on the separator — which is true, and beside the point
|
|
46
|
+
* bearing on the separator — which is true, and beside the point.
|
|
47
47
|
*
|
|
48
48
|
* **Two names that differ only in case are two names nobody can tell apart.** A
|
|
49
49
|
* shortcode is how a person names a thing when writing a reference —
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
* `sohl-sohl-weapongear-clb` and its `_id` derived from that. The authored name
|
|
56
56
|
* and its address disagreed, and everything downstream keys on the address —
|
|
57
57
|
* which left two notes differing only in case sharing one address, one `_id` and
|
|
58
|
-
* one URL, with nothing to report it. It also
|
|
59
|
-
*
|
|
60
|
-
* other segment, and
|
|
61
|
-
*
|
|
58
|
+
* one URL, with nothing to report it. It also forces two exceptions elsewhere:
|
|
59
|
+
* the shortcode has to be exempted from the lowercase rule pinned on every
|
|
60
|
+
* other segment, and its case has to be folded in the item catalogue because
|
|
61
|
+
* an address is lowercased when read.
|
|
62
62
|
*
|
|
63
63
|
* One case, one spelling, no exceptions. Every tree already complies but two,
|
|
64
64
|
* and nothing in any of them collides when folded.
|
package/engine/address-diff.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Diffing a package's published item addresses against a released one
|
|
15
|
+
* Diffing a package's published item addresses against a released one.
|
|
16
16
|
*
|
|
17
17
|
* A package's `(type, shortcode)` addresses are a **published interface**.
|
|
18
18
|
* Every satellite that declares `itemCatalog: true` assembles its beings out of
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
* mean" from string similarity would be worse than saying nothing, because a
|
|
49
49
|
* wrong one sends the reader to the wrong fix.
|
|
50
50
|
*
|
|
51
|
-
*
|
|
51
|
+
* **That match is narrow, and a declaration is what makes up the
|
|
52
52
|
* difference.** The join rested on the id being independent of the shortcode: a
|
|
53
53
|
* note authored its `_id`, so the `Tabri` → `Taburi` commit changed the
|
|
54
|
-
* shortcode alone and left the id to join the two sides.
|
|
54
|
+
* shortcode alone and left the id to join the two sides. An id is
|
|
55
55
|
* *derived from the canonical address*, which carries the shortcode — so
|
|
56
56
|
* renaming a shortcode moves the id too, both sides of the join move together,
|
|
57
57
|
* and the match finds nothing. It stays exact for a note that **pins** an `id`,
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
* one.
|
|
62
62
|
*
|
|
63
63
|
* So an author who has just renamed a shortcode **says so**, with
|
|
64
|
-
* `renamedFrom:` on the note that made the change (
|
|
64
|
+
* `renamedFrom:` on the note that made the change (and see
|
|
65
65
|
* `engine/note-renames.mjs`). That is neither a guess nor an identity match but
|
|
66
66
|
* testimony from the only party that knows, and the diagnostic reports which of
|
|
67
67
|
* the two it had rather than blending them — a reader can verify a matched id
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
*
|
|
75
75
|
* **Severity is decided per case.** A withdrawal is legitimate — content is
|
|
76
76
|
* allowed to be retired — so it is reported and does not fail a build. A rename
|
|
77
|
-
* is equally legitimate as a decision (
|
|
77
|
+
* is equally legitimate as a decision (the charset rule forces some), which
|
|
78
78
|
* is why it does not fail one either; what it must not do is happen in silence.
|
|
79
79
|
* A caller that wants a gate passes `error` and treats any finding as one.
|
|
80
80
|
*
|
|
@@ -91,7 +91,7 @@ import path from "node:path";
|
|
|
91
91
|
import { formatDiagnostic, positionInFrontmatter } from "./diagnostics.mjs";
|
|
92
92
|
import { positionOfLiteral } from "./diagnostics.mjs";
|
|
93
93
|
import { assertStatedScope } from "./helpers.mjs";
|
|
94
|
-
// The corpus, read from the one pass that derives it
|
|
94
|
+
// The corpus, read from the one pass that derives it. Nothing in the
|
|
95
95
|
// index's import graph reaches this module — only `bin/` imports it — so this
|
|
96
96
|
// is a plain static import, as in the link checker.
|
|
97
97
|
import { indexRecordsFor, isNoteRecord, noteFile } from "./content-index.mjs";
|
|
@@ -173,59 +173,19 @@ export function readItemAddresses(dirs) {
|
|
|
173
173
|
return space;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
/**
|
|
177
|
-
* Every rename the tree's notes **declare**, as old address → where it went.
|
|
178
|
-
*
|
|
179
|
-
* Read from the content tree rather than from compiled output, because a
|
|
180
|
-
* declaration is authored and the compiled document does not carry it: nothing
|
|
181
|
-
* downstream consumes `renamedFrom:`, so emitting it into every pack to let one
|
|
182
|
-
* diagnostic read it back would put a build-time note in shipped data forever.
|
|
183
|
-
* The tree is already read by this module for the same reason
|
|
184
|
-
* ({@link noteFilesById}) — to place a finding where its author can fix it.
|
|
185
|
-
*
|
|
186
|
-
* **A declaration is keyed by document subtype, not by note type.** The address
|
|
187
|
-
* space is the one consumers resolve against, and it is spelled in compiled
|
|
188
|
-
* documents: `hm3` compiles a `projectile` note into a `missilegear` item,
|
|
189
|
-
* so that is the address a rename of it moves. {@link referencedSubtype} is the
|
|
190
|
-
* function that already answers this for a being's embedded `(type, shortcode)`
|
|
191
|
-
* references, so both sides read the same rule rather than a second copy of it.
|
|
192
|
-
*
|
|
193
|
-
* **An entry is emitted for every system that maps the type**, whether or not
|
|
194
|
-
* the note declares that system's block. Over-emitting is inert — the diff uses
|
|
195
|
-
* an entry only when the baseline published the old address *and* this build
|
|
196
|
-
* publishes the new one, and a system the note does not compile for satisfies
|
|
197
|
-
* neither — while asking which blocks a note declares would put a second,
|
|
198
|
-
* subtly different answer to that question in a third place.
|
|
199
|
-
*
|
|
200
|
-
* **First claim wins on a collision.** Two notes naming one predecessor is a
|
|
201
|
-
* contradiction — an address has one successor — and it is reported as an error
|
|
202
|
-
* by `engine/content-lint.mjs`, where both notes are in hand and can both be
|
|
203
|
-
* named. Picking one here keeps this a map; it is not a resolution, and nothing
|
|
204
|
-
* rests on which one it picked.
|
|
205
|
-
*
|
|
206
|
-
* @param {string} contentBase - Root of the content tree.
|
|
207
|
-
* @param {object} opts
|
|
208
|
-
* @param {readonly string[]} [opts.skipDirectories] - The corpus scope. Stated
|
|
209
|
-
* by the caller, never defaulted — see {@link addressCorpus}.
|
|
210
|
-
* @param {readonly object[]} [opts.maps] - The document-subtype maps.
|
|
211
|
-
* @param {object} [opts.config] - The resolved build configuration.
|
|
212
|
-
* @param {readonly object[]} [opts.records] - Index records the caller already
|
|
213
|
-
* derived, shared with {@link noteFilesById} so one command reads one corpus.
|
|
214
|
-
* @returns {Map<string, {to: string, file: string, shortcode: string}>} Old
|
|
215
|
-
* address → the address the declaring note publishes at now, and that note.
|
|
216
|
-
*/
|
|
217
176
|
/**
|
|
218
177
|
* The corpus both reads below share, as content-index records.
|
|
219
178
|
*
|
|
220
179
|
* **One walk, not two.** `addresses diff` reads the tree twice — once for the
|
|
221
|
-
* declarations and once to place its findings — and
|
|
180
|
+
* declarations and once to place its findings — and those would otherwise be
|
|
181
|
+
* two
|
|
222
182
|
* independent walks that each parsed every note. They are now one derivation,
|
|
223
183
|
* shared: the caller derives the records and hands them to both, so the two
|
|
224
184
|
* halves of a single command cannot disagree about which files the corpus is,
|
|
225
185
|
* or about the ids in it.
|
|
226
186
|
*
|
|
227
187
|
* **The id is why it matters, and not only tidiness.** `noteFilesById` joins
|
|
228
|
-
* tree-side ids against ids read out of the *compiled packs*.
|
|
188
|
+
* tree-side ids against ids read out of the *compiled packs*. An id
|
|
229
189
|
* is derived from the canonical address, whose first segment is the content
|
|
230
190
|
* package — and the tree side used to derive it through `resolveNoteId(fm)`
|
|
231
191
|
* with no package, which falls back to `contentPackage()` and so to whichever
|
|
@@ -257,6 +217,49 @@ function addressCorpus(contentBase, { skipDirectories, config, records, problems
|
|
|
257
217
|
return indexRecordsFor({ contentBase, config, skipDirectories, problems });
|
|
258
218
|
}
|
|
259
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Every rename the tree's notes **declare**, as old address → where it went.
|
|
222
|
+
*
|
|
223
|
+
* Read from the content tree rather than from compiled output, because a
|
|
224
|
+
* declaration is authored and the compiled document does not carry it: nothing
|
|
225
|
+
* downstream consumes `renamedFrom:`, so emitting it into every pack to let one
|
|
226
|
+
* diagnostic read it back would put a build-time note in shipped data forever.
|
|
227
|
+
* The tree is already read by this module for the same reason
|
|
228
|
+
* ({@link noteFilesById}) — to place a finding where its author can fix it.
|
|
229
|
+
*
|
|
230
|
+
* **A declaration is keyed by document subtype, not by note type.** The address
|
|
231
|
+
* space is the one consumers resolve against, and it is spelled in compiled
|
|
232
|
+
* documents: `hm3` compiles a `projectile` note into a `missilegear` item,
|
|
233
|
+
* so that is the address a rename of it moves. {@link referencedSubtype} is the
|
|
234
|
+
* function that already answers this for a being's embedded `(type, shortcode)`
|
|
235
|
+
* references, so both sides read the same rule rather than a second copy of it.
|
|
236
|
+
*
|
|
237
|
+
* **An entry is emitted for every system that maps the type**, whether or not
|
|
238
|
+
* the note declares that system's block. Over-emitting is inert — the diff uses
|
|
239
|
+
* an entry only when the baseline published the old address *and* this build
|
|
240
|
+
* publishes the new one, and a system the note does not compile for satisfies
|
|
241
|
+
* neither — while asking which blocks a note declares would put a second,
|
|
242
|
+
* subtly different answer to that question in a third place.
|
|
243
|
+
*
|
|
244
|
+
* **First claim wins on a collision.** Two notes naming one predecessor is a
|
|
245
|
+
* contradiction — an address has one successor — and it is reported as an error
|
|
246
|
+
* by `engine/content-lint.mjs`, where both notes are in hand and can both be
|
|
247
|
+
* named. Picking one here keeps this a map; it is not a resolution, and nothing
|
|
248
|
+
* rests on which one it picked.
|
|
249
|
+
*
|
|
250
|
+
* @param {string} contentBase - Root of the content tree.
|
|
251
|
+
* @param {object} opts
|
|
252
|
+
* @param {readonly string[]} [opts.skipDirectories] - The corpus scope. Stated
|
|
253
|
+
* by the caller, never defaulted — see {@link addressCorpus}.
|
|
254
|
+
* @param {readonly object[]} [opts.maps] - The document-subtype maps.
|
|
255
|
+
* @param {object} [opts.config] - The resolved build configuration.
|
|
256
|
+
* @param {readonly object[]} [opts.records] - Index records the caller already
|
|
257
|
+
* derived, shared with {@link noteFilesById} so one command reads one corpus.
|
|
258
|
+
* @param {object[]} [opts.problems] - Collects the notes the index cannot
|
|
259
|
+
* record, so one of them does not abort the diff before it reports.
|
|
260
|
+
* @returns {Map<string, {to: string, file: string, shortcode: string}>} Old
|
|
261
|
+
* address → the address the declaring note publishes at now, and that note.
|
|
262
|
+
*/
|
|
260
263
|
export function declaredPredecessors(
|
|
261
264
|
contentBase,
|
|
262
265
|
{ skipDirectories, maps = KNOWN_DOCUMENT_SUBTYPE_MAPS, config, records, problems } = {},
|
|
@@ -315,7 +318,7 @@ export function declaredPredecessors(
|
|
|
315
318
|
* @param {Map<string, {to: string, file: string}>} [opts.predecessors] - The
|
|
316
319
|
* declared renames, from {@link declaredPredecessors}. Omitted, the diff
|
|
317
320
|
* falls back to the id join alone and reports an unpinned rename as a
|
|
318
|
-
* withdrawal, which is what it did before
|
|
321
|
+
* withdrawal, which is what it did before.
|
|
319
322
|
* @returns {Array<object>} One finding per departed address, in address order
|
|
320
323
|
* so two runs read the same. `kind` is `"renamed"` (with `to`, and `declared`
|
|
321
324
|
* when it was the note's word rather than an id match) or `"withdrawn"`.
|
|
@@ -393,6 +396,8 @@ export function diffItemAddresses(baseline, current, { baseline: label, predeces
|
|
|
393
396
|
* id is derived against. See {@link addressCorpus} for why that matters.
|
|
394
397
|
* @param {readonly object[]} [opts.records] - Index records the caller already
|
|
395
398
|
* derived, shared with {@link declaredPredecessors}.
|
|
399
|
+
* @param {object[]} [opts.problems] - Collects the notes the index cannot
|
|
400
|
+
* record, so one of them does not abort the diff before it reports.
|
|
396
401
|
* @returns {Map<string, string>} Document id → the note's absolute path.
|
|
397
402
|
*/
|
|
398
403
|
export function noteFilesById(contentBase, { skipDirectories, config, records, problems } = {}) {
|
|
@@ -431,7 +436,7 @@ export function noteFilesById(contentBase, { skipDirectories, config, records, p
|
|
|
431
436
|
* A **declared** rename knows its note without any lookup — the declaration is
|
|
432
437
|
* how it was found — and is reported at the `renamedFrom:` line rather than the
|
|
433
438
|
* `shortcode:` line, because that is the line the finding is about and the one
|
|
434
|
-
* the author deletes once the declaration has done its work
|
|
439
|
+
* the author deletes once the declaration has done its work.
|
|
435
440
|
*
|
|
436
441
|
* @param {object} finding - One finding from {@link diffItemAddresses}.
|
|
437
442
|
* @param {Map<string, string>} noteFiles - From {@link noteFilesById}.
|
|
@@ -480,7 +485,7 @@ export function locateAddressFinding(finding, noteFiles) {
|
|
|
480
485
|
* known — and says so, rather than leaving the reader to wonder whether one was
|
|
481
486
|
* looked for.
|
|
482
487
|
*
|
|
483
|
-
* **A declared rename says it is declared
|
|
488
|
+
* **A declared rename says it is declared**. The two claims are not
|
|
484
489
|
* equally checkable: an id match is a fact in the artefacts, while a
|
|
485
490
|
* declaration is an author's word, and a reader deciding whether to trust the
|
|
486
491
|
* successor needs to know which one they have. Saying "the same document" of a
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* `{#dossier}` and `{#spoilers}`. *Which field* each lands in is a system's
|
|
20
20
|
* business — SoHL writes the first to an actor's `appearance`, HM3 to an
|
|
21
21
|
* actor's and an item's `description` — but *finding* it is not, so the
|
|
22
|
-
* extraction lives here where every compiler reaches it
|
|
22
|
+
* extraction lives here where every compiler reaches it.
|
|
23
23
|
*
|
|
24
24
|
* It was a pair of private functions inside the SoHL actors pass, which is
|
|
25
25
|
* where the convention was first needed and not where it belongs: the anchors
|
package/engine/anchors.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* The anchors a note declares on its headings — read in one place
|
|
15
|
+
* The anchors a note declares on its headings — read in one place.
|
|
16
16
|
*
|
|
17
17
|
* **A leaf, deliberately.** This is asked by the link checker, by the content
|
|
18
18
|
* index, and by the builds that emit a link, and they cannot all import one
|