@heroiclands/package-build 21.1.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 +204 -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/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.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 +9 -2
- 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/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/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/sohl/actors.d.mts +0 -1
|
@@ -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;
|
|
@@ -198,7 +198,9 @@ export function bookTypstPreamble(): string;
|
|
|
198
198
|
* @param {string} opts.title - The document's title.
|
|
199
199
|
* @param {string} [opts.subtitle] - Shown under it on the title page.
|
|
200
200
|
* @param {string[]} [opts.front] - Rendered Typst for each front-matter file.
|
|
201
|
-
* @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.
|
|
202
204
|
* @param {string} [opts.version] - Stamped on the title page when given.
|
|
203
205
|
* @param {string} [opts.preamble] - Definitions the bodies call, emitted once
|
|
204
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.
|
|
@@ -47,6 +47,26 @@ export function schemaSubtypeOf(system: string | undefined, type: string): strin
|
|
|
47
47
|
* @type {readonly import("./document-subtypes.mjs").DocumentSubtypeMap[]}
|
|
48
48
|
*/
|
|
49
49
|
export const KNOWN_DOCUMENT_SUBTYPE_MAPS: readonly import("./document-subtypes.mjs").DocumentSubtypeMap[];
|
|
50
|
+
/**
|
|
51
|
+
* The map a pack declaring no `system:` compiles its documents against.
|
|
52
|
+
*
|
|
53
|
+
* A pack names the system its documents are shaped for, and one declaring none
|
|
54
|
+
* is compiled by the fallback pass for its document type — a single-system
|
|
55
|
+
* package's ordinary arrangement, and the one `sohl-thalorna` ships. That pass
|
|
56
|
+
* follows one map whatever a note carries, which makes this the answer to "a
|
|
57
|
+
* document compiled here belongs to *which* system?" wherever a pack has not
|
|
58
|
+
* said.
|
|
59
|
+
*
|
|
60
|
+
* Stated here rather than read off the compiler classes because those are not
|
|
61
|
+
* reachable from a leaf: `engine/item-compiler.mjs` imports the journals pass,
|
|
62
|
+
* which draws infoboxes, so anything the infobox reads cannot import a pass.
|
|
63
|
+
* `tests/default-document-subtypes.test.ts` holds this to `compilerFor`, which
|
|
64
|
+
* is where the fallback is actually decided — so the two cannot drift apart in
|
|
65
|
+
* silence.
|
|
66
|
+
*
|
|
67
|
+
* @type {import("./document-subtypes.mjs").DocumentSubtypeMap}
|
|
68
|
+
*/
|
|
69
|
+
export const DEFAULT_DOCUMENT_SUBTYPES: import("./document-subtypes.mjs").DocumentSubtypeMap;
|
|
50
70
|
/**
|
|
51
71
|
* Every note type any shipped map compiles into an **Actor**.
|
|
52
72
|
*
|
|
@@ -66,15 +66,25 @@ export function frontmatterWikilinks(fm: unknown): Array<{
|
|
|
66
66
|
* web pages, so the author wrote a real address and there is simply nothing to
|
|
67
67
|
* link to.
|
|
68
68
|
*
|
|
69
|
+
* ## Embeds first, and they are not links
|
|
70
|
+
*
|
|
71
|
+
* `![[address|label]]` names a file rather than a note, so it is resolved into
|
|
72
|
+
* an ordinary markdown image before anything looks for a link — which is what
|
|
73
|
+
* stops the link pass reading an embed's interior as a link to a note nobody
|
|
74
|
+
* wrote. The image the rewrite leaves behind is what
|
|
75
|
+
* {@link module:engine/content-images.renderImageFigures} turns into a figure
|
|
76
|
+
* for the website, and what the book reads its staging list out of.
|
|
77
|
+
*
|
|
69
78
|
* @param {string} body - The markdown body.
|
|
70
|
-
* @param {object} ctx - `{ index, collide, sections, contentTypes,
|
|
71
|
-
* foreign, type, errors, src, file }`.
|
|
79
|
+
* @param {object} ctx - `{ index, assets, collide, sections, contentTypes,
|
|
80
|
+
* packages, foreign, type, errors, src, file }`.
|
|
72
81
|
* `packages` is every package an address may name, without which the leading
|
|
73
82
|
* package segment of a canonical address reads as an unknown type; `foreign`
|
|
74
|
-
* is the cross-package manifest index
|
|
83
|
+
* is the cross-package manifest index; `assets` is the address space an embed
|
|
84
|
+
* resolves against. `src` is the page's display
|
|
75
85
|
* path and `file` the source file a diagnostic should name — absent, `src`
|
|
76
86
|
* stands in.
|
|
77
|
-
* @returns {string} The body with wikilinks rewritten.
|
|
87
|
+
* @returns {string} The body with embeds and wikilinks rewritten.
|
|
78
88
|
*/
|
|
79
89
|
export function resolveWebWikilinks(body: string, ctx: object): string;
|
|
80
90
|
export { slugify };
|
|
@@ -128,15 +128,18 @@ export function ambiguousAddressMessage(target: string, packages?: Iterable<stri
|
|
|
128
128
|
* @param {Iterable<string>} [finding.packages] - For `ambiguous`, the
|
|
129
129
|
* claimants.
|
|
130
130
|
* @param {string} [finding.anchor] - For `unknown-anchor`, the section named.
|
|
131
|
+
* @param {string} [finding.type] - For `not-an-asset`, the type the address
|
|
132
|
+
* named.
|
|
131
133
|
* @returns {string} The message.
|
|
132
134
|
* @throws {Error} On a reason outside the closed set — a resolver inventing one
|
|
133
135
|
* would otherwise report a link with no explanation at all.
|
|
134
136
|
*/
|
|
135
|
-
export function linkFindingMessage({ reason, target, packages, anchor }: {
|
|
137
|
+
export function linkFindingMessage({ reason, target, packages, anchor, type }: {
|
|
136
138
|
reason: string;
|
|
137
139
|
target: string;
|
|
138
140
|
packages?: Iterable<string> | undefined;
|
|
139
141
|
anchor?: string | undefined;
|
|
142
|
+
type?: string | undefined;
|
|
140
143
|
}): string;
|
|
141
144
|
/**
|
|
142
145
|
* Whether a parsed link addresses a section of the page it is written on.
|
|
@@ -193,6 +196,13 @@ export function isSamePage({ target, anchor }: ParsedWikilink): boolean;
|
|
|
193
196
|
* unclosed `[[` is a typo, and the alternative is letting it swallow arbitrary
|
|
194
197
|
* prose in search of a closer. Erring towards "not a link" leaves the author's
|
|
195
198
|
* text as written, which is the safe direction for a rewriter.
|
|
199
|
+
*
|
|
200
|
+
* **A leading `!` makes it an embed, not a link**, and the lookbehind is what
|
|
201
|
+
* keeps every reader from seeing one as the other. Stated here rather than in
|
|
202
|
+
* each reader for the reason the rest of this module exists: the checker, the
|
|
203
|
+
* pack compilers and the web resolver all match on this pattern, and three
|
|
204
|
+
* copies of the exclusion is three places for it to be forgotten. An embed's
|
|
205
|
+
* own grammar is {@link module:engine/content-embeds}.
|
|
196
206
|
*/
|
|
197
207
|
export const WIKILINK: RegExp;
|
|
198
208
|
/**
|
|
@@ -207,7 +217,9 @@ export const WIKILINK: RegExp;
|
|
|
207
217
|
*
|
|
208
218
|
* - `unlabelled` — no `|`, so the link addresses nothing.
|
|
209
219
|
* - `not-an-address` — labelled, but the target does not parse as an address.
|
|
220
|
+
* - `not-lowercase` — a package, system or type segment carries a capital.
|
|
210
221
|
* - `unknown-type` — definitely qualified, but names no type this build knows.
|
|
222
|
+
* - `not-an-asset` — a real address, embedded where only a file can be drawn.
|
|
211
223
|
* - `unresolved` — parses as an address, and nothing publishes it.
|
|
212
224
|
* - `ambiguous` — more than one package publishes the short address.
|
|
213
225
|
* - `unknown-anchor` — the address resolved, the `#section` it names did not.
|