@heroiclands/package-build 20.4.0 → 20.6.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 +288 -0
- package/CONTENT.md +213 -20
- package/README.md +19 -1
- package/bin/content-build.mjs +135 -32
- package/bin/package-build.mjs +46 -13
- package/content-config.mjs +345 -101
- package/docs/api.md +1352 -0
- package/docs/commands.md +1609 -0
- package/docs/configuration.md +1432 -0
- package/docs/content-format.md +16 -6
- package/docs/diagnostics.md +356 -0
- package/docs/getting-started.md +813 -0
- package/docs/project-setup.md +469 -0
- package/engine/actor-compiler.mjs +30 -27
- package/engine/address-diff.mjs +45 -41
- package/engine/base-compiler.mjs +6 -0
- package/engine/bundles.mjs +9 -0
- package/engine/content-address.mjs +9 -9
- package/engine/content-index.mjs +44 -23
- package/engine/content-links.mjs +44 -11
- package/engine/content-lint.mjs +44 -10
- package/engine/content-tables.mjs +32 -27
- package/engine/folder-notes.mjs +4 -2
- package/engine/frontmatter-lint.mjs +35 -38
- package/engine/generate.mjs +5 -0
- package/engine/helpers.mjs +86 -32
- package/engine/index.mjs +12 -2
- package/engine/journals.mjs +9 -0
- package/engine/note-claims.mjs +18 -10
- package/engine/note-schemas.mjs +0 -5
- package/engine/note-vocabulary.mjs +32 -31
- package/engine/pack-config.mjs +26 -12
- package/engine/pack-router.mjs +0 -0
- package/engine/pdf-build.mjs +464 -0
- package/engine/pdf-fonts.mjs +420 -0
- package/engine/pdf-render.mjs +876 -0
- package/engine/pdf-toc.mjs +525 -0
- package/engine/scenes.mjs +14 -5
- package/engine/schema-check.mjs +1 -1
- package/engine/site-build.mjs +21 -3
- package/engine/web-wikilinks.mjs +6 -3
- package/engine/wikilinks.mjs +2 -4
- package/hm3/actors.mjs +8 -0
- package/hm3/items.mjs +8 -0
- package/package.json +1 -1
- package/release.mjs +63 -3
- package/sohl/actors.mjs +8 -0
- package/sohl/items.mjs +8 -0
- package/sohl/note-schemas.mjs +5 -5
- package/types/content-config.d.mts +66 -15
- package/types/engine/actor-compiler.d.mts +34 -30
- package/types/engine/address-diff.d.mts +57 -3
- package/types/engine/base-compiler.d.mts +10 -2
- package/types/engine/bundles.d.mts +9 -0
- package/types/engine/content-address.d.mts +9 -9
- package/types/engine/content-index.d.mts +57 -13
- package/types/engine/content-lint.d.mts +6 -4
- package/types/engine/content-tables.d.mts +49 -18
- package/types/engine/frontmatter-lint.d.mts +3 -2
- package/types/engine/helpers.d.mts +105 -31
- package/types/engine/index.d.mts +4 -0
- package/types/engine/journals.d.mts +9 -0
- package/types/engine/note-claims.d.mts +17 -10
- package/types/engine/note-vocabulary.d.mts +23 -196
- package/types/engine/pack-config.d.mts +4 -4
- package/types/engine/pdf-build.d.mts +42 -0
- package/types/engine/pdf-fonts.d.mts +30 -0
- package/types/engine/pdf-render.d.mts +156 -0
- package/types/engine/pdf-toc.d.mts +114 -0
- package/types/engine/scenes.d.mts +10 -1
- package/types/engine/schema-check.d.mts +2 -2
- package/types/engine/site-build.d.mts +34 -6
- package/types/engine/wikilinks.d.mts +2 -3
- package/types/hm3/actors.d.mts +8 -0
- package/types/hm3/items.d.mts +8 -0
- package/types/release.d.mts +15 -4
- package/types/sohl/actors.d.mts +10 -2
- package/types/sohl/items.d.mts +8 -0
package/bin/content-build.mjs
CHANGED
|
@@ -63,7 +63,9 @@ import prefix from "loglevel-plugin-prefix";
|
|
|
63
63
|
import yargs from "yargs";
|
|
64
64
|
import { hideBin } from "yargs/helpers";
|
|
65
65
|
import { compilePacks, cleanPacks, unpackPacks } from "../engine/compendiums.mjs";
|
|
66
|
+
import { compilesFoundryDocuments } from "../content-config.mjs";
|
|
66
67
|
import { loadPackConfig } from "../engine/pack-config.mjs";
|
|
68
|
+
import { buildPdf } from "../engine/pdf-build.mjs";
|
|
67
69
|
import {
|
|
68
70
|
fetchAllCatalogs,
|
|
69
71
|
fetchCatalogFromPath,
|
|
@@ -245,6 +247,7 @@ const argv = yargs(hideBin(process.argv))
|
|
|
245
247
|
.command(markdownCommand())
|
|
246
248
|
.command(contentIndexCommand())
|
|
247
249
|
.command(siteCommand())
|
|
250
|
+
.command(pdfCommand())
|
|
248
251
|
.command(reachabilityCommand())
|
|
249
252
|
.command(addressesCommand())
|
|
250
253
|
.version(ownVersion())
|
|
@@ -349,13 +352,19 @@ function docsCommand() {
|
|
|
349
352
|
if (current !== page) {
|
|
350
353
|
// Staleness belongs to the whole file, so no line is
|
|
351
354
|
// named — the diagnostics contract drops a field it
|
|
352
|
-
// cannot supply rather than guessing one.
|
|
353
|
-
log.error
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
355
|
+
// cannot supply rather than guessing one. Routed
|
|
356
|
+
// through `emitDiagnostic`, not `log.error`, so the
|
|
357
|
+
// path starts the line unprefixed by loglevel's
|
|
358
|
+
// `[timestamp] [ERROR]:` banner — the same reason
|
|
359
|
+
// every other located failure in this file uses it.
|
|
360
|
+
emitDiagnostic({
|
|
361
|
+
file: relative,
|
|
362
|
+
severity: "error",
|
|
363
|
+
message:
|
|
364
|
+
"out of date with the item-field declarations " +
|
|
365
|
+
"— run `content-build docs item-fields` and " +
|
|
366
|
+
"commit the regenerated file",
|
|
367
|
+
});
|
|
359
368
|
process.exitCode = 1;
|
|
360
369
|
return;
|
|
361
370
|
}
|
|
@@ -1363,6 +1372,87 @@ function contentIndexCommand() {
|
|
|
1363
1372
|
};
|
|
1364
1373
|
}
|
|
1365
1374
|
|
|
1375
|
+
/**
|
|
1376
|
+
* `content-build pdf` — build the book the content tree publishes as.
|
|
1377
|
+
*
|
|
1378
|
+
* The third surface, beside `package compile` and `site`. It takes the same
|
|
1379
|
+
* `--out` override the site command does, and reports what it found in the same
|
|
1380
|
+
* `file:line:column: severity: message` shape every other pass here uses — so
|
|
1381
|
+
* one editor, one CI annotator and one `grep` read all three.
|
|
1382
|
+
*
|
|
1383
|
+
* **Not building is a normal outcome, and it exits 0.** A package publishing
|
|
1384
|
+
* only a homepage, a package with no `pdf:` block and a package with no content
|
|
1385
|
+
* tree have each said they publish no book; saying so on stderr and failing the
|
|
1386
|
+
* command would break the release of every package that is not a book.
|
|
1387
|
+
*
|
|
1388
|
+
* @returns {object} The yargs command module.
|
|
1389
|
+
*/
|
|
1390
|
+
function pdfCommand() {
|
|
1391
|
+
return {
|
|
1392
|
+
command: "pdf",
|
|
1393
|
+
describe: "Build the content tree as a PDF",
|
|
1394
|
+
builder: (yargs) => {
|
|
1395
|
+
yargs
|
|
1396
|
+
.option("out", {
|
|
1397
|
+
describe: "Write the book here instead of the configured `pdf.out`.",
|
|
1398
|
+
type: "string",
|
|
1399
|
+
})
|
|
1400
|
+
.option("book-version", {
|
|
1401
|
+
describe: "Stamp this version on the title page and in the file name.",
|
|
1402
|
+
type: "string",
|
|
1403
|
+
})
|
|
1404
|
+
// Declared positively so yargs derives `--no-compile` from it;
|
|
1405
|
+
// an option literally named `no-compile` is rejected as unknown
|
|
1406
|
+
// when it is actually passed.
|
|
1407
|
+
.option("compile", {
|
|
1408
|
+
describe: "Run the Typst compiler. `--no-compile` emits the source and stops.",
|
|
1409
|
+
type: "boolean",
|
|
1410
|
+
default: true,
|
|
1411
|
+
});
|
|
1412
|
+
},
|
|
1413
|
+
handler: async (argv) => {
|
|
1414
|
+
try {
|
|
1415
|
+
const result = await buildPdf({
|
|
1416
|
+
...(argv.out ? { out: argv.out } : {}),
|
|
1417
|
+
...(argv.bookVersion ? { version: String(argv.bookVersion) } : {}),
|
|
1418
|
+
compile: argv.compile !== false,
|
|
1419
|
+
});
|
|
1420
|
+
|
|
1421
|
+
for (const finding of result.findings) emitDiagnostic(finding);
|
|
1422
|
+
|
|
1423
|
+
if (!result.built) {
|
|
1424
|
+
// A reason is a deliberate no-op — the fence, an absent
|
|
1425
|
+
// block, an absent tree. No reason means the findings above
|
|
1426
|
+
// say what went wrong, and those decide the exit code.
|
|
1427
|
+
if (result.reason) {
|
|
1428
|
+
log.info(`No book built: ${result.reason}`);
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
process.exitCode = 1;
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
const { stats } = result;
|
|
1436
|
+
log.info(
|
|
1437
|
+
`${stats.notes} entr(ies) and ${stats.prose} prose file(s) across ` +
|
|
1438
|
+
`${stats.sections} section(s)` +
|
|
1439
|
+
(stats.repeated ?
|
|
1440
|
+
`, ${stats.repeated} of them printed more than once`
|
|
1441
|
+
: ""),
|
|
1442
|
+
);
|
|
1443
|
+
log.info(`Typst source: ${result.typ}`);
|
|
1444
|
+
if (result.pdf) log.info(`Book: ${result.pdf}`);
|
|
1445
|
+
// Findings are reported, never fatal — a filter that selected
|
|
1446
|
+
// nothing is worth fixing and is not worth refusing to publish
|
|
1447
|
+
// the other two thousand entries over.
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
reportFailure(err);
|
|
1450
|
+
process.exitCode = 1;
|
|
1451
|
+
}
|
|
1452
|
+
},
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1366
1456
|
/**
|
|
1367
1457
|
* `content-build site` — publish the content tree as a website.
|
|
1368
1458
|
*
|
|
@@ -1611,30 +1701,6 @@ function reachabilityCommand() {
|
|
|
1611
1701
|
}
|
|
1612
1702
|
|
|
1613
1703
|
// eslint-disable-next-line
|
|
1614
|
-
/**
|
|
1615
|
-
* `deps fetch` — fill the caches this build resolves other packages through:
|
|
1616
|
-
* the **content index** of every declared dependency, and the **item
|
|
1617
|
-
* catalogue** of those additionally declaring `itemCatalog: true`.
|
|
1618
|
-
*
|
|
1619
|
-
* The two sets differ deliberately. Citing another package's *addresses* and
|
|
1620
|
-
* embedding its *items* are separate edges, and a package may have either
|
|
1621
|
-
* without the other — `harn-ensemble` cites no foreign address and embeds
|
|
1622
|
-
* 324,016 item references.
|
|
1623
|
-
*
|
|
1624
|
-
* Its own command rather than a step of `package compile`, so that a compile
|
|
1625
|
-
* never reaches the network. A build that downloads silently is not
|
|
1626
|
-
* reproducible, breaks offline, and hides a dependency's version change behind
|
|
1627
|
-
* a passing run.
|
|
1628
|
-
*
|
|
1629
|
-
* `--from` fills the cache from a locally built artifact instead of a release,
|
|
1630
|
-
* which is what makes iterating across packages possible: change the system,
|
|
1631
|
-
* build it, and see the effect on every consumer **before** any of it ships.
|
|
1632
|
-
* Otherwise testing a dependency change against its consumers costs a release
|
|
1633
|
-
* round-trip, which makes releasing a debugging tool rather than a publishing
|
|
1634
|
-
* decision.
|
|
1635
|
-
*
|
|
1636
|
-
* @returns {object} The yargs command module.
|
|
1637
|
-
*/
|
|
1638
1704
|
/**
|
|
1639
1705
|
* Resolve which declared dependency `--from` supplies, and cache it.
|
|
1640
1706
|
*
|
|
@@ -1668,6 +1734,30 @@ async function fetchFromLocalArtifact(config, argv) {
|
|
|
1668
1734
|
}
|
|
1669
1735
|
}
|
|
1670
1736
|
|
|
1737
|
+
/**
|
|
1738
|
+
* `deps fetch` — fill the caches this build resolves other packages through:
|
|
1739
|
+
* the **content index** of every declared dependency, and the **item
|
|
1740
|
+
* catalogue** of those additionally declaring `itemCatalog: true`.
|
|
1741
|
+
*
|
|
1742
|
+
* The two sets differ deliberately. Citing another package's *addresses* and
|
|
1743
|
+
* embedding its *items* are separate edges, and a package may have either
|
|
1744
|
+
* without the other — `harn-ensemble` cites no foreign address and embeds
|
|
1745
|
+
* 324,016 item references.
|
|
1746
|
+
*
|
|
1747
|
+
* Its own command rather than a step of `package compile`, so that a compile
|
|
1748
|
+
* never reaches the network. A build that downloads silently is not
|
|
1749
|
+
* reproducible, breaks offline, and hides a dependency's version change behind
|
|
1750
|
+
* a passing run.
|
|
1751
|
+
*
|
|
1752
|
+
* `--from` fills the cache from a locally built artifact instead of a release,
|
|
1753
|
+
* which is what makes iterating across packages possible: change the system,
|
|
1754
|
+
* build it, and see the effect on every consumer **before** any of it ships.
|
|
1755
|
+
* Otherwise testing a dependency change against its consumers costs a release
|
|
1756
|
+
* round-trip, which makes releasing a debugging tool rather than a publishing
|
|
1757
|
+
* decision.
|
|
1758
|
+
*
|
|
1759
|
+
* @returns {object} The yargs command module.
|
|
1760
|
+
*/
|
|
1671
1761
|
function depsCommand() {
|
|
1672
1762
|
return {
|
|
1673
1763
|
command: "deps <action>",
|
|
@@ -1906,11 +1996,24 @@ function packageCommand() {
|
|
|
1906
1996
|
// an unhandled-rejection stack trace. Report the message and set a
|
|
1907
1997
|
// failing exit code, so a build guard reads as a build failure.
|
|
1908
1998
|
try {
|
|
1999
|
+
const config = loadPackConfig();
|
|
2000
|
+
// The compile passes do not run for a package that declares no
|
|
2001
|
+
// packs by rule. Refused rather than exiting 0 having compiled
|
|
2002
|
+
// nothing: a build that succeeds and produces no documents is
|
|
2003
|
+
// the quiet failure this toolchain reports everywhere else.
|
|
2004
|
+
if (!compilesFoundryDocuments(config)) {
|
|
2005
|
+
throw new Error(
|
|
2006
|
+
`\`packageKind: ${config.packageKind}\` compiles no ` +
|
|
2007
|
+
`compendium, so there is nothing to ${action}. Build ` +
|
|
2008
|
+
`its site with \`content-build site\` and its book ` +
|
|
2009
|
+
`with \`content-build pdf\`.`,
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
1909
2012
|
// The one directory the pipeline creates rather than expects:
|
|
1910
2013
|
// `unpack` writes the extracted JSON there and `compile` reads
|
|
1911
2014
|
// it back. Created here rather than at module scope so that
|
|
1912
2015
|
// asking the CLI its version needs no configuration (#2).
|
|
1913
|
-
fs.mkdirSync(
|
|
2016
|
+
fs.mkdirSync(config.paths.unpack, {
|
|
1914
2017
|
recursive: true,
|
|
1915
2018
|
});
|
|
1916
2019
|
switch (action) {
|
package/bin/package-build.mjs
CHANGED
|
@@ -78,6 +78,7 @@ import yargs from "yargs";
|
|
|
78
78
|
import { hideBin } from "yargs/helpers";
|
|
79
79
|
|
|
80
80
|
import { loadPackageBuildConfig } from "../config.mjs";
|
|
81
|
+
import { compilesFoundryDocuments } from "../content-config.mjs";
|
|
81
82
|
import { loadPackConfig, packConfigPath } from "../engine/pack-config.mjs";
|
|
82
83
|
import { cleanBuildArtifacts, stageAssets } from "../stage.mjs";
|
|
83
84
|
import { buildSchemaArtifact } from "../engine/schema-extract.mjs";
|
|
@@ -413,6 +414,18 @@ function manifestCommand() {
|
|
|
413
414
|
handler: handler(async () => {
|
|
414
415
|
const config = loadPackageBuildConfig();
|
|
415
416
|
const shared = loadPackConfig();
|
|
417
|
+
// Refused rather than written: a manifest is the file Foundry reads
|
|
418
|
+
// to install a package, and a documentation package is not one. An
|
|
419
|
+
// emitted `module.json` would advertise an installable package with
|
|
420
|
+
// no packs, no compatibility range and no id — the plausible lie
|
|
421
|
+
// this toolchain refuses everywhere else.
|
|
422
|
+
if (!compilesFoundryDocuments(shared)) {
|
|
423
|
+
die(
|
|
424
|
+
`\`packageKind: ${shared.packageKind}\` ships no Foundry ` +
|
|
425
|
+
`package, so there is no manifest to generate. The site ` +
|
|
426
|
+
`and the book are built by \`content-build\`.`,
|
|
427
|
+
);
|
|
428
|
+
}
|
|
416
429
|
const packageJson = readPackageJson(config);
|
|
417
430
|
|
|
418
431
|
let flags;
|
|
@@ -704,16 +717,6 @@ function langHardcoded(config) {
|
|
|
704
717
|
);
|
|
705
718
|
}
|
|
706
719
|
|
|
707
|
-
/**
|
|
708
|
-
* `lang <action>` — the three localization guards.
|
|
709
|
-
*
|
|
710
|
-
* They are three questions about one subject, and each is blind to what the
|
|
711
|
-
* others see: `check` asks whether the file will load at all, `coverage`
|
|
712
|
-
* whether the keys and the code agree, `hardcoded` whether the markup ever
|
|
713
|
-
* asks for a key in the first place.
|
|
714
|
-
*
|
|
715
|
-
* @returns {object} The yargs command module.
|
|
716
|
-
*/
|
|
717
720
|
/**
|
|
718
721
|
* `package-build yaml` — lint note frontmatter and every YAML file.
|
|
719
722
|
*
|
|
@@ -826,6 +829,16 @@ function labelsCheck(args) {
|
|
|
826
829
|
console.log(`package-build: registry and §3 agree (${count} labels).`);
|
|
827
830
|
}
|
|
828
831
|
|
|
832
|
+
/**
|
|
833
|
+
* `lang <action>` — the three localization guards.
|
|
834
|
+
*
|
|
835
|
+
* They are three questions about one subject, and each is blind to what the
|
|
836
|
+
* others see: `check` asks whether the file will load at all, `coverage`
|
|
837
|
+
* whether the keys and the code agree, `hardcoded` whether the markup ever
|
|
838
|
+
* asks for a key in the first place.
|
|
839
|
+
*
|
|
840
|
+
* @returns {object} The yargs command module.
|
|
841
|
+
*/
|
|
829
842
|
function langCommand() {
|
|
830
843
|
return {
|
|
831
844
|
command: "lang <action>",
|
|
@@ -931,17 +944,37 @@ function releaseCommand() {
|
|
|
931
944
|
return {
|
|
932
945
|
command: "release",
|
|
933
946
|
describe: "Package the staged build for release",
|
|
934
|
-
builder: (y) =>
|
|
935
|
-
|
|
947
|
+
builder: (y) =>
|
|
948
|
+
y.option("no-pdf", {
|
|
949
|
+
describe:
|
|
950
|
+
"Skip the content-tree book. A package that publishes no content " +
|
|
951
|
+
"already builds none; this is for a release that has a tree and " +
|
|
952
|
+
"does not want the book.",
|
|
953
|
+
type: "boolean",
|
|
954
|
+
}),
|
|
955
|
+
handler: handler(async (argv) => {
|
|
936
956
|
const config = loadPackageBuildConfig();
|
|
937
|
-
const
|
|
957
|
+
const result = await packRelease({
|
|
938
958
|
artifact: config.artifact,
|
|
959
|
+
pdf: argv.pdf !== false,
|
|
939
960
|
});
|
|
961
|
+
const { zip, version, bytes } = result;
|
|
940
962
|
console.log(
|
|
941
963
|
`✅ Packaged ${version} for release: ` +
|
|
942
964
|
`${path.relative(config.rootDir, zip)} ` +
|
|
943
965
|
`(${(bytes / 1024 / 1024).toFixed(1)} MB)`,
|
|
944
966
|
);
|
|
967
|
+
// Reported, never fatal: the archive above is the release, and a
|
|
968
|
+
// book that would not set is a problem to fix rather than a reason
|
|
969
|
+
// to have published nothing.
|
|
970
|
+
for (const finding of result.pdfFindings ?? []) {
|
|
971
|
+
console.error(`${finding.file ?? "book"}: ${finding.severity}: ${finding.message}`);
|
|
972
|
+
}
|
|
973
|
+
if (result.pdf) {
|
|
974
|
+
console.log(`📕 Book: ${path.relative(config.rootDir, result.pdf)}`);
|
|
975
|
+
} else if (result.pdfSkipped) {
|
|
976
|
+
console.log(` No book: ${result.pdfSkipped}`);
|
|
977
|
+
}
|
|
945
978
|
}),
|
|
946
979
|
};
|
|
947
980
|
}
|