@heroiclands/package-build 25.6.2 → 25.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 +23 -0
- package/README.md +19 -1
- package/bin/content-commands.mjs +64 -79
- package/bin/package-build.mjs +25 -10
- package/ci/wip-workflows.test.mjs +252 -0
- package/content-config.mjs +118 -8
- package/docs/api.md +237 -47
- package/docs/commands.md +99 -35
- package/docs/configuration.md +93 -44
- package/docs/guides/release-and-deploy.md +26 -14
- package/docs/guides/site.md +53 -0
- package/engine/cdn-publish.mjs +164 -6
- package/engine/content-index.mjs +71 -19
- package/engine/content-spans.mjs +18 -1
- package/engine/content-styles.mjs +85 -0
- package/engine/derived-sections.mjs +4 -3
- package/engine/event-views.mjs +6 -4
- package/engine/helpers.mjs +33 -9
- package/engine/index.mjs +1 -0
- package/engine/note-cache.mjs +1107 -0
- package/engine/note-page.mjs +424 -0
- package/engine/pack-config.mjs +47 -4
- package/engine/pathnames.mjs +22 -7
- package/engine/prepared-only.mjs +32 -0
- package/engine/preview-index.mjs +55 -13
- package/engine/site-build.mjs +34 -448
- package/engine/site-config.mjs +33 -4
- package/engine/site-maps.mjs +16 -24
- package/engine/site-origins.mjs +23 -0
- package/engine/site-page.mjs +648 -0
- package/engine/site-render.mjs +142 -10
- package/engine/site-serve.mjs +1 -1
- package/engine/sql-tables.mjs +12 -3
- package/package.json +6 -1
- package/site-theme/static/css/style.css +14 -0
- package/types/content-config.d.mts +34 -0
- package/types/engine/cdn-publish.d.mts +22 -0
- package/types/engine/content-index.d.mts +36 -2
- package/types/engine/content-styles.d.mts +20 -0
- package/types/engine/derived-sections.d.mts +3 -3
- package/types/engine/event-views.d.mts +4 -3
- package/types/engine/helpers.d.mts +18 -1
- package/types/engine/index.d.mts +1 -0
- package/types/engine/note-cache.d.mts +149 -0
- package/types/engine/note-page.d.mts +92 -0
- package/types/engine/pack-config.d.mts +30 -0
- package/types/engine/prepared-only.d.mts +14 -0
- package/types/engine/preview-index.d.mts +35 -0
- package/types/engine/site-build.d.mts +5 -100
- package/types/engine/site-config.d.mts +3 -2
- package/types/engine/site-maps.d.mts +7 -11
- package/types/engine/site-origins.d.mts +9 -0
- package/types/engine/site-page.d.mts +261 -0
- package/types/engine/site-render.d.mts +20 -1
- package/types/engine/sql-tables.d.mts +8 -4
package/content-config.mjs
CHANGED
|
@@ -228,6 +228,93 @@ export function siteBase(config) {
|
|
|
228
228
|
return config.site.base || `/${config.contentPackage}/`;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Apply validated runtime site URLs to a resolved configuration, without changing it.
|
|
233
|
+
* The caller checks the authored homepage before applying these build options.
|
|
234
|
+
*
|
|
235
|
+
* @param {ContentBuildConfig} config - The resolved authored configuration.
|
|
236
|
+
* @param {object} options - Runtime options.
|
|
237
|
+
* @param {string} [options.root] - Domain from which www and CDN origins derive.
|
|
238
|
+
* Defaults to internal.heroiclands.org; explicit root replaces configured assets.
|
|
239
|
+
* @param {string} [options.baseUrl] - Absolute HTTP(S) site URL ending in `/`;
|
|
240
|
+
* overrides the root-derived site URL.
|
|
241
|
+
* @param {string} [options.assets] - Absolute HTTP(S) asset root; overrides both
|
|
242
|
+
* root-derived and configured assets.
|
|
243
|
+
* @returns {ContentBuildConfig} The effective configuration, frozen. Its homepage
|
|
244
|
+
* and site.assets are the selected inputs for downstream site integrations.
|
|
245
|
+
*/
|
|
246
|
+
export function siteBuildConfig(config, { root, baseUrl, assets } = {}) {
|
|
247
|
+
const domain = root ?? "internal.heroiclands.org";
|
|
248
|
+
if (
|
|
249
|
+
typeof domain !== "string" ||
|
|
250
|
+
domain.length > 253 ||
|
|
251
|
+
!domain.includes(".") ||
|
|
252
|
+
!domain.split(".").every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(label))
|
|
253
|
+
) {
|
|
254
|
+
throw new TypeError("--root must be a domain without a scheme, path, port or credentials");
|
|
255
|
+
}
|
|
256
|
+
const homepage =
|
|
257
|
+
baseUrl === undefined ?
|
|
258
|
+
`https://www.${domain.toLowerCase()}${new URL(config.homepage).pathname}`
|
|
259
|
+
: buildUrl(baseUrl, "--base-url").href;
|
|
260
|
+
const base = normalizeSiteBase(new URL(homepage).pathname);
|
|
261
|
+
const assetRoot =
|
|
262
|
+
assets !== undefined ? normalizeSiteAssets(buildUrl(assets, "--assets").href)
|
|
263
|
+
: root !== undefined ? `https://cdn.${domain.toLowerCase()}`
|
|
264
|
+
: config.site.assets || `https://cdn.${domain.toLowerCase()}`;
|
|
265
|
+
checkSiteSitemaps(config.site.sitemaps, base, config.contentPackage);
|
|
266
|
+
return Object.freeze({
|
|
267
|
+
...config,
|
|
268
|
+
homepage,
|
|
269
|
+
site: Object.freeze({ ...config.site, base, assets: assetRoot }),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* A runtime web root must survive URL joining and mapping to a local directory.
|
|
275
|
+
*
|
|
276
|
+
* @param {string} value - The command-line value.
|
|
277
|
+
* @param {string} option - The option naming it.
|
|
278
|
+
* @returns {URL} The checked URL.
|
|
279
|
+
*/
|
|
280
|
+
function buildUrl(value, option) {
|
|
281
|
+
// URL parsing consumes both literal and escaped dot segments.
|
|
282
|
+
const rawPath = /^https?:\/\/[^/?#]+([^?#]*)/i.exec(value)?.[1] ?? "";
|
|
283
|
+
if (
|
|
284
|
+
rawPath.includes("%") ||
|
|
285
|
+
rawPath.split("/").some((segment) => segment === "." || segment === "..")
|
|
286
|
+
) {
|
|
287
|
+
throw new TypeError(
|
|
288
|
+
`${option} must use a plain path without percent escapes or dot segments`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
let url;
|
|
292
|
+
try {
|
|
293
|
+
url = new URL(value);
|
|
294
|
+
} catch {
|
|
295
|
+
throw new TypeError(`${option} must be an absolute HTTP(S) URL`);
|
|
296
|
+
}
|
|
297
|
+
if (
|
|
298
|
+
!/^https?:\/\/[^/]+/i.test(value) ||
|
|
299
|
+
/[\s\\]/.test(value) ||
|
|
300
|
+
!["http:", "https:"].includes(url.protocol) ||
|
|
301
|
+
url.username ||
|
|
302
|
+
url.password ||
|
|
303
|
+
value.includes("?") ||
|
|
304
|
+
value.includes("#") ||
|
|
305
|
+
url.pathname.includes("//") ||
|
|
306
|
+
url.pathname.includes("%")
|
|
307
|
+
) {
|
|
308
|
+
throw new TypeError(
|
|
309
|
+
`${option} must be an absolute HTTP(S) URL with a plain path and no credentials, query or fragment`,
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
if (option === "--base-url" && !url.pathname.endsWith("/")) {
|
|
313
|
+
throw new TypeError(`${option} must end with /`);
|
|
314
|
+
}
|
|
315
|
+
return url;
|
|
316
|
+
}
|
|
317
|
+
|
|
231
318
|
/**
|
|
232
319
|
* Whether this package publishes the pages its content tree compiles to.
|
|
233
320
|
*
|
|
@@ -625,6 +712,8 @@ export function publishesContentPages(config) {
|
|
|
625
712
|
* `pack:` frontmatter, and one pack of
|
|
626
713
|
* the type is marked `default: true` to
|
|
627
714
|
* receive the notes that name none.
|
|
715
|
+
* @property {Record<string, any> & {inputs?: string}} [site] Site settings;
|
|
716
|
+
* inputs names the optional local input provider.
|
|
628
717
|
* @property {PathsInput} [paths] Layout overrides. See {@link DEFAULT_PATHS}.
|
|
629
718
|
* @property {string[]} [skipDirectories] Directory names the content walk ignores
|
|
630
719
|
* wherever they appear (e.g. Obsidian's
|
|
@@ -680,6 +769,8 @@ export function publishesContentPages(config) {
|
|
|
680
769
|
* which Foundry serves no files for. See
|
|
681
770
|
* {@link module:engine/helpers.resolveImg},
|
|
682
771
|
* the one reader of it.
|
|
772
|
+
* @property {Readonly<Record<string, any> & {inputs: string}>} site Frozen site settings;
|
|
773
|
+
* inputs is the local provider path or an empty string.
|
|
683
774
|
* @property {Readonly<ResolvedPaths>} paths
|
|
684
775
|
* @property {Readonly<StatsSpec>|null} stats `null` for a `documentation`
|
|
685
776
|
* package, which stamps no `_stats`.
|
|
@@ -785,6 +876,7 @@ const SITE_KEYS = [
|
|
|
785
876
|
"tags",
|
|
786
877
|
"sitemaps",
|
|
787
878
|
"mergeIndexes",
|
|
879
|
+
"inputs",
|
|
788
880
|
];
|
|
789
881
|
const SITE_NOTFOUND_KEYS = ["tagline", "sitenoun", "heroimage", "links"];
|
|
790
882
|
const SITE_NOTFOUND_LINK_KEYS = ["title", "url", "text"];
|
|
@@ -1874,6 +1966,23 @@ function packageSiteList(value, field, contentPackage) {
|
|
|
1874
1966
|
);
|
|
1875
1967
|
}
|
|
1876
1968
|
|
|
1969
|
+
/**
|
|
1970
|
+
* @param {readonly string[]} sitemaps - The configured package sitemaps.
|
|
1971
|
+
* @param {string} base - The site path.
|
|
1972
|
+
* @param {string} contentPackage - The package id.
|
|
1973
|
+
* @returns {void}
|
|
1974
|
+
*/
|
|
1975
|
+
function checkSiteSitemaps(sitemaps, base, contentPackage) {
|
|
1976
|
+
if (sitemaps.length && base !== "/") {
|
|
1977
|
+
fail(
|
|
1978
|
+
"site.sitemaps",
|
|
1979
|
+
"names the package sites a sitemap index lists, and a sitemap index and " +
|
|
1980
|
+
"`robots.txt` belong at the root of an origin; this site is served at " +
|
|
1981
|
+
`\`${base || `/${contentPackage}/`}\`, so declare \`site.base: /\` or drop the key`,
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1877
1986
|
/**
|
|
1878
1987
|
* The `site` section — how this repository frames the website it publishes.
|
|
1879
1988
|
*
|
|
@@ -1922,6 +2031,7 @@ function normalizeSite(value, contentPackage) {
|
|
|
1922
2031
|
tags: false,
|
|
1923
2032
|
sitemaps: Object.freeze([]),
|
|
1924
2033
|
mergeIndexes: Object.freeze([]),
|
|
2034
|
+
inputs: "",
|
|
1925
2035
|
});
|
|
1926
2036
|
if (value === undefined) return empty;
|
|
1927
2037
|
if (!isPlainObject(value)) fail("site", "must be a mapping");
|
|
@@ -1939,14 +2049,7 @@ function normalizeSite(value, contentPackage) {
|
|
|
1939
2049
|
const base = normalizeSiteBase(input.base);
|
|
1940
2050
|
const search = optionalBoolean(input.search, "site.search", true);
|
|
1941
2051
|
const sitemaps = packageSiteList(input.sitemaps, "site.sitemaps", contentPackage);
|
|
1942
|
-
|
|
1943
|
-
fail(
|
|
1944
|
-
"site.sitemaps",
|
|
1945
|
-
"names the package sites a sitemap index lists, and a sitemap index and " +
|
|
1946
|
-
"`robots.txt` belong at the root of an origin; this site is served at " +
|
|
1947
|
-
`\`${base || `/${contentPackage}/`}\`, so declare \`site.base: /\` or drop the key`,
|
|
1948
|
-
);
|
|
1949
|
-
}
|
|
2052
|
+
checkSiteSitemaps(sitemaps, base, contentPackage);
|
|
1950
2053
|
const mergeIndexes = packageSiteList(input.mergeIndexes, "site.mergeIndexes", contentPackage);
|
|
1951
2054
|
if (mergeIndexes.length && !search) {
|
|
1952
2055
|
fail(
|
|
@@ -1956,6 +2059,12 @@ function normalizeSite(value, contentPackage) {
|
|
|
1956
2059
|
);
|
|
1957
2060
|
}
|
|
1958
2061
|
|
|
2062
|
+
const inputs =
|
|
2063
|
+
input.inputs === undefined ? "" : requireNonEmptyString(input.inputs, "site.inputs");
|
|
2064
|
+
if (inputs && !inputs.split("/").every((segment) => /^[a-z0-9][a-z0-9._-]*$/i.test(segment))) {
|
|
2065
|
+
fail("site.inputs", "must be a plain relative module path without dot segments");
|
|
2066
|
+
}
|
|
2067
|
+
|
|
1959
2068
|
return Object.freeze({
|
|
1960
2069
|
base,
|
|
1961
2070
|
title: input.title === undefined ? "" : requireNonEmptyString(input.title, "site.title"),
|
|
@@ -1978,6 +2087,7 @@ function normalizeSite(value, contentPackage) {
|
|
|
1978
2087
|
tags: optionalBoolean(input.tags, "site.tags", false),
|
|
1979
2088
|
sitemaps,
|
|
1980
2089
|
mergeIndexes,
|
|
2090
|
+
inputs,
|
|
1981
2091
|
});
|
|
1982
2092
|
}
|
|
1983
2093
|
|
package/docs/api.md
CHANGED
|
@@ -193,16 +193,18 @@ Whether a content tree has anything to compile. The pack build's worst failure i
|
|
|
193
193
|
|
|
194
194
|
The consuming repository's resolved `package-build.config.yaml`: the content package, the Foundry package and its kind, every path, the `_stats` identity, item-type membership and the pack list — read on call rather than hoisted at import, so importing this package never requires a configuration to exist.
|
|
195
195
|
|
|
196
|
-
| Export | Signature | Returns | Use it when
|
|
197
|
-
| ------------------- | ------------------------------------ | ----------------------------- |
|
|
198
|
-
| `CONFIG_BASENAME` | `const CONFIG_BASENAME` | — | naming the stem every consuming repository declares its build under
|
|
199
|
-
| `CONFIG_FILENAMES` | `const CONFIG_FILENAMES` | — | listing the file names a configuration may be written as
|
|
200
|
-
| `findConfigFile` | `findConfigFile(from)` | `string \| undefined` | finding the nearest configuration file at or above a directory
|
|
201
|
-
| `resolveConfigFile` | `resolveConfigFile(...)` | `{path, fromCwd, fromModule}` | asking which configuration file a build launched here would read, without loading it
|
|
202
|
-
| `locateConfigError` | `locateConfigError(err, configPath)` | the decorated error | attaching the position of the key a configuration error names
|
|
203
|
-
| `configFromData` | `configFromData(data, configPath)` | `ContentBuildConfig` | turning a parsed YAML configuration into the frozen one the engine reads
|
|
204
|
-
| `loadPackConfig` | `loadPackConfig()` | `ContentBuildConfig` | reading the consuming repository's resolved, frozen configuration
|
|
205
|
-
| `packConfigPath` | `packConfigPath()` | `string` | naming the file `loadPackConfig` resolved the configuration from, for a diagnostic
|
|
196
|
+
| Export | Signature | Returns | Use it when |
|
|
197
|
+
| ------------------- | ------------------------------------ | ----------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
198
|
+
| `CONFIG_BASENAME` | `const CONFIG_BASENAME` | — | naming the stem every consuming repository declares its build under |
|
|
199
|
+
| `CONFIG_FILENAMES` | `const CONFIG_FILENAMES` | — | listing the file names a configuration may be written as |
|
|
200
|
+
| `findConfigFile` | `findConfigFile(from)` | `string \| undefined` | finding the nearest configuration file at or above a directory |
|
|
201
|
+
| `resolveConfigFile` | `resolveConfigFile(...)` | `{path, fromCwd, fromModule}` | asking which configuration file a build launched here would read, without loading it |
|
|
202
|
+
| `locateConfigError` | `locateConfigError(err, configPath)` | the decorated error | attaching the position of the key a configuration error names |
|
|
203
|
+
| `configFromData` | `configFromData(data, configPath)` | `ContentBuildConfig` | turning a parsed YAML configuration into the frozen one the engine reads |
|
|
204
|
+
| `loadPackConfig` | `loadPackConfig()` | `ContentBuildConfig` | reading the consuming repository's resolved, frozen configuration |
|
|
205
|
+
| `packConfigPath` | `packConfigPath()` | `string` | naming the file `loadPackConfig` resolved the configuration from, for a diagnostic |
|
|
206
|
+
| `readPackConfig` | `readPackConfig(configPath)` | `ContentBuildConfig` | reading the configuration one named file declares, unmemoised |
|
|
207
|
+
| `withPackConfig` | `withPackConfig(config, fn, file?)` | what `fn` returns | running work, asynchronous included, with `config` as the configuration `loadPackConfig` answers |
|
|
206
208
|
|
|
207
209
|
### `engine.packRouter`
|
|
208
210
|
|
|
@@ -621,12 +623,11 @@ The npm-installed Graphviz runtime draws SVG maps. The `.dot` source stays besid
|
|
|
621
623
|
|
|
622
624
|
The map from each place, drawn for the site: `package-build site build` draws the map from every place of this package given a **From here** section — with the site's base, so every name links through it — and sets each drawing inline in that section, where its place names stay links. `site.maps: false` gives no place the section, and nothing is drawn.
|
|
623
625
|
|
|
624
|
-
| Export
|
|
625
|
-
|
|
|
626
|
-
| `SITE_MAP_DIR`
|
|
627
|
-
| `inlineSvg`
|
|
628
|
-
| `drawSiteMaps`
|
|
629
|
-
| `inlineDrawingFigure` | `inlineDrawingFigure(svg, alt)` | `string` | the one HTML block the website sets an inline drawing in, with no blank line to end it early |
|
|
626
|
+
| Export | Signature | Returns | Use it when |
|
|
627
|
+
| -------------- | ----------------------------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
628
|
+
| `SITE_MAP_DIR` | `const SITE_MAP_DIR` | `string` | where the site build draws below a package's root, `build/map/site` |
|
|
629
|
+
| `inlineSvg` | `inlineSvg(svg)` | `string` | rewriting a GraphViz SVG for inlining — no prologue, no comment, no `xlink:`, the root sized by `viewBox` alone |
|
|
630
|
+
| `drawSiteMaps` | `drawSiteMaps({ records, foreignIndex, config, base, only?, outDir? })` | `{maps, findings}` | drawing the map from every place given a **From here** section, keyed by the file name the section names |
|
|
630
631
|
|
|
631
632
|
### `engine.systems`
|
|
632
633
|
|
|
@@ -1277,6 +1278,36 @@ The deployed layout of a package's pictures, and which of them ship. A Foundry p
|
|
|
1277
1278
|
| `stagePackageAssets` | `stagePackageAssets({ assetsBase, contentPackage, stageDir, title, transform, shippingLicenses })` | `{staged, excluded, findings, manifest}` | staging a package's shipped pictures flat and writing `asset-sets/default.json`; nothing is staged when `findings` is non-empty |
|
|
1278
1279
|
| `rowsStagingPictureRoots` | `rowsStagingPictureRoots(rows, { rootDir, assetsBase })` | `{index, from, root}[]` | finding `packageBuild.assets` rows that would copy a picture root around the filter |
|
|
1279
1280
|
|
|
1281
|
+
### CDN publication transports
|
|
1282
|
+
|
|
1283
|
+
Import `@heroiclands/package-build/engine/cdn-publish` directly. `planCdnPublish`
|
|
1284
|
+
collects the same asset records and shipping selection as staging, applies the
|
|
1285
|
+
provided transform, and builds destination-relative keys plus a named set whose
|
|
1286
|
+
sources use its `host` argument. It does not upload anything.
|
|
1287
|
+
|
|
1288
|
+
`publishToCdn(plan, { store, dryRun, log })` accepts a destination-independent
|
|
1289
|
+
store with async `size(key)`, `read(key)`, optional `write(key, body, contentType)`
|
|
1290
|
+
and a safe `describe` string. It validates every planned relative key before
|
|
1291
|
+
reading or writing, skips pictures by size, compares set bytes, and withholds the
|
|
1292
|
+
set after a picture failure. `dryRun` never calls `write`.
|
|
1293
|
+
|
|
1294
|
+
`internalStore({ destination, fetch, transfer })` combines public HTTPS reads at
|
|
1295
|
+
`INTERNAL_CDN_HOST` with rsync writes, defaulting to `INTERNAL_CDN_DESTINATION`
|
|
1296
|
+
(`atlas:/srv/preview/cdn`). An explicit SSH alias may target `alias:cdn` for the
|
|
1297
|
+
forced-rrsync receiver. Writes stage only the supplied bytes in temporary regular
|
|
1298
|
+
files, invoke rsync without deletion, and clean up after success or failure.
|
|
1299
|
+
`fetch` and `transfer(args)` can be supplied for isolated tests; the default
|
|
1300
|
+
transfer executes rsync with batch SSH and strict host-key checking.
|
|
1301
|
+
|
|
1302
|
+
`s3Store(credentials)` retains signed S3/R2 requests. `publicStore(host, fetch)`
|
|
1303
|
+
provides read-only HTTP comparisons. `CANONICAL_CDN_ORIGIN`, exported from
|
|
1304
|
+
`engine/site-config`, names the owned public CDN origin used by pathname
|
|
1305
|
+
projection. Its single definition lives in the leaf `engine/site-origins` module
|
|
1306
|
+
to avoid a cycle through site configuration and content rendering.
|
|
1307
|
+
The CLI owns environment loading and
|
|
1308
|
+
`--dest` selection; site builds never call a publisher. See
|
|
1309
|
+
[CDN publication](commands.md#package-build-cdn-publish) for operator access.
|
|
1310
|
+
|
|
1280
1311
|
### `engine.assetReferences`
|
|
1281
1312
|
|
|
1282
1313
|
Every asset reference in a compiled document states the asset's address: an `<img>` carries `data-asset`, and a path field's address sits in `flags.<system>.assets` on the document holding it, nested to mirror the field's path. A reference to a picture its package does not ship compiles to that package's stand-in and keeps the excluded address.
|
|
@@ -1357,6 +1388,16 @@ configuration and incremental render state stay in the calling thread. Every
|
|
|
1357
1388
|
update is prepared in a separate output tree, then installed between HTTP
|
|
1358
1389
|
requests so readers receive complete files.
|
|
1359
1390
|
|
|
1391
|
+
`buildPackageSite` invokes configured `site.inputs` before content work. The
|
|
1392
|
+
module's default export has the `SiteInputsProvider` contract:
|
|
1393
|
+
`({config}) => {navigation, files}` or a promise of that object. It receives the
|
|
1394
|
+
immutable effective configuration; `navigation` uses `NavigationEntry[]`, and
|
|
1395
|
+
`files` is `Record<string, string>` of relative output paths to UTF-8 text.
|
|
1396
|
+
Provider files are validated against unsafe paths, symlinks and builder-owned
|
|
1397
|
+
output before output replacement, written after the renderer's clearing step,
|
|
1398
|
+
and recorded in `written.files`. Without a provider, cached navigation remains
|
|
1399
|
+
required. See [local site inputs](configuration.md#local-site-inputs).
|
|
1400
|
+
|
|
1360
1401
|
### `engine.contentRender`
|
|
1361
1402
|
|
|
1362
1403
|
`createRenderer(target, options?)` builds the one markdown-it configuration every target renders through. `target` is `"foundry"`, `"web"`, `"preview"` or `"book"`. The renderer holds the configured parser (`md`), the names of the plugins installed (`plugins`), and three functions: `prepare` writes the constructs markdown-it has no syntax for — marked text, captioned items, named blocks, verse and alerts — as HTML between blank lines; `render` prepares and renders to HTML; `renderInline` renders one inline run. The `book` target parses only, and its Typst stage reads the tokens.
|
|
@@ -1407,9 +1448,17 @@ locate it in the complete source. LF and CRLF retain their authored lengths.
|
|
|
1407
1448
|
|
|
1408
1449
|
`previewIndex({ config, records, foreign? })` builds what [`renderPreview`](#enginesitepreview) takes as `index`: the link index, the asset address space, the languages' maps, the icon registry and an `expand` function that resolves a buffer's links, embeds, expressions and figure numbers as the website does. `records` are the content index's records and `foreign` the dependencies' indexes. Build it once per index and reuse it for every render.
|
|
1409
1450
|
|
|
1410
|
-
| Export
|
|
1411
|
-
|
|
|
1412
|
-
| `previewIndex`
|
|
1451
|
+
| Export | Signature | Returns | Use it when |
|
|
1452
|
+
| ------------------- | ------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------- |
|
|
1453
|
+
| `previewIndex` | `previewIndex({ config, records, foreign })` | `{ runs, icons, lookupAsset, expand }` | An editor holds a content index and wants the preview to render with it. |
|
|
1454
|
+
| `recordSiteContext` | `recordSiteContext({ config, records, foreign })` | `{ site, assets, events, runs }` | Resolving a page against content-index records instead of a content tree. |
|
|
1455
|
+
|
|
1456
|
+
`recordSiteContext` places every note that publishes a page at the URL the
|
|
1457
|
+
site gives it: the homepage at the package root, a note `site.sections` names
|
|
1458
|
+
at its section, and every other note at its address. `anchorsOf(record)` may
|
|
1459
|
+
answer a note's anchors as its page emits them, generated sections included;
|
|
1460
|
+
answering nothing keeps the record's own. `pages` maps each page's URL to its
|
|
1461
|
+
record.
|
|
1413
1462
|
|
|
1414
1463
|
### `engine.sitePreview`
|
|
1415
1464
|
|
|
@@ -1589,16 +1638,16 @@ A list item opened with `[ ]` or `[x]`, reported. The format has no checkbox: a
|
|
|
1589
1638
|
|
|
1590
1639
|
One authored pathname, and the four addresses it resolves to. A note names a file once — in `img:`, in `data.portrait:`, in the body of a markdown image — and the first segment says which package owns it when an `assets/` follows. Every surface derives its own address from that one statement: the path inside a Foundry install, the file in the owning repository's tree, the address the website serves, and where the book stages its copy.
|
|
1591
1640
|
|
|
1592
|
-
| Export | Signature | Returns | Use it when
|
|
1593
|
-
| ----------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
1594
|
-
| `ASSETS_SEGMENT` | `const ASSETS_SEGMENT` | — | The directory a package ships its files in.
|
|
1595
|
-
| `PATHNAME_SURFACES` | `const PATHNAME_SURFACES` | — | The surfaces one authored pathname resolves for.
|
|
1596
|
-
| `pathnameProblem` | `function pathnameProblem(raw)` | {string} The problem, as a finding's sentence, or `""`. | What is wrong with an authored pathname, or `""` when nothing is.
|
|
1597
|
-
| `packageAddresses` | `function packageAddresses(config)` | {Map<string, {root: string\|null, id: string\|null, own: boolean}>} The packages, by package name. | Every content package this build can resolve a pathname against.
|
|
1598
|
-
| `resolvePathname` | `function resolvePathname(raw, config)` | {PathnameForms\|null} The four forms, or `null` when the note names no file. | Resolve one authored pathname into the address each surface serves.
|
|
1599
|
-
| `assetPathnameKey` | `function assetPathnameKey(src, config)` | {string\|null} The pathname, or `null` for an address naming no asset record to look up. | The pathname one authored image address keys an asset's role and pixel size under, whichever form it was written in.
|
|
1600
|
-
| `servesFoundry` | `function servesFoundry(config)` | {boolean} Whether the package being built has a Foundry root. | Whether this build installs anything into a Foundry data directory.
|
|
1601
|
-
| `foundryAddressProblem` | `function foundryAddressProblem(raw, config)` | {string} The problem, as a finding's sentence, or `""`. | Why a pathname has no Foundry address, or `""` when it has one.
|
|
1641
|
+
| Export | Signature | Returns | Use it when |
|
|
1642
|
+
| ----------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1643
|
+
| `ASSETS_SEGMENT` | `const ASSETS_SEGMENT` | — | The directory a package ships its files in. |
|
|
1644
|
+
| `PATHNAME_SURFACES` | `const PATHNAME_SURFACES` | — | The surfaces one authored pathname resolves for. |
|
|
1645
|
+
| `pathnameProblem` | `function pathnameProblem(raw)` | {string} The problem, as a finding's sentence, or `""`. | What is wrong with an authored pathname, or `""` when nothing is. |
|
|
1646
|
+
| `packageAddresses` | `function packageAddresses(config)` | {Map<string, {root: string\|null, id: string\|null, own: boolean}>} The packages, by package name. | Every content package this build can resolve a pathname against. |
|
|
1647
|
+
| `resolvePathname` | `function resolvePathname(raw, config)` | {PathnameForms\|null} The four forms, or `null` when the note names no file. | Resolve one authored pathname into the address each surface serves; canonical Heroic Lands CDN assets use effective site.assets in the web form only. |
|
|
1648
|
+
| `assetPathnameKey` | `function assetPathnameKey(src, config)` | {string\|null} The pathname, or `null` for an address naming no asset record to look up. | The pathname one authored image address keys an asset's role and pixel size under, whichever form it was written in. |
|
|
1649
|
+
| `servesFoundry` | `function servesFoundry(config)` | {boolean} Whether the package being built has a Foundry root. | Whether this build installs anything into a Foundry data directory. |
|
|
1650
|
+
| `foundryAddressProblem` | `function foundryAddressProblem(raw, config)` | {string} The problem, as a finding's sentence, or `""`. | Why a pathname has no Foundry address, or `""` when it has one. |
|
|
1602
1651
|
|
|
1603
1652
|
### `engine.contentLinks`
|
|
1604
1653
|
|
|
@@ -1654,7 +1703,8 @@ Shared helpers for the pack compilers in `packages/package-build/`. The HeroicLa
|
|
|
1654
1703
|
| `convertNoteWikilinks` | `convertNoteWikilinks(body, { type, id, pack, docPack, index, name, file, bodyLine, bodyColumn, lineMap })` | `{{markdown: string, unresolved: Array<object>}}` | Converts the wikilinks in one note's markdown, reporting any that have no target in the content tree. |
|
|
1655
1704
|
| `expandNoteTables` | `function expandNoteTables(body,` | `{{markdown: string, lineMap: Array<{line: number, generated: boolean}>}}` The body with every table expanded, and where each emitted line came from — which is what lets a diagnostic about the expanded body name an authored position. | Expand prepared SQL tables in one note's markdown, before wikilinks are resolved — so a generated cell may itself be a wikilink. |
|
|
1656
1705
|
| `folderFilename` | `function folderFilename(name, id)` | — | Builds a compendium-source filename for a folder JSON document: `folder_Name_id.json` with non-alphanumeric runs replaced by underscores. |
|
|
1657
|
-
| `walkMarkdownTree` | `walkMarkdownTree(rootDir, { skipDirectories, sources, renderDescription })`
|
|
1706
|
+
| `walkMarkdownTree` | `walkMarkdownTree(rootDir, { skipDirectories, sources, renderDescription, parse })` | generator yielding `{frontmatter, body, description, raw, bodyLine?, bodyColumn?, file, absPath}` | walking a content tree and reading every markdown file's frontmatter and body; `skipDirectories` is required rather than defaulted, so two callers cannot silently disagree about the corpus's scope |
|
|
1707
|
+
| `walkMarkdownFiles` | `walkMarkdownFiles(rootDir, { skipDirectories })` | generator yielding each `.md` file's absolute path | listing the files `walkMarkdownTree` reads, in its order, without reading them |
|
|
1658
1708
|
|
|
1659
1709
|
`buildContentLinkIndex` accepts `{ config?, records, sqlTables?, foreign? }`.
|
|
1660
1710
|
`records` is the required, supplied content corpus. The optional prepared
|
|
@@ -1665,9 +1715,12 @@ so glossary word links resolve to their dictionary entries.
|
|
|
1665
1715
|
`renderDescription` option defaults to true; false leaves `description` empty
|
|
1666
1716
|
while retaining authored body and positions. `walkMarkdownTree` accepts a
|
|
1667
1717
|
selected `sources` map in walk order and the same rendering option, also true
|
|
1668
|
-
by default
|
|
1669
|
-
|
|
1670
|
-
|
|
1718
|
+
by default, and a `parse` function called as `parseMarkdownFile` is, for a
|
|
1719
|
+
caller answering from earlier parses. Index collection explicitly omits unused
|
|
1720
|
+
rendered descriptions. `indexRecordsFor` accepts that selected map, a `syntax`
|
|
1721
|
+
projection function, a captured `foreignIndex` and a `cache` of earlier
|
|
1722
|
+
parses and per-note records, the one [`./note-page`](#note-page) keeps. These
|
|
1723
|
+
adapters do not retain state globally.
|
|
1671
1724
|
|
|
1672
1725
|
The physical wrappers `lintContentCharset`, `lintContentHtml`,
|
|
1673
1726
|
`lintContentIcons`, `lintContentImages` and `lintContentTaskLists` accept an
|
|
@@ -2152,6 +2205,138 @@ Where HM3 records the template priority — one statement (`data.templatePriorit
|
|
|
2152
2205
|
| `HM3_DEFAULT_ITEM_ART` | `const HM3_DEFAULT_ITEM_ART` | — | reading the full map of default item artwork keyed by **note** type (not document subtype) for HM3 items |
|
|
2153
2206
|
| `hm3DefaultItemArt` | `hm3DefaultItemArt(type)` | `string` — the default image path | getting the default art path for an HM3 item's note type, throwing when the type is unknown |
|
|
2154
2207
|
|
|
2208
|
+
### `engine.sitePage`
|
|
2209
|
+
|
|
2210
|
+
One content page, from its note to its body HTML. The site build renders every
|
|
2211
|
+
page through these functions, and [`./note-page`](#note-page) renders a single
|
|
2212
|
+
note through the same ones. Nothing here reads a file.
|
|
2213
|
+
|
|
2214
|
+
| Export | Signature | Returns | Use it when |
|
|
2215
|
+
| --------------------------- | ---------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
2216
|
+
| `parseNote` | `parseNote(source, file, ctx)` | `{fm, body, bodyLine} \| null` | reading a note's frontmatter and body from its text, addresses decoded |
|
|
2217
|
+
| `contentPage` | `contentPage(note, ctx)` | `{page?, fmLinks, addressFinding?} \| null` | deciding whether a note publishes a page, and building it |
|
|
2218
|
+
| `inlineDrawingFigure` | `inlineDrawingFigure(svg, alt)` | `string` | the one HTML block the website sets an inline drawing in, with no blank line to end it early |
|
|
2219
|
+
| `pageFrontmatter` | `pageFrontmatter(page, options)` | `object` | the frontmatter a page publishes with |
|
|
2220
|
+
| `pageTitle` | `pageTitle(page)` | `string` | the title a page publishes under |
|
|
2221
|
+
| `resolveArtFields` | `resolveArtFields(data, webSrc, artSrc)` | `void` | rewriting a page's artwork addresses into the URLs the website serves |
|
|
2222
|
+
| `isPlainObject` | `isPlainObject(value)` | `boolean` | asking whether a value is a mapping a field may be read from |
|
|
2223
|
+
| `renderSitePage` | `renderSitePage(page, options)` | `{markdown, figures, data, resolved, …Errors}` | expanding one page with the passes the site writer uses |
|
|
2224
|
+
| `resolveSitePass` | `resolveSitePass(name, options)` | `{beforeLinks?: Function}` | resolving `site.pass` to its bundle |
|
|
2225
|
+
| `sitePageDecorator` | `sitePageDecorator(config, index)` | `Function` | adding the site's infobox and being metadata to a page's frontmatter |
|
|
2226
|
+
| `siteBodyRenderer` | `siteBodyRenderer(config)` | `(markdown, {runs, figures}) => string` | rendering an expanded page body to the HTML the site writer receives |
|
|
2227
|
+
| `pageDiagnostics` | `pageDiagnostics(result, rawOf)` | `Array<{file, line?, column?, severity, message}>` | turning a page render's findings into located diagnostics |
|
|
2228
|
+
| `frontmatterLinkDiagnostic` | `frontmatterLinkDiagnostic(finding)` | `{file, severity, message}` | reporting a wikilink authored in frontmatter |
|
|
2229
|
+
| `addressDiagnostic` | `addressDiagnostic(finding)` | `{file, severity, message}` | reporting a note whose page has no address |
|
|
2230
|
+
|
|
2231
|
+
`renderSitePage` takes `drawing`, a function from the file name a generated
|
|
2232
|
+
**From here** section names to that drawing's SVG text, and sets the drawing
|
|
2233
|
+
inline when it answers. The site build answers with the maps it drew.
|
|
2234
|
+
|
|
2235
|
+
## `./note-page`
|
|
2236
|
+
|
|
2237
|
+
One note, rendered to the body HTML its site page carries, for a preview that
|
|
2238
|
+
reads like the published page: links as their labels and unresolved ones
|
|
2239
|
+
marked, `.name` spans in bold, query fences evaluated into tables, inline verse
|
|
2240
|
+
broken onto its lines and the generated sections a page carries.
|
|
2241
|
+
|
|
2242
|
+
```js
|
|
2243
|
+
import { renderNoteFile } from "@heroiclands/package-build/note-page";
|
|
2244
|
+
|
|
2245
|
+
const { html, styles, findings, cache } = await renderNoteFile("assets/content/Lore/Tides.md", {
|
|
2246
|
+
root: "/path/to/repository",
|
|
2247
|
+
});
|
|
2248
|
+
```
|
|
2249
|
+
|
|
2250
|
+
| Export | Signature | Returns | Use it when |
|
|
2251
|
+
| ---------------- | --------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------- |
|
|
2252
|
+
| `renderNoteFile` | `renderNoteFile(path, { root?, cache?, prepareTables? })` | `Promise<{ html, styles, findings, cache }>` | rendering a saved note of a repository as its site page shows |
|
|
2253
|
+
|
|
2254
|
+
`path` is the note, relative to `root` or absolute; `root` is the repository
|
|
2255
|
+
or any directory inside it, the working directory by default. The note is read
|
|
2256
|
+
from disk, so what is rendered is what is saved. `renderNoteFile` loads the
|
|
2257
|
+
repository's `package-build.config.yaml` and its dependencies' fetched indexes,
|
|
2258
|
+
derives the content tree's index records as every build does, answers the
|
|
2259
|
+
note's own queries and generated sections over them as `package-build site
|
|
2260
|
+
build` does, and renders the note through the site build's own page render.
|
|
2261
|
+
The repository's configuration answers every read of the configuration made
|
|
2262
|
+
during the call, wherever the caller stands. Nothing has to be built first: no
|
|
2263
|
+
content index and no site.
|
|
2264
|
+
|
|
2265
|
+
The page resolves against the notes it links as their own pages emit them.
|
|
2266
|
+
The note is rendered once to learn which of the package's pages it looks up,
|
|
2267
|
+
and those notes' query answers and generated sections are prepared beside its
|
|
2268
|
+
own, so a link to a generated section such as `#fromhere` resolves, and a
|
|
2269
|
+
cross-note `{{ref}}` finds the target's figures, numbered as its page numbers
|
|
2270
|
+
them. A place's **From here** drawing is drawn for that place alone, in a
|
|
2271
|
+
scratch directory under the system's temporary directory that is removed once
|
|
2272
|
+
the drawing is read, and set inline as the site sets it.
|
|
2273
|
+
|
|
2274
|
+
**The cache.** The records and the note's answers are kept in
|
|
2275
|
+
`build/cache/note-page/` under the repository root, and reused while every
|
|
2276
|
+
input they were derived from is unchanged. Nothing is reused otherwise: each
|
|
2277
|
+
stored answer is keyed by a hash of its inputs, which are
|
|
2278
|
+
|
|
2279
|
+
- package-build's version and the bytes of its own modules, the Node.js
|
|
2280
|
+
version and the DuckDB version;
|
|
2281
|
+
- the configuration file's bytes and the resolved configuration;
|
|
2282
|
+
- the bytes of every fetched dependency index, and the installed
|
|
2283
|
+
`@heroiclands/fonts` version and manifest;
|
|
2284
|
+
- every note's path and the hash of its text, and the package's asset records.
|
|
2285
|
+
|
|
2286
|
+
The dependencies' indexes and the configuration are read between two
|
|
2287
|
+
readings of those inputs, which are read again after the records are derived
|
|
2288
|
+
and around preparing any query answers the store lacks. When any reading
|
|
2289
|
+
differs, something changed while it was read: nothing is stored, and the whole
|
|
2290
|
+
render is done again from the start, the configuration resolved and the note's
|
|
2291
|
+
place in the tree checked afresh, so a retry answers as a fresh call would and
|
|
2292
|
+
a store always holds what was derived from the bytes its key names. After
|
|
2293
|
+
three such attempts the call throws. The cache holds two stores, each
|
|
2294
|
+
replaced whole by renaming a complete file over it. `notes.v8` keeps each note's parse, keyed by its text, and the
|
|
2295
|
+
records derived from that note alone, keyed also by what the tree gives every
|
|
2296
|
+
note: the setting date and calendars, the addresses the notes declare and the
|
|
2297
|
+
asset records. `tree.v8` keeps the whole tree's records, keyed by every input,
|
|
2298
|
+
and beside them the query answers of each note a render has needed. So a second render of an
|
|
2299
|
+
unchanged tree reads the records and the answers; a changed note re-derives
|
|
2300
|
+
its own records and re-runs the passes that read the whole tree; a changed
|
|
2301
|
+
address, calendar, asset, dependency index, configuration or toolchain
|
|
2302
|
+
re-derives every note. A store that cannot be read, that was written for
|
|
2303
|
+
other inputs, or that holds an entry of the wrong shape, down to each table
|
|
2304
|
+
result, inline answer, page-list result and parse inside it, is derived again
|
|
2305
|
+
and overwritten. Deleting the directory loses
|
|
2306
|
+
only time. `cache: false` derives everything and reads and writes nothing.
|
|
2307
|
+
`prepareTables` prepares the query answers, `prepareTreeSqlTables` from
|
|
2308
|
+
`engine/sql-tables.mjs` by default; a host may wrap it to time or observe the
|
|
2309
|
+
preparation.
|
|
2310
|
+
|
|
2311
|
+
`html` is the body before the site writer minifies it and before it unlinks
|
|
2312
|
+
links to pages its homepage cannot reach. Set it in
|
|
2313
|
+
`<div class="single-content"><div class="single-body">…</div></div>` with
|
|
2314
|
+
`styles`, the CSS the site theme applies to a page body, to show it as the page
|
|
2315
|
+
does. `styles` carries the theme's reset, body typography and ordinary link
|
|
2316
|
+
rules scoped to `.single-content`, so the body reads as the page does whatever
|
|
2317
|
+
the host's own styles, and sets the root font size on `:root`, since the
|
|
2318
|
+
theme measures its lengths in `rem`. Each finding is `{ file, line?, column?, severity, message }` and prints
|
|
2319
|
+
through `formatDiagnostic` as `file:line:column: severity: message`. `cache`
|
|
2320
|
+
says what the cache answered: `tree` is `"hit"` when the tree's records were
|
|
2321
|
+
reused whole, `"miss"` when they were derived, and `"off"` without the cache;
|
|
2322
|
+
`notes` counts the notes whose own records were derived again; `tables` is
|
|
2323
|
+
`"hit"` when the answers of the note and of every note it links were all
|
|
2324
|
+
reused, `"miss"` when any was prepared, and `"off"` without the cache.
|
|
2325
|
+
|
|
2326
|
+
It throws when there is no configuration at or above `root`; when the file is
|
|
2327
|
+
not a note of the content tree (outside `paths.content`, in a skipped
|
|
2328
|
+
directory, or not Markdown); when a dependency's index has not been fetched or
|
|
2329
|
+
cannot be read, naming `package-build deps fetch`; when a note of the tree
|
|
2330
|
+
cannot be indexed, as the content-index build reports it; and when the
|
|
2331
|
+
configuration, fonts or dependency indexes keep changing while they are read,
|
|
2332
|
+
three times over. A finding in the
|
|
2333
|
+
rendered note itself is returned in `findings`, never thrown.
|
|
2334
|
+
|
|
2335
|
+
`prepareTreeSqlTables(contentBase, { only })`, with one note's file or a
|
|
2336
|
+
collection of them, answers those notes' directives and generated sections and
|
|
2337
|
+
no other note's; its queries still read the whole corpus, so each note's
|
|
2338
|
+
results equal its results in a preparation of the whole tree.
|
|
2339
|
+
|
|
2155
2340
|
## `./preview`
|
|
2156
2341
|
|
|
2157
2342
|
Import the buffer-only renderer directly without loading the build pipeline:
|
|
@@ -2193,20 +2378,21 @@ const config = defineConfig({
|
|
|
2193
2378
|
});
|
|
2194
2379
|
```
|
|
2195
2380
|
|
|
2196
|
-
| Export | Signature
|
|
2197
|
-
| -------------------------- |
|
|
2198
|
-
| `defineConfig` | `defineConfig(config)`
|
|
2199
|
-
| `PACKAGE_KINDS` | `const PACKAGE_KINDS`
|
|
2200
|
-
| `DOCUMENTATION_KIND` | `const DOCUMENTATION_KIND`
|
|
2201
|
-
| `AUTHOR_ROLES` | `const AUTHOR_ROLES`
|
|
2202
|
-
| `RELATIONSHIP_KEYS` | `const RELATIONSHIP_KEYS`
|
|
2203
|
-
| `compilesFoundryDocuments` | `compilesFoundryDocuments(config)`
|
|
2204
|
-
| `PACK_DOCUMENT_TYPES` | `const PACK_DOCUMENT_TYPES`
|
|
2205
|
-
| `DEFAULT_PATHS` | `const DEFAULT_PATHS`
|
|
2206
|
-
| `DEFAULT_ADDRESS_SCHEME` | `const DEFAULT_ADDRESS_SCHEME`
|
|
2207
|
-
| `DERIVED_SYSTEM_VERSION` | `const DERIVED_SYSTEM_VERSION`
|
|
2208
|
-
| `publishesContentPages` | `publishesContentPages(config)`
|
|
2209
|
-
| `siteBase` | `siteBase(config)`
|
|
2381
|
+
| Export | Signature | Returns | Use it when |
|
|
2382
|
+
| -------------------------- | ---------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2383
|
+
| `defineConfig` | `defineConfig(config)` | `ContentBuildConfig` — the frozen, defaulted configuration | validating and normalizing a content configuration; every configuration reaches this function whether authored as YAML or as `.mjs` |
|
|
2384
|
+
| `PACKAGE_KINDS` | `const PACKAGE_KINDS` | — | reading the three kinds of Foundry package a content module can be built into — `systems`, `modules`, and `documentation`, the kind that compiles no Foundry document at all (also the Foundry install directory name for the first two) |
|
|
2385
|
+
| `DOCUMENTATION_KIND` | `const DOCUMENTATION_KIND` | — | naming the `packageKind` value that compiles no Foundry documents, spelled once so the validator, the CLI and the compile passes cannot disagree about what it means |
|
|
2386
|
+
| `AUTHOR_ROLES` | `const AUTHOR_ROLES` | `readonly string[]` | reading the closed list an `authors` entry's `role` is drawn from — the configuration check refuses any other value |
|
|
2387
|
+
| `RELATIONSHIP_KEYS` | `const RELATIONSHIP_KEYS` | `readonly string[]` | reading every key a declared relationship may carry — the configuration check refuses anything else, and the manifest writer drops the ones Foundry's own schema does not name |
|
|
2388
|
+
| `compilesFoundryDocuments` | `compilesFoundryDocuments(config)` | `boolean` | checking whether a resolved configuration compiles Foundry documents at all — false only for a `documentation` package |
|
|
2389
|
+
| `PACK_DOCUMENT_TYPES` | `const PACK_DOCUMENT_TYPES` | — | reading the Foundry document types this toolchain is able to compile a compendium pack of |
|
|
2390
|
+
| `DEFAULT_PATHS` | `const DEFAULT_PATHS` | — | reading the conventional directory layout a build reads from and writes to, relative to `rootDir` |
|
|
2391
|
+
| `DEFAULT_ADDRESS_SCHEME` | `const DEFAULT_ADDRESS_SCHEME` | — | reading an unconfigured repository's address-scheme defaults (`prefix`, where the content tree mounts inside the package) |
|
|
2392
|
+
| `DERIVED_SYSTEM_VERSION` | `const DERIVED_SYSTEM_VERSION` | — | the loader-only symbol key `defineConfig` uses internally to receive a resolved system version; not something a configuration author writes |
|
|
2393
|
+
| `publishesContentPages` | `publishesContentPages(config)` | `boolean` | checking whether the authored content tree contains notes beyond its homepage, shared by site, PDF, index, and Foundry address emission |
|
|
2394
|
+
| `siteBase` | `siteBase(config)` | `string` | reading the path a package's site is served at — `site.base` where the configuration states one, `/<contentPackage>/` otherwise |
|
|
2395
|
+
| `siteBuildConfig` | `siteBuildConfig(config, { root, baseUrl, assets })` | `ContentBuildConfig` | selecting internal www by default, explicit root-derived CDN over configured assets, and low-level baseUrl/assets over derived values; exposes effective homepage/site.base/site.assets without changing authored configuration; the caller first validates the authored homepage with `checkHomepage`; the CLI uses it before index/body preflight |
|
|
2210
2396
|
|
|
2211
2397
|
## `./config`
|
|
2212
2398
|
|
|
@@ -2637,6 +2823,10 @@ preparation and kept separate.
|
|
|
2637
2823
|
`prepareTreeSqlTables` retains the complete record membership when opening a
|
|
2638
2824
|
public database, so derived citations can distinguish hidden notes from
|
|
2639
2825
|
unknown addresses. Only public records contribute rendered sources and links.
|
|
2826
|
+
`prepareTreeSqlTables(contentBase, { only })`, with one note's file, answers
|
|
2827
|
+
that note's directives and generated sections and no other note's; its queries
|
|
2828
|
+
still read the whole corpus, so its results equal that note's in a preparation
|
|
2829
|
+
of the whole tree.
|
|
2640
2830
|
|
|
2641
2831
|
| Export | Contract |
|
|
2642
2832
|
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|