@heroiclands/package-build 21.2.0 → 22.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 +41 -0
- package/bin/package-build.mjs +6 -5
- package/docs/api.md +3 -1
- package/docs/commands.md +13 -11
- package/docs/content-format.md +11 -2
- package/engine/dependency-bump.mjs +14 -16
- package/engine/pdf-render.mjs +40 -10
- package/manifest.mjs +67 -13
- package/package.json +1 -1
- package/types/engine/dependency-bump.d.mts +2 -2
- package/types/manifest.d.mts +42 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- a278438: **A manifest's `url` is the package's homepage.** It is the Project Homepage link
|
|
8
|
+
a reader follows from the Foundry package listing _before_ installing anything,
|
|
9
|
+
so it answers "what is this?" — which the authored page at
|
|
10
|
+
`https://www.heroiclands.org/<contentPackage>/` does and a source tree does not.
|
|
11
|
+
`bugs`, `manifest` and `download` address release artefacts and stay on the
|
|
12
|
+
repository holding them. The address is derived from the content package rather
|
|
13
|
+
than declared, because the shared site-deploy workflow already publishes there; a
|
|
14
|
+
declared copy would be a second spelling of a settled fact, and the one free to
|
|
15
|
+
drift, since nothing fetches `url` the way Foundry fetches `manifest`.
|
|
16
|
+
|
|
17
|
+
**Breaking — `releaseUrls` takes `homeUrl`.** A call without it produced a
|
|
18
|
+
manifest advertising `undefined`, so the parameter is required rather than
|
|
19
|
+
defaulted. `packageHomepage` and `HOMEPAGE_ORIGIN` are exported beside it, and
|
|
20
|
+
`packageHomepage` refuses an empty name for the same reason.
|
|
21
|
+
|
|
22
|
+
**A configuration always names a content package**, so the manifest no longer
|
|
23
|
+
carries the branch that handled one that did not: the content index is advertised
|
|
24
|
+
unconditionally, which is what the comment above it already claimed.
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- dec6ef4: **A full-page picture prints where it was written** — In the book, an image
|
|
29
|
+
marked as full width now opens the page that follows the prose introducing it,
|
|
30
|
+
with the rest of that prose running below it. It can no longer appear above the
|
|
31
|
+
sentence that points at it, or a page later than the text that follows it.
|
|
32
|
+
|
|
33
|
+
- _A picture that asks for a float still floats_, which is what a float is for.
|
|
34
|
+
- _A picture taller than the page takes a page of its own._
|
|
35
|
+
- 32322bd: **Dependency bumps** — `package-build bump` is described by what it is for: npm
|
|
36
|
+
performs the resolution, so a version whose dependency set differs from the one
|
|
37
|
+
it replaces is taken as correctly as one that moves three lines, while patching
|
|
38
|
+
the lockfile by hand is right only while the two dependency sets match. npm
|
|
39
|
+
writes `package-lock.json` with the indentation `package.json` uses, so a
|
|
40
|
+
formatted manifest yields a formatted lockfile; the bump holds each file to the
|
|
41
|
+
indent it already carries, which is what covers a lockfile indented unlike its
|
|
42
|
+
manifest.
|
|
43
|
+
|
|
3
44
|
## 21.2.0
|
|
4
45
|
|
|
5
46
|
### Minor Changes
|
package/bin/package-build.mjs
CHANGED
|
@@ -1137,10 +1137,11 @@ function e2eCommand() {
|
|
|
1137
1137
|
* `bump [packages..]` — take a newer version of a dependency.
|
|
1138
1138
|
*
|
|
1139
1139
|
* npm does the resolving, so a bump whose dependency set changed is as correct
|
|
1140
|
-
* as one that moves three lines
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1140
|
+
* as one that moves three lines; patching the lockfile by hand is right only
|
|
1141
|
+
* while the two dependency sets match, and nothing says when they stop
|
|
1142
|
+
* matching. npm writes the lockfile with `package.json`'s indentation, and
|
|
1143
|
+
* this holds each file to the indent it already carried, so a lockfile indented
|
|
1144
|
+
* unlike its manifest keeps its own.
|
|
1144
1145
|
*
|
|
1145
1146
|
* Named nothing, it takes the first-party packages — the ones a person bumps
|
|
1146
1147
|
* by hand, the moment a release publishes, usually to unblock the change that
|
|
@@ -1151,7 +1152,7 @@ function e2eCommand() {
|
|
|
1151
1152
|
function bumpCommand() {
|
|
1152
1153
|
return {
|
|
1153
1154
|
command: "bump [packages..]",
|
|
1154
|
-
describe: "Take a newer version of a dependency
|
|
1155
|
+
describe: "Take a newer published version of a declared dependency",
|
|
1155
1156
|
builder: (y) =>
|
|
1156
1157
|
y
|
|
1157
1158
|
.positional("packages", {
|
package/docs/api.md
CHANGED
|
@@ -1487,7 +1487,9 @@ console.log(normalizeRepoUrl("git@github.com:HeroicLands/sohl.git"));
|
|
|
1487
1487
|
| ------------------------------ | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1488
1488
|
| `ARTIFACTS` | `const ARTIFACTS` | — | reading the two Foundry package kinds (`"system"`, `"module"`) as the artifact name their manifest and release archive are called |
|
|
1489
1489
|
| `normalizeRepoUrl` | `normalizeRepoUrl(repository)` | `string` — normalised `https://` URL, no trailing slash | normalising `package.json`'s `repository` field (object or shorthand string, `git+…git` or plain) to the exact URL Foundry fetches release assets from |
|
|
1490
|
-
| `
|
|
1490
|
+
| `HOMEPAGE_ORIGIN` | `HOMEPAGE_ORIGIN` | `string` — the origin every package's homepage is served from | stating the site origin once, so the address a manifest advertises and the address the configuration documents cannot disagree |
|
|
1491
|
+
| `packageHomepage` | `packageHomepage(contentPackage)` | `string` — `<origin>/<contentPackage>/` | deriving the homepage a manifest's `url` points at; throws when given no name rather than advertising `<origin>/undefined/` |
|
|
1492
|
+
| `releaseUrls` | `releaseUrls({ repoUrl, homeUrl, version, artifact })` | `{url: string, bugs: string, manifest: string, download: string}` | building the manifest's addresses — `url` is the homepage a reader follows before installing, while `bugs`, `manifest` and `download` stay on the repository holding the artefacts |
|
|
1491
1493
|
| `metadataUrl` | `metadataUrl({ repoUrl, version, contentPackage })` | `string` — the version-pinned asset URL | computing where this release publishes its content index, pinned to this version like `download` so a dependency's manifest and its fetched index always describe the same release |
|
|
1492
1494
|
| `manifestPacks` | `manifestPacks(config)` | `object[]` | deriving the manifest's `packs` array from the one pack list the build already has, in build order, companions flattened in |
|
|
1493
1495
|
| `packFolderFindings` | `packFolderFindings({ packFolders, packs = [] })` | `Array<{severity: "error"\|"warning", message: string, pack: string, folder?: string, keyPath: Array<string\|number>}>` | checking a declared `packFolders` against the derived pack list — a folder naming a pack that does not exist is an error, a pack no folder names is a warning |
|
package/docs/commands.md
CHANGED
|
@@ -441,7 +441,7 @@ None.
|
|
|
441
441
|
|
|
442
442
|
**NAME**
|
|
443
443
|
|
|
444
|
-
Take a newer version of a dependency
|
|
444
|
+
Take a newer published version of a declared dependency.
|
|
445
445
|
|
|
446
446
|
**SYNOPSIS**
|
|
447
447
|
|
|
@@ -453,17 +453,20 @@ package-build bump [packages..] [--tag <tag>] [--check]
|
|
|
453
453
|
|
|
454
454
|
Takes the newest published version of one or more declared dependencies,
|
|
455
455
|
updating `package-lock.json` — and `package.json` when the declared range has to
|
|
456
|
-
move —
|
|
456
|
+
move — and holding both files to the indentation they already carry.
|
|
457
457
|
|
|
458
|
-
npm performs the resolution,
|
|
459
|
-
one it replaces is handled as correctly as one
|
|
460
|
-
|
|
461
|
-
|
|
458
|
+
npm performs the resolution, which is what this exists for. A version whose
|
|
459
|
+
dependency set differs from the one it replaces is handled as correctly as one
|
|
460
|
+
that moves three lines, while editing the `version` / `resolved` / `integrity`
|
|
461
|
+
lines by hand is only right while the two dependency sets are identical — and
|
|
462
|
+
nothing tells the author when they are not.
|
|
462
463
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
464
|
+
npm writes `package-lock.json` with the indentation `package.json` uses, so a
|
|
465
|
+
consumer whose manifest is formatted gets a formatted lockfile back and the
|
|
466
|
+
diff is the version change alone. The indentation step covers the case where
|
|
467
|
+
the two files disagree: each is written back with the indent it already
|
|
468
|
+
carried, rather than the lockfile taking the manifest's. A run that had to put
|
|
469
|
+
an indent back names the file it rewrote.
|
|
467
470
|
|
|
468
471
|
Named no packages, it takes every `@heroiclands/*` dependency the manifest
|
|
469
472
|
declares. That scope is the one a person bumps by hand — a first-party release
|
|
@@ -496,7 +499,6 @@ every package is already current.
|
|
|
496
499
|
```
|
|
497
500
|
$ package-build bump
|
|
498
501
|
@heroiclands/package-build 20.6.0 → 20.7.0
|
|
499
|
-
kept the existing indentation of package-lock.json
|
|
500
502
|
|
|
501
503
|
Install it with `npm ci`, which resolves from the lockfile this just moved.
|
|
502
504
|
```
|
package/docs/content-format.md
CHANGED
|
@@ -1754,8 +1754,17 @@ not. The website and a Foundry journal get true CSS wrap from the same
|
|
|
1754
1754
|
directive. Expect the same statement, not the same page.
|
|
1755
1755
|
|
|
1756
1756
|
An image with no `float:` is an ordinary block in the flow, where it was
|
|
1757
|
-
written. A `.full-width` image is
|
|
1758
|
-
|
|
1757
|
+
written. A `.full-width` image is set at the **top of a new page**: the book is
|
|
1758
|
+
set in two columns, only a float spans them both, and a float is placed where
|
|
1759
|
+
the page has room rather than where it was written — so the page breaks before
|
|
1760
|
+
the picture, and the prose that follows it runs below it on the same page. The
|
|
1761
|
+
picture can therefore never print above the prose that introduces it or after
|
|
1762
|
+
the prose that follows it, at the cost of the page before it ending short. A
|
|
1763
|
+
picture taller than the page takes a page of its own.
|
|
1764
|
+
|
|
1765
|
+
A `.full-width` image that **also states a `float:`** is asking for a float and
|
|
1766
|
+
gets one, with no break before it. A float is placed where it fits, which may be
|
|
1767
|
+
the next page.
|
|
1759
1768
|
|
|
1760
1769
|
##### Both vocabularies are closed
|
|
1761
1770
|
|
|
@@ -12,19 +12,17 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Taking a newer version of a dependency
|
|
15
|
+
* Taking a newer version of a dependency.
|
|
16
16
|
*
|
|
17
|
-
* npm
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* reviewer can read past.
|
|
17
|
+
* npm does the resolution, and that is the point of the command: editing the
|
|
18
|
+
* three `version` / `resolved` / `integrity` lines by hand is correct only
|
|
19
|
+
* while the new version's dependency set is identical to the old one's, and
|
|
20
|
+
* nothing tells the author when it is not. npm is what knows.
|
|
22
21
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* afterwards.
|
|
22
|
+
* npm writes `package-lock.json` with the indentation `package.json` uses, so
|
|
23
|
+
* a consumer whose two files agree sees only the lines that moved. Each file
|
|
24
|
+
* is written back with the indent it already carried, so a lockfile indented
|
|
25
|
+
* unlike its manifest keeps its own.
|
|
28
26
|
*/
|
|
29
27
|
|
|
30
28
|
import fs from "node:fs";
|
|
@@ -121,8 +119,8 @@ export function lockedVersion(lock, name) {
|
|
|
121
119
|
* Take the newest published version of one or more dependencies.
|
|
122
120
|
*
|
|
123
121
|
* npm performs the resolution — so a bump that changes the dependency set is
|
|
124
|
-
* as correct as one that moves three lines — and both JSON files are
|
|
125
|
-
*
|
|
122
|
+
* as correct as one that moves three lines — and both JSON files are written
|
|
123
|
+
* back with the indentation they already used.
|
|
126
124
|
*
|
|
127
125
|
* @param {object} options - Options.
|
|
128
126
|
* @param {string} options.rootDir - The repository root holding `package.json`.
|
|
@@ -196,9 +194,9 @@ export function bumpDependencies({ rootDir, packages, tag = "latest", check = fa
|
|
|
196
194
|
rootDir,
|
|
197
195
|
);
|
|
198
196
|
|
|
199
|
-
//
|
|
200
|
-
// manifest too when a range has to move — which below 1.0 it
|
|
201
|
-
// a caret there being locked to the minor.
|
|
197
|
+
// Hold each file to the indent it already carried. Both, because npm
|
|
198
|
+
// rewrites the manifest too when a range has to move — which below 1.0 it
|
|
199
|
+
// always does, a caret there being locked to the minor.
|
|
202
200
|
const reindented = [];
|
|
203
201
|
if (reindentJsonFile(lockPath, detectJsonIndent(lockText))) reindented.push(lockPath);
|
|
204
202
|
if (reindentJsonFile(manifestPath, detectJsonIndent(manifestText))) {
|
package/engine/pdf-render.mjs
CHANGED
|
@@ -667,14 +667,22 @@ function renderLink(href, inner, ctx) {
|
|
|
667
667
|
* ## The width class is the measure
|
|
668
668
|
*
|
|
669
669
|
* An image with no class is one column wide. That is `width: 100%` of whatever
|
|
670
|
-
* container it is set in —
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
* `.full-width` has to leave its column, and
|
|
675
|
-
*
|
|
676
|
-
*
|
|
677
|
-
*
|
|
670
|
+
* container it is set in — a column of the two the body is set in — so the
|
|
671
|
+
* ordinary case needs nothing but an ordinary block, and lands exactly where it
|
|
672
|
+
* was written.
|
|
673
|
+
*
|
|
674
|
+
* `.full-width` has to leave its column, and only a float placed with
|
|
675
|
+
* `scope: "parent"` spans every column of a page. A float, though, is placed
|
|
676
|
+
* where the page has room rather than where it was written: it is set at the
|
|
677
|
+
* top of the page, above the prose that introduces it, and where the page is
|
|
678
|
+
* too far along to take it, on the next page — after prose that follows it in
|
|
679
|
+
* the note. Document order governs what follows an image, so
|
|
680
|
+
* {@link bookTypstPreamble}'s `book-figure` breaks the page first and places
|
|
681
|
+
* the figure at the top of the fresh one, where nothing is above it to displace
|
|
682
|
+
* it and nothing that follows it can print first.
|
|
683
|
+
*
|
|
684
|
+
* A `.full-width` image that **also states a `float:`** is asking for a float,
|
|
685
|
+
* and keeps one — deferral is the honest consequence of the request.
|
|
678
686
|
*
|
|
679
687
|
* ## A float occupies the measure
|
|
680
688
|
*
|
|
@@ -712,8 +720,10 @@ function renderImage(token, ctx) {
|
|
|
712
720
|
// In the flow where it was written: no class asking for the page, and no
|
|
713
721
|
// position asking for the top or the bottom of the column.
|
|
714
722
|
if (!float && scope === "column") return `\n${figure}\n\n`;
|
|
715
|
-
|
|
716
|
-
|
|
723
|
+
// The page, in document order: a width class says how wide the picture is
|
|
724
|
+
// and not when it appears.
|
|
725
|
+
if (!float) return `\n#book-figure[\n${figure}\n]\n\n`;
|
|
726
|
+
return `\n#place(${float.align}, float: true, scope: "${scope}", clearance: 0.7em)[\n${figure}\n]\n\n`;
|
|
717
727
|
}
|
|
718
728
|
|
|
719
729
|
/**
|
|
@@ -904,6 +914,26 @@ export function bookTypstPreamble() {
|
|
|
904
914
|
" place(top + left)[#book-plate(kicker, title, banner, 9cm, body)]\n" +
|
|
905
915
|
" pagebreak()\n" +
|
|
906
916
|
"}",
|
|
917
|
+
// A full-width figure spans the page in document order. Only a float
|
|
918
|
+
// spans every column, and a float is placed where the page has room
|
|
919
|
+
// rather than where it was written — at the top, above the prose that
|
|
920
|
+
// introduces it, or on the next page when this one is too far along.
|
|
921
|
+
// Breaking first puts it at the top of a page whose float region is
|
|
922
|
+
// empty, which is the one place it cannot be displaced. A picture
|
|
923
|
+
// taller than the page takes a page of its own, for the reason
|
|
924
|
+
// `book-wide` states.
|
|
925
|
+
//
|
|
926
|
+
// `measure` alone is stable here. A rule reading `here().position()`
|
|
927
|
+
// to keep the break for the cases that need it does not converge: the
|
|
928
|
+
// position decides the layout and the layout decides the position.
|
|
929
|
+
"#let book-figure(body) = context {\n" +
|
|
930
|
+
" if measure(block(width: book-text-width)[#body]).height >= book-text-height * 0.88 {\n" +
|
|
931
|
+
" page(columns: 1)[#body]\n" +
|
|
932
|
+
" } else {\n" +
|
|
933
|
+
" pagebreak(weak: true)\n" +
|
|
934
|
+
' place(top, float: true, scope: "parent", clearance: 0.7em)[#body]\n' +
|
|
935
|
+
" }\n" +
|
|
936
|
+
"}",
|
|
907
937
|
// Wide content spans the page, and how it spans depends on how tall it
|
|
908
938
|
// is: a float is unbreakable and silently overflows, so anything taller
|
|
909
939
|
// than a page takes pages of its own instead.
|
package/manifest.mjs
CHANGED
|
@@ -94,6 +94,49 @@ export function normalizeRepoUrl(repository) {
|
|
|
94
94
|
return url;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Where every HeroicLands package's homepage is served from.
|
|
99
|
+
*
|
|
100
|
+
* Stated once here and read by {@link packageHomepage}, so the origin a
|
|
101
|
+
* manifest advertises and the origin the configuration documents cannot come
|
|
102
|
+
* to disagree.
|
|
103
|
+
*
|
|
104
|
+
* @type {string}
|
|
105
|
+
*/
|
|
106
|
+
export const HOMEPAGE_ORIGIN = "https://www.heroiclands.org";
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A package's homepage — the page `url` sends a reader to.
|
|
110
|
+
*
|
|
111
|
+
* Derived from the content package rather than declared, because the address is
|
|
112
|
+
* already fixed: every package publishes an authored homepage at
|
|
113
|
+
* `<origin>/<contentPackage>/`, and the shared site-deploy workflow publishes
|
|
114
|
+
* it there. A declared copy would be a second spelling of a settled fact, free
|
|
115
|
+
* to drift — and the one that drifts is this one, because nothing fetches `url`
|
|
116
|
+
* the way Foundry fetches `manifest`, so a wrong value is never reported.
|
|
117
|
+
*
|
|
118
|
+
* The site's own `baseURL` says the same thing, and is deliberately not the
|
|
119
|
+
* source: it sits at `site/hugo.toml` in most repositories and `kb/hugo.toml`
|
|
120
|
+
* in the system, so reading it would mean the packaging half knowing where each
|
|
121
|
+
* repository keeps its site configuration.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} contentPackage - The package's content-package name.
|
|
124
|
+
* @returns {string} The homepage URL, with its trailing slash.
|
|
125
|
+
* @throws {TypeError} When no name is given. Interpolating a missing one yields
|
|
126
|
+
* `<origin>/undefined/`, a URL that resolves and is wrong — and nothing
|
|
127
|
+
* fetches `url`, so it would be advertised for as long as nobody clicked it.
|
|
128
|
+
*/
|
|
129
|
+
export function packageHomepage(contentPackage) {
|
|
130
|
+
const name = String(contentPackage ?? "").trim();
|
|
131
|
+
if (!name) {
|
|
132
|
+
throw new TypeError(
|
|
133
|
+
"the configuration declares no `contentPackage`, so the manifest has " +
|
|
134
|
+
"no homepage to advertise.",
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return `${HOMEPAGE_ORIGIN}/${name}/`;
|
|
138
|
+
}
|
|
139
|
+
|
|
97
140
|
/**
|
|
98
141
|
* The addresses a Foundry manifest advertises.
|
|
99
142
|
*
|
|
@@ -103,15 +146,23 @@ export function normalizeRepoUrl(repository) {
|
|
|
103
146
|
* install at that release forever. `download` points at this exact version,
|
|
104
147
|
* because that is the archive this manifest describes.
|
|
105
148
|
*
|
|
149
|
+
* **`url` is the homepage, not the repository.** It is the Project Homepage
|
|
150
|
+
* link a reader follows from the package listing *before* installing anything,
|
|
151
|
+
* so it answers "what is this?" — which a page written for that question does
|
|
152
|
+
* and a source tree does not. `bugs`, `manifest` and `download` address release
|
|
153
|
+
* artefacts and stay on the repository that holds them.
|
|
154
|
+
*
|
|
106
155
|
* @param {object} opts
|
|
107
156
|
* @param {string} opts.repoUrl - Normalised repository URL.
|
|
157
|
+
* @param {string} opts.homeUrl - The package's homepage, from
|
|
158
|
+
* {@link packageHomepage}.
|
|
108
159
|
* @param {string} opts.version - The version being built.
|
|
109
160
|
* @param {"system"|"module"} opts.artifact - Which artifact is shipped.
|
|
110
161
|
* @returns {{url: string, bugs: string, manifest: string, download: string}}
|
|
111
162
|
*/
|
|
112
|
-
export function releaseUrls({ repoUrl, version, artifact }) {
|
|
163
|
+
export function releaseUrls({ repoUrl, homeUrl, version, artifact }) {
|
|
113
164
|
return {
|
|
114
|
-
url:
|
|
165
|
+
url: homeUrl,
|
|
115
166
|
bugs: `${repoUrl}/issues`,
|
|
116
167
|
manifest: `${repoUrl}/releases/latest/download/${artifact}.json`,
|
|
117
168
|
download: `${repoUrl}/releases/download/v${version}/${artifact}.zip`,
|
|
@@ -434,7 +485,12 @@ export function buildManifest({ config, packageJson, artifact, flags }) {
|
|
|
434
485
|
id: config.foundryPackage,
|
|
435
486
|
version: packageJson.version,
|
|
436
487
|
packs: manifestPacks(config),
|
|
437
|
-
...releaseUrls({
|
|
488
|
+
...releaseUrls({
|
|
489
|
+
repoUrl,
|
|
490
|
+
homeUrl: packageHomepage(config.contentPackage),
|
|
491
|
+
version: packageJson.version,
|
|
492
|
+
artifact,
|
|
493
|
+
}),
|
|
438
494
|
};
|
|
439
495
|
if (config.compatibility) derived.compatibility = config.compatibility;
|
|
440
496
|
|
|
@@ -482,16 +538,14 @@ export function buildManifest({ config, packageJson, artifact, flags }) {
|
|
|
482
538
|
// A flag rather than a top-level key because Foundry's manifest schema is
|
|
483
539
|
// closed and `flags` is its declared extension point; an unknown key at the
|
|
484
540
|
// top level is dropped by some readers and rejected by others.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
};
|
|
494
|
-
}
|
|
541
|
+
merged.flags = {
|
|
542
|
+
...(declared.flags ?? {}),
|
|
543
|
+
metadataUrl: metadataUrl({
|
|
544
|
+
repoUrl,
|
|
545
|
+
version: packageJson.version,
|
|
546
|
+
contentPackage: config.contentPackage,
|
|
547
|
+
}),
|
|
548
|
+
};
|
|
495
549
|
|
|
496
550
|
if (flags && Object.keys(flags).length) {
|
|
497
551
|
merged.flags = { ...(merged.flags ?? declared.flags ?? {}) };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "22.0.0",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -57,8 +57,8 @@ export function lockedVersion(lock: object, name: string): string | undefined;
|
|
|
57
57
|
* Take the newest published version of one or more dependencies.
|
|
58
58
|
*
|
|
59
59
|
* npm performs the resolution — so a bump that changes the dependency set is
|
|
60
|
-
* as correct as one that moves three lines — and both JSON files are
|
|
61
|
-
*
|
|
60
|
+
* as correct as one that moves three lines — and both JSON files are written
|
|
61
|
+
* back with the indentation they already used.
|
|
62
62
|
*
|
|
63
63
|
* @param {object} options - Options.
|
|
64
64
|
* @param {string} options.rootDir - The repository root holding `package.json`.
|
package/types/manifest.d.mts
CHANGED
|
@@ -17,6 +17,28 @@
|
|
|
17
17
|
export function normalizeRepoUrl(repository: string | {
|
|
18
18
|
url?: string;
|
|
19
19
|
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* A package's homepage — the page `url` sends a reader to.
|
|
22
|
+
*
|
|
23
|
+
* Derived from the content package rather than declared, because the address is
|
|
24
|
+
* already fixed: every package publishes an authored homepage at
|
|
25
|
+
* `<origin>/<contentPackage>/`, and the shared site-deploy workflow publishes
|
|
26
|
+
* it there. A declared copy would be a second spelling of a settled fact, free
|
|
27
|
+
* to drift — and the one that drifts is this one, because nothing fetches `url`
|
|
28
|
+
* the way Foundry fetches `manifest`, so a wrong value is never reported.
|
|
29
|
+
*
|
|
30
|
+
* The site's own `baseURL` says the same thing, and is deliberately not the
|
|
31
|
+
* source: it sits at `site/hugo.toml` in most repositories and `kb/hugo.toml`
|
|
32
|
+
* in the system, so reading it would mean the packaging half knowing where each
|
|
33
|
+
* repository keeps its site configuration.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} contentPackage - The package's content-package name.
|
|
36
|
+
* @returns {string} The homepage URL, with its trailing slash.
|
|
37
|
+
* @throws {TypeError} When no name is given. Interpolating a missing one yields
|
|
38
|
+
* `<origin>/undefined/`, a URL that resolves and is wrong — and nothing
|
|
39
|
+
* fetches `url`, so it would be advertised for as long as nobody clicked it.
|
|
40
|
+
*/
|
|
41
|
+
export function packageHomepage(contentPackage: string): string;
|
|
20
42
|
/**
|
|
21
43
|
* The addresses a Foundry manifest advertises.
|
|
22
44
|
*
|
|
@@ -26,14 +48,23 @@ export function normalizeRepoUrl(repository: string | {
|
|
|
26
48
|
* install at that release forever. `download` points at this exact version,
|
|
27
49
|
* because that is the archive this manifest describes.
|
|
28
50
|
*
|
|
51
|
+
* **`url` is the homepage, not the repository.** It is the Project Homepage
|
|
52
|
+
* link a reader follows from the package listing *before* installing anything,
|
|
53
|
+
* so it answers "what is this?" — which a page written for that question does
|
|
54
|
+
* and a source tree does not. `bugs`, `manifest` and `download` address release
|
|
55
|
+
* artefacts and stay on the repository that holds them.
|
|
56
|
+
*
|
|
29
57
|
* @param {object} opts
|
|
30
58
|
* @param {string} opts.repoUrl - Normalised repository URL.
|
|
59
|
+
* @param {string} opts.homeUrl - The package's homepage, from
|
|
60
|
+
* {@link packageHomepage}.
|
|
31
61
|
* @param {string} opts.version - The version being built.
|
|
32
62
|
* @param {"system"|"module"} opts.artifact - Which artifact is shipped.
|
|
33
63
|
* @returns {{url: string, bugs: string, manifest: string, download: string}}
|
|
34
64
|
*/
|
|
35
|
-
export function releaseUrls({ repoUrl, version, artifact }: {
|
|
65
|
+
export function releaseUrls({ repoUrl, homeUrl, version, artifact }: {
|
|
36
66
|
repoUrl: string;
|
|
67
|
+
homeUrl: string;
|
|
37
68
|
version: string;
|
|
38
69
|
artifact: "system" | "module";
|
|
39
70
|
}): {
|
|
@@ -223,6 +254,16 @@ export function writeManifest({ config, packageJson, artifact, outDir, flags, co
|
|
|
223
254
|
* convention this project is free to choose.
|
|
224
255
|
*/
|
|
225
256
|
export const ARTIFACTS: readonly string[];
|
|
257
|
+
/**
|
|
258
|
+
* Where every HeroicLands package's homepage is served from.
|
|
259
|
+
*
|
|
260
|
+
* Stated once here and read by {@link packageHomepage}, so the origin a
|
|
261
|
+
* manifest advertises and the origin the configuration documents cannot come
|
|
262
|
+
* to disagree.
|
|
263
|
+
*
|
|
264
|
+
* @type {string}
|
|
265
|
+
*/
|
|
266
|
+
export const HOMEPAGE_ORIGIN: string;
|
|
226
267
|
/**
|
|
227
268
|
* Relationship keys that direct the **build**, rather than describe the
|
|
228
269
|
* package.
|