@heroiclands/package-build 23.8.0 → 23.10.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +2 -0
  3. package/bin/content-commands.mjs +207 -70
  4. package/docs/api.md +646 -78
  5. package/docs/authoring/first-note.md +1 -1
  6. package/docs/authoring/links-and-markup.md +253 -102
  7. package/docs/commands.md +111 -13
  8. package/docs/content-format.md +7 -2
  9. package/docs/diagnostics.md +1 -1
  10. package/docs/guides/packs.md +2 -1
  11. package/docs/guides/reference-pages.md +86 -63
  12. package/docs/reference/format-details.md +398 -137
  13. package/docs/reference/note-types.md +188 -174
  14. package/engine/anchors.mjs +15 -26
  15. package/engine/base-compiler.mjs +6 -4
  16. package/engine/changelog-group.mjs +58 -34
  17. package/engine/changelog-lint.mjs +6 -2
  18. package/engine/compendiums.mjs +15 -1
  19. package/engine/compile-corpus.mjs +17 -3
  20. package/engine/content-charset.mjs +13 -1
  21. package/engine/content-format.yaml +1 -0
  22. package/engine/content-html.mjs +18 -4
  23. package/engine/content-icons.mjs +15 -1
  24. package/engine/content-images.mjs +28 -9
  25. package/engine/content-index.mjs +496 -16
  26. package/engine/content-links.mjs +70 -27
  27. package/engine/content-session.mjs +247 -0
  28. package/engine/content-sources.mjs +110 -0
  29. package/engine/content-spans.mjs +87 -8
  30. package/engine/content-tables.mjs +9 -4
  31. package/engine/content-tasklists.mjs +20 -4
  32. package/engine/culture-reach.mjs +61 -34
  33. package/engine/data-keys.mjs +3 -1
  34. package/engine/diagnostics.mjs +17 -6
  35. package/engine/dictionary-layout.mjs +151 -19
  36. package/engine/dictionary-rows.mjs +129 -79
  37. package/engine/extension-attributes.mjs +28 -5
  38. package/engine/first-use.mjs +371 -0
  39. package/engine/foundry-entries.mjs +29 -8
  40. package/engine/generate.mjs +13 -4
  41. package/engine/glossary-entries.mjs +11 -11
  42. package/engine/heading-attributes.mjs +21 -28
  43. package/engine/helpers.mjs +54 -19
  44. package/engine/index-records.mjs +1 -0
  45. package/engine/index.mjs +3 -0
  46. package/engine/journals.mjs +13 -6
  47. package/engine/language-data.mjs +55 -2
  48. package/engine/language-rows.mjs +4 -4
  49. package/engine/language-terms.mjs +90 -4
  50. package/engine/language-words.mjs +2 -2
  51. package/engine/lexical-sections.mjs +247 -0
  52. package/engine/markup-validation.mjs +7 -2
  53. package/engine/metadata-index.mjs +1 -0
  54. package/engine/name-markup.mjs +114 -0
  55. package/engine/name-rows.mjs +70 -0
  56. package/engine/names.mjs +460 -0
  57. package/engine/note-addresses.mjs +25 -4
  58. package/engine/note-claims.mjs +2 -0
  59. package/engine/note-state.mjs +9 -3
  60. package/engine/note-vocabulary.mjs +7 -6
  61. package/engine/path-charset.mjs +24 -1
  62. package/engine/pdf-build.mjs +9 -9
  63. package/engine/pdf-render.mjs +15 -1
  64. package/engine/site-build.mjs +16 -2
  65. package/engine/site-index.mjs +5 -1
  66. package/engine/sql-tables.mjs +324 -44
  67. package/engine/stub-lint.mjs +10 -5
  68. package/engine/web-wikilinks.mjs +8 -6
  69. package/engine/word-rows.mjs +20 -12
  70. package/engine/word-terms.mjs +15 -6
  71. package/engine/yaml-lint.mjs +3 -5
  72. package/hugo-theme/static/css/style.css +4 -0
  73. package/package.json +1 -1
  74. package/types/engine/anchors.d.mts +4 -2
  75. package/types/engine/compendiums.d.mts +5 -1
  76. package/types/engine/compile-corpus.d.mts +5 -2
  77. package/types/engine/content-charset.d.mts +5 -1
  78. package/types/engine/content-html.d.mts +5 -1
  79. package/types/engine/content-icons.d.mts +5 -1
  80. package/types/engine/content-images.d.mts +5 -1
  81. package/types/engine/content-index.d.mts +102 -18
  82. package/types/engine/content-links.d.mts +22 -8
  83. package/types/engine/content-session.d.mts +108 -0
  84. package/types/engine/content-sources.d.mts +32 -0
  85. package/types/engine/content-spans.d.mts +3 -5
  86. package/types/engine/content-tables.d.mts +2 -1
  87. package/types/engine/content-tasklists.d.mts +5 -1
  88. package/types/engine/culture-reach.d.mts +22 -2
  89. package/types/engine/data-keys.d.mts +7 -0
  90. package/types/engine/diagnostics.d.mts +10 -0
  91. package/types/engine/dictionary-layout.d.mts +35 -4
  92. package/types/engine/dictionary-rows.d.mts +9 -0
  93. package/types/engine/extension-attributes.d.mts +16 -2
  94. package/types/engine/first-use.d.mts +31 -0
  95. package/types/engine/foundry-entries.d.mts +14 -5
  96. package/types/engine/generate.d.mts +5 -1
  97. package/types/engine/heading-attributes.d.mts +2 -2
  98. package/types/engine/helpers.d.mts +33 -7
  99. package/types/engine/index.d.mts +1 -0
  100. package/types/engine/journals.d.mts +5 -2
  101. package/types/engine/language-terms.d.mts +7 -0
  102. package/types/engine/lexical-sections.d.mts +96 -0
  103. package/types/engine/markup-validation.d.mts +2 -1
  104. package/types/engine/name-markup.d.mts +176 -0
  105. package/types/engine/name-rows.d.mts +35 -0
  106. package/types/engine/names.d.mts +356 -0
  107. package/types/engine/note-addresses.d.mts +3 -3
  108. package/types/engine/note-state.d.mts +2 -1
  109. package/types/engine/path-charset.d.mts +16 -1
  110. package/types/engine/site-build.d.mts +6 -3
  111. package/types/engine/site-index.d.mts +3 -1
  112. package/types/engine/sql-tables.d.mts +39 -4
  113. package/types/engine/stub-lint.d.mts +3 -1
  114. package/types/engine/word-rows.d.mts +9 -7
@@ -1013,7 +1013,15 @@ async function prepareWorld(resolved, { contentBase, findings, resolveReplacemen
1013
1013
  scheme,
1014
1014
  };
1015
1015
  const collected = collectContentPages(contentBase, ctx);
1016
- const gates = siteGates(collected.pages, collected, { config: resolved, records });
1016
+ const sqlTables = await prepareTreeSqlTables(contentBase, {
1017
+ config: resolved,
1018
+ skipDirectories: resolved.skipDirectories,
1019
+ records,
1020
+ parsed,
1021
+ database: db,
1022
+ audience: "public",
1023
+ });
1024
+ const gates = siteGates(collected.pages, collected, { config: resolved, records, sqlTables });
1017
1025
  if (gatesFailed(gates)) {
1018
1026
  for (const [name, list] of Object.entries(gates)) {
1019
1027
  if (!Array.isArray(list)) continue;
@@ -1030,14 +1038,6 @@ async function prepareWorld(resolved, { contentBase, findings, resolveReplacemen
1030
1038
 
1031
1039
  const byFile = new Map(collected.pages.map((page) => [page.file, page]));
1032
1040
  const universe = tableUniverse(collected.pages);
1033
- const sqlTables = await prepareTreeSqlTables(contentBase, {
1034
- config: resolved,
1035
- skipDirectories: resolved.skipDirectories,
1036
- records,
1037
- parsed,
1038
- database: db,
1039
- audience: "public",
1040
- });
1041
1041
  // The address space an `![[…]]` embed resolves against — the same one the
1042
1042
  // site builds, so one authored picture reaches both surfaces or neither.
1043
1043
  const assets = assetAddressIndex(records, {
@@ -1210,7 +1210,15 @@ function renderInline(token, ctx) {
1210
1210
  out.push(inlineRaw(child.content));
1211
1211
  break;
1212
1212
  case "span_open": {
1213
- out.push("#box[");
1213
+ const classes = (child.attrGet?.("class") ?? "").split(/\s+/).filter(Boolean);
1214
+ const values = classes
1215
+ .map((value) => '"' + escapeTypstString(value) + '"')
1216
+ .join(", ");
1217
+ out.push(
1218
+ classes.length ?
1219
+ "#book-span(classes: (" + values + (classes.length === 1 ? "," : "") + "))["
1220
+ : "#box[",
1221
+ );
1214
1222
  break;
1215
1223
  }
1216
1224
  case "span_close": {
@@ -1618,6 +1626,12 @@ export function bookTypstPreamble() {
1618
1626
  "#let book-page-height = 11in",
1619
1627
  "#let book-text-width = book-page-width - 2 * book-margin",
1620
1628
  "#let book-text-height = book-page-height - 2 * book-margin",
1629
+ // Span classes reach the book intact; name styling sets an absolute
1630
+ // weight so it remains bold inside an ordinary strong phrase.
1631
+ "#let book-span(body, classes: ()) = {\n" +
1632
+ ' let styled = if classes.contains("name") { text(weight: "bold", body) } else { body }\n' +
1633
+ " box(styled)\n" +
1634
+ "}",
1621
1635
  // Use the file's natural measure for auto. Every requested width is
1622
1636
  // bounded by the available measure and by the height of a page.
1623
1637
  "#let book-image(path, requested: auto, caption: none) = layout(size => {\n" +
@@ -430,9 +430,11 @@ export function writeHomepages(outRoot, pages, config, { related, records, forei
430
430
  * @param {object} options
431
431
  * @param {object} options.config - The resolved build configuration.
432
432
  * @param {object[]} options.records - Content-index records.
433
+ * @param {Map<string, object[]>} [options.sqlTables] - Prepared directives,
434
+ * whose emitted anchors belong to the pages they expand in.
433
435
  * @returns {object} The gate results and, when they pass, the built index.
434
436
  */
435
- export function siteGates(pages, findings, { config, records }) {
437
+ export function siteGates(pages, findings, { config, records, sqlTables }) {
436
438
  const out = {
437
439
  // Always empty here: the homepage count is decided in `buildSite`
438
440
  // before the content walk, and a failing count returns without ever
@@ -464,7 +466,18 @@ export function siteGates(pages, findings, { config, records }) {
464
466
  out.unaddressable = unaddressableForeignPackages(foreign.index);
465
467
  if (out.unaddressable.length) return out;
466
468
 
467
- out.index = buildSiteIndex(pages, {
469
+ const expanded =
470
+ sqlTables ?
471
+ pages.map((page) => ({
472
+ ...page,
473
+ body: expandContentTables(page.body ?? "", {
474
+ source: page.file,
475
+ sqlTables: sqlTables.get(page.file),
476
+ pageLists: sqlTables.pageLists?.get(page.file),
477
+ }).markdown,
478
+ }))
479
+ : pages;
480
+ out.index = buildSiteIndex(expanded, {
468
481
  package: config.contentPackage,
469
482
  foreignIndex: foreign.index,
470
483
  foreignReferences: foreign.references,
@@ -1367,6 +1380,7 @@ export function buildSite({ config, sqlTables } = {}) {
1367
1380
  const gates = siteGates([...pages, ...homepageEntries], content, {
1368
1381
  config: resolved,
1369
1382
  records: ctx.records,
1383
+ sqlTables,
1370
1384
  });
1371
1385
  if (gatesFailed(gates)) {
1372
1386
  return {
@@ -174,6 +174,7 @@ function mergeForeign(index, foreignIndex) {
174
174
  * ordinary dead address.
175
175
  * @param {object[]} [options.records] - Content-index records.
176
176
  * @param {Map<string, object>} [options.foreignReferences] - Foreign reference targets.
177
+ * @param {import("./content-session.mjs").ContentSyntax} [options.syntax] - Exact-text scanner projections.
177
178
  * @returns {SiteIndex} The index, and what could not be addressed unambiguously.
178
179
  */
179
180
  export function buildSiteIndex(
@@ -184,6 +185,7 @@ export function buildSiteIndex(
184
185
  package: builderPackage,
185
186
  records = [],
186
187
  foreignReferences = new Map(),
188
+ syntax,
187
189
  } = {},
188
190
  ) {
189
191
  const index = new Map();
@@ -241,7 +243,9 @@ export function buildSiteIndex(
241
243
  // written against it can be checked rather than joined onto the
242
244
  // URL unverified. A Set even when empty: a page that declares no
243
245
  // anchor still has a definite answer for one an author names.
244
- anchors: new Set(collectAnchors(e.body ?? "").map((anchor) => anchor.slug)),
246
+ anchors: new Set(
247
+ collectAnchors(e.body ?? "", 1, undefined, syntax).map((anchor) => anchor.slug),
248
+ ),
245
249
  // The note's event ids, which a wikilink may not name.
246
250
  eventAnchors: new Set(eventAnchors(e.fm).map((anchor) => anchor.slug)),
247
251
  };