@heroiclands/package-build 21.0.0 → 21.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 +228 -0
- package/CONTENT.md +109 -7
- package/assets/fonts/libertinus/LibertinusMono-Regular.otf +0 -0
- package/assets/fonts/libertinus/LibertinusSans-Bold.otf +0 -0
- package/assets/fonts/libertinus/LibertinusSans-Italic.otf +0 -0
- package/assets/fonts/libertinus/LibertinusSans-Regular.otf +0 -0
- package/assets/fonts/libertinus/OFL.txt +94 -0
- package/assets/fonts/libertinus/provenance.yaml +11 -0
- package/assets/images/banners/afflictionbnr.webp +0 -0
- package/assets/images/banners/armorclothingbnr.webp +0 -0
- package/assets/images/banners/attributebnr.webp +0 -0
- package/assets/images/banners/containerbnr.webp +0 -0
- package/assets/images/banners/devdocsbnr.webp +0 -0
- package/assets/images/banners/miscgearbnr.webp +0 -0
- package/assets/images/banners/mysticalabilitybnr.webp +0 -0
- package/assets/images/banners/projectilebnr.webp +0 -0
- package/assets/images/banners/rulesbnr.webp +0 -0
- package/assets/images/banners/skillbnr.webp +0 -0
- package/assets/images/banners/traumabnr.webp +0 -0
- package/assets/images/banners/userguidebnr.webp +0 -0
- package/assets/images/banners/weapongearbnr.webp +0 -0
- package/assets/images/provenance.yaml +4 -0
- package/bin/content-build.mjs +19 -5
- package/ci/emit-asset-index.mjs +32 -0
- package/content-config.mjs +30 -1
- package/docs/api.md +100 -26
- package/docs/configuration.md +16 -7
- package/docs/content-format.md +512 -109
- package/engine/actor-compiler.mjs +58 -9
- package/engine/art-fields.mjs +292 -0
- package/engine/asset-index.mjs +397 -0
- package/engine/asset-types.mjs +192 -0
- package/engine/base-compiler.mjs +69 -1
- package/engine/bundles.mjs +5 -5
- package/engine/compile-corpus.mjs +4 -0
- package/engine/content-address.mjs +14 -2
- package/engine/content-charset.mjs +5 -1
- package/engine/content-embeds.mjs +314 -0
- package/engine/content-html.mjs +5 -1
- package/engine/content-icons.mjs +5 -1
- package/engine/content-images.mjs +26 -5
- package/engine/content-index.mjs +68 -33
- package/engine/content-links.mjs +164 -24
- package/engine/frontmatter-lint.mjs +36 -23
- package/engine/helpers.mjs +83 -31
- package/engine/index-records.mjs +63 -4
- package/engine/index.mjs +15 -0
- package/engine/infobox-registry.mjs +50 -3
- package/engine/infobox-render.mjs +4 -3
- package/engine/infobox.mjs +12 -8
- package/engine/item-compiler.mjs +10 -10
- package/engine/journals.mjs +3 -0
- package/engine/macros.mjs +16 -13
- package/engine/map-notes.mjs +29 -22
- package/engine/metadata-index.mjs +44 -36
- package/engine/note-vocabulary.mjs +71 -29
- package/engine/pack-router.mjs +14 -0
- package/engine/packagebuild-index.mjs +124 -0
- package/engine/packages.mjs +83 -0
- package/engine/pathnames.mjs +74 -0
- package/engine/pdf-build.mjs +133 -10
- package/engine/pdf-render.mjs +41 -41
- package/engine/scenes.mjs +12 -9
- package/engine/site-build.mjs +43 -16
- package/engine/site-index.mjs +10 -1
- package/engine/subtype-registry.mjs +21 -0
- package/engine/web-wikilinks.mjs +46 -12
- package/engine/wikilink-syntax.mjs +20 -2
- package/engine/wikilinks.mjs +15 -2
- package/hm3/actors.mjs +11 -38
- package/hm3/infobox.mjs +1 -1
- package/package.json +5 -2
- package/packagebuild-metadata.jsonl +13 -0
- package/sohl/actors.mjs +12 -86
- package/sohl/infobox.mjs +1 -1
- package/sohl/note-schemas.mjs +4 -16
- package/types/content-config.d.mts +8 -0
- package/types/engine/actor-compiler.d.mts +29 -0
- package/types/engine/art-fields.d.mts +192 -0
- package/types/engine/asset-index.d.mts +92 -0
- package/types/engine/asset-types.d.mts +110 -0
- package/types/engine/base-compiler.d.mts +42 -1
- package/types/engine/compile-corpus.d.mts +4 -1
- package/types/engine/content-charset.d.mts +4 -0
- package/types/engine/content-embeds.d.mts +218 -0
- package/types/engine/content-html.d.mts +4 -0
- package/types/engine/content-icons.d.mts +4 -0
- package/types/engine/content-images.d.mts +15 -2
- package/types/engine/content-index.d.mts +27 -15
- package/types/engine/frontmatter-lint.d.mts +11 -14
- package/types/engine/helpers.d.mts +7 -2
- package/types/engine/index-records.d.mts +44 -3
- package/types/engine/index.d.mts +5 -0
- package/types/engine/infobox-registry.d.mts +36 -1
- package/types/engine/infobox.d.mts +6 -4
- package/types/engine/macros.d.mts +9 -5
- package/types/engine/map-notes.d.mts +10 -6
- package/types/engine/metadata-index.d.mts +2 -17
- package/types/engine/note-vocabulary.d.mts +30 -0
- package/types/engine/packagebuild-index.d.mts +56 -0
- package/types/engine/packages.d.mts +62 -0
- package/types/engine/pathnames.d.mts +41 -81
- package/types/engine/pdf-build.d.mts +58 -1
- package/types/engine/pdf-render.d.mts +3 -3
- package/types/engine/scenes.d.mts +2 -1
- package/types/engine/site-build.d.mts +5 -1
- package/types/engine/site-index.d.mts +4 -1
- package/types/engine/subtype-registry.d.mts +20 -0
- package/types/engine/web-wikilinks.d.mts +14 -4
- package/types/engine/wikilink-syntax.d.mts +13 -1
- package/types/engine/wikilinks.d.mts +7 -1
- package/types/sohl/actors.d.mts +0 -1
package/sohl/actors.mjs
CHANGED
|
@@ -46,13 +46,7 @@
|
|
|
46
46
|
* @module
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
-
import {
|
|
50
|
-
sohlField,
|
|
51
|
-
resolveName,
|
|
52
|
-
resolveImg,
|
|
53
|
-
systemTemplatePriority,
|
|
54
|
-
folderField,
|
|
55
|
-
} from "../engine/helpers.mjs";
|
|
49
|
+
import { sohlField, resolveName, systemTemplatePriority, folderField } from "../engine/helpers.mjs";
|
|
56
50
|
import { openingMasteryLevel } from "./skill-base.mjs";
|
|
57
51
|
import { SystemActorCompiler, renderSection } from "../engine/actor-compiler.mjs";
|
|
58
52
|
// Which Foundry Actor subtype a note's `type` compiles into. Looked up in the
|
|
@@ -63,14 +57,6 @@ import { SOHL_DOCUMENT_SUBTYPES } from "./document-subtypes.mjs";
|
|
|
63
57
|
// verbatim, and `sohl.img` / `sohl.effects` / `sohl.flags` overriding their
|
|
64
58
|
// shared top-level forms for this system alone.
|
|
65
59
|
import { blockProperty, mergeSystemData } from "../engine/system-block.mjs";
|
|
66
|
-
import { readField, retiredTopLevelKey } from "../engine/field-spec.mjs";
|
|
67
|
-
// The retirement window's reports, shared with the frontmatter lint so the two
|
|
68
|
-
// cannot say different things about the same key.
|
|
69
|
-
import {
|
|
70
|
-
legacyKeyMessage,
|
|
71
|
-
locateFrontmatterKey,
|
|
72
|
-
retiredTopLevelMessage,
|
|
73
|
-
} from "../engine/retired-fields.mjs";
|
|
74
60
|
|
|
75
61
|
/**
|
|
76
62
|
* The system this pass compiles for — the block its notes write.
|
|
@@ -89,38 +75,6 @@ const DEFAULT_IMG = {
|
|
|
89
75
|
being: "systems/sohl/assets/icons/game-icons/delapouite/person.svg",
|
|
90
76
|
};
|
|
91
77
|
|
|
92
|
-
/**
|
|
93
|
-
* The being's sheet portrait — the one row of the content format's actor
|
|
94
|
-
* mapping table that is authored rather than derived.
|
|
95
|
-
*
|
|
96
|
-
* **Declared, because the position is not a spelling anyone can guess.** This
|
|
97
|
-
* was read with `blockProperty(fm, SYSTEM, "portrait")`, which knows the block
|
|
98
|
-
* and the note's top level and nothing else — so `data.portrait`, the position
|
|
99
|
-
* the specification names and `sohl-thalorna` writes on 646 beings, was
|
|
100
|
-
* invisible, and `?? defaultImg` on the next line turned every miss into the
|
|
101
|
-
* generic person icon rather than into a complaint. Going through
|
|
102
|
-
* {@link module:engine/field-spec.readField} is what makes the mapping table
|
|
103
|
-
* executable here as it already is for HM3's `data.species`.
|
|
104
|
-
*
|
|
105
|
-
* `img` is deliberately **not** declared beside it: the mapping table keeps a
|
|
106
|
-
* note's token art at the top level, so `blockProperty` is the whole of its
|
|
107
|
-
* resolution and there is no `data.img` to reach for.
|
|
108
|
-
*
|
|
109
|
-
* @type {import("../engine/field-spec.mjs").FieldSpec}
|
|
110
|
-
*/
|
|
111
|
-
const PORTRAIT_FIELD = Object.freeze({
|
|
112
|
-
name: "data.portrait",
|
|
113
|
-
legacyKey: "portrait",
|
|
114
|
-
to: "portrait",
|
|
115
|
-
shape: "path",
|
|
116
|
-
// The two empties survive, because the caller's `?? defaultImg` is what
|
|
117
|
-
// tells them apart: `null` and an absent key mean "no art named, default
|
|
118
|
-
// me", `""` means "ship blank on purpose".
|
|
119
|
-
read: (raw) => resolveImg(raw),
|
|
120
|
-
default: null,
|
|
121
|
-
describe: "Path to the portrait image.",
|
|
122
|
-
});
|
|
123
|
-
|
|
124
78
|
/**
|
|
125
79
|
* The default art for an actor subtype.
|
|
126
80
|
*
|
|
@@ -366,43 +320,16 @@ export class Actors extends SystemActorCompiler {
|
|
|
366
320
|
absPath: this.currentNote?.absPath,
|
|
367
321
|
})
|
|
368
322
|
);
|
|
369
|
-
|
|
323
|
+
// The being's own default sits above the subtype's: only the note's
|
|
324
|
+
// tags say whether it is a person or a creature, and only this pass
|
|
325
|
+
// reads them.
|
|
326
|
+
const art = this.actorArt(fm, defaultActorImg(subType));
|
|
370
327
|
|
|
371
328
|
const items = this.buildEmbeddedItems(itemsMap, id, fm, ctx);
|
|
372
329
|
|
|
373
330
|
const { value: authoredFolder, isAddress } = folderField(fm);
|
|
374
331
|
const folder = this.folderResolver(authoredFolder, { isAddress });
|
|
375
332
|
|
|
376
|
-
// The two retiring positions a declared field may be read from.
|
|
377
|
-
// **Warnings**, on the pattern every retirement in this package
|
|
378
|
-
// follows: the note compiles to the correct document either way, so
|
|
379
|
-
// reddening a tree over one would refuse before the sweep rather than
|
|
380
|
-
// after it. What they buy is a count — without one, nothing says which
|
|
381
|
-
// position a value came from, and a default is indistinguishable from
|
|
382
|
-
// a miss.
|
|
383
|
-
const portraitReports = {
|
|
384
|
-
block: SYSTEM,
|
|
385
|
-
onLegacyKey: (field) =>
|
|
386
|
-
this.noteWarn(
|
|
387
|
-
legacyKeyMessage(SYSTEM, field),
|
|
388
|
-
locateFrontmatterKey(this.currentNote?.absPath, field.legacyKey),
|
|
389
|
-
),
|
|
390
|
-
// Anchored at column 1: the two positions share a spelling here —
|
|
391
|
-
// `sohl.portrait` and `portrait` — so a locator that took the first
|
|
392
|
-
// match would point at the block key while the message named the
|
|
393
|
-
// top-level one.
|
|
394
|
-
onRetiredTopLevel: (field) =>
|
|
395
|
-
this.noteWarn(
|
|
396
|
-
retiredTopLevelMessage(field),
|
|
397
|
-
locateFrontmatterKey(
|
|
398
|
-
this.currentNote?.absPath,
|
|
399
|
-
retiredTopLevelKey(field),
|
|
400
|
-
undefined,
|
|
401
|
-
{ topLevel: true },
|
|
402
|
-
),
|
|
403
|
-
),
|
|
404
|
-
};
|
|
405
|
-
|
|
406
333
|
const system = {
|
|
407
334
|
// The frontmatter shortcode is the actor's stable `(type, shortcode)`
|
|
408
335
|
// key — and, for a being that is an archetype, its archetype
|
|
@@ -414,11 +341,11 @@ export class Actors extends SystemActorCompiler {
|
|
|
414
341
|
// with the schema, since an undeclared `system` key is discarded at
|
|
415
342
|
// construction without a warning.
|
|
416
343
|
templatePriority: systemTemplatePriority(fm, ctx),
|
|
417
|
-
//
|
|
418
|
-
//
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
|
|
344
|
+
// `system.portrait` is **not** written here. A picture of the
|
|
345
|
+
// subject is a picture, so a being's portrait is the lead image of
|
|
346
|
+
// its `{#appearance}` section — which is the markup below — and the
|
|
347
|
+
// key that used to declare one is not a key. With no authored
|
|
348
|
+
// source left, the field keeps the schema's own initial.
|
|
422
349
|
appearance: renderSection(body || "", "appearance"),
|
|
423
350
|
dossier: renderSection(body || "", "dossier"),
|
|
424
351
|
};
|
|
@@ -470,8 +397,7 @@ export class Actors extends SystemActorCompiler {
|
|
|
470
397
|
return {
|
|
471
398
|
name,
|
|
472
399
|
type: subType,
|
|
473
|
-
|
|
474
|
-
img: resolveImg(blockProperty(fm, SYSTEM, "img")) ?? defaultImg,
|
|
400
|
+
img: art.img,
|
|
475
401
|
_id: id,
|
|
476
402
|
system,
|
|
477
403
|
items,
|
|
@@ -479,7 +405,7 @@ export class Actors extends SystemActorCompiler {
|
|
|
479
405
|
name,
|
|
480
406
|
displayName: 0,
|
|
481
407
|
actorLink: false,
|
|
482
|
-
texture: { src:
|
|
408
|
+
texture: { src: art.token },
|
|
483
409
|
width: 1,
|
|
484
410
|
height: 1,
|
|
485
411
|
sight: { enabled: false },
|
package/sohl/infobox.mjs
CHANGED
|
@@ -67,7 +67,7 @@ import { NOTE_SCHEMAS } from "./note-schemas.mjs";
|
|
|
67
67
|
import { GEAR_TYPE_TO_KEY } from "./being-info.mjs";
|
|
68
68
|
|
|
69
69
|
/** What this system's box is called. @type {string} */
|
|
70
|
-
export const SOHL_INFOBOX_TITLE = "
|
|
70
|
+
export const SOHL_INFOBOX_TITLE = "Song of Heroic Lands";
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* What a value nobody stated is shown as, where showing nothing would be the
|
package/sohl/note-schemas.mjs
CHANGED
|
@@ -146,26 +146,14 @@ const BEING_FIELDS = Object.freeze([
|
|
|
146
146
|
* business; their authored vocabulary is the same, so they share one
|
|
147
147
|
* declaration rather than three copies that could drift.
|
|
148
148
|
*
|
|
149
|
-
* `
|
|
150
|
-
* since a scene with no background is not a map. It
|
|
151
|
-
*
|
|
152
|
-
*
|
|
149
|
+
* `data.bgImage` is the one required piece of art — the compiler refuses a map
|
|
150
|
+
* note without it, since a scene with no background is not a map. It is
|
|
151
|
+
* declared in the note vocabulary rather than here, because it is an art slot
|
|
152
|
+
* like every other and a Scene has no `img` for the shared key to reach.
|
|
153
153
|
*
|
|
154
154
|
* @type {readonly import("../engine/field-spec.mjs").FieldSpec[]}
|
|
155
155
|
*/
|
|
156
156
|
const MAP_FIELDS = Object.freeze([
|
|
157
|
-
{
|
|
158
|
-
name: "img",
|
|
159
|
-
...STRING,
|
|
160
|
-
required: true,
|
|
161
|
-
// Art is not system-specific — a Scene is a core Foundry document, and
|
|
162
|
-
// every other note type carries its `img` at the note's top level.
|
|
163
|
-
shared: true,
|
|
164
|
-
describe:
|
|
165
|
-
"The scene's background image. Owned by whichever package its first segment " +
|
|
166
|
-
"names — `systems/…` and `modules/…` are emitted unchanged, anything else is " +
|
|
167
|
-
"this package's own and is rooted under its assets.",
|
|
168
|
-
},
|
|
169
157
|
{
|
|
170
158
|
name: "dimensions",
|
|
171
159
|
...LIST,
|
|
@@ -66,6 +66,7 @@ export const PACKAGE_KINDS: readonly ["systems", "modules", "documentation"];
|
|
|
66
66
|
export const DOCUMENTATION_KIND: string;
|
|
67
67
|
export namespace DEFAULT_PATHS {
|
|
68
68
|
let content: "assets/content";
|
|
69
|
+
let assets: "assets";
|
|
69
70
|
let contentIndex: "build/content-index";
|
|
70
71
|
let packJson: "build/packs-json";
|
|
71
72
|
let stage: "build/stage/packs";
|
|
@@ -299,6 +300,12 @@ export type PathsInput = {
|
|
|
299
300
|
* Content tree root.
|
|
300
301
|
*/
|
|
301
302
|
content?: string | undefined;
|
|
303
|
+
/**
|
|
304
|
+
* The asset roots' parent — the directory
|
|
305
|
+
* holding `icons/`, `images/` and
|
|
306
|
+
* `audio/`.
|
|
307
|
+
*/
|
|
308
|
+
assets?: string | undefined;
|
|
302
309
|
/**
|
|
303
310
|
* Where `content-index` writes this
|
|
304
311
|
* package's note index. Outbound, and a
|
|
@@ -338,6 +345,7 @@ export type PathsInput = {
|
|
|
338
345
|
*/
|
|
339
346
|
export type ResolvedPaths = {
|
|
340
347
|
content: string;
|
|
348
|
+
assets: string;
|
|
341
349
|
contentIndex: string;
|
|
342
350
|
packJson: string;
|
|
343
351
|
stage: string;
|
|
@@ -182,6 +182,29 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
182
182
|
itemsSourceDirs?: never[] | undefined;
|
|
183
183
|
foreignSourceDirs?: never[] | undefined;
|
|
184
184
|
});
|
|
185
|
+
/**
|
|
186
|
+
* The actor's two pieces of art, resolved, with the being default beneath
|
|
187
|
+
* them.
|
|
188
|
+
*
|
|
189
|
+
* **The default is chosen from the note's tags**, which only a compiler can
|
|
190
|
+
* read: a `character` falls back to one file and a `creature` to another,
|
|
191
|
+
* and both are addresses in the package that ships them. A tree whose index
|
|
192
|
+
* cannot answer that address — a dependency not yet fetched — falls through
|
|
193
|
+
* to the subtype's own default, so the document is never left with no art.
|
|
194
|
+
*
|
|
195
|
+
* `tokenIcon` unset follows `icon`, and the fallback is applied after
|
|
196
|
+
* resolution rather than before: a note naming an icon and no token icon
|
|
197
|
+
* means "the token wears the profile art", not "the token wears the
|
|
198
|
+
* default".
|
|
199
|
+
*
|
|
200
|
+
* @param {object} fm - The note's frontmatter.
|
|
201
|
+
* @param {string} fallback - The subtype's own default art path.
|
|
202
|
+
* @returns {{img: string, token: string}} The two paths.
|
|
203
|
+
*/
|
|
204
|
+
actorArt(fm: object, fallback: string): {
|
|
205
|
+
img: string;
|
|
206
|
+
token: string;
|
|
207
|
+
};
|
|
185
208
|
/** @type {readonly string[]} */
|
|
186
209
|
itemsSourceDirs: readonly string[];
|
|
187
210
|
foreignSourceDirs: any;
|
|
@@ -260,6 +283,12 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
260
283
|
* every embedded id exactly where it was.
|
|
261
284
|
* Returns null if the descriptor cannot be resolved.
|
|
262
285
|
*
|
|
286
|
+
* **An entry's `data:` is the authoring container, not a document field.**
|
|
287
|
+
* Its art slot is read here and the container itself goes no further, so an
|
|
288
|
+
* entry writing `data.icon` reaches the document as a resolved `img` and an
|
|
289
|
+
* entry writing none takes its type's default — the same two rules an item
|
|
290
|
+
* note compiles under, reached by the same functions.
|
|
291
|
+
*
|
|
263
292
|
* @param {Map<string, object>} itemsMap - The predefined items, by address.
|
|
264
293
|
* @param {string} actorId - The owning actor's id, seeding embedded ids.
|
|
265
294
|
* @param {string} type - The **note** type the reference names.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The art slot one key names, or `undefined`.
|
|
3
|
+
*
|
|
4
|
+
* @param {unknown} key - The key under `data:`.
|
|
5
|
+
* @returns {ArtSlot|undefined} The slot.
|
|
6
|
+
*/
|
|
7
|
+
export function artSlot(key: unknown): ArtSlot | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* The address an authored art value names.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} value - The value as authored.
|
|
12
|
+
* @param {string} defaultType - The type the field declares.
|
|
13
|
+
* @returns {string} A written address, which may be partial.
|
|
14
|
+
*/
|
|
15
|
+
export function artTarget(value: string, defaultType: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* The address space an asset reference resolves against, from a corpus.
|
|
18
|
+
*
|
|
19
|
+
* Shaped exactly as {@link module:engine/wikilinks.buildWikilinkIndex}'s result
|
|
20
|
+
* is in the parts a resolver reads, so the site, the book and the pack compilers
|
|
21
|
+
* answer one authored address the same way.
|
|
22
|
+
*
|
|
23
|
+
* **The note types belong in `types` as well as the asset ones.** Without them
|
|
24
|
+
* `being-thorn` does not parse as an address at all, and an embed naming a note
|
|
25
|
+
* is reported as an unknown type on one surface and as the wrong kind of type on
|
|
26
|
+
* another — one mistake, two verdicts, which is what the shared vocabulary
|
|
27
|
+
* exists to prevent.
|
|
28
|
+
*
|
|
29
|
+
* @param {readonly object[]} records - The corpus, from
|
|
30
|
+
* {@link module:engine/content-index.indexRecordsFor}.
|
|
31
|
+
* @param {object} [opts]
|
|
32
|
+
* @param {object} [opts.config] - The resolved build configuration.
|
|
33
|
+
* @param {{index?: Map<string, object>, packages?: Iterable<string>}} [opts.foreign] -
|
|
34
|
+
* The vendored indexes a dependency published.
|
|
35
|
+
* @param {Iterable<string>} [opts.types] - The note types this tree knows.
|
|
36
|
+
* @returns {object} The index.
|
|
37
|
+
*/
|
|
38
|
+
export function assetAddressIndex(records?: readonly object[], { config, foreign, types }?: {
|
|
39
|
+
config?: object | undefined;
|
|
40
|
+
foreign?: {
|
|
41
|
+
index?: Map<string, object>;
|
|
42
|
+
packages?: Iterable<string>;
|
|
43
|
+
} | undefined;
|
|
44
|
+
types?: Iterable<string> | undefined;
|
|
45
|
+
}): object;
|
|
46
|
+
/**
|
|
47
|
+
* The asset one authored value names, or why it names none.
|
|
48
|
+
*
|
|
49
|
+
* The whole lookup in one place, because two callers need it and they need
|
|
50
|
+
* different halves of the answer: an art slot needs the record, and an embed
|
|
51
|
+
* needs to tell an address that resolves to nothing from one that reaches the
|
|
52
|
+
* wrong *kind* of type. Those are different mistakes with different fixes, and a
|
|
53
|
+
* single `null` would collapse them into one message.
|
|
54
|
+
*
|
|
55
|
+
* Local files answer first and foreign ones after, which is an ordering of maps
|
|
56
|
+
* rather than a precedence rule: an address carries its own package, so the two
|
|
57
|
+
* cannot both hold one.
|
|
58
|
+
*
|
|
59
|
+
* @param {object} index - From {@link module:engine/wikilinks.buildWikilinkIndex},
|
|
60
|
+
* or the equivalent the site and the book build.
|
|
61
|
+
* @param {unknown} value - The value as authored.
|
|
62
|
+
* @param {string} defaultType - The type a bare value takes.
|
|
63
|
+
* @returns {{record: {package: string, asset: {path: string}}, pathname: string}
|
|
64
|
+
* |{record: null, reason: string, type?: string}} The asset and the pathname
|
|
65
|
+
* it is at, or a reason from
|
|
66
|
+
* {@link module:engine/wikilink-syntax.LINK_FINDING_REASONS}.
|
|
67
|
+
*/
|
|
68
|
+
export function readAssetAddress(index: object, value: unknown, defaultType: string): {
|
|
69
|
+
record: {
|
|
70
|
+
package: string;
|
|
71
|
+
asset: {
|
|
72
|
+
path: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
pathname: string;
|
|
76
|
+
} | {
|
|
77
|
+
record: null;
|
|
78
|
+
reason: string;
|
|
79
|
+
type?: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* The index record an art value resolves to, or `null`.
|
|
83
|
+
*
|
|
84
|
+
* @param {object} index - From {@link module:engine/wikilinks.buildWikilinkIndex}.
|
|
85
|
+
* @param {unknown} value - The value as authored.
|
|
86
|
+
* @param {string} defaultType - The type the field declares.
|
|
87
|
+
* @returns {{package: string, asset: {path: string}}|null} The record.
|
|
88
|
+
*/
|
|
89
|
+
export function resolveArtRecord(index: object, value: unknown, defaultType: string): {
|
|
90
|
+
package: string;
|
|
91
|
+
asset: {
|
|
92
|
+
path: string;
|
|
93
|
+
};
|
|
94
|
+
} | null;
|
|
95
|
+
/**
|
|
96
|
+
* The pathname an art value names, in the form an authored one takes.
|
|
97
|
+
*
|
|
98
|
+
* Handing the result to {@link module:engine/helpers.resolveImg} is what puts an
|
|
99
|
+
* art address and a body image through one ownership rule. The two empties
|
|
100
|
+
* survive it unchanged: `null` and an absent key mean *no art named, apply the
|
|
101
|
+
* default*, and `""` means *ship blank on purpose*.
|
|
102
|
+
*
|
|
103
|
+
* @param {object} index - From {@link module:engine/wikilinks.buildWikilinkIndex}.
|
|
104
|
+
* @param {unknown} value - The value as authored.
|
|
105
|
+
* @param {string} defaultType - The type the field declares.
|
|
106
|
+
* @returns {{pathname: string|null, resolved: boolean}} The pathname, and
|
|
107
|
+
* whether an address was actually answered — which tells a caller applying a
|
|
108
|
+
* default apart from one whose address named nothing.
|
|
109
|
+
*/
|
|
110
|
+
export function artPathname(index: object, value: unknown, defaultType: string): {
|
|
111
|
+
pathname: string | null;
|
|
112
|
+
resolved: boolean;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* The default art address a being's own tags choose, or `null`.
|
|
116
|
+
*
|
|
117
|
+
* `character` means a **person**, not a human, and `creature` everything else;
|
|
118
|
+
* a being carries exactly one of the two, which is what makes the choice a
|
|
119
|
+
* lookup rather than a precedence rule.
|
|
120
|
+
*
|
|
121
|
+
* @param {object} fm - The note's frontmatter.
|
|
122
|
+
* @returns {string|null} The address, or `null` for a note carrying neither tag.
|
|
123
|
+
*/
|
|
124
|
+
export function beingDefaultArt(fm: object): string | null;
|
|
125
|
+
/**
|
|
126
|
+
* What an unresolved art address is reported as.
|
|
127
|
+
*
|
|
128
|
+
* One wording, so the four compilers that can meet the case do not each invent
|
|
129
|
+
* their own.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} key - The key that was authored.
|
|
132
|
+
* @param {unknown} value - The value it carried.
|
|
133
|
+
* @param {string} defaultType - The type the field declares.
|
|
134
|
+
* @returns {string} The message.
|
|
135
|
+
*/
|
|
136
|
+
export function unresolvedArtMessage(key: string, value: unknown, defaultType: string): string;
|
|
137
|
+
/**
|
|
138
|
+
* One art slot: the key a note authors, and the type a bare value takes.
|
|
139
|
+
*
|
|
140
|
+
* @typedef {object} ArtSlot
|
|
141
|
+
* @property {string} key - The key under `data:`.
|
|
142
|
+
* @property {string} type - The asset type a bare shortcode defaults to.
|
|
143
|
+
* @property {boolean} document - Whether the slot reaches a compiled document.
|
|
144
|
+
* @property {string} describe - One line, for the author-facing reference.
|
|
145
|
+
*/
|
|
146
|
+
/**
|
|
147
|
+
* The four art slots, in the order the specification tabulates them.
|
|
148
|
+
*
|
|
149
|
+
* `banner` is the one that reaches no compiled document: it is the page's hero
|
|
150
|
+
* image, read by the site and by the book's section plates and by nothing else.
|
|
151
|
+
* That is what `document: false` states, and it is why the inert-art check
|
|
152
|
+
* skips it — a key that is *meant* to reach no document is not an inert key.
|
|
153
|
+
*
|
|
154
|
+
* @type {readonly ArtSlot[]}
|
|
155
|
+
*/
|
|
156
|
+
export const ART_SLOTS: readonly ArtSlot[];
|
|
157
|
+
/**
|
|
158
|
+
* The art a being falls back to, by the kind it is tagged.
|
|
159
|
+
*
|
|
160
|
+
* Both files ship in `sohl`, under `assets/icons/other/`, and both are named
|
|
161
|
+
* here as addresses rather than as paths for the reason every art reference is:
|
|
162
|
+
* the address resolves to a record that carries the owning package, so a
|
|
163
|
+
* package borrowing the default gets the same file the system ships.
|
|
164
|
+
*
|
|
165
|
+
* **Only the compiler can choose between them**, because only the compiler
|
|
166
|
+
* reads the note's tags. A schema default is the last resort beneath this one,
|
|
167
|
+
* and covers a world document created by hand, which no note describes.
|
|
168
|
+
*
|
|
169
|
+
* @type {Readonly<Record<string, string>>}
|
|
170
|
+
*/
|
|
171
|
+
export const BEING_DEFAULT_ART: Readonly<Record<string, string>>;
|
|
172
|
+
/**
|
|
173
|
+
* One art slot: the key a note authors, and the type a bare value takes.
|
|
174
|
+
*/
|
|
175
|
+
export type ArtSlot = {
|
|
176
|
+
/**
|
|
177
|
+
* - The key under `data:`.
|
|
178
|
+
*/
|
|
179
|
+
key: string;
|
|
180
|
+
/**
|
|
181
|
+
* - The asset type a bare shortcode defaults to.
|
|
182
|
+
*/
|
|
183
|
+
type: string;
|
|
184
|
+
/**
|
|
185
|
+
* - Whether the slot reaches a compiled document.
|
|
186
|
+
*/
|
|
187
|
+
document: boolean;
|
|
188
|
+
/**
|
|
189
|
+
* - One line, for the author-facing reference.
|
|
190
|
+
*/
|
|
191
|
+
describe: string;
|
|
192
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a package's asset trees into index records.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} assetsBase - The package's asset directory, the three roots'
|
|
5
|
+
* parent. A directory that does not exist yields nothing: a package with no
|
|
6
|
+
* art is ordinary.
|
|
7
|
+
* @param {object} options - Options.
|
|
8
|
+
* @param {string} options.contentPackage - The package the trees belong to.
|
|
9
|
+
* @param {object[]} [options.problems] - Supplied by a **reader**: a file that
|
|
10
|
+
* cannot be addressed is pushed here as a diagnostic and skipped. Omitted, it
|
|
11
|
+
* throws — the contract the emitter needs, since an index missing an asset
|
|
12
|
+
* asserts that the address does not exist.
|
|
13
|
+
* @returns {Array<Record<string, any>>} One record per addressable file, in walk
|
|
14
|
+
* order; the caller imposes the index's total order.
|
|
15
|
+
* @throws {Error} When a file cannot be addressed and no `problems` array was
|
|
16
|
+
* supplied. `file` rides on the error.
|
|
17
|
+
*/
|
|
18
|
+
export function collectAssetRecords(assetsBase: string, { contentPackage, problems }: {
|
|
19
|
+
contentPackage: string;
|
|
20
|
+
problems?: object[] | undefined;
|
|
21
|
+
}): Array<Record<string, any>>;
|
|
22
|
+
/**
|
|
23
|
+
* The file a directory records provenance for its subtree in.
|
|
24
|
+
*
|
|
25
|
+
* @type {string}
|
|
26
|
+
*/
|
|
27
|
+
export const PROVENANCE_FILE: string;
|
|
28
|
+
/**
|
|
29
|
+
* The suffix a per-file provenance sidecar carries.
|
|
30
|
+
*
|
|
31
|
+
* Appended to the **whole** filename, extension included — `anvil.svg.yaml`,
|
|
32
|
+
* not `anvil.yaml` — because the address holds one file whose format is free to
|
|
33
|
+
* change, and a sidecar named after the address alone would be orphaned the day
|
|
34
|
+
* an SVG became a WebP without anything saying so.
|
|
35
|
+
*
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
export const PROVENANCE_SIDECAR_SUFFIX: string;
|
|
39
|
+
/**
|
|
40
|
+
* One field of the `asset` block.
|
|
41
|
+
*
|
|
42
|
+
* @typedef {object} AssetRecordField
|
|
43
|
+
* @property {string} name - The key inside `asset`.
|
|
44
|
+
* @property {"walk"|"provenance"} from - Where the value comes from: the walk
|
|
45
|
+
* itself, or the provenance record resolved for the address.
|
|
46
|
+
* @property {string} describe - One line, for the author-facing reference.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* Every field an `asset` block carries, in the order it is documented.
|
|
50
|
+
*
|
|
51
|
+
* **The emitter builds a record from this list**, rather than from a literal
|
|
52
|
+
* that a second list somewhere else would have to be kept in step with. So a
|
|
53
|
+
* field added here is emitted, a field removed here stops being emitted, and the
|
|
54
|
+
* completeness guard derives what it checks from the same declaration instead of
|
|
55
|
+
* hand-copying it.
|
|
56
|
+
*
|
|
57
|
+
* Every field is always present, blank where nothing states it. A fixed record
|
|
58
|
+
* shape is what lets a consumer read `asset.license` without branching on
|
|
59
|
+
* whether the package happened to record one, and blank is the honest answer to
|
|
60
|
+
* "what does this package say about where this file came from" when it says
|
|
61
|
+
* nothing.
|
|
62
|
+
*
|
|
63
|
+
* @type {readonly AssetRecordField[]}
|
|
64
|
+
*/
|
|
65
|
+
export const ASSET_RECORD_FIELDS: readonly AssetRecordField[];
|
|
66
|
+
/**
|
|
67
|
+
* The keys a provenance file may declare.
|
|
68
|
+
*
|
|
69
|
+
* Derived from {@link ASSET_RECORD_FIELDS} rather than restated, so the file
|
|
70
|
+
* format and the record cannot disagree about which keys exist.
|
|
71
|
+
*
|
|
72
|
+
* @type {ReadonlySet<string>}
|
|
73
|
+
*/
|
|
74
|
+
export const PROVENANCE_KEYS: ReadonlySet<string>;
|
|
75
|
+
/**
|
|
76
|
+
* One field of the `asset` block.
|
|
77
|
+
*/
|
|
78
|
+
export type AssetRecordField = {
|
|
79
|
+
/**
|
|
80
|
+
* - The key inside `asset`.
|
|
81
|
+
*/
|
|
82
|
+
name: string;
|
|
83
|
+
/**
|
|
84
|
+
* - Where the value comes from: the walk
|
|
85
|
+
* itself, or the provenance record resolved for the address.
|
|
86
|
+
*/
|
|
87
|
+
from: "walk" | "provenance";
|
|
88
|
+
/**
|
|
89
|
+
* - One line, for the author-facing reference.
|
|
90
|
+
*/
|
|
91
|
+
describe: string;
|
|
92
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a type name addresses a file rather than a note.
|
|
3
|
+
*
|
|
4
|
+
* The one test the rewrite scoping rests on: a rewrite rule may substitute an
|
|
5
|
+
* asset and nothing else, so a fourth asset type is covered by this answer
|
|
6
|
+
* rather than by editing a list somewhere else.
|
|
7
|
+
*
|
|
8
|
+
* @param {unknown} type - The type name.
|
|
9
|
+
* @returns {boolean} True for `icon`, `image` or `audio`.
|
|
10
|
+
*/
|
|
11
|
+
export function isAssetType(type: unknown): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The asset type a root directory declares, or `undefined`.
|
|
14
|
+
*
|
|
15
|
+
* @param {unknown} root - A directory name below `paths.assets`.
|
|
16
|
+
* @returns {AssetType|undefined} The type it holds.
|
|
17
|
+
*/
|
|
18
|
+
export function assetTypeOfRoot(root: unknown): AssetType | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a filename can be an address at all.
|
|
21
|
+
*
|
|
22
|
+
* A shortcode is lowercase alphanumerics, so a version string, a hyphen or a
|
|
23
|
+
* date stamp in a basename means the file cannot be addressed. The build says so
|
|
24
|
+
* rather than inventing a shortcode for it.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} shortcode - The basename with its extension removed.
|
|
27
|
+
* @returns {boolean} Whether it matches {@link ADDRESS_SEGMENT_PATTERN}.
|
|
28
|
+
*/
|
|
29
|
+
export function isAssetShortcode(shortcode: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The `<system>` segment every asset address carries.
|
|
32
|
+
*
|
|
33
|
+
* Spelled here rather than imported from `engine/systems.mjs` so this module
|
|
34
|
+
* stays a leaf. The two are held to one value by the address round-trip guard,
|
|
35
|
+
* which reads both.
|
|
36
|
+
*
|
|
37
|
+
* @type {string}
|
|
38
|
+
*/
|
|
39
|
+
export const ASSET_SYSTEM: string;
|
|
40
|
+
/**
|
|
41
|
+
* File extensions that make a file a picture, lowercase and dot-led.
|
|
42
|
+
*
|
|
43
|
+
* Foundry's own `IMAGE_FILE_EXTENSIONS`, because these files are installed into
|
|
44
|
+
* a Foundry data directory and a format Foundry will not display is not one this
|
|
45
|
+
* toolchain should hand it an address for.
|
|
46
|
+
*
|
|
47
|
+
* @type {readonly string[]}
|
|
48
|
+
*/
|
|
49
|
+
export const IMAGE_EXTENSIONS: readonly string[];
|
|
50
|
+
/**
|
|
51
|
+
* File extensions that make a file a sound, lowercase and dot-led.
|
|
52
|
+
*
|
|
53
|
+
* Foundry's own `AUDIO_FILE_EXTENSIONS`, for the reason above.
|
|
54
|
+
*
|
|
55
|
+
* @type {readonly string[]}
|
|
56
|
+
*/
|
|
57
|
+
export const AUDIO_EXTENSIONS: readonly string[];
|
|
58
|
+
/**
|
|
59
|
+
* One asset type: what it is called, which directory holds it, and which files
|
|
60
|
+
* in that directory are assets of it.
|
|
61
|
+
*
|
|
62
|
+
* @typedef {object} AssetType
|
|
63
|
+
* @property {string} type - The type name, and the third segment of an address.
|
|
64
|
+
* @property {string} root - The directory below `paths.assets` that holds it.
|
|
65
|
+
* @property {readonly string[]} extensions - Lowercase, dot-led.
|
|
66
|
+
* @property {string} describe - One line, for the author-facing reference.
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* The three asset types, in address order.
|
|
70
|
+
*
|
|
71
|
+
* The directory is named for what it holds and the type for what an address
|
|
72
|
+
* reaches, so the two differ by a letter and the mapping is **declared** rather
|
|
73
|
+
* than derived from the name.
|
|
74
|
+
*
|
|
75
|
+
* `icon` and `image` are two types rather than one because an icon has to stay
|
|
76
|
+
* coherent drawn into a 32×32 slot while an image is unbounded — a fitness
|
|
77
|
+
* property of the asset itself. They therefore have separate shortcode
|
|
78
|
+
* namespaces, and `icon-anvil` and `image-anvil` are different addresses.
|
|
79
|
+
*
|
|
80
|
+
* @type {readonly AssetType[]}
|
|
81
|
+
*/
|
|
82
|
+
export const ASSET_TYPES: readonly AssetType[];
|
|
83
|
+
/**
|
|
84
|
+
* Every asset type name.
|
|
85
|
+
*
|
|
86
|
+
* @type {ReadonlySet<string>}
|
|
87
|
+
*/
|
|
88
|
+
export const ASSET_TYPE_NAMES: ReadonlySet<string>;
|
|
89
|
+
/**
|
|
90
|
+
* One asset type: what it is called, which directory holds it, and which files
|
|
91
|
+
* in that directory are assets of it.
|
|
92
|
+
*/
|
|
93
|
+
export type AssetType = {
|
|
94
|
+
/**
|
|
95
|
+
* - The type name, and the third segment of an address.
|
|
96
|
+
*/
|
|
97
|
+
type: string;
|
|
98
|
+
/**
|
|
99
|
+
* - The directory below `paths.assets` that holds it.
|
|
100
|
+
*/
|
|
101
|
+
root: string;
|
|
102
|
+
/**
|
|
103
|
+
* - Lowercase, dot-led.
|
|
104
|
+
*/
|
|
105
|
+
extensions: readonly string[];
|
|
106
|
+
/**
|
|
107
|
+
* - One line, for the author-facing reference.
|
|
108
|
+
*/
|
|
109
|
+
describe: string;
|
|
110
|
+
};
|