@heroiclands/package-build 23.0.0 → 23.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +1 -1
  3. package/bin/content-commands.mjs +1 -1
  4. package/ci/content-format-reference.mjs +46 -0
  5. package/docs/api.md +124 -141
  6. package/docs/authoring/assets.md +1 -1
  7. package/docs/authoring/dates-and-calendars.md +12 -6
  8. package/docs/authoring/frontmatter.md +2 -2
  9. package/docs/authoring/links-and-markup.md +145 -29
  10. package/docs/commands.md +8 -10
  11. package/docs/configuration.md +13 -11
  12. package/docs/content-format.md +2 -2
  13. package/docs/guides/book.md +59 -4
  14. package/docs/guides/icons.md +4 -5
  15. package/docs/guides/packs.md +6 -0
  16. package/docs/guides/reference-pages.md +21 -1
  17. package/docs/guides/release-and-deploy.md +39 -7
  18. package/docs/guides/site.md +17 -18
  19. package/docs/reference/format-details.md +877 -276
  20. package/docs/reference/note-types.md +278 -91
  21. package/docs/reference/theme-pages.md +58 -97
  22. package/engine/address-values.mjs +124 -4
  23. package/engine/address.mjs +44 -3
  24. package/engine/anchors.mjs +103 -3
  25. package/engine/art-slots.mjs +2 -9
  26. package/engine/base-compiler.mjs +25 -6
  27. package/engine/calendar-artifacts.mjs +4 -1
  28. package/engine/calendar-notes.mjs +166 -102
  29. package/engine/content-format-check.mjs +2 -3
  30. package/engine/content-format.mjs +44 -1
  31. package/engine/content-format.yaml +79 -16
  32. package/engine/content-images.mjs +10 -1
  33. package/engine/content-index.mjs +37 -9
  34. package/engine/content-links.mjs +24 -5
  35. package/engine/content-tables.mjs +24 -3
  36. package/engine/data-keys.mjs +347 -0
  37. package/engine/derived-sections.mjs +322 -0
  38. package/engine/diagnostics.mjs +28 -0
  39. package/engine/event-fields.mjs +187 -0
  40. package/engine/event-rows.mjs +126 -0
  41. package/engine/event-views.mjs +305 -0
  42. package/engine/exported-scene.mjs +29 -53
  43. package/engine/frontmatter-lint.mjs +103 -77
  44. package/engine/frontmatter.mjs +7 -2
  45. package/engine/generate.mjs +53 -0
  46. package/engine/generated-sections.mjs +223 -0
  47. package/engine/heading-attributes.mjs +4 -2
  48. package/engine/helpers.mjs +12 -1
  49. package/engine/holdings.mjs +12 -33
  50. package/engine/ids.mjs +17 -11
  51. package/engine/index.mjs +4 -4
  52. package/engine/infobox-render.mjs +21 -6
  53. package/engine/infobox.mjs +217 -99
  54. package/engine/journals.mjs +104 -47
  55. package/engine/literature-notes.mjs +4 -1
  56. package/engine/literature-works.mjs +21 -13
  57. package/engine/map-graphviz.mjs +4 -18
  58. package/engine/markdown-expressions.mjs +116 -11
  59. package/engine/metadata-index.mjs +26 -0
  60. package/engine/near-miss.mjs +90 -0
  61. package/engine/note-addresses.mjs +75 -19
  62. package/engine/note-dates.mjs +5 -3
  63. package/engine/note-event-terms.mjs +364 -0
  64. package/engine/note-events.mjs +823 -0
  65. package/engine/note-vocabulary.mjs +184 -88
  66. package/engine/office-holders.mjs +20 -54
  67. package/engine/packagebuild-index.mjs +16 -1
  68. package/engine/pdf-build.mjs +97 -60
  69. package/engine/pdf-index.mjs +263 -0
  70. package/engine/pdf-render.mjs +47 -5
  71. package/engine/place-relation-terms.mjs +174 -0
  72. package/engine/place-relations.mjs +72 -160
  73. package/engine/rank-ladder.mjs +14 -41
  74. package/engine/reckoning-markers.mjs +2 -0
  75. package/engine/region-events.mjs +6 -12
  76. package/engine/scenes.mjs +73 -468
  77. package/engine/site-build.mjs +75 -101
  78. package/engine/site-index.mjs +3 -1
  79. package/engine/site-maps.mjs +43 -29
  80. package/engine/site-preview.mjs +40 -31
  81. package/engine/social-ties.mjs +2 -1
  82. package/engine/sql-tables.mjs +212 -9
  83. package/engine/standing-terms.mjs +145 -6
  84. package/engine/standings.mjs +37 -49
  85. package/engine/web-wikilinks.mjs +21 -1
  86. package/engine/wikilink-syntax.mjs +34 -4
  87. package/engine/wikilinks.mjs +27 -2
  88. package/engine/yaml-lint.mjs +7 -4
  89. package/hugo-theme/layouts/partials/infobox/entry.html +4 -1
  90. package/hugo-theme/layouts/partials/page-body.html +0 -3
  91. package/hugo-theme/static/css/style.css +25 -55
  92. package/package.json +1 -2
  93. package/packagebuild-metadata.jsonl +13 -13
  94. package/release.mjs +62 -4
  95. package/sohl/note-schemas.mjs +8 -73
  96. package/types/engine/address-values.d.mts +50 -3
  97. package/types/engine/address.d.mts +21 -0
  98. package/types/engine/anchors.d.mts +49 -2
  99. package/types/engine/art-slots.d.mts +1 -1
  100. package/types/engine/base-compiler.d.mts +13 -4
  101. package/types/engine/calendar-notes.d.mts +7 -0
  102. package/types/engine/content-format.d.mts +52 -0
  103. package/types/engine/content-images.d.mts +5 -1
  104. package/types/engine/content-tables.d.mts +9 -1
  105. package/types/engine/data-keys.d.mts +145 -0
  106. package/types/engine/derived-sections.d.mts +73 -0
  107. package/types/engine/diagnostics.d.mts +15 -0
  108. package/types/engine/event-fields.d.mts +99 -0
  109. package/types/engine/event-rows.d.mts +12 -0
  110. package/types/engine/event-views.d.mts +67 -0
  111. package/types/engine/exported-scene.d.mts +5 -2
  112. package/types/engine/frontmatter-lint.d.mts +3 -3
  113. package/types/engine/generated-sections.d.mts +143 -0
  114. package/types/engine/holdings.d.mts +6 -20
  115. package/types/engine/ids.d.mts +15 -12
  116. package/types/engine/index.d.mts +1 -1
  117. package/types/engine/infobox.d.mts +13 -3
  118. package/types/engine/journals.d.mts +24 -11
  119. package/types/engine/literature-works.d.mts +1 -2
  120. package/types/engine/map-graphviz.d.mts +2 -10
  121. package/types/engine/markdown-expressions.d.mts +12 -3
  122. package/types/engine/near-miss.d.mts +42 -0
  123. package/types/engine/note-addresses.d.mts +7 -1
  124. package/types/engine/note-event-terms.d.mts +68 -0
  125. package/types/engine/note-events.d.mts +71 -0
  126. package/types/engine/note-vocabulary.d.mts +37 -8
  127. package/types/engine/office-holders.d.mts +3 -0
  128. package/types/engine/pdf-index.d.mts +35 -0
  129. package/types/engine/pdf-render.d.mts +8 -2
  130. package/types/engine/place-relation-terms.d.mts +83 -0
  131. package/types/engine/place-relations.d.mts +11 -66
  132. package/types/engine/rank-ladder.d.mts +2 -0
  133. package/types/engine/region-events.d.mts +6 -12
  134. package/types/engine/scenes.d.mts +6 -32
  135. package/types/engine/site-build.d.mts +8 -22
  136. package/types/engine/site-maps.d.mts +15 -7
  137. package/types/engine/sql-tables.d.mts +77 -2
  138. package/types/engine/standing-terms.d.mts +37 -4
  139. package/types/engine/standings.d.mts +14 -9
  140. package/types/engine/wikilink-syntax.d.mts +20 -0
  141. package/types/engine/wikilinks.d.mts +3 -2
  142. package/types/engine/yaml-lint.d.mts +5 -4
  143. package/types/release.d.mts +4 -0
  144. package/docs/guides/government-migration.md +0 -52
  145. package/engine/itinerary-scenes.mjs +0 -166
  146. package/engine/lore-events.mjs +0 -197
  147. package/engine/map-notes.mjs +0 -1309
  148. package/engine/map-raster.mjs +0 -51
  149. package/hugo-theme/layouts/partials/holdings/entry.html +0 -21
  150. package/hugo-theme/layouts/partials/holdings/kind-groups.html +0 -71
  151. package/hugo-theme/layouts/partials/holdings.html +0 -61
  152. package/hugo-theme/layouts/partials/literature-works.html +0 -29
  153. package/hugo-theme/layouts/partials/place-map.html +0 -9
  154. package/types/engine/itinerary-scenes.d.mts +0 -29
  155. package/types/engine/lore-events.d.mts +0 -14
  156. package/types/engine/map-notes.d.mts +0 -297
  157. package/types/engine/map-raster.d.mts +0 -8
@@ -1,51 +0,0 @@
1
- /*
2
- * SPDX-License-Identifier: GPL-3.0-or-later
3
- */
4
-
5
- import fs from "node:fs";
6
- import path from "node:path";
7
- import { Resvg } from "@resvg/resvg-js";
8
- import { resolvePackageBuildConfig } from "../config.mjs";
9
-
10
- /** Rasterize an authored SVG map into the staged Foundry package. */
11
- export function rasterizeMapSvg({ foundryPath, width, height, sceneId, config }) {
12
- if (!config) throw new Error("SVG map rasterization requires the package build configuration");
13
- const buildConfig = resolvePackageBuildConfig(config);
14
- if (![width, height].every((value) => Number.isInteger(value) && value > 0)) {
15
- throw new Error("an SVG map needs `sohl.dimensions: [width, height]` in whole pixels");
16
- }
17
- const marker = "/assets/";
18
- const at = foundryPath.indexOf(marker);
19
- if (at < 0 || !foundryPath.toLowerCase().endsWith(".svg")) {
20
- throw new Error(`map art path "${foundryPath}" is not an SVG inside assets`);
21
- }
22
- const suffix = foundryPath.slice(at + marker.length);
23
- const source = path.resolve(config.rootDir, "assets", suffix);
24
- const assetRoot = path.resolve(config.rootDir, "assets");
25
- if (!source.startsWith(`${assetRoot}${path.sep}`) || !fs.existsSync(source)) {
26
- throw new Error(`map SVG "${foundryPath}" is not a local asset this package can rasterize`);
27
- }
28
- const staged = path.resolve(
29
- config.rootDir,
30
- buildConfig.stageDir,
31
- "assets/maps/rasterized",
32
- `${sceneId}.png`,
33
- );
34
- fs.mkdirSync(path.dirname(staged), { recursive: true });
35
- try {
36
- const image = new Resvg(fs.readFileSync(source), {
37
- fitTo: { mode: "width", value: width },
38
- }).render();
39
- if (image.height !== height) {
40
- throw new Error(
41
- `the SVG is ${width}×${image.height} at the stated width, not ${width}×${height}`,
42
- );
43
- }
44
- fs.writeFileSync(staged, image.asPng());
45
- } catch (error) {
46
- throw new Error(`could not rasterize map SVG "${foundryPath}": ${error.message}`, {
47
- cause: error,
48
- });
49
- }
50
- return `${buildConfig.packageKind}/${buildConfig.packageId}/assets/maps/rasterized/${sceneId}.png`;
51
- }
@@ -1,21 +0,0 @@
1
- {{- /*
2
- One entry of a holdings list — `{title, url, type, subType}`, as
3
- `@heroiclands/package-build` derives from `contains`, `governed_by` and
4
- `governed_places` (see the "holdings card" section of the README).
5
-
6
- `url` is absent for a stub: a note with an empty body, which carries its
7
- facts into every list that names it but publishes no page of its own. The
8
- build omits the key outright rather than writing `url: null` — confirmed by
9
- stringifying a stub entry through the same `gray-matter`/`js-yaml` path the
10
- build writes frontmatter with — but `with` guards both the same way, since
11
- a missing map key and an empty string both read false. This is the same
12
- guard `infobox/entry.html` already applies to its own `{text, url}` shape.
13
-
14
- Takes `entry` and the `class` its medium gives it.
15
- */ -}}
16
- {{- $entry := .entry -}}
17
- {{- with $entry.url -}}
18
- <a class="{{ $.class }}" href="{{ . }}">{{ $entry.title }}</a>
19
- {{- else -}}
20
- <span class="{{ $.class }}">{{ $entry.title }}</span>
21
- {{- end -}}
@@ -1,71 +0,0 @@
1
- {{- /*
2
- The kind-grouped body of a "Within" or "Holdings" table: its entries
3
- broken into named groups by `subType`, in the closed order region,
4
- settlement, site, structure, feature — the order a reader wants a place
5
- hierarchy read in, not alphabetical. A `subType` outside that order, or
6
- missing entirely, is grouped last, one group per remaining kind,
7
- alphabetically by its `humanize`d label.
8
-
9
- Each group is a CSS grid (`repeat(auto-fill, minmax(14em, 1fr))`, the same
10
- the Related card uses) so a region with forty settlements stays scannable.
11
-
12
- Takes the entries (a `HoldingsEntry` list). Renders nothing for an empty
13
- list, so a caller can include it unconditionally once its own presence
14
- check on the list has passed.
15
- */ -}}
16
- {{- $entries := . -}}
17
- {{- $kindOrder := slice "region" "settlement" "site" "structure" "feature" -}}
18
- {{- $kindLabels := dict
19
- "region" "Regions"
20
- "settlement" "Settlements"
21
- "site" "Sites"
22
- "structure" "Structures"
23
- "feature" "Features"
24
- -}}
25
-
26
- {{- /* Bucket entries by subType, defaulting an absent one to "". */ -}}
27
- {{- $byKind := dict -}}
28
- {{- range $entries -}}
29
- {{- $kind := .subType | default "" -}}
30
- {{- $existing := index $byKind $kind | default slice -}}
31
- {{- $byKind = merge $byKind (dict $kind ($existing | append .)) -}}
32
- {{- end -}}
33
-
34
- {{- /* The closed order first. */ -}}
35
- {{- $groups := slice -}}
36
- {{- $seen := slice -}}
37
- {{- range $kindOrder -}}
38
- {{- $kind := . -}}
39
- {{- with index $byKind $kind -}}
40
- {{- $groups = $groups | append (dict "label" (index $kindLabels $kind) "entries" .) -}}
41
- {{- $seen = $seen | append $kind -}}
42
- {{- end -}}
43
- {{- end -}}
44
-
45
- {{- /* Anything else — a kind outside the closed set, or none at all —
46
- grouped last, alphabetically by its rendered label. */ -}}
47
- {{- $leftover := slice -}}
48
- {{- range $kind, $group := $byKind -}}
49
- {{- if not (in $seen $kind) -}}
50
- {{- $label := humanize $kind -}}
51
- {{- if eq $kind "" -}}{{- $label = "Other" -}}{{- end -}}
52
- {{- $leftover = $leftover | append (dict "label" $label "entries" $group) -}}
53
- {{- end -}}
54
- {{- end -}}
55
- {{- if $leftover -}}
56
- {{- $leftover = sort $leftover "label" "asc" -}}
57
- {{- range $leftover -}}
58
- {{- $groups = $groups | append . -}}
59
- {{- end -}}
60
- {{- end -}}
61
-
62
- {{- range $groups }}
63
- <div class="holdings-kind-group">
64
- <h4 class="holdings-kind-label">{{ .label }}</h4>
65
- <ul class="holdings-table-grid">
66
- {{- range .entries }}
67
- <li>{{ partial "holdings/entry.html" (dict "entry" . "class" "holdings-entry-name") }}</li>
68
- {{- end }}
69
- </ul>
70
- </div>
71
- {{- end -}}
@@ -1,61 +0,0 @@
1
- {{- /*
2
- Geography and government card.
3
-
4
- Three small tables, rendered after the body and before the Related card
5
- (see `page-body.html`), from front matter `@heroiclands/package-build`
6
- derives and a note never authors itself:
7
-
8
- contains: [{ title, url, type, subType }] places sitting within this one
9
- governed_by: [{ title, url, type, subType }] affiliations governing this place
10
- governed_places: [{ title, url, type, subType }] places this affiliation governs
11
-
12
- A place page carries `contains` and/or `governed_by`; an affiliation page
13
- carries `governed_places`. Neither is checked here — presence of the key is the
14
- only test, the same silent-disappear convention the Related card follows:
15
- a page carrying none of the three renders no card at all.
16
-
17
- `contains` and `governed_places` list places, so each is broken into groups by
18
- kind (`holdings/kind-groups.html`) — the towns together, the hamlets
19
- together. `governed_by` lists affiliations, whose kinds have no fixed
20
- hierarchy to group by, so it stays one flat grid with the kind printed
21
- beside each name instead of as a group heading.
22
-
23
- An entry's `url` is absent for a stub — a note with an empty body, which
24
- carries its facts into every list that names it but publishes no page of
25
- its own. `holdings/entry.html` renders such an entry as plain text and
26
- every other entry as a link — see it for the guard and how its correctness
27
- was established.
28
- */ -}}
29
- {{- $within := .Params.contains -}}
30
- {{- $government := .Params.governed_by -}}
31
- {{- $governed := .Params.governed_places -}}
32
-
33
- {{- if or $within $government $governed -}}
34
- <section class="holdings" data-pagefind-ignore>
35
- {{- with $within }}
36
- <div class="holdings-table">
37
- <h3 class="holdings-table-label">Within</h3>
38
- {{ partial "holdings/kind-groups.html" . }}
39
- </div>
40
- {{- end }}
41
- {{- with $government }}
42
- <div class="holdings-table">
43
- <h3 class="holdings-table-label">Governed by</h3>
44
- <ul class="holdings-table-grid">
45
- {{- range . }}
46
- <li>
47
- {{- partial "holdings/entry.html" (dict "entry" . "class" "holdings-entry-name") -}}
48
- {{- with .subType }}<span class="holdings-entry-kind"> ({{ humanize . }})</span>{{ end -}}
49
- </li>
50
- {{- end }}
51
- </ul>
52
- </div>
53
- {{- end }}
54
- {{- with $governed }}
55
- <div class="holdings-table">
56
- <h3 class="holdings-table-label">Governed places</h3>
57
- {{ partial "holdings/kind-groups.html" . }}
58
- </div>
59
- {{- end }}
60
- </section>
61
- {{- end -}}
@@ -1,29 +0,0 @@
1
- {{- /*
2
- The "In song and story" card: the works of literature that name this page's
3
- subject, rendered after the body and the geography and government card.
4
-
5
- Front matter `@heroiclands/package-build` derives from every `literature`
6
- lore note's `data.subjects`, and a note never authors itself:
7
-
8
- works: [{ title, url, form? }] works naming this page, sorted by title
9
-
10
- `form` is the work's `data.form` — an epic, a saga, a praise-song — printed
11
- beside its name. Presence of the key is the only test: a page no work names
12
- carries no `works` and renders no card. An entry with no `url` is a work
13
- that publishes no page, rendered as plain text by `holdings/entry.html`.
14
- */ -}}
15
- {{- with .Params.works -}}
16
- <section class="holdings literature-works" data-pagefind-ignore>
17
- <div class="holdings-table">
18
- <h3 class="holdings-table-label">In song and story</h3>
19
- <ul class="holdings-table-grid">
20
- {{- range . }}
21
- <li>
22
- {{- partial "holdings/entry.html" (dict "entry" . "class" "holdings-entry-name") -}}
23
- {{- with .form }}<span class="holdings-entry-kind"> ({{ . }})</span>{{ end -}}
24
- </li>
25
- {{- end }}
26
- </ul>
27
- </div>
28
- </section>
29
- {{- end -}}
@@ -1,9 +0,0 @@
1
- {{- /* A page bundle's generated itinerary. The SVG carries its own place links. */ -}}
2
- {{- with .Params.map -}}
3
- {{- with $.Resources.GetMatch . -}}
4
- <section class="place-map" aria-labelledby="place-map-heading" data-pagefind-ignore>
5
- <h2 id="place-map-heading" class="place-map-heading">From here</h2>
6
- <div class="place-map-drawing">{{ .Content | safeHTML }}</div>
7
- </section>
8
- {{- end -}}
9
- {{- end -}}
@@ -1,29 +0,0 @@
1
- /** GraphViz's plain coordinates, converted to pixel positions on its PNG. */
2
- export function pinPositions(plain: any, width: any, height: any): Map<any, any>;
3
- /**
4
- * Emit backgrounds into the staged package and return Scenes and the journals
5
- * their pins need. The caller writes them into its Scene and Adventure packs.
6
- */
7
- export function buildItineraryScenes({ config, records, contentBase, journalSourceDirs, stats, foreign, }: {
8
- config: any;
9
- records: any;
10
- contentBase: any;
11
- journalSourceDirs?: never[] | undefined;
12
- stats: any;
13
- foreign?: {
14
- index: Map<string, object>;
15
- packages: Set<string>;
16
- stale: Array<{
17
- package: string;
18
- reason: string;
19
- }>;
20
- } | undefined;
21
- }): {
22
- scenes: object[];
23
- journal: any[];
24
- findings: {
25
- file: any;
26
- severity: string;
27
- message: string;
28
- }[];
29
- };
@@ -1,14 +0,0 @@
1
- /**
2
- * Validate one `lore` note's `data.events`.
3
- *
4
- * Registered as the `events` field's own `check` in `note-vocabulary.mjs`, so
5
- * it runs on every `lore` note regardless of `subType` — an occasion is not a
6
- * calendar fact, and nothing here is scoped to `subType: calendar`.
7
- *
8
- * @param {object} note - The note, as the link index hands it over.
9
- * @param {{index?: object}} [options]
10
- * @returns {object[]} Findings, each positioned at the entry that earned it.
11
- */
12
- export function checkLoreEvents(note: object, { index }?: {
13
- index?: object;
14
- }): object[];
@@ -1,297 +0,0 @@
1
- /**
2
- * Whether a content note's type compiles into a Scene.
3
- *
4
- * @param {string} [type] - The note's `type` frontmatter.
5
- * @returns {boolean} True for a map type.
6
- */
7
- export function isMapType(type?: string): boolean;
8
- /**
9
- * The canvas profile for a map subType.
10
- *
11
- * Keyed on the subType rather than the type: every map note is
12
- * `type: map`, and which canvas it derives is the one thing the three
13
- * spellings ever decided.
14
- *
15
- * @param {string} subType - The note's `subType`.
16
- * @returns {object} The profile from {@link MAP_SUBTYPE_PROFILES}.
17
- * @throws {Error} When the subType is not a map subType — the build's
18
- * fail-fast contract, so a typo never ships a scene with Foundry's own
19
- * defaults.
20
- */
21
- export function mapProfile(subType: string): object;
22
- /**
23
- * The id of one region within its scene.
24
- *
25
- * Derived rather than stored so a cross-reference (`teleportToken`,
26
- * `toggleBehavior`) can be resolved to a UUID before the target scene has been
27
- * compiled. An authored `_id` always wins — the converter pins ids on
28
- * write-back exactly as it does for items and actors.
29
- *
30
- * @param {string} sceneId - The owning scene's `_id`.
31
- * @param {string} key - The region's authored key.
32
- * @param {string} [pinned] - An authored `_id`, if any.
33
- * @returns {string} A 16-character Foundry id.
34
- */
35
- export function regionDocId(sceneId: string, key: string, pinned?: string): string;
36
- /**
37
- * The id of one behaviour within its region.
38
- *
39
- * @param {string} regionId - The owning region's `_id`.
40
- * @param {string} key - The behaviour's authored key.
41
- * @param {string} [pinned] - An authored `_id`, if any.
42
- * @returns {string} A 16-character Foundry id.
43
- */
44
- export function behaviorDocId(regionId: string, key: string, pinned?: string): string;
45
- /**
46
- * A region's highlight colour, derived from its key.
47
- *
48
- * Foundry's default is `Color.fromHSV([Math.random(), 0.8, 0.8])` — a different
49
- * value on every create, which would make each build's output differ from the
50
- * last for no reason anyone could see. Hashing the key keeps builds
51
- * reproducible and diffs quiet, in the same hue/saturation family Foundry
52
- * itself would have chosen, and keeps the value out of the note entirely.
53
- *
54
- * @param {string} key - The region's authored key.
55
- * @returns {string} A CSS hex colour.
56
- */
57
- export function regionColor(key: string): string;
58
- /**
59
- * The map's own measurements, from which both unit lints are derived.
60
- *
61
- * @typedef {object} MapGeometry
62
- * @property {string} label - The authored key, for error messages.
63
- * @property {number} pxPerGrid - Pixels per grid square.
64
- * @property {number[]} dimensions - `[width, height]` in pixels.
65
- */
66
- /**
67
- * Reject geometry authored in grid squares where pixels belong.
68
- *
69
- * A grid-valued wall or region is not rejected by Foundry: it becomes a
70
- * 12x11-pixel feature in the top-left corner, invisible on the map and
71
- * impossible to notice in a diff. The test is derived from the map itself
72
- * rather than a magic number — when every coordinate of one feature is smaller
73
- * than a single grid square, on a map several squares across, the author
74
- * counted squares.
75
- *
76
- * @param {number[]} coords - The feature's coordinates, in pixels.
77
- * @param {MapGeometry} geom - The map's measurements.
78
- * @throws {Error} When the coordinates read as grid units.
79
- */
80
- export function assertPixelGeometry(coords: number[], geom: MapGeometry): void;
81
- /**
82
- * Reject a map pin authored in pixels where grid squares belong.
83
- *
84
- * @param {number[]} at - The pin's `[x, y]`, in grid squares.
85
- * @param {MapGeometry} geom - The map's measurements.
86
- * @throws {Error} When the coordinates read as pixels.
87
- */
88
- export function assertGridLocation(at: number[], geom: MapGeometry): void;
89
- /**
90
- * Compile a wall's `blocks:` / `limits:` lists into Foundry's four numeric
91
- * restriction fields.
92
- *
93
- * The authored vocabulary is deliberately not Foundry's.
94
- * `WALL_MOVEMENT_TYPES.NONE` means movement does **not** collide — i.e.
95
- * passable — so `movement: none` reads as the exact opposite of what it does.
96
- * `blocks:` says what the wall stops and `limits:` what it merely attenuates;
97
- * anything unnamed is passable.
98
- *
99
- * @param {{blocks?: string[], limits?: string[]}} spec - The authored lists.
100
- * @param {string} label - The authored key, for error messages.
101
- * @returns {{move: number, sight: number, light: number, sound: number}} The
102
- * Wall restriction fields.
103
- * @throws {Error} On an unknown sense, a sense in both lists, or a *limited*
104
- * movement restriction (movement is binary — it has no LIMITED value).
105
- */
106
- export function wallRestrictions(spec: {
107
- blocks?: string[];
108
- limits?: string[];
109
- }, label: string): {
110
- move: number;
111
- sight: number;
112
- light: number;
113
- sound: number;
114
- };
115
- /**
116
- * Compile one authored shape into a Foundry shape record.
117
- *
118
- * Four forms only — `rectangle` (`rect` is accepted as its short spelling),
119
- * `circle`, `ellipse` and `polygon`. The remaining six Foundry shapes are
120
- * template and token-attached forms with no place in an authored map, and
121
- * `gridBased` is deliberately not exposed: it re-interprets a shape metrically,
122
- * and one unit convention per note is the whole point.
123
- *
124
- * @param {object} spec - The authored shape entry.
125
- * @param {MapGeometry} geom - The map's measurements.
126
- * @returns {object} The Foundry shape record.
127
- * @throws {Error} On an unknown form, a degenerate polygon, or grid-unit
128
- * coordinates.
129
- */
130
- export function buildShape(spec: object, geom: MapGeometry): object;
131
- /**
132
- * Compile a map note into a Scene document, embedded documents and all.
133
- *
134
- * Every embedded document carries its own `_key`. This is not decoration: the
135
- * compendium CLI writes each one straight to its sublevel by that key, and a
136
- * missing one fails the compile with `Key cannot be null or undefined`.
137
- *
138
- * @param {object} fm - The note's frontmatter.
139
- * @param {object} ctx - The compile context:
140
- * `packageId`, `journalEntryId`, `journalPack` (the pack the note's derived
141
- * JournalEntry landed in), `pageIds` (heading key → page id),
142
- * `resolveRegionRef` / `resolveBehaviorRef` / `resolveEffectRef` (address →
143
- * UUID), `art` (an art address → the path each surface serves),
144
- * `knownActions`, `warnings`, and optionally `folder` and `stats`.
145
- * @returns {object} The Scene document, keyed for the pack.
146
- * @throws {Error} On any authoring mistake Foundry would accept silently.
147
- */
148
- export function buildScene(fm: object, ctx: object): object;
149
- /**
150
- * Synthesise the scene's single embedded Level from `img:` / `overlay:`.
151
- *
152
- * Authors never write `levels:`. A scene must ship at least one Level — the
153
- * client-side `_preCreate` net that would create one does not run for offline
154
- * pack compilation, and the server-side migration shim is version-gated on
155
- * `_stats.coreVersion`, so a pack stamped 14.x+ skips it and ships a scene with
156
- * no Level and no map.
157
- *
158
- * @param {object} sohl - The note's `sohl:` block.
159
- * @param {string} sceneId - The owning scene's `_id`.
160
- * @param {string} img - The background art, already resolved from the note's
161
- * `bgImage` address by {@link buildScene}. Passed rather than resolved here,
162
- * because an address is answered by the compile's index and this function
163
- * takes none.
164
- * @param {(value: unknown, key: string, type: string, accepts?: Iterable<string>) => string|null} [art] -
165
- * The art resolver, for the foreground overlay. Omitted, a note naming one
166
- * gets no overlay rather than a path nothing serves.
167
- * @returns {object} The Level document, keyed for the pack.
168
- */
169
- export function buildLevel(sohl: object, sceneId: string, img: string, art?: (value: unknown, key: string, type: string, accepts?: Iterable<string>) => string | null): object;
170
- /**
171
- * Compile the `walls:` and `doors:` blocks into Wall documents.
172
- *
173
- * Walls are keyed by **feature** rather than by restriction signature, so a
174
- * diff reads "the hayloft walls changed" instead of "line 143 changed", and a
175
- * human can find the one wall they meant to move.
176
- *
177
- * @param {object} sohl - The note's `sohl:` block.
178
- * @param {MapGeometry} geom - The map's measurements.
179
- * @param {object} ctx - The compile context.
180
- * @returns {object[]} The Wall documents.
181
- */
182
- export function buildWalls(sohl: object, geom: MapGeometry, ctx: object): object[];
183
- /**
184
- * Compile the `lights:` block into AmbientLight documents.
185
- *
186
- * `dim` and `bright` are radii in the scene's **distance units** (Foundry's own
187
- * meaning), not pixels; only `position:` is pixels.
188
- *
189
- * @param {object} sohl - The note's `sohl:` block.
190
- * @param {MapGeometry} geom - The map's measurements.
191
- * @param {object} ctx - The compile context.
192
- * @returns {object[]} The AmbientLight documents.
193
- */
194
- export function buildLights(sohl: object, geom: MapGeometry, ctx: object): object[];
195
- /**
196
- * Compile the `tiles:` block into Tile documents.
197
- *
198
- * @param {object} sohl - The note's `sohl:` block.
199
- * @param {MapGeometry} geom - The map's measurements.
200
- * @param {object} ctx - The compile context.
201
- * @returns {object[]} The Tile documents.
202
- */
203
- export function buildTiles(sohl: object, geom: MapGeometry, ctx: object): object[];
204
- /**
205
- * Compile the `sounds:` block into AmbientSound documents.
206
- *
207
- * Positional audio is the one audio mechanism that packages cleanly: `path` is
208
- * a plain `FilePathField` with no document reference behind it.
209
- *
210
- * @param {object} sohl - The note's `sohl:` block.
211
- * @param {MapGeometry} geom - The map's measurements.
212
- * @param {object} ctx - The compile context.
213
- * @returns {object[]} The AmbientSound documents.
214
- */
215
- export function buildSounds(sohl: object, geom: MapGeometry, ctx: object): object[];
216
- /**
217
- * Compile the `locations:` block into Note documents — the map pins.
218
- *
219
- * A location's key names a heading in the note's body, and the pin points at
220
- * the journal page that heading compiled into. `Note.entryId` / `pageId` are
221
- * `{idOnly: true}` fields, which return before the compendium guard, so pin
222
- * targets survive packing intact — but `Note#entry` resolves by bare id against
223
- * the **world** collection, which is why a map with pins ships inside an
224
- * Adventure (`keepId: true`).
225
- *
226
- * @param {object} sohl - The note's `sohl:` block.
227
- * @param {MapGeometry} geom - The map's measurements.
228
- * @param {object} ctx - The compile context.
229
- * @returns {object[]} The Note documents.
230
- */
231
- export function buildLocations(sohl: object, geom: MapGeometry, ctx: object): object[];
232
- /**
233
- * Compile the `regions:` block into Region documents with their behaviours.
234
- *
235
- * @param {object} sohl - The note's `sohl:` block.
236
- * @param {MapGeometry} geom - The map's measurements.
237
- * @param {object} ctx - The compile context.
238
- * @returns {object[]} The Region documents.
239
- */
240
- export function buildRegions(sohl: object, geom: MapGeometry, ctx: object): object[];
241
- /**
242
- * Per-subtype canvas defaults, emitted **explicitly** on every scene.
243
- *
244
- * This is not a convenience. `grid.type`, `grid.distance` and `grid.units` all
245
- * declare `initial: () => game.system.grid.*`, and there is no `game` at build
246
- * time — left to their initial they would throw or ship undefined. The numeric
247
- * values are `CONST.GRID_TYPES` and `CONST.FOG_EXPLORATION_MODES`, spelled out
248
- * here because the constants module is Foundry's, not ours.
249
- *
250
- * @type {Readonly<Record<string, object>>}
251
- */
252
- export const MAP_SUBTYPE_PROFILES: Readonly<Record<string, object>>;
253
- /**
254
- * Foundry's own id for the level a scene is created with
255
- * (`Scene.metadata.defaultLevelId`). Adopting it makes every reference to the
256
- * synthesised level derivable, and matches what Foundry would have produced.
257
- */
258
- export const DEFAULT_LEVEL_ID: "defaultLevel0000";
259
- /**
260
- * The behaviour types a map note may carry (v1).
261
- *
262
- * @type {ReadonlySet<string>}
263
- */
264
- export const REGION_BEHAVIOR_TYPES: ReadonlySet<string>;
265
- /**
266
- * Behaviour types a map note may **never** carry, and why.
267
- *
268
- * `executeScript` is banned outright: its `source` is a `JavaScriptField`, so a
269
- * note carrying one would compile data into code — the system's top security
270
- * constraint (non-negotiable rule 10). There is no escape hatch and no
271
- * configuration that re-enables it. `executeMacro` is merely deferred: its
272
- * target Macro has to ship in the same Adventure to resolve, and
273
- * Adventure-bundled macros are not built yet.
274
- *
275
- * @type {ReadonlyMap<string, string>}
276
- */
277
- export const BANNED_REGION_BEHAVIOR_TYPES: ReadonlyMap<string, string>;
278
- /**
279
- * The map's own measurements, from which both unit lints are derived.
280
- */
281
- export type MapGeometry = {
282
- /**
283
- * - The authored key, for error messages.
284
- */
285
- label: string;
286
- /**
287
- * - Pixels per grid square.
288
- */
289
- pxPerGrid: number;
290
- /**
291
- * - `[width, height]` in pixels.
292
- */
293
- dimensions: number[];
294
- };
295
- import { MAP_SUBTYPES } from "./ids.mjs";
296
- import { MAP_TYPES } from "./ids.mjs";
297
- export { MAP_SUBTYPES, MAP_TYPES };
@@ -1,8 +0,0 @@
1
- /** Rasterize an authored SVG map into the staged Foundry package. */
2
- export function rasterizeMapSvg({ foundryPath, width, height, sceneId, config }: {
3
- foundryPath: any;
4
- width: any;
5
- height: any;
6
- sceneId: any;
7
- config: any;
8
- }): string;