@heroiclands/package-build 23.1.1 → 23.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 +63 -0
- package/bin/content-commands.mjs +68 -149
- package/bin/package-build.mjs +56 -10
- package/ci/check-banners.mjs +42 -6
- package/ci/confirm-npm-version.mjs +135 -0
- package/ci/content-format-reference.mjs +14 -5
- package/config.mjs +1 -0
- package/container.mjs +185 -4
- package/content-config.mjs +333 -210
- package/deploy.mjs +116 -10
- package/docs/api.md +238 -246
- package/docs/authoring/assets.md +11 -5
- package/docs/authoring/frontmatter.md +1 -1
- package/docs/authoring/links-and-markup.md +87 -0
- package/docs/commands.md +138 -99
- package/docs/configuration.md +277 -125
- package/docs/content-format.md +2 -0
- package/docs/diagnostics.md +48 -13
- package/docs/guides/book.md +341 -21
- package/docs/guides/e2e.md +13 -2
- package/docs/guides/icons.md +14 -4
- package/docs/guides/module-project.md +18 -8
- package/docs/guides/release-and-deploy.md +32 -0
- package/docs/guides/site.md +5 -2
- package/docs/project-setup.md +30 -10
- package/docs/reference/format-details.md +373 -170
- package/docs/reference/note-types.md +128 -109
- package/docs/reference/theme-pages.md +31 -6
- package/e2e.mjs +140 -28
- package/engine/actor-compiler.mjs +22 -31
- package/engine/address-charset.mjs +4 -17
- package/engine/address-fields.mjs +1 -1
- package/engine/address-render.mjs +12 -1
- package/engine/address-values.mjs +6 -0
- package/engine/address.mjs +46 -33
- package/engine/art-fields.mjs +30 -5
- package/engine/art-slots.mjs +10 -1
- package/engine/asset-bindings.mjs +12 -1
- package/engine/base-compiler.mjs +34 -65
- package/engine/being-age.mjs +2 -7
- package/engine/being-measurements.mjs +12 -1
- package/engine/calendar-artifacts.mjs +6 -0
- package/engine/calendar-choice.mjs +12 -1
- package/engine/calendar-format.mjs +12 -1
- package/engine/calendar-human.mjs +12 -1
- package/engine/compile-corpus.mjs +3 -1
- package/engine/content-address.mjs +9 -12
- package/engine/content-alerts.mjs +13 -1
- package/engine/content-blocks.mjs +14 -3
- package/engine/content-embeds.mjs +11 -3
- package/engine/content-figures.mjs +9 -0
- package/engine/content-footnotes.mjs +12 -1
- package/engine/content-format-check.mjs +11 -262
- package/engine/content-format.yaml +5 -2
- package/engine/content-images.mjs +3 -0
- package/engine/content-index.mjs +443 -20
- package/engine/content-links.mjs +29 -35
- package/engine/content-lint.mjs +2 -3
- package/engine/content-poetry.mjs +12 -1
- package/engine/content-slug.mjs +2 -14
- package/engine/content-spans.mjs +13 -1
- package/engine/content-tables.mjs +12 -1
- package/engine/culture-choice.mjs +210 -13
- package/engine/data-keys.mjs +19 -16
- package/engine/date-conversion.mjs +12 -1
- package/engine/declaration-check.mjs +9 -0
- package/engine/derived-fields.mjs +6 -7
- package/engine/diagnostics.mjs +34 -4
- package/engine/docs-checks.mjs +9 -0
- package/engine/document-subtypes.mjs +47 -34
- package/engine/event-views.mjs +139 -14
- package/engine/exported-scene.mjs +92 -28
- package/engine/extension-attributes.mjs +12 -1
- package/engine/field-spec.mjs +11 -102
- package/engine/folder-notes.mjs +0 -64
- package/engine/foreign-catalog.mjs +2 -1
- package/engine/format-generated.mjs +9 -0
- package/engine/foundry-entries.mjs +10 -28
- package/engine/frontmatter-lint.mjs +83 -392
- package/engine/frontmatter.mjs +20 -70
- package/engine/generate.mjs +10 -15
- package/engine/heading-attributes.mjs +12 -1
- package/engine/helpers.mjs +41 -102
- package/engine/holdings.mjs +1 -1
- package/engine/homepage.mjs +3 -10
- package/engine/ids.mjs +1 -167
- package/engine/index-records.mjs +6 -4
- package/engine/index.mjs +0 -3
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +13 -14
- package/engine/item-compiler.mjs +4 -10
- package/engine/item-docs.mjs +3 -5
- package/engine/item-registry.mjs +2 -10
- package/engine/journals.mjs +1 -5
- package/engine/literature-notes.mjs +4 -12
- package/engine/macros.mjs +1 -2
- package/engine/map-graphviz.mjs +12 -1
- package/engine/markdown-expressions.mjs +12 -1
- package/engine/markdownlint-run.mjs +567 -0
- package/engine/metadata-index.mjs +42 -12
- package/engine/note-addresses.mjs +143 -35
- package/engine/note-claims.mjs +14 -28
- package/engine/note-dates.mjs +3 -3
- package/engine/note-frontmatter.mjs +6 -0
- package/engine/note-ids.mjs +8 -14
- package/engine/note-package.mjs +8 -25
- package/engine/note-state.mjs +1 -3
- package/engine/note-vocabulary.mjs +148 -84
- package/engine/number-words.mjs +12 -1
- package/engine/pack-config.mjs +15 -25
- package/engine/pack-router.mjs +10 -16
- package/engine/pathnames.mjs +8 -22
- package/engine/pdf-build.mjs +773 -121
- package/engine/pdf-coverage.mjs +188 -0
- package/engine/pdf-index.mjs +54 -7
- package/engine/pdf-pages.mjs +247 -0
- package/engine/pdf-render.mjs +114 -4
- package/engine/pdf-toc.mjs +29 -32
- package/engine/project-init.mjs +46 -6
- package/engine/prose-config.mjs +1 -1
- package/engine/prose-lint.mjs +52 -88
- package/engine/readability-lint.mjs +9 -0
- package/engine/reckoning-markers.mjs +12 -1
- package/engine/reference-targets.mjs +7 -0
- package/engine/runtime-only-fields.mjs +5 -8
- package/engine/scene-levels.mjs +2 -2
- package/engine/scenes.mjs +1 -1
- package/engine/shortcode-references.mjs +7 -0
- package/engine/site-build.mjs +30 -16
- package/engine/site-index.mjs +10 -16
- package/engine/site-preview.mjs +6 -0
- package/engine/site-root.mjs +8 -1
- package/engine/social-tie-terms.mjs +12 -1
- package/engine/social-ties.mjs +3 -0
- package/engine/sql-tables.mjs +56 -20
- package/engine/standing-terms.mjs +11 -1
- package/engine/standings.mjs +11 -27
- package/engine/system-block.mjs +39 -141
- package/engine/system-vocabulary.mjs +6 -0
- package/engine/walk-files.mjs +69 -0
- package/engine/web-wikilinks.mjs +23 -3
- package/engine/wikilink-syntax.mjs +32 -21
- package/engine/wikilinks.mjs +27 -16
- package/githooks/attribution.mjs +8 -0
- package/githooks/commit-message.mjs +9 -0
- package/hm3/actors.mjs +9 -48
- package/hm3/default-item-art.mjs +9 -9
- package/hm3/item-fields.mjs +2 -9
- package/hm3/template-priority.mjs +6 -7
- package/hugo-theme/data/banner-kinds.yaml +78 -0
- package/hugo-theme/data/banners.yaml +2 -3
- package/hugo-theme/layouts/404.html +3 -3
- package/hugo-theme/layouts/partials/banner-url.html +31 -7
- package/hugo-theme/layouts/partials/hero-banner.html +13 -14
- package/hugo-theme/layouts/partials/related.html +1 -1
- package/hugo-theme/layouts/partials/warn-missing-banner.html +1 -1
- package/hugo-theme/static/css/style.css +1 -1
- package/manifest.mjs +11 -4
- package/markdownlint-config.mjs +1 -1
- package/package.json +6 -3
- package/release.mjs +21 -14
- package/sohl/actors.mjs +16 -27
- package/sohl/default-item-art.mjs +3 -3
- package/sohl/document-subtypes.mjs +1 -16
- package/sohl/infobox.mjs +2 -3
- package/sohl/item-builders.mjs +5 -8
- package/sohl/item-fields.mjs +5 -35
- package/sohl/items.mjs +0 -4
- package/sohl/kb-passes.mjs +3 -3
- package/types/container.d.mts +116 -5
- package/types/content-config.d.mts +83 -35
- package/types/deploy.d.mts +42 -6
- package/types/e2e.d.mts +35 -3
- package/types/engine/address-charset.d.mts +4 -17
- package/types/engine/address.d.mts +17 -8
- package/types/engine/art-fields.d.mts +7 -4
- package/types/engine/art-slots.d.mts +6 -0
- package/types/engine/base-compiler.d.mts +15 -17
- package/types/engine/content-address.d.mts +9 -12
- package/types/engine/content-embeds.d.mts +4 -2
- package/types/engine/content-format-check.d.mts +0 -64
- package/types/engine/content-index.d.mts +82 -3
- package/types/engine/content-links.d.mts +2 -4
- package/types/engine/culture-choice.d.mts +51 -8
- package/types/engine/data-keys.d.mts +2 -2
- package/types/engine/derived-fields.d.mts +1 -2
- package/types/engine/diagnostics.d.mts +27 -4
- package/types/engine/document-subtypes.d.mts +12 -31
- package/types/engine/event-views.d.mts +14 -2
- package/types/engine/exported-scene.d.mts +3 -2
- package/types/engine/field-spec.d.mts +13 -122
- package/types/engine/folder-notes.d.mts +0 -39
- package/types/engine/foreign-catalog.d.mts +2 -1
- package/types/engine/foundry-entries.d.mts +4 -5
- package/types/engine/frontmatter-lint.d.mts +2 -2
- package/types/engine/frontmatter.d.mts +19 -45
- package/types/engine/generate.d.mts +1 -1
- package/types/engine/helpers.d.mts +25 -42
- package/types/engine/homepage.d.mts +3 -10
- package/types/engine/ids.d.mts +0 -114
- package/types/engine/index-records.d.mts +6 -4
- package/types/engine/index.d.mts +0 -1
- package/types/engine/infobox-render.d.mts +7 -1
- package/types/engine/infobox.d.mts +3 -2
- package/types/engine/item-docs.d.mts +1 -1
- package/types/engine/item-registry.d.mts +2 -4
- package/types/engine/literature-notes.d.mts +1 -1
- package/types/engine/markdownlint-run.d.mts +40 -0
- package/types/engine/metadata-index.d.mts +9 -1
- package/types/engine/note-addresses.d.mts +27 -2
- package/types/engine/note-claims.d.mts +3 -5
- package/types/engine/note-ids.d.mts +2 -4
- package/types/engine/note-package.d.mts +1 -1
- package/types/engine/note-state.d.mts +1 -3
- package/types/engine/note-vocabulary.d.mts +28 -21
- package/types/engine/pack-config.d.mts +2 -6
- package/types/engine/pack-router.d.mts +4 -4
- package/types/engine/pathnames.d.mts +3 -3
- package/types/engine/pdf-build.d.mts +98 -12
- package/types/engine/pdf-coverage.d.mts +60 -0
- package/types/engine/pdf-index.d.mts +34 -5
- package/types/engine/pdf-pages.d.mts +143 -0
- package/types/engine/pdf-render.d.mts +45 -1
- package/types/engine/pdf-toc.d.mts +12 -14
- package/types/engine/prose-config.d.mts +1 -1
- package/types/engine/prose-lint.d.mts +11 -10
- package/types/engine/runtime-only-fields.d.mts +2 -2
- package/types/engine/site-build.d.mts +9 -5
- package/types/engine/site-index.d.mts +4 -5
- package/types/engine/site-root.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -2
- package/types/engine/standing-terms.d.mts +2 -1
- package/types/engine/standings.d.mts +7 -9
- package/types/engine/system-block.d.mts +10 -44
- package/types/engine/walk-files.d.mts +15 -0
- package/types/engine/wikilink-syntax.d.mts +18 -19
- package/types/hm3/actors.d.mts +1 -2
- package/types/hm3/item-fields.d.mts +2 -4
- package/types/hm3/template-priority.d.mts +6 -7
- package/types/manifest.d.mts +3 -2
- package/types/release.d.mts +8 -7
- package/types/sohl/actors.d.mts +2 -1
- package/types/sohl/document-subtypes.d.mts +1 -2
- package/types/sohl/item-fields.d.mts +3 -7
- package/engine/retired-fields.mjs +0 -631
- package/types/engine/retired-fields.d.mts +0 -354
package/engine/wikilinks.mjs
CHANGED
|
@@ -36,7 +36,6 @@ import { readCanonicalKey } from "./content-address.mjs";
|
|
|
36
36
|
// is stated there and read here — the anchor and the label are this module's,
|
|
37
37
|
// and the tuple inside them is not.
|
|
38
38
|
import {
|
|
39
|
-
ITEM_DOC_PREFIX,
|
|
40
39
|
readQualifier,
|
|
41
40
|
resolveItemDocType,
|
|
42
41
|
parseAddress,
|
|
@@ -197,16 +196,7 @@ export function buildWikilinkIndex(
|
|
|
197
196
|
for (const v of foreignByKey.values()) {
|
|
198
197
|
if (v.type) foreignTypes.push(norm(v.type));
|
|
199
198
|
}
|
|
200
|
-
|
|
201
|
-
// vocabulary separate so the input alias can resolve to its base type.
|
|
202
|
-
for (const t of foreignTypes) {
|
|
203
|
-
if (!t.startsWith(ITEM_DOC_PREFIX)) types.add(t);
|
|
204
|
-
}
|
|
205
|
-
for (const t of foreignTypes) {
|
|
206
|
-
if (!t.startsWith(ITEM_DOC_PREFIX)) continue;
|
|
207
|
-
if (types.has(t.slice(ITEM_DOC_PREFIX.length))) continue;
|
|
208
|
-
types.add(t);
|
|
209
|
-
}
|
|
199
|
+
for (const t of foreignTypes) types.add(t);
|
|
210
200
|
|
|
211
201
|
// Every package an address may name: this one, plus every package a
|
|
212
202
|
// vendored manifest speaks for. What lets `thalorna-creature-grkrahk` be
|
|
@@ -274,7 +264,7 @@ function foreignHits(index, read) {
|
|
|
274
264
|
if (!read || read.reason || !index.foreign?.size) return [];
|
|
275
265
|
const tuple = completeAddress(read, { package: index.contentPackage, system: NOTE_SYSTEM });
|
|
276
266
|
const wanted = norm(tuple.type);
|
|
277
|
-
const shortcode =
|
|
267
|
+
const shortcode = read.shortcode;
|
|
278
268
|
|
|
279
269
|
// **An omitted package means this package**, so a short form
|
|
280
270
|
// addresses nothing foreign and never reaches a dependency's index. A link
|
|
@@ -300,6 +290,26 @@ function foreignHits(index, read) {
|
|
|
300
290
|
return hits;
|
|
301
291
|
}
|
|
302
292
|
|
|
293
|
+
/**
|
|
294
|
+
* What a `shortcode-not-lowercase` finding carries: the shortcode as written,
|
|
295
|
+
* and the lowercase spelling when a local note or a fetched dependency declares
|
|
296
|
+
* it.
|
|
297
|
+
*
|
|
298
|
+
* @param {object} index - From {@link buildWikilinkIndex}.
|
|
299
|
+
* @param {{shortcode: string, lowercase: object}} problem - The reader's verdict.
|
|
300
|
+
* @returns {{shortcode: string, declared?: string}} The finding's fields.
|
|
301
|
+
*/
|
|
302
|
+
function shortcodeCase(index, problem) {
|
|
303
|
+
const read = problem.lowercase;
|
|
304
|
+
const local =
|
|
305
|
+
(read.package ?? index.contentPackage) === index.contentPackage &&
|
|
306
|
+
index.byShortcode?.has(
|
|
307
|
+
`${resolveItemDocType(read.type, index.types) ?? read.type}/${read.shortcode}`,
|
|
308
|
+
);
|
|
309
|
+
const declared = local || foreignHits(index, read).length > 0;
|
|
310
|
+
return { shortcode: problem.shortcode, ...(declared ? { declared: read.shortcode } : {}) };
|
|
311
|
+
}
|
|
312
|
+
|
|
303
313
|
/**
|
|
304
314
|
* How an **unresolved** link renders.
|
|
305
315
|
*
|
|
@@ -335,8 +345,7 @@ function unresolvedLink(text, target) {
|
|
|
335
345
|
* **The wrapper carries the cue and nothing else.** The link itself is
|
|
336
346
|
* untouched — Foundry enriches inside HTML, so the `@UUID` still becomes a live
|
|
337
347
|
* content link, and the note is in the packs, the manifest and the index
|
|
338
|
-
* exactly as any other.
|
|
339
|
-
* which moved a note from published to unresolvable without saying so.
|
|
348
|
+
* exactly as any other.
|
|
340
349
|
*
|
|
341
350
|
* The appearance lives in `scss/components/_draft-link.scss`, beside the
|
|
342
351
|
* unresolved-link partial, not here.
|
|
@@ -409,8 +418,7 @@ export function convertWikilinks(markdown, { type, id, pack, docPack, index, cap
|
|
|
409
418
|
const slug = parsed.anchor || null;
|
|
410
419
|
|
|
411
420
|
// **Every link carries a label**. Without one there is nothing
|
|
412
|
-
// to resolve against:
|
|
413
|
-
// up in is retired, and a shortcode is an address rather than prose, so
|
|
421
|
+
// to resolve against: a shortcode is an address rather than prose, so
|
|
414
422
|
// the link has neither a target this build can find nor text to show.
|
|
415
423
|
// Reported before anything else, including the same-page form, because
|
|
416
424
|
// it is a statement about how the link is *written* — `[[#slug]]` needs
|
|
@@ -452,6 +460,9 @@ export function convertWikilinks(markdown, { type, id, pack, docPack, index, cap
|
|
|
452
460
|
target,
|
|
453
461
|
offset,
|
|
454
462
|
reason: qualified?.reason ?? "not-an-address",
|
|
463
|
+
...(qualified?.reason === "shortcode-not-lowercase" ?
|
|
464
|
+
shortcodeCase(index, qualified)
|
|
465
|
+
: {}),
|
|
455
466
|
addressed: true,
|
|
456
467
|
});
|
|
457
468
|
return unresolvedLink(text || target, target);
|
package/githooks/attribution.mjs
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
2
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
|
+
*
|
|
3
11
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
12
|
*/
|
|
5
13
|
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
2
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
|
+
*
|
|
3
11
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
12
|
*/
|
|
13
|
+
|
|
5
14
|
import { readFileSync } from "node:fs";
|
|
6
15
|
import { relative } from "node:path";
|
|
7
16
|
import { attribution } from "./attribution.mjs";
|
package/hm3/actors.mjs
CHANGED
|
@@ -46,20 +46,13 @@
|
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
48
|
import { resolveName } from "../engine/helpers.mjs";
|
|
49
|
-
import { buildFromFields,
|
|
49
|
+
import { buildFromFields, STRING } from "../engine/field-spec.mjs";
|
|
50
50
|
import { SystemActorCompiler } from "../engine/actor-compiler.mjs";
|
|
51
51
|
import { renderSection } from "../engine/anchored-sections.mjs";
|
|
52
52
|
import { withDraftNotice } from "../engine/draft-notice.mjs";
|
|
53
53
|
import { documentSubtype } from "../engine/document-subtypes.mjs";
|
|
54
54
|
import { HM3_DOCUMENT_SUBTYPES } from "./document-subtypes.mjs";
|
|
55
55
|
import { templateFlags } from "./template-priority.mjs";
|
|
56
|
-
// The retirement window's reports, shared with the frontmatter lint so the
|
|
57
|
-
// two cannot say different things about the same key.
|
|
58
|
-
import {
|
|
59
|
-
legacyKeyMessage,
|
|
60
|
-
locateFrontmatterKey,
|
|
61
|
-
retiredTopLevelMessage,
|
|
62
|
-
} from "../engine/retired-fields.mjs";
|
|
63
56
|
// The note-level `hm3:` block: `hm3.system` onto the document's `system`
|
|
64
57
|
// verbatim, and `hm3.img` / `hm3.items` / `hm3.effects` / `hm3.flags`
|
|
65
58
|
// overriding their shared top-level forms for this system alone.
|
|
@@ -92,15 +85,13 @@ export const ACTOR_FIELDS = Object.freeze([
|
|
|
92
85
|
/**
|
|
93
86
|
* The two `data:` facts HM3 declares on a `character` and not on a `creature`.
|
|
94
87
|
*
|
|
95
|
-
* Both name
|
|
96
|
-
* {@link ACTOR_FIELDS} does.
|
|
88
|
+
* Both name a shared source in `data:`, which is the only place they are authored.
|
|
97
89
|
*
|
|
98
90
|
* @type {readonly import("../engine/field-spec.mjs").FieldSpec[]}
|
|
99
91
|
*/
|
|
100
92
|
export const CHARACTER_FIELDS = Object.freeze([
|
|
101
93
|
{
|
|
102
94
|
name: "data.gender",
|
|
103
|
-
legacyKey: "gender",
|
|
104
95
|
to: "gender",
|
|
105
96
|
...STRING,
|
|
106
97
|
default: "",
|
|
@@ -108,7 +99,6 @@ export const CHARACTER_FIELDS = Object.freeze([
|
|
|
108
99
|
},
|
|
109
100
|
{
|
|
110
101
|
name: "data.occupation",
|
|
111
|
-
legacyKey: "occupation",
|
|
112
102
|
to: "occupation",
|
|
113
103
|
...STRING,
|
|
114
104
|
default: "",
|
|
@@ -126,8 +116,8 @@ export const CHARACTER_FIELDS = Object.freeze([
|
|
|
126
116
|
* @type {Readonly<Record<string, string>>}
|
|
127
117
|
*/
|
|
128
118
|
const DEFAULT_IMG = Object.freeze({
|
|
129
|
-
character: "systems/hm3/images/
|
|
130
|
-
creature: "systems/hm3/images/
|
|
119
|
+
character: "systems/hm3/assets/images/knightsilhouette.svg",
|
|
120
|
+
creature: "systems/hm3/assets/images/monstersilhouette.svg",
|
|
131
121
|
});
|
|
132
122
|
|
|
133
123
|
/**
|
|
@@ -176,9 +166,9 @@ function defaultActorImg(subType) {
|
|
|
176
166
|
* @type {Readonly<Record<string, string>>}
|
|
177
167
|
*/
|
|
178
168
|
const EMBEDDED_ITEM_ART = Object.freeze({
|
|
179
|
-
invocation: "systems/hm3/
|
|
180
|
-
psionic: "systems/hm3/
|
|
181
|
-
spell: "systems/hm3/
|
|
169
|
+
invocation: "systems/hm3/assets/icons/circle.svg",
|
|
170
|
+
psionic: "systems/hm3/assets/icons/psionics.svg",
|
|
171
|
+
spell: "systems/hm3/assets/icons/pentacle.svg",
|
|
182
172
|
});
|
|
183
173
|
|
|
184
174
|
/**
|
|
@@ -297,38 +287,9 @@ export class Hm3Actors extends SystemActorCompiler {
|
|
|
297
287
|
|
|
298
288
|
const items = this.buildEmbeddedItems(itemsMap, id, fm, ctx);
|
|
299
289
|
|
|
300
|
-
|
|
301
|
-
// soonest — every consumer runs the compile, and not every one runs the
|
|
302
|
-
// lint. A warning: the note compiles to the correct document
|
|
303
|
-
// either way, and refusing the position comes once no tree writes it.
|
|
304
|
-
const onLegacyKey = (field) =>
|
|
305
|
-
this.noteWarn(
|
|
306
|
-
legacyKeyMessage(block, field),
|
|
307
|
-
locateFrontmatterKey(this.currentNote?.absPath, field.legacyKey),
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
// The shared level's own retiring position — the top-level key `data:`
|
|
311
|
-
// gathered the field off. Same signal, same severity, separate
|
|
312
|
-
// callback: a note may have moved one position and not the other.
|
|
313
|
-
// Anchored at column 1, because the two spellings coincide — `portrait`
|
|
314
|
-
// names a block key and a top-level one — and a locator that took the
|
|
315
|
-
// first match would point at the wrong line.
|
|
316
|
-
const onRetiredTopLevel = (field) =>
|
|
317
|
-
this.noteWarn(
|
|
318
|
-
retiredTopLevelMessage(field),
|
|
319
|
-
locateFrontmatterKey(
|
|
320
|
-
this.currentNote?.absPath,
|
|
321
|
-
retiredTopLevelKey(field),
|
|
322
|
-
undefined,
|
|
323
|
-
{ topLevel: true },
|
|
324
|
-
),
|
|
325
|
-
);
|
|
326
|
-
const reports = { block, onLegacyKey, onRetiredTopLevel };
|
|
290
|
+
const reports = { block };
|
|
327
291
|
|
|
328
|
-
//
|
|
329
|
-
// by its address. This pass once read only the Foundry id, so an HM3
|
|
330
|
-
// tree could not file an actor by address at all — which its own sweep
|
|
331
|
-
// needs; the id spelling is retired outright.
|
|
292
|
+
// `packFolder` names a folder note by its address.
|
|
332
293
|
const folder = this.folderResolver(blockDataProperty(fm, block, "packFolder", null), {
|
|
333
294
|
isAddress: true,
|
|
334
295
|
});
|
package/hm3/default-item-art.mjs
CHANGED
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
* @type {Readonly<Record<string, string>>}
|
|
42
42
|
*/
|
|
43
43
|
export const HM3_DEFAULT_ITEM_ART = Object.freeze({
|
|
44
|
-
armorgear: "hm3/assets/
|
|
45
|
-
armorlocation: "hm3/assets/
|
|
46
|
-
containergear: "hm3/assets/
|
|
47
|
-
miscgear: "hm3/assets/
|
|
48
|
-
mysticalability: "hm3/assets/
|
|
49
|
-
projectilegear: "hm3/assets/
|
|
50
|
-
skill: "hm3/assets/
|
|
51
|
-
trauma: "hm3/assets/
|
|
52
|
-
weapongear: "hm3/assets/
|
|
44
|
+
armorgear: "hm3/assets/icons/armor.svg",
|
|
45
|
+
armorlocation: "hm3/assets/icons/anatomy.svg",
|
|
46
|
+
containergear: "hm3/assets/icons/sack.svg",
|
|
47
|
+
miscgear: "hm3/assets/icons/miscgear.svg",
|
|
48
|
+
mysticalability: "hm3/assets/icons/psionics.svg",
|
|
49
|
+
projectilegear: "hm3/assets/icons/arrow.svg",
|
|
50
|
+
skill: "hm3/assets/icons/skills.svg",
|
|
51
|
+
trauma: "hm3/assets/icons/injury.svg",
|
|
52
|
+
weapongear: "hm3/assets/icons/sword.svg",
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
/**
|
package/hm3/item-fields.mjs
CHANGED
|
@@ -77,7 +77,6 @@ import { AS_AUTHORED, NUMBER } from "../engine/field-spec.mjs";
|
|
|
77
77
|
const GEAR_COMMON = Object.freeze([
|
|
78
78
|
{
|
|
79
79
|
name: "data.weight",
|
|
80
|
-
legacyKey: "weight",
|
|
81
80
|
to: "weight",
|
|
82
81
|
...AS_AUTHORED,
|
|
83
82
|
kind: "number",
|
|
@@ -86,7 +85,6 @@ const GEAR_COMMON = Object.freeze([
|
|
|
86
85
|
},
|
|
87
86
|
{
|
|
88
87
|
name: "data.value",
|
|
89
|
-
legacyKey: "value",
|
|
90
88
|
to: "value",
|
|
91
89
|
...AS_AUTHORED,
|
|
92
90
|
kind: "number",
|
|
@@ -107,7 +105,6 @@ const GEAR_COMMON = Object.freeze([
|
|
|
107
105
|
*/
|
|
108
106
|
const QUANTITY = Object.freeze({
|
|
109
107
|
name: "data.quantity",
|
|
110
|
-
legacyKey: "quantity",
|
|
111
108
|
to: "quantity",
|
|
112
109
|
...NUMBER,
|
|
113
110
|
default: 1,
|
|
@@ -127,10 +124,8 @@ const QUANTITY = Object.freeze({
|
|
|
127
124
|
* a registry is addressed by what a note calls itself. What the document is
|
|
128
125
|
* called is the map's answer, and only the map's.
|
|
129
126
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* source the content format's mapping tables state, and `legacyKey` is the key
|
|
133
|
-
* the `hm3:` block still carries.
|
|
127
|
+
* A field whose `name` is a path into `data:` is authored there and nowhere
|
|
128
|
+
* else: `name` is the shared source the content format's mapping tables state.
|
|
134
129
|
*
|
|
135
130
|
* @type {Readonly<Record<string, readonly import("../engine/field-spec.mjs").FieldSpec[]>>}
|
|
136
131
|
*/
|
|
@@ -148,7 +143,6 @@ export const HM3_ITEM_FIELDS = Object.freeze({
|
|
|
148
143
|
...GEAR_COMMON,
|
|
149
144
|
{
|
|
150
145
|
name: "data.capacity",
|
|
151
|
-
legacyKey: "capacity",
|
|
152
146
|
to: "capacity.max",
|
|
153
147
|
...NUMBER,
|
|
154
148
|
default: 0,
|
|
@@ -171,7 +165,6 @@ export const HM3_ITEM_FIELDS = Object.freeze({
|
|
|
171
165
|
skill: Object.freeze([
|
|
172
166
|
{
|
|
173
167
|
name: "data.masteryLevel",
|
|
174
|
-
legacyKey: "masteryLevel",
|
|
175
168
|
to: "masteryLevel",
|
|
176
169
|
...NUMBER,
|
|
177
170
|
default: 0,
|
|
@@ -49,13 +49,12 @@ import { blockProperty } from "../engine/system-block.mjs";
|
|
|
49
49
|
* than a `null` nothing reads.
|
|
50
50
|
*
|
|
51
51
|
* **Read through the shared resolver, not a field declaration**. A
|
|
52
|
-
* `FieldSpec`'s shared source is a single position, and this value has
|
|
53
|
-
* `data:`, this block, the top level
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* HM3 flag until it sweeps to `data:`.
|
|
52
|
+
* `FieldSpec`'s shared source is a single position, and this value has three:
|
|
53
|
+
* `data:`, this block, and the top level. The resolver is the single
|
|
54
|
+
* implementation of what a note said, so the two systems cannot disagree about
|
|
55
|
+
* it. It is read against **this** block: the `sohl:` block is not a source for
|
|
56
|
+
* an HM3 document, so a note that states the priority only there writes no HM3
|
|
57
|
+
* flag.
|
|
59
58
|
*
|
|
60
59
|
* @param {object} fm - The note's frontmatter.
|
|
61
60
|
* @param {string} block - This pass's system block.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Which banner a page of each kind opens with.
|
|
2
|
+
#
|
|
3
|
+
# `partials/banner-url.html` reads a page's note `type` and `subType` here and
|
|
4
|
+
# resolves the result against `banners.yaml`. A type maps to one banner name for
|
|
5
|
+
# every subType, or to a table keyed by every subType the note vocabulary
|
|
6
|
+
# declares for it. `default` is a deliberate choice of the default banner; a
|
|
7
|
+
# kind absent from this file resolves to its own name and warns when that name
|
|
8
|
+
# is not declared.
|
|
9
|
+
#
|
|
10
|
+
# `npm run lint:banners` and the test suite fail on a mapped name that
|
|
11
|
+
# `banners.yaml` does not declare, and on a type or subType missing here.
|
|
12
|
+
|
|
13
|
+
# Types whose banner is named by the page's `category`.
|
|
14
|
+
categoryTypes:
|
|
15
|
+
- doc
|
|
16
|
+
|
|
17
|
+
kinds:
|
|
18
|
+
affiliation:
|
|
19
|
+
arcanetradition: organization
|
|
20
|
+
criminal: organization
|
|
21
|
+
fellowship: organization
|
|
22
|
+
faithtradition: faith
|
|
23
|
+
governmental: organization
|
|
24
|
+
guild: organization
|
|
25
|
+
lineage: organization
|
|
26
|
+
order: organization
|
|
27
|
+
polity: organization
|
|
28
|
+
spirittradition: organization
|
|
29
|
+
venture: organization
|
|
30
|
+
affliction: affliction
|
|
31
|
+
armorgear: armor-clothing
|
|
32
|
+
armorlocation: default
|
|
33
|
+
attribute: skills-attributes
|
|
34
|
+
being:
|
|
35
|
+
character: character
|
|
36
|
+
creature: creature
|
|
37
|
+
npc: character
|
|
38
|
+
bundle: default
|
|
39
|
+
concoctiongear: default
|
|
40
|
+
containergear: containers
|
|
41
|
+
folder: default
|
|
42
|
+
homepage: default
|
|
43
|
+
lore:
|
|
44
|
+
arcana: default
|
|
45
|
+
bestiary: default
|
|
46
|
+
calendar: default
|
|
47
|
+
cosmology: default
|
|
48
|
+
culture: people
|
|
49
|
+
custom: default
|
|
50
|
+
deity: default
|
|
51
|
+
economy: default
|
|
52
|
+
folk: default
|
|
53
|
+
gathering: default
|
|
54
|
+
history: default
|
|
55
|
+
law: default
|
|
56
|
+
literature: default
|
|
57
|
+
material: default
|
|
58
|
+
spirit: default
|
|
59
|
+
theology: default
|
|
60
|
+
macro: default
|
|
61
|
+
map: default
|
|
62
|
+
miscgear: misc-gear
|
|
63
|
+
mystery: default
|
|
64
|
+
mysticalability: mystical-abilities
|
|
65
|
+
place:
|
|
66
|
+
celestial: default
|
|
67
|
+
feature: default
|
|
68
|
+
region: region
|
|
69
|
+
settlement: settlement
|
|
70
|
+
site: default
|
|
71
|
+
structure: default
|
|
72
|
+
world: default
|
|
73
|
+
projectilegear: projectiles
|
|
74
|
+
scenario: default
|
|
75
|
+
skill: skills-attributes
|
|
76
|
+
trauma: trauma
|
|
77
|
+
vehicle: default
|
|
78
|
+
weapongear: weapons
|
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
# `images/banners/`, and that path is emitted into a `background-image` with no
|
|
5
5
|
# way to test it: the artwork is served from the consuming site's
|
|
6
6
|
# `params.cdnBaseURL`, and Hugo cannot ask a remote host whether a URL exists.
|
|
7
|
-
# So a banner that was never drawn
|
|
7
|
+
# So a banner that was never drawn would 404 in silence — the band renders
|
|
8
8
|
# with its title, palette and gradient intact and a dead image URL behind it,
|
|
9
|
-
# and nothing
|
|
10
|
-
# (issue #36).
|
|
9
|
+
# and nothing fails: not the build, not Hugo, not the deploy guard.
|
|
11
10
|
#
|
|
12
11
|
# This file is the declaration that replaces that missing test. A name listed
|
|
13
12
|
# here is asserted to exist; a resolved banner whose name is absent falls back
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
the deployment does not publish. Without it, Pages falls back to the site
|
|
7
7
|
root, so an unknown path answers 200 with the landing page: a soft-404 that
|
|
8
8
|
makes every "does this URL resolve?" check report success, and lets search
|
|
9
|
-
engines index
|
|
9
|
+
engines index withdrawn content as live.
|
|
10
10
|
|
|
11
11
|
Every consumer needs exactly this, so it lives here rather than being copied
|
|
12
12
|
into each one (issue #1454). The theme carries layout, not addresses, so the
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
<div class="single-content">
|
|
42
42
|
<div class="single-body">
|
|
43
43
|
<p>
|
|
44
|
-
The page may have been
|
|
45
|
-
{{ $noun }}, or
|
|
44
|
+
The page may have been moved to another part of the
|
|
45
|
+
{{ $noun }}, or withdrawn along with the concept it described. Links
|
|
46
46
|
from older discussions, issues, and search results can outlive the
|
|
47
47
|
pages they point at.
|
|
48
48
|
</p>
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
2. `banner` — a hand-authored page's value. `none` (or `false`) declines an
|
|
14
14
|
image and returns "". A full URL is used as-is; anything else is a
|
|
15
15
|
fragment under `images/`.
|
|
16
|
-
3. `images/banners/{
|
|
17
|
-
supplied
|
|
16
|
+
3. `images/banners/{name}.webp`, when neither is set. The name is the
|
|
17
|
+
`subtype` supplied, or, when the caller passes the page's `type`, the
|
|
18
|
+
banner `data/banner-kinds.yaml` maps that `type` and `subType` to — a
|
|
19
|
+
`category` for the types it lists as taking theirs from there. A type
|
|
20
|
+
absent from the mapping keeps its own name. A caller that supplies
|
|
21
|
+
neither gets "" instead, which is
|
|
18
22
|
what a card wants: a section with no banner of its own renders as the
|
|
19
23
|
text card it rendered before.
|
|
20
24
|
4. `images/banners/{fallback}` — whenever the name picked by 2 or 3 is not
|
|
@@ -44,8 +48,13 @@
|
|
|
44
48
|
the content build resolved. Omit for a page that carries none.
|
|
45
49
|
banner — the raw `banner:` value; may be unset, `none`/`false`, a
|
|
46
50
|
fragment or an absolute URL.
|
|
47
|
-
subtype — optional. The name to default to when `banner` is unset
|
|
48
|
-
for "no banner means no image".
|
|
51
|
+
subtype — optional. The name to default to when `banner` is unset and no
|
|
52
|
+
`type` is given. Omit for "no banner means no image".
|
|
53
|
+
type — optional. The page's note `type`; with `subType` and `category`
|
|
54
|
+
it selects the default name through `data/banner-kinds.yaml`.
|
|
55
|
+
subType — optional. The page's note `subType`.
|
|
56
|
+
category — optional. The page's `category`, for the types that take their
|
|
57
|
+
banner name from it.
|
|
49
58
|
context — optional. A page address, named in the missing-banner warning so
|
|
50
59
|
the report says where the want came from.
|
|
51
60
|
*/ -}}
|
|
@@ -54,6 +63,22 @@
|
|
|
54
63
|
{{- $context := .context | default "" -}}
|
|
55
64
|
{{- $data := .data | default dict -}}
|
|
56
65
|
|
|
66
|
+
{{- /* The default name for a page that states its `type`. A type maps to one
|
|
67
|
+
name or to a table keyed by subType; one that the mapping does not know
|
|
68
|
+
keeps its own name, so the missing-banner warning below still reports
|
|
69
|
+
it. */ -}}
|
|
70
|
+
{{- with .type -}}
|
|
71
|
+
{{- $kinds := index (hugo.Data | default dict) "banner-kinds" | default dict -}}
|
|
72
|
+
{{- $entry := index ($kinds.kinds | default dict) . -}}
|
|
73
|
+
{{- if in ($kinds.categoryTypes | default slice) . -}}
|
|
74
|
+
{{- $subtype = $.category | default "default" -}}
|
|
75
|
+
{{- else if reflect.IsMap $entry -}}
|
|
76
|
+
{{- $subtype = (index $entry (lower ($.subType | default ""))) | default . -}}
|
|
77
|
+
{{- else -}}
|
|
78
|
+
{{- $subtype = $entry | default . -}}
|
|
79
|
+
{{- end -}}
|
|
80
|
+
{{- end -}}
|
|
81
|
+
|
|
57
82
|
{{- $banners := hugo.Data.banners | default dict -}}
|
|
58
83
|
{{- $dir := $banners.dir | default "images/banners" -}}
|
|
59
84
|
{{- $fallback := $banners.fallback | default "default.webp" -}}
|
|
@@ -68,11 +93,10 @@
|
|
|
68
93
|
{{- $declined := or (eq (lower $raw) "none") (eq $raw "false") -}}
|
|
69
94
|
|
|
70
95
|
{{- /* A note's resolved banner, formatted for the same reason the decline
|
|
71
|
-
above is: an unset key and
|
|
96
|
+
above is: an unset key and an empty string are both falsy, and only
|
|
72
97
|
formatting tells them apart. `<nil>` covers both an absent key and an
|
|
73
98
|
explicit `null`, which the note format reads as *unset* — so the
|
|
74
|
-
resolution carries on to the subtype default.
|
|
75
|
-
deliberate blank: a note naming no hero image, which declines one. */ -}}
|
|
99
|
+
resolution carries on to the subtype default. */ -}}
|
|
76
100
|
{{- $resolved := printf "%v" (index $data "banner") -}}
|
|
77
101
|
{{- $fromBuild := ne $resolved "<nil>" -}}
|
|
78
102
|
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
see "Declining" below. A full URL is used
|
|
24
24
|
as-is; anything else is treated as a
|
|
25
25
|
fragment under images/.
|
|
26
|
-
3. images/banners/{
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
3. images/banners/{name}.webp — the default for the page's kind: the
|
|
27
|
+
banner data/banner-kinds.yaml maps its
|
|
28
|
+
type and subType to, or its category for
|
|
29
|
+
type=doc pages
|
|
29
30
|
4. images/banners/default.webp — used when the page has no type, *and*
|
|
30
31
|
whenever the name picked by 2 or 3 is not
|
|
31
32
|
in the declared inventory (see below).
|
|
@@ -58,22 +59,20 @@
|
|
|
58
59
|
considered answer was "none", so declining has to be sayable.
|
|
59
60
|
*/ -}}
|
|
60
61
|
|
|
61
|
-
{{- /*
|
|
62
|
-
`
|
|
63
|
-
|
|
62
|
+
{{- /* The order above, the `none` decision, the type-to-banner mapping in
|
|
63
|
+
`data/banner-kinds.yaml` and the declared-existence check all live in
|
|
64
|
+
`banner-url.html`, which a derived landing card calls too. A hero band
|
|
65
|
+
always wants the default for its page's kind; a card never does. A page
|
|
66
|
+
with no type gets `default`. */ -}}
|
|
64
67
|
{{- $type := .Params.type | default "" -}}
|
|
65
|
-
{{- $subtype := cond (eq $type "doc") (.Params.category | default "") $type -}}
|
|
66
|
-
{{- if not $subtype }}{{ $subtype = "default" }}{{ end -}}
|
|
67
|
-
|
|
68
|
-
{{- /* The order above, the `none` decision and the declared-existence check
|
|
69
|
-
all live in `banner-url.html`, which a derived landing card calls too
|
|
70
|
-
(issue #41). A hero band always wants the subtype default; a card never
|
|
71
|
-
does. */ -}}
|
|
72
68
|
{{- $bannerURL := partial "banner-url.html" (dict
|
|
73
69
|
"site" .Site
|
|
74
70
|
"data" .Params.data
|
|
75
71
|
"banner" .Params.banner
|
|
76
|
-
"
|
|
72
|
+
"type" $type
|
|
73
|
+
"subType" .Params.subType
|
|
74
|
+
"category" .Params.category
|
|
75
|
+
"subtype" (cond (eq $type "") "default" "")
|
|
77
76
|
"context" .RelPermalink) -}}
|
|
78
77
|
|
|
79
78
|
<section class="hero hero-with-image"{{ with $bannerURL }} style="background-image: url('{{ . }}');"{{ end }}>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
computed first and the <section> is rendered only when there is something
|
|
26
26
|
to put in it.
|
|
27
27
|
|
|
28
|
-
`return` cannot
|
|
28
|
+
`return` cannot bail out early here. It sets the partial's
|
|
29
29
|
return value; it does not discard template text the partial has already
|
|
30
30
|
emitted, so a guard written that way still prints the empty shell. Hence
|
|
31
31
|
the emptiness test wraps the markup instead of preceding it.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
{{- warnidf (printf "hero-banner-missing-%s" .name)
|
|
2
|
-
"hero-banner: no banner named %q in the shared artwork set; falling back to %s/%s. Draw it and add %q to data/banners.yaml, or name a hero image
|
|
2
|
+
"hero-banner: no banner named %q in the shared artwork set; falling back to %s/%s. Draw it and add %q to data/banners.yaml, or name a hero image with `data.banner`. Write `data.banner: none` to decline a hero image. First seen on %s."
|
|
3
3
|
.name .dir .fallback .name .context -}}
|
|
@@ -771,7 +771,7 @@ img.door-image {
|
|
|
771
771
|
margin: 0;
|
|
772
772
|
}
|
|
773
773
|
|
|
774
|
-
/* One card per row once two
|
|
774
|
+
/* One card per row once two do not fit beside each other; the fixed width
|
|
775
775
|
would otherwise overflow a narrow viewport. */
|
|
776
776
|
@media (max-width: 400px) {
|
|
777
777
|
.door {
|
package/manifest.mjs
CHANGED
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
* `descriptionHtml` is the one exception, folded into the derived
|
|
32
32
|
* `description` below rather than surviving under its own name.
|
|
33
33
|
* - **Derived** — the identity, the description (from `descriptionHtml`), the
|
|
34
|
-
* version, the release addresses, the compatibility ranges and
|
|
35
|
-
* list. Declaring `description` directly is an error rather than an
|
|
34
|
+
* version, the authors, the release addresses, the compatibility ranges and
|
|
35
|
+
* the pack list. Declaring `description` directly is an error rather than an
|
|
36
36
|
* override: the authored copy would be silently overwritten.
|
|
37
37
|
* - **Computed** — namespaced `flags` a repository works out for itself.
|
|
38
38
|
*
|
|
@@ -478,8 +478,9 @@ function requireManifestTitle(config) {
|
|
|
478
478
|
* a key Foundry adds later needs no release of this package. The one
|
|
479
479
|
* exception is `descriptionHtml`, folded into the description below rather
|
|
480
480
|
* than surviving under its own name.
|
|
481
|
-
* - **Derived** — the identity, the description, the
|
|
482
|
-
*
|
|
481
|
+
* - **Derived** — the identity, the description, the authors (the top-level
|
|
482
|
+
* `authors` list without its roles), the release addresses, the version, the
|
|
483
|
+
* Foundry and system compatibility ranges, and the pack list.
|
|
483
484
|
* These are refused if also declared (`description` directly; `descriptionHtml`
|
|
484
485
|
* is how it is authored) and the two would disagree with nothing to say so.
|
|
485
486
|
* - **Computed** — namespaced `flags` a repository works out for itself, merged
|
|
@@ -519,6 +520,12 @@ export function buildManifest({ config, packageJson, artifact, flags }) {
|
|
|
519
520
|
// in it. Set only when the repository actually declares one.
|
|
520
521
|
if (descriptionHtml !== undefined) derived.description = descriptionHtml;
|
|
521
522
|
if (config.compatibility) derived.compatibility = config.compatibility;
|
|
523
|
+
// Foundry's author schema is name, email, url, discord and flags; a role
|
|
524
|
+
// is the book's, printed on its title page, and the manifest ships what
|
|
525
|
+
// it is given.
|
|
526
|
+
if (config.authors?.length) {
|
|
527
|
+
derived.authors = config.authors.map(({ role: _role, ...person }) => ({ ...person }));
|
|
528
|
+
}
|
|
522
529
|
|
|
523
530
|
// `requiresSystem` is the gate half of the declare/require split. It
|
|
524
531
|
// emits the `relationships.systems` entry Foundry's `supportsSystem` reads,
|
package/markdownlint-config.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* The shared markdownlint rules, as a markdownlint-cli2 options module.
|
|
15
|
+
* The shared markdownlint rules, as a `.markdownlint-cli2.mjs` options module.
|
|
16
16
|
*
|
|
17
17
|
* `package-build markdown` applies these without a consumer declaring
|
|
18
18
|
* anything; this is for an editor's markdownlint extension, and for a consumer
|