@heroiclands/package-build 23.8.0 → 23.10.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +2 -0
  3. package/bin/content-commands.mjs +207 -70
  4. package/docs/api.md +646 -78
  5. package/docs/authoring/first-note.md +1 -1
  6. package/docs/authoring/links-and-markup.md +253 -102
  7. package/docs/commands.md +111 -13
  8. package/docs/content-format.md +7 -2
  9. package/docs/diagnostics.md +1 -1
  10. package/docs/guides/packs.md +2 -1
  11. package/docs/guides/reference-pages.md +86 -63
  12. package/docs/reference/format-details.md +398 -137
  13. package/docs/reference/note-types.md +188 -174
  14. package/engine/anchors.mjs +15 -26
  15. package/engine/base-compiler.mjs +6 -4
  16. package/engine/changelog-group.mjs +58 -34
  17. package/engine/changelog-lint.mjs +6 -2
  18. package/engine/compendiums.mjs +15 -1
  19. package/engine/compile-corpus.mjs +17 -3
  20. package/engine/content-charset.mjs +13 -1
  21. package/engine/content-format.yaml +1 -0
  22. package/engine/content-html.mjs +18 -4
  23. package/engine/content-icons.mjs +15 -1
  24. package/engine/content-images.mjs +28 -9
  25. package/engine/content-index.mjs +496 -16
  26. package/engine/content-links.mjs +70 -27
  27. package/engine/content-session.mjs +247 -0
  28. package/engine/content-sources.mjs +110 -0
  29. package/engine/content-spans.mjs +87 -8
  30. package/engine/content-tables.mjs +9 -4
  31. package/engine/content-tasklists.mjs +20 -4
  32. package/engine/culture-reach.mjs +61 -34
  33. package/engine/data-keys.mjs +3 -1
  34. package/engine/diagnostics.mjs +17 -6
  35. package/engine/dictionary-layout.mjs +151 -19
  36. package/engine/dictionary-rows.mjs +129 -79
  37. package/engine/extension-attributes.mjs +28 -5
  38. package/engine/first-use.mjs +371 -0
  39. package/engine/foundry-entries.mjs +29 -8
  40. package/engine/generate.mjs +13 -4
  41. package/engine/glossary-entries.mjs +11 -11
  42. package/engine/heading-attributes.mjs +21 -28
  43. package/engine/helpers.mjs +54 -19
  44. package/engine/index-records.mjs +1 -0
  45. package/engine/index.mjs +3 -0
  46. package/engine/journals.mjs +13 -6
  47. package/engine/language-data.mjs +55 -2
  48. package/engine/language-rows.mjs +4 -4
  49. package/engine/language-terms.mjs +90 -4
  50. package/engine/language-words.mjs +2 -2
  51. package/engine/lexical-sections.mjs +247 -0
  52. package/engine/markup-validation.mjs +7 -2
  53. package/engine/metadata-index.mjs +1 -0
  54. package/engine/name-markup.mjs +114 -0
  55. package/engine/name-rows.mjs +70 -0
  56. package/engine/names.mjs +460 -0
  57. package/engine/note-addresses.mjs +25 -4
  58. package/engine/note-claims.mjs +2 -0
  59. package/engine/note-state.mjs +9 -3
  60. package/engine/note-vocabulary.mjs +7 -6
  61. package/engine/path-charset.mjs +24 -1
  62. package/engine/pdf-build.mjs +9 -9
  63. package/engine/pdf-render.mjs +15 -1
  64. package/engine/site-build.mjs +16 -2
  65. package/engine/site-index.mjs +5 -1
  66. package/engine/sql-tables.mjs +324 -44
  67. package/engine/stub-lint.mjs +10 -5
  68. package/engine/web-wikilinks.mjs +8 -6
  69. package/engine/word-rows.mjs +20 -12
  70. package/engine/word-terms.mjs +15 -6
  71. package/engine/yaml-lint.mjs +3 -5
  72. package/hugo-theme/static/css/style.css +4 -0
  73. package/package.json +1 -1
  74. package/types/engine/anchors.d.mts +4 -2
  75. package/types/engine/compendiums.d.mts +5 -1
  76. package/types/engine/compile-corpus.d.mts +5 -2
  77. package/types/engine/content-charset.d.mts +5 -1
  78. package/types/engine/content-html.d.mts +5 -1
  79. package/types/engine/content-icons.d.mts +5 -1
  80. package/types/engine/content-images.d.mts +5 -1
  81. package/types/engine/content-index.d.mts +102 -18
  82. package/types/engine/content-links.d.mts +22 -8
  83. package/types/engine/content-session.d.mts +108 -0
  84. package/types/engine/content-sources.d.mts +32 -0
  85. package/types/engine/content-spans.d.mts +3 -5
  86. package/types/engine/content-tables.d.mts +2 -1
  87. package/types/engine/content-tasklists.d.mts +5 -1
  88. package/types/engine/culture-reach.d.mts +22 -2
  89. package/types/engine/data-keys.d.mts +7 -0
  90. package/types/engine/diagnostics.d.mts +10 -0
  91. package/types/engine/dictionary-layout.d.mts +35 -4
  92. package/types/engine/dictionary-rows.d.mts +9 -0
  93. package/types/engine/extension-attributes.d.mts +16 -2
  94. package/types/engine/first-use.d.mts +31 -0
  95. package/types/engine/foundry-entries.d.mts +14 -5
  96. package/types/engine/generate.d.mts +5 -1
  97. package/types/engine/heading-attributes.d.mts +2 -2
  98. package/types/engine/helpers.d.mts +33 -7
  99. package/types/engine/index.d.mts +1 -0
  100. package/types/engine/journals.d.mts +5 -2
  101. package/types/engine/language-terms.d.mts +7 -0
  102. package/types/engine/lexical-sections.d.mts +96 -0
  103. package/types/engine/markup-validation.d.mts +2 -1
  104. package/types/engine/name-markup.d.mts +176 -0
  105. package/types/engine/name-rows.d.mts +35 -0
  106. package/types/engine/names.d.mts +356 -0
  107. package/types/engine/note-addresses.d.mts +3 -3
  108. package/types/engine/note-state.d.mts +2 -1
  109. package/types/engine/path-charset.d.mts +16 -1
  110. package/types/engine/site-build.d.mts +6 -3
  111. package/types/engine/site-index.d.mts +3 -1
  112. package/types/engine/sql-tables.d.mts +39 -4
  113. package/types/engine/stub-lint.d.mts +3 -1
  114. package/types/engine/word-rows.d.mts +9 -7
package/docs/commands.md CHANGED
@@ -1004,9 +1004,11 @@ scattered entries instead of one.
1004
1004
 
1005
1005
  `group` rewrites the first `## <version>` section of `CHANGELOG.md` in
1006
1006
  place. Within each `### <Bump> Changes` body, every block sharing one bold
1007
- label is merged into a single block for that label — its bullets kept in
1008
- the order they were originally written, an exact-duplicate bullet kept
1009
- once — and the merged blocks are reordered: the unlabelled lead paragraph a
1007
+ label is merged into a single block for that label. Prose and bullets are
1008
+ retained, with exact duplicate items kept once. Opening paragraphs from
1009
+ merged labels combine in source order before their items. Wrapped
1010
+ paragraphs, nested item content and literal code stay intact. The merged
1011
+ blocks are reordered: the unlabelled lead paragraph a
1010
1012
  changeset writes with no category first, then every label
1011
1013
  [`changelog.labels`](configuration.md#changelog) declares, in the order
1012
1014
  given, then any label absent from that list last, in the order it first
@@ -1501,6 +1503,73 @@ package-build: This repository declares no end-to-end suite to `run`. Name one u
1501
1503
 
1502
1504
  ## Content operations
1503
1505
 
1506
+ ### `package-build content run <targets..>`
1507
+
1508
+ **NAME**
1509
+
1510
+ Run selected content checks and outputs from one captured source tree.
1511
+
1512
+ **SYNOPSIS**
1513
+
1514
+ ```text
1515
+ package-build content run <targets..> [--no-references] [--pack <name>] [--out <dir>]
1516
+ ```
1517
+
1518
+ **DESCRIPTION**
1519
+
1520
+ Choose one or more of `index`, `lint`, `links` and `compile`. The command runs
1521
+ each selected target once, in that order, regardless of the argument order.
1522
+ They perform the same operations as `content-index`, `lint`, `links` and
1523
+ `package compile`. The standalone commands remain available.
1524
+
1525
+ The selected operations share captured files, parsed frontmatter, content
1526
+ records and exact-source markup scans. Public and complete SQL preparations
1527
+ remain separate, as do prose-link checking and native document resolution.
1528
+ Each invocation starts a fresh in-memory session; independent commands do
1529
+ their own work. Finish dependency fetching, source generation and asset
1530
+ preparation before running this command, and start a new invocation after
1531
+ changing any input.
1532
+
1533
+ All selected preparations finish before the first output is written. If
1534
+ source or writer preparation fails, `index` and `compile` leave existing
1535
+ index, intermediate JSON and staged packs untouched. Read-only targets still
1536
+ report the findings they can produce. An ordinary lint error does not block
1537
+ an otherwise successful index or compile target. The command writes no
1538
+ persistent source cache.
1539
+
1540
+ Selecting `compile` applies the package command's existing package-kind rule
1541
+ before any writer. A documentation package can select `index` alone; selecting
1542
+ `index compile` reports the compile refusal and leaves its index untouched.
1543
+
1544
+ **OPTIONS**
1545
+
1546
+ | Option | Type | Default | Description |
1547
+ | ----------------- | ------- | ------------------------ | ------------------------------------------- |
1548
+ | `--references` | boolean | true | Check frontmatter references during `lint`. |
1549
+ | `--pack` `<name>` | string | all configured packs | Restrict `compile` to this pack. |
1550
+ | `--out` `<dir>` | string | configured content index | Set the `index` output directory. |
1551
+
1552
+ **EXIT STATUS**
1553
+
1554
+ 0 when every selected target succeeds, including advisory warnings. 1 when
1555
+ arguments or preparation fail, or any selected target reports an error.
1556
+
1557
+ **EXAMPLES**
1558
+
1559
+ ```bash
1560
+ package-build content run lint links
1561
+ package-build content run index compile
1562
+ package-build content run index lint links compile
1563
+ ```
1564
+
1565
+ **SEE ALSO**
1566
+
1567
+ `package-build content-index`, `package-build lint`, `package-build links`,
1568
+ `package-build package compile`, [Configuration](configuration.md),
1569
+ [Programmatic sessions](api.md#enginecontentsession).
1570
+
1571
+ ---
1572
+
1504
1573
  ### `package-build package <action> [pack] [entry]`
1505
1574
 
1506
1575
  **NAME**
@@ -2012,6 +2081,21 @@ dependencies; exact Item UUID validation remains part of compilation. Reads
2012
2081
  the content tree named by `root`, defaulting to
2013
2082
  `paths.content`; writes nothing.
2014
2083
 
2084
+ Name marking is advisory: lint checks explicit `.name` spans and authored link
2085
+ labels against the [name-marking
2086
+ conventions](authoring/links-and-markup.md#marking-names-in-prose). Plain prose
2087
+ is not searched for names. It builds one matcher from the current local and
2088
+ dependency names, then
2089
+ reports each affected occurrence at its exact source location. These warnings
2090
+ also appear when `lint` is selected in `content run`; they do not fail the run.
2091
+
2092
+ Lint also emits one grouped package advisory for marked names without an
2093
+ indexed full-name or alias match, and for conflicting supplied classifications.
2094
+ It lists every source use and is located at the earliest reported span.
2095
+ Untyped uses and compatible type/subtype refinements do not conflict.
2096
+ An invalid supplied `.name` `data-type` is a located preparation error and
2097
+ prevents selected writers. See the same name-marking guide for typed examples.
2098
+
2015
2099
  Content lint computes source positions when it emits findings and shares each
2016
2100
  note's YAML position document across consecutive lookups.
2017
2101
 
@@ -2182,6 +2266,9 @@ wikilink at all. Also reports a vendored foreign-package content index that
2182
2266
  has drifted out of reach, naming `package-build deps fetch` as the fix. Resolves
2183
2267
  address-valued SoHL system fields declared by the installed schema against this
2184
2268
  package and its declared dependencies.
2269
+ An anchored reference to a dependency's readable note must name a prose anchor
2270
+ in its fetched content index. A missing section is an error even when the page
2271
+ address resolves. Event ids are not prose sections and cannot be wikilink targets.
2185
2272
  Reads the content tree named by `root`, defaulting to `paths.content`, and
2186
2273
  the cached content indexes of any declared dependency; writes nothing.
2187
2274
 
@@ -2342,16 +2429,27 @@ package-build content-index [root] [--out <dir>]
2342
2429
 
2343
2430
  **DESCRIPTION**
2344
2431
 
2345
- Emits this package's note index as JSON Lines — one record per note,
2346
- carrying its full frontmatter plus its place in the tree. Every build
2347
- already walks the tree and parses every note's frontmatter and then throws
2348
- the result away; this publishes that walk so anything outside a build can
2349
- query the content without paying for a second walk. Its own command rather
2350
- than only a build step, because the point is that anyone can regenerate it
2351
- at will — the artifact costs a frontmatter parse, not a build, which is
2352
- also what lets it stay uncommitted. Reads the content tree named by `root`,
2353
- defaulting to `paths.content`; writes `<contentPackage>-metadata.jsonl`
2354
- into `--out`, defaulting to the configured `paths.contentIndex`.
2432
+ Emits this package's note index as JSON Lines, carrying full frontmatter,
2433
+ tree positions, prose and event anchors, and document targets. Reads the
2434
+ content tree named by `root`, defaulting to `paths.content`; writes
2435
+ `<contentPackage>-metadata.jsonl`, `<contentPackage>-dictionary.jsonl` and
2436
+ `<contentPackage>-terms.jsonl` into `--out`, defaulting to the configured
2437
+ `paths.contentIndex`.
2438
+
2439
+ Metadata includes each own note's authored `.name` occurrences under `names`,
2440
+ with visible text, nullable type/subtype and original source line/column.
2441
+ Local and dependency SQL schemas expose them through `names`; they travel in
2442
+ the metadata artifact.
2443
+
2444
+ The command prepares SQL tables, page lists, automatic sections and scalar
2445
+ expressions before publishing their prose targets. Each source uses its own
2446
+ audience for prose declarations: public notes use public providers and usage,
2447
+ and GM notes use the complete corpus. Native target maps use the compendium's
2448
+ complete SQL corpus and expose only declared prose slugs present there, with
2449
+ their actual native page targets. Readable item documentation targets its
2450
+ documentation journal. An empty published prose-anchor list declares no prose targets,
2451
+ including for pages without a Foundry document. Preparation errors leave all
2452
+ three output files untouched.
2355
2453
 
2356
2454
  **OPTIONS**
2357
2455
 
@@ -9,7 +9,7 @@ subType: userguide
9
9
 
10
10
  A content package begins with Markdown notes under `assets/content/`. Each note has YAML frontmatter describing its identity and data, followed by prose. Folder names beneath `assets/content/` are for authors; `type`, `subType`, and Addresses determine what the build creates.
11
11
 
12
- Every typed note requires a nonempty body, including drafts, folders and homepages. An empty or whitespace-only body is an error. A nonempty body with fewer than 25 prose words warns unless tagged `draft`; the tag never exempts an empty body. A `folder` note needs only a nonempty body: any content passes, with or without `draft`.
12
+ Nonempty `data.words` on a language note (`type: skill`, `subType: language`), or `data.glossary` on a culture or affiliation, supplies page content without an authored body. Every other typed note requires a nonempty body, including drafts, folders and homepages. An empty or whitespace-only body is otherwise an error. A nonempty body with fewer than 25 prose words warns unless tagged `draft`; the tag never exempts an empty body. A `folder` note needs only a nonempty body: any content passes, with or without `draft`.
13
13
 
14
14
  Start with [your first note](authoring/first-note.md). It explains the smallest valid note and shows the JournalEntry, web page, book entry, and content-index record made from it. Then use the chapters below in the order your note needs them.
15
15
 
@@ -31,6 +31,11 @@ Leading `:` captions describe the next supported block; `:@` captions also numbe
31
31
 
32
32
  A code fence with language `poetry` keeps verse lines, stanza breaks and relative indentation. Its numbered caption uses the **Poem** label. Generic `:::` divs and `[inline spans]{.class}` accept attributes. See [poetry](authoring/links-and-markup.md#poetry), [fenced divs](authoring/links-and-markup.md#fenced-divs) and [inline spans](authoring/links-and-markup.md#inline-spans).
33
33
 
34
+ Mark a name without a note as `[Name]{.name data-type="being"}`; the optional
35
+ classification uses the declared note vocabulary. The [name-marking
36
+ guide](authoring/links-and-markup.md#marking-names-in-prose) explains its syntax,
37
+ index and grouped lint advice.
38
+
34
39
  Body extensions use braces with space-separated `key=value` attributes:
35
40
  `![[icon-harbor|Harbor]]{float=top-left size=medium}` and an SQL fence with
36
41
  `{allow-empty=true}` are examples. Inline font glyphs use the package's icon
@@ -166,6 +171,6 @@ Places, affiliations, lore and beings may name their culture in `data.culture`,
166
171
 
167
172
  An affiliation may name the trade, temple or order tongue it keeps in its own `data.language`. An affiliation that reaches no culture is a warning, in a tree holding a culture note. A language needs no culture and no affiliation. See [type: affiliation](reference/format-details.md#type-affiliation).
168
173
 
169
- A language note (`type: skill`, `subType: language`) states its words in frontmatter: `data.words` states each word as a map of its form, class, field and gloss — one sense or a list of them, which a dictionary numbers — with its source, its variant forms, the pieces it is built from and a note, beside `data.classModifiers`, `data.fields` and `data.affixes`, each affix with the `kind` it makes, for a given name's ending who the name is `given` to, and the stem closes it is barred after; a zero affix states `zero: true` and no form. The notes a word is cited from are derived, not written: a note cites a word by marking it in italics in its prose, matched by form or a variant with diacritics and case set aside. The language of a word is the note it sits on, and none of it reaches the compiled Item. A daughter language names its parent in `data.family` and reads the parent's words as its own; the `language_lineage` relation joins a language to its ancestors. Classes come from the [master word classes](reference/format-details.md#word-classes). A culture or an affiliation states its own glossary terms in `data.glossary`, and every entry resolves to a language — its own `language`, else the affiliation's, its parents' or its culture's, else the culture's — or is an error at the entry. The `words`, `affixes`, `fields`, `glossary` and `language_lineage` relations hold them for `sql` fences, the `dictionary` relation lists each word under every language that has it, inherited words included, and the `terms` relation each glossary entry, rank and office with the cultures it reaches; a fence sets them with `layout=dictionary` or `layout=glossary`. A language note names the tag a dictionary prints for it in `data.abbreviation`. Every fact a check reads about a language's names, sounds and history is frontmatter too: `data.tongues` and `data.register` (every name the setting gives in the language's reach, the notes carrying each derived from the index), `data.retired`, `data.scope`, `data.sounds` (letters with their place, word edges from a closed list, the cluster limit and the groups of clusters inside a word, the stress rule, syllable finals, syllable rules and vowel harmony with each vowel's front partner, the joining of parts, written marks, a root's skeleton vowel and frames, the spellings read past, and named mutations such as wearing and voicing), `data.soundChanges` (named sets of ordered steps), `data.elements` (each standing `opening`, `closing`, `either` or `link`, for one kind of name, with the word it is the stem of and its genitive), `data.roots`, `data.cognates` (with a reconstructed `proto` form), `data.callingNames`, `data.older` (the forms older than the rules), `data.negation` (the negative particle and the mutation it brings) and `data.naming` (how long each class of name runs, the edges names keep that words do not, the element kinds each kind of name draws on, what a place name takes from what it is held from, and the near name), each a relation — `sounds` as `letters`, `edges`, `clusters`, `cluster_groups`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past` and `mutations`, `soundChanges` as `sound_changes`, `callingNames` as `calling_names` — that a fence sets back on the page. A word's citations also come from a note whose name, alias or rank or office title spells it whole. See [a language's words](reference/format-details.md#a-languages-words), [a language's register, sounds and history](reference/format-details.md#a-languages-register-sounds-and-history), [glossary terms](reference/format-details.md#glossary-terms) and [dictionaries and glossaries](reference/format-details.md#dictionaries-and-glossaries).
174
+ A language note (`type: skill`, `subType: language`) states its words in frontmatter: `data.words` states each word as a map of its form, class, field and gloss — one sense or a list of them, which a dictionary numbers — with its source, its variant forms, the pieces it is built from and a note, beside `data.classModifiers`, `data.fields` and `data.affixes`, each affix with the `kind` it makes, for a given name's ending who the name is `given` to, and the stem closes it is barred after; a zero affix states `zero: true` and no form. The notes a word is cited from are derived, not written: a note cites a word by marking it in italics in its prose, matched by form or a variant with diacritics and case set aside. The language of a word is the note it sits on, and none of it reaches the compiled Item. A daughter language names its parent in `data.family` and reads the parent's words as its own; the `language_lineage` relation joins a language to its ancestors. Classes come from the [master word classes](reference/format-details.md#word-classes). A culture or an affiliation states its own glossary entries in `data.glossary`: common words in its core vocabulary, dictionary words with a context meaning, or phrases, compounds and terms of art outside the dictionary with their own gloss. An entry naming a word of its resolved language takes the word's senses and class and links to its language entry; a `definition` supplies the entry's meaning instead. Common marks belong to the glossary's owner. A language note with nonempty `data.words` receives its full Dictionary section automatically: one alphabetical list with field tags and one key. A culture or affiliation with nonempty `data.glossary` receives only its explicitly declared entries in its Glossary section; ranks and offices stand in the affiliation's own sections. A note without the relevant frontmatter receives no such section. All surfaces show these sections after the authored text, or under an existing `{#dictionary}`, `{#lexicon}` or `{#glossary}` heading after its introduction. There are no setting-wide dictionary or glossary pages. Every entry resolves to a language — its own `language`, else the affiliation's, its parents' or its culture's, else the culture's — or is an error at the entry. The `words`, `affixes`, `fields`, `glossary` and `language_lineage` relations hold them for `sql` fences, the `dictionary` relation lists each word under every language that has it, inherited words included, and the `terms` relation each glossary entry, rank and office with its culture associations; a fence sets custom views with `layout=dictionary` or `layout=glossary`. A language note names the tag a dictionary prints for it in `data.abbreviation`. Every fact a check reads about a language's names, sounds and history is frontmatter too: `data.tongues` and `data.register` (every name the setting gives in the language's reach, the notes carrying each derived from the index), `data.retired`, `data.scope`, `data.sounds` (letters with their place, word edges from a closed list, the cluster limit and the groups of clusters inside a word, the stress rule, syllable finals, syllable rules and vowel harmony with each vowel's front partner, the joining of parts, written marks, a root's skeleton vowel and frames, the spellings read past, and named mutations such as wearing and voicing), `data.soundChanges` (named sets of ordered steps), `data.elements` (each standing `opening`, `closing`, `either` or `link`, for one kind of name, with the word it is the stem of and its joining form), `data.roots`, `data.cognates` (with a reconstructed `proto` form), `data.callingNames`, `data.older` (the forms older than the rules), `data.negation` (the negative particle and the mutation it brings) and `data.naming` (how long each class of name runs, the edges names keep that words do not, the element kinds each kind of name draws on, what a place name takes from what it is held from, and the near name), each a relation — `sounds` as `letters`, `edges`, `clusters`, `cluster_groups`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past` and `mutations`, `soundChanges` as `sound_changes`, `callingNames` as `calling_names` — that a fence sets back on the page. A word's citations also come from a note whose name, alias or rank or office title spells it whole. See [a language's words](reference/format-details.md#a-languages-words), [a language's register, sounds and history](reference/format-details.md#a-languages-register-sounds-and-history), [glossary terms](reference/format-details.md#glossary-terms) and [dictionaries and glossaries](reference/format-details.md#dictionaries-and-glossaries).
170
175
 
171
176
  Blockquote alerts use `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, or `[!]`, with optional attributes after the marker. They replace the former info and warn div fences; secret blocks remain supported. See [alerts](authoring/links-and-markup.md#alerts).
@@ -170,7 +170,7 @@ package-build.config.yaml:382:64: error: package-build config: `site.sections.be
170
170
 
171
171
  ## A worked case: the three states of a note
172
172
 
173
- A note with an empty body is a **stub**, and the diagnostics about one show each
173
+ A place note with an empty body is a **stub**, and the diagnostics about one show each
174
174
  rule above in turn.
175
175
 
176
176
  An empty body must be deliberate, so a stub that says nothing about itself is an
@@ -20,7 +20,8 @@ Start with one pack for each document class the notes produce. An Item, Actor,
20
20
  Macro, Scene, or Adventure note can also produce a JournalEntry for its prose,
21
21
  so a package with those notes generally needs a JournalEntry pack. A missing
22
22
  pack for a document a note actually produces is a finding on that note. An
23
- empty body produces no prose journal and needs no pack for it.
23
+ empty body without automatic Dictionary or Glossary content produces no prose
24
+ journal and needs no pack for it.
24
25
 
25
26
  ```yaml
26
27
  packs:
@@ -62,10 +62,10 @@ takes.
62
62
 
63
63
  `data.pack: none` is appropriate when the page belongs on the site and in the
64
64
  index but does not need a Foundry compendium entry. A documentation package
65
- has no packs at all. A page with an empty body is a stub: it remains in the
66
- index for data references, but publishes no page address or anchors. Write a
67
- description for a stub and leave off the `draft` tag; use `draft` for a page
68
- with prose still in progress. The [stub rules](../reference/format-details.md#a-stub-is-a-note-with-an-empty-body)
65
+ has no packs at all. A page with neither an authored body nor automatic
66
+ Dictionary or Glossary content is a stub: it remains in the index for data
67
+ references, but publishes no page address or anchors. Supply content before
68
+ publishing; use `draft` for prose still in progress. The [stub rules](../reference/format-details.md#a-stub-is-a-note-with-an-empty-body)
69
69
  and [pack routing](packs.md) cover these cases.
70
70
 
71
71
  ## Link to the intended target
@@ -165,92 +165,115 @@ reconstructing them from filenames.
165
165
 
166
166
  ## Set words as a dictionary and terms as a glossary
167
167
 
168
- A language's words and a people's terms are each one `sql` fence, and nothing
169
- is copied into the note: the words come from the language notes' `data.words`,
170
- the terms from the `data.glossary` entries of cultures and affiliations and
171
- from the affiliations' ranks and offices, and a section changes when they do.
172
- `layout=dictionary` sets rows of the `dictionary` relation and
173
- `layout=glossary` rows of the `terms` relation. The query decides what
174
- appears, so any note may carry either.
168
+ A language note's `data.words` supplies its Dictionary section automatically
169
+ on the site, in the Foundry journal and in the book. The dictionary is the
170
+ language's full word list, including inherited words, in one alphabetical
171
+ sequence with letter headings, field tags and one key. A language with absent
172
+ or empty `data.words` receives no Dictionary section.
175
173
 
176
- A language note lists its words, with the words it inherits from its parent
177
- language:
174
+ The frontmatter states the words:
178
175
 
179
- ````markdown
180
- # Dictionary {#dictionary}
181
-
182
- ```sql {layout=dictionary section-level=2}
183
- SELECT * FROM dictionary WHERE language = 'thalorna-note-skill-provnzlng'
176
+ ```yaml
177
+ shortcode: provnzlng
178
+ name: { full: Provenzal Language }
179
+ type: skill
180
+ subType: language
181
+ data:
182
+ classModifiers: [f, m]
183
+ fields:
184
+ - { name: Love and its conduct, holds: "Longing, courtship and the courts of love." }
185
+ words:
186
+ - {
187
+ form: solmère,
188
+ class: n m,
189
+ pronunciation: sol-MEH-reh,
190
+ field: Love and its conduct,
191
+ gloss: "longing; the ache for a person, a place or a time that is gone",
192
+ }
193
+ - {
194
+ form: amère,
195
+ class: n f,
196
+ field: Love and its conduct,
197
+ gloss: ["a beloved", "a sweetheart, in the songs"],
198
+ }
184
199
  ```
185
- ````
186
200
 
187
- A culture note lists the words of its tongue a player is expected to know, and
188
- its glossary: its own terms and the ranks, offices and terms of every
189
- affiliation that reaches it.
201
+ A culture or affiliation's `data.glossary` supplies its Glossary section. It
202
+ contains only that owner's declared entries, so each culture and affiliation
203
+ using a language chooses its own common words and context meanings. Ranks
204
+ and offices stand in the affiliation's own sections; an explicit glossary
205
+ entry can name one, but a glossary does not draw in the whole ladder or list
206
+ of offices. A note with absent or empty `data.glossary` receives no Glossary
207
+ section.
190
208
 
191
- ````markdown
192
- # Words Everyone Knows {#common-words}
209
+ The [worked culture glossary](../reference/format-details.md#glossary-terms)
210
+ uses all three reasons for an entry:
193
211
 
194
- ```sql {layout=dictionary section-level=2}
195
- SELECT * FROM dictionary WHERE language = 'thalorna-note-skill-provnzlng' AND common
212
+ ```yaml
213
+ data:
214
+ language: skill-provnzlng
215
+ glossary:
216
+ - { name: solmère, common: true }
217
+ - { name: amère, definition: "a sweetheart, in the songs" }
218
+ - {
219
+ name: blood-field,
220
+ definition: "ground where a battle tore the boundary with the spirit world, and it did not close",
221
+ }
196
222
  ```
197
223
 
198
- # Glossary {#glossary}
199
-
200
- ```sql {layout=glossary section-level=2}
201
- SELECT * FROM terms WHERE list_contains(cultures, 'thalorna-note-lore-provenzianclt')
202
- ```
203
- ````
224
+ `solmère` is part of this culture's core vocabulary: the words a player needs
225
+ to adventure there. With no `definition`, it carries the senses and class of
226
+ the dictionary word and links to that word's entry. `amère` supplies a context
227
+ meaning, which takes the place of its dictionary senses while retaining the
228
+ word link and class. `blood-field` supplies a gloss for a term outside the
229
+ dictionary. Common marks belong to the glossary's owner; dictionaries mark
230
+ nothing common. There are no setting-wide dictionary or glossary pages.
204
231
 
205
- The glossary renders as a key, a heading per letter and one paragraph per
206
- term, each sense tagged with the body or culture it comes from and each term
207
- in another tongue tagged with it:
232
+ The generated sections follow the note's authored text. A heading with
233
+ `{#dictionary}` or `{#lexicon}` receives the Dictionary list, and a heading
234
+ with `{#glossary}` receives the Glossary list, after the authored text in
235
+ that section. This preserves an introduction or loanword discussion under
236
+ an anchored heading:
208
237
 
209
238
  ```markdown
210
- **Key:** _Lit._ Liturgic Language; • a common word, which a player is expected to know by heart.
239
+ # Lexicon {#lexicon}
211
240
 
212
- ## K
213
-
214
- **Knight-Captain** **1** (_Kingdom of Provenzia_) A knight who leads a company. **2** (_Kingdom of Provenzia_) Commands the guard in the field. — [[thalorna-note-affiliation-kingdom|Kingdom of Provenzia]]
215
-
216
- ## O
217
-
218
- **Ordained Priest** _Lit._ (_Church of the Rite_) Ordained to serve a parish. — [[thalorna-note-affiliation-church|Church of the Rite]]
241
+ The tongue of Provenzia, whose _solmère_ is its own word.
219
242
  ```
220
243
 
221
- The culture shapes both through its own `data.glossary`.
222
- `{name: solmère, common: true, pronunciation: sol-MEH-reh}` marks a word of its
223
- tongue common, so the first fence lists it, and gives it a respelling;
224
- `{name: Subject, common: true}` marks a rank and lets in a title of one word,
225
- which no glossary holds unless an entry names it; and
226
- `{name: blood-field, definition: …}` is a term of the culture's own.
244
+ The list is generated once under that heading. Without such a heading, the
245
+ build supplies **Dictionary** or **Glossary** at the end of the note.
227
246
 
228
- An affiliation lists its own terms with `WHERE owner = '<its Address>'`. The
229
- setting's two pages list everything, each word once and each term under every
230
- owner that holds it:
247
+ ### Custom views
231
248
 
232
- ````markdown
233
- ```sql {layout=dictionary}
234
- SELECT * EXCLUDE (common) FROM dictionary WHERE depth = 0
235
- ```
236
- ````
249
+ An `sql` fence with `layout=dictionary` or `layout=glossary` can add a custom
250
+ view of the same `dictionary` and `terms` relations. This one selects only a
251
+ culture's common entries:
237
252
 
238
253
  ````markdown
239
- ```sql {layout=glossary}
240
- SELECT * EXCLUDE (common) FROM terms
254
+ # Words Everyone Knows {#common-words}
255
+
256
+ ```sql {layout=glossary section-level=2}
257
+ SELECT * FROM terms WHERE owner = 'thalorna-note-lore-provenzianclt' AND common
241
258
  ```
242
259
  ````
243
260
 
244
- `package-build content-index` also writes both relations beside the index, for
245
- reading with `jq`:
261
+ The `terms` relation also holds ranks and offices for custom queries. The
262
+ default Glossary section selects only rows arising from its owner's explicit
263
+ `data.glossary` entries, including an entry naming a rank or office. The
264
+ [layout guide](../authoring/links-and-markup.md#dictionaries-and-glossaries)
265
+ describes query options and rendering.
266
+
267
+ `package-build content-index` writes both relations beside the index. To
268
+ read a culture's own entries with `jq`:
246
269
 
247
270
  ```bash
248
- jq -r 'select(.cultures | index("thalorna-note-lore-provenzianclt")) | .name' \
271
+ jq -r 'select(.owner == "thalorna-note-lore-provenzianclt") | .name' \
249
272
  build/content-index/thalorna-terms.jsonl
250
273
  ```
251
274
 
252
275
  The [format reference](../reference/format-details.md#dictionaries-and-glossaries)
253
- gives every column and every rule.
276
+ gives every column and rule.
254
277
 
255
278
  ## Resolve another package
256
279