@heroiclands/package-build 23.1.1 → 23.2.1
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 +69 -0
- package/bin/content-commands.mjs +68 -149
- package/bin/package-build.mjs +56 -10
- package/ci/check-banners.mjs +42 -6
- package/ci/confirm-npm-version.mjs +135 -0
- package/ci/content-format-reference.mjs +14 -5
- package/config.mjs +1 -0
- package/container.mjs +185 -4
- package/content-config.mjs +333 -210
- package/deploy.mjs +116 -10
- package/docs/api.md +238 -246
- package/docs/authoring/assets.md +11 -5
- package/docs/authoring/frontmatter.md +1 -1
- package/docs/authoring/links-and-markup.md +87 -0
- package/docs/commands.md +138 -99
- package/docs/configuration.md +277 -125
- package/docs/content-format.md +2 -0
- package/docs/diagnostics.md +48 -13
- package/docs/guides/book.md +341 -21
- package/docs/guides/e2e.md +13 -2
- package/docs/guides/icons.md +14 -4
- package/docs/guides/module-project.md +18 -8
- package/docs/guides/release-and-deploy.md +32 -0
- package/docs/guides/site.md +5 -2
- package/docs/project-setup.md +30 -10
- package/docs/reference/format-details.md +373 -170
- package/docs/reference/note-types.md +128 -109
- package/docs/reference/theme-pages.md +31 -6
- package/e2e.mjs +140 -28
- package/engine/actor-compiler.mjs +22 -31
- package/engine/address-charset.mjs +4 -17
- package/engine/address-fields.mjs +1 -1
- package/engine/address-render.mjs +12 -1
- package/engine/address-values.mjs +6 -0
- package/engine/address.mjs +46 -33
- package/engine/art-fields.mjs +30 -5
- package/engine/art-slots.mjs +10 -1
- package/engine/asset-bindings.mjs +12 -1
- package/engine/base-compiler.mjs +34 -65
- package/engine/being-age.mjs +2 -7
- package/engine/being-measurements.mjs +12 -1
- package/engine/calendar-artifacts.mjs +6 -0
- package/engine/calendar-choice.mjs +12 -1
- package/engine/calendar-format.mjs +12 -1
- package/engine/calendar-human.mjs +12 -1
- package/engine/compile-corpus.mjs +3 -1
- package/engine/content-address.mjs +9 -12
- package/engine/content-alerts.mjs +13 -1
- package/engine/content-blocks.mjs +14 -3
- package/engine/content-embeds.mjs +11 -3
- package/engine/content-figures.mjs +9 -0
- package/engine/content-footnotes.mjs +12 -1
- package/engine/content-format-check.mjs +11 -262
- package/engine/content-format.yaml +5 -2
- package/engine/content-images.mjs +3 -0
- package/engine/content-index.mjs +443 -20
- package/engine/content-links.mjs +29 -35
- package/engine/content-lint.mjs +2 -3
- package/engine/content-poetry.mjs +12 -1
- package/engine/content-slug.mjs +2 -14
- package/engine/content-spans.mjs +13 -1
- package/engine/content-tables.mjs +12 -1
- package/engine/culture-choice.mjs +210 -13
- package/engine/data-keys.mjs +19 -16
- package/engine/date-conversion.mjs +12 -1
- package/engine/declaration-check.mjs +9 -0
- package/engine/derived-fields.mjs +6 -7
- package/engine/diagnostics.mjs +34 -4
- package/engine/docs-checks.mjs +9 -0
- package/engine/document-subtypes.mjs +47 -34
- package/engine/event-views.mjs +139 -14
- package/engine/exported-scene.mjs +92 -28
- package/engine/extension-attributes.mjs +12 -1
- package/engine/field-spec.mjs +11 -102
- package/engine/folder-notes.mjs +0 -64
- package/engine/foreign-catalog.mjs +2 -1
- package/engine/format-generated.mjs +9 -0
- package/engine/foundry-entries.mjs +10 -28
- package/engine/frontmatter-lint.mjs +83 -392
- package/engine/frontmatter.mjs +20 -70
- package/engine/generate.mjs +10 -15
- package/engine/heading-attributes.mjs +12 -1
- package/engine/helpers.mjs +41 -102
- package/engine/holdings.mjs +1 -1
- package/engine/homepage.mjs +3 -10
- package/engine/ids.mjs +1 -167
- package/engine/index-records.mjs +6 -4
- package/engine/index.mjs +0 -3
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +13 -14
- package/engine/item-compiler.mjs +4 -10
- package/engine/item-docs.mjs +3 -5
- package/engine/item-registry.mjs +2 -10
- package/engine/journals.mjs +1 -5
- package/engine/literature-notes.mjs +4 -12
- package/engine/macros.mjs +1 -2
- package/engine/map-graphviz.mjs +12 -1
- package/engine/markdown-expressions.mjs +12 -1
- package/engine/markdownlint-run.mjs +567 -0
- package/engine/metadata-index.mjs +42 -12
- package/engine/note-addresses.mjs +143 -35
- package/engine/note-claims.mjs +14 -28
- package/engine/note-dates.mjs +3 -3
- package/engine/note-frontmatter.mjs +6 -0
- package/engine/note-ids.mjs +8 -14
- package/engine/note-package.mjs +8 -25
- package/engine/note-state.mjs +1 -3
- package/engine/note-vocabulary.mjs +148 -84
- package/engine/number-words.mjs +12 -1
- package/engine/pack-config.mjs +15 -25
- package/engine/pack-router.mjs +10 -16
- package/engine/pathnames.mjs +8 -22
- package/engine/pdf-build.mjs +773 -121
- package/engine/pdf-coverage.mjs +188 -0
- package/engine/pdf-index.mjs +54 -7
- package/engine/pdf-pages.mjs +247 -0
- package/engine/pdf-render.mjs +114 -4
- package/engine/pdf-toc.mjs +29 -32
- package/engine/project-init.mjs +46 -6
- package/engine/prose-config.mjs +1 -1
- package/engine/prose-lint.mjs +52 -88
- package/engine/readability-lint.mjs +9 -0
- package/engine/reckoning-markers.mjs +12 -1
- package/engine/reference-targets.mjs +7 -0
- package/engine/runtime-only-fields.mjs +5 -8
- package/engine/scene-levels.mjs +2 -2
- package/engine/scenes.mjs +1 -1
- package/engine/shortcode-references.mjs +7 -0
- package/engine/site-build.mjs +30 -16
- package/engine/site-index.mjs +10 -16
- package/engine/site-preview.mjs +6 -0
- package/engine/site-root.mjs +8 -1
- package/engine/social-tie-terms.mjs +12 -1
- package/engine/social-ties.mjs +3 -0
- package/engine/sql-tables.mjs +56 -20
- package/engine/standing-terms.mjs +11 -1
- package/engine/standings.mjs +11 -27
- package/engine/system-block.mjs +39 -141
- package/engine/system-vocabulary.mjs +6 -0
- package/engine/walk-files.mjs +69 -0
- package/engine/web-wikilinks.mjs +23 -3
- package/engine/wikilink-syntax.mjs +32 -21
- package/engine/wikilinks.mjs +27 -16
- package/githooks/attribution.mjs +8 -0
- package/githooks/commit-message.mjs +9 -0
- package/hm3/actors.mjs +9 -48
- package/hm3/default-item-art.mjs +9 -9
- package/hm3/item-fields.mjs +2 -9
- package/hm3/template-priority.mjs +6 -7
- package/hugo-theme/data/banner-kinds.yaml +78 -0
- package/hugo-theme/data/banners.yaml +2 -3
- package/hugo-theme/layouts/404.html +3 -3
- package/hugo-theme/layouts/partials/banner-url.html +31 -7
- package/hugo-theme/layouts/partials/hero-banner.html +13 -14
- package/hugo-theme/layouts/partials/related.html +1 -1
- package/hugo-theme/layouts/partials/warn-missing-banner.html +1 -1
- package/hugo-theme/static/css/style.css +1 -1
- package/labels.mjs +2 -2
- package/manifest.mjs +11 -4
- package/markdownlint-config.mjs +1 -1
- package/package.json +6 -3
- package/release.mjs +21 -14
- package/sohl/actors.mjs +16 -27
- package/sohl/default-item-art.mjs +3 -3
- package/sohl/document-subtypes.mjs +1 -16
- package/sohl/infobox.mjs +2 -3
- package/sohl/item-builders.mjs +5 -8
- package/sohl/item-fields.mjs +5 -35
- package/sohl/items.mjs +0 -4
- package/sohl/kb-passes.mjs +3 -3
- package/types/container.d.mts +116 -5
- package/types/content-config.d.mts +83 -35
- package/types/deploy.d.mts +42 -6
- package/types/e2e.d.mts +35 -3
- package/types/engine/address-charset.d.mts +4 -17
- package/types/engine/address.d.mts +17 -8
- package/types/engine/art-fields.d.mts +7 -4
- package/types/engine/art-slots.d.mts +6 -0
- package/types/engine/base-compiler.d.mts +15 -17
- package/types/engine/content-address.d.mts +9 -12
- package/types/engine/content-embeds.d.mts +4 -2
- package/types/engine/content-format-check.d.mts +0 -64
- package/types/engine/content-index.d.mts +82 -3
- package/types/engine/content-links.d.mts +2 -4
- package/types/engine/culture-choice.d.mts +51 -8
- package/types/engine/data-keys.d.mts +2 -2
- package/types/engine/derived-fields.d.mts +1 -2
- package/types/engine/diagnostics.d.mts +27 -4
- package/types/engine/document-subtypes.d.mts +12 -31
- package/types/engine/event-views.d.mts +14 -2
- package/types/engine/exported-scene.d.mts +3 -2
- package/types/engine/field-spec.d.mts +13 -122
- package/types/engine/folder-notes.d.mts +0 -39
- package/types/engine/foreign-catalog.d.mts +2 -1
- package/types/engine/foundry-entries.d.mts +4 -5
- package/types/engine/frontmatter-lint.d.mts +2 -2
- package/types/engine/frontmatter.d.mts +19 -45
- package/types/engine/generate.d.mts +1 -1
- package/types/engine/helpers.d.mts +25 -42
- package/types/engine/homepage.d.mts +3 -10
- package/types/engine/ids.d.mts +0 -114
- package/types/engine/index-records.d.mts +6 -4
- package/types/engine/index.d.mts +0 -1
- package/types/engine/infobox-render.d.mts +7 -1
- package/types/engine/infobox.d.mts +3 -2
- package/types/engine/item-docs.d.mts +1 -1
- package/types/engine/item-registry.d.mts +2 -4
- package/types/engine/literature-notes.d.mts +1 -1
- package/types/engine/markdownlint-run.d.mts +40 -0
- package/types/engine/metadata-index.d.mts +9 -1
- package/types/engine/note-addresses.d.mts +27 -2
- package/types/engine/note-claims.d.mts +3 -5
- package/types/engine/note-ids.d.mts +2 -4
- package/types/engine/note-package.d.mts +1 -1
- package/types/engine/note-state.d.mts +1 -3
- package/types/engine/note-vocabulary.d.mts +28 -21
- package/types/engine/pack-config.d.mts +2 -6
- package/types/engine/pack-router.d.mts +4 -4
- package/types/engine/pathnames.d.mts +3 -3
- package/types/engine/pdf-build.d.mts +98 -12
- package/types/engine/pdf-coverage.d.mts +60 -0
- package/types/engine/pdf-index.d.mts +34 -5
- package/types/engine/pdf-pages.d.mts +143 -0
- package/types/engine/pdf-render.d.mts +45 -1
- package/types/engine/pdf-toc.d.mts +12 -14
- package/types/engine/prose-config.d.mts +1 -1
- package/types/engine/prose-lint.d.mts +11 -10
- package/types/engine/runtime-only-fields.d.mts +2 -2
- package/types/engine/site-build.d.mts +9 -5
- package/types/engine/site-index.d.mts +4 -5
- package/types/engine/site-root.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -2
- package/types/engine/standing-terms.d.mts +2 -1
- package/types/engine/standings.d.mts +7 -9
- package/types/engine/system-block.d.mts +10 -44
- package/types/engine/walk-files.d.mts +15 -0
- package/types/engine/wikilink-syntax.d.mts +18 -19
- package/types/hm3/actors.d.mts +1 -2
- package/types/hm3/item-fields.d.mts +2 -4
- package/types/hm3/template-priority.d.mts +6 -7
- package/types/manifest.d.mts +3 -2
- package/types/release.d.mts +8 -7
- package/types/sohl/actors.d.mts +2 -1
- package/types/sohl/document-subtypes.d.mts +1 -2
- package/types/sohl/item-fields.d.mts +3 -7
- package/engine/retired-fields.mjs +0 -631
- package/types/engine/retired-fields.d.mts +0 -354
package/markdownlint-config.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* The shared markdownlint rules, as a markdownlint-cli2 options module.
|
|
15
|
+
* The shared markdownlint rules, as a `.markdownlint-cli2.mjs` options module.
|
|
16
16
|
*
|
|
17
17
|
* `package-build markdown` applies these without a consumer declaring
|
|
18
18
|
* anything; this is for an editor's markdownlint extension, and for a consumer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "23.
|
|
3
|
+
"version": "23.2.1",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -145,13 +145,16 @@
|
|
|
145
145
|
"flesch": "^2.0.1",
|
|
146
146
|
"glob": "^13.0.6",
|
|
147
147
|
"gray-matter": "^4.0.3",
|
|
148
|
-
"handlebars": "^4.7.
|
|
148
|
+
"handlebars": "^4.7.10",
|
|
149
|
+
"ignore": "^7.0.12",
|
|
150
|
+
"jsonc-parser": "^3.3.1",
|
|
149
151
|
"loglevel": "^1.9.2",
|
|
150
152
|
"loglevel-plugin-prefix": "^0.8.4",
|
|
151
153
|
"markdown-it": "^15.0.0",
|
|
152
154
|
"markdown-it-deflist": "^4.0.0",
|
|
153
155
|
"markdown-it-footnote": "^4.0.0",
|
|
154
|
-
"markdownlint
|
|
156
|
+
"markdownlint": "^0.41.1",
|
|
157
|
+
"minimatch": "^10.2.6",
|
|
155
158
|
"pagefind": "^1.5.2",
|
|
156
159
|
"prettier": "^3.9.6",
|
|
157
160
|
"remark-frontmatter": "^5.0.0",
|
package/release.mjs
CHANGED
|
@@ -120,17 +120,18 @@ async function appendTree(archive, root, date) {
|
|
|
120
120
|
* Determines both asset names.
|
|
121
121
|
* @param {string} [opts.metadataDir] - Where the build writes its content
|
|
122
122
|
* index, consulted when the advertised file was not staged.
|
|
123
|
-
* @param {boolean} [opts.pdf] - Whether to build the
|
|
123
|
+
* @param {boolean} [opts.pdf] - Whether to build the books that ship beside the
|
|
124
124
|
* archive. `true` by default; `false` skips the build and reports the skip.
|
|
125
125
|
* @returns {Promise<{zip: string, manifest: string, metadata?: string,
|
|
126
|
-
* schema?: string,
|
|
126
|
+
* schema?: string, pdfs: string[], pdfFindings: object[], pdfSkipped: string|null,
|
|
127
127
|
* bytes: number, version: string}>} The paths written, what the book build
|
|
128
128
|
* found, the archive's size, and the version the manifest declares.
|
|
129
129
|
* `metadata` is absent when the manifest advertises no content index,
|
|
130
|
-
* `schema` is absent when the stage carries no `schema.json`, and `
|
|
131
|
-
*
|
|
132
|
-
* built, and otherwise the reason none was — itself
|
|
133
|
-
* builder could not be loaded
|
|
130
|
+
* `schema` is absent when the stage carries no `schema.json`, and `pdfs` is
|
|
131
|
+
* every book's PDF that was written, in declared order. `pdfSkipped` is
|
|
132
|
+
* `null` when a book was built, and otherwise the reason none was — itself
|
|
133
|
+
* `null` when the book builder could not be loaded or a book failed, which
|
|
134
|
+
* is reported through `pdfFindings`.
|
|
134
135
|
* @throws {Error} When the stage has no manifest — there is nothing to release,
|
|
135
136
|
* and an archive without one installs as nothing.
|
|
136
137
|
*/
|
|
@@ -190,23 +191,24 @@ export async function packRelease({
|
|
|
190
191
|
const book =
|
|
191
192
|
pdf ?
|
|
192
193
|
await packReleasePdf({ out, version: manifest.version })
|
|
193
|
-
: {
|
|
194
|
+
: { pdfs: [], findings: [], reason: "the release was asked not to build one" };
|
|
194
195
|
|
|
195
196
|
return {
|
|
196
197
|
zip: zipPath,
|
|
197
198
|
manifest: path.join(out, manifestName),
|
|
198
199
|
...(metadata ? { metadata } : {}),
|
|
199
200
|
...(schema ? { schema } : {}),
|
|
200
|
-
|
|
201
|
+
pdfs: book.pdfs,
|
|
201
202
|
pdfFindings: book.findings,
|
|
202
|
-
pdfSkipped: book.
|
|
203
|
+
pdfSkipped: book.pdfs.length ? null : book.reason,
|
|
203
204
|
bytes: archive.pointer(),
|
|
204
205
|
version: manifest.version,
|
|
205
206
|
};
|
|
206
207
|
}
|
|
207
208
|
|
|
208
209
|
/**
|
|
209
|
-
* Build the
|
|
210
|
+
* Build the books that ship beside the archive — every one `pdf.books`
|
|
211
|
+
* declares.
|
|
210
212
|
*
|
|
211
213
|
* **Imported when it is used, not when this module is.** The book build pulls
|
|
212
214
|
* in a markdown parser, DuckDB and the whole content engine; `release.mjs`
|
|
@@ -223,8 +225,9 @@ export async function packRelease({
|
|
|
223
225
|
* @param {object} opts - Options.
|
|
224
226
|
* @param {string} opts.out - The release directory.
|
|
225
227
|
* @param {string} opts.version - The version the manifest declares.
|
|
226
|
-
* @returns {Promise<{
|
|
227
|
-
*
|
|
228
|
+
* @returns {Promise<{pdfs: string[], findings: object[], reason: string|null}>}
|
|
229
|
+
* Each book's PDF that was built, in declared order, and what was found on
|
|
230
|
+
* the way.
|
|
228
231
|
*/
|
|
229
232
|
async function packReleasePdf({ out, version }) {
|
|
230
233
|
let buildPdf;
|
|
@@ -232,7 +235,7 @@ async function packReleasePdf({ out, version }) {
|
|
|
232
235
|
({ buildPdf } = await import("./engine/pdf-build.mjs"));
|
|
233
236
|
} catch (err) {
|
|
234
237
|
return {
|
|
235
|
-
|
|
238
|
+
pdfs: [],
|
|
236
239
|
findings: [
|
|
237
240
|
{
|
|
238
241
|
severity: "warning",
|
|
@@ -243,7 +246,11 @@ async function packReleasePdf({ out, version }) {
|
|
|
243
246
|
};
|
|
244
247
|
}
|
|
245
248
|
const result = await buildPdf({ out, version });
|
|
246
|
-
return {
|
|
249
|
+
return {
|
|
250
|
+
pdfs: result.books.map((book) => book.pdf).filter((pdf) => pdf),
|
|
251
|
+
findings: result.findings,
|
|
252
|
+
reason: result.reason,
|
|
253
|
+
};
|
|
247
254
|
}
|
|
248
255
|
|
|
249
256
|
/**
|
package/sohl/actors.mjs
CHANGED
|
@@ -42,10 +42,11 @@
|
|
|
42
42
|
* **A membership is derived, never authored here.** `data.affiliations` names
|
|
43
43
|
* the bodies a being belongs to and the standing it holds in each, and each
|
|
44
44
|
* entry becomes one embedded affiliation item: the entry's `rank` is that
|
|
45
|
-
* item's `system.level
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* item's `system.level`, its `office` is `system.office`, and the first of its
|
|
46
|
+
* `societies` is `system.society`, the one society the SoHL item carries. A
|
|
47
|
+
* standing is a fact about the setting rather than about one system — it does
|
|
48
|
+
* not become true because SoHL is installed — so the system block states none
|
|
49
|
+
* of it, and a sheet and a page cannot come to disagree.
|
|
49
50
|
*
|
|
50
51
|
* Not a standalone script — exports the `Actors` compiler class, imported and
|
|
51
52
|
* driven by `engine/generate.mjs`. Must run after the items passes, since it
|
|
@@ -155,18 +156,7 @@ export class Actors extends SystemActorCompiler {
|
|
|
155
156
|
this.errorCount++;
|
|
156
157
|
return;
|
|
157
158
|
}
|
|
158
|
-
const { model,
|
|
159
|
-
if (shortcode !== undefined) {
|
|
160
|
-
this.noteError(
|
|
161
|
-
`${ctx}: sohl.items[${index}] carries a top-level ` +
|
|
162
|
-
`\`shortcode\` — that key is retired. Name the item ` +
|
|
163
|
-
`this entry copies with \`model:\` (an address, e.g. ` +
|
|
164
|
-
`\`${type ?? "skill"}-${shortcode}\`), and use ` +
|
|
165
|
-
`\`system.shortcode\` for this item's own identity.`,
|
|
166
|
-
);
|
|
167
|
-
this.errorCount++;
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
159
|
+
const { model, type, ...rest } = entry;
|
|
170
160
|
const read = model === undefined ? null : this.readModel(model, index, ctx);
|
|
171
161
|
if (model !== undefined && !read) return;
|
|
172
162
|
if (read && type !== undefined) {
|
|
@@ -216,7 +206,8 @@ export class Actors extends SystemActorCompiler {
|
|
|
216
206
|
* The body's own compiled item is the model, so a membership carries
|
|
217
207
|
* whatever that body declares — its subtype, its common skills, its
|
|
218
208
|
* standings toward others — and the being adds only what is true of *this*
|
|
219
|
-
* membership: the rung it stands on
|
|
209
|
+
* membership: the rung it stands on, the post it holds, and the society it
|
|
210
|
+
* is held in.
|
|
220
211
|
*
|
|
221
212
|
* A being naming a body that compiles to no item is a finding rather than a
|
|
222
213
|
* silently dropped membership: the note says the being belongs somewhere,
|
|
@@ -236,9 +227,12 @@ export class Actors extends SystemActorCompiler {
|
|
|
236
227
|
if (!shortcode) continue;
|
|
237
228
|
const level = Number(standing?.rank);
|
|
238
229
|
const office = typeof standing?.office === "string" ? standing.office.trim() : "";
|
|
230
|
+
const [first] = Array.isArray(standing?.societies) ? standing.societies : [];
|
|
231
|
+
const society = typeof first === "string" ? first.trim() : "";
|
|
239
232
|
const system = {
|
|
240
233
|
...(Number.isFinite(level) ? { level } : {}),
|
|
241
234
|
...(office ? { office } : {}),
|
|
235
|
+
...(society ? { society } : {}),
|
|
242
236
|
};
|
|
243
237
|
const embedded = this.resolveEmbedded(
|
|
244
238
|
itemsMap,
|
|
@@ -335,16 +329,12 @@ export class Actors extends SystemActorCompiler {
|
|
|
335
329
|
// identity (the dedup/override key of the Create-dialog picker).
|
|
336
330
|
shortcode: fm.shortcode || "",
|
|
337
331
|
// Required nullable number: a priority, or `null` for a being that
|
|
338
|
-
// is not a template (the archetype contract).
|
|
339
|
-
// is the legacy spelling; the emitted key moves
|
|
340
|
-
// with the schema, since an undeclared `system` key is discarded at
|
|
341
|
-
// construction without a warning.
|
|
332
|
+
// is not a template (the archetype contract).
|
|
342
333
|
templatePriority: systemTemplatePriority(fm, ctx),
|
|
343
334
|
// `system.portrait` is **not** written here. A picture of the
|
|
344
335
|
// subject is a picture, so a being's portrait is the lead image of
|
|
345
|
-
// its `{#appearance}` section — which is the markup below
|
|
346
|
-
//
|
|
347
|
-
// source left, the field keeps the schema's own initial.
|
|
336
|
+
// its `{#appearance}` section — which is the markup below. With no
|
|
337
|
+
// authored source, the field keeps the schema's own initial.
|
|
348
338
|
appearance: renderSection(body || "", "appearance"),
|
|
349
339
|
// One document says it once. `dossier` is the field that carries
|
|
350
340
|
// an unsettled entry's notice, and `appearance` carries none —
|
|
@@ -399,9 +389,8 @@ export class Actors extends SystemActorCompiler {
|
|
|
399
389
|
folder,
|
|
400
390
|
sort: 0,
|
|
401
391
|
ownership: { default: 0 },
|
|
402
|
-
// Whatever the note authors, and nothing else. The
|
|
403
|
-
//
|
|
404
|
-
// field now and sits in `system`.
|
|
392
|
+
// Whatever the note authors, and nothing else. The template
|
|
393
|
+
// priority is a schema field and sits in `system`.
|
|
405
394
|
flags: blockProperty(fm, SYSTEM, "flags", {}),
|
|
406
395
|
_stats: this.stats,
|
|
407
396
|
_key: `!actors!${id}`,
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
* **The keys are SoHL *document* subtypes, not markdown note types.** The
|
|
47
47
|
* runtime reads this with `itemData.type`, which is a Foundry Item subtype, and
|
|
48
48
|
* that is the vocabulary a compendium document carries. The two vocabularies
|
|
49
|
-
*
|
|
50
|
-
* `
|
|
51
|
-
* because that is the side the runtime cannot translate: `sohl/item-builders.mjs`
|
|
49
|
+
* are the same string but for three note types (`armor` and its two siblings,
|
|
50
|
+
* whose document subtypes are `armorgear` and its siblings), and this map stays
|
|
51
|
+
* on the document side because that is the side the runtime cannot translate: `sohl/item-builders.mjs`
|
|
52
52
|
* asks SoHL's own note-type → subtype map before it looks art up here, so the
|
|
53
53
|
* build translates once and no second copy of those three rows exists.
|
|
54
54
|
*/
|
|
@@ -28,20 +28,6 @@
|
|
|
28
28
|
* silently. Sixteen lines of data are the price of the two vocabularies being
|
|
29
29
|
* separately stated.
|
|
30
30
|
*
|
|
31
|
-
* **Three rows are no longer the identity, and that is what the map was for.**
|
|
32
|
-
* `armor`, `concoction` and `projectile` were renamed from the `…gear`
|
|
33
|
-
* spellings that named SoHL's *document* subtype rather than the thing the note
|
|
34
|
-
* is about; the subtypes themselves did not move, so those three rows now
|
|
35
|
-
* say two different words where they used to say one twice. Landing the rename
|
|
36
|
-
* cost exactly what having the map first promised it would: a data change on
|
|
37
|
-
* three lines here, and no mechanism change anywhere.
|
|
38
|
-
*
|
|
39
|
-
* The old spellings are still read — {@link RENAMED_TYPES} normalises them
|
|
40
|
-
* before this map is consulted — so a tree that has not swept its 30,741
|
|
41
|
-
* embedded `(type, shortcode)` references compiles byte-identically. `weapon`
|
|
42
|
-
* is deliberately **not** among them: both systems call that document a
|
|
43
|
-
* `weapongear`, so the name says nothing SoHL-specific and is left alone.
|
|
44
|
-
*
|
|
45
31
|
* **What this map is not.** It says which document a note becomes, never what
|
|
46
32
|
* that document contains: the `system` block comes from the item registry's
|
|
47
33
|
* builders (`item-builders.mjs`), and an item's own `system.subType` field —
|
|
@@ -58,8 +44,7 @@ import { defineDocumentSubtypes } from "../engine/document-subtypes.mjs";
|
|
|
58
44
|
* becomes.
|
|
59
45
|
*
|
|
60
46
|
* The Item rows are the thirteen types the item registry declares; the one
|
|
61
|
-
* Actor row is `being
|
|
62
|
-
* compiling to the same actor before they were retired. Types this
|
|
47
|
+
* Actor row is `being`. Types this
|
|
63
48
|
* map does not name — `doc`, `macro`, the three map types — compile into
|
|
64
49
|
* documents that carry no system subtype at all, so they have no row and never
|
|
65
50
|
* needed one.
|
package/sohl/infobox.mjs
CHANGED
|
@@ -62,7 +62,6 @@ import {
|
|
|
62
62
|
humanizeValue,
|
|
63
63
|
systemRowsSection,
|
|
64
64
|
} from "../engine/infobox.mjs";
|
|
65
|
-
import { currentType } from "../engine/ids.mjs";
|
|
66
65
|
import { subTypes } from "../engine/note-vocabulary.mjs";
|
|
67
66
|
import { systemBlock, systemData } from "../engine/system-block.mjs";
|
|
68
67
|
import { readCanonicalKey } from "../engine/content-address.mjs";
|
|
@@ -205,7 +204,7 @@ function modelAddress(model) {
|
|
|
205
204
|
const target = parseAddress(
|
|
206
205
|
model,
|
|
207
206
|
{ package: contentPackage(), system: "sohl", types: MODEL_TYPES },
|
|
208
|
-
{ declared: true
|
|
207
|
+
{ declared: true },
|
|
209
208
|
);
|
|
210
209
|
return target.reason ? undefined : target;
|
|
211
210
|
}
|
|
@@ -240,7 +239,7 @@ export function decodeItem(entry) {
|
|
|
240
239
|
if (!type) return undefined;
|
|
241
240
|
return {
|
|
242
241
|
...(address ? { address } : {}),
|
|
243
|
-
type:
|
|
242
|
+
type: type,
|
|
244
243
|
shortcode,
|
|
245
244
|
name: typeof entry.name === "string" ? entry.name : "",
|
|
246
245
|
system,
|
package/sohl/item-builders.mjs
CHANGED
|
@@ -18,13 +18,10 @@
|
|
|
18
18
|
* There is one list, not two. This repository hands {@link ITEM_BUILDERS} to
|
|
19
19
|
* the build as `itemBuilders` in `package-build.config.yaml`, and `itemTypes()`
|
|
20
20
|
* — the whitelist — is derived from that table's own keys, so a type cannot be
|
|
21
|
-
* whitelisted for compilation without a builder to compile it.
|
|
22
|
-
* whitelist
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* still advertised as compilable, so a `type: trait` note passed the gate and
|
|
26
|
-
* then died on `BUILDERS[type] is not a function`, swallowed as a per-file
|
|
27
|
-
* error.
|
|
21
|
+
* whitelisted for compilation without a builder to compile it. Kept apart, a
|
|
22
|
+
* whitelist naming a type absent from `documentTypes.Item` would let a note of
|
|
23
|
+
* that type pass the gate and then die on `BUILDERS[type] is not a function`,
|
|
24
|
+
* swallowed as a per-file error.
|
|
28
25
|
*
|
|
29
26
|
* **The builders are generated, not written.** Each type's `system` builder
|
|
30
27
|
* comes from its field declaration in `item-fields.mjs` by way of
|
|
@@ -58,7 +55,7 @@ import { ITEM_FIELDS } from "./item-fields.mjs";
|
|
|
58
55
|
*
|
|
59
56
|
* Reading {@link defaultItemArt} here is what makes the two lists one: this
|
|
60
57
|
* module cannot name a type the art map does not cover, because that function
|
|
61
|
-
* throws and this module evaluates at import. A drift
|
|
58
|
+
* throws and this module evaluates at import. A drift between the lists
|
|
62
59
|
* is unrepresentable.
|
|
63
60
|
*
|
|
64
61
|
* **The art map is keyed by the document subtype**, which the runtime reads
|
package/sohl/item-fields.mjs
CHANGED
|
@@ -246,7 +246,7 @@ const STRIKE_MODES = Object.freeze({
|
|
|
246
246
|
* @returns {number} The die size, `0` when the projectile declares none.
|
|
247
247
|
*/
|
|
248
248
|
function impactDie(fm) {
|
|
249
|
-
return Number(sohlSystemField(fm, "impactBase.die", 0, {
|
|
249
|
+
return Number(sohlSystemField(fm, "impactBase.die", 0, { name: "impact.die" })) || 0;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
/** A strike mode discriminated by `type`, mandatory on a combat technique. */
|
|
@@ -281,7 +281,6 @@ const GEAR_COMMON = Object.freeze([
|
|
|
281
281
|
},
|
|
282
282
|
{
|
|
283
283
|
name: "data.weight",
|
|
284
|
-
legacyKey: "weight",
|
|
285
284
|
to: "weightBase",
|
|
286
285
|
...AS_AUTHORED,
|
|
287
286
|
kind: "number",
|
|
@@ -290,7 +289,6 @@ const GEAR_COMMON = Object.freeze([
|
|
|
290
289
|
},
|
|
291
290
|
{
|
|
292
291
|
name: "data.value",
|
|
293
|
-
legacyKey: "value",
|
|
294
292
|
to: "valueBase",
|
|
295
293
|
...AS_AUTHORED,
|
|
296
294
|
kind: "number",
|
|
@@ -299,7 +297,6 @@ const GEAR_COMMON = Object.freeze([
|
|
|
299
297
|
},
|
|
300
298
|
{
|
|
301
299
|
name: "data.quality",
|
|
302
|
-
legacyKey: "quality",
|
|
303
300
|
to: "qualityBase",
|
|
304
301
|
...AS_AUTHORED,
|
|
305
302
|
kind: "number",
|
|
@@ -308,7 +305,6 @@ const GEAR_COMMON = Object.freeze([
|
|
|
308
305
|
},
|
|
309
306
|
{
|
|
310
307
|
name: "data.durability",
|
|
311
|
-
legacyKey: "durability",
|
|
312
308
|
to: "durabilityBase",
|
|
313
309
|
...AS_AUTHORED,
|
|
314
310
|
kind: "number",
|
|
@@ -352,13 +348,9 @@ export const COMBAT_TECHNIQUE_STRIKE_MODE = Object.freeze({
|
|
|
352
348
|
* Every item type's frontmatter vocabulary, in the order the `system` block
|
|
353
349
|
* emits it.
|
|
354
350
|
*
|
|
355
|
-
* **A field whose shared source is a path into `data:`
|
|
356
|
-
* `name` is the source the content format's mapping tables
|
|
357
|
-
* `data.
|
|
358
|
-
* wins while a tree writes it. Naming only the source would move the in-block
|
|
359
|
-
* read to a key spelled `data.seat`, which nothing authors; naming only the key
|
|
360
|
-
* leaves the container the specification points at unread, and the field then
|
|
361
|
-
* compiles its default over an authored value with nothing said.
|
|
351
|
+
* **A field whose shared source is a path into `data:` is authored there and
|
|
352
|
+
* nowhere else.** `name` is the source the content format's mapping tables
|
|
353
|
+
* state — `data.seat`, `data.weight`.
|
|
362
354
|
*
|
|
363
355
|
* @type {Readonly<Record<string, readonly import("../engine/field-spec.mjs").FieldSpec[]>>}
|
|
364
356
|
*/
|
|
@@ -418,7 +410,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
418
410
|
// Plural because the field holds a map of many standings, one per
|
|
419
411
|
// affiliation — the singular reads as a misnomer.
|
|
420
412
|
name: "data.relations",
|
|
421
|
-
legacyKey: "relations",
|
|
422
413
|
to: "relations",
|
|
423
414
|
...RELATION,
|
|
424
415
|
address: AFFILIATION_KEYS,
|
|
@@ -430,7 +421,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
430
421
|
// A list, because an affiliation may sit under more than one at
|
|
431
422
|
// once — an arcane tradition within an order, say.
|
|
432
423
|
name: "data.parents",
|
|
433
|
-
legacyKey: "parents",
|
|
434
424
|
to: "parents",
|
|
435
425
|
...ADDRESS_LIST,
|
|
436
426
|
address: AFFILIATION_ITEMS,
|
|
@@ -442,7 +432,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
442
432
|
// subTypes, while a seat covers a polity, a guild, an order and a
|
|
443
433
|
// faith alike.
|
|
444
434
|
name: "data.seat",
|
|
445
|
-
legacyKey: "seat",
|
|
446
435
|
to: "seat",
|
|
447
436
|
...BLANK_IS_NULL,
|
|
448
437
|
address: PLACE_VALUE,
|
|
@@ -487,7 +476,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
487
476
|
},
|
|
488
477
|
{
|
|
489
478
|
name: "data.contagionIndex",
|
|
490
|
-
legacyKey: "contagionIndex",
|
|
491
479
|
to: "contagionIndexBase",
|
|
492
480
|
...NUMBER,
|
|
493
481
|
default: 0,
|
|
@@ -495,7 +483,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
495
483
|
},
|
|
496
484
|
{
|
|
497
485
|
name: "data.transmission",
|
|
498
|
-
legacyKey: "transmission",
|
|
499
486
|
to: "transmission",
|
|
500
487
|
...AS_AUTHORED,
|
|
501
488
|
default: "none",
|
|
@@ -518,7 +505,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
518
505
|
},
|
|
519
506
|
{
|
|
520
507
|
name: "data.outcomeTraumas",
|
|
521
|
-
legacyKey: "outcomeTraumas",
|
|
522
508
|
to: "outcomeTraumas",
|
|
523
509
|
...BLANK_IS_NULL,
|
|
524
510
|
default: null,
|
|
@@ -526,7 +512,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
526
512
|
},
|
|
527
513
|
{
|
|
528
514
|
name: "data.outcome",
|
|
529
|
-
legacyKey: "outcome",
|
|
530
515
|
to: "outcome",
|
|
531
516
|
...BLANK_IS_DEFAULT,
|
|
532
517
|
default: "cured",
|
|
@@ -551,7 +536,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
551
536
|
// the whole content of the declaration.
|
|
552
537
|
{
|
|
553
538
|
name: "data.onsetDurationFormula",
|
|
554
|
-
legacyKey: "onsetDurationFormula",
|
|
555
539
|
to: "onsetDurationFormula",
|
|
556
540
|
...DURATION_FORMULA,
|
|
557
541
|
omitWhenAbsent: true,
|
|
@@ -560,7 +544,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
560
544
|
},
|
|
561
545
|
{
|
|
562
546
|
name: "data.onsetDurationBase",
|
|
563
|
-
legacyKey: "onsetDurationBase",
|
|
564
547
|
to: "onsetDurationBase",
|
|
565
548
|
...DURATION_BASE,
|
|
566
549
|
omitWhenAbsent: true,
|
|
@@ -569,7 +552,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
569
552
|
},
|
|
570
553
|
{
|
|
571
554
|
name: "data.healingCheckDurationFormula",
|
|
572
|
-
legacyKey: "healingCheckDurationFormula",
|
|
573
555
|
to: "healingCheckDurationFormula",
|
|
574
556
|
...DURATION_FORMULA,
|
|
575
557
|
omitWhenAbsent: true,
|
|
@@ -578,7 +560,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
578
560
|
},
|
|
579
561
|
{
|
|
580
562
|
name: "data.healingCheckDurationBase",
|
|
581
|
-
legacyKey: "healingCheckDurationBase",
|
|
582
563
|
to: "healingCheckDurationBase",
|
|
583
564
|
...DURATION_BASE,
|
|
584
565
|
omitWhenAbsent: true,
|
|
@@ -587,7 +568,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
587
568
|
},
|
|
588
569
|
{
|
|
589
570
|
name: "data.resolutionDurationFormula",
|
|
590
|
-
legacyKey: "resolutionDurationFormula",
|
|
591
571
|
to: "resolutionDurationFormula",
|
|
592
572
|
...DURATION_FORMULA,
|
|
593
573
|
omitWhenAbsent: true,
|
|
@@ -596,7 +576,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
596
576
|
},
|
|
597
577
|
{
|
|
598
578
|
name: "data.resolutionDurationBase",
|
|
599
|
-
legacyKey: "resolutionDurationBase",
|
|
600
579
|
to: "resolutionDurationBase",
|
|
601
580
|
...DURATION_BASE,
|
|
602
581
|
omitWhenAbsent: true,
|
|
@@ -831,7 +810,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
831
810
|
},
|
|
832
811
|
{
|
|
833
812
|
name: "data.skillAptitudes",
|
|
834
|
-
legacyKey: "skillAptitudes",
|
|
835
813
|
to: "skillAptitudes",
|
|
836
814
|
...SKILL_APTITUDES,
|
|
837
815
|
default: {},
|
|
@@ -839,7 +817,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
839
817
|
},
|
|
840
818
|
{
|
|
841
819
|
name: "data.charges",
|
|
842
|
-
legacyKey: "charges",
|
|
843
820
|
to: "charges",
|
|
844
821
|
...CHARGES,
|
|
845
822
|
default: { value: null, max: null },
|
|
@@ -896,7 +873,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
896
873
|
},
|
|
897
874
|
{
|
|
898
875
|
name: "data.charges",
|
|
899
|
-
legacyKey: "charges",
|
|
900
876
|
to: "charges",
|
|
901
877
|
...CHARGES,
|
|
902
878
|
default: { value: null, max: null },
|
|
@@ -1089,7 +1065,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1089
1065
|
// that sets it bleeds, and one that leaves it unset does not.
|
|
1090
1066
|
{
|
|
1091
1067
|
name: "data.healingCheckDurationFormula",
|
|
1092
|
-
legacyKey: "healingCheckDurationFormula",
|
|
1093
1068
|
to: "healingCheckDurationFormula",
|
|
1094
1069
|
...DURATION_FORMULA,
|
|
1095
1070
|
omitWhenAbsent: true,
|
|
@@ -1098,7 +1073,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1098
1073
|
},
|
|
1099
1074
|
{
|
|
1100
1075
|
name: "data.healingCheckDurationBase",
|
|
1101
|
-
legacyKey: "healingCheckDurationBase",
|
|
1102
1076
|
to: "healingCheckDurationBase",
|
|
1103
1077
|
...DURATION_BASE,
|
|
1104
1078
|
omitWhenAbsent: true,
|
|
@@ -1107,7 +1081,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1107
1081
|
},
|
|
1108
1082
|
{
|
|
1109
1083
|
name: "data.bloodLossAdvanceDurationFormula",
|
|
1110
|
-
legacyKey: "bloodLossAdvanceDurationFormula",
|
|
1111
1084
|
to: "bloodLossAdvanceDurationFormula",
|
|
1112
1085
|
...DURATION_FORMULA,
|
|
1113
1086
|
omitWhenAbsent: true,
|
|
@@ -1116,7 +1089,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1116
1089
|
},
|
|
1117
1090
|
{
|
|
1118
1091
|
name: "data.bloodLossAdvanceDurationBase",
|
|
1119
|
-
legacyKey: "bloodLossAdvanceDurationBase",
|
|
1120
1092
|
to: "bloodLossAdvanceDurationBase",
|
|
1121
1093
|
...DURATION_BASE,
|
|
1122
1094
|
omitWhenAbsent: true,
|
|
@@ -1125,7 +1097,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1125
1097
|
},
|
|
1126
1098
|
{
|
|
1127
1099
|
name: "data.courseDurationFormula",
|
|
1128
|
-
legacyKey: "courseDurationFormula",
|
|
1129
1100
|
to: "courseDurationFormula",
|
|
1130
1101
|
...DURATION_FORMULA,
|
|
1131
1102
|
omitWhenAbsent: true,
|
|
@@ -1134,7 +1105,6 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1134
1105
|
},
|
|
1135
1106
|
{
|
|
1136
1107
|
name: "data.courseDurationBase",
|
|
1137
|
-
legacyKey: "courseDurationBase",
|
|
1138
1108
|
to: "courseDurationBase",
|
|
1139
1109
|
...DURATION_BASE,
|
|
1140
1110
|
omitWhenAbsent: true,
|
|
@@ -1177,7 +1147,7 @@ export const ITEM_FIELDS = Object.freeze({
|
|
|
1177
1147
|
to: "strikeModes",
|
|
1178
1148
|
...STRIKE_MODES,
|
|
1179
1149
|
default: [],
|
|
1180
|
-
describe: "The ways the weapon can
|
|
1150
|
+
describe: "The ways the weapon can strike.",
|
|
1181
1151
|
},
|
|
1182
1152
|
]),
|
|
1183
1153
|
});
|
package/sohl/items.mjs
CHANGED
|
@@ -88,10 +88,6 @@ export class Items extends SystemItemCompiler {
|
|
|
88
88
|
shortcode: fm.shortcode,
|
|
89
89
|
// Required nullable number: a priority, or `null` for a document
|
|
90
90
|
// that is not a template (the archetype contract).
|
|
91
|
-
// `system.archetype` is the legacy spelling; the receiving
|
|
92
|
-
// schema declares only the new name, so the emitted key moves with
|
|
93
|
-
// it — an undeclared `system` key is discarded at construction
|
|
94
|
-
// without a warning.
|
|
95
91
|
templatePriority: systemTemplatePriority(fm, label),
|
|
96
92
|
actionDefs: [],
|
|
97
93
|
notes: "",
|
package/sohl/kb-passes.mjs
CHANGED
|
@@ -51,9 +51,9 @@ import log from "loglevel";
|
|
|
51
51
|
* code spans rather than refuse to build.
|
|
52
52
|
*
|
|
53
53
|
* **Configuring one that cannot be used is a defect, and it fails the build.**
|
|
54
|
-
* A missing file, a malformed one, a permissions error and a path typo
|
|
54
|
+
* A missing file, a malformed one, a permissions error and a path typo would
|
|
55
55
|
* be indistinguishable from each other *and* from a correctly configured build
|
|
56
|
-
* with no symbols
|
|
56
|
+
* with no symbols, were a bare `catch` to return `{}` for all of them. Nothing then
|
|
57
57
|
* compares an emitted page against what its source asked for, so the first
|
|
58
58
|
* observer of a broken map was a reader who clicked nothing, because every
|
|
59
59
|
* `{@link}` on the published site had quietly become a code span.
|
|
@@ -112,7 +112,7 @@ function readSymbolMap(file, repoRoot) {
|
|
|
112
112
|
|
|
113
113
|
// Reported because a map that loaded and a map that loaded empty are
|
|
114
114
|
// otherwise indistinguishable without reading the emitted HTML — and an
|
|
115
|
-
// empty one degrades every tag exactly as a missing one
|
|
115
|
+
// empty one degrades every tag exactly as a missing one does.
|
|
116
116
|
log.info(`resolved ${Object.keys(parsed).length} API symbols from ${file}`);
|
|
117
117
|
return parsed;
|
|
118
118
|
}
|