@heroiclands/package-build 22.3.0 → 22.4.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 +59 -0
- package/CONTENT.md +182 -306
- package/bin/content-build.mjs +40 -23
- package/bin/package-build.mjs +4 -3
- package/content-config.mjs +82 -180
- package/docs/api.md +27 -32
- package/docs/commands.md +54 -19
- package/docs/configuration.md +102 -132
- package/docs/content-format.md +25 -15
- package/docs/getting-started.md +5 -4
- package/docs/project-setup.md +1 -1
- package/engine/content-links.mjs +25 -60
- package/engine/diagnostics.mjs +2 -2
- package/engine/field-reference.mjs +141 -0
- package/engine/homepage.mjs +91 -172
- package/engine/metadata-index.mjs +7 -3
- package/engine/note-vocabulary.mjs +0 -20
- package/engine/pdf-build.mjs +2 -2
- package/engine/site-build.mjs +64 -225
- package/engine/site-config.mjs +15 -53
- package/engine/site-root.mjs +26 -70
- package/package.json +1 -1
- package/types/content-config.d.mts +14 -8
- package/types/engine/content-links.d.mts +12 -23
- package/types/engine/diagnostics.d.mts +2 -2
- package/types/engine/field-reference.d.mts +78 -0
- package/types/engine/homepage.d.mts +51 -91
- package/types/engine/note-vocabulary.d.mts +0 -12
- package/types/engine/site-build.d.mts +28 -129
- package/types/engine/site-config.d.mts +10 -19
- package/types/engine/site-root.d.mts +11 -36
package/CONTENT.md
CHANGED
|
@@ -179,10 +179,8 @@ publish:
|
|
|
179
179
|
# How this repository frames the website `content-build site` publishes.
|
|
180
180
|
# Framing only: addresses come from `publish.address` above.
|
|
181
181
|
site:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
sections:
|
|
185
|
-
being: { title: Beings, banner: banners/creature.webp }
|
|
182
|
+
assets: https://cdn.heroiclands.org
|
|
183
|
+
description: The rules, the setting, and the reference material.
|
|
186
184
|
```
|
|
187
185
|
|
|
188
186
|
The loader validates the document, resolves every path against the directory
|
|
@@ -1033,7 +1031,7 @@ npx content-build links [root] [--manifests <dir>]
|
|
|
1033
1031
|
npx content-build format [paths..] [--write]
|
|
1034
1032
|
npx content-build markdown [paths..] [--fix]
|
|
1035
1033
|
npx content-build content-index [root] [--out <dir>]
|
|
1036
|
-
npx content-build site
|
|
1034
|
+
npx content-build site
|
|
1037
1035
|
npx content-build reachability <dir> [file] [--index <shortcode>]
|
|
1038
1036
|
npx content-build addresses diff --from <zip|dir> [--strict]
|
|
1039
1037
|
```
|
|
@@ -1105,12 +1103,11 @@ package whose front page is not the page a person chose.
|
|
|
1105
1103
|
authored homepage exists to prevent, and a silent one: the site build reports
|
|
1106
1104
|
`wrote 0 homepage(s)` and exits 0.
|
|
1107
1105
|
- _Two_ and it serves a page nobody chose. **This is a cardinality rule, and
|
|
1108
|
-
only that.**
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
and both being reachable is not an answer to it.
|
|
1106
|
+
only that.** Both are written to the mount's `_index.md`, so the second
|
|
1107
|
+
silently overwrites the first: the duplicate-address check catches only the
|
|
1108
|
+
pair that happen to share a shortcode, and says nothing at all about a
|
|
1109
|
+
`homepage-root` beside a `homepage-front`. Which of the two should be the
|
|
1110
|
+
front page is a question nothing here can answer.
|
|
1114
1111
|
|
|
1115
1112
|
Neither has a safe default, so neither is a warning: a build that proceeded past
|
|
1116
1113
|
either would publish the wrong front page while reporting success, which is
|
|
@@ -1136,7 +1133,7 @@ naming the other, because each note is a place an author has to open and edit:
|
|
|
1136
1133
|
|
|
1137
1134
|
```text
|
|
1138
1135
|
assets/content: error: holds no `type: homepage` note, so package "sohl" publishes nothing at its own address /sohl/ — a package's front page is one authored note in this tree, routed by `type:` rather than by filename
|
|
1139
|
-
assets/content/homepage.md:3:7: error: duplicate `type: homepage` note, also declared by assets/content/Landing.md; a package has one front page, at /sohl/, and
|
|
1136
|
+
assets/content/homepage.md:3:7: error: duplicate `type: homepage` note, also declared by assets/content/Landing.md; a package has one front page, at /sohl/, and nothing here can say which of these it should be. Keep one, and make the rest ordinary notes
|
|
1140
1137
|
```
|
|
1141
1138
|
|
|
1142
1139
|
### Frontmatter, against the schema its type declares
|
|
@@ -1332,190 +1329,125 @@ because the emitter spreads a note's frontmatter wholesale and stripping it
|
|
|
1332
1329
|
there would mean referencing it. Write it if you have a use for it later —
|
|
1333
1330
|
nothing today will read it.
|
|
1334
1331
|
|
|
1335
|
-
### The homepage is addressed like every other note
|
|
1336
|
-
|
|
1337
|
-
A homepage declares a `shortcode` — conventionally `root` —
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
`[[homepage-<shortcode>]]` resolved _green_ to a page the site build never
|
|
1347
|
-
wrote, and a build reporting a live link to a 404 is worse than one saying
|
|
1348
|
-
nothing.
|
|
1349
|
-
|
|
1350
|
-
[A page's URL is its address](#a-pages-url-is-its-address) removed the premise:
|
|
1351
|
-
the address a `shortcode` computes is now the address the build publishes. Both
|
|
1352
|
-
fields are therefore permitted, and `shortcode` is **required**, like every
|
|
1353
|
-
other note's. A homepage that declares none is refused, located at the `type:`
|
|
1332
|
+
### The homepage is the package root, addressed like every other note
|
|
1333
|
+
|
|
1334
|
+
A homepage declares a `shortcode` — conventionally `root` — because that is
|
|
1335
|
+
what a link is written with: `[[homepage-root|Read the introduction]]` is an
|
|
1336
|
+
ordinary wikilink. It resolves to `/<package>/`, because the homepage _is_ the
|
|
1337
|
+
package root: the site build writes it as the mount's `_index.md`, and Hugo
|
|
1338
|
+
renders that as the `home` kind at `baseURL`. The shortcode names the page in
|
|
1339
|
+
links; the address is the package root, and `[[thalorna-homepage-root]]` from
|
|
1340
|
+
another package lands on `/thalorna/` for the same reason.
|
|
1341
|
+
|
|
1342
|
+
A homepage that declares no `shortcode` is refused, located at the `type:`
|
|
1354
1343
|
value that makes it necessary:
|
|
1355
1344
|
|
|
1356
1345
|
```text
|
|
1357
|
-
assets/content/homepage.md:3:7: error: a `type: homepage` note declares a `shortcode`, like every other note: it is addressed as `homepage-<shortcode
|
|
1346
|
+
assets/content/homepage.md:3:7: error: a `type: homepage` note declares a `shortcode`, like every other note: it is addressed as `homepage-<shortcode>`, which is what `[[homepage-<shortcode>|Text]]` is written with to reach the package's front page at `/<package>/`. Write `shortcode: root` — the front page is `homepage-root` in every package
|
|
1358
1347
|
```
|
|
1359
1348
|
|
|
1360
1349
|
`root` is a **convention, not a rule**: the address only has to be unique within
|
|
1361
1350
|
the package, which `(type, shortcode)` already guarantees, and nothing here
|
|
1362
|
-
knows better than an author what their
|
|
1363
|
-
buys is one spelling shared by
|
|
1364
|
-
same link in every package.
|
|
1351
|
+
knows better than an author what their front page is called. What the
|
|
1352
|
+
convention buys is one spelling shared by every tree, so `[[homepage-root|…]]`
|
|
1353
|
+
is the same link in every package.
|
|
1365
1354
|
|
|
1366
1355
|
**Not a bare `[[homepage]]`.** With no hyphen it does not parse as an address,
|
|
1367
|
-
so it would need a hardcoded single-token exception in the grammar
|
|
1368
|
-
thing the addressing work removes.
|
|
1356
|
+
so it would need a hardcoded single-token exception in the grammar.
|
|
1369
1357
|
|
|
1370
|
-
#### `id`
|
|
1358
|
+
#### `id` and `landing` are refused
|
|
1371
1359
|
|
|
1372
|
-
|
|
1373
|
-
the Foundry document id a compendium UUID is built from, and a
|
|
1374
|
-
into **no document
|
|
1360
|
+
Two top-level keys are refused, because neither decides anything on a page.
|
|
1361
|
+
`id` is the Foundry document id a compendium UUID is built from, and a
|
|
1362
|
+
homepage compiles into **no document**:
|
|
1375
1363
|
|
|
1376
1364
|
```text
|
|
1377
|
-
assets/content/homepage.md:4:1: error: `id` decides nothing on a `type: homepage` note: it is the Foundry document id a compendium UUID is built from, and a homepage compiles into no document — it appears in no pack and
|
|
1365
|
+
assets/content/homepage.md:4:1: error: `id` decides nothing on a `type: homepage` note: it is the Foundry document id a compendium UUID is built from, and a homepage compiles into no document — it appears in no pack and in no link manifest. Delete it
|
|
1378
1366
|
```
|
|
1379
1367
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1368
|
+
`landing` is a card block. The homepage is a page with a body, rendered as
|
|
1369
|
+
one, and no card block is read off it — an index of what the package
|
|
1370
|
+
publishes is a `doc` note carrying a content table, linked from the homepage
|
|
1371
|
+
like any other page:
|
|
1372
|
+
|
|
1373
|
+
```text
|
|
1374
|
+
assets/content/homepage.md:5:1: error: `landing` decides nothing on a `type: homepage` note: the homepage is a page with a body, rendered as one, and no card block is read off it. Write the page's links in its body, and author an index of what the package publishes as a `doc` note carrying a content table. Delete it
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
That is also why a homepage states **no Foundry address**. A manifest entry is
|
|
1378
|
+
how another package resolves a _document_; a cross-package link to a package's
|
|
1379
|
+
front page is its bare `/<package>/` address, which needs no index.
|
|
1384
1380
|
|
|
1385
1381
|
**A named class, not an allow-list.** The documented envelope is `type` and
|
|
1386
|
-
`shortcode`, with `name`, `title`, `
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1382
|
+
`shortcode`, with `name`, `title`, `description` and `banner` legitimate beside
|
|
1383
|
+
them — but an unknown top-level key is **not** refused, and that boundary is
|
|
1384
|
+
the decision rather than an omission. A homepage's frontmatter is emitted into
|
|
1385
|
+
the published page, so an unrecognised key is a Hugo or theme parameter this
|
|
1386
|
+
build has never heard of and has no standing to reject; a closed list would
|
|
1387
|
+
make every new theme parameter wait on a package-build release. `aliases` is
|
|
1388
|
+
not in the class either — it is a retired field, refused on every note
|
|
1389
|
+
whatever its type.
|
|
1394
1390
|
|
|
1395
1391
|
**Where it fires: `content-build lint` only.** Unlike a rule about the shape of
|
|
1396
1392
|
the _tree_, which the site build has its own reason to gate on, this is a
|
|
1397
1393
|
_frontmatter-schema_ rule and `content-build site` runs none of them — wiring in
|
|
1398
1394
|
one type's field rule would have the site build refuse `id` on a homepage while
|
|
1399
1395
|
accepting `weight: heavy` on a weapon. The site build does refuse a homepage it
|
|
1400
|
-
cannot address, because it
|
|
1401
|
-
beside the count so the finding reaches `publish.site: homepage`
|
|
1402
|
-
The remaining gap is `HarnMaster-3-FoundryVTT`, which runs no
|
|
1403
|
-
lint` at all and so receives no frontmatter finding of any kind;
|
|
1404
|
-
missing script in that repository, not a rule to duplicate one at a
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
Both forms, because Cloudflare Pages matches the raw path: redirect matching
|
|
1418
|
-
runs before any trailing-slash or `index.html` handling, so `/sohl` and `/sohl/`
|
|
1419
|
-
are distinct keys and a rule on one does not catch the other. A redirect also
|
|
1420
|
-
**wins over a static asset at the same path** — _"Redirects are always followed,
|
|
1421
|
-
regardless of whether or not an asset matches the incoming request"_ — so the
|
|
1422
|
-
rule fires whatever else happens to be published there.
|
|
1423
|
-
|
|
1424
|
-
**The 301 carries a pinned lifetime**, and that is the part worth being
|
|
1425
|
-
deliberate about:
|
|
1426
|
-
|
|
1427
|
-
```text
|
|
1428
|
-
# _headers
|
|
1429
|
-
/sohl/
|
|
1430
|
-
Cache-Control: max-age=3600
|
|
1431
|
-
/sohl
|
|
1432
|
-
Cache-Control: max-age=3600
|
|
1433
|
-
```
|
|
1434
|
-
|
|
1435
|
-
Cloudflare Pages sets **no** `Cache-Control` on a redirect it generates — its
|
|
1436
|
-
redirect responses carry `location` and nothing else — and a 301 with no
|
|
1437
|
-
`Cache-Control` is cacheable indefinitely by default under RFC 9111. Browsers
|
|
1438
|
-
persist one to disk and stop asking the server, so a scheme that later changed
|
|
1439
|
-
would strand every returning visitor on the package's most-linked URL. An
|
|
1440
|
-
explicit `Cache-Control` overrides that heuristic and keeps the 301's canonical
|
|
1441
|
-
signal without the permanence.
|
|
1442
|
-
|
|
1443
|
-
**`_headers` does apply to a `_redirects` response, and this is verified rather
|
|
1444
|
-
than documented.** Cloudflare's docs say only that _"redirects are applied
|
|
1445
|
-
before headers, so when a request matches both a redirect and a header, the
|
|
1446
|
-
redirect takes priority"_ — a sentence routinely misread as "headers are skipped
|
|
1447
|
-
on a redirect". Its open-source asset server settles it: the redirect response
|
|
1448
|
-
returns from `generateResponse()` and then flows through `attachHeaders()`, and
|
|
1449
|
-
the only short-circuit past that is `status >= 500`. The one documented "headers
|
|
1450
|
-
are not applied" carve-out is Pages Functions, not redirects.
|
|
1451
|
-
|
|
1452
|
-
Because that is observed behaviour rather than a documented guarantee, **verify
|
|
1453
|
-
it once after deploying** and treat a regression as a Cloudflare change rather
|
|
1454
|
-
than a content bug:
|
|
1455
|
-
|
|
1456
|
-
```bash
|
|
1457
|
-
curl -sSI https://www.heroiclands.org/sohl/ | grep -i 'location\|cache-control'
|
|
1458
|
-
```
|
|
1459
|
-
|
|
1460
|
-
If it ever stops holding, the documented alternative is a zone-level **Response
|
|
1461
|
-
Header Transform Rule** (or Bulk Redirects, which sets both), not a Pages
|
|
1462
|
-
Function — `_redirects` and `_headers` both stop applying to a route a Function
|
|
1463
|
-
serves.
|
|
1396
|
+
cannot address, because a link to it could not resolve otherwise, and it
|
|
1397
|
+
reports that beside the count so the finding reaches `publish.site: homepage`
|
|
1398
|
+
mode as well. The remaining gap is `HarnMaster-3-FoundryVTT`, which runs no
|
|
1399
|
+
`content-build lint` at all and so receives no frontmatter finding of any kind;
|
|
1400
|
+
that is a missing script in that repository, not a rule to duplicate one at a
|
|
1401
|
+
time.
|
|
1402
|
+
|
|
1403
|
+
### `/<package>/` is the homepage, and nothing redirects
|
|
1404
|
+
|
|
1405
|
+
The package's own address serves the homepage directly: Hugo renders the
|
|
1406
|
+
mount's `_index.md` as the `home` kind at `baseURL`, which is
|
|
1407
|
+
`https://www.heroiclands.org/<package>/`. `package-build site-root` writes no
|
|
1408
|
+
`_redirects` beside the site — and removes one an earlier build left there,
|
|
1409
|
+
since Cloudflare Pages would apply it. Its `_headers` suppress indexing on
|
|
1410
|
+
every host-assigned address and nothing else: no `Cache-Control` is pinned on
|
|
1411
|
+
the prefix root, because a lifetime on the homepage would hold a stale copy at
|
|
1412
|
+
the most-linked address after a deploy.
|
|
1464
1413
|
|
|
1465
1414
|
### The homepage's own links
|
|
1466
1415
|
|
|
1467
|
-
The homepage is the page a reader arrives at, and it is the one page
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
body as ordinary markdown and two carry them in `landing:` — and the one whose
|
|
1476
|
-
dead links prompted this has an _empty body_. A dead link in a card is exactly
|
|
1477
|
-
as broken as one in a paragraph, so `landing.install.url`, every
|
|
1478
|
-
`cards….url` / `.href`, the markdown links inside the prose fields (`lead`,
|
|
1479
|
-
`closing`, `install.intro`, `install.note`, a card's `description`, a link's
|
|
1480
|
-
`note`) and the body's own markdown links are all read.
|
|
1481
|
-
|
|
1482
|
-
**`url` and `href` are not the same address and are not checked the same way.**
|
|
1483
|
-
The theme resolves a `url` against the site with `relURL`, so a package writes
|
|
1484
|
-
`kb/rules/` and is served `/sohl/kb/rules/` without naming its own prefix; an
|
|
1485
|
-
`href` is an address that is _already_ resolved and is used verbatim, which is
|
|
1486
|
-
what `cards.source: sections` fills in. A leading `/` is therefore a defect in a
|
|
1487
|
-
`url` — Hugo prefixes it a second time — and correct in an `href`.
|
|
1488
|
-
|
|
1489
|
-
Four findings, and each one names the form to write instead:
|
|
1416
|
+
The homepage is the page a reader arrives at, and it is the one page no
|
|
1417
|
+
wikilink resolver reaches: a homepage is published verbatim in every
|
|
1418
|
+
publishing mode, so its links are markdown links in its body, and `links`
|
|
1419
|
+
audits them. A body link is emitted as written and resolved by the browser
|
|
1420
|
+
against the homepage's own address, which _is_ the package root, so a
|
|
1421
|
+
package-relative one (`kb/rules/`) lands where a reader expects.
|
|
1422
|
+
|
|
1423
|
+
Three findings, and each one names the form to write instead:
|
|
1490
1424
|
|
|
1491
1425
|
| Finding | Why |
|
|
1492
1426
|
| ---------------------------- | --------------------------------------------------------------------------------- |
|
|
1493
1427
|
| A **retired content type** | `kb/creature/` when `creature` became `being`. The engine knows what was retired. |
|
|
1494
|
-
| A **hardcoded absolute URL** | Into this package's own prefix, or into one a
|
|
1495
|
-
| A **root-relative `url:`** | `relURL` prefixes it again. `href:` is exempt — verbatim is what it means. |
|
|
1428
|
+
| A **hardcoded absolute URL** | Into this package's own prefix, or into one a fetched index names. |
|
|
1496
1429
|
| A **wikilink** | Nothing resolves one here: a homepage is published verbatim in every mode. |
|
|
1497
1430
|
|
|
1498
1431
|
That last one is why a homepage does **not** get the wikilink resolution every
|
|
1499
1432
|
other note body gets. In `homepage` mode the content tree is never walked, so
|
|
1500
1433
|
there is no index for a wikilink to resolve against — and giving the page one
|
|
1501
1434
|
would make the mode depend on exactly the machinery its licensing fence exists
|
|
1502
|
-
to not build. So a
|
|
1435
|
+
to not build. So a homepage addresses the web the way the web does, and a
|
|
1503
1436
|
wikilink on one is reported rather than resolved.
|
|
1504
1437
|
|
|
1505
1438
|
**What is checkable, and what is not.** Only an address into this site is, and
|
|
1506
1439
|
only against facts the build already holds — the retired-type table and the
|
|
1507
|
-
package prefixes a
|
|
1440
|
+
package prefixes a fetched index names. Two things are deliberately not
|
|
1508
1441
|
attempted:
|
|
1509
1442
|
|
|
1510
1443
|
- **Whether an external URL answers.** There is no network at build time, and a
|
|
1511
1444
|
build must not go red because a third party is down.
|
|
1512
1445
|
- **Whether a live in-site address names a page that exists.** Several surfaces
|
|
1513
|
-
a
|
|
1514
|
-
documentation,
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
better form to write.
|
|
1446
|
+
a homepage routes to are produced by other tools entirely — generated API
|
|
1447
|
+
documentation, say — so this build does not hold the set of published pages
|
|
1448
|
+
and would report a working link as dead. A bare `/<package>/` names another
|
|
1449
|
+
package's front page and needs no index: it is left alone because it cannot
|
|
1450
|
+
be improved.
|
|
1519
1451
|
|
|
1520
1452
|
## The content format specification
|
|
1521
1453
|
|
|
@@ -1895,18 +1827,16 @@ to the legacy-URL map" — and no such map was ever written, here or in any
|
|
|
1895
1827
|
consumer. All of it is gone.
|
|
1896
1828
|
|
|
1897
1829
|
The `type-` half earns its place: it keeps every content address clear of the
|
|
1898
|
-
package's fixed mounts (`/<package>/` for the
|
|
1830
|
+
package's fixed mounts (`/<package>/` for the homepage, `/<package>/api/` for
|
|
1899
1831
|
generated API docs), neither of which contains a hyphen or names a type. So the
|
|
1900
1832
|
namespace is provably disjoint rather than conventionally so.
|
|
1901
1833
|
|
|
1902
|
-
**A page is written flat, named by its address**, not filed
|
|
1903
|
-
|
|
1904
|
-
written and a section
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
`<mount>/<type>-<shortcode>.md` and the front-matter `url:` still publishes it at
|
|
1909
|
-
the package root, one level above.
|
|
1834
|
+
**A page is written flat, named by its address**, not filed into a
|
|
1835
|
+
directory, because Hugo derives a page's section from where the file is
|
|
1836
|
+
written, and a section appears in no address. The file is
|
|
1837
|
+
`<mount>/<type>-<shortcode>.md` and the front-matter `url:` publishes it at
|
|
1838
|
+
the package root, one level above; the `section` kind is disabled on every
|
|
1839
|
+
site, so no directory would answer even if one were written.
|
|
1910
1840
|
|
|
1911
1841
|
**A page states its address without the package base; everything pointing _at_
|
|
1912
1842
|
it composes one**. They read as one quantity and are two:
|
|
@@ -1923,15 +1853,11 @@ its own base to a value that already carried one and published every content
|
|
|
1923
1853
|
page a segment too deep — `/sohl/sohl/doc-rulesintro/`, 404 at the address the
|
|
1924
1854
|
manifest, the sitemap and every inbound link named.
|
|
1925
1855
|
|
|
1926
|
-
**There is no landing page.** A
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
**Sections stay, as configuration.** `site.sections` still writes an `_index.md`
|
|
1933
|
-
per section, and that is now the _only_ thing that makes one exist — see
|
|
1934
|
-
[What a section may declare](#what-a-section-may-declare).
|
|
1856
|
+
**There is no landing page and no section.** A page that introduces the notes
|
|
1857
|
+
of a type is an ordinary note addressed `doc-<type>`, with no build path of its
|
|
1858
|
+
own, carrying a content table over what it introduces. A site is its homepage
|
|
1859
|
+
and its pages, and nothing is generated between them — see
|
|
1860
|
+
[What the site publishes](#what-the-site-publishes).
|
|
1935
1861
|
|
|
1936
1862
|
### The address scheme
|
|
1937
1863
|
|
|
@@ -1961,9 +1887,7 @@ publish:
|
|
|
1961
1887
|
`section:` key are refused by name.
|
|
1962
1888
|
|
|
1963
1889
|
A note's `subType` is checked against the values its type declares, and only
|
|
1964
|
-
those.
|
|
1965
|
-
_address_ it landed at, so the closed genre list could not answer for it. The
|
|
1966
|
-
cause is removed rather than the vocabulary widened again.
|
|
1890
|
+
those.
|
|
1967
1891
|
|
|
1968
1892
|
The only note the scheme yields no address for is one carrying no `shortcode`.
|
|
1969
1893
|
It is **reported and omitted**, never guessed: the command prints one located
|
|
@@ -2217,15 +2141,15 @@ indistinguishable from one built against a mis-pointed tree.
|
|
|
2217
2141
|
## Publishing a website
|
|
2218
2142
|
|
|
2219
2143
|
```bash
|
|
2220
|
-
npx content-build site # the configured tree
|
|
2221
|
-
npx content-build site --out tmp/kb # or somewhere else
|
|
2144
|
+
npx content-build site # the configured tree, under build/hugo/
|
|
2222
2145
|
```
|
|
2223
2146
|
|
|
2224
2147
|
The sibling of `package compile`: the same content tree, rendered as pages
|
|
2225
2148
|
instead of compiled into packs. It does the walk, the frontmatter read, the
|
|
2226
2149
|
address derivation, the address index, table expansion, wikilink resolution,
|
|
2227
|
-
code-fence protection, the foreign-manifest merge
|
|
2228
|
-
|
|
2150
|
+
code-fence protection, the foreign-manifest merge and the page emission. A
|
|
2151
|
+
site is its homepage and its pages — see
|
|
2152
|
+
[What the site publishes](#what-the-site-publishes).
|
|
2229
2153
|
|
|
2230
2154
|
### The homepage, and how much else is published
|
|
2231
2155
|
|
|
@@ -2249,15 +2173,14 @@ A package declares **exactly one** of these, and both `content-build lint` and
|
|
|
2249
2173
|
|
|
2250
2174
|
That is the whole envelope. A homepage **compiles into no compendium
|
|
2251
2175
|
document**, and so appears in no pack and in no link manifest — which is why it
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
`
|
|
2255
|
-
[The homepage is
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
explainer about the source tree.
|
|
2176
|
+
refuses `id`. It is the package root: written as the mount's `_index.md`,
|
|
2177
|
+
rendered at `/<contentPackage>/`, and cited as `[[homepage-root|Text]]` by
|
|
2178
|
+
the `shortcode` it declares (see
|
|
2179
|
+
[The homepage is the package root](#the-homepage-is-the-package-root-addressed-like-every-other-note)).
|
|
2180
|
+
It is dispatched on `type` like every other note, not on a filename — nothing
|
|
2181
|
+
in this format is decided by a file's name, which is why `sohl-thalorna` can
|
|
2182
|
+
keep a `README.md` in its content tree as a developer explainer about the
|
|
2183
|
+
source tree.
|
|
2261
2184
|
|
|
2262
2185
|
`type: homepage` is declared by the **engine**, not by the `sohl` item registry,
|
|
2263
2186
|
so a package that configures no `itemBuilders` at all — `HarnMaster-3-FoundryVTT`
|
|
@@ -2284,8 +2207,7 @@ content_ — journal text, artwork, item descriptions, compiled notes — and a
|
|
|
2284
2207
|
announcing the module discloses none of it. Because the failure mode is silent,
|
|
2285
2208
|
the mode **fences the content surfaces off** rather than trusting a
|
|
2286
2209
|
configuration to stay empty: in `homepage` mode the tree is never walked for
|
|
2287
|
-
pages,
|
|
2288
|
-
they are declared.
|
|
2210
|
+
pages, whatever else the `site:` block declares.
|
|
2289
2211
|
|
|
2290
2212
|
That is separate from the **dependency** edge, which such a module also
|
|
2291
2213
|
declines: being cited by another package is what would stop it being
|
|
@@ -2294,60 +2216,47 @@ address anyone links to. A package publishes its content index regardless — th
|
|
|
2294
2216
|
licensing constraint is against publishing _pages_, not against the artifact
|
|
2295
2217
|
existing — but nothing may declare it as a dependency.
|
|
2296
2218
|
|
|
2297
|
-
The homepage's file is written at the root of the
|
|
2298
|
-
`build/hugo/content/` — the package's own site root, one level
|
|
2299
|
-
content mount, which is where `publish.address.prefix` puts
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
does not reach it.
|
|
2219
|
+
The homepage's file is the mount's `_index.md`, written at the root of the
|
|
2220
|
+
content tree, `build/hugo/content/` — the package's own site root, one level
|
|
2221
|
+
above the content mount, which is where `publish.address.prefix` puts
|
|
2222
|
+
everything else. Hugo renders it as the `home` kind at `baseURL`, so it states
|
|
2223
|
+
no `url` of its own.
|
|
2303
2224
|
|
|
2304
2225
|
**What it does not do is decide addresses.** Those come from `publish.address`,
|
|
2305
2226
|
the same setting the content index reads, so a page and its index record cannot
|
|
2306
2227
|
disagree about where the page is. Everything under `site:` is _framing_ —
|
|
2307
|
-
|
|
2308
|
-
that is this repository's own. What the site publishes is the
|
|
2309
|
-
nothing beside
|
|
2310
|
-
`pack: none` where it compiles into
|
|
2311
|
-
mechanism for mounting a directory of
|
|
2312
|
-
`readmeSections:` key is refused with a message
|
|
2228
|
+
the repository's own body rewrites, and the residue of the generated Hugo
|
|
2229
|
+
configuration that is this repository's own. What the site publishes is the
|
|
2230
|
+
homepage and the content tree and nothing beside them: a page of
|
|
2231
|
+
documentation is a note (`type: doc`, with `pack: none` where it compiles into
|
|
2232
|
+
no document), so there is no second mechanism for mounting a directory of
|
|
2233
|
+
markdown, and a `trees:` or `readmeSections:` key is refused with a message
|
|
2234
|
+
saying so.
|
|
2313
2235
|
|
|
2314
2236
|
```yaml
|
|
2315
2237
|
site:
|
|
2316
2238
|
base: /sohl/ # default: /<contentPackage>/ — hrefs only, never a page's `url:`
|
|
2317
2239
|
packages: [sohl, thalorna] # default: just contentPackage
|
|
2318
|
-
backfillSections: true
|
|
2319
|
-
landing: { title: Knowledgebase, type: knowledgebase }
|
|
2320
2240
|
pass: sohlKb
|
|
2321
2241
|
passOptions:
|
|
2322
2242
|
apiBase: /sohl/api/
|
|
2323
2243
|
symbolMap: kb/data/api-symbols.json
|
|
2324
|
-
sections:
|
|
2325
|
-
being:
|
|
2326
|
-
title: Beings
|
|
2327
|
-
banner: banners/creature.webp
|
|
2328
|
-
description: Folk, animals and the things that walk the world.
|
|
2329
|
-
reference: { title: Reference, listType: doc, listSubType: reference }
|
|
2330
|
-
list: { shortcodes: true }
|
|
2331
2244
|
notfound:
|
|
2332
2245
|
tagline: Song of Heroic Lands has no page at
|
|
2333
2246
|
sitenoun: site
|
|
2334
2247
|
links:
|
|
2335
|
-
- { title:
|
|
2336
|
-
```
|
|
2337
|
-
|
|
2338
|
-
| Key
|
|
2339
|
-
|
|
|
2340
|
-
| `base`
|
|
2341
|
-
| `packages`
|
|
2342
|
-
| `
|
|
2343
|
-
| `
|
|
2344
|
-
| `
|
|
2345
|
-
| `
|
|
2346
|
-
| `
|
|
2347
|
-
| `assets` | The host every package's imagery is served from; the generated `params.cdnBaseURL`. |
|
|
2348
|
-
| `list` | How a listing page renders; the generated `params.list`. |
|
|
2349
|
-
| `notfound` | The wording of the "page not found" page; the generated `params.notfound`. |
|
|
2350
|
-
| `hugo` | A mapping deep-merged over the generated Hugo configuration, last. Every key the generator writes is refused here — see `docs/configuration.md`. |
|
|
2248
|
+
- { title: Rules, url: doc-rulesintro/, text: Success and opposed tests, injury, healing. }
|
|
2249
|
+
```
|
|
2250
|
+
|
|
2251
|
+
| Key | What it decides |
|
|
2252
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2253
|
+
| `base` | Where the package is served: the prefix on every rendered `href`, and what a manifest `path` is measured against. It reaches no page's own `url:` — see [A page's URL is its address](#a-pages-url-is-its-address). Defaults to `/<contentPackage>/`. |
|
|
2254
|
+
| `packages` | Which content packages this site renders. Defaults to its own. |
|
|
2255
|
+
| `pass` | A named bundle of this repository's own body rewrites. |
|
|
2256
|
+
| `passOptions` | That bundle's options. |
|
|
2257
|
+
| `assets` | The host every package's imagery is served from; the generated `params.cdnBaseURL`. |
|
|
2258
|
+
| `notfound` | The wording of the "page not found" page; the generated `params.notfound`. |
|
|
2259
|
+
| `hugo` | A mapping deep-merged over the generated Hugo configuration, last. Every key the generator writes is refused here — see `docs/configuration.md`. |
|
|
2351
2260
|
|
|
2352
2261
|
Where the tree is written is not among them. `content-build site` writes the
|
|
2353
2262
|
whole Hugo source tree under `build/hugo/` — the generated `hugo.toml`, the
|
|
@@ -2356,99 +2265,66 @@ script runs `hugo --source build/hugo` over it. The generated file's every
|
|
|
2356
2265
|
value has a source the repository already states; `docs/configuration.md`
|
|
2357
2266
|
lists them.
|
|
2358
2267
|
|
|
2359
|
-
### What
|
|
2268
|
+
### What the site publishes
|
|
2360
2269
|
|
|
2361
|
-
|
|
2362
|
-
`
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
`
|
|
2270
|
+
**A site is its homepage and its pages, and nothing is generated between
|
|
2271
|
+
them.** The `type: homepage` note is `/<package>/`; every other note is one
|
|
2272
|
+
page at `/<package>/<type>-<shortcode>/`. No section directory is written, no
|
|
2273
|
+
listing of a type, no tag page: the generated Hugo configuration disables the
|
|
2274
|
+
`section`, `taxonomy`, `term` and `RSS` kinds on every site, so `home` and
|
|
2275
|
+
`page` are the only kinds that render, and a request for `/<package>/being/`
|
|
2276
|
+
is a 404.
|
|
2366
2277
|
|
|
2367
|
-
|
|
2278
|
+
Every structure above the pages — which notes belong together, in what order,
|
|
2279
|
+
under which headings, with which columns — is **authored**, as a `doc` note
|
|
2280
|
+
carrying a content table over the content index:
|
|
2368
2281
|
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
Whatever the entry may carry is the whole of what the section can say.
|
|
2379
|
-
|
|
2380
|
-
| Key | Required | What it does |
|
|
2381
|
-
| ------------- | -------- | ------------------------------------------------------------------------- |
|
|
2382
|
-
| `title` | yes | The landing's heading, so it matches the card that links to it. |
|
|
2383
|
-
| `banner` | no | The hero image, resolved as a CDN asset like any other `banner:`. |
|
|
2384
|
-
| `description` | no | The hero standfirst under the heading, and the blurb a landing card uses. |
|
|
2385
|
-
| `listType` | no | The content **type** whose pages this section lists. |
|
|
2386
|
-
| `listSubType` | no | Narrows that to one **subType**. Only with a `listType`. |
|
|
2387
|
-
|
|
2388
|
-
#### Saying what a section lists
|
|
2282
|
+
````markdown
|
|
2283
|
+
---
|
|
2284
|
+
type: doc
|
|
2285
|
+
subType: reference
|
|
2286
|
+
shortcode: beings
|
|
2287
|
+
pack: none
|
|
2288
|
+
name:
|
|
2289
|
+
full: Beings
|
|
2290
|
+
---
|
|
2389
2291
|
|
|
2390
|
-
|
|
2391
|
-
landing used to get free from Hugo's page tree no longer exists anywhere the
|
|
2392
|
-
theme can read: not on the page, not on the landing, not in any URL — only here.
|
|
2393
|
-
So a section states its own query, and a layout substitutes it when `.Pages` is
|
|
2394
|
-
empty:
|
|
2292
|
+
Every person and creature of the setting, by realm.
|
|
2395
2293
|
|
|
2396
|
-
```
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
user-guide: { title: User Guide, listType: doc, listSubType: userguide }
|
|
2294
|
+
```dataview
|
|
2295
|
+
TABLE name.full AS Name, subType AS Kind, data.realm AS Realm
|
|
2296
|
+
FROM type = "being"
|
|
2297
|
+
SORT data.realm, name.full
|
|
2401
2298
|
```
|
|
2299
|
+
````
|
|
2402
2300
|
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
```yaml
|
|
2406
|
-
---
|
|
2407
|
-
title: User Guide
|
|
2408
|
-
listType: doc
|
|
2409
|
-
listSubType: userguide
|
|
2410
|
-
---
|
|
2411
|
-
```
|
|
2301
|
+
````
|
|
2412
2302
|
|
|
2413
|
-
|
|
2303
|
+
That page is `doc-beings`, published at `/<package>/doc-beings/`, and it is the
|
|
2304
|
+
index — linked from the homepage like any other page, and choosing its own
|
|
2305
|
+
membership, order, headings and columns. A tag is a field such a table
|
|
2306
|
+
filters on, not a page of its own.
|
|
2414
2307
|
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
`sohl` they do not: the section is `user-guide`, because that is a published
|
|
2423
|
-
URL, while the subType is `userguide` because an address segment is
|
|
2424
|
-
lowercase alphanumeric. Both values are checked against that charset here, so
|
|
2425
|
-
copying the section's name in is refused rather than quietly matching nothing.
|
|
2426
|
-
- **`listSubType` needs a `listType`.** A subType only tells pages apart within
|
|
2427
|
-
a type — `rules`, `userguide` and `reference` are all `doc` — so alone it
|
|
2428
|
-
names no query.
|
|
2308
|
+
**One page per note, whatever it compiles into.** A system-bearing note — an
|
|
2309
|
+
`affiliation`, a `being`, every item type — compiles into two Foundry
|
|
2310
|
+
documents, the Item and the JournalEntry carrying its prose, addressed
|
|
2311
|
+
`doc<type>-<shortcode>`. On the web it renders as one page, which is its own
|
|
2312
|
+
documentation: the site index keys that page under both `<type>/<shortcode>`
|
|
2313
|
+
and `doc<type>/<shortcode>`, so a link written either way lands on it, and a
|
|
2314
|
+
content table that lists a type surfaces each note once.
|
|
2429
2315
|
|
|
2430
|
-
|
|
2316
|
+
A configuration that asks the build to generate an index — `site.sections`
|
|
2317
|
+
(with the `listType` / `listSubType` an entry carried), `site.landing`,
|
|
2318
|
+
`site.backfillSections`, and `site.list`, which said how such a listing
|
|
2319
|
+
renders — is refused by name, with one message:
|
|
2431
2320
|
|
|
2432
2321
|
```text
|
|
2433
|
-
package-build config: `site.sections
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
written once, for the mount, in one landing template's own vocabulary. A section
|
|
2440
|
-
entry is written fourteen to twenty times per build against a contract every
|
|
2441
|
-
package and every section shares, so an unbounded one would let a mistyped
|
|
2442
|
-
`descrption:` publish into front matter, be read by nobody, and say nothing to
|
|
2443
|
-
anyone. Refusing it costs one line here when the vocabulary genuinely grows, and
|
|
2444
|
-
buys a build that cannot quietly emit a key no theme reads. `listType` and
|
|
2445
|
-
`listSubType` are that growth: two named keys, checked, rather than an open
|
|
2446
|
-
passthrough in which `listTpye:` would publish and no landing would list
|
|
2447
|
-
anything.
|
|
2448
|
-
|
|
2449
|
-
The **writers** name no keys: a section's `_index.md` is whatever the entry
|
|
2450
|
-
resolved to, `title` first. So extending the vocabulary is a change to the
|
|
2451
|
-
schema alone, and the two can no longer drift apart.
|
|
2322
|
+
package-build config: `site.sections` is retired — a site is its homepage and
|
|
2323
|
+
its pages, and any index between them is a `doc` note: write one with
|
|
2324
|
+
`type: doc`, a `shortcode` and `pack: none`, carrying a content table over the
|
|
2325
|
+
notes it lists, and link it from the homepage. Nothing is generated between
|
|
2326
|
+
the homepage and the pages, so delete the key.
|
|
2327
|
+
````
|
|
2452
2328
|
|
|
2453
2329
|
### Why the output location is fixed
|
|
2454
2330
|
|
|
@@ -2833,7 +2709,7 @@ path now rides on the error, and the loader that read the file resolves it
|
|
|
2833
2709
|
against the YAML, so all of them come out located:
|
|
2834
2710
|
|
|
2835
2711
|
```text
|
|
2836
|
-
package-build.config.yaml:382:64: error: package-build config: `site.
|
|
2712
|
+
package-build.config.yaml:382:64: error: package-build config: `site.notfound.links[0].descrption` is not a recognized option (expected one of: title, url, text).
|
|
2837
2713
|
```
|
|
2838
2714
|
|
|
2839
2715
|
The same two rules apply. A key the file never declares — a required one that is
|