@heroiclands/package-build 0.6.0 → 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 +95 -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 -34
- 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,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a qualifier as the **virtual `doc<type>`** form, or reports that it is
|
|
3
|
+
* not one.
|
|
4
|
+
*
|
|
5
|
+
* A document and its documentation are two documents in two packs, so they
|
|
6
|
+
* need two addresses (#1362). `skill/wpnc` is the item; `docskill/wpnc` is the
|
|
7
|
+
* JournalEntry its prose compiled into, and `docmacro/autoattack` is the same
|
|
8
|
+
* arrangement for a macro (#1514).
|
|
9
|
+
*
|
|
10
|
+
* The virtual form exists for a type that carries separate documentation
|
|
11
|
+
* ({@link sohl.utils.packs.docEntryTypes} — the set the journals compiler and
|
|
12
|
+
* the link manifest read too), **or** for one that routes to the items pack.
|
|
13
|
+
* The second clause is the older rule and stays: types that compile into items
|
|
14
|
+
* are the open, unenumerated set (#1276), and a foreign package may publish an
|
|
15
|
+
* item type this build has never heard of. Dropping it would silently unlink
|
|
16
|
+
* every `doc<type>` address into such a package.
|
|
17
|
+
*
|
|
18
|
+
* A **real** type of the same name always wins: the virtual reading is only
|
|
19
|
+
* consulted for a qualifier no authored note claims.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} qualifier - The already-normalised text before the `/`.
|
|
22
|
+
* @param {Set<string>} types - Every type the content tree contains.
|
|
23
|
+
* @returns {string|null} The underlying document type, or `null` when the
|
|
24
|
+
* qualifier is not a virtual one.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveItemDocType(qualifier: string, types: Set<string>): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Read a link target as a **qualified** `type-shortcode` reference, or report
|
|
29
|
+
* that it is a bare alias instead.
|
|
30
|
+
*
|
|
31
|
+
* Two separators are accepted, and they are **not** interchangeable in how
|
|
32
|
+
* confidently they mark a target as qualified:
|
|
33
|
+
*
|
|
34
|
+
* - **`type-shortcode`** — the canonical form (#1398). Obsidian reads `/` inside
|
|
35
|
+
* a wikilink as a *path* and resolves it against the vault's folders, so a
|
|
36
|
+
* slash-qualified link is a broken link in the editor where the content is now
|
|
37
|
+
* authored. A hyphen qualifies **only when what precedes it is a known type**:
|
|
38
|
+
* note names contain hyphens too (`Grukar-ahk`), and those must keep resolving
|
|
39
|
+
* as aliases. The split is at the **first** hyphen, so a shortcode may itself
|
|
40
|
+
* contain one (`trauma-self-pro` → `trauma` + `self-pro`).
|
|
41
|
+
* - **`type/shortcode`** — the legacy form, still resolved so that a link
|
|
42
|
+
* written before the vault migrated does not silently die. A slash is
|
|
43
|
+
* *unconditionally* a qualifier: nothing else uses one, so an unknown type
|
|
44
|
+
* before it is an error rather than an invitation to try the alias index. The
|
|
45
|
+
* split is at the **last** slash, as it always was.
|
|
46
|
+
*
|
|
47
|
+
* A leading **package** segment is optional and outermost: `sohl-skill-lang` is
|
|
48
|
+
* `skill-lang` in the `sohl` package. It is read only when `packages` is given
|
|
49
|
+
* and names the segment, and only when the remainder is itself a valid address,
|
|
50
|
+
* so a note called "Grukar-ahk" stays an alias (#1499).
|
|
51
|
+
*
|
|
52
|
+
* @param {string} target - The link target, anchor already removed.
|
|
53
|
+
* @param {Set<string>} types - Every type the content tree contains.
|
|
54
|
+
* @param {Set<string>} [packages] - Every package an address may name. Omitted
|
|
55
|
+
* by callers that resolve within one package, where the form cannot occur.
|
|
56
|
+
* @returns {{type: string, shortcode: string, itemDoc: boolean,
|
|
57
|
+
* package?: string, reason?: undefined} | {reason: "unknown-type"} | null}
|
|
58
|
+
* The resolved qualifier; a `reason` when the target is definitely qualified
|
|
59
|
+
* but names no known type; or `null` when it is a bare alias.
|
|
60
|
+
*/
|
|
61
|
+
export function readQualifier(target: string, types: Set<string>, packages?: Set<string>): {
|
|
62
|
+
type: string;
|
|
63
|
+
shortcode: string;
|
|
64
|
+
itemDoc: boolean;
|
|
65
|
+
package?: string;
|
|
66
|
+
reason?: undefined;
|
|
67
|
+
} | {
|
|
68
|
+
reason: "unknown-type";
|
|
69
|
+
} | null;
|
|
70
|
+
/**
|
|
71
|
+
* The deterministic JournalEntryPage id for one anchor: SHA-256 of
|
|
72
|
+
* `"<noteId>-<anchorSlug>"`, base64-encoded, reduced to the 16 alphanumeric
|
|
73
|
+
* characters a Foundry id allows.
|
|
74
|
+
*
|
|
75
|
+
* Base64's `+`, `/`, and `=` are **not** legal in a Foundry document id
|
|
76
|
+
* (`/^[A-Za-z0-9]{16}$/`), so they are dropped before the first 16 characters
|
|
77
|
+
* are taken — the value stays a pure function of its two inputs, which is what
|
|
78
|
+
* lets the link and the page be computed independently.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} noteId - The owning JournalEntry's `_id`.
|
|
81
|
+
* @param {string} anchorSlug - The slug declared by `{#slug}` on the heading.
|
|
82
|
+
* @returns {string} A 16-character alphanumeric id.
|
|
83
|
+
*/
|
|
84
|
+
export function anchorPageId(noteId: string, anchorSlug: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Builds the link-resolution tables for a content tree.
|
|
87
|
+
*
|
|
88
|
+
* @param {Array<{type: string, id: string, shortcode?: string|null,
|
|
89
|
+
* aliases?: string[], name?: string, pack?: string, docPack?: string}>} docs -
|
|
90
|
+
* One entry per content note. `pack` / `docPack` name the packs the note's
|
|
91
|
+
* document and its documentation entry landed in; omitted, the conventional
|
|
92
|
+
* one-pack-per-type names stand in.
|
|
93
|
+
* @param {string} packageId - The Foundry package shipping the packs; the first
|
|
94
|
+
* segment of every emitted UUID.
|
|
95
|
+
* @param {Map<string, object>} [foreign] - Canonically keyed entries from
|
|
96
|
+
* vendored manifests of packages this build links into but does not publish.
|
|
97
|
+
* @param {string} [contentPackage] - This build's *content* package, which an
|
|
98
|
+
* authored address may name explicitly. Defaults to `packageId`.
|
|
99
|
+
* @returns {{byShortcode: Map<string, object>, byAlias: Map<string, object|null>,
|
|
100
|
+
* types: Set<string>}} `byAlias` holds `null` where a type-scoped alias is
|
|
101
|
+
* claimed by more than one document, which makes the bare `[[Text]]` form
|
|
102
|
+
* unusable for it. `types` is every type the tree actually contains, so a
|
|
103
|
+
* qualifier naming no real type can be told apart from a missing target.
|
|
104
|
+
*/
|
|
105
|
+
export function buildWikilinkIndex(docs: Array<{
|
|
106
|
+
type: string;
|
|
107
|
+
id: string;
|
|
108
|
+
shortcode?: string | null;
|
|
109
|
+
aliases?: string[];
|
|
110
|
+
name?: string;
|
|
111
|
+
pack?: string;
|
|
112
|
+
docPack?: string;
|
|
113
|
+
}>, packageId: string, foreign?: Map<string, object>, contentPackage?: string): {
|
|
114
|
+
byShortcode: Map<string, object>;
|
|
115
|
+
byAlias: Map<string, object | null>;
|
|
116
|
+
types: Set<string>;
|
|
117
|
+
};
|
|
118
|
+
/** Matches a whole wikilink, capturing its inner text. */
|
|
119
|
+
/**
|
|
120
|
+
* Rewrites every wikilink in a markdown body as a Foundry UUID enricher.
|
|
121
|
+
*
|
|
122
|
+
* A link that cannot be resolved is left exactly as it was and reported in
|
|
123
|
+
* `unresolved`, so a content gap degrades to visible literal text rather than
|
|
124
|
+
* a broken link or a failed build.
|
|
125
|
+
*
|
|
126
|
+
* **Code is verbatim.** A `[[…]]` inside a fenced or indented code block, or
|
|
127
|
+
* inside an inline code span, is source text an author wrote to be read as
|
|
128
|
+
* written, so it is left alone and not reported (#1505). Without that, a
|
|
129
|
+
* script sample containing `grid[[0]]` became a link — and only for some
|
|
130
|
+
* array shapes, `[[1,2],[3,4]]` having an inner `]` the pattern cannot cross,
|
|
131
|
+
* so the corruption looked arbitrary. It reaches the reader through the
|
|
132
|
+
* *documented* copy of a macro while the executable copy stays correct.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} markdown - The note body (frontmatter already stripped).
|
|
135
|
+
* @param {object} ctx
|
|
136
|
+
* @param {string} ctx.type - The source note's `type`, which scopes a bare `[[Text]]`.
|
|
137
|
+
* @param {string} ctx.id - The source note's document id.
|
|
138
|
+
* @param {string} [ctx.pack] - The pack the source note's own document landed
|
|
139
|
+
* in, which addresses a `[[#slug]]` self-link — the one target with no index
|
|
140
|
+
* entry.
|
|
141
|
+
* @param {string} [ctx.docPack] - The pack the source note's documentation
|
|
142
|
+
* entry landed in.
|
|
143
|
+
* @param {{byShortcode: Map, byAlias: Map, types: Set}} ctx.index - From
|
|
144
|
+
* {@link buildWikilinkIndex}.
|
|
145
|
+
* @returns {{markdown: string, unresolved: Array<{link: string, target: string,
|
|
146
|
+
* offset: number, reason: "unknown"|"ambiguous"|"unknown-type"}>}} `offset`
|
|
147
|
+
* is the link's 0-based position in `markdown`, which is what lets a caller
|
|
148
|
+
* report the line and column it sits on (#17).
|
|
149
|
+
*/
|
|
150
|
+
export function convertWikilinks(markdown: string, { type, id, pack, docPack, index }: {
|
|
151
|
+
type: string;
|
|
152
|
+
id: string;
|
|
153
|
+
pack?: string | undefined;
|
|
154
|
+
docPack?: string | undefined;
|
|
155
|
+
index: {
|
|
156
|
+
byShortcode: Map<any, any>;
|
|
157
|
+
byAlias: Map<any, any>;
|
|
158
|
+
types: Set<any>;
|
|
159
|
+
};
|
|
160
|
+
}): {
|
|
161
|
+
markdown: string;
|
|
162
|
+
unresolved: Array<{
|
|
163
|
+
link: string;
|
|
164
|
+
target: string;
|
|
165
|
+
offset: number;
|
|
166
|
+
reason: "unknown" | "ambiguous" | "unknown-type";
|
|
167
|
+
}>;
|
|
168
|
+
};
|
|
169
|
+
import { ITEM_PACK } from "./ids.mjs";
|
|
170
|
+
import { PACK_BY_TYPE } from "./ids.mjs";
|
|
171
|
+
import { packForType } from "./ids.mjs";
|
|
172
|
+
export { ITEM_PACK, PACK_BY_TYPE, packForType };
|
package/types/index.d.mts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * as engine from "./engine/index.mjs";
|
|
2
|
+
export * as sohl from "./sohl/index.mjs";
|
|
1
3
|
export * as manifest from "./manifest.mjs";
|
|
2
4
|
export * as bundle from "./bundle.mjs";
|
|
3
5
|
export * as stage from "./stage.mjs";
|
|
@@ -8,3 +10,4 @@ export * as e2e from "./e2e.mjs";
|
|
|
8
10
|
export * as lang from "./lang.mjs";
|
|
9
11
|
export * as coverage from "./coverage.mjs";
|
|
10
12
|
export * as templates from "./templates.mjs";
|
|
13
|
+
export { defineConfig, PACKAGE_KINDS, PACK_DOCUMENT_TYPES } from "./content-config.mjs";
|
package/types/manifest.d.mts
CHANGED
|
@@ -45,7 +45,7 @@ export function releaseUrls({ repoUrl, version, artifact }: {
|
|
|
45
45
|
/**
|
|
46
46
|
* The manifest's `packs`, derived from the one pack list the build already has.
|
|
47
47
|
*
|
|
48
|
-
* The two used to be written separately — `
|
|
48
|
+
* The two used to be written separately — `package-build.config.yaml` declared
|
|
49
49
|
* a pack's name and type, and the manifest template declared them again beside
|
|
50
50
|
* a label, a path and a system id, with nothing checking that the pairs agreed.
|
|
51
51
|
* They are one list now.
|
|
@@ -55,10 +55,26 @@ export function releaseUrls({ repoUrl, version, artifact }: {
|
|
|
55
55
|
* ships as an ordinary compendium. The order matches `packDirectories`, so the
|
|
56
56
|
* manifest lists packs in the order the build compiles them.
|
|
57
57
|
*
|
|
58
|
-
* @param {object} config - The resolved content
|
|
58
|
+
* @param {object} config - The resolved content configuration.
|
|
59
59
|
* @returns {object[]} The manifest's `packs` array.
|
|
60
60
|
*/
|
|
61
61
|
export function manifestPacks(config: object): object[];
|
|
62
|
+
/**
|
|
63
|
+
* The `relationships` block as published — every declared dependency, with the
|
|
64
|
+
* build's own keys dropped.
|
|
65
|
+
*
|
|
66
|
+
* Shape is otherwise preserved: kinds keep their order and their entries, an
|
|
67
|
+
* entry keeps its remaining keys in the order it declared them, and a block
|
|
68
|
+
* carrying no build-only key comes back equal to what went in. Only
|
|
69
|
+
* {@link BUILD_ONLY_RELATIONSHIP_KEYS} are removed — an unrecognised key is
|
|
70
|
+
* left alone, on the same reasoning that lets a declared manifest key through
|
|
71
|
+
* unread: a key Foundry adds later should not need a release of this package.
|
|
72
|
+
*
|
|
73
|
+
* @param {Record<string, unknown>} relationships - The declared block, as
|
|
74
|
+
* content-build resolved it.
|
|
75
|
+
* @returns {Record<string, unknown>} It, without the build-only keys.
|
|
76
|
+
*/
|
|
77
|
+
export function publishedRelationships(relationships: Record<string, unknown>): Record<string, unknown>;
|
|
62
78
|
/**
|
|
63
79
|
* Build a Foundry package manifest from the resolved configuration.
|
|
64
80
|
*
|
|
@@ -73,8 +89,12 @@ export function manifestPacks(config: object): object[];
|
|
|
73
89
|
* - **Computed** — namespaced `flags` a repository works out for itself, merged
|
|
74
90
|
* over any it declared.
|
|
75
91
|
*
|
|
92
|
+
* `relationships` is derived but not copied whole: the keys that direct the
|
|
93
|
+
* build rather than describe the package are dropped first — see
|
|
94
|
+
* {@link publishedRelationships}.
|
|
95
|
+
*
|
|
76
96
|
* @param {object} options - Inputs.
|
|
77
|
-
* @param {object} options.config - The resolved content
|
|
97
|
+
* @param {object} options.config - The resolved content configuration.
|
|
78
98
|
* @param {object} options.packageJson - The repository's `package.json`.
|
|
79
99
|
* @param {string} options.artifact - `system` or `module`.
|
|
80
100
|
* @param {Record<string, object>} [options.flags] - Namespaced flags to merge.
|
|
@@ -90,7 +110,7 @@ export function buildManifest({ config, packageJson, artifact, flags }: {
|
|
|
90
110
|
* Write the generated manifest into the staged package.
|
|
91
111
|
*
|
|
92
112
|
* @param {object} options - As {@link buildManifest}, plus where to write.
|
|
93
|
-
* @param {object} options.config - The resolved content
|
|
113
|
+
* @param {object} options.config - The resolved content configuration.
|
|
94
114
|
* @param {object} options.packageJson - The repository's `package.json`.
|
|
95
115
|
* @param {string} options.artifact - `system` or `module`.
|
|
96
116
|
* @param {string} options.outDir - Directory to write into.
|
|
@@ -116,3 +136,31 @@ export function writeManifest({ config, packageJson, artifact, outDir, flags, }:
|
|
|
116
136
|
* convention this project is free to choose.
|
|
117
137
|
*/
|
|
118
138
|
export const ARTIFACTS: readonly string[];
|
|
139
|
+
/**
|
|
140
|
+
* Relationship keys that direct the **build**, rather than describe the
|
|
141
|
+
* package.
|
|
142
|
+
*
|
|
143
|
+
* `relationships` is the one manifest block with a second reader.
|
|
144
|
+
* `@heroiclands/content-build` consumes it too, and v1.8.0 added
|
|
145
|
+
* `itemCatalog: true` as an opt-in on a declared dependency
|
|
146
|
+
* (content-build#82): it selects that package's Item packs as a resolution
|
|
147
|
+
* source for the actors pass. That is an instruction to the build, not a fact
|
|
148
|
+
* about the shipped package — Foundry's relationship schema does not define
|
|
149
|
+
* it, and someone reading a published manifest cannot tell a build directive
|
|
150
|
+
* from a declaration about what the package needs.
|
|
151
|
+
*
|
|
152
|
+
* So the block is filtered rather than copied whole (#29). The rule is the
|
|
153
|
+
* distinction, not the name: a key listed here answers *how is this built?*,
|
|
154
|
+
* and every key that survives answers *what does this package depend on?*.
|
|
155
|
+
* `itemCatalog` is the first build-time key to land on a relationship and is
|
|
156
|
+
* unlikely to be the last.
|
|
157
|
+
*
|
|
158
|
+
* A list is enough, and needs no prefix agreed between the two packages,
|
|
159
|
+
* because the input is already closed: content-build normalises a relationship
|
|
160
|
+
* to `id`, `type`, `manifest`, `compatibility` and its own build keys, and
|
|
161
|
+
* rejects anything else at configuration time. A key that reaches here is one
|
|
162
|
+
* the toolchain itself put there.
|
|
163
|
+
*
|
|
164
|
+
* @type {readonly string[]}
|
|
165
|
+
*/
|
|
166
|
+
export const BUILD_ONLY_RELATIONSHIP_KEYS: readonly string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PRETTIER_CONFIG as default } from "./engine/prose-config.mjs";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export class Actors extends BasePackCompiler {
|
|
2
|
+
constructor({ itemsSourceDirs, foreignSourceDirs, ...options }: {
|
|
3
|
+
[x: string]: any;
|
|
4
|
+
itemsSourceDirs: any;
|
|
5
|
+
foreignSourceDirs?: never[] | undefined;
|
|
6
|
+
});
|
|
7
|
+
/** @type {readonly string[]} */
|
|
8
|
+
itemsSourceDirs: readonly string[];
|
|
9
|
+
foreignSourceDirs: any;
|
|
10
|
+
itemsMap: Map<string, object> | undefined;
|
|
11
|
+
/** @inheritdoc */
|
|
12
|
+
reportDetail(stats: any): void;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve one embedded item from a `(type, shortcode?, overlay)`
|
|
15
|
+
* descriptor. If `shortcode` is given, the predefined item is fetched
|
|
16
|
+
* from `itemsMap` and the overlay deep-merged on top. If absent, the
|
|
17
|
+
* descriptor must carry enough fields to stand alone. The embedded
|
|
18
|
+
* item's `_id` is regenerated deterministically from
|
|
19
|
+
* `(actorId, type, shortcode, indexKey)` so re-exports are stable.
|
|
20
|
+
* Returns null if the descriptor cannot be resolved.
|
|
21
|
+
*/
|
|
22
|
+
resolveEmbedded(itemsMap: any, actorId: any, type: any, shortcode: any, overlay: any, indexKey: any, ctx: any): any;
|
|
23
|
+
/**
|
|
24
|
+
* Build all embedded items for an actor: one per `sohl.attributes`
|
|
25
|
+
* entry plus one per `sohl.items` entry. `sohl.skills` is ignored.
|
|
26
|
+
*/
|
|
27
|
+
buildEmbeddedItems(itemsMap: any, actorId: any, fm: any, ctx: any): any[];
|
|
28
|
+
buildBeing(itemsMap: any, fm: any, body: any): {
|
|
29
|
+
name: any;
|
|
30
|
+
type: string;
|
|
31
|
+
img: string;
|
|
32
|
+
_id: any;
|
|
33
|
+
system: {
|
|
34
|
+
shortcode: any;
|
|
35
|
+
portrait: string;
|
|
36
|
+
appearance: any;
|
|
37
|
+
dossier: any;
|
|
38
|
+
};
|
|
39
|
+
items: any[];
|
|
40
|
+
prototypeToken: {
|
|
41
|
+
name: any;
|
|
42
|
+
displayName: number;
|
|
43
|
+
actorLink: boolean;
|
|
44
|
+
texture: {
|
|
45
|
+
src: string;
|
|
46
|
+
};
|
|
47
|
+
width: number;
|
|
48
|
+
height: number;
|
|
49
|
+
sight: {
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
};
|
|
52
|
+
detectionModes: never[];
|
|
53
|
+
};
|
|
54
|
+
effects: never[];
|
|
55
|
+
folder: string | null;
|
|
56
|
+
sort: number;
|
|
57
|
+
ownership: {
|
|
58
|
+
default: number;
|
|
59
|
+
};
|
|
60
|
+
flags: object;
|
|
61
|
+
_stats: object;
|
|
62
|
+
_key: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
import { BasePackCompiler } from "../engine/base-compiler.mjs";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The affiliation standings an authored `relation` map may use — one
|
|
3
|
+
* affiliation's stance toward another (#1404).
|
|
4
|
+
*
|
|
5
|
+
* Plain ESM for the same reason `./default-item-art.mjs` is: the pack scripts
|
|
6
|
+
* run under bare `node`, so they cannot read the runtime's TypeScript
|
|
7
|
+
* `AFFILIATION_STANDING`. This module is where the pipeline reads the list
|
|
8
|
+
* from, rather than restating it inside a compiler (#1510).
|
|
9
|
+
*
|
|
10
|
+
* The runtime keeps its own `defineType("SOHL.Affiliation.Standing", { … })`
|
|
11
|
+
* declaration in `src/utils/constants.ts`, because that literal is *parsed out
|
|
12
|
+
* of the source* by two build guards — the generated type catalog
|
|
13
|
+
* (`utils/build-type-catalog.mjs`) and the localization-coverage check
|
|
14
|
+
* (`utils/check-lang-coverage.mjs`) — and replacing it with an imported
|
|
15
|
+
* reference would blind both. The two lists are held identical by a test
|
|
16
|
+
* (`tests/build/src-import-severance.test.ts`), so the drift the
|
|
17
|
+
* duplication would otherwise allow is a failing build rather than an
|
|
18
|
+
* affiliation whose authored hostility quietly became neutrality.
|
|
19
|
+
*
|
|
20
|
+
* @type {readonly string[]}
|
|
21
|
+
*/
|
|
22
|
+
export const AFFILIATION_STANDINGS: readonly string[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a note's frontmatter describes a being.
|
|
3
|
+
*
|
|
4
|
+
* @param {{type?: unknown}|null|undefined} fm - A note's frontmatter.
|
|
5
|
+
* @returns {boolean} `true` when the note is a being.
|
|
6
|
+
*/
|
|
7
|
+
export function isBeing(fm: {
|
|
8
|
+
type?: unknown;
|
|
9
|
+
} | null | undefined): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Derive a being's info-block fields from its raw `sohl.items[]`.
|
|
12
|
+
*
|
|
13
|
+
* Each item's `shortcode` is resolved against `index` — keyed
|
|
14
|
+
* `"<type>:<shortcode>"` — for a display name and a link to the item's own
|
|
15
|
+
* page. `attributes` already match the sidebar shape and pass through
|
|
16
|
+
* untouched.
|
|
17
|
+
*
|
|
18
|
+
* **Authored values win.** Only fields the author did not supply are derived,
|
|
19
|
+
* so a note that hand-writes `sohl.skills` keeps exactly what it wrote. An
|
|
20
|
+
* item's inline `name` beats the index, and an unresolved shortcode falls back
|
|
21
|
+
* to *itself* rather than being dropped — a page that names an item the index
|
|
22
|
+
* has not heard of is better than a page silently missing a row.
|
|
23
|
+
*
|
|
24
|
+
* Returns a new object; the input is not mutated.
|
|
25
|
+
*
|
|
26
|
+
* @param {object|null|undefined} sohl - The note's `sohl` frontmatter block.
|
|
27
|
+
* @param {Map<string, {name?: string, url?: string}>} index - Content index,
|
|
28
|
+
* `"<type>:<shortcode>"` → the item's page.
|
|
29
|
+
* @returns {object|null|undefined} The block with its info-block fields filled
|
|
30
|
+
* in, or the input unchanged when there is nothing to derive from.
|
|
31
|
+
*/
|
|
32
|
+
export function deriveBeingInfo(sohl: object | null | undefined, index: Map<string, {
|
|
33
|
+
name?: string;
|
|
34
|
+
url?: string;
|
|
35
|
+
}>): object | null | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* **A being's info-block fields**, derived from the items it embeds.
|
|
38
|
+
*
|
|
39
|
+
* A `being` note carries its embedded documents as `sohl.items` — a flat list
|
|
40
|
+
* of `{ shortcode, type, system? }` — but the shared theme's sidebar reads
|
|
41
|
+
* *resolved* shapes: a `skills` map, `gear` grouped by kind, and `spells` /
|
|
42
|
+
* `talents` split out of the mystical abilities. This is the translation
|
|
43
|
+
* between the two, and it is SoHL data-model knowledge: which item type is a
|
|
44
|
+
* skill, where a mastery level lives, what distinguishes a spell from a talent.
|
|
45
|
+
*
|
|
46
|
+
* **It lives here because it was living in two places.** Both
|
|
47
|
+
* `Song-of-Heroic-Lands-FoundryVTT` and `sohl-thalorna` carried a copy, and the
|
|
48
|
+
* copies drifted: SoHL's caller still gated the derivation on `character` and
|
|
49
|
+
* `creature`, the two types #1580 merged into `being`, so it had matched
|
|
50
|
+
* nothing since the merge and all 95 of its being pages published with empty
|
|
51
|
+
* sidebar sections (SoHL#1696). thalorna's copy checked `being` and was right.
|
|
52
|
+
* Nothing failed in either repository; the pages built and shipped.
|
|
53
|
+
*
|
|
54
|
+
* {@link isBeing} exists for that reason. The bug was not in the derivation —
|
|
55
|
+
* it was in each caller's idea of what a being *is*, written out per repository
|
|
56
|
+
* where it could rot independently. One definition, imported.
|
|
57
|
+
*
|
|
58
|
+
* @module
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* The note `type` whose pages carry a being info block.
|
|
62
|
+
*
|
|
63
|
+
* One name, since #1580 merged `character` and `creature` into the `being` they
|
|
64
|
+
* had always compiled into. The retired names are deliberately **not** accepted
|
|
65
|
+
* as aliases: they throw elsewhere in the system, and tolerating them here
|
|
66
|
+
* would hide the next drift of this kind rather than surface it.
|
|
67
|
+
*/
|
|
68
|
+
export const BEING_TYPE: "being";
|
|
69
|
+
/**
|
|
70
|
+
* The sidebar group each gear item type is displayed under.
|
|
71
|
+
*
|
|
72
|
+
* Presentation naming, not data-model naming: the model says `weapongear`, the
|
|
73
|
+
* sidebar heading says "weapons". Kept as one table so a new gear type is added
|
|
74
|
+
* in a single place rather than in each consumer's site build.
|
|
75
|
+
*
|
|
76
|
+
* @type {Readonly<Record<string, string>>}
|
|
77
|
+
*/
|
|
78
|
+
export const GEAR_TYPE_TO_KEY: Readonly<Record<string, string>>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default art path for an item `type`, or throw when the type is unknown —
|
|
3
|
+
* the build's fail-fast contract, so an unrecognized type is never silently
|
|
4
|
+
* defaulted (aborting the pack build rather than shipping a mismatched icon).
|
|
5
|
+
*
|
|
6
|
+
* Runtime callers that must tolerate unknown or `base`-typed items should read
|
|
7
|
+
* {@link DEFAULT_ITEM_ART} directly and fall back to Foundry's default instead
|
|
8
|
+
* of calling this — see `SohlItem.getDefaultArtwork`.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} type - the item type.
|
|
11
|
+
* @returns {string} the default image path for that type.
|
|
12
|
+
*/
|
|
13
|
+
export function defaultItemArt(type: string): string;
|
|
14
|
+
export namespace DEFAULT_ITEM_ART {
|
|
15
|
+
let affiliation: string;
|
|
16
|
+
let affliction: string;
|
|
17
|
+
let armorgear: string;
|
|
18
|
+
let attribute: string;
|
|
19
|
+
let concoctiongear: string;
|
|
20
|
+
let containergear: string;
|
|
21
|
+
let miscgear: string;
|
|
22
|
+
let mystery: string;
|
|
23
|
+
let mysticalability: string;
|
|
24
|
+
let projectilegear: string;
|
|
25
|
+
let skill: string;
|
|
26
|
+
let trauma: string;
|
|
27
|
+
let weapongear: string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * as itemBuilders from "./item-builders.mjs";
|
|
2
|
+
export * as items from "./items.mjs";
|
|
3
|
+
export * as actors from "./actors.mjs";
|
|
4
|
+
export * as kbPasses from "./kb-passes.mjs";
|
|
5
|
+
export { AFFILIATION_STANDINGS } from "./affiliation-standings.mjs";
|
|
6
|
+
export { DEFAULT_ITEM_ART, defaultItemArt } from "./default-item-art.mjs";
|
|
7
|
+
export { BEING_TYPE, GEAR_TYPE_TO_KEY, deriveBeingInfo, isBeing } from "./being-info.mjs";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every item type, paired with the builder for its `system` block, the default
|
|
3
|
+
* art for the type, and the frontmatter fields it declares.
|
|
4
|
+
*
|
|
5
|
+
* @type {Readonly<Record<string, Readonly<{system: (fm: object) => object, img: string, fields: readonly object[]}>>>}
|
|
6
|
+
*/
|
|
7
|
+
export const ITEM_BUILDERS: Readonly<Record<string, Readonly<{
|
|
8
|
+
system: (fm: object) => object;
|
|
9
|
+
img: string;
|
|
10
|
+
fields: readonly object[];
|
|
11
|
+
}>>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every item type's frontmatter vocabulary, in the order the `system` block
|
|
3
|
+
* emits it.
|
|
4
|
+
*
|
|
5
|
+
* @type {Readonly<Record<string, readonly import("../engine/field-spec.mjs").FieldSpec[]>>}
|
|
6
|
+
*/
|
|
7
|
+
export const ITEM_FIELDS: Readonly<Record<string, readonly import("../engine/field-spec.mjs").FieldSpec[]>>;
|
|
8
|
+
/**
|
|
9
|
+
* The one conditional field in the vocabulary: a combat technique's strike
|
|
10
|
+
* mode.
|
|
11
|
+
*
|
|
12
|
+
* A combat technique is authored as a `skill` of subtype `combattechnique` —
|
|
13
|
+
* the standalone item type was merged into Skill — and carries an embedded,
|
|
14
|
+
* discriminated strike mode. It is mandatory for that subtype and absent from
|
|
15
|
+
* every other skill, which is a conditional a flat field list cannot state, so
|
|
16
|
+
* it is applied after the declaration runs.
|
|
17
|
+
*
|
|
18
|
+
* @type {import("../engine/field-spec.mjs").FieldSpec}
|
|
19
|
+
*/
|
|
20
|
+
export const COMBAT_TECHNIQUE_STRIKE_MODE: import("../engine/field-spec.mjs").FieldSpec;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class Items extends BasePackCompiler {
|
|
2
|
+
/**
|
|
3
|
+
* How many of each item type this pass wrote, for the summary. Every type
|
|
4
|
+
* is present from the start so the tally reads as a census of the
|
|
5
|
+
* whitelist rather than of what happened to compile.
|
|
6
|
+
*
|
|
7
|
+
* @type {Record<string, number>}
|
|
8
|
+
*/
|
|
9
|
+
counts: Record<string, number>;
|
|
10
|
+
/** An item is named by its own type in the log, not by "item". */
|
|
11
|
+
noteLabel(fm: any): any;
|
|
12
|
+
/** @inheritdoc */
|
|
13
|
+
onCompiled(fm: any): void;
|
|
14
|
+
/** @inheritdoc */
|
|
15
|
+
reportCompiled(stats: any): void;
|
|
16
|
+
/** @inheritdoc */
|
|
17
|
+
reportDetail(stats: any): void;
|
|
18
|
+
}
|
|
19
|
+
import { BasePackCompiler } from "../engine/base-compiler.mjs";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves inline TypeDoc `{@link}` / `{@linkcode}` / `{@linkplain}` tags
|
|
3
|
+
* against the API symbol map.
|
|
4
|
+
*
|
|
5
|
+
* - A known target becomes a Markdown link to its page on the API site;
|
|
6
|
+
* `@linkcode` renders the text as code.
|
|
7
|
+
* - Optional display text (`{@link Target | text}` or `{@link Target text}`)
|
|
8
|
+
* wins; otherwise the last dotted segment is the link text.
|
|
9
|
+
* - An external URL target becomes a plain Markdown link.
|
|
10
|
+
* - Anything the map does not know — `{@link Symbol.member}` written as a syntax
|
|
11
|
+
* example, say — degrades to a code span. Never a broken link, never a build
|
|
12
|
+
* failure.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} body - The markdown body.
|
|
15
|
+
* @param {Record<string, string>} symbols - The symbol map.
|
|
16
|
+
* @param {string} apiBase - Where the generated API documentation is served.
|
|
17
|
+
* @returns {string} The body with every tag resolved.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveApiLinks(body: string, symbols: Record<string, string>, apiBase: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Rewrites the relative links in a developer-doc body so they resolve on the
|
|
22
|
+
* published site.
|
|
23
|
+
*
|
|
24
|
+
* Developer docs are authored to link one another and the source tree with
|
|
25
|
+
* repository-relative paths, and neither target exists at the same path once
|
|
26
|
+
* rendered. Each link is resolved against the doc's own location:
|
|
27
|
+
*
|
|
28
|
+
* - a `*.md` link landing inside the documentation tree becomes the published
|
|
29
|
+
* route, preserving any `#anchor`; a `README` is its directory's landing, so
|
|
30
|
+
* that segment is dropped.
|
|
31
|
+
* - anything else — source, templates, a repository-root `*.md` — becomes its
|
|
32
|
+
* GitHub blob URL.
|
|
33
|
+
*
|
|
34
|
+
* Absolute URLs, anchor-only links, `mailto:` and site-root links are untouched.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} body - The markdown body.
|
|
37
|
+
* @param {string} docRel - The doc's path relative to the documentation tree.
|
|
38
|
+
* @param {object} options - `{ repoRoot, docsSrc, docsRel, route, blob }`.
|
|
39
|
+
* @returns {string} The body with every relative link rewritten.
|
|
40
|
+
*/
|
|
41
|
+
export function rewriteRepoLinks(body: string, docRel: string, options: object): string;
|
|
42
|
+
/**
|
|
43
|
+
* The `sohl` knowledgebase pass bundle, built from its options.
|
|
44
|
+
*
|
|
45
|
+
* A pass bundle is two optional hooks the page renderer calls around wikilink
|
|
46
|
+
* resolution, and the order matters:
|
|
47
|
+
*
|
|
48
|
+
* - `beforeLinks` runs on every page, before wikilinks resolve, because a
|
|
49
|
+
* `{@link}` tag may sit inside prose a wikilink also touches.
|
|
50
|
+
* - `afterLinks` runs only on pages from an **extra tree** — the documentation
|
|
51
|
+
* tree — because repository-relative links are a property of how those pages
|
|
52
|
+
* are authored, not of content notes.
|
|
53
|
+
*
|
|
54
|
+
* Both run inside code-fence protection, so neither can rewrite a fenced example.
|
|
55
|
+
*
|
|
56
|
+
* @param {object} options - Resolved from `site.passOptions`.
|
|
57
|
+
* @param {string} [options.symbolMap] - Path to the TypeDoc symbol map.
|
|
58
|
+
* @param {string} [options.apiBase] - Where the API documentation is served.
|
|
59
|
+
* @param {string} [options.blob] - GitHub blob base for repository files.
|
|
60
|
+
* @param {string} options.repoRoot - The repository root, for relative paths.
|
|
61
|
+
* @returns {{beforeLinks: Function, afterLinks: Function}} The bundle.
|
|
62
|
+
*/
|
|
63
|
+
export function sohlKbPass(options: {
|
|
64
|
+
symbolMap?: string | undefined;
|
|
65
|
+
apiBase?: string | undefined;
|
|
66
|
+
blob?: string | undefined;
|
|
67
|
+
repoRoot: string;
|
|
68
|
+
}): {
|
|
69
|
+
beforeLinks: Function;
|
|
70
|
+
afterLinks: Function;
|
|
71
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every content type this package compiles, and what a note of that type may
|
|
3
|
+
* write.
|
|
4
|
+
*
|
|
5
|
+
* @type {Readonly<Record<string, readonly import("../engine/field-spec.mjs").FieldSpec[]>>}
|
|
6
|
+
*/
|
|
7
|
+
export const NOTE_SCHEMAS: Readonly<Record<string, readonly import("../engine/field-spec.mjs").FieldSpec[]>>;
|