@heroiclands/package-build 23.13.0 → 24.0.1
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 +50 -0
- package/README.md +2 -1
- package/assets/preview/gitea.ini +12 -7
- package/assets/styles/content-base.css +150 -1
- package/bin/content-commands.mjs +356 -210
- package/bin/package-build.mjs +3 -2
- package/ci/check-banners.mjs +7 -7
- package/config.mjs +21 -6
- package/content-config.mjs +199 -80
- package/docs/api.md +93 -72
- package/docs/authoring/links-and-markup.md +316 -78
- package/docs/commands.md +248 -80
- package/docs/configuration.md +210 -102
- package/docs/content-format.md +2 -2
- package/docs/diagnostics.md +2 -2
- package/docs/getting-started.md +1 -1
- package/docs/guides/icons.md +1 -1
- package/docs/guides/module-project.md +5 -8
- package/docs/guides/release-and-deploy.md +2 -2
- package/docs/guides/site.md +155 -23
- package/docs/guides/system-project.md +1 -1
- package/docs/guides/writing-in-invented-scripts.md +1247 -0
- package/docs/index.md +1 -0
- package/docs/project-setup.md +28 -30
- package/docs/reference/format-details.md +589 -308
- package/docs/reference/note-types.md +40 -10
- package/docs/reference/theme-pages.md +127 -108
- package/docs/source-preview.md +15 -1
- package/engine/asset-shipping.mjs +22 -10
- package/engine/base-compiler.mjs +62 -104
- package/engine/changelog-lint.mjs +1 -1
- package/engine/content-address.mjs +1 -1
- package/engine/content-alerts.mjs +8 -4
- package/engine/content-blocks.mjs +26 -11
- package/engine/content-embeds.mjs +1 -1
- package/engine/content-expand.mjs +376 -0
- package/engine/content-figures.mjs +13 -6
- package/engine/content-format.yaml +8 -0
- package/engine/content-glyphs.mjs +213 -0
- package/engine/content-images.mjs +6 -7
- package/engine/content-links.mjs +3 -3
- package/engine/content-lint.mjs +1 -1
- package/engine/content-render.mjs +453 -0
- package/engine/content-scripts.mjs +326 -27
- package/engine/content-spans.mjs +4 -1
- package/engine/content-styles.mjs +91 -0
- package/engine/content-symbols.mjs +186 -0
- package/engine/content-verse.mjs +6 -18
- package/engine/core-report.mjs +169 -0
- package/engine/core-vocabulary.mjs +208 -0
- package/engine/dictionary-html.mjs +119 -0
- package/engine/field-reference.mjs +1 -1
- package/engine/frontmatter-lint.mjs +1 -1
- package/engine/heading-attributes.mjs +89 -0
- package/engine/helpers.mjs +61 -101
- package/engine/homepage.mjs +17 -29
- package/engine/html-minify.mjs +70 -0
- package/engine/index.mjs +8 -5
- package/engine/language-rows.mjs +8 -2
- package/engine/language-terms.mjs +115 -14
- package/engine/language-words.mjs +12 -0
- package/engine/logographic.mjs +255 -0
- package/engine/map-lexicon.mjs +221 -25
- package/engine/map-places.mjs +5 -4
- package/engine/markdown-expressions.mjs +0 -2
- package/engine/markdownlint-run.mjs +9 -3
- package/engine/markup-validation.mjs +21 -0
- package/engine/metre-declaration.mjs +134 -0
- package/engine/note-matter.mjs +2 -2
- package/engine/note-vocabulary.mjs +187 -3
- package/engine/pdf-build.mjs +68 -133
- package/engine/pdf-render.mjs +102 -44
- package/engine/post-fields.mjs +157 -0
- package/engine/preview-index.mjs +130 -0
- package/engine/preview-source.mjs +450 -0
- package/engine/project-init.mjs +5 -12
- package/engine/prose-config.mjs +3 -3
- package/engine/run-words.mjs +3 -2
- package/engine/script-emphasis-terms.mjs +38 -0
- package/engine/script-emphasis.mjs +295 -0
- package/engine/script-font-delivery.mjs +4 -4
- package/engine/site-build.mjs +265 -313
- package/engine/site-config.mjs +26 -238
- package/engine/site-files.mjs +175 -0
- package/engine/site-index.mjs +9 -4
- package/engine/site-preview.mjs +50 -523
- package/engine/site-reach.mjs +213 -0
- package/engine/site-render.mjs +668 -0
- package/engine/site-root.mjs +90 -39
- package/engine/site-search.mjs +161 -0
- package/engine/site-serve.mjs +274 -0
- package/engine/site-theme-banner.mjs +154 -0
- package/engine/site-theme-urls.mjs +125 -0
- package/engine/site-theme.mjs +939 -0
- package/engine/sql-tables.mjs +9 -6
- package/engine/text-maps.mjs +57 -10
- package/engine/typographer.mjs +248 -0
- package/engine/verse-metre.mjs +357 -0
- package/engine/wikilink-syntax.mjs +29 -47
- package/engine/wikilinks.mjs +758 -279
- package/engine/word-forms.mjs +39 -24
- package/engine/word-rows.mjs +12 -2
- package/engine/word-terms.mjs +29 -4
- package/manifest.mjs +3 -4
- package/package.json +10 -7
- package/{hugo-theme → site-theme}/data/banners.yaml +6 -10
- package/site-theme/layouts/base.hbs +31 -0
- package/site-theme/layouts/blog-list.hbs +30 -0
- package/site-theme/layouts/blog-post.hbs +40 -0
- package/site-theme/layouts/home.hbs +35 -0
- package/site-theme/layouts/list.hbs +20 -0
- package/site-theme/layouts/not-found.hbs +31 -0
- package/site-theme/layouts/page.hbs +7 -0
- package/site-theme/partials/copy-buttons.hbs +37 -0
- package/site-theme/partials/draft-notice.hbs +5 -0
- package/site-theme/partials/exturl.hbs +2 -0
- package/{hugo-theme/layouts/partials/footer.html → site-theme/partials/footer.hbs} +10 -7
- package/site-theme/partials/header.hbs +44 -0
- package/site-theme/partials/hero-banner.hbs +11 -0
- package/site-theme/partials/infobox-entry.hbs +2 -0
- package/site-theme/partials/infobox-section.hbs +31 -0
- package/site-theme/partials/infobox-value.hbs +2 -0
- package/site-theme/partials/infobox.hbs +18 -0
- package/site-theme/partials/list-members.hbs +9 -0
- package/site-theme/partials/nav-links.hbs +5 -0
- package/site-theme/partials/page-body.hbs +48 -0
- package/site-theme/partials/page-list.hbs +14 -0
- package/site-theme/partials/related.hbs +24 -0
- package/site-theme/partials/search-meta.hbs +6 -0
- package/site-theme/partials/search-names.hbs +2 -0
- package/site-theme/partials/search.hbs +52 -0
- package/site-theme/partials/tags.hbs +4 -0
- package/site-theme/partials/toc.hbs +7 -0
- package/{hugo-theme → site-theme}/static/css/style.css +14 -0
- package/stage.mjs +1 -2
- package/types/config.d.mts +8 -4
- package/types/content-config.d.mts +15 -15
- package/types/engine/asset-shipping.d.mts +5 -2
- package/types/engine/base-compiler.d.mts +20 -2
- package/types/engine/content-address.d.mts +1 -1
- package/types/engine/content-alerts.d.mts +8 -2
- package/types/engine/content-blocks.d.mts +11 -4
- package/types/engine/content-expand.d.mts +288 -0
- package/types/engine/content-figures.d.mts +11 -3
- package/types/engine/content-glyphs.d.mts +85 -0
- package/types/engine/content-images.d.mts +6 -7
- package/types/engine/content-links.d.mts +1 -1
- package/types/engine/content-render.d.mts +199 -0
- package/types/engine/content-scripts.d.mts +62 -0
- package/types/engine/content-spans.d.mts +1 -1
- package/types/engine/content-styles.d.mts +33 -0
- package/types/engine/content-symbols.d.mts +35 -0
- package/types/engine/core-report.d.mts +45 -0
- package/types/engine/core-vocabulary.d.mts +53 -0
- package/types/engine/dictionary-html.d.mts +8 -0
- package/types/engine/field-reference.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +20 -0
- package/types/engine/helpers.d.mts +3 -10
- package/types/engine/homepage.d.mts +11 -24
- package/types/engine/html-minify.d.mts +9 -0
- package/types/engine/index.d.mts +2 -1
- package/types/engine/language-terms.d.mts +24 -2
- package/types/engine/logographic.d.mts +45 -0
- package/types/engine/map-lexicon.d.mts +48 -8
- package/types/engine/map-places.d.mts +8 -0
- package/types/engine/markdown-expressions.d.mts +0 -2
- package/types/engine/metre-declaration.d.mts +39 -0
- package/types/engine/pdf-render.d.mts +6 -2
- package/types/engine/post-fields.d.mts +44 -0
- package/types/engine/preview-index.d.mts +72 -0
- package/types/engine/preview-source.d.mts +51 -0
- package/types/engine/script-emphasis-terms.d.mts +21 -0
- package/types/engine/script-emphasis.d.mts +84 -0
- package/types/engine/script-font-delivery.d.mts +4 -4
- package/types/engine/site-build.d.mts +71 -113
- package/types/engine/site-config.d.mts +14 -134
- package/types/engine/site-files.d.mts +73 -0
- package/types/engine/site-index.d.mts +11 -3
- package/types/engine/site-preview.d.mts +15 -19
- package/types/engine/site-reach.d.mts +76 -0
- package/types/engine/site-render.d.mts +173 -0
- package/types/engine/site-root.d.mts +14 -4
- package/types/engine/site-search.d.mts +54 -0
- package/types/engine/site-serve.d.mts +44 -0
- package/types/engine/site-theme-banner.d.mts +51 -0
- package/types/engine/site-theme-urls.d.mts +60 -0
- package/types/engine/site-theme.d.mts +127 -0
- package/types/engine/text-maps.d.mts +17 -3
- package/types/engine/typographer.d.mts +11 -0
- package/types/engine/verse-metre.d.mts +131 -0
- package/types/engine/wikilink-syntax.d.mts +30 -48
- package/types/engine/wikilinks.d.mts +330 -14
- package/types/engine/word-forms.d.mts +3 -2
- package/types/manifest.d.mts +3 -4
- package/types/stage.d.mts +1 -2
- package/types/vendor/markdownlint.d.mts +8 -0
- package/vendor/markdownlint.mjs +20388 -0
- package/engine/web-wikilinks.mjs +0 -594
- package/hugo-theme/layouts/404.html +0 -85
- package/hugo-theme/layouts/_default/baseof.html +0 -67
- package/hugo-theme/layouts/_default/list.html +0 -139
- package/hugo-theme/layouts/_default/single.html +0 -4
- package/hugo-theme/layouts/blog/list.html +0 -54
- package/hugo-theme/layouts/blog-post/single.html +0 -36
- package/hugo-theme/layouts/index.html +0 -75
- package/hugo-theme/layouts/partials/banner-url.html +0 -141
- package/hugo-theme/layouts/partials/cdn-url.html +0 -36
- package/hugo-theme/layouts/partials/dictionary-lists.html +0 -58
- package/hugo-theme/layouts/partials/draft-notice.html +0 -41
- package/hugo-theme/layouts/partials/draft-state.html +0 -26
- package/hugo-theme/layouts/partials/header.html +0 -35
- package/hugo-theme/layouts/partials/hero-banner.html +0 -85
- package/hugo-theme/layouts/partials/infobox/entry.html +0 -18
- package/hugo-theme/layouts/partials/infobox/items.html +0 -26
- package/hugo-theme/layouts/partials/infobox/section.html +0 -56
- package/hugo-theme/layouts/partials/infobox/value.html +0 -43
- package/hugo-theme/layouts/partials/infobox.html +0 -57
- package/hugo-theme/layouts/partials/page-body.html +0 -152
- package/hugo-theme/layouts/partials/related.html +0 -138
- package/hugo-theme/layouts/partials/search.html +0 -84
- package/hugo-theme/layouts/partials/site-url.html +0 -32
- package/hugo-theme/layouts/partials/tags.html +0 -30
- package/hugo-theme/layouts/partials/toc.html +0 -28
- package/hugo-theme/layouts/partials/warn-missing-banner.html +0 -3
- package/hugo-theme/layouts/shortcodes/cartouche.html +0 -64
- package/hugo-theme/layouts/shortcodes/exturl.html +0 -12
- package/hugo-theme/layouts/shortcodes/glyph.html +0 -43
- package/hugo-theme/layouts/shortcodes/pagelist.html +0 -63
- package/hugo-theme/theme.toml +0 -11
- package/types/engine/web-wikilinks.d.mts +0 -107
- /package/{hugo-theme → site-theme}/data/banner-kinds.yaml +0 -0
- /package/{hugo-theme → site-theme}/static/css/sohl-icons.css +0 -0
- /package/{hugo-theme → site-theme}/static/fonts/game-icons-kb.woff2 +0 -0
- /package/{hugo-theme → site-theme}/static/img/banners/takheperu-hieroglyphs.svg +0 -0
- /package/{hugo-theme → site-theme}/static/img/cartouches/takheperu.svg +0 -0
- /package/{hugo-theme → site-theme}/static/js/inline-spoilers.js +0 -0
|
@@ -112,6 +112,12 @@ import { checkNoteEvents } from "./note-events.mjs";
|
|
|
112
112
|
import { AFFILIATION_STANDINGS } from "../sohl/affiliation-standings.mjs";
|
|
113
113
|
import { EVENT_ENTRY } from "./note-event-terms.mjs";
|
|
114
114
|
import { CULTURE_FIELD, checkCultureSubType } from "./culture-choice.mjs";
|
|
115
|
+
import {
|
|
116
|
+
POST_AUTHOR_FIELD,
|
|
117
|
+
POST_DATE_FIELD,
|
|
118
|
+
POST_SUBTYPE,
|
|
119
|
+
checkPostFields,
|
|
120
|
+
} from "./post-fields.mjs";
|
|
115
121
|
import { checkCultureParents } from "./culture-parents.mjs";
|
|
116
122
|
import {
|
|
117
123
|
checkAppearanceProfile,
|
|
@@ -154,6 +160,10 @@ import { MARKET_CLASSES, checkMarket } from "./market-class.mjs";
|
|
|
154
160
|
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
155
161
|
import { checkSettlementTables } from "./settlement-tables.mjs";
|
|
156
162
|
import { checkMapField } from "./text-maps.mjs";
|
|
163
|
+
import { checkConceptList, checkCoreFlag } from "./core-vocabulary.mjs";
|
|
164
|
+
import { METRE_KINDS, checkMetresField } from "./metre-declaration.mjs";
|
|
165
|
+
import { checkLanguageEmphasis, checkScriptField } from "./script-emphasis.mjs";
|
|
166
|
+
import { EMPHASIS_CONVENTIONS, LANGUAGE_EMPHASES } from "./script-emphasis-terms.mjs";
|
|
157
167
|
|
|
158
168
|
/**
|
|
159
169
|
* One `data:` key a note type may carry.
|
|
@@ -655,6 +665,67 @@ const ABBREVIATION_FIELD = Object.freeze({
|
|
|
655
665
|
"note only. See [a language's words](format-details.md#a-languages-words).",
|
|
656
666
|
});
|
|
657
667
|
|
|
668
|
+
/**
|
|
669
|
+
* A language's `data.core`: whether it must cover the core vocabulary.
|
|
670
|
+
* {@link checkCoreFlag} checks where it sits.
|
|
671
|
+
*
|
|
672
|
+
* @type {DataFieldSpec}
|
|
673
|
+
*/
|
|
674
|
+
const CORE_FIELD = Object.freeze({
|
|
675
|
+
name: "core",
|
|
676
|
+
kind: "boolean",
|
|
677
|
+
shape: "`true` or `false`",
|
|
678
|
+
check: checkCoreFlag,
|
|
679
|
+
describe:
|
|
680
|
+
"Whether the language must cover the core vocabulary: `true` lists it in the " +
|
|
681
|
+
"`package-build core` report. A language skill note only. See " +
|
|
682
|
+
"[the core vocabulary](format-details.md#the-core-vocabulary).",
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* A `doc` note's `data.concepts`: the core vocabulary's concept list.
|
|
687
|
+
* {@link checkConceptList} checks what an entry means.
|
|
688
|
+
*
|
|
689
|
+
* @type {DataFieldSpec}
|
|
690
|
+
*/
|
|
691
|
+
const CONCEPTS_FIELD = Object.freeze({
|
|
692
|
+
name: "concepts",
|
|
693
|
+
kind: "list",
|
|
694
|
+
shape: "list of `{ id, gloss, group }`",
|
|
695
|
+
check: checkConceptList,
|
|
696
|
+
entries: Object.freeze({
|
|
697
|
+
kind: "map",
|
|
698
|
+
shape: "a map — `{ id, gloss, group }`",
|
|
699
|
+
fields: Object.freeze([
|
|
700
|
+
Object.freeze({
|
|
701
|
+
name: "id",
|
|
702
|
+
kind: "string",
|
|
703
|
+
required: true,
|
|
704
|
+
shape: "lowercase letters, digits and `-`",
|
|
705
|
+
describe:
|
|
706
|
+
"The concept's id, which a word's `concept` names. Unique in the package.",
|
|
707
|
+
}),
|
|
708
|
+
Object.freeze({
|
|
709
|
+
name: "gloss",
|
|
710
|
+
kind: "string",
|
|
711
|
+
required: true,
|
|
712
|
+
shape: "a short gloss, such as `a smell; a scent`",
|
|
713
|
+
describe: "What the concept means, in brief.",
|
|
714
|
+
}),
|
|
715
|
+
Object.freeze({
|
|
716
|
+
name: "group",
|
|
717
|
+
kind: "string",
|
|
718
|
+
required: true,
|
|
719
|
+
shape: "a group name, such as `senses`",
|
|
720
|
+
describe: "The group the report lists the concept under.",
|
|
721
|
+
}),
|
|
722
|
+
]),
|
|
723
|
+
}),
|
|
724
|
+
describe:
|
|
725
|
+
"The concepts of a core vocabulary, in the order the report lists them. See " +
|
|
726
|
+
"[the core vocabulary](format-details.md#the-core-vocabulary).",
|
|
727
|
+
});
|
|
728
|
+
|
|
658
729
|
/**
|
|
659
730
|
* A culture's or an affiliation's `data.glossary`: the terms that belong to
|
|
660
731
|
* its people or members rather than to a language's grammar.
|
|
@@ -2096,8 +2167,64 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2096
2167
|
NAMES_FIELD,
|
|
2097
2168
|
FAMILY_FIELD,
|
|
2098
2169
|
ABBREVIATION_FIELD,
|
|
2170
|
+
CORE_FIELD,
|
|
2099
2171
|
...WORD_DATA_FIELDS,
|
|
2100
2172
|
...LANGUAGE_DATA_FIELDS,
|
|
2173
|
+
{
|
|
2174
|
+
name: "emphasis",
|
|
2175
|
+
kind: "string",
|
|
2176
|
+
shape: "`words`, `rubric` or `overline`",
|
|
2177
|
+
allowed: LANGUAGE_EMPHASES,
|
|
2178
|
+
check: checkLanguageEmphasis,
|
|
2179
|
+
describe:
|
|
2180
|
+
"How the language marks a stressed word, over its script's `emphasis`: " +
|
|
2181
|
+
"`rubric` or `overline` sets `*…*` and `**…**` so in a run of the language, " +
|
|
2182
|
+
"and `words` marks it with a word, so either is a finding. Only a skill of " +
|
|
2183
|
+
"`subType: language` states it.",
|
|
2184
|
+
},
|
|
2185
|
+
{
|
|
2186
|
+
name: "script",
|
|
2187
|
+
kind: "map",
|
|
2188
|
+
shape: "a map — `{ fonts, emphasis, strongEmphasis? }`",
|
|
2189
|
+
check: checkScriptField,
|
|
2190
|
+
fields: Object.freeze([
|
|
2191
|
+
{
|
|
2192
|
+
name: "fonts",
|
|
2193
|
+
kind: "list",
|
|
2194
|
+
shape: "list of installed faces' slugs",
|
|
2195
|
+
required: true,
|
|
2196
|
+
entries: Object.freeze({
|
|
2197
|
+
kind: "string",
|
|
2198
|
+
shape: "an installed face's slug",
|
|
2199
|
+
}),
|
|
2200
|
+
describe:
|
|
2201
|
+
"The faces the script is written in, by the slug `font=` names them by. " +
|
|
2202
|
+
"A face belongs to one script.",
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
name: "emphasis",
|
|
2206
|
+
kind: "string",
|
|
2207
|
+
shape: "`rubric` or `overline`",
|
|
2208
|
+
allowed: EMPHASIS_CONVENTIONS,
|
|
2209
|
+
required: true,
|
|
2210
|
+
describe:
|
|
2211
|
+
"How the script marks a stressed word: `rubric` sets it in red, " +
|
|
2212
|
+
"`overline` draws a line above it. It sets `*…*` and `**…**` inside a " +
|
|
2213
|
+
"run in one of its faces, unless the run's language states its own " +
|
|
2214
|
+
"`emphasis`.",
|
|
2215
|
+
},
|
|
2216
|
+
{
|
|
2217
|
+
name: "strongEmphasis",
|
|
2218
|
+
kind: "string",
|
|
2219
|
+
shape: "`rubric` or `overline`",
|
|
2220
|
+
allowed: EMPHASIS_CONVENTIONS,
|
|
2221
|
+
describe: "The convention `**…**` takes instead of `emphasis`'s.",
|
|
2222
|
+
},
|
|
2223
|
+
]),
|
|
2224
|
+
describe:
|
|
2225
|
+
"A script note's faces and how it marks emphasis. Only a skill of " +
|
|
2226
|
+
"`subType: script` states it.",
|
|
2227
|
+
},
|
|
2101
2228
|
]),
|
|
2102
2229
|
}),
|
|
2103
2230
|
|
|
@@ -2176,14 +2303,20 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2176
2303
|
"howto",
|
|
2177
2304
|
"concept",
|
|
2178
2305
|
"settingguide",
|
|
2306
|
+
POST_SUBTYPE,
|
|
2179
2307
|
]),
|
|
2180
|
-
// A setting guide introduces one culture and names it
|
|
2181
|
-
// states
|
|
2308
|
+
// A setting guide introduces one culture and names it, and a post
|
|
2309
|
+
// states the day it was published and who wrote it; no other genre
|
|
2310
|
+
// states either.
|
|
2182
2311
|
check: (note, context) => [
|
|
2183
2312
|
...checkCitedPopulations(note, context),
|
|
2184
2313
|
...checkCultureSubType(note, context),
|
|
2314
|
+
...checkPostFields(note),
|
|
2185
2315
|
],
|
|
2186
2316
|
data: Object.freeze([
|
|
2317
|
+
CONCEPTS_FIELD,
|
|
2318
|
+
POST_DATE_FIELD,
|
|
2319
|
+
POST_AUTHOR_FIELD,
|
|
2187
2320
|
{
|
|
2188
2321
|
...CULTURE_FIELD,
|
|
2189
2322
|
describe:
|
|
@@ -2193,7 +2326,7 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2193
2326
|
{
|
|
2194
2327
|
name: "map",
|
|
2195
2328
|
kind: "map",
|
|
2196
|
-
shape: "a map — `{ name, vowels?, fonts, rows }`",
|
|
2329
|
+
shape: "a map — `{ name, logographic?, vowels?, fonts, rows }`",
|
|
2197
2330
|
check: checkMapField,
|
|
2198
2331
|
fields: Object.freeze([
|
|
2199
2332
|
{
|
|
@@ -2204,6 +2337,15 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2204
2337
|
"What `map=` names the map by: lowercase letters, digits and `-`, " +
|
|
2205
2338
|
"unique in the package.",
|
|
2206
2339
|
},
|
|
2340
|
+
{
|
|
2341
|
+
name: "logographic",
|
|
2342
|
+
kind: "boolean",
|
|
2343
|
+
shape: "`true`",
|
|
2344
|
+
describe:
|
|
2345
|
+
"The script writes meanings: a mapped run's words are written by " +
|
|
2346
|
+
"the language's lexicon alone, and the rows write only the text " +
|
|
2347
|
+
"between them.",
|
|
2348
|
+
},
|
|
2207
2349
|
{
|
|
2208
2350
|
name: "vowels",
|
|
2209
2351
|
...TEXT,
|
|
@@ -2261,6 +2403,48 @@ export const NOTE_VOCABULARY = Object.freeze({
|
|
|
2261
2403
|
"before it is set. See " +
|
|
2262
2404
|
"[mapping notes](format-details.md#mapping-notes).",
|
|
2263
2405
|
},
|
|
2406
|
+
{
|
|
2407
|
+
name: "metres",
|
|
2408
|
+
kind: "list",
|
|
2409
|
+
shape: "list of `{ name, beats, kind }`",
|
|
2410
|
+
check: checkMetresField,
|
|
2411
|
+
entries: Object.freeze({
|
|
2412
|
+
kind: "map",
|
|
2413
|
+
shape: "a map — `{ name, beats, kind }`",
|
|
2414
|
+
fields: Object.freeze([
|
|
2415
|
+
{
|
|
2416
|
+
name: "name",
|
|
2417
|
+
...TEXT,
|
|
2418
|
+
required: true,
|
|
2419
|
+
describe:
|
|
2420
|
+
"What a verse fence's `scan=` names the metre by: lowercase " +
|
|
2421
|
+
"letters, digits and `-`, unique in the package.",
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
name: "beats",
|
|
2425
|
+
kind: "integer",
|
|
2426
|
+
shape: "a whole number above zero",
|
|
2427
|
+
required: true,
|
|
2428
|
+
describe: "The beats of one line.",
|
|
2429
|
+
},
|
|
2430
|
+
{
|
|
2431
|
+
name: "kind",
|
|
2432
|
+
kind: "string",
|
|
2433
|
+
allowed: METRE_KINDS,
|
|
2434
|
+
shape: `one of ${METRE_KINDS.join(", ")}`,
|
|
2435
|
+
required: true,
|
|
2436
|
+
describe:
|
|
2437
|
+
"How the beats are counted: `accentual`, one beat for each " +
|
|
2438
|
+
"stressed syllable the language's stress rule and the beat " +
|
|
2439
|
+
"convention give.",
|
|
2440
|
+
},
|
|
2441
|
+
]),
|
|
2442
|
+
}),
|
|
2443
|
+
describe:
|
|
2444
|
+
"The metres a verse fence's `scan=` names. A fence that states one is " +
|
|
2445
|
+
"warned at each line that cannot have its beats. See " +
|
|
2446
|
+
"[metres](../authoring/links-and-markup.md#metre).",
|
|
2447
|
+
},
|
|
2264
2448
|
]),
|
|
2265
2449
|
}),
|
|
2266
2450
|
|
package/engine/pdf-build.mjs
CHANGED
|
@@ -26,11 +26,12 @@
|
|
|
26
26
|
* has found a bug in one of them, so the book does not get its own walk, its
|
|
27
27
|
* own frontmatter reader or its own link resolver. It collects pages with
|
|
28
28
|
* {@link module:engine/site-build.collectContentPages}, indexes them with
|
|
29
|
-
* `siteGates`, expands
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
29
|
+
* `siteGates`, and expands each body with
|
|
30
|
+
* {@link module:engine/content-expand.expandContent} for the `book` target —
|
|
31
|
+
* the same calls the site makes. What differs is how a link is written, the
|
|
32
|
+
* figure numbering, which runs across the whole book, the last step and the
|
|
33
|
+
* *selection*: the site publishes every page, and the book publishes what its
|
|
34
|
+
* document tree asked for.
|
|
34
35
|
*
|
|
35
36
|
* The book builds when the authored tree contains content pages. The same
|
|
36
37
|
* {@link module:content-config.publishesContentPages} decision governs the
|
|
@@ -97,20 +98,9 @@ import {
|
|
|
97
98
|
} from "./pdf-pages.mjs";
|
|
98
99
|
import { cachedDependencies, openNotesDatabase, prepareTreeSqlTables } from "./sql-tables.mjs";
|
|
99
100
|
import { parseDocumentTree, runTreeFilters, planDocument } from "./pdf-toc.mjs";
|
|
100
|
-
import {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
tableUniverse,
|
|
104
|
-
gatesFailed,
|
|
105
|
-
resolveSitePass,
|
|
106
|
-
} from "./site-build.mjs";
|
|
107
|
-
import {
|
|
108
|
-
figureIndexKeys,
|
|
109
|
-
resolveCrossNoteFigures,
|
|
110
|
-
resolveInfoboxRef,
|
|
111
|
-
wikiContext,
|
|
112
|
-
} from "./site-index.mjs";
|
|
113
|
-
import { resolveWebWikilinks } from "./web-wikilinks.mjs";
|
|
101
|
+
import { collectContentPages, siteGates, gatesFailed, resolveSitePass } from "./site-build.mjs";
|
|
102
|
+
import { figureIndexKeys, resolveInfoboxRef } from "./site-index.mjs";
|
|
103
|
+
import { expandContent, expandTables } from "./content-expand.mjs";
|
|
114
104
|
import { linkFindingMessage } from "./wikilink-syntax.mjs";
|
|
115
105
|
import {
|
|
116
106
|
positionOfFrontmatterPath,
|
|
@@ -120,14 +110,11 @@ import {
|
|
|
120
110
|
} from "./diagnostics.mjs";
|
|
121
111
|
import { artPathname, assetAddressIndex, pathnameRoles } from "./art-fields.mjs";
|
|
122
112
|
import { embedRole } from "./content-embeds.mjs";
|
|
123
|
-
import { expandContentTables } from "./content-tables.mjs";
|
|
124
113
|
import { seeAlsoEntries, seeAlsoMarkdown, seeAlsoWebLink } from "./see-also.mjs";
|
|
125
|
-
import { renderMarkdownExpressions } from "./markdown-expressions.mjs";
|
|
126
114
|
import { eventNoteIndex } from "./event-fields.mjs";
|
|
127
115
|
import { numberFigures, scanFigures } from "./content-figures.mjs";
|
|
128
|
-
import { collectAnchors } from "./anchors.mjs";
|
|
129
|
-
import { protectCode } from "./code-fences.mjs";
|
|
130
116
|
import { imagesIn, parseImageDirective } from "./content-images.mjs";
|
|
117
|
+
import { symbolImagesIn } from "./content-symbols.mjs";
|
|
131
118
|
import {
|
|
132
119
|
bookImageWidthIn,
|
|
133
120
|
PDF_IMAGE_INCHES,
|
|
@@ -159,7 +146,7 @@ import { infoboxTypstPreamble, infoboxesToTypst, linkToTypst } from "./infobox-r
|
|
|
159
146
|
import { noteInfoboxes } from "./infobox-registry.mjs";
|
|
160
147
|
import { resolveIconGlyphs } from "./pdf-fonts.mjs";
|
|
161
148
|
import { drawMapsFrom } from "./derived-sections.mjs";
|
|
162
|
-
import { generatedDrawing
|
|
149
|
+
import { generatedDrawing } from "./generated-sections.mjs";
|
|
163
150
|
import { resolveAssetReplacement } from "./asset-replacement.mjs";
|
|
164
151
|
import { typstScriptFontPath } from "./script-font-delivery.mjs";
|
|
165
152
|
|
|
@@ -1041,7 +1028,6 @@ async function prepareWorld(resolved, { contentBase, findings, resolveReplacemen
|
|
|
1041
1028
|
}
|
|
1042
1029
|
|
|
1043
1030
|
const byFile = new Map(collected.pages.map((page) => [page.file, page]));
|
|
1044
|
-
const universe = tableUniverse(collected.pages);
|
|
1045
1031
|
// The address space an `![[…]]` embed resolves against — the same one the
|
|
1046
1032
|
// site builds, so one authored picture reaches both surfaces or neither.
|
|
1047
1033
|
const assets = assetAddressIndex(records, {
|
|
@@ -1070,7 +1056,6 @@ async function prepareWorld(resolved, { contentBase, findings, resolveReplacemen
|
|
|
1070
1056
|
site,
|
|
1071
1057
|
gates,
|
|
1072
1058
|
byFile,
|
|
1073
|
-
universe,
|
|
1074
1059
|
sqlTables,
|
|
1075
1060
|
assets,
|
|
1076
1061
|
md,
|
|
@@ -1196,8 +1181,7 @@ async function buildBook(book, shared) {
|
|
|
1196
1181
|
const staged = stagedImagePath(src, resolved, world.stagingOpts);
|
|
1197
1182
|
return staged && { ...staged, to: inBook(staged.to) };
|
|
1198
1183
|
};
|
|
1199
|
-
const { records, site, gates, byFile,
|
|
1200
|
-
world;
|
|
1184
|
+
const { records, site, gates, byFile, sqlTables, assets, md, glyphs, stagingOpts } = world;
|
|
1201
1185
|
|
|
1202
1186
|
fs.mkdirSync(outDir, { recursive: true });
|
|
1203
1187
|
|
|
@@ -1244,7 +1228,14 @@ async function buildBook(book, shared) {
|
|
|
1244
1228
|
}
|
|
1245
1229
|
return positionOfLiteral(raw, src, occurrence);
|
|
1246
1230
|
};
|
|
1247
|
-
|
|
1231
|
+
// A glyph or a cartouche is a picture the package ships, staged like
|
|
1232
|
+
// any other and located in the note by its slug.
|
|
1233
|
+
const symbols = symbolImagesIn(body).map(({ src, locate }) => ({
|
|
1234
|
+
src,
|
|
1235
|
+
locate,
|
|
1236
|
+
directive: "",
|
|
1237
|
+
}));
|
|
1238
|
+
for (const image of [...imagesIn(body), ...symbols]) {
|
|
1248
1239
|
const src = image.src;
|
|
1249
1240
|
const occurrence = (seenHere.get(src) ?? 0) + 1;
|
|
1250
1241
|
seenHere.set(src, occurrence);
|
|
@@ -1287,7 +1278,7 @@ async function buildBook(book, shared) {
|
|
|
1287
1278
|
if (problem) {
|
|
1288
1279
|
findings.push({
|
|
1289
1280
|
file,
|
|
1290
|
-
...where(src, occurrence),
|
|
1281
|
+
...where(image.locate ?? src, occurrence),
|
|
1291
1282
|
severity: "error",
|
|
1292
1283
|
message: problem,
|
|
1293
1284
|
});
|
|
@@ -1299,7 +1290,7 @@ async function buildBook(book, shared) {
|
|
|
1299
1290
|
} catch (err) {
|
|
1300
1291
|
findings.push({
|
|
1301
1292
|
file,
|
|
1302
|
-
...where(src, occurrence),
|
|
1293
|
+
...where(image.locate ?? src, occurrence),
|
|
1303
1294
|
severity: "error",
|
|
1304
1295
|
message: err.message,
|
|
1305
1296
|
});
|
|
@@ -1308,7 +1299,7 @@ async function buildBook(book, shared) {
|
|
|
1308
1299
|
if (!staged) {
|
|
1309
1300
|
findings.push({
|
|
1310
1301
|
file,
|
|
1311
|
-
...where(src, occurrence),
|
|
1302
|
+
...where(image.locate ?? src, occurrence),
|
|
1312
1303
|
severity: "warning",
|
|
1313
1304
|
message:
|
|
1314
1305
|
`\`${src}\` names a file this package does not ship, so the book ` +
|
|
@@ -1324,7 +1315,7 @@ async function buildBook(book, shared) {
|
|
|
1324
1315
|
} catch (err) {
|
|
1325
1316
|
findings.push({
|
|
1326
1317
|
file,
|
|
1327
|
-
...where(src, occurrence),
|
|
1318
|
+
...where(image.locate ?? src, occurrence),
|
|
1328
1319
|
severity: "warning",
|
|
1329
1320
|
message:
|
|
1330
1321
|
`\`${src}\` cannot be read from ` +
|
|
@@ -1389,12 +1380,12 @@ async function buildBook(book, shared) {
|
|
|
1389
1380
|
* order, before any entry's expressions render — so a cross-note `ref`
|
|
1390
1381
|
* finds the number its target carries in the finished book rather than a
|
|
1391
1382
|
* page-local recount. Walked in the same order {@link bodies} fills
|
|
1392
|
-
* below, so `figureCounts` lands on the same final tallies either way
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1383
|
+
* below, so `figureCounts` lands on the same final tallies either way. A
|
|
1384
|
+
* note's {@link module:engine/content-expand.expandTables} is kept here
|
|
1385
|
+
* with its figures numbered, and the render loop expands the rest from it.
|
|
1395
1386
|
*
|
|
1396
|
-
* @type {Map<string, {
|
|
1397
|
-
*
|
|
1387
|
+
* @type {Map<string, {staged?: import("./content-expand.mjs").ExpandedTables,
|
|
1388
|
+
* numberedFigures: object[]}>}
|
|
1398
1389
|
*/
|
|
1399
1390
|
const prepared = new Map();
|
|
1400
1391
|
// The map from each selected place given a From here section, drawn before
|
|
@@ -1424,25 +1415,18 @@ async function buildBook(book, shared) {
|
|
|
1424
1415
|
const file = noteFile(contentBase, entry.record);
|
|
1425
1416
|
const page = byFile.get(file);
|
|
1426
1417
|
if (!page) continue; // reported as `missing` by the render loop below
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
self: { fm: page.fm, path: page.relPath },
|
|
1418
|
+
const staged = expandTables(page.body, {
|
|
1419
|
+
source: page.relPath ?? page.base,
|
|
1420
|
+
prepared: {
|
|
1421
|
+
sqlTables: sqlTables?.get(page.file),
|
|
1422
|
+
pageLists: sqlTables?.pageLists?.get(page.file),
|
|
1423
|
+
},
|
|
1424
|
+
resolveRole,
|
|
1435
1425
|
});
|
|
1436
|
-
const numberedFigures = numberFigures(
|
|
1437
|
-
scanFigures(markdown, { resolveRole }).figures,
|
|
1438
|
-
figureCounts,
|
|
1439
|
-
);
|
|
1426
|
+
const numberedFigures = numberFigures(staged.figures.figures, figureCounts);
|
|
1440
1427
|
prepared.set(entry.anchor, {
|
|
1441
|
-
|
|
1442
|
-
errors,
|
|
1443
|
-
lineMap,
|
|
1428
|
+
staged: { ...staged, figures: { ...staged.figures, figures: numberedFigures } },
|
|
1444
1429
|
numberedFigures,
|
|
1445
|
-
generatedFrom,
|
|
1446
1430
|
});
|
|
1447
1431
|
const shortcode = page.fm.shortcode;
|
|
1448
1432
|
if (typeof shortcode === "string" && shortcode) {
|
|
@@ -1482,15 +1466,36 @@ async function buildBook(book, shared) {
|
|
|
1482
1466
|
}
|
|
1483
1467
|
|
|
1484
1468
|
const renderPage = (page, headingOffset, anchorPrefix, columns) => {
|
|
1485
|
-
const
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1469
|
+
const { staged, numberedFigures } = prepared.get(anchorPrefix);
|
|
1470
|
+
// The book's own figure numbering, from `prepared`: the book numbers
|
|
1471
|
+
// each kind across the whole book in reading order, so a reference
|
|
1472
|
+
// reads the number the book gives the figure, not the number the note
|
|
1473
|
+
// would give it alone.
|
|
1474
|
+
const expanded = expandContent(page.body, {
|
|
1475
|
+
target: "book",
|
|
1476
|
+
index: gates.index,
|
|
1477
|
+
note: {
|
|
1478
|
+
fm: page.fm,
|
|
1479
|
+
file: page.file,
|
|
1480
|
+
source: page.relPath ?? page.base,
|
|
1481
|
+
bodyLine: page.bodyLine,
|
|
1482
|
+
},
|
|
1483
|
+
prepared: { inline: sqlTables?.inline?.get(page.file) },
|
|
1484
|
+
events,
|
|
1485
|
+
figuresByAddress,
|
|
1486
|
+
tables: staged,
|
|
1487
|
+
links: {
|
|
1488
|
+
foreign: gates.foreign.index,
|
|
1489
|
+
assets,
|
|
1490
|
+
beforeLinks: pass.beforeLinks ? (text) => pass.beforeLinks(text, page) : undefined,
|
|
1491
|
+
},
|
|
1492
|
+
});
|
|
1493
|
+
const { lineMap, generatedFrom } = expanded;
|
|
1489
1494
|
// A content-table finding states its `reason`, its 0-based line within
|
|
1490
1495
|
// the body and its column, exactly as the site build reports them.
|
|
1491
1496
|
// Reading it as `message` yields `[object Object]` and discards the
|
|
1492
1497
|
// position, which is the one thing a reader needs to find the fence.
|
|
1493
|
-
for (const err of
|
|
1498
|
+
for (const err of expanded.findings.tables) {
|
|
1494
1499
|
findings.push({
|
|
1495
1500
|
file: page.file,
|
|
1496
1501
|
...(typeof err.line === "number" ?
|
|
@@ -1500,77 +1505,7 @@ async function buildBook(book, shared) {
|
|
|
1500
1505
|
message: err.reason ?? String(err.message ?? err),
|
|
1501
1506
|
});
|
|
1502
1507
|
}
|
|
1503
|
-
|
|
1504
|
-
src,
|
|
1505
|
-
file: page.file,
|
|
1506
|
-
type: page.fm.type ?? null,
|
|
1507
|
-
errors: wikiErrors,
|
|
1508
|
-
foreignIndex: gates.foreign.index,
|
|
1509
|
-
assets,
|
|
1510
|
-
});
|
|
1511
|
-
linkCtx.captionLabels = new Map(
|
|
1512
|
-
numberedFigures
|
|
1513
|
-
.filter((figure) => figure.id)
|
|
1514
|
-
.map((figure) => [figure.id, figure.label]),
|
|
1515
|
-
);
|
|
1516
|
-
// This page's own anchors, so a `[[#slug]]` self-link is checked
|
|
1517
|
-
// against what the page actually declares, exactly as the site build
|
|
1518
|
-
// checks it.
|
|
1519
|
-
linkCtx.anchors = new Set(collectAnchors(markdown).map((anchor) => anchor.slug));
|
|
1520
|
-
linkCtx.output = "book";
|
|
1521
|
-
// What the `ref` expression helper needs beyond the label — the
|
|
1522
|
-
// caption text and whether one was authored — keyed as
|
|
1523
|
-
// `engine/site-build.mjs` keys its own, but built from this note's
|
|
1524
|
-
// *book-wide* numbering rather than its page-local count: the book
|
|
1525
|
-
// numbers each kind across the whole book in reading order, so a
|
|
1526
|
-
// reference has to read the number the book gives the figure, not the
|
|
1527
|
-
// number the note would give it alone.
|
|
1528
|
-
const figuresById = new Map(
|
|
1529
|
-
numberedFigures
|
|
1530
|
-
.filter((figure) => figure.id)
|
|
1531
|
-
.map((figure) => [
|
|
1532
|
-
figure.id,
|
|
1533
|
-
{ label: figure.label, caption: figure.caption, hasCaption: figure.hasCaption },
|
|
1534
|
-
]),
|
|
1535
|
-
);
|
|
1536
|
-
// Code fences are protected for the same reason every other pass
|
|
1537
|
-
// protects them: a wikilink shown as an example is prose about a
|
|
1538
|
-
// wikilink, and resolving it would make the example impossible to write.
|
|
1539
|
-
// Where the generated sections begin is marked before any pass can move
|
|
1540
|
-
// a line, and the body is split there once its links resolve: the
|
|
1541
|
-
// sections are set by the rules for generated links — see
|
|
1542
|
-
// `renderLink` in `engine/pdf-render.mjs`.
|
|
1543
|
-
const expressions = renderMarkdownExpressions(markGenerated(markdown, generatedFrom), {
|
|
1544
|
-
fm: page.fm,
|
|
1545
|
-
dates: gates.index.dateContext,
|
|
1546
|
-
sqlResults: sqlTables?.inline?.get(page.file),
|
|
1547
|
-
file: page.file,
|
|
1548
|
-
bodyLine: page.bodyLine,
|
|
1549
|
-
events,
|
|
1550
|
-
figures: {
|
|
1551
|
-
get: (id) => figuresById.get(id),
|
|
1552
|
-
// A cross-note `ref` resolves the written address exactly as
|
|
1553
|
-
// a wikilink does, against every note's figures numbered
|
|
1554
|
-
// before any entry's expressions render — see `prepared`
|
|
1555
|
-
// above. The default link renders the target's own web
|
|
1556
|
-
// address, which `renderLink` in `engine/pdf-render.mjs`
|
|
1557
|
-
// resolves to the entry the book gave it, exactly as an
|
|
1558
|
-
// ordinary cross-note wikilink does.
|
|
1559
|
-
note: (target) =>
|
|
1560
|
-
resolveCrossNoteFigures(target, {
|
|
1561
|
-
contentTypes: gates.index.contentTypes,
|
|
1562
|
-
packages: gates.index.packages,
|
|
1563
|
-
noIndexPackages: gates.index.noIndexPackages,
|
|
1564
|
-
contentPackage: gates.index.contentPackage,
|
|
1565
|
-
siteIndexMap: gates.index.index,
|
|
1566
|
-
figuresByAddress,
|
|
1567
|
-
}),
|
|
1568
|
-
},
|
|
1569
|
-
});
|
|
1570
|
-
findings.push(...expressions.findings);
|
|
1571
|
-
const resolvedBody = protectCode(expressions.markdown, (text) =>
|
|
1572
|
-
resolveWebWikilinks(pass.beforeLinks ? pass.beforeLinks(text, page) : text, linkCtx),
|
|
1573
|
-
);
|
|
1508
|
+
findings.push(...expanded.findings.expressions);
|
|
1574
1509
|
// A link finding carries the authored link and which occurrence of it
|
|
1575
1510
|
// this was, which is exactly what locates it: the position is implicit
|
|
1576
1511
|
// in the literal the pass matched, so it is recovered by searching the
|
|
@@ -1594,7 +1529,7 @@ async function buildBook(book, shared) {
|
|
|
1594
1529
|
// The source is written and the compiler still runs, so the finding is a
|
|
1595
1530
|
// report on a book that was built, exactly as the site writes its pages
|
|
1596
1531
|
// and refuses the run.
|
|
1597
|
-
for (const err of
|
|
1532
|
+
for (const err of expanded.findings.links) {
|
|
1598
1533
|
findings.push({
|
|
1599
1534
|
file: page.file,
|
|
1600
1535
|
...positionOfLiteral(noteSource(), err.link, err.occurrence),
|
|
@@ -1605,8 +1540,8 @@ async function buildBook(book, shared) {
|
|
|
1605
1540
|
message: err.message ?? (err.reason ? linkFindingMessage(err) : String(err)),
|
|
1606
1541
|
});
|
|
1607
1542
|
}
|
|
1608
|
-
stageImages(
|
|
1609
|
-
const { authored, generated } =
|
|
1543
|
+
stageImages(expanded.markdown, page.file, columns);
|
|
1544
|
+
const { authored, generated } = expanded;
|
|
1610
1545
|
const typst = (text, options) =>
|
|
1611
1546
|
markdownToTypst(text, {
|
|
1612
1547
|
md,
|