@heroiclands/package-build 10.0.1 → 11.0.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 +279 -0
- package/CONTENT.md +218 -71
- package/MIGRATING.md +64 -0
- package/bin/content-build.mjs +59 -75
- package/docs/content-format.md +90 -67
- package/engine/base-compiler.mjs +7 -1
- package/engine/content-address.mjs +71 -18
- package/engine/content-format-check.mjs +1 -1
- package/engine/content-links.mjs +93 -112
- package/engine/content-lint.mjs +14 -10
- package/engine/content-slug.mjs +39 -105
- package/engine/diagnostics.mjs +16 -2
- package/engine/frontmatter-lint.mjs +26 -13
- package/engine/helpers.mjs +31 -68
- package/engine/homepage.mjs +131 -86
- package/engine/index.mjs +2 -5
- package/engine/manifest-emit.mjs +23 -4
- package/engine/note-vocabulary.mjs +58 -1
- package/engine/retired-fields.mjs +117 -6
- package/engine/site-build.mjs +182 -59
- package/engine/site-index.mjs +57 -102
- package/engine/web-wikilinks.mjs +183 -127
- package/engine/wikilink-syntax.mjs +174 -34
- package/engine/wikilinks.mjs +159 -117
- package/package.json +1 -1
- package/types/engine/base-compiler.d.mts +1 -1
- package/types/engine/content-address.d.mts +46 -14
- package/types/engine/content-links.d.mts +13 -17
- package/types/engine/content-slug.d.mts +11 -48
- package/types/engine/diagnostics.d.mts +14 -1
- package/types/engine/helpers.d.mts +4 -3
- package/types/engine/homepage.d.mts +96 -60
- package/types/engine/index.d.mts +0 -1
- package/types/engine/note-vocabulary.d.mts +43 -0
- package/types/engine/retired-fields.d.mts +78 -1
- package/types/engine/site-build.d.mts +70 -17
- package/types/engine/site-index.d.mts +19 -21
- package/types/engine/web-wikilinks.d.mts +29 -28
- package/types/engine/wikilink-syntax.d.mts +126 -40
- package/types/engine/wikilinks.d.mts +29 -24
- package/engine/abbreviations.mjs +0 -0
- package/engine/alias-index.mjs +0 -153
- package/types/engine/abbreviations.d.mts +0 -44
- package/types/engine/alias-index.d.mts +0 -122
package/CONTENT.md
CHANGED
|
@@ -343,7 +343,7 @@ consumer keeps it somewhere else.
|
|
|
343
343
|
**The configuration is resolved on first read, never at import.** Every module
|
|
344
344
|
here can be imported — and `content-build --version` and `--help` answered — in a
|
|
345
345
|
directory with no `package-build.config.yaml` and no Foundry package manifest, so
|
|
346
|
-
a consumer can reach for one pure helper (`engine/content-
|
|
346
|
+
a consumer can reach for one pure helper (`engine/content-address`,
|
|
347
347
|
`engine/wikilinks`) without standing up a pack build. Anything derived from
|
|
348
348
|
configuration is therefore an accessor rather than a hoisted constant —
|
|
349
349
|
`loadPackConfig()`, `contentPackage()`, `foundryPackageId()`, `itemTypes()`,
|
|
@@ -666,7 +666,7 @@ each finding in the located form below:
|
|
|
666
666
|
- **Uniqueness** — `(type, shortcode)` names one note. A document is addressed
|
|
667
667
|
across _every_ pack of its document type, so routing two same-address notes to
|
|
668
668
|
different packs with `pack:` does not separate them.
|
|
669
|
-
- **
|
|
669
|
+
- **One front page** — exactly one note declares `type: homepage`. See
|
|
670
670
|
[Exactly one homepage](#exactly-one-homepage) below.
|
|
671
671
|
|
|
672
672
|
It compiles nothing, opens no LevelDB and needs no Foundry manifest, so it runs
|
|
@@ -675,11 +675,12 @@ rather than passing: "every one of nothing is unique" is a vacuous pass, and it
|
|
|
675
675
|
is exactly what a tree that failed to check out produces.
|
|
676
676
|
|
|
677
677
|
What that guard reports is an **empty walk**, not an empty set of addresses. A
|
|
678
|
-
note may be keyless
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
678
|
+
note may be keyless — a folder document carries no `shortcode` — so a tree of
|
|
679
|
+
them is populated, correct and unkeyed. That tree passes; a tree holding no
|
|
680
|
+
notes at all still fails. (The homepage used to be the headline example, because
|
|
681
|
+
it was addressed by the package rather than by a slug. It carries an address
|
|
682
|
+
like every other note now (#182); the guard is unchanged, because what it reads
|
|
683
|
+
was never the key count.)
|
|
683
684
|
|
|
684
685
|
### Exactly one homepage
|
|
685
686
|
|
|
@@ -690,11 +691,15 @@ package whose front page is not the page a person chose.
|
|
|
690
691
|
- _Zero_ and the package serves nothing at `/<package>/` — the failure the
|
|
691
692
|
authored homepage exists to prevent, and a silent one: the site build reports
|
|
692
693
|
`wrote 0 homepage(s)` and exits 0.
|
|
693
|
-
- _Two_ and it serves a page nobody chose.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
694
|
+
- _Two_ and it serves a page nobody chose. **This is a cardinality rule, and
|
|
695
|
+
since #182 it is only that.** It used to rest on the fixed destination every
|
|
696
|
+
homepage shared — the second overwrote the first — so the address rule
|
|
697
|
+
enforced it as a side effect. A homepage is written at its own address now, so
|
|
698
|
+
two of them publish two pages and collide over nothing: the duplicate-address
|
|
699
|
+
check catches only the pair that happen to share a shortcode, and says nothing
|
|
700
|
+
at all about a `homepage-root` beside a `homepage-front`. Which of the two the
|
|
701
|
+
redirect at `/<package>/` should name is a question nothing here can answer,
|
|
702
|
+
and both being reachable is not an answer to it.
|
|
698
703
|
|
|
699
704
|
Neither has a safe default, so neither is a warning: a build that proceeded past
|
|
700
705
|
either would publish the wrong front page while reporting success, which is
|
|
@@ -720,7 +725,7 @@ naming the other, because each note is a place an author has to open and edit:
|
|
|
720
725
|
|
|
721
726
|
```text
|
|
722
727
|
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
|
|
723
|
-
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
|
|
728
|
+
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 each of these publishes at an address of its own — so nothing here can say which one that address should redirect to. Keep one, and make the rest ordinary notes
|
|
724
729
|
```
|
|
725
730
|
|
|
726
731
|
### Frontmatter, against the schema its type declares
|
|
@@ -805,54 +810,154 @@ does not exist. Removing it was verified output-neutral first: across 1,735
|
|
|
805
810
|
stripped notes, `package compile` produced byte-identical `build/packs-json` and
|
|
806
811
|
the site build byte-identical `site/content`.
|
|
807
812
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
813
|
+
**And the top-level field itself is now retired (#180).** `aliases:` fed the
|
|
814
|
+
alias index, which is what a bare `[[Alias]]` was looked up in. That form
|
|
815
|
+
resolved to nothing anywhere in the corpus, while the collision rule guarding it
|
|
816
|
+
folded in every note's `name.full` and so decided what a note could be named
|
|
817
|
+
(#179). Both are gone: every wikilink is an address, written
|
|
818
|
+
`[[type-shortcode|Text]]`, and declaring `aliases:` is refused naming the file
|
|
819
|
+
and the line.
|
|
820
|
+
|
|
821
|
+
**`name.aliases` is kept, and is read by nothing.** It fed the same index and
|
|
822
|
+
lost the same reader, but unlike the top-level list it is **reserved** — held
|
|
823
|
+
for a use that does not exist yet. So it is the one field in the format that is
|
|
824
|
+
neither retired nor consulted: no index folds it in, no rule validates it,
|
|
825
|
+
nothing derives a name, address or URL from it, and no build branches on it. A
|
|
826
|
+
note carrying one compiles, resolves and addresses exactly as the same note
|
|
827
|
+
without it; it rides through into a page's emitted front matter untouched,
|
|
828
|
+
because the emitter spreads a note's frontmatter wholesale and stripping it
|
|
829
|
+
there would mean referencing it. Write it if you have a use for it later —
|
|
830
|
+
nothing today will read it.
|
|
831
|
+
|
|
832
|
+
### The homepage is addressed like every other note
|
|
833
|
+
|
|
834
|
+
A homepage declares a `shortcode` — conventionally `root` — and publishes at its
|
|
835
|
+
address, `/<package>/homepage-root/`, written by the same rule as everything
|
|
836
|
+
else (#182). So `[[homepage-root|Read the introduction]]` is an ordinary
|
|
837
|
+
wikilink, resolving to the page the build actually writes.
|
|
838
|
+
|
|
839
|
+
It did not use to be. A page's URL derived from `name.full` while a homepage's
|
|
840
|
+
destination was fixed at `_index.md`, so `content-build lint` **refused** `name`
|
|
841
|
+
and `shortcode` on one (#53) — not out of tidiness, but because they were not
|
|
842
|
+
inert. A `shortcode` put the note in the address index, so
|
|
843
|
+
`[[homepage-<shortcode>]]` resolved _green_ to a page the site build never
|
|
844
|
+
wrote, and a build reporting a live link to a 404 is worse than one saying
|
|
845
|
+
nothing.
|
|
846
|
+
|
|
847
|
+
[A page's URL is its address](#a-pages-url-is-its-address) removed the premise:
|
|
848
|
+
the address a `shortcode` computes is now the address the build publishes. Both
|
|
849
|
+
fields are therefore permitted, and `shortcode` is **required**, like every
|
|
850
|
+
other note's. A homepage that declares none is refused, located at the `type:`
|
|
851
|
+
value that makes it necessary:
|
|
831
852
|
|
|
832
853
|
```text
|
|
833
|
-
assets/content/homepage.md:
|
|
834
|
-
assets/content/homepage.md:28:1: error: `name` decides nothing on a `type: homepage` note: a page's slug derives from `name.full`, and a homepage's destination is fixed — it is written to `_index.md` at the package's own address, `/<package>/`. Write `title:` for what the page is called, and delete `name`
|
|
854
|
+
assets/content/homepage.md:3:7: error: a `type: homepage` note declares a `shortcode`, like every other note: it is addressed as `homepage-<shortcode>` and published at `/<package>/homepage-<shortcode>/`, which is where `[[homepage-<shortcode>|Text]]` lands. Write `shortcode: root` — the package landing is `homepage-root` in every package
|
|
835
855
|
```
|
|
836
856
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
857
|
+
`root` is a **convention, not a rule**: the address only has to be unique within
|
|
858
|
+
the package, which `(type, shortcode)` already guarantees, and nothing here
|
|
859
|
+
knows better than an author what their landing is called. What the convention
|
|
860
|
+
buys is one spelling shared by all six trees, so `[[homepage-root|…]]` is the
|
|
861
|
+
same link in every package.
|
|
862
|
+
|
|
863
|
+
**Not a bare `[[homepage]]`.** With no hyphen it does not parse as an address,
|
|
864
|
+
so it would need a hardcoded single-token exception in the grammar — the one
|
|
865
|
+
thing the addressing work removes.
|
|
866
|
+
|
|
867
|
+
#### `id` is still refused
|
|
868
|
+
|
|
869
|
+
One field is left in the class, and on ground the change does not touch: `id` is
|
|
870
|
+
the Foundry document id a compendium UUID is built from, and a homepage compiles
|
|
871
|
+
into **no document**.
|
|
872
|
+
|
|
873
|
+
```text
|
|
874
|
+
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
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
That is also why a homepage stays **out of the link manifest**, now that a
|
|
878
|
+
shortcode alone would put it in. A manifest entry is how another package
|
|
879
|
+
resolves a _document_; a cross-package link to a package's front page is its
|
|
880
|
+
bare `/<package>/` address, which needs no index.
|
|
881
|
+
|
|
882
|
+
**A named class, not an allow-list.** The documented envelope is `type` and
|
|
883
|
+
`shortcode`, with `name`, `title`, `landing`, `description` and `banner`
|
|
884
|
+
legitimate beside them — but an unknown top-level key is **not** refused, and
|
|
885
|
+
that boundary is the decision rather than an omission. A homepage's frontmatter
|
|
886
|
+
is emitted into the published page, so an unrecognised key is a Hugo or theme
|
|
887
|
+
parameter this build has never heard of and has no standing to reject; a closed
|
|
888
|
+
list would make every new theme parameter wait on a package-build release.
|
|
889
|
+
`aliases` is not in the class either — it is a retired field now, refused on
|
|
890
|
+
every note whatever its type (#180).
|
|
847
891
|
|
|
848
892
|
**Where it fires: `content-build lint` only.** Unlike a rule about the shape of
|
|
849
893
|
the _tree_, which the site build has its own reason to gate on, this is a
|
|
850
|
-
_frontmatter-schema_ rule and `content-build site` runs none of them — wiring in
|
|
851
|
-
rule would have the site build refuse `
|
|
852
|
-
`weight: heavy` on a weapon. The
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
894
|
+
_frontmatter-schema_ rule and `content-build site` runs none of them — wiring in
|
|
895
|
+
one type's field rule would have the site build refuse `id` on a homepage while
|
|
896
|
+
accepting `weight: heavy` on a weapon. The site build does refuse a homepage it
|
|
897
|
+
cannot address, because it cannot write the page otherwise, and it reports that
|
|
898
|
+
beside the count so the finding reaches `publish.site: homepage` mode as well.
|
|
899
|
+
The remaining gap is `HarnMaster-3-FoundryVTT`, which runs no `content-build
|
|
900
|
+
lint` at all and so receives no frontmatter finding of any kind; that is a
|
|
901
|
+
missing script in that repository, not a rule to duplicate one at a time.
|
|
902
|
+
|
|
903
|
+
### `/<package>/` is a redirect the package authors
|
|
904
|
+
|
|
905
|
+
Nothing is written at `/<package>/` any more. The package's own address is a
|
|
906
|
+
**routing fact**, and it belongs in the package's own `_redirects`:
|
|
907
|
+
|
|
908
|
+
```text
|
|
909
|
+
# _redirects
|
|
910
|
+
/sohl/ /sohl/homepage-root/ 301
|
|
911
|
+
/sohl /sohl/homepage-root/ 301
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
Both forms, because Cloudflare Pages matches the raw path: redirect matching
|
|
915
|
+
runs before any trailing-slash or `index.html` handling, so `/sohl` and `/sohl/`
|
|
916
|
+
are distinct keys and a rule on one does not catch the other. A redirect also
|
|
917
|
+
**wins over a static asset at the same path** — _"Redirects are always followed,
|
|
918
|
+
regardless of whether or not an asset matches the incoming request"_ — so the
|
|
919
|
+
rule fires whatever else happens to be published there.
|
|
920
|
+
|
|
921
|
+
**The 301 carries a pinned lifetime**, and that is the part worth being
|
|
922
|
+
deliberate about:
|
|
923
|
+
|
|
924
|
+
```text
|
|
925
|
+
# _headers
|
|
926
|
+
/sohl/
|
|
927
|
+
Cache-Control: max-age=3600
|
|
928
|
+
/sohl
|
|
929
|
+
Cache-Control: max-age=3600
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
Cloudflare Pages sets **no** `Cache-Control` on a redirect it generates — its
|
|
933
|
+
redirect responses carry `location` and nothing else — and a 301 with no
|
|
934
|
+
`Cache-Control` is cacheable indefinitely by default under RFC 9111. Browsers
|
|
935
|
+
persist one to disk and stop asking the server, so a scheme that later changed
|
|
936
|
+
would strand every returning visitor on the package's most-linked URL. An
|
|
937
|
+
explicit `Cache-Control` overrides that heuristic and keeps the 301's canonical
|
|
938
|
+
signal without the permanence.
|
|
939
|
+
|
|
940
|
+
**`_headers` does apply to a `_redirects` response, and this is verified rather
|
|
941
|
+
than documented.** Cloudflare's docs say only that _"redirects are applied
|
|
942
|
+
before headers, so when a request matches both a redirect and a header, the
|
|
943
|
+
redirect takes priority"_ — a sentence routinely misread as "headers are skipped
|
|
944
|
+
on a redirect". Its open-source asset server settles it: the redirect response
|
|
945
|
+
returns from `generateResponse()` and then flows through `attachHeaders()`, and
|
|
946
|
+
the only short-circuit past that is `status >= 500`. The one documented "headers
|
|
947
|
+
are not applied" carve-out is Pages Functions, not redirects.
|
|
948
|
+
|
|
949
|
+
Because that is observed behaviour rather than a documented guarantee, **verify
|
|
950
|
+
it once after deploying** and treat a regression as a Cloudflare change rather
|
|
951
|
+
than a content bug:
|
|
952
|
+
|
|
953
|
+
```bash
|
|
954
|
+
curl -sSI https://www.heroiclands.org/sohl/ | grep -i 'location\|cache-control'
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
If it ever stops holding, the documented alternative is a zone-level **Response
|
|
958
|
+
Header Transform Rule** (or Bulk Redirects, which sets both), not a Pages
|
|
959
|
+
Function — `_redirects` and `_headers` both stop applying to a route a Function
|
|
960
|
+
serves.
|
|
856
961
|
|
|
857
962
|
### The homepage's own links
|
|
858
963
|
|
|
@@ -1077,6 +1182,40 @@ vendored by other repositories and read as authoritative, so emitting one is a
|
|
|
1077
1182
|
statement about this package. With the switch off the command fails rather than
|
|
1078
1183
|
writing.
|
|
1079
1184
|
|
|
1185
|
+
### A page's URL is its address
|
|
1186
|
+
|
|
1187
|
+
```text
|
|
1188
|
+
/<package>/<type>-<shortcode>/
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
`(type, shortcode)` names one note within a package — that is the rule
|
|
1192
|
+
`content-build lint` enforces — so the URL is **unique by construction**. There
|
|
1193
|
+
is no collision check behind it, there never can be one to fail, and renaming a
|
|
1194
|
+
note changes nothing: no part of the address comes from a display string.
|
|
1195
|
+
|
|
1196
|
+
It used to come from `name.full`. That made a display name load-bearing three
|
|
1197
|
+
ways at once — a rename silently 404'd every inbound link, two notes in one
|
|
1198
|
+
section could derive the same URL so a uniqueness gate had to run, and long names
|
|
1199
|
+
had to be shortened through a table of 200 abbreviations. The header of the
|
|
1200
|
+
module doing it justified the cost by promising redirects "every change appends
|
|
1201
|
+
to the legacy-URL map" — and no such map was ever written, here or in any
|
|
1202
|
+
consumer. All of it is gone (#181).
|
|
1203
|
+
|
|
1204
|
+
The `type-` half earns its place: it keeps every content address clear of the
|
|
1205
|
+
package's fixed mounts (`/<package>/` for the landing page, `/<package>/api/` for
|
|
1206
|
+
generated API docs), neither of which contains a hyphen or names a type. So the
|
|
1207
|
+
namespace is provably disjoint rather than conventionally so.
|
|
1208
|
+
|
|
1209
|
+
**Sections stay, as directories.** Hugo derives a page's section from where the
|
|
1210
|
+
file is written, not from its URL, and that section is what gives a landing page,
|
|
1211
|
+
`.CurrentSection` and the per-section layout lookup. So a page is still written
|
|
1212
|
+
into `<section>/`, and carries a front-matter `url:` publishing it at its
|
|
1213
|
+
address. The two are free to differ, and do.
|
|
1214
|
+
|
|
1215
|
+
**A landing page is the one exception**, because it is not addressed by
|
|
1216
|
+
`(type, shortcode)` at all: it _is_ its section, so it addresses the section —
|
|
1217
|
+
under the content mount, where the section directories live (`kb/rules/`).
|
|
1218
|
+
|
|
1080
1219
|
### The address scheme
|
|
1081
1220
|
|
|
1082
1221
|
Where the content tree mounts _inside the package_, and which note addresses a
|
|
@@ -1095,14 +1234,15 @@ publish:
|
|
|
1095
1234
|
landing: readme # default: readme
|
|
1096
1235
|
```
|
|
1097
1236
|
|
|
1098
|
-
- **`prefix`** — the content tree's mount within the package
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1237
|
+
- **`prefix`** — the content tree's mount within the package: where its section
|
|
1238
|
+
directories and their landing pages live. `sohl` publishes a knowledgebase
|
|
1239
|
+
alongside generated API docs, so its sections sit under `kb/` (`kb/affliction/`)
|
|
1240
|
+
while its pages address the package root (`affliction-aconite/`); `thalorna`'s
|
|
1241
|
+
site is nothing but its content, so it has no prefix. It must end in a slash and
|
|
1102
1242
|
must not begin with one — where the _package_ is mounted is the consuming
|
|
1103
1243
|
build's knowledge and is never recorded here.
|
|
1104
|
-
- **`landing`** — which note is a section's landing page, and so
|
|
1105
|
-
|
|
1244
|
+
- **`landing`** — which note is a section's landing page, and so is addressed by
|
|
1245
|
+
the section rather than by `(type, shortcode)`:
|
|
1106
1246
|
- `readme` — a `README.md` addresses its section. A `doc` note then routes by
|
|
1107
1247
|
its `category` like any other, so a `category: collection` note publishes
|
|
1108
1248
|
under a literal `collection/` section.
|
|
@@ -1112,8 +1252,9 @@ publish:
|
|
|
1112
1252
|
The two are alternatives rather than a pair that could both apply: each live
|
|
1113
1253
|
content tree holds notes the other rule would move.
|
|
1114
1254
|
|
|
1115
|
-
A note the scheme yields no address for —
|
|
1116
|
-
|
|
1255
|
+
A note the scheme yields no address for — one carrying no `shortcode`, a `doc`
|
|
1256
|
+
with no subtype (so no section to be filed under), a collection note naming no
|
|
1257
|
+
section — is **reported and omitted**, never guessed. The command
|
|
1117
1258
|
prints one located diagnostic per note and still writes the file, because a note
|
|
1118
1259
|
with no address is ordinary while a manifest entry pointing at a page that does
|
|
1119
1260
|
not exist is not.
|
|
@@ -1140,6 +1281,7 @@ written by a person:
|
|
|
1140
1281
|
```markdown
|
|
1141
1282
|
---
|
|
1142
1283
|
type: homepage
|
|
1284
|
+
shortcode: root
|
|
1143
1285
|
title: HârnMaster Kethira Basic # optional; defaults to packageBuild.manifest.title
|
|
1144
1286
|
---
|
|
1145
1287
|
|
|
@@ -1151,9 +1293,13 @@ A package declares **exactly one** of these, and both `content-build lint` and
|
|
|
1151
1293
|
[Exactly one homepage](#exactly-one-homepage).
|
|
1152
1294
|
|
|
1153
1295
|
That is the whole envelope. A homepage **compiles into no compendium
|
|
1154
|
-
document**, appears in no pack and in no link manifest
|
|
1155
|
-
|
|
1156
|
-
|
|
1296
|
+
document**, and so appears in no pack and in no link manifest — which is why it
|
|
1297
|
+
still refuses `id`. Everything else about its address is ordinary: it declares a
|
|
1298
|
+
`shortcode`, publishes at `/<contentPackage>/homepage-root/`, and is cited as
|
|
1299
|
+
`[[homepage-root|Text]]` (#182 — see
|
|
1300
|
+
[The homepage is addressed like every other note](#the-homepage-is-addressed-like-every-other-note)).
|
|
1301
|
+
`/<contentPackage>/` itself is a redirect the package authors, not a page this
|
|
1302
|
+
build writes. It is dispatched on `type` like every other note, not on a
|
|
1157
1303
|
filename: `README.md` is already a section landing under `landing: readme`, and
|
|
1158
1304
|
in `sohl-thalorna` it is a developer explainer about the source tree.
|
|
1159
1305
|
|
|
@@ -1189,9 +1335,11 @@ That is separate from `publish.manifests.publish`, which stays off for both for
|
|
|
1189
1335
|
an unrelated reason: a link manifest is the dependency edge that would stop the
|
|
1190
1336
|
module being withdrawable, and a homepage is one row in a routing table.
|
|
1191
1337
|
|
|
1192
|
-
The homepage is written at the root of `site.out` — the package's own
|
|
1193
|
-
one level above the content mount, which is where
|
|
1194
|
-
everything else
|
|
1338
|
+
The homepage's file is written at the root of `site.out` — the package's own
|
|
1339
|
+
site root, one level above the content mount, which is where
|
|
1340
|
+
`publish.address.prefix` puts everything else — under the name its address gives
|
|
1341
|
+
it, `homepage-root.md`. As with every other page, the file's location decides
|
|
1342
|
+
the Hugo section and the front matter's `url` decides where it publishes.
|
|
1195
1343
|
|
|
1196
1344
|
**What it does not do is decide addresses.** Those come from `publish.address`,
|
|
1197
1345
|
the same setting the link manifest reads, so a page and its manifest entry cannot
|
|
@@ -1320,8 +1468,7 @@ after the links that failed because of it reads as a pile of broken notes.
|
|
|
1320
1468
|
| Gate | What it catches |
|
|
1321
1469
|
| ---------------------- | ---------------------------------------------------------------------------------- |
|
|
1322
1470
|
| Frontmatter wikilinks | A link in frontmatter, which is copied verbatim and reaches the reader as `[[…]]`. |
|
|
1323
|
-
|
|
|
1324
|
-
| Collisions | Two notes claiming one page URL. |
|
|
1471
|
+
| Addresses | A note with no shortcode to be addressed by, or no section to be filed under. |
|
|
1325
1472
|
| Unusable manifest | A vendored manifest this build cannot read. |
|
|
1326
1473
|
| Unaddressable manifest | One it can read but cannot look anything up in. |
|
|
1327
1474
|
| Package conflicts | One address claimed by two packages. |
|
|
@@ -1404,7 +1551,7 @@ form every C-family compiler, `tsc` and ESLint already use, so an editor, a CI
|
|
|
1404
1551
|
annotator or a `grep` parses it with no knowledge of this build:
|
|
1405
1552
|
|
|
1406
1553
|
```text
|
|
1407
|
-
assets/content/Regions/Capital_Nome.md:43:635:
|
|
1554
|
+
assets/content/Regions/Capital_Nome.md:43:635: error: address [[place-kenbetpat]] resolves to no note — no package publishes it. Fix the shortcode, or vendor the link manifest of the package that does — in "The Capital Nome".
|
|
1408
1555
|
```
|
|
1409
1556
|
|
|
1410
1557
|
`file:line:column: severity: message`. The path is relative to the working
|
package/MIGRATING.md
CHANGED
|
@@ -1,3 +1,67 @@
|
|
|
1
|
+
# Migrating to `@heroiclands/package-build` 11.0.0
|
|
2
|
+
|
|
3
|
+
**Two edits, and the second is one line per repository.** Every published page
|
|
4
|
+
moves to its address (#181), and the package homepage becomes an ordinary
|
|
5
|
+
addressed note (#182).
|
|
6
|
+
|
|
7
|
+
## 1. A page's URL is its address
|
|
8
|
+
|
|
9
|
+
Every content page now serves at `/<package>/<type>-<shortcode>/` rather than at
|
|
10
|
+
a slug derived from `name.full`. No content edit is required for it — the
|
|
11
|
+
address is computed from fields every note already declares — but **every
|
|
12
|
+
published URL moves**, so anything holding one (an external link, a bookmark, a
|
|
13
|
+
citation in another repository) has to be re-derived.
|
|
14
|
+
|
|
15
|
+
## 2. Give the homepage a `shortcode`
|
|
16
|
+
|
|
17
|
+
The homepage used to **refuse** `shortcode` and `name`, because a URL derived
|
|
18
|
+
from a display name while a homepage's destination was fixed. That premise is
|
|
19
|
+
gone, so both fields are permitted and `shortcode` is **required**:
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
---
|
|
23
|
+
type: homepage
|
|
24
|
+
shortcode: root
|
|
25
|
+
title: HârnMaster Kethira Basic
|
|
26
|
+
---
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`root` is the convention, not a rule. Without one, `content-build lint` and
|
|
30
|
+
`content-build site` both refuse the note:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
assets/content/homepage.md:3:7: error: a `type: homepage` note declares a `shortcode`, like every other note: it is addressed as `homepage-<shortcode>` and published at `/<package>/homepage-<shortcode>/`, which is where `[[homepage-<shortcode>|Text]]` lands. Write `shortcode: root` — the package landing is `homepage-root` in every package
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`id` is still refused, on ground this does not touch: a homepage compiles into
|
|
37
|
+
no compendium document.
|
|
38
|
+
|
|
39
|
+
## 3. Author the `/<package>/` redirect
|
|
40
|
+
|
|
41
|
+
The landing is published at `/<package>/homepage-root/`, and nothing is written
|
|
42
|
+
at `/<package>/` any more. Add the redirect to the repository's own
|
|
43
|
+
`_redirects`, and pin its lifetime in `_headers` — Cloudflare Pages sets no
|
|
44
|
+
`Cache-Control` on a redirect it generates, and an unpinned 301 is cacheable
|
|
45
|
+
indefinitely:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
# _redirects
|
|
49
|
+
/sohl/ /sohl/homepage-root/ 301
|
|
50
|
+
/sohl /sohl/homepage-root/ 301
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
# _headers
|
|
55
|
+
/sohl/
|
|
56
|
+
Cache-Control: max-age=3600
|
|
57
|
+
/sohl
|
|
58
|
+
Cache-Control: max-age=3600
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Both path forms, because Pages matches the raw path and `/sohl` and `/sohl/` are
|
|
62
|
+
distinct keys. See `CONTENT.md` for why the pairing works and how to verify it
|
|
63
|
+
after a deploy.
|
|
64
|
+
|
|
1
65
|
# Migrating to `@heroiclands/package-build` 6.0.0
|
|
2
66
|
|
|
3
67
|
**No configuration change to make, and one build check that may now fail.**
|