@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
|
@@ -6,6 +6,38 @@
|
|
|
6
6
|
* toolchain ships none for it.
|
|
7
7
|
*/
|
|
8
8
|
export function infoboxFor(system: string | undefined): object | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Whether one system compiles a document for one note.
|
|
11
|
+
*
|
|
12
|
+
* This is what a system box's _available_ asserts, and it is the compile's own
|
|
13
|
+
* question rather than a reading of the frontmatter. A note carrying no block
|
|
14
|
+
* is not a note a system has nothing for: where the pack compiling its document
|
|
15
|
+
* declares no `system:`, the document is built from `data:` and the field
|
|
16
|
+
* defaults and ships exactly like any other.
|
|
17
|
+
*
|
|
18
|
+
* Three statements answer it, and they are the three the compile itself
|
|
19
|
+
* follows:
|
|
20
|
+
*
|
|
21
|
+
* 1. **The map** says which document class this system makes of the note's
|
|
22
|
+
* type. No row, no document — and no box either, which is why a caller
|
|
23
|
+
* reaching here already has one.
|
|
24
|
+
* 2. **The router** says which pack that document goes to, read from the pack
|
|
25
|
+
* list this build is driven by.
|
|
26
|
+
* 3. **That pack's `system:`** decides the rest. Declaring one, it writes that
|
|
27
|
+
* system's data and takes only notes that say something about it — the rule
|
|
28
|
+
* {@link module:engine/base-compiler.BasePackCompiler#eligibleFor} applies,
|
|
29
|
+
* asked here from outside. Declaring none, it is compiled by the fallback
|
|
30
|
+
* pass, which needs no block and answers for
|
|
31
|
+
* {@link module:engine/subtype-registry.DEFAULT_DOCUMENT_SUBTYPES} alone —
|
|
32
|
+
* so a tree with no HM3 pack ships no HM3 document however a note is
|
|
33
|
+
* written.
|
|
34
|
+
*
|
|
35
|
+
* @param {object} fm - The note's frontmatter.
|
|
36
|
+
* @param {object} map - The system's note-type → document-subtype map.
|
|
37
|
+
* @param {object} router - The pack router this build is driven by.
|
|
38
|
+
* @returns {boolean} True when this system compiles a document for this note.
|
|
39
|
+
*/
|
|
40
|
+
export function compilesSystemDocument(fm: object, map: object, router: object): boolean;
|
|
9
41
|
/**
|
|
10
42
|
* Every box one note carries, wired to the registries this toolchain ships.
|
|
11
43
|
*
|
|
@@ -17,12 +49,15 @@ export function infoboxFor(system: string | undefined): object | undefined;
|
|
|
17
49
|
* @param {object} [options] - Options.
|
|
18
50
|
* @param {(ref: unknown, hint?: object) => object|undefined} [options.resolve] -
|
|
19
51
|
* Resolves a reference to `{name, url?, uuid?, address?, subType?}`.
|
|
52
|
+
* @param {object} [options.router] - The pack router deciding which system
|
|
53
|
+
* compiles a document for this note. Defaults to the consuming repository's.
|
|
20
54
|
* @returns {object[]} The boxes, in the order every medium renders them.
|
|
21
55
|
* @throws {Error} When the built set disagrees with what the note's type maps
|
|
22
56
|
* to — see {@link module:engine/infobox.assertInfoboxSet}.
|
|
23
57
|
*/
|
|
24
|
-
export function noteInfoboxes(fm: object, { resolve }?: {
|
|
58
|
+
export function noteInfoboxes(fm: object, { resolve, router }?: {
|
|
25
59
|
resolve?: ((ref: unknown, hint?: object) => object | undefined) | undefined;
|
|
60
|
+
router?: object | undefined;
|
|
26
61
|
}): object[];
|
|
27
62
|
/**
|
|
28
63
|
* Every system's infobox declaration, in the order a page shows them.
|
|
@@ -246,9 +246,11 @@ export function systemRowsSection(fm: object, fields: readonly object[], { block
|
|
|
246
246
|
* build ships, which decide the box set.
|
|
247
247
|
* @param {readonly object[]} [options.providers] - The systems' infobox
|
|
248
248
|
* declarations, keyed by `system`.
|
|
249
|
-
* @param {(fm: object,
|
|
250
|
-
* Whether
|
|
251
|
-
* {@link NOT_AVAILABLE}.
|
|
249
|
+
* @param {(fm: object, map: object) => boolean} options.compilesDocument -
|
|
250
|
+
* Whether that system compiles a document for this note, which decides
|
|
251
|
+
* {@link NOT_AVAILABLE}. Asked of the routing and the passes rather than of
|
|
252
|
+
* the frontmatter: a pack declaring no `system:` compiles a note from `data:`
|
|
253
|
+
* and the field defaults, so the block's presence is not the question.
|
|
252
254
|
* @param {(field: object, fm: object, opts: object) => object} options.resolveField -
|
|
253
255
|
* Resolves one declared field against the note.
|
|
254
256
|
* @param {(ref: unknown) => object|undefined} [options.resolve] - Resolves a
|
|
@@ -259,7 +261,7 @@ export function systemRowsSection(fm: object, fields: readonly object[], { block
|
|
|
259
261
|
export function buildInfoboxes(fm: object, options: {
|
|
260
262
|
maps: readonly object[];
|
|
261
263
|
providers?: readonly object[] | undefined;
|
|
262
|
-
|
|
264
|
+
compilesDocument: (fm: object, map: object) => boolean;
|
|
263
265
|
resolveField: (field: object, fm: object, opts: object) => object;
|
|
264
266
|
resolve?: ((ref: unknown) => object | undefined) | undefined;
|
|
265
267
|
vocabulary?: object | undefined;
|
|
@@ -83,13 +83,17 @@ export function resolveMacroScope(fm: object, label: string): string;
|
|
|
83
83
|
* @param {string} opts.command - The command, from {@link macroCommand}.
|
|
84
84
|
* @param {string|null} [opts.folder] - The resolved folder id.
|
|
85
85
|
* @param {object} [opts.stats] - The `_stats` block.
|
|
86
|
+
* @param {string|null} [opts.img] - The resolved art, from the note's `icon`
|
|
87
|
+
* address. Passed in rather than resolved here, because an address is
|
|
88
|
+
* answered by the compile's index and this function takes no index.
|
|
86
89
|
* @returns {MacroDocument} The Macro document.
|
|
87
90
|
* @throws {Error} When the frontmatter's macro type or scope is unusable.
|
|
88
91
|
*/
|
|
89
|
-
export function buildMacroEntry(fm: object, { command, folder, stats }: {
|
|
92
|
+
export function buildMacroEntry(fm: object, { command, folder, stats, img }: {
|
|
90
93
|
command: string;
|
|
91
94
|
folder?: string | null | undefined;
|
|
92
95
|
stats?: object | undefined;
|
|
96
|
+
img?: string | null | undefined;
|
|
93
97
|
}): MacroDocument;
|
|
94
98
|
/**
|
|
95
99
|
* The anchor the executable script lives under: `# Script {#script}`.
|
|
@@ -112,11 +116,11 @@ export const MACRO_TYPES: readonly string[];
|
|
|
112
116
|
/** The Foundry macro scopes (`CONST.MACRO_SCOPES`), in schema order. */
|
|
113
117
|
export const MACRO_SCOPES: readonly string[];
|
|
114
118
|
/**
|
|
115
|
-
* Foundry's own default macro artwork, used when a note
|
|
119
|
+
* Foundry's own default macro artwork, used when a note names no `icon`.
|
|
116
120
|
*
|
|
117
|
-
* A core path, deliberately: it
|
|
118
|
-
*
|
|
119
|
-
*
|
|
121
|
+
* A core path, deliberately: it names a file Foundry itself ships rather than an
|
|
122
|
+
* address in any package, so it is stated after the art resolution rather than
|
|
123
|
+
* as something a note could author.
|
|
120
124
|
*/
|
|
121
125
|
export const DEFAULT_MACRO_IMG: "icons/svg/dice-target.svg";
|
|
122
126
|
/**
|
|
@@ -140,7 +140,8 @@ export function buildShape(spec: object, geom: MapGeometry): object;
|
|
|
140
140
|
* `packageId`, `journalEntryId`, `journalPack` (the pack the note's derived
|
|
141
141
|
* JournalEntry landed in), `pageIds` (heading key → page id),
|
|
142
142
|
* `resolveRegionRef` / `resolveBehaviorRef` / `resolveEffectRef` (address →
|
|
143
|
-
* UUID), `
|
|
143
|
+
* UUID), `art` (an art address → the path each surface serves),
|
|
144
|
+
* `knownActions`, `warnings`, and optionally `folder` and `stats`.
|
|
144
145
|
* @returns {object} The Scene document, keyed for the pack.
|
|
145
146
|
* @throws {Error} On any authoring mistake Foundry would accept silently.
|
|
146
147
|
*/
|
|
@@ -156,13 +157,16 @@ export function buildScene(fm: object, ctx: object): object;
|
|
|
156
157
|
*
|
|
157
158
|
* @param {object} sohl - The note's `sohl:` block.
|
|
158
159
|
* @param {string} sceneId - The owning scene's `_id`.
|
|
159
|
-
* @param {string}
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* @param {string} img - The background art, already resolved from the note's
|
|
161
|
+
* `bgImage` address by {@link buildScene}. Passed rather than resolved here,
|
|
162
|
+
* because an address is answered by the compile's index and this function
|
|
163
|
+
* takes none.
|
|
164
|
+
* @param {(value: unknown, key: string, type: string) => string|null} [art] -
|
|
165
|
+
* The art resolver, for the foreground overlay. Omitted, a note naming one
|
|
166
|
+
* gets no overlay rather than a path nothing serves.
|
|
163
167
|
* @returns {object} The Level document, keyed for the pack.
|
|
164
168
|
*/
|
|
165
|
-
export function buildLevel(sohl: object, sceneId: string, img?: string): object;
|
|
169
|
+
export function buildLevel(sohl: object, sceneId: string, img: string, art?: (value: unknown, key: string, type: string) => string | null): object;
|
|
166
170
|
/**
|
|
167
171
|
* Compile the `walls:` and `doors:` blocks into Wall documents.
|
|
168
172
|
*
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a package's content index is called, wherever it is written or fetched.
|
|
3
|
-
*
|
|
4
|
-
* **The local index and the published artifact are one file.** A package emits
|
|
5
|
-
* this, ships it as a release asset, and advertises it as `flags.metadataUrl`;
|
|
6
|
-
* a consumer fetches that same file into its cache and reads it. Naming it in
|
|
7
|
-
* one function is what keeps the emitter, the release and the fetcher from
|
|
8
|
-
* drifting into three spellings of one artifact.
|
|
9
|
-
*
|
|
10
|
-
* The `-metadata` suffix earns its place: a bare `<package>.jsonl` says nothing
|
|
11
|
-
* about what it holds, and these files land in a cache directory beside other
|
|
12
|
-
* packages' artifacts where the name is all a reader has.
|
|
13
|
-
*
|
|
14
|
-
* @param {string} pkg - The content package name.
|
|
15
|
-
* @returns {string} The file name, e.g. `sohl-metadata.jsonl`.
|
|
16
|
-
*/
|
|
17
|
-
export function metadataFileName(pkg: string): string;
|
|
18
1
|
/**
|
|
19
2
|
* Every dependency whose published index this build resolves addresses through.
|
|
20
3
|
*
|
|
@@ -211,6 +194,7 @@ export function formatUnaddressableFinding(finding: {
|
|
|
211
194
|
entries: number;
|
|
212
195
|
sampleKey: string;
|
|
213
196
|
}, config: object): string;
|
|
197
|
+
export { metadataFileName };
|
|
214
198
|
/**
|
|
215
199
|
* The relationship kinds that are dependencies, and therefore citable.
|
|
216
200
|
*
|
|
@@ -224,3 +208,4 @@ export function formatUnaddressableFinding(finding: {
|
|
|
224
208
|
*/
|
|
225
209
|
export const METADATA_RELATIONSHIP_KINDS: readonly string[];
|
|
226
210
|
export function isComplete(dir: string): boolean;
|
|
211
|
+
import { metadataFileName } from "./packages.mjs";
|
|
@@ -115,6 +115,9 @@ export function assertVocabularyCharset(vocabulary: Readonly<Record<string, Type
|
|
|
115
115
|
* @param {string} type - The note's `type`.
|
|
116
116
|
* @param {Readonly<Record<string, TypeVocabulary>>} [vocabulary] - The registry
|
|
117
117
|
* to read, defaulting to {@link NOTE_VOCABULARY}.
|
|
118
|
+
* {@link SHARED_DATA_FIELDS} come first, because they are part of every type's
|
|
119
|
+
* declaration and a caller asking what a type accepts must be told all of it.
|
|
120
|
+
*
|
|
118
121
|
* @returns {readonly DataFieldSpec[]|undefined} The declaration, or `undefined`
|
|
119
122
|
* when the type declares none — which is not the same as declaring an empty
|
|
120
123
|
* one, and is why the lint makes no claim rather than refusing every key.
|
|
@@ -131,6 +134,26 @@ export function dataFields(type: string, vocabulary?: Readonly<Record<string, Ty
|
|
|
131
134
|
* it has no `subType` at all — see {@link TypeVocabulary}.
|
|
132
135
|
*/
|
|
133
136
|
export function subTypes(type: string, vocabulary?: Readonly<Record<string, TypeVocabulary>>): readonly string[] | null | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* The `data:` keys **every** note type accepts, whatever it is.
|
|
139
|
+
*
|
|
140
|
+
* `data:` is a closed container and the per-type vocabularies are the only
|
|
141
|
+
* lists there are, so a key legal on every type needs somewhere that is not one
|
|
142
|
+
* type's list — including the types whose own vocabulary is empty. Repeating a
|
|
143
|
+
* row in twenty-five tables would be twenty-five chances for one of them to
|
|
144
|
+
* disagree with the rest.
|
|
145
|
+
*
|
|
146
|
+
* Both are art slots, and they are legal everywhere for different reasons.
|
|
147
|
+
* `icon` is the document's profile art and most types compile into a document
|
|
148
|
+
* that carries one; where a type's passes emit none, the frontmatter lint says
|
|
149
|
+
* so as a warning rather than the vocabulary refusing the key, because the
|
|
150
|
+
* value may still be read by a page template. `banner` reaches no compiled
|
|
151
|
+
* document at all — it is the page's hero image — and a page is what every note
|
|
152
|
+
* publishes.
|
|
153
|
+
*
|
|
154
|
+
* @type {readonly DataFieldSpec[]}
|
|
155
|
+
*/
|
|
156
|
+
export const SHARED_DATA_FIELDS: readonly DataFieldSpec[];
|
|
134
157
|
/**
|
|
135
158
|
* The declared tag that marks a note as **unfinished**.
|
|
136
159
|
*
|
|
@@ -269,6 +292,13 @@ export type DataFieldSpec = {
|
|
|
269
292
|
* one the message holds.
|
|
270
293
|
*/
|
|
271
294
|
entryShape?: string | undefined;
|
|
295
|
+
/**
|
|
296
|
+
* - The type a bare value takes. An art slot declares
|
|
297
|
+
* one — `icon` for `icon` and `tokenIcon`, `image` for `bgImage` and
|
|
298
|
+
* `banner` — so `icon: anvil` names `icon-anvil` while a value carrying the
|
|
299
|
+
* separator states its own address.
|
|
300
|
+
*/
|
|
301
|
+
ref?: string | undefined;
|
|
272
302
|
/**
|
|
273
303
|
* - For a `scalar-or-map` field, what its keys name.
|
|
274
304
|
* `"pack"` means each is a pack this package declares, so a key naming none
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The index records for the files this package ships.
|
|
3
|
+
*
|
|
4
|
+
* Walked rather than read back, so an installed copy and a git checkout answer
|
|
5
|
+
* alike and there is no state to be stale. The tree is small — a handful of
|
|
6
|
+
* banners — so the walk costs nothing a build would notice.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} [assetsBase] - The asset directory, for a caller testing
|
|
9
|
+
* against a tree of its own.
|
|
10
|
+
* @returns {Array<Record<string, any>>} One record per addressable file.
|
|
11
|
+
*/
|
|
12
|
+
export function packageBuildRecords(assetsBase?: string): Array<Record<string, any>>;
|
|
13
|
+
/**
|
|
14
|
+
* Publish the index as a file, for the readers that are not this process.
|
|
15
|
+
*
|
|
16
|
+
* The website, the book and the Foundry runtime each read a package's index as
|
|
17
|
+
* JSON Lines; this package's has to be one too, and it ships in the tarball
|
|
18
|
+
* beside the images it describes.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} [options] - Options.
|
|
21
|
+
* @param {string} [options.assetsBase] - The asset directory to walk.
|
|
22
|
+
* @param {string} [options.file] - Where to write it.
|
|
23
|
+
* @returns {{file: string, assets: number, bytes: number}} Where it was
|
|
24
|
+
* written, how many files it holds, and its size.
|
|
25
|
+
*/
|
|
26
|
+
export function emitPackageBuildIndex({ assetsBase, file }?: {
|
|
27
|
+
assetsBase?: string | undefined;
|
|
28
|
+
file?: string | undefined;
|
|
29
|
+
}): {
|
|
30
|
+
file: string;
|
|
31
|
+
assets: number;
|
|
32
|
+
bytes: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* This package's own root, wherever it is installed.
|
|
36
|
+
*
|
|
37
|
+
* Derived from this module's location rather than from a configuration: the
|
|
38
|
+
* files being indexed sit beside it in the same tarball, so the one reliable
|
|
39
|
+
* answer is "up from here". A consuming repository's `rootDir` names its own
|
|
40
|
+
* tree and says nothing about where its dependencies live.
|
|
41
|
+
*
|
|
42
|
+
* @type {string}
|
|
43
|
+
*/
|
|
44
|
+
export const PACKAGEBUILD_ROOT: string;
|
|
45
|
+
/**
|
|
46
|
+
* The asset directory this package ships.
|
|
47
|
+
*
|
|
48
|
+
* @type {string}
|
|
49
|
+
*/
|
|
50
|
+
export const PACKAGEBUILD_ASSETS: string;
|
|
51
|
+
/**
|
|
52
|
+
* Where the published index sits, beside the files it describes.
|
|
53
|
+
*
|
|
54
|
+
* @type {string}
|
|
55
|
+
*/
|
|
56
|
+
export const PACKAGEBUILD_INDEX_FILE: string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a package's content index is called, wherever it is written or fetched.
|
|
3
|
+
*
|
|
4
|
+
* **The local index and the published artifact are one file.** A package emits
|
|
5
|
+
* this, ships it as a release asset, and advertises it as `flags.metadataUrl`;
|
|
6
|
+
* a consumer fetches that same file into its cache and reads it. Naming it in
|
|
7
|
+
* one function is what keeps the emitter, the release and the fetcher from
|
|
8
|
+
* drifting into three spellings of one artifact.
|
|
9
|
+
*
|
|
10
|
+
* The `-metadata` suffix earns its place: a bare `<package>.jsonl` says nothing
|
|
11
|
+
* about what it holds, and these files land in a cache directory beside other
|
|
12
|
+
* packages' artifacts where the name is all a reader has.
|
|
13
|
+
*
|
|
14
|
+
* It lives here rather than beside the loader because the loader reaches the
|
|
15
|
+
* toolchain's own index, which has to name its file without importing the
|
|
16
|
+
* loader back.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} pkg - The content package name.
|
|
19
|
+
* @returns {string} The file name, e.g. `sohl-metadata.jsonl`.
|
|
20
|
+
*/
|
|
21
|
+
export function metadataFileName(pkg: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether a package name is held back from the open registry.
|
|
24
|
+
*
|
|
25
|
+
* @param {unknown} pkg - The candidate `contentPackage`.
|
|
26
|
+
* @returns {boolean} True when the name is reserved.
|
|
27
|
+
*/
|
|
28
|
+
export function isReservedPackage(pkg: unknown): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The `<package>` segment's own registry: the names no repository may claim.
|
|
31
|
+
*
|
|
32
|
+
* A content package names itself, so the registry is open — and exactly one
|
|
33
|
+
* name is held back from it.
|
|
34
|
+
*
|
|
35
|
+
* **`packagebuild` is a package that is not a package.** package-build is an npm
|
|
36
|
+
* package rather than a system or a module, and it ships a set of images —
|
|
37
|
+
* section banners chiefly — that many packages draw on. Addressing them as
|
|
38
|
+
* `packagebuild-none-image-<shortcode>` lets a note reach one without declaring a
|
|
39
|
+
* dependency on some parent system or module it otherwise has no relationship
|
|
40
|
+
* with, which is the whole point: the alternative is every package depending on
|
|
41
|
+
* one of the others just to borrow a banner.
|
|
42
|
+
*
|
|
43
|
+
* So nothing may create a real package that collides with the name, and its
|
|
44
|
+
* resolution is special-cased, because no installed directory sits behind it.
|
|
45
|
+
*
|
|
46
|
+
* This module is a **leaf with no local imports**, so the configuration
|
|
47
|
+
* validator can name it without closing a cycle around `content-config.mjs`.
|
|
48
|
+
*
|
|
49
|
+
* @module
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* The address namespace package-build's own assets publish under.
|
|
53
|
+
*
|
|
54
|
+
* @type {string}
|
|
55
|
+
*/
|
|
56
|
+
export const PACKAGEBUILD_PACKAGE: string;
|
|
57
|
+
/**
|
|
58
|
+
* Every package name a repository may not claim.
|
|
59
|
+
*
|
|
60
|
+
* @type {ReadonlySet<string>}
|
|
61
|
+
*/
|
|
62
|
+
export const RESERVED_PACKAGES: ReadonlySet<string>;
|
|
@@ -9,6 +9,47 @@
|
|
|
9
9
|
* @returns {string} The problem, as a finding's sentence, or `""`.
|
|
10
10
|
*/
|
|
11
11
|
export function pathnameProblem(raw: string | null | undefined): string;
|
|
12
|
+
/**
|
|
13
|
+
* Whether this build installs anything into a Foundry data directory.
|
|
14
|
+
*
|
|
15
|
+
* A `documentation` package compiles no packs and installs nowhere, so no note
|
|
16
|
+
* of its reaches a Foundry document and no pathname of its can be dead on a
|
|
17
|
+
* surface it never touches. A check that reports a missing Foundry address asks
|
|
18
|
+
* this first, so the one kind with no Foundry surface is not told about it.
|
|
19
|
+
*
|
|
20
|
+
* Read from {@link packageAddresses} rather than from a key, so "does this
|
|
21
|
+
* package have a Foundry root?" is answered in one place by the map that
|
|
22
|
+
* derives every other package's.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} config - The resolved build configuration.
|
|
25
|
+
* @returns {boolean} Whether the package being built has a Foundry root.
|
|
26
|
+
*/
|
|
27
|
+
export function servesFoundry(config: object): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Why a pathname has no Foundry address, or `""` when it has one.
|
|
30
|
+
*
|
|
31
|
+
* The sibling of {@link pathnameProblem} one step further on: that one asks
|
|
32
|
+
* whether a pathname is written correctly at all, and this one asks whether
|
|
33
|
+
* *this* build can turn a correctly written pathname into a path a Foundry
|
|
34
|
+
* install serves. Both answer in a sentence rather than a code, so the caller
|
|
35
|
+
* that holds a line and a column and the caller that holds only a file say the
|
|
36
|
+
* same thing about the same value.
|
|
37
|
+
*
|
|
38
|
+
* `""` for every pathname that resolves — and for the three shapes that
|
|
39
|
+
* legitimately reach Foundry untranslated: a URL, a protocol-relative
|
|
40
|
+
* `//host/…`, and a `/`-rooted path Foundry serves from its data root. A blank
|
|
41
|
+
* pathname is a deliberate blank and resolves to a blank on every surface, so
|
|
42
|
+
* it is not a problem either.
|
|
43
|
+
*
|
|
44
|
+
* `""` as well for a pathname {@link pathnameProblem} already refuses. That
|
|
45
|
+
* defect has its own finding naming its own replacement, and reporting a second
|
|
46
|
+
* one about the same characters would send the author to one mistake twice.
|
|
47
|
+
*
|
|
48
|
+
* @param {string|null|undefined} raw - The pathname, as authored.
|
|
49
|
+
* @param {object} config - The resolved build configuration.
|
|
50
|
+
* @returns {string} The problem, as a finding's sentence, or `""`.
|
|
51
|
+
*/
|
|
52
|
+
export function foundryAddressProblem(raw: string | null | undefined, config: object): string;
|
|
12
53
|
/**
|
|
13
54
|
* Every content package this build can resolve a pathname against.
|
|
14
55
|
*
|
|
@@ -41,87 +82,6 @@ export function packageAddresses(config: object): Map<string, {
|
|
|
41
82
|
* resolves on one surface and nowhere else.
|
|
42
83
|
*/
|
|
43
84
|
export function resolvePathname(raw: string | null | undefined, config: object): PathnameForms | null;
|
|
44
|
-
/**
|
|
45
|
-
* One authored pathname, and the four addresses it resolves to.
|
|
46
|
-
*
|
|
47
|
-
* A note names a file once — in `img:`, in `data.portrait:`, in the body of a
|
|
48
|
-
* markdown image — and four surfaces have to serve it: a Foundry install, this
|
|
49
|
-
* repository's own working tree, the website, and the book. Each addresses the
|
|
50
|
-
* same file differently, so the authored pathname is a *statement of
|
|
51
|
-
* ownership* and every surface derives its own address from it. One statement,
|
|
52
|
-
* four derivations, one rule.
|
|
53
|
-
*
|
|
54
|
-
* ## The rule
|
|
55
|
-
*
|
|
56
|
-
* **The first segment says which package owns the file, when it is followed by
|
|
57
|
-
* `assets/`.** Everything after `assets/` is the *suffix* — the path inside
|
|
58
|
-
* that package's shipped tree, and the one piece every form is built from.
|
|
59
|
-
*
|
|
60
|
-
* | Authored | Owner | Suffix |
|
|
61
|
-
* | --------------------------- | ---------------- | ------------------- |
|
|
62
|
-
* | `sohl/assets/icons/a.svg` | the `sohl` package | `icons/a.svg` |
|
|
63
|
-
* | `images/beings/b.webp` | **this** package | `images/beings/b.webp` |
|
|
64
|
-
*
|
|
65
|
-
* A pathname that does not open with `<package>/assets/` belongs to the package
|
|
66
|
-
* being built, and the whole of it is the suffix. That is the ordinary case and
|
|
67
|
-
* the one nearly every note writes.
|
|
68
|
-
*
|
|
69
|
-
* The four forms, for a `thalorna` note writing `images/map.webp` (`thalorna`
|
|
70
|
-
* ships as the Foundry module `sohl-thalorna`):
|
|
71
|
-
*
|
|
72
|
-
* | Form | Address |
|
|
73
|
-
* | --------- | -------------------------------------------------- |
|
|
74
|
-
* | `foundry` | `modules/sohl-thalorna/assets/images/map.webp` |
|
|
75
|
-
* | `local` | `assets/images/map.webp` |
|
|
76
|
-
* | `web` | `https://cdn.heroiclands.org/thalorna/images/map.webp` |
|
|
77
|
-
* | `pdf` | `assets/images/map.webp` |
|
|
78
|
-
*
|
|
79
|
-
* **`<package>` and `<foundry-id>` are two different names.** The package is
|
|
80
|
-
* `thalorna` — what the content is called, what the website serves it under,
|
|
81
|
-
* and what a note writes. The Foundry id is `sohl-thalorna` — what Foundry
|
|
82
|
-
* installs the module as, and the only place that name appears. They coincide
|
|
83
|
-
* for `sohl` and `hm3`, which is exactly why the two are kept apart here rather
|
|
84
|
-
* than treated as one value.
|
|
85
|
-
*
|
|
86
|
-
* `local` and `pdf` read the same and mean different places: `local` is the file
|
|
87
|
-
* in the owning repository's working tree, `pdf` is where the book stages a copy
|
|
88
|
-
* beside its Typst source. They are derived separately because only one of them
|
|
89
|
-
* is a file a build may open — see {@link PathnameForms.own}.
|
|
90
|
-
*
|
|
91
|
-
* ## What is not a package pathname
|
|
92
|
-
*
|
|
93
|
-
* **An off-install address passes through on every surface**: a URL, a
|
|
94
|
-
* protocol-relative `//host/…`, or a `/`-rooted path, which Foundry serves from
|
|
95
|
-
* the data root and which names no package at all. That is how a note addresses
|
|
96
|
-
* core Foundry art (`/icons/svg/mystery-man.svg`) or a package this build knows
|
|
97
|
-
* nothing about (`/systems/dnd5e/icons/spell.webp`).
|
|
98
|
-
*
|
|
99
|
-
* **A package this build has never heard of keeps its ownership.** The website
|
|
100
|
-
* and the book need only the package's name and the suffix, so both resolve;
|
|
101
|
-
* the Foundry address needs the package's kind and its Foundry id, which only a
|
|
102
|
-
* declared relationship carries, so that one form comes back `null` and the
|
|
103
|
-
* caller that needs it refuses. Reading such a pathname as this package's own
|
|
104
|
-
* would file one package's name inside another's tree and say nothing.
|
|
105
|
-
*
|
|
106
|
-
* **A `systems/…` or `modules/…` pathname is refused.** It is a Foundry address
|
|
107
|
-
* written where an ownership statement belongs: it resolves for Foundry and for
|
|
108
|
-
* nothing else, because neither the website nor the book has any such directory.
|
|
109
|
-
* {@link pathnameProblem} names the replacement, and every surface refuses the
|
|
110
|
-
* value rather than deriving an address from it — a wrong address that resolves
|
|
111
|
-
* to a 404 is the failure this module exists to remove, and inventing one here
|
|
112
|
-
* would reintroduce it one directory along.
|
|
113
|
-
*
|
|
114
|
-
* ## The two empties
|
|
115
|
-
*
|
|
116
|
-
* `null` — or an absent key, which arrives as `undefined` — means **unset**: the
|
|
117
|
-
* note names no file and the caller's default applies. `""` means **blank on
|
|
118
|
-
* purpose**: the note names no file and wants none, so no default may replace
|
|
119
|
-
* it. `resolvePathname` returns `null` for the first and a form object whose
|
|
120
|
-
* every address is `""` for the second, so the two stay distinguishable all the
|
|
121
|
-
* way to the caller.
|
|
122
|
-
*
|
|
123
|
-
* @module
|
|
124
|
-
*/
|
|
125
85
|
/**
|
|
126
86
|
* The directory a package ships its files in, and the segment that marks a
|
|
127
87
|
* pathname's first segment as a package name.
|
|
@@ -74,15 +74,72 @@ export function buildPdf({ config, out, version, compile }?: {
|
|
|
74
74
|
version?: string | undefined;
|
|
75
75
|
compile?: boolean | undefined;
|
|
76
76
|
}): Promise<object>;
|
|
77
|
+
/**
|
|
78
|
+
* The command line the compile runs, as data.
|
|
79
|
+
*
|
|
80
|
+
* Separate from running it so the flags that decide which faces are in play
|
|
81
|
+
* can be asserted without a compiler installed — which is the half of the
|
|
82
|
+
* invocation that changes what the book looks like.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} typPath - The `.typ` file.
|
|
85
|
+
* @param {string} pdfPath - Where the PDF goes.
|
|
86
|
+
* @param {object} [pdf] - The resolved `pdf:` block.
|
|
87
|
+
* @returns {string[]} The arguments, in order.
|
|
88
|
+
*/
|
|
89
|
+
export function typstArgs(typPath: string, pdfPath: string, pdf?: object): string[];
|
|
90
|
+
/**
|
|
91
|
+
* The compiler's own warnings, as findings.
|
|
92
|
+
*
|
|
93
|
+
* A compile that says `unknown font family` still exits 0 and still writes a
|
|
94
|
+
* book — one set in whatever face the fallback reached. That is the failure
|
|
95
|
+
* this surface is least able to see, so the compiler's warnings are read back
|
|
96
|
+
* and reported on the same terms as everything else the build finds.
|
|
97
|
+
*
|
|
98
|
+
* Typst writes a warning as a `warning:` line followed by a `┌─ file:line:col`
|
|
99
|
+
* locator over a source excerpt. The message and the position are taken; the
|
|
100
|
+
* excerpt is not, since the reader has the file.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} output - What the compiler wrote to stderr.
|
|
103
|
+
* @returns {Array<{file: string, line?: number, column?: number,
|
|
104
|
+
* severity: string, message: string}>} One finding per warning.
|
|
105
|
+
*/
|
|
106
|
+
export function typstWarnings(output: string): Array<{
|
|
107
|
+
file: string;
|
|
108
|
+
line?: number;
|
|
109
|
+
column?: number;
|
|
110
|
+
severity: string;
|
|
111
|
+
message: string;
|
|
112
|
+
}>;
|
|
77
113
|
/**
|
|
78
114
|
* Run Typst over the emitted source.
|
|
79
115
|
*
|
|
80
116
|
* @param {string} typPath - The `.typ` file.
|
|
81
117
|
* @param {string} pdfPath - Where the PDF goes.
|
|
82
118
|
* @param {object} pdf - The resolved `pdf:` block.
|
|
83
|
-
* @returns {{ok: boolean, message: string}} What happened
|
|
119
|
+
* @returns {{ok: boolean, message: string, findings: object[]}} What happened,
|
|
120
|
+
* and what the compiler warned about on the way.
|
|
84
121
|
*/
|
|
85
122
|
export function compileTypst(typPath: string, pdfPath: string, pdf?: object): {
|
|
86
123
|
ok: boolean;
|
|
87
124
|
message: string;
|
|
125
|
+
findings: object[];
|
|
88
126
|
};
|
|
127
|
+
/**
|
|
128
|
+
* The faces the book is set in that the compiler does not carry itself.
|
|
129
|
+
*
|
|
130
|
+
* Resolved from this module rather than from the working directory, on the same
|
|
131
|
+
* rule the specification and `--version` follow: a consumer runs the build
|
|
132
|
+
* inside its own repository, and the faces it sets the book in are the ones
|
|
133
|
+
* that came with the toolchain version it resolved.
|
|
134
|
+
*
|
|
135
|
+
* What is here is the **sans**, in the three styles a heading can ask for, the
|
|
136
|
+
* superfamily's **mono** for a package that names it, and the licence they
|
|
137
|
+
* travel under. The serif is not: the compiler embeds one, and a second copy of
|
|
138
|
+
* a face it already carries is a file nothing selects.
|
|
139
|
+
*
|
|
140
|
+
* It is **not** an addressable asset root: the compiler matches a face by
|
|
141
|
+
* family name, so nothing addresses these files and nothing needs to.
|
|
142
|
+
*
|
|
143
|
+
* @type {string}
|
|
144
|
+
*/
|
|
145
|
+
export const BOOK_FONTS_PATH: string;
|
|
@@ -55,7 +55,6 @@ export function createParser(registry?: object): object;
|
|
|
55
55
|
* note's own `##` nests beneath the entry heading the book gave it.
|
|
56
56
|
* @param {string} [opts.anchorPrefix] - The entry's anchor, which namespaces
|
|
57
57
|
* every `{#slug}` the body declares.
|
|
58
|
-
* @param {boolean} [opts.dropCap] - Whether to open the body with a raised
|
|
59
58
|
* capital. Set for an entry, which begins a page; not for front matter or a
|
|
60
59
|
* prose file, which carry headings of their own.
|
|
61
60
|
* @returns {string} Typst markup.
|
|
@@ -68,7 +67,6 @@ export function markdownToTypst(markdown: string, opts?: {
|
|
|
68
67
|
images?: Map<string, string> | undefined;
|
|
69
68
|
headingOffset?: number | undefined;
|
|
70
69
|
anchorPrefix?: string | undefined;
|
|
71
|
-
dropCap?: boolean | undefined;
|
|
72
70
|
}): string;
|
|
73
71
|
/**
|
|
74
72
|
* The Typst definitions the book's page furniture is drawn with.
|
|
@@ -200,7 +198,9 @@ export function bookTypstPreamble(): string;
|
|
|
200
198
|
* @param {string} opts.title - The document's title.
|
|
201
199
|
* @param {string} [opts.subtitle] - Shown under it on the title page.
|
|
202
200
|
* @param {string[]} [opts.front] - Rendered Typst for each front-matter file.
|
|
203
|
-
* @param {object} [opts.fonts] - `{ serif, sans, mono }` family names.
|
|
201
|
+
* @param {object} [opts.fonts] - `{ serif, sans, mono }` family names. Each
|
|
202
|
+
* falls back to the face the toolchain ships or the compiler embeds, so a
|
|
203
|
+
* caller that names none still sets the book in all three.
|
|
204
204
|
* @param {string} [opts.version] - Stamped on the title page when given.
|
|
205
205
|
* @param {string} [opts.preamble] - Definitions the bodies call, emitted once
|
|
206
206
|
* above the title page. A panel every entry draws is a set of rules stated
|
|
@@ -23,8 +23,9 @@ export function collectKnownActionNames(repoRoot: string): Set<string>;
|
|
|
23
23
|
* scene's id-based references resolve on import.
|
|
24
24
|
*/
|
|
25
25
|
export class Scenes extends BasePackCompiler {
|
|
26
|
-
constructor({ contentBase, dest, skipDirectories, companionDests, folderResolver, repoRoot, }: {
|
|
26
|
+
constructor({ contentBase, assetsBase, dest, skipDirectories, companionDests, folderResolver, repoRoot, }: {
|
|
27
27
|
contentBase: any;
|
|
28
|
+
assetsBase: any;
|
|
28
29
|
dest: any;
|
|
29
30
|
skipDirectories: any;
|
|
30
31
|
companionDests?: {} | undefined;
|
|
@@ -237,15 +237,19 @@ export function sectionFrontmatter(meta: object): object;
|
|
|
237
237
|
* for.
|
|
238
238
|
* @param {(data: object, page: object) => void} [options.decorate] - Called
|
|
239
239
|
* with each page's frontmatter, for whatever a consumer's own pass adds.
|
|
240
|
+
* @param {(value: unknown, type: string) => string|null} [options.artSrc] -
|
|
241
|
+
* Translates an art address into the pathname the website resolver takes, or
|
|
242
|
+
* `null` where nothing answers it.
|
|
240
243
|
* @param {(src: string) => string} [options.webSrc] - Translates an authored
|
|
241
244
|
* pathname into the address the website serves. Every artwork field goes
|
|
242
245
|
* through it, so a page's `img:` and its body images name the same file the
|
|
243
246
|
* same way.
|
|
244
247
|
* @returns {object} The frontmatter to write.
|
|
245
248
|
*/
|
|
246
|
-
export function pageFrontmatter(page: object, { readmeSections, decorate, webSrc }: {
|
|
249
|
+
export function pageFrontmatter(page: object, { readmeSections, decorate, webSrc, artSrc }: {
|
|
247
250
|
readmeSections?: Record<string, object> | undefined;
|
|
248
251
|
decorate?: ((data: object, page: object) => void) | undefined;
|
|
252
|
+
artSrc?: ((value: unknown, type: string) => string | null) | undefined;
|
|
249
253
|
webSrc?: ((src: string) => string) | undefined;
|
|
250
254
|
}): object;
|
|
251
255
|
/**
|
|
@@ -34,6 +34,8 @@ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex }?:
|
|
|
34
34
|
* diagnostic names. Absent, `src` stands in.
|
|
35
35
|
* @param {Map<string, object>} [options.foreignIndex] - The foreign index, for
|
|
36
36
|
* resolvers that distinguish a foreign hit from a local one.
|
|
37
|
+
* @param {object} [options.assets] - The address space an `![[…]]` embed
|
|
38
|
+
* resolves against, shaped as every asset resolver reads one.
|
|
37
39
|
* @returns {object} The resolver context.
|
|
38
40
|
*
|
|
39
41
|
* There is deliberately **no `manifestsComplete`**. It used to let a resolver
|
|
@@ -42,12 +44,13 @@ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex }?:
|
|
|
42
44
|
* checker never had it and one authored link must not get two verdicts. A
|
|
43
45
|
* caller still passing it is ignored rather than obeyed.
|
|
44
46
|
*/
|
|
45
|
-
export function wikiContext(built: SiteIndex, { src, file, type, errors, foreignIndex }: {
|
|
47
|
+
export function wikiContext(built: SiteIndex, { src, file, type, errors, foreignIndex, assets }: {
|
|
46
48
|
src: string;
|
|
47
49
|
type?: string | null | undefined;
|
|
48
50
|
errors: object[];
|
|
49
51
|
file?: string | undefined;
|
|
50
52
|
foreignIndex?: Map<string, object> | undefined;
|
|
53
|
+
assets?: object | undefined;
|
|
51
54
|
}): object;
|
|
52
55
|
/**
|
|
53
56
|
* Resolve one infobox reference against a site index.
|