@heroiclands/package-build 20.6.0 → 20.7.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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 20.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6c10f17: **A `trees` entry's pages stay where their tree mounts them** — declaring
8
+ `subType` on a note inside `site.trees` no longer moves its published address.
9
+ A `subType` classifies a page for the site index; it never routed a tree
10
+ page's URL to begin with for a note that left it unset, and now it does not
11
+ for one that sets it either. A site that already worked around this by
12
+ avoiding `subType` on its tree notes can declare it again: those pages move
13
+ back under the tree's own section on upgrade.
14
+
15
+ ### Patch Changes
16
+
17
+ - 72daae4: **A being that declares no `sohl:` block no longer takes the site build down.**
18
+ `content-build site` failed with `unacceptable kind of an object to dump [object
19
+ Undefined]` for any `type: being` note whose front matter carried no `sohl:` key
20
+ at all, and the throw aborted the entire run rather than the one page. A note
21
+ carrying `sohl: null` had always been fine, so the failure only appeared once a
22
+ tree removed the empty key rather than emptying it. Both shapes now publish the
23
+ same page. Fixes HeroicLands/package-build#478.
24
+
3
25
  ## 20.6.0
4
26
 
5
27
  ### Minor Changes
@@ -267,6 +267,14 @@ export function collectContentPages(contentBase, ctx) {
267
267
  * addressed by type and slug: they are a book with chapters, and a reader
268
268
  * follows their paths. A `README` is its directory's landing.
269
269
  *
270
+ * **The section is the tree's, never the note's.** `tree.section` is the
271
+ * mount point a `trees` entry configures — fixed, physical, and the same
272
+ * value `site-index.mjs` indexes a tree page's address under. A note's own
273
+ * `subType` is a genre and reaches no address, the same contract
274
+ * `packageAddress()` holds for a content page: reading it here would move a
275
+ * page's URL, its file destination (`pageDestination`) and the address a
276
+ * wikilink cites it by, every time an author classified it.
277
+ *
270
278
  * @param {object} tree - `{ from, rel, section, route }`.
271
279
  * @param {object} ctx - `{ mount }`.
272
280
  * @returns {{pages: object[], fmLinkFindings: object[]}}
@@ -287,7 +295,7 @@ export function collectTreePages(tree, ctx) {
287
295
  const rel = path.relative(tree.from, file).replace(/\\/g, "/");
288
296
  const base = path.basename(rel);
289
297
  const isReadme = base.toLowerCase() === "readme.md";
290
- const sec = fm.subType ?? tree.section;
298
+ const sec = tree.section;
291
299
  const h1 = /^#\s+(.+?)\s*$/m.exec(body);
292
300
  const h1Title = h1 ? h1[1].replace(/\{@link\s+[^}]*\}/g, "").trim() : null;
293
301
  const name = fm.name?.full ?? fm.title ?? h1Title ?? path.basename(base, ".md");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "20.6.0",
3
+ "version": "20.7.0",
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",
@@ -154,6 +154,7 @@
154
154
  "devDependencies": {
155
155
  "@changesets/cli": "^3.0.0",
156
156
  "@types/node": "^26.2.0",
157
+ "npm-run-all": "^4.1.5",
157
158
  "vitest": "^5.0.0"
158
159
  },
159
160
  "scripts": {
@@ -163,7 +164,7 @@
163
164
  "build:types": "tsc -p tsconfig.dts.json",
164
165
  "format": "prettier --write .",
165
166
  "format:check": "prettier --check .",
166
- "lint": "npm run format:check && npm run lint:markdown && npm run lint:yaml && npm run lint:labels && npm run lint:content-format",
167
+ "lint": "run-p --aggregate-output -c --max-parallel 4 format:check lint:markdown lint:yaml lint:labels lint:content-format",
167
168
  "lint:markdown": "node bin/content-build.mjs markdown",
168
169
  "lint:yaml": "node bin/package-build.mjs yaml",
169
170
  "lint:labels": "node bin/package-build.mjs labels check",
@@ -108,11 +108,17 @@ const nonEmpty = (v) => Array.isArray(v) && v.length > 0;
108
108
  * @param {object|null|undefined} sohl - The note's `sohl` frontmatter block.
109
109
  * @param {Map<string, {name?: string, url?: string}>} index - Content index,
110
110
  * `"<type>:<shortcode>"` → the item's page.
111
- * @returns {object|null|undefined} The block with its info-block fields filled
112
- * in, or the input unchanged when there is nothing to derive from.
111
+ * @returns {object|null} The block with its info-block fields filled in, or the
112
+ * input unchanged when there is nothing to derive from — with an absent block
113
+ * reported as `null`, the value an empty one already carries.
113
114
  */
114
115
  export function deriveBeingInfo(sohl, index) {
115
- if (!isMap(sohl)) return sohl;
116
+ // A note declaring no `sohl:` key at all arrives as `undefined`, and the
117
+ // site emitter assigns this result straight into a page's front matter.
118
+ // js-yaml refuses to dump a property whose value is `undefined`, and the
119
+ // throw aborts the whole build rather than the one page — so "no block"
120
+ // is answered with the same `null` an empty block gets.
121
+ if (!isMap(sohl)) return sohl ?? null;
116
122
  const out = { ...sohl };
117
123
  const items = Array.isArray(out.items) ? out.items : [];
118
124
  if (items.length === 0) return out;
@@ -36,6 +36,14 @@ export function collectContentPages(contentBase: string, ctx: object): {
36
36
  * addressed by type and slug: they are a book with chapters, and a reader
37
37
  * follows their paths. A `README` is its directory's landing.
38
38
  *
39
+ * **The section is the tree's, never the note's.** `tree.section` is the
40
+ * mount point a `trees` entry configures — fixed, physical, and the same
41
+ * value `site-index.mjs` indexes a tree page's address under. A note's own
42
+ * `subType` is a genre and reaches no address, the same contract
43
+ * `packageAddress()` holds for a content page: reading it here would move a
44
+ * page's URL, its file destination (`pageDestination`) and the address a
45
+ * wikilink cites it by, every time an author classified it.
46
+ *
39
47
  * @param {object} tree - `{ from, rel, section, route }`.
40
48
  * @param {object} ctx - `{ mount }`.
41
49
  * @returns {{pages: object[], fmLinkFindings: object[]}}
@@ -26,13 +26,14 @@ export function isBeing(fm: {
26
26
  * @param {object|null|undefined} sohl - The note's `sohl` frontmatter block.
27
27
  * @param {Map<string, {name?: string, url?: string}>} index - Content index,
28
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.
29
+ * @returns {object|null} The block with its info-block fields filled in, or the
30
+ * input unchanged when there is nothing to derive from — with an absent block
31
+ * reported as `null`, the value an empty one already carries.
31
32
  */
32
33
  export function deriveBeingInfo(sohl: object | null | undefined, index: Map<string, {
33
34
  name?: string;
34
35
  url?: string;
35
- }>): object | null | undefined;
36
+ }>): object | null;
36
37
  /**
37
38
  * The note `type` whose pages carry a being info block.
38
39
  *