@heroiclands/package-build 22.21.0 → 22.23.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 +223 -0
- package/assets/styles/content-base.css +162 -0
- package/bin/content-commands.mjs +77 -17
- package/bin/package-build.mjs +15 -2
- package/ci/content-format-reference.mjs +68 -1
- package/config.mjs +26 -0
- package/content-config.mjs +153 -6
- package/docs/api.md +120 -89
- package/docs/authoring/assets.md +14 -0
- package/docs/authoring/dates-and-calendars.md +41 -3
- package/docs/authoring/frontmatter.md +2 -2
- package/docs/authoring/links-and-markup.md +325 -35
- package/docs/commands.md +12 -10
- package/docs/configuration.md +117 -14
- package/docs/content-format.md +4 -2
- package/docs/guides/book.md +5 -4
- package/docs/guides/reference-pages.md +15 -0
- package/docs/reference/format-details.md +545 -104
- package/docs/reference/note-types.md +30 -13
- package/engine/actor-compiler.mjs +23 -0
- package/engine/anchored-sections.mjs +35 -4
- package/engine/anchors.mjs +26 -30
- package/engine/art-fields.mjs +118 -0
- package/engine/art-slots.mjs +7 -1
- package/engine/asset-index.mjs +160 -10
- package/engine/asset-replacement.mjs +93 -0
- package/engine/asset-types.mjs +240 -0
- package/engine/base-compiler.mjs +139 -22
- package/engine/base-styles.mjs +149 -0
- package/engine/bundles.mjs +13 -2
- package/engine/compendiums.mjs +8 -1
- package/engine/content-blocks.mjs +410 -0
- package/engine/content-embeds.mjs +19 -0
- package/engine/content-figures.mjs +468 -0
- package/engine/content-footnotes.mjs +197 -0
- package/engine/content-format-check.mjs +15 -12
- package/engine/content-format.yaml +1 -1
- package/engine/content-images.mjs +126 -25
- package/engine/content-index.mjs +38 -12
- package/engine/content-links.mjs +14 -6
- package/engine/content-tables.mjs +45 -4
- package/engine/content-tasklists.mjs +189 -0
- package/engine/docs-checks.mjs +4 -4
- package/engine/extension-attributes.mjs +48 -2
- package/engine/field-reference.mjs +31 -10
- package/engine/field-spec.mjs +10 -8
- package/engine/foreign-catalog.mjs +143 -18
- package/engine/frontmatter-lint.mjs +120 -65
- package/engine/frontmatter.mjs +3 -3
- package/engine/heading-attributes.mjs +321 -0
- package/engine/helpers.mjs +109 -41
- package/engine/homepage.mjs +8 -8
- package/engine/index.mjs +3 -0
- package/engine/infobox-registry.mjs +4 -1
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +129 -15
- package/engine/itinerary-scenes.mjs +4 -10
- package/engine/journals.mjs +294 -50
- package/engine/lore-events.mjs +197 -0
- package/engine/macros.mjs +1 -1
- package/engine/markdown-expressions.mjs +434 -59
- package/engine/note-dates.mjs +354 -12
- package/engine/note-frontmatter.mjs +7 -16
- package/engine/note-vocabulary.mjs +183 -42
- package/engine/page-lists.mjs +358 -0
- package/engine/pathnames.mjs +36 -0
- package/engine/pdf-build.mjs +431 -74
- package/engine/pdf-images.mjs +64 -0
- package/engine/pdf-render.mjs +563 -66
- package/engine/rank-ladder.mjs +198 -0
- package/engine/reckoning-markers.mjs +1 -1
- package/engine/retired-fields.mjs +8 -13
- package/engine/scenes.mjs +26 -7
- package/engine/site-build.mjs +166 -23
- package/engine/site-config.mjs +10 -1
- package/engine/site-index.mjs +90 -3
- package/engine/site-preview.mjs +20 -7
- package/engine/social-ties.mjs +52 -14
- package/engine/sql-tables.mjs +66 -9
- package/engine/standings.mjs +89 -6
- package/engine/system-block.mjs +56 -30
- package/engine/web-wikilinks.mjs +48 -1
- package/hm3/actors.mjs +8 -5
- package/manifest.mjs +43 -24
- package/package.json +1 -1
- package/packagebuild-metadata.jsonl +13 -13
- package/sohl/actors.mjs +22 -99
- package/sohl/item-fields.mjs +5 -5
- package/sohl/items.mjs +1 -1
- package/sohl/note-schemas.mjs +11 -21
- package/types/config.d.mts +9 -0
- package/types/content-config.d.mts +48 -1
- package/types/engine/actor-compiler.d.mts +11 -0
- package/types/engine/anchored-sections.d.mts +24 -0
- package/types/engine/anchors.d.mts +9 -4
- package/types/engine/art-fields.d.mts +64 -0
- package/types/engine/asset-index.d.mts +43 -0
- package/types/engine/asset-replacement.d.mts +22 -0
- package/types/engine/asset-types.d.mts +18 -0
- package/types/engine/base-compiler.d.mts +19 -17
- package/types/engine/base-styles.d.mts +93 -0
- package/types/engine/content-blocks.d.mts +87 -0
- package/types/engine/content-embeds.d.mts +16 -0
- package/types/engine/content-figures.d.mts +101 -0
- package/types/engine/content-footnotes.d.mts +80 -0
- package/types/engine/content-format-check.d.mts +8 -6
- package/types/engine/content-images.d.mts +78 -12
- package/types/engine/content-index.d.mts +8 -2
- package/types/engine/content-tables.d.mts +12 -4
- package/types/engine/content-tasklists.d.mts +72 -0
- package/types/engine/extension-attributes.d.mts +22 -1
- package/types/engine/field-reference.d.mts +21 -0
- package/types/engine/field-spec.d.mts +20 -16
- package/types/engine/foreign-catalog.d.mts +39 -0
- package/types/engine/frontmatter.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +179 -0
- package/types/engine/helpers.d.mts +29 -10
- package/types/engine/homepage.d.mts +7 -7
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox-registry.d.mts +4 -1
- package/types/engine/infobox-render.d.mts +6 -1
- package/types/engine/infobox.d.mts +6 -0
- package/types/engine/journals.d.mts +41 -12
- package/types/engine/lore-events.d.mts +14 -0
- package/types/engine/markdown-expressions.d.mts +46 -2
- package/types/engine/note-dates.d.mts +64 -1
- package/types/engine/note-frontmatter.d.mts +1 -4
- package/types/engine/note-vocabulary.d.mts +82 -6
- package/types/engine/page-lists.d.mts +126 -0
- package/types/engine/pathnames.d.mts +26 -0
- package/types/engine/pdf-build.d.mts +28 -6
- package/types/engine/pdf-images.d.mts +52 -0
- package/types/engine/pdf-render.d.mts +84 -2
- package/types/engine/rank-ladder.d.mts +32 -0
- package/types/engine/retired-fields.d.mts +4 -6
- package/types/engine/site-build.d.mts +27 -4
- package/types/engine/site-config.d.mts +9 -0
- package/types/engine/site-index.d.mts +67 -1
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -7
- package/types/engine/standings.d.mts +21 -3
- package/types/engine/system-block.d.mts +37 -14
- package/types/engine/web-wikilinks.d.mts +3 -1
- package/types/hm3/actors.d.mts +21 -3
- package/types/manifest.d.mts +19 -23
- package/types/sohl/actors.d.mts +6 -7
- package/engine/content-admonitions.mjs +0 -114
- package/engine/content-captions.mjs +0 -181
- package/engine/content-secrets.mjs +0 -112
- package/types/engine/content-admonitions.d.mts +0 -24
- package/types/engine/content-captions.d.mts +0 -45
- package/types/engine/content-secrets.d.mts +0 -17
|
@@ -61,6 +61,29 @@ export function assetAddressIndex(records?: readonly object[], { config, foreign
|
|
|
61
61
|
} | undefined;
|
|
62
62
|
types?: Iterable<string> | undefined;
|
|
63
63
|
}): object;
|
|
64
|
+
/**
|
|
65
|
+
* What a renderer needs to size one picture, keyed by the pathname its
|
|
66
|
+
* address resolves to.
|
|
67
|
+
*
|
|
68
|
+
* An image reaches a renderer as the resolved pathname an embed or an authored
|
|
69
|
+
* body image already carries — see {@link readAssetAddress} — never as the
|
|
70
|
+
* address that produced it, so the lookup a renderer wants is by pathname, not
|
|
71
|
+
* by {@link assetAddressIndex}'s own `assets` map.
|
|
72
|
+
*
|
|
73
|
+
* @param {readonly object[]} records - Asset records, local or foreign.
|
|
74
|
+
* @returns {Map<string, {type: string, role?: string, width: number|"", height: number|""}>}
|
|
75
|
+
* One entry per addressable file, carrying only what a renderer sizes a
|
|
76
|
+
* picture from. `role` is omitted when the record states none; `width` and
|
|
77
|
+
* `height` are always present, blank (`""`) for a vector — the record's own
|
|
78
|
+
* convention, carried through rather than collapsed into an absence a
|
|
79
|
+
* renderer could not tell apart from "no asset resolved at all".
|
|
80
|
+
*/
|
|
81
|
+
export function assetImageInfoByPathname(records?: readonly object[]): Map<string, {
|
|
82
|
+
type: string;
|
|
83
|
+
role?: string;
|
|
84
|
+
width: number | "";
|
|
85
|
+
height: number | "";
|
|
86
|
+
}>;
|
|
64
87
|
/**
|
|
65
88
|
* The asset one authored value names, or why it names none.
|
|
66
89
|
*
|
|
@@ -116,6 +139,47 @@ export function resolveArtRecord(index: object, value: unknown, defaultType: str
|
|
|
116
139
|
path: string;
|
|
117
140
|
};
|
|
118
141
|
} | null;
|
|
142
|
+
/**
|
|
143
|
+
* Every asset's role, keyed by the pathname it resolves to — the form a body
|
|
144
|
+
* carries once an embed's address has been rewritten into the ordinary image
|
|
145
|
+
* every surface renders ({@link module:engine/content-embeds.resolveEmbeds}).
|
|
146
|
+
*
|
|
147
|
+
* This is the lookup a `:::figure` fence's `map` counter reaches through —
|
|
148
|
+
* see {@link module:engine/content-figures.scanFigures}'s `resolveRole` —
|
|
149
|
+
* for a caller that reads a body after that rewrite: a Foundry journal, an
|
|
150
|
+
* item or actor's documentation, and the book.
|
|
151
|
+
*
|
|
152
|
+
* @param {object} index - From {@link module:engine/wikilinks.buildWikilinkIndex},
|
|
153
|
+
* or the equivalent the site and the book build.
|
|
154
|
+
* @returns {Map<string, string>} Pathname → role, one entry per asset that
|
|
155
|
+
* declares one.
|
|
156
|
+
*/
|
|
157
|
+
export function pathnameRoles(index: object): Map<string, string>;
|
|
158
|
+
/**
|
|
159
|
+
* Flag a note whose art slot names a picture that is not the size that slot
|
|
160
|
+
* is cut to.
|
|
161
|
+
*
|
|
162
|
+
* The size is stated by the slot itself, in
|
|
163
|
+
* {@link module:engine/art-slots.ART_SLOTS}, so it is written once and a slot
|
|
164
|
+
* that states none asks nothing of the picture it names. Today the hero image
|
|
165
|
+
* is the one slot with a fixed strip to fill; a picture written in prose is
|
|
166
|
+
* fitted to the room it has and is never measured here.
|
|
167
|
+
*
|
|
168
|
+
* A vector carries no pixel size to compare, and neither does a raster whose
|
|
169
|
+
* header cannot be read; neither is flagged.
|
|
170
|
+
*
|
|
171
|
+
* @param {readonly object[]} records - The corpus, notes and assets together.
|
|
172
|
+
* @param {object} [opts]
|
|
173
|
+
* @param {object} [opts.config] - The resolved build configuration.
|
|
174
|
+
* @param {string} [opts.assetsBase] - Where the asset roots sit, so a finding
|
|
175
|
+
* names the file from the working directory as every other finding does.
|
|
176
|
+
* @returns {object[]} A finding per picture off its slot's size,
|
|
177
|
+
* `severity: "error"`.
|
|
178
|
+
*/
|
|
179
|
+
export function checkArtSlotSizes(records?: readonly object[], { config, assetsBase }?: {
|
|
180
|
+
config?: object | undefined;
|
|
181
|
+
assetsBase?: string | undefined;
|
|
182
|
+
}): object[];
|
|
119
183
|
/**
|
|
120
184
|
* The pathname an art value names, in the form an authored one takes.
|
|
121
185
|
*
|
|
@@ -19,6 +19,16 @@ export function collectAssetRecords(assetsBase: string, { contentPackage, proble
|
|
|
19
19
|
contentPackage: string;
|
|
20
20
|
problems?: object[] | undefined;
|
|
21
21
|
}): Array<Record<string, any>>;
|
|
22
|
+
/**
|
|
23
|
+
* The closed set of roles a picture may declare.
|
|
24
|
+
*
|
|
25
|
+
* Shared with the field declaration below and with every medium that sizes a
|
|
26
|
+
* picture by its role, so the vocabulary cannot drift between the record that
|
|
27
|
+
* carries it and the renderer that reads it.
|
|
28
|
+
*
|
|
29
|
+
* @type {readonly string[]}
|
|
30
|
+
*/
|
|
31
|
+
export const ASSET_ROLES: readonly string[];
|
|
22
32
|
/**
|
|
23
33
|
* The file a directory records provenance for its subtree in.
|
|
24
34
|
*
|
|
@@ -47,6 +57,18 @@ export const PROVENANCE_SIDECAR_SUFFIX: string;
|
|
|
47
57
|
* state this key. Omitting one is a finding rather than a blank, because a
|
|
48
58
|
* record resolves wholesale: the nearest one is the whole answer, so a key it
|
|
49
59
|
* leaves out is not inherited from above but simply absent.
|
|
60
|
+
* @property {"boolean"|"integer"} [type] - The value's own type, for a field
|
|
61
|
+
* whose answer is not a string. Omitted for every string field; `ai` carries
|
|
62
|
+
* the YAML boolean itself rather than a stringified copy, and `width` and
|
|
63
|
+
* `height` carry the pixel count the walk measured. Each is refused rather
|
|
64
|
+
* than coerced when the value does not match.
|
|
65
|
+
* @property {readonly string[]} [values] - The closed set a provenance
|
|
66
|
+
* declaration must choose one of; a value outside it is a finding and the
|
|
67
|
+
* key is left blank, the same treatment an `ai` value of the wrong shape
|
|
68
|
+
* gets. `role` is the one field that carries it.
|
|
69
|
+
* @property {string} [onlyType] - The one asset type this field may be
|
|
70
|
+
* declared for. A provenance record stating it for another type is a
|
|
71
|
+
* finding, and the value is dropped rather than carried through.
|
|
50
72
|
* @property {string} describe - One line, for the author-facing reference.
|
|
51
73
|
*/
|
|
52
74
|
/**
|
|
@@ -105,6 +127,27 @@ export type AssetRecordField = {
|
|
|
105
127
|
* leaves out is not inherited from above but simply absent.
|
|
106
128
|
*/
|
|
107
129
|
required?: boolean | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* - The value's own type, for a field
|
|
132
|
+
* whose answer is not a string. Omitted for every string field; `ai` carries
|
|
133
|
+
* the YAML boolean itself rather than a stringified copy, and `width` and
|
|
134
|
+
* `height` carry the pixel count the walk measured. Each is refused rather
|
|
135
|
+
* than coerced when the value does not match.
|
|
136
|
+
*/
|
|
137
|
+
type?: "boolean" | "integer" | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* - The closed set a provenance
|
|
140
|
+
* declaration must choose one of; a value outside it is a finding and the
|
|
141
|
+
* key is left blank, the same treatment an `ai` value of the wrong shape
|
|
142
|
+
* gets. `role` is the one field that carries it.
|
|
143
|
+
*/
|
|
144
|
+
values?: readonly string[] | undefined;
|
|
145
|
+
/**
|
|
146
|
+
* - The one asset type this field may be
|
|
147
|
+
* declared for. A provenance record stating it for another type is a
|
|
148
|
+
* finding, and the value is dropped rather than carried through.
|
|
149
|
+
*/
|
|
150
|
+
onlyType?: string | undefined;
|
|
108
151
|
/**
|
|
109
152
|
* - One line, for the author-facing reference.
|
|
110
153
|
*/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The replacement record for one asset address, or `null`.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} address - A canonical asset address.
|
|
5
|
+
* @param {object} opts
|
|
6
|
+
* @param {string} opts.localPackage - The compiling package's own segment.
|
|
7
|
+
* @param {readonly string[]} opts.replacements - The package segments of
|
|
8
|
+
* every relationship declaring `assetReplacement: true`, in declaration
|
|
9
|
+
* order.
|
|
10
|
+
* @param {Map<string, object>} opts.index - The merged content index, keyed
|
|
11
|
+
* by canonical address.
|
|
12
|
+
* @returns {{record: object, package: string}|null} The first replacement
|
|
13
|
+
* carrying the address, or `null` when none does.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveAssetReplacement(address: string, { localPackage, replacements, index }: {
|
|
16
|
+
localPackage: string;
|
|
17
|
+
replacements: readonly string[];
|
|
18
|
+
index: Map<string, object>;
|
|
19
|
+
}): {
|
|
20
|
+
record: object;
|
|
21
|
+
package: string;
|
|
22
|
+
} | null;
|
|
@@ -27,6 +27,24 @@ export function assetTypeOfRoot(root: unknown): AssetType | undefined;
|
|
|
27
27
|
* @returns {boolean} Whether it matches {@link ADDRESS_SEGMENT_PATTERN}.
|
|
28
28
|
*/
|
|
29
29
|
export function isAssetShortcode(shortcode: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The pixel dimensions a raster image's own header states.
|
|
32
|
+
*
|
|
33
|
+
* Read from the file's bytes directly rather than through a decoder, so a
|
|
34
|
+
* corrupt or partial file fails closed — the same `undefined` answer as a
|
|
35
|
+
* format this carries no reader for — instead of throwing out of the asset
|
|
36
|
+
* walk. An SVG has no pixel dimensions to read; stating one would be a
|
|
37
|
+
* fabricated viewBox reading rather than a fact about the file.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} absPath - The file's absolute path.
|
|
40
|
+
* @param {string} ext - Its extension, lowercase and dot-led.
|
|
41
|
+
* @returns {{width: number, height: number}|undefined} The declared size, or
|
|
42
|
+
* `undefined` when the format carries none, or the header cannot be read.
|
|
43
|
+
*/
|
|
44
|
+
export function imageDimensions(absPath: string, ext: string): {
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
} | undefined;
|
|
30
48
|
/**
|
|
31
49
|
* The `<system>` segment every asset address carries.
|
|
32
50
|
*
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The tallies one pass accumulates while walking the tree.
|
|
3
|
-
*
|
|
4
|
-
* `declined` and `skippedOther` are deliberately separate numbers. A declined
|
|
5
|
-
* note is one this build **refused** — it declares a retired frontmatter field
|
|
6
|
-
* — and it is an error; a skipped one legitimately belongs to another pass, and
|
|
7
|
-
* there are thousands of those. Folding the first into the second is what let a
|
|
8
|
-
* whole tree be filtered out in silence.
|
|
9
|
-
*
|
|
10
|
-
* @typedef {object} PassStats
|
|
11
|
-
* @property {number} compiled - Notes that became a document.
|
|
12
|
-
* @property {number} skippedNoId - Notes with no `id`, where that is tolerated.
|
|
13
|
-
* @property {number} skippedOther - Notes this pass does not claim.
|
|
14
|
-
* @property {number} declined - Notes this pack **refused** — one declaring a
|
|
15
|
-
* retired frontmatter field, or one routed to a system pack whose system it
|
|
16
|
-
* says nothing about. Counted as errors, never as skips.
|
|
17
|
-
*/
|
|
18
1
|
/**
|
|
19
2
|
* The shared walk → filter → expand → convert → build → write → count loop.
|
|
20
3
|
*
|
|
@@ -378,6 +361,25 @@ export class BasePackCompiler {
|
|
|
378
361
|
linkIndex: any;
|
|
379
362
|
sqlTables: any;
|
|
380
363
|
worldPresent: unknown;
|
|
364
|
+
/**
|
|
365
|
+
* Report every finding {@link BasePackCompiler#convertBody} collected
|
|
366
|
+
* across its passes, and decline the note if there were any.
|
|
367
|
+
*
|
|
368
|
+
* Reported directly, one `noteError` per finding, rather than thrown as a
|
|
369
|
+
* single wrapped message: the site build and the book report the same way,
|
|
370
|
+
* each finding at its own line, and a note with three problems meets all
|
|
371
|
+
* three in the run that found them instead of one per rebuild. The thrown
|
|
372
|
+
* sentinel carries `alreadyReported` so the compile loop's generic catch
|
|
373
|
+
* does not add a fourth, vaguer line on top of the three already said.
|
|
374
|
+
*
|
|
375
|
+
* @param {readonly {message: string, line?: number, column?: number}[]} findings
|
|
376
|
+
* @throws {Error} When `findings` is non-empty, after reporting all of them.
|
|
377
|
+
*/
|
|
378
|
+
reportConvertBodyFindings(findings: readonly {
|
|
379
|
+
message: string;
|
|
380
|
+
line?: number;
|
|
381
|
+
column?: number;
|
|
382
|
+
}[]): void;
|
|
381
383
|
/**
|
|
382
384
|
* The body {@link BasePackCompiler#buildEntry} receives.
|
|
383
385
|
*
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cascade layer the sheet loads into, per package kind.
|
|
3
|
+
*
|
|
4
|
+
* Foundry declares its layer order in `css/foundry2.css`, ending
|
|
5
|
+
* `… layouts, system, modules, exceptions` — the eighth and ninth being, by its
|
|
6
|
+
* own comments, default game system styles and default module styles. That is
|
|
7
|
+
* what this sheet is, so it takes the layer its kind is given and is therefore
|
|
8
|
+
* the weakest thing a package can load:
|
|
9
|
+
*
|
|
10
|
+
* - **An unlayered package sheet beats it**, because an unlayered rule beats
|
|
11
|
+
* every layered one whatever its specificity.
|
|
12
|
+
* - **A package sheet naming any other layer beats it too**, because a layer
|
|
13
|
+
* Foundry's order does not mention is appended after the ones it does.
|
|
14
|
+
*
|
|
15
|
+
* So a package overrides the base sheet from its own, whichever way it declares
|
|
16
|
+
* one, and the override needs no `!important` and no specificity contest.
|
|
17
|
+
*
|
|
18
|
+
* @param {"system"|"module"} artifact - Which artifact is shipped.
|
|
19
|
+
* @returns {string} The layer name.
|
|
20
|
+
*/
|
|
21
|
+
export function baseStyleLayer(artifact: "system" | "module"): string;
|
|
22
|
+
/**
|
|
23
|
+
* The manifest `styles` entry for the base sheet.
|
|
24
|
+
*
|
|
25
|
+
* Foundry's `styles` is an array of `{layer?, src}`, and a bare string is
|
|
26
|
+
* migrated into that shape on read, so the object form is written directly.
|
|
27
|
+
*
|
|
28
|
+
* @param {"system"|"module"} artifact - Which artifact is shipped.
|
|
29
|
+
* @returns {{src: string, layer: string}} The entry.
|
|
30
|
+
*/
|
|
31
|
+
export function baseStyleEntry(artifact: "system" | "module"): {
|
|
32
|
+
src: string;
|
|
33
|
+
layer: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The absolute path of the sheet as installed, so the stage can copy it.
|
|
37
|
+
*
|
|
38
|
+
* Resolved against this module rather than against the consumer's working
|
|
39
|
+
* directory, because the file belongs to this package and arrives through
|
|
40
|
+
* `node_modules`.
|
|
41
|
+
*
|
|
42
|
+
* @returns {string} Absolute path of the shipped stylesheet.
|
|
43
|
+
*/
|
|
44
|
+
export function baseStylesheetSource(): string;
|
|
45
|
+
/**
|
|
46
|
+
* The `[source, destination]` pair that stages the sheet.
|
|
47
|
+
*
|
|
48
|
+
* The destination is relative, in the same spelling the repository's own asset
|
|
49
|
+
* table uses, so the caller resolves both against the repository root exactly
|
|
50
|
+
* as it resolves every other entry.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} stageDir - The configured stage directory, relative to the
|
|
53
|
+
* repository root.
|
|
54
|
+
* @returns {[string, string]} The pair, for `stageAssets`.
|
|
55
|
+
*/
|
|
56
|
+
export function baseStyleStageEntry(stageDir: string): [string, string];
|
|
57
|
+
/**
|
|
58
|
+
* The manifest's `styles`, with the base sheet named first.
|
|
59
|
+
*
|
|
60
|
+
* **First rather than last**, because `styles` is load order: a package's own
|
|
61
|
+
* sheet has to be read after the base one for an override written at equal
|
|
62
|
+
* specificity in an equal layer to take. The cascade layer makes the override
|
|
63
|
+
* work anyway, and the order makes it work for the right reason.
|
|
64
|
+
*
|
|
65
|
+
* A declared entry addressing the same file is not duplicated — a repository
|
|
66
|
+
* that named the staged path itself gets one entry, keeping whatever layer it
|
|
67
|
+
* chose, so declaring it is a way of placing it rather than an error.
|
|
68
|
+
*
|
|
69
|
+
* @param {object} options
|
|
70
|
+
* @param {unknown} [options.declared] - The declared `styles`, whatever shape
|
|
71
|
+
* it was written in; anything that is not a list is returned untouched.
|
|
72
|
+
* @param {"system"|"module"} options.artifact - Which artifact is shipped.
|
|
73
|
+
* @param {boolean} [options.enabled] - Whether the package takes the base
|
|
74
|
+
* sheet. `false` returns the declared list unchanged.
|
|
75
|
+
* @returns {unknown} The `styles` to emit, or `undefined` when there is
|
|
76
|
+
* nothing to emit at all.
|
|
77
|
+
*/
|
|
78
|
+
export function withBaseStyle({ declared, artifact, enabled }: {
|
|
79
|
+
declared?: unknown;
|
|
80
|
+
artifact: "system" | "module";
|
|
81
|
+
enabled?: boolean | undefined;
|
|
82
|
+
}): unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Where the shipped sheet lands inside the staged package.
|
|
85
|
+
*
|
|
86
|
+
* Under `styles/` beside a package's own sheet, and named for the toolchain so
|
|
87
|
+
* nothing a repository writes can collide with it. The path is relative to the
|
|
88
|
+
* staged package root, which is what both the stage entry and the manifest's
|
|
89
|
+
* `styles` are addressed in.
|
|
90
|
+
*
|
|
91
|
+
* @type {string}
|
|
92
|
+
*/
|
|
93
|
+
export const BASE_STYLESHEET_DEST: string;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find named blocks, leaving code examples alone.
|
|
3
|
+
*
|
|
4
|
+
* A block reaches `blocks` only when it is well formed and closed; everything
|
|
5
|
+
* else is a finding, and the surrounding blocks are unaffected.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} source - Markdown that may contain named blocks.
|
|
8
|
+
* @returns {{blocks: Array<{name: string, title: string, id: string, classes: string[], attributes: Record<string, string>, start: number, end: number, body: string}>, errors: Array<{line: number, column: number, message: string}>}}
|
|
9
|
+
*/
|
|
10
|
+
export function scanBlocks(source: string): {
|
|
11
|
+
blocks: Array<{
|
|
12
|
+
name: string;
|
|
13
|
+
title: string;
|
|
14
|
+
id: string;
|
|
15
|
+
classes: string[];
|
|
16
|
+
attributes: Record<string, string>;
|
|
17
|
+
start: number;
|
|
18
|
+
end: number;
|
|
19
|
+
body: string;
|
|
20
|
+
}>;
|
|
21
|
+
errors: Array<{
|
|
22
|
+
line: number;
|
|
23
|
+
column: number;
|
|
24
|
+
message: string;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Render named blocks for one publishing surface.
|
|
29
|
+
*
|
|
30
|
+
* `foundry` emits a `<section>` whose heading is its first line; `web` emits a
|
|
31
|
+
* `<details>` the reader opens. Neither carries an inline `style`.
|
|
32
|
+
*
|
|
33
|
+
* The body is left as Markdown between the wrapper's tags, each separated from
|
|
34
|
+
* its tag by a blank line — see the module docs for why that is what lets the
|
|
35
|
+
* surrounding render treat the body as real content rather than an opaque
|
|
36
|
+
* fragment.
|
|
37
|
+
*
|
|
38
|
+
* A finding does not stop the well-formed blocks around it from rendering.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} source - Markdown containing named blocks.
|
|
41
|
+
* @param {"foundry"|"web"} target - Publishing surface.
|
|
42
|
+
* @returns {{markdown: string, errors: Array<{line: number, column: number, message: string}>}}
|
|
43
|
+
*/
|
|
44
|
+
export function renderBlocks(source: string, target: "foundry" | "web"): {
|
|
45
|
+
markdown: string;
|
|
46
|
+
errors: Array<{
|
|
47
|
+
line: number;
|
|
48
|
+
column: number;
|
|
49
|
+
message: string;
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Wrap each withheld section in the disclosure a `secret` block renders as.
|
|
54
|
+
*
|
|
55
|
+
* The section's own Markdown is left as Markdown, with a blank line either side
|
|
56
|
+
* of it, so the page's renderer still reads it: the heading keeps its id, the
|
|
57
|
+
* prose keeps its links, and only the disclosure around them is written as HTML.
|
|
58
|
+
*
|
|
59
|
+
* **A spoiler, not access control.** The section is in the published page, so a
|
|
60
|
+
* reader who opens the element or reads the source reads it. Foundry is the one
|
|
61
|
+
* surface that withholds anything.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} source - A page's Markdown, headings intact.
|
|
64
|
+
* @returns {string} The same Markdown, each withheld section inside a
|
|
65
|
+
* `<details>`.
|
|
66
|
+
*/
|
|
67
|
+
export function renderWithheldSections(source: string): string;
|
|
68
|
+
/** The blocks an author may open, with the heading each takes by default. */
|
|
69
|
+
export const BLOCK_NAMES: Readonly<{
|
|
70
|
+
info: "Info";
|
|
71
|
+
secret: "Secret";
|
|
72
|
+
warn: "Warn";
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Blocks that may hold another named block.
|
|
76
|
+
*
|
|
77
|
+
* A box inside a GM-only section is a real thing to write — the section is a
|
|
78
|
+
* container for whatever the GM reads, boxes included — so a `secret` holds one
|
|
79
|
+
* and the box stays inside it. A box inside a box is noise, so `info` and `warn`
|
|
80
|
+
* hold no named block and a second opener inside one is a finding.
|
|
81
|
+
*
|
|
82
|
+
* Exported because a renderer has to know it: the body of a container is read
|
|
83
|
+
* for blocks of its own, and the body of a box is not.
|
|
84
|
+
*
|
|
85
|
+
* @type {readonly string[]}
|
|
86
|
+
*/
|
|
87
|
+
export const BLOCK_CONTAINERS: readonly string[];
|
|
@@ -45,6 +45,22 @@ export function resolveEmbed(index: object, embed: ParsedEmbed): {
|
|
|
45
45
|
target: string;
|
|
46
46
|
type?: string;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* The role an address's asset declares, read through the same resolution an
|
|
50
|
+
* embed's address takes.
|
|
51
|
+
*
|
|
52
|
+
* This is the lookup a `:::figure` fence's `map` counter reaches through —
|
|
53
|
+
* see {@link module:engine/content-figures.scanFigures}'s `resolveRole` — for
|
|
54
|
+
* an address still in its authored form, before {@link resolveEmbeds} has
|
|
55
|
+
* rewritten it into the ordinary image every surface renders.
|
|
56
|
+
*
|
|
57
|
+
* @param {object} index - From {@link module:engine/wikilinks.buildWikilinkIndex},
|
|
58
|
+
* or the equivalent the site and the book build.
|
|
59
|
+
* @param {string} address - The address as authored, inside `![[...]]`.
|
|
60
|
+
* @returns {string|undefined} The role, or `undefined` for a note's address,
|
|
61
|
+
* one that resolves nowhere, or a picture that declares none.
|
|
62
|
+
*/
|
|
63
|
+
export function embedRole(index: object, address: string): string | undefined;
|
|
48
64
|
/**
|
|
49
65
|
* What is wrong with one embed's directive or placement, if anything.
|
|
50
66
|
*
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/** Number a sequence of figures with counters shared across documents. */
|
|
2
|
+
export function numberFigures(figures: any, counts: any): any;
|
|
3
|
+
/**
|
|
4
|
+
* Read every `:::figure` fence in a body.
|
|
5
|
+
*
|
|
6
|
+
* SQL fences are expanded before this pass, so their output is a table.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} source - A note body with expanded tables.
|
|
9
|
+
* @param {object} [options] - Options.
|
|
10
|
+
* @param {(address: string) => string|undefined} [options.resolveRole] - From
|
|
11
|
+
* a picture's address to the role its asset declares, so a picture whose
|
|
12
|
+
* asset declares `role: map` counts as `map` rather than `figure`. Omitted,
|
|
13
|
+
* every picture counts as `figure` — the same reading a role other than
|
|
14
|
+
* `map` gets.
|
|
15
|
+
* @returns {{figures: Array<{id: string, slug: string, caption: string,
|
|
16
|
+
* hasCaption: boolean, classes: string[], kind: string, number: number,
|
|
17
|
+
* label: string, line: number, bodyStart: number, bodyEnd: number,
|
|
18
|
+
* captionStart: number, captionEnd: number, close: number}>,
|
|
19
|
+
* errors: Array<{line: number, column: number, message: string}>}}
|
|
20
|
+
*/
|
|
21
|
+
export function scanFigures(source: string, { resolveRole }?: {
|
|
22
|
+
resolveRole?: ((address: string) => string | undefined) | undefined;
|
|
23
|
+
}): {
|
|
24
|
+
figures: Array<{
|
|
25
|
+
id: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
caption: string;
|
|
28
|
+
hasCaption: boolean;
|
|
29
|
+
classes: string[];
|
|
30
|
+
kind: string;
|
|
31
|
+
number: number;
|
|
32
|
+
label: string;
|
|
33
|
+
line: number;
|
|
34
|
+
bodyStart: number;
|
|
35
|
+
bodyEnd: number;
|
|
36
|
+
captionStart: number;
|
|
37
|
+
captionEnd: number;
|
|
38
|
+
close: number;
|
|
39
|
+
}>;
|
|
40
|
+
errors: Array<{
|
|
41
|
+
line: number;
|
|
42
|
+
column: number;
|
|
43
|
+
message: string;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Render figure fences as HTML, leaving other Markdown untouched.
|
|
48
|
+
*
|
|
49
|
+
* A code, table or prose figure's contents are left as Markdown inside the
|
|
50
|
+
* wrapper, blank-line separated from its tags exactly as
|
|
51
|
+
* {@link module:engine/content-blocks.renderBlocks} leaves a named block's
|
|
52
|
+
* body — so the surrounding render sees it as part of its own document and a
|
|
53
|
+
* footnote reference inside it resolves against the note's own definitions.
|
|
54
|
+
*
|
|
55
|
+
* A figure's contents are rendered here rather than left for a later pass,
|
|
56
|
+
* because a picture-only fence has to become the surface's own `<figure>`
|
|
57
|
+
* markup directly inside the wrapper this function writes; the surrounding
|
|
58
|
+
* render never sees it as Markdown, so a footnote reference inside one is not
|
|
59
|
+
* resolved, the same gap a block's own title carries.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} source - A note body with expanded tables.
|
|
62
|
+
* @param {(markdown: string) => string} [renderMarkdown] - How to render a
|
|
63
|
+
* figure's own contents.
|
|
64
|
+
* @param {Array<{id: string, label: string}>} [numbers] - Labels assigned by a
|
|
65
|
+
* surface that counts across documents, matched by id.
|
|
66
|
+
* @param {object} [options] - Options.
|
|
67
|
+
* @param {(address: string) => string|undefined} [options.resolveRole] - See
|
|
68
|
+
* {@link scanFigures}.
|
|
69
|
+
* @returns {{markdown: string, errors: Array<{line: number, column: number, message: string}>}}
|
|
70
|
+
*/
|
|
71
|
+
export function renderFigureBlocks(source: string, renderMarkdown?: (markdown: string) => string, numbers?: Array<{
|
|
72
|
+
id: string;
|
|
73
|
+
label: string;
|
|
74
|
+
}>, { resolveRole }?: {
|
|
75
|
+
resolveRole?: ((address: string) => string | undefined) | undefined;
|
|
76
|
+
}): {
|
|
77
|
+
markdown: string;
|
|
78
|
+
errors: Array<{
|
|
79
|
+
line: number;
|
|
80
|
+
column: number;
|
|
81
|
+
message: string;
|
|
82
|
+
}>;
|
|
83
|
+
};
|
|
84
|
+
/** A figure's automatically determined kind, and the word that labels it. */
|
|
85
|
+
export const FIGURE_NAMES: Readonly<{
|
|
86
|
+
code: "Code";
|
|
87
|
+
table: "Table";
|
|
88
|
+
figure: "Figure";
|
|
89
|
+
map: "Map";
|
|
90
|
+
prose: "Prose";
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* The classes a figure takes.
|
|
94
|
+
*
|
|
95
|
+
* `.border` states that the captioned thing is drawn inside a border, and each
|
|
96
|
+
* medium owns what that means. The vocabulary is closed: a class absent from it
|
|
97
|
+
* is a finding naming the class.
|
|
98
|
+
*
|
|
99
|
+
* @type {readonly string[]}
|
|
100
|
+
*/
|
|
101
|
+
export const FIGURE_CLASSES: readonly string[];
|
|
@@ -8,3 +8,83 @@ export function separateFootnotes(source: string): {
|
|
|
8
8
|
markdown: string;
|
|
9
9
|
definitions: string;
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* A footnote definition written inside a list item or a block quote, where
|
|
13
|
+
* the web and Foundry can resolve it but the book drops it silently.
|
|
14
|
+
*
|
|
15
|
+
* A definition inside a table cell is not reported here: a table cell is
|
|
16
|
+
* inline content, so `[^id]:` there is never recognised as a definition on
|
|
17
|
+
* any surface and simply prints as written — the reference it was meant to
|
|
18
|
+
* answer is what {@link unresolvedFootnoteReferences} reports.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} source - A note's markdown body.
|
|
21
|
+
* @returns {Array<{line: number, column: number, label: string, message: string}>}
|
|
22
|
+
*/
|
|
23
|
+
export function misplacedFootnoteDefinitions(source: string): Array<{
|
|
24
|
+
line: number;
|
|
25
|
+
column: number;
|
|
26
|
+
label: string;
|
|
27
|
+
message: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* A footnote reference with no top-level definition to resolve against.
|
|
31
|
+
*
|
|
32
|
+
* Covers both commoner slips alike: a label never defined at all, and one
|
|
33
|
+
* "defined" only inside a table cell, which is inline content and never
|
|
34
|
+
* registers as a definition on any surface. A label misplaced in a list or a
|
|
35
|
+
* block quote is excluded — {@link misplacedFootnoteDefinitions} already
|
|
36
|
+
* reports that mistake at the definition's own line, and reporting it again
|
|
37
|
+
* at the reference would say the same thing twice.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} source - A note's markdown body.
|
|
40
|
+
* @param {string} [definitions] - Its top-level definitions, when a caller
|
|
41
|
+
* already extracted them with {@link separateFootnotes}. Derived from
|
|
42
|
+
* `source` when omitted; a caller already holding both passes its own
|
|
43
|
+
* extraction instead, so the two cannot disagree about what is defined.
|
|
44
|
+
* @returns {Array<{line: number, column: number, message: string}>}
|
|
45
|
+
*/
|
|
46
|
+
export function unresolvedFootnoteReferences(source: string, definitions?: string): Array<{
|
|
47
|
+
line: number;
|
|
48
|
+
column: number;
|
|
49
|
+
message: string;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* A top-level footnote definition no reference anywhere in the note uses.
|
|
53
|
+
*
|
|
54
|
+
* `separateFootnotes` lifts it out correctly, nothing resolves against it,
|
|
55
|
+
* and the paragraph it held vanishes from every surface with the build
|
|
56
|
+
* exiting 0 — a dropped paragraph is not something a reader can notice is
|
|
57
|
+
* missing, so it is an error here rather than a warning, the same severity
|
|
58
|
+
* every other silent loss this pass catches already carries. A note mid-edit,
|
|
59
|
+
* with the reference already deleted and the definition not yet followed, is
|
|
60
|
+
* exactly the case this refuses — which is the point: the alternative is
|
|
61
|
+
* shipping it.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} source - A note's markdown body.
|
|
64
|
+
* @returns {Array<{line: number, column: number, message: string}>}
|
|
65
|
+
*/
|
|
66
|
+
export function unusedFootnoteDefinitions(source: string): Array<{
|
|
67
|
+
line: number;
|
|
68
|
+
column: number;
|
|
69
|
+
message: string;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Every footnote placement finding for one note body — the union
|
|
73
|
+
* {@link misplacedFootnoteDefinitions}, {@link unresolvedFootnoteReferences}
|
|
74
|
+
* and {@link unusedFootnoteDefinitions} report, in document order.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} source - A note's markdown body.
|
|
77
|
+
* @returns {Array<{line: number, column: number, message: string}>}
|
|
78
|
+
*/
|
|
79
|
+
export function footnoteFindings(source: string): Array<{
|
|
80
|
+
line: number;
|
|
81
|
+
column: number;
|
|
82
|
+
message: string;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* A footnote reference's shape, wherever it is written — excluding a
|
|
86
|
+
* definition's own `[^id]:` opener, which this never matches.
|
|
87
|
+
*
|
|
88
|
+
* @type {RegExp}
|
|
89
|
+
*/
|
|
90
|
+
export const FOOTNOTE_REFERENCE: RegExp;
|
|
@@ -180,12 +180,14 @@ export function checkDeclaredFields({ format, itemFields, system, severity }: {
|
|
|
180
180
|
/**
|
|
181
181
|
* Top-level keys the format names as the note's own, whatever its type.
|
|
182
182
|
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
183
|
+
* The top-level vocabulary itself, read rather than restated: this set exists
|
|
184
|
+
* to keep a note's own identity fields from being mistaken for a misplaced
|
|
185
|
+
* `data` property where the two share a name, and the keys that are a note's
|
|
186
|
+
* own are exactly the ones the region declares. `type` and `subType` are the
|
|
187
|
+
* pair that matters — several mapping tables name `subType` as a shared source,
|
|
188
|
+
* and it is authored at top level by design. A key the region does *not*
|
|
189
|
+
* declare, such as `id` beside `data.id`, is reported as the misplaced `data`
|
|
190
|
+
* property it is.
|
|
189
191
|
*
|
|
190
192
|
* @type {ReadonlySet<string>}
|
|
191
193
|
*/
|