@heroiclands/package-build 22.12.2 → 22.13.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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 22.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ **Content links**
8
+
9
+ - Ordinary wikilinks open readable notes by default; image embeds and art fields resolve systemless assets.
10
+ - Readable notes use `note` addresses, while explicit game systems select Actors and Items and `none` selects systemless targets.
11
+
12
+ **Editor navigation**
13
+
14
+ - Install `@heroiclands/content-language-server` for content note search and navigation in an editor.
15
+
16
+ ## 22.12.3
17
+
18
+ ### Patch Changes
19
+
20
+ - Content authors can find notes by name, alias, tag, shortcode, or Address and follow references from an LSP-capable editor.
21
+ - Editor reference search works without ripgrep installed.
22
+
3
23
  ## 22.12.2
4
24
 
5
25
  ### Patch Changes
package/README.md CHANGED
@@ -14,6 +14,9 @@ The content half is documented separately in **[CONTENT.md](CONTENT.md)** — th
14
14
  note format, the pack pipeline, and the configuration contract a content tree
15
15
  declares itself with.
16
16
 
17
+ Editor navigation for content projects is provided by
18
+ [`@heroiclands/content-language-server`](https://github.com/HeroicLands/content-language-server).
19
+
17
20
  ## Install
18
21
 
19
22
  ```
package/docs/api.md CHANGED
@@ -596,16 +596,17 @@ The map from each place, drawn for the site: `content-build site` draws the map
596
596
 
597
597
  The closed registry of system ids, and the `none` that stands for no system at all. An unknown system value is an error; adding a system is a data change to this registry rather than a hardcoded set scattered through the pipeline.
598
598
 
599
- | Export | Signature | Returns | Use it when |
600
- | ---------------------- | -------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------- |
601
- | `NO_SYSTEM` | `const NO_SYSTEM` | — | naming the `<system>` segment of a note that belongs to no game system |
602
- | `SYSTEM_IDS` | `const SYSTEM_IDS` | — | enumerating every game system this toolchain compiles for |
603
- | `SYSTEM_SEGMENTS` | `const SYSTEM_SEGMENTS` | — | enumerating everything the `<system>` address segment may say — the systems plus `NO_SYSTEM` |
604
- | `isSystemId` | `isSystemId(value)` | `boolean` | checking whether a value names a game system this toolchain knows (`none` is rejected) |
605
- | `isSystemSegment` | `isSystemSegment(value)` | `boolean` | checking whether a value is something the `<system>` address segment may hold |
606
- | `unknownSystemMessage` | `unknownSystemMessage(value, where)` | `string` | building the message for a caller that wrote an unknown system |
607
- | `assertSystemSegment` | `assertSystemSegment(value, where)` | `string` — the value, unchanged | refusing a value the `<system>` segment may not hold, validating inline |
608
- | `assertSystemCharset` | `assertSystemCharset(segments, where)` | throws | refusing a registry declaration whose id could not be an address segment |
599
+ | Export | Signature | Returns | Use it when |
600
+ | ---------------------- | -------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------- |
601
+ | `NO_SYSTEM` | `const NO_SYSTEM` | — | naming a systemless asset or Foundry document |
602
+ | `NOTE_SYSTEM` | `const NOTE_SYSTEM` | — | naming readable note content across web, book and Foundry |
603
+ | `SYSTEM_IDS` | `const SYSTEM_IDS` | — | enumerating every game system this toolchain compiles for |
604
+ | `SYSTEM_SEGMENTS` | `const SYSTEM_SEGMENTS` | — | enumerating the game systems, `note` and `none` |
605
+ | `isSystemId` | `isSystemId(value)` | `boolean` | checking whether a value names a game system this toolchain knows (`none` is rejected) |
606
+ | `isSystemSegment` | `isSystemSegment(value)` | `boolean` | checking whether a value is something the `<system>` address segment may hold |
607
+ | `unknownSystemMessage` | `unknownSystemMessage(value, where)` | `string` | building the message for a caller that wrote an unknown system |
608
+ | `assertSystemSegment` | `assertSystemSegment(value, where)` | `string` — the value, unchanged | refusing a value the `<system>` segment may not hold, validating inline |
609
+ | `assertSystemCharset` | `assertSystemCharset(segments, where)` | throws | refusing a registry declaration whose id could not be an address segment |
609
610
 
610
611
  ### `engine.calendars`
611
612
 
@@ -675,7 +676,7 @@ Where a content note publishes on the web. One rule, in one place, because two b
675
676
  | `addressSlug` | `function addressSlug(fm)` | {string} The address segment, e.g. | The single path segment a note is addressed by: `type-shortcode`. |
676
677
  | `packageAddress` | `function packageAddress(fm)` | {string} The package-relative address, with a trailing slash and no leading one. | A note's address: `<type>-<shortcode>/`, e.g. |
677
678
  | `canonicalKey` | `function canonicalKey(pkg, system, type, shortcode)` | {string} `package-system-type-shortcode`, lowercased. | The **canonical** address of a note: fully qualified, one spelling per document, and globally unique. |
678
- | `blockSystem` | `function blockSystem(keyPath)` | {string} The system id, or `none`. | Which system a frontmatter key path is written under. |
679
+ | `blockSystem` | `function blockSystem(keyPath)` | {string} The game system id, or `note`. | Which system a frontmatter key path is written under. |
679
680
  | `expandAddress` | `function expandAddress(read, where)` | {string} The canonical `package-system-type-shortcode`. | Expand a written address to the one canonical address it names. |
680
681
  | `CANONICAL_KEY_SEGMENTS` | `const CANONICAL_KEY_SEGMENTS` | — | How many segments a canonical key has, and therefore how many the reader below counts. |
681
682
  | `readCanonicalKey` | `function readCanonicalKey(key)` | {{package: string, system: string, type: string, shortcode: string} \|null\|undefined} The parts; `null` when there is a string that is not in canonical form; `undefined` when there is no key at all. | Reads a canonical key back into its parts. |
@@ -1062,12 +1063,12 @@ Shared helpers for the pack compilers in `packages/content-build/`. The HeroicLa
1062
1063
 
1063
1064
  **Item docs** — an item's prose compiled as a JournalEntry, with the item keeping only a pointer to it. An item note's body describes what the thing _is_. That is documentation, and documentation belongs in the journals pack, so each item note compiles into a JournalEntry and the item's `system.docHtml` becomes nothing but a `@UUID` link to that entry's first page — the description-as-pointer convention, which {@link sohl.utils.descriptionLinkTarget} recognises and Display Description follows.
1064
1065
 
1065
- | Export | Signature | Returns | Use it when |
1066
- | ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
1067
- | `docEntryTypes` | `function docEntryTypes()` | {ReadonlySet<string>} The configured doc-carrying types. | Every content type whose **prose compiles into a JournalEntry of its own**, addressed by the virtual `doc<type>` qualifier. |
1068
- | `hasDocEntry` | `function hasDocEntry(type)` | {boolean} True for an item type, for `macro` and for a map type; false for `doc` and for actors. | Whether a content note's type is one whose prose becomes a JournalEntry of its own. |
1069
- | `itemDocEntryId` | `function itemDocEntryId(itemId)` | {string} A 16-character Foundry id. | The id of the JournalEntry a note's prose compiles into — an item's, or a macro's. |
1070
- | `itemDocPointer` | `function itemDocPointer(packageId, itemId, name, firstPageId)` | {string} The pointer to store in `system.docHtml`. | The description an item carries in place of its prose: a `@UUID` link to the first page of its item doc, and nothing else. |
1066
+ | Export | Signature | Returns | Use it when |
1067
+ | ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
1068
+ | `docEntryTypes` | `function docEntryTypes()` | {ReadonlySet<string>} The configured doc-carrying types. | Every content type whose **prose compiles into a JournalEntry of its own**, addressed by `note` with the authored type. |
1069
+ | `hasDocEntry` | `function hasDocEntry(type)` | {boolean} True for an item type, for `macro` and for a map type; false for `doc` and for actors. | Whether a content note's type is one whose prose becomes a JournalEntry of its own. |
1070
+ | `itemDocEntryId` | `function itemDocEntryId(itemId)` | {string} A 16-character Foundry id. | The id of the JournalEntry a note's prose compiles into — an item's, or a macro's. |
1071
+ | `itemDocPointer` | `function itemDocPointer(packageId, itemId, name, firstPageId)` | {string} The pointer to store in `system.docHtml`. | The description an item carries in place of its prose: a `@UUID` link to the first page of its item doc, and nothing else. |
1071
1072
 
1072
1073
  - `itemTypes` — re-exported: Every content type that compiles into an item — and therefore into an item doc.
1073
1074
 
@@ -1077,7 +1078,7 @@ Wikilink resolution for the pack compilers. Content notes link to one another wi
1077
1078
 
1078
1079
  | Export | Signature | Returns | Use it when |
1079
1080
  | -------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1080
- | `resolveItemDocType` | `function resolveItemDocType(qualifier, types)` | {string\|null} The underlying document type, or `null` when the qualifier is not a virtual one. | Reads a qualifier as the **virtual `doc<type>`** form, or reports that it is not one. |
1081
+ | `resolveItemDocType` | `function resolveItemDocType(qualifier, types)` | {string\|null} The underlying document type, or `null` when the qualifier is not a virtual one. | Reads an accepted `doc<type>` input alias as its authored type. |
1081
1082
  | `readQualifier` | `function readQualifier(target, types, packages, noIndexPackages)` | {{type: string, shortcode: string, itemDoc: boolean, package?: string, system?: string, reason?: undefined} \| {reason: "unknown-type"\|"no-content-index", package?: string} \| null} The resolved qualifier; a `reason` when the target is definitely qualified but names no known type or no fetched index; or `null` when it is not an address at all. | Read a link target as a **qualified** `type-shortcode` reference, or report that it does not parse as one. |
1082
1083
  | `anchorPageId` | `function anchorPageId(noteId, anchorSlug)` | {string} A 16-character alphanumeric id. | The deterministic JournalEntryPage id for one anchor: SHA-256 of `"<noteId>-<anchorSlug>"`, base64-encoded, reduced to the 16 alphanumeric characters a Foundry id allows. |
1083
1084
  | `buildWikilinkIndex` | `function buildWikilinkIndex(docs, packageId, foreign, contentPackage)` | {{byShortcode: Map<string, object>, types: Set<string>}} `types` is every type the tree actually contains, so a qualifier naming no real type can be told apart from a missing target. | Builds the link-resolution tables for a content tree. |
package/docs/commands.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Command reference
2
2
 
3
- `@heroiclands/package-build` ships two binaries. `package-build` is the
3
+ `@heroiclands/package-build` ships two build binaries. `package-build` is the
4
4
  packaging half — clean, stage, check, package, deploy, run a Foundry
5
5
  container, drive the end-to-end suite. `content-build` is the content half —
6
6
  compile a note tree into compendium packs, check it, publish it as a site or a
@@ -21,7 +21,7 @@ says so under **OPTIONS** rather than omitting the section.
21
21
 
22
22
  **Every finding is `file:line:column: severity: message`**, the path starting
23
23
  the line — the diagnostic contract this package's own build tooling emits and
24
- that both binaries' content-side commands use for anything found in a
24
+ that both build binaries' content-side commands use for anything found in a
25
25
  specific file. A field that cannot be known is dropped rather than guessed:
26
26
  `file:line:` when the column means nothing, `file:` when only the file is
27
27
  known. See [Diagnostics](diagnostics.md) for the full contract.
@@ -96,7 +96,7 @@ column regardless.
96
96
 
97
97
  **Embedded models link to documentation in an infobox.** The model Address
98
98
  continues to identify the native Item used for compilation. Its displayed link
99
- uses that same package, type and Shortcode under `none`, which names the
99
+ uses that same package, type and Shortcode under `note`, which names the
100
100
  corresponding documentation journal. A model with no published documentation
101
101
  keeps its known name as plain text; the infobox does not substitute an Actor or
102
102
  Item link.
@@ -1268,85 +1268,78 @@ below.
1268
1268
  <package>-<system>-<note_type>-<shortcode>
1269
1269
  ```
1270
1270
 
1271
- Read it from the right: the last segment is always the shortcode, the one before
1272
- it always the note type, the one before that always the system, and the first the
1273
- package. Nothing is positional-by-guess — a segment means what its position says
1274
- it means.
1271
+ The final segment is the shortcode, preceded by the note type, the system and
1272
+ the package. Each segment has one position. The system says which kind of target
1273
+ is named:
1275
1274
 
1276
- The `<system>` segment is `none` for a note that belongs to no system, which is
1277
- most of them: `harnadventures-none-being-grod`. A note that exists only for one
1278
- system names it.
1275
+ | system | target |
1276
+ | ------------- | --------------------------------------------------------------------------- |
1277
+ | `note` | Readable note content: a web page, a book entry, or a Foundry JournalEntry. |
1278
+ | `none` | A systemless target such as an asset, Folder, Macro or Scene. |
1279
+ | `sohl`, `hm3` | A game system's Actor or Item document. |
1280
+
1281
+ A note can publish more than one Address. A `being` note, for example, publishes
1282
+ `thalorna-note-being-bctrncml` for its readable content and
1283
+ `thalorna-sohl-being-bctrncml` for its SoHL Actor. An item note follows the same
1284
+ pattern for its page and Item. The type segment remains the authored note type
1285
+ in each Address.
1279
1286
 
1280
1287
  #### Shorter forms
1281
1288
 
1282
- The full address is the unambiguous form, and almost nothing uses it — 92 of
1283
- 12,056 links in the current trees. The rest rely on shorter forms, each dropping
1284
- segments from the left:
1289
+ Authors may omit segments from the left. The complete Address states all four:
1285
1290
 
1286
1291
  | form | expands to |
1287
1292
  | ------------------------------- | -------------------------------------------------------- |
1288
1293
  | `package-system-type-shortcode` | itself |
1289
1294
  | `system-type-shortcode` | `<this package>-system-type-shortcode` |
1290
- | `type-shortcode` | `<this package>-<this block's system>-type-shortcode` |
1291
- | `shortcode` | as above, with the type from the field's own declaration |
1295
+ | `type-shortcode` | `<this package>-<this position's system>-type-shortcode` |
1296
+ | `shortcode` | as above, with the type from the field's declaration |
1292
1297
 
1293
- There is no `package-type-shortcode`: the forms are exactly the **suffixes** of
1294
- the canonical address, so naming another package means naming its system too.
1295
- `kethira-place-tashal` is three segments, which reads as system `kethira`, and
1296
- fails.
1298
+ There is no `package-type-shortcode` form. A reference to another package states
1299
+ its system as well as its package.
1297
1300
 
1298
1301
  #### Authored references and generated references
1299
1302
 
1300
- Authored notes may use any permitted suffix. Builds leave those source bytes
1301
- unchanged. Generated content indexes, SQL records, site frontmatter and generated
1302
- Wikilinks contain full `package-system-type-shortcode` Addresses. For example,
1303
- `data.parents: [north]` in the `thalorna` package emits
1304
- `data.parents: [thalorna-none-place-north]`.
1303
+ Authored notes may use any permitted suffix. Builds leave source bytes unchanged.
1304
+ Generated content indexes, SQL records, site frontmatter and generated
1305
+ Wikilinks contain complete Addresses. For example, `data.parents: [north]` in
1306
+ `thalorna` emits `data.parents: [thalorna-note-place-north]`.
1305
1307
 
1306
- SQL queries compare Address-valued fields to full Addresses. A note's `shortcode`
1307
- is a distinct identity component, so it is not equal to an Address stored in
1308
- `data.parents`, `data.domains` or a governance rank's `lore`. Use the target's
1309
- complete identity for that comparison, including its package, system and type.
1310
- A stub has no published page address; its note identity still contains those
1311
- components and its Shortcode.
1308
+ SQL queries compare Address-valued fields to complete Addresses. A note's
1309
+ `shortcode` is a distinct identity component, so it is not equal to an Address
1310
+ stored in `data.parents`, `data.domains` or a governance rank's `lore`. Use the
1311
+ target's complete identity for that comparison. A stub has no published page
1312
+ address; its note identity still contains the package, system, type and shortcode.
1312
1313
 
1313
- The toolchain holds parsed Address properties as complete tuples internally.
1314
- Address-keyed relation maps hold typed targets and standing values. Only generated
1315
- output serializes these properties to Address strings. Runtime Shortcodes,
1316
- Foundry UUIDs, file paths and URLs keep their own representations.
1314
+ The toolchain holds parsed Addresses as complete tuples internally. Address-keyed
1315
+ relation maps hold typed targets and standing values. Only generated output
1316
+ serializes these properties to Address strings. Runtime Shortcodes, Foundry
1317
+ UUIDs, file paths and URLs keep their own representations.
1317
1318
 
1318
1319
  An Address-valued `data:` field must name a target in this package or a declared
1319
- dependency index. `content-build lint` reports a missing target as an error at
1320
- the value or map key that names it. A stub counts as a target for data even
1321
- though it publishes no page. Art slots use their own missing-art warning and
1322
- document fallback.
1320
+ dependency index. `content-build lint` reports a missing target at the value or
1321
+ map key that names it. A stub counts as a target for data even though it
1322
+ publishes no page. Art slots use their own missing-art warning and document
1323
+ fallback.
1323
1324
 
1324
1325
  #### An omitted segment defaults from where the link is written
1325
1326
 
1326
- It is **not** a wildcard and resolution is not a search. Every short form expands
1327
- to exactly one canonical address before anything is looked up, so a lookup either
1328
- finds one entry or none — there is no candidate set, and a cross-package
1329
- ambiguity is impossible by construction.
1330
-
1331
- - **package** omitted → the current package. A short address therefore names
1332
- _this_ package and never falls through to a dependency; reaching another one is
1333
- the fully qualified form's job.
1334
- - **system** omitted → **the system block the link is written under**. Anywhere
1335
- under `sohl:` is `sohl`; anywhere under `hm3:` is `hm3`; **anywhere else** —
1336
- top-level frontmatter, `data:`, and body prose — is `none`. The enclosing block
1337
- decides at any depth, so `sohl.items[3].model` and `sohl.system.body.structure`
1338
- default alike; the field has no say.
1339
-
1340
- **Under `none`, a system-bearing type addresses its documentation.** A note's
1341
- `none` address _is_ its `doc<type>` journal — the Item is the one with a system —
1342
- so a prose `[[affiliation-sirvadar|Sirvadar]]` names the page, which is what
1343
- prose almost always means. A prose link that means the **Item** states the
1344
- system: `[[sohl-affiliation-sirvadar|…]]`.
1345
-
1346
- Only a type whose own document carries a system is redirected this way. A
1347
- `macro` and the map types have documentation journals too, but their own
1348
- documents are core ones already at `none`, so `macro-autoattack` names the Macro
1349
- and `docmacro-autoattack` its journal — two live addresses.
1327
+ An omitted segment is a default, not a wildcard. Every short form expands to one
1328
+ complete Address before lookup.
1329
+
1330
+ - **Package:** the current package. A short address never falls through to a
1331
+ dependency.
1332
+ - **System in `[[link|text]]`:** `note`, for every note type. Use an explicit
1333
+ game system to name its Actor or Item, or `none` to name a systemless target.
1334
+ - **System in `![[link|text]]`:** `none`. An embed names an image or icon asset;
1335
+ it also supplies `image` as the type of a bare shortcode.
1336
+ - **System in frontmatter:** a system block such as `sohl:` or `hm3:` supplies
1337
+ its game system. Other Address fields default to `note`, except fields
1338
+ declared for images, icons or folders, which default to `none`.
1339
+
1340
+ For example, `[[macro-autoattack|Automated Attack]]` names the readable macro
1341
+ note, while `[[none-macro-autoattack|Automated Attack]]` names the Foundry Macro.
1342
+ `![[icon-anvil|Anvil]]` names the systemless icon asset.
1350
1343
 
1351
1344
  **A complete Address is lowercase throughout.** Every segment — package,
1352
1345
  system, type and shortcode alike — contains only lowercase ASCII letters and
@@ -1572,7 +1565,7 @@ A **`Wikilink`** is how body prose names something:
1572
1565
  The brackets, the `#<anchor>` and the `|<text>` label are the Wikilink's own.
1573
1566
  What sits inside them is an `Address` like any other — read by the same grammar,
1574
1567
  written at any of its lengths, and taking each omitted segment from where the
1575
- link is written, which for body prose is this package and system `none`. So
1568
+ link is written, which for body prose is this package and system `note`. So
1576
1569
  nothing about resolution belongs to the bracketed form: a wikilink and a
1577
1570
  frontmatter field ask the same question of the same value, and the findings above
1578
1571
  are the answers either of them gets.
@@ -2054,10 +2047,10 @@ system a note might write. A package shipping for a second system declares
2054
2047
  `system:` on a pack of each class it compiles.
2055
2048
 
2056
2049
  That includes actors. A being producing its Actor and nothing else would be
2057
- the one system-bearing note with no address at `none`, leaving a prose link
2050
+ a system-bearing note with readable content, giving a prose link
2058
2051
  naming it nowhere to land. It carries a documentation journal like every other
2059
2052
  such note, addressed
2060
- `<package>-none-docbeing-<shortcode>` beside the Actor's
2053
+ `<package>-note-being-<shortcode>` beside the Actor's
2061
2054
  `<package>-<system>-being-<shortcode>`.
2062
2055
 
2063
2056
  **A being keeps its prose inline as well.** `system.appearance` and
@@ -4065,7 +4058,7 @@ await CONFIG.SOHL.class.Utility.currentCombatantAttack();
4065
4058
 
4066
4059
  Three rules follow, and each is deliberate. The anchor names the **page**, not
4067
4060
  the heading text, so the heading may be worded freely and
4068
- `[[docmacro-autoattack#script]]` still opens exactly this page. The fence must
4061
+ `[[macro-autoattack#script]]` still opens exactly this page. The fence must
4069
4062
  be **tagged** — an untagged fence is a code sample whose language nobody stated,
4070
4063
  and treating it as executable would make an illustrative snippet the macro. And
4071
4064
  only the **first** tagged fence counts, so a note may document its macro
@@ -4141,8 +4134,8 @@ persists in the pack.
4141
4134
  **Each address names the note's own document.** That is the same rule `pack:`
4142
4135
  follows, so there is one answer and not two. A note that compiles into _two_
4143
4136
  documents — an item and the JournalEntry its prose became — puts the second in a
4144
- bundle only when the bundle names it by its own `doc…` address:
4145
- `miscgear-bowlcer` is the item, `docmiscgear-bowlcer` its description page.
4137
+ bundle when the bundle names its `note` Address:
4138
+ `sohl-miscgear-bowlcer` is the Item, `miscgear-bowlcer` its description page.
4146
4139
 
4147
4140
  **An address that resolves to nothing fails the build.** A `folder` address is
4148
4141
  refused with a message of its own: a folder materialises in every pack holding
@@ -132,9 +132,8 @@ repository.
132
132
  npm install --save-dev @heroiclands/package-build
133
133
  ```
134
134
 
135
- That installs two binaries into `node_modules/.bin`: `package-build`, the
136
- packaging half, and `content-build`, the content half. Every command below is
137
- one of those two. Run them through `npx`, or wire them into npm scripts as
135
+ That installs `package-build`, the packaging half, and `content-build`, the
136
+ content half, into `node_modules/.bin`. Run them through `npx`, or wire them into npm scripts as
138
137
  [`project-setup.md`](project-setup.md) describes.
139
138
 
140
139
  **How it worked:** `npx package-build --version` prints the installed version.