@heroiclands/package-build 9.0.0 → 10.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.md +721 -0
- package/CONTENT.md +273 -13
- package/bin/content-build.mjs +437 -7
- package/content-config.mjs +259 -28
- package/docs/content-format.md +1418 -0
- package/engine/address-charset.mjs +62 -0
- package/engine/alias-index.mjs +153 -0
- package/engine/base-compiler.mjs +194 -4
- package/engine/content-address.mjs +4 -4
- package/engine/content-format-check.mjs +570 -0
- package/engine/content-format.mjs +253 -0
- package/engine/content-links.mjs +132 -56
- package/engine/content-lint.mjs +8 -1
- package/engine/diagnostics.mjs +33 -0
- package/engine/document-subtypes.mjs +440 -0
- package/engine/field-spec.mjs +49 -43
- package/engine/frontmatter-lint.mjs +351 -28
- package/engine/generate.mjs +32 -4
- package/engine/helpers.mjs +41 -29
- package/engine/ids.mjs +19 -1
- package/engine/index.mjs +15 -0
- package/engine/item-registry.mjs +72 -5
- package/engine/kb-manifest.mjs +36 -7
- package/engine/map-notes.mjs +34 -18
- package/engine/note-claims.mjs +383 -0
- package/engine/note-vocabulary.mjs +678 -0
- package/engine/pack-config.mjs +39 -22
- package/engine/pack-router.mjs +17 -6
- package/engine/prose-lint.mjs +55 -3
- package/engine/retired-fields.mjs +117 -3
- package/engine/scenes.mjs +19 -1
- package/engine/schema-check.mjs +347 -3
- package/engine/site-build.mjs +1 -1
- package/engine/site-index.mjs +38 -21
- package/engine/system-block.mjs +513 -0
- package/engine/web-wikilinks.mjs +112 -80
- package/engine/wikilink-syntax.mjs +30 -0
- package/engine/wikilinks.mjs +67 -51
- package/package.json +6 -2
- package/sohl/actors.mjs +249 -36
- package/sohl/document-subtypes.mjs +82 -0
- package/sohl/index.mjs +3 -0
- package/sohl/items.mjs +110 -14
- package/sohl/note-schemas.mjs +11 -7
- package/types/content-config.d.mts +48 -4
- package/types/engine/address-charset.d.mts +45 -0
- package/types/engine/alias-index.d.mts +122 -0
- package/types/engine/base-compiler.d.mts +132 -4
- package/types/engine/content-address.d.mts +2 -2
- package/types/engine/content-format-check.d.mts +163 -0
- package/types/engine/content-format.d.mts +101 -0
- package/types/engine/content-links.d.mts +16 -1
- package/types/engine/content-lint.d.mts +6 -0
- package/types/engine/diagnostics.d.mts +29 -0
- package/types/engine/document-subtypes.d.mts +233 -0
- package/types/engine/field-spec.d.mts +76 -23
- package/types/engine/frontmatter-lint.d.mts +47 -2
- package/types/engine/generate.d.mts +14 -1
- package/types/engine/helpers.d.mts +21 -13
- package/types/engine/ids.d.mts +10 -0
- package/types/engine/index.d.mts +5 -0
- package/types/engine/item-registry.d.mts +21 -2
- package/types/engine/kb-manifest.d.mts +35 -8
- package/types/engine/map-notes.d.mts +21 -11
- package/types/engine/note-claims.d.mts +113 -0
- package/types/engine/note-vocabulary.d.mts +251 -0
- package/types/engine/pack-config.d.mts +4 -3
- package/types/engine/pack-router.d.mts +4 -4
- package/types/engine/prose-lint.d.mts +6 -2
- package/types/engine/retired-fields.d.mts +73 -2
- package/types/engine/schema-check.d.mts +182 -0
- package/types/engine/system-block.d.mts +281 -0
- package/types/engine/web-wikilinks.d.mts +23 -12
- package/types/engine/wikilink-syntax.d.mts +29 -0
- package/types/sohl/actors.d.mts +62 -6
- package/types/sohl/document-subtypes.d.mts +14 -0
- package/types/sohl/index.d.mts +1 -0
- package/types/sohl/items.d.mts +21 -0
|
@@ -1,31 +1,37 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Write `value` at a dotted path, creating the intermediate objects.
|
|
3
|
-
*
|
|
4
|
-
* Insertion order is the emitted JSON's key order, so a declaration's order is
|
|
5
|
-
* the compiled document's order — which is what lets a field list replace a
|
|
6
|
-
* hand-written object literal without changing a single byte of output.
|
|
7
|
-
*
|
|
8
|
-
* @param {object} target - The object to write into (mutated).
|
|
9
|
-
* @param {string} dotted - Path, e.g. `"locations.flexible"`.
|
|
10
|
-
* @param {any} value - The value to set.
|
|
11
|
-
* @returns {object} `target`, for chaining.
|
|
12
|
-
*/
|
|
13
|
-
export function setPath(target: object, dotted: string, value: any): object;
|
|
14
1
|
/**
|
|
15
2
|
* Read one declared field out of a note's frontmatter.
|
|
16
3
|
*
|
|
4
|
+
* The *position* is resolved by {@link resolveFieldValue} — `<system>.system`
|
|
5
|
+
* first, then the legacy in-block key, then the declared shared source, then
|
|
6
|
+
* the default (#58). The **coercion** is applied here, once, wherever the value
|
|
7
|
+
* came from: a field's `read` is a statement about the field, not about where
|
|
8
|
+
* an author happened to write it, so `weight: "7"` reads as `7` at every one of
|
|
9
|
+
* those positions.
|
|
10
|
+
*
|
|
17
11
|
* @param {FieldSpec} field - The declaration.
|
|
18
12
|
* @param {object} fm - The note's frontmatter.
|
|
13
|
+
* @param {object} [options] - Options.
|
|
14
|
+
* @param {string} [options.block="sohl"] - Which system's block to resolve
|
|
15
|
+
* against. The default is the one block every existing tree authors; a
|
|
16
|
+
* second system passes its own.
|
|
19
17
|
* @returns {any} The value to emit.
|
|
20
18
|
*/
|
|
21
|
-
export function readField(field: FieldSpec, fm: object
|
|
19
|
+
export function readField(field: FieldSpec, fm: object, { block }?: {
|
|
20
|
+
block?: string | undefined;
|
|
21
|
+
}): any;
|
|
22
22
|
/**
|
|
23
23
|
* Turn a field declaration into the builder it declares.
|
|
24
24
|
*
|
|
25
25
|
* @param {readonly FieldSpec[]} fields - The declaration, in emission order.
|
|
26
|
+
* @param {object} [options] - Options.
|
|
27
|
+
* @param {string} [options.block="sohl"] - Which system's block the builder
|
|
28
|
+
* reads. One declaration compiles against any block, which is what lets two
|
|
29
|
+
* systems declare the same shared source and different destinations.
|
|
26
30
|
* @returns {(fm: object) => object} A `system`-block builder.
|
|
27
31
|
*/
|
|
28
|
-
export function buildFromFields(fields: readonly FieldSpec[]
|
|
32
|
+
export function buildFromFields(fields: readonly FieldSpec[], { block }?: {
|
|
33
|
+
block?: string | undefined;
|
|
34
|
+
}): (fm: object) => object;
|
|
29
35
|
/**
|
|
30
36
|
* The fields of a declaration an author actually writes.
|
|
31
37
|
*
|
|
@@ -38,12 +44,25 @@ export function buildFromFields(fields: readonly FieldSpec[]): (fm: object) => o
|
|
|
38
44
|
* @returns {FieldSpec[]} Only the fields with a frontmatter `name`.
|
|
39
45
|
*/
|
|
40
46
|
export function authoredFields(fields: readonly FieldSpec[]): FieldSpec[];
|
|
47
|
+
export { setPath };
|
|
41
48
|
/**
|
|
42
49
|
* @typedef {object} FieldSpec
|
|
43
|
-
* @property {string} to - Dotted path in the emitted `system` block
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
50
|
+
* @property {string} to - Dotted path in the emitted `system` block — and,
|
|
51
|
+
* since #58, the path a note authors the field at directly:
|
|
52
|
+
* `<system>.system.<to>`.
|
|
53
|
+
* @property {string} [name] - The **shared, top-level property this field draws
|
|
54
|
+
* from** when the note authors no value at `<system>.system.<to>`. Dotted for
|
|
55
|
+
* a path into a shared container (`data.portrait`), which is now the ordinary
|
|
56
|
+
* case: `data:` (#128) puts every type-specific fact under one.
|
|
57
|
+
*
|
|
58
|
+
* It used to mean "frontmatter key under `sohl:`", and that reading is the
|
|
59
|
+
* degenerate case where the shared source and the system destination happen
|
|
60
|
+
* to share a name. They constantly do not — one shared `data.portrait` feeds
|
|
61
|
+
* `sohl.system.portrait` *and* `hm3.system.bioImage` — so the source is
|
|
62
|
+
* declared rather than matched by spelling (#58). The in-block position is
|
|
63
|
+
* still read, second, until #126 moves the corpus off it.
|
|
64
|
+
*
|
|
65
|
+
* Absent means the value is not authored at all — see `value`.
|
|
47
66
|
* @property {string} [shape] - Human-readable shape, for documentation. Comes
|
|
48
67
|
* paired with `read` from one of the coercion constants below.
|
|
49
68
|
* @property {(raw: any, ctx: {fm: object, field: FieldSpec}) => any} [read] -
|
|
@@ -51,6 +70,15 @@ export function authoredFields(fields: readonly FieldSpec[]): FieldSpec[];
|
|
|
51
70
|
* @property {any} [default] - Emitted when the note does not carry the field.
|
|
52
71
|
* @property {boolean} [required] - Whether a note must carry it. A required
|
|
53
72
|
* field's `read` is expected to throw when it is missing.
|
|
73
|
+
* @property {boolean} [shared] - Whether the field is authored at the note's
|
|
74
|
+
* **top level** rather than inside a system block, because what it states is
|
|
75
|
+
* not system-specific — a map's background art is the same art whichever
|
|
76
|
+
* system reads the note. It changes no reader: the top level is already the
|
|
77
|
+
* third step of {@link module:engine/system-block.resolveFieldValue}'s order,
|
|
78
|
+
* so the value resolves whichever region carries it. What it tells the
|
|
79
|
+
* author-facing surfaces is which of the two is the field's *home*, so a
|
|
80
|
+
* message about it names `img` rather than sending an author to `sohl.img`
|
|
81
|
+
* (#142).
|
|
54
82
|
* @property {"string"|"number"|"boolean"|"list"|"map"} [kind] - The value's
|
|
55
83
|
* shape, for the frontmatter linter (#19). Distinct from `shape`, which is
|
|
56
84
|
* prose for a reader, and from `read`, which is what the compiler does: a
|
|
@@ -121,13 +149,25 @@ export const BLANK_IS_DEFAULT: Readonly<{
|
|
|
121
149
|
}>;
|
|
122
150
|
export type FieldSpec = {
|
|
123
151
|
/**
|
|
124
|
-
* - Dotted path in the emitted `system` block
|
|
152
|
+
* - Dotted path in the emitted `system` block — and,
|
|
153
|
+
* since #58, the path a note authors the field at directly:
|
|
154
|
+
* `<system>.system.<to>`.
|
|
125
155
|
*/
|
|
126
156
|
to: string;
|
|
127
157
|
/**
|
|
128
|
-
* -
|
|
129
|
-
*
|
|
130
|
-
* `
|
|
158
|
+
* - The **shared, top-level property this field draws
|
|
159
|
+
* from** when the note authors no value at `<system>.system.<to>`. Dotted for
|
|
160
|
+
* a path into a shared container (`data.portrait`), which is now the ordinary
|
|
161
|
+
* case: `data:` (#128) puts every type-specific fact under one.
|
|
162
|
+
*
|
|
163
|
+
* It used to mean "frontmatter key under `sohl:`", and that reading is the
|
|
164
|
+
* degenerate case where the shared source and the system destination happen
|
|
165
|
+
* to share a name. They constantly do not — one shared `data.portrait` feeds
|
|
166
|
+
* `sohl.system.portrait` *and* `hm3.system.bioImage` — so the source is
|
|
167
|
+
* declared rather than matched by spelling (#58). The in-block position is
|
|
168
|
+
* still read, second, until #126 moves the corpus off it.
|
|
169
|
+
*
|
|
170
|
+
* Absent means the value is not authored at all — see `value`.
|
|
131
171
|
*/
|
|
132
172
|
name?: string | undefined;
|
|
133
173
|
/**
|
|
@@ -152,6 +192,18 @@ export type FieldSpec = {
|
|
|
152
192
|
* field's `read` is expected to throw when it is missing.
|
|
153
193
|
*/
|
|
154
194
|
required?: boolean | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* - Whether the field is authored at the note's
|
|
197
|
+
* **top level** rather than inside a system block, because what it states is
|
|
198
|
+
* not system-specific — a map's background art is the same art whichever
|
|
199
|
+
* system reads the note. It changes no reader: the top level is already the
|
|
200
|
+
* third step of {@link module :engine/system-block.resolveFieldValue}'s order,
|
|
201
|
+
* so the value resolves whichever region carries it. What it tells the
|
|
202
|
+
* author-facing surfaces is which of the two is the field's *home*, so a
|
|
203
|
+
* message about it names `img` rather than sending an author to `sohl.img`
|
|
204
|
+
* (#142).
|
|
205
|
+
*/
|
|
206
|
+
shared?: boolean | undefined;
|
|
155
207
|
/**
|
|
156
208
|
* - The value's
|
|
157
209
|
* shape, for the frontmatter linter (#19). Distinct from `shape`, which is
|
|
@@ -179,3 +231,4 @@ export type FieldSpec = {
|
|
|
179
231
|
*/
|
|
180
232
|
describe: string;
|
|
181
233
|
};
|
|
234
|
+
import { setPath } from "./system-block.mjs";
|
|
@@ -20,11 +20,25 @@ export function matchesKind(value: unknown, kind: string): boolean;
|
|
|
20
20
|
* @param {Record<string, readonly object[]>} opts.schemas - Type → declaration.
|
|
21
21
|
* @param {object} [opts.index] - The link index, for the reference check. Its
|
|
22
22
|
* absence skips that check rather than reporting every reference as dead.
|
|
23
|
+
* @param {Record<string, object>} [opts.vocabulary] - Type → the closed regions
|
|
24
|
+
* it declares, as `engine/note-vocabulary.mjs` states them (#128). Supplied
|
|
25
|
+
* by the caller for the same reason `schemas` is: this module validates a
|
|
26
|
+
* note against whatever its type declares and knows no type names of its
|
|
27
|
+
* own. Its absence skips the `data:` and `subType` checks rather than
|
|
28
|
+
* reporting every key as unknown.
|
|
29
|
+
* @param {Readonly<Record<string, {known?: readonly string[], fieldVocabulary?: boolean}>>} [opts.systems]
|
|
30
|
+
* The system blocks to check, and what each accepts. See
|
|
31
|
+
* {@link DEFAULT_SYSTEM_BLOCKS}.
|
|
23
32
|
* @returns {object[]} Findings, each with a locator where one is obtainable.
|
|
24
33
|
*/
|
|
25
|
-
export function lintNote(note: object, { schemas, index }: {
|
|
34
|
+
export function lintNote(note: object, { schemas, index, vocabulary, systems }: {
|
|
26
35
|
schemas: Record<string, readonly object[]>;
|
|
27
36
|
index?: object | undefined;
|
|
37
|
+
vocabulary?: Record<string, object> | undefined;
|
|
38
|
+
systems?: Readonly<Record<string, {
|
|
39
|
+
known?: readonly string[];
|
|
40
|
+
fieldVocabulary?: boolean;
|
|
41
|
+
}>> | undefined;
|
|
28
42
|
}): object[];
|
|
29
43
|
/**
|
|
30
44
|
* Check every note in a built index against its type's schema.
|
|
@@ -32,13 +46,22 @@ export function lintNote(note: object, { schemas, index }: {
|
|
|
32
46
|
* @param {object} index - From `buildLinkIndex`.
|
|
33
47
|
* @param {object} opts
|
|
34
48
|
* @param {Record<string, readonly object[]>} opts.schemas - Type → declaration.
|
|
49
|
+
* @param {Record<string, object>} [opts.vocabulary] - Type → the closed regions
|
|
50
|
+
* it declares (#128); see {@link lintNote}.
|
|
35
51
|
* @param {boolean} [opts.references=true] - Whether to check references.
|
|
52
|
+
* @param {Readonly<Record<string, {known?: readonly string[], fieldVocabulary?: boolean}>>} [opts.systems]
|
|
53
|
+
* The system blocks to check. See {@link DEFAULT_SYSTEM_BLOCKS}.
|
|
36
54
|
* @returns {{findings: object[], notes: number}} The findings, and how many
|
|
37
55
|
* notes were inspected.
|
|
38
56
|
*/
|
|
39
|
-
export function lintFrontmatter(index: object, { schemas, references }: {
|
|
57
|
+
export function lintFrontmatter(index: object, { schemas, vocabulary, references, systems }: {
|
|
40
58
|
schemas: Record<string, readonly object[]>;
|
|
59
|
+
vocabulary?: Record<string, object> | undefined;
|
|
41
60
|
references?: boolean | undefined;
|
|
61
|
+
systems?: Readonly<Record<string, {
|
|
62
|
+
known?: readonly string[];
|
|
63
|
+
fieldVocabulary?: boolean;
|
|
64
|
+
}>> | undefined;
|
|
42
65
|
}): {
|
|
43
66
|
findings: object[];
|
|
44
67
|
notes: number;
|
|
@@ -72,3 +95,25 @@ export function lintFrontmatter(index: object, { schemas, references }: {
|
|
|
72
95
|
* @type {ReadonlySet<string>}
|
|
73
96
|
*/
|
|
74
97
|
export const UNIVERSAL_KEYS: ReadonlySet<string>;
|
|
98
|
+
/**
|
|
99
|
+
* The system blocks a build checks, and what each accepts beyond the shared
|
|
100
|
+
* vocabulary.
|
|
101
|
+
*
|
|
102
|
+
* One entry, because one system is what every existing tree declares — and the
|
|
103
|
+
* default is a *declaration*, not a hard-coded assumption: a build that ships
|
|
104
|
+
* content for two systems passes both, and each block is then checked against
|
|
105
|
+
* its own vocabulary rather than against the other's (#58). A block nothing
|
|
106
|
+
* declares is not checked, because nothing can say what it may carry, and
|
|
107
|
+
* inventing a rule for it would report a correct tree red.
|
|
108
|
+
*
|
|
109
|
+
* `fieldVocabulary` says the note type's own declared field names are keys of
|
|
110
|
+
* this block. True for `sohl` and untrue in general: those names come from the
|
|
111
|
+
* `itemBuilders` registry that this system declares, and a second system's
|
|
112
|
+
* notes write a second system's fields.
|
|
113
|
+
*
|
|
114
|
+
* @type {Readonly<Record<string, {known?: readonly string[], fieldVocabulary?: boolean}>>}
|
|
115
|
+
*/
|
|
116
|
+
export const DEFAULT_SYSTEM_BLOCKS: Readonly<Record<string, {
|
|
117
|
+
known?: readonly string[];
|
|
118
|
+
fieldVocabulary?: boolean;
|
|
119
|
+
}>>;
|
|
@@ -10,14 +10,27 @@
|
|
|
10
10
|
* order among packs of one type — and every one of them is written before the
|
|
11
11
|
* actors pass that reads them.
|
|
12
12
|
*
|
|
13
|
+
* **Scoped to one system when the caller has one (#58).** A being addresses an
|
|
14
|
+
* item by `(type, shortcode)`, and that address is unique within one system and
|
|
15
|
+
* not across two: `skill:sword` is an HM3 skill *and* a SoHL skill, with
|
|
16
|
+
* different data models behind them. The reference itself is unambiguous — it
|
|
17
|
+
* sits inside a system block, so position says which it means — but the
|
|
18
|
+
* resolver has to know which catalogue it is searching, or it resolves the pair
|
|
19
|
+
* by whichever pack was read first. So an Actor pass reads the Item packs of
|
|
20
|
+
* **its own** system plus the system-neutral ones, which belong to every
|
|
21
|
+
* system. Asking for no system reads them all, which is every single-system
|
|
22
|
+
* build and the behaviour this always had.
|
|
23
|
+
*
|
|
13
24
|
* @param {object} [config] - The resolved build configuration. Defaults to this
|
|
14
25
|
* repository's.
|
|
26
|
+
* @param {string|null} [system] - The system whose catalogue is wanted. Omitted
|
|
27
|
+
* or `null`, every Item pack is read.
|
|
15
28
|
* @returns {string[]} Each Item pack's JSON directory. Empty when the
|
|
16
29
|
* repository ships no items at all, which is a legitimate package: the actors
|
|
17
30
|
* pass accepts an empty list and reports an item it cannot resolve per
|
|
18
31
|
* `(type, shortcode)` instead, naming the being (#49).
|
|
19
32
|
*/
|
|
20
|
-
export function itemPackJsonDirs(config?: object): string[];
|
|
33
|
+
export function itemPackJsonDirs(config?: object, system?: string | null): string[];
|
|
21
34
|
/**
|
|
22
35
|
* The passes to run, ordered so that each one follows the output it reads.
|
|
23
36
|
*
|
|
@@ -62,8 +62,8 @@ export function walkMarkdownTree(rootDir: string, { skipDirectories }?: {
|
|
|
62
62
|
}, void, unknown>;
|
|
63
63
|
/**
|
|
64
64
|
* Resolve the required `sohl.archetype` frontmatter for an Item/Actor entry
|
|
65
|
-
* (
|
|
66
|
-
*
|
|
65
|
+
* (the archetype contract, #604). The property is a nullable number that
|
|
66
|
+
* authors must state explicitly:
|
|
67
67
|
* - a number → the document is an archetype of that priority.
|
|
68
68
|
* - `null` → the document is not an archetype.
|
|
69
69
|
* - absent → an authoring error (throws), so "not an archetype" is never
|
|
@@ -79,19 +79,27 @@ export function walkMarkdownTree(rootDir: string, { skipDirectories }?: {
|
|
|
79
79
|
*/
|
|
80
80
|
export function resolveArchetype(fm: object, label: string): number | undefined;
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
82
|
+
* The value a document's `system.archetype` carries, from the required
|
|
83
|
+
* `sohl.archetype` frontmatter (#126, sohl#1780).
|
|
84
|
+
*
|
|
85
|
+
* A **schema field**, so the tri-state is written out in full rather than
|
|
86
|
+
* expressed by a key's presence: a number is an archetype at that priority,
|
|
87
|
+
* and `null` is not an archetype. This is where {@link resolveArchetype}'s
|
|
88
|
+
* `undefined` becomes the field's `null` — an emitted `undefined` would be
|
|
89
|
+
* dropped by `JSON.stringify`, leaving the compiled document with no
|
|
90
|
+
* `archetype` at all and the tri-state readable as two.
|
|
91
|
+
*
|
|
92
|
+
* **`0` is an archetype.** It is the priority SoHL's own archetypes ship at,
|
|
93
|
+
* and it is falsy, so this returns it unchanged and every caller must ask
|
|
94
|
+
* `typeof v === "number"` rather than testing truthiness.
|
|
95
|
+
*
|
|
96
|
+
* @param {object} fm Parsed frontmatter.
|
|
97
|
+
* @param {string} label Human-readable context for error messages.
|
|
98
|
+
* @returns {number|null} The archetype priority, or `null` for a document
|
|
99
|
+
* that is not an archetype.
|
|
92
100
|
* @throws {Error} When `sohl.archetype` is absent or invalid.
|
|
93
101
|
*/
|
|
94
|
-
export function
|
|
102
|
+
export function systemArchetype(fm: object, label: string): number | null;
|
|
95
103
|
/**
|
|
96
104
|
* Generates a compendium-source filename: `Name_id.json` with non-
|
|
97
105
|
* alphanumeric runs replaced by underscores.
|
package/types/engine/ids.d.mts
CHANGED
|
@@ -84,6 +84,16 @@ export function pageUuid(entryUuid: string, pageId: string): string;
|
|
|
84
84
|
* @type {ReadonlySet<string>}
|
|
85
85
|
*/
|
|
86
86
|
export const MAP_TYPES: ReadonlySet<string>;
|
|
87
|
+
/**
|
|
88
|
+
* The map subTypes, which differ only in the canvas defaults derived for them.
|
|
89
|
+
*
|
|
90
|
+
* They were three *types* until #174, which cost three entries in the pack
|
|
91
|
+
* router, three in the claims set and three in every consumer's section config
|
|
92
|
+
* — for one idea that the specification had always described as one type.
|
|
93
|
+
*
|
|
94
|
+
* @type {readonly string[]}
|
|
95
|
+
*/
|
|
96
|
+
export const MAP_SUBTYPES: readonly string[];
|
|
87
97
|
/**
|
|
88
98
|
* Content type → the pack its documents compile into, and the document type
|
|
89
99
|
* that pack holds.
|
package/types/engine/index.d.mts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
export * as ids from "./ids.mjs";
|
|
2
|
+
export * as systemBlock from "./system-block.mjs";
|
|
2
3
|
export * as codeFences from "./code-fences.mjs";
|
|
3
4
|
export * as frontmatter from "./frontmatter.mjs";
|
|
4
5
|
export * as contentTree from "./content-tree.mjs";
|
|
5
6
|
export * as packConfig from "./pack-config.mjs";
|
|
6
7
|
export * as packRouter from "./pack-router.mjs";
|
|
8
|
+
export * as noteClaims from "./note-claims.mjs";
|
|
7
9
|
export * as contentPackage from "./content-package.mjs";
|
|
8
10
|
export * as notePackage from "./note-package.mjs";
|
|
9
11
|
export * as retiredFields from "./retired-fields.mjs";
|
|
10
12
|
export * as homepage from "./homepage.mjs";
|
|
11
13
|
export * as noteSchemas from "./note-schemas.mjs";
|
|
14
|
+
export * as noteVocabulary from "./note-vocabulary.mjs";
|
|
12
15
|
export * as contentSlug from "./content-slug.mjs";
|
|
13
16
|
export * as contentAddress from "./content-address.mjs";
|
|
14
17
|
export * as foreignManifests from "./foreign-manifests.mjs";
|
|
@@ -21,9 +24,11 @@ export * as webWikilinks from "./web-wikilinks.mjs";
|
|
|
21
24
|
export * as contentTables from "./content-tables.mjs";
|
|
22
25
|
export * as helpers from "./helpers.mjs";
|
|
23
26
|
export * as itemRegistry from "./item-registry.mjs";
|
|
27
|
+
export * as documentSubtypes from "./document-subtypes.mjs";
|
|
24
28
|
export * as itemDocs from "./item-docs.mjs";
|
|
25
29
|
export * as wikilinks from "./wikilinks.mjs";
|
|
26
30
|
export * as wikilinkSyntax from "./wikilink-syntax.mjs";
|
|
31
|
+
export * as aliasIndex from "./alias-index.mjs";
|
|
27
32
|
export * as siteIndex from "./site-index.mjs";
|
|
28
33
|
export * as baseCompiler from "./base-compiler.mjs";
|
|
29
34
|
export * as journals from "./journals.mjs";
|
|
@@ -24,10 +24,27 @@ export function itemTypes(): ReadonlySet<string>;
|
|
|
24
24
|
* failing as an anonymous `is not a function` (#1504).
|
|
25
25
|
*
|
|
26
26
|
* @param {string} type - The note's `type` frontmatter.
|
|
27
|
+
* @param {string} [system] - The system compiling it, where a build declares
|
|
28
|
+
* more than one registry. Omitted, a type only one registry declares still
|
|
29
|
+
* resolves; a contested one throws rather than picking a side.
|
|
27
30
|
* @returns {(fm: object) => object} The builder for that type.
|
|
28
31
|
* @throws {Error} When the configuration registers no builder for `type`.
|
|
29
32
|
*/
|
|
30
|
-
export function itemBuilder(type: string): (fm: object) => object;
|
|
33
|
+
export function itemBuilder(type: string, system?: string): (fm: object) => object;
|
|
34
|
+
/**
|
|
35
|
+
* The frontmatter fields a type's registry entry declares, if any.
|
|
36
|
+
*
|
|
37
|
+
* Sparse by design: a type whose entry declares none compiles normally and is
|
|
38
|
+
* simply undocumented (#22). What reads it is the `system`-block passthrough,
|
|
39
|
+
* which has to know which paths a declared field already writes before it
|
|
40
|
+
* writes the rest (#58).
|
|
41
|
+
*
|
|
42
|
+
* @param {string} type - The item type.
|
|
43
|
+
* @param {string} [system] - The system compiling it, where a build declares
|
|
44
|
+
* more than one registry.
|
|
45
|
+
* @returns {readonly object[]|undefined} The declaration, or `undefined`.
|
|
46
|
+
*/
|
|
47
|
+
export function itemFields(type: string, system?: string): readonly object[] | undefined;
|
|
31
48
|
/**
|
|
32
49
|
* The default art for an item type — the image a note of that type is given
|
|
33
50
|
* when it carries no `img:` of its own.
|
|
@@ -51,7 +68,9 @@ export function itemBuilder(type: string): (fm: object) => object;
|
|
|
51
68
|
* One spelling, one meaning, wherever it is written.
|
|
52
69
|
*
|
|
53
70
|
* @param {string} type - the item type.
|
|
71
|
+
* @param {string} [system] - The system compiling it, where a build declares
|
|
72
|
+
* more than one registry.
|
|
54
73
|
* @returns {string} The default image path for that type.
|
|
55
74
|
* @throws {Error} When the type's registry entry pairs no `img`.
|
|
56
75
|
*/
|
|
57
|
-
export function itemArt(type: string): string;
|
|
76
|
+
export function itemArt(type: string, system?: string): string;
|
|
@@ -24,18 +24,34 @@ export function canonicalKey(pkg: string, type: string, shortcode: string): stri
|
|
|
24
24
|
/**
|
|
25
25
|
* Reads a canonical key back into its parts.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
27
|
+
* Parsing is plain positional counting: split on the separator, require
|
|
28
|
+
* {@link CANONICAL_KEY_SEGMENTS} of them, and assign each position its field.
|
|
29
|
+
* **The charset rule is what makes that sound** — every segment is
|
|
30
|
+
* `^[A-Za-z0-9]+$` (`ADDRESS_SEGMENT_PATTERN` in `engine/address-charset.mjs`),
|
|
31
|
+
* so the hyphen is purely a separator and the count alone determines every
|
|
32
|
+
* field. That is enforced at each of the three sources rather than assumed of
|
|
33
|
+
* the data: shortcodes by `content-lint.mjs` (#1397), `contentPackage` by
|
|
34
|
+
* `defineConfig` (#59), and types are bare words. Were any of them free to
|
|
35
|
+
* carry a hyphen, no amount of counting would recover the fields and the reader
|
|
36
|
+
* would need a vocabulary to match against instead.
|
|
37
|
+
*
|
|
38
|
+
* **Nothing to read and nothing readable are different answers.** A key that
|
|
39
|
+
* cannot be canonical — `harn-adventures-skill-melee`, four segments — yields
|
|
40
|
+
* `null`, while an absent or blank input yields `undefined`. Both are falsy, so
|
|
41
|
+
* every call site (all of which test the result for truthiness) is unaffected;
|
|
42
|
+
* the distinction is there so a caller reporting "this key is unreadable" can
|
|
43
|
+
* tell that it has a key to report about.
|
|
44
|
+
*
|
|
45
|
+
* @param {unknown} key - A canonical key, or nothing.
|
|
46
|
+
* @returns {{package: string, type: string, shortcode: string}|null|undefined}
|
|
47
|
+
* The parts; `null` when there is a string that is not in canonical form;
|
|
48
|
+
* `undefined` when there is no key at all.
|
|
33
49
|
*/
|
|
34
|
-
export function readCanonicalKey(key:
|
|
50
|
+
export function readCanonicalKey(key: unknown): {
|
|
35
51
|
package: string;
|
|
36
52
|
type: string;
|
|
37
53
|
shortcode: string;
|
|
38
|
-
} | null;
|
|
54
|
+
} | null | undefined;
|
|
39
55
|
/**
|
|
40
56
|
* The package-relative address a site-absolute URL records as.
|
|
41
57
|
*
|
|
@@ -151,6 +167,17 @@ export function manifestsComplete(localPackages: Iterable<string>, manifestPacka
|
|
|
151
167
|
* relaxes the build rather than breaking it.
|
|
152
168
|
*/
|
|
153
169
|
export const LINK_PACKAGES: readonly string[];
|
|
170
|
+
/**
|
|
171
|
+
* How many segments a canonical key has, and therefore how many the reader
|
|
172
|
+
* below counts.
|
|
173
|
+
*
|
|
174
|
+
* Named rather than written as a literal because it is the *grammar*, not an
|
|
175
|
+
* implementation detail of one function: it is the number a change to the
|
|
176
|
+
* address form would move, and the thing a reader of that change has to find.
|
|
177
|
+
*
|
|
178
|
+
* @type {number}
|
|
179
|
+
*/
|
|
180
|
+
export const CANONICAL_KEY_SEGMENTS: number;
|
|
154
181
|
/**
|
|
155
182
|
* Manifest format version.
|
|
156
183
|
*
|
|
@@ -6,14 +6,19 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export function isMapType(type?: string): boolean;
|
|
8
8
|
/**
|
|
9
|
-
* The canvas profile for a map
|
|
9
|
+
* The canvas profile for a map subType.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Keyed on the subType rather than the type since #174: every map note is
|
|
12
|
+
* `type: map`, and which canvas it derives is the one thing the three
|
|
13
|
+
* spellings ever decided.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} subType - The note's `subType`.
|
|
16
|
+
* @returns {object} The profile from {@link MAP_SUBTYPE_PROFILES}.
|
|
17
|
+
* @throws {Error} When the subType is not a map subType — the build's
|
|
18
|
+
* fail-fast contract, so a typo never ships a scene with Foundry's own
|
|
19
|
+
* defaults.
|
|
15
20
|
*/
|
|
16
|
-
export function mapProfile(
|
|
21
|
+
export function mapProfile(subType: string): object;
|
|
17
22
|
/**
|
|
18
23
|
* The id of one region within its scene.
|
|
19
24
|
*
|
|
@@ -141,7 +146,7 @@ export function buildShape(spec: object, geom: MapGeometry): object;
|
|
|
141
146
|
*/
|
|
142
147
|
export function buildScene(fm: object, ctx: object): object;
|
|
143
148
|
/**
|
|
144
|
-
* Synthesise the scene's single embedded Level from `
|
|
149
|
+
* Synthesise the scene's single embedded Level from `img:` / `overlay:`.
|
|
145
150
|
*
|
|
146
151
|
* Authors never write `levels:`. A scene must ship at least one Level — the
|
|
147
152
|
* client-side `_preCreate` net that would create one does not run for offline
|
|
@@ -151,9 +156,13 @@ export function buildScene(fm: object, ctx: object): object;
|
|
|
151
156
|
*
|
|
152
157
|
* @param {object} sohl - The note's `sohl:` block.
|
|
153
158
|
* @param {string} sceneId - The owning scene's `_id`.
|
|
159
|
+
* @param {string} [img] - The background art, already resolved from the note.
|
|
160
|
+
* Passed by {@link buildScene}, which reads it from the note rather than from
|
|
161
|
+
* the block; defaults to whichever spelling the block itself carries, so a
|
|
162
|
+
* direct two-argument call still works (#142).
|
|
154
163
|
* @returns {object} The Level document, keyed for the pack.
|
|
155
164
|
*/
|
|
156
|
-
export function buildLevel(sohl: object, sceneId: string): object;
|
|
165
|
+
export function buildLevel(sohl: object, sceneId: string, img?: string): object;
|
|
157
166
|
/**
|
|
158
167
|
* Compile the `walls:` and `doors:` blocks into Wall documents.
|
|
159
168
|
*
|
|
@@ -225,9 +234,8 @@ export function buildLocations(sohl: object, geom: MapGeometry, ctx: object): ob
|
|
|
225
234
|
* @returns {object[]} The Region documents.
|
|
226
235
|
*/
|
|
227
236
|
export function buildRegions(sohl: object, geom: MapGeometry, ctx: object): object[];
|
|
228
|
-
export { MAP_TYPES };
|
|
229
237
|
/**
|
|
230
|
-
* Per-
|
|
238
|
+
* Per-subtype canvas defaults, emitted **explicitly** on every scene.
|
|
231
239
|
*
|
|
232
240
|
* This is not a convenience. `grid.type`, `grid.distance` and `grid.units` all
|
|
233
241
|
* declare `initial: () => game.system.grid.*`, and there is no `game` at build
|
|
@@ -237,7 +245,7 @@ export { MAP_TYPES };
|
|
|
237
245
|
*
|
|
238
246
|
* @type {Readonly<Record<string, object>>}
|
|
239
247
|
*/
|
|
240
|
-
export const
|
|
248
|
+
export const MAP_SUBTYPE_PROFILES: Readonly<Record<string, object>>;
|
|
241
249
|
/**
|
|
242
250
|
* Foundry's own id for the level a scene is created with
|
|
243
251
|
* (`Scene.metadata.defaultLevelId`). Adopting it makes every reference to the
|
|
@@ -280,4 +288,6 @@ export type MapGeometry = {
|
|
|
280
288
|
*/
|
|
281
289
|
dimensions: number[];
|
|
282
290
|
};
|
|
291
|
+
import { MAP_SUBTYPES } from "./ids.mjs";
|
|
283
292
|
import { MAP_TYPES } from "./ids.mjs";
|
|
293
|
+
export { MAP_SUBTYPES, MAP_TYPES };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The note types a pass of one document type claims — the claim table.
|
|
3
|
+
*
|
|
4
|
+
* Each row restates one pass's `selects`, in the only form that can be asked of
|
|
5
|
+
* a pack the configuration does not declare. A document type no compiler is
|
|
6
|
+
* registered for claims nothing, which is what keeps a prebuilt `Adventure`
|
|
7
|
+
* pack from appearing to answer for any note.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} docType - The Foundry document type a pack holds.
|
|
10
|
+
* @param {ClaimSources} [sources] - What to answer from. Defaults to the
|
|
11
|
+
* configured registries and the systems this toolchain ships.
|
|
12
|
+
* @returns {ReadonlySet<string>} The note types such a pass would claim.
|
|
13
|
+
*/
|
|
14
|
+
export function noteTypesClaimedBy(docType: string, sources?: ClaimSources): ReadonlySet<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Every note type some pack in a configuration would compile.
|
|
17
|
+
*
|
|
18
|
+
* The union across the configured pack list, so a type claimed by any one pack
|
|
19
|
+
* is claimed — which is what keeps a type deliberately unmapped for one system,
|
|
20
|
+
* and claimed for another, silent (#79).
|
|
21
|
+
*
|
|
22
|
+
* @param {object} [config] - The resolved build configuration. Defaults to this
|
|
23
|
+
* repository's.
|
|
24
|
+
* @param {ClaimSources} [sources] - What to answer from.
|
|
25
|
+
* @returns {ReadonlySet<string>} The claimed note types.
|
|
26
|
+
*/
|
|
27
|
+
export function claimedNoteTypes(config?: object, sources?: ClaimSources): ReadonlySet<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Every note type this build knows, whatever any one repository configures.
|
|
30
|
+
*
|
|
31
|
+
* Wider than {@link claimedNoteTypes} on purpose: it is what distinguishes a
|
|
32
|
+
* repository that has not configured a pack for a real content type from an
|
|
33
|
+
* author who wrote a word nothing anywhere compiles. The engine's own types,
|
|
34
|
+
* the types every shipped system maps, and whatever the configured registries
|
|
35
|
+
* declare on top.
|
|
36
|
+
*
|
|
37
|
+
* @param {ClaimSources} [sources] - What to answer from.
|
|
38
|
+
* @returns {ReadonlySet<string>} The vocabulary.
|
|
39
|
+
*/
|
|
40
|
+
export function noteTypeVocabulary(sources?: ClaimSources): ReadonlySet<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Every note in the content tree that no configured pack would compile.
|
|
43
|
+
*
|
|
44
|
+
* Read-only: it walks the tree and reports, and writes nothing. Three kinds of
|
|
45
|
+
* note are passed over, each for a stated reason rather than by omission — a
|
|
46
|
+
* file with no frontmatter is not a note; a note with no `type:` is the
|
|
47
|
+
* frontmatter linter's finding, which can say what a type is *for*; and a
|
|
48
|
+
* retired type is answered by `assertTypeNotRetired` in `ids.mjs`, which names the
|
|
49
|
+
* replacement.
|
|
50
|
+
*
|
|
51
|
+
* @param {object} [config] - The resolved build configuration. Defaults to this
|
|
52
|
+
* repository's.
|
|
53
|
+
* @param {ClaimSources} [sources] - What to answer from.
|
|
54
|
+
* @returns {Array<{file: string, line?: number, column?: number,
|
|
55
|
+
* severity: "error", message: string, type: string}>} One finding per note.
|
|
56
|
+
*/
|
|
57
|
+
export function unclaimedNoteFindings(config?: object, sources?: ClaimSources): Array<{
|
|
58
|
+
file: string;
|
|
59
|
+
line?: number;
|
|
60
|
+
column?: number;
|
|
61
|
+
severity: "error";
|
|
62
|
+
message: string;
|
|
63
|
+
type: string;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Note types that compile into **no compendium document, by design**.
|
|
67
|
+
*
|
|
68
|
+
* A homepage compiles into a *page*: it carries no compendium UUID, appears in
|
|
69
|
+
* no pack and in no link-manifest entry, and every package that publishes one
|
|
70
|
+
* would otherwise be told its front page is unclaimed. It is the one type whose
|
|
71
|
+
* absence from every pack is the intended state rather than a gap.
|
|
72
|
+
*
|
|
73
|
+
* @type {ReadonlySet<string>}
|
|
74
|
+
*/
|
|
75
|
+
export const NEVER_PACKED_TYPES: ReadonlySet<string>;
|
|
76
|
+
/**
|
|
77
|
+
* The note-type → document-subtype maps this toolchain ships.
|
|
78
|
+
*
|
|
79
|
+
* One today. `hm3/` is #139, and when it lands its map joins this list rather
|
|
80
|
+
* than the claim table below growing a second copy of the same fact.
|
|
81
|
+
*
|
|
82
|
+
* `engine/` importing from `sohl/` is the arrangement `generate.mjs` already
|
|
83
|
+
* has — its `COMPILERS` table names the SoHL compilers by class — and for the
|
|
84
|
+
* same reason: the engine owns the *mechanism* that asks each system what it
|
|
85
|
+
* compiles, and the systems own the answers.
|
|
86
|
+
*
|
|
87
|
+
* @type {readonly import("./document-subtypes.mjs").DocumentSubtypeMap[]}
|
|
88
|
+
*/
|
|
89
|
+
export const KNOWN_DOCUMENT_SUBTYPE_MAPS: readonly import("./document-subtypes.mjs").DocumentSubtypeMap[];
|
|
90
|
+
/**
|
|
91
|
+
* What a claim question is asked against.
|
|
92
|
+
*
|
|
93
|
+
* Each field defaults to what the compilers themselves read, so the answer here
|
|
94
|
+
* and the answer a pass gives are drawn from one source. They are parameters so
|
|
95
|
+
* that a test can pose a configuration this toolchain does not ship — two
|
|
96
|
+
* systems cutting the vocabulary differently, a registry declaring nothing —
|
|
97
|
+
* without a content tree or a config file on disk.
|
|
98
|
+
*/
|
|
99
|
+
export type ClaimSources = {
|
|
100
|
+
/**
|
|
101
|
+
* -
|
|
102
|
+
* The systems' note-type → document-subtype maps.
|
|
103
|
+
*/
|
|
104
|
+
maps?: readonly import("./document-subtypes.mjs").DocumentSubtypeMap[] | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* - The declared item vocabulary.
|
|
107
|
+
*/
|
|
108
|
+
itemTypes?: ReadonlySet<string> | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* - The doc-carrying types.
|
|
111
|
+
*/
|
|
112
|
+
docEntryTypes?: ReadonlySet<string> | undefined;
|
|
113
|
+
};
|