@heroiclands/package-build 20.7.0 → 21.1.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 +183 -0
- package/CONTENT.md +132 -44
- package/bin/content-build.mjs +37 -5
- package/bin/package-build.mjs +77 -0
- package/content-config.mjs +59 -1
- package/docs/api.md +149 -19
- package/docs/commands.md +75 -0
- package/docs/configuration.md +37 -10
- package/docs/content-format.md +450 -49
- package/engine/content-format.mjs +52 -3
- package/engine/content-images.mjs +699 -0
- package/engine/dependency-bump.mjs +218 -0
- package/engine/frontmatter-lint.mjs +89 -2
- package/engine/helpers.mjs +81 -142
- package/engine/index.mjs +15 -0
- package/engine/infobox-registry.mjs +81 -0
- package/engine/infobox-render.mjs +382 -0
- package/engine/infobox.mjs +963 -0
- package/engine/item-registry.mjs +5 -5
- package/engine/journals.mjs +22 -1
- package/engine/map-notes.mjs +11 -5
- package/engine/metadata-index.mjs +5 -0
- package/engine/note-vocabulary.mjs +57 -2
- package/engine/pathnames.mjs +374 -0
- package/engine/pdf-build.mjs +206 -9
- package/engine/pdf-render.mjs +453 -20
- package/engine/pdf-toc.mjs +77 -5
- package/engine/scenes.mjs +2 -1
- package/engine/site-build.mjs +106 -7
- package/engine/site-index.mjs +93 -4
- package/engine/wikilinks.mjs +93 -0
- package/hm3/default-item-art.mjs +14 -15
- package/hm3/index.mjs +3 -0
- package/hm3/infobox.mjs +64 -0
- package/package.json +1 -1
- package/sohl/default-item-art.mjs +18 -16
- package/sohl/index.mjs +3 -0
- package/sohl/infobox.mjs +499 -0
- package/types/content-config.d.mts +7 -0
- package/types/engine/content-format.d.mts +36 -0
- package/types/engine/content-images.d.mts +281 -0
- package/types/engine/dependency-bump.d.mts +89 -0
- package/types/engine/frontmatter-lint.d.mts +23 -0
- package/types/engine/helpers.d.mts +30 -72
- package/types/engine/index.d.mts +5 -0
- package/types/engine/infobox-registry.d.mts +36 -0
- package/types/engine/infobox-render.d.mts +87 -0
- package/types/engine/infobox.d.mts +443 -0
- package/types/engine/item-registry.d.mts +5 -5
- package/types/engine/journals.d.mts +9 -1
- package/types/engine/note-vocabulary.d.mts +51 -0
- package/types/engine/pathnames.d.mts +189 -0
- package/types/engine/pdf-build.d.mts +46 -0
- package/types/engine/pdf-render.d.mts +97 -1
- package/types/engine/pdf-toc.d.mts +10 -5
- package/types/engine/site-build.d.mts +11 -3
- package/types/engine/site-index.d.mts +35 -3
- package/types/engine/wikilinks.d.mts +22 -0
- package/types/hm3/default-item-art.d.mts +5 -6
- package/types/hm3/index.d.mts +1 -0
- package/types/hm3/infobox.d.mts +22 -0
- package/types/sohl/index.d.mts +1 -0
- package/types/sohl/infobox.d.mts +145 -0
|
@@ -61,6 +61,16 @@ export const CONTENT_FORMAT_PATH: string;
|
|
|
61
61
|
* @property {number} line - 1-based line of the row.
|
|
62
62
|
* @property {number} column - 1-based column of the cell's first character.
|
|
63
63
|
*/
|
|
64
|
+
/**
|
|
65
|
+
* One closed vocabulary the specification states as a table.
|
|
66
|
+
*
|
|
67
|
+
* @typedef {object} VocabularySpec
|
|
68
|
+
* @property {string} name - The key the header names, without its backticks.
|
|
69
|
+
* @property {number} line - 1-based line of the header row.
|
|
70
|
+
* @property {string[]} values - The values, in document order. A row whose
|
|
71
|
+
* first cell is not a single inline-code span states no value and is skipped,
|
|
72
|
+
* which is how a table says "no marker" in a row of its own.
|
|
73
|
+
*/
|
|
64
74
|
/**
|
|
65
75
|
* The specification, as data.
|
|
66
76
|
*
|
|
@@ -68,6 +78,8 @@ export const CONTENT_FORMAT_PATH: string;
|
|
|
68
78
|
* @property {string} file - Where it was read from, for diagnostics.
|
|
69
79
|
* @property {Map<string, TypeSpec>} types - Note type → what its section declares.
|
|
70
80
|
* @property {MappingClaim[]} claims - Every `system.*` target, in document order.
|
|
81
|
+
* @property {Map<string, VocabularySpec>} vocabularies - Key → the values it
|
|
82
|
+
* admits, for every closed vocabulary the document states as a table.
|
|
71
83
|
*/
|
|
72
84
|
/**
|
|
73
85
|
* What a shared row's `noteType` reads, in place of a type name.
|
|
@@ -147,6 +159,25 @@ export type MappingClaim = {
|
|
|
147
159
|
*/
|
|
148
160
|
column: number;
|
|
149
161
|
};
|
|
162
|
+
/**
|
|
163
|
+
* One closed vocabulary the specification states as a table.
|
|
164
|
+
*/
|
|
165
|
+
export type VocabularySpec = {
|
|
166
|
+
/**
|
|
167
|
+
* - The key the header names, without its backticks.
|
|
168
|
+
*/
|
|
169
|
+
name: string;
|
|
170
|
+
/**
|
|
171
|
+
* - 1-based line of the header row.
|
|
172
|
+
*/
|
|
173
|
+
line: number;
|
|
174
|
+
/**
|
|
175
|
+
* - The values, in document order. A row whose
|
|
176
|
+
* first cell is not a single inline-code span states no value and is skipped,
|
|
177
|
+
* which is how a table says "no marker" in a row of its own.
|
|
178
|
+
*/
|
|
179
|
+
values: string[];
|
|
180
|
+
};
|
|
150
181
|
/**
|
|
151
182
|
* The specification, as data.
|
|
152
183
|
*/
|
|
@@ -163,4 +194,9 @@ export type ContentFormat = {
|
|
|
163
194
|
* - Every `system.*` target, in document order.
|
|
164
195
|
*/
|
|
165
196
|
claims: MappingClaim[];
|
|
197
|
+
/**
|
|
198
|
+
* - Key → the values it
|
|
199
|
+
* admits, for every closed vocabulary the document states as a table.
|
|
200
|
+
*/
|
|
201
|
+
vocabularies: Map<string, VocabularySpec>;
|
|
166
202
|
};
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is wrong with an image's address, or `""` when nothing is.
|
|
3
|
+
*
|
|
4
|
+
* The address is the one piece of author-supplied text that has to reach an
|
|
5
|
+
* `src` attribute, so it is the one piece that has to be held to a shape. A
|
|
6
|
+
* scheme this does not name — `javascript:`, `data:`, `vbscript:` — is refused
|
|
7
|
+
* rather than escaped, because escaping makes it inert markup and this makes it
|
|
8
|
+
* a finding the author can act on.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} src - The address, exactly as authored.
|
|
11
|
+
* @returns {string} The problem, as a finding's sentence, or `""`.
|
|
12
|
+
*/
|
|
13
|
+
export function imageSourceProblem(src: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Read the directive on an image.
|
|
16
|
+
*
|
|
17
|
+
* Values are validated here rather than at the point of rendering, so a mistake
|
|
18
|
+
* is one finding with a position rather than three surfaces quietly drawing
|
|
19
|
+
* something else. A directive that holds a problem yields **no** class and no
|
|
20
|
+
* float: a half-honoured directive is the silent failure in a smaller costume.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} [raw] - The text between the braces, braces included or not.
|
|
23
|
+
* @returns {{classes: string[], float: string, problems: string[]}} What was
|
|
24
|
+
* written, and what cannot be honoured.
|
|
25
|
+
*/
|
|
26
|
+
export function parseImageDirective(raw?: string): {
|
|
27
|
+
classes: string[];
|
|
28
|
+
float: string;
|
|
29
|
+
problems: string[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The classes a figure carries, from a parsed directive.
|
|
33
|
+
*
|
|
34
|
+
* @param {{classes?: string[], float?: string}} [directive] - As parsed.
|
|
35
|
+
* @returns {string} A space-separated class list, always naming
|
|
36
|
+
* {@link IMAGE_FIGURE_CLASS} first.
|
|
37
|
+
*/
|
|
38
|
+
export function figureClasses({ classes, float }?: {
|
|
39
|
+
classes?: string[];
|
|
40
|
+
float?: string;
|
|
41
|
+
}): string;
|
|
42
|
+
/**
|
|
43
|
+
* Text going inside an HTML attribute or between tags.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} text - The raw value.
|
|
46
|
+
* @returns {string} The same value, safe in markup.
|
|
47
|
+
*/
|
|
48
|
+
export function escapeHtml(text: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* One image as the `<figure>` both HTML surfaces render.
|
|
51
|
+
*
|
|
52
|
+
* The website and a Foundry journal page get the identical string, from one
|
|
53
|
+
* function, so the two cannot drift into styling the same directive through
|
|
54
|
+
* different class names.
|
|
55
|
+
*
|
|
56
|
+
* @param {object} image - The image.
|
|
57
|
+
* @param {string} image.src - The address, resolved for the surface.
|
|
58
|
+
* @param {string} [image.alt] - The alt text, which is also the caption.
|
|
59
|
+
* @param {string[]} [image.classes] - Width classes, from the directive.
|
|
60
|
+
* @param {string} [image.float] - The float position, from the directive.
|
|
61
|
+
* @returns {string} The figure, as one HTML block.
|
|
62
|
+
*/
|
|
63
|
+
export function imageFigureHtml({ src, alt, classes, float }: {
|
|
64
|
+
src: string;
|
|
65
|
+
alt?: string | undefined;
|
|
66
|
+
classes?: string[] | undefined;
|
|
67
|
+
float?: string | undefined;
|
|
68
|
+
}): string;
|
|
69
|
+
/**
|
|
70
|
+
* Whether a match sits alone in its own paragraph.
|
|
71
|
+
*
|
|
72
|
+
* "Alone" is the whole of a block: nothing else on its line, and a blank line
|
|
73
|
+
* or the end of the body either side of it. A leading `>` or list marker
|
|
74
|
+
* disqualifies it for the same reason a word does — the paragraph it belongs to
|
|
75
|
+
* holds something the figure would have to be lifted out of.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} text - The body the match indexes into.
|
|
78
|
+
* @param {number} start - Where the match begins.
|
|
79
|
+
* @param {number} end - Where it ends.
|
|
80
|
+
* @returns {boolean} Whether the match is a block of its own.
|
|
81
|
+
*/
|
|
82
|
+
export function standsAlone(text: string, start: number, end: number): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Every image in one body, with its directive and its position.
|
|
85
|
+
*
|
|
86
|
+
* Code is skipped, because an image shown as an example is prose *about* an
|
|
87
|
+
* image and resolving it would make this very module impossible to document.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} body - The note's markdown, without its frontmatter.
|
|
90
|
+
* @returns {Array<{alt: string, src: string, title: string, directive: string,
|
|
91
|
+
* index: number, length: number, block: boolean}>} One entry per image, in
|
|
92
|
+
* source order.
|
|
93
|
+
*/
|
|
94
|
+
export function imagesIn(body: string): Array<{
|
|
95
|
+
alt: string;
|
|
96
|
+
src: string;
|
|
97
|
+
title: string;
|
|
98
|
+
directive: string;
|
|
99
|
+
index: number;
|
|
100
|
+
length: number;
|
|
101
|
+
block: boolean;
|
|
102
|
+
}>;
|
|
103
|
+
/**
|
|
104
|
+
* Every image address one body names, in order of appearance.
|
|
105
|
+
*
|
|
106
|
+
* What a build reads to know which files it has to stage before a compiler can
|
|
107
|
+
* see them.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} body - The note's markdown.
|
|
110
|
+
* @returns {string[]} The addresses, with repeats.
|
|
111
|
+
*/
|
|
112
|
+
export function imageSourcesIn(body: string): string[];
|
|
113
|
+
/**
|
|
114
|
+
* Every defect in one note's images.
|
|
115
|
+
*
|
|
116
|
+
* **Errors, not warnings.** A refusal that does not fail the build is not a
|
|
117
|
+
* refusal: `reportFindings` fails on an error and not on a warning, so a
|
|
118
|
+
* directive reported as advisory publishes anyway, looking exactly like one
|
|
119
|
+
* that worked.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} body - The note's markdown, without its frontmatter.
|
|
122
|
+
* @param {string} file - The note's path, for the finding.
|
|
123
|
+
* @param {object} [opts]
|
|
124
|
+
* @param {number} [opts.bodyLine=1] - The 1-based file line the body starts on.
|
|
125
|
+
* @param {number} [opts.bodyColumn=1] - The 1-based file column it starts at.
|
|
126
|
+
* @returns {Array<{file: string, line: number, column: number|undefined,
|
|
127
|
+
* severity: "error", message: string}>} One finding per defect, in source
|
|
128
|
+
* order.
|
|
129
|
+
*/
|
|
130
|
+
export function checkImages(body: string, file: string, { bodyLine, bodyColumn }?: {
|
|
131
|
+
bodyLine?: number | undefined;
|
|
132
|
+
bodyColumn?: number | undefined;
|
|
133
|
+
}): Array<{
|
|
134
|
+
file: string;
|
|
135
|
+
line: number;
|
|
136
|
+
column: number | undefined;
|
|
137
|
+
severity: "error";
|
|
138
|
+
message: string;
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* Walk a content tree and report every image it cannot render as authored.
|
|
142
|
+
*
|
|
143
|
+
* Its own walk, like the icon and HTML checks beside it, so all three stay
|
|
144
|
+
* leaves with nothing imported between them.
|
|
145
|
+
*
|
|
146
|
+
* @param {string} contentBase - Root of the content tree.
|
|
147
|
+
* @param {object} [opts]
|
|
148
|
+
* @param {readonly string[]} [opts.skipDirectories] - Directory names to ignore
|
|
149
|
+
* in addition to the dot-directories always skipped.
|
|
150
|
+
* @returns {{findings: Array<{file: string, line: number, column: number|undefined,
|
|
151
|
+
* severity: "error", message: string}>, files: number}} The findings, and how
|
|
152
|
+
* many files were read.
|
|
153
|
+
*/
|
|
154
|
+
export function lintContentImages(contentBase: string, { skipDirectories }?: {
|
|
155
|
+
skipDirectories?: readonly string[] | undefined;
|
|
156
|
+
}): {
|
|
157
|
+
findings: Array<{
|
|
158
|
+
file: string;
|
|
159
|
+
line: number;
|
|
160
|
+
column: number | undefined;
|
|
161
|
+
severity: "error";
|
|
162
|
+
message: string;
|
|
163
|
+
}>;
|
|
164
|
+
files: number;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Rewrite every block image in a body into the figure the website publishes.
|
|
168
|
+
*
|
|
169
|
+
* **Hugo is handed markdown, not a rendered page.** The site emitter writes a
|
|
170
|
+
* note's body through verbatim, so a `{…}` directive left in it reaches the
|
|
171
|
+
* page as its own literal braces: Goldmark's block-attribute parser is off, and
|
|
172
|
+
* turning it on would accept `style` and `id` alongside the two vocabularies,
|
|
173
|
+
* which is the injection surface this rule exists to avoid. So the directive is
|
|
174
|
+
* resolved here, into markup Goldmark passes through.
|
|
175
|
+
*
|
|
176
|
+
* An image whose directive does not parse is left exactly as written, so the
|
|
177
|
+
* page shows the braces and the lint says why — the same visible degradation an
|
|
178
|
+
* unknown icon name gets.
|
|
179
|
+
*
|
|
180
|
+
* Call this **inside** {@link module:engine/code-fences.protectCode}: an image
|
|
181
|
+
* in a fence is an example of one.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} body - The note's markdown.
|
|
184
|
+
* @param {(src: string) => string} [resolveSrc] - Translates an authored
|
|
185
|
+
* pathname into the address this surface serves. The default is the identity,
|
|
186
|
+
* for a caller rendering the format rather than publishing it.
|
|
187
|
+
* @returns {string} The same body, with each block image as a `<figure>`.
|
|
188
|
+
*/
|
|
189
|
+
export function renderImageFigures(body: string, resolveSrc?: (src: string) => string): string;
|
|
190
|
+
/**
|
|
191
|
+
* A markdown-it plugin that reads an image's directive and renders its figure.
|
|
192
|
+
*
|
|
193
|
+
* **A core rule, not an inline one.** markdown-it's own `image` rule consumes
|
|
194
|
+
* `` and leaves `{float: top-left}` behind as text, and a rule
|
|
195
|
+
* running before it would have to re-implement link parsing to find the brace.
|
|
196
|
+
* Reading the token stream afterwards costs one pass and re-implements nothing.
|
|
197
|
+
*
|
|
198
|
+
* Two things happen to a paragraph holding one image and nothing else: the
|
|
199
|
+
* directive is lifted off the text token that follows it, and the paragraph's
|
|
200
|
+
* own tokens are hidden, so the figure is a block rather than a `<figure>`
|
|
201
|
+
* nested inside a `<p>`. The Typst renderer reads the same `meta`, which is
|
|
202
|
+
* what keeps the book and the two HTML surfaces honouring one statement.
|
|
203
|
+
*
|
|
204
|
+
* An image whose directive does not parse keeps its braces and renders as its
|
|
205
|
+
* own literal text, which is how the author sees the mistake without reading a
|
|
206
|
+
* log.
|
|
207
|
+
*
|
|
208
|
+
* @param {(src: string) => string} [resolveSrc] - Translates an authored
|
|
209
|
+
* address into the one this surface serves. Foundry is handed the path inside
|
|
210
|
+
* the install; a renderer that resolves the address itself — the book stages
|
|
211
|
+
* its own copy — passes nothing and gets the address as authored.
|
|
212
|
+
* @returns {(md: object) => void} A markdown-it plugin.
|
|
213
|
+
*/
|
|
214
|
+
export function imagePlugin(resolveSrc?: (src: string) => string): (md: object) => void;
|
|
215
|
+
/**
|
|
216
|
+
* The width classes an image may carry, and what each means to a renderer.
|
|
217
|
+
*
|
|
218
|
+
* **The ordinary width is absent from this table on purpose.** It is what an
|
|
219
|
+
* image with no marker gets, and giving it a name would invite a note to write
|
|
220
|
+
* it — two spellings of one thing, one of which every existing note omits.
|
|
221
|
+
*
|
|
222
|
+
* `scope` is Typst's: a float placed with `scope: "parent"` spans every column
|
|
223
|
+
* of the page, and one placed with `scope: "column"` occupies the column it
|
|
224
|
+
* sits in. The book is set in one column, where the two measure the same, and
|
|
225
|
+
* stays correct when it is set in two.
|
|
226
|
+
*
|
|
227
|
+
* `class` is the class the HTML surfaces put on the `<figure>`. Named rather
|
|
228
|
+
* than reused from the authored spelling so a bare `full-width` in some other
|
|
229
|
+
* stylesheet cannot claim it.
|
|
230
|
+
*
|
|
231
|
+
* @type {Readonly<Record<string, {class: string, scope: string, describe: string}>>}
|
|
232
|
+
*/
|
|
233
|
+
export const IMAGE_CLASSES: Readonly<Record<string, {
|
|
234
|
+
class: string;
|
|
235
|
+
scope: string;
|
|
236
|
+
describe: string;
|
|
237
|
+
}>>;
|
|
238
|
+
/**
|
|
239
|
+
* The `float:` positions an image may take, and where each puts it.
|
|
240
|
+
*
|
|
241
|
+
* `align` is the Typst alignment the float is placed at. **Print cannot wrap
|
|
242
|
+
* text around an arbitrary shape**: a Typst float occupies the column measure,
|
|
243
|
+
* so the horizontal half of a position has no effect on the page and only the
|
|
244
|
+
* vertical half — top of the column, or bottom of it — does. The website and a
|
|
245
|
+
* Foundry journal get true CSS wrap from the same directive. Same statement,
|
|
246
|
+
* different fidelity, which is stated in the specification rather than left for
|
|
247
|
+
* a reader to discover by comparing two outputs.
|
|
248
|
+
*
|
|
249
|
+
* @type {Readonly<Record<string, {class: string, align: string, describe: string}>>}
|
|
250
|
+
*/
|
|
251
|
+
export const IMAGE_FLOATS: Readonly<Record<string, {
|
|
252
|
+
class: string;
|
|
253
|
+
align: string;
|
|
254
|
+
describe: string;
|
|
255
|
+
}>>;
|
|
256
|
+
/**
|
|
257
|
+
* The class every figure carries, whatever its width or position.
|
|
258
|
+
*
|
|
259
|
+
* One hook a stylesheet can reach every authored image through, so the two
|
|
260
|
+
* vocabularies stay about what differs between images rather than what they
|
|
261
|
+
* share.
|
|
262
|
+
*
|
|
263
|
+
* @type {string}
|
|
264
|
+
*/
|
|
265
|
+
export const IMAGE_FIGURE_CLASS: string;
|
|
266
|
+
/**
|
|
267
|
+
* A markdown image, with the directive it may carry.
|
|
268
|
+
*
|
|
269
|
+
* The alt text admits no `]`, and the address no whitespace or `)`, which is
|
|
270
|
+
* the shape markdown-it itself accepts for the common case and the only shape
|
|
271
|
+
* this format asks anyone to write. A title — `` — is
|
|
272
|
+
* matched so it can be reported rather than silently dropped.
|
|
273
|
+
*
|
|
274
|
+
* The directive is `{…}` immediately after the closing parenthesis, holding no
|
|
275
|
+
* newline: a brace that opens and never closes on its line is prose, not a
|
|
276
|
+
* directive, and reading on to the next paragraph to find its `}` would make
|
|
277
|
+
* one stray character swallow a page.
|
|
278
|
+
*
|
|
279
|
+
* @type {RegExp}
|
|
280
|
+
*/
|
|
281
|
+
export const IMAGE_PATTERN: RegExp;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The indentation a JSON file already uses, as the literal string to indent
|
|
3
|
+
* with.
|
|
4
|
+
*
|
|
5
|
+
* Read from the first indented line rather than assumed, because the two-space
|
|
6
|
+
* default is right for some consumers and wrong for most of them. A file whose
|
|
7
|
+
* second line is not indented — a one-line document — reports the npm default,
|
|
8
|
+
* which is what rewriting it would produce anyway.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} text - The file's contents.
|
|
11
|
+
* @returns {string} The indent string, e.g. `" "` or `" "`.
|
|
12
|
+
*/
|
|
13
|
+
export function detectJsonIndent(text: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Rewrite a JSON file with a given indent, leaving its content untouched.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} file - Absolute path to the JSON file.
|
|
18
|
+
* @param {string} indent - The indent string to write with.
|
|
19
|
+
* @returns {boolean} Whether the file's bytes changed.
|
|
20
|
+
*/
|
|
21
|
+
export function reindentJsonFile(file: string, indent: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Every package name a manifest declares a range for, in declaration order.
|
|
24
|
+
*
|
|
25
|
+
* @param {object} manifest - The parsed `package.json`.
|
|
26
|
+
* @returns {string[]} The declared package names.
|
|
27
|
+
*/
|
|
28
|
+
export function declaredDependencies(manifest: object): string[];
|
|
29
|
+
/**
|
|
30
|
+
* The packages a bump targets when the caller names none.
|
|
31
|
+
*
|
|
32
|
+
* The first-party scope, because that is the bump a consumer runs by hand: a
|
|
33
|
+
* third-party one arrives from Dependabot on its own schedule, while a
|
|
34
|
+
* first-party release is taken the moment it publishes, usually to unblock the
|
|
35
|
+
* very change that prompted it.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} manifest - The parsed `package.json`.
|
|
38
|
+
* @param {string} [scope] - The scope prefix to match.
|
|
39
|
+
* @returns {string[]} The package names to bump.
|
|
40
|
+
*/
|
|
41
|
+
export function firstPartyDependencies(manifest: object, scope?: string): string[];
|
|
42
|
+
/**
|
|
43
|
+
* The version the lockfile currently resolves a package to.
|
|
44
|
+
*
|
|
45
|
+
* Read from the lockfile rather than the manifest, because the manifest states
|
|
46
|
+
* a *range* and the lockfile states what `npm ci` will actually install — which
|
|
47
|
+
* is the thing a bump moves. A caret range that already admits the new version
|
|
48
|
+
* needs no manifest change at all, and reporting the range would then show a
|
|
49
|
+
* bump as changing nothing.
|
|
50
|
+
*
|
|
51
|
+
* @param {object} lock - The parsed `package-lock.json`.
|
|
52
|
+
* @param {string} name - The package name.
|
|
53
|
+
* @returns {string|undefined} The locked version, if the lockfile holds one.
|
|
54
|
+
*/
|
|
55
|
+
export function lockedVersion(lock: object, name: string): string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Take the newest published version of one or more dependencies.
|
|
58
|
+
*
|
|
59
|
+
* npm performs the resolution — so a bump that changes the dependency set is
|
|
60
|
+
* as correct as one that moves three lines — and both JSON files are restored
|
|
61
|
+
* to the indentation they already used.
|
|
62
|
+
*
|
|
63
|
+
* @param {object} options - Options.
|
|
64
|
+
* @param {string} options.rootDir - The repository root holding `package.json`.
|
|
65
|
+
* @param {string[]} [options.packages] - Packages to bump. Defaults to every
|
|
66
|
+
* first-party dependency the manifest declares.
|
|
67
|
+
* @param {string} [options.tag] - The dist-tag to take. Defaults to `latest`.
|
|
68
|
+
* @param {boolean} [options.check] - Report what would change and write nothing.
|
|
69
|
+
* @param {(command: string, args: string[], cwd: string) => void} [options.run] -
|
|
70
|
+
* How to invoke npm. Injected by the tests, which have no registry.
|
|
71
|
+
* @returns {{changes: Array<{name: string, from: string|undefined, to: string|undefined}>,
|
|
72
|
+
* unchanged: string[], reindented: string[], checked: boolean}} What moved.
|
|
73
|
+
*/
|
|
74
|
+
export function bumpDependencies({ rootDir, packages, tag, check, run }: {
|
|
75
|
+
rootDir: string;
|
|
76
|
+
packages?: string[] | undefined;
|
|
77
|
+
tag?: string | undefined;
|
|
78
|
+
check?: boolean | undefined;
|
|
79
|
+
run?: ((command: string, args: string[], cwd: string) => void) | undefined;
|
|
80
|
+
}): {
|
|
81
|
+
changes: Array<{
|
|
82
|
+
name: string;
|
|
83
|
+
from: string | undefined;
|
|
84
|
+
to: string | undefined;
|
|
85
|
+
}>;
|
|
86
|
+
unchanged: string[];
|
|
87
|
+
reindented: string[];
|
|
88
|
+
checked: boolean;
|
|
89
|
+
};
|
|
@@ -239,6 +239,29 @@ export const UNIVERSAL_KEYS: ReadonlySet<string>;
|
|
|
239
239
|
* @type {Readonly<Record<string, SystemBlockSpec>>}
|
|
240
240
|
*/
|
|
241
241
|
export const DEFAULT_SYSTEM_BLOCKS: Readonly<Record<string, SystemBlockSpec>>;
|
|
242
|
+
/**
|
|
243
|
+
* The frontmatter fields that name artwork, and so resolve through
|
|
244
|
+
* {@link module:engine/helpers.resolveImg}.
|
|
245
|
+
*
|
|
246
|
+
* Both, always: a being carries `img` and `portrait` independently — the token
|
|
247
|
+
* art and the sheet portrait — and a rule about how the translator reads an
|
|
248
|
+
* empty value belongs to the translator, not to whichever key happens to be
|
|
249
|
+
* more common. Eleven `sohl-kethira-basic` beings write `portrait: ""` and no
|
|
250
|
+
* note in any tree writes `img: ""` on a being; a check keyed on `img` alone
|
|
251
|
+
* would have called that tree clean.
|
|
252
|
+
*
|
|
253
|
+
* **Each carries where it is authored**, because the two no longer agree. The
|
|
254
|
+
* specification puts an actor's portrait under `data:` and leaves its token art
|
|
255
|
+
* at the note's top level, so `portrait` has a third position to read and `img`
|
|
256
|
+
* does not — and a check that read only the two they share would pass a
|
|
257
|
+
* `data.portrait: ""` it could not see.
|
|
258
|
+
*
|
|
259
|
+
* @type {readonly {key: string, inData: boolean}[]}
|
|
260
|
+
*/
|
|
261
|
+
export const ART_FIELDS: readonly {
|
|
262
|
+
key: string;
|
|
263
|
+
inData: boolean;
|
|
264
|
+
}[];
|
|
242
265
|
/**
|
|
243
266
|
* What one system block accepts beyond the keys every block carries.
|
|
244
267
|
*/
|
|
@@ -178,90 +178,48 @@ export function systemTemplatePriority(fm: object, label: string): number | null
|
|
|
178
178
|
*/
|
|
179
179
|
export function makeFilename(name: any, id: any): string;
|
|
180
180
|
/**
|
|
181
|
-
* Translate
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
* and
|
|
196
|
-
* root is derived from the configuration, and is the one place `systems/sohl`
|
|
197
|
-
* is ever spelled. An authored
|
|
198
|
-
* `systems/sohl/assets/icons/noun/shield.svg` is left exactly as written,
|
|
199
|
-
* whichever package is compiling it.
|
|
200
|
-
*
|
|
201
|
-
* **This is a rule about ownership, not an allowlist of directories.** It used
|
|
202
|
-
* to prefix `icons/…` and `images/…` and pass everything else through — the
|
|
203
|
-
* same answer for every path any tree authors today, and the wrong one for the
|
|
204
|
-
* next directory a package ships. `sohl-kethira-basic` keeps art under
|
|
205
|
-
* `assets/artwork/`, so an authored `artwork/deity.webp` would have shipped
|
|
206
|
-
* unprefixed: a 404 in Foundry, reported by nothing. That a package owns its
|
|
207
|
-
* own tree is the fact; the directory names inside it are that package's
|
|
208
|
-
* business.
|
|
209
|
-
*
|
|
210
|
-
* **Off-install addresses pass through too**, which is the same rule rather
|
|
211
|
-
* than a fourth: a URL, a `data:` URI, or a `/`-rooted path names something no
|
|
212
|
-
* package owns. See {@link addressesAnotherPackage}.
|
|
213
|
-
*
|
|
214
|
-
* **`banner:` does not follow this rule, deliberately.** It is not an
|
|
215
|
-
* asset path inside a Foundry install at all: it reaches no compiled document,
|
|
216
|
-
* and its only consumer is the Hugo theme, which prefixes a relative value with
|
|
217
|
-
* `images/` and joins it onto `params.cdnBaseURL`. The two fields look alike
|
|
218
|
-
* and address different places — `img:` a file Foundry serves, `banner:` a file
|
|
219
|
-
* the CDN serves — so they are documented apart rather than reconciled into one
|
|
220
|
-
* rule that would be true of neither.
|
|
221
|
-
*
|
|
222
|
-
* **Two empties, and they mean opposite things.** `null` — or an absent
|
|
223
|
-
* key, which reaches here as `undefined` — means _unset_: the note names no art
|
|
224
|
-
* and the caller's default applies. `""` means _blank on purpose_: the note
|
|
225
|
-
* names no art **and wants none**, so no default may replace it. Both come back
|
|
181
|
+
* Translate an authored pathname into the address a Foundry install serves.
|
|
182
|
+
*
|
|
183
|
+
* The Foundry half of {@link module:engine/pathnames.resolvePathname}, which
|
|
184
|
+
* states the rule and derives the other three surfaces from the same
|
|
185
|
+
* statement. Kept as its own function because the compilers want one address
|
|
186
|
+
* and nothing else, and because the default a caller applies to an unset one is
|
|
187
|
+
* domain-specific — actors default differently from items, and gear differently
|
|
188
|
+
* again — so each compiler owns its default and applies it with **nullish**
|
|
189
|
+
* coalescing: `resolveImg(fm.img) ?? <default>`. Not `||`, which would collapse
|
|
190
|
+
* a deliberate blank back into the default.
|
|
191
|
+
*
|
|
192
|
+
* **Two empties, and they mean opposite things.** `null` — or an absent key,
|
|
193
|
+
* which reaches here as `undefined` — means _unset_: the note names no art and
|
|
194
|
+
* the caller's default applies. `""` means _blank on purpose_: the note names
|
|
195
|
+
* no art **and wants none**, so no default may replace it. Both come back
|
|
226
196
|
* distinguishable, `null` and `""` respectively, and neither is invented from
|
|
227
197
|
* the other.
|
|
228
198
|
*
|
|
229
|
-
* This used to open `if (!raw) return ""`, which made the two one case: every
|
|
230
|
-
* caller then applied its default with `||`, so a deliberate blank was
|
|
231
|
-
* unspellable and an unset key and an empty string compiled identically. That
|
|
232
|
-
* is the convention the project already rejects for an optional "not specified"
|
|
233
|
-
* DataModel string, where `nullable, initial: null` keeps "unset" a single
|
|
234
|
-
* honest value rather than two.
|
|
235
|
-
*
|
|
236
199
|
* **`title` does not follow this rule**, and must not be made to. On a
|
|
237
200
|
* `type: affiliation` note `title` is *also* a declared item field whose default
|
|
238
201
|
* is `""` (`sohl/item-fields.mjs`), resolved from the very same shared top-level
|
|
239
202
|
* key the site emitter reads as the page title — so `title: null` stringifies
|
|
240
203
|
* into the compiled document as the literal `"null"`. One key, two destinations
|
|
241
|
-
* that disagree about what empty means
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* `itemArt()`, which runs the
|
|
250
|
-
* entry and a note's `img:` are spelled the same way
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* from the package kind, and a `documentation` package has none: Foundry serves
|
|
254
|
-
* no files for it. Only a compiling pass reaches here, and a documentation
|
|
255
|
-
* package runs none, so a path arriving with no root to put it under is a pass
|
|
256
|
-
* running where it should not — reported as that, rather than emitted as
|
|
257
|
-
* `null/icons/relic.svg` into a document nobody would check.
|
|
258
|
-
*
|
|
259
|
-
* @param {string | null | undefined} raw - content-relative path from frontmatter.
|
|
204
|
+
* that disagree about what empty means.
|
|
205
|
+
*
|
|
206
|
+
* **`banner:` does not follow it either, deliberately.** It is not a file
|
|
207
|
+
* inside a Foundry install: it reaches no compiled document and no book, its
|
|
208
|
+
* only consumer is the Hugo theme, and the theme resolves it against the site's
|
|
209
|
+
* own asset root. See `docs/content-format.md`.
|
|
210
|
+
*
|
|
211
|
+
* For items, the default is the art paired with the type's builder, reached
|
|
212
|
+
* through `itemArt()`, which runs the pathname back through this function so a
|
|
213
|
+
* registry entry and a note's `img:` are spelled the same way.
|
|
214
|
+
*
|
|
215
|
+
* @param {string | null | undefined} raw - The pathname from frontmatter.
|
|
260
216
|
* @param {{assetRoot: string|null}} [config] - The resolved build configuration.
|
|
261
217
|
* Defaults to this repository's.
|
|
262
218
|
* @returns {string | null} the Foundry-relative path; `""` for a deliberate
|
|
263
219
|
* blank, and `null` when the note names no art at all.
|
|
264
|
-
* @throws {Error} When
|
|
220
|
+
* @throws {Error} When no Foundry address can be derived — a `documentation`
|
|
221
|
+
* package, which Foundry installs nothing of, or a pathname naming a package
|
|
222
|
+
* this build declares no relationship with.
|
|
265
223
|
*/
|
|
266
224
|
export function resolveImg(raw: string | null | undefined, config?: {
|
|
267
225
|
assetRoot: string | null;
|
package/types/engine/index.d.mts
CHANGED
|
@@ -19,6 +19,9 @@ export * as systems from "./systems.mjs";
|
|
|
19
19
|
export * as contentSlug from "./content-slug.mjs";
|
|
20
20
|
export * as contentAddress from "./content-address.mjs";
|
|
21
21
|
export * as subtypeRegistry from "./subtype-registry.mjs";
|
|
22
|
+
export * as infobox from "./infobox.mjs";
|
|
23
|
+
export * as infoboxRegistry from "./infobox-registry.mjs";
|
|
24
|
+
export * as infoboxRender from "./infobox-render.mjs";
|
|
22
25
|
export * as noteIds from "./note-ids.mjs";
|
|
23
26
|
export * as noteRenames from "./note-renames.mjs";
|
|
24
27
|
export * as metadataIndex from "./metadata-index.mjs";
|
|
@@ -29,6 +32,8 @@ export * as contentLint from "./content-lint.mjs";
|
|
|
29
32
|
export * as contentCharset from "./content-charset.mjs";
|
|
30
33
|
export * as contentIcons from "./content-icons.mjs";
|
|
31
34
|
export * as contentHtml from "./content-html.mjs";
|
|
35
|
+
export * as contentImages from "./content-images.mjs";
|
|
36
|
+
export * as pathnames from "./pathnames.mjs";
|
|
32
37
|
export * as contentLinks from "./content-links.mjs";
|
|
33
38
|
export * as webWikilinks from "./web-wikilinks.mjs";
|
|
34
39
|
export * as contentTables from "./content-tables.mjs";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One system's declaration, by its id.
|
|
3
|
+
*
|
|
4
|
+
* @param {string|undefined} system - The system id.
|
|
5
|
+
* @returns {object|undefined} Its declaration, or `undefined` where this
|
|
6
|
+
* toolchain ships none for it.
|
|
7
|
+
*/
|
|
8
|
+
export function infoboxFor(system: string | undefined): object | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Every box one note carries, wired to the registries this toolchain ships.
|
|
11
|
+
*
|
|
12
|
+
* The one call each medium makes. What varies between them is the resolver —
|
|
13
|
+
* a website has URLs, a compendium has UUIDs, the book has its own labels —
|
|
14
|
+
* and nothing else, which is what keeps the three showing the same panel.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} fm - The note's frontmatter.
|
|
17
|
+
* @param {object} [options] - Options.
|
|
18
|
+
* @param {(ref: unknown, hint?: object) => object|undefined} [options.resolve] -
|
|
19
|
+
* Resolves a reference to `{name, url?, uuid?, address?, subType?}`.
|
|
20
|
+
* @returns {object[]} The boxes, in the order every medium renders them.
|
|
21
|
+
* @throws {Error} When the built set disagrees with what the note's type maps
|
|
22
|
+
* to — see {@link module:engine/infobox.assertInfoboxSet}.
|
|
23
|
+
*/
|
|
24
|
+
export function noteInfoboxes(fm: object, { resolve }?: {
|
|
25
|
+
resolve?: ((ref: unknown, hint?: object) => object | undefined) | undefined;
|
|
26
|
+
}): object[];
|
|
27
|
+
/**
|
|
28
|
+
* Every system's infobox declaration, in the order a page shows them.
|
|
29
|
+
*
|
|
30
|
+
* The order matches {@link module:engine/subtype-registry.KNOWN_DOCUMENT_SUBTYPE_MAPS},
|
|
31
|
+
* because the box set is derived from those maps and a reader meeting two
|
|
32
|
+
* pages of one type should meet the boxes in one order.
|
|
33
|
+
*
|
|
34
|
+
* @type {readonly object[]}
|
|
35
|
+
*/
|
|
36
|
+
export const KNOWN_INFOBOXES: readonly object[];
|