@heroiclands/package-build 24.1.1 → 25.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -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 +154 -11
- package/docs/authoring/links-and-markup.md +260 -473
- package/docs/commands.md +118 -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 +453 -569
- package/docs/reference/format-details.md +290 -380
- package/docs/reference/note-types.md +80 -62
- package/docs/source-preview.md +8 -0
- package/e2e.mjs +1 -1
- package/engine/base-compiler.mjs +27 -9
- package/engine/content-charset.mjs +21 -1
- package/engine/content-format.yaml +7 -2
- package/engine/content-index.mjs +6 -2
- package/engine/content-links.mjs +1 -0
- package/engine/content-scripts.mjs +658 -423
- 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 +10 -0
- package/engine/language-data.mjs +4 -1
- package/engine/language-terms.mjs +23 -12
- 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 +232 -0
- 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-charset.d.mts +8 -0
- package/types/engine/content-index.d.mts +4 -1
- package/types/engine/content-scripts.d.mts +108 -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 +5 -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 +45 -0
- 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 -1034
- 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
|
@@ -146,6 +146,8 @@ export function refusedAttributes(values) {
|
|
|
146
146
|
problems.push(
|
|
147
147
|
`set ${key} with ${key.toLowerCase() === "id" ? "#id" : ".class"} rather than ${key}=`,
|
|
148
148
|
);
|
|
149
|
+
} else if (key === "map") {
|
|
150
|
+
problems.push("map is not an attribute");
|
|
149
151
|
} else if (/^on/i.test(key)) {
|
|
150
152
|
problems.push(`${key} is an event handler and is not written`);
|
|
151
153
|
}
|
package/engine/helpers.mjs
CHANGED
|
@@ -194,7 +194,7 @@ function localAssetImageInfo() {
|
|
|
194
194
|
* {@link module:engine/content-figures.scanFigures}.
|
|
195
195
|
* @param {import("./content-scripts.mjs").RunContext} [runs] - The package's
|
|
196
196
|
* languages, faces and maps. Given, text marked with `lang=`, `font=` and
|
|
197
|
-
* `
|
|
197
|
+
* `enc=` is rewritten first, so it is tagged for its language, mapped and
|
|
198
198
|
* set in its font.
|
|
199
199
|
* @returns {string} The rendered HTML.
|
|
200
200
|
*/
|
package/engine/index.mjs
CHANGED
|
@@ -227,6 +227,9 @@ export * as contentLint from "./content-lint.mjs";
|
|
|
227
227
|
|
|
228
228
|
/** The charset authored content is held to, so a book can choose its face. */
|
|
229
229
|
export * as contentCharset from "./content-charset.mjs";
|
|
230
|
+
|
|
231
|
+
/** Exact permitted Roman source characters for configured languages. */
|
|
232
|
+
export * as romanCharacters from "./roman-characters.mjs";
|
|
230
233
|
export * as pathCharset from "./path-charset.mjs";
|
|
231
234
|
|
|
232
235
|
/** Naming an interface icon in a note, without drawing one there. */
|
|
@@ -328,3 +331,10 @@ export {
|
|
|
328
331
|
|
|
329
332
|
/** The curated region-event vocabulary, shared with the Foundry runtime. */
|
|
330
333
|
export * as regionEvents from "./region-events.mjs";
|
|
334
|
+
|
|
335
|
+
/** Browser-safe encoding-document compilation and conversion. */
|
|
336
|
+
export * as encoding from "./encoding.mjs";
|
|
337
|
+
export * as encodingLanguage from "./encoding-language.mjs";
|
|
338
|
+
/** Consumer-root file loading and authored language projections. */
|
|
339
|
+
export * as encodingNotes from "./encoding-notes.mjs";
|
|
340
|
+
export * as encodingLexicon from "./encoding-lexicon.mjs";
|
package/engine/language-data.mjs
CHANGED
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
import { LANGUAGE_SUBTYPE } from "./word-terms.mjs";
|
|
74
74
|
import { WORD_CLASS_BASES } from "./word-classes.mjs";
|
|
75
75
|
import { nearest } from "./near-miss.mjs";
|
|
76
|
+
import { romanInventoryProblems } from "./roman-characters.mjs";
|
|
76
77
|
|
|
77
78
|
/** The bases a frame's `class` names. */
|
|
78
79
|
const CLASS_BASES = new Set(WORD_CLASS_BASES.map((item) => item.token));
|
|
@@ -614,7 +615,9 @@ export function checkLanguageData(note, { index, types } = {}) {
|
|
|
614
615
|
),
|
|
615
616
|
);
|
|
616
617
|
|
|
617
|
-
const findings =
|
|
618
|
+
const findings = romanInventoryProblems(data.roman).map((message) =>
|
|
619
|
+
finding(["data", "roman"], "error", message),
|
|
620
|
+
);
|
|
618
621
|
|
|
619
622
|
// Only the shape of a supplied declaration: no word is compared with it.
|
|
620
623
|
const grammar = isMap(data.grammar) ? data.grammar : {};
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
/** The `data` keys a language note states its sounds, names and history in. */
|
|
32
32
|
export const LANGUAGE_DATA_KEYS = Object.freeze([
|
|
33
|
+
"roman",
|
|
33
34
|
"tongues",
|
|
34
35
|
"register",
|
|
35
36
|
"retired",
|
|
@@ -1695,7 +1696,7 @@ export const VERB_PERSON_FIELDS = Object.freeze(
|
|
|
1695
1696
|
);
|
|
1696
1697
|
|
|
1697
1698
|
/**
|
|
1698
|
-
* The endings `data.grammar.native` writes under a
|
|
1699
|
+
* The endings `data.grammar.native` writes under a encoding: the noun
|
|
1699
1700
|
* plural, then the six persons of the verb pattern.
|
|
1700
1701
|
*/
|
|
1701
1702
|
export const WRITTEN_ENDINGS = Object.freeze([
|
|
@@ -1716,18 +1717,18 @@ const GRAMMAR_NATIVE_FIELDS = Object.freeze([
|
|
|
1716
1717
|
"for a verb's present form.",
|
|
1717
1718
|
}),
|
|
1718
1719
|
Object.freeze({
|
|
1719
|
-
name: "
|
|
1720
|
+
name: "enc",
|
|
1720
1721
|
kind: "string",
|
|
1721
1722
|
required: true,
|
|
1722
|
-
shape: "
|
|
1723
|
-
describe: "The
|
|
1723
|
+
shape: "an encoding document Address",
|
|
1724
|
+
describe: "The encoding the ending is written for.",
|
|
1724
1725
|
}),
|
|
1725
1726
|
Object.freeze({
|
|
1726
1727
|
name: "font",
|
|
1727
1728
|
kind: "string",
|
|
1728
|
-
shape: "a face the
|
|
1729
|
+
shape: "a face the encoding lists",
|
|
1729
1730
|
describe:
|
|
1730
|
-
"The one face the writing is for; unstated, it is for every face the
|
|
1731
|
+
"The one face the writing is for; unstated, it is for every face the encoding lists, " +
|
|
1731
1732
|
"and a writing stated for a face wins over it there.",
|
|
1732
1733
|
}),
|
|
1733
1734
|
Object.freeze({
|
|
@@ -1869,15 +1870,15 @@ const GRAMMAR_FIELDS = Object.freeze([
|
|
|
1869
1870
|
Object.freeze({
|
|
1870
1871
|
name: "native",
|
|
1871
1872
|
kind: "list",
|
|
1872
|
-
shape: "a list of `{ ending,
|
|
1873
|
+
shape: "a list of `{ ending, enc, font?, text }`",
|
|
1873
1874
|
entries: Object.freeze({
|
|
1874
1875
|
kind: "map",
|
|
1875
|
-
shape: "a map — `{ ending,
|
|
1876
|
+
shape: "a map — `{ ending, enc, font?, text }`",
|
|
1876
1877
|
fields: GRAMMAR_NATIVE_FIELDS,
|
|
1877
1878
|
}),
|
|
1878
1879
|
describe:
|
|
1879
|
-
"Under
|
|
1880
|
-
"written with after its stem's writing, one entry per ending,
|
|
1880
|
+
"Under an encoding, the signs a noun's plural or a verb's present form is " +
|
|
1881
|
+
"written with after its stem's writing, one entry per ending, encoding and face.",
|
|
1881
1882
|
}),
|
|
1882
1883
|
]);
|
|
1883
1884
|
|
|
@@ -1889,6 +1890,16 @@ const GRAMMAR_FIELDS = Object.freeze([
|
|
|
1889
1890
|
* @type {readonly object[]}
|
|
1890
1891
|
*/
|
|
1891
1892
|
export const LANGUAGE_DATA_FIELDS = Object.freeze([
|
|
1893
|
+
Object.freeze({
|
|
1894
|
+
name: "roman",
|
|
1895
|
+
kind: "string",
|
|
1896
|
+
shape: "a literal NFC string of additional source characters, including exact letter case and digits",
|
|
1897
|
+
describe:
|
|
1898
|
+
"The additional Roman source characters the language permits, each once. Standard " +
|
|
1899
|
+
"punctuation and structural whitespace remain available. No ranges, case expansion " +
|
|
1900
|
+
"or inherited inventory. An empty string declares no additions. Required on each " +
|
|
1901
|
+
"configured language note.",
|
|
1902
|
+
}),
|
|
1892
1903
|
Object.freeze({
|
|
1893
1904
|
name: "grammar",
|
|
1894
1905
|
kind: "map",
|
|
@@ -1896,8 +1907,8 @@ export const LANGUAGE_DATA_FIELDS = Object.freeze([
|
|
|
1896
1907
|
fields: GRAMMAR_FIELDS,
|
|
1897
1908
|
describe:
|
|
1898
1909
|
"Optional noun plurals, one verb pattern, agreement, participles and the endings' " +
|
|
1899
|
-
"
|
|
1900
|
-
"
|
|
1910
|
+
"native writings, for dictionary presentation, language word checks and encodings. " +
|
|
1911
|
+
"Only the shape of supplied keys is " +
|
|
1901
1912
|
"checked; no word must follow or state a rule. A language skill note only.",
|
|
1902
1913
|
}),
|
|
1903
1914
|
listOfMaps(
|
|
@@ -12,39 +12,19 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* 1. **The word's own `native` entry** for the map, and for the run's face
|
|
20
|
-
* where an entry names one.
|
|
21
|
-
* 2. **Otherwise its parts.** A word stating `built` is written by the
|
|
22
|
-
* writings of its pieces joined in order: a piece is a word of the
|
|
23
|
-
* lexicon, matched exactly and then with its joining hyphens taken off, or
|
|
24
|
-
* an affix of `data.affixes` with its own `native`; a word piece resolves
|
|
25
|
-
* by this same rule. A noun's plural and a verb's present forms are written
|
|
26
|
-
* by the stem's writing followed by the ending's, which
|
|
27
|
-
* `data.grammar.native` states by the ending's name: `plural`, or one of
|
|
28
|
-
* the six persons. A hyphenated word no entry states is written by its
|
|
29
|
-
* parts, each by this rule.
|
|
30
|
-
* 3. **Otherwise the word has no writing**, which a run reports at the word.
|
|
31
|
-
*
|
|
32
|
-
* A run's word is matched case folded, so one roman form may stand for more
|
|
33
|
-
* than one entry. Where those entries are written alike the word takes that
|
|
34
|
-
* writing; where they differ, or one has a writing and another none, the word
|
|
35
|
-
* is ambiguous, and the finding names every entry's gloss. A part matched to
|
|
36
|
-
* entries written differently makes the word ambiguous the same way.
|
|
37
|
-
*
|
|
38
|
-
* @module
|
|
15
|
+
* Native word spellings under any encoding: authored entries first, then all
|
|
16
|
+
* stated parts, affixes and grammatical endings. Ambiguous spellings remain
|
|
17
|
+
* findings, with every matching gloss. Exact lexical forms precede folded
|
|
18
|
+
* lookup, preserving explicitly distinct capitalized spellings.
|
|
39
19
|
*/
|
|
40
20
|
|
|
41
|
-
import { pluralOf } from "./
|
|
21
|
+
import { pluralOf } from "./word-inflections.mjs";
|
|
42
22
|
import { verbForm, verbPattern } from "./verb-pattern.mjs";
|
|
43
23
|
import { parseWordClass } from "./word-classes.mjs";
|
|
44
24
|
import { foldWord } from "./word-forms.mjs";
|
|
45
25
|
import { glossText } from "./word-terms.mjs";
|
|
46
26
|
|
|
47
|
-
/** Whether a value is a plain
|
|
27
|
+
/** Whether a value is a plain object. */
|
|
48
28
|
const isMap = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
49
29
|
|
|
50
30
|
/** A list value, or an empty one. */
|
|
@@ -65,17 +45,18 @@ const JOINS = /[–-]/u;
|
|
|
65
45
|
*/
|
|
66
46
|
|
|
67
47
|
/**
|
|
68
|
-
* The text a list of native entries states for a
|
|
48
|
+
* The text a list of native entries states for a enc in a face: the entry for
|
|
69
49
|
* the face, else the entry for no face.
|
|
70
50
|
*
|
|
71
51
|
* @param {unknown} natives - A `native` list as authored.
|
|
72
|
-
* @param {string}
|
|
52
|
+
* @param {string} enc - The encoding's name.
|
|
73
53
|
* @param {string|undefined} font - The face.
|
|
74
54
|
* @returns {string|undefined} The text.
|
|
75
55
|
*/
|
|
76
|
-
|
|
56
|
+
|
|
57
|
+
export function nativeText(natives, enc, font) {
|
|
77
58
|
const entries = listOf(natives).filter(
|
|
78
|
-
(entry) => isMap(entry) && entry.
|
|
59
|
+
(entry) => isMap(entry) && entry.enc === enc && typeof entry.text === "string",
|
|
79
60
|
);
|
|
80
61
|
const own = font === undefined ? undefined : entries.find((entry) => entry.font === font);
|
|
81
62
|
return (own ?? entries.find((entry) => typeof entry.font !== "string"))?.text;
|
|
@@ -100,15 +81,15 @@ function oneOf(form, candidates) {
|
|
|
100
81
|
}
|
|
101
82
|
|
|
102
83
|
/**
|
|
103
|
-
* The writings of a language's words under one
|
|
84
|
+
* The writings of a language's words under one encoding in one face.
|
|
104
85
|
*
|
|
105
86
|
* @param {Record<string, any>|undefined} data - The language note's `data`.
|
|
106
|
-
* @param {string}
|
|
87
|
+
* @param {string} enc - The encoding's name.
|
|
107
88
|
* @param {string|undefined} font - The face.
|
|
108
89
|
* @returns {{word: (word: string) => Writing, entry: (index: number) => Writing}}
|
|
109
90
|
* The writing of a run's word, and of the `data.words` entry at an index.
|
|
110
91
|
*/
|
|
111
|
-
export function writingsOf(data,
|
|
92
|
+
export function writingsOf(data, enc, font) {
|
|
112
93
|
const words = listOf(data?.words);
|
|
113
94
|
const affixes = listOf(data?.affixes).filter(isMap);
|
|
114
95
|
const grammar = isMap(data?.grammar) ? data.grammar : undefined;
|
|
@@ -127,7 +108,7 @@ export function writingsOf(data, map, font) {
|
|
|
127
108
|
*/
|
|
128
109
|
const entry = (index, visiting) => {
|
|
129
110
|
const word = words[index];
|
|
130
|
-
const own = nativeText(word?.native,
|
|
111
|
+
const own = nativeText(word?.native, enc, font);
|
|
131
112
|
if (own !== undefined) return { text: own, source: "own" };
|
|
132
113
|
const pieces = listOf(word?.built).filter((piece) => typeof piece === "string");
|
|
133
114
|
if (!pieces.length || visiting.has(index)) return { missing: true };
|
|
@@ -148,7 +129,7 @@ export function writingsOf(data, map, font) {
|
|
|
148
129
|
gloss: glossOf(word),
|
|
149
130
|
})),
|
|
150
131
|
...matchedAffixes.map((affix) => {
|
|
151
|
-
const text = nativeText(affix.native,
|
|
132
|
+
const text = nativeText(affix.native, enc, font);
|
|
152
133
|
return {
|
|
153
134
|
writing: /** @type {Writing} */ (
|
|
154
135
|
text === undefined ? { missing: true } : { text, source: "own" }
|
|
@@ -192,7 +173,7 @@ export function writingsOf(data, map, font) {
|
|
|
192
173
|
const endingText = (ending) =>
|
|
193
174
|
nativeText(
|
|
194
175
|
listOf(endings).filter((one) => isMap(one) && one.ending === ending),
|
|
195
|
-
|
|
176
|
+
enc,
|
|
196
177
|
font,
|
|
197
178
|
);
|
|
198
179
|
|
|
@@ -205,8 +186,18 @@ export function writingsOf(data, map, font) {
|
|
|
205
186
|
const word = (written) => {
|
|
206
187
|
const folded = foldWord(written);
|
|
207
188
|
const none = new Set();
|
|
208
|
-
const
|
|
209
|
-
|
|
189
|
+
const stages = [
|
|
190
|
+
indexed.filter(({ word: one }) => one.form === written),
|
|
191
|
+
indexed.filter(({ word: one }) => listOf(one.variants).includes(written)),
|
|
192
|
+
indexed.filter(({ word: one }) => foldWord(one.form) === folded),
|
|
193
|
+
indexed.filter(({ word: one }) =>
|
|
194
|
+
listOf(one.variants).some(
|
|
195
|
+
(form) => typeof form === "string" && foldWord(form) === folded,
|
|
196
|
+
),
|
|
197
|
+
),
|
|
198
|
+
];
|
|
199
|
+
for (const stated of stages)
|
|
200
|
+
if (stated.length) return oneOf(written, candidatesOf(stated, [], none));
|
|
210
201
|
const stripped = indexed.filter(({ word: one }) => bare(foldWord(one.form)) === folded);
|
|
211
202
|
if (stripped.length) return oneOf(written, candidatesOf(stripped, [], none));
|
|
212
203
|
const derived = [];
|
|
@@ -43,7 +43,7 @@ function shortcodeErrors(body) {
|
|
|
43
43
|
* @param {import("./content-session.mjs").ContentSyntax} [syntax] - Exact-text scanner projections.
|
|
44
44
|
* @param {import("./content-scripts.mjs").RunContext} [runs] - The package's
|
|
45
45
|
* languages, faces and maps. Given, text marked with `lang=`, `font=` and
|
|
46
|
-
* `
|
|
46
|
+
* `enc=` is checked against them; a caller with no package configuration
|
|
47
47
|
* leaves it out.
|
|
48
48
|
* @returns {Array<{file: string, line: number, column: number, severity: string, message: string}>} Syntax errors,
|
|
49
49
|
* then warnings.
|
|
@@ -140,6 +140,7 @@ import {
|
|
|
140
140
|
} from "./language-words.mjs";
|
|
141
141
|
import { checkGlossary } from "./glossary-entries.mjs";
|
|
142
142
|
import { GUIDE_SOUND_FIELDS, LANGUAGE_DATA_FIELDS } from "./language-terms.mjs";
|
|
143
|
+
import { ENCODING_NOTE_FIELDS } from "./encoding-terms.mjs";
|
|
143
144
|
import { checkGuideSounds, checkLanguageData } from "./language-data.mjs";
|
|
144
145
|
import { checkAffiliationReach } from "./culture-reach.mjs";
|
|
145
146
|
import { checkLanguageNames, requiredGivenGenders } from "./language-names.mjs";
|
|
@@ -159,11 +160,9 @@ import { checkCitedPopulations, checkPopulation } from "./populations.mjs";
|
|
|
159
160
|
import { MARKET_CLASSES, checkMarket } from "./market-class.mjs";
|
|
160
161
|
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
161
162
|
import { checkSettlementTables } from "./settlement-tables.mjs";
|
|
162
|
-
import { checkMapField } from "./text-maps.mjs";
|
|
163
163
|
import { checkConceptList, checkCoreFlag } from "./core-vocabulary.mjs";
|
|
164
164
|
import { METRE_KINDS, checkMetresField } from "./metre-declaration.mjs";
|
|
165
165
|
import { checkLanguageEmphasis, checkScriptField } from "./script-emphasis.mjs";
|
|
166
|
-
import { WRITTEN_IN_KEY, checkWrittenIn } from "./written-in.mjs";
|
|
167
166
|
import {
|
|
168
167
|
EMPHASIS_CONVENTIONS,
|
|
169
168
|
LANGUAGE_EMPHASES,
|
|
@@ -1591,47 +1590,6 @@ export const BEING_ARCHETYPES = Object.freeze({
|
|
|
1591
1590
|
guildsperson: "Has professional training, standing, or connections that open doors.",
|
|
1592
1591
|
});
|
|
1593
1592
|
|
|
1594
|
-
/**
|
|
1595
|
-
* One row of a mapping note's `data.map.rows` or of a face's own `rows`.
|
|
1596
|
-
*
|
|
1597
|
-
* @type {object}
|
|
1598
|
-
*/
|
|
1599
|
-
const MAP_ROW_ENTRY = Object.freeze({
|
|
1600
|
-
kind: "list-or-map",
|
|
1601
|
-
shape: "`[from, to]` or `{ from, to, before?, at? }`",
|
|
1602
|
-
entries: Object.freeze({ ...TEXT, shape: "a string" }),
|
|
1603
|
-
fields: Object.freeze([
|
|
1604
|
-
{
|
|
1605
|
-
name: "from",
|
|
1606
|
-
...TEXT,
|
|
1607
|
-
shape: "a string of one or more characters",
|
|
1608
|
-
required: true,
|
|
1609
|
-
describe: "The one or more characters the row matches.",
|
|
1610
|
-
},
|
|
1611
|
-
{
|
|
1612
|
-
name: "to",
|
|
1613
|
-
...TEXT,
|
|
1614
|
-
shape: "a string, which may be empty",
|
|
1615
|
-
required: true,
|
|
1616
|
-
allowEmpty: true,
|
|
1617
|
-
describe: "What the row writes in their place; empty to drop them.",
|
|
1618
|
-
},
|
|
1619
|
-
{
|
|
1620
|
-
name: "before",
|
|
1621
|
-
...TEXT,
|
|
1622
|
-
allowed: Object.freeze(["vowel", "consonant"]),
|
|
1623
|
-
describe:
|
|
1624
|
-
"`vowel` or `consonant`: what must follow the match for the " + "row to apply.",
|
|
1625
|
-
},
|
|
1626
|
-
{
|
|
1627
|
-
name: "at",
|
|
1628
|
-
...TEXT,
|
|
1629
|
-
allowed: Object.freeze(["start", "end"]),
|
|
1630
|
-
describe: "`start` or `end`: where the match must sit for the row to " + "apply.",
|
|
1631
|
-
},
|
|
1632
|
-
]),
|
|
1633
|
-
});
|
|
1634
|
-
|
|
1635
1593
|
/**
|
|
1636
1594
|
* Every note type this toolchain compiles, and the closed vocabulary it
|
|
1637
1595
|
* declares.
|
|
@@ -2187,36 +2145,10 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2187
2145
|
"and `words` marks it with a word, so either is a finding. Only a skill of " +
|
|
2188
2146
|
"`subType: language` states it.",
|
|
2189
2147
|
},
|
|
2190
|
-
{
|
|
2191
|
-
name: WRITTEN_IN_KEY,
|
|
2192
|
-
kind: "map",
|
|
2193
|
-
shape: "a map — `{ map, font }`",
|
|
2194
|
-
check: checkWrittenIn,
|
|
2195
|
-
fields: Object.freeze([
|
|
2196
|
-
{
|
|
2197
|
-
name: "map",
|
|
2198
|
-
kind: "string",
|
|
2199
|
-
shape: "a mapping note's `data.map.name`",
|
|
2200
|
-
required: true,
|
|
2201
|
-
describe: "The map the language's text is written by.",
|
|
2202
|
-
},
|
|
2203
|
-
{
|
|
2204
|
-
name: "font",
|
|
2205
|
-
kind: "string",
|
|
2206
|
-
shape: "an installed face's slug",
|
|
2207
|
-
required: true,
|
|
2208
|
-
describe: "The face the text is set in, one the map is drawn in.",
|
|
2209
|
-
},
|
|
2210
|
-
]),
|
|
2211
|
-
describe:
|
|
2212
|
-
"The script the language is written in, as the default map and face selected " +
|
|
2213
|
-
"by a run with explicit `lang=` and `.nativefont`; a run's own `map=` or " +
|
|
2214
|
-
"`font=` overrides its half. Only a skill of `subType: language` states it.",
|
|
2215
|
-
},
|
|
2216
2148
|
{
|
|
2217
2149
|
name: "script",
|
|
2218
2150
|
kind: "map",
|
|
2219
|
-
shape: "a map — `{ fonts, emphasis,
|
|
2151
|
+
shape: "a map — `{ fonts, emphasis, direction? }`",
|
|
2220
2152
|
check: checkScriptField,
|
|
2221
2153
|
fields: Object.freeze([
|
|
2222
2154
|
{
|
|
@@ -2240,17 +2172,10 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2240
2172
|
required: true,
|
|
2241
2173
|
describe:
|
|
2242
2174
|
"How the script marks a stressed word: `rubric` sets it in red, " +
|
|
2243
|
-
"`overline` draws a line above it. It sets
|
|
2175
|
+
"`overline` draws a line above it. It sets `.emph` and accepted English emphasis inside a " +
|
|
2244
2176
|
"run in one of its faces, unless the run's language states its own " +
|
|
2245
2177
|
"`emphasis`.",
|
|
2246
2178
|
},
|
|
2247
|
-
{
|
|
2248
|
-
name: "strongEmphasis",
|
|
2249
|
-
kind: "string",
|
|
2250
|
-
shape: "`rubric` or `overline`",
|
|
2251
|
-
allowed: EMPHASIS_CONVENTIONS,
|
|
2252
|
-
describe: "The convention `**…**` takes instead of `emphasis`'s.",
|
|
2253
|
-
},
|
|
2254
2179
|
{
|
|
2255
2180
|
name: "direction",
|
|
2256
2181
|
kind: "string",
|
|
@@ -2355,6 +2280,7 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2355
2280
|
...checkPostFields(note),
|
|
2356
2281
|
],
|
|
2357
2282
|
data: Object.freeze([
|
|
2283
|
+
...ENCODING_NOTE_FIELDS,
|
|
2358
2284
|
CONCEPTS_FIELD,
|
|
2359
2285
|
POST_DATE_FIELD,
|
|
2360
2286
|
POST_AUTHOR_FIELD,
|
|
@@ -2375,86 +2301,6 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2375
2301
|
"tongue of the setting: each letter row's `tongue` names the language notes " +
|
|
2376
2302
|
"that write it.",
|
|
2377
2303
|
},
|
|
2378
|
-
{
|
|
2379
|
-
name: "map",
|
|
2380
|
-
kind: "map",
|
|
2381
|
-
shape: "a map — `{ name, logographic?, vowels?, fonts, rows }`",
|
|
2382
|
-
check: checkMapField,
|
|
2383
|
-
fields: Object.freeze([
|
|
2384
|
-
{
|
|
2385
|
-
name: "name",
|
|
2386
|
-
...TEXT,
|
|
2387
|
-
required: true,
|
|
2388
|
-
describe:
|
|
2389
|
-
"What `map=` names the map by: lowercase letters, digits and `-`, " +
|
|
2390
|
-
"unique in the package.",
|
|
2391
|
-
},
|
|
2392
|
-
{
|
|
2393
|
-
name: "logographic",
|
|
2394
|
-
kind: "boolean",
|
|
2395
|
-
shape: "`true`",
|
|
2396
|
-
describe:
|
|
2397
|
-
"The script writes meanings: a mapped run's words are written by " +
|
|
2398
|
-
"the language's lexicon alone, and the rows write only the text " +
|
|
2399
|
-
"between them.",
|
|
2400
|
-
},
|
|
2401
|
-
{
|
|
2402
|
-
name: "vowels",
|
|
2403
|
-
...TEXT,
|
|
2404
|
-
describe:
|
|
2405
|
-
"The characters a row's `before: vowel` reads as vowels; any other " +
|
|
2406
|
-
"letter is a consonant.",
|
|
2407
|
-
},
|
|
2408
|
-
{
|
|
2409
|
-
name: "rows",
|
|
2410
|
-
kind: "list",
|
|
2411
|
-
shape: "list of `[from, to]` or `{ from, to, before?, at? }`",
|
|
2412
|
-
required: true,
|
|
2413
|
-
entries: MAP_ROW_ENTRY,
|
|
2414
|
-
describe:
|
|
2415
|
-
"The rewrites, each `[from, to]` or `{ from, to, before?, at? }`: " +
|
|
2416
|
-
"`before` is `vowel` or `consonant`, `at` is `start` or `end`. The " +
|
|
2417
|
-
"longest `from` wins, and a character no row matches passes through.",
|
|
2418
|
-
},
|
|
2419
|
-
{
|
|
2420
|
-
name: "fonts",
|
|
2421
|
-
kind: "list",
|
|
2422
|
-
shape: "list of `{ font, rows? }`",
|
|
2423
|
-
required: true,
|
|
2424
|
-
entries: Object.freeze({
|
|
2425
|
-
kind: "map",
|
|
2426
|
-
shape: "a map — `{ font, rows? }`",
|
|
2427
|
-
fields: Object.freeze([
|
|
2428
|
-
{
|
|
2429
|
-
name: "font",
|
|
2430
|
-
...TEXT,
|
|
2431
|
-
required: true,
|
|
2432
|
-
shape: "an installed face's slug",
|
|
2433
|
-
describe:
|
|
2434
|
-
"A face the map is drawn in, by the slug `font=` names it by.",
|
|
2435
|
-
},
|
|
2436
|
-
{
|
|
2437
|
-
name: "rows",
|
|
2438
|
-
kind: "list",
|
|
2439
|
-
shape: "list of `[from, to]` or `{ from, to, before?, at? }`",
|
|
2440
|
-
entries: MAP_ROW_ENTRY,
|
|
2441
|
-
describe:
|
|
2442
|
-
"Rows for this face alone, tried before the shared `rows`; " +
|
|
2443
|
-
"the same shapes and conditions.",
|
|
2444
|
-
},
|
|
2445
|
-
]),
|
|
2446
|
-
}),
|
|
2447
|
-
describe:
|
|
2448
|
-
"The faces the map is drawn in, at least one, each with any rows of " +
|
|
2449
|
-
"its own. A run in another face is refused, and each face must draw " +
|
|
2450
|
-
"every character its rows and the lexicon's native forms write.",
|
|
2451
|
-
},
|
|
2452
|
-
]),
|
|
2453
|
-
describe:
|
|
2454
|
-
"A mapping, which native text marked with `lang=`, `.nativefont` and its " +
|
|
2455
|
-
"`map=` name is rewritten by before it is set. See " +
|
|
2456
|
-
"[mapping notes](format-details.md#mapping-notes).",
|
|
2457
|
-
},
|
|
2458
2304
|
{
|
|
2459
2305
|
name: "metres",
|
|
2460
2306
|
kind: "list",
|
package/engine/pdf-render.mjs
CHANGED
|
@@ -318,12 +318,24 @@ function reportUnrenderable(source, definitions, opts, original) {
|
|
|
318
318
|
if (!findings) return;
|
|
319
319
|
const file = opts.file ? { file: opts.file } : {};
|
|
320
320
|
/**
|
|
321
|
-
* @param {{line: number, column?: number}} position - Where it is.
|
|
321
|
+
* @param {{file?: string, line: number, column?: number}} position - Where it is.
|
|
322
322
|
* @param {"warning"|"error"} severity - Which level.
|
|
323
323
|
* @param {string} message - What is wrong.
|
|
324
324
|
* @returns {void}
|
|
325
325
|
*/
|
|
326
326
|
const report = (position, severity, message) => {
|
|
327
|
+
if (
|
|
328
|
+
position.file &&
|
|
329
|
+
position.file !== opts.file &&
|
|
330
|
+
findings.some(
|
|
331
|
+
(one) =>
|
|
332
|
+
one.file === position.file &&
|
|
333
|
+
one.line === position.line &&
|
|
334
|
+
one.column === position.column &&
|
|
335
|
+
one.message === message,
|
|
336
|
+
)
|
|
337
|
+
)
|
|
338
|
+
return;
|
|
327
339
|
findings.push({ ...file, ...position, severity, message });
|
|
328
340
|
};
|
|
329
341
|
|
|
@@ -357,7 +369,13 @@ function reportUnrenderable(source, definitions, opts, original) {
|
|
|
357
369
|
...scanRuns(source, opts.runs).errors,
|
|
358
370
|
...markupAnchorFindings(source),
|
|
359
371
|
])
|
|
360
|
-
report(
|
|
372
|
+
report(
|
|
373
|
+
error.file ?
|
|
374
|
+
{ file: error.file, line: error.line, column: error.column }
|
|
375
|
+
: linePosition(error.line, error.column, opts),
|
|
376
|
+
"error",
|
|
377
|
+
error.message,
|
|
378
|
+
);
|
|
361
379
|
for (const error of scanFigures(source).errors)
|
|
362
380
|
report(linePosition(error.line, error.column, opts), "error", error.message);
|
|
363
381
|
// An image sharing its paragraph with other text, or an address or title
|
|
@@ -450,7 +468,7 @@ function reportUnrenderable(source, definitions, opts, original) {
|
|
|
450
468
|
* finding.
|
|
451
469
|
* @param {import("./content-scripts.mjs").RunContext} [opts.runs] - The
|
|
452
470
|
* package's languages, faces and maps, which text marked with `lang=`,
|
|
453
|
-
* `font=` and `
|
|
471
|
+
* `font=` and `enc=` is checked against and set by.
|
|
454
472
|
* @param {number} [opts.bodyLine] - The 1-based file line the body starts on, so
|
|
455
473
|
* a finding's line is the file's rather than the body's.
|
|
456
474
|
* @param {number} [opts.bodyColumn] - The 1-based column the body starts at.
|
|
@@ -1413,6 +1431,16 @@ function renderInline(token, ctx) {
|
|
|
1413
1431
|
out.push(inlineRaw(child.content));
|
|
1414
1432
|
break;
|
|
1415
1433
|
case "span_open": {
|
|
1434
|
+
if (["em", "strong"].includes(child.tag)) {
|
|
1435
|
+
const classes = (child.attrGet?.("class") ?? "").split(/\s+/);
|
|
1436
|
+
out.push(
|
|
1437
|
+
classes.includes("emph-rubric") ?
|
|
1438
|
+
`#text(fill: ${ctx.textFill ?? "book-rubric"})[`
|
|
1439
|
+
: classes.includes("emph-overline") ? "#overline["
|
|
1440
|
+
: `#${child.tag === "em" ? "emph" : "strong"}[`,
|
|
1441
|
+
);
|
|
1442
|
+
break;
|
|
1443
|
+
}
|
|
1416
1444
|
const sign = renderGlyph(children, i, ctx) ?? renderCartouche(children, i, ctx);
|
|
1417
1445
|
if (sign) {
|
|
1418
1446
|
out.push(sign.typst);
|