@heroiclands/package-build 25.1.2 → 25.2.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/assets/styles/content-base.css +0 -9
- package/bin/content-commands.mjs +22 -16
- package/bin/package-build.mjs +24 -25
- package/content-config.mjs +7 -34
- package/docs/api.md +38 -21
- package/docs/authoring/first-note.md +3 -3
- package/docs/authoring/frontmatter.md +30 -2
- package/docs/authoring/links-and-markup.md +92 -31
- package/docs/commands.md +103 -59
- package/docs/configuration.md +10 -45
- package/docs/content-format.md +7 -5
- package/docs/diagnostics.md +75 -0
- package/docs/encoding-core.md +11 -0
- package/docs/guides/book.md +3 -3
- package/docs/guides/module-project.md +1 -1
- package/docs/guides/reference-pages.md +7 -3
- package/docs/project-setup.md +3 -0
- package/docs/reference/format-details.md +329 -187
- package/docs/reference/note-types.md +274 -274
- package/engine/changelog-group.mjs +84 -173
- package/engine/changelog-labels.mjs +73 -0
- package/engine/changelog-lint.mjs +168 -44
- package/engine/content-expand.mjs +58 -38
- package/engine/content-format.yaml +0 -2
- package/engine/content-index.mjs +49 -23
- package/engine/content-links.mjs +4 -0
- package/engine/content-lint.mjs +2 -3
- package/engine/content-render.mjs +6 -2
- package/engine/culture-parents.mjs +1 -1
- package/engine/culture-reach.mjs +10 -1
- package/engine/diagnostics.mjs +3 -2
- package/engine/dictionary-rows.mjs +3 -1
- package/engine/encoding-lexicon.mjs +12 -2
- package/engine/first-use.mjs +301 -87
- package/engine/frontmatter-lint.mjs +40 -14
- package/engine/glossary-entries.mjs +5 -5
- package/engine/glossary-language.mjs +21 -44
- package/engine/homepage.mjs +0 -4
- package/engine/index-records.mjs +3 -1
- package/engine/infobox.mjs +6 -3
- package/engine/language-names.mjs +70 -10
- package/engine/language-rows.mjs +6 -7
- package/engine/lexical-sections.mjs +3 -1
- package/engine/literature-notes.mjs +4 -76
- package/engine/metadata-index.mjs +15 -8
- package/engine/name-forms.mjs +99 -0
- package/engine/name-refs.mjs +143 -0
- package/engine/name-rows.mjs +11 -1
- package/engine/names.mjs +27 -22
- package/engine/note-addresses.mjs +0 -3
- package/engine/note-frontmatter.mjs +3 -5
- package/engine/note-language.mjs +348 -0
- package/engine/note-vocabulary.mjs +35 -13
- package/engine/pdf-index.mjs +3 -2
- package/engine/pdf-render.mjs +2 -4
- package/engine/settlement-tables.mjs +4 -3
- package/engine/site-build.mjs +2 -7
- package/engine/site-search.mjs +3 -5
- package/engine/site-theme.mjs +1 -1
- package/engine/sql-tables.mjs +29 -14
- package/engine/wikilink-syntax.mjs +2 -0
- package/engine/word-citations.mjs +3 -3
- package/engine/word-rows.mjs +3 -1
- package/engine/word-terms.mjs +2 -2
- package/package.json +1 -1
- package/site-theme/static/css/style.css +0 -4
- package/types/engine/changelog-group.d.mts +6 -10
- package/types/engine/changelog-labels.d.mts +10 -0
- package/types/engine/changelog-lint.d.mts +11 -6
- package/types/engine/content-index.d.mts +16 -16
- package/types/engine/diagnostics.d.mts +1 -1
- package/types/engine/first-use.d.mts +97 -1
- package/types/engine/frontmatter-lint.d.mts +9 -2
- package/types/engine/glossary-language.d.mts +13 -6
- package/types/engine/homepage.d.mts +0 -3
- package/types/engine/language-names.d.mts +3 -0
- package/types/engine/literature-notes.d.mts +2 -27
- package/types/engine/name-forms.d.mts +61 -0
- package/types/engine/name-refs.d.mts +51 -0
- package/types/engine/name-rows.d.mts +4 -0
- package/types/engine/names.d.mts +12 -92
- package/types/engine/note-frontmatter.d.mts +1 -4
- package/types/engine/note-language.d.mts +47 -0
- package/types/engine/settlement-tables.d.mts +1 -1
- package/types/engine/site-build.d.mts +2 -6
package/engine/sql-tables.mjs
CHANGED
|
@@ -55,6 +55,7 @@ import { LANGUAGE_COLUMN_TYPES, LANGUAGE_RELATIONS } from "./language-rows.mjs";
|
|
|
55
55
|
import { VERB_PERSON_FIELDS } from "./language-terms.mjs";
|
|
56
56
|
import { renderDictionary, renderGlossary } from "./dictionary-layout.mjs";
|
|
57
57
|
import { glossaryLanguage } from "./glossary-language.mjs";
|
|
58
|
+
import { languageNotesByCode } from "./note-language.mjs";
|
|
58
59
|
import { lexicalSectionsFor } from "./lexical-sections.mjs";
|
|
59
60
|
import { eventViewSections } from "./event-views.mjs";
|
|
60
61
|
import { appendGeneratedSections, joinSections } from "./generated-sections.mjs";
|
|
@@ -466,6 +467,22 @@ export async function openNotesDatabase(
|
|
|
466
467
|
system: "note",
|
|
467
468
|
},
|
|
468
469
|
stubsExcluded,
|
|
470
|
+
// Each language code's note, for a page whose language is read from
|
|
471
|
+
// its frontmatter.
|
|
472
|
+
languageNotes: languageNotesByCode(encoded, (record) =>
|
|
473
|
+
(
|
|
474
|
+
typeof record.package === "string" &&
|
|
475
|
+
typeof record.type === "string" &&
|
|
476
|
+
typeof record.shortcode === "string"
|
|
477
|
+
) ?
|
|
478
|
+
renderAddress({
|
|
479
|
+
package: record.package,
|
|
480
|
+
system: "note",
|
|
481
|
+
type: record.type,
|
|
482
|
+
shortcode: record.shortcode,
|
|
483
|
+
})
|
|
484
|
+
: undefined,
|
|
485
|
+
),
|
|
469
486
|
async query(sql) {
|
|
470
487
|
const reader = await connection.runAndReadAll(sql);
|
|
471
488
|
return {
|
|
@@ -1019,7 +1036,7 @@ function toPlain(value) {
|
|
|
1019
1036
|
* DuckDB returns an integer as a `BigInt`, which `String()` renders without its
|
|
1020
1037
|
* `n` — but a struct or a list would stringify as `[object Object]`, so those
|
|
1021
1038
|
* are refused rather than printed. A list of scalars is joined, because that is
|
|
1022
|
-
* what a `tags`
|
|
1039
|
+
* what a `tags` column means.
|
|
1023
1040
|
*
|
|
1024
1041
|
* @param {unknown} value - The cell value.
|
|
1025
1042
|
* @param {string} column - Its column, named in the message.
|
|
@@ -1296,20 +1313,17 @@ async function noteLabels(db) {
|
|
|
1296
1313
|
|
|
1297
1314
|
/**
|
|
1298
1315
|
* The language a note's frontmatter says it is in: a language note's own
|
|
1299
|
-
* Address, else its
|
|
1316
|
+
* Address, else the note of its language — the code the content index derived
|
|
1317
|
+
* for it where the frontmatter is its record, else its own `data.lang`.
|
|
1300
1318
|
*
|
|
1301
|
-
* @param {object|undefined} frontmatter - The note's
|
|
1302
|
-
* @param {object} db - From {@link openNotesDatabase}, for its Address context
|
|
1319
|
+
* @param {object|undefined} frontmatter - The note's frontmatter or record.
|
|
1320
|
+
* @param {object} db - From {@link openNotesDatabase}, for its Address context
|
|
1321
|
+
* and its language notes.
|
|
1303
1322
|
* @returns {string|undefined} The language's Address.
|
|
1304
1323
|
*/
|
|
1305
1324
|
function frontmatterLanguage(frontmatter, db) {
|
|
1306
1325
|
if (!frontmatter || typeof frontmatter !== "object") return undefined;
|
|
1307
1326
|
const context = db.addressContext ?? {};
|
|
1308
|
-
const read = (value, type) => {
|
|
1309
|
-
if (typeof value !== "string" || !value) return undefined;
|
|
1310
|
-
const tuple = parseAddress(value, { ...context, system: "note", type }, { declared: true });
|
|
1311
|
-
return tuple.reason ? undefined : renderAddress({ ...tuple, system: "note" });
|
|
1312
|
-
};
|
|
1313
1327
|
if (
|
|
1314
1328
|
String(frontmatter.type ?? "").toLowerCase() === "skill" &&
|
|
1315
1329
|
frontmatter.subType === "language" &&
|
|
@@ -1322,7 +1336,8 @@ function frontmatterLanguage(frontmatter, db) {
|
|
|
1322
1336
|
type: "skill",
|
|
1323
1337
|
shortcode: frontmatter.shortcode,
|
|
1324
1338
|
});
|
|
1325
|
-
|
|
1339
|
+
const code = frontmatter.lang ?? frontmatter.data?.lang;
|
|
1340
|
+
return typeof code === "string" ? db.languageNotes?.get(code) : undefined;
|
|
1326
1341
|
}
|
|
1327
1342
|
|
|
1328
1343
|
/** Evaluate scalar SQL calls before synchronous Markdown renderers run. */
|
|
@@ -1535,9 +1550,8 @@ async function attachPreparedAnchors(prepared, records, contentBase, parsed, con
|
|
|
1535
1550
|
|
|
1536
1551
|
/**
|
|
1537
1552
|
* The language each note of a tree is in, by its file: a language note itself,
|
|
1538
|
-
*
|
|
1539
|
-
*
|
|
1540
|
-
* {@link module:engine/glossary-language}.
|
|
1553
|
+
* and every other note the note of the language the content index derived for
|
|
1554
|
+
* it — see {@link module:engine/glossary-language}.
|
|
1541
1555
|
*
|
|
1542
1556
|
* @param {object[]} records - Content-index records.
|
|
1543
1557
|
* @param {string} contentBase - Root of the content tree.
|
|
@@ -1566,12 +1580,13 @@ function pageLanguages(records, contentBase) {
|
|
|
1566
1580
|
.filter((record) => isNoteRecord(record))
|
|
1567
1581
|
.map((record, i) => [noteFile(contentBase, record), notes[i]]),
|
|
1568
1582
|
);
|
|
1583
|
+
const languageNotes = languageNotesByCode(byKey.values(), keyOf);
|
|
1569
1584
|
return (source) => {
|
|
1570
1585
|
const record = byFile.get(source);
|
|
1571
1586
|
if (!record) return undefined;
|
|
1572
1587
|
return glossaryLanguage(undefined, record, {
|
|
1573
1588
|
keyOf: (value) => (typeof value === "string" && value ? value : undefined),
|
|
1574
|
-
|
|
1589
|
+
noteOf: (code) => languageNotes.get(code),
|
|
1575
1590
|
self: keyOf(record),
|
|
1576
1591
|
});
|
|
1577
1592
|
};
|
|
@@ -104,6 +104,8 @@ export function parseWikilink(rawInner, literal = "") {
|
|
|
104
104
|
const attributes =
|
|
105
105
|
suffix.startsWith("{") ? parseExtensionAttributes(suffix.slice(1, -1)) : null;
|
|
106
106
|
if (attributes) attributes.problems.push(...refusedAttributes(attributes.values));
|
|
107
|
+
if (attributes && Object.hasOwn(attributes.values, "ref"))
|
|
108
|
+
attributes.problems.push("a wikilink never takes ref; its address is its ref");
|
|
107
109
|
return {
|
|
108
110
|
inner: inner.trim(),
|
|
109
111
|
target,
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
import MarkdownIt from "markdown-it";
|
|
41
41
|
|
|
42
42
|
import { isLanguageRecord, noteAddressOf } from "./word-rows.mjs";
|
|
43
|
+
import { nameFormsOf } from "./name-forms.mjs";
|
|
43
44
|
|
|
44
45
|
/** The parser marked uses are read with: CommonMark's emphasis and nothing added. */
|
|
45
46
|
const PARSER = new MarkdownIt("commonmark");
|
|
@@ -101,7 +102,7 @@ export function markedUses(body) {
|
|
|
101
102
|
|
|
102
103
|
/**
|
|
103
104
|
* The names a note carries whole, which cite a word they spell exactly: its
|
|
104
|
-
* full name and
|
|
105
|
+
* full name and listed forms, and an affiliation's rank and office titles.
|
|
105
106
|
*
|
|
106
107
|
* @param {Record<string, any>} record - An index record.
|
|
107
108
|
* @returns {string[]}
|
|
@@ -110,8 +111,7 @@ function namesCarried(record) {
|
|
|
110
111
|
const out = [];
|
|
111
112
|
const name = isMap(record.name) ? record.name : {};
|
|
112
113
|
if (typeof name.full === "string") out.push(name.full);
|
|
113
|
-
|
|
114
|
-
if (typeof alias === "string") out.push(alias);
|
|
114
|
+
out.push(...nameFormsOf(name));
|
|
115
115
|
const governance = isMap(record.data?.governance) ? record.data.governance : {};
|
|
116
116
|
for (const rank of Array.isArray(governance.ranks) ? governance.ranks : [])
|
|
117
117
|
if (isMap(rank) && typeof rank.title === "string") out.push(rank.title);
|
package/engine/word-rows.mjs
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
import { renderAddress } from "./address.mjs";
|
|
38
38
|
import { glossaryLanguage } from "./glossary-language.mjs";
|
|
39
|
+
import { languageNotesByCode } from "./note-language.mjs";
|
|
39
40
|
import {
|
|
40
41
|
AFFIX_KEYS,
|
|
41
42
|
ZERO_AFFIX,
|
|
@@ -368,9 +369,10 @@ export function glossaryRows(records, all = records) {
|
|
|
368
369
|
const key = noteAddressOf(record);
|
|
369
370
|
if (key && !byAddress.has(key)) byAddress.set(key, record);
|
|
370
371
|
}
|
|
372
|
+
const languageNotes = languageNotesByCode(byAddress.values(), noteAddressOf);
|
|
371
373
|
const reader = {
|
|
372
374
|
keyOf: (value) => (typeof value === "string" && value ? value : undefined),
|
|
373
|
-
|
|
375
|
+
noteOf: (code) => languageNotes.get(code),
|
|
374
376
|
};
|
|
375
377
|
const rows = [];
|
|
376
378
|
for (const record of records) {
|
package/engine/word-terms.mjs
CHANGED
|
@@ -489,8 +489,8 @@ export const GLOSSARY_ENTRY_FIELDS = Object.freeze([
|
|
|
489
489
|
kind: "address",
|
|
490
490
|
shape: "a language skill Address",
|
|
491
491
|
describe:
|
|
492
|
-
"The language the term is in. Unstated, it is the
|
|
493
|
-
"
|
|
492
|
+
"The language the term is in. Unstated, it is the note of the language the " +
|
|
493
|
+
"note is in, its `data.lang` as the content index derives it.",
|
|
494
494
|
}),
|
|
495
495
|
]);
|
|
496
496
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.2.0",
|
|
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",
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `changelog group`:
|
|
3
|
-
* their bold label, order them, and file an undeclared one last.
|
|
2
|
+
* `changelog group`: give the newest release its final shape.
|
|
4
3
|
*
|
|
5
|
-
* Every earlier release section is untouched, byte for byte
|
|
6
|
-
*
|
|
7
|
-
* each independently (a label groups within its own bump level, never
|
|
8
|
-
* across one). Running this on its own output is a no-op: a release already
|
|
9
|
-
* in label order, with each label merged to one block, groups to itself.
|
|
4
|
+
* Every earlier release section is untouched, byte for byte. Running this on
|
|
5
|
+
* its own output is a no-op.
|
|
10
6
|
*
|
|
11
7
|
* @param {string} text - The changelog's full contents.
|
|
12
8
|
* @param {object} [opts]
|
|
13
|
-
* @param {readonly string[]|null} [opts.labels] - `
|
|
14
|
-
* display order. `null`/absent orders
|
|
15
|
-
*
|
|
9
|
+
* @param {readonly string[]|null} [opts.labels] - the changelog `labels`, in
|
|
10
|
+
* display order. `null`/absent orders by first appearance and reports
|
|
11
|
+
* nothing as undeclared.
|
|
16
12
|
* @returns {{text: string, findings: Array<{line: number,
|
|
17
13
|
* severity: "warning", message: string}>}}
|
|
18
14
|
*/
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read `labels` from the changelog options in `.changeset/config.json`.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} [cwd] - The repository root.
|
|
5
|
+
* @returns {readonly string[]|null} The labels in display order, or `null`
|
|
6
|
+
* when the file, the options or `labels` is absent.
|
|
7
|
+
* @throws {Error} When `config.json` is not JSON, or `labels` is not an array
|
|
8
|
+
* of distinct non-empty strings or names `Miscellaneous`.
|
|
9
|
+
*/
|
|
10
|
+
export function readChangelogLabels(cwd?: string): readonly string[] | null;
|
|
@@ -77,9 +77,9 @@ export function topLevelBlocks(text: string, codeLines: Set<number>, scaffoldLin
|
|
|
77
77
|
*
|
|
78
78
|
* @param {string} text - The file's full contents, frontmatter included.
|
|
79
79
|
* @param {object} [opts]
|
|
80
|
-
* @param {readonly string[]|null} [opts.labels] - `
|
|
81
|
-
* display order, or `null`/absent when the repository declares none
|
|
82
|
-
* {@link
|
|
80
|
+
* @param {readonly string[]|null} [opts.labels] - the changelog `labels`, in
|
|
81
|
+
* display order, or `null`/absent when the repository declares none, in
|
|
82
|
+
* which case only {@link MISCELLANEOUS} is accepted.
|
|
83
83
|
* @returns {{findings: Array<{line: number, column?: number,
|
|
84
84
|
* severity: "error"|"warning", message: string}>}}
|
|
85
85
|
*/
|
|
@@ -98,9 +98,9 @@ export function lintChangesetText(text: string, { labels }?: {
|
|
|
98
98
|
*
|
|
99
99
|
* @param {string} text - The changelog's full contents.
|
|
100
100
|
* @param {object} [opts]
|
|
101
|
-
* @param {readonly string[]|null} [opts.labels] - `
|
|
102
|
-
* display order, or `null`/absent when the repository declares none
|
|
103
|
-
* {@link
|
|
101
|
+
* @param {readonly string[]|null} [opts.labels] - the changelog `labels`, in
|
|
102
|
+
* display order, or `null`/absent when the repository declares none, in
|
|
103
|
+
* which case only {@link MISCELLANEOUS} is accepted.
|
|
104
104
|
* @returns {{findings: Array<{line?: number, column?: number,
|
|
105
105
|
* severity: "error"|"warning", message: string}>}}
|
|
106
106
|
*/
|
|
@@ -135,6 +135,11 @@ export function releaseSectionRange(text: string): {
|
|
|
135
135
|
start: number;
|
|
136
136
|
end: number;
|
|
137
137
|
} | null;
|
|
138
|
+
/**
|
|
139
|
+
* The label every repository may use without declaring it, for the changes
|
|
140
|
+
* that fit no declared label. `changelog group` writes it last.
|
|
141
|
+
*/
|
|
142
|
+
export const MISCELLANEOUS: "Miscellaneous";
|
|
138
143
|
/**
|
|
139
144
|
* The finding one rule reports, before its line is mapped into the caller's
|
|
140
145
|
* file.
|
|
@@ -32,30 +32,30 @@ export function noteAddress(frontmatter: Record<string, any>, contentPackage: st
|
|
|
32
32
|
canonical: string;
|
|
33
33
|
} | null;
|
|
34
34
|
/**
|
|
35
|
-
* A note's
|
|
35
|
+
* A note's listed name forms reduced to printable 7-bit ASCII, by language.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* A listed form is a name a reader is at least as likely to reach for as the
|
|
38
|
+
* full one — `Killer Whale` for an orca, a people's own name for the people —
|
|
39
|
+
* so anything searching or completing over the index has to match them too,
|
|
40
|
+
* and needs the same keyboard-typeable form {@link asciiName} gives the full
|
|
41
|
+
* name.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
* came from.
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* Each language keeps its authored order, so a caller can pair an entry with
|
|
44
|
+
* the form it came from. A form that leaves nothing printable behind is
|
|
45
|
+
* dropped rather than left as a hole, and a language left with no form is
|
|
46
|
+
* left out.
|
|
47
47
|
*
|
|
48
|
-
* @param {unknown}
|
|
49
|
-
* @returns {
|
|
50
|
-
* has an empty
|
|
51
|
-
*
|
|
48
|
+
* @param {unknown} name - The note's `name`; may be absent or null.
|
|
49
|
+
* @returns {Record<string, string[]>} Possibly empty, never null: a note
|
|
50
|
+
* listing no form has an empty map, which a consumer iterating it need not
|
|
51
|
+
* check first.
|
|
52
52
|
*/
|
|
53
|
-
export function
|
|
53
|
+
export function asciiForms(name: unknown): Record<string, string[]>;
|
|
54
54
|
/**
|
|
55
55
|
* Build one index record from a note's frontmatter and its place in the tree.
|
|
56
56
|
*
|
|
57
57
|
* The frontmatter as authored, plus what the index derives from it: the package
|
|
58
|
-
* it compiles as, its address, ASCII folds of its name and
|
|
58
|
+
* it compiles as, its address, ASCII folds of its name and listed forms, the anchors
|
|
59
59
|
* of its body, its Foundry block, the address of its documentation journal, and
|
|
60
60
|
* where the file sits within the tree.
|
|
61
61
|
*
|
|
@@ -130,7 +130,7 @@ export function positionInBody(body: string, offset: number, { bodyLine, bodyCol
|
|
|
130
130
|
* @param {string} raw - The file's full contents, frontmatter included.
|
|
131
131
|
* @param {string} key - The top-level frontmatter key.
|
|
132
132
|
* @param {string} [value] - When given, prefer the occurrence whose line also
|
|
133
|
-
* carries this text. A list-valued key (`
|
|
133
|
+
* carries this text. A list-valued key (`tags`) is reported at the entry
|
|
134
134
|
* that is wrong, not at the key that introduces it.
|
|
135
135
|
* @param {object} [options] - Options.
|
|
136
136
|
* @param {boolean} [options.topLevel=false] - Require the key at column 1, so
|
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* A use of a name in a page's prose.
|
|
3
|
+
*
|
|
4
|
+
* @typedef {object} NameUse
|
|
5
|
+
* @property {number} start - Inclusive UTF-16 offset of the use.
|
|
6
|
+
* @property {number} end - Exclusive UTF-16 offset after it, attributes included.
|
|
7
|
+
* @property {string} key - What the use is counted under.
|
|
8
|
+
* @property {boolean} emphasised - It sits inside authored strong text.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Every use of a name in a body's prose, in source order.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} markdown - A body, as authored or expanded.
|
|
14
|
+
* @param {NameVocabulary} [vocabulary] - What its addresses are read against.
|
|
15
|
+
* @returns {NameUse[]} The uses that count toward a first use.
|
|
16
|
+
*/
|
|
17
|
+
export function nameUses(markdown: string, vocabulary?: NameVocabulary): NameUse[];
|
|
18
|
+
/**
|
|
19
|
+
* Mark the first use of each name in a body's prose as bold.
|
|
20
|
+
*
|
|
21
|
+
* Each first use is wrapped in {@link FIRST_USE_OPEN} and
|
|
22
|
+
* {@link FIRST_USE_CLOSE}, which {@link firstUsePlugin} renders as strong
|
|
23
|
+
* text. A first use already inside authored strong text is left as it is.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} markdown - A body's prose, with its generated sections split
|
|
26
|
+
* off and its wikilinks not yet resolved.
|
|
27
|
+
* @param {NameVocabulary} [vocabulary] - What its addresses are read against.
|
|
28
|
+
* @returns {string} The same markdown with each first use marked.
|
|
29
|
+
*/
|
|
30
|
+
export function boldFirstUses(markdown: string, vocabulary?: NameVocabulary): string;
|
|
31
|
+
/**
|
|
32
|
+
* Render the first-use marks {@link boldFirstUses} wrote as strong text.
|
|
33
|
+
*
|
|
34
|
+
* A mark in inline text opens or closes a `strong`; a mark anywhere else, as in
|
|
35
|
+
* raw HTML or code, is dropped, so no mark reaches a reader.
|
|
36
|
+
*
|
|
37
|
+
* @param {import("markdown-it")} md - Markdown parser to extend.
|
|
38
|
+
*/
|
|
39
|
+
export function firstUsePlugin(md: typeof import("markdown-it")): void;
|
|
40
|
+
/**
|
|
41
|
+
* Prepare indexed names once, then check each note's marked names without
|
|
42
|
+
* reading files.
|
|
43
|
+
*
|
|
44
|
+
* One rule, a warning at the occurrence:
|
|
45
|
+
*
|
|
46
|
+
* - `unlinked-name`: a `.name` span with no `ref` names an indexed note, which
|
|
47
|
+
* a link or a `ref` ties to its note.
|
|
48
|
+
*
|
|
3
49
|
* @param {{records: readonly object[], index: object,
|
|
4
50
|
* catalog?: import("./names.mjs").NameCatalog,
|
|
5
51
|
* parsed?: Map<string, {raw: string, body: string, bodyLine?: number, bodyColumn?: number}>,
|
|
@@ -29,3 +75,53 @@ export function createFirstUseChecker({ records, index, parsed, syntax, catalog,
|
|
|
29
75
|
rules: string[];
|
|
30
76
|
message: string;
|
|
31
77
|
}>;
|
|
78
|
+
/**
|
|
79
|
+
* Opens a first use in expanded markdown: a Unicode noncharacter, which no
|
|
80
|
+
* authored text, font or encoding uses.
|
|
81
|
+
*/
|
|
82
|
+
export const FIRST_USE_OPEN: "\uFDD0";
|
|
83
|
+
/** Closes a first use in expanded markdown. */
|
|
84
|
+
export const FIRST_USE_CLOSE: "\uFDD1";
|
|
85
|
+
/**
|
|
86
|
+
* The addresses a page's names are read against: the tree's types and
|
|
87
|
+
* packages, and the package an address that names none belongs to.
|
|
88
|
+
*/
|
|
89
|
+
export type NameVocabulary = {
|
|
90
|
+
/**
|
|
91
|
+
* - Every type an address may name.
|
|
92
|
+
*/
|
|
93
|
+
types?: Set<string> | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* - Every package an address may name.
|
|
96
|
+
*/
|
|
97
|
+
packages?: Set<string> | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* - Packages with no content index.
|
|
100
|
+
*/
|
|
101
|
+
noIndexPackages?: Set<string> | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* - The package the page belongs to.
|
|
104
|
+
*/
|
|
105
|
+
contentPackage?: string | undefined;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* A use of a name in a page's prose.
|
|
109
|
+
*/
|
|
110
|
+
export type NameUse = {
|
|
111
|
+
/**
|
|
112
|
+
* - Inclusive UTF-16 offset of the use.
|
|
113
|
+
*/
|
|
114
|
+
start: number;
|
|
115
|
+
/**
|
|
116
|
+
* - Exclusive UTF-16 offset after it, attributes included.
|
|
117
|
+
*/
|
|
118
|
+
end: number;
|
|
119
|
+
/**
|
|
120
|
+
* - What the use is counted under.
|
|
121
|
+
*/
|
|
122
|
+
key: string;
|
|
123
|
+
/**
|
|
124
|
+
* - It sits inside authored strong text.
|
|
125
|
+
*/
|
|
126
|
+
emphasised: boolean;
|
|
127
|
+
};
|
|
@@ -54,13 +54,16 @@ export function systemAddressFindings(note: object, { index, schemas, systems }?
|
|
|
54
54
|
* configuration through {@link systemBlocksFor}, and this module states no
|
|
55
55
|
* system name of its own. See {@link DEFAULT_SYSTEM_BLOCKS} for the fallback.
|
|
56
56
|
* @param {object} [opts.addressContext] - Builder package and Address type vocabulary.
|
|
57
|
+
* @param {Iterable<string>} [opts.languages] - The language codes the
|
|
58
|
+
* configuration's `languages:` declares. A `name` key that is one of them, or
|
|
59
|
+
* `en`, is a list of forms; absent, only `en` is.
|
|
57
60
|
* @param {readonly string[]} [opts.packs] - The pack names this package
|
|
58
61
|
* declares, for a `data:` field whose map is keyed by pack. Supplied by the
|
|
59
62
|
* caller like `schemas` and `vocabulary`, and absent it no claim is made
|
|
60
63
|
* about those keys.
|
|
61
64
|
* @returns {object[]} Findings, each with a locator where one is obtainable.
|
|
62
65
|
*/
|
|
63
|
-
export function lintNote(note: object, { schemas, index, currentDate, vocabulary, packs, emittedArt, addressContext, systems, }: {
|
|
66
|
+
export function lintNote(note: object, { schemas, index, currentDate, vocabulary, packs, emittedArt, addressContext, languages, systems, }: {
|
|
64
67
|
schemas: Record<string, readonly object[]>;
|
|
65
68
|
currentDate?: string | undefined;
|
|
66
69
|
index?: object | undefined;
|
|
@@ -71,6 +74,7 @@ export function lintNote(note: object, { schemas, index, currentDate, vocabulary
|
|
|
71
74
|
} | null) | undefined;
|
|
72
75
|
systems?: Readonly<Record<string, SystemBlockSpec>> | undefined;
|
|
73
76
|
addressContext?: object | undefined;
|
|
77
|
+
languages?: Iterable<string> | undefined;
|
|
74
78
|
packs?: readonly string[] | undefined;
|
|
75
79
|
}): object[];
|
|
76
80
|
/**
|
|
@@ -86,6 +90,8 @@ export function lintNote(note: object, { schemas, index, currentDate, vocabulary
|
|
|
86
90
|
* @param {Readonly<Record<string, SystemBlockSpec>>} [opts.systems]
|
|
87
91
|
* The system blocks to check; see {@link lintNote} and
|
|
88
92
|
* {@link systemBlocksFor}.
|
|
93
|
+
* @param {Iterable<string>} [opts.languages] - The configured language codes,
|
|
94
|
+
* which a note's `name` lists its forms under; see {@link lintNote}.
|
|
89
95
|
* @param {readonly string[]} [opts.packs] - The declared pack names; see
|
|
90
96
|
* {@link lintNote}.
|
|
91
97
|
* @param {(type: string) => {document: string|null, art: readonly string[]}|null} [opts.emittedArt]
|
|
@@ -93,12 +99,13 @@ export function lintNote(note: object, { schemas, index, currentDate, vocabulary
|
|
|
93
99
|
* @returns {{findings: object[], notes: number}} The findings, and how many
|
|
94
100
|
* notes were inspected.
|
|
95
101
|
*/
|
|
96
|
-
export function lintFrontmatter(index: object, { schemas, vocabulary, packs, emittedArt, references, systems, currentDate }: {
|
|
102
|
+
export function lintFrontmatter(index: object, { schemas, vocabulary, packs, emittedArt, references, systems, currentDate, languages }: {
|
|
97
103
|
schemas: Record<string, readonly object[]>;
|
|
98
104
|
currentDate?: string | undefined;
|
|
99
105
|
vocabulary?: Record<string, object> | undefined;
|
|
100
106
|
references?: boolean | undefined;
|
|
101
107
|
systems?: Readonly<Record<string, SystemBlockSpec>> | undefined;
|
|
108
|
+
languages?: Iterable<string> | undefined;
|
|
102
109
|
packs?: readonly string[] | undefined;
|
|
103
110
|
emittedArt?: ((type: string) => {
|
|
104
111
|
document: string | null;
|
|
@@ -5,10 +5,17 @@
|
|
|
5
5
|
* @property {(value: unknown, type: string) => string|undefined} keyOf - A
|
|
6
6
|
* value's canonical Address in the `note` system, read with `type` as the
|
|
7
7
|
* default type, or `undefined` where it is no Address.
|
|
8
|
-
* @property {(
|
|
9
|
-
*
|
|
8
|
+
* @property {(code: string) => string|undefined} noteOf - The Address of a
|
|
9
|
+
* language code's note, or `undefined` where no note is configured for it.
|
|
10
10
|
* @property {string} [self] - The owning note's own Address, for a language.
|
|
11
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* The language a note is in, as the content index derived it.
|
|
14
|
+
*
|
|
15
|
+
* @param {object} note - An index record, or a link-index note carrying it.
|
|
16
|
+
* @returns {string|undefined} The code.
|
|
17
|
+
*/
|
|
18
|
+
export function noteLang(note: object): string | undefined;
|
|
12
19
|
/**
|
|
13
20
|
* The language a glossary entry resolves to.
|
|
14
21
|
*
|
|
@@ -19,7 +26,7 @@
|
|
|
19
26
|
* @returns {string|undefined} The language's Address, or `undefined` where the
|
|
20
27
|
* chain finds none.
|
|
21
28
|
*/
|
|
22
|
-
export function glossaryLanguage(entry: object | undefined, owner: object, { keyOf,
|
|
29
|
+
export function glossaryLanguage(entry: object | undefined, owner: object, { keyOf, noteOf, self }: GlossaryLanguageReader): string | undefined;
|
|
23
30
|
/**
|
|
24
31
|
* How a caller reads Addresses and finds notes.
|
|
25
32
|
*/
|
|
@@ -31,10 +38,10 @@ export type GlossaryLanguageReader = {
|
|
|
31
38
|
*/
|
|
32
39
|
keyOf: (value: unknown, type: string) => string | undefined;
|
|
33
40
|
/**
|
|
34
|
-
* - The
|
|
35
|
-
*
|
|
41
|
+
* - The Address of a
|
|
42
|
+
* language code's note, or `undefined` where no note is configured for it.
|
|
36
43
|
*/
|
|
37
|
-
|
|
44
|
+
noteOf: (code: string) => string | undefined;
|
|
38
45
|
/**
|
|
39
46
|
* - The owning note's own Address, for a language.
|
|
40
47
|
*/
|
|
@@ -140,9 +140,6 @@ export function homepageTitle(fm: object | null | undefined, config: object): st
|
|
|
140
140
|
* **No `url` and no `slug`.** The homepage publishes at the package root, so
|
|
141
141
|
* the page has no address to state.
|
|
142
142
|
*
|
|
143
|
-
* An authored `aliases` is dropped, as it is on every other page: this build
|
|
144
|
-
* emits no redirects.
|
|
145
|
-
*
|
|
146
143
|
* `related` is derived like every other page's — what links to the homepage
|
|
147
144
|
* is a fact about the rest of the tree — so an authored value is dropped and
|
|
148
145
|
* the caller's block, where it has one, is set in its place.
|
|
@@ -104,6 +104,8 @@ export function drawName(names: object, gender: string, next: () => number): str
|
|
|
104
104
|
export function nameMisfit(full: string, names: object, gender: string): string | undefined;
|
|
105
105
|
/** The `skill` subType whose notes may carry name lists. */
|
|
106
106
|
export const NAMES_SUBTYPE: "language";
|
|
107
|
+
/** The key whose groups of lists hold English names. */
|
|
108
|
+
export const ENGLISH_GROUP: "en";
|
|
107
109
|
/** The placeholder that draws from the given-name list for a gender. */
|
|
108
110
|
export const GIVEN_LIST: "given";
|
|
109
111
|
/**
|
|
@@ -115,6 +117,7 @@ export type PatternPart = {
|
|
|
115
117
|
} | {
|
|
116
118
|
list: string;
|
|
117
119
|
gender?: string;
|
|
120
|
+
sub?: string;
|
|
118
121
|
};
|
|
119
122
|
/**
|
|
120
123
|
* One thing wrong with a language's name lists.
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `language`.
|
|
4
|
-
*
|
|
5
|
-
* An Address that does not resolve is the reference check's to report, so
|
|
6
|
-
* this speaks only about a target that exists and is the wrong kind.
|
|
7
|
-
*
|
|
8
|
-
* @param {object} note
|
|
9
|
-
* @param {{index?: object}} [options]
|
|
10
|
-
* @returns {object[]} The findings.
|
|
11
|
-
*/
|
|
12
|
-
export function checkLanguageChoice(note: object, { index }?: {
|
|
13
|
-
index?: object;
|
|
14
|
-
}): object[];
|
|
15
|
-
/**
|
|
16
|
-
* Refuse a literature field on a lore note of any other subType, and
|
|
17
|
-
* `data.language` on a lore note that is neither a work nor a culture.
|
|
2
|
+
* Refuse a literature field on a lore note of any other subType.
|
|
18
3
|
*
|
|
19
4
|
* @param {object} note
|
|
20
5
|
* @returns {object[]} One error per key written off the subTypes that take it.
|
|
@@ -22,18 +7,8 @@ export function checkLanguageChoice(note: object, { index }?: {
|
|
|
22
7
|
export function checkLiteratureNote(note: object): object[];
|
|
23
8
|
/** The `lore` subType whose notes are works of literature. */
|
|
24
9
|
export const LITERATURE_SUBTYPE: "literature";
|
|
25
|
-
/** The `lore` subTypes that may name a language. */
|
|
26
|
-
export const LANGUAGE_SUBTYPES: readonly string[];
|
|
27
|
-
/**
|
|
28
|
-
* `data.language`: the tongue a work is composed in, the tongue a culture's
|
|
29
|
-
* people speak, or the tongue an affiliation keeps. Optional on all three.
|
|
30
|
-
*
|
|
31
|
-
* @type {object}
|
|
32
|
-
*/
|
|
33
|
-
export const LANGUAGE_FIELD: object;
|
|
34
10
|
/**
|
|
35
|
-
* The fields only a `literature` note may state
|
|
36
|
-
* {@link LANGUAGE_FIELD}. Every one is optional.
|
|
11
|
+
* The fields only a `literature` note may state. Every one is optional.
|
|
37
12
|
*
|
|
38
13
|
* @type {ReadonlyArray<object>}
|
|
39
14
|
*/
|