@heroiclands/package-build 23.1.0 → 23.2.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 +71 -0
- package/bin/content-commands.mjs +68 -149
- package/bin/package-build.mjs +56 -10
- package/ci/check-banners.mjs +42 -6
- package/ci/confirm-npm-version.mjs +135 -0
- package/ci/content-format-reference.mjs +14 -5
- package/config.mjs +1 -0
- package/container.mjs +185 -4
- package/content-config.mjs +333 -210
- package/deploy.mjs +116 -10
- package/docs/api.md +238 -246
- package/docs/authoring/assets.md +11 -5
- package/docs/authoring/frontmatter.md +1 -1
- package/docs/authoring/links-and-markup.md +87 -0
- package/docs/commands.md +138 -99
- package/docs/configuration.md +277 -125
- package/docs/content-format.md +2 -0
- package/docs/diagnostics.md +48 -13
- package/docs/guides/book.md +341 -21
- package/docs/guides/e2e.md +13 -2
- package/docs/guides/icons.md +14 -4
- package/docs/guides/module-project.md +18 -8
- package/docs/guides/release-and-deploy.md +54 -6
- package/docs/guides/site.md +5 -2
- package/docs/project-setup.md +30 -10
- package/docs/reference/format-details.md +373 -170
- package/docs/reference/note-types.md +128 -109
- package/docs/reference/theme-pages.md +31 -6
- package/e2e.mjs +140 -28
- package/engine/actor-compiler.mjs +22 -31
- package/engine/address-charset.mjs +4 -17
- package/engine/address-fields.mjs +1 -1
- package/engine/address-render.mjs +12 -1
- package/engine/address-values.mjs +6 -0
- package/engine/address.mjs +46 -33
- package/engine/art-fields.mjs +30 -5
- package/engine/art-slots.mjs +10 -1
- package/engine/asset-bindings.mjs +12 -1
- package/engine/base-compiler.mjs +34 -65
- package/engine/being-age.mjs +2 -7
- package/engine/being-measurements.mjs +12 -1
- package/engine/calendar-artifacts.mjs +6 -0
- package/engine/calendar-choice.mjs +12 -1
- package/engine/calendar-format.mjs +12 -1
- package/engine/calendar-human.mjs +12 -1
- package/engine/compile-corpus.mjs +3 -1
- package/engine/content-address.mjs +9 -12
- package/engine/content-alerts.mjs +13 -1
- package/engine/content-blocks.mjs +14 -3
- package/engine/content-embeds.mjs +11 -3
- package/engine/content-figures.mjs +9 -0
- package/engine/content-footnotes.mjs +12 -1
- package/engine/content-format-check.mjs +11 -262
- package/engine/content-format.yaml +5 -2
- package/engine/content-images.mjs +3 -0
- package/engine/content-index.mjs +443 -20
- package/engine/content-links.mjs +29 -35
- package/engine/content-lint.mjs +2 -3
- package/engine/content-poetry.mjs +12 -1
- package/engine/content-slug.mjs +2 -14
- package/engine/content-spans.mjs +13 -1
- package/engine/content-tables.mjs +12 -1
- package/engine/culture-choice.mjs +210 -13
- package/engine/data-keys.mjs +19 -16
- package/engine/date-conversion.mjs +12 -1
- package/engine/declaration-check.mjs +9 -0
- package/engine/derived-fields.mjs +6 -7
- package/engine/diagnostics.mjs +34 -4
- package/engine/docs-checks.mjs +9 -0
- package/engine/document-subtypes.mjs +47 -34
- package/engine/event-views.mjs +139 -14
- package/engine/exported-scene.mjs +92 -28
- package/engine/extension-attributes.mjs +12 -1
- package/engine/field-spec.mjs +11 -102
- package/engine/folder-notes.mjs +0 -64
- package/engine/foreign-catalog.mjs +2 -1
- package/engine/format-generated.mjs +9 -0
- package/engine/foundry-entries.mjs +10 -28
- package/engine/frontmatter-lint.mjs +83 -392
- package/engine/frontmatter.mjs +20 -70
- package/engine/generate.mjs +10 -15
- package/engine/heading-attributes.mjs +12 -1
- package/engine/helpers.mjs +41 -102
- package/engine/holdings.mjs +1 -1
- package/engine/homepage.mjs +3 -10
- package/engine/ids.mjs +1 -167
- package/engine/index-records.mjs +6 -4
- package/engine/index.mjs +0 -3
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +13 -14
- package/engine/item-compiler.mjs +4 -10
- package/engine/item-docs.mjs +3 -5
- package/engine/item-registry.mjs +2 -10
- package/engine/journals.mjs +1 -5
- package/engine/literature-notes.mjs +4 -12
- package/engine/macros.mjs +1 -2
- package/engine/map-graphviz.mjs +12 -1
- package/engine/markdown-expressions.mjs +12 -1
- package/engine/markdownlint-run.mjs +567 -0
- package/engine/metadata-index.mjs +42 -12
- package/engine/note-addresses.mjs +143 -35
- package/engine/note-claims.mjs +14 -28
- package/engine/note-dates.mjs +3 -3
- package/engine/note-frontmatter.mjs +6 -0
- package/engine/note-ids.mjs +8 -14
- package/engine/note-package.mjs +8 -25
- package/engine/note-state.mjs +1 -3
- package/engine/note-vocabulary.mjs +148 -84
- package/engine/number-words.mjs +12 -1
- package/engine/pack-config.mjs +15 -25
- package/engine/pack-router.mjs +10 -16
- package/engine/pathnames.mjs +8 -22
- package/engine/pdf-build.mjs +773 -121
- package/engine/pdf-coverage.mjs +188 -0
- package/engine/pdf-index.mjs +54 -7
- package/engine/pdf-pages.mjs +247 -0
- package/engine/pdf-render.mjs +114 -4
- package/engine/pdf-toc.mjs +29 -32
- package/engine/project-init.mjs +46 -6
- package/engine/prose-config.mjs +1 -1
- package/engine/prose-lint.mjs +52 -88
- package/engine/readability-lint.mjs +9 -0
- package/engine/reckoning-markers.mjs +12 -1
- package/engine/reference-targets.mjs +7 -0
- package/engine/runtime-only-fields.mjs +5 -8
- package/engine/scene-levels.mjs +2 -2
- package/engine/scenes.mjs +1 -1
- package/engine/shortcode-references.mjs +7 -0
- package/engine/site-build.mjs +30 -16
- package/engine/site-index.mjs +10 -16
- package/engine/site-preview.mjs +6 -0
- package/engine/site-root.mjs +8 -1
- package/engine/social-tie-terms.mjs +12 -1
- package/engine/social-ties.mjs +3 -0
- package/engine/sql-tables.mjs +56 -20
- package/engine/standing-terms.mjs +11 -1
- package/engine/standings.mjs +11 -27
- package/engine/system-block.mjs +39 -141
- package/engine/system-vocabulary.mjs +6 -0
- package/engine/walk-files.mjs +69 -0
- package/engine/web-wikilinks.mjs +23 -3
- package/engine/wikilink-syntax.mjs +32 -21
- package/engine/wikilinks.mjs +27 -16
- package/engine/yaml-lint.mjs +7 -4
- package/githooks/attribution.mjs +8 -0
- package/githooks/commit-message.mjs +9 -0
- package/hm3/actors.mjs +9 -48
- package/hm3/default-item-art.mjs +9 -9
- package/hm3/item-fields.mjs +2 -9
- package/hm3/template-priority.mjs +6 -7
- package/hugo-theme/data/banner-kinds.yaml +78 -0
- package/hugo-theme/data/banners.yaml +2 -3
- package/hugo-theme/layouts/404.html +3 -3
- package/hugo-theme/layouts/partials/banner-url.html +31 -7
- package/hugo-theme/layouts/partials/hero-banner.html +13 -14
- package/hugo-theme/layouts/partials/related.html +1 -1
- package/hugo-theme/layouts/partials/warn-missing-banner.html +1 -1
- package/hugo-theme/static/css/style.css +1 -1
- package/manifest.mjs +11 -4
- package/markdownlint-config.mjs +1 -1
- package/package.json +6 -3
- package/release.mjs +83 -18
- package/sohl/actors.mjs +16 -27
- package/sohl/default-item-art.mjs +3 -3
- package/sohl/document-subtypes.mjs +1 -16
- package/sohl/infobox.mjs +2 -3
- package/sohl/item-builders.mjs +5 -8
- package/sohl/item-fields.mjs +5 -35
- package/sohl/items.mjs +0 -4
- package/sohl/kb-passes.mjs +3 -3
- package/types/container.d.mts +116 -5
- package/types/content-config.d.mts +83 -35
- package/types/deploy.d.mts +42 -6
- package/types/e2e.d.mts +35 -3
- package/types/engine/address-charset.d.mts +4 -17
- package/types/engine/address.d.mts +17 -8
- package/types/engine/art-fields.d.mts +7 -4
- package/types/engine/art-slots.d.mts +6 -0
- package/types/engine/base-compiler.d.mts +15 -17
- package/types/engine/content-address.d.mts +9 -12
- package/types/engine/content-embeds.d.mts +4 -2
- package/types/engine/content-format-check.d.mts +0 -64
- package/types/engine/content-index.d.mts +82 -3
- package/types/engine/content-links.d.mts +2 -4
- package/types/engine/culture-choice.d.mts +51 -8
- package/types/engine/data-keys.d.mts +2 -2
- package/types/engine/derived-fields.d.mts +1 -2
- package/types/engine/diagnostics.d.mts +27 -4
- package/types/engine/document-subtypes.d.mts +12 -31
- package/types/engine/event-views.d.mts +14 -2
- package/types/engine/exported-scene.d.mts +3 -2
- package/types/engine/field-spec.d.mts +13 -122
- package/types/engine/folder-notes.d.mts +0 -39
- package/types/engine/foreign-catalog.d.mts +2 -1
- package/types/engine/foundry-entries.d.mts +4 -5
- package/types/engine/frontmatter-lint.d.mts +2 -2
- package/types/engine/frontmatter.d.mts +19 -45
- package/types/engine/generate.d.mts +1 -1
- package/types/engine/helpers.d.mts +25 -42
- package/types/engine/homepage.d.mts +3 -10
- package/types/engine/ids.d.mts +0 -114
- package/types/engine/index-records.d.mts +6 -4
- package/types/engine/index.d.mts +0 -1
- package/types/engine/infobox-render.d.mts +7 -1
- package/types/engine/infobox.d.mts +3 -2
- package/types/engine/item-docs.d.mts +1 -1
- package/types/engine/item-registry.d.mts +2 -4
- package/types/engine/literature-notes.d.mts +1 -1
- package/types/engine/markdownlint-run.d.mts +40 -0
- package/types/engine/metadata-index.d.mts +9 -1
- package/types/engine/note-addresses.d.mts +27 -2
- package/types/engine/note-claims.d.mts +3 -5
- package/types/engine/note-ids.d.mts +2 -4
- package/types/engine/note-package.d.mts +1 -1
- package/types/engine/note-state.d.mts +1 -3
- package/types/engine/note-vocabulary.d.mts +28 -21
- package/types/engine/pack-config.d.mts +2 -6
- package/types/engine/pack-router.d.mts +4 -4
- package/types/engine/pathnames.d.mts +3 -3
- package/types/engine/pdf-build.d.mts +98 -12
- package/types/engine/pdf-coverage.d.mts +60 -0
- package/types/engine/pdf-index.d.mts +34 -5
- package/types/engine/pdf-pages.d.mts +143 -0
- package/types/engine/pdf-render.d.mts +45 -1
- package/types/engine/pdf-toc.d.mts +12 -14
- package/types/engine/prose-config.d.mts +1 -1
- package/types/engine/prose-lint.d.mts +11 -10
- package/types/engine/runtime-only-fields.d.mts +2 -2
- package/types/engine/site-build.d.mts +9 -5
- package/types/engine/site-index.d.mts +4 -5
- package/types/engine/site-root.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -2
- package/types/engine/standing-terms.d.mts +2 -1
- package/types/engine/standings.d.mts +7 -9
- package/types/engine/system-block.d.mts +10 -44
- package/types/engine/walk-files.d.mts +15 -0
- package/types/engine/wikilink-syntax.d.mts +18 -19
- package/types/engine/yaml-lint.d.mts +5 -4
- package/types/hm3/actors.d.mts +1 -2
- package/types/hm3/item-fields.d.mts +2 -4
- package/types/hm3/template-priority.d.mts +6 -7
- package/types/manifest.d.mts +3 -2
- package/types/release.d.mts +12 -7
- package/types/sohl/actors.d.mts +2 -1
- package/types/sohl/document-subtypes.d.mts +1 -2
- package/types/sohl/item-fields.d.mts +3 -7
- package/engine/retired-fields.mjs +0 -631
- package/types/engine/retired-fields.d.mts +0 -354
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 23.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
**Books**
|
|
8
|
+
|
|
9
|
+
- `pdf:` declares its books in a `books:` list; a configuration that still writes `pdf.title` or `pdf.document` fails. To move, put `title`, `subtitle`, `document` and `front` into one `pdf.books` entry with an `id`; `fonts`, `iconFonts`, `binary` and `out` stay directly under `pdf:`.
|
|
10
|
+
- `package-build pdf` builds every declared book, and `--book <id>` builds one. Each book's PDF is named from its `out` stem (default `<package>-<id>`) and the version; write `out: <package>` to keep a single book's file name.
|
|
11
|
+
|
|
12
|
+
**Authors**
|
|
13
|
+
|
|
14
|
+
- Authors are listed once, in a top-level `authors` list, each with an optional role; the Foundry manifest's authors and the site's byline come from it. Move `packageBuild.manifest.authors` up to `authors`; the manifest block refuses it.
|
|
15
|
+
|
|
16
|
+
**Cultures**
|
|
17
|
+
|
|
18
|
+
- A setting guide must name the culture it introduces in `data.culture`. Places, affiliations and every kind of lore may name theirs; other `doc` notes may not, and a culture note may state it only as itself.
|
|
19
|
+
|
|
20
|
+
**Closed note fields**
|
|
21
|
+
|
|
22
|
+
- `icon` is accepted only on beings, Items, macros and bundles; a document, map, lore, place or scenario that writes it is refused at the key. An empty `icon`, `tokenIcon` or `banner` is an error at its line.
|
|
23
|
+
- A `data.banner` naming no image is an error at its line, and `data.affiliations` written as a list is an error at its line.
|
|
24
|
+
- A note or a being's `items:` entry with an undeclared `type` is refused at its `type:` line, including `character`, `creature`, `armor`, `concoction`, `projectile` and the map types `battlemap`, `localmap` and `regionalmap`.
|
|
25
|
+
- A `data:` property written at the top level, or in a `sohl:` or `hm3:` block, is an error at its own line; `archetype`, `relation`, `birthday`, a being's `stations`, and top-level `draft`, `aliases`, `section`, `traits` and `folder` are unrecognized keys.
|
|
26
|
+
- Address shortcodes must be lowercase; a reference that spells one with capitals is an error.
|
|
27
|
+
- Undeclared configuration keys, such as `packs[].folders` and `site.trees`, are refused as unrecognized options, and `package-build content-format notes` is not a command.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
**Books**
|
|
32
|
+
|
|
33
|
+
- A run reports every printable note no book selects, as a warning by default; `pdf.coverage` makes it an error or silences it, and `pdf.unprinted` names notes that belong in no book.
|
|
34
|
+
- A note several books select prints in each, and the summary names its home book, the first in the list; a cross-reference to a note in another book names that book and its page.
|
|
35
|
+
- Each book's index lists its own notes.
|
|
36
|
+
- A section whose queries select nothing is left out of the book; a book that selects nothing at all is an error.
|
|
37
|
+
- A book can open with a full-page cover image under its title, and its title page lists the authors, the copyright and the licence.
|
|
38
|
+
- `package-build pdf --list-assets` prints the output path of each declared book as JSON, without building anything.
|
|
39
|
+
|
|
40
|
+
**Cultures**
|
|
41
|
+
|
|
42
|
+
- A place takes the culture of the places it sits within, and an affiliation that of the bodies it answers to; a polity with neither takes that of its seat and the places it governs. Content tables, book queries and place and affiliation pages use that inherited culture.
|
|
43
|
+
- A note whose parents belong to different cultures is an error until it names its own.
|
|
44
|
+
|
|
45
|
+
**Pages and maps**
|
|
46
|
+
|
|
47
|
+
- A page declines its hero image with `data.banner: none`, and a `data.banner` image resolves to the picture it names on homepages and content pages alike.
|
|
48
|
+
- A map note can name its thumbnail with `data.thumbnail`, an image Address, and the compiled Scene shows that picture in Foundry's Scene lists without changing the map's background art.
|
|
49
|
+
|
|
50
|
+
**Beings**
|
|
51
|
+
|
|
52
|
+
- A membership in `data.affiliations` can list the societies it is held in with `societies`; on SoHL, the first society named becomes the membership's society on the character sheet.
|
|
53
|
+
- Compiled actors and items keep their default artwork under the HM3 system's asset layout.
|
|
54
|
+
- `package-build lint` resolves a being's embedded `model:` addresses against a `recommends` system that declares `itemCatalog: true`, as the compile does.
|
|
55
|
+
|
|
56
|
+
**Dependencies**
|
|
57
|
+
|
|
58
|
+
- A dependency whose cached index comes from an older package-build fails naming that dependency and the fix: update it, then run `package-build deps fetch`.
|
|
59
|
+
|
|
60
|
+
**Foundry test containers and deployment**
|
|
61
|
+
|
|
62
|
+
- An e2e run seeds its test world as the container's user and launches it, even after Foundry has repaired a database in it; when the world does not activate, the hint names the stage, so `package-build container <stage> logs` can be pasted as written.
|
|
63
|
+
- A container pinned to an exact Foundry build runs that build's own image, such as `felddy/foundryvtt:14.359`, and with the build cached and a licence present it starts without signing in to foundryvtt.com.
|
|
64
|
+
- A deployment removes its previous package tree even when Foundry's container owns the files in it, and sweeps away the `<id>.old-<pid>` trees earlier deployments left; a tree that still cannot be removed is a warning naming the command that removes it.
|
|
65
|
+
|
|
66
|
+
## 23.1.1
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
`package-build yaml` accepts an empty trigger such as `workflow_dispatch:` in a Gitea workflow under `.gitea/workflows/`, as it already does under `.github/workflows/`.
|
|
71
|
+
|
|
72
|
+
Rebuilding a release of the same commit produces an identical `module.zip` or `system.zip`, so a rebuilt archive can be compared with the one already published. Setting `SOURCE_DATE_EPOCH` stamps the archive's files with that time.
|
|
73
|
+
|
|
3
74
|
## 23.1.0
|
|
4
75
|
|
|
5
76
|
### Minor Changes
|
package/bin/content-commands.mjs
CHANGED
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
* npx package-build lint [root] [--no-references]
|
|
25
25
|
* npx package-build content-format schema --schema <system>=<path>
|
|
26
26
|
* npx package-build content-format fields [--fields <system>]
|
|
27
|
-
* npx package-build content-format notes [root] [--strict]
|
|
28
27
|
* npx package-build links [root] [--manifests <dir>]
|
|
29
28
|
* npx package-build format [paths..] [--write]
|
|
30
29
|
* npx package-build markdown [paths..] [--fix]
|
|
@@ -46,7 +45,8 @@ import prefix from "loglevel-plugin-prefix";
|
|
|
46
45
|
import { compilePacks, cleanPacks, unpackPacks } from "../engine/compendiums.mjs";
|
|
47
46
|
import { compilesFoundryDocuments, publishesContentPages } from "../content-config.mjs";
|
|
48
47
|
import { loadPackConfig, packConfigPath } from "../engine/pack-config.mjs";
|
|
49
|
-
import { buildPdf } from "../engine/pdf-build.mjs";
|
|
48
|
+
import { buildPdf, listBookAssets } from "../engine/pdf-build.mjs";
|
|
49
|
+
import { summaryLines } from "../engine/pdf-coverage.mjs";
|
|
50
50
|
import {
|
|
51
51
|
fetchAllCatalogs,
|
|
52
52
|
fetchCatalogFromPath,
|
|
@@ -79,11 +79,7 @@ import {
|
|
|
79
79
|
systemBlocksFor,
|
|
80
80
|
} from "../engine/frontmatter-lint.mjs";
|
|
81
81
|
import { loadContentFormat } from "../engine/content-format.mjs";
|
|
82
|
-
import {
|
|
83
|
-
checkDeclaredFields,
|
|
84
|
-
checkSchemaTargets,
|
|
85
|
-
measureCorpus,
|
|
86
|
-
} from "../engine/content-format-check.mjs";
|
|
82
|
+
import { checkDeclaredFields, checkSchemaTargets } from "../engine/content-format-check.mjs";
|
|
87
83
|
import {
|
|
88
84
|
compareFields,
|
|
89
85
|
resolveSchemaArtifact,
|
|
@@ -106,14 +102,7 @@ import { NOTE_VOCABULARY } from "../engine/note-vocabulary.mjs";
|
|
|
106
102
|
import { checkFormatting, checkPrettierConventions, lintMarkdown } from "../engine/prose-lint.mjs";
|
|
107
103
|
import { lintProse, scoreProseTree } from "../engine/readability-lint.mjs";
|
|
108
104
|
import { loadPackageBuildConfig } from "../config.mjs";
|
|
109
|
-
import {
|
|
110
|
-
authoredFrontmatter,
|
|
111
|
-
emitContentIndex,
|
|
112
|
-
indexRecordsFor,
|
|
113
|
-
isAssetRecord,
|
|
114
|
-
isNoteRecord,
|
|
115
|
-
noteFile,
|
|
116
|
-
} from "../engine/content-index.mjs";
|
|
105
|
+
import { emitContentIndex, indexRecordsFor, isAssetRecord } from "../engine/content-index.mjs";
|
|
117
106
|
import {
|
|
118
107
|
buildSite,
|
|
119
108
|
gatesFailed,
|
|
@@ -123,11 +112,7 @@ import { auditLinks, buildLinkIndex, walkReachability } from "../engine/content-
|
|
|
123
112
|
import { prepareTreeSqlTables } from "../engine/sql-tables.mjs";
|
|
124
113
|
// The one place a link finding is worded, shared with both builds.
|
|
125
114
|
import { linkFindingMessage } from "../engine/wikilink-syntax.mjs";
|
|
126
|
-
import {
|
|
127
|
-
emitDiagnostic,
|
|
128
|
-
positionInFrontmatter,
|
|
129
|
-
positionOfLiteral,
|
|
130
|
-
} from "../engine/diagnostics.mjs";
|
|
115
|
+
import { emitDiagnostic, positionOfLiteral } from "../engine/diagnostics.mjs";
|
|
131
116
|
import { reportFindings } from "./report.mjs";
|
|
132
117
|
import {
|
|
133
118
|
readItemAddresses,
|
|
@@ -199,8 +184,8 @@ function reportFailure(err) {
|
|
|
199
184
|
/**
|
|
200
185
|
* A note's source text, or `""` when it cannot be read.
|
|
201
186
|
*
|
|
202
|
-
* Used only to turn a link finding into a position. A path that
|
|
203
|
-
*
|
|
187
|
+
* Used only to turn a link finding into a position. A path that does not
|
|
188
|
+
* resolve — a page a build generated, a tree walked from somewhere else —
|
|
204
189
|
* yields `""`, and {@link positionOfLiteral} then reports nothing, so the
|
|
205
190
|
* diagnostic drops the line and column rather than guessing them.
|
|
206
191
|
*
|
|
@@ -637,7 +622,6 @@ function docsCommand() {
|
|
|
637
622
|
* naming system's published `schema.json`. A failure means the specification
|
|
638
623
|
* and the system disagree, which is a defect in one of the two.
|
|
639
624
|
* - `fields` compares declared field mappings with compiler declarations.
|
|
640
|
-
* - `notes` measures authored notes against the declared vocabulary.
|
|
641
625
|
*
|
|
642
626
|
* The shipped contract is `engine/content-format.yaml`; guide layout does not
|
|
643
627
|
* participate in validation.
|
|
@@ -648,12 +632,11 @@ function docsCommand() {
|
|
|
648
632
|
function contentFormatCommand() {
|
|
649
633
|
return {
|
|
650
634
|
command: "content-format <action>",
|
|
651
|
-
describe: "Check the content format specification against schemas and
|
|
635
|
+
describe: "Check the content format specification against schemas and field declarations",
|
|
652
636
|
builder: (yargs) =>
|
|
653
637
|
yargs
|
|
654
638
|
.command(contentFormatSchemaCommand())
|
|
655
639
|
.command(contentFormatFieldsCommand())
|
|
656
|
-
.command(contentFormatNotesCommand())
|
|
657
640
|
.demandCommand(1, "Name an action.")
|
|
658
641
|
.strict(),
|
|
659
642
|
handler: () => {},
|
|
@@ -865,95 +848,6 @@ function contentFormatFieldsCommand() {
|
|
|
865
848
|
};
|
|
866
849
|
}
|
|
867
850
|
|
|
868
|
-
/**
|
|
869
|
-
* `content-format notes` — a content tree, against the declared vocabulary.
|
|
870
|
-
*
|
|
871
|
-
* **A report, not a gate.** Every authored note predates the format, so a
|
|
872
|
-
* failing check would be red in every repository from the day it lands and
|
|
873
|
-
* would stay red for the length of the migration — which is a check nobody
|
|
874
|
-
* can act on. `--strict` raises the findings to errors, turned on slice by
|
|
875
|
-
* slice as each class of finding reaches zero.
|
|
876
|
-
*
|
|
877
|
-
* @returns {object} The yargs command module.
|
|
878
|
-
*/
|
|
879
|
-
function contentFormatNotesCommand() {
|
|
880
|
-
return {
|
|
881
|
-
command: "notes [root]",
|
|
882
|
-
describe: "Measure a content tree against the vocabulary the format declares (a report)",
|
|
883
|
-
builder: (yargs) => {
|
|
884
|
-
yargs.positional("root", {
|
|
885
|
-
describe: "Content tree to measure. Defaults to the configured contentBase.",
|
|
886
|
-
type: "string",
|
|
887
|
-
});
|
|
888
|
-
yargs.option("spec", {
|
|
889
|
-
describe:
|
|
890
|
-
"The format contract to read. Defaults to the engine/content-format.yaml this package ships.",
|
|
891
|
-
type: "string",
|
|
892
|
-
});
|
|
893
|
-
yargs.option("strict", {
|
|
894
|
-
describe:
|
|
895
|
-
"Fail on the findings instead of reporting them. Turned on per slice, as each class reaches zero.",
|
|
896
|
-
type: "boolean",
|
|
897
|
-
default: false,
|
|
898
|
-
});
|
|
899
|
-
},
|
|
900
|
-
handler: (argv) => {
|
|
901
|
-
try {
|
|
902
|
-
const config = loadPackConfig();
|
|
903
|
-
const root = argv.root ?? config.paths.content;
|
|
904
|
-
const format = specFrom(argv);
|
|
905
|
-
|
|
906
|
-
// The corpus from the index, like every other check.
|
|
907
|
-
// A report measuring the tree against the declared vocabulary
|
|
908
|
-
// has to be looking at the same tree the compile will, or its
|
|
909
|
-
// counts describe a corpus nobody builds.
|
|
910
|
-
const corpusProblems = [];
|
|
911
|
-
const records = indexRecordsFor({
|
|
912
|
-
contentBase: root,
|
|
913
|
-
config,
|
|
914
|
-
skipDirectories: config.skipDirectories,
|
|
915
|
-
problems: corpusProblems,
|
|
916
|
-
});
|
|
917
|
-
for (const problem of corpusProblems) emitDiagnostic(problem);
|
|
918
|
-
if (corpusProblems.length) process.exitCode = 1;
|
|
919
|
-
|
|
920
|
-
const notes = [];
|
|
921
|
-
for (const record of records) {
|
|
922
|
-
// A documentation journal is a document this tree emits,
|
|
923
|
-
// not a note in it, and has no authored frontmatter to
|
|
924
|
-
// measure.
|
|
925
|
-
if (!isNoteRecord(record) || typeof record.type !== "string") continue;
|
|
926
|
-
const absPath = noteFile(root, record);
|
|
927
|
-
notes.push({
|
|
928
|
-
file: absPath,
|
|
929
|
-
// What the author wrote, never the keys the index
|
|
930
|
-
// derived — this measures a note against a vocabulary,
|
|
931
|
-
// and `address:` is in no vocabulary.
|
|
932
|
-
fm: authoredFrontmatter(record),
|
|
933
|
-
raw: fs.readFileSync(absPath, "utf8"),
|
|
934
|
-
});
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
const { findings, byClass } = measureCorpus(notes, format, {
|
|
938
|
-
strict: argv.strict,
|
|
939
|
-
});
|
|
940
|
-
for (const finding of findings) emitDiagnostic(finding);
|
|
941
|
-
|
|
942
|
-
const counts = Object.entries(byClass).sort(([a], [b]) => (a < b ? -1 : 1));
|
|
943
|
-
for (const [cls, count] of counts) log.info(`${cls}: ${count}`);
|
|
944
|
-
log.info(
|
|
945
|
-
`${findings.length} finding(s) across ${notes.length} note(s) ` +
|
|
946
|
-
`measured against ${format.file}.`,
|
|
947
|
-
);
|
|
948
|
-
if (argv.strict && findings.length) process.exitCode = 1;
|
|
949
|
-
} catch (err) {
|
|
950
|
-
reportFailure(err);
|
|
951
|
-
process.exitCode = 1;
|
|
952
|
-
}
|
|
953
|
-
},
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
|
-
|
|
957
851
|
/**
|
|
958
852
|
* `package-build lint` — check a content tree's addresses.
|
|
959
853
|
*
|
|
@@ -999,11 +893,13 @@ function lintCommand() {
|
|
|
999
893
|
// not take every other finding in the tree with it, and the
|
|
1000
894
|
// reader needs a line to open, not a stack.
|
|
1001
895
|
const corpusProblems = [];
|
|
896
|
+
const parsed = new Map();
|
|
1002
897
|
const records = indexRecordsFor({
|
|
1003
898
|
contentBase: root,
|
|
1004
899
|
config,
|
|
1005
900
|
skipDirectories: config.skipDirectories,
|
|
1006
901
|
problems: corpusProblems,
|
|
902
|
+
parsed,
|
|
1007
903
|
});
|
|
1008
904
|
for (const problem of corpusProblems) emitDiagnostic(problem);
|
|
1009
905
|
// An error whatever the command's own strictness: the note is
|
|
@@ -1029,6 +925,7 @@ function lintCommand() {
|
|
|
1029
925
|
sqlTables: await prepareTreeSqlTables(root, {
|
|
1030
926
|
config,
|
|
1031
927
|
records,
|
|
928
|
+
parsed,
|
|
1032
929
|
skipDirectories: config.skipDirectories,
|
|
1033
930
|
}),
|
|
1034
931
|
});
|
|
@@ -1142,9 +1039,8 @@ function lintCommand() {
|
|
|
1142
1039
|
builders: fieldSpecs,
|
|
1143
1040
|
artifact: schema.artifact,
|
|
1144
1041
|
// A schema is keyed by document subtype and a field
|
|
1145
|
-
// declaration by note type
|
|
1146
|
-
//
|
|
1147
|
-
// after that would drop `armorgear`'s findings without
|
|
1042
|
+
// declaration by note type, and the two can differ, so
|
|
1043
|
+
// joining them by name would drop findings without
|
|
1148
1044
|
// saying so — the seam exists for exactly this.
|
|
1149
1045
|
subtypeOf: (type) => schemaSubtypeOf(config.stats?.systemId, type),
|
|
1150
1046
|
});
|
|
@@ -1265,13 +1161,8 @@ function lintCommand() {
|
|
|
1265
1161
|
...generatedArt,
|
|
1266
1162
|
...artSizes,
|
|
1267
1163
|
];
|
|
1268
|
-
// Only an **error** fails the run.
|
|
1269
|
-
//
|
|
1270
|
-
// but a field retired in favour of another is reported while
|
|
1271
|
-
// both spellings still compile, and failing a build over a note
|
|
1272
|
-
// that produces the correct document would red a tree that has
|
|
1273
|
-
// done nothing wrong. `reportFindings` already draws exactly
|
|
1274
|
-
// that line, so the rule is the shared one rather than a second
|
|
1164
|
+
// Only an **error** fails the run. `reportFindings` draws that
|
|
1165
|
+
// line, so the rule is the shared one rather than a second
|
|
1275
1166
|
// copy here. Each finding names its own file.
|
|
1276
1167
|
const errors = reportFindings(findings, {});
|
|
1277
1168
|
if (errors) {
|
|
@@ -1377,8 +1268,8 @@ function formatCommand() {
|
|
|
1377
1268
|
);
|
|
1378
1269
|
// `--write` collects findings too — a file Prettier cannot
|
|
1379
1270
|
// parse, or one that will not format to a fixpoint — and
|
|
1380
|
-
//
|
|
1381
|
-
//
|
|
1271
|
+
// a run that leaves files unformatted must not report
|
|
1272
|
+
// success.
|
|
1382
1273
|
for (const finding of findings) emitDiagnostic(finding);
|
|
1383
1274
|
if (findings.length) {
|
|
1384
1275
|
log.error(
|
|
@@ -1482,11 +1373,13 @@ function linksCommand() {
|
|
|
1482
1373
|
// Enumerated once and shared, as in `lint`, and a note
|
|
1483
1374
|
// it cannot record is reported rather than thrown.
|
|
1484
1375
|
const corpusProblems = [];
|
|
1376
|
+
const parsed = new Map();
|
|
1485
1377
|
const records = indexRecordsFor({
|
|
1486
1378
|
contentBase,
|
|
1487
1379
|
config,
|
|
1488
1380
|
...scope,
|
|
1489
1381
|
problems: corpusProblems,
|
|
1382
|
+
parsed,
|
|
1490
1383
|
});
|
|
1491
1384
|
for (const problem of corpusProblems) emitDiagnostic(problem);
|
|
1492
1385
|
// An error whatever the command's own strictness: the note is
|
|
@@ -1500,6 +1393,7 @@ function linksCommand() {
|
|
|
1500
1393
|
sqlTables: await prepareTreeSqlTables(contentBase, {
|
|
1501
1394
|
config,
|
|
1502
1395
|
records,
|
|
1396
|
+
parsed,
|
|
1503
1397
|
...scope,
|
|
1504
1398
|
}),
|
|
1505
1399
|
});
|
|
@@ -1690,9 +1584,10 @@ function contentIndexCommand() {
|
|
|
1690
1584
|
}
|
|
1691
1585
|
|
|
1692
1586
|
/**
|
|
1693
|
-
* `package-build pdf` — build the
|
|
1587
|
+
* `package-build pdf` — build the books the content tree publishes as.
|
|
1694
1588
|
*
|
|
1695
|
-
* The third surface, beside `package compile` and `site`. It
|
|
1589
|
+
* The third surface, beside `package compile` and `site`. It builds every book
|
|
1590
|
+
* `pdf.books` declares, or the one `--book <id>` names, and takes the same
|
|
1696
1591
|
* `--out` override the site command does, and reports what it found in the same
|
|
1697
1592
|
* `file:line:column: severity: message` shape every other pass here uses — so
|
|
1698
1593
|
* one editor, one CI annotator and one `grep` read all three.
|
|
@@ -1707,17 +1602,27 @@ function contentIndexCommand() {
|
|
|
1707
1602
|
function pdfCommand() {
|
|
1708
1603
|
return {
|
|
1709
1604
|
command: "pdf",
|
|
1710
|
-
describe: "Build the content tree as
|
|
1605
|
+
describe: "Build the content tree as one PDF per declared book",
|
|
1711
1606
|
builder: (yargs) => {
|
|
1712
1607
|
yargs
|
|
1608
|
+
.option("book", {
|
|
1609
|
+
describe: "Build only the book with this `id`. Every declared book by default.",
|
|
1610
|
+
type: "string",
|
|
1611
|
+
})
|
|
1713
1612
|
.option("out", {
|
|
1714
|
-
describe: "Write the
|
|
1613
|
+
describe: "Write the books here instead of the configured `pdf.out`.",
|
|
1715
1614
|
type: "string",
|
|
1716
1615
|
})
|
|
1717
1616
|
.option("book-version", {
|
|
1718
1617
|
describe: "Stamp this version on the title page and in the file name.",
|
|
1719
1618
|
type: "string",
|
|
1720
1619
|
})
|
|
1620
|
+
.option("list-assets", {
|
|
1621
|
+
describe:
|
|
1622
|
+
"Print each book's output path as JSON, in configuration order, and build nothing.",
|
|
1623
|
+
type: "boolean",
|
|
1624
|
+
default: false,
|
|
1625
|
+
})
|
|
1721
1626
|
// Declared positively so yargs derives `--no-compile` from it;
|
|
1722
1627
|
// an option literally named `no-compile` is rejected as unknown
|
|
1723
1628
|
// when it is actually passed.
|
|
@@ -1729,7 +1634,16 @@ function pdfCommand() {
|
|
|
1729
1634
|
},
|
|
1730
1635
|
handler: async (argv) => {
|
|
1731
1636
|
try {
|
|
1637
|
+
if (argv.listAssets) {
|
|
1638
|
+
const assets = listBookAssets({
|
|
1639
|
+
...(argv.out ? { out: argv.out } : {}),
|
|
1640
|
+
...(argv.bookVersion ? { version: String(argv.bookVersion) } : {}),
|
|
1641
|
+
});
|
|
1642
|
+
console.log(JSON.stringify(assets, null, 2));
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1732
1645
|
const result = await buildPdf({
|
|
1646
|
+
...(argv.book !== undefined ? { book: String(argv.book) } : {}),
|
|
1733
1647
|
...(argv.out ? { out: argv.out } : {}),
|
|
1734
1648
|
...(argv.bookVersion ? { version: String(argv.bookVersion) } : {}),
|
|
1735
1649
|
compile: argv.compile !== false,
|
|
@@ -1746,28 +1660,30 @@ function pdfCommand() {
|
|
|
1746
1660
|
log.info(`${report.file}: ${report.message}`);
|
|
1747
1661
|
}
|
|
1748
1662
|
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
log.info(`No book built: ${result.reason}`);
|
|
1755
|
-
return;
|
|
1756
|
-
}
|
|
1757
|
-
process.exitCode = 1;
|
|
1663
|
+
// A reason is a deliberate no-op — the fence, an absent block,
|
|
1664
|
+
// an absent tree. No reason means the findings above say what
|
|
1665
|
+
// went wrong, and those decide the exit code.
|
|
1666
|
+
if (result.reason) {
|
|
1667
|
+
log.info(`No book built: ${result.reason}`);
|
|
1758
1668
|
return;
|
|
1759
1669
|
}
|
|
1760
1670
|
|
|
1761
|
-
const
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
`${stats.
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1671
|
+
for (const book of result.books) {
|
|
1672
|
+
const { stats } = book;
|
|
1673
|
+
log.info(
|
|
1674
|
+
`${book.id}: ${stats.notes} entr(ies) and ${stats.prose} prose ` +
|
|
1675
|
+
`file(s) across ${stats.sections} section(s)` +
|
|
1676
|
+
(stats.repeated ?
|
|
1677
|
+
`, ${stats.repeated} of them printed more than once`
|
|
1678
|
+
: ""),
|
|
1679
|
+
);
|
|
1680
|
+
log.info(`${book.id}: Typst source: ${book.typ}`);
|
|
1681
|
+
if (book.pdf) log.info(`${book.id}: Book: ${book.pdf}`);
|
|
1682
|
+
}
|
|
1683
|
+
if (result.summary) {
|
|
1684
|
+
for (const line of summaryLines(result.summary)) log.info(line);
|
|
1685
|
+
}
|
|
1686
|
+
if (!result.built) process.exitCode = 1;
|
|
1771
1687
|
if (errors) process.exitCode = 1;
|
|
1772
1688
|
} catch (err) {
|
|
1773
1689
|
reportFailure(err);
|
|
@@ -2178,11 +2094,13 @@ function reachabilityCommand() {
|
|
|
2178
2094
|
const dir = String(argv.dir).replace(/\/+$/, "");
|
|
2179
2095
|
const scope = { skipDirectories: config.skipDirectories };
|
|
2180
2096
|
const corpusProblems = [];
|
|
2097
|
+
const parsed = new Map();
|
|
2181
2098
|
const records = indexRecordsFor({
|
|
2182
2099
|
contentBase,
|
|
2183
2100
|
config,
|
|
2184
2101
|
...scope,
|
|
2185
2102
|
problems: corpusProblems,
|
|
2103
|
+
parsed,
|
|
2186
2104
|
});
|
|
2187
2105
|
for (const problem of corpusProblems) emitDiagnostic(problem);
|
|
2188
2106
|
// An error whatever the command's own strictness: the note is
|
|
@@ -2196,6 +2114,7 @@ function reachabilityCommand() {
|
|
|
2196
2114
|
sqlTables: await prepareTreeSqlTables(contentBase, {
|
|
2197
2115
|
config,
|
|
2198
2116
|
records,
|
|
2117
|
+
parsed,
|
|
2199
2118
|
...scope,
|
|
2200
2119
|
}),
|
|
2201
2120
|
});
|
package/bin/package-build.mjs
CHANGED
|
@@ -87,7 +87,7 @@ import { hideBin } from "yargs/helpers";
|
|
|
87
87
|
|
|
88
88
|
import { loadPackageBuildConfig } from "../config.mjs";
|
|
89
89
|
import { checkForeignAssetBindings } from "../engine/asset-bindings.mjs";
|
|
90
|
-
import { formatDiagnostic } from "../engine/diagnostics.mjs";
|
|
90
|
+
import { emitDiagnostic, formatDiagnostic } from "../engine/diagnostics.mjs";
|
|
91
91
|
import { writeSiteRoot } from "../engine/site-root.mjs";
|
|
92
92
|
import { DEPLOY_ROOT } from "../engine/site-config.mjs";
|
|
93
93
|
import { compilesFoundryDocuments } from "../content-config.mjs";
|
|
@@ -117,8 +117,15 @@ import { findHardcodedText, findTemplateSyntaxErrors } from "../templates.mjs";
|
|
|
117
117
|
import { checkBundleLoading } from "../bundle.mjs";
|
|
118
118
|
import { packRelease } from "../release.mjs";
|
|
119
119
|
import { writeManifest } from "../manifest.mjs";
|
|
120
|
-
import { deployStage } from "../deploy.mjs";
|
|
121
|
-
import {
|
|
120
|
+
import { deployStage, resolveStage } from "../deploy.mjs";
|
|
121
|
+
import {
|
|
122
|
+
CONTAINER_ACTIONS,
|
|
123
|
+
containerAction,
|
|
124
|
+
containerRemovalCommand,
|
|
125
|
+
containerTreeRemover,
|
|
126
|
+
dataEnvVar,
|
|
127
|
+
resolveContainer,
|
|
128
|
+
} from "../container.mjs";
|
|
122
129
|
import { E2E_MODES, e2eFast, e2eRun, e2eSweep, seedTestWorld } from "../e2e.mjs";
|
|
123
130
|
import { reportFindings } from "./report.mjs";
|
|
124
131
|
import { formatGenerated } from "../engine/format-generated.mjs";
|
|
@@ -214,8 +221,16 @@ function initCommand() {
|
|
|
214
221
|
const root = path.resolve(args.directory ?? process.cwd());
|
|
215
222
|
if (args.check) {
|
|
216
223
|
const findings = checkProject(root);
|
|
217
|
-
for (const { file, message } of findings) {
|
|
218
|
-
console.error(
|
|
224
|
+
for (const { file, line, column, message } of findings) {
|
|
225
|
+
console.error(
|
|
226
|
+
formatDiagnostic({
|
|
227
|
+
file: path.join(root, file),
|
|
228
|
+
line,
|
|
229
|
+
column,
|
|
230
|
+
severity: "error",
|
|
231
|
+
message,
|
|
232
|
+
}),
|
|
233
|
+
);
|
|
219
234
|
}
|
|
220
235
|
if (findings.length) process.exitCode = 1;
|
|
221
236
|
else console.log(`package-build: ${root} is ready to build.`);
|
|
@@ -1440,11 +1455,19 @@ function releaseCommand() {
|
|
|
1440
1455
|
// book that would not set is a problem to fix rather than a reason
|
|
1441
1456
|
// to have published nothing.
|
|
1442
1457
|
for (const finding of result.pdfFindings ?? []) {
|
|
1443
|
-
console.error(
|
|
1458
|
+
console.error(
|
|
1459
|
+
formatDiagnostic({
|
|
1460
|
+
...finding,
|
|
1461
|
+
...(finding.file ?
|
|
1462
|
+
{ file: path.relative(process.cwd(), finding.file) }
|
|
1463
|
+
: {}),
|
|
1464
|
+
}),
|
|
1465
|
+
);
|
|
1444
1466
|
}
|
|
1445
|
-
|
|
1446
|
-
console.log(`📕 Book: ${path.relative(config.rootDir,
|
|
1447
|
-
}
|
|
1467
|
+
for (const pdf of result.pdfs ?? []) {
|
|
1468
|
+
console.log(`📕 Book: ${path.relative(config.rootDir, pdf)}`);
|
|
1469
|
+
}
|
|
1470
|
+
if (!result.pdfs?.length && result.pdfSkipped) {
|
|
1448
1471
|
console.log(` No book: ${result.pdfSkipped}`);
|
|
1449
1472
|
}
|
|
1450
1473
|
}),
|
|
@@ -1475,15 +1498,38 @@ function deployCommand() {
|
|
|
1475
1498
|
|
|
1476
1499
|
await loadEnvironment(config);
|
|
1477
1500
|
|
|
1478
|
-
|
|
1501
|
+
// The container is resolved only once the host user is refused a
|
|
1502
|
+
// removal, so a deploy that meets no refusal needs no container.
|
|
1503
|
+
const containerFor = () =>
|
|
1504
|
+
resolveContainer({ stage: resolveStage(args.stage), config });
|
|
1505
|
+
const { stage, leftovers, remote } = await deployStage({
|
|
1479
1506
|
stage: args.stage,
|
|
1480
1507
|
source: path.join(config.rootDir, config.stageDir),
|
|
1481
1508
|
packageKind: config.packageKind,
|
|
1482
1509
|
packageId: config.packageId,
|
|
1483
1510
|
prefix: config.envPrefix,
|
|
1484
1511
|
log: (message) => console.log(message),
|
|
1512
|
+
removeTree: (tree, where) =>
|
|
1513
|
+
containerTreeRemover({ container: containerFor() })(tree, where),
|
|
1485
1514
|
});
|
|
1486
1515
|
console.log(`Deployed stage '${stage}' successfully.`);
|
|
1516
|
+
for (const leftover of leftovers) {
|
|
1517
|
+
const remedy =
|
|
1518
|
+
remote ?
|
|
1519
|
+
"remove it on the host as the user that owns its files"
|
|
1520
|
+
: `remove it with \`${containerRemovalCommand({
|
|
1521
|
+
image: containerFor().image,
|
|
1522
|
+
dataRoot: process.env[dataEnvVar(stage)].trim(),
|
|
1523
|
+
tree: leftover.path,
|
|
1524
|
+
})}\``;
|
|
1525
|
+
emitDiagnostic({
|
|
1526
|
+
file: leftover.path,
|
|
1527
|
+
severity: "warning",
|
|
1528
|
+
message:
|
|
1529
|
+
`the new package is installed, but its previous tree could ` +
|
|
1530
|
+
`not be removed (${leftover.reason}); ${remedy}`,
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1487
1533
|
}),
|
|
1488
1534
|
};
|
|
1489
1535
|
}
|