@heroiclands/package-build 21.1.0 → 22.0.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 +245 -0
- package/CONTENT.md +107 -3
- 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/bin/package-build.mjs +6 -5
- package/ci/emit-asset-index.mjs +32 -0
- package/content-config.mjs +30 -1
- package/docs/api.md +103 -27
- package/docs/commands.md +13 -11
- package/docs/configuration.md +16 -7
- package/docs/content-format.md +523 -111
- 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/dependency-bump.mjs +14 -16
- 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.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 -8
- package/engine/pdf-render.mjs +49 -12
- 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/manifest.mjs +67 -13
- package/package.json +5 -2
- package/packagebuild-metadata.jsonl +13 -0
- package/sohl/actors.mjs +12 -86
- 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/dependency-bump.d.mts +2 -2
- 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 -1
- 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/manifest.d.mts +42 -1
- package/types/sohl/actors.d.mts +0 -1
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
|
+
};
|
|
@@ -129,6 +129,11 @@ export class BasePackCompiler {
|
|
|
129
129
|
/**
|
|
130
130
|
* @param {object} options
|
|
131
131
|
* @param {string} options.contentBase - Root of the content tree.
|
|
132
|
+
* @param {string} [options.assetsBase] - The asset roots' parent, whose
|
|
133
|
+
* files the art addresses resolve against. Stated beside `contentBase`
|
|
134
|
+
* because the two move independently: a caller compiling a tree it
|
|
135
|
+
* assembled states where that tree's files are, and one compiling the
|
|
136
|
+
* repository's own leaves it to the configuration.
|
|
132
137
|
* @param {string} options.dest - Where this pass writes its JSON.
|
|
133
138
|
* @param {readonly string[]} options.skipDirectories - Directories the walk
|
|
134
139
|
* never descends into. Required: see {@link assertStatedScope}.
|
|
@@ -148,8 +153,9 @@ export class BasePackCompiler {
|
|
|
148
153
|
* over, derived once and shared by every pass. A pass handed none derives
|
|
149
154
|
* its own in `prepare`, and reports that corpus's problems itself.
|
|
150
155
|
*/
|
|
151
|
-
constructor({ contentBase, dest, skipDirectories, folderResolver, packName, packSystem, docType, router, routingReporter, corpus, }?: {
|
|
156
|
+
constructor({ contentBase, assetsBase, dest, skipDirectories, folderResolver, packName, packSystem, docType, router, routingReporter, corpus, }?: {
|
|
152
157
|
contentBase: string;
|
|
158
|
+
assetsBase?: string | undefined;
|
|
153
159
|
dest: string;
|
|
154
160
|
skipDirectories: readonly string[];
|
|
155
161
|
folderResolver?: ((address: string | null) => string | null) | undefined;
|
|
@@ -164,6 +170,12 @@ export class BasePackCompiler {
|
|
|
164
170
|
});
|
|
165
171
|
/** @type {string} */
|
|
166
172
|
contentBase: string;
|
|
173
|
+
/**
|
|
174
|
+
* The asset roots' parent, whose files the art addresses resolve against.
|
|
175
|
+
*
|
|
176
|
+
* @type {string|undefined}
|
|
177
|
+
*/
|
|
178
|
+
assetsBase: string | undefined;
|
|
167
179
|
/** @type {string} */
|
|
168
180
|
outputDir: string;
|
|
169
181
|
/** @type {(path: string|null) => string|null} */
|
|
@@ -348,6 +360,35 @@ export class BasePackCompiler {
|
|
|
348
360
|
* that does not convert.
|
|
349
361
|
*/
|
|
350
362
|
convertBody(fm: object, body: string): string;
|
|
363
|
+
/**
|
|
364
|
+
* The Foundry path one authored art address names, or `null`.
|
|
365
|
+
*
|
|
366
|
+
* **The two empties survive.** `null` and an absent key mean *no art named*,
|
|
367
|
+
* so the caller's own default applies with nullish coalescing; `""` means
|
|
368
|
+
* *ship blank on purpose* and no default may replace it. That is
|
|
369
|
+
* {@link module:engine/helpers.resolveImg}'s rule, reached through it rather
|
|
370
|
+
* than restated, which is also what puts an art address and a body image
|
|
371
|
+
* through one ownership rule.
|
|
372
|
+
*
|
|
373
|
+
* An address nothing answers is reported against the note and treated as
|
|
374
|
+
* unnamed, so the document takes its default rather than shipping a path
|
|
375
|
+
* that installs nowhere.
|
|
376
|
+
*
|
|
377
|
+
* @param {unknown} value - The value as authored.
|
|
378
|
+
* @param {string} key - The key it was authored at, for the message.
|
|
379
|
+
* @param {string} type - The asset type a bare value takes.
|
|
380
|
+
* @returns {string|null} The Foundry-relative path, `""` for a deliberate
|
|
381
|
+
* blank, or `null` where the note names none.
|
|
382
|
+
*/
|
|
383
|
+
artPathOf(value: unknown, key: string, type: string): string | null;
|
|
384
|
+
/**
|
|
385
|
+
* The Foundry path one art slot of a note names, or `null`.
|
|
386
|
+
*
|
|
387
|
+
* @param {object} fm - The note's frontmatter.
|
|
388
|
+
* @param {string} key - The slot's key under `data:`.
|
|
389
|
+
* @returns {string|null} As {@link BasePackCompiler#artPathOf}.
|
|
390
|
+
*/
|
|
391
|
+
artPath(fm: object, key: string): string | null;
|
|
351
392
|
/**
|
|
352
393
|
* Reports a warning about the note being compiled.
|
|
353
394
|
*
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @param {object} opts - Options.
|
|
5
5
|
* @param {string} opts.contentBase - Root of the content tree.
|
|
6
|
+
* @param {string} [opts.assetsBase] - The asset roots' parent, whose files the
|
|
7
|
+
* art addresses resolve against. Defaults to the configured one.
|
|
6
8
|
* @param {readonly string[]} opts.skipDirectories - The scope, stated by the
|
|
7
9
|
* caller as every corpus read requires.
|
|
8
10
|
* @param {object} opts.router - The pack router this compile resolved. Shared
|
|
@@ -17,8 +19,9 @@
|
|
|
17
19
|
* sqlTables: Map<string, object[]>|undefined, problems: object[]}>} The corpus,
|
|
18
20
|
* its indexes, and the notes it could not record.
|
|
19
21
|
*/
|
|
20
|
-
export function buildCompileCorpus({ contentBase, skipDirectories, router, config, problems, }: {
|
|
22
|
+
export function buildCompileCorpus({ contentBase, assetsBase, skipDirectories, router, config, problems, }: {
|
|
21
23
|
contentBase: string;
|
|
24
|
+
assetsBase?: string | undefined;
|
|
22
25
|
skipDirectories: readonly string[];
|
|
23
26
|
router: object;
|
|
24
27
|
config?: object | undefined;
|
|
@@ -78,6 +78,10 @@ export function checkText(text: string, file: string): Array<{
|
|
|
78
78
|
* theoretical exclusion — it was the first thing a run over `sohl-thalorna`
|
|
79
79
|
* reported before the skip existed.
|
|
80
80
|
*
|
|
81
|
+
* A finding names its file **relative to the working directory**, which is
|
|
82
|
+
* where a reader is standing and what `formatDiagnostic` emits. The content
|
|
83
|
+
* root is where the walk starts, not what a path is measured from.
|
|
84
|
+
*
|
|
81
85
|
* @param {string} contentBase - Root of the content tree.
|
|
82
86
|
* @param {object} [opts]
|
|
83
87
|
* @param {readonly string[]} [opts.skipDirectories] - Directory names to ignore
|