@heroiclands/package-build 22.9.2 → 22.11.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 (97) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/CONTENT.md +54 -0
  3. package/bin/content-build.mjs +3 -1
  4. package/docs/api.md +11 -6
  5. package/docs/commands.md +1 -1
  6. package/docs/content-format.md +411 -201
  7. package/engine/actor-compiler.mjs +20 -7
  8. package/engine/address-fields.mjs +426 -0
  9. package/engine/address-values.mjs +80 -0
  10. package/engine/address.mjs +769 -0
  11. package/engine/art-fields.mjs +112 -97
  12. package/engine/art-slots.mjs +81 -0
  13. package/engine/base-compiler.mjs +61 -7
  14. package/engine/bundle-notes.mjs +5 -2
  15. package/engine/bundles.mjs +17 -10
  16. package/engine/content-address.mjs +23 -186
  17. package/engine/content-embeds.mjs +18 -4
  18. package/engine/content-format-check.mjs +50 -22
  19. package/engine/content-index.mjs +85 -43
  20. package/engine/content-links.mjs +105 -104
  21. package/engine/content-lint.mjs +11 -1
  22. package/engine/content-tables.mjs +9 -1
  23. package/engine/field-spec.mjs +21 -4
  24. package/engine/folder-notes.mjs +44 -15
  25. package/engine/foundry-entries.mjs +3 -0
  26. package/engine/frontmatter-lint.mjs +150 -47
  27. package/engine/frontmatter.mjs +55 -10
  28. package/engine/generate.mjs +7 -1
  29. package/engine/helpers.mjs +37 -9
  30. package/engine/holdings.mjs +41 -12
  31. package/engine/index-records.mjs +2 -0
  32. package/engine/infobox-render.mjs +2 -1
  33. package/engine/infobox.mjs +26 -6
  34. package/engine/item-compiler.mjs +5 -0
  35. package/engine/item-docs.mjs +7 -44
  36. package/engine/map-dot.mjs +2 -0
  37. package/engine/map-notes.mjs +7 -2
  38. package/engine/map-places.mjs +42 -10
  39. package/engine/metadata-index.mjs +60 -5
  40. package/engine/note-addresses.mjs +325 -0
  41. package/engine/note-vocabulary.mjs +140 -28
  42. package/engine/pdf-build.mjs +1 -1
  43. package/engine/pdf-toc.mjs +17 -2
  44. package/engine/place-relations.mjs +160 -50
  45. package/engine/populations.mjs +17 -9
  46. package/engine/reference-targets.mjs +54 -0
  47. package/engine/scenes.mjs +5 -2
  48. package/engine/shortcode-references.mjs +68 -0
  49. package/engine/site-build.mjs +39 -15
  50. package/engine/site-index.mjs +57 -75
  51. package/engine/sql-tables.mjs +43 -9
  52. package/engine/system-block.mjs +21 -0
  53. package/engine/system-vocabulary.mjs +46 -0
  54. package/engine/web-wikilinks.mjs +11 -9
  55. package/engine/wikilink-syntax.mjs +21 -0
  56. package/engine/wikilinks.mjs +92 -306
  57. package/hm3/actors.mjs +8 -24
  58. package/hm3/item-fields.mjs +15 -5
  59. package/package.json +1 -1
  60. package/sohl/infobox.mjs +111 -17
  61. package/sohl/item-fields.mjs +131 -41
  62. package/types/engine/address-fields.d.mts +95 -0
  63. package/types/engine/address-values.d.mts +34 -0
  64. package/types/engine/address.d.mts +452 -0
  65. package/types/engine/art-fields.d.mts +59 -53
  66. package/types/engine/art-slots.d.mts +40 -0
  67. package/types/engine/base-compiler.d.mts +24 -2
  68. package/types/engine/bundle-notes.d.mts +2 -2
  69. package/types/engine/content-address.d.mts +3 -139
  70. package/types/engine/content-embeds.d.mts +1 -1
  71. package/types/engine/content-format-check.d.mts +25 -0
  72. package/types/engine/content-index.d.mts +2 -2
  73. package/types/engine/content-links.d.mts +6 -5
  74. package/types/engine/field-spec.d.mts +46 -9
  75. package/types/engine/folder-notes.d.mts +11 -10
  76. package/types/engine/frontmatter-lint.d.mts +7 -97
  77. package/types/engine/frontmatter.d.mts +16 -1
  78. package/types/engine/helpers.d.mts +2 -2
  79. package/types/engine/infobox.d.mts +6 -0
  80. package/types/engine/item-docs.d.mts +1 -35
  81. package/types/engine/map-notes.d.mts +2 -2
  82. package/types/engine/note-addresses.d.mts +41 -0
  83. package/types/engine/note-vocabulary.d.mts +20 -3
  84. package/types/engine/place-relations.d.mts +12 -1
  85. package/types/engine/populations.d.mts +17 -2
  86. package/types/engine/reference-targets.d.mts +9 -0
  87. package/types/engine/shortcode-references.d.mts +14 -0
  88. package/types/engine/site-build.d.mts +3 -3
  89. package/types/engine/site-index.d.mts +9 -30
  90. package/types/engine/sql-tables.d.mts +2 -2
  91. package/types/engine/system-block.d.mts +17 -0
  92. package/types/engine/system-vocabulary.d.mts +16 -0
  93. package/types/engine/wikilink-syntax.d.mts +7 -0
  94. package/types/engine/wikilinks.d.mts +6 -109
  95. package/types/hm3/item-fields.d.mts +5 -0
  96. package/types/sohl/infobox.d.mts +6 -5
  97. package/types/sohl/item-fields.d.mts +8 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 22.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **Affiliations:** SoHL common skills link to their exact native Items; authors declare them in the SoHL block, and shared declarations receive an error.
8
+
9
+ ## 22.10.0
10
+
11
+ ### Minor Changes
12
+
13
+ **Affiliations** — a `seat`, a `parents` list, a `domains` list and a `relations`
14
+ map written under `data:` now reach the compiled item, so an affiliation carries
15
+ the place its authority sits in, the bodies it answers to, the places it holds
16
+ sway over and its standing toward other societies. Every affiliation shipped
17
+ these empty whatever its note said, so a setting's compiled packs change without
18
+ a word of its content changing, and anything reading those fields — a sheet, a
19
+ chat card, a rules outcome — begins seeing them. Every other field the format
20
+ maps out of `data:` is read from there too: a gear item's weight, worth,
21
+ craftsmanship and durability, an affliction's and a trauma's timed phases, and a
22
+ mystery's charges and skill aptitudes. Writing one at its destination still wins.
23
+
24
+ **Addresses** — a field that points at another note names it by _address_,
25
+ written at whatever length says what it means: a note in another package in
26
+ full, one in this package by its shortcode alone, with the compiled document
27
+ carrying the shortcode the game reads either way. A value naming the wrong kind
28
+ of thing now says so, instead of compiling into a reference that resolves to
29
+ nothing — a `seat` or a `domains` entry that is not a place, a `parents` entry or
30
+ a `relations` key that is not an affiliation, a border's or a route's `to` that
31
+ is not a place.
32
+
33
+ **Art** — `icon`, `tokenIcon`, `bgImage` and `banner` each accept an `icon` or an
34
+ `image` address, whichever one they default to, so a deity's profile art can be a
35
+ full illustration rather than a game icon. Any other type, an `audio` address
36
+ among them, is now an error naming what the slot accepts rather than a silent
37
+ fall back to the document's default art.
38
+
39
+ **Shortcodes** — `assocSkillCode`, `assocAffiliationCode` and `parentSkillCode`
40
+ name another item by its bare shortcode, resolved among one actor's own embedded
41
+ items, where a qualified value can never resolve. Such a value is now refused
42
+ with that reason rather than reported as a dead reference, and no authored value
43
+ in any tree carries one today.
44
+
45
+ **The specification** names three different things where it had one word: an
46
+
47
+ - Published references identify their complete package and document; authored abbreviations remain accepted and source notes stay unchanged.
48
+ - Documentation references open their journals, and native character species text stays independent of shared species lore.
49
+ - Content authors receive errors at malformed references and references naming an unsupported kind of note.
50
+ - Economy references require an explicit type and accept only affiliations or lore.
51
+
52
+ ### Patch Changes
53
+
54
+ **Places**
55
+
56
+ - A border or a route naming a place in another package is written as a _full
57
+ address_; a bare shortcode names a place in the package being built.
58
+
3
59
  ## 22.9.2
4
60
 
5
61
  ### 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,43 @@ 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
+
1447
+ An affiliation authors native SoHL skill references at
1448
+ `sohl.system.commonSkills`:
1449
+
1450
+ ```yaml
1451
+ sohl:
1452
+ system:
1453
+ commonSkills:
1454
+ - herb
1455
+ - sohl-sohl-skill-law
1456
+ ```
1457
+
1458
+ The first Address names this content package's SoHL skill; the second names a
1459
+ skill in the declared SoHL dependency. The content index retains their complete
1460
+ Addresses. Foundry compilation resolves each exact native skill Item in the
1461
+ local or declared dependency index and writes its published Item UUID to the
1462
+ affiliation's `system.commonSkills` array. The producer's module ID and pack
1463
+ come from that index. An unresolved target or a target without a native Item
1464
+ UUID is a located error. The shared `data:` container has no `commonSkills`
1465
+ property. Infoboxes use a skill's published documentation journal when it has
1466
+ one and show its known name as plain text otherwise.
1467
+
1414
1468
  **There is deliberately no third rule** requiring every note to repeat its own
1415
1469
  `type-shortcode` address in `aliases:`. It would serve one reader — Obsidian, so
1416
1470
  `[[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. |
@@ -1365,6 +1369,7 @@ Which of SoHL's facts a note's summary panel carries, and how they group. Read o
1365
1369
  | `SOHL_FIELD_PRESENTATION` | `const SOHL_FIELD_PRESENTATION` | — | looking up what one of SoHL's fields is called, or why it carries no row |
1366
1370
  | `PROTECTION_FIELDS` | `const PROTECTION_FIELDS` | — | reading the declarations of the aspects armour is rated against, in the order shown |
1367
1371
  | `UNSTATED` | `const UNSTATED` | — | naming what a strike mode shows where a value was not stated |
1372
+ | `affiliationSections` | `affiliationSections(fm, ctx)` | `object[]` | building an affiliation's box with skill documentation links |
1368
1373
  | `armorSections` | `armorSections(fm, ctx)` | `object[]` | building armour's box, protection included |
1369
1374
  | `beingSections` | `beingSections(fm, ctx)` | `object[]` | building a being's attributes, skills, mystical abilities and equipment |
1370
1375
  | `decodeItem` | `decodeItem(entry)` | `object \| undefined` | reading what one `sohl.items` entry names, whichever form it was written in |
package/docs/commands.md CHANGED
@@ -1445,7 +1445,7 @@ declaration that compiles it. Otherwise 0.
1445
1445
  $ content-build content-format fields --fields sohl --coverage
1446
1446
  […] 13 type(s) compared against sohl's declarations (56 field pair(s)).
1447
1447
  […] 12 type(s) the format declares are out of reach — no `itemBuilders` entry covers them: being, homepage, vehicle, armorlocation, lore, map, place, scenario, doc, macro, bundle, folder.
1448
- […] affiliation: format only [commonSkills, demonym, economy, epithet, governance, lore, population, symbol, templatePriority], declaration only [level, office, society, subType, title]
1448
+ […] affiliation: format only [demonym, economy, epithet, governance, lore, population, symbol, templatePriority], declaration only [commonSkills, level, office, society, subType, title]
1449
1449
  ```
1450
1450
 
1451
1451
  **SEE ALSO**