@heroiclands/package-build 25.0.0 → 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 (105) hide show
  1. package/CHANGELOG.md +14 -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 +137 -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 +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 +450 -574
  19. package/docs/reference/format-details.md +289 -404
  20. package/docs/reference/note-types.md +80 -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 +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 +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 +43 -0
  82. package/types/engine/encoding-terms.d.mts +105 -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
@@ -0,0 +1,135 @@
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
+ | `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. |
52
+ | `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. |
53
+ | `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. |
54
+ | `diaeresis` | `{allowed: false}` forbids diaeresis mappings. |
55
+ | `grave-accent` | `{allowed: false}` forbids grave-accent mappings. |
56
+ | `contextual-mappings` | A list of `{match, before: vowel, emit}`; the contextual mapping precedes an unconditional mapping and `emit` names one code or a sequence. |
57
+ | `y` | `{kind: consonant, sound: "y in yes", vowel-reading: false}`; y cannot also appear in `data.vowels`. |
58
+
59
+ A contextual match cannot contain whitespace, literal markers or forbidden
60
+ accents. Mapping outputs must be uniquely decodable across arbitrary adjacent
61
+ mappings and spaces; ambiguous concatenations are refused. The compiler does
62
+ not infer linguistic vowel groups or silently add missing letter mappings.
63
+
64
+ Lint checks every authored word, variant and registered name for a language
65
+ with an encoding document, including unused entries. It also checks actual
66
+ name-list entries and name-element spellings and examples; patterns and
67
+ abstract roots are excluded. Bound-element edge hyphens mark joining positions.
68
+ These are bare Roman checks, so a native writing cannot bypass spelling rules.
69
+ Different case and multiword names retain their authored spelling.
70
+
71
+ Every encoding inherits the shared standard's fifteen Roman punctuation
72
+ mappings, verse and name controls, and literal boundaries. `‼` marks an
73
+ imperative and `!` an exclamation. An explicit mapping can give a standard
74
+ source its own font glyph. Other punctuation needs its own mapping.
75
+
76
+ ## Conversion API
77
+
78
+ The pure engine works in browsers and Node and opens no files. The caller
79
+ supplies the selected font's resolved code-to-Unicode table separately:
80
+
81
+ ```js
82
+ import {
83
+ compileEncoding,
84
+ encodePieces,
85
+ encodeText,
86
+ decodeText,
87
+ } from "@heroiclands/package-build/engine/encoding";
88
+
89
+ const encoding = compileEncoding(note.data, {
90
+ codes: fontCodes,
91
+ name: "thalorna-note-doc-aelwsemaronenc",
92
+ });
93
+ const native = encodeText(encoding, roman);
94
+ const reading = decodeText(encoding, native);
95
+ const pieces = encodePieces(encoding, roman);
96
+ ```
97
+
98
+ `validateSource(encoding, text, options)` validates accepted Roman characters
99
+ and source rules without requiring an ordinary mapping for every letter;
100
+ authoritative lexical writings can supply that coverage. It throws the same
101
+ positioned errors as encoding and shares its source normalization.
102
+
103
+ Only the executable fields belong in the compiler's `data` argument: language,
104
+ font, mappings, rules, and optional accepts and vowels. A loader separates
105
+ ordinary document metadata. The closed public compiler accepts encoding-note
106
+ data; `compileRows` is an internal row-execution entry used by conformance
107
+ fixtures, not an authored input format.
108
+
109
+ `encodeText` and `decodeText` return strings. Unknown input throws
110
+ `EncodingError` and returns no partial text. `offset` is a zero-based UTF-16
111
+ offset into the input, suitable for composing with a Markdown offset map.
112
+ `line` and `column` are one-based Unicode code-point positions; schema errors
113
+ expose their `key`. Decoding resolves the complete unambiguous output sequence.
114
+
115
+ `encodePieces` uses the same rules and returns `{from, to, start, end, row}`
116
+ records. `start` and exclusive `end` delimit original UTF-16 input, including
117
+ all whitespace consumed by a piece. A matched row identifies its source and
118
+ schema key. Literal syntax has a null row. Optional `start` and `end` bounds
119
+ retain surrounding source context while preventing matches beyond the bound.
120
+
121
+ Outside literal markers, Unicode Zs and U+0009 through U+000D normalize to one
122
+ space. Other whitespace needs a mapping. `⟦…⟧` reads the font's codes or strict
123
+ `U+XXXX` scalars, with four to six uppercase hex digits and no surrogates.
124
+ Whitespace between literal codes writes nothing. Literal payload occurrences
125
+ of the opening, closing or escape control are quoted with U+E0115; decoding
126
+ unquotes them before reading their codes. Unknown codes, malformed escapes,
127
+ nested markers and unmatched markers are errors.
128
+
129
+ `{verse: true}` handles authored stanza and canto structure. The Markdown
130
+ renderer additionally writes a boundary after every content line, including
131
+ the final line before a stanza or canto. Roman line layout is retained.
132
+
133
+ The internal row conformance fixtures cover their captured source programs;
134
+ they do not establish that every language has an authored encoding document.
135
+ The Aelwythi Semaron template is the public-note integration fixture.
@@ -505,14 +505,14 @@ the font registry.
505
505
 
506
506
  ### Fonts for marked text
507
507
 
508
- Native text marked with `lang=` and `.nativefont` in one of the faces of `@heroiclands/fonts` is set in
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 mapping](../authoring/links-and-markup.md#marking-language-font-and-mapping).
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 marked with `lang=` and `.nativefont` in one of the faces of
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
@@ -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 `lang=` and `.nativefont` in one of the faces of
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-mapping)
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