@heroiclands/package-build 25.5.4 → 25.6.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 +40 -0
- package/README.md +7 -0
- package/assets/styles/content-base.css +1 -1
- package/bin/content-commands.mjs +32 -8
- package/docs/api.md +81 -32
- package/docs/authoring/frontmatter.md +1 -1
- package/docs/authoring/links-and-markup.md +59 -10
- package/docs/commands.md +60 -17
- package/docs/configuration.md +3 -2
- package/docs/content-format.md +50 -1
- package/docs/diagnostics.md +17 -0
- package/docs/guides/module-project.md +11 -3
- package/docs/guides/reference-pages.md +4 -1
- package/docs/guides/site.md +13 -3
- package/docs/guides/writing-in-invented-scripts.md +5 -2
- package/docs/reference/format-details.md +233 -138
- package/docs/reference/note-types.md +165 -152
- package/docs/reference/theme-pages.md +1 -0
- package/e2e.mjs +1 -1
- package/engine/base-compiler.mjs +2 -0
- package/engine/compile-corpus.mjs +6 -2
- package/engine/content-charset.mjs +1 -1
- package/engine/content-format.yaml +9 -7
- package/engine/content-html.mjs +3 -2
- package/engine/content-index.mjs +23 -0
- package/engine/content-links.mjs +8 -0
- package/engine/content-render.mjs +14 -2
- package/engine/content-scripts.mjs +44 -6
- package/engine/content-session.mjs +11 -7
- package/engine/content-spans.mjs +3 -4
- package/engine/content-tables.mjs +12 -5
- package/engine/content-verse.mjs +52 -10
- package/engine/core-report.mjs +27 -18
- package/engine/culture-reach.mjs +3 -0
- package/engine/declared-sections.mjs +100 -0
- package/engine/derived-sections.mjs +36 -2
- package/engine/dictionary-rows.mjs +2 -1
- package/engine/generated-sections.mjs +2 -0
- package/engine/holdings.mjs +107 -3
- package/engine/index-records.mjs +3 -1
- package/engine/index.mjs +1 -1
- package/engine/language-data.mjs +0 -1
- package/engine/language-names.mjs +53 -23
- package/engine/language-rows.mjs +1 -3
- package/engine/language-terms.mjs +7 -10
- package/engine/map-dot.mjs +22 -0
- package/engine/markdown-blocks.mjs +23 -8
- package/engine/markdownlint-run.mjs +1 -1
- package/engine/markup-validation.mjs +2 -0
- package/engine/metadata-index.mjs +1 -0
- package/engine/note-addresses.mjs +16 -0
- package/engine/note-vocabulary.mjs +29 -13
- package/engine/npc-generate.mjs +52 -7
- package/engine/office-holders.mjs +76 -0
- package/engine/page-breaks.mjs +143 -0
- package/engine/pdf-build.mjs +12 -4
- package/engine/pdf-render.mjs +12 -2
- package/engine/place-kinds.mjs +106 -0
- package/engine/preview-index.mjs +4 -2
- package/engine/settlement-tables.mjs +410 -675
- package/engine/settlement-terms.mjs +118 -0
- package/engine/site-build.mjs +14 -7
- package/engine/site-preview.mjs +3 -0
- package/engine/site-render.mjs +18 -4
- package/engine/site-root.mjs +10 -1
- package/engine/site-serve-http.mjs +151 -0
- package/engine/site-serve.mjs +196 -126
- package/engine/sql-tables.mjs +101 -7
- package/engine/standing-terms.mjs +9 -5
- package/engine/standings.mjs +83 -31
- package/engine/unique-items.mjs +85 -0
- package/engine/verse-metre.mjs +50 -5
- package/engine/verse-regions.mjs +16 -0
- package/package.json +9 -4
- package/site-theme/data/banner-kinds.yaml +2 -0
- package/sohl/actors.mjs +4 -3
- package/types/e2e.d.mts +1 -1
- package/types/engine/content-html.d.mts +2 -1
- package/types/engine/content-scripts.d.mts +9 -1
- package/types/engine/content-verse.d.mts +11 -2
- package/types/engine/core-report.d.mts +6 -2
- package/types/engine/culture-reach.d.mts +3 -0
- package/types/engine/declared-sections.d.mts +30 -0
- package/types/engine/derived-sections.d.mts +5 -1
- package/types/engine/holdings.d.mts +34 -2
- package/types/engine/index-records.d.mts +2 -1
- package/types/engine/language-names.d.mts +18 -6
- package/types/engine/language-terms.d.mts +5 -1
- package/types/engine/markdown-blocks.d.mts +5 -1
- package/types/engine/npc-generate.d.mts +3 -0
- package/types/engine/office-holders.d.mts +33 -0
- package/types/engine/page-breaks.d.mts +38 -0
- package/types/engine/pdf-render.d.mts +2 -0
- package/types/engine/place-kinds.d.mts +18 -0
- package/types/engine/settlement-tables.d.mts +25 -158
- package/types/engine/settlement-terms.d.mts +53 -0
- package/types/engine/site-build.d.mts +3 -1
- package/types/engine/site-render.d.mts +6 -2
- package/types/engine/site-root.d.mts +3 -1
- package/types/engine/site-serve-http.d.mts +1 -0
- package/types/engine/site-serve.d.mts +12 -6
- package/types/engine/sql-tables.d.mts +35 -3
- package/types/engine/standing-terms.d.mts +3 -2
- package/types/engine/standings.d.mts +14 -2
- package/types/engine/unique-items.d.mts +12 -0
- package/types/engine/verse-metre.d.mts +2 -1
- package/types/engine/verse-regions.d.mts +8 -0
- package/vendor/markdownlint.mjs +855 -569
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 25.6.0
|
|
4
|
+
|
|
5
|
+
**Changes to act on**
|
|
6
|
+
|
|
7
|
+
- Note queries and a language note's `scope` select notes by property, tag or address; a query that reads `file.path`, `file.folder` or `file.name`, or a scope that lists `paths`, is an error at its position.
|
|
8
|
+
- A scenario no longer takes `data.status`, and a note that still writes it fails the build; mark an unfinished scenario with the `draft` tag instead.
|
|
9
|
+
- A region's settlement table comes from its frontmatter on the website, in Foundry and in books, and a table still written in the body must move there. It needs no holding-model tag, and shows a Held by column only where a row names its holder by address.
|
|
10
|
+
|
|
11
|
+
**New**
|
|
12
|
+
|
|
13
|
+
- Places can be districts, such as a city's quarter or a kingdom's shire, standing within a settlement or a region and falling under its government unless they name their own.
|
|
14
|
+
- Places can be routes, such as a road, a pass or a sea lane, with the journeys along them.
|
|
15
|
+
- An affiliation's page lists who holds each of its offices, drawn from the living beings that name the office, and the content index carries the same list.
|
|
16
|
+
- A being can hold several posts in one body by listing them under `office`.
|
|
17
|
+
- Gear can be marked `unique: true` for a one-of-a-kind item; such an item's note must link a place or a being.
|
|
18
|
+
- A language or spelling guide can declare a written mark of kind `quality`, for a mark that changes which vowel is said rather than how long it is held.
|
|
19
|
+
- A quotation typed with `<<` and `>>` draws no raw-HTML warning.
|
|
20
|
+
|
|
21
|
+
## 25.5.5
|
|
22
|
+
|
|
23
|
+
**Languages and scripts**
|
|
24
|
+
|
|
25
|
+
- Ch'alish P'ilam Ceremonial text passes character checks and is recognized as native script alongside Common.
|
|
26
|
+
- Core vocabulary reports name the languages left unmeasured, including when no language opts into coverage.
|
|
27
|
+
- Generated NPC names capitalize their name words for English prose while keeping connecting words as written.
|
|
28
|
+
- Distinct source names keep their authored spelling under the culture's language code, except when the selected pattern draws English words.
|
|
29
|
+
- The language reference explains that Roman inventories list language additions and refuse shared punctuation and whitespace in the list.
|
|
30
|
+
- A language can supply one list of given names for everyone; NPC generation draws from it for every gender.
|
|
31
|
+
|
|
32
|
+
**Verse**
|
|
33
|
+
|
|
34
|
+
- Metre checks allow multi-syllable function words to go unstressed, so lines can scan without placing a beat on every particle or pronoun.
|
|
35
|
+
- Verse inside blockquotes and nested lists keeps its line breaks, stanza boundaries and indentation, with findings located at the authored text.
|
|
36
|
+
- Verse metre checks count a linked name's visible words without adding beats from its address.
|
|
37
|
+
|
|
38
|
+
**Rendering and sites**
|
|
39
|
+
|
|
40
|
+
- A book can break the page at a chosen point with `--- {.page-break}`.
|
|
41
|
+
- Website previews start immediately, keep the last successful pages available during rebuilds, and report progress while building pages and search.
|
|
42
|
+
|
|
3
43
|
## 25.5.4
|
|
4
44
|
|
|
5
45
|
**Builds and commands**
|
package/README.md
CHANGED
|
@@ -53,6 +53,13 @@ repository’s setup installs the two canonical shell hooks; it installs no
|
|
|
53
53
|
pre-push hook. Run `npm test` and the other checks directly, or use
|
|
54
54
|
`package-build ci` for a container run.
|
|
55
55
|
|
|
56
|
+
The repository's `vitest.config.ts` limits both `npm test` and `npm run
|
|
57
|
+
test:watch` to two workers, with Vitest's isolated fork pool. CI runs the same
|
|
58
|
+
`npm test` command. This bounds concurrent test files on the shared runner,
|
|
59
|
+
including files that start CLI subprocesses, load SQL databases, or emit
|
|
60
|
+
TypeScript declarations. Keep this bound when reproducing CI failures locally;
|
|
61
|
+
a percentage of the host's CPUs does not reserve resources for other jobs.
|
|
62
|
+
|
|
56
63
|
## Documentation
|
|
57
64
|
|
|
58
65
|
The documentation lives in the Markdown files in this repository. Start with [the documentation home](docs/index.md). This toolchain does not build its own site or book.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* It carries what every package's compiled content needs to read in Foundry as
|
|
19
19
|
* it does in the preview and on the site: definition lists, verse, alerts,
|
|
20
|
-
* inline spoilers,
|
|
20
|
+
* inline spoilers, unresolved links, captioned blocks and
|
|
21
21
|
* highlighted code. Every
|
|
22
22
|
* class the Foundry renderer emits is styled here or exempted by name in
|
|
23
23
|
* `tests/base-styles.test.ts`. A package keeps its own stylesheet for its own
|
package/bin/content-commands.mjs
CHANGED
|
@@ -1289,7 +1289,12 @@ function lintCommand() {
|
|
|
1289
1289
|
// Text marked with a language, a font or a map, checked against
|
|
1290
1290
|
// the languages this package declares, the faces it installed
|
|
1291
1291
|
// and the maps its notes declare.
|
|
1292
|
-
const runs = runContext(config, records
|
|
1292
|
+
const runs = runContext(config, records, {
|
|
1293
|
+
referenceName: (target) => {
|
|
1294
|
+
const hit = index.resolveAddress(target) ?? index.manifestHit(target);
|
|
1295
|
+
return hit?.fm?.name?.full ?? hit?.name;
|
|
1296
|
+
},
|
|
1297
|
+
});
|
|
1293
1298
|
const loaderLocations = new Set(
|
|
1294
1299
|
(runs.encodingFindings ?? []).map((one) =>
|
|
1295
1300
|
JSON.stringify([one.file, one.line, one.column, one.message]),
|
|
@@ -2346,7 +2351,11 @@ function siteBuildCommand() {
|
|
|
2346
2351
|
const config = argv[CONTENT_CONFIG] ?? loadPackConfig();
|
|
2347
2352
|
const root = path.resolve(config.rootDir, argv.out ?? DEPLOY_ROOT);
|
|
2348
2353
|
const out = siteDirectory(config, root);
|
|
2349
|
-
const result = await buildPackageSite({
|
|
2354
|
+
const result = await buildPackageSite({
|
|
2355
|
+
config,
|
|
2356
|
+
out,
|
|
2357
|
+
progress: (message) => log.info(message),
|
|
2358
|
+
});
|
|
2350
2359
|
// A note in error is written as its page shows it, and the
|
|
2351
2360
|
// build fails without indexing a site that is not to be
|
|
2352
2361
|
// deployed.
|
|
@@ -2374,6 +2383,7 @@ function siteBuildCommand() {
|
|
|
2374
2383
|
base: siteBase(config),
|
|
2375
2384
|
out: root,
|
|
2376
2385
|
search: config.site.search,
|
|
2386
|
+
progress: (message) => log.info(message),
|
|
2377
2387
|
});
|
|
2378
2388
|
if (search) {
|
|
2379
2389
|
log.info(
|
|
@@ -2429,8 +2439,10 @@ function siteServeCommand() {
|
|
|
2429
2439
|
host: argv.host,
|
|
2430
2440
|
port: argv.port,
|
|
2431
2441
|
report: (event) => {
|
|
2432
|
-
if (event.kind === "
|
|
2433
|
-
else if (event.kind === "
|
|
2442
|
+
if (event.kind === "progress") log.info(event.message);
|
|
2443
|
+
else if (event.kind === "error") {
|
|
2444
|
+
if (!event.fatal) reportFailure(event.error);
|
|
2445
|
+
} else if (event.kind === "failed") {
|
|
2434
2446
|
if (event.built) reportSiteBuild(event.built);
|
|
2435
2447
|
for (const finding of event.findings ?? []) emitDiagnostic(finding);
|
|
2436
2448
|
} else {
|
|
@@ -2444,11 +2456,22 @@ function siteServeCommand() {
|
|
|
2444
2456
|
},
|
|
2445
2457
|
});
|
|
2446
2458
|
log.info(`serving ${served.url} — interrupt to stop`);
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2459
|
+
let interrupt;
|
|
2460
|
+
const interrupted = new Promise((resolve) => {
|
|
2461
|
+
interrupt = resolve;
|
|
2462
|
+
process.once("SIGINT", interrupt);
|
|
2463
|
+
process.once("SIGTERM", interrupt);
|
|
2450
2464
|
});
|
|
2451
|
-
|
|
2465
|
+
try {
|
|
2466
|
+
await Promise.race([interrupted, served.done]);
|
|
2467
|
+
} catch (err) {
|
|
2468
|
+
reportFailure(err);
|
|
2469
|
+
process.exitCode = 1;
|
|
2470
|
+
} finally {
|
|
2471
|
+
process.removeListener("SIGINT", interrupt);
|
|
2472
|
+
process.removeListener("SIGTERM", interrupt);
|
|
2473
|
+
await served.close();
|
|
2474
|
+
}
|
|
2452
2475
|
} catch (err) {
|
|
2453
2476
|
reportFailure(err);
|
|
2454
2477
|
process.exitCode = 1;
|
|
@@ -3467,6 +3490,7 @@ function newNpc(config, argv) {
|
|
|
3467
3490
|
profile,
|
|
3468
3491
|
names,
|
|
3469
3492
|
language: languageKey,
|
|
3493
|
+
languageCode: code,
|
|
3470
3494
|
seed: argv.seed,
|
|
3471
3495
|
currentDate: config.currentDate,
|
|
3472
3496
|
dateContext: reckoningContext(index),
|
package/docs/api.md
CHANGED
|
@@ -496,13 +496,15 @@ What a place is next to (`data.borders`) and reachable from (`data.routes`): the
|
|
|
496
496
|
|
|
497
497
|
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 lists a note's generated **Within**, **Governed by** and **Governed places** sections show — and the population-based government advisory `package-build lint` runs on a place.
|
|
498
498
|
|
|
499
|
-
| Export
|
|
500
|
-
|
|
|
501
|
-
| `holdingsNode`
|
|
502
|
-
| `foreignHoldingsNodes`
|
|
503
|
-
| `holdingsPages`
|
|
504
|
-
| `shortcodesOf`
|
|
505
|
-
| `checkGovernment`
|
|
499
|
+
| Export | Signature | Returns | Use it when |
|
|
500
|
+
| ---------------------------- | -------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
501
|
+
| `holdingsNode` | `holdingsNode(fm, { title, url, package, system, canonical })` | `HoldingsNode\|null` | reading a local note as a node of the derivation, or `null` for one that is neither a place nor an affiliation |
|
|
502
|
+
| `foreignHoldingsNodes` | `foreignHoldingsNodes(foreignIndex)` | `HoldingsNode[]` | reading a fetched index's places and affiliations as nodes |
|
|
503
|
+
| `holdingsPages` | `holdingsPages(nodes, { governmentNodes })` | `Map<string, Holdings>` | inverting `parents` and resolved explicit `government` into each node's sorted lists, keyed by its `url`, for every node with a `url` and an entry |
|
|
504
|
+
| `shortcodesOf` | `shortcodesOf(value)` | `string[]` | the shortcodes a `parents` value names — bare or qualified Addresses — empties dropped and repeats collapsed |
|
|
505
|
+
| `checkGovernment` | `checkGovernment(note)` | `object[]` | warning at `data.population` for positive population with no `data.government` key, own or inherited; explicit null means anarchy |
|
|
506
|
+
| `inheritDistrictGovernments` | `inheritDistrictGovernments(records, { foreignRecord })` | `void` | giving each district record that states no `data.government` the value of its nearest parent that states one, as the content index does |
|
|
507
|
+
| `governmentInherited` | `governmentInherited(record)` | `boolean` | asking whether a district record's `data.government` came from a parent rather than its own note |
|
|
506
508
|
|
|
507
509
|
An entry carries the listed note's `title`, its `address` in the `note` system, its `type` and `subType`, and its `url` where the note has one. A node with no `url` — a stub — is listed by others and carries no list of its own. Records passed as `governmentNodes` take part in government alone, never in geography.
|
|
508
510
|
|
|
@@ -531,16 +533,18 @@ What trade a settlement supports (`data.market`): the six-step scale, stated onc
|
|
|
531
533
|
|
|
532
534
|
### `engine.settlementTables`
|
|
533
535
|
|
|
534
|
-
A region
|
|
536
|
+
A region declares its rows in indexed `data.settlements`. The guard checks populations, markets, holders and regional coverage, and refuses authored body tables. Every publishing surface uses the same generated table, retaining the canonical `#settlements` heading or filling the author's existing section.
|
|
535
537
|
|
|
536
|
-
| Export
|
|
537
|
-
|
|
|
538
|
-
| `
|
|
539
|
-
| `
|
|
540
|
-
| `
|
|
541
|
-
| `
|
|
542
|
-
| `
|
|
543
|
-
| `
|
|
538
|
+
| Export | Signature | Returns | Use it when |
|
|
539
|
+
| ------------------------- | ------------------------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
540
|
+
| `SETTLEMENT_COLUMNS` | `const SETTLEMENT_COLUMNS` | `readonly object[]` | the table's columns in header order, each its `name` and whether it is `required`; an optional one appears when a row states it |
|
|
541
|
+
| `SETTLEMENTS_HEADING` | `const SETTLEMENTS_HEADING` | `string` | the generated settlements heading |
|
|
542
|
+
| `SETTLEMENT_TABLE_RULES` | `const SETTLEMENT_TABLE_RULES` | `readonly object[]` | the rules in order, each its `name` — the prefix its findings carry — and what it `describe`s |
|
|
543
|
+
| `settlementMarkdown` | `settlementMarkdown(record)` | `string` | rendering indexed rows as the shared table |
|
|
544
|
+
| `assertSettlementRecords` | `assertSettlementRecords(records, { fileOf, rawOf, foreignIndex })` | `void` | refusing invalid indexed rows before publication |
|
|
545
|
+
| `SETTLEMENTS_FIELD` | `const SETTLEMENTS_FIELD` | `object` | the vocabulary declaration for rows and tail |
|
|
546
|
+
| `SETTLEMENT_ROW_FIELDS` | `const SETTLEMENT_ROW_FIELDS` | `readonly object[]` | the closed row declaration |
|
|
547
|
+
| `checkSettlementTables` | `checkSettlementTables(note, { index })` | `object[]` | linting a place note's settlements tables against the corpus the index holds |
|
|
544
548
|
|
|
545
549
|
### `engine.mapPlaces`
|
|
546
550
|
|
|
@@ -1329,12 +1333,30 @@ content tree can also compile into Foundry compendium packs.
|
|
|
1329
1333
|
| `renderPages` | `function renderPages(pages, options)` | `{{written: number, byKind: Record<string, number>, tableErrors: object[], wikiErrors: object[]}}` | Renders every page. |
|
|
1330
1334
|
| `resolveSitePass` | `function resolveSitePass(name, options)` | `{{beforeLinks?: Function}}` The bundle. | Resolves `site.pass` to its bundle. |
|
|
1331
1335
|
| `sitePageDecorator` | `sitePageDecorator(config, index)` | Function | Add the site's infobox and being metadata to a rendered page. |
|
|
1332
|
-
| `buildSite` | `buildSite({ config, sqlTables })`
|
|
1336
|
+
| `buildSite` | `buildSite({ config, sqlTables, progress })` | `{{gates: object, stats: object\|null, tableErrors: object[], wikiErrors: object[], mapFindings: object[], manifests: object\|null, site?: object}}` | Collects, checks and renders a content tree's pages, and reports what it found; returns each page for the site's renderer. |
|
|
1333
1337
|
|
|
1334
1338
|
`siteGates` takes `{ config, records, sqlTables? }`. Pass the prepared
|
|
1335
1339
|
`sqlTables` map so anchors emitted by automatic dictionary sections are present in the
|
|
1336
1340
|
index for checking page links.
|
|
1337
1341
|
|
|
1342
|
+
`buildSite`, `engine/site-render.mjs`'s `buildPackageSite` and `writeSite`, and
|
|
1343
|
+
`engine/site-root.mjs`'s `writeSiteRoot` accept an optional `progress(message)`
|
|
1344
|
+
callback for phase summaries. It receives prose, independently of findings.
|
|
1345
|
+
|
|
1346
|
+
`engine/site-serve.mjs`'s `serveSite({ config, out, root?, host?, port?, search?,
|
|
1347
|
+
year?, report? })` resolves with `{ url, settled, close, done }` when HTTP listens,
|
|
1348
|
+
before the initial build. Await `settled()` to wait for that build and queued
|
|
1349
|
+
edits, and `close()` to stop watching and serving. `done` resolves on close;
|
|
1350
|
+
an unexpected HTTP failure rejects it and stops the watchers. Its `report` callback
|
|
1351
|
+
receives `progress` events with a `message`, alongside `built`, `page`,
|
|
1352
|
+
`theme`, `failed` and `error` events; a fatal HTTP error has `fatal: true`.
|
|
1353
|
+
Failed builds are reported through that
|
|
1354
|
+
callback and leave the previous output in service. HTTP runs in a separate
|
|
1355
|
+
thread so synchronous rendering does not stall requests; the resolved
|
|
1356
|
+
configuration and incremental render state stay in the calling thread. Every
|
|
1357
|
+
update is prepared in a separate output tree, then installed between HTTP
|
|
1358
|
+
requests so readers receive complete files.
|
|
1359
|
+
|
|
1338
1360
|
### `engine.contentRender`
|
|
1339
1361
|
|
|
1340
1362
|
`createRenderer(target, options?)` builds the one markdown-it configuration every target renders through. `target` is `"foundry"`, `"web"`, `"preview"` or `"book"`. The renderer holds the configured parser (`md`), the names of the plugins installed (`plugins`), and three functions: `prepare` writes the constructs markdown-it has no syntax for — marked text, captioned items, named blocks, verse and alerts — as HTML between blank lines; `render` prepares and renders to HTML; `renderInline` renders one inline run. The `book` target parses only, and its Typst stage reads the tokens.
|
|
@@ -1362,6 +1384,16 @@ complete source. Reference-only positions contribute no work shape. A wholly
|
|
|
1362
1384
|
reference-only body carries its references in `model.notes`, rendered once
|
|
1363
1385
|
outside native-font wrappers without a verse row or label.
|
|
1364
1386
|
|
|
1387
|
+
Verse regions retain the authored `body` and its absolute `bodyStart` and
|
|
1388
|
+
`bodyEnd`. Their `logicalBody` excludes Markdown list and blockquote prefixes;
|
|
1389
|
+
`bodyOffsets` maps each logical UTF-16 position, including the exclusive end,
|
|
1390
|
+
back to an authored body offset. `parseVerse(logicalBody, {sourceOffsets:
|
|
1391
|
+
bodyOffsets, footnotes})` returns the whole model in authored body coordinates:
|
|
1392
|
+
line bounds and character offsets, stanza and canto bounds, boundaries, layout
|
|
1393
|
+
ranges and findings all use that map. Omitted prefixes are layout ranges, so
|
|
1394
|
+
Roman and native projections exclude them. Add `bodyStart` to a model offset to
|
|
1395
|
+
locate it in the complete source. LF and CRLF retain their authored lengths.
|
|
1396
|
+
|
|
1365
1397
|
| Export | Signature | Returns | Use it when |
|
|
1366
1398
|
| ---------------- | ---------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
|
|
1367
1399
|
| `createRenderer` | `createRenderer(target, options?)` | `{ target, md, plugins, prepare, render, renderInline }` | Rendering a note body for one target with the rules every target shares. |
|
|
@@ -1446,17 +1478,17 @@ The charset authored content is held to, so a book can choose its face. The pack
|
|
|
1446
1478
|
|
|
1447
1479
|
### `engine.romanCharacters`
|
|
1448
1480
|
|
|
1449
|
-
|
|
1450
|
-
encoding. Inventories come from `data.roman` on each language's own note.
|
|
1481
|
+
A configured language's Roman additions to the shared punctuation standard,
|
|
1482
|
+
before script encoding. Inventories come from `data.roman` on each language's own note.
|
|
1451
1483
|
|
|
1452
|
-
| Export | Signature | Returns | Use it when
|
|
1453
|
-
| ------------------------- | -------------------------------------------- | ----------------------------- |
|
|
1454
|
-
| `isRomanWhitespace` | `isRomanWhitespace(char)` | `boolean` | recognizing standard spaces and ASCII tab or line whitespace
|
|
1455
|
-
| `romanInventoryProblems` | `romanInventoryProblems(value)` | `string[]` | checking NFC,
|
|
1456
|
-
| `romanInventoriesOf` | `romanInventoriesOf(records, languages)` | `Map<string, RomanInventory>` | looking up a configured language's own inventory by name or BCP 47 tag
|
|
1457
|
-
| `romanTextProblems` | `romanTextProblems(text, inventory, stream)` | `{offset, message}[]` | validating standard Roman punctuation and language additions with exact UTF-16 offsets; pass a `stream` state to continue sentences and quotations from earlier runs
|
|
1458
|
-
| `romanPunctuationState` | `romanPunctuationState()` | `{sentenceStart, quotes}` | starting a stream of runs whose sentences and quotations continue from one run to the next
|
|
1459
|
-
| `romanUnclosedQuotations` | `romanUnclosedQuotations(quotes)` | `{offset, message}[]` | reporting the quotations still open where a stream of runs ends
|
|
1484
|
+
| Export | Signature | Returns | Use it when |
|
|
1485
|
+
| ------------------------- | -------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1486
|
+
| `isRomanWhitespace` | `isRomanWhitespace(char)` | `boolean` | recognizing standard spaces and ASCII tab or line whitespace |
|
|
1487
|
+
| `romanInventoryProblems` | `romanInventoryProblems(value)` | `string[]` | checking NFC, repeats and forbidden whitespace, controls, standard punctuation, literal markers, semicolons, colons, English double quotes and setting-script characters |
|
|
1488
|
+
| `romanInventoriesOf` | `romanInventoriesOf(records, languages)` | `Map<string, RomanInventory>` | looking up a configured language's own inventory by name or BCP 47 tag |
|
|
1489
|
+
| `romanTextProblems` | `romanTextProblems(text, inventory, stream)` | `{offset, message}[]` | validating standard Roman punctuation and language additions with exact UTF-16 offsets; pass a `stream` state to continue sentences and quotations from earlier runs |
|
|
1490
|
+
| `romanPunctuationState` | `romanPunctuationState()` | `{sentenceStart, quotes}` | starting a stream of runs whose sentences and quotations continue from one run to the next |
|
|
1491
|
+
| `romanUnclosedQuotations` | `romanUnclosedQuotations(quotes)` | `{offset, message}[]` | reporting the quotations still open where a stream of runs ends |
|
|
1460
1492
|
|
|
1461
1493
|
### `engine.pathCharset`
|
|
1462
1494
|
|
|
@@ -1491,6 +1523,10 @@ Naming an interface icon in a note, without drawing it there. The user guide des
|
|
|
1491
1523
|
|
|
1492
1524
|
Raw HTML in a note's prose, reported. **A note is markdown.** What markdown cannot say, a note does not say — it gets a construct every surface can render, the way `:icon …:` replaces a pasted glyph.
|
|
1493
1525
|
|
|
1526
|
+
`HTML_TAG` excludes the doubled `<<` that opens a typed quotation. A quotation
|
|
1527
|
+
written with `<<` and `>>` draws no raw-HTML warning; adjacent real tags retain
|
|
1528
|
+
their findings and positions.
|
|
1529
|
+
|
|
1494
1530
|
| Export | Signature | Returns | Use it when |
|
|
1495
1531
|
| ----------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
1496
1532
|
| `HTML_TAG` | `const HTML_TAG` | — | A raw HTML tag, opening, closing or self-closing. |
|
|
@@ -2573,6 +2609,16 @@ points derive their own inputs. Generation and pack compilation accept
|
|
|
2573
2609
|
`reportPreparation` (default true); a coordinating caller may set it false
|
|
2574
2610
|
only after reporting the shared source findings itself.
|
|
2575
2611
|
|
|
2612
|
+
`engine/content-scripts` exposes `runContext(config, records?, {referenceName}?)`.
|
|
2613
|
+
It returns the language, encoding and metre context used by run scanning.
|
|
2614
|
+
`referenceName(target)` supplies the rendering or validation index's current
|
|
2615
|
+
name for an Address, including dependency targets, or `undefined` when none
|
|
2616
|
+
resolves. This lookup takes precedence over the local-record fallback and
|
|
2617
|
+
belongs only to the returned context; shared cached lexical data does not
|
|
2618
|
+
share a lookup between page or audience views. A metre line whose empty link
|
|
2619
|
+
label has no resolved spoken text stays unscanned, while the link validator
|
|
2620
|
+
reports invalid targets independently.
|
|
2621
|
+
|
|
2576
2622
|
`buildLinkIndex` and `buildContentLinkIndex` accept an optional `foreign` view
|
|
2577
2623
|
from the same session; their diagnostic and routed resolver contracts remain
|
|
2578
2624
|
distinct. `collectAnchors`, `markupAnchorFindings`, `markupFindings`, journal
|
|
@@ -2922,10 +2968,13 @@ const inferred = encode(data, null, "say", { enc: "aelwsemaronenc" });
|
|
|
2922
2968
|
|
|
2923
2969
|
Both functions take `(data, language, text, options?)` and return
|
|
2924
2970
|
`{text, findings}`; encoding with a language also returns source-positioned
|
|
2925
|
-
`pieces`.
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2971
|
+
`pieces`. `options.enc` selects a consumer-authored encoding document, which
|
|
2972
|
+
supplies its language and font. An explicit language must agree with that
|
|
2973
|
+
document; a null or omitted language infers it and uses its lexical inputs.
|
|
2974
|
+
`options.font` must agree with the encoding's font; `options.verse` asks the
|
|
2975
|
+
encoder to interpret verse structure. An omitted `enc`, or `enc: "default"`,
|
|
2976
|
+
preserves the Roman text. Bare conversion without lexical inputs uses the
|
|
2977
|
+
pure `encodeText` and `decodeText` functions in `engine/encoding.mjs`.
|
|
2929
2978
|
|
|
2930
2979
|
Language conversion uses the same pure `encodeWithLanguage` and
|
|
2931
2980
|
`decodeWithLanguage` functions as the build. Recorded native writings and
|
|
@@ -2933,7 +2982,7 @@ parts precede encoding rows, and decoding can recover an unmarked word from
|
|
|
2933
2982
|
the lexicon. An unknown word gives a positioned finding. A bare refusal
|
|
2934
2983
|
returns empty text and an error finding. Findings carry `severity`, `message`,
|
|
2935
2984
|
`offset` (UTF-16), and one-based Unicode-code-point `line` and `column`.
|
|
2936
|
-
Invalid data, unknown languages and
|
|
2985
|
+
Invalid data, unknown languages and unknown encoding selections throw an
|
|
2937
2986
|
error before conversion. `validateData(data)` returns the validated data or
|
|
2938
2987
|
throws; it opens no files.
|
|
2939
2988
|
|
|
@@ -117,7 +117,7 @@ Write `government: null` for **complete anarchy**. Omitting the key leaves gover
|
|
|
117
117
|
| Any | Explicit `null` | None; complete anarchy |
|
|
118
118
|
| Any | Affiliation Address | None; the reference must resolve |
|
|
119
119
|
|
|
120
|
-
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. `parents`, containment and capitals do not supply a government. The generated **Governed by** and **Governed places** sections use
|
|
120
|
+
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. `parents`, containment and capitals do not supply a government, with one exception: a `district` that omits the key falls under the government of its nearest parent that states one, and is treated as stating that value, so it receives no advisory. An explicit value on the district, `null` included, is its own. The generated **Governed by** and **Governed places** sections use the explicit references and these inherited ones.
|
|
121
121
|
|
|
122
122
|
## Publication and summaries
|
|
123
123
|
|
|
@@ -237,6 +237,30 @@ A captioned item inside the section is withheld with it: in Foundry the item's o
|
|
|
237
237
|
|
|
238
238
|
The special Actor anchors `{#appearance}` and `{#dossier}` feed the same authored sections to each system's Actor fields, and take an H1 only — not the lower-level heading a journal page may otherwise start from. The section runs to the next H1, nested headings included. An anchor declared on a lower heading is still found, and is a build error rather than a quietly empty field: move the heading to the top level, or drop the anchor if the section is meant to stay unaddressed prose.
|
|
239
239
|
|
|
240
|
+
## Book page breaks
|
|
241
|
+
|
|
242
|
+
Write `--- {.page-break}` on its own line between blocks, with blank lines around it:
|
|
243
|
+
|
|
244
|
+
```markdown
|
|
245
|
+
The first passage ends here.
|
|
246
|
+
|
|
247
|
+
--- {.page-break}
|
|
248
|
+
|
|
249
|
+
The next passage starts on a fresh book page.
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The book starts a fresh page without drawing a rule. If the marker already
|
|
253
|
+
falls at the top of a page, it adds no blank page. The website, Foundry and
|
|
254
|
+
both editor preview views omit the marker. Plain `---`, `***` and `___` keep
|
|
255
|
+
their ordinary horizontal rules. Code blocks and verse divs keep the marker
|
|
256
|
+
as literal text.
|
|
257
|
+
|
|
258
|
+
Only `---` accepts `.page-break`; `*** {.page-break}` and `___ {.page-break}`
|
|
259
|
+
are findings. Other classes, ids and attributes on an attributed `---` line
|
|
260
|
+
are findings too. A page break stands between blocks at the top level of a
|
|
261
|
+
note: putting one inside a list, block quote, alert, footnote definition,
|
|
262
|
+
secret block or fenced div is a finding at the marker's line and column.
|
|
263
|
+
|
|
240
264
|
## Captions and numbered references
|
|
241
265
|
|
|
242
266
|
Write a caption on its own line **before** the item it describes, with a blank line before and after the caption. `:` produces an unnumbered caption; `:@` produces a numbered caption. One or more spaces separate the marker from its text. An optional attribute block at the end accepts an identifier, classes and named attributes:
|
|
@@ -424,6 +448,20 @@ Periods inside the first inline span can set indentation; periods in later spans
|
|
|
424
448
|
are literal. Tabs inside a verse div are errors. The div body is opaque to Markdown block syntax:
|
|
425
449
|
lines beginning `- `, `1. `, `# `, `> ` or four spaces stay verse text.
|
|
426
450
|
|
|
451
|
+
A verse div may sit inside a blockquote, a list item, or nested combinations of
|
|
452
|
+
both. Write the surrounding container prefix on each line, including blank
|
|
453
|
+
stanza lines. Container markers stay outside the verse text; logical lines,
|
|
454
|
+
indentation and stanza boundaries follow the same rules as a standalone div.
|
|
455
|
+
Findings point to the authored line and column, including its container prefix.
|
|
456
|
+
|
|
457
|
+
```markdown
|
|
458
|
+
> ::: {.verse}
|
|
459
|
+
> One/..Two
|
|
460
|
+
>
|
|
461
|
+
> Three
|
|
462
|
+
> :::
|
|
463
|
+
```
|
|
464
|
+
|
|
427
465
|
These two bodies have the same lines and indentation:
|
|
428
466
|
|
|
429
467
|
```markdown
|
|
@@ -491,13 +529,23 @@ language's stress rules; it reports an error at the line:
|
|
|
491
529
|
Speaker labels and stage directions (`.speaker` and `.direction`) are presentation
|
|
492
530
|
only: their text is not scanned, and a line containing only those spans is skipped.
|
|
493
531
|
|
|
532
|
+
Wikilinks contribute only their visible labels to the beat count. An empty label
|
|
533
|
+
(`[[place-ashkarad|]]`) contributes the indexed target's name, including a name
|
|
534
|
+
from a dependency. Address segments, anchors and link attributes contribute no
|
|
535
|
+
beats. If an empty label has no resolved spoken text, the line is not scanned;
|
|
536
|
+
the link check reports invalid targets separately. Empty same-page caption
|
|
537
|
+
references depend on page or book numbering and leave the line unscanned when
|
|
538
|
+
that display text is unavailable.
|
|
539
|
+
|
|
494
540
|
Beats are counted this way:
|
|
495
541
|
|
|
496
542
|
- **Syllables** are vowel groups. A vowel is a letter whose base is `a`, `e`,
|
|
497
543
|
`i`, `o` or `u`, and a pair the language lists in
|
|
498
544
|
`data.sounds.syllables.vowelPairs` is one syllable.
|
|
499
|
-
- **
|
|
500
|
-
syllable
|
|
545
|
+
- **A word of two or more syllables has one beat**, on its stressed
|
|
546
|
+
syllable, but may go unstressed when every lexicon class is a function class:
|
|
547
|
+
any base other than `n`, `v`, `adj`, `num` or `name`. A word with any content
|
|
548
|
+
class, or no lexicon entry, keeps its beat. The language's stress rule places it: `two` for a word of two
|
|
501
549
|
syllables, `longer` for a word of three or more, and a vowel carrying the
|
|
502
550
|
rule's `mark` is stressed wherever it sits.
|
|
503
551
|
- **A one-syllable noun, verb, adjective, numeral or name has a beat.** A
|
|
@@ -506,7 +554,7 @@ Beats are counted this way:
|
|
|
506
554
|
through `lang=` as it is for the word check, including words inherited from
|
|
507
555
|
its family. All entries for a spelling in the nearest lexicon supply their
|
|
508
556
|
classes. A form the
|
|
509
|
-
language's own rules derive takes its word's class. A word
|
|
557
|
+
language's own rules derive takes its word's class. A one-syllable word with both content and function classes has a
|
|
510
558
|
beat that may be left out.
|
|
511
559
|
- **A one-syllable word the lexicon does not hold is a content word** and has a
|
|
512
560
|
beat. The word check reports the word separately.
|
|
@@ -1490,13 +1538,14 @@ Nested frontmatter is addressed exactly as a note writes it: `name.full`, `sohl.
|
|
|
1490
1538
|
|
|
1491
1539
|
The build adds sections to the end of a note, after everything you wrote, listing what other notes say about it. Each appears only where it has something to list, under a fixed anchor:
|
|
1492
1540
|
|
|
1493
|
-
| Section | Anchor | Lists
|
|
1494
|
-
| ----------------- | ---------------- |
|
|
1495
|
-
| Within | `within` | on a place, the places whose `parents` name it, grouped by kind
|
|
1496
|
-
| Governed by | `governedby` | on a place, the affiliation its `government` names
|
|
1497
|
-
| Governed places | `governedplaces` | on an affiliation, the places naming it as their `government`
|
|
1498
|
-
|
|
|
1499
|
-
|
|
|
1541
|
+
| Section | Anchor | Lists |
|
|
1542
|
+
| ----------------- | ---------------- | ----------------------------------------------------------------------------- |
|
|
1543
|
+
| Within | `within` | on a place, the places whose `parents` name it, grouped by kind |
|
|
1544
|
+
| Governed by | `governedby` | on a place, the affiliation its `government` names |
|
|
1545
|
+
| Governed places | `governedplaces` | on an affiliation, the places naming it as their `government` |
|
|
1546
|
+
| Office holders | `officeholders` | on an affiliation, each office's living holders, from the beings that name it |
|
|
1547
|
+
| In song and story | `insongandstory` | the works of literature whose `subjects` name the note or its events |
|
|
1548
|
+
| From here | `fromhere` | on a place with borders or routes, the map drawn from it |
|
|
1500
1549
|
|
|
1501
1550
|
The event sections below sit among them, and the [format reference](../reference/format-details.md#generated-sections) gives the order. Each entry links to the note it names; a note with no page of its own is named in plain text. Replace a section the way you replace an event view, by writing your own with the same anchor:
|
|
1502
1551
|
|