@heroiclands/package-build 25.0.0 → 25.1.1

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 (105) hide show
  1. package/CHANGELOG.md +26 -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 +144 -6
  9. package/docs/authoring/links-and-markup.md +260 -481
  10. package/docs/commands.md +110 -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 +193 -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 +458 -575
  19. package/docs/reference/format-details.md +292 -404
  20. package/docs/reference/note-types.md +83 -63
  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 +13 -1
  25. package/engine/content-format.yaml +6 -2
  26. package/engine/content-index.mjs +6 -2
  27. package/engine/content-links.mjs +1 -0
  28. package/engine/content-scripts.mjs +614 -459
  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 +701 -0
  37. package/engine/encoding-notes.mjs +186 -0
  38. package/engine/encoding-standard.mjs +42 -0
  39. package/engine/encoding-template.mjs +370 -0
  40. package/engine/encoding-terms.mjs +178 -0
  41. package/engine/encoding.mjs +952 -0
  42. package/engine/extension-attributes.mjs +2 -0
  43. package/engine/helpers.mjs +1 -1
  44. package/engine/index.mjs +7 -0
  45. package/engine/language-terms.mjs +17 -16
  46. package/engine/{logographic.mjs → language-writings.mjs} +29 -38
  47. package/engine/markup-validation.mjs +1 -1
  48. package/engine/note-vocabulary.mjs +4 -158
  49. package/engine/pdf-render.mjs +31 -3
  50. package/engine/roman-characters.mjs +135 -16
  51. package/engine/roman-run.mjs +149 -0
  52. package/engine/roman-verse.mjs +95 -0
  53. package/engine/run-rows.mjs +29 -31
  54. package/engine/run-words.mjs +2 -2
  55. package/engine/script-emphasis-terms.mjs +3 -0
  56. package/engine/script-emphasis.mjs +3 -10
  57. package/engine/script-font-delivery.mjs +9 -12
  58. package/engine/script-fonts.mjs +2 -1
  59. package/engine/site-build.mjs +14 -5
  60. package/engine/site-preview.mjs +12 -2
  61. package/engine/sql-tables.mjs +36 -31
  62. package/engine/verse-metre.mjs +1 -1
  63. package/engine/word-forms.mjs +1 -1
  64. package/engine/word-inflections.mjs +48 -0
  65. package/engine/word-rows.mjs +1 -1
  66. package/engine/word-terms.mjs +16 -17
  67. package/package.json +11 -5
  68. package/types/config.d.mts +5 -0
  69. package/types/convert.d.mts +44 -0
  70. package/types/e2e.d.mts +1 -1
  71. package/types/engine/base-compiler.d.mts +4 -2
  72. package/types/engine/content-index.d.mts +4 -1
  73. package/types/engine/content-scripts.d.mts +103 -42
  74. package/types/engine/converter-data.d.mts +11 -0
  75. package/types/engine/dictionary-rows.d.mts +1 -25
  76. package/types/engine/encoding-integrity.d.mts +14 -0
  77. package/types/engine/encoding-language.d.mts +36 -0
  78. package/types/engine/encoding-lexicon.d.mts +259 -0
  79. package/types/engine/encoding-notes.d.mts +39 -0
  80. package/types/engine/encoding-standard.d.mts +11 -0
  81. package/types/engine/encoding-template.d.mts +44 -0
  82. package/types/engine/encoding-terms.d.mts +143 -0
  83. package/types/engine/encoding.d.mts +155 -0
  84. package/types/engine/helpers.d.mts +1 -1
  85. package/types/engine/index.d.mts +4 -0
  86. package/types/engine/language-terms.d.mts +1 -1
  87. package/types/engine/{logographic.d.mts → language-writings.d.mts} +6 -6
  88. package/types/engine/markup-validation.d.mts +1 -1
  89. package/types/engine/pdf-render.d.mts +1 -1
  90. package/types/engine/roman-characters.d.mts +2 -2
  91. package/types/engine/roman-run.d.mts +101 -0
  92. package/types/engine/roman-verse.d.mts +23 -0
  93. package/types/engine/run-rows.d.mts +13 -20
  94. package/types/engine/script-emphasis-terms.d.mts +2 -0
  95. package/types/engine/script-emphasis.d.mts +1 -1
  96. package/types/engine/script-font-delivery.d.mts +2 -3
  97. package/types/engine/script-fonts.d.mts +5 -0
  98. package/types/engine/site-preview.d.mts +1 -1
  99. package/types/engine/word-inflections.d.mts +25 -0
  100. package/engine/map-lexicon.mjs +0 -1045
  101. package/engine/text-maps.mjs +0 -654
  102. package/engine/written-in.mjs +0 -204
  103. package/types/engine/map-lexicon.d.mts +0 -330
  104. package/types/engine/text-maps.d.mts +0 -189
  105. package/types/engine/written-in.d.mts +0 -76
@@ -1960,208 +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 language note declares its Roman source inventory in `data.roman`.** It is
2006
- one literal NFC string containing each permitted character once, including every
2007
- capital, accent, digit and punctuation mark the language uses. For example,
2008
- `roman: "kaKàÀ.1"` permits exactly those seven characters. There is no range
2009
- syntax, automatic case expansion, or inventory inherited from a parent language.
2010
- An empty string explicitly declares that the language has no written characters.
2011
- Spaces, tabs and line breaks are structural and are not listed in the inventory.
2012
- A missing declaration on a configured language note is an error even when no
2013
- passage uses the language. A directly typed native sign is separate from
2014
- Roman input only when the run explicitly selects `.nativefont`, the character
2015
- belongs to a recognized setting-script encoding, and the selected face draws it.
2016
- A font's ability to draw Roman punctuation does not admit that punctuation.
2017
-
2018
- `package-build lint` checks the visible source of language-tagged spans, divs,
2019
- verse and scroll fences against that inventory before any map or native-word
2020
- replacement can hide a character. Both the configured name and its BCP 47 tag
2021
- select the same inventory. A nested language selects its own; link destinations,
2022
- attributes, column numbers, indentation periods and `***` stanza separators are
2023
- structure. Escaping a character does not admit it. Source spelling must be NFC;
2024
- errors retain the original file position. Unassociated external tags such as
2025
- `en` and `zxx` keep their ordinary behavior. Standalone `package-build markdown`
2026
- checks markup without loading language inventories. Structured frontmatter words
2027
- are separate from prose runs.
2028
-
2029
- **A face draws the code points its `fonts.json` entry lists in `codepoints`,
2030
- and whitespace.** After the map, any other character in a run set in a face is
2031
- an error, located at the source character it came from; through a map, at the
2032
- start of the matched `from`. Each character is reported once per run. The
2033
- generic families are not checked. `input`, `layout` and `encoding` in
2034
- `fonts.json` are not read.
2035
-
2036
- Text marked with `font=` or `map=`, or with a declared language, is plain: a
2037
- span or a verse holds no emphasis, link, image, footnote, wikilink, code or
2038
- HTML, and no span but a marked one inside a div or a fence; a div holds
2039
- paragraphs and line breaks only. Text set in a face takes `*…*` and `**…**`,
2040
- set by its [emphasis convention](#script-notes-and-emphasis). The text is read as written, so `[`, `]`, `"`,
2041
- `<<`, `>>`, `!` and `@#$%^&` are characters, and a bracket pair is markup only
2042
- when `(`, `{` or a second `[` makes it a link, a span or a wikilink. Text marked
2043
- with a real language's tag alone keeps its Markdown. See
2044
- [marking language, font and mapping](../authoring/links-and-markup.md#marking-language-font-and-mapping).
2045
-
2046
- Each own-note metadata record carries `runs` in source order, an empty array
2047
- when the body marks nothing. Every entry has `kind` (`span`, `block`, `scroll` or
2048
- `verse`), `lang`, `tag`, `font`, `map`, `line` and `column`: `lang`, `font` and
2049
- `map` as written, or its language's `data.writtenIn` defaults only for an
2050
- explicit `.nativefont` run, `tag` the BCP 47 tag `lang` resolves
2051
- to, each `null` when absent, and the position of the span's `[`, the div's
2052
- `:::` or the fence's opening. An opted-in run also carries optional `nativefont: true`; Roman runs omit
2053
- that flag and leave unused script defaults null. The `runs` SQL relation
2054
- retains its existing columns and projects no flag column. Tags differing
2055
- only in case remain separate values. This is derived
2056
- metadata, not frontmatter. The [`runs` relation](#content-tables) flattens
2057
- these entries with their containing NOTE Address.
2058
-
2059
- #### Mapping notes
2060
-
2061
- A `doc` note's `data.map` is a mapping: rows that rewrite sequences of
2062
- characters into characters, which a run marked `map=` with its `name` is
2063
- rewritten by before it is set. A mapping belongs to a script, and serves every
2064
- language written in it.
1963
+ #### Text marked with a language, font or encoding
2065
1964
 
2066
- ```yaml
2067
- data:
2068
- map:
2069
- name: semaron
2070
- vowels: "aeiouAEIOU"
2071
- fonts:
2072
- - font: semaron-kuriale
2073
- - font: semaron-carved
2074
- rows:
2075
- - [th, "\U000F0251"]
2076
- rows:
2077
- - [a, "\U000F0230"]
2078
- - [th, "\U000F0250"]
2079
- - { from: y, to: "\U000F0246", before: consonant }
2080
- ```
2081
-
2082
- | Key | Shape | Meaning |
2083
- | ------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------- |
2084
- | `name` | string, required | What `map=` names it by: lowercase letters, digits and `-`, unique in the index |
2085
- | `logographic` | `true` | The script writes meanings; see [a logographic map](#a-logographic-map) |
2086
- | `vowels` | string | The characters `before: vowel` reads as vowels |
2087
- | `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 |
2088
- | `rows` | list of `[from, to]` or `{ from, to, before?, at? }` | The shared rewrites, in authored order |
2089
-
2090
- **A face's own rows come first.** A run in a face tries that face's `rows`,
2091
- the longest match among them, and only where none matches the shared `rows`; a
2092
- face listed with no `rows` uses the shared rows alone, and a run with no
2093
- `font=` uses them too. Rows take the same shapes and conditions in both places,
2094
- and `vowels` serves them all. A run whose `font=` is not one of the map's
2095
- `fonts` is an error at its `map=`:
2096
-
2097
- > `` `thuravark-carved` is not a font of the map `semaron`; it is for `semaron-kuriale` and `semaron-carved` ``
2098
-
2099
- A row's `from` is one or more characters and its `to` any number, none
2100
- included, each a whole code point; a code point above U+FFFF is written in YAML
2101
- with the eight-digit escape, as `"\U000F0200"`. The longest match wins; among rows of one length, a row with a
2102
- condition that holds comes before a row with none, and otherwise the earlier
2103
- row wins. A row whose condition fails is skipped, and a character no row
2104
- matches passes through unchanged.
2105
-
2106
- | Condition | Holds when |
2107
- | ------------------- | ---------------------------------------------------------------------------- |
2108
- | `before: vowel` | the next character is one of `vowels` |
2109
- | `before: consonant` | the next character is any other letter |
2110
- | `at: start` | the match is the run's first character, or follows whitespace or punctuation |
2111
- | `at: end` | the match ends the run, or is followed by whitespace or punctuation |
2112
-
2113
- Neither `before` condition holds at the end of the text. The note's body is
2114
- for a reader: nothing reads it. Each row is a row of the
2115
- [`maps` relation](#content-tables), never a struct key, so `A` and `a` are two
2116
- rows; a face's own rows carry its slug in `font`.
2117
-
2118
- The data-key check holds every key of `data.map` and of each row to the table
2119
- under [`type: doc`](#type-doc), at its own line and column:
2120
-
2121
- > `` `data.map.rows[2]` should be `[from, to]` or `{ from, to, before?, at? }`, but reads "a" ``
2122
-
2123
- > `` `data.map.rows[3]` must state `to` — a string, which may be empty ``
2124
-
2125
- > `` "when" is not a key of `data.map.rows[5]`; it takes only `from`, `to`, `before`, `at` ``
2126
-
2127
- > `` `data.map.rows[6].before` should be `vowel` or `consonant`, but reads "liquid" ``
2128
-
2129
- The map's own check reports the rest, each at its key:
2130
-
2131
- > `` `data.map.name` is `Vyl_Semaron`; a map's name is lowercase letters, digits and `-` ``
2132
-
2133
- > `` `data.map.name` is `vyl-semaron`, which Lore/Other.md also declares; a map's name is unique ``
2134
-
2135
- > `` `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.
2136
1970
 
2137
- > `` `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.
2138
1975
 
2139
- > `` `data.map.rows[4]` has `before: consonant`, and the map states no `vowels` to read it by ``
2140
-
2141
- > `` `data.map.fonts` is empty; a map lists each face it is drawn in ``
2142
-
2143
- > `` `data.map.fonts[0].font` is `mono`, a generic family; a map lists the faces it is drawn in ``
2144
-
2145
- > `` `data.map.rows[2]` matches `z`, a letter, and the rows of a logographic map write only the text between words ``
2146
-
2147
- The lint checks the listed faces against the installed `@heroiclands/fonts`,
2148
- each at the entry or the row at fault. Every listed face draws every code point
2149
- its own rows write, every code point the shared rows it can reach write (a
2150
- shared row is out of a face's reach where a plain row of the face's own matches
2151
- the start of its `from`), and every code point of the native forms that apply
2152
- to it:
2153
-
2154
- > `` `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.
2155
2032
 
2156
- > `` `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
+ ```
2157
2038
 
2158
- > `` `data.map.fonts[1].rows[0]` writes U+F0251, which the font `semaron-carved` does not draw ``
2039
+ ##### Literal codes
2159
2040
 
2160
- > `` `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.
2161
2049
 
2162
- 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.
2163
2055
 
2164
- #### A map reads the dictionary first
2056
+ #### An encoding reads the dictionary first
2165
2057
 
2166
2058
  The sound rules belong to the script, and the exceptions to the language. A
2167
2059
  word of a [language's words](#a-languages-words) states a `native` form for a
@@ -2174,18 +2066,17 @@ words:
2174
2066
  field: "Law, the court and the written act"
2175
2067
  gloss: an oath
2176
2068
  native:
2177
- - { map: semaron, text: "\U000F024F\U000F0230\U000F023F\U000F023C" }
2178
- - { 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" }
2179
2071
  ```
2180
2072
 
2181
2073
  | Key | Shape | Meaning |
2182
2074
  | ------ | ---------------- | -------------------------------------------------------------------------------------------- |
2183
- | `map` | string, required | The `data.map.name` the native form is written for |
2184
2075
  | `font` | string | The one face it is for; unstated, every face the map lists, and a face's own form wins there |
2185
2076
  | `text` | string, required | The word as the script writes it, in the map's characters |
2186
2077
 
2187
2078
  A run marked `lang=` with a declared language whose
2188
- [`note`](../configuration.md#languages) names its language note, and `map=`,
2079
+ [`note`](../configuration.md#languages) names its language note, and `enc=`,
2189
2080
  is written word by word:
2190
2081
 
2191
2082
  1. **A word** is a maximal run of letters, combining marks and digits, an
@@ -2211,12 +2102,12 @@ declared language with no `note` are spelled by the rows alone. A character the
2211
2102
  face does not draw inside a word written by its native form is an error at the
2212
2103
  word's start:
2213
2104
 
2214
- > `` `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 ``
2215
2106
 
2216
- > `` `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 ``
2217
2108
 
2218
2109
  **Language word-book validation applies to Roman and native runs alike**,
2219
- independently of `.nativefont` or mapping. Every word is a word of the
2110
+ independently of encoding selection. Every word is a word of the
2220
2111
  language, case folded: a
2221
2112
  `data.words[].form`, a word of a name the language note's own `data.register`
2222
2113
  lists under a `tongue` other than `translation`, or a form one rule derives from a lexicon form —
@@ -2231,7 +2122,7 @@ gives a word of one of its `classes`, or a participle `data.grammar.participles`
2231
2122
  gives a verb (see [optional noun and verb forms](#optional-noun-and-verb-forms)). A compound not known whole is checked part by
2232
2123
  part at its hyphens and en dashes. Any other word is an error at its first
2233
2124
  character, once per run; see
2234
- [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):
2235
2126
 
2236
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 ``
2237
2128
 
@@ -2240,24 +2131,24 @@ struct key, so forms that differ only in case are two rows. The data-key check
2240
2131
  holds each entry to its three keys; the lint checks the rest, each at the entry
2241
2132
  or the key at fault:
2242
2133
 
2243
- > `` `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 ``
2244
2135
 
2245
- > `` `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` ``
2246
2137
 
2247
- > `` `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]` ``
2248
2139
 
2249
- > `` `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 ``
2250
2141
 
2251
- > `` `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 ``
2252
2143
 
2253
2144
  The "states what the rows already give" finding compares a native form stated
2254
2145
  for a face with that face's rows, and one stated for no face with every listed
2255
2146
  face's rows: it is redundant only where every face's rows give it. This is what
2256
2147
  keeps a lexicon to its exceptions.
2257
2148
 
2258
- `package-build transliterate` maps a passage, and `package-build lexicon` lists
2259
- every word with its native form, through the same code as the build: see
2260
- [`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
2261
2152
  [`lexicon`](../commands.md#package-build-lexicon-language).
2262
2153
 
2263
2154
  #### Metres
@@ -2293,103 +2184,74 @@ its count can be the metre's.
2293
2184
  The count is an author-side check. The rendered fence carries `data-scan` with
2294
2185
  the metre's name and nothing a reader sees.
2295
2186
 
2296
- #### A logographic map
2297
-
2298
- A map stating `logographic: true` writes meanings, so its rows spell no word.
2299
- Every word of a run under it is written from the run language's lexicon, and
2300
- the rows write only the text between words: whitespace, points and any other
2301
- text holding no letter. A word holds at least one letter; a run of digits is
2302
- text between words. A word is matched case folded, NFC, with `’` read as `'`,
2303
- and written by the first of these that gives a writing:
2304
-
2305
- 1. **The entries of its form.** Each entry whose `form`, folded, is the word,
2306
- and failing that each whose folded `form` with its joining hyphens taken
2307
- off is the word (`Gar-` for `gar`). An entry is written by its own `native`
2308
- for the map, the one for the run's face where it states one, else the one
2309
- for no face; else by its `built` pieces' writings joined in order.
2310
- 2. **A derived form.** A noun's plural (its own `plural`, else the
2311
- `data.grammar.plural` rule) and a verb's present form for one person of
2312
- `data.grammar.verbs.persons` are written by the stem's entry's writing,
2313
- followed by the `text` of the `data.grammar.native` entry for that ending.
2314
- Other derived forms (a replacing suffix, an agreeing form, a participle)
2315
- have no writing of their own here; they are coined as words, or written in
2316
- signs.
2317
- 3. **Its hyphenated parts.** A word holding a hyphen or an en dash that the
2318
- steps above do not write is written by each part in turn, each by steps 1
2319
- and 2; the hyphen writes nothing.
2320
-
2321
- A `built` piece is a word of the lexicon written exactly as the piece, else an
2322
- affix of `data.affixes` whose `form` or `front` is the piece, else either one
2323
- with joining hyphens taken off; a word piece is written by its own `native` or
2324
- its own pieces, recursively, and an affix by its own `native`. A piece that
2325
- reaches a word already being resolved has no writing.
2326
-
2327
- **Ambiguity.** Where a step matches more than one entry and their writings are
2328
- not all one text, or one has a writing and another none, the word has no
2329
- writing and is an error naming every entry's gloss. A part matched that way
2330
- makes the word ambiguous the same way, naming the part.
2331
-
2332
- | Key | Shape | Meaning |
2333
- | ------------------------------ | ------------------------------------------------------- | ------------------------------------------------------- |
2334
- | `data.affixes[].native` | list of `{ map, font?, text }` | The affix's writing, for a `built` piece naming it |
2335
- | `data.grammar.native` | list of `{ ending, map, font?, text }` | The signs a derived form takes after its stem's writing |
2336
- | `data.grammar.native[].ending` | `plural`, `I`, `you`, `heShe`, `we`, `youAll` or `they` | The ending written |
2337
- | `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.
2338
2195
 
2339
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]
2340
2209
  affixes:
2341
- - form: "-unet"
2342
- gloss: "a thing made of"
2210
+ - form: -unet
2211
+ gloss: a thing made of
2343
2212
  native:
2344
- - { map: zethu, text: "\U0001EBC7" }
2345
- grammar:
2346
- plural:
2347
- - { ending: "", becomes: "im" }
2348
- verbs:
2349
- persons: { I: en, you: et, heShe: "", we: enu, youAll: etu, they: ar }
2350
- native:
2351
- - { ending: plural, map: zethu, text: "\U0001EBE1" }
2352
- - { ending: I, map: zethu, text: "\U0001EBDF" }
2353
- ```
2354
-
2355
- A word with no writing, an ambiguous word, and a word in a run with no lexicon
2356
- to write it from are each an error at the word, once per run:
2357
-
2358
- > `` `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.
2359
2244
 
2360
- > `` `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` ``
2361
-
2362
- > `` `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` ``
2363
-
2364
- > `` `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 ``
2365
-
2366
- > `` `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 ``
2367
-
2368
- Signs typed in the run hold no letter, so they are no word and pass through as
2369
- typed. The face-coverage check reads the writings as it reads native forms; a
2370
- word with no writing is reported by its own finding alone. The lexicon check
2371
- and the register check apply to the run as to any mapped run.
2372
-
2373
- Under a logographic map a word's `native` is its writing and is not compared
2374
- with the rows. An affix's `native` and `data.grammar.native` are read only by
2375
- a logographic map, so an entry naming any other map is an error, as is an
2376
- ending of a person where the pattern states no `persons`. The checks of a
2377
- word's `native` (an unknown map, a face the map is not for, a second entry, an
2378
- undrawn code point) apply to both, a second entry being one for the same
2379
- ending, map and face:
2380
-
2381
- > `` `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 ``
2382
-
2383
- > `` `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 ``
2384
-
2385
- > `` `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
2386
2246
 
2387
- > `` `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`.
2388
2251
 
2389
- Affix and ending writings are not rows of the `natives` relation, which holds
2390
- the words' native forms; `package-build lexicon` resolves them.
2391
-
2392
- #### 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.
2393
2255
 
2394
2256
  A `skill` note of `subType: script` states the faces its script is written in,
2395
2257
  how the script marks a stressed word, and the direction it is written in, in
@@ -2400,36 +2262,18 @@ data:
2400
2262
  script:
2401
2263
  fonts: [qalezu-hand]
2402
2264
  emphasis: overline
2403
- strongEmphasis: rubric
2404
2265
  ```
2405
2266
 
2406
2267
  - **`fonts`** lists installed faces by the slug `font=` names them by, at least
2407
2268
  one. A face belongs to one script.
2408
2269
  - **`emphasis`** is `rubric` or `overline`, and sets both `*…*` and `**…**`
2409
2270
  (or `_…_` and `__…__`) inside a run in one of the faces.
2410
- - **`strongEmphasis`**, optional, is `rubric` or `overline`, and sets `**…**`
2411
- alone.
2412
2271
  - **`direction`**, optional, is `vertical-rl` for a script written in columns,
2413
2272
  top to bottom, with the columns read from the right. A
2414
2273
  [`scroll` fence](../authoring/links-and-markup.md#scrolls) sets text in
2415
2274
  such a script, and is an error in any other. A script that states no
2416
2275
  direction is written in lines.
2417
2276
 
2418
- A `skill` note of `subType: language` may state `data.writtenIn`, the script
2419
- the language is written in: `map`, the `data.map.name` of a mapping note, and
2420
- `font`, one of the faces that map lists, both required.
2421
-
2422
- ```yaml
2423
- data:
2424
- writtenIn: { map: semaron, font: semaron-kuriale }
2425
- ```
2426
-
2427
- A run explicitly marked with the language and `.nativefont` is mapped by
2428
- `map` and set in `font`, as
2429
- [text marked with a language, a font or a map](#text-marked-with-a-language-a-font-or-a-map)
2430
- describes. A face a language's `writtenIn` names counts as used, so the
2431
- package's fonts are delivered for it.
2432
-
2433
2277
  A `skill` note of `subType: language` may state `data.emphasis`: `words`,
2434
2278
  `rubric` or `overline`. It overrides the script's convention in every run of the
2435
2279
  language. `words` means the language marks emphasis with a word, so `*…*` or
@@ -2464,12 +2308,6 @@ Each of these is an error at the key or the entry at fault:
2464
2308
 
2465
2309
  > `` `data.emphasis` states how a language marks emphasis, and this note's `subType` is not `language` ``
2466
2310
 
2467
- > `` `data.writtenIn` names the script a language is written in, and this note's `subType` is not `language` ``
2468
-
2469
- > `` `data.writtenIn.map` is `semoran`, which no mapping note's `data.map.name` declares; did you mean `semaron`? ``
2470
-
2471
- > `` `data.writtenIn.font` is `teng-chou`, which the map `semaron` is not drawn in; it is drawn in `semaron-kuriale` ``
2472
-
2473
2311
  > `` `data.script.fonts` is empty; a script lists each face it is written in ``
2474
2312
 
2475
2313
  > `` `data.script.fonts[0]` is `serif`, a generic family; a script lists the faces it is written in ``
@@ -2482,7 +2320,7 @@ Each of these is an error at the key or the entry at fault:
2482
2320
 
2483
2321
  In a run:
2484
2322
 
2485
- > ``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 `__…__` ``
2486
2324
 
2487
2325
  > `` `vyl` marks emphasis with a word, not a mark; write the word ``
2488
2326
 
@@ -3635,7 +3473,7 @@ GM-only owners; all/native contexts retain them. Only authored occurrences
3635
3473
  contribute rows, so generated queries and sections add no further names.
3636
3474
 
3637
3475
  **`runs`** is one row per span, generic div and verse fence an authored note
3638
- 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,
3639
3477
  including on an empty relation:
3640
3478
 
3641
3479
  | Column | SQL type | Meaning |
@@ -3645,7 +3483,7 @@ including on an empty relation:
3645
3483
  | `lang` | `VARCHAR` | The language as written, its own or inherited, or `NULL`. |
3646
3484
  | `tag` | `VARCHAR` | The BCP 47 tag `lang` resolves to, or `NULL` when it resolves to none. |
3647
3485
  | `font` | `VARCHAR` | The selected font; language defaults apply only to native runs, else `NULL`. |
3648
- | `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`. |
3649
3487
  | `line` | `BIGINT` | Original 1-based source line of the span's `[`, the div's `:::` or the fence's opening. |
3650
3488
  | `column` | `BIGINT` | Original 1-based UTF-16 source column there. |
3651
3489
 
@@ -3656,29 +3494,8 @@ WHERE font = 'semaron-kuriale'
3656
3494
  ORDER BY owner, line, "column"
3657
3495
  ```
3658
3496
 
3659
- **`maps`** is one row per well-formed row of a [mapping note](#mapping-notes)'s
3660
- `data.map.rows` and of each face's own `rows`. Each row has these columns,
3661
- including on an empty relation:
3662
-
3663
- | Column | SQL type | Meaning |
3664
- | -------- | --------- | ----------------------------------------------------------- |
3665
- | `owner` | `VARCHAR` | The mapping note's canonical NOTE Address. |
3666
- | `name` | `VARCHAR` | The map's `name`. |
3667
- | `font` | `VARCHAR` | The face whose own row it is; `NULL` for a shared row. |
3668
- | `row` | `BIGINT` | The row's 1-based place in its `rows`. |
3669
- | `from` | `VARCHAR` | The characters it matches. |
3670
- | `to` | `VARCHAR` | What it writes; empty for a row that drops what it matches. |
3671
- | `before` | `VARCHAR` | `vowel`, `consonant` or `NULL`. |
3672
- | `at` | `VARCHAR` | `start`, `end` or `NULL`. |
3673
-
3674
- `from`, `to` and `at` are SQL keywords, so a query quotes them:
3675
-
3676
- ```sql
3677
- SELECT "row", "from", "to", before FROM maps WHERE name = 'vyl-semaron' ORDER BY "row"
3678
- ```
3679
-
3680
3497
  **`natives`** is one row per entry of a word's `native` on every
3681
- [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,
3682
3499
  including on an empty relation:
3683
3500
 
3684
3501
  | Column | SQL type | Meaning |
@@ -3687,7 +3504,7 @@ including on an empty relation:
3687
3504
  | `word` | `BIGINT` | The word's place in `data.words`, from `0`, as `words.position`. |
3688
3505
  | `form` | `VARCHAR` | The word's `form`. |
3689
3506
  | `native` | `BIGINT` | The entry's place in the word's `native`, from `0`. |
3690
- | `map` | `VARCHAR` | The map the form is written for. |
3507
+ | `enc` | `VARCHAR` | The encoding the form is written for. |
3691
3508
  | `font` | `VARCHAR` | The one face it is for; `NULL` for every face the map lists. |
3692
3509
  | `text` | `VARCHAR` | The word as the script writes it; a value, so case is kept. |
3693
3510
 
@@ -6163,8 +5980,8 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6163
5980
  | `words[].tones` | `string` | A tone pattern, as `LHL` |
6164
5981
  | `words[].root` | `string` | A consonantal skeleton, as `d-l-k` |
6165
5982
  | `words[].frame` | `string` | The frame a root is set in, named in `sounds.frames` of the language or an ancestor |
6166
- | `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) |
6167
- | `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 |
6168
5985
  | `words[].native[].font` | `string` | The one face the form is for, one the map lists; unstated, every face it lists |
6169
5986
  | `words[].native[].text` | `string` | Required: the word as the script writes it |
6170
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` |
@@ -6351,23 +6168,19 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6351
6168
  | `naming.nearName.examples` | `{ near, given }[]` | Worked near names |
6352
6169
  | `naming.nearName.examples[].near` | `string`, required | The near name |
6353
6170
  | `naming.nearName.examples[].given` | `string`, required | The given name it is the near name of |
6354
- | `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) |
6355
6172
  | `grammar.native[].ending` | `plural`, `I`, `you`, `heShe`, `we`, `youAll` or `they`, required | The ending written; a person only where `verbs.persons` is stated |
6356
- | `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 |
6357
6174
  | `grammar.native[].font` | `string` | The one face the writing is for, one the map lists; unstated, every face it lists |
6358
6175
  | `grammar.native[].text` | `string`, required, may be empty | The ending's signs; empty writes the stem alone |
6359
- | `affixes[].native` | `{ map, font?, text }[]` | The affix's writing under a logographic map, for a `built` piece naming it |
6360
- | `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 |
6361
6178
  | `affixes[].native[].font` | `string` | The one face the writing is for, one the map lists; unstated, every face it lists |
6362
6179
  | `affixes[].native[].text` | `string`, required | The affix as the script writes it |
6363
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) |
6364
- | `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) |
6365
- | `writtenIn.map` | `string`, required | The `data.map.name` of a mapping note |
6366
- | `writtenIn.font` | `string`, required | A face the map lists |
6367
- | `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) |
6368
6182
  | `script.fonts` | `string[]`, required | Installed faces by the slug `font=` names them by; a face belongs to one script |
6369
6183
  | `script.emphasis` | `rubric` or `overline`, required | Sets `*…*` and `**…**` in a run in one of its faces |
6370
- | `script.strongEmphasis` | `rubric` or `overline` | Sets `**…**` instead of `emphasis` |
6371
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 |
6372
6185
 
6373
6186
  #### A language's words
@@ -6529,7 +6342,7 @@ states; an affix it names that is a prefix, or that the language does not
6529
6342
  state, is an error at the entry.
6530
6343
 
6531
6344
  Neither rule is used by the dictionary. Both are read by the
6532
- [mapped-run word check](#mapping-notes), which accepts the forms they give,
6345
+ [mapped-run word check](#encodings), which accepts the forms they give,
6533
6346
  and `package-build lexicon --derived` lists the same forms.
6534
6347
 
6535
6348
  All grammar is optional. Only a supplied key's shape is checked: no language
@@ -8271,48 +8084,72 @@ Content prepared to be played — a situation with its cast, places, and possibl
8271
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.
8272
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.
8273
8086
 
8274
- | `data` property | Values | Description |
8275
- | --------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
8276
- | `culture` | `Address` | `settingguide` only, and required there: the culture the guide introduces, naming a lore note with `subType: culture` |
8277
- | `concepts` | list of `{ id, gloss, group }` | A core vocabulary's concept list, any subType. See [the core vocabulary](#the-core-vocabulary) |
8278
- | `date` | `YYYY-MM-DD` | `post` only, and required there: the day the post was published |
8279
- | `author` | string | `post` only: who wrote the post; a post naming none carries the site's byline, the first entry of `authors` |
8280
- | `concepts[].id` | string | Required: lowercase letters, digits and `-`, unique in the package |
8281
- | `concepts[].gloss` | string | Required: what the concept means, in brief |
8282
- | `concepts[].group` | string | Required: the group the report lists the concept under |
8283
- | `map` | `{ name, vowels?, fonts, rows }` | A mapping, which text marked `map=` with its `name` is rewritten by; any subType. See [mapping notes](#mapping-notes) |
8284
- | `map.name` | string | Required: what `map=` names it by, lowercase letters, digits and `-`, unique in the index |
8285
- | `map.vowels` | string | The characters `before: vowel` reads as vowels |
8286
- | `map.rows` | list of `[from, to]` or `{ from, to, before?, at? }` | Required: the rewrites, in authored order |
8287
- | `map.rows[].from` | string of one or more characters | Required in a map row: the characters it matches |
8288
- | `map.rows[].to` | string, which may be empty | Required in a map row: what it writes in their place |
8289
- | `map.rows[].before` | `vowel \| consonant` | What must follow the match |
8290
- | `map.rows[].at` | `start \| end` | Where the match must sit |
8291
- | `map.fonts` | list of `{ font, rows? }` | Required, at least one: the faces the map is drawn in |
8292
- | `map.fonts[].font` | an installed face's slug | Required: the face, as `font=` names it; not `mono`, `serif` or `sans` |
8293
- | `map.fonts[].rows` | list of `[from, to]` or `{ from, to, before?, at? }` | Rows for this face alone, tried before the shared `rows` |
8294
- | `map.fonts[].rows[].from` | string of one or more characters | Required in a map row: the characters it matches |
8295
- | `map.fonts[].rows[].to` | string, which may be empty | Required in a map row: what it writes in their place |
8296
- | `map.fonts[].rows[].before` | `vowel \| consonant` | What must follow the match |
8297
- | `map.fonts[].rows[].at` | `start \| end` | Where the match must sit |
8298
- | `metres` | `{ name, beats, kind }[]` | The metres a verse fence's `scan=` names; any subType. See [metres](#metres) |
8299
- | `metres[].name` | string | Required: what `scan=` names it by, lowercase letters, digits and `-`, unique in the package |
8300
- | `metres[].beats` | `integer`, required | The beats of one line, above zero |
8301
- | `metres[].kind` | `accentual` | Required: how the beats are counted |
8302
- | `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 |
8303
- | `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) |
8304
- | `sounds.letters` | `{ letters, kind, like?, place?, ipa?, tongue? }[]` | The letters, each row's keys as a language note's `sounds.letters` |
8305
- | `sounds.letters[].letters` | `string[]`, required | The letters or digraphs the row describes |
8306
- | `sounds.letters[].kind` | `string`, required | What kind of sound they write, as `consonant` or `vowel pair` |
8307
- | `sounds.letters[].like` | `string` | What they sound like |
8308
- | `sounds.letters[].place` | `string` | Where in the mouth they are made |
8309
- | `sounds.letters[].ipa` | `string` | The sounds they write, in the International Phonetic Alphabet |
8310
- | `sounds.letters[].tongue` | an Address, or a list of them | The language notes that write the letters; every tongue where absent |
8311
- | `sounds.marks` | `{ mark, letters, kind, limit }[]` | The marks written on the letters, each row's keys as a language note's `sounds.marks` |
8312
- | `sounds.marks[].mark` | `string`, required | The mark's name, as `acute` |
8313
- | `sounds.marks[].letters` | `string[]`, required | The letters that carry it |
8314
- | `sounds.marks[].kind` | `stress`, `length` or `apart`, required | What it says of its letter |
8315
- | `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.roundTrip` | a string | Exact by default; canonical permits aliases and empty code sequences and decodes an authored conventional spelling. |
8098
+ | `rules.word-separators` | a list of nonempty NFC source sequences | Source word dividers written as shared spaces, after contextual alternatives; cannot also be ordinary mappings or replace shared punctuation. |
8099
+ | `rules.case` | a map | Case handling for letters and consonant groups. |
8100
+ | `rules.case.single-letter` | "preserve" | Required value: "preserve". |
8101
+ | `rules.case.consonant-group` | "lowercase-or-initial-uppercase" | Required value: "lowercase-or-initial-uppercase". |
8102
+ | `rules.case.other-group-cases` | "forbidden" | Required value: "forbidden". |
8103
+ | `rules.stress` | a map | The font's nonprinting stress modifier after an acute vowel. |
8104
+ | `rules.stress.modifier` | a string | The font code for U+E0114. |
8105
+ | `rules.stress.position` | "after-stressed-vowel" | Required value: "after-stressed-vowel". |
8106
+ | `rules.stress.printing` | false | Required value: false. |
8107
+ | `rules.stress.effect` | "stress-only" | Required value: "stress-only". |
8108
+ | `rules.stress.changes-sound` | false | Required value: false. |
8109
+ | `rules.stress.changes-length` | false | Required value: false. |
8110
+ | `rules.stress.vowel-group-position` | "first-vowel" | Required value: "first-vowel". |
8111
+ | `rules.vowel-groups` | a map | Explicit recognized vowel groups and their acute placement. |
8112
+ | `rules.vowel-groups.reading` | "established" | Required value: "established". |
8113
+ | `rules.vowel-groups.allow-splitting` | false | Required value: false. |
8114
+ | `rules.vowel-groups.unrecognized-adjacent-vowels` | "separate" | Required value: "separate". |
8115
+ | `rules.vowel-groups.groups` | a list of vowel groups | The complete authored group inventory. |
8116
+ | `rules.diaeresis` | a map | Whether diaeresis mappings are allowed. |
8117
+ | `rules.diaeresis.allowed` | true or false | False forbids the accent; true permits explicitly mapped and accepted characters. |
8118
+ | `rules.grave-accent` | a map | Whether grave-accent mappings are allowed. |
8119
+ | `rules.grave-accent.allowed` | true or false | False forbids the accent; true permits explicitly mapped and accepted characters. |
8120
+ | `rules.contextual-mappings` | a list of conditional mappings | Alternatives conditioned on the following letter or source position, applied before unconditional mappings. |
8121
+ | `rules.contextual-mappings[].match` | a string | The source sequence. |
8122
+ | `rules.contextual-mappings[].before` | a string | Match before a declared vowel or another letter. |
8123
+ | `rules.contextual-mappings[].at` | a string | Match at word start, word end or line start. |
8124
+ | `rules.contextual-mappings[].emit` | a glyph code or list of codes (empty only with canonical round trips) | The font codes written by this alternative. |
8125
+ | `rules.y` | a map | The consonant reading of y. |
8126
+ | `rules.y.kind` | "consonant" | Required value: "consonant". |
8127
+ | `rules.y.sound` | "y in yes" | Required value: "y in yes". |
8128
+ | `rules.y.vowel-reading` | false | Required value: false. |
8129
+ | `culture` | `Address` | `settingguide` only, and required there: the culture the guide introduces, naming a lore note with `subType: culture` |
8130
+ | `concepts` | list of `{ id, gloss, group }` | A core vocabulary's concept list, any subType. See [the core vocabulary](#the-core-vocabulary) |
8131
+ | `date` | `YYYY-MM-DD` | `post` only, and required there: the day the post was published |
8132
+ | `author` | string | `post` only: who wrote the post; a post naming none carries the site's byline, the first entry of `authors` |
8133
+ | `concepts[].id` | string | Required: lowercase letters, digits and `-`, unique in the package |
8134
+ | `concepts[].gloss` | string | Required: what the concept means, in brief |
8135
+ | `concepts[].group` | string | Required: the group the report lists the concept under |
8136
+ | `metres` | `{ name, beats, kind }[]` | The metres a verse fence's `scan=` names; any subType. See [metres](#metres) |
8137
+ | `metres[].name` | string | Required: what `scan=` names it by, lowercase letters, digits and `-`, unique in the package |
8138
+ | `metres[].beats` | `integer`, required | The beats of one line, above zero |
8139
+ | `metres[].kind` | `accentual` | Required: how the beats are counted |
8140
+ | `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) |
8141
+ | `sounds.letters` | `{ letters, kind, like?, place?, ipa?, tongue? }[]` | The letters, each row's keys as a language note's `sounds.letters` |
8142
+ | `sounds.letters[].letters` | `string[]`, required | The letters or digraphs the row describes |
8143
+ | `sounds.letters[].kind` | `string`, required | What kind of sound they write, as `consonant` or `vowel pair` |
8144
+ | `sounds.letters[].like` | `string` | What they sound like |
8145
+ | `sounds.letters[].place` | `string` | Where in the mouth they are made |
8146
+ | `sounds.letters[].ipa` | `string` | The sounds they write, in the International Phonetic Alphabet |
8147
+ | `sounds.letters[].tongue` | an Address, or a list of them | The language notes that write the letters; every tongue where absent |
8148
+ | `sounds.marks` | `{ mark, letters, kind, limit }[]` | The marks written on the letters, each row's keys as a language note's `sounds.marks` |
8149
+ | `sounds.marks[].mark` | `string`, required | The mark's name, as `acute` |
8150
+ | `sounds.marks[].letters` | `string[]`, required | The letters that carry it |
8151
+ | `sounds.marks[].kind` | `stress`, `length` or `apart`, required | What it says of its letter |
8152
+ | `sounds.marks[].limit` | `one` or `any`, required | How many a word may carry |
8316
8153
 
8317
8154
  A setting guide introduces one culture's view of the setting, so it names that
8318
8155
  culture, and a `doc` of any other `subType` has no culture of its own to name.
@@ -8632,3 +8469,54 @@ base without a comma, so `n I f` reads "noun of class I, feminine".
8632
8469
  | `i` | conjugation | i | of the third conjugation |
8633
8470
  | `c` | conjugation | c | of the fourth conjugation |
8634
8471
  | `dep` | voice | dep. | deponent |
8472
+
8473
+ ### Converter data format
8474
+
8475
+ A module can ship one JSON converter file during its manifest build when
8476
+ [`packageBuild.converterData`](../configuration.md#packagebuildconverterdata)
8477
+ names a staged artifact. `format` is `2`.
8478
+
8479
+ ```json
8480
+ {
8481
+ "format": 2,
8482
+ "contentPackage": "demo",
8483
+ "encodings": {
8484
+ "demo-note-doc-aelwsemaronenc": {
8485
+ "data": {
8486
+ "language": "aelw",
8487
+ "font": "semaron-kuriale",
8488
+ "mappings": { "a": "ANKRON_MIN" },
8489
+ "rules": { "normalization": "NFC", "matching": "longest-first" }
8490
+ },
8491
+ "codes": { "ANKRON_MIN": "󰈰" }
8492
+ }
8493
+ },
8494
+ "languages": {
8495
+ "aelw": {
8496
+ "name": "Aelwythi",
8497
+ "lexicon": { "language": "aelw", "data": { "words": [], "affixes": [], "register": [] } }
8498
+ }
8499
+ }
8500
+ }
8501
+ ```
8502
+
8503
+ `contentPackage` supplies the namespace for unqualified document references;
8504
+ an unqualified reference never selects a foreign document. Each encoding key
8505
+ is the document's canonical Address. Its `data` contains
8506
+ only executable authored fields; `codes` is a generated snapshot from the
8507
+ selected font's `fonts.json`, not a code table authored in the note. All valid
8508
+ encoding documents are included. Languages carry display names and serialized
8509
+ lexical inputs, with no default encoding or font. `enc=default`, or an omitted
8510
+ encoding option, preserves Roman text. An explicit selection supplies its
8511
+ language and font; contradictory language or face selections are errors.
8512
+
8513
+ A lexicon's data contains only the word, affix, grammar and name-register
8514
+ fields conversion reads. Native encoding references are canonical Addresses
8515
+ resolved in each source note's own package, including inherited vocabulary.
8516
+ Authored order, case and senses are retained; prose, source records, closures
8517
+ and Maps are absent. The same pure conversion functions serve the build and
8518
+ [browser entry point](../api.md#browser-conversion). A null or omitted language
8519
+ is inferred from the selected encoding and uses that language's lexical inputs.
8520
+ The pure `encodeText` and `decodeText` functions and the CLI commands provide
8521
+ bare encoding without lexical overrides. No font or encoding files are fetched
8522
+ separately by the browser.