@heroiclands/package-build 23.9.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 (85) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +2 -0
  3. package/bin/content-commands.mjs +197 -68
  4. package/docs/api.md +336 -68
  5. package/docs/authoring/links-and-markup.md +114 -47
  6. package/docs/commands.md +92 -3
  7. package/docs/content-format.md +6 -1
  8. package/docs/reference/format-details.md +129 -14
  9. package/docs/reference/note-types.md +4 -4
  10. package/engine/anchors.mjs +8 -6
  11. package/engine/base-compiler.mjs +6 -4
  12. package/engine/changelog-group.mjs +58 -34
  13. package/engine/changelog-lint.mjs +6 -2
  14. package/engine/compendiums.mjs +15 -1
  15. package/engine/compile-corpus.mjs +14 -1
  16. package/engine/content-charset.mjs +13 -1
  17. package/engine/content-html.mjs +18 -4
  18. package/engine/content-icons.mjs +15 -1
  19. package/engine/content-images.mjs +28 -9
  20. package/engine/content-index.mjs +102 -23
  21. package/engine/content-links.mjs +27 -12
  22. package/engine/content-session.mjs +247 -0
  23. package/engine/content-sources.mjs +110 -0
  24. package/engine/content-spans.mjs +87 -8
  25. package/engine/content-tables.mjs +1 -0
  26. package/engine/content-tasklists.mjs +20 -4
  27. package/engine/diagnostics.mjs +17 -6
  28. package/engine/extension-attributes.mjs +28 -5
  29. package/engine/first-use.mjs +371 -0
  30. package/engine/foundry-entries.mjs +12 -9
  31. package/engine/generate.mjs +13 -4
  32. package/engine/helpers.mjs +43 -14
  33. package/engine/index-records.mjs +1 -0
  34. package/engine/index.mjs +3 -0
  35. package/engine/journals.mjs +9 -5
  36. package/engine/language-data.mjs +2 -2
  37. package/engine/language-rows.mjs +4 -4
  38. package/engine/language-terms.mjs +4 -4
  39. package/engine/lexical-sections.mjs +5 -5
  40. package/engine/markup-validation.mjs +7 -2
  41. package/engine/metadata-index.mjs +1 -0
  42. package/engine/name-markup.mjs +114 -0
  43. package/engine/name-rows.mjs +70 -0
  44. package/engine/names.mjs +460 -0
  45. package/engine/note-addresses.mjs +25 -4
  46. package/engine/path-charset.mjs +24 -1
  47. package/engine/pdf-render.mjs +15 -1
  48. package/engine/site-index.mjs +5 -1
  49. package/engine/sql-tables.mjs +76 -15
  50. package/engine/stub-lint.mjs +4 -3
  51. package/engine/yaml-lint.mjs +3 -5
  52. package/hugo-theme/static/css/style.css +4 -0
  53. package/package.json +1 -1
  54. package/types/engine/anchors.d.mts +4 -2
  55. package/types/engine/compendiums.d.mts +5 -1
  56. package/types/engine/compile-corpus.d.mts +5 -2
  57. package/types/engine/content-charset.d.mts +5 -1
  58. package/types/engine/content-html.d.mts +5 -1
  59. package/types/engine/content-icons.d.mts +5 -1
  60. package/types/engine/content-images.d.mts +5 -1
  61. package/types/engine/content-index.d.mts +39 -19
  62. package/types/engine/content-links.d.mts +22 -8
  63. package/types/engine/content-session.d.mts +108 -0
  64. package/types/engine/content-sources.d.mts +32 -0
  65. package/types/engine/content-spans.d.mts +3 -5
  66. package/types/engine/content-tasklists.d.mts +5 -1
  67. package/types/engine/diagnostics.d.mts +10 -0
  68. package/types/engine/extension-attributes.d.mts +16 -2
  69. package/types/engine/first-use.d.mts +31 -0
  70. package/types/engine/foundry-entries.d.mts +11 -4
  71. package/types/engine/generate.d.mts +5 -1
  72. package/types/engine/helpers.d.mts +30 -7
  73. package/types/engine/index.d.mts +1 -0
  74. package/types/engine/journals.d.mts +5 -2
  75. package/types/engine/lexical-sections.d.mts +3 -2
  76. package/types/engine/markup-validation.d.mts +2 -1
  77. package/types/engine/name-markup.d.mts +176 -0
  78. package/types/engine/name-rows.d.mts +35 -0
  79. package/types/engine/names.d.mts +356 -0
  80. package/types/engine/note-addresses.d.mts +3 -3
  81. package/types/engine/path-charset.d.mts +16 -1
  82. package/types/engine/site-build.d.mts +2 -2
  83. package/types/engine/site-index.d.mts +3 -1
  84. package/types/engine/sql-tables.d.mts +7 -2
  85. package/types/engine/stub-lint.d.mts +3 -1
@@ -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 its `cultures` associations. 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
  ```
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
 
@@ -2352,6 +2436,11 @@ content tree named by `root`, defaulting to `paths.content`; writes
2352
2436
  `<contentPackage>-terms.jsonl` into `--out`, defaulting to the configured
2353
2437
  `paths.contentIndex`.
2354
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
+
2355
2444
  The command prepares SQL tables, page lists, automatic sections and scalar
2356
2445
  expressions before publishing their prose targets. Each source uses its own
2357
2446
  audience for prose declarations: public notes use public providers and usage,
@@ -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 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 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).