@heroiclands/package-build 25.1.3 → 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 +29 -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/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 +299 -185
- package/docs/reference/note-types.md +16 -17
- 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/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 +3 -2
- 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 +13 -11
- 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/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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 25.2.0
|
|
4
|
+
|
|
5
|
+
**Content and notes**
|
|
6
|
+
|
|
7
|
+
- A note lists its other names under the code of their language, beside the English `full`: `name: {full: Johnathan Lewis, en: [John], vyla: [juan juis]}`.
|
|
8
|
+
- A note states its language as `data.lang`, a code `languages:` declares or `en`; a note that states none takes its culture's, then its parents', then `en`.
|
|
9
|
+
- A culture that states no language, and inherits none from a parent culture, is an error wherever a note names it.
|
|
10
|
+
- Names match whatever their case, so `[arden vale]{.name}` names the note _Arden Vale_.
|
|
11
|
+
- A `.name` span can carry `ref=` to tie each spelling of a person, place or thing to its note without linking it: `[Tom]{.name ref=being-tomr}`.
|
|
12
|
+
- A `ref` may be a page-local key such as `ref="#jane"` for a subject with no note, and a `ref` that matches no note is an error.
|
|
13
|
+
|
|
14
|
+
**Rendering and sites**
|
|
15
|
+
|
|
16
|
+
- The first use of each name in a page is bold on the website, in Foundry journals and in the book, and its later uses are plain text.
|
|
17
|
+
- Every spelling tied by one `ref`, every link to one note and every case of one label count as one name.
|
|
18
|
+
- A wikilink counts as a name when it carries `.name`, such as `[[place-harbor|the harbor]]{.name}`; names in headings, tables, captions and other-language runs take no bold.
|
|
19
|
+
|
|
20
|
+
**Builds and commands**
|
|
21
|
+
|
|
22
|
+
- `changelog check` now refuses a changeset that is not labelled blocks of bullets: a lead paragraph, an unlabelled bullet, prose between blocks and a label that is not declared are errors.
|
|
23
|
+
- A label must be in `labels` or be `Miscellaneous`, which every repository has and never declares; with no list declared, only `Miscellaneous` is accepted.
|
|
24
|
+
- `changelog check --release` holds a Version Packages section to the same shape.
|
|
25
|
+
- `changelog group` removes the `### … Changes` headings, merges blocks that share a label, orders them as `labels` declares and lists `Miscellaneous` last.
|
|
26
|
+
|
|
27
|
+
**Upgrading**
|
|
28
|
+
|
|
29
|
+
- Declare `labels` in the changelog options of `.changeset/config.json`, and rewrite pending changesets as labelled blocks of bullets before upgrading.
|
|
30
|
+
- Move each `aliases` entry under its language's code, or `en`, and write `data.lang: <code>` in place of `data.language: skill-…`; both old keys are refused.
|
|
31
|
+
|
|
3
32
|
## 25.1.3
|
|
4
33
|
|
|
5
34
|
**Spelling checks**
|
|
@@ -584,15 +584,6 @@
|
|
|
584
584
|
outline-offset: 2px;
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
-
/*
|
|
588
|
-
* A name the text marks is bold, as on the site, in the preview and in the book.
|
|
589
|
-
* Foundry's interface and a system's sheets use `.name` for their own elements,
|
|
590
|
-
* which the content roots leave untouched.
|
|
591
|
-
*/
|
|
592
|
-
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .name {
|
|
593
|
-
font-weight: var(--pb-name-weight, 700);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
587
|
/*
|
|
597
588
|
* A wikilink whose target no package publishes keeps its text and is marked, so
|
|
598
589
|
* the sentence still reads and a reader can tell a link was meant. Each value
|
package/bin/content-commands.mjs
CHANGED
|
@@ -139,6 +139,7 @@ import { stagePackageBuildAssets } from "../engine/build-assets.mjs";
|
|
|
139
139
|
import { DEPLOYED_ASSET_TYPES } from "../engine/asset-types.mjs";
|
|
140
140
|
import { createContentSession, CONTENT_TARGETS } from "../engine/content-session.mjs";
|
|
141
141
|
import { createFirstUseChecker } from "../engine/first-use.mjs";
|
|
142
|
+
import { createNameRefChecker } from "../engine/name-refs.mjs";
|
|
142
143
|
import { createNameCatalog, createNamesReport, namesReportFinding } from "../engine/names.mjs";
|
|
143
144
|
// The one place a link finding is worded, shared with both builds.
|
|
144
145
|
import { linkFindingMessage } from "../engine/wikilink-syntax.mjs";
|
|
@@ -1037,6 +1038,11 @@ function lintCommand() {
|
|
|
1037
1038
|
syntax: session.syntax,
|
|
1038
1039
|
catalog,
|
|
1039
1040
|
});
|
|
1041
|
+
const nameRefChecker = createNameRefChecker({
|
|
1042
|
+
catalog,
|
|
1043
|
+
parsed: session.parsed,
|
|
1044
|
+
syntax: session.syntax,
|
|
1045
|
+
});
|
|
1040
1046
|
const names = namesReportFinding(
|
|
1041
1047
|
createNamesReport({ package: config.contentPackage, records, catalog }),
|
|
1042
1048
|
{ contentBase: root },
|
|
@@ -1075,6 +1081,8 @@ function lintCommand() {
|
|
|
1075
1081
|
}
|
|
1076
1082
|
const frontmatter = lintFrontmatter(index, {
|
|
1077
1083
|
currentDate: config.currentDate,
|
|
1084
|
+
// The codes a note's `name` lists its forms under.
|
|
1085
|
+
languages: Object.keys(config.languages ?? {}),
|
|
1078
1086
|
schemas: { ...ENGINE_NOTE_SCHEMAS, ...NOTE_SCHEMAS },
|
|
1079
1087
|
// The closed frontmatter regions. Passed in rather
|
|
1080
1088
|
// than reached for, so the linter stays a checker of
|
|
@@ -1300,6 +1308,7 @@ function lintCommand() {
|
|
|
1300
1308
|
...(runs.encodingFindings ?? []),
|
|
1301
1309
|
...languageNoteFindings({ ...config, configFile: packConfigPath() }, records),
|
|
1302
1310
|
...index.notes.flatMap(firstUseChecker),
|
|
1311
|
+
...index.notes.flatMap(nameRefChecker),
|
|
1303
1312
|
...(names ? [names] : []),
|
|
1304
1313
|
...addresses.findings,
|
|
1305
1314
|
...frontmatter.findings,
|
|
@@ -3400,16 +3409,16 @@ function newNpc(config, argv) {
|
|
|
3400
3409
|
throw new Error(`${key}'s appearance profile has ${profileErrors.length} problem(s)`);
|
|
3401
3410
|
}
|
|
3402
3411
|
|
|
3403
|
-
const
|
|
3404
|
-
|
|
3412
|
+
const code = hit.lang;
|
|
3413
|
+
const tongue = typeof code === "string" ? config.languages?.[code]?.note : undefined;
|
|
3414
|
+
if (tongue === undefined)
|
|
3405
3415
|
throw noteError(
|
|
3406
3416
|
cultureNote,
|
|
3407
|
-
["data"],
|
|
3408
|
-
`${key}
|
|
3409
|
-
"
|
|
3417
|
+
Object.hasOwn(culture.data ?? {}, "lang") ? ["data", "lang"] : ["data"],
|
|
3418
|
+
`${key} is in ${code ?? "no language"}, which \`languages:\` names no language ` +
|
|
3419
|
+
"note for, so `npc new` has no name lists to draw from; state the culture's " +
|
|
3420
|
+
"`data.lang` and its language's `note`",
|
|
3410
3421
|
);
|
|
3411
|
-
const languageSource = cultureFieldSource(records, key, "language") ?? hit;
|
|
3412
|
-
const languageSourceNote = located(languageSource);
|
|
3413
3422
|
const tuple = parseAddress(tongue, {
|
|
3414
3423
|
package: index.contentPackage,
|
|
3415
3424
|
system: "note",
|
|
@@ -3420,18 +3429,15 @@ function newNpc(config, argv) {
|
|
|
3420
3429
|
const languageKey = tuple.reason ? undefined : renderAddress(tuple);
|
|
3421
3430
|
const languageHit = languageKey ? index.addressHit(languageKey) : undefined;
|
|
3422
3431
|
if (!languageHit)
|
|
3423
|
-
throw
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
`${key}'s \`data.language\` names no note in this package or its dependencies`,
|
|
3432
|
+
throw new Error(
|
|
3433
|
+
`\`languages.${code}.note\` ${tongue}, ${key}'s language, names no note in this ` +
|
|
3434
|
+
"package or its dependencies",
|
|
3427
3435
|
);
|
|
3428
3436
|
const language = languageHit.fm ?? languageHit;
|
|
3429
3437
|
if (String(language.type ?? languageHit.type) !== "skill" || language.subType !== "language")
|
|
3430
|
-
throw
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
`${key}'s \`data.language\` ${languageKey} is not a language: it names a ` +
|
|
3434
|
-
`${language.type ?? languageHit.type ?? "note"} of subType ` +
|
|
3438
|
+
throw new Error(
|
|
3439
|
+
`\`languages.${code}.note\` ${languageKey}, ${key}'s language, is not a language: ` +
|
|
3440
|
+
`it names a ${language.type ?? languageHit.type ?? "note"} of subType ` +
|
|
3435
3441
|
`${language.subType ?? "none"}`,
|
|
3436
3442
|
);
|
|
3437
3443
|
const languageNote = located(languageHit);
|
package/bin/package-build.mjs
CHANGED
|
@@ -92,7 +92,7 @@ import { emitDiagnostic, formatDiagnostic } from "../engine/diagnostics.mjs";
|
|
|
92
92
|
import { writeSiteRoot } from "../engine/site-root.mjs";
|
|
93
93
|
import { DEPLOY_ROOT } from "../engine/site-config.mjs";
|
|
94
94
|
import { compilesFoundryDocuments, siteBase } from "../content-config.mjs";
|
|
95
|
-
import { loadPackConfig, packConfigPath
|
|
95
|
+
import { loadPackConfig, packConfigPath } from "../engine/pack-config.mjs";
|
|
96
96
|
import { cleanBuildArtifacts, resetStage } from "../stage.mjs";
|
|
97
97
|
import {
|
|
98
98
|
CDN_ENV,
|
|
@@ -115,6 +115,7 @@ import { validateLangSource } from "../lang.mjs";
|
|
|
115
115
|
import { lintYaml } from "../engine/yaml-lint.mjs";
|
|
116
116
|
import { lintChangesetText, lintReleaseText } from "../engine/changelog-lint.mjs";
|
|
117
117
|
import { groupChangelogText } from "../engine/changelog-group.mjs";
|
|
118
|
+
import { readChangelogLabels } from "../engine/changelog-labels.mjs";
|
|
118
119
|
import { bumpDependencies } from "../engine/dependency-bump.mjs";
|
|
119
120
|
import {
|
|
120
121
|
analyzeCoverage,
|
|
@@ -1066,35 +1067,33 @@ function yamlCommand() {
|
|
|
1066
1067
|
}
|
|
1067
1068
|
|
|
1068
1069
|
/**
|
|
1069
|
-
* `changelog check` / `changelog group` —
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
* `check`
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
* changeset; `--release` reads the first `## <version>`
|
|
1076
|
-
* `CHANGELOG.md` instead, for the **Version Packages** branch a
|
|
1077
|
-
* `main` opens.
|
|
1078
|
-
*
|
|
1079
|
-
* `group` rewrites that same first `## <version>` section in place:
|
|
1080
|
-
*
|
|
1081
|
-
* the
|
|
1082
|
-
* `changelog.labels` for the vocabulary and display order, when the
|
|
1083
|
-
* repository declares one.
|
|
1070
|
+
* `changelog check` / `changelog group` — the changeset shape check, and the
|
|
1071
|
+
* final grouping of a release.
|
|
1072
|
+
*
|
|
1073
|
+
* `check` holds a changeset to the house shape — labelled blocks of
|
|
1074
|
+
* bullets, labels from `.changeset/config.json` or `Miscellaneous` — and to the
|
|
1075
|
+
* rules that keep a pull-request description out of a release note. Default
|
|
1076
|
+
* reads every pending changeset; `--release` reads the first `## <version>`
|
|
1077
|
+
* section of `CHANGELOG.md` instead, for the **Version Packages** branch a
|
|
1078
|
+
* merge to `main` opens.
|
|
1079
|
+
*
|
|
1080
|
+
* `group` rewrites that same first `## <version>` section in place: it removes
|
|
1081
|
+
* the `### … Changes` headings, merges blocks sharing a label and orders them
|
|
1082
|
+
* as the labels in `.changeset/config.json` declare, `Miscellaneous` last.
|
|
1084
1083
|
*
|
|
1085
1084
|
* @returns {object} The yargs command module.
|
|
1086
1085
|
*/
|
|
1087
1086
|
function changelogCommand() {
|
|
1088
1087
|
return {
|
|
1089
1088
|
command: "changelog <action> [paths..]",
|
|
1090
|
-
describe: "
|
|
1089
|
+
describe: "Check changesets against the house shape, and group a release's blocks by label",
|
|
1091
1090
|
builder: (y) =>
|
|
1092
1091
|
y
|
|
1093
1092
|
.positional("action", {
|
|
1094
1093
|
choices: ["check", "group"],
|
|
1095
1094
|
describe:
|
|
1096
1095
|
"check: lint pending changesets, or a release section. " +
|
|
1097
|
-
"group:
|
|
1096
|
+
"group: give the newest release its final shape",
|
|
1098
1097
|
})
|
|
1099
1098
|
.positional("paths", {
|
|
1100
1099
|
describe:
|
|
@@ -1135,17 +1134,17 @@ function changelogFiles(args) {
|
|
|
1135
1134
|
}
|
|
1136
1135
|
|
|
1137
1136
|
/**
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
* `package-build.config.yaml` at all, exactly as `check` already does for
|
|
1141
|
-
* pending changesets with no configuration to read.
|
|
1137
|
+
* The labels in `.changeset/config.json`, or `null` when it declares none.
|
|
1138
|
+
* An invalid declaration stops the command.
|
|
1142
1139
|
*
|
|
1143
1140
|
* @returns {readonly string[]|null}
|
|
1144
1141
|
*/
|
|
1145
1142
|
function loadChangelogLabels() {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1143
|
+
try {
|
|
1144
|
+
return readChangelogLabels();
|
|
1145
|
+
} catch (error) {
|
|
1146
|
+
return die(`changelog: ${error.message}`);
|
|
1147
|
+
}
|
|
1149
1148
|
}
|
|
1150
1149
|
|
|
1151
1150
|
/**
|
package/content-config.mjs
CHANGED
|
@@ -71,6 +71,7 @@ import { normalizeCurrentDate } from "./engine/current-date.mjs";
|
|
|
71
71
|
// a cycle around a consumer's config file (see `engine/pack-config.mjs`).
|
|
72
72
|
import { ADDRESS_SEGMENT_PATTERN, isAddressSegment } from "./engine/address-charset.mjs";
|
|
73
73
|
import { isLanguageTag } from "./engine/language-tag.mjs";
|
|
74
|
+
import { NAME_STRING_KEYS } from "./engine/name-forms.mjs";
|
|
74
75
|
import { ASSET_TYPE_NAMES, shippingLicensesProblem } from "./engine/asset-types.mjs";
|
|
75
76
|
import { isReservedPackage } from "./engine/packages.mjs";
|
|
76
77
|
import { EMPTY_ICON_REGISTRY, checkIconRegistry } from "./engine/content-icons.mjs";
|
|
@@ -764,12 +765,10 @@ const CONFIG_KEYS = [
|
|
|
764
765
|
"requiresSystem",
|
|
765
766
|
"packageBuild",
|
|
766
767
|
"publish",
|
|
767
|
-
"changelog",
|
|
768
768
|
];
|
|
769
769
|
const SYSTEM_KEYS = ["manifest", "compatibility"];
|
|
770
770
|
const COMPATIBILITY_KEYS = ["minimum", "verified"];
|
|
771
771
|
const DOCS_KEYS = ["itemFields"];
|
|
772
|
-
const CHANGELOG_KEYS = ["labels"];
|
|
773
772
|
const SITE_KEYS = [
|
|
774
773
|
"base",
|
|
775
774
|
"title",
|
|
@@ -983,6 +982,12 @@ function normalizeLanguages(value) {
|
|
|
983
982
|
"is not a name: a name is lowercase letters, digits and single hyphens, " +
|
|
984
983
|
"starting with a letter",
|
|
985
984
|
);
|
|
985
|
+
if (NAME_STRING_KEYS.includes(name))
|
|
986
|
+
fail(
|
|
987
|
+
where,
|
|
988
|
+
`is a \`name\` key that holds a single string (${NAME_STRING_KEYS.join(", ")}), ` +
|
|
989
|
+
"so a note's forms cannot be listed under it; choose another name",
|
|
990
|
+
);
|
|
986
991
|
if (!isPlainObject(entry)) fail(where, "must be a mapping with `tag`");
|
|
987
992
|
rejectUnknownKeys(entry, ["tag", "note"], `${where}.`);
|
|
988
993
|
const { tag, note } = /** @type {Record<string, unknown>} */ (entry);
|
|
@@ -1627,37 +1632,6 @@ function normalizeDocs(value) {
|
|
|
1627
1632
|
});
|
|
1628
1633
|
}
|
|
1629
1634
|
|
|
1630
|
-
/**
|
|
1631
|
-
* `changelog.labels` — the vocabulary and display order `changelog check`
|
|
1632
|
-
* and `changelog group` read a release block's bold label against.
|
|
1633
|
-
*
|
|
1634
|
-
* Optional: a repository that groups nothing declares none, and `group`
|
|
1635
|
-
* falls back to ordering every label by first appearance. Declared, it is a
|
|
1636
|
-
* list of non-empty strings with no duplicate — a repeated label could never
|
|
1637
|
-
* be told apart from a genuine drift (`Compendiums` twice would silently
|
|
1638
|
-
* swallow the `Character data` beside `Characters` the list exists to catch).
|
|
1639
|
-
*
|
|
1640
|
-
* @param {unknown} value - The configured value, or `undefined`.
|
|
1641
|
-
* @returns {Readonly<{labels: readonly string[]|null}>}
|
|
1642
|
-
*/
|
|
1643
|
-
function normalizeChangelog(value) {
|
|
1644
|
-
if (value === undefined) return Object.freeze({ labels: null });
|
|
1645
|
-
if (!isPlainObject(value)) fail("changelog", "must be a mapping");
|
|
1646
|
-
const input = /** @type {Record<string, unknown>} */ (value);
|
|
1647
|
-
rejectUnknownKeys(input, CHANGELOG_KEYS, "changelog.");
|
|
1648
|
-
if (input.labels === undefined) return Object.freeze({ labels: null });
|
|
1649
|
-
if (!Array.isArray(input.labels)) fail("changelog.labels", "must be an array");
|
|
1650
|
-
const labels = input.labels.map((label, index) =>
|
|
1651
|
-
requireNonEmptyString(label, `changelog.labels[${index}]`),
|
|
1652
|
-
);
|
|
1653
|
-
const seen = new Set();
|
|
1654
|
-
for (const label of labels) {
|
|
1655
|
-
if (seen.has(label)) fail("changelog.labels", `declares \`${label}\` more than once`);
|
|
1656
|
-
seen.add(label);
|
|
1657
|
-
}
|
|
1658
|
-
return Object.freeze({ labels: Object.freeze(labels) });
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
1635
|
/**
|
|
1662
1636
|
* The asset host the website resolves a pathname against.
|
|
1663
1637
|
*
|
|
@@ -3228,6 +3202,5 @@ export function defineConfig(config) {
|
|
|
3228
3202
|
requiresSystem,
|
|
3229
3203
|
packageBuild: normalizePackageBuild(input.packageBuild),
|
|
3230
3204
|
publish: normalizePublish(input.publish),
|
|
3231
|
-
changelog: normalizeChangelog(input.changelog),
|
|
3232
3205
|
});
|
|
3233
3206
|
}
|
package/docs/api.md
CHANGED
|
@@ -989,24 +989,40 @@ content and asset scopes preserve their own filtering and order.
|
|
|
989
989
|
|
|
990
990
|
Import from `@heroiclands/package-build/engine/first-use`.
|
|
991
991
|
|
|
992
|
-
| Export | Signature | Returns | Use it when
|
|
993
|
-
| ----------------------- | ----------------------------------------------------------------------- | ------------------------ |
|
|
994
|
-
| `
|
|
992
|
+
| Export | Signature | Returns | Use it when |
|
|
993
|
+
| ----------------------- | ----------------------------------------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------- |
|
|
994
|
+
| `nameUses` | `nameUses(markdown, vocabulary?)` | `NameUse[]` | Listing the uses of names a body's prose makes, each with the key it counts under. |
|
|
995
|
+
| `boldFirstUses` | `boldFirstUses(markdown, vocabulary?)` | `string` | Marking the first use of each key in a body's prose before a target renders it. |
|
|
996
|
+
| `firstUsePlugin` | `md.use(firstUsePlugin)` | — | Rendering the marks as strong text in a markdown-it parser. |
|
|
997
|
+
| `FIRST_USE_OPEN` | constant | `"\uFDD0"` | Recognizing where a first use opens in expanded markdown. |
|
|
998
|
+
| `FIRST_USE_CLOSE` | constant | `"\uFDD1"` | Recognizing where a first use closes in expanded markdown. |
|
|
999
|
+
| `createFirstUseChecker` | `createFirstUseChecker({ records, index, catalog?, parsed?, syntax? })` | `checker({ file, raw })` | Checking a note's marked names against the index. |
|
|
1000
|
+
|
|
1001
|
+
A `NameUse` is `{start, end, key, emphasised}`: the use's UTF-16 range in the
|
|
1002
|
+
markdown, the key it counts under, and whether it sits inside authored strong
|
|
1003
|
+
text. The key is a name wikilink's address, a span's `ref`, or the span's
|
|
1004
|
+
case-folded label with its `lang`. `vocabulary` is `{types, packages,
|
|
1005
|
+
noIndexPackages, contentPackage}`, which reads every spelling of an address as
|
|
1006
|
+
one note; without it an address is keyed as written. Only prose counts:
|
|
1007
|
+
headings, tables, captions, raw HTML, code, verse and runs that state `lang`,
|
|
1008
|
+
`font` or `enc` neither take the bold nor count. `boldFirstUses` wraps each
|
|
1009
|
+
first use in the two marks, except one already inside authored strong text,
|
|
1010
|
+
and `firstUsePlugin` turns each mark in inline text into a `strong` token and
|
|
1011
|
+
drops a mark anywhere else. `expandContent` runs `boldFirstUses` on the
|
|
1012
|
+
author's prose for every target, and `createRenderer` installs the plugin on
|
|
1013
|
+
every target.
|
|
995
1014
|
|
|
996
1015
|
Construct one checker with the session's read-only `records` and
|
|
997
1016
|
`await session.audit("lint")`. Call it for each existing link-index note.
|
|
998
1017
|
It performs no I/O and returns `{file, line, column, severity: "warning",
|
|
999
|
-
rules, message}` diagnostics. `rules` is a list of applicable rule names,
|
|
1000
|
-
into one warning for each occurrence
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
Local and captured dependency names and aliases share the same corpus
|
|
1005
|
-
context. The command's lint target constructs
|
|
1006
|
-
the checker once, uses exact authored `raw` strings and keeps these findings
|
|
1018
|
+
rules, message}` diagnostics. `rules` is a list of applicable rule names,
|
|
1019
|
+
merged into one warning for each occurrence: `unlinked-name` for a `.name`
|
|
1020
|
+
span without `ref` whose label is an indexed full name or listed form. Plain
|
|
1021
|
+
text is not searched. The command's lint target constructs the
|
|
1022
|
+
checker once, uses exact authored `raw` strings and keeps these findings
|
|
1007
1023
|
advisory. See the [authoring conventions](authoring/links-and-markup.md#marking-names-in-prose).
|
|
1008
1024
|
|
|
1009
|
-
Supply the invocation's `catalog` to share its full-name and
|
|
1025
|
+
Supply the invocation's `catalog` to share its full-name and form lookup with
|
|
1010
1026
|
the package names report. Optional `parsed` maps absolute files to captured
|
|
1011
1027
|
`{raw, body, bodyLine?, bodyColumn?}`; `syntax` is the session's scanner
|
|
1012
1028
|
projection. When the captured raw text matches, the checker rebases the body's
|
|
@@ -1050,7 +1066,7 @@ Import from `@heroiclands/package-build/engine/name-rows`.
|
|
|
1050
1066
|
|
|
1051
1067
|
| Export | Signature | Returns | Use it when |
|
|
1052
1068
|
| -------------- | -------------------- | --------------------------- | ---------------------------------------------------------------------- |
|
|
1053
|
-
| `NAME_COLUMNS` | `const NAME_COLUMNS` | Frozen ordered column names | Reading `owner`, `name`, `type`, `subType`, `line`, `column`.
|
|
1069
|
+
| `NAME_COLUMNS` | `const NAME_COLUMNS` | Frozen ordered column names | Reading `owner`, `name`, `type`, `subType`, `ref`, `line`, `column`. |
|
|
1054
1070
|
| `namesRows` | `namesRows(records)` | `NameRow[]` | Projecting own-note occurrences into SQL rows without I/O or mutation. |
|
|
1055
1071
|
|
|
1056
1072
|
Rows preserve record and occurrence order. `owner` is the canonical NOTE page
|
|
@@ -1067,7 +1083,8 @@ Import from `@heroiclands/package-build/engine/names`.
|
|
|
1067
1083
|
|
|
1068
1084
|
| Export | Signature | Returns | Use it when |
|
|
1069
1085
|
| ----------------------- | -------------------------------------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
1070
|
-
| `normalizeName` | `normalizeName(text)` | `string` | Normalizing NFC, apostrophes and whitespace
|
|
1086
|
+
| `normalizeName` | `normalizeName(text)` | `string` | Normalizing NFC, apostrophes and whitespace and folding case, as names are matched. |
|
|
1087
|
+
| `displayName` | `displayName(text)` | `string` | Normalizing NFC, apostrophes and whitespace while keeping case, as names are displayed. |
|
|
1071
1088
|
| `nameForms` | `nameForms(text)` | `string[]` | Enumerating supported whole-label possessives and regular plurals. |
|
|
1072
1089
|
| `createNameCatalog` | `createNameCatalog({ records, index })` | `NameCatalog` | Sharing indexed full-name, alias and resolved Address matching across checks. |
|
|
1073
1090
|
| `collectUnwrittenNames` | `collectUnwrittenNames({ records, catalog })` | `{groups, firstUse}` | Grouping every unresolved captured occurrence by supplied classification. |
|
|
@@ -1102,8 +1119,8 @@ at the earliest reported actual use, and returns no warning for an empty report.
|
|
|
1102
1119
|
Collecting and publishing this package's content index. Records describe note frontmatter, assets, prose and event anchors, and the document targets those notes produce. Dynamic publication prepares the same generated Markdown and scalar expressions as the rendering surfaces, using each source note's audience.
|
|
1103
1120
|
|
|
1104
1121
|
Own-note records carry derived `names` entries in source order as
|
|
1105
|
-
`{name, type, subType, line, column}`. Missing classifications
|
|
1106
|
-
`null`; no occurrences gives `[]`. Positions refer to original authored span
|
|
1122
|
+
`{name, type, subType, ref, line, column}`. Missing classifications and an
|
|
1123
|
+
absent `ref` are explicit `null`; no occurrences gives `[]`. Positions refer to original authored span
|
|
1107
1124
|
openings, before generated content. Metadata JSONL transports these entries
|
|
1108
1125
|
to dependency SQL without an additional artifact. This field is reserved for
|
|
1109
1126
|
derived data, and is not an authored frontmatter key.
|
|
@@ -1120,7 +1137,7 @@ configuration's `itemTypes`.
|
|
|
1120
1137
|
| `noteAddress` | `function noteAddress(frontmatter, contentPackage)` | {{slug: string, canonical: string}\|null} `slug` is what goes inside `[[…]]` within this package; `canonical` is the fully qualified key the manifest files the note under, carrying the package and the system as well. | The address a wikilink writes to reach a note, or `null` when it has none. |
|
|
1121
1138
|
| `sortKeysDeep` | `function sortKeysDeep(value)` | {unknown} The value with every plain object's keys in sorted order. | Recursively sort an object's keys, so serialization is order-independent. |
|
|
1122
1139
|
| `asciiName` | `function asciiName(name)` | {string\|null} The ASCII form, or `null` when there is no name, or nothing printable survives. | A note's display name reduced to printable 7-bit ASCII. |
|
|
1123
|
-
| `
|
|
1140
|
+
| `asciiForms` | `function asciiForms(name)` | {Record<string, string[]>} Possibly empty, never null: a note listing no form has an empty map, which a consumer iterating it need not check first. | A note's listed name forms reduced to printable 7-bit ASCII, by language. |
|
|
1124
1141
|
| `serializeContentIndex` | `function serializeContentIndex(records)` | {string} One compact JSON object per line, newline-terminated. | Serialize records as JSON Lines. |
|
|
1125
1142
|
| `indexRecordsFor` | `indexRecordsFor({ contentBase, config, skipDirectories, problems, parsed, sources, syntax, foreignIndex, nameTypes? })` | {object[]} One record per note, plus one per documentation entry. | The index records for a content tree, without writing anything. |
|
|
1126
1143
|
| `indexRecordsForNote` | `indexRecordsForNote({ frontmatter, body, bodyLine, bodyColumn?, nameTypes?, relPath, absPath, raw, contentPackage, manifest, addressContext })` | `object[]` | Derive the note's own record and its documentation record from parsed text. |
|
|
@@ -1181,8 +1198,8 @@ scalar expressions, events or other generated sections require
|
|
|
1181
1198
|
`indexRecordsFor` and `collectContentIndex` collect authored records and pure
|
|
1182
1199
|
lexical sections; use preparation and emission to publish dynamic body targets.
|
|
1183
1200
|
|
|
1184
|
-
On lore and affiliation notes, `data.
|
|
1185
|
-
|
|
1201
|
+
On lore and affiliation notes, `data.glossary[].language` requires a
|
|
1202
|
+
language NOTE Address. Decoding refuses other recognized system
|
|
1186
1203
|
segments at the authored value, naming the complete
|
|
1187
1204
|
`<pkg>-note-skill-<shortcode>` to write. A short local form such as
|
|
1188
1205
|
`skill-provnzlng` is also accepted. See the [glossary language
|
|
@@ -2494,8 +2511,8 @@ focusable inline spoiler: scoped content CSS redacts its text and descendants
|
|
|
2494
2511
|
until pointer hover or keyboard focus reveals them. Its focus outline and
|
|
2495
2512
|
accessible cue identify the reveal interaction. Native Foundry secret sections
|
|
2496
2513
|
keep their separate controls. Book rendering discards inline `.secret` classes
|
|
2497
|
-
and prints their content normally, retaining emphasis, links, anchors and
|
|
2498
|
-
bold
|
|
2514
|
+
and prints their content normally, retaining emphasis, links, anchors and a
|
|
2515
|
+
name's first-use bold. Book secret sections and fences retain their visible labelled
|
|
2499
2516
|
boxes. The span parser's opaque source tokens retain a `secret` boolean from
|
|
2500
2517
|
their parsed classes for preview presentation.
|
|
2501
2518
|
`collectAnchors` includes `secret: true` on secret anchors for destination
|
|
@@ -41,9 +41,9 @@ For optional writing suggestions, run `npx package-build prose lint assets/conte
|
|
|
41
41
|
|
|
42
42
|
The full Address is `<package>-note-lore-harbor`; `<package>` comes from `contentPackage` in `package-build.config.yaml`. In another note, `[[lore-harbor|Harbor]]` links to it. `[[lore-harbor|]]` asks the renderer to use the target's current name. The pipe is required.
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
text. Link indexed subjects even when they are private: the destination's
|
|
44
|
+
Mark another subject's name with a link or a `.name` span; its first use in
|
|
45
|
+
the page is bold when it renders. Keep a note's own
|
|
46
|
+
subject in plain text. Link indexed subjects even when they are private: the destination's
|
|
47
47
|
audience automatically makes the whole reference a spoiler. Add `.show` only
|
|
48
48
|
to intentionally reveal the reference; it grants no access to the destination.
|
|
49
49
|
For an unwritten subject, use a typed span such as
|
|
@@ -12,7 +12,7 @@ HeroicLands notes begin with YAML frontmatter. A file is recognized as a note wh
|
|
|
12
12
|
```yaml
|
|
13
13
|
---
|
|
14
14
|
shortcode: harbor
|
|
15
|
-
name: { full: Harbor,
|
|
15
|
+
name: { full: Harbor, en: [The Harbor] }
|
|
16
16
|
type: lore
|
|
17
17
|
subType: economy
|
|
18
18
|
description: A sheltered trading port.
|
|
@@ -21,7 +21,35 @@ data: {}
|
|
|
21
21
|
---
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
`name` is a map with a required, nonempty `full` display name
|
|
24
|
+
`name` is a map with a required, nonempty `full` display name: the English name a page, a compendium entry and an index print. Every other name the subject goes by is listed under the code of its language, a code [`languages:`](../configuration.md#languages) declares, or `en`, which needs no declaration. `full` already counts as an English form, so `en` lists only the other English names and never repeats `full`. The first form in each list is that language's standard form. Any other key under `name` is an error at its line. The note infobox lists every form directly beneath the full name.
|
|
25
|
+
|
|
26
|
+
`sort` gives the form the name takes in an index, such as `Black Flame, The` or `Hilvan, Doran`. `sort` files the note wherever notes are ordered by name — the book index, page lists, generated lists of related notes, and the `nameSort` column of the `entries` relation — and is the note's entry text in the book index. Every other list still displays the `full` name. A note with no `sort` files and indexes by its `full` name. For `name: {full: The Black Flame, sort: "Black Flame, The"}`, the book index prints _Black Flame, The_ under **B**, and a page list prints _The Black Flame_ at the same place.
|
|
27
|
+
|
|
28
|
+
A person with nicknames lists them in the language they are said in:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
name: { full: Johnathan Lewis, en: [John, Long John], vyla: [juan juis] }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
A people with a name of its own gives its English name as `full` and its own name first under its language. Another people's name for it, an exonym, goes under that people's language:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
name: { full: Grass People, tenl: [tenlaya], kiic: [kitchek] }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Names match whatever their case: `Harbor`, `harbor` and `HARBOR` all name the note above, and every form is matched the same way. Display keeps the case the note writes. Two notes whose forms differ only by case are one ambiguous name, reported wherever the name is used.
|
|
41
|
+
|
|
42
|
+
`data.lang` states the language the note is in, as a code `languages:` declares or `en`. Any note may state it. A note that does not takes its language from its `data.culture`'s language, then from its `data.parents`, nearest first, then `en`; see [a note's language](../reference/format-details.md#a-notes-language). A culture note's language is how the notes of its people find their tongue:
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
---
|
|
46
|
+
shortcode: grassfolk
|
|
47
|
+
name: { full: Grass People, tenl: [tenlaya] }
|
|
48
|
+
type: lore
|
|
49
|
+
subType: culture
|
|
50
|
+
data: { lang: tenl }
|
|
51
|
+
---
|
|
52
|
+
```
|
|
25
53
|
|
|
26
54
|
`description` is the short page summary. `tags` hold draft state and descriptive labels. The note type's classification belongs in `subType` where it is declared. `data` holds facts about the subject shared by systems. A YAML comment is the place for an author-only note: commented values remain valid YAML but do not enter the content index or generated documents.
|
|
27
55
|
|