@heroiclands/package-build 0.6.1 → 3.0.1
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-content-build.md +965 -0
- package/CHANGELOG.md +68 -0
- package/CONTENT.md +824 -0
- package/MIGRATING.md +127 -0
- package/README.md +29 -17
- package/bin/content-build.mjs +1082 -0
- package/bin/package-build.mjs +2 -2
- package/bin/report.mjs +2 -2
- package/config.mjs +21 -18
- package/content-config.mjs +1424 -0
- package/coverage.mjs +1 -1
- package/e2e.mjs +1 -1
- package/engine/abbreviations.mjs +0 -0
- package/engine/base-compiler.mjs +608 -0
- package/engine/code-fences.mjs +311 -0
- package/engine/compendiums.mjs +353 -0
- package/engine/content-address.mjs +141 -0
- package/engine/content-links.mjs +438 -0
- package/engine/content-lint.mjs +204 -0
- package/engine/content-package.mjs +67 -0
- package/engine/content-slug.mjs +169 -0
- package/engine/content-tables.mjs +1216 -0
- package/engine/content-tree.mjs +56 -0
- package/engine/diagnostics.mjs +270 -0
- package/engine/field-reference.mjs +242 -0
- package/engine/field-spec.mjs +218 -0
- package/engine/foreign-catalog.mjs +450 -0
- package/engine/foreign-manifests.mjs +129 -0
- package/engine/frontmatter-lint.mjs +343 -0
- package/engine/frontmatter.mjs +258 -0
- package/engine/generate.mjs +305 -0
- package/engine/helpers.mjs +809 -0
- package/engine/ids.mjs +192 -0
- package/engine/index.mjs +142 -0
- package/engine/item-docs.mjs +153 -0
- package/engine/item-registry.mjs +129 -0
- package/engine/journals.mjs +374 -0
- package/engine/kb-manifest.mjs +473 -0
- package/engine/macros.mjs +333 -0
- package/engine/manifest-emit.mjs +339 -0
- package/engine/map-notes.mjs +1302 -0
- package/engine/pack-config.mjs +479 -0
- package/engine/pack-router.mjs +254 -0
- package/engine/prose-config.mjs +238 -0
- package/engine/prose-lint.mjs +294 -0
- package/engine/region-events.mjs +79 -0
- package/engine/scene-levels.mjs +420 -0
- package/engine/scenes.mjs +528 -0
- package/engine/site-build.mjs +778 -0
- package/engine/site-index.mjs +332 -0
- package/engine/web-wikilinks.mjs +330 -0
- package/engine/wikilink-syntax.mjs +105 -0
- package/engine/wikilinks.mjs +645 -0
- package/index.mjs +42 -25
- package/lang.mjs +1 -1
- package/manifest.mjs +79 -5
- package/markdownlint-config.mjs +45 -0
- package/package.json +78 -35
- package/prettier-config.mjs +34 -0
- package/sohl/actors.mjs +581 -0
- package/sohl/affiliation-standings.mjs +44 -0
- package/sohl/being-info.mjs +173 -0
- package/sohl/default-item-art.mjs +82 -0
- package/sohl/index.mjs +55 -0
- package/sohl/item-builders.mjs +114 -0
- package/sohl/item-fields.mjs +867 -0
- package/sohl/items.mjs +197 -0
- package/sohl/kb-passes.mjs +207 -0
- package/sohl/note-schemas.mjs +322 -0
- package/templates.mjs +1 -1
- package/types/config.d.mts +1 -1
- package/types/content-config.d.mts +571 -0
- package/types/engine/abbreviations.d.mts +44 -0
- package/types/engine/base-compiler.d.mts +320 -0
- package/types/engine/code-fences.d.mts +102 -0
- package/types/engine/compendiums.d.mts +77 -0
- package/types/engine/content-address.d.mts +61 -0
- package/types/engine/content-links.d.mts +87 -0
- package/types/engine/content-lint.d.mts +47 -0
- package/types/engine/content-package.d.mts +36 -0
- package/types/engine/content-slug.d.mts +59 -0
- package/types/engine/content-tables.d.mts +131 -0
- package/types/engine/content-tree.d.mts +12 -0
- package/types/engine/diagnostics.d.mts +152 -0
- package/types/engine/field-reference.d.mts +20 -0
- package/types/engine/field-spec.d.mts +181 -0
- package/types/engine/foreign-catalog.d.mts +103 -0
- package/types/engine/foreign-manifests.d.mts +43 -0
- package/types/engine/frontmatter-lint.d.mts +74 -0
- package/types/engine/frontmatter.d.mts +99 -0
- package/types/engine/generate.d.mts +56 -0
- package/types/engine/helpers.d.mts +348 -0
- package/types/engine/ids.d.mts +126 -0
- package/types/engine/index.d.mts +33 -0
- package/types/engine/item-docs.d.mts +73 -0
- package/types/engine/item-registry.d.mts +57 -0
- package/types/engine/journals.d.mts +121 -0
- package/types/engine/kb-manifest.d.mts +214 -0
- package/types/engine/macros.d.mts +201 -0
- package/types/engine/manifest-emit.d.mts +137 -0
- package/types/engine/map-notes.d.mts +283 -0
- package/types/engine/pack-config.d.mts +77 -0
- package/types/engine/pack-router.d.mts +53 -0
- package/types/engine/prose-config.d.mts +121 -0
- package/types/engine/prose-lint.d.mts +59 -0
- package/types/engine/region-events.d.mts +43 -0
- package/types/engine/scene-levels.d.mts +36 -0
- package/types/engine/scenes.d.mts +48 -0
- package/types/engine/site-build.d.mts +214 -0
- package/types/engine/site-index.d.mts +141 -0
- package/types/engine/web-wikilinks.d.mts +67 -0
- package/types/engine/wikilink-syntax.d.mts +101 -0
- package/types/engine/wikilinks.d.mts +172 -0
- package/types/index.d.mts +3 -0
- package/types/manifest.d.mts +52 -4
- package/types/markdownlint-config.d.mts +8 -0
- package/types/prettier-config.d.mts +1 -0
- package/types/sohl/actors.d.mts +65 -0
- package/types/sohl/affiliation-standings.d.mts +22 -0
- package/types/sohl/being-info.d.mts +78 -0
- package/types/sohl/default-item-art.d.mts +28 -0
- package/types/sohl/index.d.mts +7 -0
- package/types/sohl/item-builders.d.mts +11 -0
- package/types/sohl/item-fields.d.mts +20 -0
- package/types/sohl/items.d.mts +19 -0
- package/types/sohl/kb-passes.d.mts +71 -0
- package/types/sohl/note-schemas.d.mts +7 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate and normalize a content configuration.
|
|
3
|
+
*
|
|
4
|
+
* Every configuration reaches this function — a YAML one through the loader in
|
|
5
|
+
* `engine/pack-config.mjs`, an `.mjs` one by calling it itself — so that a
|
|
6
|
+
* malformed configuration fails at load with a message naming the offending
|
|
7
|
+
* field, rather than surfacing much later as an empty pack or a missing asset.
|
|
8
|
+
* The returned object is a deeply frozen **copy**: mutating the input
|
|
9
|
+
* afterwards cannot reach the configuration the build reads.
|
|
10
|
+
*
|
|
11
|
+
* @param {ContentBuildConfigInput} config The configuration to validate.
|
|
12
|
+
* @returns {ContentBuildConfig} The frozen, defaulted configuration.
|
|
13
|
+
* @throws {TypeError} If any field is missing, mistyped, or unrecognized.
|
|
14
|
+
*/
|
|
15
|
+
export function defineConfig(config: ContentBuildConfigInput): ContentBuildConfig;
|
|
16
|
+
/**
|
|
17
|
+
* The two kinds of Foundry package a content module can be built into. The
|
|
18
|
+
* value is also the directory Foundry installs the package under, which is why
|
|
19
|
+
* it is plural.
|
|
20
|
+
*
|
|
21
|
+
* @satisfies {readonly PackageKind[]}
|
|
22
|
+
*/
|
|
23
|
+
export const PACKAGE_KINDS: readonly ["systems", "modules"];
|
|
24
|
+
export namespace DEFAULT_PATHS {
|
|
25
|
+
let content: "assets/content";
|
|
26
|
+
let manifests: "assets/manifests";
|
|
27
|
+
let manifestOut: "build/manifests";
|
|
28
|
+
let packJson: "build/packs-json";
|
|
29
|
+
let stage: "build/stage/packs";
|
|
30
|
+
let unpack: "build/tmp/packs";
|
|
31
|
+
let foreignCache: "build/cache/foreign";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The Foundry document types a compendium pack may hold. This is the set the
|
|
35
|
+
* toolchain is able to compile a pack of; a document type Foundry supports but
|
|
36
|
+
* this toolchain does not compile is deliberately absent (see #1501 — playlists
|
|
37
|
+
* and roll tables are out of scope).
|
|
38
|
+
*
|
|
39
|
+
* @satisfies {readonly PackDocumentType[]}
|
|
40
|
+
*/
|
|
41
|
+
export const PACK_DOCUMENT_TYPES: readonly ["Actor", "Adventure", "Item", "JournalEntry", "Macro", "Scene"];
|
|
42
|
+
/**
|
|
43
|
+
* The landing-page rules a repository may route by.
|
|
44
|
+
*
|
|
45
|
+
* A *landing page* is a note that addresses a whole section rather than a page
|
|
46
|
+
* within one, so it has no slug of its own. Which note that is differs between
|
|
47
|
+
* repositories, and both live rules are represented here because switching
|
|
48
|
+
* either one on for the other repository moves addresses that are already
|
|
49
|
+
* published:
|
|
50
|
+
*
|
|
51
|
+
* - `readme` — a `README.md` **is** its section's landing page. This is `sohl`'s
|
|
52
|
+
* rule, and a `doc` note routes by its `category` like any other, so `sohl`'s
|
|
53
|
+
* eleven `category: collection` notes publish under a literal `collection/`
|
|
54
|
+
* section (`kb/collection/skills/`).
|
|
55
|
+
* - `collection` — a `doc` note whose `category` is `collection` addresses the
|
|
56
|
+
* section it introduces, named by its authored `section`. This is `thalorna`'s
|
|
57
|
+
* rule, under which the same note publishes at `creature/`.
|
|
58
|
+
*
|
|
59
|
+
* The two are not disjoint and cannot simply both apply: each tree holds notes
|
|
60
|
+
* the other rule would move.
|
|
61
|
+
*
|
|
62
|
+
* @type {readonly string[]}
|
|
63
|
+
*/
|
|
64
|
+
export const LANDING_RULES: readonly string[];
|
|
65
|
+
/**
|
|
66
|
+
* A repository's address scheme, with the defaults an unconfigured one gets.
|
|
67
|
+
*
|
|
68
|
+
* `prefix` is where the content tree mounts *inside the package* — `"kb/"` for
|
|
69
|
+
* `sohl`, whose knowledgebase is one surface among several, and empty for
|
|
70
|
+
* `thalorna`, whose site is nothing but its content. It is not the package's
|
|
71
|
+
* own mount point: where the package itself is served is the consuming build's
|
|
72
|
+
* knowledge, held in `PACKAGE_BASE` (`engine/kb-manifest.mjs`) and prefixed at
|
|
73
|
+
* resolve time, so it is never recorded here (#1465).
|
|
74
|
+
*/
|
|
75
|
+
export const DEFAULT_ADDRESS_SCHEME: Readonly<{
|
|
76
|
+
prefix: "";
|
|
77
|
+
landing: "readme";
|
|
78
|
+
}>;
|
|
79
|
+
export type PackageKind = "systems" | "modules";
|
|
80
|
+
export type PackDocumentType = "Actor" | "Adventure" | "Item" | "JournalEntry" | "Macro" | "Scene";
|
|
81
|
+
/**
|
|
82
|
+
* One compendium pack the build compiles, named exactly as it is declared in
|
|
83
|
+
* the package manifest's `packs` array.
|
|
84
|
+
*
|
|
85
|
+
* Several packs may share a `type`. The `type` selects the **compiler** that
|
|
86
|
+
* fills the pack; a note's `pack:` frontmatter selects **which pack of that
|
|
87
|
+
* type** receives its document. The two are orthogonal, and both are needed
|
|
88
|
+
* once a repository groups same-type documents editorially — which it may have
|
|
89
|
+
* to, since a compendium UUID carries its pack name and collapsing such a
|
|
90
|
+
* layout breaks every stored reference (#1566).
|
|
91
|
+
*/
|
|
92
|
+
export type PackSpec = {
|
|
93
|
+
/**
|
|
94
|
+
* Pack name — the manifest `name`, and the
|
|
95
|
+
* directory under `packs/`.
|
|
96
|
+
*/
|
|
97
|
+
name: string;
|
|
98
|
+
/**
|
|
99
|
+
* Foundry document type the pack holds.
|
|
100
|
+
*/
|
|
101
|
+
type: PackDocumentType;
|
|
102
|
+
/**
|
|
103
|
+
* Human-readable label. Defaults to `name`.
|
|
104
|
+
*/
|
|
105
|
+
label?: string | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Whether the pack is GM-only. Default `false`.
|
|
108
|
+
*/
|
|
109
|
+
private?: boolean | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* The pack's folder-hierarchy file, relative
|
|
112
|
+
* to `paths.content`. Default `null` — no
|
|
113
|
+
* folder documents are emitted.
|
|
114
|
+
*/
|
|
115
|
+
folders?: string | null | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Packs written by this pack's own compiler
|
|
118
|
+
* pass rather than a pass of their own (the
|
|
119
|
+
* scenes pass also emits the adventures
|
|
120
|
+
* bundling them). Default `[]`.
|
|
121
|
+
*/
|
|
122
|
+
companions?: PackSpec[] | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Whether a pass compiling zero entries is
|
|
125
|
+
* legitimate rather than a build failure.
|
|
126
|
+
* Default `false`.
|
|
127
|
+
*/
|
|
128
|
+
mayBeEmpty?: boolean | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Whether this is the pack of its `type`
|
|
131
|
+
* that receives notes declaring no `pack:`
|
|
132
|
+
* of their own. Default `false`. A type
|
|
133
|
+
* with exactly one pack is its default
|
|
134
|
+
* implicitly; a type with several and no
|
|
135
|
+
* `default: true` requires every note of
|
|
136
|
+
* that type to declare one. Not permitted
|
|
137
|
+
* on a companion — no note is routed into
|
|
138
|
+
* one. See `engine/pack-router.mjs`.
|
|
139
|
+
*/
|
|
140
|
+
default?: boolean | undefined;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* The normalized form of a {@link PackSpec}: every optional half filled in.
|
|
144
|
+
*/
|
|
145
|
+
export type ResolvedPackSpec = {
|
|
146
|
+
name: string;
|
|
147
|
+
type: PackDocumentType;
|
|
148
|
+
label: string;
|
|
149
|
+
private: boolean;
|
|
150
|
+
folders: string | null;
|
|
151
|
+
companions: readonly Readonly<ResolvedPackSpec>[];
|
|
152
|
+
mayBeEmpty: boolean;
|
|
153
|
+
default: boolean;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* The directories a consumer may relocate, each relative to `rootDir`.
|
|
157
|
+
*/
|
|
158
|
+
export type PathsInput = {
|
|
159
|
+
/**
|
|
160
|
+
* Content tree root.
|
|
161
|
+
*/
|
|
162
|
+
content?: string | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Vendored cross-package link manifests,
|
|
165
|
+
* read by `links`. Inbound.
|
|
166
|
+
*/
|
|
167
|
+
manifests?: string | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* Where `manifest` writes this package's
|
|
170
|
+
* own link manifest. Outbound, and a
|
|
171
|
+
* build artifact — the published copy is
|
|
172
|
+
* the one a consumer vendors into its
|
|
173
|
+
* `manifests` directory.
|
|
174
|
+
*/
|
|
175
|
+
manifestOut?: string | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Build-only per-entry JSON intermediate.
|
|
178
|
+
*/
|
|
179
|
+
packJson?: string | undefined;
|
|
180
|
+
/**
|
|
181
|
+
* Compiled LevelDB packs.
|
|
182
|
+
*/
|
|
183
|
+
stage?: string | undefined;
|
|
184
|
+
/**
|
|
185
|
+
* Where `unpack` extracts JSON back to.
|
|
186
|
+
*/
|
|
187
|
+
unpack?: string | undefined;
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* {@link PathsInput}, resolved to absolute paths against `rootDir`.
|
|
191
|
+
*/
|
|
192
|
+
export type ResolvedPaths = {
|
|
193
|
+
content: string;
|
|
194
|
+
manifests: string;
|
|
195
|
+
manifestOut: string;
|
|
196
|
+
packJson: string;
|
|
197
|
+
stage: string;
|
|
198
|
+
unpack: string;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* The identity every compiled document's `_stats` block carries.
|
|
202
|
+
*
|
|
203
|
+
* `coreVersion` is **not** here: it is the top-level `compatibility.minimum`,
|
|
204
|
+
* so the floor is declared in one place and stamped from it.
|
|
205
|
+
*/
|
|
206
|
+
export type StatsSpec = {
|
|
207
|
+
/**
|
|
208
|
+
* The game system the documents are for —
|
|
209
|
+
* `"sohl"` even for a module, which ships
|
|
210
|
+
* content *for* the system rather than being it.
|
|
211
|
+
*/
|
|
212
|
+
systemId: string;
|
|
213
|
+
/**
|
|
214
|
+
* The system version the packs were built against.
|
|
215
|
+
*/
|
|
216
|
+
systemVersion: string;
|
|
217
|
+
/**
|
|
218
|
+
* The 16-character id stamped as the author.
|
|
219
|
+
*/
|
|
220
|
+
lastModifiedBy: string;
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* The section of the configuration belonging to `@heroiclands/package-build`.
|
|
224
|
+
*
|
|
225
|
+
* **Opaque here, on purpose.** One repository describes itself in one file, so
|
|
226
|
+
* the two shared build packages share it — but they split by *input*, and
|
|
227
|
+
* neither should learn the other's schema. This validator checks only that the
|
|
228
|
+
* section is a mapping and hands it back frozen; package-build validates what
|
|
229
|
+
* is inside it, exactly as this module validates the keys around it.
|
|
230
|
+
*
|
|
231
|
+
* That is also why it is a section rather than a scatter of top-level keys: one
|
|
232
|
+
* reserved name keeps {@link ContentBuildConfig}'s unknown-key guard intact for
|
|
233
|
+
* everything else, which is the guard that catches a typo'd `packs` before it
|
|
234
|
+
* becomes an empty compendium.
|
|
235
|
+
*
|
|
236
|
+
* The values package-build needs that are *not* in here — `packageKind`,
|
|
237
|
+
* `foundryPackage` — it reads from the top level, where they already are. They
|
|
238
|
+
* were duplicated in each consumer's deploy script until this existed, which is
|
|
239
|
+
* two places for one fact.
|
|
240
|
+
*/
|
|
241
|
+
export type PackageBuildSection = Record<string, unknown>;
|
|
242
|
+
/**
|
|
243
|
+
* The two manifest switches. A package may publish a link manifest, consume
|
|
244
|
+
* other packages' manifests, both, or neither — the four combinations are all
|
|
245
|
+
* real (see #1385/#1446: `kethira` consumes but never publishes).
|
|
246
|
+
*/
|
|
247
|
+
export type ManifestSwitches = {
|
|
248
|
+
/**
|
|
249
|
+
* Emit this package's link manifest.
|
|
250
|
+
*/
|
|
251
|
+
publish: boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Resolve cross-package links through vendored manifests.
|
|
254
|
+
*/
|
|
255
|
+
consume: boolean;
|
|
256
|
+
};
|
|
257
|
+
export type PublishSwitches = {
|
|
258
|
+
/**
|
|
259
|
+
* Render this package's knowledgebase/site pages.
|
|
260
|
+
*/
|
|
261
|
+
site: boolean;
|
|
262
|
+
manifests: ManifestSwitches;
|
|
263
|
+
};
|
|
264
|
+
export type ManifestSwitchesInput = {
|
|
265
|
+
publish?: boolean | undefined;
|
|
266
|
+
consume?: boolean | undefined;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* The **Foundry core** version range this package supports.
|
|
270
|
+
*
|
|
271
|
+
* `minimum` is stamped into every compiled document as `_stats.coreVersion`, so
|
|
272
|
+
* a document never claims to predate the migrations that would rewrite it.
|
|
273
|
+
*
|
|
274
|
+
* `verified` names the newest build the full suite has **actually passed** —
|
|
275
|
+
* never an aspiration. Moving this out of the hand-authored manifest and into a
|
|
276
|
+
* configuration file does not soften that; if anything it makes the claim
|
|
277
|
+
* easier to edit casually, so it is written down here beside the key rather
|
|
278
|
+
* than left behind in the template.
|
|
279
|
+
*
|
|
280
|
+
* Not to be confused with `relationships.systems[].compatibility`, which is the
|
|
281
|
+
* **game system's** version range. Same key, different subject.
|
|
282
|
+
*/
|
|
283
|
+
export type CompatibilitySpec = {
|
|
284
|
+
/**
|
|
285
|
+
* Oldest Foundry core this package supports.
|
|
286
|
+
*/
|
|
287
|
+
minimum: string;
|
|
288
|
+
/**
|
|
289
|
+
* Newest Foundry core the suite has passed on.
|
|
290
|
+
*/
|
|
291
|
+
verified?: string | undefined;
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* What this package declares about other packages, in Foundry's own shape.
|
|
295
|
+
*
|
|
296
|
+
* Passed through to the shipped manifest, and read here for one derivation: a
|
|
297
|
+
* module's `_stats.systemVersion` comes from the `verified` field of the system
|
|
298
|
+
* it declares a relationship with, because a module's own `package.json`
|
|
299
|
+
* version is the *module's* and stamping it would claim a system version that
|
|
300
|
+
* never existed.
|
|
301
|
+
*/
|
|
302
|
+
export type Relationships = {
|
|
303
|
+
/**
|
|
304
|
+
* Game systems this package targets.
|
|
305
|
+
*/
|
|
306
|
+
systems?: RelationshipSpec[] | undefined;
|
|
307
|
+
/**
|
|
308
|
+
* Packages this one needs.
|
|
309
|
+
*/
|
|
310
|
+
requires?: RelationshipSpec[] | undefined;
|
|
311
|
+
/**
|
|
312
|
+
* Packages it works well with.
|
|
313
|
+
*/
|
|
314
|
+
recommends?: RelationshipSpec[] | undefined;
|
|
315
|
+
/**
|
|
316
|
+
* Packages it cannot run beside.
|
|
317
|
+
*/
|
|
318
|
+
conflicts?: RelationshipSpec[] | undefined;
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* One declared relationship.
|
|
322
|
+
*/
|
|
323
|
+
export type RelationshipSpec = {
|
|
324
|
+
/**
|
|
325
|
+
* The other package's id.
|
|
326
|
+
*/
|
|
327
|
+
id: string;
|
|
328
|
+
/**
|
|
329
|
+
* `system`, `module`, or `world`.
|
|
330
|
+
*/
|
|
331
|
+
type?: string | undefined;
|
|
332
|
+
/**
|
|
333
|
+
* Where its manifest is published.
|
|
334
|
+
*/
|
|
335
|
+
manifest?: string | undefined;
|
|
336
|
+
/**
|
|
337
|
+
* The version range of *that*
|
|
338
|
+
* package this one targets — for a system
|
|
339
|
+
* relationship, `verified` is what
|
|
340
|
+
* `_stats.systemVersion` is stamped from.
|
|
341
|
+
*/
|
|
342
|
+
compatibility?: CompatibilitySpec | undefined;
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* How a generated documentation page is framed in the repository publishing it.
|
|
346
|
+
*
|
|
347
|
+
* The tables come from the `itemBuilders` registry and are the same wherever
|
|
348
|
+
* they are rendered. Everything around them is the consumer's: the heading, the
|
|
349
|
+
* "See also" line its section's pages carry, the orientation a reader needs
|
|
350
|
+
* before the tables start, and where the page is filed. Those were the reason
|
|
351
|
+
* every consumer wrapped the renderer in a script of its own.
|
|
352
|
+
*/
|
|
353
|
+
export type DocPageSpec = {
|
|
354
|
+
/**
|
|
355
|
+
* The page's H1.
|
|
356
|
+
*/
|
|
357
|
+
title?: string | undefined;
|
|
358
|
+
/**
|
|
359
|
+
* Where to write it, relative to `rootDir`.
|
|
360
|
+
* Without it the page goes to stdout.
|
|
361
|
+
*/
|
|
362
|
+
out?: string | undefined;
|
|
363
|
+
/**
|
|
364
|
+
* Lines between the generated banner and the
|
|
365
|
+
* first table. Markdown, emitted verbatim.
|
|
366
|
+
*/
|
|
367
|
+
preamble?: string[] | undefined;
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* The documentation pages this repository generates.
|
|
371
|
+
*/
|
|
372
|
+
export type DocsSpec = {
|
|
373
|
+
/**
|
|
374
|
+
* The item-frontmatter reference,
|
|
375
|
+
* rendered by `content-build docs
|
|
376
|
+
* item-fields`.
|
|
377
|
+
*/
|
|
378
|
+
itemFields?: DocPageSpec | undefined;
|
|
379
|
+
};
|
|
380
|
+
export type PublishSwitchesInput = {
|
|
381
|
+
site?: boolean | undefined;
|
|
382
|
+
manifests?: ManifestSwitchesInput | undefined;
|
|
383
|
+
};
|
|
384
|
+
/**
|
|
385
|
+
* One entry of a consumer's `itemBuilders` registry.
|
|
386
|
+
*
|
|
387
|
+
* Either a bare builder function, or that builder paired with the type's
|
|
388
|
+
* default art and the frontmatter fields it declares. See
|
|
389
|
+
* {@link normalizeItemBuilders} for why the paired form exists.
|
|
390
|
+
*
|
|
391
|
+
* `fields` is what makes the type documentable: a builder function says
|
|
392
|
+
* nothing about the vocabulary it consumes, so a consumer that declares its
|
|
393
|
+
* fields can generate its own authoring reference and check its own notes,
|
|
394
|
+
* while one that does not is simply undocumented rather than broken (#22).
|
|
395
|
+
*/
|
|
396
|
+
export type ItemBuilderEntry = ((fm: object) => object) | {
|
|
397
|
+
system: (fm: object) => object;
|
|
398
|
+
img?: string;
|
|
399
|
+
fields?: readonly object[];
|
|
400
|
+
};
|
|
401
|
+
/**
|
|
402
|
+
* The configuration a consumer writes.
|
|
403
|
+
*/
|
|
404
|
+
export type ContentBuildConfigInput = {
|
|
405
|
+
/**
|
|
406
|
+
* Absolute path of the consuming
|
|
407
|
+
* repository — every configured path is
|
|
408
|
+
* resolved against it, so the build never
|
|
409
|
+
* depends on the working directory.
|
|
410
|
+
*/
|
|
411
|
+
rootDir: string;
|
|
412
|
+
/**
|
|
413
|
+
* Content package name — the value each
|
|
414
|
+
* content note carries in its `package:`
|
|
415
|
+
* frontmatter.
|
|
416
|
+
*/
|
|
417
|
+
contentPackage: string;
|
|
418
|
+
/**
|
|
419
|
+
* Foundry package id, as it appears in
|
|
420
|
+
* `system.json` / `module.json`.
|
|
421
|
+
*/
|
|
422
|
+
foundryPackage: string;
|
|
423
|
+
/**
|
|
424
|
+
* Whether the package is a system or a module.
|
|
425
|
+
*/
|
|
426
|
+
packageKind: PackageKind;
|
|
427
|
+
/**
|
|
428
|
+
* Identity stamped into every document's `_stats`.
|
|
429
|
+
*/
|
|
430
|
+
stats: StatsSpec;
|
|
431
|
+
/**
|
|
432
|
+
* The consumer's
|
|
433
|
+
* item-type registry: each content `type`
|
|
434
|
+
* that compiles into an Item, paired with
|
|
435
|
+
* the builder producing its `system` block
|
|
436
|
+
* — and, optionally, the default art a
|
|
437
|
+
* note of that type gets when it sets no
|
|
438
|
+
* `img:` of its own. Default `{}` — a
|
|
439
|
+
* content module that ships no items
|
|
440
|
+
* declares none.
|
|
441
|
+
*/
|
|
442
|
+
itemBuilders?: Record<string, ItemBuilderEntry> | undefined;
|
|
443
|
+
/**
|
|
444
|
+
* Packs to compile. More than one entry
|
|
445
|
+
* may share a `type`: a note then names
|
|
446
|
+
* the pack it belongs in with its
|
|
447
|
+
* `pack:` frontmatter, and one pack of
|
|
448
|
+
* the type is marked `default: true` to
|
|
449
|
+
* receive the notes that name none
|
|
450
|
+
* (#1566).
|
|
451
|
+
*/
|
|
452
|
+
packs: PackSpec[];
|
|
453
|
+
/**
|
|
454
|
+
* Layout overrides. See {@link DEFAULT_PATHS}.
|
|
455
|
+
*/
|
|
456
|
+
paths?: PathsInput | undefined;
|
|
457
|
+
/**
|
|
458
|
+
* Directory names the content walk ignores
|
|
459
|
+
* wherever they appear (e.g. Obsidian's
|
|
460
|
+
* `Templates`). Default `[]`.
|
|
461
|
+
*/
|
|
462
|
+
skipDirectories?: string[] | undefined;
|
|
463
|
+
/**
|
|
464
|
+
* Reserved for
|
|
465
|
+
* `@heroiclands/package-build`, which
|
|
466
|
+
* validates it. Not read here.
|
|
467
|
+
*/
|
|
468
|
+
packageBuild?: PackageBuildSection | undefined;
|
|
469
|
+
/**
|
|
470
|
+
* How this repository frames the
|
|
471
|
+
* documentation pages it generates.
|
|
472
|
+
*/
|
|
473
|
+
docs?: DocsSpec | undefined;
|
|
474
|
+
/**
|
|
475
|
+
* The Foundry core range this
|
|
476
|
+
* package supports. Required for any
|
|
477
|
+
* repository that ships one — reading
|
|
478
|
+
* the floor throws without it — and
|
|
479
|
+
* absent for a content-only consumer,
|
|
480
|
+
* which has none to invent.
|
|
481
|
+
*/
|
|
482
|
+
compatibility?: CompatibilitySpec | undefined;
|
|
483
|
+
/**
|
|
484
|
+
* What this package declares about
|
|
485
|
+
* others, in Foundry's own shape.
|
|
486
|
+
*/
|
|
487
|
+
relationships?: Relationships | undefined;
|
|
488
|
+
/**
|
|
489
|
+
* Publishing switches. Each defaults to off.
|
|
490
|
+
*/
|
|
491
|
+
publish?: PublishSwitchesInput | undefined;
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* The normalized, frozen configuration the toolchain reads.
|
|
495
|
+
*/
|
|
496
|
+
export type ContentBuildConfig = {
|
|
497
|
+
rootDir: string;
|
|
498
|
+
contentPackage: string;
|
|
499
|
+
foundryPackage: string;
|
|
500
|
+
packageKind: PackageKind;
|
|
501
|
+
/**
|
|
502
|
+
* Derived: the served Foundry asset root,
|
|
503
|
+
* `<packageKind>/<foundryPackage>/assets`.
|
|
504
|
+
*/
|
|
505
|
+
assetRoot: string;
|
|
506
|
+
paths: Readonly<ResolvedPaths>;
|
|
507
|
+
stats: Readonly<StatsSpec>;
|
|
508
|
+
/**
|
|
509
|
+
* Derived: the
|
|
510
|
+
* `system` builder of each entry, whichever
|
|
511
|
+
* of the two spellings declared it.
|
|
512
|
+
*/
|
|
513
|
+
itemBuilders: Readonly<Record<string, Function>>;
|
|
514
|
+
/**
|
|
515
|
+
* Derived: the default art
|
|
516
|
+
* of each entry that paired one. Sparse — a
|
|
517
|
+
* type absent here has no default, and a note
|
|
518
|
+
* of it must carry `img:` (#7).
|
|
519
|
+
*/
|
|
520
|
+
itemArt: Readonly<Record<string, string>>;
|
|
521
|
+
/**
|
|
522
|
+
* Derived:
|
|
523
|
+
* the frontmatter fields each entry
|
|
524
|
+
* declared. Sparse, like `itemArt` — a type
|
|
525
|
+
* absent here compiles normally and is
|
|
526
|
+
* simply undocumented (#22).
|
|
527
|
+
*/
|
|
528
|
+
itemFields: Readonly<Record<string, readonly object[]>>;
|
|
529
|
+
/**
|
|
530
|
+
* Derived: the keys of
|
|
531
|
+
* {@link ContentBuildConfigInput.itemBuilders},
|
|
532
|
+
* so the accepted item types and the builder
|
|
533
|
+
* table are one list (#1504).
|
|
534
|
+
*/
|
|
535
|
+
itemTypes: ReadonlySet<string>;
|
|
536
|
+
/**
|
|
537
|
+
* Derived: every type whose prose
|
|
538
|
+
* compiles into a JournalEntry of its own —
|
|
539
|
+
* the item types, plus `macro`, plus the map
|
|
540
|
+
* types. The one set the compilers and the
|
|
541
|
+
* link-manifest emitter both read.
|
|
542
|
+
*/
|
|
543
|
+
docEntryTypes: ReadonlySet<string>;
|
|
544
|
+
skipDirectories: readonly string[];
|
|
545
|
+
packs: readonly Readonly<ResolvedPackSpec>[];
|
|
546
|
+
/**
|
|
547
|
+
* Derived: every pack directory
|
|
548
|
+
* the build produces, in compile order —
|
|
549
|
+
* each pack followed by its companions.
|
|
550
|
+
*/
|
|
551
|
+
packDirectories: readonly string[];
|
|
552
|
+
/**
|
|
553
|
+
* Passed through
|
|
554
|
+
* frozen, uninterpreted. `{}` when absent.
|
|
555
|
+
*/
|
|
556
|
+
packageBuild: Readonly<PackageBuildSection>;
|
|
557
|
+
/**
|
|
558
|
+
* Frozen; `{}` when absent.
|
|
559
|
+
*/
|
|
560
|
+
docs: Readonly<DocsSpec>;
|
|
561
|
+
/**
|
|
562
|
+
* The Foundry core
|
|
563
|
+
* range, or `null` when none is declared.
|
|
564
|
+
*/
|
|
565
|
+
compatibility: Readonly<CompatibilitySpec> | null;
|
|
566
|
+
/**
|
|
567
|
+
* Frozen; `{}` when absent.
|
|
568
|
+
*/
|
|
569
|
+
relationships: Readonly<Relationships>;
|
|
570
|
+
publish: Readonly<PublishSwitches>;
|
|
571
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace whole words with their abbreviations.
|
|
3
|
+
*
|
|
4
|
+
* Greedy and longest-first: at each position the longest run of tokens that
|
|
5
|
+
* names an entry wins, so `tribunus militum` never abbreviates as
|
|
6
|
+
* `trib militum`, and `countess` is never reached by `count`'s rule.
|
|
7
|
+
*
|
|
8
|
+
* @param {readonly string[]} tokens - Lowercased, alphanumeric-only tokens.
|
|
9
|
+
* @returns {string[]} The tokens, with each matched run replaced by one token.
|
|
10
|
+
*/
|
|
11
|
+
export function abbreviateTokens(tokens: readonly string[]): string[];
|
|
12
|
+
/**
|
|
13
|
+
* The abbreviations a slug may use to stay short.
|
|
14
|
+
*
|
|
15
|
+
* Names in this setting are long and formulaic — a rank, an office, a material,
|
|
16
|
+
* a unit — so a slug built from one runs to a mouthful that says little more
|
|
17
|
+
* than a short one would. These are the conventional shortenings for that
|
|
18
|
+
* vocabulary.
|
|
19
|
+
*
|
|
20
|
+
* **Whole words only.** `count` abbreviates, `countess` does not become
|
|
21
|
+
* `ctess`: it has its own entry. Matching is greedy and longest-first, so a
|
|
22
|
+
* multi-word phrase wins over its own first word — `tribunus militum` is
|
|
23
|
+
* `tribmil`, a bare `tribunus` is `trib` — and a longer word wins over a
|
|
24
|
+
* shorter one that prefixes it.
|
|
25
|
+
*
|
|
26
|
+
* **Abbreviations are not unique, and that is the caller's problem.** Several
|
|
27
|
+
* words share one: `abbess` and `abbot` are both `abb`, `monk` and `brother`
|
|
28
|
+
* both `br`, `emperor` and `empress` both `emp`. Two names that differ only in
|
|
29
|
+
* such a word therefore slug alike, which for a URL is a collision — the
|
|
30
|
+
* build's existing slug-collision guard is what catches it, and the fix is a
|
|
31
|
+
* more specific name.
|
|
32
|
+
*
|
|
33
|
+
* @module
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Word (or phrase) → abbreviation.
|
|
37
|
+
*
|
|
38
|
+
* Keys are lowercase and space-separated as they read; a hyphenated key like
|
|
39
|
+
* `shire-reeve` is stored with its hyphen because that is how the word is
|
|
40
|
+
* written, and the matcher tokenises the same way it tokenises a name.
|
|
41
|
+
*
|
|
42
|
+
* @type {Readonly<Record<string, string>>}
|
|
43
|
+
*/
|
|
44
|
+
export const ABBREVIATIONS: Readonly<Record<string, string>>;
|