@heroiclands/package-build 23.1.0 → 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 +71 -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 +54 -6
- 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/engine/yaml-lint.mjs +7 -4
- 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 +83 -18
- 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/engine/yaml-lint.d.mts +5 -4
- 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 +12 -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/art-slots.mjs
CHANGED
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
* `icon` while its accepted set also takes `image`. A value naming a type
|
|
24
24
|
* outside it is an error, against this set rather than against `type`.
|
|
25
25
|
* @property {boolean} document - Whether the slot reaches a compiled document.
|
|
26
|
+
* @property {string} [declines] - The literal value that declines the slot's
|
|
27
|
+
* art on purpose. It is never read as an Address: it resolves to no image and
|
|
28
|
+
* is emitted as a blank, which a theme reads as "draw none".
|
|
26
29
|
* @property {string} describe - One line, for the author-facing reference.
|
|
27
30
|
*/
|
|
28
31
|
|
|
@@ -76,6 +79,12 @@ export const ART_SLOTS = Object.freeze([
|
|
|
76
79
|
// fitted to whatever room it has, so no slot but this one states a
|
|
77
80
|
// size.
|
|
78
81
|
size: Object.freeze({ width: 1792, height: 768 }),
|
|
79
|
-
|
|
82
|
+
// `none` is the one way to decline a hero image. It is a word rather
|
|
83
|
+
// than a blank because `""` is refused: a blank is how an unfinished
|
|
84
|
+
// note looks, and declining has to be said on purpose.
|
|
85
|
+
declines: "none",
|
|
86
|
+
describe:
|
|
87
|
+
"The page's hero image, cut to 1792×768; `none` declines it. " +
|
|
88
|
+
"Reaches no compiled document.",
|
|
80
89
|
}),
|
|
81
90
|
]);
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
import fs from "node:fs";
|
|
4
15
|
import path from "node:path";
|
package/engine/base-compiler.mjs
CHANGED
|
@@ -92,20 +92,17 @@ import {
|
|
|
92
92
|
import { isNoteRecord, noteFile } from "./index-records.mjs";
|
|
93
93
|
import { reduceAddressFields } from "./address-fields.mjs";
|
|
94
94
|
import { artPathname, artSlot, unacceptedArtMessage, unresolvedArtMessage } from "./art-fields.mjs";
|
|
95
|
-
import { emitDiagnostic, positionOfFrontmatterPath, positionOfLiteral } from "./diagnostics.mjs";
|
|
96
|
-
import { assertNoDeclaredPackage } from "./note-package.mjs";
|
|
97
|
-
import { assertNoDeclaredFolder } from "./folder-notes.mjs";
|
|
98
95
|
import {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
} from "./
|
|
104
|
-
import {
|
|
96
|
+
emitDiagnostic,
|
|
97
|
+
locateFrontmatterKey,
|
|
98
|
+
positionOfFrontmatterPath,
|
|
99
|
+
positionOfLiteral,
|
|
100
|
+
} from "./diagnostics.mjs";
|
|
101
|
+
import { assertNoDeclaredPackage } from "./note-package.mjs";
|
|
102
|
+
import { packForType } from "./ids.mjs";
|
|
105
103
|
import { resolveNoteId } from "./note-ids.mjs";
|
|
106
104
|
import { carriesSystemBlock } from "./system-block.mjs";
|
|
107
105
|
import { checkAuthoredSystemData, checkEmittedSystemData } from "./schema-check.mjs";
|
|
108
|
-
import { locateFrontmatterKey } from "./retired-fields.mjs";
|
|
109
106
|
// A being's computed `age`, filled in against the package's own declared
|
|
110
107
|
// present before this pass reads `data:` for anything else — see
|
|
111
108
|
// `engine/being-age.mjs`.
|
|
@@ -116,8 +113,8 @@ import { reckoningContext } from "./reckoning-markers.mjs";
|
|
|
116
113
|
* The tallies one pass accumulates while walking the tree.
|
|
117
114
|
*
|
|
118
115
|
* `declined` and `skippedOther` are deliberately separate numbers. A declined
|
|
119
|
-
* note is one this build **refused** — it declares
|
|
120
|
-
*
|
|
116
|
+
* note is one this build **refused** — it declares `package:` — and it is an
|
|
117
|
+
* error; a skipped one legitimately belongs to another pass, and
|
|
121
118
|
* there are thousands of those. Folding the first into the second is what let a
|
|
122
119
|
* whole tree be filtered out in silence.
|
|
123
120
|
*
|
|
@@ -125,9 +122,9 @@ import { reckoningContext } from "./reckoning-markers.mjs";
|
|
|
125
122
|
* @property {number} compiled - Notes that became a document.
|
|
126
123
|
* @property {number} skippedNoId - Notes with no `id`, where that is tolerated.
|
|
127
124
|
* @property {number} skippedOther - Notes this pass does not claim.
|
|
128
|
-
* @property {number} declined - Notes this pack **refused** — one declaring
|
|
129
|
-
*
|
|
130
|
-
*
|
|
125
|
+
* @property {number} declined - Notes this pack **refused** — one declaring
|
|
126
|
+
* `package:`, or one routed to a system pack whose system it says nothing
|
|
127
|
+
* about. Counted as errors, never as skips.
|
|
131
128
|
*/
|
|
132
129
|
|
|
133
130
|
/**
|
|
@@ -524,14 +521,14 @@ export class BasePackCompiler {
|
|
|
524
521
|
* A refusal only this pass can make, because its subject is the note's
|
|
525
522
|
* **type**.
|
|
526
523
|
*
|
|
527
|
-
* The `
|
|
528
|
-
* construction: it runs before `selects`, so that a note declaring
|
|
529
|
-
*
|
|
524
|
+
* The `assertNoDeclaredPackage` check above it in the walk is type-agnostic
|
|
525
|
+
* by construction: it runs before `selects`, so that a note declaring
|
|
526
|
+
* `package:` is answered whichever pass would have claimed it. A rule
|
|
530
527
|
* about what a *`trauma`* may write cannot live there — it needs the type's
|
|
531
528
|
* field declaration, which only the pass that compiles the type can reach.
|
|
532
529
|
*
|
|
533
530
|
* So it is a hook, called once the note is known to be this pass's, and its
|
|
534
|
-
* throw is counted and located exactly as
|
|
531
|
+
* throw is counted and located exactly as that check's is: the note is
|
|
535
532
|
* declined rather than skipped, and the build fails naming the line.
|
|
536
533
|
*
|
|
537
534
|
* The default refuses nothing, which is the honest position for a pass
|
|
@@ -832,12 +829,10 @@ export class BasePackCompiler {
|
|
|
832
829
|
/**
|
|
833
830
|
* The Foundry path one authored art address names, or `null`.
|
|
834
831
|
*
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
* than restated, which is also what puts an art address and a body image
|
|
840
|
-
* through one ownership rule.
|
|
832
|
+
* `null` and an absent key mean *no art named*, so the caller's own default
|
|
833
|
+
* applies with nullish coalescing. The address goes through
|
|
834
|
+
* {@link module:engine/helpers.resolveImg}, which puts an art address and a
|
|
835
|
+
* body image through one ownership rule.
|
|
841
836
|
*
|
|
842
837
|
* An address nothing answers is reported against the note and treated as
|
|
843
838
|
* unnamed, so the document takes its default rather than shipping a path
|
|
@@ -849,8 +844,8 @@ export class BasePackCompiler {
|
|
|
849
844
|
* @param {string} key - The key it was authored at, for the message.
|
|
850
845
|
* @param {string} type - The asset type a bare value takes.
|
|
851
846
|
* @param {Iterable<string>} [accepts] - The types this slot accepts.
|
|
852
|
-
* @returns {string|null} The Foundry-relative path, `
|
|
853
|
-
*
|
|
847
|
+
* @returns {string|null} The Foundry-relative path, or `null` where the
|
|
848
|
+
* note names none.
|
|
854
849
|
*/
|
|
855
850
|
artPathOf(value, key, type, accepts) {
|
|
856
851
|
const {
|
|
@@ -1216,7 +1211,7 @@ export class BasePackCompiler {
|
|
|
1216
1211
|
// A note the index could not record is a note this pass declines —
|
|
1217
1212
|
// counted and reported exactly as the loop below does for the same
|
|
1218
1213
|
// refusal, because it *is* the same refusal: the index defers to
|
|
1219
|
-
// `assertNoDeclaredPackage` for a
|
|
1214
|
+
// `assertNoDeclaredPackage` for a declared `package:`, which is the
|
|
1220
1215
|
// check this loop makes a few lines further down. All that changed is
|
|
1221
1216
|
// which pass sees the note first.
|
|
1222
1217
|
if (this.reportsCorpusProblems) {
|
|
@@ -1240,9 +1235,8 @@ export class BasePackCompiler {
|
|
|
1240
1235
|
// this pass's own. Each note is then read for its **prose**: the
|
|
1241
1236
|
// index carries what is *about* a note and deliberately not its text,
|
|
1242
1237
|
// nor the `bodyLine`/`bodyColumn` a diagnostic needs, and this pass has
|
|
1243
|
-
// to have the body anyway. So the read is one this pass
|
|
1244
|
-
//
|
|
1245
|
-
// make it over.
|
|
1238
|
+
// to have the body anyway. So the read is one this pass makes anyway;
|
|
1239
|
+
// the index decides which files it covers.
|
|
1246
1240
|
const dates = reckoningContext({ notes: this.corpus.records });
|
|
1247
1241
|
for (const record of this.corpus.records) {
|
|
1248
1242
|
if (!isNoteRecord(record)) continue;
|
|
@@ -1258,44 +1252,20 @@ export class BasePackCompiler {
|
|
|
1258
1252
|
continue;
|
|
1259
1253
|
}
|
|
1260
1254
|
applyComputedBeingAge(fm, this.worldPresent, dates);
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1263
|
-
//
|
|
1264
|
-
//
|
|
1265
|
-
//
|
|
1266
|
-
//
|
|
1267
|
-
// - `draft:`: it excluded the note from the packs, the
|
|
1268
|
-
// manifest and the site, and no checker reported the links that
|
|
1269
|
-
// left dangling.
|
|
1270
|
-
// - `aliases:`: it fed the alias index, which the bare
|
|
1271
|
-
// `[[Alias]]` form was looked up in; the form is retired, so the
|
|
1272
|
-
// list has no reader left. The nested `name.aliases` is a
|
|
1273
|
-
// different field: the infobox displays it, and the note name
|
|
1274
|
-
// check validates it.
|
|
1275
|
-
//
|
|
1276
|
-
// Both are reported and counted — never skipped, which is how a
|
|
1277
|
-
// tree naming a package nothing answers to used to compile zero
|
|
1278
|
-
// notes and exit 0. The file comes from the diagnostic locator, so
|
|
1279
|
-
// neither message may repeat it.
|
|
1255
|
+
// `package:` is refused before `selects`, so a note is answered
|
|
1256
|
+
// whichever pass would have claimed it: a note's package is the
|
|
1257
|
+
// repository's configured one, so declaring it restates a
|
|
1258
|
+
// constant. It is reported and counted, never skipped. The file
|
|
1259
|
+
// comes from the diagnostic locator, so the message must not
|
|
1260
|
+
// repeat it.
|
|
1280
1261
|
try {
|
|
1281
1262
|
assertNoDeclaredPackage(fm, { absPath });
|
|
1282
|
-
assertNoDeclaredFolder(fm, { absPath });
|
|
1283
|
-
assertNoDraftField(fm, { absPath });
|
|
1284
|
-
assertNoAliasesField(fm, { absPath });
|
|
1285
|
-
assertNoSectionField(fm, { absPath });
|
|
1286
|
-
assertNoTraitsField(fm, { absPath });
|
|
1287
1263
|
} catch (err) {
|
|
1288
1264
|
stats.declined++;
|
|
1289
1265
|
this.errorCount++;
|
|
1290
1266
|
this.noteError(err.message, err.position);
|
|
1291
1267
|
continue;
|
|
1292
1268
|
}
|
|
1293
|
-
// Checked before `selects`, and therefore for every note this
|
|
1294
|
-
// package owns rather than only the ones some pass claims. A
|
|
1295
|
-
// retired type is claimed by no pass, so the alternative is not a
|
|
1296
|
-
// wrong document — it is no document, skipped as quietly as the
|
|
1297
|
-
// thousands of notes that legitimately belong to another pass.
|
|
1298
|
-
assertTypeNotRetired(fm.type, absPath);
|
|
1299
1269
|
if (!this.selects(fm)) {
|
|
1300
1270
|
stats.skippedOther++;
|
|
1301
1271
|
continue;
|
|
@@ -1313,7 +1283,7 @@ export class BasePackCompiler {
|
|
|
1313
1283
|
// `shortcode`. It is not addressable, so there is nothing to
|
|
1314
1284
|
// derive from and nothing for a link to point at; the message
|
|
1315
1285
|
// names the reason rather than the missing field, because the
|
|
1316
|
-
// field is
|
|
1286
|
+
// field is not something an author writes.
|
|
1317
1287
|
if (this.constructor.requiresId) {
|
|
1318
1288
|
throw new Error(
|
|
1319
1289
|
`${Label} note has no address, so it has no document id: ` +
|
|
@@ -1350,11 +1320,10 @@ export class BasePackCompiler {
|
|
|
1350
1320
|
stats.skippedOther++;
|
|
1351
1321
|
continue;
|
|
1352
1322
|
}
|
|
1353
|
-
//
|
|
1354
|
-
// what a note of *this* type may not write, which needs the
|
|
1323
|
+
// What a note of *this* type may not write, which needs the
|
|
1355
1324
|
// type's own field declaration and so cannot be asked before
|
|
1356
1325
|
// `selects`. Counted as a declined note for the same reason
|
|
1357
|
-
//
|
|
1326
|
+
// a declared `package:` is — the alternative is a tree that compiles fewer
|
|
1358
1327
|
// documents than it has notes and exits 0.
|
|
1359
1328
|
this.assertAuthorable(fm);
|
|
1360
1329
|
} catch (err) {
|
package/engine/being-age.mjs
CHANGED
|
@@ -59,11 +59,6 @@ import { worldInvariants } from "./calendar-notes.mjs";
|
|
|
59
59
|
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
60
60
|
import { parseNoteDate } from "./note-dates.mjs";
|
|
61
61
|
import { reckoningContext } from "./reckoning-markers.mjs";
|
|
62
|
-
// `born`'s retired spelling is still read during its retirement window — see
|
|
63
|
-
// `docs/content-format.md`'s "`birthday:` is the retired spelling of `born:`"
|
|
64
|
-
// — so a being on the old spelling still computes an age rather than reading
|
|
65
|
-
// as never born.
|
|
66
|
-
import { readAliasedField } from "./retired-fields.mjs";
|
|
67
62
|
|
|
68
63
|
/** The note type this module's derivation and check apply to. */
|
|
69
64
|
const BEING_TYPE = "being";
|
|
@@ -170,7 +165,7 @@ export function applyComputedBeingAge(fm, presentRaw, dateContext = {}) {
|
|
|
170
165
|
return;
|
|
171
166
|
}
|
|
172
167
|
|
|
173
|
-
const born =
|
|
168
|
+
const born = data?.born;
|
|
174
169
|
const computed = computeAge(born, presentRaw, dateContext);
|
|
175
170
|
if (computed !== null) data.age = computed;
|
|
176
171
|
}
|
|
@@ -237,7 +232,7 @@ export function checkBeingAge(note, { index } = {}) {
|
|
|
237
232
|
const data = dataOf(note?.fm);
|
|
238
233
|
if (!data) return [];
|
|
239
234
|
|
|
240
|
-
const bornRaw =
|
|
235
|
+
const bornRaw = data.born;
|
|
241
236
|
const ageRaw = data.age;
|
|
242
237
|
if (ageRaw === undefined || ageRaw === null || ageRaw === "") return [];
|
|
243
238
|
if (!index) return [];
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
4
15
|
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
3
3
|
* Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
|
|
4
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
|
+
*
|
|
5
11
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
12
|
*/
|
|
7
13
|
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
import { isAddressTuple, parseAddress, renderAddress } from "./address.mjs";
|
|
4
15
|
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
import { dayOfYear } from "./calendars.mjs";
|
|
4
15
|
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
import { calendarStructure } from "./calendars.mjs";
|
|
4
15
|
import {
|
|
@@ -73,15 +73,17 @@ export async function buildCompileCorpus({
|
|
|
73
73
|
}) {
|
|
74
74
|
const resolved = config ?? loadPackConfig();
|
|
75
75
|
const collected = problems ?? [];
|
|
76
|
+
const parsed = new Map();
|
|
76
77
|
const records = indexRecordsFor({
|
|
77
78
|
contentBase,
|
|
78
79
|
assetsBase,
|
|
79
80
|
config: resolved,
|
|
80
81
|
skipDirectories,
|
|
81
82
|
problems: collected,
|
|
83
|
+
parsed,
|
|
82
84
|
});
|
|
83
85
|
const corpusOptions = { config: resolved, records };
|
|
84
|
-
const sqlOptions = { ...corpusOptions, skipDirectories };
|
|
86
|
+
const sqlOptions = { ...corpusOptions, skipDirectories, parsed };
|
|
85
87
|
return {
|
|
86
88
|
records,
|
|
87
89
|
problems: collected,
|
|
@@ -148,12 +148,10 @@ export function addressSlug(fm) {
|
|
|
148
148
|
* docs, neither of which contains a hyphen or names a type.
|
|
149
149
|
*
|
|
150
150
|
* **It is a pure function of the frontmatter**, and takes no options. Nothing
|
|
151
|
-
* about the file the note was read from reaches it
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* discarded; with that key retired, `prefix` was the only thing left in the
|
|
156
|
-
* scheme and the paragraph above is the reason it never applied.
|
|
151
|
+
* about the file the note was read from reaches it, so every note is addressed
|
|
152
|
+
* alike and there is one rule and no branch. It takes no address scheme:
|
|
153
|
+
* `prefix` is the whole scheme and the paragraph above is the reason it never
|
|
154
|
+
* applies here.
|
|
157
155
|
*
|
|
158
156
|
* @param {object} fm - Parsed frontmatter.
|
|
159
157
|
* @returns {string} The package-relative address, with a trailing slash and no
|
|
@@ -288,13 +286,12 @@ export const DOCUMENT_ID_NAMESPACE = "document";
|
|
|
288
286
|
* The Foundry `_id` of the document a note compiles into, derived from its
|
|
289
287
|
* canonical address.
|
|
290
288
|
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
289
|
+
* An authored id would be an opaque string that says nothing its address
|
|
290
|
+
* does not and that no check guarantees. The address is the identity that
|
|
291
|
+
* *is* guaranteed: `content-lint` refuses a
|
|
294
292
|
* duplicate `(type, shortcode)` across every pack of a document type, which is
|
|
295
293
|
* exactly the scope a primary document's id must be unique within. So the
|
|
296
|
-
* derived id inherits
|
|
297
|
-
* none.
|
|
294
|
+
* derived id inherits that guard.
|
|
298
295
|
*
|
|
299
296
|
* **The coupling this creates, stated plainly.** The address carries the
|
|
300
297
|
* shortcode, so renaming a shortcode moves the document's id — where an
|
|
@@ -303,7 +300,7 @@ export const DOCUMENT_ID_NAMESPACE = "document";
|
|
|
303
300
|
* note, so it is a breaking change either way; and a note that must keep its
|
|
304
301
|
* identity across a rename pins an `id`, which is what the pin is for. One
|
|
305
302
|
* thing genuinely degrades — `engine/address-diff.mjs` tells a rename from a
|
|
306
|
-
* withdrawal by matching document ids, and
|
|
303
|
+
* withdrawal by matching document ids, and cannot do so for a note that
|
|
307
304
|
* authors none. Its module note records that.
|
|
308
305
|
*
|
|
309
306
|
* @param {string} pkg - The owning **content** package.
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
/*
|
|
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
|
+
|
|
2
14
|
import MarkdownIt from "markdown-it";
|
|
3
15
|
import { parseExtensionAttributes, refusedAttributes } from "./extension-attributes.mjs";
|
|
4
16
|
import { slugify } from "./content-slug.mjs";
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
/**
|
|
4
15
|
* General divs and the `:::secret` disclosure fence.
|
|
@@ -30,8 +41,8 @@
|
|
|
30
41
|
* whole page, or Hugo's of the whole site page — read the body as part of its
|
|
31
42
|
* own document rather than as an isolated fragment. A fragment rendered on its
|
|
32
43
|
* own has no access to the note's footnote definitions, which live at the top
|
|
33
|
-
* level outside every block, so a reference inside one
|
|
34
|
-
* literal `[^id]` text; reached by the one parse that also sees the
|
|
44
|
+
* level outside every block, so a reference inside one would fall through as
|
|
45
|
+
* literal `[^id]` text if rendered alone; reached by the one parse that also sees the
|
|
35
46
|
* definitions, it resolves exactly as a reference inside a list item or a
|
|
36
47
|
* block quote already does.
|
|
37
48
|
*
|
|
@@ -153,8 +153,8 @@ export function embedsIn(body, context) {
|
|
|
153
153
|
* @param {object} index - From {@link module:engine/wikilinks.buildWikilinkIndex},
|
|
154
154
|
* or the equivalent the site and the book build.
|
|
155
155
|
* @param {ParsedEmbed} embed - The embed.
|
|
156
|
-
* @returns {{pathname: string}|{reason: string, target: string, type?: string
|
|
157
|
-
* The authored pathname the picture is at, or the finding.
|
|
156
|
+
* @returns {{pathname: string}|{reason: string, target: string, type?: string,
|
|
157
|
+
* shortcode?: string, declared?: string}} The authored pathname the picture is at, or the finding.
|
|
158
158
|
*/
|
|
159
159
|
export function resolveEmbed(index, embed) {
|
|
160
160
|
// **Every link carries a label**, and an embed is a link. Without one there
|
|
@@ -170,7 +170,13 @@ export function resolveEmbed(index, embed) {
|
|
|
170
170
|
if (read.record) {
|
|
171
171
|
return { pathname: read.pathname };
|
|
172
172
|
}
|
|
173
|
-
return {
|
|
173
|
+
return {
|
|
174
|
+
reason: read.reason,
|
|
175
|
+
target: embed.written,
|
|
176
|
+
type: read.type,
|
|
177
|
+
...(read.shortcode ? { shortcode: read.shortcode } : {}),
|
|
178
|
+
...(read.declared ? { declared: read.declared } : {}),
|
|
179
|
+
};
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
/**
|
|
@@ -288,6 +294,8 @@ export function resolveEmbeds(body, { index }) {
|
|
|
288
294
|
offset: embed.index,
|
|
289
295
|
reason: resolved.reason,
|
|
290
296
|
...(resolved.type ? { type: resolved.type } : {}),
|
|
297
|
+
...(resolved.shortcode ? { shortcode: resolved.shortcode } : {}),
|
|
298
|
+
...(resolved.declared ? { declared: resolved.declared } : {}),
|
|
291
299
|
});
|
|
292
300
|
continue;
|
|
293
301
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
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
|
+
*
|
|
2
11
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
12
|
*/
|
|
4
13
|
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
/*
|
|
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
|
+
*/
|
|
2
13
|
|
|
3
14
|
/**
|
|
4
15
|
* Where a footnote's two halves belong, and the two findings that hold the
|