@heroiclands/package-build 23.1.1 → 23.2.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 +69 -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/labels.mjs +2 -2
- 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/field-spec.mjs
CHANGED
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
* @module
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
-
import {
|
|
46
|
+
import { resolveFieldValue, setPath } from "./system-block.mjs";
|
|
47
47
|
|
|
48
|
-
export {
|
|
48
|
+
export { setPath };
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* @typedef {object} FieldSpec
|
|
@@ -61,29 +61,10 @@ export { legacyKeyOf, retiredTopLevelKey, setPath };
|
|
|
61
61
|
* degenerate case where the shared source and the system destination happen
|
|
62
62
|
* to share a name. They constantly do not — one shared `data.portrait` feeds
|
|
63
63
|
* `sohl.system.portrait` *and* `hm3.system.bioImage` — so the source is
|
|
64
|
-
* declared rather than matched by spelling.
|
|
65
|
-
*
|
|
66
|
-
* `legacyKey` where the two spellings differ.
|
|
64
|
+
* declared rather than matched by spelling. A name that is not a path into
|
|
65
|
+
* `data:` is also read inside the system block, second.
|
|
67
66
|
*
|
|
68
67
|
* Absent means the value is not authored at all — see `value`.
|
|
69
|
-
* @property {string} [legacyKey] - **The key this field is authored at inside
|
|
70
|
-
* the system block** — the second position of the resolution order — when
|
|
71
|
-
* that is not `name`. Absent, the position is keyed on `name`.
|
|
72
|
-
*
|
|
73
|
-
* As one property the two would hold only while a field's
|
|
74
|
-
* shared source and its in-block key were the same word. `data:` ended
|
|
75
|
-
* that: a shared source is a path into a container, so `data.species` and
|
|
76
|
-
* `species` name two different places and no single value reached both.
|
|
77
|
-
* `name: "species"` could not see `data.species`; `name: "data.species"`
|
|
78
|
-
* could not see `hm3.species`; and each yielded the field's **default**
|
|
79
|
-
* wherever only the other position was authored, with the note compiling and
|
|
80
|
-
* the value simply gone.
|
|
81
|
-
*
|
|
82
|
-
* Declaring both restores the shape every other retirement in this package
|
|
83
|
-
* uses — read both spellings, let the current one win, and *report* the
|
|
84
|
-
* retiring one — so a field can move into `data:` while the corpus catches
|
|
85
|
-
* up, instead of on a flag day across four repositories. A declaration that
|
|
86
|
-
* names one is mid-sweep by construction; see {@link readsLegacyKey}.
|
|
87
68
|
* @property {string} [topLevelMeans] - **Why the note's top-level key of this
|
|
88
69
|
* name is not this field's source** — declared wherever that key's spelling
|
|
89
70
|
* means something else at the note level, or the closed top-level
|
|
@@ -109,7 +90,7 @@ export { legacyKeyOf, retiredTopLevelKey, setPath };
|
|
|
109
90
|
*
|
|
110
91
|
* The exempted field is still authorable, at both of the positions that
|
|
111
92
|
* describe the *document* rather than the note: `<system>.system.<to>` and
|
|
112
|
-
* the
|
|
93
|
+
* the in-block `<system>.<name>`. Absent means the ordinary case —
|
|
113
94
|
* the top level is read, as the third step.
|
|
114
95
|
*
|
|
115
96
|
* **It is read from the other side too**, because the statement is symmetric:
|
|
@@ -211,7 +192,7 @@ export { legacyKeyOf, retiredTopLevelKey, setPath };
|
|
|
211
192
|
* itself a valid world time, which is why such a field is nullable rather
|
|
212
193
|
* than sentinelled and why a default cannot stand in for one.
|
|
213
194
|
*
|
|
214
|
-
* Nothing
|
|
195
|
+
* Nothing else stops a note writing one. The three checks that might have
|
|
215
196
|
* each declined for its own correct reason —
|
|
216
197
|
* {@link module:engine/system-block.unknownBlockKeys} reads the block's top
|
|
217
198
|
* level and never descends into `system:`;
|
|
@@ -306,57 +287,12 @@ export const BLANK_IS_DEFAULT = Object.freeze({
|
|
|
306
287
|
/* Applying a declaration */
|
|
307
288
|
/* --------------------------------------------------------------------- */
|
|
308
289
|
|
|
309
|
-
/**
|
|
310
|
-
* Whether a resolution read a field from the position it is being swept off.
|
|
311
|
-
*
|
|
312
|
-
* The sweep's progress signal, in one predicate so the compile-time report and
|
|
313
|
-
* the frontmatter lint cannot disagree about what counts — the role
|
|
314
|
-
* {@link module:engine/retired-fields.declaresRetiredAlias} plays for a renamed
|
|
315
|
-
* field.
|
|
316
|
-
*
|
|
317
|
-
* **Only for a field that declares a `legacyKey`.** Every other field's
|
|
318
|
-
* in-block position is simply where it lives; reporting those would put a
|
|
319
|
-
* finding on every field of every note in every tree, which is the corpus
|
|
320
|
-
* migration rather than a signal anyone could act on.
|
|
321
|
-
*
|
|
322
|
-
* @param {FieldSpec} field - The declaration.
|
|
323
|
-
* @param {import("./system-block.mjs").FieldSource} from - Where
|
|
324
|
-
* {@link resolveFieldValue} said the value came from.
|
|
325
|
-
* @returns {boolean} True when the value came from the retiring position.
|
|
326
|
-
*/
|
|
327
|
-
export function readsLegacyKey(field, from) {
|
|
328
|
-
return field?.legacyKey !== undefined && from === "block";
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Whether a resolution read a field from the top-level key `data:` gathered it
|
|
333
|
-
* off — the shared level's retiring position.
|
|
334
|
-
*
|
|
335
|
-
* {@link readsLegacyKey}'s sibling, and the same signal: a finding here counts
|
|
336
|
-
* one note still on the pre-`data:` spelling, so the sweep has something to
|
|
337
|
-
* count down instead of a corpus nobody has surveyed.
|
|
338
|
-
*
|
|
339
|
-
* The `from` tag already carries the whole answer — step 3b is the only thing
|
|
340
|
-
* that produces it, and it produces it only for a `data.` source — so this is a
|
|
341
|
-
* name for the question rather than a second test of it. Named all the same,
|
|
342
|
-
* because a compile-time report and the frontmatter lint both ask it and must
|
|
343
|
-
* not drift apart about what counts.
|
|
344
|
-
*
|
|
345
|
-
* @param {FieldSpec} field - The declaration.
|
|
346
|
-
* @param {import("./system-block.mjs").FieldSource} from - Where
|
|
347
|
-
* {@link resolveFieldValue} said the value came from.
|
|
348
|
-
* @returns {boolean} True when the value came from the retiring top-level key.
|
|
349
|
-
*/
|
|
350
|
-
export function readsRetiredTopLevel(field, from) {
|
|
351
|
-
return from === "topLevel" && retiredTopLevelKey(field) !== undefined;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
290
|
/**
|
|
355
291
|
* Read one declared field out of a note's frontmatter.
|
|
356
292
|
*
|
|
357
293
|
* The *position* is resolved by {@link resolveFieldValue} — `<system>.system`
|
|
358
|
-
* first, then the
|
|
359
|
-
*
|
|
294
|
+
* first, then the in-block key, then the declared shared source, then the
|
|
295
|
+
* default. The **coercion** is applied here, once, wherever the value
|
|
360
296
|
* came from: a field's `read` is a statement about the field, not about where
|
|
361
297
|
* an author happened to write it, so `weight: "7"` reads as `7` at every one of
|
|
362
298
|
* those positions.
|
|
@@ -367,17 +303,6 @@ export function readsRetiredTopLevel(field, from) {
|
|
|
367
303
|
* @param {string} [options.block="sohl"] - Which system's block to resolve
|
|
368
304
|
* against. The default is the one block every existing tree authors; a
|
|
369
305
|
* second system passes its own.
|
|
370
|
-
* @param {(field: FieldSpec) => void} [options.onLegacyKey] - Called with each
|
|
371
|
-
* field read from the position it is being swept off. A callback
|
|
372
|
-
* rather than a returned list because the caller is a compiler, which already
|
|
373
|
-
* knows the note and how to locate a key in it; this module knows neither and
|
|
374
|
-
* would have to invent a finding shape to say so.
|
|
375
|
-
* @param {(field: FieldSpec) => void} [options.onRetiredTopLevel] - Called with
|
|
376
|
-
* each field read from the top-level key `data:` gathered it off. The
|
|
377
|
-
* shared level's counterpart to `onLegacyKey`, and a separate callback
|
|
378
|
-
* because it is a separate position: a note may have moved one of the two and
|
|
379
|
-
* not the other, and a caller that conflated them would tell its author to
|
|
380
|
-
* fix the wrong line.
|
|
381
306
|
* @returns {any} The value to emit.
|
|
382
307
|
*/
|
|
383
308
|
export function readField(field, fm, options = {}) {
|
|
@@ -403,18 +328,12 @@ export function readField(field, fm, options = {}) {
|
|
|
403
328
|
* @param {object} [options] - Options, as {@link readField} takes them.
|
|
404
329
|
* @param {string} [options.block="sohl"] - Which system's block to resolve
|
|
405
330
|
* against.
|
|
406
|
-
* @param {(field: FieldSpec) => void} [options.onLegacyKey] - See
|
|
407
|
-
* {@link readField}.
|
|
408
|
-
* @param {(field: FieldSpec) => void} [options.onRetiredTopLevel] - See
|
|
409
|
-
* {@link readField}.
|
|
410
331
|
* @returns {{value: any, from: import("./system-block.mjs").FieldSource}} The
|
|
411
332
|
* value to emit, and the position it was read from.
|
|
412
333
|
*/
|
|
413
|
-
export function readFieldEntry(field, fm, { block = "sohl"
|
|
334
|
+
export function readFieldEntry(field, fm, { block = "sohl" } = {}) {
|
|
414
335
|
const { value, from } = resolveFieldValue(field, fm, { block });
|
|
415
336
|
if (from === "value") return { value, from };
|
|
416
|
-
if (onLegacyKey && readsLegacyKey(field, from)) onLegacyKey(field);
|
|
417
|
-
if (onRetiredTopLevel && readsRetiredTopLevel(field, from)) onRetiredTopLevel(field);
|
|
418
337
|
return { value: field.read ? field.read(value, { fm, field }) : value, from };
|
|
419
338
|
}
|
|
420
339
|
|
|
@@ -453,15 +372,9 @@ export function isAuthored(from, value) {
|
|
|
453
372
|
* @param {string} [options.block="sohl"] - Which system's block the builder
|
|
454
373
|
* reads. One declaration compiles against any block, which is what lets two
|
|
455
374
|
* systems declare the same shared source and different destinations.
|
|
456
|
-
* @param {(field: FieldSpec) => void} [options.onLegacyKey] - Passed through to
|
|
457
|
-
* {@link readField}: called with each field the note authored at the position
|
|
458
|
-
* it is being swept off.
|
|
459
|
-
* @param {(field: FieldSpec) => void} [options.onRetiredTopLevel] - Passed
|
|
460
|
-
* through to {@link readField}: called with each field the note authored at
|
|
461
|
-
* the top-level key `data:` gathered it off.
|
|
462
375
|
* @returns {(fm: object) => object} A `system`-block builder.
|
|
463
376
|
*/
|
|
464
|
-
export function buildFromFields(fields, { block = "sohl"
|
|
377
|
+
export function buildFromFields(fields, { block = "sohl" } = {}) {
|
|
465
378
|
return function buildDeclaredSystem(fm) {
|
|
466
379
|
const out = {};
|
|
467
380
|
for (const field of fields) {
|
|
@@ -474,11 +387,7 @@ export function buildFromFields(fields, { block = "sohl", onLegacyKey, onRetired
|
|
|
474
387
|
// `initial` standing; writing the `undefined` a source-less
|
|
475
388
|
// declaration resolves to would put the key in the document.
|
|
476
389
|
if (field.runtimeOnly) continue;
|
|
477
|
-
const { value, from } = readFieldEntry(field, fm, {
|
|
478
|
-
block,
|
|
479
|
-
onLegacyKey,
|
|
480
|
-
onRetiredTopLevel,
|
|
481
|
-
});
|
|
390
|
+
const { value, from } = readFieldEntry(field, fm, { block });
|
|
482
391
|
// The other conditional row: a field whose *absence* is meaningful.
|
|
483
392
|
// Writing a declared default would answer a question the
|
|
484
393
|
// note did not ask — "this affliction's onset takes `null` days" —
|
package/engine/folder-notes.mjs
CHANGED
|
@@ -57,7 +57,6 @@ import { NO_SYSTEM, canonicalKey, readCanonicalKey } from "./content-address.mjs
|
|
|
57
57
|
import { parseAddress, renderAddress } from "./address.mjs";
|
|
58
58
|
import { ADDRESS_SEGMENT_PATTERN, isAddressSegment } from "./address-charset.mjs";
|
|
59
59
|
import { makeId } from "./ids.mjs";
|
|
60
|
-
import { locateFrontmatterKey } from "./retired-fields.mjs";
|
|
61
60
|
|
|
62
61
|
/**
|
|
63
62
|
* The note type a folder is authored as.
|
|
@@ -522,66 +521,3 @@ export function folderDocument(folder, parent, documentType, stats) {
|
|
|
522
521
|
_key: `!folders!${folder.id}`,
|
|
523
522
|
};
|
|
524
523
|
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* Refuse a note that declares the retired `folder:` spelling.
|
|
528
|
-
*
|
|
529
|
-
* `folder:` named a compendium folder by the raw Foundry id declared in a
|
|
530
|
-
* per-pack `*-folders.yaml`. Both halves are retired together: the id
|
|
531
|
-
* spelling has nothing left to resolve against once the YAML is gone, and the
|
|
532
|
-
* YAML has no reader once the spelling is refused.
|
|
533
|
-
*
|
|
534
|
-
* **Presence is the whole test.** An empty `folder:` — which parses as `null`
|
|
535
|
-
* — is still the field, and a value that happens to match a folder note's id
|
|
536
|
-
* is still the retired spelling. There is no value that makes writing it
|
|
537
|
-
* correct, so the message says what to write instead rather than which value
|
|
538
|
-
* to change.
|
|
539
|
-
*
|
|
540
|
-
* **Both positions**, because notes wrote it both ways: top-level, and inside
|
|
541
|
-
* the `sohl:` block. Checking only the more common one is how a sweep leaves
|
|
542
|
-
* a tail behind.
|
|
543
|
-
*
|
|
544
|
-
* Refused rather than ignored, on the pattern `package:` set: a retired field
|
|
545
|
-
* left ignored reads to its author as though it still works — the note says
|
|
546
|
-
* one thing and the build does another, and nothing says so.
|
|
547
|
-
*
|
|
548
|
-
* @param {object|null|undefined} fm - Parsed frontmatter, or nothing when it
|
|
549
|
-
* could not be parsed.
|
|
550
|
-
* @param {object} [options] - Options.
|
|
551
|
-
* @param {string} [options.file] - The note's path, named in the message. Omit
|
|
552
|
-
* it where the caller emits through a diagnostic, which puts the locator at
|
|
553
|
-
* the start of the line already — repeating it prints the path twice.
|
|
554
|
-
* @param {string} [options.absPath] - The note's file on disk, read only on
|
|
555
|
-
* the failing path to locate the offending line and column. The position
|
|
556
|
-
* rides on the thrown error as `position`, for a caller that emits a
|
|
557
|
-
* diagnostic.
|
|
558
|
-
* @returns {void}
|
|
559
|
-
* @throws {Error} When the note declares the field.
|
|
560
|
-
*/
|
|
561
|
-
export function assertNoDeclaredFolder(fm, { file, absPath } = {}) {
|
|
562
|
-
if (!fm || typeof fm !== "object") return;
|
|
563
|
-
const sohl = fm.sohl;
|
|
564
|
-
const inBlock = !!sohl && typeof sohl === "object" && Object.hasOwn(sohl, "folder");
|
|
565
|
-
if (!Object.hasOwn(fm, "folder") && !inBlock) return;
|
|
566
|
-
|
|
567
|
-
const declared = inBlock ? sohl.folder : fm.folder;
|
|
568
|
-
const wrote =
|
|
569
|
-
declared === null || declared === undefined || declared === "" ?
|
|
570
|
-
"`folder:`"
|
|
571
|
-
: `\`folder: ${declared}\``;
|
|
572
|
-
|
|
573
|
-
const err = new Error(
|
|
574
|
-
`${wrote} is a retired frontmatter field — write \`packFolder\` ` +
|
|
575
|
-
`instead` +
|
|
576
|
-
(file ? ` — ${file}` : "") +
|
|
577
|
-
`. A folder is a note now, and \`packFolder\` names it by its ` +
|
|
578
|
-
`address (\`packFolder: miscgear\`), not by the Foundry id a ` +
|
|
579
|
-
`retired \`*-folders.yaml\` used to declare.`,
|
|
580
|
-
);
|
|
581
|
-
// Where the field is, so the caller's diagnostic opens on the line that
|
|
582
|
-
// has to be rewritten. Read here rather than carried through every walk:
|
|
583
|
-
// this is the failing path, and the build stops on it.
|
|
584
|
-
const position = locateFrontmatterKey(absPath, "folder");
|
|
585
|
-
if (position) err.position = position;
|
|
586
|
-
throw err;
|
|
587
|
-
}
|
|
@@ -795,7 +795,8 @@ function findLocalIndex(root, name) {
|
|
|
795
795
|
* Fetch every declared dependency's content index.
|
|
796
796
|
*
|
|
797
797
|
* A wider set than {@link fetchAllCatalogs}: an index is fetched for *every*
|
|
798
|
-
* dependency,
|
|
798
|
+
* dependency, plus every other relationship declaring `itemCatalog: true`; a
|
|
799
|
+
* catalogue only for those declaring `itemCatalog: true`. See
|
|
799
800
|
* {@link metadataRelationships} for why the two sets differ.
|
|
800
801
|
*
|
|
801
802
|
* @param {object} config - The resolved build configuration.
|
|
@@ -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
|
|
|
@@ -36,8 +36,7 @@
|
|
|
36
36
|
* no uniqueness check stands between the two. The system segment goes with the
|
|
37
37
|
* package because a note publishes one page however many systems' documents it
|
|
38
38
|
* compiles into. Every entry is
|
|
39
|
-
* derivable that way
|
|
40
|
-
* that was not. The field is still written rather than left for a consumer to
|
|
39
|
+
* derivable that way. The field is still written rather than left for a consumer to
|
|
41
40
|
* compute, because an absent `path` already means something else entirely (a
|
|
42
41
|
* package that publishes no pages).
|
|
43
42
|
*
|
|
@@ -72,19 +71,12 @@ import { DEFAULT_DOCUMENT_SUBTYPES, SYSTEM_DOCUMENT_CLASSES } from "./subtype-re
|
|
|
72
71
|
import { carriesSystemBlock } from "./system-block.mjs";
|
|
73
72
|
import { walkMarkdownTree } from "./helpers.mjs";
|
|
74
73
|
import { resolveNoteId } from "./note-ids.mjs";
|
|
75
|
-
import { compendiumUuid,
|
|
74
|
+
import { compendiumUuid, packForType, pageUuid } from "./ids.mjs";
|
|
76
75
|
import { hasDocEntry, itemDocEntryId } from "./item-docs.mjs";
|
|
77
76
|
import { journalHasContent } from "./note-state.mjs";
|
|
78
77
|
import { isHomepage } from "./homepage.mjs";
|
|
79
78
|
import { declaresNoPack } from "./pack-router.mjs";
|
|
80
79
|
import { assertNoDeclaredPackage } from "./note-package.mjs";
|
|
81
|
-
import { assertNoDeclaredFolder } from "./folder-notes.mjs";
|
|
82
|
-
import {
|
|
83
|
-
assertNoAliasesField,
|
|
84
|
-
assertNoDraftField,
|
|
85
|
-
assertNoSectionField,
|
|
86
|
-
assertNoTraitsField,
|
|
87
|
-
} from "./retired-fields.mjs";
|
|
88
80
|
import { collectAnchors } from "./anchors.mjs";
|
|
89
81
|
import { journalPageId, splitPages } from "./journals.mjs";
|
|
90
82
|
import { routerFor } from "./pack-router.mjs";
|
|
@@ -180,11 +172,9 @@ export function entriesForNote(fm, name, address, body, ctx) {
|
|
|
180
172
|
}
|
|
181
173
|
|
|
182
174
|
// A type this cannot name a single compendium document for has no UUID
|
|
183
|
-
// to publish, whatever id it derives.
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
// rule is stated where it belongs — beside the addresses — rather than
|
|
187
|
-
// resting on an absent field. `collectFoundryEntries` skips such a note
|
|
175
|
+
// to publish, whatever id it derives. Every addressable note derives an
|
|
176
|
+
// id, so "has an id" is no evidence a document exists; the rule is
|
|
177
|
+
// stated beside the addresses. `collectFoundryEntries` skips such a note
|
|
188
178
|
// outright; the content index calls this function directly, so the
|
|
189
179
|
// guard has to live on this side of it.
|
|
190
180
|
//
|
|
@@ -250,9 +240,7 @@ export function entriesForNote(fm, name, address, body, ctx) {
|
|
|
250
240
|
};
|
|
251
241
|
|
|
252
242
|
const carriesDoc =
|
|
253
|
-
ctx.docEntryTypes ?
|
|
254
|
-
ctx.docEntryTypes.has(String(currentType(fm.type)))
|
|
255
|
-
: hasDocEntry(fm.type);
|
|
243
|
+
ctx.docEntryTypes ? ctx.docEntryTypes.has(String(fm.type)) : hasDocEntry(fm.type);
|
|
256
244
|
if (carriesDoc) {
|
|
257
245
|
// `NO_SYSTEM`, whatever the item is: a documentation journal is a
|
|
258
246
|
// JournalEntry, which no game system defines, and there is one of them
|
|
@@ -311,11 +299,10 @@ export function entriesForNote(fm, name, address, body, ctx) {
|
|
|
311
299
|
* Every note this package publishes, as manifest entries.
|
|
312
300
|
*
|
|
313
301
|
* Every note in the tree is this package's, so nothing here selects by package:
|
|
314
|
-
* the key's first segment is `contentPackage`. A note
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* a drafted note's inbound links look like links to a note that never existed.
|
|
302
|
+
* the key's first segment is `contentPackage`. A note declaring `package:`
|
|
303
|
+
* **throws** rather than being skipped — skipping one silently is how a whole
|
|
304
|
+
* tree came to be filtered out of a manifest that then claimed the package
|
|
305
|
+
* published nothing.
|
|
319
306
|
*
|
|
320
307
|
* A note that has no address is **reported, not guessed** — the finding carries
|
|
321
308
|
* the file and the reason, so a caller can print it or fail on it. Inventing an
|
|
@@ -349,11 +336,6 @@ export function collectFoundryEntries(contentBase, ctx) {
|
|
|
349
336
|
absPath,
|
|
350
337
|
configured: ctx.contentPackage,
|
|
351
338
|
});
|
|
352
|
-
assertNoDeclaredFolder(fm, { file: rel, absPath });
|
|
353
|
-
assertNoDraftField(fm, { file: rel, absPath });
|
|
354
|
-
assertNoAliasesField(fm, { file: rel, absPath });
|
|
355
|
-
assertNoSectionField(fm, { file: rel, absPath });
|
|
356
|
-
assertNoTraitsField(fm, { file: rel, absPath });
|
|
357
339
|
if (!fm.type || !fm.shortcode) continue;
|
|
358
340
|
// A homepage is addressed like every other note, and a
|
|
359
341
|
// shortcode alone would now put it here. It stays out for the reason it
|