@heroiclands/package-build 23.8.0 → 23.9.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 +27 -0
- package/bin/content-commands.mjs +12 -4
- package/docs/api.md +328 -28
- package/docs/authoring/first-note.md +1 -1
- package/docs/authoring/links-and-markup.md +140 -56
- package/docs/commands.md +19 -10
- package/docs/content-format.md +2 -2
- package/docs/diagnostics.md +1 -1
- package/docs/guides/packs.md +2 -1
- package/docs/guides/reference-pages.md +86 -63
- package/docs/reference/format-details.md +269 -123
- package/docs/reference/note-types.md +184 -170
- package/engine/anchors.mjs +7 -20
- package/engine/compile-corpus.mjs +3 -2
- package/engine/content-format.yaml +1 -0
- package/engine/content-index.mjs +412 -11
- package/engine/content-links.mjs +43 -15
- package/engine/content-tables.mjs +8 -4
- package/engine/culture-reach.mjs +61 -34
- package/engine/data-keys.mjs +3 -1
- package/engine/dictionary-layout.mjs +151 -19
- package/engine/dictionary-rows.mjs +129 -79
- package/engine/foundry-entries.mjs +21 -3
- package/engine/glossary-entries.mjs +11 -11
- package/engine/heading-attributes.mjs +21 -28
- package/engine/helpers.mjs +12 -6
- package/engine/journals.mjs +4 -1
- package/engine/language-data.mjs +53 -0
- package/engine/language-terms.mjs +86 -0
- package/engine/language-words.mjs +2 -2
- package/engine/lexical-sections.mjs +247 -0
- package/engine/note-claims.mjs +2 -0
- package/engine/note-state.mjs +9 -3
- package/engine/note-vocabulary.mjs +7 -6
- package/engine/pdf-build.mjs +9 -9
- package/engine/site-build.mjs +16 -2
- package/engine/sql-tables.mjs +262 -43
- package/engine/stub-lint.mjs +6 -2
- package/engine/web-wikilinks.mjs +8 -6
- package/engine/word-rows.mjs +20 -12
- package/engine/word-terms.mjs +15 -6
- package/package.json +1 -1
- package/types/engine/content-index.d.mts +65 -1
- package/types/engine/content-tables.d.mts +2 -1
- package/types/engine/culture-reach.d.mts +22 -2
- package/types/engine/data-keys.d.mts +7 -0
- package/types/engine/dictionary-layout.d.mts +35 -4
- package/types/engine/dictionary-rows.d.mts +9 -0
- package/types/engine/foundry-entries.d.mts +3 -1
- package/types/engine/heading-attributes.d.mts +2 -2
- package/types/engine/helpers.d.mts +4 -1
- package/types/engine/language-terms.d.mts +7 -0
- package/types/engine/lexical-sections.d.mts +95 -0
- package/types/engine/note-state.d.mts +2 -1
- package/types/engine/site-build.d.mts +4 -1
- package/types/engine/sql-tables.d.mts +33 -3
- package/types/engine/word-rows.d.mts +9 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 23.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
**Dictionaries and glossaries**
|
|
8
|
+
|
|
9
|
+
- Language dictionaries and declared culture or affiliation glossaries appear automatically in journals, sites and books; remove SQL fences for these defaults.
|
|
10
|
+
- Dictionaries use one full alphabetical list with field tags and one key; existing anchored Dictionary, Lexicon and Glossary headings keep their introductions and receive the lists.
|
|
11
|
+
- Language notes with nonempty `data.words`, and cultures or affiliations with nonempty `data.glossary`, need no prose body; glossary sections show only their owner's declared entries.
|
|
12
|
+
- Glossary entries naming dictionary words show their class and word link, with dictionary senses or the entry's context definition; sole-owner sense labels are omitted on that owner's page, while other attribution remains.
|
|
13
|
+
- Common marks belong only to glossary terms; select or filter `terms.common`, because queries using `dictionary.common` fail.
|
|
14
|
+
- Custom culture views select the culture's own entries and reached ranks or offices, applying common marks only to entries the culture owns.
|
|
15
|
+
- Glossary entries without definitions must name a word in their resolved language or a reachable rank or office; specify the correct language or supply a definition when a name cannot resolve.
|
|
16
|
+
|
|
17
|
+
**Links and publishing**
|
|
18
|
+
|
|
19
|
+
- Correct links to headings inside HTML comments or raw HTML, which publish no section; builds also refuse section links absent from a dependency's published notes, including pages without prose anchors or journal documents.
|
|
20
|
+
- Rebuild and fetch package indexes so dependent packages can link to generated sections and SQL-expression anchors; readable item documentation anchors target their documentation journals.
|
|
21
|
+
- Engine publishers with dynamic content must await `prepareContentIndex` and pass its publication to `emitContentIndex` before writing metadata.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Language dictionaries can show optional noun plurals and one verb pattern beside existing gender labels; languages without these details retain their output.
|
|
26
|
+
- Dictionary fragments without a key omit the verb table; key-only fragments print abbreviations alone.
|
|
27
|
+
- Built words show element senses in dictionary etymologies and pass the built-piece check, including declared variants, inherited elements and front-vowel affix forms.
|
|
28
|
+
- Public dictionaries omit GM-only citations, preventing false link errors from hidden notes.
|
|
29
|
+
|
|
3
30
|
## 23.8.0
|
|
4
31
|
|
|
5
32
|
### Minor Changes
|
package/bin/content-commands.mjs
CHANGED
|
@@ -105,14 +105,19 @@ import { markupFindings } from "../engine/markup-validation.mjs";
|
|
|
105
105
|
import { checkFormatting, checkPrettierConventions, lintMarkdown } from "../engine/prose-lint.mjs";
|
|
106
106
|
import { lintProse, scoreProseTree } from "../engine/readability-lint.mjs";
|
|
107
107
|
import { loadPackageBuildConfig } from "../config.mjs";
|
|
108
|
-
import {
|
|
108
|
+
import {
|
|
109
|
+
emitContentIndex,
|
|
110
|
+
prepareContentIndex,
|
|
111
|
+
indexRecordsFor,
|
|
112
|
+
isAssetRecord,
|
|
113
|
+
} from "../engine/content-index.mjs";
|
|
109
114
|
import {
|
|
110
115
|
buildSite,
|
|
111
116
|
gatesFailed,
|
|
112
117
|
formatUnaddressableFinding as formatUnaddressable,
|
|
113
118
|
} from "../engine/site-build.mjs";
|
|
114
119
|
import { auditLinks, buildLinkIndex, walkReachability } from "../engine/content-links.mjs";
|
|
115
|
-
import { prepareTreeSqlTables } from "../engine/sql-tables.mjs";
|
|
120
|
+
import { prepareLinkSqlTables, prepareTreeSqlTables } from "../engine/sql-tables.mjs";
|
|
116
121
|
// The one place a link finding is worded, shared with both builds.
|
|
117
122
|
import { linkFindingMessage } from "../engine/wikilink-syntax.mjs";
|
|
118
123
|
import {
|
|
@@ -1438,7 +1443,7 @@ function linksCommand() {
|
|
|
1438
1443
|
config,
|
|
1439
1444
|
records,
|
|
1440
1445
|
...scope,
|
|
1441
|
-
sqlTables: await
|
|
1446
|
+
sqlTables: await prepareLinkSqlTables(contentBase, {
|
|
1442
1447
|
config,
|
|
1443
1448
|
records,
|
|
1444
1449
|
parsed,
|
|
@@ -1616,12 +1621,15 @@ function contentIndexCommand() {
|
|
|
1616
1621
|
type: "string",
|
|
1617
1622
|
});
|
|
1618
1623
|
},
|
|
1619
|
-
handler: (argv) => {
|
|
1624
|
+
handler: async (argv) => {
|
|
1620
1625
|
try {
|
|
1621
1626
|
const config = loadPackConfig();
|
|
1627
|
+
const contentBase = argv.root ?? config.paths.content;
|
|
1628
|
+
const publication = await prepareContentIndex({ config, contentBase });
|
|
1622
1629
|
const { file, notes, bytes, full, draft, stub, dictionary, terms } =
|
|
1623
1630
|
emitContentIndex({
|
|
1624
1631
|
config,
|
|
1632
|
+
publication,
|
|
1625
1633
|
...(argv.root ? { contentBase: argv.root } : {}),
|
|
1626
1634
|
...(argv.out ? { outDir: argv.out } : {}),
|
|
1627
1635
|
});
|
package/docs/api.md
CHANGED
|
@@ -426,7 +426,14 @@ Drawing a declared infobox: HTML for separate Foundry pages appended after autho
|
|
|
426
426
|
|
|
427
427
|
### `engine.noteState`
|
|
428
428
|
|
|
429
|
-
The three states of a note — **stub**, **draft**, **full** —
|
|
429
|
+
The three states of a note — **stub**, **draft**, **full** — describe its page
|
|
430
|
+
content. A stubbable note with an empty body and no generated Dictionary or
|
|
431
|
+
Glossary content is a stub: its facts remain queryable in the index, but it
|
|
432
|
+
has no page, address or link target. `isStubNote` recognizes nonempty lexical
|
|
433
|
+
frontmatter as generated content, so collectors retain the resulting page.
|
|
434
|
+
That lexical frontmatter supplies content without an authored body.
|
|
435
|
+
The ladder is derived in the SQL `entries` view; a note cannot assert its own
|
|
436
|
+
state.
|
|
430
437
|
|
|
431
438
|
| Export | Signature | Returns | Use it when |
|
|
432
439
|
| --------------------- | ------------------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -458,7 +465,7 @@ What a draft note says about itself, in one sentence, on every surface it reache
|
|
|
458
465
|
|
|
459
466
|
### `engine.stubLint`
|
|
460
467
|
|
|
461
|
-
Every typed note must have a nonempty body
|
|
468
|
+
Nonempty `data.words` on a `skill`/`language` note, or `data.glossary` on a culture or affiliation, supplies content without an authored body. Absent or empty arrays supply no such exemption. Every other typed note must have a nonempty body: empty and whitespace-only bodies are errors regardless of description or `draft` tag, including `folder` and `homepage`. Nonempty placeholder-only bodies still produce errors, including on lexical notes. Nonempty bodies with fewer than 25 prose words produce warnings unless tagged `draft`. A `folder` note is held only to the nonempty rule: any body, placeholder or short, passes with or without `draft`. Untyped vault scaffolding is excluded. The lint, content-index, package compile, site and PDF commands enforce body errors before publishing.
|
|
462
469
|
|
|
463
470
|
| Export | Signature | Returns | Use it when |
|
|
464
471
|
| ------------------ | ---------------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
@@ -861,32 +868,87 @@ The published content index — the artifact packages exchange addresses through
|
|
|
861
868
|
|
|
862
869
|
Emitting this package's cross-package link manifest. `engine/content-address.mjs` owns the address _grammar_ — how a key is version is read, how a foreign file resolves. This module owns the _pass_: walking a content tree and deriving, for every note it publishes, the addresses that entry states. The two halves were split across the format module and a hand-written script in each consuming repository, which is how the two scripts came to differ in ways nobody chose — one routes its UUIDs through the pack router and one does not, and neither knew.
|
|
863
870
|
|
|
864
|
-
| Export | Signature | Returns | Use it when
|
|
865
|
-
| ----------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
866
|
-
| `LEAD_ANCHOR` | `const LEAD_ANCHOR` | — | The reserved anchor name for a journal's **first** page.
|
|
867
|
-
| `anchorsOf` | `function anchorsOf(entryUuid, entryId, body, name)` | {Record<string, string>} The anchors. | Every
|
|
868
|
-
| `entriesForNote` | `function entriesForNote(fm, name, address, body, ctx)` | {Array<object>} One or two entries, in {@link buildManifest}'s shape. | The manifest entries a single note produces.
|
|
869
|
-
| `collectFoundryEntries` | `function collectFoundryEntries(contentBase, ctx)` | `{{entries: Array<object>, notes: number, skipped: Array<{file: string, reason: string}>}}` | Every note this package publishes, as manifest entries.
|
|
870
|
-
| `foundryIdentities` | `function foundryIdentities(config` | `{{contentPackage: string, foundryPackageId: string, packRouter: object, web: boolean, skipDirectories: readonly string[]}}` | The identities an emission runs against, from configuration.
|
|
871
|
-
| `entryContext` | `function entryContext(config` | `{{contentPackage: string, foundryPackageId: string, packRouter: object, web: boolean, skipDirectories: readonly string[]}}` | The identities an emission runs against, from configuration.
|
|
871
|
+
| Export | Signature | Returns | Use it when |
|
|
872
|
+
| ----------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
873
|
+
| `LEAD_ANCHOR` | `const LEAD_ANCHOR` | — | The reserved anchor name for a journal's **first** page. |
|
|
874
|
+
| `anchorsOf` | `function anchorsOf(entryUuid, entryId, body, name)` | {Record<string, string>} The anchors. | Every anchor of a note's journal, as `anchorName → Foundry target`. |
|
|
875
|
+
| `entriesForNote` | `function entriesForNote(fm, name, address, body, ctx)` | {Array<object>} One or two entries, in {@link buildManifest}'s shape. | The manifest entries a single note produces. |
|
|
876
|
+
| `collectFoundryEntries` | `function collectFoundryEntries(contentBase, ctx)` | `{{entries: Array<object>, notes: number, skipped: Array<{file: string, reason: string}>}}` | Every note this package publishes, as manifest entries. |
|
|
877
|
+
| `foundryIdentities` | `function foundryIdentities(config` | `{{contentPackage: string, foundryPackageId: string, packRouter: object, web: boolean, skipDirectories: readonly string[]}}` | The identities an emission runs against, from configuration. |
|
|
878
|
+
| `entryContext` | `function entryContext(config` | `{{contentPackage: string, foundryPackageId: string, packRouter: object, web: boolean, skipDirectories: readonly string[]}}` | The identities an emission runs against, from configuration. |
|
|
879
|
+
|
|
880
|
+
A generated dictionary headword maps to its containing page's UUID followed
|
|
881
|
+
by its word fragment. Other authored spans keep their containing-page
|
|
882
|
+
mapping.
|
|
872
883
|
|
|
873
884
|
### `engine.contentIndex`
|
|
874
885
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
| Export | Signature | Returns
|
|
878
|
-
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
879
|
-
| `noteAddress` | `function noteAddress(frontmatter, contentPackage)` | {{slug: string, canonical: string}\|null} `slug` is what goes inside `[[…]]` within this package; `canonical` is the fully qualified key the manifest files the note under, carrying the package and the system as well.
|
|
880
|
-
| `sortKeysDeep` | `function sortKeysDeep(value)` | {unknown} The value with every plain object's keys in sorted order.
|
|
881
|
-
| `asciiName` | `function asciiName(name)` | {string\|null} The ASCII form, or `null` when there is no name, or nothing printable survives.
|
|
882
|
-
| `asciiAliases` | `function asciiAliases(aliases)` | {Array<string>} Possibly empty, never null: a note with no aliases has an empty set of them, which is a fact rather than a missing value, and a consumer iterating it should not have to check first.
|
|
883
|
-
| `serializeContentIndex` | `function serializeContentIndex(records)` | {string} One compact JSON object per line, newline-terminated.
|
|
884
|
-
| `indexRecordsFor` | `indexRecordsFor({ contentBase, config, skipDirectories, problems, parsed })` | {object[]} One record per note, plus one per documentation entry.
|
|
885
|
-
| `indexRecordsForNote` | `indexRecordsForNote({ frontmatter, body, bodyLine, relPath, absPath, raw, contentPackage, manifest, addressContext })` | `object[]`
|
|
886
|
-
| `
|
|
887
|
-
| `
|
|
888
|
-
| `
|
|
889
|
-
| `
|
|
886
|
+
Collecting and publishing this package's content index. Records describe note frontmatter, assets, prose and event anchors, and the document targets those notes produce. Dynamic publication prepares the same generated Markdown and scalar expressions as the rendering surfaces, using each source note's audience.
|
|
887
|
+
|
|
888
|
+
| Export | Signature | Returns | Use it when |
|
|
889
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
890
|
+
| `noteAddress` | `function noteAddress(frontmatter, contentPackage)` | {{slug: string, canonical: string}\|null} `slug` is what goes inside `[[…]]` within this package; `canonical` is the fully qualified key the manifest files the note under, carrying the package and the system as well. | The address a wikilink writes to reach a note, or `null` when it has none. |
|
|
891
|
+
| `sortKeysDeep` | `function sortKeysDeep(value)` | {unknown} The value with every plain object's keys in sorted order. | Recursively sort an object's keys, so serialization is order-independent. |
|
|
892
|
+
| `asciiName` | `function asciiName(name)` | {string\|null} The ASCII form, or `null` when there is no name, or nothing printable survives. | A note's display name reduced to printable 7-bit ASCII. |
|
|
893
|
+
| `asciiAliases` | `function asciiAliases(aliases)` | {Array<string>} Possibly empty, never null: a note with no aliases has an empty set of them, which is a fact rather than a missing value, and a consumer iterating it should not have to check first. | A note's `name.aliases` reduced to printable 7-bit ASCII, in order. |
|
|
894
|
+
| `serializeContentIndex` | `function serializeContentIndex(records)` | {string} One compact JSON object per line, newline-terminated. | Serialize records as JSON Lines. |
|
|
895
|
+
| `indexRecordsFor` | `indexRecordsFor({ contentBase, config, skipDirectories, problems, parsed })` | {object[]} One record per note, plus one per documentation entry. | The index records for a content tree, without writing anything. |
|
|
896
|
+
| `indexRecordsForNote` | `indexRecordsForNote({ frontmatter, body, bodyLine, relPath, absPath, raw, contentPackage, manifest, addressContext })` | `object[]` | Derive the note's own record and its documentation record from parsed text. |
|
|
897
|
+
| `prepareContentIndex` | `async prepareContentIndex({ contentBase, config } = {})` | `Promise<PreparedContentIndex>` — the captured source context and complete expanded bodies, described below | Prepare dynamic publication without writing files. |
|
|
898
|
+
| `emitContentIndex` | `emitContentIndex({ contentBase, outDir, config, publication } = {})` | `{{file: string, notes: number, assets: number, records: number, bytes: number, full: number, draft: number, stub: number, dictionary: {file: string, rows: number}, terms: {file: string, rows: number}}}` | Synchronously publish metadata and the dictionary and terms datafiles; dynamic content requires a complete `publication`. |
|
|
899
|
+
| `buildIndexRecord` | `buildIndexRecord({ frontmatter, relPath, absPath, raw, contentPackage, body, bodyLine, manifest })` | `Record<string, any>` — the record, with derived fields sorted deep | building one note's content-index record; refuses a note that authors a key the index derives itself (`package` among them) before building anything |
|
|
900
|
+
| `collectContentIndex` | `collectContentIndex(contentBase, { contentPackage, skipDirectories, assetsBase, manifest, problems, foreignRecord, parsed })` | `Array<Record<string, any>>` | reading a whole content tree into index records, in a total order independent of directory-read order; an item note yields two records (its own and its documentation journal's), and each asset root yields one per file; each note carries its resolved culture as `data.culture` |
|
|
901
|
+
| `resolveCultures` | `resolveCultures(records, { contentPackage, contentBase, foreignRecord, problems })` | `Array<Record<string, any>>` — the same records | writing each note's resolved culture into its record as `data.culture`: its own value, else its parents', else for a polity its seat's and governed places', pooled; parents that disagree give a finding into `problems`, or one thrown Error listing every conflict |
|
|
902
|
+
|
|
903
|
+
`prepareContentIndex` resolves `contentBase` from the configured `paths.content`
|
|
904
|
+
when omitted. Its `PreparedContentIndex` contains:
|
|
905
|
+
|
|
906
|
+
| Field | Value |
|
|
907
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
908
|
+
| `config` | The resolved configuration object used for preparation. |
|
|
909
|
+
| `contentBase` | The absolute source root. |
|
|
910
|
+
| `records` | The complete note, documentation and asset records, including hidden providers needed for lineage. |
|
|
911
|
+
| `parsed` | A `Map` keyed by absolute note file, holding authored `frontmatter`, `body`, `raw`, `bodyLine` and `bodyColumn`. |
|
|
912
|
+
| `expandedBodies` | A `Map` keyed by absolute note file, holding `markdown`, its body-relative `lineMap` of `{line, generated}` entries, and optional `generatedFrom`. |
|
|
913
|
+
| `foundryBodies` | A `Map` with the same body shape, prepared against the complete native compendium corpus. |
|
|
914
|
+
|
|
915
|
+
Preparation expands SQL tables, page lists, automatic sections and scalar
|
|
916
|
+
expressions. Prose declarations in `expandedBodies` use each source's audience:
|
|
917
|
+
public notes use public providers and usage; GM notes use the complete corpus.
|
|
918
|
+
Automatic lexical sections keep that source audience on every surface.
|
|
919
|
+
Explicit native SQL uses the complete corpus in `foundryBodies`.
|
|
920
|
+
|
|
921
|
+
Native own and documentation target maps derive their actual page identities
|
|
922
|
+
from `foundryBodies`. Each map contains only prose slugs declared in the
|
|
923
|
+
source-audience body and present in the native body, plus the journal's
|
|
924
|
+
reserved `$lead` target. A prose target present only on the website remains
|
|
925
|
+
valid for website links and prose-link checks; a native link to it is refused.
|
|
926
|
+
Native-only slugs and private heading names stay out of a public source's
|
|
927
|
+
metadata. Event anchors and authored source positions remain attached to their
|
|
928
|
+
sources. A published empty prose-anchor list declares no prose targets,
|
|
929
|
+
including on web-only pages.
|
|
930
|
+
|
|
931
|
+
Pass the envelope directly to the synchronous emitter:
|
|
932
|
+
|
|
933
|
+
```js
|
|
934
|
+
const publication = await prepareContentIndex({ config, contentBase });
|
|
935
|
+
const result = emitContentIndex({ publication, outDir });
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
The emitter defaults `config` and `contentBase` from the envelope. If supplied,
|
|
939
|
+
they must name that same configuration object and source root. It consumes
|
|
940
|
+
`records`, `parsed`, `expandedBodies` and `foundryBodies` without mutating them;
|
|
941
|
+
frozen inputs are valid. Every note requires a parsed source and both body
|
|
942
|
+
entries.
|
|
943
|
+
Missing or mismatched preparation is refused before creating or replacing any
|
|
944
|
+
metadata, dictionary or terms file.
|
|
945
|
+
|
|
946
|
+
Without `publication`, the synchronous emitter accepts authored bodies and
|
|
947
|
+
pure frontmatter dictionary or glossary sections. Active SQL, page lists,
|
|
948
|
+
scalar expressions, events or other generated sections require
|
|
949
|
+
`prepareContentIndex`. The CLI performs this preparation automatically.
|
|
950
|
+
`indexRecordsFor` and `collectContentIndex` collect authored records and pure
|
|
951
|
+
lexical sections; use preparation and emission to publish dynamic body targets.
|
|
890
952
|
|
|
891
953
|
`engine.contentIndex` also re-exports eight names from neighbouring leaf modules, at this same import path:
|
|
892
954
|
|
|
@@ -897,7 +959,7 @@ Emitting this package's content index. Every content build already walks the who
|
|
|
897
959
|
| `noteFile` | `noteFile(contentBase, record)` | `string` — the note's absolute path | composing an index record's `file.path` (recorded relative, for a byte-stable artifact) back into an openable absolute path |
|
|
898
960
|
| `authoredFrontmatter` | `authoredFrontmatter(record)` | `Record<string, any>` — the frontmatter without `DERIVED_KEYS` | reading a note's frontmatter back from its index record, its resolved `data.culture` included, so a pass can lint or compile from the index without reasoning about derived keys as if the author wrote them |
|
|
899
961
|
| `isNoteRecord` | `isNoteRecord(record)` | `boolean` | telling a note's own record apart from its documentation journal's and from an asset's, when enumerating the corpus |
|
|
900
|
-
| `isStub` | `isStub(record)` | `boolean` | telling a stub
|
|
962
|
+
| `isStub` | `isStub(record)` | `boolean` | telling a stub apart from a note that publishes a page; asked of the absent address, which is the whole signal |
|
|
901
963
|
| `isAssetRecord` | `isAssetRecord(record)` | `boolean` | telling a record that addresses a file apart from one that addresses a note; the `asset` block is what marks it |
|
|
902
964
|
| `recordPath` | `recordPath(record)` | `string` — the path the record names inside its package | ordering or reporting across both record shapes: a note names the `.md` it was parsed from, an asset the file it is |
|
|
903
965
|
|
|
@@ -1002,7 +1064,7 @@ content tree can also compile into Foundry compendium packs.
|
|
|
1002
1064
|
| `collectContentPages` | `function collectContentPages(contentBase, ctx)` | `{{pages: object[], addressFindings: object[], fmLinkFindings: object[]}}` | The content tree's pages, and what could not be addressed. |
|
|
1003
1065
|
| `collectHomepages` | `function collectHomepages(contentBase, ctx)` | `{{pages: object[], addressFindings: object[]}}` The homepage notes, in walk order, and the ones among them that could not be addressed. | The package's homepage notes — the authored page at `/<contentPackage>/`. |
|
|
1004
1066
|
| `writeHomepages` | `function writeHomepages(outRoot, pages, config)` | {number} How many pages were written. | Writes each homepage as the package root's `_index.md`. |
|
|
1005
|
-
| `siteGates` | `
|
|
1067
|
+
| `siteGates` | `siteGates(pages, findings, options)` | {object} The gate results and, when they pass, the built index. | The integrity gates a site build runs before it writes anything. |
|
|
1006
1068
|
| `emptyGates` | `function emptyGates()` | {object} An all-clear gate result. | The gate result of a build that ran none of them. |
|
|
1007
1069
|
| `gatesFailed` | `function gatesFailed(gates)` | — | Whether any gate produced a finding. |
|
|
1008
1070
|
| `tableUniverse` | `function tableUniverse(pages)` | {Map<string, object[]>} Package → the notes it may tabulate. | The universe a generated table searches, grouped by package. |
|
|
@@ -1014,6 +1076,10 @@ content tree can also compile into Foundry compendium packs.
|
|
|
1014
1076
|
| `sitePageDecorator` | `sitePageDecorator(config, index)` | Function | Add the site's infobox and being metadata to a rendered page. |
|
|
1015
1077
|
| `buildSite` | `buildSite({ config, sqlTables })` | `{{gates: object, stats: object\|null, tableErrors: object[], wikiErrors: object[], mapFindings: object[], manifests: object\|null}}` | Builds a Hugo content tree from a content tree, and reports what it found. |
|
|
1016
1078
|
|
|
1079
|
+
`siteGates` takes `{ config, records, sqlTables? }`. Pass the prepared
|
|
1080
|
+
`sqlTables` map so anchors emitted by automatic dictionary sections are present in the
|
|
1081
|
+
index for checking page links.
|
|
1082
|
+
|
|
1017
1083
|
### `engine.sitePreview`
|
|
1018
1084
|
|
|
1019
1085
|
`prepareSitePreview({ config })` reads the saved content tree and declared dependency indexes, prepares its SQL corpus, and returns a private preview context. Pass the active note's absolute path and complete buffer text to `render(file, text)`. A successful result has `{ ok: true, markdown, frontmatter, findings: [] }`; a failed result has `{ ok: false, findings }` and no replacement content. Findings identify the source file and carry a line and column when the offending text can be located.
|
|
@@ -1224,12 +1290,17 @@ Shared helpers for the pack compilers in `packages/package-build/`. The HeroicLa
|
|
|
1224
1290
|
| `buildStats` | `function buildStats(systemVersion` | {object} The `_stats` block. | Default `_stats` block for compiled compendium entries. |
|
|
1225
1291
|
| `statsForPack` | `function statsForPack(packSystem, config` | {object} The `_stats` block for that pack. | The `_stats` block for one pack, stamped with the system that pack is for. |
|
|
1226
1292
|
| `defaultStats` | `function defaultStats()` | {object} The default `_stats` block, shared by every compiler. | The `_stats` block every compiler stamps on an entry it emits, built once. |
|
|
1227
|
-
| `buildContentLinkIndex` | `buildContentLinkIndex(contentBase, router
|
|
1293
|
+
| `buildContentLinkIndex` | `buildContentLinkIndex(contentBase, router?, options?)` | `{{byShortcode: Map, types: Set}}` From `buildWikilinkIndex`. | Indexes **every** note in the content tree so any pack compiler can resolve a wikilink to any other document. |
|
|
1228
1294
|
| `convertNoteWikilinks` | `convertNoteWikilinks(body, { type, id, pack, docPack, index, name, file, bodyLine, bodyColumn, lineMap })` | `{{markdown: string, unresolved: Array<object>}}` | Converts the wikilinks in one note's markdown, reporting any that have no target in the content tree. |
|
|
1229
1295
|
| `expandNoteTables` | `function expandNoteTables(body,` | `{{markdown: string, lineMap: Array<{line: number, generated: boolean}>}}` The body with every table expanded, and where each emitted line came from — which is what lets a diagnostic about the expanded body name an authored position. | Expand prepared SQL tables in one note's markdown, before wikilinks are resolved — so a generated cell may itself be a wikilink. |
|
|
1230
1296
|
| `folderFilename` | `function folderFilename(name, id)` | — | Builds a compendium-source filename for a folder JSON document: `folder_Name_id.json` with non-alphanumeric runs replaced by underscores. |
|
|
1231
1297
|
| `walkMarkdownTree` | `walkMarkdownTree(rootDir, { skipDirectories })` | generator yielding `{frontmatter, body, description, raw, bodyLine?, bodyColumn?, file, absPath}` | walking a content tree and reading every markdown file's frontmatter and body; `skipDirectories` is required rather than defaulted, so two callers cannot silently disagree about the corpus's scope |
|
|
1232
1298
|
|
|
1299
|
+
`buildContentLinkIndex` accepts `{ config?, records, sqlTables? }`.
|
|
1300
|
+
`records` is the required, supplied content corpus. The optional prepared
|
|
1301
|
+
`sqlTables` map supplies generated anchors and their Foundry page mappings,
|
|
1302
|
+
so glossary word links resolve to their dictionary entries.
|
|
1303
|
+
|
|
1233
1304
|
### `engine.itemRegistry`
|
|
1234
1305
|
|
|
1235
1306
|
**The resolved item-type registry** — the consuming repository's `itemBuilders` table, and the type whitelist derived from its keys. Both are read from the one resolved configuration, so they are literally the same object's keys and values: a type cannot be whitelisted for compilation without the builder that compiles it, which is the guarantee this exists for. Where a consumer declares **several** registries, one per system, the vocabulary is their union and every lookup below takes the system that is asking — a type both systems declare has two builders, and answering with one of them because it was declared first is the silent-wrong-output failure this package spends its time removing. The Item compiler dispatches through {@link itemBuilder}, so the table a consumer configured is the table its notes compile with — the whitelist and the dispatch would otherwise come from different places, and a consumer supplying its own registry got the types it asked for and the builders it did not.
|
|
@@ -2074,3 +2145,232 @@ set by `joinGeneratedSections`. Subsequent fences are generated event queries
|
|
|
2074
2145
|
whose stub-inclusive results are identical; only authored fences receive a
|
|
2075
2146
|
stub-inclusion comparison. Query answers and comparisons are cached for one
|
|
2076
2147
|
preparation and kept separate.
|
|
2148
|
+
|
|
2149
|
+
`prepareTreeSqlTables` retains the complete record membership when opening a
|
|
2150
|
+
public database, so derived citations can distinguish hidden notes from
|
|
2151
|
+
unknown addresses. Only public records contribute rendered sources and links.
|
|
2152
|
+
|
|
2153
|
+
| Export | Contract |
|
|
2154
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
2155
|
+
| `prepareLinkSqlTables` | Prepare SQL, page-list and automatic lexical sections for link checking, using one preparation per required source audience. |
|
|
2156
|
+
|
|
2157
|
+
`engine/sql-tables.mjs` exports `prepareLinkSqlTables(contentBase, options)`.
|
|
2158
|
+
Its options are `config`, `skipDirectories`, complete `records`, the shared
|
|
2159
|
+
`parsed` map and `foreignIndex`. It returns prepared tables with `pageLists`
|
|
2160
|
+
and `inline` maps, or `undefined` when no source needs a directive or automatic
|
|
2161
|
+
lexical section. Public
|
|
2162
|
+
sources use public rows; GM sources use all rows. Query results remain local
|
|
2163
|
+
to each audience preparation, and the caller’s records remain complete for
|
|
2164
|
+
checking authored references. Unresolved derived citations retain the
|
|
2165
|
+
renderer’s plain-label behavior.
|
|
2166
|
+
|
|
2167
|
+
`generatedSectionsFor(db, records, contentBase, options?)` accepts complete
|
|
2168
|
+
lineage records as `options.all` (default `records`). Its result includes
|
|
2169
|
+
`lexical`, a map from note file to `LexicalSection[]`, beside `sections`,
|
|
2170
|
+
`views` and `derived`. `attachGeneratedSections(prepared, generated)` places
|
|
2171
|
+
those lists on each note's prepared results as `lexical`; body expansion
|
|
2172
|
+
inserts them alongside the prepared directives.
|
|
2173
|
+
|
|
2174
|
+
## Dictionary and glossary rows
|
|
2175
|
+
|
|
2176
|
+
The wildcard engine subpath exposes
|
|
2177
|
+
`@heroiclands/package-build/engine/dictionary-rows` for deriving the
|
|
2178
|
+
`dictionary` and `terms` SQL relations from content-index records:
|
|
2179
|
+
|
|
2180
|
+
| Export | Signature | Returns | Use it when |
|
|
2181
|
+
| ----------------------- | ----------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------- |
|
|
2182
|
+
| `DICTIONARY_COLUMNS` | `const DICTIONARY_COLUMNS` | A readonly list of column names | Declaring the schema of a language's dictionary. |
|
|
2183
|
+
| `TERM_COLUMNS` | `const TERM_COLUMNS` | A readonly list of column names | Declaring the schema of owner-specific glossary terms. |
|
|
2184
|
+
| `ETYMOLOGY_KEYS` | `const ETYMOLOGY_KEYS` | A readonly list of keys | Reading the structure of a dictionary word's etymology. |
|
|
2185
|
+
| `dictionaryLetter` | `dictionaryLetter(text)` | `string` | Deriving a heading letter from a sort key. |
|
|
2186
|
+
| `dictionaryEntryAnchor` | `dictionaryEntryAnchor(language, name)` | `string` | Deriving the stable entry anchor for a word in a language's dictionary. |
|
|
2187
|
+
| `dictionaryAndTermRows` | `dictionaryAndTermRows(records, all = records)` | `{ dictionary: object[], terms: object[] }` | Deriving dictionary words and glossary terms for the selected records. |
|
|
2188
|
+
| `serializeRows` | `serializeRows(rows)` | `string` | Writing deterministic JSON Lines with keys sorted at every depth. |
|
|
2189
|
+
|
|
2190
|
+
`dictionaryEntryAnchor` takes the language's canonical Address and the
|
|
2191
|
+
word's form. Its `word-` anchor is derived from the full SHA-256 digest of
|
|
2192
|
+
that language and the NFC-normalized form, with case and accents preserved.
|
|
2193
|
+
It identifies the word's entry on that language page, including a word
|
|
2194
|
+
inherited from an ancestor.
|
|
2195
|
+
|
|
2196
|
+
`records` is the selected audience; `all` supplies the complete record set for
|
|
2197
|
+
language and ownership resolution. A dictionary word takes its sort key and
|
|
2198
|
+
pronunciation from the language's word declaration. A glossary entry can
|
|
2199
|
+
supply its own sort key and pronunciation, using the dictionary word's
|
|
2200
|
+
values where unstated.
|
|
2201
|
+
|
|
2202
|
+
A term naming a dictionary word carries its `class` and a `word` Address
|
|
2203
|
+
linking to its dictionary entry. The target is in the resolved language's
|
|
2204
|
+
dictionary when that language has own words; otherwise it is in the visible
|
|
2205
|
+
language that defines the word. The term's `language` stays resolved to the
|
|
2206
|
+
owner or entry's language. Without an entry's `definition`, its `senses`
|
|
2207
|
+
contain every dictionary gloss sense with
|
|
2208
|
+
an empty `bodies` list. With a definition, that owner's meaning is the sense
|
|
2209
|
+
instead. A rank or office of the same owner contributes its distinct
|
|
2210
|
+
descriptions after the dictionary senses; the owner's definition replaces
|
|
2211
|
+
both. Ranks, offices and terms outside the dictionary carry their source
|
|
2212
|
+
bodies. `common` belongs to
|
|
2213
|
+
glossary entries and `terms`, with each owner's choice kept on that owner's
|
|
2214
|
+
row. The [format
|
|
2215
|
+
reference](reference/format-details.md#dictionaries-and-glossaries) defines
|
|
2216
|
+
all columns and the rules for culture reach and ranks. The `cultures` list
|
|
2217
|
+
records associations for custom queries. Automatic Glossary sections select
|
|
2218
|
+
only their owner's explicitly declared `data.glossary` entries. A custom
|
|
2219
|
+
view can also select reached rank and office rows, keeping common marks only
|
|
2220
|
+
on its owner's own rows.
|
|
2221
|
+
|
|
2222
|
+
Dictionary rows carry `plural`, the noun's nonempty explicit plural or its
|
|
2223
|
+
listed language's first matching literal suffix replacement, and `verbs`,
|
|
2224
|
+
that language's stated `{invariant: true}` or six-person pattern, otherwise
|
|
2225
|
+
null. These optional facts use no ancestor grammar and perform no word-rule
|
|
2226
|
+
validation. The raw `words` relation's `plural` remains the authored value.
|
|
2227
|
+
Dictionary SQL types are projected only for that relation, retaining its
|
|
2228
|
+
etymology struct, sense list, usage list and integer depth even when all
|
|
2229
|
+
optional grammar values are null.
|
|
2230
|
+
|
|
2231
|
+
`@heroiclands/package-build/engine/language-terms` exposes the person
|
|
2232
|
+
descriptors used by the schema, SQL pattern type and head table:
|
|
2233
|
+
|
|
2234
|
+
| Export | Signature | Returns | Use it when |
|
|
2235
|
+
| -------------------- | -------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------- |
|
|
2236
|
+
| `VERB_PERSON_FIELDS` | `const VERB_PERSON_FIELDS` | Readonly inner-key descriptors | Reading the six present person names, labels and ending-string shapes in presentation order. |
|
|
2237
|
+
|
|
2238
|
+
`serializeRows` returns the empty string for no rows; otherwise each object
|
|
2239
|
+
occupies one line and the file ends with a newline.
|
|
2240
|
+
|
|
2241
|
+
## Dictionary and glossary layouts
|
|
2242
|
+
|
|
2243
|
+
`@heroiclands/package-build/engine/dictionary-layout` renders SQL results as
|
|
2244
|
+
Markdown for the dictionary or glossary on its owner's note:
|
|
2245
|
+
|
|
2246
|
+
| Export | Signature | Returns | Use it when |
|
|
2247
|
+
| ------------------------- | ------------------------------------ | -------------------------- | ----------------------------------------------------------------------------------- |
|
|
2248
|
+
| `LAYOUT_REQUIRED_COLUMNS` | `const LAYOUT_REQUIRED_COLUMNS` | Required columns by layout | Checking the columns a dictionary or glossary query must select. |
|
|
2249
|
+
| `COMMON_MARK` | `const COMMON_MARK` | `string` | Reading the mark a common glossary entry opens with. |
|
|
2250
|
+
| `DICTIONARY_ENTRY_CLASS` | `const DICTIONARY_ENTRY_CLASS` | `string` | Identifying generated headword spans that are native dictionary targets in Foundry. |
|
|
2251
|
+
| `dictionaryEntryPlugin` | `dictionaryEntryPlugin(md)` | `void` | Registering native dictionary headword rendering on the Foundry Markdown parser. |
|
|
2252
|
+
| `renderDictionary` | `renderDictionary(result, options?)` | `string` | Rendering a language's words with classes, etymology, senses and citations. |
|
|
2253
|
+
| `renderGlossary` | `renderGlossary(result, options?)` | `string` | Rendering an owner's glossary entries, ranks and offices. |
|
|
2254
|
+
|
|
2255
|
+
`result` is `{ columns: string[], rows: object[] }`. Both layouts require
|
|
2256
|
+
`name`, `senses` and `usage`; a missing column throws an error naming it.
|
|
2257
|
+
`LayoutOptions` accepts `linkable(ref)`, `sectionLevel`, `addressContext`,
|
|
2258
|
+
`labelOf(address)`, `showKey` (`true`, `false` or `"only"`), `pageLanguage`, `pageOwner`,
|
|
2259
|
+
`verbs` and `entryAnchors` (default `true`). These control link availability, letter-heading level,
|
|
2260
|
+
Address resolution, labels, the abbreviation key and the language whose tag
|
|
2261
|
+
is omitted. `entryAnchors` controls canonical dictionary headword targets;
|
|
2262
|
+
custom SQL dictionary views set it to `false`, leaving those targets to the
|
|
2263
|
+
language's automatic Dictionary section. A dictionary marks nothing common;
|
|
2264
|
+
a glossary prints the mark and its explanation when a selected term carries
|
|
2265
|
+
`common: true`.
|
|
2266
|
+
|
|
2267
|
+
A dictionary entry has a stable word anchor. A glossary headword with a
|
|
2268
|
+
`word` Address links to that entry, and its `class` prints beside the language
|
|
2269
|
+
tag. Glossary rows sharing a headword and language combine into one entry;
|
|
2270
|
+
identical senses print once with all their source bodies. Dictionary-derived
|
|
2271
|
+
senses carry no body label. Dictionary entries print their `field` in italic
|
|
2272
|
+
parentheses and their etymology in brackets.
|
|
2273
|
+
|
|
2274
|
+
Nouns print their optional `plural` beside the class. Each represented
|
|
2275
|
+
language's optional `verbs` column supplies one table after the key and
|
|
2276
|
+
before the first letter, with empty endings shown as "unchanged". For an
|
|
2277
|
+
automatic dictionary, `options.verbs` supplies the owning language's pattern
|
|
2278
|
+
even when its own words contain only excluded classes. The existing
|
|
2279
|
+
nonempty-own-words gate still applies. `showKey: false` suppresses the key
|
|
2280
|
+
and verb table while retaining entries; `showKey: "only"` prints the
|
|
2281
|
+
abbreviation key alone. With the default or `showKey: true`, a stated pattern
|
|
2282
|
+
still prints when the result needs no abbreviation key. Each head-enabled
|
|
2283
|
+
result prints its represented languages' tables independently.
|
|
2284
|
+
|
|
2285
|
+
`pageOwner` is the containing page's canonical note Address. A glossary omits
|
|
2286
|
+
a sense's body label only when every contributing row belongs to that page
|
|
2287
|
+
and attributes the sense solely to itself. Other bodies and shared senses
|
|
2288
|
+
keep their labels. Without `pageOwner` or a selected `owner` column, all body
|
|
2289
|
+
labels remain.
|
|
2290
|
+
|
|
2291
|
+
`DICTIONARY_ENTRY_CLASS` is `"dictionary-entry"`. The Foundry parser's
|
|
2292
|
+
`dictionaryEntryPlugin` promotes the marked headword at the start of a
|
|
2293
|
+
dictionary paragraph to an inline native H6 heading in a div container. It
|
|
2294
|
+
keeps the containing journal page. Site and book rendering retain the
|
|
2295
|
+
headword's span and paragraph. `anchorsOf` maps this dictionary target to
|
|
2296
|
+
its containing page's UUID with the word fragment; generic authored spans
|
|
2297
|
+
keep their containing-page behavior.
|
|
2298
|
+
|
|
2299
|
+
## Automatic dictionary and glossary sections
|
|
2300
|
+
|
|
2301
|
+
`@heroiclands/package-build/engine/lexical-sections` derives and inserts the
|
|
2302
|
+
same automatic lists for the site, Foundry journal, book and published index:
|
|
2303
|
+
|
|
2304
|
+
| Export | Signature | Returns | Use it when |
|
|
2305
|
+
| ----------------------- | ------------------------------------------------------ | ------------------------------------- | ----------------------------------------------------------------- |
|
|
2306
|
+
| `LEXICAL_SECTIONS` | `const LEXICAL_SECTIONS` | A frozen list of section declarations | Reading section headings, accepted anchors and frontmatter gates. |
|
|
2307
|
+
| `hasLexicalEntries` | `hasLexicalEntries(frontmatter)` | `boolean` | Checking whether a note supplies automatic lexical content. |
|
|
2308
|
+
| `lexicalSectionsFor` | `lexicalSectionsFor(records, all = records)` | `Map<string, LexicalSection[]>` | Deriving lists keyed by their owner's canonical Address. |
|
|
2309
|
+
| `insertLexicalSections` | `insertLexicalSections(markdown, sections?, context?)` | `{markdown, lineMap, generatedFrom?}` | Inserting lists while preserving authored text and source lines. |
|
|
2310
|
+
|
|
2311
|
+
Each registry declaration has `slug`, `heading`, `aliases`, `dataKey` and
|
|
2312
|
+
`types`, whose entries have `type` and an optional `subType`. The Dictionary
|
|
2313
|
+
declaration applies to `skill`/`language` notes with nonempty `data.words`,
|
|
2314
|
+
and accepts `dictionary` and `lexicon` heading anchors. The Glossary
|
|
2315
|
+
declaration applies to cultures (`lore`/`culture`) and affiliations with
|
|
2316
|
+
nonempty `data.glossary`, and accepts `glossary`. `hasLexicalEntries` reads
|
|
2317
|
+
these same type and nonempty-array gates; it does not validate the authored
|
|
2318
|
+
body.
|
|
2319
|
+
|
|
2320
|
+
`records` is the visible audience; `all` supplies complete lineage records.
|
|
2321
|
+
Each `LexicalSection` has `slug`, `heading`, `aliases`, a query-shaped
|
|
2322
|
+
`result: {columns, rows}` and dictionary-layout `options`. Dictionary rows
|
|
2323
|
+
cover the language's full dictionary; glossary rows select its owner's
|
|
2324
|
+
explicit entries only, including a rank or office only when named there.
|
|
2325
|
+
A qualifying words declaration containing only excluded word classes still
|
|
2326
|
+
produces its Dictionary heading, without entries or a key.
|
|
2327
|
+
|
|
2328
|
+
`insertLexicalSections` takes the body after authored directives expand.
|
|
2329
|
+
Pass the original body as `context.authored` together with the expansion's
|
|
2330
|
+
line map, so generated headings cannot select or end an authored section.
|
|
2331
|
+
Without `authored`, the helper treats `markdown` as its source. It inserts a
|
|
2332
|
+
list at the end of the first matching authored anchored section, after its
|
|
2333
|
+
text and before the next authored heading at the same or a higher level.
|
|
2334
|
+
Headings inside comments, raw HTML, literal code or named blocks do not select
|
|
2335
|
+
sections.
|
|
2336
|
+
Without that heading, it appends an H1 with the section's canonical anchor.
|
|
2337
|
+
Letter headings sit one level below the containing heading, up to H6. The
|
|
2338
|
+
optional context is `{authored?, lineMap?, generatedFrom?}`; the returned line map keeps
|
|
2339
|
+
authored positions, marks inserted lines as generated and adjusts the start
|
|
2340
|
+
of appended nonlexical sections. It leaves the supplied line-map array
|
|
2341
|
+
unchanged.
|
|
2342
|
+
|
|
2343
|
+
## Glossary term validation
|
|
2344
|
+
|
|
2345
|
+
The wildcard module `@heroiclands/package-build/engine/culture-reach`
|
|
2346
|
+
exposes the term lookup used for glossary validation;
|
|
2347
|
+
`@heroiclands/package-build/engine/glossary-entries` exposes its findings:
|
|
2348
|
+
|
|
2349
|
+
| Export | Signature | Returns | Use it when |
|
|
2350
|
+
| --------------- | ------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------- |
|
|
2351
|
+
| `noteTerms` | `noteTerms(index, note, entry?)` | `Map<string, string[]>` | Reading eligible dictionary words and reached rank or office descriptions by NFC name. |
|
|
2352
|
+
| `checkGlossary` | `checkGlossary(note, { index } = {})` | `object[]` | Checking the meanings and language references of a culture's or affiliation's glossary entries. |
|
|
2353
|
+
|
|
2354
|
+
`noteTerms` selects words from the entry's resolved language and its
|
|
2355
|
+
ancestors; without `entry`, it uses the note's own resolved language. It also
|
|
2356
|
+
includes ranks and offices that reach the note. `checkGlossary` returns
|
|
2357
|
+
located findings for entries naming no language, duplicate names, invalid
|
|
2358
|
+
pronunciations and entries without a definition that match neither a word in
|
|
2359
|
+
their resolved language nor a reached rank or office. A definition repeating
|
|
2360
|
+
the only sense it replaces produces a warning. With no `index`, the check
|
|
2361
|
+
validates only what the note states locally.
|
|
2362
|
+
|
|
2363
|
+
## Built-piece resolution
|
|
2364
|
+
|
|
2365
|
+
The wildcard engine subpath exposes `pieceGlosses` from
|
|
2366
|
+
`@heroiclands/package-build/engine/word-rows`.
|
|
2367
|
+
|
|
2368
|
+
| Export | Signature | Returns | Use it when |
|
|
2369
|
+
| -------------- | ------------------------ | ----------------------------------- | ---------------------------------------------------------------------------- |
|
|
2370
|
+
| `pieceGlosses` | `pieceGlosses(...datas)` | A lookup returning a string or null | Resolving a word's built pieces for lint, word rows or dictionary etymology. |
|
|
2371
|
+
|
|
2372
|
+
Pass language `data` objects nearest first, in `lineageChain` order. Each
|
|
2373
|
+
language contributes words, affixes and elements, in that order. Words and
|
|
2374
|
+
affixes supply `gloss`, including an affix matched by its `front` form. Elements
|
|
2375
|
+
supply `sense` and match their `form` and `variants`. Exact matches precede matches without joining hyphens; case and
|
|
2376
|
+
accents are preserved. A missing gloss returns `null`.
|
|
@@ -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
|
-
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.
|
|
48
|
+
Nonempty `data.words` on a language note, or `data.glossary` on a culture or affiliation, supplies content without an authored body. Every other typed note must have a nonempty body after its frontmatter, including folder and homepage notes. An empty or whitespace-only body is otherwise an error, even with `tags: [draft]` or a description. A nonempty body with fewer than 25 prose words produces a warning unless the note has a `draft` tag. A folder note needs only a nonempty body: any content passes, with or without the tag. See [note states](../reference/format-details.md#three-states-of-a-note).
|