@heroiclands/package-build 22.14.3 → 22.15.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 +32 -0
- package/CONTENT.md +25 -1
- package/bin/content-build.mjs +3 -7
- package/bin/package-build.mjs +25 -0
- package/docs/api.md +64 -36
- package/docs/commands.md +65 -9
- package/docs/configuration.md +6 -3
- package/docs/content-format.md +187 -140
- package/docs/diagnostics.md +1 -1
- package/docs/getting-started.md +27 -3
- package/engine/base-compiler.mjs +3 -1
- package/engine/being-age.mjs +16 -24
- package/engine/calendar-artifacts.mjs +153 -0
- package/engine/calendar-notes.mjs +64 -16
- package/engine/calendars.mjs +129 -0
- package/engine/content-images.mjs +20 -10
- package/engine/content-index.mjs +3 -1
- package/engine/exported-scene.mjs +230 -0
- package/engine/generate.mjs +1 -0
- package/engine/ids.mjs +1 -1
- package/engine/index.mjs +6 -0
- package/engine/infobox.mjs +4 -0
- package/engine/itinerary-scenes.mjs +170 -0
- package/engine/map-build.mjs +10 -45
- package/engine/map-dot.mjs +6 -3
- package/engine/map-graphviz.mjs +50 -131
- package/engine/map-notes.mjs +26 -3
- package/engine/map-places.mjs +12 -6
- package/engine/map-raster.mjs +49 -0
- package/engine/note-dates.mjs +125 -85
- package/engine/note-vocabulary.mjs +22 -6
- package/engine/pdf-build.mjs +57 -1
- package/engine/pdf-render.mjs +48 -7
- package/engine/reckoning-markers.mjs +207 -0
- package/engine/scenes.mjs +113 -26
- package/engine/site-build.mjs +11 -13
- package/engine/site-maps.mjs +5 -35
- package/engine/site-preview.mjs +6 -1
- package/engine/social-tie-terms.mjs +3 -0
- package/engine/social-ties.mjs +30 -19
- package/package.json +3 -1
- package/types/engine/being-age.d.mts +2 -2
- package/types/engine/calendar-artifacts.d.mts +16 -0
- package/types/engine/calendar-notes.d.mts +1 -1
- package/types/engine/calendars.d.mts +65 -0
- package/types/engine/content-images.d.mts +7 -4
- package/types/engine/exported-scene.d.mts +12 -0
- package/types/engine/index.d.mts +2 -0
- package/types/engine/itinerary-scenes.d.mts +29 -0
- package/types/engine/map-build.d.mts +4 -13
- package/types/engine/map-graphviz.d.mts +17 -59
- package/types/engine/map-places.d.mts +5 -1
- package/types/engine/map-raster.d.mts +8 -0
- package/types/engine/note-dates.d.mts +6 -0
- package/types/engine/note-vocabulary.d.mts +3 -3
- package/types/engine/pdf-render.d.mts +16 -1
- package/types/engine/reckoning-markers.d.mts +27 -0
- package/types/engine/scenes.d.mts +9 -2
- package/types/engine/site-build.d.mts +1 -5
- package/types/engine/site-maps.d.mts +2 -7
- package/types/engine/social-tie-terms.d.mts +2 -0
- package/types/engine/social-ties.d.mts +2 -1
package/engine/site-build.mjs
CHANGED
|
@@ -78,6 +78,7 @@ import { indexRecordsFor } from "./content-index.mjs";
|
|
|
78
78
|
// A being's computed `age` — see `engine/being-age.mjs`. `pdf-build.mjs`
|
|
79
79
|
// reuses `collectContentPages`'s pages, so wiring it here reaches the book too.
|
|
80
80
|
import { applyComputedBeingAge, presentAmongRecords } from "./being-age.mjs";
|
|
81
|
+
import { reckoningContext } from "./reckoning-markers.mjs";
|
|
81
82
|
import { isNoteRecord, noteFile } from "./index-records.mjs";
|
|
82
83
|
// The one statement of what an empty body means, shared with the index.
|
|
83
84
|
import { isStubNote } from "./note-state.mjs";
|
|
@@ -196,19 +197,20 @@ export function collectContentPages(contentBase, ctx) {
|
|
|
196
197
|
// The package's declared present, read once from the same corpus the site
|
|
197
198
|
// and the PDF share — see `engine/being-age.mjs`. `pdf-build.mjs` reaches
|
|
198
199
|
// this through the pages this function returns, so one call covers both.
|
|
199
|
-
const
|
|
200
|
+
const records =
|
|
200
201
|
ctx.records ??
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
);
|
|
202
|
+
indexRecordsFor({
|
|
203
|
+
contentBase,
|
|
204
|
+
config: ctx.config,
|
|
205
|
+
skipDirectories: ctx.skipDirectories,
|
|
206
|
+
});
|
|
207
|
+
const present = presentAmongRecords(records);
|
|
208
|
+
const dates = reckoningContext({ notes: records });
|
|
207
209
|
|
|
208
210
|
for (const file of siteCorpusFiles(contentBase, ctx)) {
|
|
209
211
|
const note = readNote(file, ctx);
|
|
210
212
|
if (!note) continue;
|
|
211
|
-
applyComputedBeingAge(note.fm, present);
|
|
213
|
+
applyComputedBeingAge(note.fm, present, dates);
|
|
212
214
|
const { fm, body, bodyLine } = note;
|
|
213
215
|
// The configuration's, never a note's: `package:` is retired, so every
|
|
214
216
|
// note in the tree belongs to the package this repository compiles.
|
|
@@ -987,15 +989,12 @@ export function sitePageDecorator(config, index) {
|
|
|
987
989
|
* {@link module:engine/sql-tables.prepareSqlTables}. A page authoring an
|
|
988
990
|
* `sql` directive with none prepared is a table error: nothing here runs a
|
|
989
991
|
* query.
|
|
990
|
-
* @param {(engine: string) => string|undefined} [options.locate] - How a
|
|
991
|
-
* GraphViz engine's binary is found, for the maps; the real lookup by
|
|
992
|
-
* default.
|
|
993
992
|
* @returns {{gates: object, stats: object|null, tableErrors: object[],
|
|
994
993
|
* wikiErrors: object[], imageErrors: object[], mapFindings: object[],
|
|
995
994
|
* manifests: object|null}} `mapFindings` is what drawing the maps found —
|
|
996
995
|
* warnings, never a reason to fail the build.
|
|
997
996
|
*/
|
|
998
|
-
export function buildSite({ config, sqlTables
|
|
997
|
+
export function buildSite({ config, sqlTables } = {}) {
|
|
999
998
|
const resolved = config ?? loadPackConfig();
|
|
1000
999
|
const site = resolved.site;
|
|
1001
1000
|
const scheme = resolved.publish.address;
|
|
@@ -1179,7 +1178,6 @@ export function buildSite({ config, sqlTables, locate } = {}) {
|
|
|
1179
1178
|
foreignIndex: gates.foreign.index,
|
|
1180
1179
|
config: resolved,
|
|
1181
1180
|
base,
|
|
1182
|
-
...(locate ? { locate } : {}),
|
|
1183
1181
|
})
|
|
1184
1182
|
: { maps: new Map(), findings: [] };
|
|
1185
1183
|
|
package/engine/site-maps.mjs
CHANGED
|
@@ -23,10 +23,8 @@
|
|
|
23
23
|
* and every `href` in it composes `<base><slug>/` the way every other href
|
|
24
24
|
* the build renders does.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* would without maps. `site.maps: false` says the site carries none and asks
|
|
29
|
-
* nothing of GraphViz.
|
|
26
|
+
* The npm Graphviz runtime draws each map. `site.maps: false` says the site
|
|
27
|
+
* carries none and skips map rendering.
|
|
30
28
|
*
|
|
31
29
|
* The drawings land under `build/map/site/` — beside the author's own
|
|
32
30
|
* drawings under `build/map/`, and apart from them, because the site's
|
|
@@ -40,7 +38,6 @@ import fs from "node:fs";
|
|
|
40
38
|
import path from "node:path";
|
|
41
39
|
|
|
42
40
|
import { buildMaps, relatedPlaces } from "./map-build.mjs";
|
|
43
|
-
import { GRAPHVIZ_INSTALL, findGraphviz } from "./map-graphviz.mjs";
|
|
44
41
|
import { mapWorld } from "./map-places.mjs";
|
|
45
42
|
|
|
46
43
|
/**
|
|
@@ -50,13 +47,6 @@ import { mapWorld } from "./map-places.mjs";
|
|
|
50
47
|
*/
|
|
51
48
|
export const SITE_MAP_DIR = "build/map/site";
|
|
52
49
|
|
|
53
|
-
/**
|
|
54
|
-
* The engine the map from a place is drawn with.
|
|
55
|
-
*
|
|
56
|
-
* @type {string}
|
|
57
|
-
*/
|
|
58
|
-
const ENGINE = "neato";
|
|
59
|
-
|
|
60
50
|
/**
|
|
61
51
|
* A drawing as the page writer receives it.
|
|
62
52
|
*
|
|
@@ -106,16 +96,12 @@ export function inlineSvg(svg) {
|
|
|
106
96
|
* @param {object} opts.config - The resolved configuration.
|
|
107
97
|
* @param {string} opts.base - The site base every page is served under,
|
|
108
98
|
* ending in a slash: what every name in a drawing links through.
|
|
109
|
-
* @param {(engine: string) => string|undefined} [opts.locate] - How the
|
|
110
|
-
* engine's binary is found; the real lookup by default.
|
|
111
99
|
* @returns {{maps: Map<string, SiteMap>, findings: Array<{file: string,
|
|
112
100
|
* line?: number, column?: number, severity: "error"|"warning",
|
|
113
101
|
* message: string}>}} The drawings, keyed by the URL of the page each
|
|
114
|
-
* belongs to, and
|
|
115
|
-
* install when GraphViz is absent, and a warning for each relation that
|
|
116
|
-
* names no place.
|
|
102
|
+
* belongs to, and warnings for relations that name no place.
|
|
117
103
|
*/
|
|
118
|
-
export function drawSiteMaps({ records, foreignIndex, config, base
|
|
104
|
+
export function drawSiteMaps({ records, foreignIndex, config, base }) {
|
|
119
105
|
/** @type {Map<string, SiteMap>} */
|
|
120
106
|
const maps = new Map();
|
|
121
107
|
const outDir = path.join(config.rootDir, ...SITE_MAP_DIR.split("/"));
|
|
@@ -123,22 +109,6 @@ export function drawSiteMaps({ records, foreignIndex, config, base, locate = fin
|
|
|
123
109
|
// the map an earlier run drew.
|
|
124
110
|
fs.rmSync(outDir, { recursive: true, force: true });
|
|
125
111
|
|
|
126
|
-
if (!locate(ENGINE)) {
|
|
127
|
-
return {
|
|
128
|
-
maps,
|
|
129
|
-
findings: [
|
|
130
|
-
{
|
|
131
|
-
file: config.rootDir,
|
|
132
|
-
severity: "warning",
|
|
133
|
-
message:
|
|
134
|
-
`GraphViz's \`${ENGINE}\` is not installed, so no place page carries ` +
|
|
135
|
-
`the map from that place; ${GRAPHVIZ_INSTALL} to draw them, or set ` +
|
|
136
|
-
"`site.maps: false` to say the site carries none",
|
|
137
|
-
},
|
|
138
|
-
],
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
112
|
const world = mapWorld({
|
|
143
113
|
records,
|
|
144
114
|
foreignIndex,
|
|
@@ -152,7 +122,7 @@ export function drawSiteMaps({ records, foreignIndex, config, base, locate = fin
|
|
|
152
122
|
const centres = relatedPlaces(world.places).filter((s) => world.places.get(s)?.local);
|
|
153
123
|
if (centres.length === 0) return { maps, findings: [] };
|
|
154
124
|
|
|
155
|
-
const { findings } = buildMaps({ world, outDir, from: centres
|
|
125
|
+
const { findings } = buildMaps({ world, outDir, from: centres });
|
|
156
126
|
for (const centre of centres) {
|
|
157
127
|
const place = world.places.get(centre);
|
|
158
128
|
if (!place?.url) continue;
|
package/engine/site-preview.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { noteAddressContext, decodeNoteAddresses, encodeAddresses } from "./note
|
|
|
14
14
|
import { noteFile } from "./index-records.mjs";
|
|
15
15
|
import { foundryIdentities } from "./foundry-entries.mjs";
|
|
16
16
|
import { applyComputedBeingAge, presentAmongRecords } from "./being-age.mjs";
|
|
17
|
+
import { reckoningContext } from "./reckoning-markers.mjs";
|
|
17
18
|
import { cachedMetadataIndexes, noContentIndexPackages } from "./metadata-index.mjs";
|
|
18
19
|
import { buildSiteIndex } from "./site-index.mjs";
|
|
19
20
|
import { openNotesDatabase, prepareSqlTables, findSqlBlocks } from "./sql-tables.mjs";
|
|
@@ -133,7 +134,11 @@ export async function prepareSitePreview({ config = loadPackConfig() } = {}) {
|
|
|
133
134
|
...noteAddressContext(config),
|
|
134
135
|
package: config.contentPackage,
|
|
135
136
|
});
|
|
136
|
-
applyComputedBeingAge(
|
|
137
|
+
applyComputedBeingAge(
|
|
138
|
+
fm,
|
|
139
|
+
presentAmongRecords(snapshot.records),
|
|
140
|
+
reckoningContext({ notes: snapshot.records }),
|
|
141
|
+
);
|
|
137
142
|
} catch (error) {
|
|
138
143
|
return {
|
|
139
144
|
ok: false,
|
|
@@ -9,3 +9,6 @@ export const SOCIAL_TIES = Object.freeze([
|
|
|
9
9
|
{ term: "rival", meaning: "Opposes the subject without implacable hostility." },
|
|
10
10
|
{ term: "nemesis", meaning: "Opposes the subject personally and implacably." },
|
|
11
11
|
]);
|
|
12
|
+
|
|
13
|
+
/** The note types a being can name as a social tie. */
|
|
14
|
+
export const SOCIAL_TIE_TARGET_TYPES = Object.freeze(["being", "affiliation"]);
|
package/engine/social-ties.mjs
CHANGED
|
@@ -8,14 +8,13 @@
|
|
|
8
8
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { parseAddress, renderAddress } from "./address.mjs";
|
|
11
|
+
import { acceptsType, parseAddress, renderAddress } from "./address.mjs";
|
|
12
12
|
import { positionOfFrontmatterPath } from "./diagnostics.mjs";
|
|
13
|
-
import { SOCIAL_TIES } from "./social-tie-terms.mjs";
|
|
13
|
+
import { SOCIAL_TIES, SOCIAL_TIE_TARGET_TYPES } from "./social-tie-terms.mjs";
|
|
14
14
|
|
|
15
|
-
export { SOCIAL_TIES };
|
|
15
|
+
export { SOCIAL_TIES, SOCIAL_TIE_TARGET_TYPES };
|
|
16
16
|
|
|
17
17
|
const TERMS = new Set(SOCIAL_TIES.map(({ term }) => term));
|
|
18
|
-
const ACCEPTED = new Set(["being", "affiliation"]);
|
|
19
18
|
|
|
20
19
|
/** Validate a being's map of defining relationships. */
|
|
21
20
|
export function checkSocialTies(note, { index } = {}) {
|
|
@@ -38,6 +37,7 @@ export function checkSocialTies(note, { index } = {}) {
|
|
|
38
37
|
},
|
|
39
38
|
];
|
|
40
39
|
const findings = [];
|
|
40
|
+
const seen = new Map();
|
|
41
41
|
for (const [key, term] of Object.entries(ties)) {
|
|
42
42
|
const tuple = parseAddress(
|
|
43
43
|
key,
|
|
@@ -54,25 +54,36 @@ export function checkSocialTies(note, { index } = {}) {
|
|
|
54
54
|
...at(key),
|
|
55
55
|
message: `data.socialTies key ${JSON.stringify(key)} is not a complete Address (${tuple.reason}); write being or affiliation as its type`,
|
|
56
56
|
});
|
|
57
|
-
} else if (!
|
|
57
|
+
} else if (!acceptsType(tuple, SOCIAL_TIE_TARGET_TYPES)) {
|
|
58
58
|
findings.push({
|
|
59
59
|
...at(key),
|
|
60
60
|
message: `data.socialTies accepts being or affiliation, not ${tuple.type}`,
|
|
61
61
|
});
|
|
62
|
-
} else
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
} else {
|
|
63
|
+
const target = renderAddress(tuple);
|
|
64
|
+
if (seen.has(target)) {
|
|
65
|
+
findings.push({
|
|
66
|
+
...at(key),
|
|
67
|
+
message: `data.socialTies names the same target ${target} as ${JSON.stringify(seen.get(target))}; keep one tie per target`,
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
seen.set(target, key);
|
|
71
|
+
}
|
|
72
|
+
if (
|
|
73
|
+
tuple.package === (index?.contentPackage ?? note.fm?.package) &&
|
|
74
|
+
tuple.type === "being" &&
|
|
75
|
+
tuple.shortcode === note.fm?.shortcode
|
|
76
|
+
) {
|
|
77
|
+
findings.push({
|
|
78
|
+
...at(key),
|
|
79
|
+
message: `data.socialTies cannot address this being itself`,
|
|
80
|
+
});
|
|
81
|
+
} else if (index?.addressHit && !index.addressHit(target)) {
|
|
82
|
+
findings.push({
|
|
83
|
+
...at(key),
|
|
84
|
+
message: `data.socialTies target ${target} does not resolve`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
76
87
|
}
|
|
77
88
|
if (!TERMS.has(term))
|
|
78
89
|
findings.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.15.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",
|
|
@@ -134,6 +134,8 @@
|
|
|
134
134
|
"dependencies": {
|
|
135
135
|
"@duckdb/node-api": "^1.5.5-r.4",
|
|
136
136
|
"@foundryvtt/foundryvtt-cli": "^3.0.4",
|
|
137
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
138
|
+
"@viz-js/viz": "^3.30.0",
|
|
137
139
|
"acorn": "^8.18.0",
|
|
138
140
|
"archiver": "^8.0.0",
|
|
139
141
|
"classic-level": "^3.0.0",
|
|
@@ -21,7 +21,7 @@ export function parseAgeMagnitude(raw: unknown): {
|
|
|
21
21
|
* @returns {number|null} The age, or `null` where `born` is `unknown` or
|
|
22
22
|
* absent, where no present is declared, or where either date fails to parse.
|
|
23
23
|
*/
|
|
24
|
-
export function computeAge(bornRaw: unknown, presentRaw: unknown): number | null;
|
|
24
|
+
export function computeAge(bornRaw: unknown, presentRaw: unknown, dateContext?: {}): number | null;
|
|
25
25
|
/**
|
|
26
26
|
* Fill in a being's computed `age`, and the numeric companion an estimate
|
|
27
27
|
* carries beside it — mutating the frontmatter object handed in, never a file
|
|
@@ -39,7 +39,7 @@ export function computeAge(bornRaw: unknown, presentRaw: unknown): number | null
|
|
|
39
39
|
* `undefined`/`null` where it states none.
|
|
40
40
|
* @returns {void}
|
|
41
41
|
*/
|
|
42
|
-
export function applyComputedBeingAge(fm: object, presentRaw: unknown): void;
|
|
42
|
+
export function applyComputedBeingAge(fm: object, presentRaw: unknown, dateContext?: {}): void;
|
|
43
43
|
/**
|
|
44
44
|
* A being's `data.present`, read from every `place` note a batch of records or
|
|
45
45
|
* frontmatter objects carries.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emit calendar definitions and import envelopes from the package's index.
|
|
3
|
+
*
|
|
4
|
+
* @param {object} opts
|
|
5
|
+
* @param {object} opts.config - Resolved content configuration.
|
|
6
|
+
* @param {string} opts.calendariaVersion - Version whose import format is targeted.
|
|
7
|
+
* @returns {{directory: string, calendars: number, files: number}}
|
|
8
|
+
*/
|
|
9
|
+
export function emitCalendarArtifacts({ config, calendariaVersion }?: {
|
|
10
|
+
config: object;
|
|
11
|
+
calendariaVersion: string;
|
|
12
|
+
}): {
|
|
13
|
+
directory: string;
|
|
14
|
+
calendars: number;
|
|
15
|
+
files: number;
|
|
16
|
+
};
|
|
@@ -103,7 +103,7 @@ export function quarterDays(daysPerYear: number): number[];
|
|
|
103
103
|
* its own package.
|
|
104
104
|
* @returns {object} The definition.
|
|
105
105
|
*/
|
|
106
|
-
export function compileCalendar({ note, invariants, contentPackage }: {
|
|
106
|
+
export function compileCalendar({ note, invariants, contentPackage, dateContext }: {
|
|
107
107
|
note: object;
|
|
108
108
|
invariants: object;
|
|
109
109
|
contentPackage?: string | undefined;
|
|
@@ -35,6 +35,60 @@ export function canonicalYear(year: number, epoch?: number): number;
|
|
|
35
35
|
* @returns {number} The sort key.
|
|
36
36
|
*/
|
|
37
37
|
export function dateSortKey(year: number, month: number | null, day: number | null): number;
|
|
38
|
+
/**
|
|
39
|
+
* Days from an arbitrary canonical origin to a canonical year and day.
|
|
40
|
+
*
|
|
41
|
+
* Canonical years form a continuous integer line. Day one opens each year;
|
|
42
|
+
* calendar month divisions play no part in this count.
|
|
43
|
+
*
|
|
44
|
+
* @param {number} year - Canonical year.
|
|
45
|
+
* @param {number} day - Day of that year, starting at one.
|
|
46
|
+
* @param {number} originYear - Canonical year whose first day is offset zero.
|
|
47
|
+
* @param {number} daysPerYear - The world's authored year length.
|
|
48
|
+
* @returns {number} Signed whole-day offset.
|
|
49
|
+
*/
|
|
50
|
+
export function canonicalDayOffset(year: number, day: number, originYear: number, daysPerYear: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* The canonical year and day at a signed offset from an arbitrary origin.
|
|
53
|
+
* Flooring the division keeps the day within the year before the origin.
|
|
54
|
+
*
|
|
55
|
+
* @param {number} offset - Whole days from the origin.
|
|
56
|
+
* @param {number} originYear - Canonical year whose first day is offset zero.
|
|
57
|
+
* @param {number} daysPerYear - The world's authored year length.
|
|
58
|
+
* @returns {{year: number, day: number}} Canonical year and day.
|
|
59
|
+
*/
|
|
60
|
+
export function canonicalDateFromOffset(offset: number, originYear: number, daysPerYear: number): {
|
|
61
|
+
year: number;
|
|
62
|
+
day: number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Print a calendar-neutral date as `<year>.<day>[:HHMMSS]`.
|
|
66
|
+
*
|
|
67
|
+
* @param {{year: number, day: number, seconds?: number}} date - Canonical date.
|
|
68
|
+
* @param {number} daysPerYear - The world's authored year length.
|
|
69
|
+
* @returns {string} The canonical spelling.
|
|
70
|
+
*/
|
|
71
|
+
export function formatCanonicalDate(date: {
|
|
72
|
+
year: number;
|
|
73
|
+
day: number;
|
|
74
|
+
seconds?: number;
|
|
75
|
+
}, daysPerYear: number): string;
|
|
76
|
+
/**
|
|
77
|
+
* Read the calendar-neutral `<year>.<day>[:HHMMSS]` spelling.
|
|
78
|
+
*
|
|
79
|
+
* This is distinct from an authored month date such as `720/6`; no calendar
|
|
80
|
+
* month list is consulted to read a canonical day of year.
|
|
81
|
+
*
|
|
82
|
+
* @param {unknown} value - Canonical date text.
|
|
83
|
+
* @param {number} daysPerYear - The world's authored year length.
|
|
84
|
+
* @returns {{year: number, day: number, seconds?: number}|null} The date, or
|
|
85
|
+
* `null` when the spelling or a component is invalid.
|
|
86
|
+
*/
|
|
87
|
+
export function parseCanonicalDate(value: unknown, daysPerYear: number): {
|
|
88
|
+
year: number;
|
|
89
|
+
day: number;
|
|
90
|
+
seconds?: number;
|
|
91
|
+
} | null;
|
|
38
92
|
/**
|
|
39
93
|
* One month of a calendar, as the note declares it.
|
|
40
94
|
*
|
|
@@ -101,6 +155,17 @@ export function monthStarts(months: readonly CalendarMonth[]): number[];
|
|
|
101
155
|
* @returns {number} The day of the year.
|
|
102
156
|
*/
|
|
103
157
|
export function dayOfYear(months: readonly CalendarMonth[], month: number, day: number): number;
|
|
158
|
+
/**
|
|
159
|
+
* Recover a calendar's month and day from an ordinal day of its year.
|
|
160
|
+
*
|
|
161
|
+
* @param {readonly CalendarMonth[]} months - The ordered month list.
|
|
162
|
+
* @param {number} ordinal - Day of year, starting at one.
|
|
163
|
+
* @returns {{month: number, day: number}|null} The named day, or `null` outside the year.
|
|
164
|
+
*/
|
|
165
|
+
export function monthDayOfYear(months: readonly CalendarMonth[], ordinal: number): {
|
|
166
|
+
month: number;
|
|
167
|
+
day: number;
|
|
168
|
+
} | null;
|
|
104
169
|
/**
|
|
105
170
|
* How far into its cycle a moon is on a given day.
|
|
106
171
|
*
|
|
@@ -32,12 +32,13 @@ export function parseImageDirective(raw?: string): {
|
|
|
32
32
|
/**
|
|
33
33
|
* The classes a figure carries, from a parsed directive.
|
|
34
34
|
*
|
|
35
|
-
* @param {{classes?: string[], float?: string}} [directive] - As parsed.
|
|
35
|
+
* @param {{classes?: string[], size?: string, float?: string}} [directive] - As parsed.
|
|
36
36
|
* @returns {string} A space-separated class list, always naming
|
|
37
37
|
* {@link IMAGE_FIGURE_CLASS} first.
|
|
38
38
|
*/
|
|
39
|
-
export function figureClasses({ classes, float }?: {
|
|
39
|
+
export function figureClasses({ classes, size, float }?: {
|
|
40
40
|
classes?: string[];
|
|
41
|
+
size?: string;
|
|
41
42
|
float?: string;
|
|
42
43
|
}): string;
|
|
43
44
|
/**
|
|
@@ -58,13 +59,15 @@ export function escapeHtml(text: string): string;
|
|
|
58
59
|
* @param {string} image.src - The address, resolved for the surface.
|
|
59
60
|
* @param {string} [image.alt] - The alt text, which is also the caption.
|
|
60
61
|
* @param {string[]} [image.classes] - Width classes, from the directive.
|
|
62
|
+
* @param {string} [image.size] - Named display size, from the directive.
|
|
61
63
|
* @param {string} [image.float] - The float position, from the directive.
|
|
62
64
|
* @returns {string} The figure, as one HTML block.
|
|
63
65
|
*/
|
|
64
|
-
export function imageFigureHtml({ src, alt, classes, float }: {
|
|
66
|
+
export function imageFigureHtml({ src, alt, classes, size, float }: {
|
|
65
67
|
src: string;
|
|
66
68
|
alt?: string | undefined;
|
|
67
69
|
classes?: string[] | undefined;
|
|
70
|
+
size?: string | undefined;
|
|
68
71
|
float?: string | undefined;
|
|
69
72
|
}): string;
|
|
70
73
|
/**
|
|
@@ -249,7 +252,7 @@ export const IMAGE_CLASSES: Readonly<Record<string, {
|
|
|
249
252
|
scope: string;
|
|
250
253
|
describe: string;
|
|
251
254
|
}>>;
|
|
252
|
-
/** The named sizes an image directive accepts
|
|
255
|
+
/** The named sizes an image directive accepts. */
|
|
253
256
|
export const IMAGE_SIZES: readonly string[];
|
|
254
257
|
/**
|
|
255
258
|
* The `float:` positions an image may take, and where each puts it.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile a Foundry Scene export into a pack document.
|
|
3
|
+
*
|
|
4
|
+
* Only the note-derived Scene ID, compendium metadata, and pins marked
|
|
5
|
+
* `#anchor` change. Every other authored Scene field passes through.
|
|
6
|
+
*
|
|
7
|
+
* @param {object} fm - The map note's frontmatter.
|
|
8
|
+
* @param {string} markdown - Its converted Markdown body.
|
|
9
|
+
* @param {object} [opts] - Pack metadata, derived JournalEntry ID, and asset resolver.
|
|
10
|
+
* @returns {object} The keyed Scene document.
|
|
11
|
+
*/
|
|
12
|
+
export function buildExportedScene(fm: object, markdown: string, { journalEntryId, stats, resolveAddress }?: object): object;
|
package/types/engine/index.d.mts
CHANGED
|
@@ -31,7 +31,9 @@ export * as siteMaps from "./site-maps.mjs";
|
|
|
31
31
|
export * as systems from "./systems.mjs";
|
|
32
32
|
export * as calendars from "./calendars.mjs";
|
|
33
33
|
export * as noteDates from "./note-dates.mjs";
|
|
34
|
+
export * as reckoningMarkers from "./reckoning-markers.mjs";
|
|
34
35
|
export * as calendarNotes from "./calendar-notes.mjs";
|
|
36
|
+
export * as calendarArtifacts from "./calendar-artifacts.mjs";
|
|
35
37
|
export * as beingAge from "./being-age.mjs";
|
|
36
38
|
export * as contentSlug from "./content-slug.mjs";
|
|
37
39
|
export * as contentAddress from "./content-address.mjs";
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
};
|
|
@@ -30,19 +30,13 @@ export function relatedPlaces(places: Map<string, import("./map-places.mjs").Map
|
|
|
30
30
|
* @param {number} [opts.ranksep] - The tree's `ranksep`, inches.
|
|
31
31
|
* @param {number} [opts.scale=1] - Multiplies every node's size and font.
|
|
32
32
|
* @param {boolean} [opts.polities=true] - Whether the tree draws polities.
|
|
33
|
-
* @param {(engine: string) => string|undefined} [opts.locate] - How a GraphViz
|
|
34
|
-
* engine's binary is found; the real lookup by default.
|
|
35
|
-
* @param {boolean} [opts.requireGraphviz=true] - Whether a missing engine is
|
|
36
|
-
* an error. False, the `.dot` files are written, the renderings skipped,
|
|
37
|
-
* and one warning returned.
|
|
38
33
|
* @returns {{written: string[], findings: Array<{file: string, line?: number,
|
|
39
|
-
* column?: number, severity: "error"|"warning", message: string}
|
|
40
|
-
*
|
|
41
|
-
* rendering was skipped for want of GraphViz.
|
|
34
|
+
* column?: number, severity: "error"|"warning", message: string}>}} What was
|
|
35
|
+
* written and what was found.
|
|
42
36
|
* @throws {Error} When no mode is asked for, a named place is not one, the
|
|
43
|
-
* horizon is not a marker of the scale
|
|
37
|
+
* horizon is not a marker of the scale.
|
|
44
38
|
*/
|
|
45
|
-
export function buildMaps({ world, outDir, tree, root, from, chart, horizon, travel, engine, rankdir, nodesep, ranksep, scale, polities,
|
|
39
|
+
export function buildMaps({ world, outDir, tree, root, from, chart, horizon, travel, engine, rankdir, nodesep, ranksep, scale, polities, }: {
|
|
46
40
|
world: import("./map-places.mjs").MapWorld;
|
|
47
41
|
outDir: string;
|
|
48
42
|
tree?: boolean | undefined;
|
|
@@ -57,8 +51,6 @@ export function buildMaps({ world, outDir, tree, root, from, chart, horizon, tra
|
|
|
57
51
|
ranksep?: number | undefined;
|
|
58
52
|
scale?: number | undefined;
|
|
59
53
|
polities?: boolean | undefined;
|
|
60
|
-
locate?: ((engine: string) => string | undefined) | undefined;
|
|
61
|
-
requireGraphviz?: boolean | undefined;
|
|
62
54
|
}): {
|
|
63
55
|
written: string[];
|
|
64
56
|
findings: Array<{
|
|
@@ -68,7 +60,6 @@ export function buildMaps({ world, outDir, tree, root, from, chart, horizon, tra
|
|
|
68
60
|
severity: "error" | "warning";
|
|
69
61
|
message: string;
|
|
70
62
|
}>;
|
|
71
|
-
skipped: boolean;
|
|
72
63
|
};
|
|
73
64
|
/**
|
|
74
65
|
* The directory the maps land in, below a package's root.
|
|
@@ -1,68 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Render a DOT source file to SVG, plain positions, or a PNG background.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* business.
|
|
4
|
+
* A PNG uses the same Graphviz SVG layout as the vector map. SVG dimensions
|
|
5
|
+
* are in points; resvg starts at 96 pixels per inch, so the zoom converts
|
|
6
|
+
* the requested DPI to the same physical size as Graphviz's PNG output.
|
|
8
7
|
*
|
|
9
|
-
* @param {string}
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {Record<string, string|undefined>} [opts.env] - The environment to
|
|
12
|
-
* read `PATH` from, defaulting to the process's.
|
|
13
|
-
* @param {readonly string[]} [opts.fallbacks] - The directories tried after
|
|
14
|
-
* `PATH`, defaulting to the package managers' ones.
|
|
15
|
-
* @returns {string|undefined} The binary, or `undefined` when none is found.
|
|
16
|
-
* @throws {Error} When `engine` is not a GraphViz engine this command uses.
|
|
17
|
-
*/
|
|
18
|
-
export function findGraphviz(engine: string, { env, fallbacks }?: {
|
|
19
|
-
env?: Record<string, string | undefined> | undefined;
|
|
20
|
-
fallbacks?: readonly string[] | undefined;
|
|
21
|
-
}): string | undefined;
|
|
22
|
-
/**
|
|
23
|
-
* What to say when an engine is not installed: the name, and what installs
|
|
24
|
-
* it.
|
|
25
|
-
*
|
|
26
|
-
* @param {string} engine - The engine that was wanted.
|
|
27
|
-
* @returns {string} The message.
|
|
28
|
-
*/
|
|
29
|
-
export function graphvizMissingMessage(engine: string): string;
|
|
30
|
-
/**
|
|
31
|
-
* Render a `.dot` file with a GraphViz engine.
|
|
32
|
-
*
|
|
33
|
-
* The engine is run over the file rather than fed the text, so the file the
|
|
34
|
-
* command keeps is exactly what was drawn. Warnings GraphViz prints — an
|
|
35
|
-
* unknown font, an overlapping label — are returned rather than swallowed,
|
|
36
|
-
* and a non-zero exit is an error naming the file.
|
|
37
|
-
*
|
|
38
|
-
* @param {string} dotPath - The `.dot` file.
|
|
39
|
-
* @param {string} outPath - Where to write the rendering.
|
|
8
|
+
* @param {string} dotPath - The saved DOT source.
|
|
9
|
+
* @param {string} outPath - The output file.
|
|
40
10
|
* @param {object} opts
|
|
41
|
-
* @param {
|
|
42
|
-
* @param {
|
|
43
|
-
* @param {
|
|
44
|
-
* @
|
|
45
|
-
* @
|
|
11
|
+
* @param {"dot"|"twopi"|"neato"} opts.engine - Layout engine.
|
|
12
|
+
* @param {"svg"|"plain"|"png"} [opts.format="svg"] - Output format.
|
|
13
|
+
* @param {2} [opts.nop] - Preserve positioned nodes as `neato -n2` does.
|
|
14
|
+
* @param {number} [opts.dpi=96] - PNG resolution.
|
|
15
|
+
* @returns {{warnings: string}} Renderer warnings.
|
|
46
16
|
*/
|
|
47
|
-
export function renderDot(dotPath: string, outPath: string, {
|
|
48
|
-
|
|
49
|
-
format?:
|
|
50
|
-
|
|
17
|
+
export function renderDot(dotPath: string, outPath: string, { engine, format, nop, dpi }: {
|
|
18
|
+
engine: "dot" | "twopi" | "neato";
|
|
19
|
+
format?: "svg" | "plain" | "png" | undefined;
|
|
20
|
+
nop?: 2 | undefined;
|
|
21
|
+
dpi?: number | undefined;
|
|
51
22
|
}): {
|
|
52
23
|
warnings: string;
|
|
53
24
|
};
|
|
54
|
-
/**
|
|
55
|
-
* The layout engines the map command may ask for. `dot` draws a tree by
|
|
56
|
-
* rank, `twopi` the same tree radially, `neato` a graph by its edge lengths —
|
|
57
|
-
* and, with every node pinned, the map from a place.
|
|
58
|
-
*
|
|
59
|
-
* @type {readonly string[]}
|
|
60
|
-
*/
|
|
25
|
+
/** The layout engines accepted by the map command. */
|
|
61
26
|
export const GRAPHVIZ_ENGINES: readonly string[];
|
|
62
|
-
/**
|
|
63
|
-
* What installs GraphViz on the two platforms a contributor is likely to be
|
|
64
|
-
* on, as the clause every "not installed" message ends with.
|
|
65
|
-
*
|
|
66
|
-
* @type {string}
|
|
67
|
-
*/
|
|
68
|
-
export const GRAPHVIZ_INSTALL: string;
|
|
@@ -214,9 +214,13 @@ export type MapWorld = {
|
|
|
214
214
|
*/
|
|
215
215
|
export type Containment = {
|
|
216
216
|
/**
|
|
217
|
-
* - The one
|
|
217
|
+
* - The world when exactly one is present.
|
|
218
218
|
*/
|
|
219
219
|
world: string | undefined;
|
|
220
|
+
/**
|
|
221
|
+
* - Every `subType: world` place, sorted.
|
|
222
|
+
*/
|
|
223
|
+
worlds: string[];
|
|
220
224
|
/**
|
|
221
225
|
* - Regions parented directly on the world,
|
|
222
226
|
* in name order.
|