@heroiclands/package-build 22.9.2 → 22.10.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/CONTENT.md +33 -0
  3. package/bin/content-build.mjs +3 -1
  4. package/docs/api.md +10 -6
  5. package/docs/content-format.md +384 -200
  6. package/engine/actor-compiler.mjs +20 -7
  7. package/engine/address-fields.mjs +404 -0
  8. package/engine/address-values.mjs +80 -0
  9. package/engine/address.mjs +769 -0
  10. package/engine/art-fields.mjs +112 -97
  11. package/engine/art-slots.mjs +81 -0
  12. package/engine/base-compiler.mjs +59 -7
  13. package/engine/bundle-notes.mjs +5 -2
  14. package/engine/bundles.mjs +17 -10
  15. package/engine/content-address.mjs +23 -186
  16. package/engine/content-embeds.mjs +18 -4
  17. package/engine/content-format-check.mjs +50 -22
  18. package/engine/content-index.mjs +85 -43
  19. package/engine/content-links.mjs +105 -104
  20. package/engine/content-lint.mjs +11 -1
  21. package/engine/content-tables.mjs +9 -1
  22. package/engine/field-spec.mjs +20 -4
  23. package/engine/folder-notes.mjs +44 -15
  24. package/engine/foundry-entries.mjs +3 -0
  25. package/engine/frontmatter-lint.mjs +144 -43
  26. package/engine/frontmatter.mjs +55 -10
  27. package/engine/generate.mjs +7 -1
  28. package/engine/helpers.mjs +37 -9
  29. package/engine/holdings.mjs +41 -12
  30. package/engine/index-records.mjs +2 -0
  31. package/engine/infobox-render.mjs +2 -1
  32. package/engine/infobox.mjs +26 -6
  33. package/engine/item-compiler.mjs +5 -0
  34. package/engine/item-docs.mjs +7 -44
  35. package/engine/map-dot.mjs +2 -0
  36. package/engine/map-notes.mjs +7 -2
  37. package/engine/map-places.mjs +42 -10
  38. package/engine/metadata-index.mjs +60 -5
  39. package/engine/note-addresses.mjs +310 -0
  40. package/engine/note-vocabulary.mjs +145 -26
  41. package/engine/pdf-build.mjs +1 -1
  42. package/engine/pdf-toc.mjs +17 -2
  43. package/engine/place-relations.mjs +160 -50
  44. package/engine/populations.mjs +17 -9
  45. package/engine/reference-targets.mjs +54 -0
  46. package/engine/scenes.mjs +5 -2
  47. package/engine/shortcode-references.mjs +68 -0
  48. package/engine/site-build.mjs +39 -15
  49. package/engine/site-index.mjs +57 -75
  50. package/engine/sql-tables.mjs +43 -9
  51. package/engine/system-block.mjs +21 -0
  52. package/engine/system-vocabulary.mjs +46 -0
  53. package/engine/web-wikilinks.mjs +11 -9
  54. package/engine/wikilink-syntax.mjs +21 -0
  55. package/engine/wikilinks.mjs +92 -306
  56. package/hm3/actors.mjs +8 -24
  57. package/hm3/item-fields.mjs +15 -5
  58. package/package.json +1 -1
  59. package/sohl/infobox.mjs +80 -17
  60. package/sohl/item-fields.mjs +114 -41
  61. package/types/engine/address-fields.d.mts +90 -0
  62. package/types/engine/address-values.d.mts +34 -0
  63. package/types/engine/address.d.mts +452 -0
  64. package/types/engine/art-fields.d.mts +59 -53
  65. package/types/engine/art-slots.d.mts +40 -0
  66. package/types/engine/base-compiler.d.mts +24 -2
  67. package/types/engine/bundle-notes.d.mts +2 -2
  68. package/types/engine/content-address.d.mts +3 -139
  69. package/types/engine/content-embeds.d.mts +1 -1
  70. package/types/engine/content-format-check.d.mts +25 -0
  71. package/types/engine/content-index.d.mts +2 -2
  72. package/types/engine/content-links.d.mts +6 -5
  73. package/types/engine/field-spec.d.mts +44 -9
  74. package/types/engine/folder-notes.d.mts +11 -10
  75. package/types/engine/frontmatter-lint.d.mts +7 -97
  76. package/types/engine/frontmatter.d.mts +16 -1
  77. package/types/engine/helpers.d.mts +2 -2
  78. package/types/engine/infobox.d.mts +6 -0
  79. package/types/engine/item-docs.d.mts +1 -35
  80. package/types/engine/map-notes.d.mts +2 -2
  81. package/types/engine/note-addresses.d.mts +41 -0
  82. package/types/engine/note-vocabulary.d.mts +20 -3
  83. package/types/engine/place-relations.d.mts +12 -1
  84. package/types/engine/populations.d.mts +17 -2
  85. package/types/engine/reference-targets.d.mts +9 -0
  86. package/types/engine/shortcode-references.d.mts +14 -0
  87. package/types/engine/site-build.d.mts +3 -3
  88. package/types/engine/site-index.d.mts +9 -30
  89. package/types/engine/sql-tables.d.mts +2 -2
  90. package/types/engine/system-block.d.mts +17 -0
  91. package/types/engine/system-vocabulary.d.mts +16 -0
  92. package/types/engine/wikilink-syntax.d.mts +7 -0
  93. package/types/engine/wikilinks.d.mts +6 -109
  94. package/types/hm3/item-fields.d.mts +5 -0
  95. package/types/sohl/infobox.d.mts +4 -5
  96. package/types/sohl/item-fields.d.mts +8 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 22.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ **Affiliations** — a `seat`, a `parents` list, a `domains` list and a `relations`
8
+ map written under `data:` now reach the compiled item, so an affiliation carries
9
+ the place its authority sits in, the bodies it answers to, the places it holds
10
+ sway over and its standing toward other societies. Every affiliation shipped
11
+ these empty whatever its note said, so a setting's compiled packs change without
12
+ a word of its content changing, and anything reading those fields — a sheet, a
13
+ chat card, a rules outcome — begins seeing them. Every other field the format
14
+ maps out of `data:` is read from there too: a gear item's weight, worth,
15
+ craftsmanship and durability, an affliction's and a trauma's timed phases, and a
16
+ mystery's charges and skill aptitudes. Writing one at its destination still wins.
17
+
18
+ **Addresses** — a field that points at another note names it by _address_,
19
+ written at whatever length says what it means: a note in another package in
20
+ full, one in this package by its shortcode alone, with the compiled document
21
+ carrying the shortcode the game reads either way. A value naming the wrong kind
22
+ of thing now says so, instead of compiling into a reference that resolves to
23
+ nothing — a `seat` or a `domains` entry that is not a place, a `parents` entry or
24
+ a `relations` key that is not an affiliation, a border's or a route's `to` that
25
+ is not a place.
26
+
27
+ **Art** — `icon`, `tokenIcon`, `bgImage` and `banner` each accept an `icon` or an
28
+ `image` address, whichever one they default to, so a deity's profile art can be a
29
+ full illustration rather than a game icon. Any other type, an `audio` address
30
+ among them, is now an error naming what the slot accepts rather than a silent
31
+ fall back to the document's default art.
32
+
33
+ **Shortcodes** — `assocSkillCode`, `assocAffiliationCode` and `parentSkillCode`
34
+ name another item by its bare shortcode, resolved among one actor's own embedded
35
+ items, where a qualified value can never resolve. Such a value is now refused
36
+ with that reason rather than reported as a dead reference, and no authored value
37
+ in any tree carries one today.
38
+
39
+ **The specification** names three different things where it had one word: an
40
+
41
+ - Published references identify their complete package and document; authored abbreviations remain accepted and source notes stay unchanged.
42
+ - Documentation references open their journals, and native character species text stays independent of shared species lore.
43
+ - Content authors receive errors at malformed references and references naming an unsupported kind of note.
44
+ - Economy references require an explicit type and accept only affiliations or lore.
45
+
46
+ ### Patch Changes
47
+
48
+ **Places**
49
+
50
+ - A border or a route naming a place in another package is written as a _full
51
+ address_; a bare shortcode names a place in the package being built.
52
+
3
53
  ## 22.9.2
4
54
 
5
55
  ### Patch Changes
package/CONTENT.md CHANGED
@@ -16,6 +16,23 @@ It ships a command line as well as a library — see
16
16
  npm install -D @heroiclands/package-build
17
17
  ```
18
18
 
19
+ ## Content references
20
+
21
+ Notes may abbreviate Addresses according to the defaults of their field and
22
+ system block. Builds preserve the authored files and write full Addresses to
23
+ generated content under `build/`. A reference under `data:` or in body prose
24
+ uses `none` as its system; a system-bearing target at `none` names its
25
+ documentation. A reference to an Item or Actor states its system explicitly.
26
+
27
+ Published SQL records use these complete identities too. Compare Address fields
28
+ with full Addresses, not a target's bare Shortcode. A stub's identity remains
29
+ available from its package, type and Shortcode even though it has no page address.
30
+ See the [content format](docs/content-format.md#addresses) for defaults, accepted
31
+ forms and examples.
32
+
33
+ Shared `data.species` names species lore. HârnMaster's native `hm3.system.species`
34
+ is independent character-sheet text; a shared lore reference does not populate it.
35
+
19
36
  ## Configure
20
37
 
21
38
  A consuming repository declares one `package-build.config.yaml` at its root:
@@ -1411,6 +1428,22 @@ taken from the content-format specification. It is note-format knowledge rather
1411
1428
  than any system's: `data:` holds what is true of the thing, and what a system
1412
1429
  makes of that value is declared in that system's own half.
1413
1430
 
1431
+ An Address field declares `kind: "address"`; an Address list declares
1432
+ `kind: "list"` and `entryKind: "address"`. A keyed map keeps `kind: "map"`
1433
+ and declares `keyKind`: `"address"` for affiliation relations, `"shortcode"`
1434
+ for skill aptitudes. Aptitude keys also accept `subType:<skill-subtype>`.
1435
+ `ref` supplies an omitted type and `accepts` states the permitted types;
1436
+ these are independent declarations. Heterogeneous fields such as `economy`
1437
+ and bundle `contents` require an explicit type. `economy` accepts only
1438
+ `affiliation` and `lore` Addresses.
1439
+
1440
+ The frontmatter lint checks these values and locates malformed entries without
1441
+ requiring their targets to exist. `parseAddress(value, defaults, { declared:
1442
+ true })` applies the shared grammar to a declared Address, validates every
1443
+ segment, and returns a complete tuple or a reason. This mode leaves package
1444
+ membership to resolution. The lint receives the builder's package separately
1445
+ from target lookup, including when reference resolution is disabled.
1446
+
1414
1447
  **There is deliberately no third rule** requiring every note to repeat its own
1415
1448
  `type-shortcode` address in `aliases:`. It would serve one reader — Obsidian, so
1416
1449
  `[[type-shortcode]]` resolves in the editor — and no build reads it: both
@@ -213,7 +213,9 @@ prefix.apply(log, {
213
213
  */
214
214
  function reportFailure(err) {
215
215
  const message = err instanceof Error ? err.message : String(err);
216
- if (/** @type {{located?: boolean}} */ (err)?.located) console.error(message);
216
+ if (err?.file && err?.keyPath)
217
+ emitDiagnostic({ file: err.file, ...(err.position ?? {}), severity: "error", message });
218
+ else if (/** @type {{located?: boolean}} */ (err)?.located) console.error(message);
217
219
  else log.error(message);
218
220
  }
219
221
 
package/docs/api.md CHANGED
@@ -134,6 +134,7 @@ The per-system frontmatter block: how one note feeds more than one game system t
134
134
  | `blockProperty` | `blockProperty(fm, block, key, defaultValue)` | the value | reading a property a system block may override, else the shared top-level one |
135
135
  | `legacyKeyOf` | `legacyKeyOf(field)` | `string \| undefined` | finding the key a field is authored at inside a system block |
136
136
  | `retiredTopLevelKey` | `retiredTopLevelKey(field)` | `string \| undefined` | finding the bare top-level key a `data:`-sourced field is being swept off |
137
+ | `authoredKey` | `authoredKey(name)` | `string` | reading a shared source as the key an author writes, without the `data:` container holding it |
137
138
  | `resolveFieldValue` | `resolveFieldValue(field, fm, ...)` | `{value, from}` | resolving one declared field against a note, in the declared source order |
138
139
  | `systemDataPaths` | `systemDataPaths(data, prefix)` | `string[]` | listing every path a note authors under `<system>.system`, containers included |
139
140
  | `undeclaredPaths` | `undeclaredPaths(data, declared, prefix)` | `string[]` | finding authored paths a system's published schema does not declare |
@@ -459,6 +460,7 @@ What a place is next to (`data.borders`) and reachable from (`data.routes`): the
459
460
 
460
461
  | Export | Signature | Returns | Use it when |
461
462
  | ----------------- | ------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------- |
463
+ | `RELATION_TYPE` | `const RELATION_TYPE` | `string` | the type a `to` names — the default its `<type>` segment takes and the whole of its accepted set |
462
464
  | `BEARINGS` | `const BEARINGS` | `readonly string[]` | the eight compass bearings, clockwise from `N` |
463
465
  | `ROUTE_MODES` | `const ROUTE_MODES` | `readonly string[]` | the modes a route is travelled by — `land`, `boat`, `ship` |
464
466
  | `TRAVEL_DAYS` | `const TRAVEL_DAYS` | `readonly number[]` | the days markers a route may state, each meaning "about this, under normal conditions" |
@@ -488,12 +490,13 @@ What lies within a place, who holds it, and what an affiliation holds — read o
488
490
 
489
491
  Whether a world's population figures agree from the region down — the polities and regions inside a place against what it states, a settlement against every place containing it, and a `doc` note's cited figures against the notes that own them. `content-build lint` runs all four as warnings.
490
492
 
491
- | Export | Signature | Returns | Use it when |
492
- | ----------------------- | ---------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------ |
493
- | `POPULATION_TOLERANCE` | `const POPULATION_TOLERANCE` | `number` | how far a figure written to two significant digits may round below what it contains before that is a finding |
494
- | `POPULATION_RULES` | `const POPULATION_RULES` | `readonly object[]` | the rules in order, each its `name` — the prefix its findings carry — and what it `describe`s |
495
- | `checkPopulation` | `checkPopulation(note, { index })` | `object[]` | linting a place's `population` — over-held land, an over-full region, and an oversized settlement |
496
- | `checkCitedPopulations` | `checkCitedPopulations(note, { index })` | `object[]` | linting a `doc` note's cited figures, each located at the `~figure` that states it |
493
+ | Export | Signature | Returns | Use it when |
494
+ | ----------------------- | ---------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------ |
495
+ | `POPULATION_TOLERANCE` | `const POPULATION_TOLERANCE` | `number` | how far a figure written to two significant digits may round below what it contains before that is a finding |
496
+ | `POPULATION_RULES` | `const POPULATION_RULES` | `readonly object[]` | the rules in order, each its `name` — the prefix its findings carry — and what it `describe`s |
497
+ | `checkPopulation` | `checkPopulation(note, { index })` | `object[]` | linting a place's `population` — over-held land, an over-full region, and an oversized settlement |
498
+ | `checkCitedPopulations` | `checkCitedPopulations(note, { index })` | `object[]` | linting a `doc` note's cited figures, each located at the `~figure` that states it |
499
+ | `foreignNode` | `foreignNode(canonical, entry)` | `PopulationNode\|null` | reading a fetched index entry into a node, or `null` for one that names neither a place nor an affiliation |
497
500
 
498
501
  ### `engine.marketClass`
499
502
 
@@ -1087,6 +1090,7 @@ What a `[[…]]` **is**, before anything decides where it points. One authored l
1087
1090
  | -------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------- |
1088
1091
  | `WIKILINK` | `const WIKILINK` | — | A wikilink, as authored. |
1089
1092
  | `parseWikilink` | `function parseWikilink(rawInner)` | {ParsedWikilink} The parts, each trimmed. | Split a wikilink's interior into its parts. |
1093
+ | `readWikilink` | `function readWikilink(inner, context)` | Typed target or literal target with diagnostic source. | Parse a link target using complete builder Address context. |
1090
1094
  | `authoredLabel` | `authoredLabel({ display })` | {string\|null} The label, or `null` when there is none to show. | The label an author actually supplied, or `null` when they supplied none. |
1091
1095
  | `unlabelledLinkMessage` | `function unlabelledLinkMessage(target)` | {string} The message, unpunctuated at the end as a finding is. | What an author writing an unlabelled link is told, in one place. |
1092
1096
  | `LINK_FINDING_REASONS` | `const LINK_FINDING_REASONS` | — | Every way a link can fail, named once for all three resolvers. |