@heroiclands/package-build 22.4.1 → 22.4.3
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 +54 -0
- package/CONTENT.md +6 -6
- package/README.md +6 -6
- package/bin/package-build.mjs +68 -18
- package/changelog.cjs +55 -0
- package/content-config.mjs +34 -0
- package/docs/api.md +16 -0
- package/docs/commands.md +70 -2
- package/docs/configuration.md +43 -3
- package/docs/project-setup.md +22 -13
- package/engine/actor-compiler.mjs +26 -1
- package/engine/changelog-group.mjs +256 -0
- package/engine/changelog-lint.mjs +168 -9
- package/engine/document-subtypes.mjs +24 -7
- package/hm3/actors.mjs +42 -0
- package/package.json +4 -3
- package/types/engine/actor-compiler.d.mts +20 -0
- package/types/engine/changelog-group.d.mts +28 -0
- package/types/engine/changelog-lint.d.mts +107 -2
- package/types/engine/document-subtypes.d.mts +14 -7
- package/types/hm3/actors.d.mts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "22.4.
|
|
3
|
+
"version": "22.4.3",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"types": "./types/templates.d.mts",
|
|
92
92
|
"import": "./templates.mjs"
|
|
93
93
|
},
|
|
94
|
+
"./changelog": "./changelog.cjs",
|
|
94
95
|
"./package.json": "./package.json"
|
|
95
96
|
},
|
|
96
97
|
"bin": {
|
|
@@ -106,6 +107,7 @@
|
|
|
106
107
|
"packagebuild-metadata.jsonl",
|
|
107
108
|
"bin",
|
|
108
109
|
"bundle.mjs",
|
|
110
|
+
"changelog.cjs",
|
|
109
111
|
"ci",
|
|
110
112
|
"config.mjs",
|
|
111
113
|
"container.mjs",
|
|
@@ -177,8 +179,7 @@
|
|
|
177
179
|
"lint:content-format:schema": "node bin/content-build.mjs content-format schema --schema sohl=tests/fixtures/content-format/schema-sohl.json --schema hm3=tests/fixtures/content-format/schema-hm3.json",
|
|
178
180
|
"lint:content-format:fields": "node bin/content-build.mjs content-format fields --fields sohl && node bin/content-build.mjs content-format fields --fields hm3",
|
|
179
181
|
"changeset": "changeset",
|
|
180
|
-
"changeset:
|
|
181
|
-
"changeset:version": "changeset version && npm install --package-lock-only",
|
|
182
|
+
"changeset:version": "changeset version && node bin/package-build.mjs changelog group && npm install --package-lock-only",
|
|
182
183
|
"prepare": "git config core.hooksPath .githooks || true"
|
|
183
184
|
},
|
|
184
185
|
"engines": {
|
|
@@ -280,6 +280,26 @@ export class SystemActorCompiler extends BasePackCompiler {
|
|
|
280
280
|
* subtype, or why the reference names none.
|
|
281
281
|
*/
|
|
282
282
|
embeddedSubtype(type: string): import("./document-subtypes.mjs").ReferencedSubtype;
|
|
283
|
+
/**
|
|
284
|
+
* The default art for an embedded item's type, when the entry names none
|
|
285
|
+
* of its own and copies no template that carries one.
|
|
286
|
+
*
|
|
287
|
+
* **The base case is {@link itemArt}**, keyed by the note vocabulary — the
|
|
288
|
+
* same table an item note's own compile defaults from, because most
|
|
289
|
+
* references are written in that vocabulary too (`weapongear`, `skill`,
|
|
290
|
+
* `armorgear`). It is not the whole answer: a reference into a one-to-many
|
|
291
|
+
* row may instead name one of the row's own **subtypes** directly — HM3's
|
|
292
|
+
* `spell`, `invocation` and `psionic` are never a note's own `type`, only
|
|
293
|
+
* `mysticalability`'s `hm3.type` discriminator ever writes them, so no
|
|
294
|
+
* note-type table has a row for them. A system whose one-to-many rows are
|
|
295
|
+
* addressed that way overrides this to answer for those subtypes too; see
|
|
296
|
+
* `hm3/actors.mjs`.
|
|
297
|
+
*
|
|
298
|
+
* @param {string} type - The **note** type the reference names.
|
|
299
|
+
* @param {string} subType - The document subtype it resolved to.
|
|
300
|
+
* @returns {string} The default image path.
|
|
301
|
+
*/
|
|
302
|
+
embeddedItemArt(type: string, subType: string): string;
|
|
283
303
|
/**
|
|
284
304
|
* Read an entry's `model:` — the address of the item it is a copy of.
|
|
285
305
|
*
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `changelog group`: fold the newest release's changeset blocks together by
|
|
3
|
+
* their bold label, order them, and file an undeclared one last.
|
|
4
|
+
*
|
|
5
|
+
* Every earlier release section is untouched, byte for byte — only the
|
|
6
|
+
* first `## <version>` section's `### <Bump> Changes` bodies are rewritten,
|
|
7
|
+
* each independently (a label groups within its own bump level, never
|
|
8
|
+
* across one). Running this on its own output is a no-op: a release already
|
|
9
|
+
* in label order, with each label merged to one block, groups to itself.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} text - The changelog's full contents.
|
|
12
|
+
* @param {object} [opts]
|
|
13
|
+
* @param {readonly string[]|null} [opts.labels] - `changelog.labels`, in
|
|
14
|
+
* display order. `null`/absent orders every group by first appearance
|
|
15
|
+
* instead, lead paragraph first, and files nothing as unknown.
|
|
16
|
+
* @returns {{text: string, findings: Array<{line: number,
|
|
17
|
+
* severity: "warning", message: string}>}}
|
|
18
|
+
*/
|
|
19
|
+
export function groupChangelogText(text: string, { labels }?: {
|
|
20
|
+
labels?: readonly string[] | null | undefined;
|
|
21
|
+
}): {
|
|
22
|
+
text: string;
|
|
23
|
+
findings: Array<{
|
|
24
|
+
line: number;
|
|
25
|
+
severity: "warning";
|
|
26
|
+
message: string;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
@@ -1,11 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a character offset in `text` falls, as a 1-based line and column.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} text - The text the offset indexes into.
|
|
5
|
+
* @param {number} index - 0-based character offset.
|
|
6
|
+
* @returns {{line: number, column: number}}
|
|
7
|
+
*/
|
|
8
|
+
export function lineColOf(text: string, index: number): {
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Every code region in `text`, as a set of 1-based line numbers it spans.
|
|
14
|
+
*
|
|
15
|
+
* Block-level only (`spans: false`): an inline code span does not remove a
|
|
16
|
+
* whole line from consideration, only the characters it covers, which the
|
|
17
|
+
* text-scanning rules mask separately.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} text - The section text.
|
|
20
|
+
* @returns {Set<number>} Lines that fall inside a fenced or indented block.
|
|
21
|
+
*/
|
|
22
|
+
export function codeLineSet(text: string): Set<number>;
|
|
23
|
+
/**
|
|
24
|
+
* Every top-level bullet, as its own contiguous run of lines.
|
|
25
|
+
*
|
|
26
|
+
* A bullet's continuation — a wrapped line, a second paragraph, a nested
|
|
27
|
+
* elaboration — is indented under it and belongs to it; a line back at
|
|
28
|
+
* column 0 that is not itself a bullet (a bold subsection label, ordinary
|
|
29
|
+
* prose) closes it.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} text - Section text.
|
|
32
|
+
* @param {Set<number>} codeLines - Lines inside a code region, from
|
|
33
|
+
* {@link codeLineSet}.
|
|
34
|
+
* @returns {Array<{startLine: number, text: string}>}
|
|
35
|
+
*/
|
|
36
|
+
export function topLevelBullets(text: string, codeLines: Set<number>): Array<{
|
|
37
|
+
startLine: number;
|
|
38
|
+
text: string;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Every top-level block of release prose — one rendered changeset entry, or
|
|
42
|
+
* one unlabelled paragraph standing in for one.
|
|
43
|
+
*
|
|
44
|
+
* `@heroiclands/package-build/changelog` (`changelog.cjs`) writes a
|
|
45
|
+
* changeset's whole summary as one block, verbatim, so a block here holds
|
|
46
|
+
* together the same way that summary is authored: a bold label opening a
|
|
47
|
+
* line at column 0 (`**Compendiums**`) starts a new block, and — unlike
|
|
48
|
+
* {@link topLevelBullets}, where a bullet marker *is* the top-level
|
|
49
|
+
* construct — a `-` bullet at column 0 belongs to whatever block is
|
|
50
|
+
* already open, since a label's bullets sit unindented directly under it.
|
|
51
|
+
* Any other column-0 line (plain prose with no label, a bullet with no
|
|
52
|
+
* block open yet) starts the one "lead" block (`label: null`) a changeset
|
|
53
|
+
* with no category writes — the case `changelog group` sorts first and
|
|
54
|
+
* `check` never flags. Nested detail — a wrapped line, a bullet's own
|
|
55
|
+
* continuation — stays indented and belongs to whatever it follows.
|
|
56
|
+
* `changelog group` folds same-label blocks together; `check` warns when a
|
|
57
|
+
* block's label is not in the declared vocabulary.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} text - Section text.
|
|
60
|
+
* @param {Set<number>} codeLines - Lines inside a code region, from
|
|
61
|
+
* {@link codeLineSet}.
|
|
62
|
+
* @param {Set<number>} [scaffoldLines] - Generated heading lines that close
|
|
63
|
+
* whatever block is open without starting one, from
|
|
64
|
+
* {@link scaffoldLineSet} — empty for a caller that already isolated one
|
|
65
|
+
* `### <Bump> Changes` body, since no heading falls inside it.
|
|
66
|
+
* @returns {Array<{startLine: number, label: string|null, text: string}>}
|
|
67
|
+
*/
|
|
68
|
+
export function topLevelBlocks(text: string, codeLines: Set<number>, scaffoldLines?: Set<number>): Array<{
|
|
69
|
+
startLine: number;
|
|
70
|
+
label: string | null;
|
|
71
|
+
text: string;
|
|
72
|
+
}>;
|
|
1
73
|
/**
|
|
2
74
|
* Lint one pending changeset (`.changeset/*.md`).
|
|
3
75
|
*
|
|
4
76
|
* @param {string} text - The file's full contents, frontmatter included.
|
|
77
|
+
* @param {object} [opts]
|
|
78
|
+
* @param {readonly string[]|null} [opts.labels] - `changelog.labels`, in
|
|
79
|
+
* display order, or `null`/absent when the repository declares none —
|
|
80
|
+
* {@link checkUnknownLabels} checks nothing in that case.
|
|
5
81
|
* @returns {{findings: Array<{line: number, column?: number,
|
|
6
82
|
* severity: "error"|"warning", message: string}>}}
|
|
7
83
|
*/
|
|
8
|
-
export function lintChangesetText(text: string
|
|
84
|
+
export function lintChangesetText(text: string, { labels }?: {
|
|
85
|
+
labels?: readonly string[] | null | undefined;
|
|
86
|
+
}): {
|
|
9
87
|
findings: Array<{
|
|
10
88
|
line: number;
|
|
11
89
|
column?: number;
|
|
@@ -17,10 +95,16 @@ export function lintChangesetText(text: string): {
|
|
|
17
95
|
* Lint the first `## <version>` release section of a `CHANGELOG.md`.
|
|
18
96
|
*
|
|
19
97
|
* @param {string} text - The changelog's full contents.
|
|
98
|
+
* @param {object} [opts]
|
|
99
|
+
* @param {readonly string[]|null} [opts.labels] - `changelog.labels`, in
|
|
100
|
+
* display order, or `null`/absent when the repository declares none —
|
|
101
|
+
* {@link checkUnknownLabels} checks nothing in that case.
|
|
20
102
|
* @returns {{findings: Array<{line?: number, column?: number,
|
|
21
103
|
* severity: "error"|"warning", message: string}>}}
|
|
22
104
|
*/
|
|
23
|
-
export function lintReleaseText(text: string
|
|
105
|
+
export function lintReleaseText(text: string, { labels }?: {
|
|
106
|
+
labels?: readonly string[] | null | undefined;
|
|
107
|
+
}): {
|
|
24
108
|
findings: Array<{
|
|
25
109
|
line?: number;
|
|
26
110
|
column?: number;
|
|
@@ -28,6 +112,27 @@ export function lintReleaseText(text: string): {
|
|
|
28
112
|
message: string;
|
|
29
113
|
}>;
|
|
30
114
|
};
|
|
115
|
+
/**
|
|
116
|
+
* The first `## <version>` release section of a changelog, as raw character
|
|
117
|
+
* offsets rather than {@link extractReleaseSection}'s line-joined copy.
|
|
118
|
+
*
|
|
119
|
+
* `extractReleaseSection` rebuilds its `body` by joining a slice of
|
|
120
|
+
* `text.split("\n")`, which is fine for reporting a line number but drops
|
|
121
|
+
* the exact byte the next `## ` heading sits after — a caller rewriting the
|
|
122
|
+
* file in place, such as `changelog group`, needs `text.slice(start, end)`
|
|
123
|
+
* to be the section verbatim, so it can splice a replacement back in without
|
|
124
|
+
* guessing at the whitespace on either side.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} text - The changelog's full contents.
|
|
127
|
+
* @returns {{start: number, end: number}|null} `null` when no `## ` heading
|
|
128
|
+
* is present. `text.slice(start, end)` is the section, byte-exact,
|
|
129
|
+
* including whatever separates it from the next `## ` heading or the end
|
|
130
|
+
* of the file.
|
|
131
|
+
*/
|
|
132
|
+
export function releaseSectionRange(text: string): {
|
|
133
|
+
start: number;
|
|
134
|
+
end: number;
|
|
135
|
+
} | null;
|
|
31
136
|
/**
|
|
32
137
|
* The finding one rule reports, before its line is mapped into the caller's
|
|
33
138
|
* file.
|
|
@@ -140,7 +140,7 @@ export function documentSubtype(map: DocumentSubtypeMap, noteType: string | unde
|
|
|
140
140
|
* dependency catalogue actually carry, and a reference is translated forward
|
|
141
141
|
* here before it is looked up.
|
|
142
142
|
*
|
|
143
|
-
*
|
|
143
|
+
* Five answers, and only the last refuses:
|
|
144
144
|
*
|
|
145
145
|
* - _A one-to-one row_ → the subtype it declares. `armor` addresses an
|
|
146
146
|
* `armorgear`.
|
|
@@ -151,12 +151,19 @@ export function documentSubtype(map: DocumentSubtypeMap, noteType: string | unde
|
|
|
151
151
|
* existed.
|
|
152
152
|
* - _A row for another document class_ → a problem. A being is not an item,
|
|
153
153
|
* however the address is spelled.
|
|
154
|
-
* - _A one-to-many
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
154
|
+
* - _A one-to-many row, named by one of its own permitted subtypes_ → that
|
|
155
|
+
* subtype. HM3's `weapongear` row is keyed by the note type `weapongear` but
|
|
156
|
+
* permits `["weapongear", "missilegear"]`; a reference spelled `weapongear`
|
|
157
|
+
* is not ambiguous — it already names the subtype it wants, the same as a
|
|
158
|
+
* reference spelled `missilegear` does by matching no row at all and taking
|
|
159
|
+
* the unmapped fallback above. Only the row's own key can coincide with one
|
|
160
|
+
* of its subtypes, so this is never a second guess at the note's
|
|
161
|
+
* frontmatter — the row was looked up by this exact spelling.
|
|
162
|
+
* - _A one-to-many row, named by neither the row's other permitted subtypes
|
|
163
|
+
* nor resolved above_ → a problem naming the candidates. The note that owns
|
|
164
|
+
* such a row resolves it from its own frontmatter block; a reference naming
|
|
165
|
+
* only the row has no block to read a discriminator from, so nothing here
|
|
166
|
+
* can choose, and choosing anyway would be right about half the time.
|
|
160
167
|
*
|
|
161
168
|
* A **retired** spelling is refused by name before any of that. Without it a
|
|
162
169
|
* reference left behind by a merge would take the unmapped fallback and address
|
package/types/hm3/actors.d.mts
CHANGED
|
@@ -15,6 +15,15 @@ export class Hm3Actors extends SystemActorCompiler {
|
|
|
15
15
|
* @type {import("../engine/document-subtypes.mjs").DocumentSubtypeMap}
|
|
16
16
|
*/
|
|
17
17
|
static documentSubtypes: import("../engine/document-subtypes.mjs").DocumentSubtypeMap;
|
|
18
|
+
/**
|
|
19
|
+
* @inheritdoc
|
|
20
|
+
*
|
|
21
|
+
* Answers for `spell`, `invocation` and `psionic` too — see
|
|
22
|
+
* {@link EMBEDDED_ITEM_ART} — falling back to the engine's note-type
|
|
23
|
+
* table for every other reference, `weapongear` and `missilegear`
|
|
24
|
+
* included.
|
|
25
|
+
*/
|
|
26
|
+
embeddedItemArt(type: any, subType: any): string;
|
|
18
27
|
/**
|
|
19
28
|
* Build every embedded item an HM3 actor carries, from `hm3.items`.
|
|
20
29
|
*
|