@heroiclands/package-build 22.26.0 → 22.28.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 +17 -0
- package/README.md +3 -1
- package/assets/styles/content-base.css +46 -3
- package/bin/content-commands.mjs +53 -5
- package/ci/publish-npm.mjs +49 -0
- package/docs/api.md +44 -24
- package/docs/authoring/first-note.md +1 -1
- package/docs/authoring/frontmatter.md +2 -2
- package/docs/authoring/links-and-markup.md +96 -149
- package/docs/content-format.md +7 -3
- package/docs/guides/government-migration.md +52 -0
- package/docs/guides/site.md +5 -5
- package/docs/reference/format-details.md +131 -230
- package/docs/reference/note-types.md +27 -29
- package/docs/reference/theme-pages.md +31 -29
- package/engine/anchors.mjs +85 -13
- package/engine/art-fields.mjs +1 -1
- package/engine/base-compiler.mjs +9 -1
- package/engine/bundles.mjs +1 -1
- package/engine/code-fences.mjs +6 -2
- package/engine/content-alerts.mjs +195 -0
- package/engine/content-blocks.mjs +119 -241
- package/engine/content-embeds.mjs +1 -1
- package/engine/content-figures.mjs +166 -230
- package/engine/content-format-check.mjs +3 -2
- package/engine/content-format.yaml +0 -5
- package/engine/content-images.mjs +3 -3
- package/engine/content-poetry.mjs +141 -0
- package/engine/content-spans.mjs +177 -0
- package/engine/folder-notes.mjs +2 -3
- package/engine/foundry-entries.mjs +2 -0
- package/engine/frontmatter-lint.mjs +2 -1
- package/engine/heading-attributes.mjs +1 -1
- package/engine/helpers.mjs +8 -3
- package/engine/holdings.mjs +165 -273
- package/engine/index.mjs +2 -2
- package/engine/infobox.mjs +1 -1
- package/engine/journals.mjs +8 -6
- package/engine/markdown-expressions.mjs +9 -3
- package/engine/metadata-index.mjs +2 -3
- package/engine/note-vocabulary.mjs +19 -15
- package/engine/pdf-build.mjs +1 -1
- package/engine/pdf-render.mjs +90 -31
- package/engine/populations.mjs +17 -83
- package/engine/site-build.mjs +44 -16
- package/engine/site-preview.mjs +22 -6
- package/engine/stub-lint.mjs +20 -64
- package/engine/wikilinks.mjs +18 -4
- package/githooks/pre-push +1 -1
- package/hugo-theme/layouts/partials/holdings/entry.html +2 -2
- package/hugo-theme/layouts/partials/holdings.html +14 -14
- package/hugo-theme/static/css/style.css +40 -2
- package/package.json +3 -1
- package/sohl/item-fields.mjs +0 -16
- package/types/engine/anchors.d.mts +13 -4
- package/types/engine/art-fields.d.mts +1 -1
- package/types/engine/code-fences.d.mts +3 -1
- package/types/engine/content-alerts.d.mts +62 -0
- package/types/engine/content-blocks.d.mts +3 -10
- package/types/engine/content-embeds.d.mts +1 -1
- package/types/engine/content-figures.d.mts +13 -20
- package/types/engine/content-images.d.mts +1 -1
- package/types/engine/content-poetry.d.mts +32 -0
- package/types/engine/content-spans.d.mts +18 -0
- package/types/engine/holdings.d.mts +59 -105
- package/types/engine/markdown-expressions.d.mts +1 -1
- package/types/engine/note-vocabulary.d.mts +12 -4
- package/types/engine/populations.d.mts +4 -13
- package/types/engine/site-build.d.mts +3 -3
- package/types/engine/wikilinks.d.mts +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.28.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
Notes now require a nonempty body, including drafts, folders and homepages. Short written notes still warn unless tagged as drafts.
|
|
8
|
+
|
|
9
|
+
## 22.27.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- Governing bodies list the places they govern from each place’s stated government, keeping those lists consistent with place descriptions.
|
|
14
|
+
- Tables that listed governing bodies through affiliation territory lists must query each place’s government instead.
|
|
15
|
+
- Captions now precede the item they describe; use `:@` for numbered captions or `:` for captions without numbers.
|
|
16
|
+
- Write poetry in a `poetry` code fence, and use attributed divs and inline spans to group or style text.
|
|
17
|
+
- Replace former figure wrappers with leading captions; the old figure and poetry div fences are no longer supported.
|
|
18
|
+
- Blockquote alerts provide note, tip, important and warning callouts; the former info and warn div fences are removed.
|
|
19
|
+
|
|
3
20
|
## 22.26.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -46,6 +46,8 @@ The documentation lives in the Markdown files in this repository. Start with [th
|
|
|
46
46
|
| Error locations and severities | [Diagnostics](docs/diagnostics.md) |
|
|
47
47
|
| Architectural rationale | [Design](docs/design.md) |
|
|
48
48
|
|
|
49
|
-
Place notes may declare a governing affiliation with `data.government`, or explicit `null` for complete anarchy. Positive population with an omitted government produces an advisory. See [place governments](docs/authoring/frontmatter.md#place-governments).
|
|
49
|
+
Place notes may declare a governing affiliation with `data.government` (`Address`, default target type `affiliation`), or explicit `null` for complete anarchy. Positive population with an omitted government produces an advisory. See [place governments](docs/authoring/frontmatter.md#place-governments) and [government migration](docs/guides/government-migration.md).
|
|
50
|
+
|
|
51
|
+
Leading captions, generic fenced divs, inline spans, and poetry code fences are described in [links and markup](docs/authoring/links-and-markup.md).
|
|
50
52
|
|
|
51
53
|
The package is GPL-3.0-or-later for code and CC-BY-SA-4.0 for original content. See [LICENSE.md](LICENSE.md).
|
|
@@ -152,9 +152,8 @@
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* inline `style` a consumer cannot override.
|
|
155
|
+
* Historical info/warn section classes remain available for styled prose.
|
|
156
|
+
* New alerts use the separate alert classes below.
|
|
158
157
|
*
|
|
159
158
|
* `secret` is deliberately absent: Foundry styles `section.secret` itself and
|
|
160
159
|
* owns the reveal control on it, and a rule here would fight both.
|
|
@@ -205,3 +204,47 @@
|
|
|
205
204
|
--pb-block-edge: #7a5100;
|
|
206
205
|
}
|
|
207
206
|
}
|
|
207
|
+
|
|
208
|
+
/* Alerts share ordinary body colors, with an accent on their edge and title. */
|
|
209
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert {
|
|
210
|
+
border-inline-start: 0.25rem solid var(--pb-alert-color);
|
|
211
|
+
padding: 0.5rem 1rem;
|
|
212
|
+
margin: 1rem 0;
|
|
213
|
+
color: inherit;
|
|
214
|
+
background: transparent;
|
|
215
|
+
}
|
|
216
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert-title {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
gap: 0.5em;
|
|
220
|
+
margin: 0 0 0.5rem;
|
|
221
|
+
font-weight: 600;
|
|
222
|
+
color: var(--pb-alert-color);
|
|
223
|
+
}
|
|
224
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert-icon {
|
|
225
|
+
width: 1em;
|
|
226
|
+
height: 1em;
|
|
227
|
+
flex-shrink: 0;
|
|
228
|
+
fill: currentColor;
|
|
229
|
+
}
|
|
230
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror)
|
|
231
|
+
.alert
|
|
232
|
+
> :last-child {
|
|
233
|
+
margin-bottom: 0;
|
|
234
|
+
}
|
|
235
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert-note {
|
|
236
|
+
--pb-alert-color: #0969da;
|
|
237
|
+
--pb-alert-color: light-dark(#0969da, #4493f8);
|
|
238
|
+
}
|
|
239
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert-tip {
|
|
240
|
+
--pb-alert-color: #1a7f37;
|
|
241
|
+
--pb-alert-color: light-dark(#1a7f37, #3fb950);
|
|
242
|
+
}
|
|
243
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert-important {
|
|
244
|
+
--pb-alert-color: #8250df;
|
|
245
|
+
--pb-alert-color: light-dark(#8250df, #ab7df8);
|
|
246
|
+
}
|
|
247
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .alert-warning {
|
|
248
|
+
--pb-alert-color: #9a6700;
|
|
249
|
+
--pb-alert-color: light-dark(#9a6700, #d29922);
|
|
250
|
+
}
|
package/bin/content-commands.mjs
CHANGED
|
@@ -226,7 +226,12 @@ const SHIPPED_ITEM_FIELDS = { sohl: ITEM_FIELDS, hm3: HM3_ITEM_FIELDS };
|
|
|
226
226
|
/** Register the content operations on the package command line. */
|
|
227
227
|
export function registerContentCommands(cli) {
|
|
228
228
|
return cli
|
|
229
|
-
.command(
|
|
229
|
+
.command(
|
|
230
|
+
withIndexPreflight(
|
|
231
|
+
withBodyPreflight(packageCommand(), (_config, argv) => argv.action === "compile"),
|
|
232
|
+
(_config, argv) => argv.action === "compile",
|
|
233
|
+
),
|
|
234
|
+
)
|
|
230
235
|
.command(depsCommand())
|
|
231
236
|
.command(docsCommand())
|
|
232
237
|
.command(withIndexPreflight(lintCommand()))
|
|
@@ -235,11 +240,17 @@ export function registerContentCommands(cli) {
|
|
|
235
240
|
.command(withIndexPreflight(linksCommand()))
|
|
236
241
|
.command(formatCommand())
|
|
237
242
|
.command(markdownCommand())
|
|
238
|
-
.command(
|
|
239
|
-
|
|
243
|
+
.command(
|
|
244
|
+
withBodyPreflight(
|
|
245
|
+
contentIndexCommand(),
|
|
246
|
+
() => true,
|
|
247
|
+
(config, argv) => argv.root || config.paths.content,
|
|
248
|
+
),
|
|
249
|
+
)
|
|
250
|
+
.command(withIndexPreflight(withBodyPreflight(siteCommand()), publishesContentPages))
|
|
240
251
|
.command(
|
|
241
252
|
withIndexPreflight(
|
|
242
|
-
pdfCommand(),
|
|
253
|
+
withBodyPreflight(pdfCommand(), (config) => Boolean(config.pdf)),
|
|
243
254
|
(config) => config.pdf && publishesContentPages(config),
|
|
244
255
|
),
|
|
245
256
|
)
|
|
@@ -380,6 +391,43 @@ function proseCommand() {
|
|
|
380
391
|
};
|
|
381
392
|
}
|
|
382
393
|
|
|
394
|
+
/** Refuse invalid note bodies before emitting metadata, packs, pages or a book. */
|
|
395
|
+
function withBodyPreflight(
|
|
396
|
+
command,
|
|
397
|
+
shouldCheck = () => true,
|
|
398
|
+
contentRoot = (config) => config.paths.content,
|
|
399
|
+
) {
|
|
400
|
+
const handler = command.handler;
|
|
401
|
+
return {
|
|
402
|
+
...command,
|
|
403
|
+
handler: async (argv) => {
|
|
404
|
+
try {
|
|
405
|
+
const config = loadPackConfig();
|
|
406
|
+
if (shouldCheck(config, argv)) {
|
|
407
|
+
const contentBase = contentRoot(config, argv);
|
|
408
|
+
if (!fs.existsSync(contentBase)) return handler(argv);
|
|
409
|
+
const records = indexRecordsFor({ config, contentBase });
|
|
410
|
+
const { findings } = lintNoteStates(contentBase, {
|
|
411
|
+
records,
|
|
412
|
+
contentPackage: config.contentPackage,
|
|
413
|
+
});
|
|
414
|
+
const errors = findings.filter((finding) => finding.severity === "error");
|
|
415
|
+
if (errors.length) {
|
|
416
|
+
for (const finding of errors) emitDiagnostic(finding);
|
|
417
|
+
process.exitCode = 1;
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} catch (err) {
|
|
422
|
+
reportFailure(err);
|
|
423
|
+
process.exitCode = 1;
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
return handler(argv);
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
383
431
|
/** Check declared dependency indexes before an index-consuming command does any work. */
|
|
384
432
|
function withIndexPreflight(command, shouldCheck = () => true) {
|
|
385
433
|
const handler = command.handler;
|
|
@@ -1167,7 +1215,7 @@ function lintCommand() {
|
|
|
1167
1215
|
skipDirectories: config.skipDirectories,
|
|
1168
1216
|
});
|
|
1169
1217
|
|
|
1170
|
-
// Whether every
|
|
1218
|
+
// Whether every note has a body, and how
|
|
1171
1219
|
// finished the tree is. The counts and the oldest drafts are
|
|
1172
1220
|
// prose rather than findings: a note nobody has finished is not
|
|
1173
1221
|
// wrong, and 464 warnings a reader cannot clear is how a report
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
3
|
+
* Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
|
|
4
|
+
*
|
|
5
|
+
* This work is licensed under the GNU General Public License v3.0 (GPLv3).
|
|
6
|
+
* You may copy, modify, and distribute it under the terms of that license.
|
|
7
|
+
*
|
|
8
|
+
* For full terms, see the LICENSE.md file in the project root or visit:
|
|
9
|
+
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Publish this package to npm, with provenance wherever it can be generated.
|
|
16
|
+
*
|
|
17
|
+
* `publishConfig.provenance` is `true`, and npm refuses a publish with
|
|
18
|
+
* `Automatic provenance generation not supported for provider: null` anywhere
|
|
19
|
+
* that cannot mint a Sigstore identity. That is a CI runner holding an OIDC
|
|
20
|
+
* token: GitHub Actions with `id-token: write`, which exposes
|
|
21
|
+
* `ACTIONS_ID_TOKEN_REQUEST_URL`, or GitLab CI with `SIGSTORE_ID_TOKEN`.
|
|
22
|
+
* Everywhere else — a desk — this passes `--provenance=false`, so the publish
|
|
23
|
+
* goes ahead unattested rather than failing.
|
|
24
|
+
*
|
|
25
|
+
* Arguments after `--` reach `npm publish` unchanged, so
|
|
26
|
+
* `npm run deploy:npm -- --dry-run` shows the tarball without publishing it.
|
|
27
|
+
* `prepack` builds the declarations and the asset index on the way.
|
|
28
|
+
*
|
|
29
|
+
* Not a `package-build` subcommand: it publishes this package and no other.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { spawnSync } from "node:child_process";
|
|
33
|
+
|
|
34
|
+
const env = process.env;
|
|
35
|
+
const provenance =
|
|
36
|
+
(env.GITHUB_ACTIONS === "true" && Boolean(env.ACTIONS_ID_TOKEN_REQUEST_URL)) ||
|
|
37
|
+
(env.GITLAB_CI === "true" && Boolean(env.SIGSTORE_ID_TOKEN));
|
|
38
|
+
|
|
39
|
+
if (!provenance) {
|
|
40
|
+
console.log("deploy:npm: no OIDC identity here; publishing without provenance.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const args = ["publish", ...(provenance ? ["--provenance"] : ["--provenance=false"])];
|
|
44
|
+
const result = spawnSync("npm", [...args, ...process.argv.slice(2)], {
|
|
45
|
+
stdio: "inherit",
|
|
46
|
+
shell: process.platform === "win32",
|
|
47
|
+
});
|
|
48
|
+
if (result.error) throw result.error;
|
|
49
|
+
process.exit(result.status ?? 1);
|
package/docs/api.md
CHANGED
|
@@ -372,6 +372,7 @@ An addressed content note accepts exactly these top-level keys, in this order: `
|
|
|
372
372
|
| `subTypeCharsetMessage` | `subTypeCharsetMessage(value)` | `string` | building the message for a `subType` outside the address charset |
|
|
373
373
|
| `typeCharsetMessage` | `typeCharsetMessage(type)` | `string` | building the message for a `type` outside the address charset |
|
|
374
374
|
| `assertVocabularyCharset` | `assertVocabularyCharset(vocabulary, where)` | throws | refusing a vocabulary declaration whose type or subType breaks the address charset |
|
|
375
|
+
| `isLegacyDataField` | `isLegacyDataField(type, key)` | `boolean` | testing accepted but ignored transitional affiliation `data.domains` input |
|
|
375
376
|
| `dataFields` | `dataFields(type, vocabulary)` | `readonly DataFieldSpec[] \| undefined` | looking up the `data:` keys a note type may carry |
|
|
376
377
|
| `subTypes` | `subTypes(type, vocabulary)` | `readonly string[] \| null \| undefined` | looking up the closed `subType` values a note type declares |
|
|
377
378
|
|
|
@@ -440,16 +441,16 @@ Drawing a declared infobox: HTML for separate Foundry pages appended after autho
|
|
|
440
441
|
|
|
441
442
|
The three states of a note — **stub**, **draft**, **full** — and the one observable fact they rest on. A note whose body is empty is a stub: it carries its facts into the index and is queryable there, and it has no page, no address and no link target. Nothing is stored: the ladder is derived once in the SQL `entries` view and no note can assert its own state.
|
|
442
443
|
|
|
443
|
-
| Export | Signature | Returns | Use it when
|
|
444
|
-
| --------------------- | ------------------------------------------- | --------------------------------------- |
|
|
445
|
-
| `NOTE_STATES` | `const NOTE_STATES` | `ReadonlyArray<string>` | naming the three states in ladder order
|
|
446
|
-
| `isEmptyBody` | `isEmptyBody(body)` | `boolean` | asking the exact question: is everything after the closing frontmatter fence whitespace?
|
|
447
|
-
| `isStubbableType` | `isStubbableType(type, vocabulary)` | `boolean` | asking whether an empty body suppresses this type's page; `folder` and `homepage`
|
|
448
|
-
| `isStubNote` | `isStubNote(frontmatter, body, vocabulary)` | `boolean` | deciding whether one note is a stub, which is what the index and the site build both ask
|
|
449
|
-
| `journalHasContent` | `journalHasContent(body)` | `boolean` | asking whether the JournalEntry a body compiles into would hold anything, which is what decides whether one is made at all
|
|
450
|
-
| `PLACEHOLDER_PHRASES` | `const PLACEHOLDER_PHRASES` | `ReadonlyArray<string>` | reading the phrases that stand in for prose nobody has written
|
|
451
|
-
| `placeholderBody` | `placeholderBody(body)` | `Array<{phrase: string, line: number}>` | finding a body that reduces to nothing but placeholders, which is an abandoned draft rather than a stub
|
|
452
|
-
| `bodyWordCount` | `bodyWordCount(body)` | `number` | counting rendered prose, with wikilinks as one word and closed dashes, slashes, and ellipses separating adjacent words
|
|
444
|
+
| Export | Signature | Returns | Use it when |
|
|
445
|
+
| --------------------- | ------------------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
446
|
+
| `NOTE_STATES` | `const NOTE_STATES` | `ReadonlyArray<string>` | naming the three states in ladder order |
|
|
447
|
+
| `isEmptyBody` | `isEmptyBody(body)` | `boolean` | asking the exact question: is everything after the closing frontmatter fence whitespace? |
|
|
448
|
+
| `isStubbableType` | `isStubbableType(type, vocabulary)` | `boolean` | asking whether an empty body suppresses this type's page; `folder` and `homepage` retain their addresses in this classification, but still require bodies |
|
|
449
|
+
| `isStubNote` | `isStubNote(frontmatter, body, vocabulary)` | `boolean` | deciding whether one note is a stub, which is what the index and the site build both ask |
|
|
450
|
+
| `journalHasContent` | `journalHasContent(body)` | `boolean` | asking whether the JournalEntry a body compiles into would hold anything, which is what decides whether one is made at all |
|
|
451
|
+
| `PLACEHOLDER_PHRASES` | `const PLACEHOLDER_PHRASES` | `ReadonlyArray<string>` | reading the phrases that stand in for prose nobody has written |
|
|
452
|
+
| `placeholderBody` | `placeholderBody(body)` | `Array<{phrase: string, line: number}>` | finding a body that reduces to nothing but placeholders, which is an abandoned draft rather than a stub |
|
|
453
|
+
| `bodyWordCount` | `bodyWordCount(body)` | `number` | counting rendered prose, with wikilinks as one word and closed dashes, slashes, and ellipses separating adjacent words |
|
|
453
454
|
|
|
454
455
|
### `engine.draftNotice`
|
|
455
456
|
|
|
@@ -470,7 +471,7 @@ What a draft note says about itself, in one sentence, on every surface it reache
|
|
|
470
471
|
|
|
471
472
|
### `engine.stubLint`
|
|
472
473
|
|
|
473
|
-
|
|
474
|
+
Every typed note must have a nonempty body. Empty and whitespace-only bodies are errors regardless of description or `draft` tag, including structural types such as `folder` and `homepage`. Placeholder-only bodies also produce errors. Nonempty bodies with fewer than 25 prose words produce warnings unless tagged `draft`. Untyped vault scaffolding is excluded. The lint, content-index, package compile, site and PDF commands enforce body errors before publishing. The state classification helpers still describe incomplete records for inspection; their classifications do not exempt notes from validation.
|
|
474
475
|
|
|
475
476
|
| Export | Signature | Returns | Use it when |
|
|
476
477
|
| ------------------ | ---------------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
@@ -497,22 +498,24 @@ What a place is next to (`data.borders`) and reachable from (`data.routes`): the
|
|
|
497
498
|
|
|
498
499
|
### `engine.holdings`
|
|
499
500
|
|
|
500
|
-
What lies within a place
|
|
501
|
+
What lies within a place and which affiliation explicitly governs it — read off `data.parents` and resolved explicit `data.government` across this package and every fetched index, inverted into the `contains`, `governed_by` and `governed_places` lists the site build writes — and the population-based government advisory `package-build lint` runs on a place.
|
|
501
502
|
|
|
502
|
-
| Export | Signature
|
|
503
|
-
| ---------------------- |
|
|
504
|
-
| `HOLDINGS_KEYS` | `const HOLDINGS_KEYS`
|
|
505
|
-
| `HELD_SUBTYPES` | `const HELD_SUBTYPES`
|
|
506
|
-
| `holdingsNode` | `holdingsNode(fm, { title, url })`
|
|
507
|
-
| `foreignHoldingsNodes` | `foreignHoldingsNodes(foreignIndex)`
|
|
508
|
-
| `holdingsPages` | `holdingsPages(nodes)`
|
|
509
|
-
| `shortcodesOf` | `shortcodesOf(value)`
|
|
510
|
-
| `checkGovernment` | `checkGovernment(note)`
|
|
511
|
-
| `checkHeld` | `checkHeld(note, { index })`
|
|
503
|
+
| Export | Signature | Returns | Use it when |
|
|
504
|
+
| ---------------------- | --------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
505
|
+
| `HOLDINGS_KEYS` | `const HOLDINGS_KEYS` | `readonly string[]` | derived `contains`, `governed_by`, `governed_places` and retired `held_by`/`holdings` keys removed from authored page metadata |
|
|
506
|
+
| `HELD_SUBTYPES` | `const HELD_SUBTYPES` | `readonly string[]` | deprecated historical tenure subtypes; government checks apply to every place subtype |
|
|
507
|
+
| `holdingsNode` | `holdingsNode(fm, { title, url, package, system })` | `HoldingsNode\|null` | reading a local note as a node of the derivation, or `null` for one that is neither a place nor an affiliation |
|
|
508
|
+
| `foreignHoldingsNodes` | `foreignHoldingsNodes(foreignIndex)` | `HoldingsNode[]` | reading a fetched index's places and affiliations as nodes |
|
|
509
|
+
| `holdingsPages` | `holdingsPages(nodes, { governmentNodes })` | `Map<string, Holdings>` | inverting `parents` and resolved explicit `government` into each page's sorted lists, keyed by URL, for every page with at least one entry |
|
|
510
|
+
| `shortcodesOf` | `shortcodesOf(value)` | `string[]` | the shortcodes a `parents` value names — bare or qualified Addresses — empties dropped and repeats collapsed |
|
|
511
|
+
| `checkGovernment` | `checkGovernment(note)` | `object[]` | warning at `data.population` for positive population with no own `data.government` key; explicit null means anarchy |
|
|
512
|
+
| `checkHeld` | `checkHeld(note, { index })` | `object[]` | deprecated compatibility wrapper for `checkGovernment`; holdings do not determine government |
|
|
513
|
+
|
|
514
|
+
Government-only supplemental records passed in `holdingsPages` options include public local stubs in the reverse lists without adding them to the geographical graph. Published nodes retain precedence; stubs without URLs render as plain text.
|
|
512
515
|
|
|
513
516
|
### `engine.populations`
|
|
514
517
|
|
|
515
|
-
Whether a world's population figures agree from the region down — the
|
|
518
|
+
Whether a world's population figures agree from the region down — the regions inside a place against what it states, a settlement against every place containing it, and a `doc` note's cited figures against the notes that own them. `package-build lint` runs all three as warnings.
|
|
516
519
|
|
|
517
520
|
| Export | Signature | Returns | Use it when |
|
|
518
521
|
| ----------------------- | ---------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
@@ -700,7 +703,7 @@ invokes the check during frontmatter lint.
|
|
|
700
703
|
|
|
701
704
|
### `engine.markdownExpressions`
|
|
702
705
|
|
|
703
|
-
`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
|
|
706
|
+
`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 captioned item 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.
|
|
704
707
|
|
|
705
708
|
| Export | Signature | Returns | Use it when |
|
|
706
709
|
| --------------------------- | ------------------------------------------ | ---------------------- | ------------------------------------------------ |
|
|
@@ -1964,3 +1967,20 @@ The Changesets changelog generator, loaded with `require` — a CommonJS module
|
|
|
1964
1967
|
## `./package.json`
|
|
1965
1968
|
|
|
1966
1969
|
Not a JavaScript module — this subpath entry exists so tooling (bundlers, `import.meta.resolve`, a script reading the installed version) can resolve the package's own `package.json` through Node's package-exports resolution instead of reaching outside the declared export map.
|
|
1970
|
+
|
|
1971
|
+
## Markup parsing modules
|
|
1972
|
+
|
|
1973
|
+
The engine wildcard subpath also exposes the body parsers below. Historical figure API names now operate on leading captions; `:::figure` is removed.
|
|
1974
|
+
|
|
1975
|
+
| Module | Exports | Contract |
|
|
1976
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1977
|
+
| `engine/content-figures.mjs` | `FIGURE_NAMES`, `FIGURE_CLASSES`, `scanFigures`, `numberFigures`, `renderFigureBlocks` | Scan leading captions and their next supported blocks; `numbered` distinguishes `:` and `:@`. `type` may override inference; `example` is supported. `FIGURE_CLASSES` retains built-in styled classes, not a closed author vocabulary. |
|
|
1978
|
+
| `engine/content-blocks.mjs` | `BLOCK_NAMES`, `BLOCK_CONTAINERS`, `scanBlocks`, `renderBlocks`, `renderWithheldSections` | Read div and secret fences; info/warn names are retired; generic div records have `name: "div"` and no generated title. Scanning includes poetry errors. |
|
|
1979
|
+
| `engine/content-poetry.mjs` | `verseLines`, `poetryStanzas`, `inlineVerse`, `poetryMarkdown`, `scanPoetry`, `renderPoetry` | Read `poetry` code fences, validate authored metadata and tabs, and preserve relative indent levels and stanzas. |
|
|
1980
|
+
| `engine/content-spans.mjs` | `spanMarkdownPlugin`, `scanSpans`, `renderSpans` | Parse bracket spans after recognized links. The scanner returns spans and located errors; the renderer preserves inline Markdown in attributed HTML spans. |
|
|
1981
|
+
|
|
1982
|
+
`scanFigures` retains `line` (1-based caption line), `bodyStart`/`bodyEnd` (0-based, exclusive-end target range), and `close` (last consumed target line), plus caption attributes, kind, label and number. Unnumbered captions have an empty label and consume no number. `collectAnchors` discovers heading, caption, div, poem and span identifiers; `markupAnchorFindings(body)` reports collisions involving non-page identifiers; Foundry maps non-page anchors to the actual containing page UUID. An unnumbered `ref` requires `form="title"` or `form="full"`.
|
|
1983
|
+
|
|
1984
|
+
`engine/content-alerts.mjs` exposes `ALERT_TYPES`, `scanAlerts(source)` and `renderAlerts(source, target)` and `alertMarkdownPlugin(md)`. The scanner returns `{blocks, errors}`; alert records carry `type`, `id`, `classes`, `attributes`, `title`, `body` and inclusive zero-based `start`/`end` source lines. The renderer produces attributed `aside.alert` wrappers while leaving alert body Markdown in the document's scope. Alert validation and anchor discovery run in site, Foundry and book pipelines.
|
|
1985
|
+
|
|
1986
|
+
Alert `title` is the displayed heading override; absent, it defaults to the label in `ALERT_TYPES`. It does not change the alert type’s icon or color.
|
|
@@ -45,4 +45,4 @@ The full Address is `<package>-note-lore-harbor`; `<package>` comes from `conten
|
|
|
45
45
|
|
|
46
46
|
Add `description` for a short page summary, `tags: [draft]` to mark unfinished prose, or `data` for fields the note's type permits. A system block such as `sohl:` or `hm3:` adds mechanics and can produce a Foundry Actor or Item. It does not replace the shared prose or make another JournalEntry. [Frontmatter](frontmatter.md) explains the allowed keys, and the [note-type reference](../reference/note-types.md) lists every type-specific field.
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Every typed note must have a nonempty body after its frontmatter. An empty or whitespace-only body is an error, even with `tags: [draft]` or a description. This includes folder and homepage notes. A nonempty body with fewer than 25 prose words produces a warning unless the note has a `draft` tag. See [note states](../reference/format-details.md#three-states-of-a-note).
|
|
@@ -41,7 +41,7 @@ One body describes the subject for both systems. A being's `{#appearance}` and `
|
|
|
41
41
|
|
|
42
42
|
## Place governments
|
|
43
43
|
|
|
44
|
-
A place may state its governing affiliation in `data.government`.
|
|
44
|
+
A place may state its governing affiliation in `data.government`. The field type is `Address`, with `affiliation` as the default target type when the type is omitted. Use either a local shortcode or a fully qualified affiliation Address from this package or a fetched dependency:
|
|
45
45
|
|
|
46
46
|
```yaml
|
|
47
47
|
data:
|
|
@@ -58,7 +58,7 @@ Write `government: null` for **complete anarchy**. Omitting the key leaves gover
|
|
|
58
58
|
| Any | Explicit `null` | None; complete anarchy |
|
|
59
59
|
| Any | Affiliation Address | None; the reference must resolve |
|
|
60
60
|
|
|
61
|
-
These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `domains`, `parents`, containment and capitals do not supply a government.
|
|
61
|
+
These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `domains`, `parents`, containment and capitals do not supply a government. The generated `governed_by` and `governed_places` lists use only explicit government references. Legacy affiliation `data.domains` is accepted temporarily but ignored; record any distinct ownership or influence in prose. See [government migration](../guides/government-migration.md).
|
|
62
62
|
|
|
63
63
|
## Publication and summaries
|
|
64
64
|
|