@heroiclands/package-build 22.21.0 → 22.23.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 +223 -0
- package/assets/styles/content-base.css +162 -0
- package/bin/content-commands.mjs +77 -17
- package/bin/package-build.mjs +15 -2
- package/ci/content-format-reference.mjs +68 -1
- package/config.mjs +26 -0
- package/content-config.mjs +153 -6
- package/docs/api.md +120 -89
- package/docs/authoring/assets.md +14 -0
- package/docs/authoring/dates-and-calendars.md +41 -3
- package/docs/authoring/frontmatter.md +2 -2
- package/docs/authoring/links-and-markup.md +325 -35
- package/docs/commands.md +12 -10
- package/docs/configuration.md +117 -14
- package/docs/content-format.md +4 -2
- package/docs/guides/book.md +5 -4
- package/docs/guides/reference-pages.md +15 -0
- package/docs/reference/format-details.md +545 -104
- package/docs/reference/note-types.md +30 -13
- package/engine/actor-compiler.mjs +23 -0
- package/engine/anchored-sections.mjs +35 -4
- package/engine/anchors.mjs +26 -30
- package/engine/art-fields.mjs +118 -0
- package/engine/art-slots.mjs +7 -1
- package/engine/asset-index.mjs +160 -10
- package/engine/asset-replacement.mjs +93 -0
- package/engine/asset-types.mjs +240 -0
- package/engine/base-compiler.mjs +139 -22
- package/engine/base-styles.mjs +149 -0
- package/engine/bundles.mjs +13 -2
- package/engine/compendiums.mjs +8 -1
- package/engine/content-blocks.mjs +410 -0
- package/engine/content-embeds.mjs +19 -0
- package/engine/content-figures.mjs +468 -0
- package/engine/content-footnotes.mjs +197 -0
- package/engine/content-format-check.mjs +15 -12
- package/engine/content-format.yaml +1 -1
- package/engine/content-images.mjs +126 -25
- package/engine/content-index.mjs +38 -12
- package/engine/content-links.mjs +14 -6
- package/engine/content-tables.mjs +45 -4
- package/engine/content-tasklists.mjs +189 -0
- package/engine/docs-checks.mjs +4 -4
- package/engine/extension-attributes.mjs +48 -2
- package/engine/field-reference.mjs +31 -10
- package/engine/field-spec.mjs +10 -8
- package/engine/foreign-catalog.mjs +143 -18
- package/engine/frontmatter-lint.mjs +120 -65
- package/engine/frontmatter.mjs +3 -3
- package/engine/heading-attributes.mjs +321 -0
- package/engine/helpers.mjs +109 -41
- package/engine/homepage.mjs +8 -8
- package/engine/index.mjs +3 -0
- package/engine/infobox-registry.mjs +4 -1
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +129 -15
- package/engine/itinerary-scenes.mjs +4 -10
- package/engine/journals.mjs +294 -50
- package/engine/lore-events.mjs +197 -0
- package/engine/macros.mjs +1 -1
- package/engine/markdown-expressions.mjs +434 -59
- package/engine/note-dates.mjs +354 -12
- package/engine/note-frontmatter.mjs +7 -16
- package/engine/note-vocabulary.mjs +183 -42
- package/engine/page-lists.mjs +358 -0
- package/engine/pathnames.mjs +36 -0
- package/engine/pdf-build.mjs +431 -74
- package/engine/pdf-images.mjs +64 -0
- package/engine/pdf-render.mjs +563 -66
- package/engine/rank-ladder.mjs +198 -0
- package/engine/reckoning-markers.mjs +1 -1
- package/engine/retired-fields.mjs +8 -13
- package/engine/scenes.mjs +26 -7
- package/engine/site-build.mjs +166 -23
- package/engine/site-config.mjs +10 -1
- package/engine/site-index.mjs +90 -3
- package/engine/site-preview.mjs +20 -7
- package/engine/social-ties.mjs +52 -14
- package/engine/sql-tables.mjs +66 -9
- package/engine/standings.mjs +89 -6
- package/engine/system-block.mjs +56 -30
- package/engine/web-wikilinks.mjs +48 -1
- package/hm3/actors.mjs +8 -5
- package/manifest.mjs +43 -24
- package/package.json +1 -1
- package/packagebuild-metadata.jsonl +13 -13
- package/sohl/actors.mjs +22 -99
- package/sohl/item-fields.mjs +5 -5
- package/sohl/items.mjs +1 -1
- package/sohl/note-schemas.mjs +11 -21
- package/types/config.d.mts +9 -0
- package/types/content-config.d.mts +48 -1
- package/types/engine/actor-compiler.d.mts +11 -0
- package/types/engine/anchored-sections.d.mts +24 -0
- package/types/engine/anchors.d.mts +9 -4
- package/types/engine/art-fields.d.mts +64 -0
- package/types/engine/asset-index.d.mts +43 -0
- package/types/engine/asset-replacement.d.mts +22 -0
- package/types/engine/asset-types.d.mts +18 -0
- package/types/engine/base-compiler.d.mts +19 -17
- package/types/engine/base-styles.d.mts +93 -0
- package/types/engine/content-blocks.d.mts +87 -0
- package/types/engine/content-embeds.d.mts +16 -0
- package/types/engine/content-figures.d.mts +101 -0
- package/types/engine/content-footnotes.d.mts +80 -0
- package/types/engine/content-format-check.d.mts +8 -6
- package/types/engine/content-images.d.mts +78 -12
- package/types/engine/content-index.d.mts +8 -2
- package/types/engine/content-tables.d.mts +12 -4
- package/types/engine/content-tasklists.d.mts +72 -0
- package/types/engine/extension-attributes.d.mts +22 -1
- package/types/engine/field-reference.d.mts +21 -0
- package/types/engine/field-spec.d.mts +20 -16
- package/types/engine/foreign-catalog.d.mts +39 -0
- package/types/engine/frontmatter.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +179 -0
- package/types/engine/helpers.d.mts +29 -10
- package/types/engine/homepage.d.mts +7 -7
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox-registry.d.mts +4 -1
- package/types/engine/infobox-render.d.mts +6 -1
- package/types/engine/infobox.d.mts +6 -0
- package/types/engine/journals.d.mts +41 -12
- package/types/engine/lore-events.d.mts +14 -0
- package/types/engine/markdown-expressions.d.mts +46 -2
- package/types/engine/note-dates.d.mts +64 -1
- package/types/engine/note-frontmatter.d.mts +1 -4
- package/types/engine/note-vocabulary.d.mts +82 -6
- package/types/engine/page-lists.d.mts +126 -0
- package/types/engine/pathnames.d.mts +26 -0
- package/types/engine/pdf-build.d.mts +28 -6
- package/types/engine/pdf-images.d.mts +52 -0
- package/types/engine/pdf-render.d.mts +84 -2
- package/types/engine/rank-ladder.d.mts +32 -0
- package/types/engine/retired-fields.d.mts +4 -6
- package/types/engine/site-build.d.mts +27 -4
- package/types/engine/site-config.d.mts +9 -0
- package/types/engine/site-index.d.mts +67 -1
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -7
- package/types/engine/standings.d.mts +21 -3
- package/types/engine/system-block.d.mts +37 -14
- package/types/engine/web-wikilinks.d.mts +3 -1
- package/types/hm3/actors.d.mts +21 -3
- package/types/manifest.d.mts +19 -23
- package/types/sohl/actors.d.mts +6 -7
- package/engine/content-admonitions.mjs +0 -114
- package/engine/content-captions.mjs +0 -181
- package/engine/content-secrets.mjs +0 -112
- package/types/engine/content-admonitions.d.mts +0 -24
- package/types/engine/content-captions.d.mts +0 -45
- package/types/engine/content-secrets.d.mts +0 -17
package/docs/api.md
CHANGED
|
@@ -132,29 +132,30 @@ can write the result directly without introducing formatting drift.
|
|
|
132
132
|
|
|
133
133
|
The per-system frontmatter block: how one note feeds more than one game system through properties named after that system (`<system>.system`, `<system>.type`, `<system>.img`, `<system>.items` on actors). Resolves a field's value through the block, the shared top level, and a retiring position in that order, and merges an authored `<system>.system` onto a compiler-built one without disturbing what the builder already wrote.
|
|
134
134
|
|
|
135
|
-
| Export | Signature
|
|
136
|
-
| --------------------------- |
|
|
137
|
-
| `SYSTEM_DATA_KEY` | `const SYSTEM_DATA_KEY`
|
|
138
|
-
| `BLOCK_DOCUMENT_PROPERTIES` | `const BLOCK_DOCUMENT_PROPERTIES`
|
|
139
|
-
| `BLOCK_DIRECTIVES` | `const BLOCK_DIRECTIVES`
|
|
140
|
-
| `SYSTEM_BLOCK_KEYS` | `const SYSTEM_BLOCK_KEYS`
|
|
141
|
-
| `setPath` | `setPath(target, dotted, value)`
|
|
142
|
-
| `systemBlock` | `systemBlock(fm, block)`
|
|
143
|
-
| `carriesSystemBlock` | `carriesSystemBlock(fm, block)`
|
|
144
|
-
| `systemData` | `systemData(fm, block)`
|
|
145
|
-
| `blockField` | `blockField(fm, block, key, defaultValue)`
|
|
146
|
-
| `sharedProperty` | `sharedProperty(fm, source, defaultValue)`
|
|
147
|
-
| `blockProperty` | `blockProperty(fm, block, key, defaultValue)`
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
135
|
+
| Export | Signature | Returns | Use it when |
|
|
136
|
+
| --------------------------- | --------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
137
|
+
| `SYSTEM_DATA_KEY` | `const SYSTEM_DATA_KEY` | — | naming the key inside a system block whose contents are the system's own vocabulary |
|
|
138
|
+
| `BLOCK_DOCUMENT_PROPERTIES` | `const BLOCK_DOCUMENT_PROPERTIES` | — | mapping a system-block key to the document property it becomes |
|
|
139
|
+
| `BLOCK_DIRECTIVES` | `const BLOCK_DIRECTIVES` | — | recognizing a build directive (e.g. `pack`) that names no document property |
|
|
140
|
+
| `SYSTEM_BLOCK_KEYS` | `const SYSTEM_BLOCK_KEYS` | — | enumerating every key any system block may carry |
|
|
141
|
+
| `setPath` | `setPath(target, dotted, value)` | `object` — `target`, for chaining | writing a value at a dotted path in a document's `system` block |
|
|
142
|
+
| `systemBlock` | `systemBlock(fm, block)` | `Record<string, unknown> \| undefined` | reading one system's whole block off a note, or nothing when it is absent or malformed |
|
|
143
|
+
| `carriesSystemBlock` | `carriesSystemBlock(fm, block)` | `boolean` | deciding whether a pack that declares a system should compile a note at all |
|
|
144
|
+
| `systemData` | `systemData(fm, block)` | `Record<string, unknown>` | reading a system block's `system` sub-block, `{}` when absent |
|
|
145
|
+
| `blockField` | `blockField(fm, block, key, defaultValue)` | the value | reading a key from one system's block, falling back to the top level |
|
|
146
|
+
| `sharedProperty` | `sharedProperty(fm, source, defaultValue)` | the value | reading a shared top-level property by a possibly-dotted path, blind to every system block |
|
|
147
|
+
| `blockProperty` | `blockProperty(fm, block, key, defaultValue)` | the value | reading a property a system block may override, else the shared top-level one |
|
|
148
|
+
| `resolveDataProperty` | `resolveDataProperty(fm, block, key, defaultValue)` | `{value, from}` | resolving a shared `data:` key every type accepts — a system override, then shared `data`, then a top-level value — and reporting which one answered |
|
|
149
|
+
| `blockDataProperty` | `blockDataProperty(fm, block, key, defaultValue)` | the value | `resolveDataProperty`'s value alone, in the same order |
|
|
150
|
+
| `legacyKeyOf` | `legacyKeyOf(field)` | `string \| undefined` | finding the key a field is authored at inside a system block |
|
|
151
|
+
| `retiredTopLevelKey` | `retiredTopLevelKey(field)` | `string \| undefined` | finding the bare top-level key a `data:`-sourced field is being swept off |
|
|
152
|
+
| `authoredKey` | `authoredKey(name)` | `string` | reading a shared source as the key an author writes, without the `data:` container holding it |
|
|
153
|
+
| `resolveFieldValue` | `resolveFieldValue(field, fm, ...)` | `{value, from}` | resolving one declared field against a note, in the declared source order |
|
|
154
|
+
| `systemDataPaths` | `systemDataPaths(data, prefix)` | `string[]` | listing every path a note authors under `<system>.system`, containers included |
|
|
155
|
+
| `undeclaredPaths` | `undeclaredPaths(data, declared, prefix)` | `string[]` | finding authored paths a system's published schema does not declare |
|
|
156
|
+
| `unknownBlockKeys` | `unknownBlockKeys(fm, block, ...)` | `string[]` | finding keys directly under a system block that neither this format nor the system recognizes |
|
|
157
|
+
| `claimedPaths` | `claimedPaths(fields)` | `Set<string>` | listing the exact `system` paths a field declaration writes, for `mergeSystemData` |
|
|
158
|
+
| `mergeSystemData` | `mergeSystemData(built, fm, ...)` | `object` — `built`, for chaining | merging a note's `<system>.system` verbatim onto a built `system` block |
|
|
158
159
|
|
|
159
160
|
### `engine.codeFences`
|
|
160
161
|
|
|
@@ -347,7 +348,7 @@ The note types the engine itself declares — vocabulary that is a fact about th
|
|
|
347
348
|
|
|
348
349
|
### `engine.noteVocabulary`
|
|
349
350
|
|
|
350
|
-
An addressed content note accepts exactly these top-level keys, in this order: `shortcode`, `name`, `type`, `subType`, `description`, `tags`, `data`, `
|
|
351
|
+
An addressed content note accepts exactly these top-level keys, in this order: `shortcode`, `name`, `type`, `subType`, `description`, `tags`, `data`, `dnd5e`, `hm3`, `sohl`. A key outside this list is an error at its own line. The system blocks are one per system the address vocabulary recognizes, sorted by name after the fixed keys, so a further system is a change to `SYSTEM_IDS` alone. No dnd5e-specific document types are declared. Within that shape, the closed vocabularies are the `data:` container and each type's `subType`.
|
|
351
352
|
|
|
352
353
|
| Export | Signature | Returns | Use it when |
|
|
353
354
|
| ------------------------- | -------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
@@ -355,6 +356,9 @@ An addressed content note accepts exactly these top-level keys, in this order: `
|
|
|
355
356
|
| `GM_TAG` | `const GM_TAG` | — | naming the declared tag that marks a GM-only note |
|
|
356
357
|
| `BEING_ARCHETYPES` | `const BEING_ARCHETYPES` | `Readonly<Record<string, string>>` | looking up the case-sensitive being archetypes and their meanings |
|
|
357
358
|
| `NOTE_VOCABULARY` | `const NOTE_VOCABULARY` | — | looking up, per content type, its `data:` field list and its closed `subType` values |
|
|
359
|
+
| `NOTE_TOP_LEVEL_FIELDS` | `const NOTE_TOP_LEVEL_FIELDS` | `readonly TopLevelFieldSpec[]` | reading the top-level keys a note accepts, in formatted order, with what each one means |
|
|
360
|
+
| `NOTE_TOP_LEVEL_KEYS` | `const NOTE_TOP_LEVEL_KEYS` | `readonly string[]` | reading just the key names, in the order the formatter writes them |
|
|
361
|
+
| `NOTE_TOP_LEVEL_KEY_SET` | `const NOTE_TOP_LEVEL_KEY_SET` | `ReadonlySet<string>` | testing whether a top-level key is one the note format declares |
|
|
358
362
|
| `SHARED_DATA_FIELDS` | `const SHARED_DATA_FIELDS` | `readonly DataFieldSpec[]` | reading the `data:` keys every type accepts, whatever it is — the art slots legal everywhere |
|
|
359
363
|
| `DECLARED_TAGS` | `const DECLARED_TAGS` | — | looking up the tags a note type may declare, grouped |
|
|
360
364
|
| `declaredTags` | `declaredTags(type, groups)` | `readonly string[]` | reading the declared tags a note of a type may carry, flattened |
|
|
@@ -420,15 +424,15 @@ The infobox declarations this toolchain ships, one per system, and the single ca
|
|
|
420
424
|
|
|
421
425
|
Drawing a declared infobox: HTML for separate Foundry pages appended after authored pages, Typst panels after each note’s authored body in the book. The website's boxes travel in front matter and the site theme draws them, so there is no renderer for it here.
|
|
422
426
|
|
|
423
|
-
| Export | Signature
|
|
424
|
-
| ---------------------- |
|
|
425
|
-
| `infoboxTypstPreamble` | `infoboxTypstPreamble()`
|
|
426
|
-
| `infoboxesToHtml` | `infoboxesToHtml(boxes, options)`
|
|
427
|
-
| `infoboxesToTypst` | `infoboxesToTypst(boxes, options)`
|
|
428
|
-
| `linkToHtml` | `linkToHtml(value)`
|
|
429
|
-
| `linkToTypst` | `linkToTypst(value, links, labelFor)` | `string` | drawing a link value as a cross-reference into the book |
|
|
430
|
-
| `linkToUuid` | `linkToUuid(value)`
|
|
431
|
-
| `sectionHasContent` | `sectionHasContent(section)`
|
|
427
|
+
| Export | Signature | Returns | Use it when |
|
|
428
|
+
| ---------------------- | ------------------------------------------- | --------- | ------------------------------------------------------------------------ |
|
|
429
|
+
| `infoboxTypstPreamble` | `infoboxTypstPreamble()` | `string` | emitting the panel definitions the book's bodies call, once per document |
|
|
430
|
+
| `infoboxesToHtml` | `infoboxesToHtml(boxes, options)` | `string` | drawing the boxes as `<details>` disclosures, open by default |
|
|
431
|
+
| `infoboxesToTypst` | `infoboxesToTypst(boxes, options)` | `string` | drawing the boxes as panels that break between their sections |
|
|
432
|
+
| `linkToHtml` | `linkToHtml(value)` | `string` | drawing a link value as an anchor on its URL |
|
|
433
|
+
| `linkToTypst` | `linkToTypst(value, links, labelFor, site)` | `string` | drawing a link value as a cross-reference into the book |
|
|
434
|
+
| `linkToUuid` | `linkToUuid(value)` | `string` | drawing a link value as a Foundry document reference |
|
|
435
|
+
| `sectionHasContent` | `sectionHasContent(section)` | `boolean` | deciding whether a section holds anything worth drawing |
|
|
432
436
|
|
|
433
437
|
### `engine.noteState`
|
|
434
438
|
|
|
@@ -648,7 +652,7 @@ The neutral day spelling is `<year>.<day>[:HHMMSS]`. The pure conversion functio
|
|
|
648
652
|
|
|
649
653
|
### `engine.noteDates`
|
|
650
654
|
|
|
651
|
-
A date on a note is one authored scalar. `<year>[.<day>[:HHMMSS]]` names a calendar-neutral year, day, or second; `datefrom vrcal 23 Taranis 326 VR` names a calendar, a named month, and an era. Year and day values span their written interval; a clock time identifies a second. Either form may begin with `~` for uncertainty beyond that interval. The `approximate` field records that explicit marker, while `precision` and `seconds` describe the interval or time. A resolved date carries a canonical year, span, and sort key; a neutral year has no `canonicalDay`, while day-precision dates have one. Print `prose ?? text`, order on `sort`, and do arithmetic on `canonicalYear`. The literal `unknown` has no sort key or canonical year. `resolvedDateFields` supplies identical derived records to JSONL and generated page frontmatter.
|
|
655
|
+
A date on a note is one authored scalar. `<year>[.<day>[:HHMMSS]]` names a calendar-neutral year, day, or second; `datefrom vrcal 23 Taranis 326 VR` names a calendar, a named month, and an era. Year and day values span their written interval; a clock time identifies a second. Either form may begin with `~` for uncertainty beyond that interval. The `approximate` field records that explicit marker, while `precision` and `seconds` describe the interval or time. A resolved date carries a canonical year, span, and sort key; a neutral year has no `canonicalDay`, while day-precision dates have one. Print `prose ?? text`, order on `sort`, and do arithmetic on `canonicalYear`. The literal `unknown` has no sort key or canonical year. Year `0` is accepted only where a caller passes `allowZeroYear` — a `lore` event's `when` — and means "this day, every year": the value carries no `canonicalYear` and no `sort`. `resolvedDateFields` supplies identical derived records to JSONL and generated page frontmatter, including a `lore` note's `data.events`, each entry's `recurs` and computed `next`.
|
|
652
656
|
|
|
653
657
|
| Export | Signature | Returns | Use it when |
|
|
654
658
|
| ----------------------- | ------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------- |
|
|
@@ -661,6 +665,7 @@ A date on a note is one authored scalar. `<year>[.<day>[:HHMMSS]]` names a calen
|
|
|
661
665
|
| `formatNoteDate` | `formatNoteDate(date, era, daysPerYear, formatName?)` | `{era, year, month, day, text, prose}` or `null` | printing a resolved date in a chosen era or its authored form |
|
|
662
666
|
| `formatDateInCalendar` | `formatDateInCalendar(date, reference, context, formatName?)` | printable record or `null` | selecting a calendar's era and printing a resolved date in it |
|
|
663
667
|
| `calendarEras` | `calendarEras(reference, context)` | ordered era records | resolving an addressed calendar or one of its eras |
|
|
668
|
+
| `occurrencesOf` | `occurrencesOf(date, recurs, options)` | occurrence records, in increasing order | finding a recurring event's next, last, or a membership probe |
|
|
664
669
|
| `resolvedDateFields` | `resolvedDateFields(fm, context)` | map of normalized dates | deriving being and lore event date records for index and pages |
|
|
665
670
|
|
|
666
671
|
### `engine.dateConversion`
|
|
@@ -692,12 +697,14 @@ invokes the check during frontmatter lint.
|
|
|
692
697
|
|
|
693
698
|
### `engine.markdownExpressions`
|
|
694
699
|
|
|
695
|
-
`renderMarkdownExpressions(body, { fm, dates, sqlResults, file, bodyLine })` expands scalar frontmatter references and registered Handlebars helpers outside Markdown code. The `dateformat` helper uses `formatDateInCalendar`; `gt`, `gte`, `lt`, `lte`, `eq`, `and`, `or`, and `not` evaluate explicit comparisons. The `sql` helper reads a prepared scalar result, which must contain one row and one column. `sqlQueriesInMarkdown` discovers SQL calls, including nested calls; `prepareInlineSqlExpressions` evaluates them through the same DuckDB connection as SQL tables. The renderer returns `{ markdown, findings }`, with source positions for invalid expressions. Site, Foundry and PDF passes invoke it after generated tables expand and before links resolve. Hugo shortcodes remain literal for the site renderer.
|
|
700
|
+
`renderMarkdownExpressions(body, { fm, dates, sqlResults, figures, file, bodyLine })` expands scalar frontmatter references and registered Handlebars helpers outside Markdown code. The `dateformat` helper uses `formatDateInCalendar`; `gt`, `gte`, `lt`, `lte`, `eq`, `and`, `or`, and `not` evaluate explicit comparisons. The `sql` helper reads a prepared scalar result, which must contain one row and one column. The `ref` helper links to a `:::figure` fence by its anchor — `"#thorn"` on the same note — in `number` (the default, and admitted explicitly), `full` or `title` form; `figures` is a `Map` of this note's own figures, by id, to `{label, caption, hasCaption}`, and an address naming another note is reported as unresolved rather than looked up. `sqlQueriesInMarkdown` discovers SQL calls, including nested calls; `prepareInlineSqlExpressions` evaluates them through the same DuckDB connection as SQL tables. `EXPRESSION_HELPERS` is the one list of helpers: the engine registers from it and the authoring document is checked against it, so each name there carries the parameters it takes and a sentence on what it does. The renderer returns `{ markdown, findings }`, with source positions for invalid expressions. Site, Foundry and PDF passes invoke it after generated tables expand and before links resolve. Hugo shortcodes remain literal for the site renderer.
|
|
696
701
|
|
|
697
|
-
| Export | Signature | Returns | Use it when
|
|
698
|
-
| --------------------------- | ------------------------------------------ | ---------------------- |
|
|
699
|
-
| `renderMarkdownExpressions` | `renderMarkdownExpressions(body, options)` | `{markdown, findings}` | expanding authored expressions in prose
|
|
700
|
-
| `sqlQueriesInMarkdown` | `sqlQueriesInMarkdown(body)`
|
|
702
|
+
| Export | Signature | Returns | Use it when |
|
|
703
|
+
| --------------------------- | ------------------------------------------ | ---------------------- | ------------------------------------------------ |
|
|
704
|
+
| `renderMarkdownExpressions` | `renderMarkdownExpressions(body, options)` | `{markdown, findings}` | expanding authored expressions in prose |
|
|
705
|
+
| `sqlQueriesInMarkdown` | `sqlQueriesInMarkdown(body, fm?)` | query strings | preparing inline SQL alongside generated tables |
|
|
706
|
+
| `EXPRESSION_HELPERS` | `EXPRESSION_HELPERS` | helpers by name | listing what an expression may call |
|
|
707
|
+
| `EXPRESSION` | `const EXPRESSION` | `RegExp` | recognising an expression a pass has yet to read |
|
|
701
708
|
|
|
702
709
|
### `engine.reckoningMarkers`
|
|
703
710
|
|
|
@@ -878,16 +885,17 @@ Emitting this package's content index. Every content build already walks the who
|
|
|
878
885
|
|
|
879
886
|
The asset types — `icon`, `image` and `audio` — and the three roots they are walked from. An asset is addressed exactly as a note is; what differs is that a `.webp` carries no frontmatter and has nowhere to say what it is, so the root supplies the type and the list of roots is closed.
|
|
880
887
|
|
|
881
|
-
| Export | Signature
|
|
882
|
-
| ------------------ |
|
|
883
|
-
| `ASSET_TYPES` | `const ASSET_TYPES`
|
|
884
|
-
| `ASSET_TYPE_NAMES` | `const ASSET_TYPE_NAMES`
|
|
885
|
-
| `ASSET_SYSTEM` | `const ASSET_SYSTEM`
|
|
886
|
-
| `IMAGE_EXTENSIONS` | `const IMAGE_EXTENSIONS`
|
|
887
|
-
| `AUDIO_EXTENSIONS` | `const AUDIO_EXTENSIONS`
|
|
888
|
-
| `isAssetType` | `isAssetType(type)`
|
|
889
|
-
| `assetTypeOfRoot` | `assetTypeOfRoot(root)`
|
|
890
|
-
| `isAssetShortcode` | `isAssetShortcode(shortcode)`
|
|
888
|
+
| Export | Signature | Returns | Use it when |
|
|
889
|
+
| ------------------ | ------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
|
890
|
+
| `ASSET_TYPES` | `const ASSET_TYPES` | `readonly AssetType[]` — type, root, extensions, description | walking the roots, or presenting the vocabulary |
|
|
891
|
+
| `ASSET_TYPE_NAMES` | `const ASSET_TYPE_NAMES` | `ReadonlySet<string>` | admitting the asset types into a type vocabulary an address is parsed against |
|
|
892
|
+
| `ASSET_SYSTEM` | `const ASSET_SYSTEM` | `string` — always `none` | writing an asset address, whose `<system>` segment is a property of the type rather than of the reference |
|
|
893
|
+
| `IMAGE_EXTENSIONS` | `const IMAGE_EXTENSIONS` | `readonly string[]` — lowercase, dot-led | deciding whether a file under a picture root is an asset at all |
|
|
894
|
+
| `AUDIO_EXTENSIONS` | `const AUDIO_EXTENSIONS` | `readonly string[]` — lowercase, dot-led | the same question for `audio/` |
|
|
895
|
+
| `isAssetType` | `isAssetType(type)` | `boolean` | scoping a rewrite rule, which may substitute a file and nothing else |
|
|
896
|
+
| `assetTypeOfRoot` | `assetTypeOfRoot(root)` | `AssetType \| undefined` | reading a root directory name back to the type it declares |
|
|
897
|
+
| `isAssetShortcode` | `isAssetShortcode(shortcode)` | `boolean` | telling an addressable filename from one that carries a version string, a hyphen or a date stamp |
|
|
898
|
+
| `imageDimensions` | `imageDimensions(absPath, ext)` | `{width, height} \| undefined` | reading a raster file's own pixel size from its header, which an SVG carries none of and a partial file fails closed on |
|
|
891
899
|
|
|
892
900
|
### `engine.assetIndex`
|
|
893
901
|
|
|
@@ -895,6 +903,7 @@ The asset record: one line of the content index per addressable file. The record
|
|
|
895
903
|
|
|
896
904
|
| Export | Signature | Returns | Use it when |
|
|
897
905
|
| --------------------------- | --------------------------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
906
|
+
| `ASSET_ROLES` | `const ASSET_ROLES` | `readonly string[]` | naming the closed set of roles a picture may declare |
|
|
898
907
|
| `ASSET_RECORD_FIELDS` | `const ASSET_RECORD_FIELDS` | `readonly AssetRecordField[]` | reading what an `asset` block carries, and where each field comes from |
|
|
899
908
|
| `PROVENANCE_KEYS` | `const PROVENANCE_KEYS` | `ReadonlySet<string>` | validating a provenance file, whose keys are derived from the record's own fields |
|
|
900
909
|
| `REQUIRED_PROVENANCE_KEYS` | `const REQUIRED_PROVENANCE_KEYS` | `ReadonlySet<string>` | the keys a provenance file must state — a record resolves wholesale, so one omitting them leaves every file it covers with no rights holder or no terms |
|
|
@@ -1042,6 +1051,7 @@ Raw HTML in a note's prose, reported. **A note is markdown.** What markdown cann
|
|
|
1042
1051
|
| `EMBED_PATTERN` | `const EMBED_PATTERN` | — | An embed, as authored, with the directive it may carry. |
|
|
1043
1052
|
| `embedsIn` | `function embedsIn(body)` | {ParsedEmbed[]} One entry per embed. | Every embed in one body, in source order. |
|
|
1044
1053
|
| `resolveEmbed` | `function resolveEmbed(index, embed)` | `{{pathname: string}\|{reason: string, target: string, type?: string}}` The authored pathname, or the finding. | What one embed resolves to, or why it does not. |
|
|
1054
|
+
| `embedRole` | `function embedRole(index, address)` | {string\|undefined} The role, or `undefined` for a note's address, one that resolves nowhere, or a picture that declares none. | The role an address's asset declares, by the same resolution. |
|
|
1045
1055
|
| `embedProblems` | `function embedProblems(embed)` | {Array<{link: string, offset: number, message: string}>} One entry per defect. | What is wrong with one embed's directive or placement. |
|
|
1046
1056
|
| `resolveEmbeds` | `function resolveEmbeds(body, ctx)` | `{{markdown: string, unresolved: Array<object>, problems: Array<object>}}` The body, the embeds that named nothing, and the directives that could not be honoured. | Rewrite every embed into the image each surface renders. |
|
|
1047
1057
|
| `checkEmbeds` | `function checkEmbeds(body, file, opts)` | {Array<{file: string, line: number, column: number\|undefined, severity: "error", message: string}>} One finding per defect, in source order. | Every defect in one note's embeds, located. |
|
|
@@ -1050,39 +1060,52 @@ Raw HTML in a note's prose, reported. **A note is markdown.** What markdown cann
|
|
|
1050
1060
|
|
|
1051
1061
|
An image saying how wide it is and where it sits. A directive in the curly-attribute convention Pandoc and Kramdown use supplies a width class, a named `size`, and a `float` position. The named size sets a maximum display width for each surface.
|
|
1052
1062
|
|
|
1053
|
-
| Export | Signature | Returns | Use it when
|
|
1054
|
-
| --------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1055
|
-
| `IMAGE_CLASSES` | `const IMAGE_CLASSES` | — | The width classes an image may carry, and what each means to a renderer.
|
|
1056
|
-
| `IMAGE_SIZES` | `const IMAGE_SIZES` | — | The named sizes an image directive accepts.
|
|
1057
|
-
| `IMAGE_FLOATS` | `const IMAGE_FLOATS` | — | The `float` positions an image may take, and where each puts it.
|
|
1058
|
-
| `IMAGE_FIGURE_CLASS` | `const IMAGE_FIGURE_CLASS` | — | The class every figure carries, whatever its width or position.
|
|
1059
|
-
| `IMAGE_PATTERN` | `const IMAGE_PATTERN` | — | A markdown image, with the directive it may carry.
|
|
1060
|
-
| `imageSourceProblem` | `function imageSourceProblem(src)` | {string} The problem, as a finding's sentence, or `""`. | What is wrong with an image's address, or `""` when nothing is.
|
|
1061
|
-
| `parseImageDirective` | `function parseImageDirective(raw)` | `{{classes: string[], size: string, float: string, problems: string[]}}` What was written, and what cannot be honoured. | Read the directive on an image.
|
|
1062
|
-
| `
|
|
1063
|
-
| `
|
|
1064
|
-
| `
|
|
1065
|
-
| `
|
|
1066
|
-
| `
|
|
1067
|
-
| `
|
|
1068
|
-
| `
|
|
1069
|
-
| `
|
|
1070
|
-
| `
|
|
1071
|
-
| `
|
|
1063
|
+
| Export | Signature | Returns | Use it when |
|
|
1064
|
+
| --------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
|
|
1065
|
+
| `IMAGE_CLASSES` | `const IMAGE_CLASSES` | — | The width classes an image may carry, and what each means to a renderer. |
|
|
1066
|
+
| `IMAGE_SIZES` | `const IMAGE_SIZES` | — | The named sizes an image directive accepts. |
|
|
1067
|
+
| `IMAGE_FLOATS` | `const IMAGE_FLOATS` | — | The `float` positions an image may take, and where each puts it. |
|
|
1068
|
+
| `IMAGE_FIGURE_CLASS` | `const IMAGE_FIGURE_CLASS` | — | The class every figure carries, whatever its width or position. |
|
|
1069
|
+
| `IMAGE_PATTERN` | `const IMAGE_PATTERN` | — | A markdown image, with the directive it may carry. |
|
|
1070
|
+
| `imageSourceProblem` | `function imageSourceProblem(src)` | {string} The problem, as a finding's sentence, or `""`. | What is wrong with an image's address, or `""` when nothing is. |
|
|
1071
|
+
| `parseImageDirective` | `function parseImageDirective(raw)` | `{{classes: string[], size: string, float: string, problems: string[]}}` What was written, and what cannot be honoured. | Read the directive on an image. |
|
|
1072
|
+
| `roleClass` | `function roleClass(role)` | {string} The class, or `""`. | The class a picture's role names, or `""` for no role or one outside the closed set. |
|
|
1073
|
+
| `figureClasses` | `function figureClasses(directive)` | {string} A space-separated class list. | The classes a figure carries, from a parsed directive and its asset's role. |
|
|
1074
|
+
| `escapeHtml` | `function escapeHtml(text)` | {string} The same value, safe in markup. | Text going inside an HTML attribute or between tags. |
|
|
1075
|
+
| `imageFigureHtml` | `function imageFigureHtml(image)` | {string} The figure, as one HTML block. | One image as the `<figure>` both HTML surfaces render. |
|
|
1076
|
+
| `standsAlone` | `function standsAlone(text, start, end)` | {boolean} Whether the match is a block of its own. | Whether a match sits alone in its own paragraph. |
|
|
1077
|
+
| `imagesIn` | `function imagesIn(body)` | {Array<{alt: string, src: string, title: string, directive: string, index: number, length: number, block: boolean}>} One entry per image. | Every image in one body, with its directive and its position. |
|
|
1078
|
+
| `imageSourcesIn` | `function imageSourcesIn(body)` | {string[]} The addresses, with repeats. | Every image address one body names, in order of appearance. |
|
|
1079
|
+
| `checkImages` | `function checkImages(body, file,` | {Array<{file: string, line: number, column: number\|undefined, severity: "error", message: string}>} One finding per defect, in source order. | Every defect in one note's images. |
|
|
1080
|
+
| `lintContentImages` | `function lintContentImages(contentBase,` | `{{findings: Array<{file: string, line: number, column: number\|undefined, severity: "error", message: string}>, files: number}}` What it found. | Walk a content tree and report every image it cannot render as authored. |
|
|
1081
|
+
| `renderImageFigures` | `function renderImageFigures(body, resolveSrc)` | {string} The same body, with each block image as a `<figure>`. | Rewrite every block image in a body into the figure the website publishes. |
|
|
1082
|
+
| `imagePlugin` | `function imagePlugin()` | {(md: object) => void} A markdown-it plugin. | A markdown-it plugin that reads an image's directive and renders its figure. |
|
|
1083
|
+
|
|
1084
|
+
### `engine.contentTaskLists`
|
|
1085
|
+
|
|
1086
|
+
A list item opened with `[ ]` or `[x]`, reported. The format has no checkbox: a list is written in plain markdown, and the two characters right after a list item's marker are read as the start of its own text on every surface.
|
|
1087
|
+
|
|
1088
|
+
| Export | Signature | Returns | Use it when |
|
|
1089
|
+
| ---------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
1090
|
+
| `TASK_LIST_MARKER` | `const TASK_LIST_MARKER` | — | A list item's marker, immediately followed by `[ ]` or `[x]` and a space. |
|
|
1091
|
+
| `taskListMessage` | `function taskListMessage(marker)` | {string} The message, unpunctuated at the end as a finding is. | What a note opening a list item with `[ ]` or `[x]` is told. |
|
|
1092
|
+
| `checkTaskLists` | `function checkTaskLists(body, file,` | {Array<{file: string, line: number, column: number, severity: "warning", message: string}>} One finding per item, in source order. | Every list item opened with `[ ]` or `[x]` in one note's body. |
|
|
1093
|
+
| `lintContentTaskLists` | `function lintContentTaskLists(contentBase,` | `{{findings: Array<{file: string, line: number, column: number, severity: "warning", message: string}>, files: number}}` The findings, and how many files were read. | Walk a content tree and report every list item opened with `[ ]` or `[x]`. |
|
|
1072
1094
|
|
|
1073
1095
|
### `engine.pathnames`
|
|
1074
1096
|
|
|
1075
1097
|
One authored pathname, and the four addresses it resolves to. A note names a file once — in `img:`, in `data.portrait:`, in the body of a markdown image — and the first segment says which package owns it when an `assets/` follows. Every surface derives its own address from that one statement: the path inside a Foundry install, the file in the owning repository's tree, the address the website serves, and where the book stages its copy.
|
|
1076
1098
|
|
|
1077
|
-
| Export | Signature | Returns | Use it when
|
|
1078
|
-
| ----------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
1079
|
-
| `ASSETS_SEGMENT` | `const ASSETS_SEGMENT` | — | The directory a package ships its files in.
|
|
1080
|
-
| `PATHNAME_SURFACES` | `const PATHNAME_SURFACES` | — | The surfaces one authored pathname resolves for.
|
|
1081
|
-
| `pathnameProblem` | `function pathnameProblem(raw)` | {string} The problem, as a finding's sentence, or `""`. | What is wrong with an authored pathname, or `""` when nothing is.
|
|
1082
|
-
| `packageAddresses` | `function packageAddresses(config)` | {Map<string, {root: string\|null, id: string\|null, own: boolean}>} The packages, by package name. | Every content package this build can resolve a pathname against.
|
|
1083
|
-
| `resolvePathname` | `function resolvePathname(raw, config)` | {PathnameForms\|null} The four forms, or `null` when the note names no file. | Resolve one authored pathname into the address each surface serves.
|
|
1084
|
-
| `
|
|
1085
|
-
| `
|
|
1099
|
+
| Export | Signature | Returns | Use it when |
|
|
1100
|
+
| ----------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
1101
|
+
| `ASSETS_SEGMENT` | `const ASSETS_SEGMENT` | — | The directory a package ships its files in. |
|
|
1102
|
+
| `PATHNAME_SURFACES` | `const PATHNAME_SURFACES` | — | The surfaces one authored pathname resolves for. |
|
|
1103
|
+
| `pathnameProblem` | `function pathnameProblem(raw)` | {string} The problem, as a finding's sentence, or `""`. | What is wrong with an authored pathname, or `""` when nothing is. |
|
|
1104
|
+
| `packageAddresses` | `function packageAddresses(config)` | {Map<string, {root: string\|null, id: string\|null, own: boolean}>} The packages, by package name. | Every content package this build can resolve a pathname against. |
|
|
1105
|
+
| `resolvePathname` | `function resolvePathname(raw, config)` | {PathnameForms\|null} The four forms, or `null` when the note names no file. | Resolve one authored pathname into the address each surface serves. |
|
|
1106
|
+
| `assetPathnameKey` | `function assetPathnameKey(src, config)` | {string\|null} The pathname, or `null` for an address naming no asset record to look up. | The pathname one authored image address keys an asset's role and pixel size under, whichever form it was written in. |
|
|
1107
|
+
| `servesFoundry` | `function servesFoundry(config)` | {boolean} Whether the package being built has a Foundry root. | Whether this build installs anything into a Foundry data directory. |
|
|
1108
|
+
| `foundryAddressProblem` | `function foundryAddressProblem(raw, config)` | {string} The problem, as a finding's sentence, or `""`. | Why a pathname has no Foundry address, or `""` when it has one. |
|
|
1086
1109
|
|
|
1087
1110
|
### `engine.contentLinks`
|
|
1088
1111
|
|
|
@@ -1111,9 +1134,9 @@ Prepared SQL content tables are expanded into Markdown before link resolution.
|
|
|
1111
1134
|
A query selecting no rows reports an error unless its fence states
|
|
1112
1135
|
`{allow-empty=true}`.
|
|
1113
1136
|
|
|
1114
|
-
| Export | Signature
|
|
1115
|
-
| --------------------- |
|
|
1116
|
-
| `expandContentTables` | `expandContentTables(markdown, { source, sqlTables })` | `{markdown: string, errors: object[], lineMap: object[], warnings: object[]}` | Replace prepared SQL fences and preserve source locations. |
|
|
1137
|
+
| Export | Signature | Returns | Use it when |
|
|
1138
|
+
| --------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
1139
|
+
| `expandContentTables` | `expandContentTables(markdown, { source, sqlTables, pageLists })` | `{markdown: string, errors: object[], lineMap: object[], warnings: object[]}` | Replace prepared SQL fences and page lists, and preserve source locations. |
|
|
1117
1140
|
|
|
1118
1141
|
### `engine.helpers`
|
|
1119
1142
|
|
|
@@ -1217,11 +1240,13 @@ What a `[[…]]` **is**, before anything decides where it points. One authored l
|
|
|
1217
1240
|
`buildSiteIndex` gathers addressable pages and ambiguity findings. `wikiContext`
|
|
1218
1241
|
provides the per-page context used when resolving a link such as `[[Something]]`.
|
|
1219
1242
|
|
|
1220
|
-
| Export
|
|
1221
|
-
|
|
|
1222
|
-
| `buildSiteIndex`
|
|
1223
|
-
| `
|
|
1224
|
-
| `
|
|
1243
|
+
| Export | Signature | Returns | Use it when |
|
|
1244
|
+
| ------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
1245
|
+
| `buildSiteIndex` | `function buildSiteIndex(entries,` | {SiteIndex} The index, and what could not be addressed unambiguously. | Build the address index a site's wikilink resolver reads. |
|
|
1246
|
+
| `figureIndexKeys` | `function figureIndexKeys(pkg, type, shortcode)` | {Set<string>} The short `type/shortcode` key and the canonical `package-system-type-shortcode` one. | Get the address keys one page's figures are reachable by, matching `buildSiteIndex`'s own. |
|
|
1247
|
+
| `resolveCrossNoteFigures` | `function resolveCrossNoteFigures(target, options)` | {{url: string, figures: Map<string, object>}\|undefined} The target's own address and figures, or `undefined` where no note resolves. | Resolve a `ref` call's cross-note address to the target's own figures, the way a wikilink would. |
|
|
1248
|
+
| `wikiContext` | `function wikiContext(built,` | {object} The resolver context. | The per-page context a wikilink resolver takes. |
|
|
1249
|
+
| `resolveInfoboxRef` | `function resolveInfoboxRef(siteIndex, ref, hint)` | {{name?: string, url?: string, address?: string, subType?: string}\|undefined} The page, or `undefined` where nothing answers. | Resolve one infobox reference — a bare shortcode, a short address or a canonical one — against a site index. |
|
|
1225
1250
|
|
|
1226
1251
|
### `engine.pdfToc`
|
|
1227
1252
|
|
|
@@ -1250,6 +1275,8 @@ A note's markdown, and a document plan, rendered as Typst source. **This module
|
|
|
1250
1275
|
| `iconNamesIn` | `function iconNamesIn(markdown)` | {string[]} The names, in order of appearance, with repeats. | Every icon name a body uses, so a build can resolve them once. |
|
|
1251
1276
|
| `BOOK_IMAGE_WIDTHS` | `const BOOK_IMAGE_WIDTHS` | — | The book measure requested by each named image size. |
|
|
1252
1277
|
| `bookTypstPreamble` | `function bookTypstPreamble()` | {string} Typst markup. | The Typst definitions the book's page furniture is drawn with. |
|
|
1278
|
+
| `stripHtmlComments` | `function stripHtmlComments(markdown)` | {string} The same body, its comments replaced by newlines. | A markdown body with its HTML comments taken out. |
|
|
1279
|
+
| `absolutePageUrl` | `function absolutePageUrl(url, site)` | {string} An absolute URL a reader of the book can follow. | A page address as a reader of the book can follow it. |
|
|
1253
1280
|
|
|
1254
1281
|
### `engine.pdfFonts`
|
|
1255
1282
|
|
|
@@ -1571,9 +1598,11 @@ HM3's Item pass — the parts of compiling a note into an HM3 Item that are fact
|
|
|
1571
1598
|
|
|
1572
1599
|
HM3's Actor pass — what an HM3 `character` or `creature` holds. A being note authors which HM3 subtype it becomes via `hm3.type` (never defaulted), and only four of the content format's `being` mapping-table rows have an HM3 destination (`portrait`, `species`, `gender`, `occupation`, `templatePriority`) plus the two anchored prose sections (`{#appearance}` → `description`, `{#dossier}` → `biography`); `gender` and `occupation` are written only on a `character`.
|
|
1573
1600
|
|
|
1574
|
-
| Export
|
|
1575
|
-
|
|
|
1576
|
-
| `Hm3Actors`
|
|
1601
|
+
| Export | Signature | Returns | Use it when |
|
|
1602
|
+
| ------------------ | ------------------------ | ------- | ----------------------------------------------------------------------------- |
|
|
1603
|
+
| `Hm3Actors` | `class Hm3Actors` | — | not called directly — imported and driven by `engine/generate.mjs` |
|
|
1604
|
+
| `ACTOR_FIELDS` | `const ACTOR_FIELDS` | — | reading the fields native to every HM3 actor subtype |
|
|
1605
|
+
| `CHARACTER_FIELDS` | `const CHARACTER_FIELDS` | — | reading the fields `hm3.actors` declares on `character` and not on `creature` |
|
|
1577
1606
|
|
|
1578
1607
|
### `hm3.templatePriority`
|
|
1579
1608
|
|
|
@@ -1613,6 +1642,7 @@ const config = defineConfig({
|
|
|
1613
1642
|
| `defineConfig` | `defineConfig(config)` | `ContentBuildConfig` — the frozen, defaulted configuration | validating and normalizing a content configuration; every configuration reaches this function whether authored as YAML or as `.mjs` |
|
|
1614
1643
|
| `PACKAGE_KINDS` | `const PACKAGE_KINDS` | — | reading the three kinds of Foundry package a content module can be built into — `systems`, `modules`, and `documentation`, the kind that compiles no Foundry document at all (also the Foundry install directory name for the first two) |
|
|
1615
1644
|
| `DOCUMENTATION_KIND` | `const DOCUMENTATION_KIND` | — | naming the `packageKind` value that compiles no Foundry documents, spelled once so the validator, the CLI and the compile passes cannot disagree about what it means |
|
|
1645
|
+
| `RELATIONSHIP_KEYS` | `const RELATIONSHIP_KEYS` | `readonly string[]` | reading every key a declared relationship may carry — the configuration check refuses anything else, and the manifest writer drops the ones Foundry's own schema does not name |
|
|
1616
1646
|
| `compilesFoundryDocuments` | `compilesFoundryDocuments(config)` | `boolean` | checking whether a resolved configuration compiles Foundry documents at all — false only for a `documentation` package |
|
|
1617
1647
|
| `PACK_DOCUMENT_TYPES` | `const PACK_DOCUMENT_TYPES` | — | reading the Foundry document types this toolchain is able to compile a compendium pack of |
|
|
1618
1648
|
| `DEFAULT_PATHS` | `const DEFAULT_PATHS` | — | reading the conventional directory layout a build reads from and writes to, relative to `rootDir` |
|
|
@@ -1850,7 +1880,8 @@ console.log(normalizeRepoUrl("git@github.com:HeroicLands/sohl.git"));
|
|
|
1850
1880
|
| `metadataUrl` | `metadataUrl({ repoUrl, version, contentPackage })` | `string` — the version-pinned asset URL | computing where this release publishes its content index, pinned to this version like `download` so a dependency's manifest and its fetched index always describe the same release |
|
|
1851
1881
|
| `manifestPacks` | `manifestPacks(config)` | `object[]` | deriving the manifest's `packs` array from the one pack list the build already has, in build order, companions flattened in |
|
|
1852
1882
|
| `packFolderFindings` | `packFolderFindings({ packFolders, packs = [] })` | `Array<{severity: "error"\|"warning", message: string, pack: string, folder?: string, keyPath: Array<string\|number>}>` | checking a declared `packFolders` against the derived pack list — a folder naming a pack that does not exist is an error, a pack no folder names is a warning |
|
|
1853
|
-
| `
|
|
1883
|
+
| `FOUNDRY_RELATIONSHIP_KEYS` | `const FOUNDRY_RELATIONSHIP_KEYS` | `readonly string[]` — `id`, `type`, `manifest`, `compatibility`, `reason` | reading which relationship keys Foundry's own schema names, which is what makes every other declared key the build's own |
|
|
1884
|
+
| `BUILD_ONLY_RELATIONSHIP_KEYS` | `const BUILD_ONLY_RELATIONSHIP_KEYS` | `readonly string[]` — derived | reading which `relationships` keys direct the build rather than describe the published package, so they can be filtered out of what ships |
|
|
1854
1885
|
| `publishedRelationships` | `publishedRelationships(relationships)` | `Record<string, unknown>` | producing the `relationships` block as it should be published, with `BUILD_ONLY_RELATIONSHIP_KEYS` dropped and everything else preserved in order |
|
|
1855
1886
|
| `buildManifest` | `buildManifest({ config, packageJson, artifact, flags })` | `object` — the manifest, ready to serialise | assembling the full Foundry package manifest object from the resolved configuration, without writing it anywhere |
|
|
1856
1887
|
| `writeManifest` | `async writeManifest({ config, packageJson, artifact, outDir, flags, configFile })` | `Promise<{path: string, manifest: object}>` | building the manifest and writing it into the staged package; refuses to write when `packFolders` names a pack the build does not produce |
|
package/docs/authoring/assets.md
CHANGED
|
@@ -28,4 +28,18 @@ The embed's label is alternative text. `![[icon-harbor|]]` is decorative. `size=
|
|
|
28
28
|
|
|
29
29
|
Record provenance for the assets you ship. Put `provenance.yaml` in an asset directory to describe files there and below, or put a YAML sidecar beside one asset to give that file its own record. A sidecar takes precedence over a directory record for that asset. An asset with no record still enters the index with blank provenance fields. Keep attribution with the authored asset so movement through the tree does not lose its source or license. See the [asset record reference](../reference/format-details.md#the-asset-record) for the accepted keys, inheritance, and examples.
|
|
30
30
|
|
|
31
|
+
A directory of portraits also states what the pictures in it are for:
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
attribution: Tom Rodriguez
|
|
35
|
+
license: CC-BY-SA-4.0
|
|
36
|
+
role: portrait
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**A hero image is 1792×768.** `data.banner` fills one fixed strip wherever it is drawn, so every banner is cut to that size and a picture of any other size is a finding naming both sizes — resize the picture to match. That is the one size any art field requires. A map's `bgImage` sets its own scene's dimensions, so that asks nothing of a picture's dimensions either.
|
|
40
|
+
|
|
41
|
+
`role` is one of `portrait`, `emblem`, `banner`, `plate` or `map`, and belongs to the `image` type only — declaring it in a `provenance.yaml` under `assets/icons` is a finding, since an icon carries one nominal size per medium whatever the file holds. Leave the key out for an ordinary picture; there is no default role name, only its absence.
|
|
42
|
+
|
|
43
|
+
**A role decides how large a picture written in prose draws, when nothing else states a size.** Each medium maps a role to a maximum, and the drawn size is the smaller of that slot and what the file's own pixels support — see [what a role draws at](../reference/format-details.md#what-a-role-draws-at). A named `size=` beside the embed still overrides it outright; an icon draws at the medium's nominal icon size whatever role it might otherwise have had, because `role` never reaches an icon address at all.
|
|
44
|
+
|
|
31
45
|
The build writes transformed or optimized copies under `build/`; the authored file remains the input for the next build. Output paths are derived from the owning package, asset type, and build target. The [icon guide](../guides/icons.md) covers generated icon variants and placement in Foundry.
|
|
@@ -7,11 +7,13 @@ subType: howto
|
|
|
7
7
|
|
|
8
8
|
# Dates, calendars, and eras
|
|
9
9
|
|
|
10
|
-
A canonical date uses the world's year and day count without choosing a culture's calendar. Write `<year>[.<day>[:HHMMSS]]`: `720` covers year 720, `720.136` covers its day 136, and `720.136:143005` identifies 14:30:05 on that day. The dot separates the year from the **day of year**, not a month. Negative years are valid, and the day must fit the world's declared year length. Prefix a date with `~` when its uncertainty extends outside the stated year, day, or second. `unknown` records an occurrence whose date is not known, in fields that permit it.
|
|
10
|
+
A canonical date uses the world's year and day count without choosing a culture's calendar. Write `<year>[.<day>[:HHMMSS]]`: `720` covers year 720, `720.136` covers its day 136, and `720.136:143005` identifies 14:30:05 on that day. The dot separates the year from the **day of year**, not a month. Negative years are valid, and the day must fit the world's declared year length — `data.year.days` on its `place` note. A tree whose notes declare no world year bounds no day at all: every value is read as written, however large, because there is no year length to check it against. Prefix a date with `~` when its uncertainty extends outside the stated year, day, or second. `unknown` records an occurrence whose date is not known, in fields that permit it.
|
|
11
|
+
|
|
12
|
+
**Put a date that states a day in quotes.** Write `born: "667.130"`, not `born: 667.130`. Unquoted, YAML reads the scalar as a number, and a number keeps no trailing zero — `667.130` becomes `667.13`, which is day 13 rather than day 130, and the authored digits are gone before any reader of the date can object. A date whose lost zero would still name a day inside the world's year is therefore refused, naming the line and both readings, so quoting it is the fix. A bare year such as `born: 667` loses nothing and needs no quotes.
|
|
11
13
|
|
|
12
14
|
## Define a calendar
|
|
13
15
|
|
|
14
|
-
A `lore` note with `subType: calendar` names months, weekdays, seasons, named days, eras, and date formats. Its `data.epoch` is the **canonical day that equals calendar year 1, day 1**. For a calendar beginning on canonical day `1.91`, write `epoch: 1.91
|
|
16
|
+
A `lore` note with `subType: calendar` names months, weekdays, seasons, named days, eras, and date formats. Its `data.epoch` is the **canonical day that equals calendar year 1, day 1**. For a calendar beginning on canonical day `1.91`, write `epoch: "1.91"` — quoted, like every canonical date that states a day: calendar year 1 still starts at its own day 1. A calendar does not state the length of the world year: its months must sum to `data.year.days` on the world's `place` note.
|
|
15
17
|
|
|
16
18
|
```yaml
|
|
17
19
|
shortcode: commoncal
|
|
@@ -19,7 +21,7 @@ name: { full: The Common Calendar }
|
|
|
19
21
|
type: lore
|
|
20
22
|
subType: calendar
|
|
21
23
|
data:
|
|
22
|
-
epoch: 1.1
|
|
24
|
+
epoch: "1.1"
|
|
23
25
|
months:
|
|
24
26
|
- { name: Floralis, abbreviation: Flor, days: 30 }
|
|
25
27
|
- { name: Lusenar, abbreviation: Luse, days: 31 }
|
|
@@ -83,3 +85,39 @@ package-build dateto commoncal 326.114 --format long
|
|
|
83
85
|
The CLI `datefrom` command requires a day and reads the default (`std`, or first) pattern. `dateto` prints the era covering the canonical day. A clock time makes a date exact; a year or day without one spans the stated interval. `data.epoch` and `data.moon.newOn` require a day. The [detailed date rules](../reference/format-details.md#dates-and-calendars) describe precision and bounds.
|
|
84
86
|
|
|
85
87
|
In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen calendar. `{{dateformat data.calendar data.born}}` uses the note's calendar Address. A third argument chooses another named pattern. A being or place can set `data.calendar`; its infobox uses that calendar for dates.
|
|
88
|
+
|
|
89
|
+
## Write a recurring date
|
|
90
|
+
|
|
91
|
+
A `lore` note states its dated occurrences under `data.events`, a list — a note may record a founding once and an annual festival beside it. Each entry is `{ when, until?, recurs? }`, with `when` the occurrence's anchor and first instance:
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
data:
|
|
95
|
+
events:
|
|
96
|
+
- when: 412.1
|
|
97
|
+
recurs: { every: 1 }
|
|
98
|
+
- when: 689.5
|
|
99
|
+
until: 1203.9
|
|
100
|
+
recurs: { every: 514 }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The first entry is annual, with no end. The second recurs every five hundred fourteen years and stopped after canonical year 1203; `recurs.every` always counts whole years on the canonical axis. In place of a period, `recurs.on` lists the dates somebody actually recorded, strictly increasing and each later than `when`:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
data:
|
|
107
|
+
events:
|
|
108
|
+
- when: 326.1
|
|
109
|
+
recurs:
|
|
110
|
+
on: ["412.1", "689.5"]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A build computes the next occurrence against the world's declared present the way it computes a being's age against it, and publishes it on the web page, in the content index, and in the infobox.
|
|
114
|
+
|
|
115
|
+
**A day that recurs every year, with no founding date of its own, writes year `0`** — quoted, since every canonical date stating a day must be:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
data:
|
|
119
|
+
events:
|
|
120
|
+
- when: "0.286"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`when: "0.286"` is the two-hundred-eighty-sixth day of the year, every year — a harvest rite nobody dates to a founding. `recurs` is refused beside it, since the entry is already annual; `until` is allowed, and bounds how long the rite was kept.
|
|
@@ -7,7 +7,7 @@ subType: howto
|
|
|
7
7
|
|
|
8
8
|
# Frontmatter and system blocks
|
|
9
9
|
|
|
10
|
-
HeroicLands notes begin with YAML frontmatter. A file is recognized as a note when its opening frontmatter has nonempty `shortcode` and `type` values. Ordinary Markdown files need neither. Keep top-level keys in this order, omitting keys that do not apply: `shortcode`, `name`, `type`, `subType`, `description`, `tags`, `data`, `hm3`, `sohl`. Any other top-level key is an error.
|
|
10
|
+
HeroicLands notes begin with YAML frontmatter. A file is recognized as a note when its opening frontmatter has nonempty `shortcode` and `type` values. Ordinary Markdown files need neither. Keep top-level keys in this order, omitting keys that do not apply: `shortcode`, `name`, `type`, `subType`, `description`, `tags`, `data`, `dnd5e`, `hm3`, `sohl`. Any other top-level key is an error at its own line, naming the closed vocabulary and the declared key it was most likely meant to be. The [note-type reference](../reference/note-types.md#top-level-keys) says what each one means.
|
|
11
11
|
|
|
12
12
|
```yaml
|
|
13
13
|
---
|
|
@@ -35,7 +35,7 @@ The [note-type reference](../reference/note-types.md) lists every field accepted
|
|
|
35
35
|
|
|
36
36
|
A being's `data.archetypes` names the roles it can fill in an adventure. Choose every specific role that fits, such as `entertainer` for a performer or `guildsperson` for someone whose professional training or connections matter. Use `[commoner]` when no specific archetype fits. `commoner` cannot share the list with another value. The [archetype reference](../reference/format-details.md#actors) defines the available roles.
|
|
37
37
|
|
|
38
|
-
A `sohl:` or `
|
|
38
|
+
A `sohl:`, `hm3:` or `dnd5e:` block holds values for that Foundry system. Its `system:` child contains values sent to the system's DataModel. The system block can override shared routing and art where the declared field permits it. `data.pack` and `data.packFolder` are shared routes; a system-specific route belongs in that system block. The [detailed mapping reference](../reference/format-details.md#mappings-every-type-shares) and [system-block explanation](../reference/format-details.md#frontmatter-has-three-regions) cover precedence and emitted fields.
|
|
39
39
|
|
|
40
40
|
One body describes the subject for both systems. A being's `{#appearance}` and `{#dossier}` sections feed SoHL Actor `system.appearance` and `system.dossier`, and HM3 Actor `system.description` and `system.biography`. An Item's `{#description}` page becomes a shared JournalEntryPage. Its resolved `@UUID[...]` pointer is stored in SoHL Item `system.docHtml` and HM3 Item `system.description`. An Item with no `{#description}` anchor uses its first page. Other H1 pages remain linkable.
|
|
41
41
|
|