@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.
- package/CHANGELOG.md +26 -0
- package/README.md +1 -0
- package/bin/content-commands.mjs +30 -96
- package/bin/encoding-commands.mjs +146 -0
- package/bin/package-build.mjs +35 -24
- package/config.mjs +25 -0
- package/convert.mjs +182 -0
- package/docs/api.md +144 -6
- package/docs/authoring/links-and-markup.md +260 -481
- package/docs/commands.md +110 -119
- package/docs/configuration.md +31 -13
- package/docs/content-format.md +11 -4
- package/docs/diagnostics.md +43 -16
- package/docs/encoding-core.md +193 -0
- package/docs/guides/book.md +2 -2
- package/docs/guides/module-project.md +23 -1
- package/docs/guides/site.md +2 -2
- package/docs/guides/writing-in-invented-scripts.md +458 -575
- package/docs/reference/format-details.md +292 -404
- package/docs/reference/note-types.md +83 -63
- package/docs/source-preview.md +8 -0
- package/e2e.mjs +1 -1
- package/engine/base-compiler.mjs +27 -9
- package/engine/content-charset.mjs +13 -1
- package/engine/content-format.yaml +6 -2
- package/engine/content-index.mjs +6 -2
- package/engine/content-links.mjs +1 -0
- package/engine/content-scripts.mjs +614 -459
- package/engine/content-scroll.mjs +4 -4
- package/engine/content-spans.mjs +40 -9
- package/engine/content-verse.mjs +1 -1
- package/engine/converter-data.mjs +70 -0
- package/engine/dictionary-rows.mjs +2 -34
- package/engine/encoding-integrity.mjs +94 -0
- package/engine/encoding-language.mjs +506 -0
- package/engine/encoding-lexicon.mjs +701 -0
- package/engine/encoding-notes.mjs +186 -0
- package/engine/encoding-standard.mjs +42 -0
- package/engine/encoding-template.mjs +370 -0
- package/engine/encoding-terms.mjs +178 -0
- package/engine/encoding.mjs +952 -0
- package/engine/extension-attributes.mjs +2 -0
- package/engine/helpers.mjs +1 -1
- package/engine/index.mjs +7 -0
- package/engine/language-terms.mjs +17 -16
- package/engine/{logographic.mjs → language-writings.mjs} +29 -38
- package/engine/markup-validation.mjs +1 -1
- package/engine/note-vocabulary.mjs +4 -158
- package/engine/pdf-render.mjs +31 -3
- package/engine/roman-characters.mjs +135 -16
- package/engine/roman-run.mjs +149 -0
- package/engine/roman-verse.mjs +95 -0
- package/engine/run-rows.mjs +29 -31
- package/engine/run-words.mjs +2 -2
- package/engine/script-emphasis-terms.mjs +3 -0
- package/engine/script-emphasis.mjs +3 -10
- package/engine/script-font-delivery.mjs +9 -12
- package/engine/script-fonts.mjs +2 -1
- package/engine/site-build.mjs +14 -5
- package/engine/site-preview.mjs +12 -2
- package/engine/sql-tables.mjs +36 -31
- package/engine/verse-metre.mjs +1 -1
- package/engine/word-forms.mjs +1 -1
- package/engine/word-inflections.mjs +48 -0
- package/engine/word-rows.mjs +1 -1
- package/engine/word-terms.mjs +16 -17
- package/package.json +11 -5
- package/types/config.d.mts +5 -0
- package/types/convert.d.mts +44 -0
- package/types/e2e.d.mts +1 -1
- package/types/engine/base-compiler.d.mts +4 -2
- package/types/engine/content-index.d.mts +4 -1
- package/types/engine/content-scripts.d.mts +103 -42
- package/types/engine/converter-data.d.mts +11 -0
- package/types/engine/dictionary-rows.d.mts +1 -25
- package/types/engine/encoding-integrity.d.mts +14 -0
- package/types/engine/encoding-language.d.mts +36 -0
- package/types/engine/encoding-lexicon.d.mts +259 -0
- package/types/engine/encoding-notes.d.mts +39 -0
- package/types/engine/encoding-standard.d.mts +11 -0
- package/types/engine/encoding-template.d.mts +44 -0
- package/types/engine/encoding-terms.d.mts +143 -0
- package/types/engine/encoding.d.mts +155 -0
- package/types/engine/helpers.d.mts +1 -1
- package/types/engine/index.d.mts +4 -0
- package/types/engine/language-terms.d.mts +1 -1
- package/types/engine/{logographic.d.mts → language-writings.d.mts} +6 -6
- package/types/engine/markup-validation.d.mts +1 -1
- package/types/engine/pdf-render.d.mts +1 -1
- package/types/engine/roman-characters.d.mts +2 -2
- package/types/engine/roman-run.d.mts +101 -0
- package/types/engine/roman-verse.d.mts +23 -0
- package/types/engine/run-rows.d.mts +13 -20
- package/types/engine/script-emphasis-terms.d.mts +2 -0
- package/types/engine/script-emphasis.d.mts +1 -1
- package/types/engine/script-font-delivery.d.mts +2 -3
- package/types/engine/script-fonts.d.mts +5 -0
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/word-inflections.d.mts +25 -0
- package/engine/map-lexicon.mjs +0 -1045
- package/engine/text-maps.mjs +0 -654
- package/engine/written-in.mjs +0 -204
- package/types/engine/map-lexicon.d.mts +0 -330
- package/types/engine/text-maps.d.mts +0 -189
- package/types/engine/written-in.d.mts +0 -76
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Encoding text
|
|
2
|
+
|
|
3
|
+
An encoding is a `doc` note for one language in one font. `enc=` resolves its
|
|
4
|
+
Address with `doc` as the default type: `enc=aelwsemaronenc` selects
|
|
5
|
+
`doc-aelwsemaronenc`. The document's `data.language` is a configured language
|
|
6
|
+
alias and `data.font` is an installed font slug. Those values supply a run's
|
|
7
|
+
language and face; contradictory explicit values are errors. `enc=default`
|
|
8
|
+
leaves Roman text as written and requires no encoding document.
|
|
9
|
+
|
|
10
|
+
Fonts publish glyphs and their codes in `fonts.json`, under each family's
|
|
11
|
+
`codepoints`: `{codepoint: "U+F0230", code: "ANKRON_MIN", ...}`. Codes are
|
|
12
|
+
case-sensitive letters, digits and underscores, unique within that font.
|
|
13
|
+
Encoding documents refer to those codes in `data.mappings`; they do not copy
|
|
14
|
+
the font's code table. Each mapping value is one code or a list of codes.
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
type: doc
|
|
18
|
+
subType: reference
|
|
19
|
+
shortcode: aelwsemaronenc
|
|
20
|
+
name: { full: Aelwythi in Semaron }
|
|
21
|
+
data:
|
|
22
|
+
language: aelw
|
|
23
|
+
font: semaron-kuriale
|
|
24
|
+
mappings:
|
|
25
|
+
a: ANKRON_MIN
|
|
26
|
+
A: ANKRON_MAJ
|
|
27
|
+
ch: CHEROLA_MIN
|
|
28
|
+
Ch: CHEROLA_MAJ
|
|
29
|
+
rules:
|
|
30
|
+
normalization: NFC
|
|
31
|
+
matching: longest-first
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This is a small illustrative mapping, not the complete Aelwythi alphabet.
|
|
35
|
+
`data.accepts`, when supplied, is a list of Roman characters or ranges such as
|
|
36
|
+
`a-z`; otherwise the mapping sources determine the accepted letters.
|
|
37
|
+
`data.vowels` is a string of vowels used by contextual rules. A document's body
|
|
38
|
+
explains the spelling to its reader. Ordinary document metadata remains
|
|
39
|
+
available alongside the executable fields.
|
|
40
|
+
|
|
41
|
+
## Executable rules
|
|
42
|
+
|
|
43
|
+
`data.rules` has a closed vocabulary. Unknown keys and unsupported values are
|
|
44
|
+
errors at their source keys; explanatory rules do not silently authorize a
|
|
45
|
+
second behaviour.
|
|
46
|
+
|
|
47
|
+
| Rule | Values and effect |
|
|
48
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `normalization` | Required `NFC`; input is normalized before matching, with original source offsets retained. |
|
|
50
|
+
| `matching` | Required `longest-first`. |
|
|
51
|
+
| `roundTrip` | Optional `exact` (default) or `canonical`; canonical permits authored aliases and empty code sequences. |
|
|
52
|
+
| `word-separators` | Optional list of source word dividers that emit shared word spaces after contextual alternatives. |
|
|
53
|
+
| `case` | `{single-letter: preserve, consonant-group: lowercase-or-initial-uppercase, other-group-cases: forbidden}`; single letters retain authored case, and groups use lowercase or an initial capital. |
|
|
54
|
+
| `stress` | `{modifier, position: after-stressed-vowel, printing: false, effect: stress-only, changes-sound: false, changes-length: false, vowel-group-position: first-vowel}`; `modifier` names a font code and acute mappings append it to the unchanged vowel. |
|
|
55
|
+
| `vowel-groups` | `{reading: established, allow-splitting: false, unrecognized-adjacent-vowels: separate, groups: [...]}`; the explicit group list determines where an acute belongs on its first vowel. |
|
|
56
|
+
| `diaeresis` | `{allowed: boolean}` permits or forbids explicitly mapped diaeresis characters. |
|
|
57
|
+
| `grave-accent` | `{allowed: boolean}` permits or forbids explicitly mapped grave-accent characters. |
|
|
58
|
+
| `contextual-mappings` | A list of `{match, emit, before?, at?}`; following-letter or source-position conditions precede unconditional mappings. |
|
|
59
|
+
| `y` | `{kind: consonant, sound: "y in yes", vowel-reading: false}`; y cannot also appear in `data.vowels`. |
|
|
60
|
+
|
|
61
|
+
The accent blocks accept an explicit Boolean `allowed`. False forbids that
|
|
62
|
+
accent; true permits it only where the character is accepted and mapped.
|
|
63
|
+
Omitting the block also permits such explicit mappings. Neither choice invents
|
|
64
|
+
an accent pronunciation or adds a character to the inventory.
|
|
65
|
+
|
|
66
|
+
`rules.roundTrip` is optional and defaults to `exact`. Exact mappings must be
|
|
67
|
+
uniquely decodable across adjacent mappings and spaces; ambiguous outputs and
|
|
68
|
+
empty code sequences are refused. This remains the default for Aelwythi.
|
|
69
|
+
|
|
70
|
+
An encoding whose orthography omits distinctions may explicitly state
|
|
71
|
+
`roundTrip: canonical`. Its mappings and conditional emissions may use `[]`
|
|
72
|
+
for an inherent vowel or deleted boundary marker, and different Roman sources
|
|
73
|
+
may name the same output. Decoding returns a conventional spelling. For an output it prefers the first
|
|
74
|
+
authored alias whose following-letter condition matches the decoded suffix,
|
|
75
|
+
with conditional rows before general mappings and longest complete native
|
|
76
|
+
matches first. When none applies, the first authored reading is retained:
|
|
77
|
+
an inherent vowel or deleted marker may have hidden the original condition. It does not invent characters for
|
|
78
|
+
empty outputs or store invisible metadata to restore the original spelling.
|
|
79
|
+
A language's authoritative vocabulary can recover fuller word spellings.
|
|
80
|
+
Shared word spaces remain spaces in both modes.
|
|
81
|
+
|
|
82
|
+
Contextual entries use `{match, emit, before?, at?}` and require at least one
|
|
83
|
+
condition. `before` is `vowel` or `consonant`; `at` is `start`, `end` or
|
|
84
|
+
`line-start`. `start` and `end` refer to word boundaries. A consonant is a
|
|
85
|
+
letter outside the declared `data.vowels`. Line start follows a newline or
|
|
86
|
+
verse slash and permits preceding indentation carets. Multiple conditions
|
|
87
|
+
combine with AND. Entries for the same source may use different conditions;
|
|
88
|
+
repeating the same source and condition tuple is an error. Equal-length
|
|
89
|
+
contextual matches retain authored order.
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
rules:
|
|
93
|
+
normalization: NFC
|
|
94
|
+
matching: longest-first
|
|
95
|
+
roundTrip: canonical
|
|
96
|
+
contextual-mappings:
|
|
97
|
+
- { match: e, before: consonant, emit: [] }
|
|
98
|
+
- { match: e, at: end, emit: [] }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Conditions govern forward matching. Inverse following-letter choices use the
|
|
102
|
+
visible decoded suffix; canonical mode keeps its authored fallback when that
|
|
103
|
+
suffix has lost an inherent vowel or marker. Position conditions govern only
|
|
104
|
+
forward matching. No mode invents deleted markers. Exact decoding retains
|
|
105
|
+
strict following-letter checks.
|
|
106
|
+
|
|
107
|
+
`rules.word-separators` lists source word dividers, such as `['-']`, that emit
|
|
108
|
+
the shared ASCII word space. Contextual rules take priority, so a canonical
|
|
109
|
+
note can emit `[]` for an edge hyphen and a word space for an internal hyphen.
|
|
110
|
+
These sources cannot also be ordinary mappings, replace shared punctuation,
|
|
111
|
+
or contain whitespace, literal markers or structural controls. Separator
|
|
112
|
+
sources participate in inferred `accepts`; no font SPACE code is invented.
|
|
113
|
+
Since a divider and an ordinary space share output, such a note selects
|
|
114
|
+
canonical round trips. Decoding keeps the shared space as a space.
|
|
115
|
+
|
|
116
|
+
A contextual match cannot contain whitespace, literal markers or forbidden
|
|
117
|
+
accents. Both modes enforce the same accepted characters, normalization,
|
|
118
|
+
case, stress, accent and literal-control rules. The compiler does not infer
|
|
119
|
+
linguistic vowel groups or silently add missing letter mappings.
|
|
120
|
+
|
|
121
|
+
Lint checks every authored word, variant and registered name for a language
|
|
122
|
+
with an encoding document, including unused entries. It also checks actual
|
|
123
|
+
name-list entries and name-element spellings and examples; patterns and
|
|
124
|
+
abstract roots are excluded. Bound-element edge hyphens mark joining positions.
|
|
125
|
+
These are bare Roman checks, so a native writing cannot bypass spelling rules.
|
|
126
|
+
Different case and multiword names retain their authored spelling.
|
|
127
|
+
|
|
128
|
+
Every encoding inherits the shared standard's fifteen Roman punctuation
|
|
129
|
+
mappings, verse and name controls, and literal boundaries. `‼` marks an
|
|
130
|
+
imperative and `!` an exclamation. An explicit mapping can give a standard
|
|
131
|
+
source its own font glyph. Other punctuation needs its own mapping.
|
|
132
|
+
|
|
133
|
+
## Conversion API
|
|
134
|
+
|
|
135
|
+
The pure engine works in browsers and Node and opens no files. The caller
|
|
136
|
+
supplies the selected font's resolved code-to-Unicode table separately:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
import {
|
|
140
|
+
compileEncoding,
|
|
141
|
+
encodePieces,
|
|
142
|
+
encodeText,
|
|
143
|
+
decodeText,
|
|
144
|
+
} from "@heroiclands/package-build/engine/encoding";
|
|
145
|
+
|
|
146
|
+
const encoding = compileEncoding(note.data, {
|
|
147
|
+
codes: fontCodes,
|
|
148
|
+
name: "thalorna-note-doc-aelwsemaronenc",
|
|
149
|
+
});
|
|
150
|
+
const native = encodeText(encoding, roman);
|
|
151
|
+
const reading = decodeText(encoding, native);
|
|
152
|
+
const pieces = encodePieces(encoding, roman);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`validateSource(encoding, text, options)` validates accepted Roman characters
|
|
156
|
+
and source rules without requiring an ordinary mapping for every letter;
|
|
157
|
+
authoritative lexical writings can supply that coverage. It throws the same
|
|
158
|
+
positioned errors as encoding and shares its source normalization.
|
|
159
|
+
|
|
160
|
+
Only the executable fields belong in the compiler's `data` argument: language,
|
|
161
|
+
font, mappings, rules, and optional accepts and vowels. A loader separates
|
|
162
|
+
ordinary document metadata. The closed public compiler accepts encoding-note
|
|
163
|
+
data; `compileRows` is an internal row-execution entry used by conformance
|
|
164
|
+
fixtures, not an authored input format.
|
|
165
|
+
|
|
166
|
+
`encodeText` and `decodeText` return strings. Unknown input throws
|
|
167
|
+
`EncodingError` and returns no partial text. `offset` is a zero-based UTF-16
|
|
168
|
+
offset into the input, suitable for composing with a Markdown offset map.
|
|
169
|
+
`line` and `column` are one-based Unicode code-point positions; schema errors
|
|
170
|
+
expose their `key`. Exact decoding resolves the complete unambiguous output sequence. Canonical
|
|
171
|
+
decoding selects the authored conventional reading.
|
|
172
|
+
|
|
173
|
+
`encodePieces` uses the same rules and returns `{from, to, start, end, row}`
|
|
174
|
+
records. `start` and exclusive `end` delimit original UTF-16 input, including
|
|
175
|
+
all whitespace consumed by a piece. A matched row identifies its source and
|
|
176
|
+
schema key. Literal syntax has a null row. Optional `start` and `end` bounds
|
|
177
|
+
retain surrounding source context while preventing matches beyond the bound.
|
|
178
|
+
|
|
179
|
+
Outside literal markers, Unicode Zs and U+0009 through U+000D normalize to one
|
|
180
|
+
space. Other whitespace needs a mapping. `⟦…⟧` reads the font's codes or strict
|
|
181
|
+
`U+XXXX` scalars, with four to six uppercase hex digits and no surrogates.
|
|
182
|
+
Whitespace between literal codes writes nothing. Literal payload occurrences
|
|
183
|
+
of the opening, closing or escape control are quoted with U+E0115; decoding
|
|
184
|
+
unquotes them before reading their codes. Unknown codes, malformed escapes,
|
|
185
|
+
nested markers and unmatched markers are errors.
|
|
186
|
+
|
|
187
|
+
`{verse: true}` handles authored stanza and canto structure. The Markdown
|
|
188
|
+
renderer additionally writes a boundary after every content line, including
|
|
189
|
+
the final line before a stanza or canto. Roman line layout is retained.
|
|
190
|
+
|
|
191
|
+
The internal row conformance fixtures cover their captured source programs;
|
|
192
|
+
they do not establish that every language has an authored encoding document.
|
|
193
|
+
The Aelwythi Semaron template is the public-note integration fixture.
|
package/docs/guides/book.md
CHANGED
|
@@ -505,14 +505,14 @@ the font registry.
|
|
|
505
505
|
|
|
506
506
|
### Fonts for marked text
|
|
507
507
|
|
|
508
|
-
Native text marked with `
|
|
508
|
+
Native text marked with `enc=` in one of the faces of `@heroiclands/fonts` is set in
|
|
509
509
|
that face once the package installs the fonts package in `devDependencies`.
|
|
510
510
|
The build then adds the fonts package's `fonts/` directory, which holds the
|
|
511
511
|
TrueType files, to the compiler's font search path after the shipped faces and
|
|
512
512
|
`fonts.path`. `font=serif`, `sans` and `mono` set the book's own serif, sans and
|
|
513
513
|
mono. A package without the fonts, or whose notes set no text in a face,
|
|
514
514
|
searches the same directories as before. See
|
|
515
|
-
[marking language, font and
|
|
515
|
+
[marking language, font and encoding](../authoring/links-and-markup.md#marking-language-font-and-encoding).
|
|
516
516
|
|
|
517
517
|
## Build and inspect
|
|
518
518
|
|
|
@@ -691,7 +691,7 @@ package-build: Cannot stage assets — these paths do not exist:
|
|
|
691
691
|
|
|
692
692
|
### Fonts for marked text
|
|
693
693
|
|
|
694
|
-
A module shows native text
|
|
694
|
+
A module shows native text selected with an `enc=` document Address in one of the faces of
|
|
695
695
|
`@heroiclands/fonts` in that face once the package installs the fonts package
|
|
696
696
|
in `devDependencies`. Nothing is configured: the build reads which faces the
|
|
697
697
|
notes use from explicit `font=` overrides or opted-in language defaults.
|
|
@@ -705,6 +705,28 @@ no text in a face, stages nothing and its manifest names nothing. The stage
|
|
|
705
705
|
refuses a fonts package that lacks its stylesheet, its licence or a file its
|
|
706
706
|
manifest lists, with a finding at the fonts package's `fonts.json`.
|
|
707
707
|
|
|
708
|
+
## Browser conversion data
|
|
709
|
+
|
|
710
|
+
A module offering a language converter declares one output in its existing
|
|
711
|
+
manifest build:
|
|
712
|
+
|
|
713
|
+
```yaml
|
|
714
|
+
packageBuild:
|
|
715
|
+
converterData: data/converter.json
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
`package-build manifest` writes the JSON beneath the build stage, so the
|
|
719
|
+
release includes the data alongside the module's other files. It embeds each
|
|
720
|
+
language's published encoding and the lexical inputs used by the build.
|
|
721
|
+
|
|
722
|
+
Bundle `@heroiclands/package-build/convert` into the module's browser code,
|
|
723
|
+
fetch `modules/<module-id>/data/converter.json` once, and pass the parsed data
|
|
724
|
+
to `encode` or `decode`. A picker can list `Object.entries(data.languages)`
|
|
725
|
+
using each entry's `name`; each entry already states its encoding and face.
|
|
726
|
+
Show the returned findings alongside the text when a word cannot be recovered.
|
|
727
|
+
See the [API](../api.md#browser-conversion) and
|
|
728
|
+
[data format](../reference/format-details.md#converter-data-format).
|
|
729
|
+
|
|
708
730
|
## Step 9 — generate the manifest
|
|
709
731
|
|
|
710
732
|
```console
|
package/docs/guides/site.md
CHANGED
|
@@ -270,10 +270,10 @@ part of the site.
|
|
|
270
270
|
|
|
271
271
|
## Show marked text in its font
|
|
272
272
|
|
|
273
|
-
A site shows native text marked with `
|
|
273
|
+
A site shows native text marked with `enc=` in one of the faces of
|
|
274
274
|
`@heroiclands/fonts` in that face once the package installs the fonts package
|
|
275
275
|
in `devDependencies`, as the
|
|
276
|
-
[authoring guide](../authoring/links-and-markup.md#marking-language-font-and-
|
|
276
|
+
[authoring guide](../authoring/links-and-markup.md#marking-language-font-and-encoding)
|
|
277
277
|
describes. Nothing else is configured: the build reads which faces the notes use
|
|
278
278
|
from explicit `font=` overrides or opted-in language defaults.
|
|
279
279
|
|