@heroiclands/package-build 22.4.5 → 22.4.7
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 +16 -0
- package/CONTENT.md +109 -0
- package/bin/content-build.mjs +36 -8
- package/content-config.mjs +8 -3
- package/docs/api.md +86 -46
- package/docs/commands.md +64 -24
- package/docs/configuration.md +20 -1
- package/docs/content-format.md +71 -0
- package/engine/frontmatter-lint.mjs +2 -0
- package/engine/holdings.mjs +391 -0
- package/engine/index.mjs +9 -0
- package/engine/map-build.mjs +41 -11
- package/engine/map-dot.mjs +84 -24
- package/engine/map-graphviz.mjs +12 -3
- package/engine/map-layout.mjs +283 -101
- package/engine/map-places.mjs +33 -3
- package/engine/market-class.mjs +178 -0
- package/engine/metadata-index.mjs +7 -4
- package/engine/note-vocabulary.mjs +19 -0
- package/engine/site-build.mjs +88 -10
- package/engine/site-maps.mjs +165 -0
- package/package.json +1 -1
- package/types/engine/holdings.d.mts +146 -0
- package/types/engine/index.d.mts +3 -0
- package/types/engine/map-build.d.mts +13 -7
- package/types/engine/map-dot.d.mts +22 -9
- package/types/engine/map-graphviz.d.mts +8 -1
- package/types/engine/map-layout.d.mts +117 -49
- package/types/engine/map-places.d.mts +26 -0
- package/types/engine/market-class.d.mts +62 -0
- package/types/engine/note-vocabulary.d.mts +10 -0
- package/types/engine/site-build.d.mts +37 -6
- package/types/engine/site-maps.d.mts +81 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.4.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
Every place page that states a border or a route, or is named in one, carries the map from that place: `from-<shortcode>.svg` beside the page and `map:` naming it in the front matter, with every place name on it a link to that place's page. GraphViz draws it; when GraphViz is not installed the site build says so once and writes every page without a map, and `site.maps: false` draws none.
|
|
8
|
+
|
|
9
|
+
A place's page carries what lies within it and who holds it, and an affiliation's page carries what it holds, read from the `parents` and `domains` the notes already state — a dependency's places and affiliations included. `content-build lint` warns of unheld land: a settlement, site or structure that no affiliation's `domains` names.
|
|
10
|
+
|
|
11
|
+
A `place` note can state a settlement's market class: `data.market`, a whole number from 1 to 6 beside `population`. `1` is a hamlet, with no market beyond what neighbours trade among themselves; `2` a village and its weekly market; `3` a town with several trades working full time; `4` a market town, its chartered fair and its moneylender; `5` a city, where anything ordinary can be had in quantity; `6` a great city that banks, imports as a matter of course, and is the market from which the other markets buy. The key is optional, and a value off the scale is reported at the line that states it rather than rounded onto a class nobody wrote.
|
|
12
|
+
|
|
13
|
+
## 22.4.6
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
`content-build map --chart <shortcode>` draws the chart from a place: the map from it at a larger horizon, north up, the hops chaining on as long as none turns back, each place on the ring of its summed days and each hop beyond the neighbours drawn fainter. `--horizon <days>` sets how far the rings reach, a year by default, and a place farther than that is left out.
|
|
18
|
+
|
|
3
19
|
## 22.4.5
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/CONTENT.md
CHANGED
|
@@ -1183,6 +1183,25 @@ parent or child, or a pair listed twice by one mode. Each finding lands on the
|
|
|
1183
1183
|
entry that states it. The keys, the sets and the days scale are specified under
|
|
1184
1184
|
`type: place` in `docs/content-format.md`.
|
|
1185
1185
|
|
|
1186
|
+
**A settlement is held by someone.** An affiliation's `domains` names the
|
|
1187
|
+
places it holds, and a `place` of subType `settlement`, `site` or `structure`
|
|
1188
|
+
that no affiliation's `domains` names — in this tree or in a fetched index —
|
|
1189
|
+
is a warning, `unheld land`, at the note's `type:` line, so a gap in tenure
|
|
1190
|
+
shows. A region is held through its polity's `domains` and a feature by
|
|
1191
|
+
nobody, so neither is checked.
|
|
1192
|
+
|
|
1193
|
+
**A settlement's market class is one of six.** `data.market` states what trade
|
|
1194
|
+
a settlement supports — `1` a hamlet, with no market beyond what neighbours
|
|
1195
|
+
trade among themselves; `2` a village and its weekly market; `3` a town with
|
|
1196
|
+
several trades working full time; `4` a market town, its chartered fair and its
|
|
1197
|
+
moneylender; `5` a city, where anything ordinary can be had in quantity; `6` a
|
|
1198
|
+
great city that banks, imports as a matter of course, and is the market from
|
|
1199
|
+
which the other markets buy. The numbers order the steps and do nothing else, so a value off the
|
|
1200
|
+
scale is an error at the value that states it rather than a number rounded onto
|
|
1201
|
+
a class the author did not write. The key is optional and the lint checks no
|
|
1202
|
+
`subType` condition, as it checks none for `population`. The scale is stated
|
|
1203
|
+
under `type: place` in `docs/content-format.md`.
|
|
1204
|
+
|
|
1186
1205
|
Nothing here writes. A check reports and an author fixes.
|
|
1187
1206
|
|
|
1188
1207
|
**`content-build map` draws what those keys state.** `--tree` is the author's
|
|
@@ -2409,6 +2428,96 @@ The theme's `related.html` partial reads both lists and renders them as one
|
|
|
2409
2428
|
`related` is derived, never authored: what links to a page is a fact about
|
|
2410
2429
|
every other page in the tree. A note that writes one has it replaced.
|
|
2411
2430
|
|
|
2431
|
+
### A place page says what lies within it and who holds it; an affiliation page says what it holds
|
|
2432
|
+
|
|
2433
|
+
Two keys the notes already carry answer three questions a reader asks of a
|
|
2434
|
+
page. A place's `data.parents` is geography — what it sits within — and an
|
|
2435
|
+
affiliation's `data.domains` is tenure — what it holds. The build reads both
|
|
2436
|
+
across the tree and every fetched index, inverts them, and writes each page
|
|
2437
|
+
the lists that concern it, shaped like `related`:
|
|
2438
|
+
|
|
2439
|
+
```yaml
|
|
2440
|
+
# on a place
|
|
2441
|
+
contains: # every place whose `parents` names this one
|
|
2442
|
+
- title: Khaset-Mehtet
|
|
2443
|
+
url: /thalorna/place-khasetmehtet/
|
|
2444
|
+
type: place
|
|
2445
|
+
subType: settlement
|
|
2446
|
+
held_by: # every affiliation whose `domains` names this one
|
|
2447
|
+
- title: The Nome of Ankhsetun
|
|
2448
|
+
url: /thalorna/affiliation-nomenkhstn/
|
|
2449
|
+
type: affiliation
|
|
2450
|
+
subType: polity
|
|
2451
|
+
|
|
2452
|
+
# on an affiliation
|
|
2453
|
+
holdings: # every place its `domains` names
|
|
2454
|
+
- title: Ankhsetun
|
|
2455
|
+
url: /thalorna/place-ankhsetunnome/
|
|
2456
|
+
type: place
|
|
2457
|
+
subType: region
|
|
2458
|
+
```
|
|
2459
|
+
|
|
2460
|
+
- **`contains` and `holdings` are sorted by `subType`, then `title`**;
|
|
2461
|
+
`held_by` by `title`. An entry carries `subType` where the note declares
|
|
2462
|
+
one.
|
|
2463
|
+
- **A key is present only when it has an entry.** A place nobody holds and
|
|
2464
|
+
nothing sits within carries neither key; an affiliation whose `domains` is
|
|
2465
|
+
empty carries no `holdings`. The theme's silent-disappear convention, kept
|
|
2466
|
+
at the source.
|
|
2467
|
+
- **`domains` names what an affiliation holds directly, and is never
|
|
2468
|
+
expanded.** A polity whose `domains` names a region holds the region; the
|
|
2469
|
+
settlements within it are reached through the region's `contains`, and are
|
|
2470
|
+
not repeated in the polity's `holdings`. Tenure runs through
|
|
2471
|
+
`affiliation.parents` — a house of its earl, an earl of the crown — and
|
|
2472
|
+
geography through `place.parents`. A subinfeudated manor sits in one region
|
|
2473
|
+
by the second and under a lord of another polity by the first, and both
|
|
2474
|
+
pages say so.
|
|
2475
|
+
- **A dependency's places and affiliations take part.** A fetched index entry
|
|
2476
|
+
carries the `parents` and `domains` its record stated, so a place another
|
|
2477
|
+
package publishes is listed within a local region, and a house another
|
|
2478
|
+
package publishes is named on the local manor it holds. A local note
|
|
2479
|
+
declaring a shortcode shadows a fetched entry declaring the same one.
|
|
2480
|
+
- **`url` composes `<base><slug>/`**, as every `related` entry does.
|
|
2481
|
+
|
|
2482
|
+
All three are derived, never authored: a note that writes one has it
|
|
2483
|
+
replaced. The theme renders each list as a table on the page.
|
|
2484
|
+
|
|
2485
|
+
### A place page carries the map from that place
|
|
2486
|
+
|
|
2487
|
+
A place that states a border or a route, or is named in one, has a map from
|
|
2488
|
+
it — the drawing `content-build map --from` makes, with the place at the
|
|
2489
|
+
centre and each neighbour at its bearing. The site build draws that map for
|
|
2490
|
+
every such place and writes it with the page: the page is a leaf bundle,
|
|
2491
|
+
`place-<shortcode>/index.md`, the drawing sits beside it as
|
|
2492
|
+
`from-<shortcode>.svg`, and the front matter names it:
|
|
2493
|
+
|
|
2494
|
+
```yaml
|
|
2495
|
+
map: from-kthrmr.svg
|
|
2496
|
+
```
|
|
2497
|
+
|
|
2498
|
+
The theme's "From here" panel reads the key, inlines the file as a page
|
|
2499
|
+
resource, and so every place name on the map is a link to that place's page.
|
|
2500
|
+
What the build guarantees:
|
|
2501
|
+
|
|
2502
|
+
- **The address does not move.** A bundled page states the same `url` a flat
|
|
2503
|
+
one does, `/<slug>/`, so `place-kthrmr/index.md` publishes exactly where
|
|
2504
|
+
`place-kthrmr.md` would.
|
|
2505
|
+
- **Every name links through the site base.** The map is drawn with the base
|
|
2506
|
+
the pages are served under, so each `href` composes `<base><slug>/` the way
|
|
2507
|
+
every other href the build renders does.
|
|
2508
|
+
- **It is written for inlining.** No XML prologue, no DOCTYPE, no comment, no
|
|
2509
|
+
reference to anything outside the file; the root carries a `viewBox` and no
|
|
2510
|
+
fixed width or height, so the theme sizes it to the column.
|
|
2511
|
+
- **A place with no relation carries nothing**: no file beside it, no `map`
|
|
2512
|
+
key, and the page stays a flat file. So does every page that is not a place.
|
|
2513
|
+
- **A site never fails for want of a map.** GraphViz draws; when it is not
|
|
2514
|
+
installed the build says so once, as a warning naming what to install, and
|
|
2515
|
+
every page is written as it would be without maps. `site.maps: false` in
|
|
2516
|
+
`package-build.config.yaml` draws nothing and asks nothing of GraphViz.
|
|
2517
|
+
|
|
2518
|
+
`map` is derived, never authored: a note that writes one has it replaced when
|
|
2519
|
+
the build draws a map, and dropped when there is none to draw.
|
|
2520
|
+
|
|
2412
2521
|
### Why the output location is fixed
|
|
2413
2522
|
|
|
2414
2523
|
The content mount is a build artifact and is **deleted on every run**, so that a
|
package/bin/content-build.mjs
CHANGED
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
* npx content-build markdown [paths..] [--fix]
|
|
48
48
|
* npx content-build manifest [root] [--out <dir>]
|
|
49
49
|
* npx content-build site [--out <dir>]
|
|
50
|
-
* npx content-build map [--tree] [--from <shortcode>] [--travel] [--out <dir>]
|
|
50
|
+
* npx content-build map [--tree] [--from <shortcode>] [--chart <shortcode>] [--travel] [--out <dir>]
|
|
51
51
|
* npx content-build reachability <dir> [file] [--index <shortcode>]
|
|
52
52
|
* npx content-build addresses diff --from <zip|dir> [--strict]
|
|
53
53
|
*
|
|
@@ -146,6 +146,7 @@ import {
|
|
|
146
146
|
} from "../engine/address-diff.mjs";
|
|
147
147
|
import { emittedArtFor, itemPackJsonDirs } from "../engine/generate.mjs";
|
|
148
148
|
import { buildMaps, FROM_ALL, MAP_DIR } from "../engine/map-build.mjs";
|
|
149
|
+
import { CHART_HORIZON_DAYS } from "../engine/map-layout.mjs";
|
|
149
150
|
import { GRAPHVIZ_ENGINES } from "../engine/map-graphviz.mjs";
|
|
150
151
|
import { loadMapWorld } from "../engine/map-places.mjs";
|
|
151
152
|
|
|
@@ -1514,7 +1515,8 @@ function pdfCommand() {
|
|
|
1514
1515
|
* wikilink resolution, code-fence protection and the foreign-manifest merge —
|
|
1515
1516
|
* happens here, from configuration. So does the Hugo configuration: the whole
|
|
1516
1517
|
* source tree Hugo reads lands under `build/hugo/`, and the consumer's script
|
|
1517
|
-
* runs Hugo over it.
|
|
1518
|
+
* runs Hugo over it. With `site.maps` on and GraphViz installed, every place
|
|
1519
|
+
* page with a border or a route carries the map from that place.
|
|
1518
1520
|
*
|
|
1519
1521
|
* **The Hugo configuration is generated before anything is written.** Its
|
|
1520
1522
|
* sources — `package.json`'s `homepage`, the cached navigation, the installed
|
|
@@ -1652,10 +1654,17 @@ function siteCommand() {
|
|
|
1652
1654
|
return;
|
|
1653
1655
|
}
|
|
1654
1656
|
|
|
1657
|
+
// What drawing the maps found: warnings, every one. A site
|
|
1658
|
+
// never fails for want of a map, so none of these touches the
|
|
1659
|
+
// exit code — GraphViz absent is one line naming what to
|
|
1660
|
+
// install, and every page is written as it would be without.
|
|
1661
|
+
for (const f of result.mapFindings) emitDiagnostic(f);
|
|
1662
|
+
|
|
1655
1663
|
const s = result.stats;
|
|
1656
1664
|
log.info(
|
|
1657
1665
|
`wrote ${s.homepages ?? 0} homepage(s) + ` +
|
|
1658
|
-
`${s.content ?? 0} content page(s)
|
|
1666
|
+
`${s.content ?? 0} content page(s), ` +
|
|
1667
|
+
`${s.maps ?? 0} with a map, to ` +
|
|
1659
1668
|
`${path.relative(process.cwd(), s.out)}`,
|
|
1660
1669
|
);
|
|
1661
1670
|
const { file } = writeHugoConfig(config, hugo);
|
|
@@ -1673,12 +1682,13 @@ function siteCommand() {
|
|
|
1673
1682
|
*
|
|
1674
1683
|
* Reads the content index — this package's and every declared dependency's —
|
|
1675
1684
|
* so a consumer's map draws its dependencies' places beside its own, and
|
|
1676
|
-
* writes under `build/map/`, always the `.dot` beside the `.svg`.
|
|
1685
|
+
* writes under `build/map/`, always the `.dot` beside the `.svg`. Four
|
|
1677
1686
|
* drawings: the containment tree from `parents` (`--tree`, the author's
|
|
1678
1687
|
* check, whose anomalies are reported as findings), the map from a place
|
|
1679
|
-
* from its `borders` and `routes` (`--from`),
|
|
1680
|
-
*
|
|
1681
|
-
*
|
|
1688
|
+
* from its `borders` and `routes` (`--from`), the chart from a place — the
|
|
1689
|
+
* same drawing at a larger horizon (`--chart`, `--horizon`) — and the whole
|
|
1690
|
+
* route graph (`--travel`). GraphViz draws; when it is absent the command
|
|
1691
|
+
* says what to install and stops.
|
|
1682
1692
|
*
|
|
1683
1693
|
* @returns {object} The yargs command module.
|
|
1684
1694
|
*/
|
|
@@ -1686,7 +1696,8 @@ function siteCommand() {
|
|
|
1686
1696
|
function mapCommand() {
|
|
1687
1697
|
return {
|
|
1688
1698
|
command: "map",
|
|
1689
|
-
describe:
|
|
1699
|
+
describe:
|
|
1700
|
+
"Draw the containment tree, the map or the chart from a place, or the route graph",
|
|
1690
1701
|
builder: (yargs) => {
|
|
1691
1702
|
yargs
|
|
1692
1703
|
.option("tree", {
|
|
@@ -1709,6 +1720,21 @@ function mapCommand() {
|
|
|
1709
1720
|
type: "string",
|
|
1710
1721
|
array: true,
|
|
1711
1722
|
})
|
|
1723
|
+
.option("chart", {
|
|
1724
|
+
describe:
|
|
1725
|
+
"Draw the chart from this place as `chart-<shortcode>.svg` — the map " +
|
|
1726
|
+
"from it at a larger horizon, the hops chaining on; repeatable, " +
|
|
1727
|
+
`or \`${FROM_ALL}\` for every place with a border or a route.`,
|
|
1728
|
+
type: "string",
|
|
1729
|
+
array: true,
|
|
1730
|
+
})
|
|
1731
|
+
.option("horizon", {
|
|
1732
|
+
describe:
|
|
1733
|
+
"The charts' horizon in days, a marker of the scale: rings are " +
|
|
1734
|
+
"drawn to it, and a place farther than it is left out.",
|
|
1735
|
+
type: "number",
|
|
1736
|
+
default: CHART_HORIZON_DAYS,
|
|
1737
|
+
})
|
|
1712
1738
|
.option("travel", {
|
|
1713
1739
|
describe: "Draw the whole route graph as `travel.svg`.",
|
|
1714
1740
|
type: "boolean",
|
|
@@ -1783,6 +1809,8 @@ function mapCommand() {
|
|
|
1783
1809
|
tree: argv.tree,
|
|
1784
1810
|
root: argv.root,
|
|
1785
1811
|
from: argv.from ?? [],
|
|
1812
|
+
chart: argv.chart ?? [],
|
|
1813
|
+
horizon: argv.horizon,
|
|
1786
1814
|
travel: argv.travel,
|
|
1787
1815
|
engine: argv.engine,
|
|
1788
1816
|
rankdir: argv.rankdir,
|
package/content-config.mjs
CHANGED
|
@@ -772,6 +772,7 @@ const SITE_KEYS = [
|
|
|
772
772
|
"notfound",
|
|
773
773
|
"hugo",
|
|
774
774
|
"search",
|
|
775
|
+
"maps",
|
|
775
776
|
];
|
|
776
777
|
const SITE_NOTFOUND_KEYS = ["tagline", "sitenoun", "heroimage", "links"];
|
|
777
778
|
const SITE_NOTFOUND_LINK_KEYS = ["title", "url", "text"];
|
|
@@ -1711,9 +1712,11 @@ const SITE_INDEX_MESSAGE =
|
|
|
1711
1712
|
* shared with the link manifest so the two cannot disagree about where a
|
|
1712
1713
|
* page is.
|
|
1713
1714
|
*
|
|
1714
|
-
*
|
|
1715
|
-
* search index beside the rendered pages.
|
|
1716
|
-
*
|
|
1715
|
+
* Two switches sit here, both on by default. `search` is whether
|
|
1716
|
+
* `package-build site-root` writes a search index beside the rendered pages.
|
|
1717
|
+
* `maps` is whether `content-build site` draws the map from each place that
|
|
1718
|
+
* states a border or a route and writes it into that place's page — a site
|
|
1719
|
+
* carries both unless it says otherwise.
|
|
1717
1720
|
*
|
|
1718
1721
|
* **What the site publishes is the homepage and the content tree, and nothing
|
|
1719
1722
|
* beside them.** A page of documentation is a note — `type: doc`, addressed
|
|
@@ -1739,6 +1742,7 @@ function normalizeSite(value) {
|
|
|
1739
1742
|
notfound: null,
|
|
1740
1743
|
hugo: Object.freeze({}),
|
|
1741
1744
|
search: true,
|
|
1745
|
+
maps: true,
|
|
1742
1746
|
});
|
|
1743
1747
|
if (value === undefined) return empty;
|
|
1744
1748
|
if (!isPlainObject(value)) fail("site", "must be a mapping");
|
|
@@ -1795,6 +1799,7 @@ function normalizeSite(value) {
|
|
|
1795
1799
|
notfound: normalizeSiteNotfound(input.notfound),
|
|
1796
1800
|
hugo: normalizeSiteHugo(input.hugo),
|
|
1797
1801
|
search: optionalBoolean(input.search, "site.search", true),
|
|
1802
|
+
maps: optionalBoolean(input.maps, "site.maps", true),
|
|
1798
1803
|
});
|
|
1799
1804
|
}
|
|
1800
1805
|
|
package/docs/api.md
CHANGED
|
@@ -429,6 +429,30 @@ What a place is next to (`data.borders`) and reachable from (`data.routes`): the
|
|
|
429
429
|
| `checkBorders` | `checkBorders(note, { index })` | `object[]` | linting a place's `borders` — targets, values, once per pair, no parent or child, and reciprocity with the other end |
|
|
430
430
|
| `checkRoutes` | `checkRoutes(note, { index })` | `object[]` | linting a place's `routes` — as `checkBorders`, plus `mode`, `days` and `terrain`, once per pair per mode |
|
|
431
431
|
|
|
432
|
+
### `engine.holdings`
|
|
433
|
+
|
|
434
|
+
What lies within a place, who holds it, and what an affiliation holds — read off `data.parents` and `data.domains` across this package and every fetched index, inverted into the `contains`, `held_by` and `holdings` lists the site build writes — and the tenure check `content-build lint` runs on a place.
|
|
435
|
+
|
|
436
|
+
| Export | Signature | Returns | Use it when |
|
|
437
|
+
| ---------------------- | ------------------------------------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
438
|
+
| `HOLDINGS_KEYS` | `const HOLDINGS_KEYS` | `readonly string[]` | the three derived keys — `contains`, `held_by`, `holdings` — which a note cannot author |
|
|
439
|
+
| `HELD_SUBTYPES` | `const HELD_SUBTYPES` | `readonly string[]` | the place subTypes tenure is checked on — `settlement`, `site`, `structure` |
|
|
440
|
+
| `holdingsNode` | `holdingsNode(fm, { title, url })` | `HoldingsNode\|null` | reading a local note as a node of the derivation, or `null` for one that is neither a place nor an affiliation |
|
|
441
|
+
| `foreignHoldingsNodes` | `foreignHoldingsNodes(foreignIndex)` | `HoldingsNode[]` | reading a fetched index's places and affiliations as nodes |
|
|
442
|
+
| `holdingsPages` | `holdingsPages(nodes)` | `Map<string, Holdings>` | inverting `parents` and `domains` into each page's sorted lists, keyed by URL, for every page with at least one entry |
|
|
443
|
+
| `checkHeld` | `checkHeld(note, { index })` | `object[]` | linting a place's tenure — a settlement, site or structure no affiliation's `domains` names is a warning at its `type:` line |
|
|
444
|
+
|
|
445
|
+
### `engine.marketClass`
|
|
446
|
+
|
|
447
|
+
What trade a settlement supports (`data.market`): the six-step scale, stated once for the lint, the author-facing reference and the specification, and the check that holds a note's value to it.
|
|
448
|
+
|
|
449
|
+
| Export | Signature | Returns | Use it when |
|
|
450
|
+
| ---------------- | ---------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
|
451
|
+
| `MARKET_CLASSES` | `const MARKET_CLASSES` | `readonly object[]` | the scale in order, each step its `value`, the `name` a settlement of it goes by, and its `trade` |
|
|
452
|
+
| `isMarketClass` | `isMarketClass(value)` | `boolean` | asking whether an authored value names a class, a quoted number included |
|
|
453
|
+
| `marketClass` | `marketClass(value)` | `object\|undefined` | the class a value names, for rendering what a number means |
|
|
454
|
+
| `checkMarket` | `checkMarket(note)` | `object[]` | linting a place's `market` — a value off the scale, located at the value that states it |
|
|
455
|
+
|
|
432
456
|
### `engine.mapPlaces`
|
|
433
457
|
|
|
434
458
|
The places a map is drawn from — this package's index records and every fetched dependency's entries, read through one shape — and what their `parents` say: the world, the continents, each place's continent, and everything the containment tree can get wrong, reported as findings located at the entry that states it.
|
|
@@ -437,42 +461,47 @@ The places a map is drawn from — this package's index records and every fetche
|
|
|
437
461
|
| --------------------- | ---------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
438
462
|
| `placesFromRecords` | `placesFromRecords(records, { contentBase, base })` | `MapWorld` | reading this package's places and polities out of its index records, with a page URL each where a site base is given |
|
|
439
463
|
| `loadMapWorld` | `loadMapWorld({ config, contentBase, base, problems })` | `MapWorld` | loading the world a map is drawn from — this package's index and every declared dependency's |
|
|
464
|
+
| `mapWorld` | `mapWorld({ records, foreignIndex, contentBase, base, config })` | `MapWorld` | the same world out of records and indexes a caller already holds, as the site build does |
|
|
440
465
|
| `analyzeContainment` | `analyzeContainment(places, polities)` | `Containment` | finding the world, the continents, each place's continent and the anomalies of `parents` |
|
|
441
466
|
| `subtreeOf` | `subtreeOf(analysis, root)` | `Set<string>` | every place beneath one, by following `parents` downward |
|
|
442
467
|
| `containmentFindings` | `containmentFindings(analysis, places, { contentBase, config })` | `object[]` | the anomalies as `file:line:column: severity: message` findings — no parent, an unresolved parent and a cycle are errors |
|
|
443
468
|
|
|
444
469
|
### `engine.mapLayout`
|
|
445
470
|
|
|
446
|
-
The geometry of the map from a place, as arithmetic over the place records: north up, east right, the angle from the bearing and the radius from the days marker on log-spaced rings,
|
|
447
|
-
|
|
448
|
-
| Export
|
|
449
|
-
|
|
|
450
|
-
| `HORIZON_DAYS`
|
|
451
|
-
| `
|
|
452
|
-
| `
|
|
453
|
-
| `
|
|
454
|
-
| `
|
|
455
|
-
| `
|
|
456
|
-
| `
|
|
457
|
-
| `
|
|
458
|
-
| `
|
|
459
|
-
| `
|
|
460
|
-
| `
|
|
461
|
-
| `
|
|
462
|
-
| `
|
|
463
|
-
| `
|
|
471
|
+
The geometry of the map from a place and of the chart from one, as arithmetic over the place records: north up, east right, the angle from the bearing and the radius from the days marker on log-spaced rings, hops composed into one bearing as long as none turns back. Nothing here touches a file or GraphViz.
|
|
472
|
+
|
|
473
|
+
| Export | Signature | Returns | Use it when |
|
|
474
|
+
| -------------------- | ------------------------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
475
|
+
| `HORIZON_DAYS` | `const HORIZON_DAYS` | `number` | the horizon of the map from a place, 90 days; beyond it a place is a name at the rim |
|
|
476
|
+
| `CHART_HORIZON_DAYS` | `const CHART_HORIZON_DAYS` | `number` | the horizon of the chart from a place when none is asked for, 360 days — the end of the scale |
|
|
477
|
+
| `RING_DAYS` | `const RING_DAYS` | `readonly number[]` | the days markers that are rings on the map from a place — every marker up to its horizon |
|
|
478
|
+
| `bearingAngle` | `bearingAngle(bearing)` | `number\|undefined` | the angle of a bearing in degrees counter-clockwise from east — `N` is 90, `E` 0 |
|
|
479
|
+
| `bearingVector` | `bearingVector(bearing)` | `{x, y}\|undefined` | the unit vector of a bearing |
|
|
480
|
+
| `bearingSteps` | `bearingSteps(a, b)` | `number\|undefined` | how many steps around the compass separate two bearings, the shorter way |
|
|
481
|
+
| `rimRadius` | `rimRadius(horizon?)` | `number` | the radius of the rim, one log step beyond the horizon — the map from a place's by default |
|
|
482
|
+
| `ringRadius` | `ringRadius(days, horizon?)` | `number` | the radius of the ring a days value sits on — the rim for none, or for a value beyond the horizon |
|
|
483
|
+
| `rings` | `rings(horizon?)` | `object[]` | the rings inside out, each marker up to the horizon with its radius |
|
|
484
|
+
| `daysMarker` | `daysMarker(total)` | `number\|undefined` | the smallest marker of the scale that covers a total of days |
|
|
485
|
+
| `edgeLength` | `edgeLength(days)` | `number` | the length a route asks of `neato` in the route graph, inches, on the rings' log scale |
|
|
486
|
+
| `composeChain` | `composeChain(hops)` | `object\|undefined` | a chain of hops composed into one bearing and one total, each hop within an octant of the running direction, else `undefined` |
|
|
487
|
+
| `composeHops` | `composeHops(first, second)` | `object\|undefined` | two hops composed into one bearing and one total where they agree — the same bearing or adjacent — else `undefined` |
|
|
488
|
+
| `relationsOf` | `relationsOf(places, shortcode)` | `object` | every border and route touching one place, read from both ends, plus the targets that resolved to nothing |
|
|
489
|
+
| `layoutFrom` | `layoutFrom(places, centre)` | `object` | laying out the map from a place: every node pinned in points, every edge, the rings and the rim |
|
|
490
|
+
| `layoutChart` | `layoutChart(places, centre, { horizon })` | `object` | laying out the chart from a place: the map from it at a larger horizon, the hops chaining on as long as none turns back |
|
|
491
|
+
| `travelGraph` | `travelGraph(places)` | `object` | the whole route graph — one edge per pair, however many ends and modes state it, each with a length from its days |
|
|
464
492
|
|
|
465
493
|
### `engine.mapDot`
|
|
466
494
|
|
|
467
|
-
The
|
|
495
|
+
The drawings of `content-build map` as DOT text, sharing one style table: shape, colour and size by `subType`, an anomaly overriding colour alone, every label a `name.full`, every tooltip an address, and a `URL` where the place carries one so the SVG's names are links.
|
|
468
496
|
|
|
469
|
-
| Export
|
|
470
|
-
|
|
|
471
|
-
| `STYLE`
|
|
472
|
-
| `dotString`
|
|
473
|
-
| `treeDot`
|
|
474
|
-
| `
|
|
475
|
-
| `
|
|
497
|
+
| Export | Signature | Returns | Use it when |
|
|
498
|
+
| ------------ | -------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
499
|
+
| `STYLE` | `const STYLE` | — | the shape, colour and size of each `subType`, and of a polity |
|
|
500
|
+
| `dotString` | `dotString(value)` | `string` | quoting text for DOT |
|
|
501
|
+
| `treeDot` | `treeDot({ places, polities, analysis, root, … })` | `string` | the containment tree — the whole world clustered by continent, or the subtree beneath `root` |
|
|
502
|
+
| `hopOpacity` | `hopOpacity(hop)` | `number` | how faint a place is drawn by its hop count — full to the second hop, a step down each hop beyond, floored |
|
|
503
|
+
| `fromDot` | `fromDot(layout, places, { scale, title })` | `string` | the map or the chart from a place, every node pinned for `neato -n2`, the rings drawn faintly with their markers |
|
|
504
|
+
| `travelDot` | `travelDot(graph, places, { scale, title })` | `string` | the whole route graph for `neato`, each edge asking for a length from its days |
|
|
476
505
|
|
|
477
506
|
### `engine.mapGraphviz`
|
|
478
507
|
|
|
@@ -481,6 +510,7 @@ GraphViz, as the map command reaches it: a build-time tool of that command alone
|
|
|
481
510
|
| Export | Signature | Returns | Use it when |
|
|
482
511
|
| ------------------------ | ------------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------ |
|
|
483
512
|
| `GRAPHVIZ_ENGINES` | `const GRAPHVIZ_ENGINES` | `readonly string[]` | the engines the map command may ask for — `dot`, `twopi`, `neato` |
|
|
513
|
+
| `GRAPHVIZ_INSTALL` | `const GRAPHVIZ_INSTALL` | `string` | what installs GraphViz, as the clause every "not installed" message ends with |
|
|
484
514
|
| `findGraphviz` | `findGraphviz(engine, { env, fallbacks })` | `string\|undefined` | finding an engine's binary on `PATH` or in the directories a package manager installs into |
|
|
485
515
|
| `graphvizMissingMessage` | `graphvizMissingMessage(engine)` | `string` | saying an engine is not installed, and what installs it |
|
|
486
516
|
| `renderDot` | `renderDot(dotPath, outPath, { binary, format, args })` | `{warnings}` | rendering a `.dot` file, the engine's warnings returned and a non-zero exit thrown |
|
|
@@ -489,12 +519,22 @@ GraphViz, as the map command reaches it: a build-time tool of that command alone
|
|
|
489
519
|
|
|
490
520
|
`content-build map` as a function: the drawings written under an output directory, always the `.dot` beside the `.svg`, the tree's anomalies returned as findings, and a missing GraphViz either an error or — for a build that would rather skip — one warning.
|
|
491
521
|
|
|
492
|
-
| Export | Signature
|
|
493
|
-
| --------------- |
|
|
494
|
-
| `MAP_DIR` | `const MAP_DIR`
|
|
495
|
-
| `FROM_ALL` | `const FROM_ALL`
|
|
496
|
-
| `relatedPlaces` | `relatedPlaces(places)`
|
|
497
|
-
| `buildMaps` | `buildMaps({ world, outDir, tree, root, from, travel, engine, rankdir, nodesep, ranksep, scale, polities, locate, requireGraphviz })` | `{written, findings, skipped}` | drawing any of the
|
|
522
|
+
| Export | Signature | Returns | Use it when |
|
|
523
|
+
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ----------------------------------------------------------------------------- |
|
|
524
|
+
| `MAP_DIR` | `const MAP_DIR` | `string` | where the maps land below a package's root, `build/map` |
|
|
525
|
+
| `FROM_ALL` | `const FROM_ALL` | `string` | the `--from` or `--chart` value that means every place with a relation, `all` |
|
|
526
|
+
| `relatedPlaces` | `relatedPlaces(places)` | `string[]` | every place that states, or is named in, a border or a route |
|
|
527
|
+
| `buildMaps` | `buildMaps({ world, outDir, tree, root, from, chart, horizon, travel, engine, rankdir, nodesep, ranksep, scale, polities, locate, requireGraphviz })` | `{written, findings, skipped}` | drawing any of the four from a loaded world |
|
|
528
|
+
|
|
529
|
+
### `engine.siteMaps`
|
|
530
|
+
|
|
531
|
+
The map from each place, drawn for the site: `content-build site` draws the map from every place of this package that states, or is named in, a border or a route — with the site's base, so every name links through it — and the page writer lays each drawing beside its page as `from-<shortcode>.svg` and names it in the front matter as `map`. GraphViz absent is one warning and no map; `site.maps: false` draws none.
|
|
532
|
+
|
|
533
|
+
| Export | Signature | Returns | Use it when |
|
|
534
|
+
| -------------- | --------------------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
535
|
+
| `SITE_MAP_DIR` | `const SITE_MAP_DIR` | `string` | where the site build draws below a package's root, `build/map/site` |
|
|
536
|
+
| `inlineSvg` | `inlineSvg(svg)` | `string` | rewriting a GraphViz SVG for inlining — no prologue, no comment, no `xlink:`, the root sized by `viewBox` alone |
|
|
537
|
+
| `drawSiteMaps` | `drawSiteMaps({ records, foreignIndex, config, base, locate })` | `{maps, findings}` | drawing the map from every related place of this package, keyed by the URL of the page that carries it |
|
|
498
538
|
|
|
499
539
|
### `engine.systems`
|
|
500
540
|
|
|
@@ -690,20 +730,20 @@ The toolchain's own content index — the files it ships, addressed. Every other
|
|
|
690
730
|
|
|
691
731
|
Publishing a content tree as a website. Compiling a content tree into compendium packs is `content-build package compile`. Publishing the _same tree_ as a website was a script each consumer wrote for itself — 473 code lines in `sohl` and 462 in `sohl-thalorna`, 87 of them identical — and the copies drifted in ways neither repository could see. `sohl-thalorna` reimplemented four things this package already exported, not because it needed different behaviour but because its script predates the extraction. That is the failure a command removes: a consumer cannot accidentally reimplement one.
|
|
692
732
|
|
|
693
|
-
| Export | Signature | Returns | Use it when
|
|
694
|
-
| --------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
695
|
-
| `collectContentPages` | `function collectContentPages(contentBase, ctx)` | {{pages: object[], addressFindings: object[], fmLinkFindings: object[]}} | The content tree's pages, and what could not be addressed.
|
|
696
|
-
| `collectHomepages` | `function collectHomepages(contentBase, ctx)` | {{pages: object[], addressFindings: object[]}} The homepage notes, in walk order, and the ones among them that could not be addressed. | The package's homepage notes — the authored page at `/<contentPackage>/`.
|
|
697
|
-
| `writeHomepages` | `function writeHomepages(outRoot, pages, config)` | {number} How many pages were written. | Writes each homepage as the package root's `_index.md`.
|
|
698
|
-
| `siteGates` | `function siteGates(pages, findings,` | {object} The gate results and, when they pass, the built index. | The integrity gates a site build runs before it writes anything.
|
|
699
|
-
| `emptyGates` | `function emptyGates()` | {object} An all-clear gate result. | The gate result of a build that ran none of them.
|
|
700
|
-
| `gatesFailed` | `function gatesFailed(gates)` | — | Whether any gate produced a finding.
|
|
701
|
-
| `tableUniverse` | `function tableUniverse(pages)` | {Map<string, object[]>} Package → the notes it may tabulate. | The universe a generated table searches, grouped by package.
|
|
702
|
-
| `pageFrontmatter` | `function pageFrontmatter(page,` | {object} The frontmatter to write. | The frontmatter a page publishes with.
|
|
703
|
-
| `pageDestination` | `function pageDestination(page)`
|
|
704
|
-
| `renderPages` | `function renderPages(pages, options)` | {{written: number, byKind: Record<string, number>, tableErrors: object[], wikiErrors: object[]}} | Renders and writes every page.
|
|
705
|
-
| `resolveSitePass` | `function resolveSitePass(name, options)` | {{beforeLinks?: Function}} The bundle. | Resolves `site.pass` to its bundle.
|
|
706
|
-
| `buildSite` | `buildSite({ config, sqlTables })`
|
|
733
|
+
| Export | Signature | Returns | Use it when |
|
|
734
|
+
| --------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
735
|
+
| `collectContentPages` | `function collectContentPages(contentBase, ctx)` | {{pages: object[], addressFindings: object[], fmLinkFindings: object[]}} | The content tree's pages, and what could not be addressed. |
|
|
736
|
+
| `collectHomepages` | `function collectHomepages(contentBase, ctx)` | {{pages: object[], addressFindings: object[]}} The homepage notes, in walk order, and the ones among them that could not be addressed. | The package's homepage notes — the authored page at `/<contentPackage>/`. |
|
|
737
|
+
| `writeHomepages` | `function writeHomepages(outRoot, pages, config)` | {number} How many pages were written. | Writes each homepage as the package root's `_index.md`. |
|
|
738
|
+
| `siteGates` | `function siteGates(pages, findings,` | {object} The gate results and, when they pass, the built index. | The integrity gates a site build runs before it writes anything. |
|
|
739
|
+
| `emptyGates` | `function emptyGates()` | {object} An all-clear gate result. | The gate result of a build that ran none of them. |
|
|
740
|
+
| `gatesFailed` | `function gatesFailed(gates)` | — | Whether any gate produced a finding. |
|
|
741
|
+
| `tableUniverse` | `function tableUniverse(pages)` | {Map<string, object[]>} Package → the notes it may tabulate. | The universe a generated table searches, grouped by package. |
|
|
742
|
+
| `pageFrontmatter` | `function pageFrontmatter(page,` | {object} The frontmatter to write. | The frontmatter a page publishes with. |
|
|
743
|
+
| `pageDestination` | `function pageDestination(page, { bundle })` | — | Where a page is written, relative to the output root: flat, or as a leaf bundle when it carries a file beside itself. |
|
|
744
|
+
| `renderPages` | `function renderPages(pages, options)` | {{written: number, byKind: Record<string, number>, tableErrors: object[], wikiErrors: object[]}} | Renders and writes every page. |
|
|
745
|
+
| `resolveSitePass` | `function resolveSitePass(name, options)` | {{beforeLinks?: Function}} The bundle. | Resolves `site.pass` to its bundle. |
|
|
746
|
+
| `buildSite` | `buildSite({ config, sqlTables, locate })` | {{gates: object, stats: object\|null, tableErrors: object[], wikiErrors: object[], mapFindings: object[], manifests: object\|null}} | Builds a Hugo content tree from a content tree, and reports what it found. |
|
|
707
747
|
|
|
708
748
|
### `engine.contentLint`
|
|
709
749
|
|