@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
package/engine/helpers.mjs
CHANGED
|
@@ -25,8 +25,7 @@
|
|
|
25
25
|
* journals.mjs, actors.mjs).
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import {
|
|
29
|
-
import { renderRuns } from "./content-scripts.mjs";
|
|
28
|
+
import { createRenderer } from "./content-render.mjs";
|
|
30
29
|
import { buildReferenceTargets } from "./reference-targets.mjs";
|
|
31
30
|
import { standingsDigest } from "./standings.mjs";
|
|
32
31
|
|
|
@@ -39,12 +38,7 @@ import crypto from "crypto";
|
|
|
39
38
|
import path from "path";
|
|
40
39
|
import yaml from "yaml";
|
|
41
40
|
import unidecode from "unidecode";
|
|
42
|
-
import
|
|
43
|
-
import footnotePlugin from "markdown-it-footnote";
|
|
44
|
-
import deflistPlugin from "markdown-it-deflist";
|
|
45
|
-
import { dictionaryListPlugin } from "./definition-list.mjs";
|
|
46
|
-
import { iconPlugin } from "./content-icons.mjs";
|
|
47
|
-
import { imagePlugin, imagesIn } from "./content-images.mjs";
|
|
41
|
+
import { imagesIn } from "./content-images.mjs";
|
|
48
42
|
import { embedRole, resolveEmbeds } from "./content-embeds.mjs";
|
|
49
43
|
import { collectAssetRecords } from "./asset-index.mjs";
|
|
50
44
|
import { assetImageInfoByPathname } from "./art-fields.mjs";
|
|
@@ -67,19 +61,15 @@ import { loadForeignIndexes, noContentIndexPackages } from "./metadata-index.mjs
|
|
|
67
61
|
// a record needs none of that.
|
|
68
62
|
import { authoredFrontmatter, isAssetRecord, isNoteRecord, noteFile } from "./index-records.mjs";
|
|
69
63
|
import { buildWikilinkIndex, convertWikilinks } from "./wikilinks.mjs";
|
|
70
|
-
// One vocabulary of link findings, and one message per class, so
|
|
71
|
-
//
|
|
64
|
+
// One vocabulary of link findings, and one message per class, so no two
|
|
65
|
+
// builds word the same defect differently.
|
|
72
66
|
import { linkFindingMessage } from "./wikilink-syntax.mjs";
|
|
73
67
|
// The declared tag vocabulary, which is where `draft` is stated. Read
|
|
74
68
|
// from there rather than respelt, so the tag and its one reader cannot drift.
|
|
75
69
|
import { isGmNote, isDraftNote } from "./note-vocabulary.mjs";
|
|
76
70
|
import { DERIVED_PACKED_TYPES, NEVER_PACKED_TYPES } from "./note-claims.mjs";
|
|
77
71
|
import { expandContentTables } from "./content-tables.mjs";
|
|
78
|
-
import {
|
|
79
|
-
import { dictionaryEntryPlugin } from "./dictionary-layout.mjs";
|
|
80
|
-
import { renderBlocks } from "./content-blocks.mjs";
|
|
81
|
-
import { headingAttributesPlugin } from "./heading-attributes.mjs";
|
|
82
|
-
import { renderFigureBlocks, scanFigures } from "./content-figures.mjs";
|
|
72
|
+
import { scanFigures } from "./content-figures.mjs";
|
|
83
73
|
import { positionInBody, splitFrontmatter } from "./diagnostics.mjs";
|
|
84
74
|
// The pure `sohl:` frontmatter readers live in a leaf module so the item-type
|
|
85
75
|
// registry can import them without reaching back through this one.
|
|
@@ -100,72 +90,68 @@ export {
|
|
|
100
90
|
let localAssetImageInfoCache;
|
|
101
91
|
|
|
102
92
|
/**
|
|
103
|
-
* The
|
|
93
|
+
* The Foundry renderer: the shared configuration of
|
|
94
|
+
* {@link module:engine/content-render.createRenderer} for the `foundry`
|
|
95
|
+
* target.
|
|
104
96
|
*
|
|
105
97
|
* `html: true` is long-standing and load-bearing — notes carry raw blocks — and
|
|
106
98
|
* it is also why {@link module:engine/content-icons} exists rather than an
|
|
107
99
|
* instruction to write `<i class="fa-solid …">` by hand: that would render on
|
|
108
100
|
* the two HTML surfaces and be silently dropped by the third.
|
|
101
|
+
*
|
|
102
|
+
* The icon registry and the image resolvers are read per render, not at import:
|
|
103
|
+
* this constant is built before any configuration is read, and a package's own
|
|
104
|
+
* icons live in the configuration. A tree with none — or a caller with no
|
|
105
|
+
* configuration to find — falls back to the shipped table and to the authored
|
|
106
|
+
* pathname.
|
|
109
107
|
*/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.use(headingAttributesPlugin)
|
|
119
|
-
.use(
|
|
120
|
-
// Resolved per render, not at import: this constant is built before any
|
|
121
|
-
// configuration is read, and a package's own icons live in the
|
|
122
|
-
// configuration. A tree with none — or a caller with no configuration to
|
|
123
|
-
// find — falls back to the shipped table.
|
|
124
|
-
iconPlugin(() => {
|
|
125
|
-
try {
|
|
126
|
-
return loadPackConfig().icons;
|
|
127
|
-
} catch {
|
|
128
|
-
return undefined;
|
|
129
|
-
}
|
|
130
|
-
}),
|
|
131
|
-
)
|
|
108
|
+
const renderer = createRenderer("foundry", {
|
|
109
|
+
icons: () => {
|
|
110
|
+
try {
|
|
111
|
+
return loadPackConfig().icons;
|
|
112
|
+
} catch {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
},
|
|
132
116
|
// The width and position an image states, honoured as a figure. The
|
|
133
117
|
// vocabularies are closed and need no configuration; the address does, and
|
|
134
118
|
// is resolved per render for the reason the icon registry is — Foundry
|
|
135
119
|
// serves a file from inside the install, so a body image's address is
|
|
136
120
|
// translated by the same rule `img:` follows.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
121
|
+
images: {
|
|
122
|
+
resolveSrc: (src) => {
|
|
123
|
+
// **Reported upstream, never here.** A renderer has no channel to
|
|
124
|
+
// report through, and this one runs inside the very passes whose
|
|
125
|
+
// job is to collect findings — a throw would take the whole lint
|
|
126
|
+
// down and lose every other finding in the tree. So nothing reaches
|
|
127
|
+
// this point unreported: {@link convertNoteWikilinks} refuses a body
|
|
128
|
+
// image with no address inside the install before a compiler renders
|
|
129
|
+
// one, and the address passes report the same pathname with a line
|
|
130
|
+
// and a column. What is left here is a fallback for a caller with no
|
|
131
|
+
// configuration to resolve against, where the authored pathname is
|
|
132
|
+
// the most honest thing to emit.
|
|
133
|
+
try {
|
|
134
|
+
return resolveImg(src, loadPackConfig()) ?? src;
|
|
135
|
+
} catch {
|
|
136
|
+
return src;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
lookupAsset: (src) => {
|
|
140
|
+
// A body image is free to write the bare, own-package form,
|
|
141
|
+
// so the address is normalized to the pathname the cache
|
|
142
|
+
// below keys by before it is looked up.
|
|
143
|
+
try {
|
|
144
|
+
const key = assetPathnameKey(src, loadPackConfig());
|
|
145
|
+
return key ? localAssetImageInfo().get(key) : undefined;
|
|
146
|
+
} catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
/** The Foundry renderer's parser, for callers that parse or render a fragment. */
|
|
154
|
+
export const md = renderer.md;
|
|
169
155
|
|
|
170
156
|
/**
|
|
171
157
|
* The pictures this package's own tree ships, by the pathname their address
|
|
@@ -194,25 +180,6 @@ function localAssetImageInfo() {
|
|
|
194
180
|
return localAssetImageInfoCache;
|
|
195
181
|
}
|
|
196
182
|
|
|
197
|
-
md.renderer.rules.footnote_block_open = () =>
|
|
198
|
-
'<section class="footnotes"><h2>Footnotes</h2><ol class="footnotes-list">\n';
|
|
199
|
-
md.renderer.rules.footnote_caption = (tokens, idx, _options, env) => {
|
|
200
|
-
const meta = tokens[idx].meta;
|
|
201
|
-
const number = env.footnoteNumbers?.get(meta.label) ?? meta.id + 1;
|
|
202
|
-
return `[${number}${meta.subId > 0 ? `:${meta.subId}` : ""}]`;
|
|
203
|
-
};
|
|
204
|
-
md.renderer.rules.footnote_anchor_name = (tokens, idx, _options, env) => {
|
|
205
|
-
const meta = tokens[idx].meta;
|
|
206
|
-
const number = env.footnoteNumbers?.get(meta.label) ?? meta.id + 1;
|
|
207
|
-
return `${env.docId ? `-${env.docId}-` : ""}${number}`;
|
|
208
|
-
};
|
|
209
|
-
md.renderer.rules.footnote_open = (tokens, idx, options, env, renderer) => {
|
|
210
|
-
const meta = tokens[idx].meta;
|
|
211
|
-
const number = env.footnoteNumbers?.get(meta.label) ?? meta.id + 1;
|
|
212
|
-
const id = renderer.rules.footnote_anchor_name(tokens, idx, options, env, renderer);
|
|
213
|
-
return `<li id="fn${id}" class="footnote-item" value="${number}">`;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
183
|
/**
|
|
217
184
|
* Render a note body with Foundry's named-block markup.
|
|
218
185
|
*
|
|
@@ -232,12 +199,7 @@ md.renderer.rules.footnote_open = (tokens, idx, options, env, renderer) => {
|
|
|
232
199
|
* @returns {string} The rendered HTML.
|
|
233
200
|
*/
|
|
234
201
|
export function renderFoundryMarkdown(body, figures, footnoteNumbers, docId, resolveRole, runs) {
|
|
235
|
-
|
|
236
|
-
const figured = renderFigureBlocks(marked, (block) => md.render(block), figures, {
|
|
237
|
-
resolveRole,
|
|
238
|
-
});
|
|
239
|
-
const blocks = renderBlocks(figured.markdown, "foundry");
|
|
240
|
-
return md.render(renderAlerts(blocks.markdown, "foundry").markdown, { footnoteNumbers, docId });
|
|
202
|
+
return renderer.render(body, { runs, figures, resolveRole, footnoteNumbers, docId });
|
|
241
203
|
}
|
|
242
204
|
|
|
243
205
|
/**
|
|
@@ -983,7 +945,7 @@ export function buildContentLinkIndex(
|
|
|
983
945
|
* @param {number} [ctx.bodyLine] - 1-based file line of the body's first line.
|
|
984
946
|
* @param {number} [ctx.bodyColumn] - 1-based file column of the same character.
|
|
985
947
|
* @param {Array<{line: number, generated: boolean}>} [ctx.lineMap] - Which
|
|
986
|
-
* authored line each body line came from, from {@link
|
|
948
|
+
* authored line each body line came from, from {@link module:engine/content-tables.expandContentTables}.
|
|
987
949
|
* @returns {{markdown: string, unresolved: Array<object>}}
|
|
988
950
|
* @throws {Error} On any link that does not resolve — an unlabelled one, a
|
|
989
951
|
* target that is not an address, or an address nothing publishes — and on a
|
|
@@ -1086,11 +1048,9 @@ export function convertNoteWikilinks(
|
|
|
1086
1048
|
}
|
|
1087
1049
|
|
|
1088
1050
|
for (const u of result.unresolved) {
|
|
1089
|
-
// Every class fails, and every class is worded by the shared table
|
|
1090
|
-
//
|
|
1091
|
-
//
|
|
1092
|
-
// two different things about the same mistake — and a class the pack
|
|
1093
|
-
// build alone knew how to describe is how they came apart before.
|
|
1051
|
+
// Every class fails, and every class is worded by the shared table,
|
|
1052
|
+
// so an author who ran the pack build first and the link checker second
|
|
1053
|
+
// is told one thing about one mistake.
|
|
1094
1054
|
//
|
|
1095
1055
|
// The note's name is appended rather than woven in: the message is the
|
|
1096
1056
|
// defect, the name is the context this build can add.
|
package/engine/homepage.mjs
CHANGED
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
* module, which is most of the packages that need a homepage and nothing else.
|
|
44
44
|
*
|
|
45
45
|
* **Published at the package root, addressed like every other note.** A
|
|
46
|
-
* homepage is
|
|
47
|
-
*
|
|
46
|
+
* homepage is rendered at `/<package>/` — the address a reader expects a
|
|
47
|
+
* package's front page at,
|
|
48
48
|
* and the one `package.json`'s `homepage` states. It still declares a
|
|
49
49
|
* `shortcode` — conventionally {@link HOMEPAGE_SHORTCODE} — because that is what
|
|
50
50
|
* a link is written with: `[[homepage-root|Text]]` is an ordinary wikilink, and
|
|
@@ -96,19 +96,6 @@ export const HOMEPAGE_FIELDS = Object.freeze([]);
|
|
|
96
96
|
*/
|
|
97
97
|
export const HOMEPAGE_SHORTCODE = "root";
|
|
98
98
|
|
|
99
|
-
/**
|
|
100
|
-
* The file a homepage is written to, relative to the package's site root.
|
|
101
|
-
*
|
|
102
|
-
* The mount's own `_index.md`: Hugo renders it as the `home` kind, at
|
|
103
|
-
* `baseURL` — which is `/<package>/`, the package's own address. One fixed
|
|
104
|
-
* destination rather than one derived from the note's address, because the
|
|
105
|
-
* homepage's address *is* the package root; the note's `shortcode` names the
|
|
106
|
-
* page in links and decides no file.
|
|
107
|
-
*
|
|
108
|
-
* @type {string}
|
|
109
|
-
*/
|
|
110
|
-
export const HOMEPAGE_DESTINATION = "_index.md";
|
|
111
|
-
|
|
112
99
|
/**
|
|
113
100
|
* Whether a note's frontmatter declares the homepage type.
|
|
114
101
|
*
|
|
@@ -337,8 +324,10 @@ function positionOfType(file) {
|
|
|
337
324
|
* authored `name.full` wins, because a front page may greet a reader
|
|
338
325
|
* differently from a package browser.
|
|
339
326
|
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
327
|
+
* A package with no manifest title — a `documentation` package has no manifest
|
|
328
|
+
* at all — takes `site.title`, the name its site is known by. It falls back to
|
|
329
|
+
* `contentPackage` last, so a package that states neither still yields a
|
|
330
|
+
* titled page rather than a blank heading.
|
|
342
331
|
*
|
|
343
332
|
* @param {object|null|undefined} fm - The note's frontmatter.
|
|
344
333
|
* @param {object} config - The resolved configuration.
|
|
@@ -351,7 +340,9 @@ export function homepageTitle(fm, config) {
|
|
|
351
340
|
config?.packageBuild?.manifest
|
|
352
341
|
);
|
|
353
342
|
const title = manifest?.title;
|
|
354
|
-
|
|
343
|
+
if (typeof title === "string" && title.trim()) return title;
|
|
344
|
+
const site = config?.site?.title;
|
|
345
|
+
return typeof site === "string" && site.trim() ? site : config.contentPackage;
|
|
355
346
|
}
|
|
356
347
|
|
|
357
348
|
/**
|
|
@@ -359,20 +350,17 @@ export function homepageTitle(fm, config) {
|
|
|
359
350
|
*
|
|
360
351
|
* The note's own, plus the two derived values every emitted page carries: the
|
|
361
352
|
* resolved `title`, and the package the build derived — no note declares one
|
|
362
|
-
* and the theme's
|
|
353
|
+
* and the theme's breadcrumbs read.
|
|
363
354
|
*
|
|
364
|
-
* **No `url` and no `slug`.**
|
|
365
|
-
*
|
|
366
|
-
* address to state; a content page states one because its file sits under the
|
|
367
|
-
* mount and its address does not.
|
|
355
|
+
* **No `url` and no `slug`.** The homepage publishes at the package root, so
|
|
356
|
+
* the page has no address to state.
|
|
368
357
|
*
|
|
369
|
-
* An authored `aliases` is dropped
|
|
370
|
-
*
|
|
371
|
-
* redirect stub at each one.
|
|
358
|
+
* An authored `aliases` is dropped, as it is on every other page: this build
|
|
359
|
+
* emits no redirects.
|
|
372
360
|
*
|
|
373
361
|
* `related` is derived like every other page's — what links to the homepage
|
|
374
362
|
* is a fact about the rest of the tree — so an authored value is dropped and
|
|
375
|
-
* the caller's block, where it has one, is
|
|
363
|
+
* the caller's block, where it has one, is set in its place.
|
|
376
364
|
*
|
|
377
365
|
* @param {object} fm - The note's frontmatter.
|
|
378
366
|
* @param {object} options - Options.
|
|
@@ -380,7 +368,7 @@ export function homepageTitle(fm, config) {
|
|
|
380
368
|
* @param {string} options.title - The resolved title.
|
|
381
369
|
* @param {object} [options.related] - The homepage's backlinks and mentions,
|
|
382
370
|
* where the site build found either.
|
|
383
|
-
* @returns {object} The frontmatter
|
|
371
|
+
* @returns {object} The frontmatter.
|
|
384
372
|
*/
|
|
385
373
|
export function homepageFrontmatter(fm, { contentPackage, title, related }) {
|
|
386
374
|
const data = { ...fm, package: contentPackage, title };
|
|
@@ -395,7 +383,7 @@ export function homepageFrontmatter(fm, { contentPackage, title, related }) {
|
|
|
395
383
|
*
|
|
396
384
|
* Reference-style links are deliberately not matched: a homepage is published
|
|
397
385
|
* verbatim, so a `[x][y]` whose definition sits in the body reaches the reader
|
|
398
|
-
* as
|
|
386
|
+
* as authored, and one whose definition is missing is a defect the
|
|
399
387
|
* rendered page shows for itself.
|
|
400
388
|
*
|
|
401
389
|
* @type {RegExp}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
3
|
+
* Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
|
|
4
|
+
*
|
|
5
|
+
* This work is licensed under the GNU General Public License v3.0 (GPLv3).
|
|
6
|
+
* You may copy, modify, and distribute it under the terms of that license.
|
|
7
|
+
*
|
|
8
|
+
* For full terms, see the LICENSE.md file in the project root or visit:
|
|
9
|
+
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* **Minified site pages.** {@link minifyHtml} drops what a browser does not
|
|
16
|
+
* read: comments, and every run of white space but one character.
|
|
17
|
+
*
|
|
18
|
+
* What a reader sees is unchanged. A run of white space between two words or
|
|
19
|
+
* two tags still separates them, as one space; it is only made shorter. The
|
|
20
|
+
* places where white space is the content are kept exactly as written: a
|
|
21
|
+
* `<pre>`, a `<textarea>`, a `<script>` or `<style>`, and a verse's lines,
|
|
22
|
+
* which set their spacing as authored. A tag is kept as written too, its
|
|
23
|
+
* attribute values included.
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/** The elements whose content is written out as it stands. */
|
|
29
|
+
const VERBATIM = /^<(pre|textarea|script|style)\b/i;
|
|
30
|
+
|
|
31
|
+
/** A verse's spans, whose white space is set as authored. */
|
|
32
|
+
const VERSE_SPAN = /\bclass\s*=\s*"[^"]*\bverse-(?:line|column|part)\b/i;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Minify a page.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} html - A complete document.
|
|
38
|
+
* @returns {string} The same document without comments and with each run of
|
|
39
|
+
* white space outside the verbatim elements cut to one character: a newline
|
|
40
|
+
* where the run held one, a space otherwise.
|
|
41
|
+
*/
|
|
42
|
+
export function minifyHtml(html) {
|
|
43
|
+
const source = String(html ?? "");
|
|
44
|
+
const pieces =
|
|
45
|
+
/<!--[\s\S]*?-->|<(pre|textarea|script|style)\b[^>]*>[\s\S]*?<\/\1\s*>|<[^>]*>|[^<]+|</gi;
|
|
46
|
+
const verse = [];
|
|
47
|
+
let out = "";
|
|
48
|
+
for (const [piece] of source.matchAll(pieces)) {
|
|
49
|
+
if (piece.startsWith("<!--")) {
|
|
50
|
+
// A conditional comment is read by the browser it names.
|
|
51
|
+
if (piece.startsWith("<!--[if")) out += piece;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (piece.startsWith("<")) {
|
|
55
|
+
if (VERBATIM.test(piece)) {
|
|
56
|
+
out += piece;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (/^<span\b/i.test(piece)) verse.push(verse.at(-1) || VERSE_SPAN.test(piece));
|
|
60
|
+
else if (/^<\/span\s*>/i.test(piece)) verse.pop();
|
|
61
|
+
out += piece;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
out +=
|
|
65
|
+
verse.at(-1) ? piece : (
|
|
66
|
+
piece.replace(/\s+/g, (run) => (run.includes("\n") ? "\n" : " "))
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return out.replace(/^\s+/, "");
|
|
70
|
+
}
|
package/engine/index.mjs
CHANGED
|
@@ -216,6 +216,12 @@ export * as siteBuild from "./site-build.mjs";
|
|
|
216
216
|
/** In-memory page rendering for an editor preview. */
|
|
217
217
|
export * as sitePreview from "./site-preview.mjs";
|
|
218
218
|
|
|
219
|
+
/** What an editor with a content index gives the preview, so it renders as the site does. */
|
|
220
|
+
export * as previewIndex from "./preview-index.mjs";
|
|
221
|
+
|
|
222
|
+
/** The one markdown-it configuration every target renders through. */
|
|
223
|
+
export * as contentRender from "./content-render.mjs";
|
|
224
|
+
|
|
219
225
|
/** Address rules every content tree is linted against: shape, uniqueness, alias. */
|
|
220
226
|
export * as contentLint from "./content-lint.mjs";
|
|
221
227
|
|
|
@@ -244,9 +250,6 @@ export * as pathnames from "./pathnames.mjs";
|
|
|
244
250
|
/** Resolving every link in a tree, and the ones that land nowhere. */
|
|
245
251
|
export * as contentLinks from "./content-links.mjs";
|
|
246
252
|
|
|
247
|
-
/** Wikilinks resolved to a **web URL** — the site half of the pair below. */
|
|
248
|
-
export * as webWikilinks from "./web-wikilinks.mjs";
|
|
249
|
-
|
|
250
253
|
/** Prepared SQL content tables, expanded into Markdown at compile time. */
|
|
251
254
|
export * as contentTables from "./content-tables.mjs";
|
|
252
255
|
|
|
@@ -262,10 +265,10 @@ export * as documentSubtypes from "./document-subtypes.mjs";
|
|
|
262
265
|
/** Which types carry documentation of their own, and where it is addressed. */
|
|
263
266
|
export * as itemDocs from "./item-docs.mjs";
|
|
264
267
|
|
|
265
|
-
/**
|
|
268
|
+
/** The link resolver: the pack index, the views, and each target's link form. */
|
|
266
269
|
export * as wikilinks from "./wikilinks.mjs";
|
|
267
270
|
|
|
268
|
-
/** What a `[[…]]` is, before
|
|
271
|
+
/** What a `[[…]]` is, before the resolver decides where it points. */
|
|
269
272
|
export * as wikilinkSyntax from "./wikilink-syntax.mjs";
|
|
270
273
|
|
|
271
274
|
/** The address index a site build resolves its wikilinks against. */
|
package/engine/language-rows.mjs
CHANGED
|
@@ -130,7 +130,7 @@ export const NEAR_NAME_COLUMNS = Object.freeze([...IDENTITY, "near", "given", "m
|
|
|
130
130
|
/** Every column of the `negation` relation, in order: one row per language. */
|
|
131
131
|
export const NEGATION_COLUMNS = Object.freeze(["language", "particle", "mutation"]);
|
|
132
132
|
/** Every column of the `stress` relation, in order. */
|
|
133
|
-
export const STRESS_COLUMNS = Object.freeze(["language", "
|
|
133
|
+
export const STRESS_COLUMNS = Object.freeze(["language", "two", "longer", "mark"]);
|
|
134
134
|
/** Every column of the `finals` relation, in order. */
|
|
135
135
|
export const FINAL_COLUMNS = Object.freeze([...IDENTITY, ...FINAL_KEYS]);
|
|
136
136
|
/** Every column of the `syllables` relation, in order: one row per language. */
|
|
@@ -789,7 +789,13 @@ export function stressRows(records) {
|
|
|
789
789
|
const rows = [];
|
|
790
790
|
for (const [language, record] of languagesOf(records)) {
|
|
791
791
|
const stress = soundsOf(isMap(record.data) ? record.data : {}).stress;
|
|
792
|
-
if (
|
|
792
|
+
if (isMap(stress))
|
|
793
|
+
rows.push({
|
|
794
|
+
language,
|
|
795
|
+
two: stress.two ?? null,
|
|
796
|
+
longer: stress.longer ?? null,
|
|
797
|
+
mark: stress.mark ?? null,
|
|
798
|
+
});
|
|
793
799
|
}
|
|
794
800
|
return rows;
|
|
795
801
|
}
|
|
@@ -126,13 +126,21 @@ export const HELD_CLIPS = Object.freeze(["first"]);
|
|
|
126
126
|
/** How often a group of clusters stands inside a word. */
|
|
127
127
|
export const CLUSTER_USES = Object.freeze(["common", "sparing"]);
|
|
128
128
|
|
|
129
|
-
/**
|
|
130
|
-
export const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
/** The syllable a word of two stresses. */
|
|
130
|
+
export const STRESS_TWO = Object.freeze(["first", "last"]);
|
|
131
|
+
|
|
132
|
+
/** The syllable a word of three or more stresses, counted from its end. */
|
|
133
|
+
export const STRESS_LONGER = Object.freeze(["antepenultimate", "penultimate", "final"]);
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The diacritics that mark a stress the rule would not choose, with the
|
|
137
|
+
* combining character each is written with.
|
|
138
|
+
*/
|
|
139
|
+
export const STRESS_MARKS = Object.freeze({
|
|
140
|
+
acute: "\u0301",
|
|
141
|
+
grave: "\u0300",
|
|
142
|
+
circumflex: "\u0302",
|
|
143
|
+
});
|
|
136
144
|
|
|
137
145
|
/** Which sounds meet where two parts of a word join. */
|
|
138
146
|
export const JOIN_MEETINGS = Object.freeze(["C+C", "V+C", "V+V"]);
|
|
@@ -690,6 +698,39 @@ export const HARMONY_FIELDS = Object.freeze([
|
|
|
690
698
|
}),
|
|
691
699
|
]);
|
|
692
700
|
|
|
701
|
+
/**
|
|
702
|
+
* The keys of a language's `data.sounds.stress`.
|
|
703
|
+
*
|
|
704
|
+
* @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
|
|
705
|
+
*/
|
|
706
|
+
export const STRESS_FIELDS = Object.freeze([
|
|
707
|
+
Object.freeze({
|
|
708
|
+
name: "two",
|
|
709
|
+
kind: "string",
|
|
710
|
+
required: true,
|
|
711
|
+
allowed: STRESS_TWO,
|
|
712
|
+
shape: `one of ${STRESS_TWO.join(", ")}`,
|
|
713
|
+
describe: "The stressed syllable of a word of two syllables.",
|
|
714
|
+
}),
|
|
715
|
+
Object.freeze({
|
|
716
|
+
name: "longer",
|
|
717
|
+
kind: "string",
|
|
718
|
+
required: true,
|
|
719
|
+
allowed: STRESS_LONGER,
|
|
720
|
+
shape: `one of ${STRESS_LONGER.join(", ")}`,
|
|
721
|
+
describe: "The stressed syllable of a word of three or more, counted from its end.",
|
|
722
|
+
}),
|
|
723
|
+
Object.freeze({
|
|
724
|
+
name: "mark",
|
|
725
|
+
kind: "string",
|
|
726
|
+
allowed: Object.freeze(Object.keys(STRESS_MARKS)),
|
|
727
|
+
shape: `one of ${Object.keys(STRESS_MARKS).join(", ")}`,
|
|
728
|
+
describe:
|
|
729
|
+
"The diacritic that marks a stress the rule would not choose; it moves the stress to " +
|
|
730
|
+
"the syllable it sits on.",
|
|
731
|
+
}),
|
|
732
|
+
]);
|
|
733
|
+
|
|
693
734
|
/**
|
|
694
735
|
* The keys of a language's `data.sounds.syllables`: what a syllable may open
|
|
695
736
|
* and close on, and what a word may.
|
|
@@ -901,10 +942,10 @@ export const SOUND_FIELDS = Object.freeze([
|
|
|
901
942
|
}),
|
|
902
943
|
Object.freeze({
|
|
903
944
|
name: "stress",
|
|
904
|
-
kind: "
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
describe: "Where a word's stress falls.",
|
|
945
|
+
kind: "map",
|
|
946
|
+
shape: "a map — `{ two, longer, mark? }`",
|
|
947
|
+
fields: STRESS_FIELDS,
|
|
948
|
+
describe: "Where a word's stress falls, as a rule a program reads.",
|
|
908
949
|
}),
|
|
909
950
|
Object.freeze({
|
|
910
951
|
name: "finals",
|
|
@@ -1623,6 +1664,52 @@ export const VERB_PERSON_FIELDS = Object.freeze(
|
|
|
1623
1664
|
),
|
|
1624
1665
|
);
|
|
1625
1666
|
|
|
1667
|
+
/**
|
|
1668
|
+
* The endings `data.grammar.native` writes under a logographic map: the noun
|
|
1669
|
+
* plural, then the six persons of the verb pattern.
|
|
1670
|
+
*/
|
|
1671
|
+
export const WRITTEN_ENDINGS = Object.freeze([
|
|
1672
|
+
"plural",
|
|
1673
|
+
...VERB_PERSON_FIELDS.map((person) => person.name),
|
|
1674
|
+
]);
|
|
1675
|
+
|
|
1676
|
+
/** The keys of one `data.grammar.native` entry. */
|
|
1677
|
+
const GRAMMAR_NATIVE_FIELDS = Object.freeze([
|
|
1678
|
+
Object.freeze({
|
|
1679
|
+
name: "ending",
|
|
1680
|
+
kind: "string",
|
|
1681
|
+
required: true,
|
|
1682
|
+
allowed: WRITTEN_ENDINGS,
|
|
1683
|
+
shape: `one of ${WRITTEN_ENDINGS.join(", ")}`,
|
|
1684
|
+
describe:
|
|
1685
|
+
"The ending written: `plural` for a noun's plural, or a person of `verbs.persons` " +
|
|
1686
|
+
"for a verb's present form.",
|
|
1687
|
+
}),
|
|
1688
|
+
Object.freeze({
|
|
1689
|
+
name: "map",
|
|
1690
|
+
kind: "string",
|
|
1691
|
+
required: true,
|
|
1692
|
+
shape: "a logographic mapping note's `data.map.name`",
|
|
1693
|
+
describe: "The logographic map the ending is written for.",
|
|
1694
|
+
}),
|
|
1695
|
+
Object.freeze({
|
|
1696
|
+
name: "font",
|
|
1697
|
+
kind: "string",
|
|
1698
|
+
shape: "a face the map lists",
|
|
1699
|
+
describe:
|
|
1700
|
+
"The one face the writing is for; unstated, it is for every face the map lists, " +
|
|
1701
|
+
"and a writing stated for a face wins over it there.",
|
|
1702
|
+
}),
|
|
1703
|
+
Object.freeze({
|
|
1704
|
+
name: "text",
|
|
1705
|
+
kind: "string",
|
|
1706
|
+
required: true,
|
|
1707
|
+
allowEmpty: true,
|
|
1708
|
+
shape: "the ending in the script, as the map's characters; empty writes the stem alone",
|
|
1709
|
+
describe: "The signs written after the stem's writing.",
|
|
1710
|
+
}),
|
|
1711
|
+
]);
|
|
1712
|
+
|
|
1626
1713
|
/** The two alternatives of a supplied optional verb pattern. */
|
|
1627
1714
|
const VERB_PATTERN_FIELDS = Object.freeze([
|
|
1628
1715
|
Object.freeze({
|
|
@@ -1749,6 +1836,19 @@ const GRAMMAR_FIELDS = Object.freeze([
|
|
|
1749
1836
|
"named suffix attaches to what is left; a participle closing on an `agreement` " +
|
|
1750
1837
|
"ending agrees. Read by the mapped-run word check.",
|
|
1751
1838
|
}),
|
|
1839
|
+
Object.freeze({
|
|
1840
|
+
name: "native",
|
|
1841
|
+
kind: "list",
|
|
1842
|
+
shape: "a list of `{ ending, map, font?, text }`",
|
|
1843
|
+
entries: Object.freeze({
|
|
1844
|
+
kind: "map",
|
|
1845
|
+
shape: "a map — `{ ending, map, font?, text }`",
|
|
1846
|
+
fields: GRAMMAR_NATIVE_FIELDS,
|
|
1847
|
+
}),
|
|
1848
|
+
describe:
|
|
1849
|
+
"Under a logographic map, the signs a noun's plural or a verb's present form is " +
|
|
1850
|
+
"written with after its stem's writing, one entry per ending, map and face.",
|
|
1851
|
+
}),
|
|
1752
1852
|
]);
|
|
1753
1853
|
|
|
1754
1854
|
/**
|
|
@@ -1762,11 +1862,12 @@ export const LANGUAGE_DATA_FIELDS = Object.freeze([
|
|
|
1762
1862
|
Object.freeze({
|
|
1763
1863
|
name: "grammar",
|
|
1764
1864
|
kind: "map",
|
|
1765
|
-
shape: "a map — `{ plural?, verbs?, agreement?, participles? }`",
|
|
1865
|
+
shape: "a map — `{ plural?, verbs?, agreement?, participles?, native? }`",
|
|
1766
1866
|
fields: GRAMMAR_FIELDS,
|
|
1767
1867
|
describe:
|
|
1768
|
-
"Optional noun plurals, one verb pattern, agreement and
|
|
1769
|
-
"presentation
|
|
1868
|
+
"Optional noun plurals, one verb pattern, agreement, participles and the endings' " +
|
|
1869
|
+
"logographic writings, for dictionary presentation, the mapped-run word check and " +
|
|
1870
|
+
"logographic maps. Only the shape of supplied keys is " +
|
|
1770
1871
|
"checked; no word must follow or state a rule. A language skill note only.",
|
|
1771
1872
|
}),
|
|
1772
1873
|
listOfMaps(
|