@heroiclands/package-build 17.1.0 → 18.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.md +1773 -0
- package/CONTENT.md +288 -72
- package/README.md +1 -1
- package/bin/content-build.mjs +218 -137
- package/bin/package-build.mjs +43 -0
- package/content-config.mjs +62 -67
- package/docs/content-format.md +768 -58
- package/engine/actor-compiler.mjs +586 -0
- package/engine/address-charset.mjs +11 -8
- package/engine/address-diff.mjs +266 -22
- package/engine/anchored-sections.mjs +83 -0
- package/engine/anchors.mjs +83 -0
- package/engine/base-compiler.mjs +148 -18
- package/engine/bundle-notes.mjs +276 -0
- package/engine/bundles.mjs +307 -0
- package/engine/code-fences.mjs +103 -0
- package/engine/compile-corpus.mjs +89 -0
- package/engine/content-address.mjs +267 -5
- package/engine/content-format-check.mjs +54 -11
- package/engine/content-format.mjs +37 -5
- package/engine/content-index.mjs +394 -111
- package/engine/content-links.mjs +185 -77
- package/engine/content-lint.mjs +232 -14
- package/engine/content-package.mjs +2 -1
- package/engine/content-tables.mjs +99 -3
- package/engine/document-subtypes.mjs +49 -6
- package/engine/field-reference.mjs +1 -1
- package/engine/field-spec.mjs +56 -6
- package/engine/folder-notes.mjs +470 -0
- package/engine/foreign-catalog.mjs +195 -4
- package/engine/{manifest-emit.mjs → foundry-entries.mjs} +78 -81
- package/engine/frontmatter-lint.mjs +245 -19
- package/engine/frontmatter.mjs +88 -8
- package/engine/generate.mjs +304 -13
- package/engine/helpers.mjs +293 -64
- package/engine/ids.mjs +137 -2
- package/engine/index-records.mjs +126 -0
- package/engine/index.mjs +23 -5
- package/engine/item-compiler.mjs +349 -0
- package/engine/item-docs.mjs +7 -1
- package/engine/item-registry.mjs +6 -0
- package/engine/journals.mjs +93 -27
- package/engine/macros.mjs +4 -2
- package/engine/metadata-index.mjs +495 -0
- package/engine/note-claims.mjs +146 -25
- package/engine/note-ids.mjs +112 -0
- package/engine/note-renames.mjs +134 -0
- package/engine/note-schemas.mjs +25 -0
- package/engine/note-vocabulary.mjs +110 -27
- package/engine/pack-config.mjs +4 -0
- package/engine/pack-router.mjs +23 -0
- package/engine/retired-fields.mjs +137 -3
- package/engine/scenes.mjs +66 -34
- package/engine/schema-check.mjs +58 -17
- package/engine/site-build.mjs +71 -12
- package/engine/site-index.mjs +20 -7
- package/engine/sql-tables.mjs +485 -0
- package/engine/subtype-registry.mjs +102 -0
- package/engine/system-block.mjs +96 -12
- package/engine/systems.mjs +201 -0
- package/engine/web-wikilinks.mjs +50 -20
- package/engine/wikilink-syntax.mjs +17 -8
- package/engine/wikilinks.mjs +124 -51
- package/engine/yaml-lint.mjs +282 -0
- package/hm3/actors.mjs +352 -0
- package/hm3/default-item-art.mjs +75 -0
- package/hm3/document-subtypes.mjs +134 -0
- package/hm3/index.mjs +56 -0
- package/hm3/item-builders.mjs +84 -0
- package/hm3/item-fields.mjs +180 -0
- package/hm3/items.mjs +96 -0
- package/hm3/template-priority.mjs +85 -0
- package/labels.mjs +191 -0
- package/manifest.mjs +43 -2
- package/package.json +19 -4
- package/release.mjs +62 -7
- package/sohl/actors.mjs +33 -487
- package/sohl/being-info.mjs +16 -7
- package/sohl/default-item-art.mjs +14 -3
- package/sohl/document-subtypes.mjs +16 -10
- package/sohl/item-builders.mjs +14 -5
- package/sohl/item-fields.mjs +68 -7
- package/sohl/items.mjs +44 -258
- package/sohl/note-schemas.mjs +2 -2
- package/types/content-config.d.mts +21 -42
- package/types/engine/actor-compiler.d.mts +204 -0
- package/types/engine/address-charset.d.mts +11 -8
- package/types/engine/address-diff.d.mts +53 -5
- package/types/engine/anchored-sections.d.mts +21 -0
- package/types/engine/anchors.d.mts +20 -0
- package/types/engine/base-compiler.d.mts +17 -17
- package/types/engine/bundle-notes.d.mts +173 -0
- package/types/engine/bundles.d.mts +60 -0
- package/types/engine/code-fences.d.mts +43 -0
- package/types/engine/compile-corpus.d.mts +32 -0
- package/types/engine/content-address.d.mts +205 -5
- package/types/engine/content-format-check.d.mts +6 -2
- package/types/engine/content-format.d.mts +57 -1
- package/types/engine/content-index.d.mts +64 -80
- package/types/engine/content-links.d.mts +52 -7
- package/types/engine/content-lint.d.mts +10 -1
- package/types/engine/content-package.d.mts +2 -1
- package/types/engine/content-tables.d.mts +21 -39
- package/types/engine/document-subtypes.d.mts +37 -3
- package/types/engine/field-spec.d.mts +76 -5
- package/types/engine/folder-notes.d.mts +159 -0
- package/types/engine/foreign-catalog.d.mts +53 -0
- package/types/engine/{manifest-emit.d.mts → foundry-entries.d.mts} +16 -38
- package/types/engine/frontmatter-lint.d.mts +10 -2
- package/types/engine/frontmatter.d.mts +64 -0
- package/types/engine/generate.d.mts +38 -0
- package/types/engine/helpers.d.mts +94 -30
- package/types/engine/ids.d.mts +96 -0
- package/types/engine/index-records.d.mts +68 -0
- package/types/engine/index.d.mts +9 -3
- package/types/engine/item-compiler.d.mts +131 -0
- package/types/engine/journals.d.mts +47 -9
- package/types/engine/metadata-index.d.mts +226 -0
- package/types/engine/note-claims.d.mts +57 -11
- package/types/engine/note-ids.d.mts +38 -0
- package/types/engine/note-renames.d.mts +102 -0
- package/types/engine/note-vocabulary.d.mts +44 -8
- package/types/engine/retired-fields.d.mts +75 -0
- package/types/engine/scenes.d.mts +3 -2
- package/types/engine/schema-check.d.mts +25 -4
- package/types/engine/site-build.d.mts +4 -4
- package/types/engine/site-index.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +185 -0
- package/types/engine/subtype-registry.d.mts +49 -0
- package/types/engine/system-block.d.mts +40 -1
- package/types/engine/systems.d.mts +106 -0
- package/types/engine/web-wikilinks.d.mts +4 -2
- package/types/engine/wikilink-syntax.d.mts +10 -3
- package/types/engine/wikilinks.d.mts +41 -13
- package/types/engine/yaml-lint.d.mts +107 -0
- package/types/hm3/actors.d.mts +48 -0
- package/types/hm3/default-item-art.d.mts +42 -0
- package/types/hm3/document-subtypes.d.mts +24 -0
- package/types/hm3/index.d.mts +7 -0
- package/types/hm3/item-builders.d.mts +11 -0
- package/types/hm3/item-fields.d.mts +12 -0
- package/types/hm3/items.d.mts +23 -0
- package/types/hm3/template-priority.d.mts +21 -0
- package/types/manifest.d.mts +22 -1
- package/types/release.d.mts +9 -4
- package/types/sohl/actors.d.mts +7 -74
- package/types/sohl/being-info.d.mts +8 -27
- package/types/sohl/default-item-art.d.mts +5 -3
- package/types/sohl/items.d.mts +17 -32
- package/engine/foreign-manifests.mjs +0 -126
- package/engine/kb-manifest.mjs +0 -490
- package/types/engine/foreign-manifests.d.mts +0 -43
- package/types/engine/kb-manifest.d.mts +0 -241
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An authored `parent` with any wikilink brackets and label stripped.
|
|
3
|
+
*
|
|
4
|
+
* The specification types `parent` as a `WikiLink`, and a frontmatter link is
|
|
5
|
+
* written as a bare address — but `[[address]]` is what an author reaches for,
|
|
6
|
+
* and Obsidian wrote that form for years. Accepting both costs one regex and
|
|
7
|
+
* removes a failure whose message would have to explain the difference.
|
|
8
|
+
*
|
|
9
|
+
* @param {string|null} value - As authored.
|
|
10
|
+
* @returns {string|null} The bare address.
|
|
11
|
+
*/
|
|
12
|
+
export function bareAddress(value: string | null): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* The canonical address of a folder note in this package.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} pkg - The content package.
|
|
17
|
+
* @param {string} shortcode - The folder's shortcode.
|
|
18
|
+
* @returns {string} `<pkg>-none-folder-<shortcode>`.
|
|
19
|
+
*/
|
|
20
|
+
export function folderAddress(pkg: string, shortcode: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Collect every folder note in a content tree.
|
|
23
|
+
*
|
|
24
|
+
* The walk is the caller's to supply, so this stays testable without a tree on
|
|
25
|
+
* disk and so one build cannot disagree with another about what the corpus is
|
|
26
|
+
* (#243).
|
|
27
|
+
*
|
|
28
|
+
* @param {Iterable<{frontmatter: object|null, absPath: string}>} notes - As
|
|
29
|
+
* yielded by `walkMarkdownTree`.
|
|
30
|
+
* @param {string} pkg - The content package, for the canonical address.
|
|
31
|
+
* @returns {FolderNote[]} One record per folder note, in walk order.
|
|
32
|
+
* @throws {Error} When a folder note is unusable on its own terms — no
|
|
33
|
+
* shortcode, a shortcode that is not an address segment, or no name.
|
|
34
|
+
*/
|
|
35
|
+
export function collectFolderNotes(notes: Iterable<{
|
|
36
|
+
frontmatter: object | null;
|
|
37
|
+
absPath: string;
|
|
38
|
+
}>, pkg: string): FolderNote[];
|
|
39
|
+
/**
|
|
40
|
+
* Index folder notes by every form an author may address one by, and check the
|
|
41
|
+
* invariants that make the index sound.
|
|
42
|
+
*
|
|
43
|
+
* Three keys per folder, and no more: the canonical address, the
|
|
44
|
+
* `folder-<shortcode>` short form, and the bare shortcode. They are the
|
|
45
|
+
* suffixes of the canonical address the grammar admits (#273) — a `packFolder`
|
|
46
|
+
* or `parent` field supplies the type itself, so a bare shortcode is a complete
|
|
47
|
+
* address there.
|
|
48
|
+
*
|
|
49
|
+
* @param {FolderNote[]} folders - From {@link collectFolderNotes}.
|
|
50
|
+
* @returns {{byKey: Map<string, FolderNote>, folders: FolderNote[],
|
|
51
|
+
* resolve: (value: string) => FolderNote, ancestorsOf: (folder: FolderNote)
|
|
52
|
+
* => FolderNote[], parentOf: (folder: FolderNote) => FolderNote|null}}
|
|
53
|
+
* @throws {Error} On a duplicate shortcode, a duplicate id, a dead `parent`,
|
|
54
|
+
* or a parent cycle.
|
|
55
|
+
*/
|
|
56
|
+
export function buildFolderNoteIndex(folders: FolderNote[]): {
|
|
57
|
+
byKey: Map<string, FolderNote>;
|
|
58
|
+
folders: FolderNote[];
|
|
59
|
+
resolve: (value: string) => FolderNote;
|
|
60
|
+
ancestorsOf: (folder: FolderNote) => FolderNote[];
|
|
61
|
+
parentOf: (folder: FolderNote) => FolderNote | null;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The Foundry `Folder` document one folder note compiles to, for one pack.
|
|
65
|
+
*
|
|
66
|
+
* The same folder materialises in several packs — the items pack and the
|
|
67
|
+
* journals pack both hold it when both hold something filed in it — and each
|
|
68
|
+
* copy differs only in `type`, which is the document class the folder holds.
|
|
69
|
+
* The `_id` is shared deliberately: a documentation journal filed beside its
|
|
70
|
+
* item is the whole point, and two ids would put them in two folders that
|
|
71
|
+
* merely looked alike.
|
|
72
|
+
*
|
|
73
|
+
* @param {FolderNote} folder - The folder note.
|
|
74
|
+
* @param {FolderNote|null} parent - Its parent, already resolved.
|
|
75
|
+
* @param {string} documentType - `"Item"`, `"JournalEntry"`, …
|
|
76
|
+
* @param {object} stats - The `_stats` block every emitted document carries.
|
|
77
|
+
* @returns {object} The Folder document.
|
|
78
|
+
*/
|
|
79
|
+
export function folderDocument(folder: FolderNote, parent: FolderNote | null, documentType: string, stats: object): object;
|
|
80
|
+
/**
|
|
81
|
+
* The note type a folder is authored as.
|
|
82
|
+
*
|
|
83
|
+
* @type {string}
|
|
84
|
+
*/
|
|
85
|
+
export const FOLDER_TYPE: string;
|
|
86
|
+
/**
|
|
87
|
+
* The id namespace a derived folder id is hashed under.
|
|
88
|
+
*
|
|
89
|
+
* Distinct from every other document's namespace so a folder and an item
|
|
90
|
+
* sharing a shortcode cannot derive the same id — the collision would be
|
|
91
|
+
* silent, since Foundry keys folders and documents in separate collections and
|
|
92
|
+
* neither would complain.
|
|
93
|
+
*
|
|
94
|
+
* @type {string}
|
|
95
|
+
*/
|
|
96
|
+
export const FOLDER_ID_NAMESPACE: string;
|
|
97
|
+
/**
|
|
98
|
+
* One folder note, read from the tree.
|
|
99
|
+
*
|
|
100
|
+
* @typedef {object} FolderNote
|
|
101
|
+
* @property {string} shortcode - Its `(type, shortcode)` identity.
|
|
102
|
+
* @property {string} address - The canonical `<pkg>-none-folder-<shortcode>`.
|
|
103
|
+
* @property {string} name - The display name.
|
|
104
|
+
* @property {string|null} color - CSS hex, or `null`.
|
|
105
|
+
* @property {Record<string, string|null>} parent - The parent's authored
|
|
106
|
+
* address per pack, keyed by pack name with {@link DEFAULT_PARENT} for the
|
|
107
|
+
* unstated case. A folder's identity is one thing; its hierarchy is per-pack.
|
|
108
|
+
* @property {string} id - The Foundry id: authored, or derived from `address`.
|
|
109
|
+
* @property {boolean} derivedId - Whether `id` was derived rather than authored.
|
|
110
|
+
* @property {string} absPath - The file it was read from, for diagnostics.
|
|
111
|
+
*/
|
|
112
|
+
/**
|
|
113
|
+
* The key a per-pack `parent` map uses for "everywhere else".
|
|
114
|
+
*
|
|
115
|
+
* Spelled out rather than left as the absence of a key, so a map that states
|
|
116
|
+
* only exceptions still reads as a complete answer.
|
|
117
|
+
*
|
|
118
|
+
* @type {string}
|
|
119
|
+
*/
|
|
120
|
+
export const DEFAULT_PARENT: string;
|
|
121
|
+
/**
|
|
122
|
+
* One folder note, read from the tree.
|
|
123
|
+
*/
|
|
124
|
+
export type FolderNote = {
|
|
125
|
+
/**
|
|
126
|
+
* - Its `(type, shortcode)` identity.
|
|
127
|
+
*/
|
|
128
|
+
shortcode: string;
|
|
129
|
+
/**
|
|
130
|
+
* - The canonical `<pkg>-none-folder-<shortcode>`.
|
|
131
|
+
*/
|
|
132
|
+
address: string;
|
|
133
|
+
/**
|
|
134
|
+
* - The display name.
|
|
135
|
+
*/
|
|
136
|
+
name: string;
|
|
137
|
+
/**
|
|
138
|
+
* - CSS hex, or `null`.
|
|
139
|
+
*/
|
|
140
|
+
color: string | null;
|
|
141
|
+
/**
|
|
142
|
+
* - The parent's authored
|
|
143
|
+
* address per pack, keyed by pack name with {@link DEFAULT_PARENT} for the
|
|
144
|
+
* unstated case. A folder's identity is one thing; its hierarchy is per-pack.
|
|
145
|
+
*/
|
|
146
|
+
parent: Record<string, string | null>;
|
|
147
|
+
/**
|
|
148
|
+
* - The Foundry id: authored, or derived from `address`.
|
|
149
|
+
*/
|
|
150
|
+
id: string;
|
|
151
|
+
/**
|
|
152
|
+
* - Whether `id` was derived rather than authored.
|
|
153
|
+
*/
|
|
154
|
+
derivedId: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* - The file it was read from, for diagnostics.
|
|
157
|
+
*/
|
|
158
|
+
absPath: string;
|
|
159
|
+
};
|
|
@@ -92,6 +92,59 @@ export function fetchCatalog(config: object, rel: {
|
|
|
92
92
|
export function fetchCatalogFromPath(config: object, rel: {
|
|
93
93
|
id: string;
|
|
94
94
|
}, source: string): Promise<string>;
|
|
95
|
+
/**
|
|
96
|
+
* Fetch one dependency's published content index (#239).
|
|
97
|
+
*
|
|
98
|
+
* **The chain is entirely declared.** The relationship names the dependency's
|
|
99
|
+
* manifest, the manifest advertises `flags.metadataUrl`, and that URL is the
|
|
100
|
+
* index — so nothing here holds an address of its own, and a dependency that
|
|
101
|
+
* moves its release assets does not break its consumers.
|
|
102
|
+
*
|
|
103
|
+
* Pinned by the same rule as the catalogue: `compatibility.verified` is the
|
|
104
|
+
* version this repository was built against, so a floating `releases/latest`
|
|
105
|
+
* URL is rewritten to it. A consumer resolving addresses against whatever the
|
|
106
|
+
* dependency published this morning is not reproducible.
|
|
107
|
+
*
|
|
108
|
+
* Idempotent: a complete cache for the resolved version is left alone.
|
|
109
|
+
*
|
|
110
|
+
* @param {object} config - The resolved build configuration.
|
|
111
|
+
* @param {{id: string, manifest: string, verified?: string}} rel - The declared
|
|
112
|
+
* relationship.
|
|
113
|
+
* @returns {Promise<string>} The cached index file.
|
|
114
|
+
*/
|
|
115
|
+
export function fetchMetadata(config: object, rel: {
|
|
116
|
+
id: string;
|
|
117
|
+
manifest: string;
|
|
118
|
+
verified?: string;
|
|
119
|
+
}): Promise<string>;
|
|
120
|
+
/**
|
|
121
|
+
* Fill the index cache from a locally built artifact rather than a release.
|
|
122
|
+
*
|
|
123
|
+
* The counterpart of {@link fetchCatalogFromPath}, and the same escape hatch
|
|
124
|
+
* for the same reason: two packages being changed together cannot each wait for
|
|
125
|
+
* the other to ship. The index is looked for beside the manifest — which is
|
|
126
|
+
* where a build leaves it and where the release publishes it — so a package
|
|
127
|
+
* directory and an unpacked zip are both usable as-is.
|
|
128
|
+
*
|
|
129
|
+
* @param {object} config - The resolved build configuration.
|
|
130
|
+
* @param {{id: string}} rel - The declared relationship.
|
|
131
|
+
* @param {string} source - Path to the artifact or its directory.
|
|
132
|
+
* @returns {Promise<string>} The cached index file.
|
|
133
|
+
*/
|
|
134
|
+
export function fetchMetadataFromPath(config: object, rel: {
|
|
135
|
+
id: string;
|
|
136
|
+
}, source: string): Promise<string>;
|
|
137
|
+
/**
|
|
138
|
+
* Fetch every declared dependency's content index.
|
|
139
|
+
*
|
|
140
|
+
* A wider set than {@link fetchAllCatalogs}: an index is fetched for *every*
|
|
141
|
+
* dependency, a catalogue only for those declaring `itemCatalog: true`. See
|
|
142
|
+
* {@link metadataRelationships} for why the two sets differ.
|
|
143
|
+
*
|
|
144
|
+
* @param {object} config - The resolved build configuration.
|
|
145
|
+
* @returns {Promise<number>} How many indexes were fetched.
|
|
146
|
+
*/
|
|
147
|
+
export function fetchAllMetadata(config: object): Promise<number>;
|
|
95
148
|
/**
|
|
96
149
|
* Fetch every opted-in dependency. The `deps fetch` command.
|
|
97
150
|
*
|
|
@@ -55,7 +55,7 @@ export function entriesForNote(fm: object, name: string, address: string, body:
|
|
|
55
55
|
* @returns {{entries: Array<object>, notes: number,
|
|
56
56
|
* skipped: Array<{file: string, reason: string}>}}
|
|
57
57
|
*/
|
|
58
|
-
export function
|
|
58
|
+
export function collectFoundryEntries(contentBase: string, ctx: object): {
|
|
59
59
|
entries: Array<object>;
|
|
60
60
|
notes: number;
|
|
61
61
|
skipped: Array<{
|
|
@@ -74,7 +74,7 @@ export function collectManifestEntries(contentBase: string, ctx: object): {
|
|
|
74
74
|
* @returns {{contentPackage: string, foundryPackageId: string, packRouter: object,
|
|
75
75
|
* web: boolean, skipDirectories: readonly string[]}}
|
|
76
76
|
*/
|
|
77
|
-
export function
|
|
77
|
+
export function foundryIdentities(config?: object): {
|
|
78
78
|
contentPackage: string;
|
|
79
79
|
foundryPackageId: string;
|
|
80
80
|
packRouter: object;
|
|
@@ -82,45 +82,23 @@ export function manifestContext(config?: object): {
|
|
|
82
82
|
skipDirectories: readonly string[];
|
|
83
83
|
};
|
|
84
84
|
/**
|
|
85
|
-
*
|
|
85
|
+
* The identities an emission runs against, from configuration.
|
|
86
86
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
87
|
+
* {@link foundryIdentities} plus what only a *manifest* emission needs. The
|
|
88
|
+
* split is what lets the content index derive the same Foundry addresses from
|
|
89
|
+
* the same code without also depending on whether the package publishes pages,
|
|
90
|
+
* which is no part of a UUID (#239).
|
|
91
91
|
*
|
|
92
|
-
* @param {object} [
|
|
93
|
-
* @
|
|
94
|
-
*
|
|
95
|
-
* @param {string} [options.outDir] - Where to write; defaults to the configured
|
|
96
|
-
* `paths.manifestOut`.
|
|
97
|
-
* @param {object} [options.config] - A resolved configuration; loaded when
|
|
98
|
-
* omitted.
|
|
99
|
-
* @returns {{written: Array<{package: string, file: string, count: number}>,
|
|
100
|
-
* entries: number, notes: number,
|
|
101
|
-
* skipped: Array<{file: string, reason: string}>}}
|
|
102
|
-
* @throws {Error} When the repository does not declare that it publishes a
|
|
103
|
-
* manifest, when the tree is absent, or when it yields no published note — a
|
|
104
|
-
* manifest claiming this package publishes nothing is worse than none, since
|
|
105
|
-
* a consumer reads it as authoritative and turns every link into this package
|
|
106
|
-
* into a reported typo.
|
|
92
|
+
* @param {object} [config] - A resolved configuration; loaded when omitted.
|
|
93
|
+
* @returns {{contentPackage: string, foundryPackageId: string, packRouter: object,
|
|
94
|
+
* web: boolean, skipDirectories: readonly string[]}}
|
|
107
95
|
*/
|
|
108
|
-
export function
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
package: string;
|
|
115
|
-
file: string;
|
|
116
|
-
count: number;
|
|
117
|
-
}>;
|
|
118
|
-
entries: number;
|
|
119
|
-
notes: number;
|
|
120
|
-
skipped: Array<{
|
|
121
|
-
file: string;
|
|
122
|
-
reason: string;
|
|
123
|
-
}>;
|
|
96
|
+
export function entryContext(config?: object): {
|
|
97
|
+
contentPackage: string;
|
|
98
|
+
foundryPackageId: string;
|
|
99
|
+
packRouter: object;
|
|
100
|
+
web: boolean;
|
|
101
|
+
skipDirectories: readonly string[];
|
|
124
102
|
};
|
|
125
103
|
/**
|
|
126
104
|
* The reserved anchor name for a journal's **first** page.
|
|
@@ -29,9 +29,13 @@ export function matchesKind(value: unknown, kind: string): boolean;
|
|
|
29
29
|
* @param {Readonly<Record<string, {known?: readonly string[], fieldVocabulary?: boolean}>>} [opts.systems]
|
|
30
30
|
* The system blocks to check, and what each accepts. See
|
|
31
31
|
* {@link DEFAULT_SYSTEM_BLOCKS}.
|
|
32
|
+
* @param {readonly string[]} [opts.packs] - The pack names this package
|
|
33
|
+
* declares, for a `data:` field whose map is keyed by pack. Supplied by the
|
|
34
|
+
* caller like `schemas` and `vocabulary`, and absent it no claim is made
|
|
35
|
+
* about those keys.
|
|
32
36
|
* @returns {object[]} Findings, each with a locator where one is obtainable.
|
|
33
37
|
*/
|
|
34
|
-
export function lintNote(note: object, { schemas, index, vocabulary, systems }: {
|
|
38
|
+
export function lintNote(note: object, { schemas, index, vocabulary, packs, systems }: {
|
|
35
39
|
schemas: Record<string, readonly object[]>;
|
|
36
40
|
index?: object | undefined;
|
|
37
41
|
vocabulary?: Record<string, object> | undefined;
|
|
@@ -39,6 +43,7 @@ export function lintNote(note: object, { schemas, index, vocabulary, systems }:
|
|
|
39
43
|
known?: readonly string[];
|
|
40
44
|
fieldVocabulary?: boolean;
|
|
41
45
|
}>> | undefined;
|
|
46
|
+
packs?: readonly string[] | undefined;
|
|
42
47
|
}): object[];
|
|
43
48
|
/**
|
|
44
49
|
* Check every note in a built index against its type's schema.
|
|
@@ -51,10 +56,12 @@ export function lintNote(note: object, { schemas, index, vocabulary, systems }:
|
|
|
51
56
|
* @param {boolean} [opts.references=true] - Whether to check references.
|
|
52
57
|
* @param {Readonly<Record<string, {known?: readonly string[], fieldVocabulary?: boolean}>>} [opts.systems]
|
|
53
58
|
* The system blocks to check. See {@link DEFAULT_SYSTEM_BLOCKS}.
|
|
59
|
+
* @param {readonly string[]} [opts.packs] - The declared pack names; see
|
|
60
|
+
* {@link lintNote}.
|
|
54
61
|
* @returns {{findings: object[], notes: number}} The findings, and how many
|
|
55
62
|
* notes were inspected.
|
|
56
63
|
*/
|
|
57
|
-
export function lintFrontmatter(index: object, { schemas, vocabulary, references, systems }: {
|
|
64
|
+
export function lintFrontmatter(index: object, { schemas, vocabulary, packs, references, systems }: {
|
|
58
65
|
schemas: Record<string, readonly object[]>;
|
|
59
66
|
vocabulary?: Record<string, object> | undefined;
|
|
60
67
|
references?: boolean | undefined;
|
|
@@ -62,6 +69,7 @@ export function lintFrontmatter(index: object, { schemas, vocabulary, references
|
|
|
62
69
|
known?: readonly string[];
|
|
63
70
|
fieldVocabulary?: boolean;
|
|
64
71
|
}>> | undefined;
|
|
72
|
+
packs?: readonly string[] | undefined;
|
|
65
73
|
}): {
|
|
66
74
|
findings: object[];
|
|
67
75
|
notes: number;
|
|
@@ -9,6 +9,40 @@ export function getFrontmatter(fm: any, key: any, defaultValue?: undefined): any
|
|
|
9
9
|
* Falls back to top-level `fm[key]` if `sohl` doesn't carry the key.
|
|
10
10
|
*/
|
|
11
11
|
export function sohlField(fm: any, key: any, defaultValue?: undefined): any;
|
|
12
|
+
/**
|
|
13
|
+
* Read a `sohl:` field, seeing the **destination** position as well (#126).
|
|
14
|
+
*
|
|
15
|
+
* Five declarations resolve their value by re-reading the note rather than by
|
|
16
|
+
* taking the one {@link module:engine/system-block.resolveFieldValue} handed
|
|
17
|
+
* them — `subType`, `charges`, a mystery's `skillAptitudes`, an affiliation's
|
|
18
|
+
* `relations` and a projectile's impact die — because each validates a *shape
|
|
19
|
+
* spread over several keys* rather than coercing one scalar.
|
|
20
|
+
*
|
|
21
|
+
* That was equivalent while every note authored inside the block, and stopped
|
|
22
|
+
* being so once a note may author at `sohl.system.<to>` instead: {@link
|
|
23
|
+
* sohlField} sees `sohl.<key>` and the top level, never inside `sohl.system`.
|
|
24
|
+
* So those five read as unset and shipped their empty value — a missing
|
|
25
|
+
* `subType` is a thrown build error, and the other four ship empty in silence,
|
|
26
|
+
* which is the failure class the passthrough exists to prevent.
|
|
27
|
+
*
|
|
28
|
+
* The **destination wins**, matching every other field's resolution order.
|
|
29
|
+
*
|
|
30
|
+
* `legacyKey` is for the one pair whose two positions are spelled differently:
|
|
31
|
+
* a projectile authors `impact.die` and stores `impactBase.die`, so the reader
|
|
32
|
+
* has to be told both. It is the same split `FieldSpec.name`/`legacyKey` makes
|
|
33
|
+
* (#305), for the same reason — one name cannot key two positions.
|
|
34
|
+
*
|
|
35
|
+
* @param {object} fm - The note's frontmatter.
|
|
36
|
+
* @param {string} to - The key at the destination, dotted for a nested one.
|
|
37
|
+
* @param {any} [defaultValue] - What an unauthored field reads as.
|
|
38
|
+
* @param {object} [options] - Options.
|
|
39
|
+
* @param {string} [options.legacyKey] - The key the block still carries, when
|
|
40
|
+
* it is not spelled `to`. Defaults to `to`.
|
|
41
|
+
* @returns {any} The value.
|
|
42
|
+
*/
|
|
43
|
+
export function sohlSystemField(fm: object, to: string, defaultValue?: any, { legacyKey }?: {
|
|
44
|
+
legacyKey?: string | undefined;
|
|
45
|
+
}): any;
|
|
12
46
|
/**
|
|
13
47
|
* Resolve the `charges` block shared by Mystery and Mystical Ability items.
|
|
14
48
|
*
|
|
@@ -97,3 +131,33 @@ export function parseValueDesc(raw: any): {
|
|
|
97
131
|
label: string;
|
|
98
132
|
maxValue: number;
|
|
99
133
|
}[];
|
|
134
|
+
/**
|
|
135
|
+
* The compendium folder a note names, and how it named it.
|
|
136
|
+
*
|
|
137
|
+
* Two spellings, deliberately not merged into one value: `packFolder:` is a
|
|
138
|
+
* folder note's **address** (`folder-poisonsandtoxins`) and `folder:` is a
|
|
139
|
+
* Foundry **id** (`ONXsqZAIZr2qzxTb`). Which one a value is cannot be told from
|
|
140
|
+
* the string — both are alphanumeric — so the field it was written in is what
|
|
141
|
+
* says, and that answer is carried rather than re-derived (#251).
|
|
142
|
+
*
|
|
143
|
+
* **`packFolder` was a path for one release** (`Possessions/Misc_Gear/Cooking`)
|
|
144
|
+
* and is an address now (#255). A path encoded the hierarchy *in the value*, so
|
|
145
|
+
* reparenting a folder made every note naming it wrong — a structural edit
|
|
146
|
+
* became a corpus-wide rewrite. An address is stable under reparenting, which
|
|
147
|
+
* is exactly why a note is addressed by `(type, shortcode)` and never by
|
|
148
|
+
* `file.path`. The path form is **removed rather than deprecated**: it had no
|
|
149
|
+
* authors to migrate, which is the whole reason the change was cheap enough to
|
|
150
|
+
* make.
|
|
151
|
+
*
|
|
152
|
+
* `packFolder` wins where both are present. Nothing about `folder` changes: a
|
|
153
|
+
* note that names one is read, resolved and emitted exactly as before, until
|
|
154
|
+
* #260 retires it.
|
|
155
|
+
*
|
|
156
|
+
* @param {object|null|undefined} fm - Parsed frontmatter.
|
|
157
|
+
* @returns {{value: string|null, isAddress: boolean}} The authored value, and
|
|
158
|
+
* whether it is a folder note's address.
|
|
159
|
+
*/
|
|
160
|
+
export function folderField(fm: object | null | undefined): {
|
|
161
|
+
value: string | null;
|
|
162
|
+
isAddress: boolean;
|
|
163
|
+
};
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compiler class a pack of one document type and one system gets.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} docType - The Foundry document type the pack holds.
|
|
5
|
+
* @param {string|null} [system] - The system the pack declares, if any.
|
|
6
|
+
* @returns {Function|undefined} The compiler class, or `undefined` for a
|
|
7
|
+
* document type nothing here compiles — which {@link generatePack} reports
|
|
8
|
+
* rather than defaulting past.
|
|
9
|
+
*/
|
|
10
|
+
export function compilerFor(docType: string, system?: string | null): Function | undefined;
|
|
1
11
|
/**
|
|
2
12
|
* The generated JSON of **every** configured Item pack — what the actors pass
|
|
3
13
|
* reads its predefined items from.
|
|
@@ -31,6 +41,34 @@
|
|
|
31
41
|
* `(type, shortcode)` instead, naming the being (#49).
|
|
32
42
|
*/
|
|
33
43
|
export function itemPackJsonDirs(config?: object, system?: string | null): string[];
|
|
44
|
+
/**
|
|
45
|
+
* The compiled JSON a bundle may hold copies of, by document type.
|
|
46
|
+
*
|
|
47
|
+
* An `Adventure` carries **copies**, not references, so a bundle resolves its
|
|
48
|
+
* `contents` against compiled output rather than against the content tree — the
|
|
49
|
+
* same arrangement the actors pass has for `itemsSourceDirs`, generalised to
|
|
50
|
+
* every document class an Adventure can hold (#259).
|
|
51
|
+
*
|
|
52
|
+
* Two kinds of pack are left out, each because it holds nothing a note
|
|
53
|
+
* addresses. A **prebuilt** pack's JSON is checked in rather than compiled, so
|
|
54
|
+
* no note is routed into it and nothing in it answers to an address. An
|
|
55
|
+
* **Adventure** pack holds Adventures, and Foundry's `contentFields` has no
|
|
56
|
+
* field for one — a bundle of bundles is not a shape the document admits.
|
|
57
|
+
*
|
|
58
|
+
* **Scoped to one system when the pack has one**, exactly as
|
|
59
|
+
* {@link itemPackJsonDirs} is: a pack declaring `system: sohl` reads that
|
|
60
|
+
* system's packs and the system-neutral ones, so a `(type, shortcode)` that
|
|
61
|
+
* exists in two systems is read out of the right catalogue. Asking for no
|
|
62
|
+
* system reads them all, which is every single-system build.
|
|
63
|
+
*
|
|
64
|
+
* @param {object} [config] - The resolved build configuration. Defaults to this
|
|
65
|
+
* repository's.
|
|
66
|
+
* @param {string|null} [system] - The system whose documents are wanted.
|
|
67
|
+
* Omitted or `null`, every pack is read.
|
|
68
|
+
* @returns {Record<string, string[]>} Each readable pack's JSON directory, by
|
|
69
|
+
* the Foundry document type it holds.
|
|
70
|
+
*/
|
|
71
|
+
export function bundleSourceJsonDirs(config?: object, system?: string | null): Record<string, string[]>;
|
|
34
72
|
/**
|
|
35
73
|
* The passes to run, ordered so that each one follows the output it reads.
|
|
36
74
|
*
|
|
@@ -41,10 +41,45 @@ export function parseMarkdownFile(filePath: any): {
|
|
|
41
41
|
* @param {readonly string[]} [opts.skipDirectories] - Directory names to ignore.
|
|
42
42
|
* Defaults to the configured list.
|
|
43
43
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Refuse a corpus read whose scope its caller did not state.
|
|
46
|
+
*
|
|
47
|
+
* The rule of #243 in one place, so every reader of the tree refuses the same
|
|
48
|
+
* way and says so in the same words. It is shared rather than repeated because
|
|
49
|
+
* the corpus is no longer read only by {@link walkMarkdownTree}: a pass that
|
|
50
|
+
* reads the content index instead is making the identical claim about which
|
|
51
|
+
* files it is looking at, and must be held to the identical requirement — a
|
|
52
|
+
* scope that quietly defaulted there would reintroduce exactly the second
|
|
53
|
+
* answer the walk's requirement removed.
|
|
54
|
+
*
|
|
55
|
+
* @param {readonly string[]|undefined} skipDirectories - The stated scope.
|
|
56
|
+
* @param {string} who - The reader, named in the message.
|
|
57
|
+
* @throws {Error} When no scope was stated.
|
|
58
|
+
* @returns {void}
|
|
59
|
+
*/
|
|
60
|
+
export function assertStatedScope(skipDirectories: readonly string[] | undefined, who: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Refuse a corpus read whose records its caller did not supply.
|
|
63
|
+
*
|
|
64
|
+
* The sibling of {@link assertStatedScope}, and required for the same reason
|
|
65
|
+
* one step further on. These two readers cannot derive the corpus themselves:
|
|
66
|
+
* deriving it reaches the pack router and the manifest emitter, which reach the
|
|
67
|
+
* compilers, which load this module — so importing the index here closes a
|
|
68
|
+
* cycle. They take the records their caller already holds.
|
|
69
|
+
*
|
|
70
|
+
* That is not a workaround dressed up as a rule. A compile runs several passes
|
|
71
|
+
* over one tree, and the whole of #243 is that they must not each answer "which
|
|
72
|
+
* files are the corpus?" for themselves. Requiring the answer to be handed in
|
|
73
|
+
* makes the sharing structural rather than remembered.
|
|
74
|
+
*
|
|
75
|
+
* @param {readonly object[]|undefined} records - The supplied corpus.
|
|
76
|
+
* @param {string} who - The reader, named in the message.
|
|
77
|
+
* @throws {Error} When no corpus was supplied.
|
|
78
|
+
* @returns {void}
|
|
79
|
+
*/
|
|
80
|
+
export function assertSuppliedCorpus(records: readonly object[] | undefined, who: string): void;
|
|
81
|
+
export function walkMarkdownTree(rootDir: any, { skipDirectories }?: {}): Generator<{
|
|
82
|
+
file: string;
|
|
48
83
|
absPath: string;
|
|
49
84
|
frontmatter: null;
|
|
50
85
|
body: string;
|
|
@@ -52,7 +87,7 @@ export function walkMarkdownTree(rootDir: string, { skipDirectories }?: {
|
|
|
52
87
|
bodyLine?: undefined;
|
|
53
88
|
bodyColumn?: undefined;
|
|
54
89
|
} | {
|
|
55
|
-
file: string
|
|
90
|
+
file: string;
|
|
56
91
|
absPath: string;
|
|
57
92
|
frontmatter: any;
|
|
58
93
|
body: string;
|
|
@@ -61,45 +96,74 @@ export function walkMarkdownTree(rootDir: string, { skipDirectories }?: {
|
|
|
61
96
|
bodyColumn: number;
|
|
62
97
|
}, void, unknown>;
|
|
63
98
|
/**
|
|
64
|
-
*
|
|
99
|
+
* The template priority a note states, for a system that treats an unstated one
|
|
100
|
+
* as "not a template" rather than as an authoring error (#266).
|
|
101
|
+
*
|
|
102
|
+
* Reads exactly the positions {@link resolveTemplatePriority} reads, including
|
|
103
|
+
* the retiring `archetype` spelling, and refuses the same contradiction — so
|
|
104
|
+
* the two systems cannot disagree about what a note said. It differs only in
|
|
105
|
+
* what silence means: SoHL requires the statement, while HM3 keeps the value in
|
|
106
|
+
* a flag it simply omits, so there is no tri-state for an absent value to
|
|
107
|
+
* corrupt and nothing to demand.
|
|
108
|
+
*
|
|
109
|
+
* @param {object} fm Parsed frontmatter.
|
|
110
|
+
* @param {string} label Human-readable context for error messages.
|
|
111
|
+
* @param {object} [options] Options.
|
|
112
|
+
* @param {string} [options.block="sohl"] The system block being compiled.
|
|
113
|
+
* @returns {number|null} The priority, or `null` when the note is not a
|
|
114
|
+
* template or states nothing.
|
|
115
|
+
* @throws {Error} When both spellings are present and disagree.
|
|
116
|
+
*/
|
|
117
|
+
export function statedTemplatePriority(fm: object, label: string, { block }?: {
|
|
118
|
+
block?: string | undefined;
|
|
119
|
+
}): number | null;
|
|
120
|
+
/**
|
|
121
|
+
* Resolve the required `templatePriority` frontmatter for an Item/Actor entry
|
|
65
122
|
* (the archetype contract, #604). The property is a nullable number that
|
|
66
123
|
* authors must state explicitly:
|
|
67
|
-
* - a number → the document is
|
|
68
|
-
* - `null` → the document is not
|
|
69
|
-
* - absent → an authoring error (throws), so "not
|
|
124
|
+
* - a number → the document is a template of that priority.
|
|
125
|
+
* - `null` → the document is not a template.
|
|
126
|
+
* - absent → an authoring error (throws), so "not a template" is never
|
|
70
127
|
* silently assumed.
|
|
71
128
|
*
|
|
72
|
-
* Reads
|
|
73
|
-
*
|
|
129
|
+
* Reads the positions {@link findTemplatePriority} lists: `data.templatePriority`
|
|
130
|
+
* first — the specified home — then the system block and the top level, and
|
|
131
|
+
* finally the retiring `archetype` spelling in the same two places (#266).
|
|
74
132
|
*
|
|
75
133
|
* @param {object} fm Parsed frontmatter.
|
|
76
134
|
* @param {string} label Human-readable context for error messages.
|
|
77
|
-
* @
|
|
78
|
-
* @
|
|
135
|
+
* @param {object} [options] Options.
|
|
136
|
+
* @param {string} [options.block="sohl"] The system block being compiled.
|
|
137
|
+
* @returns {number|undefined} The template priority, or `undefined` when null.
|
|
138
|
+
* @throws {Error} When the property is absent, is not a number/null, or both
|
|
139
|
+
* spellings are present and disagree.
|
|
79
140
|
*/
|
|
80
|
-
export function
|
|
141
|
+
export function resolveTemplatePriority(fm: object, label: string, { block }?: {
|
|
142
|
+
block?: string | undefined;
|
|
143
|
+
}): number | undefined;
|
|
81
144
|
/**
|
|
82
|
-
* The value a document's `system.
|
|
83
|
-
* `
|
|
145
|
+
* The value a document's `system.templatePriority` carries, from the required
|
|
146
|
+
* `templatePriority` frontmatter (#126, sohl#1780, renamed off `archetype` by
|
|
147
|
+
* #266 / sohl#1836).
|
|
84
148
|
*
|
|
85
149
|
* A **schema field**, so the tri-state is written out in full rather than
|
|
86
|
-
* expressed by a key's presence: a number is
|
|
87
|
-
*
|
|
150
|
+
* expressed by a key's presence: a number is a template at that priority, and
|
|
151
|
+
* `null` is not a template. This is where {@link resolveTemplatePriority}'s
|
|
88
152
|
* `undefined` becomes the field's `null` — an emitted `undefined` would be
|
|
89
153
|
* dropped by `JSON.stringify`, leaving the compiled document with no
|
|
90
|
-
* `
|
|
154
|
+
* `templatePriority` at all and the tri-state readable as two.
|
|
91
155
|
*
|
|
92
|
-
* **`0` is
|
|
93
|
-
*
|
|
156
|
+
* **`0` is a template.** It is the priority SoHL's own templates ship at, and
|
|
157
|
+
* it is falsy, so this returns it unchanged and every caller must ask
|
|
94
158
|
* `typeof v === "number"` rather than testing truthiness.
|
|
95
159
|
*
|
|
96
160
|
* @param {object} fm Parsed frontmatter.
|
|
97
161
|
* @param {string} label Human-readable context for error messages.
|
|
98
|
-
* @returns {number|null} The
|
|
99
|
-
*
|
|
100
|
-
* @throws {Error} When
|
|
162
|
+
* @returns {number|null} The template priority, or `null` for a document that
|
|
163
|
+
* is not a template.
|
|
164
|
+
* @throws {Error} When the property is absent or invalid.
|
|
101
165
|
*/
|
|
102
|
-
export function
|
|
166
|
+
export function systemTemplatePriority(fm: object, label: string): number | null;
|
|
103
167
|
/**
|
|
104
168
|
* Generates a compendium-source filename: `Name_id.json` with non-
|
|
105
169
|
* alphanumeric runs replaced by underscores.
|
|
@@ -280,7 +344,7 @@ export function defaultStats(): object;
|
|
|
280
344
|
* this repository's own.
|
|
281
345
|
* @returns {{byShortcode: Map, types: Set}} From `buildWikilinkIndex`.
|
|
282
346
|
*/
|
|
283
|
-
export function buildContentLinkIndex(contentBase: string, router?: object): {
|
|
347
|
+
export function buildContentLinkIndex(contentBase: string, router?: object, { skipDirectories, config, records, problems }?: {}): {
|
|
284
348
|
byShortcode: Map<any, any>;
|
|
285
349
|
types: Set<any>;
|
|
286
350
|
};
|
|
@@ -320,7 +384,7 @@ export function convertNoteWikilinks(body: string, { type, id, pack, docPack, in
|
|
|
320
384
|
* @returns {Array<{fm: object, path: string, tld: string, folder: string,
|
|
321
385
|
* absPath: string}>}
|
|
322
386
|
*/
|
|
323
|
-
export function collectContentDocs(contentBase: string): Array<{
|
|
387
|
+
export function collectContentDocs(contentBase: string, { skipDirectories, config, records, problems }?: {}): Array<{
|
|
324
388
|
fm: object;
|
|
325
389
|
path: string;
|
|
326
390
|
tld: string;
|
|
@@ -352,7 +416,7 @@ export function collectContentDocs(contentBase: string): Array<{
|
|
|
352
416
|
* compile rather than shipping a table-shaped hole. The error carries
|
|
353
417
|
* `position`, the directive's own line.
|
|
354
418
|
*/
|
|
355
|
-
export function expandNoteTables(body: string, { docs, name, fm, bodyLine }: {
|
|
419
|
+
export function expandNoteTables(body: string, { docs, name, fm, bodyLine, sqlTables }: {
|
|
356
420
|
docs: Array<object>;
|
|
357
421
|
name: string;
|
|
358
422
|
fm?: object | undefined;
|
|
@@ -384,7 +448,7 @@ export function loadFolders(foldersFile: any): any[];
|
|
|
384
448
|
* Returns { resolver, folders } where folders is the validated list.
|
|
385
449
|
*/
|
|
386
450
|
export function buildFolderResolver(folders: any): {
|
|
387
|
-
resolver: (
|
|
451
|
+
resolver: (value: string | null | undefined) => string | null;
|
|
388
452
|
folders: any;
|
|
389
453
|
};
|
|
390
454
|
/**
|
|
@@ -402,4 +466,4 @@ export function writeFolderDocs(folders: any, stats: any, destDir: any, document
|
|
|
402
466
|
export const md: import("markdown-it").MarkdownIt;
|
|
403
467
|
export { slugify } from "./content-slug.mjs";
|
|
404
468
|
export { makeId } from "./ids.mjs";
|
|
405
|
-
export { getFrontmatter, sohlField, resolveCharges, resolveSkillAptitudes, resolveRelation, requireSubType, parseValueDesc } from "./frontmatter.mjs";
|
|
469
|
+
export { getFrontmatter, sohlField, folderField, resolveCharges, resolveSkillAptitudes, resolveRelation, requireSubType, parseValueDesc } from "./frontmatter.mjs";
|