@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.
- package/CHANGELOG.md +14 -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 +137 -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 +135 -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 +450 -574
- package/docs/reference/format-details.md +289 -404
- package/docs/reference/note-types.md +80 -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 +699 -0
- package/engine/encoding-notes.mjs +186 -0
- package/engine/encoding-standard.mjs +42 -0
- package/engine/encoding-template.mjs +313 -0
- package/engine/encoding-terms.mjs +141 -0
- package/engine/encoding.mjs +946 -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 +43 -0
- package/types/engine/encoding-terms.d.mts +105 -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
package/convert.mjs
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
3
|
+
* Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
|
|
4
|
+
*
|
|
5
|
+
* This work is licensed under the GNU General Public License v3.0 (GPLv3).
|
|
6
|
+
* You may copy, modify, and distribute it under the terms of that license.
|
|
7
|
+
*
|
|
8
|
+
* For full terms, see the LICENSE.md file in the project root or visit:
|
|
9
|
+
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
12
|
+
*/
|
|
13
|
+
/** Browser conversion from one module's versioned, self-contained data file. */
|
|
14
|
+
import { renderAddress } from "./engine/address-render.mjs";
|
|
15
|
+
import { compileEncoding, encodeText, decodeText, EncodingError } from "./engine/encoding.mjs";
|
|
16
|
+
import { encodeWithLanguage, decodeWithLanguage } from "./engine/encoding-language.mjs";
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {{language:string,data:Record<string,any>}} ConverterLexicon
|
|
19
|
+
* @typedef {{name:string,lexicon?:ConverterLexicon}} ConverterLanguage
|
|
20
|
+
* @typedef {{format:2,contentPackage:string,encodings:Record<string,any>,languages:Record<string,ConverterLanguage>}} ConverterData
|
|
21
|
+
* @typedef {{enc?:string,font?:string,verse?:boolean}} ConversionOptions
|
|
22
|
+
*/
|
|
23
|
+
const compiled = new WeakMap();
|
|
24
|
+
const validated = new WeakSet();
|
|
25
|
+
const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
26
|
+
function keys(value, allowed, where) {
|
|
27
|
+
if (!object(value)) throw new TypeError(`${where} must be an object`);
|
|
28
|
+
for (const key of Object.keys(value))
|
|
29
|
+
if (!allowed.includes(key)) throw new TypeError(`${where}.${key} is unknown`);
|
|
30
|
+
}
|
|
31
|
+
function definition(value, name) {
|
|
32
|
+
if (!object(value)) throw new TypeError("An encoding definition must be an object");
|
|
33
|
+
keys(value, ["data", "codes"], `encodings.${name}`);
|
|
34
|
+
let known = compiled.get(value);
|
|
35
|
+
if (!known) {
|
|
36
|
+
known = compileEncoding(value.data, { codes: value.codes, name });
|
|
37
|
+
compiled.set(value, known);
|
|
38
|
+
}
|
|
39
|
+
return known;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function lexicalData(value, where) {
|
|
43
|
+
keys(value, ["words", "affixes", "grammar", "register"], where);
|
|
44
|
+
for (const field of ["words", "affixes", "register"]) {
|
|
45
|
+
if (value[field] === undefined) continue;
|
|
46
|
+
if (!Array.isArray(value[field])) throw new TypeError(`${where}.${field} must be an array`);
|
|
47
|
+
for (const row of value[field]) {
|
|
48
|
+
const name = field === "register" ? "name" : "form";
|
|
49
|
+
if (!object(row) || typeof row[name] !== "string" || !row[name])
|
|
50
|
+
throw new TypeError(`${where}.${field} needs ${name}`);
|
|
51
|
+
if (
|
|
52
|
+
row.native !== undefined &&
|
|
53
|
+
(!Array.isArray(row.native) ||
|
|
54
|
+
row.native.some(
|
|
55
|
+
(native) =>
|
|
56
|
+
!object(native) ||
|
|
57
|
+
typeof native.enc !== "string" ||
|
|
58
|
+
typeof native.text !== "string" ||
|
|
59
|
+
(native.font !== undefined && typeof native.font !== "string"),
|
|
60
|
+
))
|
|
61
|
+
)
|
|
62
|
+
throw new TypeError(`${where}.${field} has invalid native writings`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (value.grammar !== undefined && !object(value.grammar))
|
|
66
|
+
throw new TypeError(`${where}.grammar must be an object`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Validate the format-2 converter data without opening files or using Node.
|
|
70
|
+
* @param {ConverterData} data Parsed JSON, treated as read-only.
|
|
71
|
+
* @returns {ConverterData} The validated data.
|
|
72
|
+
*/
|
|
73
|
+
export function validateData(data) {
|
|
74
|
+
if (validated.has(data)) return data;
|
|
75
|
+
keys(data, ["format", "contentPackage", "encodings", "languages"], "data");
|
|
76
|
+
if (data.format !== 2) throw new TypeError("Converter data format must be 2");
|
|
77
|
+
if (
|
|
78
|
+
typeof data.contentPackage !== "string" ||
|
|
79
|
+
!/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(data.contentPackage)
|
|
80
|
+
)
|
|
81
|
+
throw new TypeError("Converter data needs its canonical contentPackage");
|
|
82
|
+
if (!object(data.encodings) || !object(data.languages))
|
|
83
|
+
throw new TypeError("Converter encodings and languages must be objects");
|
|
84
|
+
for (const [name, value] of Object.entries(data.encodings)) {
|
|
85
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*-note-doc-[a-z0-9]+$/u.test(name))
|
|
86
|
+
throw new TypeError(`Invalid encoding document Address ${name}`);
|
|
87
|
+
const encoding = definition(value, name);
|
|
88
|
+
if (!Object.hasOwn(data.languages, encoding.language))
|
|
89
|
+
throw new TypeError(`Encoding ${name} needs configured language ${encoding.language}`);
|
|
90
|
+
}
|
|
91
|
+
for (const [language, value] of Object.entries(data.languages)) {
|
|
92
|
+
keys(value, ["name", "lexicon"], `languages.${language}`);
|
|
93
|
+
if (typeof value.name !== "string")
|
|
94
|
+
throw new TypeError(`Language ${language} needs its name`);
|
|
95
|
+
if (value.lexicon !== undefined) {
|
|
96
|
+
keys(value.lexicon, ["language", "data"], `languages.${language}.lexicon`);
|
|
97
|
+
if (typeof value.lexicon.language !== "string" || !object(value.lexicon.data))
|
|
98
|
+
throw new TypeError(`Language ${language} has invalid lexicon inputs`);
|
|
99
|
+
lexicalData(value.lexicon.data, `languages.${language}.lexicon.data`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
validated.add(data);
|
|
103
|
+
return data;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function conversion(data, language, text, options, direction) {
|
|
107
|
+
validateData(data);
|
|
108
|
+
if (typeof text !== "string") throw new TypeError("Conversion input must be text");
|
|
109
|
+
let entry = language === null || language === undefined ? undefined : data.languages[language];
|
|
110
|
+
if (language !== null && language !== undefined && !Object.hasOwn(data.languages, language))
|
|
111
|
+
throw new TypeError(`Unknown language ${language}`);
|
|
112
|
+
const name = options.enc ?? "default";
|
|
113
|
+
if (name === "default") return { text, findings: [] };
|
|
114
|
+
const short = /^(?:(?:note-)?doc-|doc\/)?([a-z0-9]+)$/u.exec(name);
|
|
115
|
+
const selected =
|
|
116
|
+
Object.hasOwn(data.encodings, name) ? name
|
|
117
|
+
: short ?
|
|
118
|
+
renderAddress({
|
|
119
|
+
package: data.contentPackage,
|
|
120
|
+
system: "note",
|
|
121
|
+
type: "doc",
|
|
122
|
+
shortcode: short[1],
|
|
123
|
+
})
|
|
124
|
+
: undefined;
|
|
125
|
+
if (!selected || !Object.hasOwn(data.encodings, selected))
|
|
126
|
+
throw new TypeError(`Unknown encoding document ${name}`);
|
|
127
|
+
const encoding = definition(data.encodings[selected], selected);
|
|
128
|
+
if (entry && language !== encoding.language)
|
|
129
|
+
throw new TypeError(`Encoding ${selected} writes ${encoding.language}, not ${language}`);
|
|
130
|
+
entry ??= data.languages[encoding.language];
|
|
131
|
+
const settings = {
|
|
132
|
+
font: options.font ?? encoding.font,
|
|
133
|
+
verse: options.verse,
|
|
134
|
+
lexicon: entry?.lexicon,
|
|
135
|
+
};
|
|
136
|
+
if (entry?.lexicon)
|
|
137
|
+
return direction === "encode" ?
|
|
138
|
+
encodeWithLanguage(encoding, text, settings)
|
|
139
|
+
: decodeWithLanguage(encoding, text, settings);
|
|
140
|
+
try {
|
|
141
|
+
return {
|
|
142
|
+
text:
|
|
143
|
+
direction === "encode" ?
|
|
144
|
+
encodeText(encoding, text, settings)
|
|
145
|
+
: decodeText(encoding, text, settings),
|
|
146
|
+
findings: [],
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (!(error instanceof EncodingError)) throw error;
|
|
150
|
+
return {
|
|
151
|
+
text: "",
|
|
152
|
+
findings: [
|
|
153
|
+
{
|
|
154
|
+
severity: "error",
|
|
155
|
+
message: error.message,
|
|
156
|
+
offset: error.offset ?? 0,
|
|
157
|
+
line: error.line ?? 1,
|
|
158
|
+
column: error.column ?? 1,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Encode with the selected encoding document's language, optionally stated explicitly.
|
|
166
|
+
* @param {ConverterData} data The module's parsed converter data.
|
|
167
|
+
* @param {string|null|undefined} language A language key, or null to infer it from the encoding.
|
|
168
|
+
* @param {string} text Roman input.
|
|
169
|
+
* @param {ConversionOptions} [options] Encoding, face or verse overrides.
|
|
170
|
+
*/
|
|
171
|
+
export function encode(data, language, text, options = {}) {
|
|
172
|
+
return conversion(data, language, text, options, "encode");
|
|
173
|
+
}
|
|
174
|
+
/** Decode with the selected encoding document's optional language lexicon.
|
|
175
|
+
* @param {ConverterData} data The module's parsed converter data.
|
|
176
|
+
* @param {string|null|undefined} language A language key, or null to infer it from the encoding.
|
|
177
|
+
* @param {string} text Encoded Unicode input.
|
|
178
|
+
* @param {ConversionOptions} [options] Encoding or face overrides.
|
|
179
|
+
*/
|
|
180
|
+
export function decode(data, language, text, options = {}) {
|
|
181
|
+
return conversion(data, language, text, options, "decode");
|
|
182
|
+
}
|
package/docs/api.md
CHANGED
|
@@ -1343,6 +1343,13 @@ index for checking page links.
|
|
|
1343
1343
|
|
|
1344
1344
|
`renderPreview(text, { dark = false, infobox = true, file = "", currentDate = "720.1", index })` renders the current Markdown buffer directly to HTML. Frontmatter is optional. Without `index` it needs no package configuration, saved note, content tree, dependency cache, database or Pandoc installation. The result is `{ ok, html, frontmatter, findings }`; `file` only labels diagnostics. Malformed frontmatter produces a warning and remains visible without preventing a preview update.
|
|
1345
1345
|
|
|
1346
|
+
With `index`, every marked-text run error appears in `findings` as
|
|
1347
|
+
`{ file, severity: "error", line, column, message }`. Positions refer to the
|
|
1348
|
+
authored buffer, including frontmatter lines, before indexed expansion. Any
|
|
1349
|
+
error finding makes `ok` false. `html` is returned even when `ok` is false, with
|
|
1350
|
+
recoverable Roman text for a native-script run that cannot be set. Without
|
|
1351
|
+
`index`, marked text remains source and produces no run findings.
|
|
1352
|
+
|
|
1346
1353
|
With `index`, from [`engine.previewIndex`](#enginepreviewindex), the preview expands the buffer as the website expands a page and renders it through the same renderer: links resolve, embeds draw their pictures, marked text is mapped and set in its face, icons draw, figure numbers carry their asset roles, and a concealed link is concealed. A query, which a buffer cannot run, stays highlighted source.
|
|
1347
1354
|
|
|
1348
1355
|
| Export | Signature | Returns | Use it when |
|
|
@@ -1400,13 +1407,14 @@ The charset authored content is held to, so a book can choose its face. The pack
|
|
|
1400
1407
|
### `engine.romanCharacters`
|
|
1401
1408
|
|
|
1402
1409
|
Exact permitted Roman source characters for configured languages, before script
|
|
1403
|
-
|
|
1410
|
+
encoding. Inventories come from `data.roman` on each language's own note.
|
|
1404
1411
|
|
|
1405
|
-
| Export | Signature
|
|
1406
|
-
| ------------------------ |
|
|
1407
|
-
| `
|
|
1408
|
-
| `
|
|
1409
|
-
| `
|
|
1412
|
+
| Export | Signature | Returns | Use it when |
|
|
1413
|
+
| ------------------------ | ---------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------- |
|
|
1414
|
+
| `isRomanWhitespace` | `isRomanWhitespace(char)` | `boolean` | recognizing standard spaces and ASCII tab or line whitespace |
|
|
1415
|
+
| `romanInventoryProblems` | `romanInventoryProblems(value)` | `string[]` | checking NFC, repeated characters and forbidden whitespace or controls in a literal inventory |
|
|
1416
|
+
| `romanInventoriesOf` | `romanInventoriesOf(records, languages)` | `Map<string, RomanInventory>` | looking up a configured language's own inventory by name or BCP 47 tag |
|
|
1417
|
+
| `romanTextProblems` | `romanTextProblems(text, inventory)` | `{offset, message}[]` | validating standard Roman punctuation and language additions with exact UTF-16 offsets |
|
|
1410
1418
|
|
|
1411
1419
|
### `engine.pathCharset`
|
|
1412
1420
|
|
|
@@ -2773,3 +2781,126 @@ language contributes words, affixes and elements, in that order. Words and
|
|
|
2773
2781
|
affixes supply `gloss`, including an affix matched by its `front` form. Elements
|
|
2774
2782
|
supply `sense` and match their `form` and `variants`. Exact matches precede matches without joining hyphens; case and
|
|
2775
2783
|
accents are preserved. A missing gloss returns `null`.
|
|
2784
|
+
|
|
2785
|
+
### `engine.encoding`
|
|
2786
|
+
|
|
2787
|
+
Browser-safe compilation of an encoding document with separately resolved font glyph codes;
|
|
2788
|
+
see [encoding text](encoding-core.md). No files are read. Text errors expose a
|
|
2789
|
+
UTF-16 `offset` and one-based code-point `line` and `column`; definition errors
|
|
2790
|
+
expose their schema `key`.
|
|
2791
|
+
|
|
2792
|
+
| Export | Signature | Returns | Use it when |
|
|
2793
|
+
| ----------------- | ------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------- |
|
|
2794
|
+
| `EncodingError` | `new EncodingError(message, details)` | error | locating a schema fault or unidentified character |
|
|
2795
|
+
| `compileEncoding` | `compileEncoding(data, {codes, name})` | compiled encoding | validating executable document mappings and rules |
|
|
2796
|
+
| `compileRows` | `compileRows(definition)` | internal row program | executing captured row-conformance fixtures; application inputs use compileEncoding |
|
|
2797
|
+
| `validateSource` | `validateSource(encoding, text, options)` | void | validating accepted Roman spelling and rules independently of mapping coverage |
|
|
2798
|
+
| `encodePieces` | `encodePieces(encoding, text, options)` | piece array | retaining original UTF-16 `start` and `end` offsets while encoding |
|
|
2799
|
+
| `encodeText` | `encodeText(encoding, text, {font, verse})` | string | encoding exactly by rows and inline codes |
|
|
2800
|
+
| `decodeText` | `decodeText(encoding, text, {font})` | string | decoding by longest output matches |
|
|
2801
|
+
|
|
2802
|
+
### `engine.encodingLanguage`
|
|
2803
|
+
|
|
2804
|
+
Pure language-aware conversion takes a compiled encoding and optional plain
|
|
2805
|
+
`lexicon: {language, data}` from `serializeLexicon`. The build and browser use
|
|
2806
|
+
the same functions. Findings retain input offsets; an encoding refusal returns
|
|
2807
|
+
no partial encoded output. Decoding preserves the plain skeleton of an unknown
|
|
2808
|
+
unmarked word and reports it.
|
|
2809
|
+
|
|
2810
|
+
| Export | Signature | Returns | Use it when |
|
|
2811
|
+
| -------------------- | ------------------------------------------------------------ | -------------------------- | ---------------------------------------------------------------------- |
|
|
2812
|
+
| `encodeWithLanguage` | `encodeWithLanguage(encoding, text, {font, verse, lexicon})` | `{text, pieces, findings}` | writing authored native entries or complete parts before encoding rows |
|
|
2813
|
+
| `decodeWithLanguage` | `decodeWithLanguage(encoding, text, {font, lexicon})` | `{text, findings}` | reading native exceptions and recovering unmarked lexical skeletons |
|
|
2814
|
+
|
|
2815
|
+
### `engine.encodingNotes`
|
|
2816
|
+
|
|
2817
|
+
Node-side document resolution reads encoding records from the content index
|
|
2818
|
+
and glyph codes from the selected font's `fonts.json`. It opens no font encoding
|
|
2819
|
+
files and enforces no encoding-file release floor. Diagnostics retain the
|
|
2820
|
+
note or font manifest's own source position.
|
|
2821
|
+
|
|
2822
|
+
| Export | Signature | Returns | Use it when |
|
|
2823
|
+
| ---------------------- | ---------------------------------------------- | ------------------------------------ | ------------------------------------------------------------- |
|
|
2824
|
+
| `encodingAddress` | `encodingAddress(value, contentPackage)` | string or undefined | resolving a document Address with default type doc |
|
|
2825
|
+
| `encodingData` | `encodingData(data)` | plain executable data | separating ordinary document metadata |
|
|
2826
|
+
| `fontCodes` | `fontCodes(fonts, font)` | code-to-Unicode object | reading only the selected font's published glyph codes |
|
|
2827
|
+
| `encodingsFromRecords` | `encodingsFromRecords(records, config, fonts)` | `{encodings, definitions, findings}` | compiling addressed documents and preparing serialized inputs |
|
|
2828
|
+
|
|
2829
|
+
### `engine.encodingLexicon`
|
|
2830
|
+
|
|
2831
|
+
Node-side note projection and validation. `serializeLexicon` emits only word,
|
|
2832
|
+
affix, grammar and name-register data read by conversion; the result contains
|
|
2833
|
+
no Maps or callbacks.
|
|
2834
|
+
|
|
2835
|
+
| Export | Signature | Returns | Use it when |
|
|
2836
|
+
| ----------------------- | ----------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------ |
|
|
2837
|
+
| `lexiconsFromRecords` | `lexiconsFromRecords(records, config)` | Map | projecting language words, including nearest complete inherited definitions |
|
|
2838
|
+
| `languageRecordsByName` | `languageRecordsByName(records, config)` | Map | finding each configured language note |
|
|
2839
|
+
| `languageNoteFindings` | `languageNoteFindings(config, records)` | findings | locating configured language notes or Roman inventories that are missing |
|
|
2840
|
+
| `serializeLexicon` | `serializeLexicon(lexicon)` | plain JSON object | supplying converter input to a browser or another process |
|
|
2841
|
+
| `encodingFor` | `encodingFor(context, {enc, font, lang})` | selected conversion or undefined | choosing an addressed document, its face and optional language lexicon |
|
|
2842
|
+
| `fontProblem` | `fontProblem(encoding, font)` | string or undefined | explaining an unsupported face choice |
|
|
2843
|
+
| `lexiconEntries` | `lexiconEntries(context, {lang, enc, font, derived})` | entries or problem | listing authored or derived forms with own, parts or row spellings |
|
|
2844
|
+
| `checkLexiconNatives` | `checkLexiconNatives(note, context)` | findings | validating encoding, face, duplicate slots and visible native code points |
|
|
2845
|
+
| `checkEncodingLexicon` | `checkEncodingLexicon(note, context)` | findings | checking every authoritative word and name against its language's encoding documents |
|
|
2846
|
+
| `NATIVE_COLUMNS` | constant | column names | reading the natives SQL projection, including its enc column |
|
|
2847
|
+
| `nativeRows` | `nativeRows(records)` | rows | projecting authored native entries in source order |
|
|
2848
|
+
|
|
2849
|
+
## `./convert`
|
|
2850
|
+
|
|
2851
|
+
### Browser conversion
|
|
2852
|
+
|
|
2853
|
+
`@heroiclands/package-build/convert` exports:
|
|
2854
|
+
|
|
2855
|
+
| Export | Signature | Returns |
|
|
2856
|
+
| -------------- | ---------------------------------------- | ---------------------------------------------------------- |
|
|
2857
|
+
| `encode` | `encode(data, language, text, options?)` | Converted text, findings and source pieces for a language. |
|
|
2858
|
+
| `decode` | `decode(data, language, text, options?)` | Roman text and findings. |
|
|
2859
|
+
| `validateData` | `validateData(data)` | The validated format-2 data. |
|
|
2860
|
+
|
|
2861
|
+
Its module graph uses no Node built-in and can be bundled for
|
|
2862
|
+
a browser without shims. Load the module's [format-2 data file](reference/format-details.md#converter-data-format)
|
|
2863
|
+
once and treat it as read-only.
|
|
2864
|
+
|
|
2865
|
+
```js
|
|
2866
|
+
import { encode, decode, validateData } from "@heroiclands/package-build/convert";
|
|
2867
|
+
const data = validateData(await (await fetch("data/converter.json")).json());
|
|
2868
|
+
const native = encode(data, "aelw", "say", { enc: "aelwsemaronenc" });
|
|
2869
|
+
const roman = decode(data, "aelw", native.text, { enc: "aelwsemaronenc" });
|
|
2870
|
+
const inferred = encode(data, null, "say", { enc: "aelwsemaronenc" });
|
|
2871
|
+
```
|
|
2872
|
+
|
|
2873
|
+
Both functions take `(data, language, text, options?)` and return
|
|
2874
|
+
`{text, findings}`; encoding with a language also returns source-positioned
|
|
2875
|
+
`pieces`. A language key selects its encoding, face and lexical inputs.
|
|
2876
|
+
`options.enc` and `options.font` override the encoding and face; `options.verse`
|
|
2877
|
+
asks the encoder to interpret verse structure. With `language: null`, `enc` is
|
|
2878
|
+
required and only the encoding's rows apply.
|
|
2879
|
+
|
|
2880
|
+
Language conversion uses the same pure `encodeWithLanguage` and
|
|
2881
|
+
`decodeWithLanguage` functions as the build. Recorded native writings and
|
|
2882
|
+
parts precede encoding rows, and decoding can recover an unmarked word from
|
|
2883
|
+
the lexicon. An unknown word gives a positioned finding. A bare refusal
|
|
2884
|
+
returns empty text and an error finding. Findings carry `severity`, `message`,
|
|
2885
|
+
`offset` (UTF-16), and one-based Unicode-code-point `line` and `column`.
|
|
2886
|
+
Invalid data, unknown languages and missing encoding selections throw an
|
|
2887
|
+
error before conversion. `validateData(data)` returns the validated data or
|
|
2888
|
+
throws; it opens no files.
|
|
2889
|
+
|
|
2890
|
+
The Node-side `engine/converter-data.mjs` module prepares these inputs from an
|
|
2891
|
+
indexed package:
|
|
2892
|
+
|
|
2893
|
+
| Export | Signature | Returns |
|
|
2894
|
+
| -------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
2895
|
+
| `buildConverterData` | `buildConverterData(config, records)` | Format-1 converter data from the build context. |
|
|
2896
|
+
| `writeConverterData` | `writeConverterData({config, packageBuild, records?})` | `{path, data}` when the optional output is configured; otherwise `undefined`. |
|
|
2897
|
+
|
|
2898
|
+
The content run scanner reports diagnostic columns in Unicode code points.
|
|
2899
|
+
Its run offsets, run columns and SQL `runs.column` values retain UTF-16 source
|
|
2900
|
+
units. Encoding-file diagnostics retain their own file and position.
|
|
2901
|
+
|
|
2902
|
+
An omitted or null language is inferred from the selected encoding document,
|
|
2903
|
+
including its lexical native overrides and decoding recovery. Short document
|
|
2904
|
+
references resolve in `data.contentPackage`; foreign encodings require their
|
|
2905
|
+
full canonical Address. Use the pure engine's `encodeText` and `decodeText`
|
|
2906
|
+
when conversion must ignore vocabulary, as the CLI commands do.
|