@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
@@ -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. This includes folder and homepage notes. A nonempty body with fewer than 25 prose words produces a warning unless the note has a `draft` tag. 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).
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).
@@ -23,6 +23,69 @@ A link to a note tagged `draft` retains its target and carries a visible draft c
23
23
 
24
24
  An HTML comment is an aside to whoever reads the note next, and no surface shows one — the packs and the website emit it into the HTML, where it stays a comment, and a book leaves it out. Write a `markdownlint` pragma or a note about a quoted passage freely. A comment inside a fence or a code span is an example and is printed as written, and a comment that is never closed is an error.
25
25
 
26
+ ## Marking names in prose
27
+
28
+ Use `[Name]{.name}` for a name that has no indexed note. Link a name that has
29
+ one; an empty link label uses the indexed full name. Bold is emphasis.
30
+ Plain text, including capitalized words, is not searched for names.
31
+
32
+ ```markdown
33
+ [[place-arden|Arden Vale]] stands beside the river. Arden Vale has two gates.
34
+ [Hidden Hand]{.name} keeps watch over the crossing.
35
+ ```
36
+
37
+ To name something that has no note yet, mark it with its type instead of
38
+ creating a placeholder note:
39
+
40
+ ```markdown
41
+ [Ravenmoor]{.name data-type="place/settlement"}
42
+ [Aldric Venn]{.name data-type="being"}
43
+ ```
44
+
45
+ `data-type` is optional. It names a declared [note type and
46
+ subtype](../reference/note-types.md), written as `type` or `type/subType`.
47
+ Enumerated subtypes must belong to that type's list; an open declaration
48
+ accepts a well-formed note subtype, and a type without a subtype declaration
49
+ takes only the bare type. An invalid supplied value is an error at the
50
+ attribute. Site and Foundry spans retain the classes and attribute values;
51
+ the attribute adds no book presentation.
52
+
53
+ `package-build lint` warns when an indexed name or alias uses `.name`
54
+ instead of a link, when the same name is marked or linked again, or when a
55
+ short form appears before its full name. Only marked names and authored link
56
+ labels count toward these rules. Introduce the full name before an alias such
57
+ as `Arden`, then use plain text for later mentions. Full names and their
58
+ declared aliases count as the same name, including in links to different
59
+ headings. Different labels do not become the same name just because they link
60
+ to the same page.
61
+
62
+ A name span can sit inside emphasis:
63
+
64
+ ```markdown
65
+ **This is a phrase with [Joe Blow]{.name} in it**
66
+ ```
67
+
68
+ The marked name is `Joe Blow`. Sites and books display `.name` text in bold, including
69
+ inside an emphasized phrase. A whole bold span matching an indexed name or
70
+ alias receives an advisory to mark or link that name; bold containing an
71
+ explicit name span or link needs no such advisory.
72
+
73
+ These are warnings at each occurrence's `file:line:column`; they do not make
74
+ a valid package fail. The check reads authored prose outside headings,
75
+ tables, infoboxes, code, frontmatter, comments and embeds. See the
76
+ [complete name-marking rules](../reference/format-details.md#marking-names-in-prose).
77
+
78
+ The index records every actual `.name` span in the authored body, including
79
+ headings, tables, verse and spans inside links. The `names` SQL relation holds
80
+ its visible text, optional type/subtype and source location. Plain prose, bold,
81
+ unmarked link labels and generated content add no rows.
82
+
83
+ Lint also gives one grouped package advisory for names without a matching
84
+ indexed full name or alias, and for conflicting supplied classifications. It
85
+ lists every use and starts at the earliest reported span. Untyped uses do not
86
+ conflict, and `place` agrees with `place/settlement`; different supplied types
87
+ or different supplied subtypes conflict. These advisories do not fail lint.
88
+
26
89
  ## Journal pages and anchors
27
90
 
28
91
  Every H1 starts a JournalEntryPage. A lower-level heading with an explicit anchor starts a page too. Use `{#slug}` to make a stable target:
@@ -128,6 +191,9 @@ An attribute-bearing opener allows a nested div to be distinguished from the bar
128
191
  The watch wears [a _blue_ sash]{#watch-sash .uniform lang=en}.
129
192
  ```
130
193
 
194
+ Use `[Ravenmoor]{.name data-type="place/settlement"}` to mark a name with its
195
+ optional declared type; see [marking names](#marking-names-in-prose).
196
+
131
197
  Inline Markdown remains active inside the span. Bracket spans have lower priority than URL links, image links, reference links, footnotes and wikilinks. A bracketed form immediately preceded by `!`, followed by `(` or another `[`, or beginning with `[[` is not a span, even when the link is unresolved. Ordinary links retain their existing syntax. Escape a bracket when it should be literal, or put examples inside a code span or fence. A span identifier addresses that point in the note; it does not start a journal page.
132
198
 
133
199
  ### Alerts
@@ -323,50 +389,51 @@ A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cel
323
389
 
324
390
  ### What a query can read
325
391
 
326
- | Relation | What it holds |
327
- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
328
- | `notes` | Every note except a stub. This is the one to use unless a stub is wanted. |
329
- | `entries` | Every note, stubs included. |
330
- | `events` | One row per event a `lore`, `place` or `affiliation` note writes in `data.events`, with `whenSort` to order them by date. |
331
- | `words` | One row per word a language note writes in `data.words`, with that note as its `language`, its `position` and what it is built from. |
332
- | `affixes` | One row per affix a language note writes in `data.affixes`, with that note as its `language`, its `position`, and each key the affix states: `form` (`NULL` on a zero affix), `zero`, `kind`, `given`, `"where"`, `gloss`, `attaches`, `replaces`, `lengthens`, `front`, `examples`, `barredAfter` and `tones`, then `written`, the form as a table prints it, `∅` for a zero affix. |
333
- | `fields` | One row per field a language note writes in `data.fields`, with that note as its `language`, its `position`, and the field's `name` and what it `holds`. |
334
- | `glossary` | One row per entry a culture or an affiliation writes in `data.glossary`, with the `note` it belongs to and the `language` it resolves to. |
335
- | `language_lineage` | One row per language note and each language it inherits words from through `data.family`, itself included at `depth` 0. Join it to `words` for a language's words with inherited ones. |
336
- | `dictionary` | One row per word per language it is listed under, inherited words included, with its `depth`. See [dictionaries and glossaries](#dictionaries-and-glossaries). |
337
- | `terms` | One row per glossary entry, rank or office per note that owns it, with the `cultures` it reaches. See [dictionaries and glossaries](#dictionaries-and-glossaries). |
338
- | `register` | One row per name a language note writes in `data.register`, with its `tongue`, `kind`, `gloss` and `why`, its pieces as `built_text`, and the `notes` carrying the name, derived from the index. |
339
- | `tongues` | One row per tag a language note writes in `data.tongues`: `tag`, `meaning` and `tongue_language`. |
340
- | `retired` | One row per form a language note writes in `data.retired`: `form`, `instead` as a list, and `why`. |
341
- | `scope` | One row per value of a language note's `data.scope`: the `kind` it is under and the `value`. |
342
- | `letters` | One row per entry of a language note's `data.sounds.letters`: `letters` as a list, `kind`, `like`, `place` and `tongue`. |
343
- | `edges` | One row per entry of a language note's `data.sounds.edges`: the `edge` and its `sounds` as a list. |
344
- | `clusters` | One row per language note stating `data.sounds.clusters`, with its `max`. |
345
- | `cluster_groups` | One row per group of a language note's `data.sounds.clusters.groups`: `what`, `clusters` as a list, and `use`. |
346
- | `stress` | One row per language note stating `data.sounds.stress`, with its `stress`. |
347
- | `finals` | One row per entry of a language note's `data.sounds.finals`: `final` and `like`. |
348
- | `syllables` | One row per language note stating `data.sounds.syllables`: each rule a column, the harmony as `harmony_back`, `harmony_front`, `harmony_neutral`, `harmony_neutralAs` and `harmony_partners`, a list of `{ vowel, partner }`. |
349
- | `joining` | One row per entry of a language note's `data.sounds.joining`: `first`, `second`, `written` and `example`. |
350
- | `joins` | One row per entry of a language note's `data.sounds.joins`: `meeting`, `rule`, `letters` and `"where"`. |
351
- | `marks` | One row per entry of a language note's `data.sounds.marks`: `mark`, `letters`, `kind` and `"limit"`. |
352
- | `skeleton` | One row per entry of a language note's `data.sounds.skeleton`: `second` and `between`. |
353
- | `frames` | One row per frame of a language note's `data.sounds.frames`: `frame`, `shape`, `class`, `makes` and `examples` as `{ root, form }`. |
354
- | `read_past` | One row per entry of a language note's `data.sounds.readPast`: `written`, `readAs` and `what`. |
355
- | `mutations` | One row per entry of a language note's `data.sounds.mutations`: `mutation`, `sound`, `becomes` and `example`. |
356
- | `sound_changes` | One row per step of each set in a language note's `data.soundChanges`: the set's `position`, `name`, `from_language`, `to_language` and `takes`, then `step_position`, `step`, `change` and `"where"`. |
357
- | `elements` | One row per element of a language note's `data.elements`: `form`, `variants`, `element_position`, `kind`, `sense`, `examples`, `word` and `genitive`. |
358
- | `roots` | One row per root of a language note's `data.roots`: `root`, `sense` and `field`. |
359
- | `cognates` | One row per form of each set in a language note's `data.cognates`: the set's `position`, `gloss` and `proto`, the `form_language` and the `form`. |
360
- | `calling_names` | One row per closing of a language note's `data.callingNames`: `form`, `doubled`, `usual` and the language's `min_syllables`. |
361
- | `older` | One row per form of a language note's `data.older`: `form`, `gloss` and `layer`. |
362
- | `negation` | One row per language note stating `data.negation`: its `particle` and `mutation`. |
363
- | `name_shapes` | One row per entry of a language note's `data.naming.shapes`: `of`, `syllables_min`, `syllables_max`, `per_vowel_min` and `per_vowel_max`. |
364
- | `name_edges` | One row per entry of a language note's `data.naming.edges`: `edge`, `sounds` as a list, `vowel` and `of`. |
365
- | `name_draws` | One row per entry of a language note's `data.naming.draws`: `kind` and `elements` as a list. |
366
- | `held_from` | One row per entry of a language note's `data.naming.heldFrom`: `source`, `takes`, `clip`, and `genitive` and `elements` as lists. |
367
- | `near_names` | One row per worked example of a language note's `data.naming.nearName`: `near`, `given` and the language's `min_syllables`. |
368
- | `market` | The market scale as three columns — `value`, `name`, `trade` — so a table can print `village` beside the number a note wrote. |
369
- | `<package>.notes` | The same relations — `notes`, `entries`, `events`, `words`, `affixes`, `fields`, `glossary`, `language_lineage`, `dictionary`, `terms`, `register`, `tongues`, `retired`, `scope`, `letters`, `edges`, `clusters`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past`, `mutations`, `cluster_groups`, `sound_changes`, `elements`, `roots`, `cognates`, `calling_names`, `older`, `negation`, `name_shapes`, `name_edges`, `name_draws`, `held_from` and `near_names` — for each package this one declares a dependency on, in a schema named for it. |
392
+ | Relation | What it holds |
393
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
394
+ | `notes` | Every note except a stub. This is the one to use unless a stub is wanted. |
395
+ | `entries` | Every note, stubs included. |
396
+ | `events` | One row per event a `lore`, `place` or `affiliation` note writes in `data.events`, with `whenSort` to order them by date. |
397
+ | `names` | Each authored `.name` span, with its containing NOTE Address, visible text, optional type/subtype and source line/column. |
398
+ | `words` | One row per word a language note writes in `data.words`, with that note as its `language`, its `position` and what it is built from. |
399
+ | `affixes` | One row per affix a language note writes in `data.affixes`, with that note as its `language`, its `position`, and each key the affix states: `form` (`NULL` on a zero affix), `zero`, `kind`, `given`, `"where"`, `gloss`, `attaches`, `replaces`, `lengthens`, `front`, `examples`, `barredAfter` and `tones`, then `written`, the form as a table prints it, `∅` for a zero affix. |
400
+ | `fields` | One row per field a language note writes in `data.fields`, with that note as its `language`, its `position`, and the field's `name` and what it `holds`. |
401
+ | `glossary` | One row per entry a culture or an affiliation writes in `data.glossary`, with the `note` it belongs to and the `language` it resolves to. |
402
+ | `language_lineage` | One row per language note and each language it inherits words from through `data.family`, itself included at `depth` 0. Join it to `words` for a language's words with inherited ones. |
403
+ | `dictionary` | One row per word per language it is listed under, inherited words included, with its `depth`. See [dictionaries and glossaries](#dictionaries-and-glossaries). |
404
+ | `terms` | One row per glossary entry, rank or office per note that owns it, with its `cultures` associations. See [dictionaries and glossaries](#dictionaries-and-glossaries). |
405
+ | `register` | One row per name a language note writes in `data.register`, with its `tongue`, `kind`, `gloss` and `why`, its pieces as `built_text`, and the `notes` carrying the name, derived from the index. |
406
+ | `tongues` | One row per tag a language note writes in `data.tongues`: `tag`, `meaning` and `tongue_language`. |
407
+ | `retired` | One row per form a language note writes in `data.retired`: `form`, `instead` as a list, and `why`. |
408
+ | `scope` | One row per value of a language note's `data.scope`: the `kind` it is under and the `value`. |
409
+ | `letters` | One row per entry of a language note's `data.sounds.letters`: `letters` as a list, `kind`, `like`, `place` and `tongue`. |
410
+ | `edges` | One row per entry of a language note's `data.sounds.edges`: the `edge` and its `sounds` as a list. |
411
+ | `clusters` | One row per language note stating `data.sounds.clusters`, with its `max`. |
412
+ | `cluster_groups` | One row per group of a language note's `data.sounds.clusters.groups`: `what`, `clusters` as a list, and `use`. |
413
+ | `stress` | One row per language note stating `data.sounds.stress`, with its `stress`. |
414
+ | `finals` | One row per entry of a language note's `data.sounds.finals`: `final` and `like`. |
415
+ | `syllables` | One row per language note stating `data.sounds.syllables`: each rule a column, the harmony as `harmony_back`, `harmony_front`, `harmony_neutral`, `harmony_neutralAs` and `harmony_partners`, a list of `{ vowel, partner }`. |
416
+ | `joining` | One row per entry of a language note's `data.sounds.joining`: `first`, `second`, `written` and `example`. |
417
+ | `joins` | One row per entry of a language note's `data.sounds.joins`: `meeting`, `rule`, `letters` and `"where"`. |
418
+ | `marks` | One row per entry of a language note's `data.sounds.marks`: `mark`, `letters`, `kind` and `"limit"`. |
419
+ | `skeleton` | One row per entry of a language note's `data.sounds.skeleton`: `second` and `between`. |
420
+ | `frames` | One row per frame of a language note's `data.sounds.frames`: `frame`, `shape`, `class`, `makes` and `examples` as `{ root, form }`. |
421
+ | `read_past` | One row per entry of a language note's `data.sounds.readPast`: `written`, `readAs` and `what`. |
422
+ | `mutations` | One row per entry of a language note's `data.sounds.mutations`: `mutation`, `sound`, `becomes` and `example`. |
423
+ | `sound_changes` | One row per step of each set in a language note's `data.soundChanges`: the set's `position`, `name`, `from_language`, `to_language` and `takes`, then `step_position`, `step`, `change` and `"where"`. |
424
+ | `elements` | One row per element of a language note's `data.elements`: `form`, `variants`, `element_position`, `kind`, `sense`, `examples`, `word` and `joining`. |
425
+ | `roots` | One row per root of a language note's `data.roots`: `root`, `sense` and `field`. |
426
+ | `cognates` | One row per form of each set in a language note's `data.cognates`: the set's `position`, `gloss` and `proto`, the `form_language` and the `form`. |
427
+ | `calling_names` | One row per closing of a language note's `data.callingNames`: `form`, `doubled`, `usual` and the language's `min_syllables`. |
428
+ | `older` | One row per form of a language note's `data.older`: `form`, `gloss` and `layer`. |
429
+ | `negation` | One row per language note stating `data.negation`: its `particle` and `mutation`. |
430
+ | `name_shapes` | One row per entry of a language note's `data.naming.shapes`: `of`, `syllables_min`, `syllables_max`, `per_vowel_min` and `per_vowel_max`. |
431
+ | `name_edges` | One row per entry of a language note's `data.naming.edges`: `edge`, `sounds` as a list, `vowel` and `of`. |
432
+ | `name_draws` | One row per entry of a language note's `data.naming.draws`: `kind` and `elements` as a list. |
433
+ | `held_from` | One row per entry of a language note's `data.naming.heldFrom`: `source`, `takes`, `clip`, and `joining` and `elements` as lists. |
434
+ | `near_names` | One row per worked example of a language note's `data.naming.nearName`: `near`, `given` and the language's `min_syllables`. |
435
+ | `market` | The market scale as three columns — `value`, `name`, `trade` — so a table can print `village` beside the number a note wrote. |
436
+ | `<package>.notes` | The same relations — `notes`, `entries`, `events`, `names`, `words`, `affixes`, `fields`, `glossary`, `language_lineage`, `dictionary`, `terms`, `register`, `tongues`, `retired`, `scope`, `letters`, `edges`, `clusters`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past`, `mutations`, `cluster_groups`, `sound_changes`, `elements`, `roots`, `cognates`, `calling_names`, `older`, `negation`, `name_shapes`, `name_edges`, `name_draws`, `held_from` and `near_names` — for each package this one declares a dependency on, in a schema named for it. |
370
437
 
371
438
  Nested frontmatter is addressed exactly as a note writes it: `name.full`, `sohl.weight`, `data.born`. Every Address is a string — the full canonical Address, as in `list_contains(data.parents, 'thalorna-note-place-xerathia')` — whichever package published it. Every note carries a computed `state` column of `full`, `draft` or `stub`. Notes tagged `gm` are absent from the relations on public surfaces.
372
439
 
@@ -747,11 +814,11 @@ GROUP BY position, gloss ORDER BY position
747
814
  ```
748
815
  ````
749
816
 
750
- An element's `kind` keeps one set of elements apart from another, and a place's generic gives its `genitive`:
817
+ An element's `kind` keeps one set of elements apart from another, and a place's generic gives its `joining` form:
751
818
 
752
819
  ````markdown
753
820
  ```sql
754
- SELECT '`' || form || '`' AS "Generic", sense AS "What it names", coalesce('`' || genitive || '`', '—') AS "In the genitive"
821
+ SELECT '`' || form || '`' AS "Generic", sense AS "What it names", coalesce('`' || joining || '`', '—') AS "Joining form"
755
822
  FROM elements WHERE language = 'thalorna-note-skill-nordmalng' AND kind = 'place' ORDER BY position
756
823
  ```
757
824
  ````
@@ -809,7 +876,7 @@ SELECT source AS "held from",
809
876
  WHEN 'element' THEN array_to_string(list_transform(elements, x -> '`' || x || '`'), ', ')
810
877
  ELSE (CASE takes WHEN 'godName' THEN 'that god''s name' ELSE 'that founder''s given name' END)
811
878
  || coalesce(', clipped to its ' || clip || ' element', '')
812
- || coalesce(', with a genitive ' || array_to_string(list_transform(genitive, x -> '`' || x || '`'), ' or '), '')
879
+ || coalesce(', with a joining ending ' || array_to_string(list_transform(joining, x -> '`' || x || '`'), ' or '), '')
813
880
  END AS "what stands first"
814
881
  FROM held_from WHERE language = 'thalorna-note-skill-nordmalng' ORDER BY position
815
882
  ```
@@ -840,12 +907,12 @@ See [a language's register, sounds and history](../reference/format-details.md#a
840
907
 
841
908
  A braced list may follow the language on the opening fence. Four attributes are accepted, and anything else is reported by name.
842
909
 
843
- | Attribute | Value | Default | What it does |
844
- | --------------- | ----------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
845
- | `allow-empty` | `true` or `false` | `false` | Whether a query selecting no rows is allowed. A zero-row result is a finding otherwise, because a table that silently prints nothing is the commonest way a query goes wrong unnoticed. |
846
- | `section-level` | an integer from 1 through 6 | `2` | The heading level given to each group a `_section` column creates, and to each letter of a dictionary or a glossary. |
847
- | `key` | `true`, `false` or `only` | `true` | Whether a dictionary or a glossary prints its key. `false` leaves it out; `only` prints the key for the fence's rows and no letter or entry, so a page with one `key=false` fence per heading states its key once. Refused on a table. |
848
- | `layout` | `table`, `dictionary` or `glossary` | `table` | How the result is set: as a table, as a dictionary of words, or as a glossary of terms — see [dictionaries and glossaries](#dictionaries-and-glossaries). |
910
+ | Attribute | Value | Default | What it does |
911
+ | --------------- | ----------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
912
+ | `allow-empty` | `true` or `false` | `false` | Whether a query selecting no rows is allowed. A zero-row result is a finding otherwise, because a table that silently prints nothing is the commonest way a query goes wrong unnoticed. |
913
+ | `section-level` | an integer from 1 through 6 | `2` | The heading level given to each group a `_section` column creates, and to each letter of a dictionary or a glossary. |
914
+ | `key` | `true`, `false` or `only` | `true` | Whether a dictionary or a glossary prints its key. `false` omits the key and any dictionary verb table; `only` prints the key for the fence's rows and no table, letter or entry. Refused on a table. |
915
+ | `layout` | `table`, `dictionary` or `glossary` | `table` | How the result is set: as a table, as a dictionary of words, or as a glossary of terms — see [dictionaries and glossaries](#dictionaries-and-glossaries). |
849
916
 
850
917
  ````markdown
851
918
  ```sql {allow-empty=true section-level=3}
@@ -873,81 +940,165 @@ See [SQL details](../reference/format-details.md#content-tables) for query optio
873
940
 
874
941
  ### Dictionaries and glossaries
875
942
 
876
- Two layouts set a result as paragraphs under letter headings rather than as a table. **`layout=dictionary` sets words**, read from the `dictionary` relation: each with its class, its etymology, its senses, numbered where a word's `gloss` lists several, and the notes it is cited from — every note whose prose marks the word in italics. **`layout=glossary` sets terms**, read from the `terms` relation: a culture's or an affiliation's own glossary entries and an affiliation's ranks and offices, each sense tagged with the body or culture it comes from. Each needs the `name`, `senses` and `usage` columns, and a query that leaves one out is reported, naming the column.
877
-
878
- **The query decides what appears**, and any note may carry either fence. These are the common ones:
943
+ The build supplies a note's dictionary or glossary from its frontmatter on
944
+ every surface: the site, the Foundry journal and the book.
879
945
 
880
- | What | Layout | Query |
881
- | ----------------------------------------- | ------------ | --------------------------------------------------------------------------------- |
882
- | A language's dictionary | `dictionary` | `SELECT * FROM dictionary WHERE language = '<the language's Address>'` |
883
- | A language's common words, on any page | `dictionary` | `SELECT * FROM dictionary WHERE language = '<the language's Address>' AND common` |
884
- | A culture's glossary | `glossary` | `SELECT * FROM terms WHERE list_contains(cultures, '<the culture's Address>')` |
885
- | An affiliation's glossary | `glossary` | `SELECT * FROM terms WHERE owner = '<the affiliation's Address>'` |
886
- | The setting's _Dictionary of the Tongues_ | `dictionary` | `SELECT * EXCLUDE (common) FROM dictionary WHERE depth = 0` |
887
- | The setting's _Glossary_ | `glossary` | `SELECT * EXCLUDE (common) FROM terms` |
946
+ - **A language note with nonempty `data.words` receives a Dictionary section.** It
947
+ contains the language's full dictionary as one alphabetical list, with
948
+ letter headings, each word's field beside it and the key printed once. A
949
+ language with absent or empty `data.words` receives no Dictionary section.
950
+ - **A culture or affiliation with nonempty `data.glossary` receives a Glossary
951
+ section.** It contains only the entries that owner declares. Ranks and
952
+ offices stand in the affiliation's own sections; they enter its glossary
953
+ only when an explicit glossary entry names them. A note with absent or
954
+ empty `data.glossary` receives no Glossary section.
888
955
 
889
- A language's dictionary lists the words it inherits through `data.family` beside its own; `depth = 0` lists each word once, under the language that states it. A culture's glossary holds the culture's own terms and the ranks, offices and glossary terms of every affiliation that reaches it. The two setting pages leave out `common`, so they mark no entry: which words are common is a culture's judgement.
956
+ The sections follow the note's authored text. An existing heading with
957
+ `{#dictionary}` or `{#lexicon}` receives the dictionary after its authored
958
+ text; `{#glossary}` does the same for a glossary. The heading and its
959
+ introduction stay in place, with one generated list under it:
890
960
 
891
- The most common Vylari words, on the Vylarian culture's page:
961
+ ```markdown
962
+ ## Lexicon {#lexicon}
963
+
964
+ The tongue of Provenzia, whose _solmère_ is its own word.
965
+ ```
966
+
967
+ A dictionary belongs to a language; a glossary belongs to one culture or
968
+ affiliation. A glossary entry belongs for one of three reasons: a common word
969
+ in the owner's core vocabulary, a dictionary word with a context meaning,
970
+ or a phrase, compound or term of art outside the dictionary with its own
971
+ gloss. The [worked culture glossary](../reference/format-details.md#glossary-terms)
972
+ selects `solmère` as a common word, gives `amère` a context meaning and glosses
973
+ `blood-field` as a term outside the dictionary. Its frontmatter supplies the
974
+ whole default Glossary section. There are no setting-wide dictionary or
975
+ glossary pages.
976
+
977
+ A dictionary noun prints its gender from its existing class and its plural
978
+ where one is available: **marendos** _n. m., pl. marendoi_. An explicit
979
+ word plural wins; otherwise the language's optional `grammar.plural` rule
980
+ replaces the first matching literal ending. The language's optional
981
+ `grammar.verbs` pattern prints once as a small head table, after the key and
982
+ before the letters. Empty verb endings print as "unchanged". Grammar is
983
+ never inherited through `family`, and absent grammar leaves the dictionary
984
+ unchanged. The [worked noun and verb example](../reference/format-details.md#optional-noun-and-verb-forms)
985
+ shows both declarations. Only supplied shapes are checked; words are never
986
+ checked against the rule, and no language must state grammar.
987
+
988
+ An entry naming a word of its resolved language without a `definition`
989
+ carries the word's dictionary senses and class, with a link to the word's
990
+ entry on its language page. An entry with a `definition` carries that meaning
991
+ instead, retaining its word link and class when it names a dictionary word.
992
+ Ranks, offices and definitions carry their source body or culture beside
993
+ their senses. Common choices belong to each owner: a culture and an
994
+ affiliation using the same language choose independently, and a word may be
995
+ common in one glossary and absent from another. Dictionaries mark nothing
996
+ common.
997
+
998
+ Public dictionaries omit citations to GM-only notes. `links` checks generated
999
+ tables in the source note's audience: public notes use public rows, and GM
1000
+ notes retain GM citations. An authored link from a public note to a GM-only
1001
+ note is still reported.
1002
+
1003
+ #### Custom views
1004
+
1005
+ An `sql` fence with `layout=dictionary` or `layout=glossary` sets a custom view
1006
+ of the same relations. A dictionary view reads `dictionary`; a glossary view
1007
+ reads `terms`. Each needs the `name`, `senses` and `usage` columns; a query
1008
+ that leaves one out is reported, naming the column.
1009
+
1010
+ The optional `plural` and `verbs` columns supply noun plurals and the head
1011
+ table in a custom dictionary view; `SELECT *` includes both. A projection
1012
+ that omits these columns omits that presentation, as omitting `class` omits
1013
+ word classes. With the default or `key=true`, each selected language's pattern
1014
+ appears once per dictionary result, even when no abbreviation key is needed.
1015
+ `key=false` omits both the key and the verb table from a fragment;
1016
+ `key=only` prints only the abbreviation key. Separate head-enabled fences
1017
+ each print their own tables.
1018
+
1019
+ For a custom list of one culture's common entries:
892
1020
 
893
1021
  ````markdown
894
1022
  ## Words Everyone Knows {#common-words}
895
1023
 
896
- ```sql {layout=dictionary section-level=3}
897
- SELECT * FROM dictionary WHERE language = 'thalorna-note-skill-vylarilng' AND common
898
- ```
899
- ````
900
-
901
- A culture's glossary:
902
-
903
- ````markdown
904
- ## Glossary {#glossary}
905
-
906
1024
  ```sql {layout=glossary section-level=3}
907
- SELECT * FROM terms WHERE list_contains(cultures, 'thalorna-note-lore-provenzianclt')
1025
+ SELECT * FROM terms WHERE owner = 'thalorna-note-lore-provenzianclt' AND common
908
1026
  ```
909
1027
  ````
910
1028
 
911
- A page that sets several fences, one per heading, states its key once: a `key=only` fence at the head over all the rows the page sets, then `key=false` on each fence below it, so the abbreviations are not repeated under every heading. The `key=only` fence prints the key for its rows and no letter heading and no entry:
1029
+ A custom dictionary view can select one field from the language's dictionary:
912
1030
 
913
1031
  ````markdown
914
- ## Words {#words}
915
-
916
- ```sql {layout=dictionary key=only}
917
- SELECT * FROM dictionary WHERE language = 'thalorna-note-skill-vylarilng' AND depth = 0
918
- ```
919
-
920
- ### Love and its conduct
1032
+ ## Love and its conduct
921
1033
 
922
- ```sql {layout=dictionary key=false section-level=4}
923
- SELECT d.* FROM dictionary d JOIN words w ON w.language = d.language AND w.form = d.name
924
- WHERE d.language = 'thalorna-note-skill-vylarilng' AND w.field = 'Love and its conduct'
1034
+ ```sql {layout=dictionary section-level=3}
1035
+ SELECT * FROM dictionary
1036
+ WHERE language = 'thalorna-note-skill-provnzlng' AND field = 'Love and its conduct'
925
1037
  ```
926
1038
  ````
927
1039
 
928
- `key`, whatever its value, sets a dictionary's or a glossary's key, so it is refused on a fence set as a table.
1040
+ A custom view with several fences can print its key once: a `key=only` fence
1041
+ over all selected rows, then `key=false` on each fence below it. The
1042
+ `key=only` fence prints only the abbreviation key. `key`, whatever its value,
1043
+ is refused on a fence set as a table. The automatic Dictionary section
1044
+ prints its own key once for the full alphabetical list.
929
1045
 
930
1046
  Either layout prints, in order:
931
1047
 
932
- - **a key**, once, unless the fence sets `key=false`, and nothing else where it sets `key=only`, listing only the abbreviations the result uses — a language's tag, and for words a class or a modifier — each with what it stands for, and the common mark where an entry carries it;
933
- - **a heading per letter**, at `section-level`, accents taken off and apostrophes skipped, so `'ostal` files under O and `Écuyer` under E;
934
- - **one paragraph per entry**: `•` for a common entry, the headword in bold, its pronunciation between slashes, its language tag in italics, the senses, and after a dash the notes it is cited from, as links.
1048
+ - **a key**, once, unless the fence sets `key=false`, and nothing else where
1049
+ it sets `key=only`, listing the abbreviations the result uses — a language's
1050
+ tag, a word's class or a modifier — each with its expansion; a glossary also
1051
+ explains the common mark where an entry carries it;
1052
+ - **a heading per letter**, at `section-level`, accents taken off and
1053
+ apostrophes skipped, so `'ostal` files under O and `Écuyer` under E;
1054
+ - **one paragraph per entry**: a glossary's `•` for a common entry, the
1055
+ headword in bold, its pronunciation between slashes, its language tag and
1056
+ word class in italics where present, its senses, and after a dash the notes
1057
+ it is cited from, as links.
935
1058
 
936
- A word also carries its class beside the tag and its etymology in brackets:
1059
+ A dictionary entry gives its field in italic parentheses and its etymology
1060
+ in brackets:
937
1061
 
938
1062
  ```markdown
939
- • **solmère** /sol-MEH-reh/ _n. m._ [fr. Élav. _sólmerë_] Longing; the ache for a time that is gone. — [[thalorna-note-lore-lastshrine|The Song of the Last Shrine]]
1063
+ **solmère** /sol-MEH-reh/ _n. m._ (_Love and its conduct_) [fr. Élav. _sólmerë_] Longing; the ache for a person, a place or a time that is gone. — [[thalorna-note-lore-lastshrine|The Song of the Last Shrine]]
940
1064
  ```
941
1065
 
942
- A term carries no class, and each of its senses names its source. A glossary sets the rows sharing a headword and a language as one entry, numbering their senses in the order the rows arrive and printing a sense several bodies give once, with all of them:
1066
+ A glossary entry naming a dictionary word uses the word's senses when
1067
+ `definition` is absent; a list of dictionary glosses supplies every sense.
1068
+ Those senses carry no body label. An entry with a `definition` uses that
1069
+ meaning and labels it with the owner, retaining its word link and class
1070
+ where it names a dictionary word. On the owner's own page, a sense attributed
1071
+ only to that owner omits the repeated label; other bodies and shared senses
1072
+ keep their labels. A glossary sets the rows sharing a headword
1073
+ and a language as one entry, numbering their senses in query order and
1074
+ printing a sense several bodies give once, with all of them:
943
1075
 
944
1076
  ```markdown
945
- **Sworn Knight** **1** (_Duchy of Aubrac_) Holds land of the duke. **2** (_Kingdom of Provenzia_) Holds land of the crown. **3** (_Provenzia_) A knight bound by oath to a lord. — [[thalorna-note-affiliation-duchy|Duchy of Aubrac]], [[thalorna-note-affiliation-kingdom|Kingdom of Provenzia]], [[thalorna-note-lore-provenzianclt|Provenzia]]
946
- ```
947
-
948
- The entries are ordered by the layout, not by the query: by letter, then by `name_sort`. **The language tag prints where the entry's language is not the page's own**: a language note's own language, a culture's `data.language`, or the language an affiliation's glossary resolves to. It is the language note's `data.abbreviation`, or its full name where it states none. The etymology never repeats the entry's own language: a borrowed word prints `[fr. Élav. _sólmerë_]`, a built word its pieces each with its gloss, `[_am-_ "love" + _-ère_ "one who"]`, an inherited word its older form, `[*_hur_]` or `[Hel. *_thalass_]`, and a root word its root and pattern. A citation of a note with no published page prints as its name.
949
-
950
- A culture's or an affiliation's `data.glossary` shapes both: an entry without a definition marks a word or a rank common, gives it a sort key or a respelling, and lets in a rank whose title is a single word; an entry with a definition replaces the senses of the owner's own rank or office, or is a term of the owner's own. The [format reference](../reference/format-details.md#dictionaries-and-glossaries) gives every column and rule.
1077
+ **Sworn Knight** **1** (_Duchy of Aubrac_) Holds land of the duke. **2** (_Kingdom of Provenzia_) Holds land of the crown. **3** A knight bound by oath to a lord. — [[thalorna-note-affiliation-duchy|Duchy of Aubrac]], [[thalorna-note-affiliation-kingdom|Kingdom of Provenzia]], [[thalorna-note-lore-provenzianclt|Provenzia]]
1078
+ ```
1079
+
1080
+ The layout orders entries by letter, then by `name_sort`. **The language tag
1081
+ prints where the entry's language is not the page's own**: a language note's
1082
+ own language, a culture's `data.language`, or the language an affiliation's
1083
+ glossary resolves to. It is the language note's `data.abbreviation`, or its
1084
+ full name where unstated. Etymology never repeats the entry's own language:
1085
+ a borrowed word prints `[fr. Élav. _sólmerë_]`, a built word its pieces each
1086
+ with its gloss, `[_am-_ "love" + _-ère_ "one who"]`, an inherited word its
1087
+ older form, `[*_hur_]` or `[Hel. *_thalass_]`, and a root word its root and
1088
+ pattern. A citation of a note with no published page prints as its name.
1089
+
1090
+ A built piece can name a language element by its `form` or one of its
1091
+ `variants`; its `sense` prints beside the piece. An affix can also be named by
1092
+ its `front` form. Words and affixes take precedence over elements in the same
1093
+ language, and the language is searched before its ancestors. Exact spellings
1094
+ are checked before ignoring joining hyphens; case and accents are preserved.
1095
+
1096
+ A glossary entry may give its own sort key or respelling. A reference to a
1097
+ rank or office inherits its descriptions and admits a title of one word; its
1098
+ `common` value belongs to the entry's owner. A definition replaces the senses
1099
+ of the owner's own rank or office, or supplies an entry of the owner's own.
1100
+ The [format reference](../reference/format-details.md#dictionaries-and-glossaries)
1101
+ gives every column and rule.
951
1102
 
952
1103
  ## Page lists
953
1104
 
@@ -987,7 +1138,7 @@ That list names the `lore` notes tagged `key-concept`, grouped by type and alpha
987
1138
 
988
1139
  **A tag no page carries is a finding** at the fence's own line, naming the tag it looked for. A misspelled tag is the whole of what goes wrong here, and a heading with an empty list under it is how one goes unnoticed. Write `{allow-empty=true}` where a group that is genuinely empty is intended; the directive then leaves nothing behind rather than an empty list.
989
1140
 
990
- A page list names this package's own pages. A **stub** — a note with an empty body — publishes no page, so it joins no list. A note tagged `gm` is listed in Foundry and left out of the website and the book, exactly as it is left out of a content table's relations.
1141
+ A page list names this package's own pages. A **stub** — a note with neither an authored body nor automatic lexical content — publishes no page, so it joins no list. A note tagged `gm` is listed in Foundry and left out of the website and the book, exactly as it is left out of a content table's relations.
991
1142
 
992
1143
  See [page-list details](../reference/format-details.md#page-lists) for the directive's full behaviour.
993
1144