@heroiclands/package-build 23.0.0 → 23.1.1

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 (157) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +1 -1
  3. package/bin/content-commands.mjs +1 -1
  4. package/ci/content-format-reference.mjs +46 -0
  5. package/docs/api.md +124 -141
  6. package/docs/authoring/assets.md +1 -1
  7. package/docs/authoring/dates-and-calendars.md +12 -6
  8. package/docs/authoring/frontmatter.md +2 -2
  9. package/docs/authoring/links-and-markup.md +145 -29
  10. package/docs/commands.md +8 -10
  11. package/docs/configuration.md +13 -11
  12. package/docs/content-format.md +2 -2
  13. package/docs/guides/book.md +59 -4
  14. package/docs/guides/icons.md +4 -5
  15. package/docs/guides/packs.md +6 -0
  16. package/docs/guides/reference-pages.md +21 -1
  17. package/docs/guides/release-and-deploy.md +39 -7
  18. package/docs/guides/site.md +17 -18
  19. package/docs/reference/format-details.md +877 -276
  20. package/docs/reference/note-types.md +278 -91
  21. package/docs/reference/theme-pages.md +58 -97
  22. package/engine/address-values.mjs +124 -4
  23. package/engine/address.mjs +44 -3
  24. package/engine/anchors.mjs +103 -3
  25. package/engine/art-slots.mjs +2 -9
  26. package/engine/base-compiler.mjs +25 -6
  27. package/engine/calendar-artifacts.mjs +4 -1
  28. package/engine/calendar-notes.mjs +166 -102
  29. package/engine/content-format-check.mjs +2 -3
  30. package/engine/content-format.mjs +44 -1
  31. package/engine/content-format.yaml +79 -16
  32. package/engine/content-images.mjs +10 -1
  33. package/engine/content-index.mjs +37 -9
  34. package/engine/content-links.mjs +24 -5
  35. package/engine/content-tables.mjs +24 -3
  36. package/engine/data-keys.mjs +347 -0
  37. package/engine/derived-sections.mjs +322 -0
  38. package/engine/diagnostics.mjs +28 -0
  39. package/engine/event-fields.mjs +187 -0
  40. package/engine/event-rows.mjs +126 -0
  41. package/engine/event-views.mjs +305 -0
  42. package/engine/exported-scene.mjs +29 -53
  43. package/engine/frontmatter-lint.mjs +103 -77
  44. package/engine/frontmatter.mjs +7 -2
  45. package/engine/generate.mjs +53 -0
  46. package/engine/generated-sections.mjs +223 -0
  47. package/engine/heading-attributes.mjs +4 -2
  48. package/engine/helpers.mjs +12 -1
  49. package/engine/holdings.mjs +12 -33
  50. package/engine/ids.mjs +17 -11
  51. package/engine/index.mjs +4 -4
  52. package/engine/infobox-render.mjs +21 -6
  53. package/engine/infobox.mjs +217 -99
  54. package/engine/journals.mjs +104 -47
  55. package/engine/literature-notes.mjs +4 -1
  56. package/engine/literature-works.mjs +21 -13
  57. package/engine/map-graphviz.mjs +4 -18
  58. package/engine/markdown-expressions.mjs +116 -11
  59. package/engine/metadata-index.mjs +26 -0
  60. package/engine/near-miss.mjs +90 -0
  61. package/engine/note-addresses.mjs +75 -19
  62. package/engine/note-dates.mjs +5 -3
  63. package/engine/note-event-terms.mjs +364 -0
  64. package/engine/note-events.mjs +823 -0
  65. package/engine/note-vocabulary.mjs +184 -88
  66. package/engine/office-holders.mjs +20 -54
  67. package/engine/packagebuild-index.mjs +16 -1
  68. package/engine/pdf-build.mjs +97 -60
  69. package/engine/pdf-index.mjs +263 -0
  70. package/engine/pdf-render.mjs +47 -5
  71. package/engine/place-relation-terms.mjs +174 -0
  72. package/engine/place-relations.mjs +72 -160
  73. package/engine/rank-ladder.mjs +14 -41
  74. package/engine/reckoning-markers.mjs +2 -0
  75. package/engine/region-events.mjs +6 -12
  76. package/engine/scenes.mjs +73 -468
  77. package/engine/site-build.mjs +75 -101
  78. package/engine/site-index.mjs +3 -1
  79. package/engine/site-maps.mjs +43 -29
  80. package/engine/site-preview.mjs +40 -31
  81. package/engine/social-ties.mjs +2 -1
  82. package/engine/sql-tables.mjs +212 -9
  83. package/engine/standing-terms.mjs +145 -6
  84. package/engine/standings.mjs +37 -49
  85. package/engine/web-wikilinks.mjs +21 -1
  86. package/engine/wikilink-syntax.mjs +34 -4
  87. package/engine/wikilinks.mjs +27 -2
  88. package/engine/yaml-lint.mjs +7 -4
  89. package/hugo-theme/layouts/partials/infobox/entry.html +4 -1
  90. package/hugo-theme/layouts/partials/page-body.html +0 -3
  91. package/hugo-theme/static/css/style.css +25 -55
  92. package/package.json +1 -2
  93. package/packagebuild-metadata.jsonl +13 -13
  94. package/release.mjs +62 -4
  95. package/sohl/note-schemas.mjs +8 -73
  96. package/types/engine/address-values.d.mts +50 -3
  97. package/types/engine/address.d.mts +21 -0
  98. package/types/engine/anchors.d.mts +49 -2
  99. package/types/engine/art-slots.d.mts +1 -1
  100. package/types/engine/base-compiler.d.mts +13 -4
  101. package/types/engine/calendar-notes.d.mts +7 -0
  102. package/types/engine/content-format.d.mts +52 -0
  103. package/types/engine/content-images.d.mts +5 -1
  104. package/types/engine/content-tables.d.mts +9 -1
  105. package/types/engine/data-keys.d.mts +145 -0
  106. package/types/engine/derived-sections.d.mts +73 -0
  107. package/types/engine/diagnostics.d.mts +15 -0
  108. package/types/engine/event-fields.d.mts +99 -0
  109. package/types/engine/event-rows.d.mts +12 -0
  110. package/types/engine/event-views.d.mts +67 -0
  111. package/types/engine/exported-scene.d.mts +5 -2
  112. package/types/engine/frontmatter-lint.d.mts +3 -3
  113. package/types/engine/generated-sections.d.mts +143 -0
  114. package/types/engine/holdings.d.mts +6 -20
  115. package/types/engine/ids.d.mts +15 -12
  116. package/types/engine/index.d.mts +1 -1
  117. package/types/engine/infobox.d.mts +13 -3
  118. package/types/engine/journals.d.mts +24 -11
  119. package/types/engine/literature-works.d.mts +1 -2
  120. package/types/engine/map-graphviz.d.mts +2 -10
  121. package/types/engine/markdown-expressions.d.mts +12 -3
  122. package/types/engine/near-miss.d.mts +42 -0
  123. package/types/engine/note-addresses.d.mts +7 -1
  124. package/types/engine/note-event-terms.d.mts +68 -0
  125. package/types/engine/note-events.d.mts +71 -0
  126. package/types/engine/note-vocabulary.d.mts +37 -8
  127. package/types/engine/office-holders.d.mts +3 -0
  128. package/types/engine/pdf-index.d.mts +35 -0
  129. package/types/engine/pdf-render.d.mts +8 -2
  130. package/types/engine/place-relation-terms.d.mts +83 -0
  131. package/types/engine/place-relations.d.mts +11 -66
  132. package/types/engine/rank-ladder.d.mts +2 -0
  133. package/types/engine/region-events.d.mts +6 -12
  134. package/types/engine/scenes.d.mts +6 -32
  135. package/types/engine/site-build.d.mts +8 -22
  136. package/types/engine/site-maps.d.mts +15 -7
  137. package/types/engine/sql-tables.d.mts +77 -2
  138. package/types/engine/standing-terms.d.mts +37 -4
  139. package/types/engine/standings.d.mts +14 -9
  140. package/types/engine/wikilink-syntax.d.mts +20 -0
  141. package/types/engine/wikilinks.d.mts +3 -2
  142. package/types/engine/yaml-lint.d.mts +5 -4
  143. package/types/release.d.mts +4 -0
  144. package/docs/guides/government-migration.md +0 -52
  145. package/engine/itinerary-scenes.mjs +0 -166
  146. package/engine/lore-events.mjs +0 -197
  147. package/engine/map-notes.mjs +0 -1309
  148. package/engine/map-raster.mjs +0 -51
  149. package/hugo-theme/layouts/partials/holdings/entry.html +0 -21
  150. package/hugo-theme/layouts/partials/holdings/kind-groups.html +0 -71
  151. package/hugo-theme/layouts/partials/holdings.html +0 -61
  152. package/hugo-theme/layouts/partials/literature-works.html +0 -29
  153. package/hugo-theme/layouts/partials/place-map.html +0 -9
  154. package/types/engine/itinerary-scenes.d.mts +0 -29
  155. package/types/engine/lore-events.d.mts +0 -14
  156. package/types/engine/map-notes.d.mts +0 -297
  157. package/types/engine/map-raster.d.mts +0 -8
@@ -7,7 +7,6 @@ types:
7
7
  - templatePriority
8
8
  - archetypes
9
9
  - occupation
10
- - social
11
10
  - stations
12
11
  - lore
13
12
  - culture
@@ -44,6 +43,7 @@ types:
44
43
  affiliation:
45
44
  data:
46
45
  - templatePriority
46
+ - events
47
47
  - demonym
48
48
  - epithet
49
49
  - symbol
@@ -94,6 +94,8 @@ types:
94
94
  - value
95
95
  - quality
96
96
  - durability
97
+ - made
98
+ - lost
97
99
  subTypes: []
98
100
  armorlocation:
99
101
  data:
@@ -110,6 +112,8 @@ types:
110
112
  - value
111
113
  - quality
112
114
  - durability
115
+ - made
116
+ - lost
113
117
  - quantity
114
118
  - potency
115
119
  - strength
@@ -124,6 +128,8 @@ types:
124
128
  - value
125
129
  - quality
126
130
  - durability
131
+ - made
132
+ - lost
127
133
  - capacity
128
134
  subTypes: []
129
135
  miscgear:
@@ -133,6 +139,8 @@ types:
133
139
  - value
134
140
  - quality
135
141
  - durability
142
+ - made
143
+ - lost
136
144
  - quantity
137
145
  subTypes: []
138
146
  mystery:
@@ -179,6 +187,8 @@ types:
179
187
  - value
180
188
  - quality
181
189
  - durability
190
+ - made
191
+ - lost
182
192
  - quantity
183
193
  subTypes:
184
194
  - none
@@ -231,6 +241,8 @@ types:
231
241
  - value
232
242
  - quality
233
243
  - durability
244
+ - made
245
+ - lost
234
246
  subTypes: []
235
247
  lore:
236
248
  data:
@@ -267,21 +279,6 @@ types:
267
279
  data:
268
280
  - scene
269
281
  - fixup
270
- - bgImage
271
- - scale
272
- - dimensions
273
- - pxPerGrid
274
- - navName
275
- - levelName
276
- - backgroundColor
277
- - overlay
278
- - walls
279
- - doors
280
- - lights
281
- - tiles
282
- - sounds
283
- - regions
284
- - notes
285
282
  - place
286
283
  subTypes:
287
284
  - battlemap
@@ -290,6 +287,7 @@ types:
290
287
  - totm
291
288
  place:
292
289
  data:
290
+ - events
293
291
  - calendar
294
292
  - demonym
295
293
  - purpose
@@ -745,3 +743,68 @@ vocabularies:
745
743
  - open-sea
746
744
  - river
747
745
  - lake
746
+ eventKind:
747
+ - arrival
748
+ - departure
749
+ - migration
750
+ - contact
751
+ - displacement
752
+ - founding
753
+ - charter
754
+ - accession
755
+ - secession
756
+ - conquest
757
+ - treaty
758
+ - dissolution
759
+ - battle
760
+ - war
761
+ - siege
762
+ - revolt
763
+ - fall
764
+ - catastrophe
765
+ - plague
766
+ - famine
767
+ - raising
768
+ - ruin
769
+ - making
770
+ - loss
771
+ - discovery
772
+ - schism
773
+ - law
774
+ - council
775
+ - birth
776
+ - death
777
+ depth:
778
+ - world
779
+ - region
780
+ - local
781
+ standing:
782
+ - attested
783
+ - single-source
784
+ - reconstructed
785
+ - disputed
786
+ - legendary
787
+ knowledge:
788
+ - named
789
+ - misattributed
790
+ - unlinked
791
+ role:
792
+ - actor
793
+ - victim
794
+ - instrument
795
+ - witness
796
+ - founder
797
+ - ruler
798
+ - author
799
+ - signatory
800
+ followsHow:
801
+ - caused
802
+ - enabled
803
+ - ended
804
+ - answered
805
+ agrees:
806
+ - full
807
+ - partly
808
+ - disputes
809
+ - denies
810
+ - silent
@@ -84,6 +84,7 @@ import { positionInBody } from "./diagnostics.mjs";
84
84
  import { FOOTNOTE_REFERENCE } from "./content-footnotes.mjs";
85
85
  import { foundryAddressProblem, pathnameProblem, servesFoundry } from "./pathnames.mjs";
86
86
  import { ASSET_ROLES } from "./asset-index.mjs";
87
+ import { generatedDirectoryProblem } from "./generated-sections.mjs";
87
88
 
88
89
  /**
89
90
  * The width classes an image may carry, and what each means to a renderer.
@@ -503,11 +504,18 @@ export function imageSourcesIn(body) {
503
504
  * without any other pass noticing — see the Foundry address below. Omitted,
504
505
  * the config-free checks run alone, which is what lets a caller with no
505
506
  * repository to resolve still read a body.
507
+ * @param {boolean} [opts.generated] - Whether `body` is a note's generated
508
+ * sections, which name the build's own drawings under `generated/`; an
509
+ * author's text may not.
506
510
  * @returns {Array<{file: string, line: number, column: number|undefined,
507
511
  * severity: "error", message: string}>} One finding per defect, in source
508
512
  * order.
509
513
  */
510
- export function checkImages(body, file, { bodyLine = 1, bodyColumn = 1, lineMap, config } = {}) {
514
+ export function checkImages(
515
+ body,
516
+ file,
517
+ { bodyLine = 1, bodyColumn = 1, lineMap, config, generated = false } = {},
518
+ ) {
511
519
  const text = String(body ?? "");
512
520
  if (!text) return [];
513
521
 
@@ -532,6 +540,7 @@ export function checkImages(body, file, { bodyLine = 1, bodyColumn = 1, lineMap,
532
540
  const problem =
533
541
  imageSourceProblem(image.src) ||
534
542
  pathnameProblem(image.src) ||
543
+ (generated ? "" : generatedDirectoryProblem(image.src)) ||
535
544
  (foundry ? foundryAddressProblem(image.src, config) : "");
536
545
  if (problem) report(image.index, problem);
537
546
  if (image.title) {
@@ -92,7 +92,9 @@ import {
92
92
  decodeIndexAddresses,
93
93
  noteAddressContext,
94
94
  encodeAddresses,
95
+ publishAddresses,
95
96
  } from "./note-addresses.mjs";
97
+ import { AddressLink } from "./address-values.mjs";
96
98
  import fs from "node:fs";
97
99
  import path from "node:path";
98
100
 
@@ -102,14 +104,14 @@ import { metadataFileName } from "./metadata-index.mjs";
102
104
  import { collectAssetRecords } from "./asset-index.mjs";
103
105
  import { checkForeignAssetBindings } from "./asset-bindings.mjs";
104
106
  import { addressSlug, canonicalKey } from "./content-address.mjs";
105
- import { ownDocumentSystem } from "./address.mjs";
107
+ import { ownDocumentSystem, readCanonicalKey } from "./address.mjs";
106
108
  import { NOTE_SYSTEM } from "./systems.mjs";
107
109
  import { assetAddressIndex } from "./art-fields.mjs";
108
110
  import { embedRole } from "./content-embeds.mjs";
109
111
  // One reader for a note's anchors, shared with the link checker and with the
110
112
  // builds that emit a link. Re-exported because this is where callers
111
113
  // have always addressed it.
112
- import { collectAnchors } from "./anchors.mjs";
114
+ import { collectAnchors, eventAnchors } from "./anchors.mjs";
113
115
  import { NO_SYSTEM } from "./document-subtypes.mjs";
114
116
 
115
117
  /**
@@ -517,14 +519,28 @@ export function buildIndexRecord({
517
519
  aliasesAscii: asciiAliases(frontmatter?.name?.aliases),
518
520
  // Each anchor carries the link that reaches it, so a section is
519
521
  // addressable from the index without anyone re-deriving how an
520
- // anchor is spelled — and its file line, so an editor can jump
521
- // there rather than search for the heading.
522
+ // anchor is spelled — its file line, so an editor can jump
523
+ // there rather than search for the heading — and its kind, so
524
+ // a field accepting only an event can tell one from a heading.
525
+ // The note's events join the body's anchors: one namespace.
522
526
  anchors:
523
527
  stub ? null : (
524
- collectAnchors(body, bodyLine, resolveRole).map((a) => ({
525
- ...a,
526
- link: address ? `${address.slug}#${a.slug}` : null,
527
- }))
528
+ [
529
+ ...collectAnchors(body, bodyLine, resolveRole),
530
+ ...eventAnchors(frontmatter, rawNote(absPath)),
531
+ ]
532
+ .sort((a, b) => (a.line ?? 0) - (b.line ?? 0))
533
+ .map((a) => ({
534
+ ...a,
535
+ link:
536
+ address ?
537
+ new AddressLink(
538
+ readCanonicalKey(address.canonical),
539
+ a.slug,
540
+ a.kind,
541
+ )
542
+ : null,
543
+ }))
528
544
  ),
529
545
  foundry: foundryBlock(entries?.own, ownDocumentSystem(frontmatter?.type)),
530
546
  // Forward link to the note's documentation journal, which is its
@@ -550,6 +566,18 @@ export function buildIndexRecord({
550
566
  );
551
567
  }
552
568
 
569
+ /**
570
+ * A note's full text, for the line an event's `id` sits on; `undefined` when
571
+ * there is no file to read, so the line is dropped rather than guessed.
572
+ *
573
+ * @param {string} [absPath] - The note's file.
574
+ * @returns {string|undefined} Its contents.
575
+ */
576
+ function rawNote(absPath) {
577
+ if (!absPath || !fs.existsSync(absPath)) return undefined;
578
+ return fs.readFileSync(absPath, "utf8");
579
+ }
580
+
553
581
  /**
554
582
  * The record for an item note's **documentation journal**.
555
583
  *
@@ -848,7 +876,7 @@ export function collectContentIndex(
848
876
  */
849
877
  export function serializeContentIndex(records) {
850
878
  if (records.length === 0) return "";
851
- return `${records.map((r) => JSON.stringify(sortKeysDeep(encodeAddresses(r)))).join("\n")}\n`;
879
+ return `${records.map((r) => JSON.stringify(sortKeysDeep(publishAddresses(r)))).join("\n")}\n`;
852
880
  }
853
881
 
854
882
  /**
@@ -197,6 +197,8 @@ export function buildLinkIndex(
197
197
  /** Canonical address to asset record, for the files this package ships. */
198
198
  const byAssetKey = new Map();
199
199
  const anchors = new Map();
200
+ /** Each note to the ids of its events, which a wikilink may not name. */
201
+ const eventAnchorsOf = new Map();
200
202
 
201
203
  for (const record of indexRecords) {
202
204
  // An asset's record addresses a file rather than a note: there is no
@@ -231,7 +233,14 @@ export function buildLinkIndex(
231
233
 
232
234
  // The anchors the index recorded, rather than a second reading of the
233
235
  // same headings — the disagreement the anchor half removes.
234
- anchors.set(note, new Set((record.anchors ?? []).map((a) => a.slug)));
236
+ anchors.set(
237
+ note,
238
+ new Set((record.anchors ?? []).filter((a) => a.kind === "prose").map((a) => a.slug)),
239
+ );
240
+ eventAnchorsOf.set(
241
+ note,
242
+ new Set((record.anchors ?? []).filter((a) => a.kind === "event").map((a) => a.slug)),
243
+ );
235
244
 
236
245
  if (typeof fm.shortcode === "string" && fm.shortcode) {
237
246
  // Canonical addresses only. Every written target expands to one
@@ -251,10 +260,11 @@ export function buildLinkIndex(
251
260
  // filed where a link cannot reach it and a reference still can.
252
261
  const into = record.address ? byKey : byStub;
253
262
  into.set(canonical, note);
254
- if (hasDocEntry(type)) {
255
- // The prose has one `note` Address across all system blocks.
263
+ // The prose has one `note` Address across all system blocks, and
264
+ // every note answers to it — whether or not a system compiles the
265
+ // type into a document of its own, as the site index keys it.
266
+ if (hasDocEntry(type) || ownDocumentSystem(type) !== NOTE_SYSTEM)
256
267
  into.set(canonicalKey(pkg, NOTE_SYSTEM, type, fm.shortcode), note);
257
- }
258
268
  }
259
269
  }
260
270
 
@@ -599,6 +609,7 @@ export function buildLinkIndex(
599
609
  notes,
600
610
  frontmatterLinks,
601
611
  anchors,
612
+ eventAnchorsOf,
602
613
  types,
603
614
  packages,
604
615
  /** Packages declared `contentIndex: false`, a Foundry dependency only. */
@@ -953,6 +964,10 @@ export function auditLinks(index) {
953
964
  if (!dest) continue;
954
965
  if (!(anchors.get(dest) ?? new Set()).has(slugify(anchor))) {
955
966
  deadAnchors.push({
967
+ reason:
968
+ (index.eventAnchorsOf?.get(dest) ?? new Set()).has(anchor) ?
969
+ "event-anchor"
970
+ : "unknown-anchor",
956
971
  note,
957
972
  link: `${rawTarget}#${anchor}`,
958
973
  // The two the shared `unknown-anchor` wording reads, in the
@@ -980,7 +995,11 @@ export function auditLinks(index) {
980
995
  if (!labelled) {
981
996
  unlabelledLinks.push({
982
997
  note,
983
- target: rawTarget || (anchor ? `#${anchor}` : ""),
998
+ // Quoted as written, anchor included — the literal between
999
+ // the brackets, as the site build quotes it.
1000
+ target:
1001
+ /^!?\[\[([\s\S]*)\]\]$/.exec(text ?? "")?.[1] ??
1002
+ `${rawTarget ?? ""}${anchor ? `#${anchor}` : ""}`,
984
1003
  text,
985
1004
  occurrence,
986
1005
  // Carried like every other finding's, so a reporter reads
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { FENCE_LINE } from "./code-fences.mjs";
4
4
  import { PAGE_LIST_LANGUAGE } from "./page-lists.mjs";
5
+ import { appendGeneratedSections } from "./generated-sections.mjs";
5
6
 
6
7
  /**
7
8
  * Replace prepared SQL fences and page lists with Markdown while retaining
@@ -15,10 +16,23 @@ import { PAGE_LIST_LANGUAGE } from "./page-lists.mjs";
15
16
  * @param {string} markdown - The authored body.
16
17
  * @param {{source?: string, sqlTables?: object[], pageLists?: object[]}} [context] -
17
18
  * Prepared results.
18
- * @returns {{markdown: string, errors: object[], warnings: object[], lineMap: object[]}}
19
+ * A note's generated sections — see {@link module:engine/generated-sections} —
20
+ * are appended to the body first, from the `generated` text the preparation
21
+ * set on its results, and expanded with it.
22
+ *
23
+ * @returns {{markdown: string, errors: object[], warnings: object[], lineMap: object[],
24
+ * generatedFrom?: number}} `generatedFrom` is the 0-based line of the
25
+ * expanded body the generated sections start on, where there are any — what
26
+ * a surface reads to tell them from the author's text.
19
27
  */
20
28
  export function expandContentTables(markdown, { source = "", sqlTables, pageLists } = {}) {
21
- const lines = String(markdown ?? "").split("\n");
29
+ // A note's generated sections follow its own text, joined exactly as the
30
+ // pass that answered their fences joined them.
31
+ const authored = String(markdown ?? "");
32
+ const lines = String(appendGeneratedSections(authored, sqlTables?.generated)).split("\n");
33
+ const sectionsStart =
34
+ sqlTables?.generated ? authored.replace(/\s+$/, "").split("\n").length + 1 : -1;
35
+ let generatedFrom;
22
36
  const out = [];
23
37
  const lineMap = [];
24
38
  const errors = [];
@@ -30,6 +44,7 @@ export function expandContentTables(markdown, { source = "", sqlTables, pageList
30
44
  lineMap.push({ line, generated });
31
45
  };
32
46
  for (let i = 0; i < lines.length; i++) {
47
+ if (i === sectionsStart) generatedFrom = out.length;
33
48
  const opening = FENCE_LINE.exec(lines[i]);
34
49
  if (!opening) {
35
50
  emit(lines[i], i);
@@ -121,5 +136,11 @@ export function expandContentTables(markdown, { source = "", sqlTables, pageList
121
136
  if (close + 1 < lines.length && lines[close + 1].trim()) emit("", i, true);
122
137
  i = close;
123
138
  }
124
- return { markdown: out.join("\n"), errors, warnings, lineMap };
139
+ return {
140
+ markdown: out.join("\n"),
141
+ errors,
142
+ warnings,
143
+ lineMap,
144
+ ...(generatedFrom === undefined ? {} : { generatedFrom }),
145
+ };
125
146
  }