@heroiclands/package-build 25.5.3 → 25.5.5
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 +28 -0
- package/README.md +7 -0
- package/bin/content-commands.mjs +32 -8
- package/docs/api.md +57 -16
- package/docs/authoring/links-and-markup.md +51 -3
- package/docs/commands.md +60 -17
- package/docs/configuration.md +3 -2
- package/docs/content-format.md +10 -0
- package/docs/diagnostics.md +17 -0
- package/docs/guides/module-project.md +11 -3
- package/docs/guides/site.md +12 -2
- package/docs/guides/writing-in-invented-scripts.md +5 -2
- package/docs/reference/format-details.md +61 -11
- package/docs/reference/note-types.md +32 -32
- package/e2e.mjs +1 -1
- package/engine/base-compiler.mjs +2 -0
- package/engine/compile-corpus.mjs +6 -2
- package/engine/content-charset.mjs +1 -1
- package/engine/content-render.mjs +14 -2
- package/engine/content-scripts.mjs +44 -6
- package/engine/content-session.mjs +57 -20
- package/engine/content-spans.mjs +3 -4
- package/engine/content-verse.mjs +52 -10
- package/engine/core-report.mjs +27 -18
- package/engine/language-names.mjs +53 -23
- package/engine/markdownlint-run.mjs +1 -1
- package/engine/markup-validation.mjs +2 -0
- package/engine/note-vocabulary.mjs +10 -5
- package/engine/npc-generate.mjs +52 -7
- package/engine/page-breaks.mjs +115 -0
- package/engine/pdf-build.mjs +12 -4
- package/engine/pdf-render.mjs +10 -1
- package/engine/preview-index.mjs +4 -2
- package/engine/site-build.mjs +12 -3
- package/engine/site-preview.mjs +3 -0
- package/engine/site-render.mjs +18 -4
- package/engine/site-root.mjs +10 -1
- package/engine/site-serve-http.mjs +151 -0
- package/engine/site-serve.mjs +196 -126
- package/engine/sql-tables.mjs +379 -214
- package/engine/verse-metre.mjs +50 -5
- package/engine/verse-regions.mjs +16 -0
- package/package.json +3 -3
- package/types/e2e.d.mts +1 -1
- package/types/engine/content-scripts.d.mts +9 -1
- package/types/engine/content-session.d.mts +1 -1
- package/types/engine/content-verse.d.mts +11 -2
- package/types/engine/core-report.d.mts +6 -2
- package/types/engine/language-names.d.mts +18 -6
- package/types/engine/npc-generate.d.mts +3 -0
- package/types/engine/page-breaks.d.mts +30 -0
- package/types/engine/pdf-render.d.mts +2 -0
- package/types/engine/site-build.d.mts +3 -1
- package/types/engine/site-render.d.mts +6 -2
- package/types/engine/site-root.d.mts +3 -1
- package/types/engine/site-serve-http.d.mts +1 -0
- package/types/engine/site-serve.d.mts +12 -6
- package/types/engine/sql-tables.d.mts +37 -8
- package/types/engine/verse-metre.d.mts +2 -1
- package/types/engine/verse-regions.d.mts +8 -0
package/engine/verse-metre.mjs
CHANGED
|
@@ -62,8 +62,48 @@ import MarkdownIt from "markdown-it";
|
|
|
62
62
|
import { spanMarkdownPlugin } from "./content-spans.mjs";
|
|
63
63
|
import { parseVerse } from "./content-verse.mjs";
|
|
64
64
|
import { inlineText } from "./name-markup.mjs";
|
|
65
|
+
import { WIKILINK, authoredLabel, parseWikilink } from "./wikilink-syntax.mjs";
|
|
65
66
|
|
|
66
67
|
const verseParser = new MarkdownIt().use(spanMarkdownPlugin);
|
|
68
|
+
const wikilinkAt = new RegExp(WIKILINK.source, "y");
|
|
69
|
+
|
|
70
|
+
// Parse link labels in place so neighbouring spans keep their source offsets.
|
|
71
|
+
verseParser.inline.ruler.before("link", "metre_wikilink", (state, silent) => {
|
|
72
|
+
const start = state.pos;
|
|
73
|
+
wikilinkAt.lastIndex = start;
|
|
74
|
+
const match = wikilinkAt.exec(state.src);
|
|
75
|
+
if (!match || start + match[0].length > state.posMax) return false;
|
|
76
|
+
const finish = start + match[0].length;
|
|
77
|
+
if (silent) {
|
|
78
|
+
state.pos = finish;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
const parsed = parseWikilink(match[1], match[0]);
|
|
82
|
+
const label = authoredLabel(parsed) ?? state.env.referenceName?.(parsed.target);
|
|
83
|
+
const token = state.push("span_open", "span", 1);
|
|
84
|
+
token.meta = {
|
|
85
|
+
span: true,
|
|
86
|
+
start,
|
|
87
|
+
end: finish,
|
|
88
|
+
unresolvedReference: !parsed.labelled || label === undefined || label === "",
|
|
89
|
+
};
|
|
90
|
+
if (parsed.attributes?.classes.length)
|
|
91
|
+
token.attrSet("class", parsed.attributes.classes.join(" "));
|
|
92
|
+
for (const [key, value] of Object.entries(parsed.attributes?.values ?? {}))
|
|
93
|
+
token.attrSet(key, value);
|
|
94
|
+
const nested = [];
|
|
95
|
+
state.md.inline.parse(label ?? "", state.md, state.env, nested);
|
|
96
|
+
const labelStart = start + match[0].indexOf("|") + 1;
|
|
97
|
+
for (const child of nested)
|
|
98
|
+
if (child.meta?.span) {
|
|
99
|
+
child.meta.start += labelStart;
|
|
100
|
+
child.meta.end += labelStart;
|
|
101
|
+
}
|
|
102
|
+
state.tokens.push(...nested);
|
|
103
|
+
state.push("span_close", "span", -1);
|
|
104
|
+
state.pos = finish;
|
|
105
|
+
return true;
|
|
106
|
+
});
|
|
67
107
|
|
|
68
108
|
export { METRE_KINDS, METRE_NAME, checkMetresField } from "./metre-declaration.mjs";
|
|
69
109
|
|
|
@@ -240,11 +280,12 @@ function wordBeats(word, book) {
|
|
|
240
280
|
const folded = foldWord(word);
|
|
241
281
|
const count = nucleiOf(folded, book.pairs).length;
|
|
242
282
|
if (count === 0) return { min: 0, max: 0 };
|
|
283
|
+
const bases = book.classes.get(folded);
|
|
243
284
|
if (count > 1) {
|
|
285
|
+
const functionWord = bases && [...bases].every((base) => !BEAT_BASES.includes(base));
|
|
244
286
|
const first = stressIndex(folded, book.rule, book.pairs) === 0;
|
|
245
|
-
return { min: 1, max: count >= 4 && !first ? 2 : 1 };
|
|
287
|
+
return { min: functionWord ? 0 : 1, max: count >= 4 && !first ? 2 : 1 };
|
|
246
288
|
}
|
|
247
|
-
const bases = book.classes.get(folded);
|
|
248
289
|
if (!bases) return { min: 1, max: 1 };
|
|
249
290
|
const carrying = [...bases].filter((base) => BEAT_BASES.includes(base)).length;
|
|
250
291
|
if (carrying === bases.size) return { min: 1, max: 1 };
|
|
@@ -292,7 +333,7 @@ export function metreMessage({ min, max }, metre) {
|
|
|
292
333
|
* @param {ReadonlyArray<{start: number, end: number, indent: string, attributes: Record<string, string>, classes: string[]}>} blocks -
|
|
293
334
|
* The divs, from {@link module:engine/content-verse.scanVerse}.
|
|
294
335
|
* @param {string[]} lines - The source's lines.
|
|
295
|
-
* @param {{languages?: Readonly<Record<string, {tag: string}>>, metres?: ReadonlyMap<string, import("./metre-declaration.mjs").Metre>, metreBooks?: ReadonlyMap<string, MetreBook>, lexicons?: ReadonlyMap<string, unknown>, attributeColumns: (line: string, key: string) => {key: number, value: number}}} ctx -
|
|
336
|
+
* @param {{languages?: Readonly<Record<string, {tag: string}>>, metres?: ReadonlyMap<string, import("./metre-declaration.mjs").Metre>, metreBooks?: ReadonlyMap<string, MetreBook>, lexicons?: ReadonlyMap<string, unknown>, referenceName?: (target: string) => string|undefined, attributeColumns: (line: string, key: string) => {key: number, value: number}}} ctx -
|
|
296
337
|
* The metres and books, and how the div says its columns and where its
|
|
297
338
|
* keys sit.
|
|
298
339
|
* @returns {{errors: object[], warnings: object[]}} The findings at 1-based
|
|
@@ -358,9 +399,12 @@ export function metreFindings(blocks, lines, ctx) {
|
|
|
358
399
|
({ offset }) =>
|
|
359
400
|
!model.layout.some(([from, to]) => offset >= from && offset < to),
|
|
360
401
|
);
|
|
402
|
+
const inlineContext = { referenceName: ctx.referenceName };
|
|
361
403
|
const parsed =
|
|
362
|
-
verseParser.parseInline(
|
|
363
|
-
|
|
404
|
+
verseParser.parseInline(
|
|
405
|
+
units.map((unit) => unit.text).join(""),
|
|
406
|
+
inlineContext,
|
|
407
|
+
)[0]?.children ?? [];
|
|
364
408
|
let presentationDepth = 0;
|
|
365
409
|
const tokens = parsed.filter((token) => {
|
|
366
410
|
if (presentationDepth) {
|
|
@@ -395,6 +439,7 @@ export function metreFindings(blocks, lines, ctx) {
|
|
|
395
439
|
);
|
|
396
440
|
continue;
|
|
397
441
|
}
|
|
442
|
+
if (tokens.some((token) => token.meta?.unresolvedReference)) continue;
|
|
398
443
|
const beats = lineBeats(text, book);
|
|
399
444
|
if (metre.beats >= beats.min && metre.beats <= beats.max) continue;
|
|
400
445
|
warnings.push({
|
package/engine/verse-regions.mjs
CHANGED
|
@@ -26,6 +26,8 @@ import { parseExtensionAttributes } from "./extension-attributes.mjs";
|
|
|
26
26
|
* @property {number} bodyStart - First body offset.
|
|
27
27
|
* @property {number} bodyEnd - Offset past body text, excluding its final newline.
|
|
28
28
|
* @property {string} body - Authored body bytes.
|
|
29
|
+
* @property {string} logicalBody - Body without Markdown container prefixes.
|
|
30
|
+
* @property {number[]} bodyOffsets - Logical UTF-16 offsets mapped to authored body offsets, including the end.
|
|
29
31
|
* @property {Record<string,string>} attributes - Authored values.
|
|
30
32
|
* @property {string} id - Anchor or empty string.
|
|
31
33
|
* @property {string[]} classes - Authored classes including verse.
|
|
@@ -95,6 +97,18 @@ export function verseDivPlugin(md) {
|
|
|
95
97
|
if (original[bodyEnd - 1] === "\n") bodyEnd--;
|
|
96
98
|
if (original[bodyEnd - 1] === "\r") bodyEnd--;
|
|
97
99
|
}
|
|
100
|
+
const bodyOffsets = [];
|
|
101
|
+
let logicalBody = "";
|
|
102
|
+
for (let number = first + 1; number < (closed ? close : past); number++) {
|
|
103
|
+
const lineEnd = Math.min(starts[number] + rawLines[number].length, bodyEnd);
|
|
104
|
+
const contentStart = Math.min(contentStarts[number - first], lineEnd);
|
|
105
|
+
const pastLine = Math.min(starts[number + 1] ?? bodyEnd, bodyEnd);
|
|
106
|
+
for (let offset = contentStart; offset < pastLine; offset++) {
|
|
107
|
+
logicalBody += original[offset];
|
|
108
|
+
bodyOffsets.push(offset - bodyStart);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
bodyOffsets.push(bodyEnd - bodyStart);
|
|
98
112
|
const region = {
|
|
99
113
|
start: first,
|
|
100
114
|
end: closed ? close : past - 1,
|
|
@@ -104,6 +118,8 @@ export function verseDivPlugin(md) {
|
|
|
104
118
|
bodyStart,
|
|
105
119
|
bodyEnd,
|
|
106
120
|
body: original.slice(bodyStart, bodyEnd),
|
|
121
|
+
logicalBody,
|
|
122
|
+
bodyOffsets,
|
|
107
123
|
attributes: parsed.values,
|
|
108
124
|
id: parsed.id,
|
|
109
125
|
classes: parsed.classes,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "25.5.
|
|
3
|
+
"version": "25.5.5",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package \u2014 content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"eslint-plugin-yml": "^3.8.1",
|
|
158
158
|
"fflate": "^0.8.3",
|
|
159
159
|
"flesch": "^2.0.1",
|
|
160
|
-
"glob": "^
|
|
160
|
+
"glob": "^14.0.0",
|
|
161
161
|
"handlebars": "^4.7.10",
|
|
162
162
|
"highlight.js": "^11.12.0",
|
|
163
163
|
"ignore": "^7.0.12",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"markdown-it": "^15.0.0",
|
|
169
169
|
"markdown-it-deflist": "^4.0.0",
|
|
170
170
|
"markdown-it-footnote": "^4.0.0",
|
|
171
|
-
"minimatch": "^
|
|
171
|
+
"minimatch": "^11.0.0",
|
|
172
172
|
"pagefind": "^1.5.2",
|
|
173
173
|
"prettier": "^3.9.6",
|
|
174
174
|
"remark-frontmatter": "^5.0.0",
|
package/types/e2e.d.mts
CHANGED
|
@@ -494,7 +494,7 @@ export const E2E_SCENE_ID: "heroiclandsScene";
|
|
|
494
494
|
/** How the suite may be run. */
|
|
495
495
|
export const E2E_MODES: readonly string[];
|
|
496
496
|
/** The Chrome for Testing build shared by local and CI Cypress runs. */
|
|
497
|
-
export const CHROME_BUILD_ID: "
|
|
497
|
+
export const CHROME_BUILD_ID: "159.0.8136.0";
|
|
498
498
|
/**
|
|
499
499
|
* The disposable world's identity and credentials.
|
|
500
500
|
*/
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* resolved configuration.
|
|
6
6
|
* @param {Iterable<Record<string, any>>} [records] - The content index's
|
|
7
7
|
* records, whose language notes supply lexical writings and script choices.
|
|
8
|
+
* @param {{referenceName?: (target: string) => string|undefined}} [options] -
|
|
9
|
+
* The rendering or validation index's own target-name lookup.
|
|
8
10
|
* @returns {RunContext} Its languages, the faces installed where it sits, and
|
|
9
11
|
* the encodings. A fonts package that cannot be read gives no faces; a run naming
|
|
10
12
|
* one is reported.
|
|
@@ -16,7 +18,9 @@ export function runContext(config: {
|
|
|
16
18
|
paths?: {
|
|
17
19
|
content?: string;
|
|
18
20
|
};
|
|
19
|
-
} | undefined, records?: Iterable<Record<string, any
|
|
21
|
+
} | undefined, records?: Iterable<Record<string, any>>, { referenceName: indexedName }?: {
|
|
22
|
+
referenceName?: (target: string) => string | undefined;
|
|
23
|
+
}): RunContext;
|
|
20
24
|
/**
|
|
21
25
|
* Find the spans, divs and verse divs marked with `lang=`, `font=` or
|
|
22
26
|
* `enc=`, and every fault in their markup and their text.
|
|
@@ -326,6 +330,10 @@ export type RunContext = {
|
|
|
326
330
|
* {@link module :engine/verse-metre.metreBooksFromRecords}.
|
|
327
331
|
*/
|
|
328
332
|
metreBooks?: ReadonlyMap<string, import("./verse-metre.mjs").MetreBook> | undefined;
|
|
333
|
+
/**
|
|
334
|
+
* - An indexed wikilink target's visible name.
|
|
335
|
+
*/
|
|
336
|
+
referenceName?: ((target: string) => string | undefined) | undefined;
|
|
329
337
|
/**
|
|
330
338
|
* -
|
|
331
339
|
* Exact Roman source inventories by configured alias and BCP 47 tag.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Capture one source tree for index, lint, links and compilation.
|
|
3
3
|
* No source or parser state is persisted or reused by another invocation.
|
|
4
|
-
*
|
|
4
|
+
* Session-owned SQL resources close after both audiences settle, or on dispose.
|
|
5
5
|
* @param {object} [options]
|
|
6
6
|
* @param {import("../content-config.mjs").ContentBuildConfig} [options.config] - Exact resolved configuration.
|
|
7
7
|
* @param {string} [options.contentBase] - Content root, defaulting to configuration.
|
|
@@ -37,12 +37,13 @@ export function scanVerse(source: string, { checkWorks }?: {
|
|
|
37
37
|
* Offsets are UTF-16 positions relative to body. Delimiters and indentation are
|
|
38
38
|
* layout ranges; source newlines inside a logical line contribute one space.
|
|
39
39
|
* @param {string} body - Authored verse body.
|
|
40
|
-
* @param {{inline?: boolean, footnotes?: ReadonlySet<string
|
|
40
|
+
* @param {{inline?: boolean, footnotes?: ReadonlySet<string>, sourceOffsets?: number[]}} [options] - Inline quotations have no cantos; footnotes are same-note definition labels; sourceOffsets maps projected body positions to authored offsets, including the end.
|
|
41
41
|
* @returns {VerseModel} The shared structure with offsets relative to the body.
|
|
42
42
|
*/
|
|
43
|
-
export function parseVerse(body: string, { inline, footnotes }?: {
|
|
43
|
+
export function parseVerse(body: string, { inline, footnotes, sourceOffsets }?: {
|
|
44
44
|
inline?: boolean;
|
|
45
45
|
footnotes?: ReadonlySet<string>;
|
|
46
|
+
sourceOffsets?: number[];
|
|
46
47
|
}): VerseModel;
|
|
47
48
|
/**
|
|
48
49
|
* Validate a quoted verse span using its original source coordinates.
|
|
@@ -271,6 +272,14 @@ export type VerseBlock = {
|
|
|
271
272
|
* - Authored verse body.
|
|
272
273
|
*/
|
|
273
274
|
body: string;
|
|
275
|
+
/**
|
|
276
|
+
* - Body without Markdown container prefixes.
|
|
277
|
+
*/
|
|
278
|
+
logicalBody: string;
|
|
279
|
+
/**
|
|
280
|
+
* - Logical UTF-16 offsets mapped to authored body offsets, including the end.
|
|
281
|
+
*/
|
|
282
|
+
bodyOffsets: number[];
|
|
274
283
|
/**
|
|
275
284
|
* - Logical structure relative to the body.
|
|
276
285
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @param {Iterable<Record<string, any>>} records - Index records.
|
|
5
5
|
* @param {{language?: string}} [options] - A language to report alone, by its
|
|
6
6
|
* name, shortcode or reference slug whether or not it states `data.core`.
|
|
7
|
-
* @returns {{concepts: number, languages: Array<{name: string, language: string, core: boolean, total: number, covered: number, missing: Array<{group: string, count: number, total: number, concepts: Array<{id: string, gloss: string}>}>}>}|{problem: string, about: string}}
|
|
7
|
+
* @returns {{concepts: number, notCovered: string[], languages: Array<{name: string, language: string, core: boolean, total: number, covered: number, missing: Array<{group: string, count: number, total: number, concepts: Array<{id: string, gloss: string}>}>}>}|{problem: string, about: string}}
|
|
8
8
|
* The report, or the problem when there is no concept list or the language
|
|
9
9
|
* asked for is none.
|
|
10
10
|
*/
|
|
@@ -12,6 +12,7 @@ export function coreReport(records: Iterable<Record<string, any>>, { language }?
|
|
|
12
12
|
language?: string;
|
|
13
13
|
}): {
|
|
14
14
|
concepts: number;
|
|
15
|
+
notCovered: string[];
|
|
15
16
|
languages: Array<{
|
|
16
17
|
name: string;
|
|
17
18
|
language: string;
|
|
@@ -36,10 +37,13 @@ export function coreReport(records: Iterable<Record<string, any>>, { language }?
|
|
|
36
37
|
* A core report as text: one block per language, its missing concepts under
|
|
37
38
|
* their groups with counts, each concept's id and gloss tab-separated.
|
|
38
39
|
*
|
|
39
|
-
*
|
|
40
|
+
* The default report ends with the names of languages it does not measure.
|
|
41
|
+
*
|
|
42
|
+
* @param {{concepts: number, notCovered: string[], languages: Array<object>}} report - A report from {@link coreReport}.
|
|
40
43
|
* @returns {string} The text, ending in a newline.
|
|
41
44
|
*/
|
|
42
45
|
export function coreReportText(report: {
|
|
43
46
|
concepts: number;
|
|
47
|
+
notCovered: string[];
|
|
44
48
|
languages: Array<object>;
|
|
45
49
|
}): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The genders
|
|
2
|
+
* The genders a mapped `data.names.given` states a list for.
|
|
3
3
|
*
|
|
4
4
|
* A function rather than a `const`: `note-vocabulary.mjs` reads it while the
|
|
5
5
|
* module graph is still evaluating.
|
|
@@ -47,7 +47,7 @@ export function namesProblems(names: unknown, lookVocabulary: Readonly<Record<st
|
|
|
47
47
|
* keys cannot: a pattern that does not parse, a placeholder naming no list, a
|
|
48
48
|
* list no pattern names, a list name a placeholder cannot spell, an empty list
|
|
49
49
|
* of patterns or of names, an empty name, a pattern or given list keyed by no
|
|
50
|
-
* gender, and a missing `female` or `male` list. Each is located at the pattern, list, entry or key at fault.
|
|
50
|
+
* gender, and a missing `female` or `male` list in a gender map. Each is located at the pattern, list, entry or key at fault.
|
|
51
51
|
*
|
|
52
52
|
* @param {object} note - The note: `file`, `raw` and parsed `fm`.
|
|
53
53
|
* @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
|
|
@@ -70,8 +70,8 @@ export function namesFindings(note: object, lookVocabulary: Readonly<Record<stri
|
|
|
70
70
|
value: string;
|
|
71
71
|
}[]>>): object[];
|
|
72
72
|
/**
|
|
73
|
-
* The given names a gender draws from: its own list, or
|
|
74
|
-
* together where it has none.
|
|
73
|
+
* The given names a gender draws from: the shared list, its own list, or
|
|
74
|
+
* every given list together where it has none.
|
|
75
75
|
*
|
|
76
76
|
* @param {object} names - Checked `data.names`.
|
|
77
77
|
* @param {string} gender - A gender word.
|
|
@@ -79,8 +79,20 @@ export function namesFindings(note: object, lookVocabulary: Readonly<Record<stri
|
|
|
79
79
|
*/
|
|
80
80
|
export function givenNames(names: object, gender: string): string[];
|
|
81
81
|
/**
|
|
82
|
-
* A name
|
|
83
|
-
*
|
|
82
|
+
* A name's selected literal and placeholder parts. One of the gender's
|
|
83
|
+
* patterns is selected first, then each placeholder is an even draw from its
|
|
84
|
+
* source list.
|
|
85
|
+
*
|
|
86
|
+
* @param {object} names - Checked `data.names`.
|
|
87
|
+
* @param {string} gender - A gender word.
|
|
88
|
+
* @param {() => number} next - A stream of numbers in `[0, 1)`.
|
|
89
|
+
* @returns {(PatternPart & {text: string})[]} The selected parts in pattern order.
|
|
90
|
+
*/
|
|
91
|
+
export function drawNameParts(names: object, gender: string, next: () => number): (PatternPart & {
|
|
92
|
+
text: string;
|
|
93
|
+
})[];
|
|
94
|
+
/**
|
|
95
|
+
* A name drawn from a language's lists.
|
|
84
96
|
*
|
|
85
97
|
* @param {object} names - Checked `data.names`.
|
|
86
98
|
* @param {string} gender - A gender word.
|
|
@@ -57,6 +57,8 @@ export function appearanceParagraph({ name, age, gender, height, frame, appearan
|
|
|
57
57
|
* by `namesProblems`.
|
|
58
58
|
* @param {string} [context.language] - The language's Address, for an error
|
|
59
59
|
* about a name that does not fit.
|
|
60
|
+
* @param {string} [context.languageCode] - The language code under which a
|
|
61
|
+
* generated name's distinct source form is retained.
|
|
60
62
|
* @param {string} [context.seed] - Text joined to the spec's own seed, to draw a
|
|
61
63
|
* different person from the same spec.
|
|
62
64
|
* @param {unknown} [context.currentDate] - The setting's neutral current date, defaulting to "720.1".
|
|
@@ -74,6 +76,7 @@ export function generateNpc(spec: object, context: {
|
|
|
74
76
|
profile: object;
|
|
75
77
|
names: object;
|
|
76
78
|
language?: string | undefined;
|
|
79
|
+
languageCode?: string | undefined;
|
|
77
80
|
seed?: string | undefined;
|
|
78
81
|
currentDate?: unknown;
|
|
79
82
|
dateContext?: object | undefined;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read page-break markers before any surface rewrites their source.
|
|
3
|
+
* Code, HTML examples and entire verse divs remain literal. Parser ranges
|
|
4
|
+
* retain list and quote membership, including lazy continuation lines.
|
|
5
|
+
* @param {string} source - Authored Markdown body.
|
|
6
|
+
* @returns {{breaks: Array<{line: number, column: number}>, errors: Array<{line: number, column: number, message: string}>}}
|
|
7
|
+
*/
|
|
8
|
+
export function scanPageBreaks(source: string): {
|
|
9
|
+
breaks: Array<{
|
|
10
|
+
line: number;
|
|
11
|
+
column: number;
|
|
12
|
+
}>;
|
|
13
|
+
errors: Array<{
|
|
14
|
+
line: number;
|
|
15
|
+
column: number;
|
|
16
|
+
message: string;
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Omit valid page breaks on a screen, preserving the surrounding block boundaries.
|
|
21
|
+
* @param {string} source - Markdown body.
|
|
22
|
+
* @returns {string} Markdown without valid page-break lines.
|
|
23
|
+
*/
|
|
24
|
+
export function omitPageBreaks(source: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Produce the book's page-break token, leaving ordinary thematic breaks alone.
|
|
27
|
+
* @param {import("markdown-it")} md - The book parser.
|
|
28
|
+
* @returns {void}
|
|
29
|
+
*/
|
|
30
|
+
export function pageBreakPlugin(md: typeof import("markdown-it")): void;
|
|
@@ -98,6 +98,7 @@ export function stripHtmlComments(markdown: string): string;
|
|
|
98
98
|
* @param {Array<{line: number, generated: boolean}>} [opts.lineMap] - From
|
|
99
99
|
* table expansion, mapping each line handed in back to the line an author
|
|
100
100
|
* wrote.
|
|
101
|
+
* @param {boolean} [opts.pageBreaks] - Internal: whether this slice remains at the note top level.
|
|
101
102
|
* @param {boolean} [opts.prepared] - Whether this body has been through the
|
|
102
103
|
* passes that resolve a wikilink, an embed and an inline expression. A note's
|
|
103
104
|
* has; a front-matter file's and a prose file's have not, and markup of theirs
|
|
@@ -138,6 +139,7 @@ export function markdownToTypst(markdown: string, opts?: {
|
|
|
138
139
|
line: number;
|
|
139
140
|
generated: boolean;
|
|
140
141
|
}[] | undefined;
|
|
142
|
+
pageBreaks?: boolean | undefined;
|
|
141
143
|
prepared?: boolean | undefined;
|
|
142
144
|
url?: string | undefined;
|
|
143
145
|
elsewhere?: {
|
|
@@ -306,6 +306,7 @@ export function sitePageDecorator(config: any, index: any): (data: any, page: an
|
|
|
306
306
|
* @param {object} [options] - Options.
|
|
307
307
|
* @param {object} [options.config] - A resolved configuration; loaded when
|
|
308
308
|
* omitted.
|
|
309
|
+
* @param {(message: string) => void} [options.progress] - Build phase summaries.
|
|
309
310
|
* @param {Map<string, object[]>} [options.sqlTables] - Prepared `sql` results,
|
|
310
311
|
* keyed by the note's absolute file, from
|
|
311
312
|
* {@link module:engine/sql-tables.prepareSqlTables}. A page authoring an
|
|
@@ -322,8 +323,9 @@ export function sitePageDecorator(config: any, index: any): (data: any, page: an
|
|
|
322
323
|
* against the rest of the build, or returns `null` when its address, name
|
|
323
324
|
* or type changed and the whole site must be built again.
|
|
324
325
|
*/
|
|
325
|
-
export function buildSite({ config, sqlTables }?: {
|
|
326
|
+
export function buildSite({ config, sqlTables, progress }?: {
|
|
326
327
|
config?: object | undefined;
|
|
328
|
+
progress?: ((message: string) => void) | undefined;
|
|
327
329
|
sqlTables?: Map<string, object[]> | undefined;
|
|
328
330
|
}): {
|
|
329
331
|
gates: object;
|
|
@@ -50,19 +50,21 @@ export function writeThemeFiles(out: string, staticDir?: string): string[];
|
|
|
50
50
|
* @param {string} [options.staticDir] - The theme's own files, copied first.
|
|
51
51
|
* @param {ReadonlySet<string>} [options.only] - The addresses of the pages to
|
|
52
52
|
* draw again into a site already written. Nothing else is touched.
|
|
53
|
+
* @param {(message: string) => void} [options.progress] - Build phase summaries.
|
|
53
54
|
* @returns {{files: string[], pages: string[], reachable: string[],
|
|
54
55
|
* findings: object[]}} Every file written, the address of every page, the
|
|
55
56
|
* address of each page reachable from the homepage, and the layouts' findings.
|
|
56
57
|
* @throws {Error} When a page's address is outside the site, or a site served
|
|
57
58
|
* under a path asks for a sitemap index.
|
|
58
59
|
*/
|
|
59
|
-
export function writeSite({ site, pages, out, report, staticDir, only }: {
|
|
60
|
+
export function writeSite({ site, pages, out, report, staticDir, only, progress, }: {
|
|
60
61
|
site: object;
|
|
61
62
|
pages: readonly object[];
|
|
62
63
|
out: string;
|
|
63
64
|
report?: ((finding: import("./site-theme.mjs").Finding) => void) | undefined;
|
|
64
65
|
staticDir?: string | undefined;
|
|
65
66
|
only?: ReadonlySet<string> | undefined;
|
|
67
|
+
progress?: ((message: string) => void) | undefined;
|
|
66
68
|
}): {
|
|
67
69
|
files: string[];
|
|
68
70
|
pages: string[];
|
|
@@ -147,6 +149,7 @@ export function deliverSiteFonts(config: object, out: string): {
|
|
|
147
149
|
* @param {string} options.out - The directory the site is written to, which
|
|
148
150
|
* is the package's own directory under the deployed root.
|
|
149
151
|
* @param {number} [options.year] - The year the footer states.
|
|
152
|
+
* @param {(message: string) => void} [options.progress] - Build phase summaries.
|
|
150
153
|
* @returns {Promise<{built: object, written: object|null, fonts: object|null,
|
|
151
154
|
* site?: object, pages?: object[], pageOf?: (entry: object) => object}>}
|
|
152
155
|
* What the build found, and, when it found nothing that stops it, what was
|
|
@@ -154,10 +157,11 @@ export function deliverSiteFonts(config: object, out: string): {
|
|
|
154
157
|
* becomes its page. `written` is `null` when a gate fired.
|
|
155
158
|
* @throws {Error} When the site's settings or its cached menu cannot be read.
|
|
156
159
|
*/
|
|
157
|
-
export function buildPackageSite({ config, out, year }: {
|
|
160
|
+
export function buildPackageSite({ config, out, year, progress }: {
|
|
158
161
|
config: object;
|
|
159
162
|
out: string;
|
|
160
163
|
year?: number | undefined;
|
|
164
|
+
progress?: ((message: string) => void) | undefined;
|
|
161
165
|
}): Promise<{
|
|
162
166
|
built: object;
|
|
163
167
|
written: object | null;
|
|
@@ -73,6 +73,7 @@ export function indexSite(where: {
|
|
|
73
73
|
* `site.search` in the configuration. Default `true`.
|
|
74
74
|
* @param {SiteIndexer} [options.indexer] - What builds it. Default
|
|
75
75
|
* {@link indexSite}.
|
|
76
|
+
* @param {(message: string) => void} [options.progress] - Build phase summaries.
|
|
76
77
|
* @returns {Promise<{files: string[], search: {dir: string, pages: number}|null}>}
|
|
77
78
|
* The files written, and the index — where it is and how many pages it
|
|
78
79
|
* holds — or `null` when none was built.
|
|
@@ -81,12 +82,13 @@ export function indexSite(where: {
|
|
|
81
82
|
* under the prefix; or, located at the rendered site, when the indexer
|
|
82
83
|
* fails.
|
|
83
84
|
*/
|
|
84
|
-
export function writeSiteRoot({ pkg, base, out, search, indexer }: {
|
|
85
|
+
export function writeSiteRoot({ pkg, base, out, search, indexer, progress, }: {
|
|
85
86
|
pkg: string;
|
|
86
87
|
base?: string | undefined;
|
|
87
88
|
out: string;
|
|
88
89
|
search?: boolean | undefined;
|
|
89
90
|
indexer?: SiteIndexer | undefined;
|
|
91
|
+
progress?: ((message: string) => void) | undefined;
|
|
90
92
|
}): Promise<{
|
|
91
93
|
files: string[];
|
|
92
94
|
search: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -9,16 +9,19 @@
|
|
|
9
9
|
* directory above `out` by default; `out` itself for a site served at `/`.
|
|
10
10
|
* @param {string} [options.host] - The address to listen on.
|
|
11
11
|
* @param {number} [options.port] - The port; `0` takes any free one.
|
|
12
|
-
* @param {boolean} [options.search] - Build the search index
|
|
12
|
+
* @param {boolean} [options.search] - Build the search index with each whole
|
|
13
13
|
* build, where the site has one.
|
|
14
14
|
* @param {number} [options.year] - The year the footer states.
|
|
15
|
-
* @param {(event: {kind: string, built?: object, files?: string[], findings?: object[], error?: unknown}) => void} [options.report] -
|
|
16
|
-
* Told of each build: `built` for a whole build, `page` for one note's page,
|
|
15
|
+
* @param {(event: {kind: string, built?: object, files?: string[], findings?: object[], error?: unknown, message?: string, fatal?: boolean}) => void} [options.report] -
|
|
16
|
+
* Told of progress (`message`) and each build: `built` for a whole build, `page` for one note's page,
|
|
17
17
|
* `theme` for the theme, `failed` with what the build found, `error` with
|
|
18
18
|
* what it threw.
|
|
19
|
-
* @returns {Promise<{url: string, close: () => Promise<void>, settled: () => Promise<void>}>}
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* @returns {Promise<{url: string, close: () => Promise<void>, settled: () => Promise<void>, done: Promise<void>}>}
|
|
20
|
+
* Resolves as soon as HTTP listens, before the first build. The address of
|
|
21
|
+
* the site's home page, how to stop serving, and a promise for the initial
|
|
22
|
+
* build and every change seen so far to finish. Failed builds are reported
|
|
23
|
+
* through `report` and leave the last successful site in service. `done`
|
|
24
|
+
* resolves on close and rejects if HTTP stops unexpectedly.
|
|
22
25
|
*/
|
|
23
26
|
export function serveSite({ config, out, root, host, port, search, year, report, }: {
|
|
24
27
|
config: object;
|
|
@@ -34,11 +37,14 @@ export function serveSite({ config, out, root, host, port, search, year, report,
|
|
|
34
37
|
files?: string[];
|
|
35
38
|
findings?: object[];
|
|
36
39
|
error?: unknown;
|
|
40
|
+
message?: string;
|
|
41
|
+
fatal?: boolean;
|
|
37
42
|
}) => void) | undefined;
|
|
38
43
|
}): Promise<{
|
|
39
44
|
url: string;
|
|
40
45
|
close: () => Promise<void>;
|
|
41
46
|
settled: () => Promise<void>;
|
|
47
|
+
done: Promise<void>;
|
|
42
48
|
}>;
|
|
43
49
|
/** The address a served page listens on for the server's reloads. */
|
|
44
50
|
export const RELOAD_PATH: "/__package-build/reload";
|
|
@@ -65,12 +65,13 @@ export function findSqlBlocks(markdown: string): Array<{
|
|
|
65
65
|
* @param {object} [opts.addressContext] - Address resolution context.
|
|
66
66
|
* @param {"all"|"public"} [opts.audience] - Whether to exclude GM notes from
|
|
67
67
|
* local and dependency relations.
|
|
68
|
+
* @param {boolean} [opts.testMemoryLimit] - Test-only fixed 256 MB budget;
|
|
69
|
+
* production always uses 2 GB. This is not authored configuration.
|
|
68
70
|
* @param {string} [opts.contentBase] - The directory the records' paths are
|
|
69
71
|
* relative to, so a refused key is reported at its file and line.
|
|
70
|
-
* @returns {
|
|
71
|
-
* close: () => Promise<void>}>} The open database.
|
|
72
|
+
* @returns {ReturnType<typeof openDatabase>} The open database.
|
|
72
73
|
*/
|
|
73
|
-
export function openNotesDatabase(records: object[],
|
|
74
|
+
export function openNotesDatabase(records: object[], opts?: {
|
|
74
75
|
dir?: string | undefined;
|
|
75
76
|
dependencies?: {
|
|
76
77
|
id: string;
|
|
@@ -78,11 +79,21 @@ export function openNotesDatabase(records: object[], { dir, dependencies, addres
|
|
|
78
79
|
}[] | undefined;
|
|
79
80
|
addressContext?: object | undefined;
|
|
80
81
|
audience?: "all" | "public" | undefined;
|
|
82
|
+
testMemoryLimit?: boolean | undefined;
|
|
81
83
|
contentBase?: string | undefined;
|
|
82
|
-
}):
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
}): ReturnType<typeof openDatabase>;
|
|
85
|
+
/**
|
|
86
|
+
* Own the SQL resources of one content session. Raw local and dependency JSON
|
|
87
|
+
* tables are loaded once; each audience derives its relations unchanged in a
|
|
88
|
+
* separate catalog/connection. Openings are serialized, queries are not.
|
|
89
|
+
* @param {object[]} records - The session's captured index.
|
|
90
|
+
* @param {Omit<NonNullable<Parameters<typeof openNotesDatabase>[1]>, "audience"|"dir">} [options] - Shared load options.
|
|
91
|
+
* @returns {{database: (audience: "all"|"public") => Promise<Awaited<ReturnType<typeof openNotesDatabase>>>, dispose: () => void}}
|
|
92
|
+
*/
|
|
93
|
+
export function createNotesDatabaseScope(records: object[], options?: Omit<NonNullable<Parameters<typeof openNotesDatabase>[1]>, "audience" | "dir">): {
|
|
94
|
+
database: (audience: "all" | "public") => Promise<Awaited<ReturnType<typeof openNotesDatabase>>>;
|
|
95
|
+
dispose: () => void;
|
|
96
|
+
};
|
|
86
97
|
/**
|
|
87
98
|
* Run one authored query and shape its result for the renderer.
|
|
88
99
|
*
|
|
@@ -301,7 +312,8 @@ export function cachedDependencies(config?: object): Promise<Array<{
|
|
|
301
312
|
* @param {object} [opts.database] - An open notes database over `records`, from
|
|
302
313
|
* {@link openNotesDatabase} with this call's `audience` and the declared
|
|
303
314
|
* dependencies from {@link cachedDependencies}. It is queried and left open;
|
|
304
|
-
* absent, one is opened and closed here.
|
|
315
|
+
* absent, one is opened and closed here. A lazy async factory is also
|
|
316
|
+
* accepted and called only when this preparation needs SQL.
|
|
305
317
|
* @param {"all"|"public"} [opts.audience] - Whether to exclude GM notes.
|
|
306
318
|
* @param {Map<string, object>} [opts.foreignIndex] - The fetched indexes the
|
|
307
319
|
* generated sections take in, where the caller holds them already; absent,
|
|
@@ -376,3 +388,20 @@ export const SQL_FENCE_ATTRIBUTES: Readonly<Record<string, Readonly<{
|
|
|
376
388
|
default: string;
|
|
377
389
|
summary: string;
|
|
378
390
|
}>>>;
|
|
391
|
+
/**
|
|
392
|
+
* Open one audience connection, optionally in a session-owned instance.
|
|
393
|
+
* @param {object[]} records - Content-index records.
|
|
394
|
+
* @param {NonNullable<Parameters<typeof openNotesDatabase>[1]>} [opts] - Load options.
|
|
395
|
+
* @param {object} [shared] - Session-owned SQL resources.
|
|
396
|
+
*/
|
|
397
|
+
declare function openDatabase(records: object[], { dir, dependencies, addressContext, audience, contentBase, testMemoryLimit, }?: NonNullable<Parameters<typeof openNotesDatabase>[1]>, shared?: object): Promise<{
|
|
398
|
+
addressContext: object;
|
|
399
|
+
stubsExcluded: (sql: string, rows: number) => Promise<number>;
|
|
400
|
+
languageNotes: Map<string, string>;
|
|
401
|
+
query(sql: any): Promise<{
|
|
402
|
+
columnNames: any;
|
|
403
|
+
rows: any;
|
|
404
|
+
}>;
|
|
405
|
+
close(): Promise<void>;
|
|
406
|
+
}>;
|
|
407
|
+
export {};
|
|
@@ -73,7 +73,7 @@ export function metreMessage({ min, max }: {
|
|
|
73
73
|
* @param {ReadonlyArray<{start: number, end: number, indent: string, attributes: Record<string, string>, classes: string[]}>} blocks -
|
|
74
74
|
* The divs, from {@link module:engine/content-verse.scanVerse}.
|
|
75
75
|
* @param {string[]} lines - The source's lines.
|
|
76
|
-
* @param {{languages?: Readonly<Record<string, {tag: string}>>, metres?: ReadonlyMap<string, import("./metre-declaration.mjs").Metre>, metreBooks?: ReadonlyMap<string, MetreBook>, lexicons?: ReadonlyMap<string, unknown>, attributeColumns: (line: string, key: string) => {key: number, value: number}}} ctx -
|
|
76
|
+
* @param {{languages?: Readonly<Record<string, {tag: string}>>, metres?: ReadonlyMap<string, import("./metre-declaration.mjs").Metre>, metreBooks?: ReadonlyMap<string, MetreBook>, lexicons?: ReadonlyMap<string, unknown>, referenceName?: (target: string) => string|undefined, attributeColumns: (line: string, key: string) => {key: number, value: number}}} ctx -
|
|
77
77
|
* The metres and books, and how the div says its columns and where its
|
|
78
78
|
* keys sit.
|
|
79
79
|
* @returns {{errors: object[], warnings: object[]}} The findings at 1-based
|
|
@@ -92,6 +92,7 @@ export function metreFindings(blocks: ReadonlyArray<{
|
|
|
92
92
|
metres?: ReadonlyMap<string, import("./metre-declaration.mjs").Metre>;
|
|
93
93
|
metreBooks?: ReadonlyMap<string, MetreBook>;
|
|
94
94
|
lexicons?: ReadonlyMap<string, unknown>;
|
|
95
|
+
referenceName?: (target: string) => string | undefined;
|
|
95
96
|
attributeColumns: (line: string, key: string) => {
|
|
96
97
|
key: number;
|
|
97
98
|
value: number;
|
|
@@ -51,6 +51,14 @@ export type VerseRegion = {
|
|
|
51
51
|
* - Authored body bytes.
|
|
52
52
|
*/
|
|
53
53
|
body: string;
|
|
54
|
+
/**
|
|
55
|
+
* - Body without Markdown container prefixes.
|
|
56
|
+
*/
|
|
57
|
+
logicalBody: string;
|
|
58
|
+
/**
|
|
59
|
+
* - Logical UTF-16 offsets mapped to authored body offsets, including the end.
|
|
60
|
+
*/
|
|
61
|
+
bodyOffsets: number[];
|
|
54
62
|
/**
|
|
55
63
|
* - Authored values.
|
|
56
64
|
*/
|