@heroiclands/package-build 0.6.1 → 3.0.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-content-build.md +965 -0
- package/CHANGELOG.md +58 -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,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a content note's type compiles into a Scene.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} [type] - The note's `type` frontmatter.
|
|
5
|
+
* @returns {boolean} True for a map type.
|
|
6
|
+
*/
|
|
7
|
+
export function isMapType(type?: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* The canvas profile for a map type.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} type - The note's `type`.
|
|
12
|
+
* @returns {object} The profile from {@link MAP_TYPE_PROFILES}.
|
|
13
|
+
* @throws {Error} When the type is not a map type — the build's fail-fast
|
|
14
|
+
* contract, so a typo never ships a scene with Foundry's own defaults.
|
|
15
|
+
*/
|
|
16
|
+
export function mapProfile(type: string): object;
|
|
17
|
+
/**
|
|
18
|
+
* The id of one region within its scene.
|
|
19
|
+
*
|
|
20
|
+
* Derived rather than stored so a cross-reference (`teleportToken`,
|
|
21
|
+
* `toggleBehavior`) can be resolved to a UUID before the target scene has been
|
|
22
|
+
* compiled. An authored `_id` always wins — the converter pins ids on
|
|
23
|
+
* write-back exactly as it does for items and actors.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} sceneId - The owning scene's `_id`.
|
|
26
|
+
* @param {string} key - The region's authored key.
|
|
27
|
+
* @param {string} [pinned] - An authored `_id`, if any.
|
|
28
|
+
* @returns {string} A 16-character Foundry id.
|
|
29
|
+
*/
|
|
30
|
+
export function regionDocId(sceneId: string, key: string, pinned?: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* The id of one behaviour within its region.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} regionId - The owning region's `_id`.
|
|
35
|
+
* @param {string} key - The behaviour's authored key.
|
|
36
|
+
* @param {string} [pinned] - An authored `_id`, if any.
|
|
37
|
+
* @returns {string} A 16-character Foundry id.
|
|
38
|
+
*/
|
|
39
|
+
export function behaviorDocId(regionId: string, key: string, pinned?: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* A region's highlight colour, derived from its key.
|
|
42
|
+
*
|
|
43
|
+
* Foundry's default is `Color.fromHSV([Math.random(), 0.8, 0.8])` — a different
|
|
44
|
+
* value on every create, which would make each build's output differ from the
|
|
45
|
+
* last for no reason anyone could see. Hashing the key keeps builds
|
|
46
|
+
* reproducible and diffs quiet, in the same hue/saturation family Foundry
|
|
47
|
+
* itself would have chosen, and keeps the value out of the note entirely.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} key - The region's authored key.
|
|
50
|
+
* @returns {string} A CSS hex colour.
|
|
51
|
+
*/
|
|
52
|
+
export function regionColor(key: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* The map's own measurements, from which both unit lints are derived.
|
|
55
|
+
*
|
|
56
|
+
* @typedef {object} MapGeometry
|
|
57
|
+
* @property {string} label - The authored key, for error messages.
|
|
58
|
+
* @property {number} pxPerGrid - Pixels per grid square.
|
|
59
|
+
* @property {number[]} dimensions - `[width, height]` in pixels.
|
|
60
|
+
*/
|
|
61
|
+
/**
|
|
62
|
+
* Reject geometry authored in grid squares where pixels belong.
|
|
63
|
+
*
|
|
64
|
+
* A grid-valued wall or region is not rejected by Foundry: it becomes a
|
|
65
|
+
* 12x11-pixel feature in the top-left corner, invisible on the map and
|
|
66
|
+
* impossible to notice in a diff. The test is derived from the map itself
|
|
67
|
+
* rather than a magic number — when every coordinate of one feature is smaller
|
|
68
|
+
* than a single grid square, on a map several squares across, the author
|
|
69
|
+
* counted squares.
|
|
70
|
+
*
|
|
71
|
+
* @param {number[]} coords - The feature's coordinates, in pixels.
|
|
72
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
73
|
+
* @throws {Error} When the coordinates read as grid units.
|
|
74
|
+
*/
|
|
75
|
+
export function assertPixelGeometry(coords: number[], geom: MapGeometry): void;
|
|
76
|
+
/**
|
|
77
|
+
* Reject a map pin authored in pixels where grid squares belong.
|
|
78
|
+
*
|
|
79
|
+
* @param {number[]} at - The pin's `[x, y]`, in grid squares.
|
|
80
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
81
|
+
* @throws {Error} When the coordinates read as pixels.
|
|
82
|
+
*/
|
|
83
|
+
export function assertGridLocation(at: number[], geom: MapGeometry): void;
|
|
84
|
+
/**
|
|
85
|
+
* Compile a wall's `blocks:` / `limits:` lists into Foundry's four numeric
|
|
86
|
+
* restriction fields.
|
|
87
|
+
*
|
|
88
|
+
* The authored vocabulary is deliberately not Foundry's.
|
|
89
|
+
* `WALL_MOVEMENT_TYPES.NONE` means movement does **not** collide — i.e.
|
|
90
|
+
* passable — so `movement: none` reads as the exact opposite of what it does.
|
|
91
|
+
* `blocks:` says what the wall stops and `limits:` what it merely attenuates;
|
|
92
|
+
* anything unnamed is passable.
|
|
93
|
+
*
|
|
94
|
+
* @param {{blocks?: string[], limits?: string[]}} spec - The authored lists.
|
|
95
|
+
* @param {string} label - The authored key, for error messages.
|
|
96
|
+
* @returns {{move: number, sight: number, light: number, sound: number}} The
|
|
97
|
+
* Wall restriction fields.
|
|
98
|
+
* @throws {Error} On an unknown sense, a sense in both lists, or a *limited*
|
|
99
|
+
* movement restriction (movement is binary — it has no LIMITED value).
|
|
100
|
+
*/
|
|
101
|
+
export function wallRestrictions(spec: {
|
|
102
|
+
blocks?: string[];
|
|
103
|
+
limits?: string[];
|
|
104
|
+
}, label: string): {
|
|
105
|
+
move: number;
|
|
106
|
+
sight: number;
|
|
107
|
+
light: number;
|
|
108
|
+
sound: number;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Compile one authored shape into a Foundry shape record.
|
|
112
|
+
*
|
|
113
|
+
* Four forms only — `rectangle` (`rect` is accepted as its short spelling),
|
|
114
|
+
* `circle`, `ellipse` and `polygon`. The remaining six Foundry shapes are
|
|
115
|
+
* template and token-attached forms with no place in an authored map, and
|
|
116
|
+
* `gridBased` is deliberately not exposed: it re-interprets a shape metrically,
|
|
117
|
+
* and one unit convention per note is the whole point.
|
|
118
|
+
*
|
|
119
|
+
* @param {object} spec - The authored shape entry.
|
|
120
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
121
|
+
* @returns {object} The Foundry shape record.
|
|
122
|
+
* @throws {Error} On an unknown form, a degenerate polygon, or grid-unit
|
|
123
|
+
* coordinates.
|
|
124
|
+
*/
|
|
125
|
+
export function buildShape(spec: object, geom: MapGeometry): object;
|
|
126
|
+
/**
|
|
127
|
+
* Compile a map note into a Scene document, embedded documents and all.
|
|
128
|
+
*
|
|
129
|
+
* Every embedded document carries its own `_key`. This is not decoration: the
|
|
130
|
+
* compendium CLI writes each one straight to its sublevel by that key, and a
|
|
131
|
+
* missing one fails the compile with `Key cannot be null or undefined`.
|
|
132
|
+
*
|
|
133
|
+
* @param {object} fm - The note's frontmatter.
|
|
134
|
+
* @param {object} ctx - The compile context:
|
|
135
|
+
* `packageId`, `journalEntryId`, `journalPack` (the pack the note's derived
|
|
136
|
+
* JournalEntry landed in), `pageIds` (heading key → page id),
|
|
137
|
+
* `resolveRegionRef` / `resolveBehaviorRef` / `resolveEffectRef` (address →
|
|
138
|
+
* UUID), `knownActions`, `warnings`, and optionally `folder` and `stats`.
|
|
139
|
+
* @returns {object} The Scene document, keyed for the pack.
|
|
140
|
+
* @throws {Error} On any authoring mistake Foundry would accept silently.
|
|
141
|
+
*/
|
|
142
|
+
export function buildScene(fm: object, ctx: object): object;
|
|
143
|
+
/**
|
|
144
|
+
* Synthesise the scene's single embedded Level from `image:` / `overlay:`.
|
|
145
|
+
*
|
|
146
|
+
* Authors never write `levels:`. A scene must ship at least one Level — the
|
|
147
|
+
* client-side `_preCreate` net that would create one does not run for offline
|
|
148
|
+
* pack compilation, and the server-side migration shim is version-gated on
|
|
149
|
+
* `_stats.coreVersion`, so a pack stamped 14.x+ skips it and ships a scene with
|
|
150
|
+
* no Level and no map.
|
|
151
|
+
*
|
|
152
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
153
|
+
* @param {string} sceneId - The owning scene's `_id`.
|
|
154
|
+
* @returns {object} The Level document, keyed for the pack.
|
|
155
|
+
*/
|
|
156
|
+
export function buildLevel(sohl: object, sceneId: string): object;
|
|
157
|
+
/**
|
|
158
|
+
* Compile the `walls:` and `doors:` blocks into Wall documents.
|
|
159
|
+
*
|
|
160
|
+
* Walls are keyed by **feature** rather than by restriction signature, so a
|
|
161
|
+
* diff reads "the hayloft walls changed" instead of "line 143 changed", and a
|
|
162
|
+
* human can find the one wall they meant to move.
|
|
163
|
+
*
|
|
164
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
165
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
166
|
+
* @param {object} ctx - The compile context.
|
|
167
|
+
* @returns {object[]} The Wall documents.
|
|
168
|
+
*/
|
|
169
|
+
export function buildWalls(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
170
|
+
/**
|
|
171
|
+
* Compile the `lights:` block into AmbientLight documents.
|
|
172
|
+
*
|
|
173
|
+
* `dim` and `bright` are radii in the scene's **distance units** (Foundry's own
|
|
174
|
+
* meaning), not pixels; only `position:` is pixels.
|
|
175
|
+
*
|
|
176
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
177
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
178
|
+
* @param {object} ctx - The compile context.
|
|
179
|
+
* @returns {object[]} The AmbientLight documents.
|
|
180
|
+
*/
|
|
181
|
+
export function buildLights(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
182
|
+
/**
|
|
183
|
+
* Compile the `tiles:` block into Tile documents.
|
|
184
|
+
*
|
|
185
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
186
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
187
|
+
* @param {object} ctx - The compile context.
|
|
188
|
+
* @returns {object[]} The Tile documents.
|
|
189
|
+
*/
|
|
190
|
+
export function buildTiles(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
191
|
+
/**
|
|
192
|
+
* Compile the `sounds:` block into AmbientSound documents.
|
|
193
|
+
*
|
|
194
|
+
* Positional audio is the one audio mechanism that packages cleanly: `path` is
|
|
195
|
+
* a plain `FilePathField` with no document reference behind it.
|
|
196
|
+
*
|
|
197
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
198
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
199
|
+
* @param {object} ctx - The compile context.
|
|
200
|
+
* @returns {object[]} The AmbientSound documents.
|
|
201
|
+
*/
|
|
202
|
+
export function buildSounds(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
203
|
+
/**
|
|
204
|
+
* Compile the `locations:` block into Note documents — the map pins.
|
|
205
|
+
*
|
|
206
|
+
* A location's key names a heading in the note's body, and the pin points at
|
|
207
|
+
* the journal page that heading compiled into. `Note.entryId` / `pageId` are
|
|
208
|
+
* `{idOnly: true}` fields, which return before the compendium guard, so pin
|
|
209
|
+
* targets survive packing intact — but `Note#entry` resolves by bare id against
|
|
210
|
+
* the **world** collection, which is why a map with pins ships inside an
|
|
211
|
+
* Adventure (`keepId: true`).
|
|
212
|
+
*
|
|
213
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
214
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
215
|
+
* @param {object} ctx - The compile context.
|
|
216
|
+
* @returns {object[]} The Note documents.
|
|
217
|
+
*/
|
|
218
|
+
export function buildLocations(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
219
|
+
/**
|
|
220
|
+
* Compile the `regions:` block into Region documents with their behaviours.
|
|
221
|
+
*
|
|
222
|
+
* @param {object} sohl - The note's `sohl:` block.
|
|
223
|
+
* @param {MapGeometry} geom - The map's measurements.
|
|
224
|
+
* @param {object} ctx - The compile context.
|
|
225
|
+
* @returns {object[]} The Region documents.
|
|
226
|
+
*/
|
|
227
|
+
export function buildRegions(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
228
|
+
export { MAP_TYPES };
|
|
229
|
+
/**
|
|
230
|
+
* Per-type canvas defaults, emitted **explicitly** on every scene.
|
|
231
|
+
*
|
|
232
|
+
* This is not a convenience. `grid.type`, `grid.distance` and `grid.units` all
|
|
233
|
+
* declare `initial: () => game.system.grid.*`, and there is no `game` at build
|
|
234
|
+
* time — left to their initial they would throw or ship undefined. The numeric
|
|
235
|
+
* values are `CONST.GRID_TYPES` and `CONST.FOG_EXPLORATION_MODES`, spelled out
|
|
236
|
+
* here because the constants module is Foundry's, not ours.
|
|
237
|
+
*
|
|
238
|
+
* @type {Readonly<Record<string, object>>}
|
|
239
|
+
*/
|
|
240
|
+
export const MAP_TYPE_PROFILES: Readonly<Record<string, object>>;
|
|
241
|
+
/**
|
|
242
|
+
* Foundry's own id for the level a scene is created with
|
|
243
|
+
* (`Scene.metadata.defaultLevelId`). Adopting it makes every reference to the
|
|
244
|
+
* synthesised level derivable, and matches what Foundry would have produced.
|
|
245
|
+
*/
|
|
246
|
+
export const DEFAULT_LEVEL_ID: "defaultLevel0000";
|
|
247
|
+
/**
|
|
248
|
+
* The behaviour types a map note may carry (issue #1525, v1).
|
|
249
|
+
*
|
|
250
|
+
* @type {ReadonlySet<string>}
|
|
251
|
+
*/
|
|
252
|
+
export const REGION_BEHAVIOR_TYPES: ReadonlySet<string>;
|
|
253
|
+
/**
|
|
254
|
+
* Behaviour types a map note may **never** carry, and why.
|
|
255
|
+
*
|
|
256
|
+
* `executeScript` is banned outright: its `source` is a `JavaScriptField`, so a
|
|
257
|
+
* note carrying one would compile data into code — the system's top security
|
|
258
|
+
* constraint (non-negotiable rule 10). There is no escape hatch and no
|
|
259
|
+
* configuration that re-enables it. `executeMacro` is merely deferred: its
|
|
260
|
+
* target Macro has to ship in the same Adventure to resolve, and
|
|
261
|
+
* Adventure-bundled macros are not built yet.
|
|
262
|
+
*
|
|
263
|
+
* @type {ReadonlyMap<string, string>}
|
|
264
|
+
*/
|
|
265
|
+
export const BANNED_REGION_BEHAVIOR_TYPES: ReadonlyMap<string, string>;
|
|
266
|
+
/**
|
|
267
|
+
* The map's own measurements, from which both unit lints are derived.
|
|
268
|
+
*/
|
|
269
|
+
export type MapGeometry = {
|
|
270
|
+
/**
|
|
271
|
+
* - The authored key, for error messages.
|
|
272
|
+
*/
|
|
273
|
+
label: string;
|
|
274
|
+
/**
|
|
275
|
+
* - Pixels per grid square.
|
|
276
|
+
*/
|
|
277
|
+
pxPerGrid: number;
|
|
278
|
+
/**
|
|
279
|
+
* - `[width, height]` in pixels.
|
|
280
|
+
*/
|
|
281
|
+
dimensions: number[];
|
|
282
|
+
};
|
|
283
|
+
import { MAP_TYPES } from "./ids.mjs";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The nearest configuration file at or above a directory.
|
|
3
|
+
*
|
|
4
|
+
* **Two of them in one directory is an error.** Picking one by precedence would
|
|
5
|
+
* mean a repository mid-conversion silently builds from the file its author is
|
|
6
|
+
* no longer editing, and the build would look entirely healthy while doing it.
|
|
7
|
+
* The walk continues past a directory holding none, so a repository may still
|
|
8
|
+
* sit inside one that has its own.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} from - The directory to start from.
|
|
11
|
+
* @returns {string|undefined} Its absolute path, or `undefined` if the walk
|
|
12
|
+
* reaches the filesystem root without finding one.
|
|
13
|
+
* @throws {Error} When one directory holds more than one of
|
|
14
|
+
* {@link CONFIG_FILENAMES}.
|
|
15
|
+
*/
|
|
16
|
+
export function findConfigFile(from: string): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Turn a parsed YAML configuration into the frozen one the engine reads.
|
|
19
|
+
*
|
|
20
|
+
* Three fields exist in a code configuration only because a code file has to
|
|
21
|
+
* *compute* what a data file can simply be told, and each is derived here from
|
|
22
|
+
* where the file sits:
|
|
23
|
+
*
|
|
24
|
+
* - **`rootDir`** is the configuration's own directory, always. A data file
|
|
25
|
+
* cannot write `import.meta.dirname`, and any absolute path it wrote instead
|
|
26
|
+
* would be one machine's — so authoring it is rejected rather than honoured.
|
|
27
|
+
* - **`itemBuilders`** is a *name* (`sohl`), resolved against the built-in
|
|
28
|
+
* registries. A registry of a consumer's own is code, and code goes in an
|
|
29
|
+
* `.mjs` configuration.
|
|
30
|
+
* - **`stats.systemVersion`** is derived from the adjacent `package.json` when
|
|
31
|
+
* the configuration does not state it. Stating it is still allowed: a
|
|
32
|
+
* repository shipping content *for* another package (a module declaring
|
|
33
|
+
* `systemId: sohl`) may need a version that is not its own.
|
|
34
|
+
*
|
|
35
|
+
* Everything else passes through untouched, to be validated by the one
|
|
36
|
+
* validator both configuration forms end at.
|
|
37
|
+
*
|
|
38
|
+
* @param {unknown} data - The parsed configuration document.
|
|
39
|
+
* @param {string} configPath - Absolute path of the file it was parsed from.
|
|
40
|
+
* @returns {import("../config.mjs").ContentBuildConfig} The frozen configuration.
|
|
41
|
+
* @throws {Error} When the document is not a mapping, declares `rootDir`, or
|
|
42
|
+
* names an item-builder registry this package does not ship.
|
|
43
|
+
*/
|
|
44
|
+
export function configFromData(data: unknown, configPath: string): import("../config.mjs").ContentBuildConfig;
|
|
45
|
+
/**
|
|
46
|
+
* The consuming repository's resolved, frozen configuration.
|
|
47
|
+
*
|
|
48
|
+
* Every engine module that needs a configured value calls this, rather than
|
|
49
|
+
* hoisting one at import: that is what keeps the library importable without a
|
|
50
|
+
* configuration (#2). The result is memoised, so calling it in a default
|
|
51
|
+
* parameter — the usual spelling here — costs one property read per call.
|
|
52
|
+
*
|
|
53
|
+
* @returns {import("../config.mjs").ContentBuildConfig} The frozen configuration.
|
|
54
|
+
* @throws {Error} When no configuration file can be found, or the one named
|
|
55
|
+
* cannot be loaded. Absence is a defect, not a fallback: without it the
|
|
56
|
+
* compilers know neither what to compile nor where to put it.
|
|
57
|
+
*/
|
|
58
|
+
export function loadPackConfig(): import("../config.mjs").ContentBuildConfig;
|
|
59
|
+
/** The stem every consuming repository declares its build under. */
|
|
60
|
+
export const CONFIG_BASENAME: "package-build.config";
|
|
61
|
+
/**
|
|
62
|
+
* The file names a configuration may be written as, in resolution order.
|
|
63
|
+
*
|
|
64
|
+
* Order settles nothing in practice — two of these in one directory is an
|
|
65
|
+
* error, not a precedence question (see {@link findConfigFile}) — but it fixes
|
|
66
|
+
* the order the names are *reported* in, which is the order a reader should
|
|
67
|
+
* reach for them: YAML first, `.mjs` last.
|
|
68
|
+
*
|
|
69
|
+
* The `content-build.config.*` stem this package read before the two toolchains
|
|
70
|
+
* merged is **not** resolved. 2.0.0 renames the file rather than accepting both:
|
|
71
|
+
* a deprecation window here would mean a repository could sit indefinitely on a
|
|
72
|
+
* name for a package that no longer exists, and the upgrade already requires
|
|
73
|
+
* touching the consumer's manifest and imports.
|
|
74
|
+
*
|
|
75
|
+
* @type {readonly string[]}
|
|
76
|
+
*/
|
|
77
|
+
export const CONFIG_FILENAMES: readonly string[];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the router for one configured pack list.
|
|
3
|
+
*
|
|
4
|
+
* Pure — it reads the list and nothing else, so a consumer's routing can be
|
|
5
|
+
* tested without a content tree or a config file on disk.
|
|
6
|
+
*
|
|
7
|
+
* @param {readonly object[]} packs - The resolved `packs` list from
|
|
8
|
+
* `defineConfig`.
|
|
9
|
+
* @returns {{resolve: (fm: object, docType: string) => string,
|
|
10
|
+
* resolveOrNull: (fm: object, docType: string) => string|undefined,
|
|
11
|
+
* packsOfType: (docType: string) => string[],
|
|
12
|
+
* defaultOf: (docType: string) => string|undefined}} The router.
|
|
13
|
+
*/
|
|
14
|
+
export function createPackRouter(packs: readonly object[]): {
|
|
15
|
+
resolve: (fm: object, docType: string) => string;
|
|
16
|
+
resolveOrNull: (fm: object, docType: string) => string | undefined;
|
|
17
|
+
packsOfType: (docType: string) => string[];
|
|
18
|
+
defaultOf: (docType: string) => string | undefined;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The router for a resolved configuration, built once per configuration.
|
|
22
|
+
*
|
|
23
|
+
* @param {object} config - A configuration from `defineConfig`.
|
|
24
|
+
* @returns {ReturnType<typeof createPackRouter>} Its router.
|
|
25
|
+
*/
|
|
26
|
+
export function routerFor(config: object): ReturnType<typeof createPackRouter>;
|
|
27
|
+
/**
|
|
28
|
+
* The consuming repository's own router — what every module that emits a UUID
|
|
29
|
+
* asks where a note's document lives.
|
|
30
|
+
*
|
|
31
|
+
* An accessor rather than a hoisted constant, so that importing this module
|
|
32
|
+
* needs no configuration (#2). {@link routerFor} keeps one router per
|
|
33
|
+
* configuration object, so repeated calls return the same instance.
|
|
34
|
+
*
|
|
35
|
+
* @returns {ReturnType<typeof createPackRouter>} This repository's router.
|
|
36
|
+
*/
|
|
37
|
+
export function packRouter(): ReturnType<typeof createPackRouter>;
|
|
38
|
+
/**
|
|
39
|
+
* A note that cannot be routed to a pack. Thrown rather than returned so no
|
|
40
|
+
* caller can carry on with a plausible-looking default.
|
|
41
|
+
*/
|
|
42
|
+
export class PackRoutingError extends Error {
|
|
43
|
+
/** @param {string} message */
|
|
44
|
+
constructor(message: string);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The frontmatter field a note declares its pack in.
|
|
48
|
+
*
|
|
49
|
+
* Deliberately close to `package:` and deliberately not the same word: a note's
|
|
50
|
+
* `package:` says which *distribution* owns it, `pack:` which *compendium*
|
|
51
|
+
* receives its document.
|
|
52
|
+
*/
|
|
53
|
+
export const PACK_FIELD: "pack";
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared options for one file, with the per-language adjustment applied.
|
|
3
|
+
*
|
|
4
|
+
* What a consumer's own Prettier config would have produced, for a repository
|
|
5
|
+
* that declares none.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} file - Path of the file about to be formatted.
|
|
8
|
+
* @returns {object} Options to hand Prettier directly. Never carries
|
|
9
|
+
* `overrides`: passing that inline is what silently did nothing (#76).
|
|
10
|
+
*/
|
|
11
|
+
export function sharedPrettierOptionsFor(file: string): object;
|
|
12
|
+
/**
|
|
13
|
+
* The prose conventions every content repository writes to — one Prettier
|
|
14
|
+
* configuration and one markdownlint rule set, declared here so a note
|
|
15
|
+
* formatted in one repository is formatted the same way in the next (#69).
|
|
16
|
+
*
|
|
17
|
+
* These used to exist in exactly one consumer. The SoHL repository carried
|
|
18
|
+
* both; `sohl-thalorna` had Prettier but never ran it from `lint`; and
|
|
19
|
+
* `sohl-kethira-basic` had neither, so the package least likely to have been
|
|
20
|
+
* proofread was checked for addresses and nothing else. A rule set copied into
|
|
21
|
+
* three repositories is one rule with three implementations, which is the drift
|
|
22
|
+
* #20 exists to remove — so it is declared once, here, and every consumer
|
|
23
|
+
* invokes it.
|
|
24
|
+
*
|
|
25
|
+
* **Neither of these is an override.** A consumer that declares its own
|
|
26
|
+
* Prettier config or its own `.markdownlint-cli2.jsonc` wins; what ships here
|
|
27
|
+
* is the default a repository gets for declaring nothing. Repository *layout*
|
|
28
|
+
* knowledge — which paths to skip — stays with the repository that has the
|
|
29
|
+
* layout, in its own ignore files.
|
|
30
|
+
*
|
|
31
|
+
* @module
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* The Prettier options every content repository shares, before any per-language
|
|
35
|
+
* adjustment.
|
|
36
|
+
*
|
|
37
|
+
* The values are not arbitrary: they are the ones the SoHL repository has
|
|
38
|
+
* always used, kept identical here so a module or a note moving between
|
|
39
|
+
* repositories does not reformat on arrival. Changing one of these reformats
|
|
40
|
+
* every consumer, so treat it as a breaking change to the shared tree rather
|
|
41
|
+
* than a preference.
|
|
42
|
+
*
|
|
43
|
+
* @type {Readonly<object>}
|
|
44
|
+
*/
|
|
45
|
+
export const PRETTIER_BASE: Readonly<object>;
|
|
46
|
+
/**
|
|
47
|
+
* What markdown gets on top of {@link PRETTIER_BASE}.
|
|
48
|
+
*
|
|
49
|
+
* Markdown indents at 2, not the global 4. Notes are the thing several
|
|
50
|
+
* repositories exchange, so their indentation is the one value that most needs
|
|
51
|
+
* to be the same everywhere — a note's YAML frontmatter is nested lists, and at
|
|
52
|
+
* 4 every note reindents away from the form it was written in.
|
|
53
|
+
*
|
|
54
|
+
* **Declared apart from the `overrides` block, not derived from it.** Prettier
|
|
55
|
+
* applies `overrides` only while resolving a config *file*; options handed to
|
|
56
|
+
* it directly keep the global values, so a consumer with no config of its own
|
|
57
|
+
* silently got markdown at 4 (#76). The runner needs the adjustment as data it
|
|
58
|
+
* can apply itself, and {@link PRETTIER_CONFIG} composes the same values into
|
|
59
|
+
* the shape a config file wants — one source, two presentations.
|
|
60
|
+
*
|
|
61
|
+
* @type {Readonly<object>}
|
|
62
|
+
*/
|
|
63
|
+
export const PRETTIER_MARKDOWN: Readonly<object>;
|
|
64
|
+
/**
|
|
65
|
+
* The shared configuration in the shape a Prettier **config file** takes.
|
|
66
|
+
*
|
|
67
|
+
* This is what a consumer's `prettier.config.mjs` re-exports, and it is the
|
|
68
|
+
* form in which the markdown adjustment works: resolved from the consumer's own
|
|
69
|
+
* root, `**\/*.md` matches that repository's markdown. Shipped from inside
|
|
70
|
+
* `node_modules` it would match nothing, because Prettier resolves an
|
|
71
|
+
* override's glob relative to the config file's own directory — which is why
|
|
72
|
+
* the runner applies {@link PRETTIER_MARKDOWN} itself rather than pointing
|
|
73
|
+
* Prettier at this file.
|
|
74
|
+
*
|
|
75
|
+
* @type {Readonly<object>}
|
|
76
|
+
*/
|
|
77
|
+
export const PRETTIER_CONFIG: Readonly<object>;
|
|
78
|
+
/**
|
|
79
|
+
* The markdownlint rules — the structural checks Prettier cannot make.
|
|
80
|
+
*
|
|
81
|
+
* Prettier already formats every hand-written `.md` file, and it is indifferent
|
|
82
|
+
* to structure: it will happily reformat a document whose heading levels skip
|
|
83
|
+
* from h3 to h5, whose two sibling sections claim the same anchor, or whose
|
|
84
|
+
* link is `(text)[url]`. Those are the defects this set is for.
|
|
85
|
+
*
|
|
86
|
+
* **THE RULE SET IS DELIBERATELY NARROW, and stays that way on purpose.**
|
|
87
|
+
* Turning on markdownlint's defaults over a content tree produces tens of
|
|
88
|
+
* thousands of findings, almost all of them line length, list indentation and
|
|
89
|
+
* blank-line placement — Prettier's territory, or a second formatter's taste
|
|
90
|
+
* imposed on prose it already owns. So `default` is off and each rule below is
|
|
91
|
+
* enabled by name, with the reason it earns its place. Add a rule only if it
|
|
92
|
+
* can report that a page is *wrong*.
|
|
93
|
+
*
|
|
94
|
+
* @type {Readonly<object>}
|
|
95
|
+
*/
|
|
96
|
+
export const MARKDOWNLINT_CONFIG: Readonly<object>;
|
|
97
|
+
/**
|
|
98
|
+
* The globs `content-build markdown` checks when a consumer names no paths.
|
|
99
|
+
*
|
|
100
|
+
* Every markdown file the repository tracks, which is what a consumer means by
|
|
101
|
+
* "lint my markdown". What to *skip* is the repository's own business and comes
|
|
102
|
+
* from its `.gitignore` (honoured by default) and its own configuration.
|
|
103
|
+
*
|
|
104
|
+
* @type {readonly string[]}
|
|
105
|
+
*/
|
|
106
|
+
export const MARKDOWN_GLOBS: readonly string[];
|
|
107
|
+
/**
|
|
108
|
+
* Markdown every consumer has and nobody hand-writes.
|
|
109
|
+
*
|
|
110
|
+
* `CHANGELOG.md` is assembled by `changeset version` from the `.changeset/*.md`
|
|
111
|
+
* bodies on every release. It is not in anyone's `.gitignore` — it is
|
|
112
|
+
* committed — so nothing else excludes it, and linting it reports on the
|
|
113
|
+
* generator: the findings are real (a heading level changesets chose, an
|
|
114
|
+
* asterisk it emitted) and unfixable, because the next release rewrites the
|
|
115
|
+
* file. Every repository here releases through changesets, so this is a fact
|
|
116
|
+
* about the shared toolchain rather than any one repository's layout, and it
|
|
117
|
+
* belongs in the default instead of being rediscovered three times.
|
|
118
|
+
*
|
|
119
|
+
* @type {readonly string[]}
|
|
120
|
+
*/
|
|
121
|
+
export const MARKDOWN_IGNORES: readonly string[];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check — or rewrite — every file Prettier claims, under one root.
|
|
3
|
+
*
|
|
4
|
+
* The configuration resolution is the part that matters: a consumer's own
|
|
5
|
+
* Prettier config, found by Prettier walking up from each file, always wins.
|
|
6
|
+
* {@link sharedPrettierOptionsFor} is what a file gets when that search finds
|
|
7
|
+
* nothing, which is the case in a repository that has deliberately declared
|
|
8
|
+
* none.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} root - Repository (or subtree) to check.
|
|
11
|
+
* @param {object} [opts]
|
|
12
|
+
* @param {readonly string[]} [opts.paths] - Files or directories to check
|
|
13
|
+
* instead of the whole root.
|
|
14
|
+
* @param {boolean} [opts.write=false] - Rewrite unformatted files in place
|
|
15
|
+
* rather than reporting them.
|
|
16
|
+
* @param {object} [opts.prettier] - The Prettier module, for tests.
|
|
17
|
+
* @returns {Promise<{findings: Array<{file: string, severity: string,
|
|
18
|
+
* message: string}>, checked: number, written: string[]}>} The findings, how
|
|
19
|
+
* many files were considered, and what was rewritten.
|
|
20
|
+
*/
|
|
21
|
+
export function checkFormatting(root: string, opts?: {
|
|
22
|
+
paths?: readonly string[] | undefined;
|
|
23
|
+
write?: boolean | undefined;
|
|
24
|
+
prettier?: object | undefined;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
findings: Array<{
|
|
27
|
+
file: string;
|
|
28
|
+
severity: string;
|
|
29
|
+
message: string;
|
|
30
|
+
}>;
|
|
31
|
+
checked: number;
|
|
32
|
+
written: string[];
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Lint a repository's markdown against the shared rule set.
|
|
36
|
+
*
|
|
37
|
+
* {@link MARKDOWNLINT_CONFIG} is passed as markdownlint's `optionsDefault`,
|
|
38
|
+
* which is precisely the "shipped default, consumer overrides" behaviour the
|
|
39
|
+
* command promises: a `.markdownlint-cli2.jsonc` found in the tree replaces it,
|
|
40
|
+
* and a repository with none gets these rules.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} root - Repository to lint.
|
|
43
|
+
* @param {object} [opts]
|
|
44
|
+
* @param {readonly string[]} [opts.paths] - Globs to lint instead of every
|
|
45
|
+
* markdown file.
|
|
46
|
+
* @param {boolean} [opts.fix=false] - Apply the fixes markdownlint can make.
|
|
47
|
+
* @param {(params: object) => Promise<number>} [opts.run] - The
|
|
48
|
+
* markdownlint-cli2 entry point, for tests.
|
|
49
|
+
* @returns {Promise<{findings: object[], exitCode: number}>} The findings, and
|
|
50
|
+
* markdownlint's own exit code.
|
|
51
|
+
*/
|
|
52
|
+
export function lintMarkdown(root: string, opts?: {
|
|
53
|
+
paths?: readonly string[] | undefined;
|
|
54
|
+
fix?: boolean | undefined;
|
|
55
|
+
run?: ((params: object) => Promise<number>) | undefined;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
findings: object[];
|
|
58
|
+
exitCode: number;
|
|
59
|
+
}>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The curated Foundry region-event vocabulary, as plain data.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately **plain ESM** — no TypeScript, no `@src` aliases, no Foundry —
|
|
5
|
+
* for the same reason `../sohl/default-item-art.mjs` is: the map-note pack
|
|
6
|
+
* compiler runs under bare `node`, outside the bundler that resolves `@src` and
|
|
7
|
+
* strips types, and it must reject an authored region event that the runtime
|
|
8
|
+
* would silently drop. One list here is what keeps the build-time lint and the
|
|
9
|
+
* runtime bridge from drifting apart.
|
|
10
|
+
*
|
|
11
|
+
* It sits in this package rather than in the system's `src/` tree because the
|
|
12
|
+
* map-note compiler that reads it is installed as a dependency (#1501), and a
|
|
13
|
+
* relative path out of the package would resolve to garbage from
|
|
14
|
+
* `node_modules`. The runtime reaches it back through the package's
|
|
15
|
+
* `./engine/region-events` entry point (#1510). It is engine-side, not
|
|
16
|
+
* SoHL-side, because any content module that authors a scene region — an
|
|
17
|
+
* adventure module included — needs this vocabulary.
|
|
18
|
+
*
|
|
19
|
+
* The prose explaining *why* each event is curated or excluded lives with the
|
|
20
|
+
* typed re-exports in `src/entity/event/region-triggers.ts`, which is the
|
|
21
|
+
* documented surface.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* The curated Foundry region-event → SoHL trigger-name map. The keys are the
|
|
25
|
+
* `CONST.REGION_EVENTS` string values SoHL forwards.
|
|
26
|
+
*
|
|
27
|
+
* @type {Readonly<Record<string, string>>}
|
|
28
|
+
*/
|
|
29
|
+
export const REGION_EVENT_TO_TRIGGER: Readonly<Record<string, string>>;
|
|
30
|
+
/**
|
|
31
|
+
* The Foundry region-event names SoHL forwards (the keys of the map).
|
|
32
|
+
*
|
|
33
|
+
* @type {readonly string[]}
|
|
34
|
+
*/
|
|
35
|
+
export const CURATED_REGION_EVENTS: readonly string[];
|
|
36
|
+
/**
|
|
37
|
+
* Region events SoHL deliberately does **not** forward: the continuous
|
|
38
|
+
* (`tokenMove*`), view-dependent (`tokenAnimate*`) and lifecycle
|
|
39
|
+
* (`behavior*`, `regionBoundary`) streams.
|
|
40
|
+
*
|
|
41
|
+
* @type {readonly string[]}
|
|
42
|
+
*/
|
|
43
|
+
export const EXCLUDED_REGION_EVENTS: readonly string[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The version of `@foundryvtt/foundryvtt-cli` this build actually resolves.
|
|
3
|
+
*
|
|
4
|
+
* Resolved from *this* module, so it names the copy the pack compile runs on
|
|
5
|
+
* rather than whatever a shell happens to find. The installed version is the
|
|
6
|
+
* write path, so it is the fact a report should carry.
|
|
7
|
+
*
|
|
8
|
+
* @returns {string | undefined} The resolved version, or `undefined` when the
|
|
9
|
+
* package cannot be read (a pruned install, an exports-restricted copy).
|
|
10
|
+
*/
|
|
11
|
+
export function compendiumCliVersion(): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Every way a compiled pack can ship a Scene that has lost its Level.
|
|
14
|
+
*
|
|
15
|
+
* @param {Iterable<[string, object]>} records - `[key, value]` pairs from a
|
|
16
|
+
* compiled pack's LevelDB, in any order.
|
|
17
|
+
* @param {object} [options] - Reporting context.
|
|
18
|
+
* @param {string} [options.cliVersion] - The resolved compendium CLI version,
|
|
19
|
+
* which decides what a wholesale loss is blamed on. Defaults to unknown,
|
|
20
|
+
* which leaves the report to say only what it can prove.
|
|
21
|
+
* @returns {string[]} One human-readable problem per violation, empty when the
|
|
22
|
+
* pack is sound.
|
|
23
|
+
*/
|
|
24
|
+
export function checkSceneLevels(records: Iterable<[string, object]>, { cliVersion }?: {
|
|
25
|
+
cliVersion?: string | undefined;
|
|
26
|
+
}): string[];
|
|
27
|
+
/**
|
|
28
|
+
* Read a compiled pack back off disk and check it.
|
|
29
|
+
*
|
|
30
|
+
* The pack is opened after the compendium CLI has closed it, so this reads the
|
|
31
|
+
* bytes that will actually ship rather than the JSON they were compiled from.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} packDir - Directory of the compiled LevelDB pack.
|
|
34
|
+
* @returns {Promise<string[]>} The problems found, empty when the pack is sound.
|
|
35
|
+
*/
|
|
36
|
+
export function verifyPackSceneLevels(packDir: string): Promise<string[]>;
|