@heroiclands/package-build 22.4.3 → 22.4.5
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 +28 -18
- package/CONTENT.md +77 -1
- package/README.md +9 -0
- package/bin/content-build.mjs +143 -0
- package/bin/package-build.mjs +18 -4
- package/content-config.mjs +7 -0
- package/docs/api.md +84 -0
- package/docs/commands.md +182 -2
- package/docs/configuration.md +19 -1
- package/docs/content-format.md +105 -6
- package/docs/diagnostics.md +1 -0
- package/docs/project-setup.md +7 -6
- package/engine/changelog-group.mjs +27 -6
- package/engine/changelog-lint.mjs +27 -7
- package/engine/frontmatter-lint.mjs +11 -1
- package/engine/homepage.mjs +9 -1
- package/engine/index.mjs +18 -0
- package/engine/map-build.mjs +240 -0
- package/engine/map-dot.mjs +685 -0
- package/engine/map-graphviz.mjs +138 -0
- package/engine/map-layout.mjs +712 -0
- package/engine/map-places.mjs +561 -0
- package/engine/metadata-index.mjs +7 -0
- package/engine/note-vocabulary.mjs +28 -0
- package/engine/place-relations.mjs +637 -0
- package/engine/related-pages.mjs +161 -0
- package/engine/site-build.mjs +107 -9
- package/engine/site-config.mjs +1 -1
- package/engine/site-index.mjs +5 -1
- package/engine/site-root.mjs +147 -6
- package/engine/web-wikilinks.mjs +13 -2
- package/package.json +3 -2
- package/types/engine/changelog-lint.d.mts +9 -7
- package/types/engine/homepage.d.mts +8 -1
- package/types/engine/index.d.mts +6 -0
- package/types/engine/map-build.d.mts +78 -0
- package/types/engine/map-dot.d.mts +130 -0
- package/types/engine/map-graphviz.d.mts +61 -0
- package/types/engine/map-layout.d.mts +359 -0
- package/types/engine/map-places.d.mts +259 -0
- package/types/engine/note-vocabulary.d.mts +12 -0
- package/types/engine/place-relations.d.mts +95 -0
- package/types/engine/related-pages.d.mts +70 -0
- package/types/engine/site-build.d.mts +36 -3
- package/types/engine/site-config.d.mts +1 -1
- package/types/engine/site-index.d.mts +5 -1
- package/types/engine/site-root.d.mts +59 -7
- package/types/engine/web-wikilinks.d.mts +11 -2
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
|
|
3
|
+
* Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
|
|
4
|
+
*
|
|
5
|
+
* This work is licensed under the GNU General Public License v3.0 (GPLv3).
|
|
6
|
+
* You may copy, modify, and distribute it under the terms of that license.
|
|
7
|
+
*
|
|
8
|
+
* For full terms, see the LICENSE.md file in the project root or visit:
|
|
9
|
+
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* GraphViz, as `content-build map` reaches it.
|
|
16
|
+
*
|
|
17
|
+
* GraphViz is a build-time tool of the map command alone: nothing else in the
|
|
18
|
+
* toolchain draws, so nothing else depends on it, and a package that never
|
|
19
|
+
* runs `map` never needs it installed. The command finds the engine it needs
|
|
20
|
+
* once, names what to install when it is absent, and runs it over a `.dot`
|
|
21
|
+
* file it has already written — the `.dot` is always kept beside the `.svg`,
|
|
22
|
+
* so a drawing can be re-rendered, inspected or diffed without re-reading the
|
|
23
|
+
* content index.
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import fs from "node:fs";
|
|
29
|
+
import path from "node:path";
|
|
30
|
+
import { spawnSync } from "node:child_process";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The layout engines the map command may ask for. `dot` draws a tree by
|
|
34
|
+
* rank, `twopi` the same tree radially, `neato` a graph by its edge lengths —
|
|
35
|
+
* and, with every node pinned, the map from a place.
|
|
36
|
+
*
|
|
37
|
+
* @type {readonly string[]}
|
|
38
|
+
*/
|
|
39
|
+
export const GRAPHVIZ_ENGINES = Object.freeze(["dot", "twopi", "neato"]);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Where a package manager puts GraphViz when `PATH` does not say: Homebrew
|
|
43
|
+
* on Apple silicon, Homebrew on Intel, and the system directories.
|
|
44
|
+
*
|
|
45
|
+
* @type {readonly string[]}
|
|
46
|
+
*/
|
|
47
|
+
const KNOWN_DIRECTORIES = Object.freeze([
|
|
48
|
+
"/opt/homebrew/bin",
|
|
49
|
+
"/usr/local/bin",
|
|
50
|
+
"/usr/bin",
|
|
51
|
+
"/opt/local/bin",
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Find a GraphViz engine's binary.
|
|
56
|
+
*
|
|
57
|
+
* `PATH` first, then the directories a package manager installs into, so a
|
|
58
|
+
* shell whose profile does not export Homebrew's directory still finds it.
|
|
59
|
+
* The result is a path to a file that exists; whether it runs is the render's
|
|
60
|
+
* business.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} engine - One of {@link GRAPHVIZ_ENGINES}.
|
|
63
|
+
* @param {object} [opts]
|
|
64
|
+
* @param {Record<string, string|undefined>} [opts.env] - The environment to
|
|
65
|
+
* read `PATH` from, defaulting to the process's.
|
|
66
|
+
* @param {readonly string[]} [opts.fallbacks] - The directories tried after
|
|
67
|
+
* `PATH`, defaulting to the package managers' ones.
|
|
68
|
+
* @returns {string|undefined} The binary, or `undefined` when none is found.
|
|
69
|
+
* @throws {Error} When `engine` is not a GraphViz engine this command uses.
|
|
70
|
+
*/
|
|
71
|
+
export function findGraphviz(engine, { env = process.env, fallbacks = KNOWN_DIRECTORIES } = {}) {
|
|
72
|
+
if (!GRAPHVIZ_ENGINES.includes(engine)) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`"${engine}" is not a GraphViz engine the map command uses; ` +
|
|
75
|
+
`choose ${GRAPHVIZ_ENGINES.join(", ")}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const onPath = String(env.PATH ?? "")
|
|
79
|
+
.split(path.delimiter)
|
|
80
|
+
.filter(Boolean);
|
|
81
|
+
for (const dir of [...onPath, ...fallbacks]) {
|
|
82
|
+
const candidate = path.join(dir, engine);
|
|
83
|
+
try {
|
|
84
|
+
if (fs.statSync(candidate).isFile()) return candidate;
|
|
85
|
+
} catch {
|
|
86
|
+
// Not here; the next directory may have it.
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* What to say when an engine is not installed: the name, and what installs
|
|
94
|
+
* it on the two platforms a contributor is likely to be on.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} engine - The engine that was wanted.
|
|
97
|
+
* @returns {string} The message.
|
|
98
|
+
*/
|
|
99
|
+
export function graphvizMissingMessage(engine) {
|
|
100
|
+
return (
|
|
101
|
+
`GraphViz's \`${engine}\` is not installed, and \`content-build map\` draws with it; ` +
|
|
102
|
+
`install GraphViz (\`brew install graphviz\` on macOS, ` +
|
|
103
|
+
`\`apt-get install graphviz\` on Debian or Ubuntu) and run the command again`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Render a `.dot` file with a GraphViz engine.
|
|
109
|
+
*
|
|
110
|
+
* The engine is run over the file rather than fed the text, so the file the
|
|
111
|
+
* command keeps is exactly what was drawn. Warnings GraphViz prints — an
|
|
112
|
+
* unknown font, an overlapping label — are returned rather than swallowed,
|
|
113
|
+
* and a non-zero exit is an error naming the file.
|
|
114
|
+
*
|
|
115
|
+
* @param {string} dotPath - The `.dot` file.
|
|
116
|
+
* @param {string} outPath - Where to write the rendering.
|
|
117
|
+
* @param {object} opts
|
|
118
|
+
* @param {string} opts.binary - The engine's binary, from {@link findGraphviz}.
|
|
119
|
+
* @param {string} [opts.format="svg"] - The `-T` format.
|
|
120
|
+
* @param {string[]} [opts.args] - Further arguments, before the file.
|
|
121
|
+
* @returns {{warnings: string}} What the engine printed on stderr.
|
|
122
|
+
* @throws {Error} When the engine exits non-zero or cannot be run.
|
|
123
|
+
*/
|
|
124
|
+
export function renderDot(dotPath, outPath, { binary, format = "svg", args = [] }) {
|
|
125
|
+
const result = spawnSync(binary, [`-T${format}`, ...args, dotPath, "-o", outPath], {
|
|
126
|
+
encoding: "utf8",
|
|
127
|
+
});
|
|
128
|
+
if (result.error) {
|
|
129
|
+
throw new Error(`${binary} could not be run over ${dotPath}: ${result.error.message}`);
|
|
130
|
+
}
|
|
131
|
+
if (result.status !== 0) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`${binary} failed over ${dotPath} (exit ${result.status}): ` +
|
|
134
|
+
`${String(result.stderr ?? "").trim()}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return { warnings: String(result.stderr ?? "").trim() };
|
|
138
|
+
}
|