@heroiclands/package-build 24.1.1 → 25.1.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 (107) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +1 -0
  3. package/bin/content-commands.mjs +30 -96
  4. package/bin/encoding-commands.mjs +146 -0
  5. package/bin/package-build.mjs +35 -24
  6. package/config.mjs +25 -0
  7. package/convert.mjs +182 -0
  8. package/docs/api.md +154 -11
  9. package/docs/authoring/links-and-markup.md +260 -473
  10. package/docs/commands.md +118 -119
  11. package/docs/configuration.md +31 -13
  12. package/docs/content-format.md +11 -4
  13. package/docs/diagnostics.md +43 -16
  14. package/docs/encoding-core.md +135 -0
  15. package/docs/guides/book.md +2 -2
  16. package/docs/guides/module-project.md +23 -1
  17. package/docs/guides/site.md +2 -2
  18. package/docs/guides/writing-in-invented-scripts.md +453 -569
  19. package/docs/reference/format-details.md +290 -380
  20. package/docs/reference/note-types.md +80 -62
  21. package/docs/source-preview.md +8 -0
  22. package/e2e.mjs +1 -1
  23. package/engine/base-compiler.mjs +27 -9
  24. package/engine/content-charset.mjs +21 -1
  25. package/engine/content-format.yaml +7 -2
  26. package/engine/content-index.mjs +6 -2
  27. package/engine/content-links.mjs +1 -0
  28. package/engine/content-scripts.mjs +658 -423
  29. package/engine/content-scroll.mjs +4 -4
  30. package/engine/content-spans.mjs +40 -9
  31. package/engine/content-verse.mjs +1 -1
  32. package/engine/converter-data.mjs +70 -0
  33. package/engine/dictionary-rows.mjs +2 -34
  34. package/engine/encoding-integrity.mjs +94 -0
  35. package/engine/encoding-language.mjs +506 -0
  36. package/engine/encoding-lexicon.mjs +699 -0
  37. package/engine/encoding-notes.mjs +186 -0
  38. package/engine/encoding-standard.mjs +42 -0
  39. package/engine/encoding-template.mjs +313 -0
  40. package/engine/encoding-terms.mjs +141 -0
  41. package/engine/encoding.mjs +946 -0
  42. package/engine/extension-attributes.mjs +2 -0
  43. package/engine/helpers.mjs +1 -1
  44. package/engine/index.mjs +10 -0
  45. package/engine/language-data.mjs +4 -1
  46. package/engine/language-terms.mjs +23 -12
  47. package/engine/{logographic.mjs → language-writings.mjs} +29 -38
  48. package/engine/markup-validation.mjs +1 -1
  49. package/engine/note-vocabulary.mjs +4 -158
  50. package/engine/pdf-render.mjs +31 -3
  51. package/engine/roman-characters.mjs +232 -0
  52. package/engine/roman-run.mjs +149 -0
  53. package/engine/roman-verse.mjs +95 -0
  54. package/engine/run-rows.mjs +29 -31
  55. package/engine/run-words.mjs +2 -2
  56. package/engine/script-emphasis-terms.mjs +3 -0
  57. package/engine/script-emphasis.mjs +3 -10
  58. package/engine/script-font-delivery.mjs +9 -12
  59. package/engine/script-fonts.mjs +2 -1
  60. package/engine/site-build.mjs +14 -5
  61. package/engine/site-preview.mjs +12 -2
  62. package/engine/sql-tables.mjs +36 -31
  63. package/engine/verse-metre.mjs +1 -1
  64. package/engine/word-forms.mjs +1 -1
  65. package/engine/word-inflections.mjs +48 -0
  66. package/engine/word-rows.mjs +1 -1
  67. package/engine/word-terms.mjs +16 -17
  68. package/package.json +11 -5
  69. package/types/config.d.mts +5 -0
  70. package/types/convert.d.mts +44 -0
  71. package/types/e2e.d.mts +1 -1
  72. package/types/engine/base-compiler.d.mts +4 -2
  73. package/types/engine/content-charset.d.mts +8 -0
  74. package/types/engine/content-index.d.mts +4 -1
  75. package/types/engine/content-scripts.d.mts +108 -42
  76. package/types/engine/converter-data.d.mts +11 -0
  77. package/types/engine/dictionary-rows.d.mts +1 -25
  78. package/types/engine/encoding-integrity.d.mts +14 -0
  79. package/types/engine/encoding-language.d.mts +36 -0
  80. package/types/engine/encoding-lexicon.d.mts +259 -0
  81. package/types/engine/encoding-notes.d.mts +39 -0
  82. package/types/engine/encoding-standard.d.mts +11 -0
  83. package/types/engine/encoding-template.d.mts +43 -0
  84. package/types/engine/encoding-terms.d.mts +105 -0
  85. package/types/engine/encoding.d.mts +155 -0
  86. package/types/engine/helpers.d.mts +1 -1
  87. package/types/engine/index.d.mts +5 -0
  88. package/types/engine/language-terms.d.mts +1 -1
  89. package/types/engine/{logographic.d.mts → language-writings.d.mts} +6 -6
  90. package/types/engine/markup-validation.d.mts +1 -1
  91. package/types/engine/pdf-render.d.mts +1 -1
  92. package/types/engine/roman-characters.d.mts +45 -0
  93. package/types/engine/roman-run.d.mts +101 -0
  94. package/types/engine/roman-verse.d.mts +23 -0
  95. package/types/engine/run-rows.d.mts +13 -20
  96. package/types/engine/script-emphasis-terms.d.mts +2 -0
  97. package/types/engine/script-emphasis.d.mts +1 -1
  98. package/types/engine/script-font-delivery.d.mts +2 -3
  99. package/types/engine/script-fonts.d.mts +5 -0
  100. package/types/engine/site-preview.d.mts +1 -1
  101. package/types/engine/word-inflections.d.mts +25 -0
  102. package/engine/map-lexicon.mjs +0 -1034
  103. package/engine/text-maps.mjs +0 -654
  104. package/engine/written-in.mjs +0 -204
  105. package/types/engine/map-lexicon.d.mts +0 -330
  106. package/types/engine/text-maps.d.mts +0 -189
  107. package/types/engine/written-in.d.mts +0 -76
@@ -1960,184 +1960,100 @@ subtypes conflict. One package advisory contains both groups and is located
1960
1960
  at the earliest reported use. Advisory findings preserve a successful lint
1961
1961
  exit status. Supplied-value errors prevent publication and compilation.
1962
1962
 
1963
- #### Text marked with a language, a font or a map
1964
-
1965
- `lang=` identifies a span, generic div, verse fence or scroll fence's
1966
- language while retaining authored spelling and the surrounding prose font.
1967
- `.nativefont` explicitly requests native presentation and requires `lang=` on
1968
- that same construct; an inherited language does not satisfy the requirement.
1969
- On a named block the language, font and map keys are errors.
1970
-
1971
- - **`lang=`** is a name declared in [`languages`](../configuration.md#languages),
1972
- otherwise a BCP 47 tag checked for its form alone. Language identification
1973
- and its existing validation do not depend on native presentation.
1974
- - **`.nativefont`** selects that language's `data.writtenIn` map and font.
1975
- A native run needs an effective font; a missing default reports the
1976
- required `font=` override. The map is optional when the language supplies
1977
- none, so directly typed script code points can be set without mapping. The
1978
- build does not guess a font from a map's list of faces.
1979
- - **`font=`** overrides the native font independently. Without `.nativefont`,
1980
- only `mono`, `serif` and `sans` are permitted.
1981
- - **`map=`** overrides the native map independently and requires `.nativefont`.
1982
- It names a [mapping note](#mapping-notes). With a configured language note,
1983
- mapping reads that language's lexicon first; see
1984
- [a map reads the dictionary first](#a-map-reads-the-dictionary-first).
1985
-
1986
- Unmarked text follows its passage. Each marked child chooses its presentation:
1987
- a language-only child stays Roman, even inside a native passage of that same
1988
- language. A native child requires its own explicit `lang=` and `.nativefont`,
1989
- uses its own language's defaults and applies only its own overrides.
1990
-
1991
- Standalone wikilinks accept the same attributes. `[[address|Name]]{lang=vyl}`
1992
- stays Roman, while `[[address|Name]]{lang=vyl .nativefont}` applies native
1993
- mapping and font to the displayed name alone. Targets, spoilers, `.show`,
1994
- draft annotations and book page cues retain their behavior. Adjacent prose
1995
- belongs in sibling spans; an embedded link inside a longer native run is an error.
1996
- Parallel verse uses `cols=N`, a positive whole number defaulting to one.
1997
- With multiple columns, each content line starts with its column number and
1998
- one or more spaces. Blank-separated logical rows accept nondecreasing
1999
- numbers in `1..cols`, preserving omitted cells and any number of repeated
2000
- readings. The first reading in each column is foreground and all later ones
2001
- in that column are grey; each row resets that choice. `numstep` counts logical
2002
- rows, and `***` separates stanzas. Language and native script choices remain
2003
- on the authored inline runs, independently for every reading.
2004
-
2005
- **A face draws the code points its `fonts.json` entry lists in `codepoints`,
2006
- and whitespace.** After the map, any other character in a run set in a face is
2007
- an error, located at the source character it came from; through a map, at the
2008
- start of the matched `from`. Each character is reported once per run. The
2009
- generic families are not checked. `input`, `layout` and `encoding` in
2010
- `fonts.json` are not read.
2011
-
2012
- Text marked with `font=` or `map=`, or with a declared language, is plain: a
2013
- span or a verse holds no emphasis, link, image, footnote, wikilink, code or
2014
- HTML, and no span but a marked one inside a div or a fence; a div holds
2015
- paragraphs and line breaks only. Text set in a face takes `*…*` and `**…**`,
2016
- set by its [emphasis convention](#script-notes-and-emphasis). The text is read as written, so `[`, `]`, `"`,
2017
- `<<`, `>>`, `!` and `@#$%^&` are characters, and a bracket pair is markup only
2018
- when `(`, `{` or a second `[` makes it a link, a span or a wikilink. Text marked
2019
- with a real language's tag alone keeps its Markdown. See
2020
- [marking language, font and mapping](../authoring/links-and-markup.md#marking-language-font-and-mapping).
2021
-
2022
- Each own-note metadata record carries `runs` in source order, an empty array
2023
- when the body marks nothing. Every entry has `kind` (`span`, `block`, `scroll` or
2024
- `verse`), `lang`, `tag`, `font`, `map`, `line` and `column`: `lang`, `font` and
2025
- `map` as written, or its language's `data.writtenIn` defaults only for an
2026
- explicit `.nativefont` run, `tag` the BCP 47 tag `lang` resolves
2027
- to, each `null` when absent, and the position of the span's `[`, the div's
2028
- `:::` or the fence's opening. An opted-in run also carries optional `nativefont: true`; Roman runs omit
2029
- that flag and leave unused script defaults null. The `runs` SQL relation
2030
- retains its existing columns and projects no flag column. Tags differing
2031
- only in case remain separate values. This is derived
2032
- metadata, not frontmatter. The [`runs` relation](#content-tables) flattens
2033
- these entries with their containing NOTE Address.
2034
-
2035
- #### Mapping notes
2036
-
2037
- A `doc` note's `data.map` is a mapping: rows that rewrite sequences of
2038
- characters into characters, which a run marked `map=` with its `name` is
2039
- rewritten by before it is set. A mapping belongs to a script, and serves every
2040
- language written in it.
1963
+ #### Text marked with a language, font or encoding
2041
1964
 
2042
- ```yaml
2043
- data:
2044
- map:
2045
- name: semaron
2046
- vowels: "aeiouAEIOU"
2047
- fonts:
2048
- - font: semaron-kuriale
2049
- - font: semaron-carved
2050
- rows:
2051
- - [th, "\U000F0251"]
2052
- rows:
2053
- - [a, "\U000F0230"]
2054
- - [th, "\U000F0250"]
2055
- - { from: y, to: "\U000F0246", before: consonant }
2056
- ```
2057
-
2058
- | Key | Shape | Meaning |
2059
- | ------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------- |
2060
- | `name` | string, required | What `map=` names it by: lowercase letters, digits and `-`, unique in the index |
2061
- | `logographic` | `true` | The script writes meanings; see [a logographic map](#a-logographic-map) |
2062
- | `vowels` | string | The characters `before: vowel` reads as vowels |
2063
- | `fonts` | list of `{ font, rows? }`, required, at least one | The faces the map is drawn in, by slug, each with any rows of its own |
2064
- | `rows` | list of `[from, to]` or `{ from, to, before?, at? }` | The shared rewrites, in authored order |
2065
-
2066
- **A face's own rows come first.** A run in a face tries that face's `rows`,
2067
- the longest match among them, and only where none matches the shared `rows`; a
2068
- face listed with no `rows` uses the shared rows alone, and a run with no
2069
- `font=` uses them too. Rows take the same shapes and conditions in both places,
2070
- and `vowels` serves them all. A run whose `font=` is not one of the map's
2071
- `fonts` is an error at its `map=`:
2072
-
2073
- > `` `thuravark-carved` is not a font of the map `semaron`; it is for `semaron-kuriale` and `semaron-carved` ``
2074
-
2075
- A row's `from` is one or more characters and its `to` any number, none
2076
- included, each a whole code point; a code point above U+FFFF is written in YAML
2077
- with the eight-digit escape, as `"\U000F0200"`. The longest match wins; among rows of one length, a row with a
2078
- condition that holds comes before a row with none, and otherwise the earlier
2079
- row wins. A row whose condition fails is skipped, and a character no row
2080
- matches passes through unchanged.
2081
-
2082
- | Condition | Holds when |
2083
- | ------------------- | ---------------------------------------------------------------------------- |
2084
- | `before: vowel` | the next character is one of `vowels` |
2085
- | `before: consonant` | the next character is any other letter |
2086
- | `at: start` | the match is the run's first character, or follows whitespace or punctuation |
2087
- | `at: end` | the match ends the run, or is followed by whitespace or punctuation |
2088
-
2089
- Neither `before` condition holds at the end of the text. The note's body is
2090
- for a reader: nothing reads it. Each row is a row of the
2091
- [`maps` relation](#content-tables), never a struct key, so `A` and `a` are two
2092
- rows; a face's own rows carry its slug in `font`.
2093
-
2094
- The data-key check holds every key of `data.map` and of each row to the table
2095
- under [`type: doc`](#type-doc), at its own line and column:
2096
-
2097
- > `` `data.map.rows[2]` should be `[from, to]` or `{ from, to, before?, at? }`, but reads "a" ``
2098
-
2099
- > `` `data.map.rows[3]` must state `to` — a string, which may be empty ``
2100
-
2101
- > `` "when" is not a key of `data.map.rows[5]`; it takes only `from`, `to`, `before`, `at` ``
2102
-
2103
- > `` `data.map.rows[6].before` should be `vowel` or `consonant`, but reads "liquid" ``
2104
-
2105
- The map's own check reports the rest, each at its key:
2106
-
2107
- > `` `data.map.name` is `Vyl_Semaron`; a map's name is lowercase letters, digits and `-` ``
2108
-
2109
- > `` `data.map.name` is `vyl-semaron`, which Lore/Other.md also declares; a map's name is unique ``
2110
-
2111
- > `` `data.map.rows[0]` is a list, and a row written as a list is two strings, `[from, to]` ``
1965
+ `enc=` names an encoding document, with `doc` as its default Address type:
1966
+ `[say.]{enc=aelwsemaronenc}` selects `doc-aelwsemaronenc`. That document supplies
1967
+ its configured `language` and single `font`; an explicit `lang=` must identify
1968
+ the same language, and an explicit `font=` must be that font. Another face is
1969
+ a separate encoding document.
2112
1970
 
2113
- > `` `data.map.rows[1]` has an empty `from`; a row matches one or more characters ``
1971
+ `enc=default` leaves Roman text as written and is the default when no encoding
1972
+ is selected. `lang=` still identifies the text and selects its language's
1973
+ vocabulary; `font=mono`, `serif`, `sans` or an installed font selects its face
1974
+ without encoding it. Language identification does not select an encoding.
2114
1975
 
2115
- > `` `data.map.rows[4]` has `before: consonant`, and the map states no `vowels` to read it by ``
2116
-
2117
- > `` `data.map.fonts` is empty; a map lists each face it is drawn in ``
2118
-
2119
- > `` `data.map.fonts[0].font` is `mono`, a generic family; a map lists the faces it is drawn in ``
2120
-
2121
- > `` `data.map.rows[2]` matches `z`, a letter, and the rows of a logographic map write only the text between words ``
2122
-
2123
- The lint checks the listed faces against the installed `@heroiclands/fonts`,
2124
- each at the entry or the row at fault. Every listed face draws every code point
2125
- its own rows write, every code point the shared rows it can reach write (a
2126
- shared row is out of a face's reach where a plain row of the face's own matches
2127
- the start of its `from`), and every code point of the native forms that apply
2128
- to it:
2129
-
2130
- > `` `semaron-kurale` is not a font: `data.map.fonts[1].font` names an installed face; did you mean `semaron-kuriale`? ``
1976
+ ```markdown
1977
+ [say.]{enc=aelwsemaronenc}
1978
+ [say.]{enc=doc-aelwsemaronenc lang=aelw font=semaron-kuriale}
1979
+ [say.]{lang=aelw enc=default}
1980
+ ```
1981
+
1982
+ Class-only emphasis and name children belong to the parent's complete logical
1983
+ text; encoding preserves their rendered wrappers. A child with its own run
1984
+ keys makes a separate presentation choice. `enc=default` inside an encoded
1985
+ parent keeps the inherited language but does not inherit its inferred script
1986
+ face. An explicitly authored font remains a font choice.
1987
+
1988
+ A name's braces use the shared name controls. Resolved references encode only
1989
+ their visible labels, retaining URLs and presentation cues. These keys apply
1990
+ to spans, divs, verse fences and scroll fences. A scroll's selected font must
1991
+ belong to a script whose note declares `direction: vertical-rl`.
1992
+
1993
+ #### Encodings
1994
+
1995
+ An encoding is a `doc` note. Its `data.language` is a configured language
1996
+ alias, `data.font` is one installed font slug, and `data.mappings` maps Roman
1997
+ strings to a font glyph code or a sequence of codes. `data.rules` holds the
1998
+ closed executable rules. Optional `data.accepts` states accepted characters
1999
+ or ranges and `data.vowels` states contextual vowels. The note body explains
2000
+ the spelling to a reader.
2001
+
2002
+ The font supplies each glyph's `code` beside its `codepoint` in `fonts.json`.
2003
+ Codes belong to the selected font; the note never repeats a code table.
2004
+ Unknown fields, glyph codes, languages and fonts are positioned findings.
2005
+ An encoding's output must decode unambiguously, including across adjacent
2006
+ mappings and spaces. The compiler refuses indistinguishable spellings rather
2007
+ than choosing a guessed reading.
2008
+
2009
+ Lint checks every authored word, variant and registered name for a language
2010
+ with an encoding document, including unused entries. It also checks actual
2011
+ name-list entries and name-element spellings and examples; patterns and
2012
+ abstract roots are excluded. Bound-element edge hyphens mark joining positions.
2013
+ These are bare Roman checks, so a native writing cannot bypass spelling rules.
2014
+ Different case and multiword names retain their authored spelling.
2015
+ See [the executable rules](../encoding-core.md).
2016
+
2017
+ Mappings match longest first; contextual before-vowel rules precede their
2018
+ unconditional alternatives. A case rule may allow lowercase and initial-capital
2019
+ groups while refusing other mixed or uppercase group spellings. Encoding keeps
2020
+ authored case and never rewrites a word's Roman spelling.
2021
+
2022
+ Outside literal markers, a run of Unicode Zs characters or U+0009 through
2023
+ U+000D writes one space. Other whitespace needs an explicit mapping. Standard
2024
+ Roman punctuation, verse and name controls are inherited from the shared
2025
+ standard; an explicit mapping can give a standard source its font glyph.
2026
+
2027
+ The canonical content index retains the authored mapping object. In the SQL
2028
+ `notes` and dependency relations, `data.mappings` is an ordered list of
2029
+ `{from, codes}` records: a scalar glyph code becomes a one-entry `codes`
2030
+ list. Source keys such as `a` and `A` remain case-sensitive values, rather
2031
+ than case-insensitive SQL struct keys.
2131
2032
 
2132
- > `` `data.map.fonts[2]` lists the font `semaron-kuriale` a second time; the first is `data.map.fonts[0]` ``
2033
+ ```sql
2034
+ SELECT mapping."from", mapping.codes
2035
+ FROM notes, UNNEST(data.mappings) AS selected(mapping)
2036
+ WHERE type = 'doc' AND shortcode = 'aelwsemaronenc'
2037
+ ```
2133
2038
 
2134
- > `` `data.map.fonts[1].rows[0]` writes U+F0251, which the font `semaron-carved` does not draw ``
2039
+ ##### Literal codes
2135
2040
 
2136
- > `` `data.map.rows[5]` writes U+F0239, which the font `semaron-kuriale`, listed in `data.map.fonts`, does not draw ``
2041
+ Inside an encoded run, `⟦…⟧` writes the selected font's glyph codes or exact
2042
+ Unicode scalars: `[⟦MAN⟧]{enc=khelzethuenc}` where `MAN` is defined, and
2043
+ `[⟦U+00E1⟧]{enc=vylsemaronenc}` for an exact character. A Unicode code takes four to
2044
+ six uppercase hexadecimal digits, U+0000 through U+10FFFF excluding
2045
+ surrogates. Codes come only from the font; Unicode database
2046
+ names are not inferred. Whitespace between codes writes nothing. Nested or
2047
+ unmatched markers, unknown codes and standard marks absent from the font
2048
+ code table are errors. Without an encoding, a literal marker is a finding.
2137
2049
 
2138
- A row with a fault is left out of the map; the rest apply.
2050
+ Each outer marker writes its own invisible control. Payload occurrences of
2051
+ those controls or the literal escape are quoted with U+E0115. Decoding
2052
+ unquotes the payload before reading code rows and uses `U+XXXX` for scalars
2053
+ with no code name. Variation selectors U+E0100 through U+E01EF are valid
2054
+ encoded characters and carry distinctions the visible font does not draw.
2139
2055
 
2140
- #### A map reads the dictionary first
2056
+ #### An encoding reads the dictionary first
2141
2057
 
2142
2058
  The sound rules belong to the script, and the exceptions to the language. A
2143
2059
  word of a [language's words](#a-languages-words) states a `native` form for a
@@ -2150,18 +2066,17 @@ words:
2150
2066
  field: "Law, the court and the written act"
2151
2067
  gloss: an oath
2152
2068
  native:
2153
- - { map: semaron, text: "\U000F024F\U000F0230\U000F023F\U000F023C" }
2154
- - { map: semaron, font: semaron-carved, text: "\U000F024F\U000F0230\U000F023C" }
2069
+ - { enc: vylsemaronenc, text: "\U000F024F\U000F0230\U000F023F\U000F023C" }
2070
+ - { enc: vylsemaronenc, font: semaron-carved, text: "\U000F024F\U000F0230\U000F023C" }
2155
2071
  ```
2156
2072
 
2157
2073
  | Key | Shape | Meaning |
2158
2074
  | ------ | ---------------- | -------------------------------------------------------------------------------------------- |
2159
- | `map` | string, required | The `data.map.name` the native form is written for |
2160
2075
  | `font` | string | The one face it is for; unstated, every face the map lists, and a face's own form wins there |
2161
2076
  | `text` | string, required | The word as the script writes it, in the map's characters |
2162
2077
 
2163
2078
  A run marked `lang=` with a declared language whose
2164
- [`note`](../configuration.md#languages) names its language note, and `map=`,
2079
+ [`note`](../configuration.md#languages) names its language note, and `enc=`,
2165
2080
  is written word by word:
2166
2081
 
2167
2082
  1. **A word** is a maximal run of letters, combining marks and digits, an
@@ -2187,12 +2102,12 @@ declared language with no `note` are spelled by the rows alone. A character the
2187
2102
  face does not draw inside a word written by its native form is an error at the
2188
2103
  word's start:
2189
2104
 
2190
- > `` `Orlan` is capitalised, and the native form the lexicon of `vyl` states for `orlan` under the map `semaron` does not begin as the rows spell its first letter, so the rows cannot capitalise it; state `Orlan` as a word of its own with its native form ``
2105
+ > `` `Orlan` is capitalised, and the native form the lexicon of `vyl` states for `orlan` under the encoding `semaron` does not begin as the rows spell its first letter, so the rows cannot capitalise it; state `Orlan` as a word of its own with its native form ``
2191
2106
 
2192
- > `` `zaron` is written U+F024F by the lexicon of `vyl` for the map `semaron`, which the font `semaron-kuriale` does not draw ``
2107
+ > `` `zaron` is written U+F024F by the lexicon of `vyl` for the encoding `semaron`, which the font `semaron-kuriale` does not draw ``
2193
2108
 
2194
2109
  **Language word-book validation applies to Roman and native runs alike**,
2195
- independently of `.nativefont` or mapping. Every word is a word of the
2110
+ independently of encoding selection. Every word is a word of the
2196
2111
  language, case folded: a
2197
2112
  `data.words[].form`, a word of a name the language note's own `data.register`
2198
2113
  lists under a `tongue` other than `translation`, or a form one rule derives from a lexicon form —
@@ -2207,7 +2122,7 @@ gives a word of one of its `classes`, or a participle `data.grammar.participles`
2207
2122
  gives a verb (see [optional noun and verb forms](#optional-noun-and-verb-forms)). A compound not known whole is checked part by
2208
2123
  part at its hyphens and en dashes. Any other word is an error at its first
2209
2124
  character, once per run; see
2210
- [a mapped run's words](../authoring/links-and-markup.md#a-mapped-runs-words):
2125
+ [a mapped run's words](../authoring/links-and-markup.md#an-encoded-runs-words):
2211
2126
 
2212
2127
  > `` `thiruthrimar` is not a word of the `vyl` lexicon, a registered name, or a regular form of one; coin it in the lexicon (or register the name) first ``
2213
2128
 
@@ -2216,24 +2131,24 @@ struct key, so forms that differ only in case are two rows. The data-key check
2216
2131
  holds each entry to its three keys; the lint checks the rest, each at the entry
2217
2132
  or the key at fault:
2218
2133
 
2219
- > `` `data.words[0].native[0].map` is `semron`, which is not a map: a native form names the `data.map.name` of a mapping note; did you mean `semaron`? ``
2134
+ > `` `data.words[0].native[0].enc` is `semron`, which does not resolve to an encoding document ``
2220
2135
 
2221
- > `` `data.words[0].native[1].font` is `thuravark-carved`, which is not a font of the map `semaron`; it is for `semaron-kuriale` and `semaron-carved` ``
2136
+ > `` `data.words[0].native[1].font` is `thuravark-carved`, which is not a font of encoding `semaron`; it is for `semaron-kuriale` and `semaron-carved` ``
2222
2137
 
2223
- > `` `data.words[0].native[2]` states a second native form for the map `semaron`; the first is `data.words[0].native[0]` ``
2138
+ > `` `data.words[0].native[2]` states a second native form for the encoding `semaron`; the first is `data.words[0].native[0]` ``
2224
2139
 
2225
- > `` `data.words[0].native[0]` states what the rows already give: the map `semaron` spells `zaron` so in the font `semaron-kuriale`; a native form is stated only where the rows spell the word differently ``
2140
+ > `` `data.words[0].native[0]` states what the rows already give: the encoding `semaron` spells `zaron` so in the font `semaron-kuriale`; a native form is stated only where the rows spell the word differently ``
2226
2141
 
2227
- > `` `data.words[0].native[0]` holds U+F024F, which the font `semaron-kuriale`, listed in the map `semaron`, does not draw ``
2142
+ > `` `data.words[0].native[0]` holds U+F024F, which the font `semaron-kuriale`, listed in the encoding `semaron`, does not draw ``
2228
2143
 
2229
2144
  The "states what the rows already give" finding compares a native form stated
2230
2145
  for a face with that face's rows, and one stated for no face with every listed
2231
2146
  face's rows: it is redundant only where every face's rows give it. This is what
2232
2147
  keeps a lexicon to its exceptions.
2233
2148
 
2234
- `package-build transliterate` maps a passage, and `package-build lexicon` lists
2235
- every word with its native form, through the same code as the build: see
2236
- [`transliterate`](../commands.md#package-build-transliterate-map-text) and
2149
+ `package-build encode` and `package-build decode` apply the bare encoding;
2150
+ `package-build lexicon` lists every word with the native form the build uses. See
2151
+ [`encode`](../commands.md#package-build-encode-text), [`decode`](../commands.md#package-build-decode-text) and
2237
2152
  [`lexicon`](../commands.md#package-build-lexicon-language).
2238
2153
 
2239
2154
  #### Metres
@@ -2269,103 +2184,74 @@ its count can be the metre's.
2269
2184
  The count is an author-side check. The rendered fence carries `data-scan` with
2270
2185
  the metre's name and nothing a reader sees.
2271
2186
 
2272
- #### A logographic map
2273
-
2274
- A map stating `logographic: true` writes meanings, so its rows spell no word.
2275
- Every word of a run under it is written from the run language's lexicon, and
2276
- the rows write only the text between words: whitespace, points and any other
2277
- text holding no letter. A word holds at least one letter; a run of digits is
2278
- text between words. A word is matched case folded, NFC, with `’` read as `'`,
2279
- and written by the first of these that gives a writing:
2280
-
2281
- 1. **The entries of its form.** Each entry whose `form`, folded, is the word,
2282
- and failing that each whose folded `form` with its joining hyphens taken
2283
- off is the word (`Gar-` for `gar`). An entry is written by its own `native`
2284
- for the map, the one for the run's face where it states one, else the one
2285
- for no face; else by its `built` pieces' writings joined in order.
2286
- 2. **A derived form.** A noun's plural (its own `plural`, else the
2287
- `data.grammar.plural` rule) and a verb's present form for one person of
2288
- `data.grammar.verbs.persons` are written by the stem's entry's writing,
2289
- followed by the `text` of the `data.grammar.native` entry for that ending.
2290
- Other derived forms (a replacing suffix, an agreeing form, a participle)
2291
- have no writing of their own here; they are coined as words, or written in
2292
- signs.
2293
- 3. **Its hyphenated parts.** A word holding a hyphen or an en dash that the
2294
- steps above do not write is written by each part in turn, each by steps 1
2295
- and 2; the hyphen writes nothing.
2296
-
2297
- A `built` piece is a word of the lexicon written exactly as the piece, else an
2298
- affix of `data.affixes` whose `form` or `front` is the piece, else either one
2299
- with joining hyphens taken off; a word piece is written by its own `native` or
2300
- its own pieces, recursively, and an affix by its own `native`. A piece that
2301
- reaches a word already being resolved has no writing.
2302
-
2303
- **Ambiguity.** Where a step matches more than one entry and their writings are
2304
- not all one text, or one has a writing and another none, the word has no
2305
- writing and is an error naming every entry's gloss. A part matched that way
2306
- makes the word ambiguous the same way, naming the part.
2307
-
2308
- | Key | Shape | Meaning |
2309
- | ------------------------------ | ------------------------------------------------------- | ------------------------------------------------------- |
2310
- | `data.affixes[].native` | list of `{ map, font?, text }` | The affix's writing, for a `built` piece naming it |
2311
- | `data.grammar.native` | list of `{ ending, map, font?, text }` | The signs a derived form takes after its stem's writing |
2312
- | `data.grammar.native[].ending` | `plural`, `I`, `you`, `heShe`, `we`, `youAll` or `they` | The ending written |
2313
- | `data.grammar.native[].text` | string, required, may be empty | The ending's signs; empty writes the stem alone |
2187
+ #### Native spellings and parts
2188
+
2189
+ Every encoding uses the same order for a language word: its own `native`
2190
+ entry for that encoding and face; otherwise the writings of all its parts;
2191
+ otherwise the encoding's rows. A face-specific entry precedes an entry for no
2192
+ face. Exact lexical forms precede folded lookup, so separately authored
2193
+ capitalized spellings keep their own native text. A flat variant is a lexical
2194
+ form; it does not assign a grammatical role by itself.
2314
2195
 
2315
2196
  ```yaml
2197
+ words:
2198
+ - form: halzi
2199
+ class: n
2200
+ gloss: heart
2201
+ field: Words
2202
+ native:
2203
+ - { enc: zethu, text: "\U0001EABB" }
2204
+ - form: halzunet
2205
+ class: n
2206
+ gloss: the account
2207
+ field: Words
2208
+ built: [halzi, -unet]
2316
2209
  affixes:
2317
- - form: "-unet"
2318
- gloss: "a thing made of"
2210
+ - form: -unet
2211
+ gloss: a thing made of
2319
2212
  native:
2320
- - { map: zethu, text: "\U0001EBC7" }
2321
- grammar:
2322
- plural:
2323
- - { ending: "", becomes: "im" }
2324
- verbs:
2325
- persons: { I: en, you: et, heShe: "", we: enu, youAll: etu, they: ar }
2326
- native:
2327
- - { ending: plural, map: zethu, text: "\U0001EBE1" }
2328
- - { ending: I, map: zethu, text: "\U0001EBDF" }
2329
- ```
2330
-
2331
- A word with no writing, an ambiguous word, and a word in a run with no lexicon
2332
- to write it from are each an error at the word, once per run:
2333
-
2334
- > `` `zamlu` has no `zethu` writing in the `khel` lexicon, and its parts do not give one; state one, or write the word directly in signs ``
2213
+ - { enc: zethu, text: "\U0001EBC7" }
2214
+ ```
2215
+
2216
+ A built part is an exact word or affix, then the same form with joining
2217
+ hyphens removed. Parts can themselves be built. A plural or present form can
2218
+ use the stem's writing followed by its explicitly named ending from
2219
+ `grammar.native`, whose entries use `{ending, enc, font?, text}`. These
2220
+ writings work under every encoding. Missing parts do not invent signs, and
2221
+ recursive parts terminate without a writing. Entries with genuinely different
2222
+ writings remain an ambiguity naming every matching gloss.
2223
+
2224
+ An encoding accepting no letters, such as `zethu` or `chalish-pilam`, needs a
2225
+ lexical writing or literal codes for a word. The refusal names the word,
2226
+ language and encoding and points to that word.
2227
+
2228
+ ##### Reading script text
2229
+
2230
+ Without a language, decoding is exactly the encoding's longest-output match.
2231
+ With a language, explicit native and composed writings are tried first,
2232
+ longest first; a shared writing uses the first listed sense. Literal marker
2233
+ spans decode through their inline codes. Unknown unmarked signs in a script
2234
+ accepting no letters become `⟦codes⟧` with a finding.
2235
+
2236
+ For an unmarked word, the lexicon can recover its unwritten sounds from the
2237
+ plain decoded skeleton. A unique skeleton gives its form; a shared skeleton
2238
+ gives the first authored form. Each word's citation precedes its variants and derived forms, before the next word's citation. Registered names retain their authored order. Complete names are matched longest first across word separators and receive one pair of braces. A known ordinary word keeps its encoded case without a false unknown-word finding. An unknown skeleton keeps the
2239
+ plain decoding and produces a located finding. This is decided per word: a
2240
+ passage can mix typed words with encoded words. A word carrying any invisible
2241
+ mark keeps exact decoding without skeleton recovery; an explicit authored
2242
+ native exception still has precedence. Stress marks are preserved by exact
2243
+ rows. Names are represented with braces according to the language's rules.
2335
2244
 
2336
- > `` `nelgir` stands for 2 words of the `khel` lexicon that the map `zethu` writes differently, “a god” and “god”; write the word directly in signs, choosing by its sense in `package-build lexicon khel --map zethu` ``
2337
-
2338
- > `` `Gar-nelgir` is written from its part `nelgir`, which stands for 2 words of the `khel` lexicon that the map `zethu` writes differently, “a god” and “god”; write the word directly in signs, choosing by its sense in `package-build lexicon khel --map zethu` ``
2339
-
2340
- > `` `halzi` has no `zethu` writing: the map `zethu` is logographic, and the run names no `lang=` whose lexicon writes it; mark the run with its language, or write the word directly in signs ``
2341
-
2342
- > `` `halzi` has no `zethu` writing: the map `zethu` is logographic, and `tant` has no lexicon (`languages.tant.note`) to write it from; write the word directly in signs ``
2343
-
2344
- Signs typed in the run hold no letter, so they are no word and pass through as
2345
- typed. The face-coverage check reads the writings as it reads native forms; a
2346
- word with no writing is reported by its own finding alone. The lexicon check
2347
- and the register check apply to the run as to any mapped run.
2348
-
2349
- Under a logographic map a word's `native` is its writing and is not compared
2350
- with the rows. An affix's `native` and `data.grammar.native` are read only by
2351
- a logographic map, so an entry naming any other map is an error, as is an
2352
- ending of a person where the pattern states no `persons`. The checks of a
2353
- word's `native` (an unknown map, a face the map is not for, a second entry, an
2354
- undrawn code point) apply to both, a second entry being one for the same
2355
- ending, map and face:
2356
-
2357
- > `` `data.affixes[0].native[0]` names the map `roman`, which is not logographic; an affix is written by a native form only under a logographic map ``
2358
-
2359
- > `` `data.grammar.native[0]` names the map `roman`, which is not logographic; an ending is written by a native form only under a logographic map ``
2360
-
2361
- > `` `data.grammar.native[2]` states a second native form of the ending `plural` for the map `zethu`; the first is `data.grammar.native[1]` ``
2245
+ #### Script notes and emphasis
2362
2246
 
2363
- > `` `data.grammar.native[3]` writes the ending `they`, and `data.grammar.verbs` states no `persons` ``
2247
+ A stressed word inside a language run is `[word]{.emph}`. A class-only span
2248
+ inherits the enclosing language, font and encoding; its text is written by the
2249
+ same rules. The language's `data.emphasis`, then the script's convention,
2250
+ determines its presentation. A language stating `words` refuses `.emph`.
2364
2251
 
2365
- Affix and ending writings are not rows of the `natives` relation, which holds
2366
- the words' native forms; `package-build lexicon` resolves them.
2367
-
2368
- #### Script notes and emphasis
2252
+ In English, `.emph` equals `*…*` and `.strong` equals `**…**`. Non-English
2253
+ spans accept `.emph` only; Markdown emphasis and `.strong` are findings. A
2254
+ span carrying both `.emph` and `.strong` is a finding at its opening bracket.
2369
2255
 
2370
2256
  A `skill` note of `subType: script` states the faces its script is written in,
2371
2257
  how the script marks a stressed word, and the direction it is written in, in
@@ -2376,36 +2262,18 @@ data:
2376
2262
  script:
2377
2263
  fonts: [qalezu-hand]
2378
2264
  emphasis: overline
2379
- strongEmphasis: rubric
2380
2265
  ```
2381
2266
 
2382
2267
  - **`fonts`** lists installed faces by the slug `font=` names them by, at least
2383
2268
  one. A face belongs to one script.
2384
2269
  - **`emphasis`** is `rubric` or `overline`, and sets both `*…*` and `**…**`
2385
2270
  (or `_…_` and `__…__`) inside a run in one of the faces.
2386
- - **`strongEmphasis`**, optional, is `rubric` or `overline`, and sets `**…**`
2387
- alone.
2388
2271
  - **`direction`**, optional, is `vertical-rl` for a script written in columns,
2389
2272
  top to bottom, with the columns read from the right. A
2390
2273
  [`scroll` fence](../authoring/links-and-markup.md#scrolls) sets text in
2391
2274
  such a script, and is an error in any other. A script that states no
2392
2275
  direction is written in lines.
2393
2276
 
2394
- A `skill` note of `subType: language` may state `data.writtenIn`, the script
2395
- the language is written in: `map`, the `data.map.name` of a mapping note, and
2396
- `font`, one of the faces that map lists, both required.
2397
-
2398
- ```yaml
2399
- data:
2400
- writtenIn: { map: semaron, font: semaron-kuriale }
2401
- ```
2402
-
2403
- A run explicitly marked with the language and `.nativefont` is mapped by
2404
- `map` and set in `font`, as
2405
- [text marked with a language, a font or a map](#text-marked-with-a-language-a-font-or-a-map)
2406
- describes. A face a language's `writtenIn` names counts as used, so the
2407
- package's fonts are delivered for it.
2408
-
2409
2277
  A `skill` note of `subType: language` may state `data.emphasis`: `words`,
2410
2278
  `rubric` or `overline`. It overrides the script's convention in every run of the
2411
2279
  language. `words` means the language marks emphasis with a word, so `*…*` or
@@ -2440,12 +2308,6 @@ Each of these is an error at the key or the entry at fault:
2440
2308
 
2441
2309
  > `` `data.emphasis` states how a language marks emphasis, and this note's `subType` is not `language` ``
2442
2310
 
2443
- > `` `data.writtenIn` names the script a language is written in, and this note's `subType` is not `language` ``
2444
-
2445
- > `` `data.writtenIn.map` is `semoran`, which no mapping note's `data.map.name` declares; did you mean `semaron`? ``
2446
-
2447
- > `` `data.writtenIn.font` is `teng-chou`, which the map `semaron` is not drawn in; it is drawn in `semaron-kuriale` ``
2448
-
2449
2311
  > `` `data.script.fonts` is empty; a script lists each face it is written in ``
2450
2312
 
2451
2313
  > `` `data.script.fonts[0]` is `serif`, a generic family; a script lists the faces it is written in ``
@@ -2458,7 +2320,7 @@ Each of these is an error at the key or the entry at fault:
2458
2320
 
2459
2321
  In a run:
2460
2322
 
2461
- > ``text marked `lang=prv font=semaron-kuriale map=semaron` takes emphasis only as `*…*`, `_…_`, `**…**` or `__…__` ``
2323
+ > ``text marked `lang=prv font=semaron-kuriale enc=vylsemaronenc` takes emphasis only as `*…*`, `_…_`, `**…**` or `__…__` ``
2462
2324
 
2463
2325
  > `` `vyl` marks emphasis with a word, not a mark; write the word ``
2464
2326
 
@@ -3611,7 +3473,7 @@ GM-only owners; all/native contexts retain them. Only authored occurrences
3611
3473
  contribute rows, so generated queries and sections add no further names.
3612
3474
 
3613
3475
  **`runs`** is one row per span, generic div and verse fence an authored note
3614
- body marks with `lang=`, `font=` or `map=`. Each row has these columns,
3476
+ body marks with `lang=`, `font=` or `enc=`. Each row has these columns,
3615
3477
  including on an empty relation:
3616
3478
 
3617
3479
  | Column | SQL type | Meaning |
@@ -3621,7 +3483,7 @@ including on an empty relation:
3621
3483
  | `lang` | `VARCHAR` | The language as written, its own or inherited, or `NULL`. |
3622
3484
  | `tag` | `VARCHAR` | The BCP 47 tag `lang` resolves to, or `NULL` when it resolves to none. |
3623
3485
  | `font` | `VARCHAR` | The selected font; language defaults apply only to native runs, else `NULL`. |
3624
- | `map` | `VARCHAR` | The selected map; language defaults apply only to native runs, else `NULL`. |
3486
+ | `enc` | `VARCHAR` | The selected encoding; language defaults apply only to native runs, else `NULL`. |
3625
3487
  | `line` | `BIGINT` | Original 1-based source line of the span's `[`, the div's `:::` or the fence's opening. |
3626
3488
  | `column` | `BIGINT` | Original 1-based UTF-16 source column there. |
3627
3489
 
@@ -3632,29 +3494,8 @@ WHERE font = 'semaron-kuriale'
3632
3494
  ORDER BY owner, line, "column"
3633
3495
  ```
3634
3496
 
3635
- **`maps`** is one row per well-formed row of a [mapping note](#mapping-notes)'s
3636
- `data.map.rows` and of each face's own `rows`. Each row has these columns,
3637
- including on an empty relation:
3638
-
3639
- | Column | SQL type | Meaning |
3640
- | -------- | --------- | ----------------------------------------------------------- |
3641
- | `owner` | `VARCHAR` | The mapping note's canonical NOTE Address. |
3642
- | `name` | `VARCHAR` | The map's `name`. |
3643
- | `font` | `VARCHAR` | The face whose own row it is; `NULL` for a shared row. |
3644
- | `row` | `BIGINT` | The row's 1-based place in its `rows`. |
3645
- | `from` | `VARCHAR` | The characters it matches. |
3646
- | `to` | `VARCHAR` | What it writes; empty for a row that drops what it matches. |
3647
- | `before` | `VARCHAR` | `vowel`, `consonant` or `NULL`. |
3648
- | `at` | `VARCHAR` | `start`, `end` or `NULL`. |
3649
-
3650
- `from`, `to` and `at` are SQL keywords, so a query quotes them:
3651
-
3652
- ```sql
3653
- SELECT "row", "from", "to", before FROM maps WHERE name = 'vyl-semaron' ORDER BY "row"
3654
- ```
3655
-
3656
3497
  **`natives`** is one row per entry of a word's `native` on every
3657
- [language note](#a-map-reads-the-dictionary-first). Each row has these columns,
3498
+ [language note](#an-encoding-reads-the-dictionary-first). Each row has these columns,
3658
3499
  including on an empty relation:
3659
3500
 
3660
3501
  | Column | SQL type | Meaning |
@@ -3663,7 +3504,7 @@ including on an empty relation:
3663
3504
  | `word` | `BIGINT` | The word's place in `data.words`, from `0`, as `words.position`. |
3664
3505
  | `form` | `VARCHAR` | The word's `form`. |
3665
3506
  | `native` | `BIGINT` | The entry's place in the word's `native`, from `0`. |
3666
- | `map` | `VARCHAR` | The map the form is written for. |
3507
+ | `enc` | `VARCHAR` | The encoding the form is written for. |
3667
3508
  | `font` | `VARCHAR` | The one face it is for; `NULL` for every face the map lists. |
3668
3509
  | `text` | `VARCHAR` | The word as the script writes it; a value, so case is kept. |
3669
3510
 
@@ -6095,6 +5936,7 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6095
5936
  | `family` | `Address` | `language` only: the parent language, naming a skill note with `subType: language`; this language reads the parent's words as its own — see [a language's words](#a-languages-words) |
6096
5937
  | `abbreviation` | `string` | `language` only: the tag a dictionary prints for it, as `Prov.`; its full name where unstated — see [dictionaries and glossaries](#dictionaries-and-glossaries) |
6097
5938
  | `core` | `boolean` | `language` only: `true` where the language must cover the [core vocabulary](#the-core-vocabulary) |
5939
+ | `roman` | literal NFC string, may be empty | Exact permitted Roman source characters, including both cases, accents, digits and punctuation; required on each configured language note. No family inheritance or range syntax. |
6098
5940
  | `grammar` | `{ plural?, verbs?, agreement?, participles? }` | Optional noun plurals, one verb pattern, agreement and participles; supplied shapes only are checked |
6099
5941
  | `grammar.plural` | `{ ending, becomes }[]` | Literal suffix replacements in authored order; the first match wins |
6100
5942
  | `grammar.plural[].ending` | `string`, required, may be empty | Bare suffix to replace; empty matches every noun |
@@ -6138,8 +5980,8 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6138
5980
  | `words[].tones` | `string` | A tone pattern, as `LHL` |
6139
5981
  | `words[].root` | `string` | A consonantal skeleton, as `d-l-k` |
6140
5982
  | `words[].frame` | `string` | The frame a root is set in, named in `sounds.frames` of the language or an ancestor |
6141
- | `words[].native` | `{ map, font?, text }[]` | The word's native form under a map, stated only where the rows spell it differently — see [a map reads the dictionary first](#a-map-reads-the-dictionary-first) |
6142
- | `words[].native[].map` | `string` | Required: the `data.map.name` the form is written for |
5983
+ | `words[].native` | `{ enc, font?, text }[]` | The word's native form under a map, stated only where the rows spell it differently — see [an encoding reads the dictionary first](#an-encoding-reads-the-dictionary-first) |
5984
+ | `words[].native[].enc` | `string` | Required: the `encoding name` the form is written for |
6143
5985
  | `words[].native[].font` | `string` | The one face the form is for, one the map lists; unstated, every face it lists |
6144
5986
  | `words[].native[].text` | `string` | Required: the word as the script writes it |
6145
5987
  | `affixes` | `{ form?, zero?, kind?, given?, where?, gloss, attaches?, examples?, barredAfter?, tones? }[]` | `language` only: the affixes a word's `built` pieces may name; each states a `form` or `zero: true` |
@@ -6326,23 +6168,19 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6326
6168
  | `naming.nearName.examples` | `{ near, given }[]` | Worked near names |
6327
6169
  | `naming.nearName.examples[].near` | `string`, required | The near name |
6328
6170
  | `naming.nearName.examples[].given` | `string`, required | The given name it is the near name of |
6329
- | `grammar.native` | `{ ending, map, font?, text }[]` | Under a logographic map, the signs a derived form takes after its stem's writing — see [a logographic map](#a-logographic-map) |
6171
+ | `grammar.native` | `{ ending, enc, font?, text }[]` | Under an encoding, the signs a derived form takes after its stem's writing — see [an encoding](#native-spellings-and-parts) |
6330
6172
  | `grammar.native[].ending` | `plural`, `I`, `you`, `heShe`, `we`, `youAll` or `they`, required | The ending written; a person only where `verbs.persons` is stated |
6331
- | `grammar.native[].map` | `string`, required | The `data.map.name` of a logographic map |
6173
+ | `grammar.native[].enc` | `string`, required | The `encoding name` of an encoding |
6332
6174
  | `grammar.native[].font` | `string` | The one face the writing is for, one the map lists; unstated, every face it lists |
6333
6175
  | `grammar.native[].text` | `string`, required, may be empty | The ending's signs; empty writes the stem alone |
6334
- | `affixes[].native` | `{ map, font?, text }[]` | The affix's writing under a logographic map, for a `built` piece naming it |
6335
- | `affixes[].native[].map` | `string`, required | The `data.map.name` of a logographic map |
6176
+ | `affixes[].native` | `{ enc, font?, text }[]` | The affix's writing under an encoding, for a `built` piece naming it |
6177
+ | `affixes[].native[].enc` | `string`, required | The `encoding name` of an encoding |
6336
6178
  | `affixes[].native[].font` | `string` | The one face the writing is for, one the map lists; unstated, every face it lists |
6337
6179
  | `affixes[].native[].text` | `string`, required | The affix as the script writes it |
6338
6180
  | `emphasis` | `words`, `rubric` or `overline` | `language` only: how the language marks a stressed word, over its script's; `words` makes `*…*` and `**…**` in its runs an error — see [script notes and emphasis](#script-notes-and-emphasis) |
6339
- | `writtenIn` | `{ map, font }` | `language` only: the script the language is written in, which a run explicitly marked with the language and `.nativefont` takes — see [script notes and emphasis](#script-notes-and-emphasis) |
6340
- | `writtenIn.map` | `string`, required | The `data.map.name` of a mapping note |
6341
- | `writtenIn.font` | `string`, required | A face the map lists |
6342
- | `script` | `{ fonts, emphasis, strongEmphasis?, direction? }` | `script` only: the faces the script is written in, how it marks emphasis and its direction — see [script notes and emphasis](#script-notes-and-emphasis) |
6181
+ | `script` | `{ fonts, emphasis, direction? }` | `script` only: the faces the script is written in, how it marks emphasis and its direction — see [script notes and emphasis](#script-notes-and-emphasis) |
6343
6182
  | `script.fonts` | `string[]`, required | Installed faces by the slug `font=` names them by; a face belongs to one script |
6344
6183
  | `script.emphasis` | `rubric` or `overline`, required | Sets `*…*` and `**…**` in a run in one of its faces |
6345
- | `script.strongEmphasis` | `rubric` or `overline` | Sets `**…**` instead of `emphasis` |
6346
6184
  | `script.direction` | `vertical-rl` | Written in columns, top to bottom, read from the right, which a [`scroll` fence](../authoring/links-and-markup.md#scrolls) sets |
6347
6185
 
6348
6186
  #### A language's words
@@ -6504,7 +6342,7 @@ states; an affix it names that is a prefix, or that the language does not
6504
6342
  state, is an error at the entry.
6505
6343
 
6506
6344
  Neither rule is used by the dictionary. Both are read by the
6507
- [mapped-run word check](#mapping-notes), which accepts the forms they give,
6345
+ [mapped-run word check](#encodings), which accepts the forms they give,
6508
6346
  and `package-build lexicon --derived` lists the same forms.
6509
6347
 
6510
6348
  All grammar is optional. Only a supplied key's shape is checked: no language
@@ -8246,48 +8084,69 @@ Content prepared to be played — a situation with its cast, places, and possibl
8246
8084
  - settingguide: A culture's guide to the setting, which names its culture in `data.culture`. It orients a reader to a setting or region, bringing its places, peoples, institutions, and daily life into one usable frame with links to detailed notes.
8247
8085
  - post: A blog post, which states the day it was published in `data.date` and may name its writer in `data.author`. A site whose `site.feed` names a section lists its posts there, newest first, and feeds them as Atom.
8248
8086
 
8249
- | `data` property | Values | Description |
8250
- | --------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
8251
- | `culture` | `Address` | `settingguide` only, and required there: the culture the guide introduces, naming a lore note with `subType: culture` |
8252
- | `concepts` | list of `{ id, gloss, group }` | A core vocabulary's concept list, any subType. See [the core vocabulary](#the-core-vocabulary) |
8253
- | `date` | `YYYY-MM-DD` | `post` only, and required there: the day the post was published |
8254
- | `author` | string | `post` only: who wrote the post; a post naming none carries the site's byline, the first entry of `authors` |
8255
- | `concepts[].id` | string | Required: lowercase letters, digits and `-`, unique in the package |
8256
- | `concepts[].gloss` | string | Required: what the concept means, in brief |
8257
- | `concepts[].group` | string | Required: the group the report lists the concept under |
8258
- | `map` | `{ name, vowels?, fonts, rows }` | A mapping, which text marked `map=` with its `name` is rewritten by; any subType. See [mapping notes](#mapping-notes) |
8259
- | `map.name` | string | Required: what `map=` names it by, lowercase letters, digits and `-`, unique in the index |
8260
- | `map.vowels` | string | The characters `before: vowel` reads as vowels |
8261
- | `map.rows` | list of `[from, to]` or `{ from, to, before?, at? }` | Required: the rewrites, in authored order |
8262
- | `map.rows[].from` | string of one or more characters | Required in a map row: the characters it matches |
8263
- | `map.rows[].to` | string, which may be empty | Required in a map row: what it writes in their place |
8264
- | `map.rows[].before` | `vowel \| consonant` | What must follow the match |
8265
- | `map.rows[].at` | `start \| end` | Where the match must sit |
8266
- | `map.fonts` | list of `{ font, rows? }` | Required, at least one: the faces the map is drawn in |
8267
- | `map.fonts[].font` | an installed face's slug | Required: the face, as `font=` names it; not `mono`, `serif` or `sans` |
8268
- | `map.fonts[].rows` | list of `[from, to]` or `{ from, to, before?, at? }` | Rows for this face alone, tried before the shared `rows` |
8269
- | `map.fonts[].rows[].from` | string of one or more characters | Required in a map row: the characters it matches |
8270
- | `map.fonts[].rows[].to` | string, which may be empty | Required in a map row: what it writes in their place |
8271
- | `map.fonts[].rows[].before` | `vowel \| consonant` | What must follow the match |
8272
- | `map.fonts[].rows[].at` | `start \| end` | Where the match must sit |
8273
- | `metres` | `{ name, beats, kind }[]` | The metres a verse fence's `scan=` names; any subType. See [metres](#metres) |
8274
- | `metres[].name` | string | Required: what `scan=` names it by, lowercase letters, digits and `-`, unique in the package |
8275
- | `metres[].beats` | `integer`, required | The beats of one line, above zero |
8276
- | `metres[].kind` | `accentual` | Required: how the beats are counted |
8277
- | `map.logographic` | `true` | The script writes meanings: a run's words are written by the lexicon alone, and the rows write only the text between them |
8278
- | `sounds` | `{ letters?, marks? }` | A spelling guide's letters and marks, for every tongue of the setting; any subType. See [a spelling guide's sounds](#a-spelling-guides-sounds) |
8279
- | `sounds.letters` | `{ letters, kind, like?, place?, ipa?, tongue? }[]` | The letters, each row's keys as a language note's `sounds.letters` |
8280
- | `sounds.letters[].letters` | `string[]`, required | The letters or digraphs the row describes |
8281
- | `sounds.letters[].kind` | `string`, required | What kind of sound they write, as `consonant` or `vowel pair` |
8282
- | `sounds.letters[].like` | `string` | What they sound like |
8283
- | `sounds.letters[].place` | `string` | Where in the mouth they are made |
8284
- | `sounds.letters[].ipa` | `string` | The sounds they write, in the International Phonetic Alphabet |
8285
- | `sounds.letters[].tongue` | an Address, or a list of them | The language notes that write the letters; every tongue where absent |
8286
- | `sounds.marks` | `{ mark, letters, kind, limit }[]` | The marks written on the letters, each row's keys as a language note's `sounds.marks` |
8287
- | `sounds.marks[].mark` | `string`, required | The mark's name, as `acute` |
8288
- | `sounds.marks[].letters` | `string[]`, required | The letters that carry it |
8289
- | `sounds.marks[].kind` | `stress`, `length` or `apart`, required | What it says of its letter |
8290
- | `sounds.marks[].limit` | `one` or `any`, required | How many a word may carry |
8087
+ | `data` property | Values | Description |
8088
+ | ------------------------------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
8089
+ | `language` | a configured language alias | The configured language alias an encoding document writes. |
8090
+ | `font` | an installed font slug | The encoding's installed font, which supplies all glyph codes. |
8091
+ | `accepts` | a list of characters or ranges | Accepted Roman letters and additions to standard punctuation. |
8092
+ | `vowels` | a string | The letters a contextual vowel match reads as vowels. |
8093
+ | `mappings` | Roman strings to glyph codes | Roman source strings mapped to codes published by the selected font. |
8094
+ | `rules` | the closed encoding rules vocabulary | Executable normalization, matching, case, stress, vowel groups, accents and contextual mappings. |
8095
+ | `rules.normalization` | "NFC" | Required value: "NFC". |
8096
+ | `rules.matching` | "longest-first" | Required value: "longest-first". |
8097
+ | `rules.case` | a map | Case handling for letters and consonant groups. |
8098
+ | `rules.case.single-letter` | "preserve" | Required value: "preserve". |
8099
+ | `rules.case.consonant-group` | "lowercase-or-initial-uppercase" | Required value: "lowercase-or-initial-uppercase". |
8100
+ | `rules.case.other-group-cases` | "forbidden" | Required value: "forbidden". |
8101
+ | `rules.stress` | a map | The font's nonprinting stress modifier after an acute vowel. |
8102
+ | `rules.stress.modifier` | a string | The font code for U+E0114. |
8103
+ | `rules.stress.position` | "after-stressed-vowel" | Required value: "after-stressed-vowel". |
8104
+ | `rules.stress.printing` | false | Required value: false. |
8105
+ | `rules.stress.effect` | "stress-only" | Required value: "stress-only". |
8106
+ | `rules.stress.changes-sound` | false | Required value: false. |
8107
+ | `rules.stress.changes-length` | false | Required value: false. |
8108
+ | `rules.stress.vowel-group-position` | "first-vowel" | Required value: "first-vowel". |
8109
+ | `rules.vowel-groups` | a map | Explicit recognized vowel groups and their acute placement. |
8110
+ | `rules.vowel-groups.reading` | "established" | Required value: "established". |
8111
+ | `rules.vowel-groups.allow-splitting` | false | Required value: false. |
8112
+ | `rules.vowel-groups.unrecognized-adjacent-vowels` | "separate" | Required value: "separate". |
8113
+ | `rules.vowel-groups.groups` | a list of vowel groups | The complete authored group inventory. |
8114
+ | `rules.diaeresis` | a map | Whether diaeresis mappings are allowed. |
8115
+ | `rules.diaeresis.allowed` | false | Required value: false. |
8116
+ | `rules.grave-accent` | a map | Whether grave-accent mappings are allowed. |
8117
+ | `rules.grave-accent.allowed` | false | Required value: false. |
8118
+ | `rules.contextual-mappings` | a list of conditional mappings | Before-vowel alternatives applied before unconditional mappings. |
8119
+ | `rules.contextual-mappings[].match` | a string | The source sequence. |
8120
+ | `rules.contextual-mappings[].before` | "vowel" | Required value: "vowel". |
8121
+ | `rules.contextual-mappings[].emit` | a glyph code or list of codes | The font codes written by this alternative. |
8122
+ | `rules.y` | a map | The consonant reading of y. |
8123
+ | `rules.y.kind` | "consonant" | Required value: "consonant". |
8124
+ | `rules.y.sound` | "y in yes" | Required value: "y in yes". |
8125
+ | `rules.y.vowel-reading` | false | Required value: false. |
8126
+ | `culture` | `Address` | `settingguide` only, and required there: the culture the guide introduces, naming a lore note with `subType: culture` |
8127
+ | `concepts` | list of `{ id, gloss, group }` | A core vocabulary's concept list, any subType. See [the core vocabulary](#the-core-vocabulary) |
8128
+ | `date` | `YYYY-MM-DD` | `post` only, and required there: the day the post was published |
8129
+ | `author` | string | `post` only: who wrote the post; a post naming none carries the site's byline, the first entry of `authors` |
8130
+ | `concepts[].id` | string | Required: lowercase letters, digits and `-`, unique in the package |
8131
+ | `concepts[].gloss` | string | Required: what the concept means, in brief |
8132
+ | `concepts[].group` | string | Required: the group the report lists the concept under |
8133
+ | `metres` | `{ name, beats, kind }[]` | The metres a verse fence's `scan=` names; any subType. See [metres](#metres) |
8134
+ | `metres[].name` | string | Required: what `scan=` names it by, lowercase letters, digits and `-`, unique in the package |
8135
+ | `metres[].beats` | `integer`, required | The beats of one line, above zero |
8136
+ | `metres[].kind` | `accentual` | Required: how the beats are counted |
8137
+ | `sounds` | `{ letters?, marks? }` | A spelling guide's letters and marks, for every tongue of the setting; any subType. See [a spelling guide's sounds](#a-spelling-guides-sounds) |
8138
+ | `sounds.letters` | `{ letters, kind, like?, place?, ipa?, tongue? }[]` | The letters, each row's keys as a language note's `sounds.letters` |
8139
+ | `sounds.letters[].letters` | `string[]`, required | The letters or digraphs the row describes |
8140
+ | `sounds.letters[].kind` | `string`, required | What kind of sound they write, as `consonant` or `vowel pair` |
8141
+ | `sounds.letters[].like` | `string` | What they sound like |
8142
+ | `sounds.letters[].place` | `string` | Where in the mouth they are made |
8143
+ | `sounds.letters[].ipa` | `string` | The sounds they write, in the International Phonetic Alphabet |
8144
+ | `sounds.letters[].tongue` | an Address, or a list of them | The language notes that write the letters; every tongue where absent |
8145
+ | `sounds.marks` | `{ mark, letters, kind, limit }[]` | The marks written on the letters, each row's keys as a language note's `sounds.marks` |
8146
+ | `sounds.marks[].mark` | `string`, required | The mark's name, as `acute` |
8147
+ | `sounds.marks[].letters` | `string[]`, required | The letters that carry it |
8148
+ | `sounds.marks[].kind` | `stress`, `length` or `apart`, required | What it says of its letter |
8149
+ | `sounds.marks[].limit` | `one` or `any`, required | How many a word may carry |
8291
8150
 
8292
8151
  A setting guide introduces one culture's view of the setting, so it names that
8293
8152
  culture, and a `doc` of any other `subType` has no culture of its own to name.
@@ -8607,3 +8466,54 @@ base without a comma, so `n I f` reads "noun of class I, feminine".
8607
8466
  | `i` | conjugation | i | of the third conjugation |
8608
8467
  | `c` | conjugation | c | of the fourth conjugation |
8609
8468
  | `dep` | voice | dep. | deponent |
8469
+
8470
+ ### Converter data format
8471
+
8472
+ A module can ship one JSON converter file during its manifest build when
8473
+ [`packageBuild.converterData`](../configuration.md#packagebuildconverterdata)
8474
+ names a staged artifact. `format` is `2`.
8475
+
8476
+ ```json
8477
+ {
8478
+ "format": 2,
8479
+ "contentPackage": "demo",
8480
+ "encodings": {
8481
+ "demo-note-doc-aelwsemaronenc": {
8482
+ "data": {
8483
+ "language": "aelw",
8484
+ "font": "semaron-kuriale",
8485
+ "mappings": { "a": "ANKRON_MIN" },
8486
+ "rules": { "normalization": "NFC", "matching": "longest-first" }
8487
+ },
8488
+ "codes": { "ANKRON_MIN": "󰈰" }
8489
+ }
8490
+ },
8491
+ "languages": {
8492
+ "aelw": {
8493
+ "name": "Aelwythi",
8494
+ "lexicon": { "language": "aelw", "data": { "words": [], "affixes": [], "register": [] } }
8495
+ }
8496
+ }
8497
+ }
8498
+ ```
8499
+
8500
+ `contentPackage` supplies the namespace for unqualified document references;
8501
+ an unqualified reference never selects a foreign document. Each encoding key
8502
+ is the document's canonical Address. Its `data` contains
8503
+ only executable authored fields; `codes` is a generated snapshot from the
8504
+ selected font's `fonts.json`, not a code table authored in the note. All valid
8505
+ encoding documents are included. Languages carry display names and serialized
8506
+ lexical inputs, with no default encoding or font. `enc=default`, or an omitted
8507
+ encoding option, preserves Roman text. An explicit selection supplies its
8508
+ language and font; contradictory language or face selections are errors.
8509
+
8510
+ A lexicon's data contains only the word, affix, grammar and name-register
8511
+ fields conversion reads. Native encoding references are canonical Addresses
8512
+ resolved in each source note's own package, including inherited vocabulary.
8513
+ Authored order, case and senses are retained; prose, source records, closures
8514
+ and Maps are absent. The same pure conversion functions serve the build and
8515
+ [browser entry point](../api.md#browser-conversion). A null or omitted language
8516
+ is inferred from the selected encoding and uses that language's lexical inputs.
8517
+ The pure `encodeText` and `decodeText` functions and the CLI commands provide
8518
+ bare encoding without lexical overrides. No font or encoding files are fetched
8519
+ separately by the browser.