@heroiclands/package-build 22.3.1 → 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 +47 -0
- package/CONTENT.md +182 -306
- package/bin/content-build.mjs +15 -20
- package/bin/package-build.mjs +4 -3
- package/content-config.mjs +70 -179
- package/docs/api.md +27 -32
- package/docs/commands.md +31 -19
- package/docs/configuration.md +90 -126
- 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 +7 -1
- 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 +6 -8
- package/types/engine/content-links.d.mts +12 -23
- package/types/engine/diagnostics.d.mts +2 -2
- 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/docs/configuration.md
CHANGED
|
@@ -758,36 +758,54 @@ Any other key under `docs.itemFields` is refused:
|
|
|
758
758
|
|
|
759
759
|
**Type:** object · **Optional** · every key defaults to nothing published:
|
|
760
760
|
|
|
761
|
-
| Key
|
|
762
|
-
|
|
|
763
|
-
| `site.base`
|
|
764
|
-
| `site.assets`
|
|
765
|
-
| `site.description`
|
|
766
|
-
| `site.packages`
|
|
767
|
-
| `site.
|
|
768
|
-
| `site.
|
|
769
|
-
| `site.
|
|
770
|
-
| `site.
|
|
771
|
-
| `site.backfillSections` | boolean | `false` |
|
|
772
|
-
| `site.list` | object | `{shortcodes: false}` |
|
|
773
|
-
| `site.notfound` | object | `null` |
|
|
774
|
-
| `site.hugo` | object | `{}` |
|
|
761
|
+
| Key | Type | Default |
|
|
762
|
+
| ------------------ | -------- | ------------------------------------------- |
|
|
763
|
+
| `site.base` | string | `""` |
|
|
764
|
+
| `site.assets` | string | `""`, but required for `content-build site` |
|
|
765
|
+
| `site.description` | string | `""`, but required for `content-build site` |
|
|
766
|
+
| `site.packages` | string[] | `[]` |
|
|
767
|
+
| `site.pass` | string | `""` |
|
|
768
|
+
| `site.passOptions` | object | `{}` |
|
|
769
|
+
| `site.notfound` | object | `null` |
|
|
770
|
+
| `site.hugo` | object | `{}` |
|
|
775
771
|
|
|
776
772
|
How much of a package reaches the web at all is **not** here — it is
|
|
777
|
-
[`publish.site`](#publish). `site` is framing:
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
773
|
+
[`publish.site`](#publish). `site` is framing: which named pass bundle
|
|
774
|
+
supplies the repository's own body rewrites, and the residue of the
|
|
775
|
+
[generated Hugo configuration](#the-generated-hugo-configuration) that is
|
|
776
|
+
genuinely this repository's own.
|
|
781
777
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
778
|
+
**A site is its homepage and its pages.** The `type: homepage` note is the
|
|
779
|
+
package's front page at `/<contentPackage>/`, and every other note is one page
|
|
780
|
+
at `/<contentPackage>/<type>-<shortcode>/`. Nothing is generated between
|
|
781
|
+
them: no section directory, no listing of a type, no tag page. Every
|
|
782
|
+
structure above the pages — which notes belong together, in what order,
|
|
783
|
+
under which headings — is authored, as a `doc` note carrying a content table
|
|
784
|
+
over the content index, and linked from the homepage like any other page.
|
|
787
785
|
|
|
788
|
-
|
|
786
|
+
So a page of documentation is a note — `type: doc`, addressed by its
|
|
787
|
+
shortcode, and `pack: none` where it compiles into no Foundry document — and
|
|
788
|
+
there is no second mechanism for mounting a directory of markdown. A
|
|
789
|
+
configuration that names one is refused with a message saying where the page
|
|
790
|
+
goes instead:
|
|
789
791
|
|
|
790
|
-
> ``package-build config: `site.
|
|
792
|
+
> ``package-build config: `site.trees` is retired — a page is a note in the content tree. Give each page `type: doc`, a `shortcode` and `pack: none`, file it under `assets/content/`, and link it from the homepage or from a `doc` note that indexes it.``
|
|
793
|
+
|
|
794
|
+
> ``package-build config: `site.readmeSections` is retired — a page is a note in the content tree. Give each page `type: doc`, a `shortcode` and `pack: none`, file it under `assets/content/`, and link it from the homepage or from a `doc` note that indexes it.``
|
|
795
|
+
|
|
796
|
+
A configuration that asks the build to generate an index between the
|
|
797
|
+
homepage and the pages is refused the same way, by name and with one message
|
|
798
|
+
— `site.sections` (and the `listType` / `listSubType` an entry carried),
|
|
799
|
+
`site.landing`, `site.backfillSections` and `site.list` alike, since how a
|
|
800
|
+
listing renders is a content table's to say:
|
|
801
|
+
|
|
802
|
+
> ``package-build config: `site.sections` is retired — a site is its homepage and its pages, and any index between them is a `doc` note: write one with `type: doc`, a `shortcode` and `pack: none`, carrying a content table over the notes it lists, and link it from the homepage. Nothing is generated between the homepage and the pages, so delete the key.``
|
|
803
|
+
|
|
804
|
+
> ``package-build config: `site.landing` is retired — a site is its homepage and its pages, and any index between them is a `doc` note: write one with `type: doc`, a `shortcode` and `pack: none`, carrying a content table over the notes it lists, and link it from the homepage. Nothing is generated between the homepage and the pages, so delete the key.``
|
|
805
|
+
|
|
806
|
+
> ``package-build config: `site.backfillSections` is retired — a site is its homepage and its pages, and any index between them is a `doc` note: write one with `type: doc`, a `shortcode` and `pack: none`, carrying a content table over the notes it lists, and link it from the homepage. Nothing is generated between the homepage and the pages, so delete the key.``
|
|
807
|
+
|
|
808
|
+
> ``package-build config: `site.list` is retired — a site is its homepage and its pages, and any index between them is a `doc` note: write one with `type: doc`, a `shortcode` and `pack: none`, carrying a content table over the notes it lists, and link it from the homepage. Nothing is generated between the homepage and the pages, so delete the key.``
|
|
791
809
|
|
|
792
810
|
Where the Hugo tree is written is not a choice. `content-build site` writes
|
|
793
811
|
the whole Hugo source tree under `build/hugo/` — the generated `hugo.toml`,
|
|
@@ -799,7 +817,7 @@ published. A `site.out` is refused by name:
|
|
|
799
817
|
|
|
800
818
|
> ``package-build config: `site` must be a mapping.``
|
|
801
819
|
|
|
802
|
-
> ``package-build config: `site.<key>` is not a recognized option (expected one of: base, assets, description, packages,
|
|
820
|
+
> ``package-build config: `site.<key>` is not a recognized option (expected one of: base, assets, description, packages, pass, passOptions, notfound, hugo).``
|
|
803
821
|
|
|
804
822
|
`site.assets` is the host every package's imagery is served from, and it is
|
|
805
823
|
the one address in this file that is not this repository's own. A note names
|
|
@@ -845,62 +863,8 @@ names a registry):
|
|
|
845
863
|
|
|
846
864
|
> ``package-build config: `site.packages[<index>]` must be a non-empty string.``
|
|
847
865
|
|
|
848
|
-
`site.
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
| Key (under `site.sections.<name>`) | Type | Required | Default |
|
|
852
|
-
| ---------------------------------- | -------------------------- | -------- | ------- |
|
|
853
|
-
| `site.sections.<name>.title` | string | yes | — |
|
|
854
|
-
| `site.sections.<name>.banner` | string | no | none |
|
|
855
|
-
| `site.sections.<name>.description` | string | no | none |
|
|
856
|
-
| `site.sections.<name>.listType` | string, an address segment | no | none |
|
|
857
|
-
| `site.sections.<name>.listSubType` | string, an address segment | no | none |
|
|
858
|
-
|
|
859
|
-
> ``package-build config: `site.sections.<name>` must be a mapping.``
|
|
860
|
-
|
|
861
|
-
> ``package-build config: `site.sections.<name>.title` must be a non-empty string.``
|
|
862
|
-
|
|
863
|
-
`listType` / `listSubType` say what the section **lists** — a content type
|
|
864
|
-
and subType, which are address segments and therefore checked against
|
|
865
|
-
`^[a-z0-9]+$`, deliberately distinct from the section's own name (a URL
|
|
866
|
-
this site chose; `user-guide` is the section, `userguide` the subType):
|
|
867
|
-
|
|
868
|
-
> ``package-build config: `site.sections.<name>.listType` is `Not Ok`, which is not lowercase alphanumeric. It names a content type or subType, and those are address segments (^[a-z0-9]+$) — not the section's own name, which is a URL this site chose and need not match (`user-guide` is the section, `userguide` the subType). A value no page carries selects nothing and leaves the landing empty.``
|
|
869
|
-
|
|
870
|
-
`listSubType` alone, without `listType`, names no query — a subType only
|
|
871
|
-
distinguishes _within_ a type:
|
|
872
|
-
|
|
873
|
-
> ``package-build config: `site.sections.<name>.listSubType` is declared without a `listType`. A subType tells pages apart only within a type — `rules`, `userguide` and `reference` are all `doc` — so on its own it names no query for a layout to run.``
|
|
874
|
-
|
|
875
|
-
Any other key on a section entry is refused:
|
|
876
|
-
|
|
877
|
-
> ``package-build config: `site.sections.<name>.<key>` is not a recognized option (expected one of: title, banner, description, listType, listSubType).``
|
|
878
|
-
|
|
879
|
-
`site.landing` is different from a section entry — it is the mount's own
|
|
880
|
-
landing page frontmatter, passed through verbatim to Hugo rather than
|
|
881
|
-
validated field by field, since its vocabulary is the theme's and not this
|
|
882
|
-
package's:
|
|
883
|
-
|
|
884
|
-
> ``package-build config: `site.landing` must be a mapping.``
|
|
885
|
-
|
|
886
|
-
`site.passOptions` and `site.backfillSections` have no further shape of
|
|
887
|
-
their own — `passOptions` is passed to the resolved `site.pass` bundle
|
|
888
|
-
unchanged, and `backfillSections` is a plain boolean:
|
|
889
|
-
|
|
890
|
-
> ``package-build config: `site.backfillSections` must be a boolean.``
|
|
891
|
-
|
|
892
|
-
`site.list` is how a listing page renders, written into the generated Hugo
|
|
893
|
-
configuration as `params.list`:
|
|
894
|
-
|
|
895
|
-
| Key | Type | Required | Default |
|
|
896
|
-
| ---------------------- | ------- | -------- | ------- |
|
|
897
|
-
| `site.list.shortcodes` | boolean | no | `false` |
|
|
898
|
-
|
|
899
|
-
> ``package-build config: `site.list` must be a mapping.``
|
|
900
|
-
|
|
901
|
-
> ``package-build config: `site.list.shortcodes` must be a boolean.``
|
|
902
|
-
|
|
903
|
-
> ``package-build config: `site.list.<key>` is not a recognized option (expected one of: shortcodes).``
|
|
866
|
+
`site.passOptions` has no further shape of its own — it is passed to the
|
|
867
|
+
resolved `site.pass` bundle unchanged.
|
|
904
868
|
|
|
905
869
|
`site.notfound` is the wording of the "page not found" page, written into
|
|
906
870
|
the generated Hugo configuration as `params.notfound`. The theme renders
|
|
@@ -972,26 +936,25 @@ the block cannot grow into a second configuration file:
|
|
|
972
936
|
`content-build site` writes `build/hugo/hugo.toml` on every run. Every value
|
|
973
937
|
in it has one source, and that source is where it is edited:
|
|
974
938
|
|
|
975
|
-
| Key | Derived from
|
|
976
|
-
| --------------------------------- |
|
|
977
|
-
| `baseURL` | `package.json` `homepage`, checked by `checkHomepage` — an absolute URL ending `/<contentPackage>/`
|
|
978
|
-
| `title` | `packageBuild.manifest.title`, which is required
|
|
979
|
-
| `locale` | the organisation's locale, `en-us`, in `engine/site-config.mjs`
|
|
980
|
-
| `publishDir` | `contentPackage`, under the deployment root `build/site` — written relative to `build/hugo/`, so `../site/<contentPackage>`
|
|
981
|
-
| `contentDir` | the fixed content mount, `build/hugo/content` — written as `content`
|
|
982
|
-
| `themesDir` | where `@heroiclands/hugo-theme` is installed, resolved the way Node resolves a package and written relative to `build/hugo/`
|
|
983
|
-
| `theme` | the installed `@heroiclands/hugo-theme`, so `hugo-theme`
|
|
984
|
-
| `disableKinds` |
|
|
985
|
-
| `taxonomies` | the
|
|
986
|
-
| `outputs` | the
|
|
987
|
-
| `params.description` | `site.description`, which is required
|
|
988
|
-
| `params.author` | `package.json` `author`, its `name`; absent when the package declares none
|
|
989
|
-
| `params.cdnBaseURL` | `site.assets`, which is required
|
|
990
|
-
| `params.brand` | the organisation's brand links — `logo`, `licenseURL`, `discordURL` — in `engine/site-config.mjs`
|
|
991
|
-
| `params.
|
|
992
|
-
| `
|
|
993
|
-
| `
|
|
994
|
-
| `menu` | the navigation `content-build deps fetch` caches from `https://www.heroiclands.org/nav.json`, entry for entry, a dropdown's entries as `parent` entries |
|
|
939
|
+
| Key | Derived from |
|
|
940
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
941
|
+
| `baseURL` | `package.json` `homepage`, checked by `checkHomepage` — an absolute URL ending `/<contentPackage>/` |
|
|
942
|
+
| `title` | `packageBuild.manifest.title`, which is required |
|
|
943
|
+
| `locale` | the organisation's locale, `en-us`, in `engine/site-config.mjs` |
|
|
944
|
+
| `publishDir` | `contentPackage`, under the deployment root `build/site` — written relative to `build/hugo/`, so `../site/<contentPackage>` |
|
|
945
|
+
| `contentDir` | the fixed content mount, `build/hugo/content` — written as `content` |
|
|
946
|
+
| `themesDir` | where `@heroiclands/hugo-theme` is installed, resolved the way Node resolves a package and written relative to `build/hugo/` |
|
|
947
|
+
| `theme` | the installed `@heroiclands/hugo-theme`, so `hugo-theme` |
|
|
948
|
+
| `disableKinds` | the toolchain, which renders a site as its homepage and its pages: `["section", "taxonomy", "term", "RSS"]` on every site, whatever its notes carry |
|
|
949
|
+
| `taxonomies` | the toolchain — never written, because `taxonomy` and `term` are disabled kinds |
|
|
950
|
+
| `outputs` | the toolchain — never written, because every listing kind is disabled |
|
|
951
|
+
| `params.description` | `site.description`, which is required |
|
|
952
|
+
| `params.author` | `package.json` `author`, its `name`; absent when the package declares none |
|
|
953
|
+
| `params.cdnBaseURL` | `site.assets`, which is required |
|
|
954
|
+
| `params.brand` | the organisation's brand links — `logo`, `licenseURL`, `discordURL` — in `engine/site-config.mjs` |
|
|
955
|
+
| `params.notfound` | `site.notfound`; absent when undeclared |
|
|
956
|
+
| `markup.goldmark.renderer.unsafe` | the toolchain, whose pages carry raw HTML — a `<figure>` for every image, a `<span>` marking an unresolved link |
|
|
957
|
+
| `menu` | the navigation `content-build deps fetch` caches from `https://www.heroiclands.org/nav.json`, entry for entry, a dropdown's entries as `parent` entries |
|
|
995
958
|
|
|
996
959
|
The site build reads the navigation from the cache only. A cold cache is an
|
|
997
960
|
error naming the command that fills it:
|
|
@@ -1018,13 +981,13 @@ build the same way:
|
|
|
1018
981
|
|
|
1019
982
|
> ``package-build config: `site.assets` is not declared, and a site build needs one — it is the host every package's imagery is served from, and the theme resolves every relative asset against it.``
|
|
1020
983
|
|
|
1021
|
-
Nothing else is emitted.
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
984
|
+
Nothing else is emitted. `home` and `page` are the only kinds a site
|
|
985
|
+
renders: the homepage is the mount's `_index.md`, every note is a page, and
|
|
986
|
+
`section`, `taxonomy`, `term` and `RSS` are disabled on every site — so no
|
|
987
|
+
`[taxonomies]` or `[outputs]` is written, Hugo's default taxonomy pair never
|
|
988
|
+
applies, and a note's `tags:` reach the page's front matter and nothing
|
|
989
|
+
else. A tag is a field a content table filters on, not a page of its own.
|
|
990
|
+
Every other key is `site.hugo`'s to add.
|
|
1028
991
|
|
|
1029
992
|
### `pdf`
|
|
1030
993
|
|
|
@@ -1332,9 +1295,8 @@ its content tree's addresses mount inside the package.
|
|
|
1332
1295
|
Every HeroicLands package publishes at least an authored homepage at
|
|
1333
1296
|
`https://www.heroiclands.org/<contentPackage>/` — there is no value meaning
|
|
1334
1297
|
_no web presence at all_. `homepage` is the floor: the authored homepage
|
|
1335
|
-
and nothing else, no content-tree walk
|
|
1336
|
-
|
|
1337
|
-
publishes. `publishesContentPages(config)`, exported from
|
|
1298
|
+
and nothing else, no content-tree walk. `content` is the homepage plus every
|
|
1299
|
+
page the content tree publishes. `publishesContentPages(config)`, exported from
|
|
1338
1300
|
`content-config.mjs` alongside [`compilesFoundryDocuments`](#packagekind),
|
|
1339
1301
|
answers the one question every reader of the mode actually asks — the site
|
|
1340
1302
|
build, to decide whether to walk the tree at all, and the content index, to
|
|
@@ -1706,17 +1668,19 @@ the source directory:
|
|
|
1706
1668
|
|
|
1707
1669
|
## Every retired or forbidden key, in one place
|
|
1708
1670
|
|
|
1709
|
-
| Key
|
|
1710
|
-
|
|
|
1711
|
-
| `publish.address.landing`
|
|
1712
|
-
| `packs[].folders`
|
|
1713
|
-
| `rootDir`
|
|
1714
|
-
| `foundryPackage`
|
|
1715
|
-
| `homepage`, `author`
|
|
1716
|
-
| `stats.systemId`
|
|
1717
|
-
| `stats.systemVersion`
|
|
1718
|
-
| `packageBuild.manifest.id`, `.version`, `.description`, `.url`, `.bugs`, `.manifest`, `.download`, `.compatibility`, `.relationships`, `.packs`
|
|
1719
|
-
| `site.out`
|
|
1720
|
-
| `site.
|
|
1721
|
-
| `
|
|
1722
|
-
| `
|
|
1671
|
+
| Key | Why |
|
|
1672
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1673
|
+
| `publish.address.landing` | Retired — named a whole-section landing, and there are no sections to address. |
|
|
1674
|
+
| `packs[].folders` | Retired — a folder is a note (`type: folder`), materialised by the pack whose documents reference it. |
|
|
1675
|
+
| `rootDir` | Forbidden in a YAML configuration — always the file's own directory. |
|
|
1676
|
+
| `foundryPackage` | Forbidden in a YAML configuration — always the adjacent `package.json` `name`. |
|
|
1677
|
+
| `homepage`, `author` | Forbidden in a YAML configuration — always the adjacent `package.json`'s own `homepage` and `author`. |
|
|
1678
|
+
| `stats.systemId` | Forbidden in every configuration — derived from `packageKind`, `requiresSystem` or a lone declared system. |
|
|
1679
|
+
| `stats.systemVersion` | Forbidden in every configuration — derived from `package.json` (a system) or `systems:` / `relationships.systems` (a module). |
|
|
1680
|
+
| `packageBuild.manifest.id`, `.version`, `.description`, `.url`, `.bugs`, `.manifest`, `.download`, `.compatibility`, `.relationships`, `.packs` | Forbidden — each is derived from `package.json` or the top level of `package-build.config.yaml`; see [`packageBuild.manifest`](#packagebuildmanifest). |
|
|
1681
|
+
| `site.out` | Retired — the site build writes its content mount at `build/hugo/content`, beside the generated `hugo.toml`. |
|
|
1682
|
+
| `site.trees`, `site.readmeSections` | Retired — a page is a note in the content tree. |
|
|
1683
|
+
| `site.sections`, `site.landing`, `site.backfillSections`, `site.list` | Retired — a site is its homepage and its pages, and any index between them is a `doc` note. |
|
|
1684
|
+
| `site.hugo.baseURL`, `.title`, `.locale`, `.publishDir`, `.contentDir`, `.themesDir`, `.theme`, `.disableKinds`, `.taxonomies`, `.outputs`, `.params.description`, `.params.author`, `.params.cdnBaseURL`, `.params.brand`, `.params.notfound`, `.markup.goldmark.renderer.unsafe`, `.menu` | Forbidden — each is written by the site build from a source it names; see [the generated Hugo configuration](#the-generated-hugo-configuration). |
|
|
1685
|
+
| `publish.site: true` / `publish.site: false` | Refused rather than mapped — write `homepage` or `content`. |
|
|
1686
|
+
| `packs`, `itemBuilders`, `docs`, `compatibility`, `relationships`, `systems`, `requiresSystem`, `stats`, `foundryPackage` | Forbidden in a `documentation` package — each describes a Foundry package this kind is not; see the key's own section for its located refusal message. |
|
package/docs/content-format.md
CHANGED
|
@@ -2249,11 +2249,26 @@ A SoHL "being" document will be created, as will an "HM3" document.
|
|
|
2249
2249
|
|
|
2250
2250
|
### type: homepage
|
|
2251
2251
|
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
It
|
|
2252
|
+
The package's front page, published at `https://www.heroiclands.org/<package>/`.
|
|
2253
|
+
Exactly one note in a content tree declares this type, and it compiles into
|
|
2254
|
+
no Foundry document: it is a page and nothing else.
|
|
2255
|
+
|
|
2256
|
+
It declares a `shortcode` — conventionally `root` — because that is what a
|
|
2257
|
+
link is written with: `[[homepage-root|Text]]` is an ordinary wikilink, and it
|
|
2258
|
+
resolves to `/<package>/`. The shortcode names the page in links; its address
|
|
2259
|
+
is the package root. `title` defaults to `packageBuild.manifest.title`; a
|
|
2260
|
+
`description` and a `banner` are read by the theme's hero; any other
|
|
2261
|
+
top-level key is passed through to the page as a theme parameter.
|
|
2262
|
+
|
|
2263
|
+
The page is its body, published verbatim: no wikilink is resolved on it and
|
|
2264
|
+
no table expanded, so its links are markdown links, package-relative
|
|
2265
|
+
(`kb/rules/`) or external. An index of what the package publishes is not
|
|
2266
|
+
written here and is not generated anywhere — it is a `doc` note carrying a
|
|
2267
|
+
content table, linked from this page like any other.
|
|
2268
|
+
|
|
2269
|
+
Two top-level keys are refused, because neither decides anything on a page:
|
|
2270
|
+
`id`, the Foundry document id a compendium UUID is built from, and `landing`,
|
|
2271
|
+
a card block — the homepage is a page with a body, rendered as one.
|
|
2257
2272
|
|
|
2258
2273
|
### type: vehicle
|
|
2259
2274
|
|
|
@@ -3137,21 +3152,16 @@ any other, and the audience is the section it sits in.
|
|
|
3137
3152
|
Write `type: doc`, `subType: reference`, `shortcode: <type>` — so the
|
|
3138
3153
|
affiliations introduction is `doc-affiliation`, addressed and linked like
|
|
3139
3154
|
anything else, and typically carrying a generated table of what it introduces.
|
|
3140
|
-
It has no build path of its own
|
|
3141
|
-
|
|
3155
|
+
It has no build path of its own, and it is the only kind of index there is: a
|
|
3156
|
+
site is its homepage and its pages, and nothing is generated between them.
|
|
3142
3157
|
|
|
3143
|
-
There is no landing page and no section. A
|
|
3144
|
-
section's landing, and a `subType: collection` note with a top-level `section:`
|
|
3145
|
-
key was a second way to say the same thing. All of it is retired, because a
|
|
3146
|
-
section appears in **no address**: a
|
|
3158
|
+
There is no landing page and no section. A section appears in **no address**: a
|
|
3147
3159
|
page publishes at `/<package>/<type>-<shortcode>/`, which names no directory. A
|
|
3148
3160
|
section is what Hugo calls a content directory, and the note format does not
|
|
3149
3161
|
carry one.
|
|
3150
3162
|
|
|
3151
|
-
So a `doc`'s `subType` is a **genre** and nothing else, closed to the
|
|
3152
|
-
|
|
3153
|
-
landing's `subType` named the section it addressed; with no landings, one field
|
|
3154
|
-
has one reading again.
|
|
3163
|
+
So a `doc`'s `subType` is a **genre** and nothing else, closed to the values
|
|
3164
|
+
above.
|
|
3155
3165
|
|
|
3156
3166
|
### type: macro
|
|
3157
3167
|
|
package/docs/getting-started.md
CHANGED
|
@@ -780,10 +780,11 @@ values, and the content mount — for `hugo --source build/hugo` to render
|
|
|
780
780
|
into `build/site/<contentPackage>/`. There is no Hugo configuration to
|
|
781
781
|
write: the file is generated on every run, and what is genuinely the
|
|
782
782
|
package's own — the wording of its "page not found" page — goes in the
|
|
783
|
-
`site:` block as `site.notfound`. Set `publish.site: content
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
783
|
+
`site:` block as `site.notfound`. Set `publish.site: content`, and the same
|
|
784
|
+
command publishes the content tree's every page beside the homepage — one
|
|
785
|
+
page per note, and nothing generated between them; an index of what the
|
|
786
|
+
package publishes is a `doc` note carrying a content table.
|
|
787
|
+
[`project-setup.md`](project-setup.md) gives the npm scripts.
|
|
787
788
|
|
|
788
789
|
**Another package's content.** Declare a dependency under `relationships`, and
|
|
789
790
|
`content-build deps fetch` caches that release's published content index so
|
package/docs/project-setup.md
CHANGED
|
@@ -254,7 +254,7 @@ package carries this group:
|
|
|
254
254
|
`build:site-content` writes the whole Hugo source tree under `build/hugo/` —
|
|
255
255
|
the generated `hugo.toml` and the content mount — with `content-build site`;
|
|
256
256
|
`build:site-html` runs Hugo over it, rendering into `build/site/<contentPackage>/`;
|
|
257
|
-
`build:site-root` writes the deployment's `_headers`
|
|
257
|
+
`build:site-root` writes the deployment's `_headers` beside
|
|
258
258
|
that; and `serve:site` does the first and then `hugo server` for a live
|
|
259
259
|
preview. The repository carries no Hugo configuration of its own: `hugo.toml`
|
|
260
260
|
is generated on every run from `package.json`, `package-build.config.yaml`,
|
package/engine/content-links.mjs
CHANGED
|
@@ -621,21 +621,18 @@ export function buildLinkIndex(
|
|
|
621
621
|
const SITE_HOST = /^(?:[a-z0-9-]+\.)*heroiclands\.org$/i;
|
|
622
622
|
|
|
623
623
|
/**
|
|
624
|
-
* Every package
|
|
624
|
+
* Every package front page this build can name, as `package` → base.
|
|
625
625
|
*
|
|
626
|
-
* **A
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
* tree, reads no manifest and builds no index — which is precisely why the
|
|
635
|
-
* mechanism survives `homepage` mode, where the licensing fence means none of
|
|
636
|
-
* those exist.
|
|
626
|
+
* **A front page needs no manifest, and that is what makes it work.** A
|
|
627
|
+
* homepage compiles to no document and is entered in no manifest, but its
|
|
628
|
+
* address is not a *note's* address but the **package's** — it is the mount's
|
|
629
|
+
* `_index.md`, published at `/<package>/` — and {@link PACKAGE_BASE} already
|
|
630
|
+
* records where each package is served. That is a frozen constant compiled
|
|
631
|
+
* into every build, so consulting it walks no tree, reads no manifest and
|
|
632
|
+
* builds no index — which is precisely why the mechanism survives `homepage`
|
|
633
|
+
* mode, where the licensing fence means none of those exist.
|
|
637
634
|
*
|
|
638
|
-
* The roster is consulted **for
|
|
635
|
+
* The roster is consulted **for front pages only**. Widening the package set the
|
|
639
636
|
* other rules read would make them offer manifest-based advice about packages
|
|
640
637
|
* no index has been fetched for.
|
|
641
638
|
*
|
|
@@ -738,41 +735,30 @@ function readAddress(url, packages) {
|
|
|
738
735
|
* not and cannot: it is published *verbatim* by every publishing mode, including
|
|
739
736
|
* the homepage-only mode two fan-licensed packages ship under, where the content
|
|
740
737
|
* tree is never walked and there is no index for a wikilink to resolve against.
|
|
741
|
-
* So a
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
* `being`: two 404s on the package's front page, through every build.
|
|
738
|
+
* So a homepage addresses the web the way the web does — markdown links in its
|
|
739
|
+
* body — and this is what looks at those. A dead link on the page a reader
|
|
740
|
+
* arrives at is the one nothing else would report.
|
|
745
741
|
*
|
|
746
742
|
* **What is checkable, stated plainly.** Only an address into this site is, and
|
|
747
743
|
* only against facts this build already holds:
|
|
748
744
|
*
|
|
749
745
|
* - A **retired content type** in the path. The engine knows the retired names
|
|
750
|
-
* and what replaced it, so this is a fact rather than a guess
|
|
751
|
-
* exactly the SoHL defect.
|
|
746
|
+
* and what replaced it, so this is a fact rather than a guess.
|
|
752
747
|
* - A **hardcoded absolute URL** into this package's own prefix, or into one a
|
|
753
|
-
*
|
|
748
|
+
* fetched index names. Every one of them has a better form to write, which
|
|
754
749
|
* is why every one is reported — including a bare `/<package>/`, which names
|
|
755
|
-
* another package's
|
|
756
|
-
*
|
|
757
|
-
*
|
|
758
|
-
*
|
|
759
|
-
* True, and beside the point: it does not need resolving. A landing's address
|
|
760
|
-
* *is* its package prefix, so `/<package>/` is the absolute URL with the host
|
|
761
|
-
* struck off — host-free, emitted verbatim, and needing no index, which is
|
|
762
|
-
* what lets it hold in homepage-only mode where the tree is never walked. The
|
|
763
|
-
* form was already accepted here; nothing had ever named it as the one to use.
|
|
764
|
-
* - A **root-relative `url:`**, which the theme's `relURL` prefixes a second
|
|
765
|
-
* time. `href:` means "already resolved, use verbatim", so the same leading
|
|
766
|
-
* slash is correct there and is not reported.
|
|
750
|
+
* another package's front page. A front page's address *is* its package
|
|
751
|
+
* prefix, so `/<package>/` is the absolute URL with the host struck off —
|
|
752
|
+
* host-free, emitted verbatim, and needing no index, which is what lets it
|
|
753
|
+
* hold in homepage-only mode where the tree is never walked.
|
|
767
754
|
* - A **wikilink**, which nothing on this page will ever resolve.
|
|
768
755
|
*
|
|
769
756
|
* **What is not checkable, and is not attempted.** Whether an external URL
|
|
770
757
|
* answers — there is no network at build time, and a build must not fail because
|
|
771
758
|
* a third party is down. And whether a live in-site address names a page that
|
|
772
|
-
* exists: several of the surfaces a
|
|
773
|
-
* tools entirely (generated API documentation,
|
|
774
|
-
*
|
|
775
|
-
* link as dead.
|
|
759
|
+
* exists: several of the surfaces a homepage routes to are produced by other
|
|
760
|
+
* tools entirely (generated API documentation, say), so this build does not
|
|
761
|
+
* hold the set of published pages and would report a working link as dead.
|
|
776
762
|
*
|
|
777
763
|
* @param {ReturnType<typeof buildLinkIndex>} index - The built index.
|
|
778
764
|
* @returns {Array<{note: object, field: string, url: string, text: string,
|
|
@@ -814,7 +800,7 @@ export function auditHomepageLinks(index) {
|
|
|
814
800
|
);
|
|
815
801
|
}
|
|
816
802
|
|
|
817
|
-
for (const { field, url
|
|
803
|
+
for (const { field, url } of homepageAddresses(note.body)) {
|
|
818
804
|
// Counted for every address, checked or not, so the count is
|
|
819
805
|
// the literal's nth appearance in the file rather than the nth
|
|
820
806
|
// *finding* about it — two rules can fire on one address.
|
|
@@ -853,34 +839,13 @@ export function auditHomepageLinks(index) {
|
|
|
853
839
|
prefix === index.contentPackage ?
|
|
854
840
|
`hardcoded absolute URL into this package's own ` +
|
|
855
841
|
`address — write the package-relative ` +
|
|
856
|
-
`"${rest}/", which
|
|
857
|
-
`
|
|
842
|
+
`"${rest}/", which a browser resolves against ` +
|
|
843
|
+
`the homepage's own address, the package root`
|
|
858
844
|
: `hardcoded absolute URL into package "${prefix}" ` +
|
|
859
845
|
`— resolve it through that package's link ` +
|
|
860
846
|
`manifest, whose entries carry the address, so a ` +
|
|
861
847
|
`relocation does not leave this page behind`,
|
|
862
848
|
);
|
|
863
|
-
} else if (shape === "rooted" && kind === "url") {
|
|
864
|
-
const rest = prefix ? segments.slice(1).join("/") : segments.join("/");
|
|
865
|
-
report(
|
|
866
|
-
field,
|
|
867
|
-
url,
|
|
868
|
-
url,
|
|
869
|
-
occurrence,
|
|
870
|
-
// A `url:` is package-relative by construction, so it
|
|
871
|
-
// cannot address anything outside this package at all —
|
|
872
|
-
// there is no relative spelling of another package's root.
|
|
873
|
-
// `href:` is the field for an address already resolved.
|
|
874
|
-
!rest ?
|
|
875
|
-
`url "${url}" addresses ` +
|
|
876
|
-
(prefix ? `package "${prefix}"'s landing` : `the site root`) +
|
|
877
|
-
`, but a landing's url: is package-relative and ` +
|
|
878
|
-
`cannot leave this package — write ` +
|
|
879
|
-
`href: "${url}", which is used verbatim`
|
|
880
|
-
: `url "${url}" is root-relative, but a landing's url: ` +
|
|
881
|
-
`is resolved against the site — write "${rest}/", ` +
|
|
882
|
-
`or href: for an address that is already resolved`,
|
|
883
|
-
);
|
|
884
849
|
}
|
|
885
850
|
|
|
886
851
|
// The retired-type rule reads the path *inside* the package, so an
|
package/engine/diagnostics.mjs
CHANGED
|
@@ -297,7 +297,7 @@ export function positionOfLiteral(text, needle, occurrence = 1) {
|
|
|
297
297
|
*
|
|
298
298
|
* **`key: true` addresses the declaration rather than the value.** A finding
|
|
299
299
|
* about a *value* — this pack name is not in `packs[]` — belongs on the value,
|
|
300
|
-
* which is the default. A finding that names a **field** — `\`site.
|
|
300
|
+
* which is the default. A finding that names a **field** — `\`site.notfound.x\`
|
|
301
301
|
* is not a recognized option` — sends the reader to look for that field, so the
|
|
302
302
|
* position should be the field's own, and in a flow mapping
|
|
303
303
|
* (`{ title: X, banner: Y }`) the two are different columns on one line. The
|
|
@@ -347,7 +347,7 @@ export function positionOfYamlPath(text, keyPath, { key = false } = {}) {
|
|
|
347
347
|
* The YAML key path a **dotted field path** addresses.
|
|
348
348
|
*
|
|
349
349
|
* Configuration checks report the offending key as the path a reader would
|
|
350
|
-
* write it — `packs[1].name`, `site.
|
|
350
|
+
* write it — `packs[1].name`, `site.notfound.links[0].url` — because that
|
|
351
351
|
* is what the message has to say. {@link positionOfYamlPath} addresses a node
|
|
352
352
|
* by segments instead, so this is the one translation between them: `.`
|
|
353
353
|
* separates map keys, and a bracketed suffix is a sequence index.
|
|
@@ -442,5 +442,11 @@ export function renderItemFieldsPage(body, { title, destination, contentRoot, fr
|
|
|
442
442
|
shortcode: shortcodeFromBasename(destination),
|
|
443
443
|
frontmatter,
|
|
444
444
|
});
|
|
445
|
-
|
|
445
|
+
const page = matter.stringify(body, envelope);
|
|
446
|
+
// `matter.stringify` closes the frontmatter fence directly onto the
|
|
447
|
+
// body's first line; Prettier's markdown printer requires a blank line
|
|
448
|
+
// between them, so a page written without one fails a consumer's
|
|
449
|
+
// `lint:format` the moment it is committed. Insert it here rather than
|
|
450
|
+
// let the generator and the formatter rewrite the file back and forth.
|
|
451
|
+
return page.replace(/^(---\n[\s\S]*?\n---\n)/, "$1\n");
|
|
446
452
|
}
|