@heroiclands/package-build 20.3.1 → 20.4.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 (178) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/CONTENT.md +111 -92
  3. package/README.md +2 -9
  4. package/bin/content-build.mjs +70 -61
  5. package/bin/package-build.mjs +2 -2
  6. package/config.mjs +6 -8
  7. package/content-config.mjs +187 -64
  8. package/docs/content-format.md +57 -68
  9. package/e2e.mjs +4 -4
  10. package/engine/actor-compiler.mjs +36 -36
  11. package/engine/address-charset.mjs +6 -6
  12. package/engine/address-diff.mjs +12 -11
  13. package/engine/anchored-sections.mjs +1 -1
  14. package/engine/anchors.mjs +1 -1
  15. package/engine/base-compiler.mjs +36 -38
  16. package/engine/bundle-notes.mjs +4 -4
  17. package/engine/bundles.mjs +8 -8
  18. package/engine/code-fences.mjs +3 -3
  19. package/engine/compendiums.mjs +8 -8
  20. package/engine/compile-corpus.mjs +4 -5
  21. package/engine/content-address.mjs +15 -15
  22. package/engine/content-charset.mjs +1 -1
  23. package/engine/content-format-check.mjs +24 -25
  24. package/engine/content-format.mjs +8 -8
  25. package/engine/content-html.mjs +202 -0
  26. package/engine/content-icons.mjs +196 -165
  27. package/engine/content-index.mjs +17 -17
  28. package/engine/content-links.mjs +30 -30
  29. package/engine/content-lint.mjs +20 -24
  30. package/engine/content-package.mjs +7 -9
  31. package/engine/content-slug.mjs +2 -2
  32. package/engine/content-tables.mjs +7 -8
  33. package/engine/content-tree.mjs +1 -1
  34. package/engine/derived-fields.mjs +174 -0
  35. package/engine/diagnostics.mjs +3 -4
  36. package/engine/document-subtypes.mjs +6 -7
  37. package/engine/field-reference.mjs +8 -8
  38. package/engine/field-spec.mjs +29 -30
  39. package/engine/folder-notes.mjs +14 -14
  40. package/engine/foreign-catalog.mjs +8 -9
  41. package/engine/foundry-entries.mjs +19 -20
  42. package/engine/frontmatter-lint.mjs +64 -69
  43. package/engine/frontmatter.mjs +11 -11
  44. package/engine/generate.mjs +39 -39
  45. package/engine/helpers.mjs +63 -54
  46. package/engine/homepage.mjs +20 -22
  47. package/engine/ids.mjs +15 -15
  48. package/engine/index-records.mjs +4 -4
  49. package/engine/index.mjs +14 -8
  50. package/engine/item-compiler.mjs +54 -29
  51. package/engine/item-docs.mjs +11 -13
  52. package/engine/item-registry.mjs +13 -13
  53. package/engine/journals.mjs +15 -15
  54. package/engine/macros.mjs +3 -3
  55. package/engine/map-notes.mjs +6 -6
  56. package/engine/metadata-index.mjs +5 -5
  57. package/engine/note-claims.mjs +36 -34
  58. package/engine/note-ids.mjs +5 -5
  59. package/engine/note-package.mjs +4 -4
  60. package/engine/note-renames.mjs +3 -3
  61. package/engine/note-schemas.mjs +3 -3
  62. package/engine/note-vocabulary.mjs +27 -26
  63. package/engine/pack-config.mjs +13 -13
  64. package/engine/pack-router.mjs +0 -0
  65. package/engine/prose-config.mjs +9 -9
  66. package/engine/prose-lint.mjs +12 -13
  67. package/engine/region-events.mjs +2 -2
  68. package/engine/retired-fields.mjs +24 -22
  69. package/engine/runtime-only-fields.mjs +1 -1
  70. package/engine/scene-levels.mjs +1 -1
  71. package/engine/scenes.mjs +19 -20
  72. package/engine/schema-check.mjs +20 -20
  73. package/engine/schema-extract.mjs +1 -1
  74. package/engine/site-build.mjs +45 -47
  75. package/engine/site-index.mjs +17 -18
  76. package/engine/sql-tables.mjs +21 -13
  77. package/engine/subtype-registry.mjs +5 -4
  78. package/engine/system-block.mjs +18 -19
  79. package/engine/systems.mjs +2 -2
  80. package/engine/web-wikilinks.mjs +35 -35
  81. package/engine/wikilink-syntax.mjs +16 -16
  82. package/engine/wikilinks.mjs +39 -39
  83. package/hm3/actors.mjs +22 -22
  84. package/hm3/document-subtypes.mjs +5 -5
  85. package/hm3/index.mjs +2 -2
  86. package/hm3/item-builders.mjs +1 -1
  87. package/hm3/item-fields.mjs +3 -3
  88. package/hm3/items.mjs +20 -8
  89. package/hm3/template-priority.mjs +2 -2
  90. package/lang.mjs +3 -3
  91. package/manifest.mjs +17 -20
  92. package/package.json +1 -2
  93. package/release.mjs +3 -3
  94. package/sohl/actors.mjs +28 -28
  95. package/sohl/affiliation-standings.mjs +2 -2
  96. package/sohl/being-info.mjs +5 -5
  97. package/sohl/default-item-art.mjs +5 -5
  98. package/sohl/document-subtypes.mjs +5 -5
  99. package/sohl/index.mjs +3 -3
  100. package/sohl/item-builders.mjs +7 -7
  101. package/sohl/item-fields.mjs +8 -9
  102. package/sohl/items.mjs +20 -6
  103. package/sohl/kb-passes.mjs +5 -5
  104. package/sohl/note-schemas.mjs +7 -7
  105. package/sohl/skill-base.mjs +1 -1
  106. package/types/content-config.d.mts +25 -24
  107. package/types/e2e.d.mts +3 -3
  108. package/types/engine/actor-compiler.d.mts +14 -13
  109. package/types/engine/address-charset.d.mts +6 -6
  110. package/types/engine/address-diff.d.mts +3 -3
  111. package/types/engine/base-compiler.d.mts +17 -19
  112. package/types/engine/bundle-notes.d.mts +3 -3
  113. package/types/engine/bundles.d.mts +1 -1
  114. package/types/engine/code-fences.d.mts +3 -3
  115. package/types/engine/compendiums.d.mts +3 -3
  116. package/types/engine/compile-corpus.d.mts +1 -1
  117. package/types/engine/content-address.d.mts +11 -11
  118. package/types/engine/content-format-check.d.mts +6 -6
  119. package/types/engine/content-format.d.mts +2 -2
  120. package/types/engine/content-html.d.mts +78 -0
  121. package/types/engine/content-icons.d.mts +139 -92
  122. package/types/engine/content-index.d.mts +2 -2
  123. package/types/engine/content-links.d.mts +8 -8
  124. package/types/engine/content-lint.d.mts +2 -2
  125. package/types/engine/content-package.d.mts +6 -8
  126. package/types/engine/derived-fields.d.mts +101 -0
  127. package/types/engine/diagnostics.d.mts +2 -2
  128. package/types/engine/document-subtypes.d.mts +3 -3
  129. package/types/engine/field-spec.d.mts +37 -39
  130. package/types/engine/folder-notes.d.mts +4 -5
  131. package/types/engine/foreign-catalog.d.mts +3 -3
  132. package/types/engine/foundry-entries.d.mts +6 -7
  133. package/types/engine/frontmatter-lint.d.mts +7 -7
  134. package/types/engine/frontmatter.d.mts +7 -7
  135. package/types/engine/generate.d.mts +7 -7
  136. package/types/engine/helpers.d.mts +25 -27
  137. package/types/engine/homepage.d.mts +16 -18
  138. package/types/engine/ids.d.mts +13 -13
  139. package/types/engine/index-records.d.mts +3 -3
  140. package/types/engine/index.d.mts +2 -0
  141. package/types/engine/item-compiler.d.mts +21 -5
  142. package/types/engine/item-docs.d.mts +2 -2
  143. package/types/engine/item-registry.d.mts +6 -6
  144. package/types/engine/journals.d.mts +3 -3
  145. package/types/engine/map-notes.d.mts +2 -2
  146. package/types/engine/metadata-index.d.mts +4 -4
  147. package/types/engine/note-claims.d.mts +16 -15
  148. package/types/engine/note-ids.d.mts +4 -4
  149. package/types/engine/note-package.d.mts +1 -1
  150. package/types/engine/note-renames.d.mts +3 -3
  151. package/types/engine/note-vocabulary.d.mts +9 -8
  152. package/types/engine/pack-config.d.mts +3 -3
  153. package/types/engine/pack-router.d.mts +1 -1
  154. package/types/engine/prose-config.d.mts +9 -9
  155. package/types/engine/prose-lint.d.mts +3 -4
  156. package/types/engine/region-events.d.mts +2 -2
  157. package/types/engine/retired-fields.d.mts +10 -9
  158. package/types/engine/schema-check.d.mts +11 -11
  159. package/types/engine/site-build.d.mts +18 -19
  160. package/types/engine/site-index.d.mts +3 -4
  161. package/types/engine/sql-tables.d.mts +11 -5
  162. package/types/engine/subtype-registry.d.mts +3 -3
  163. package/types/engine/system-block.d.mts +3 -3
  164. package/types/engine/web-wikilinks.d.mts +7 -7
  165. package/types/engine/wikilink-syntax.d.mts +17 -17
  166. package/types/engine/wikilinks.d.mts +13 -12
  167. package/types/hm3/actors.d.mts +1 -1
  168. package/types/hm3/document-subtypes.d.mts +1 -1
  169. package/types/hm3/items.d.mts +1 -2
  170. package/types/hm3/template-priority.d.mts +1 -1
  171. package/types/manifest.d.mts +8 -8
  172. package/types/sohl/actors.d.mts +2 -2
  173. package/types/sohl/affiliation-standings.d.mts +2 -2
  174. package/types/sohl/being-info.d.mts +2 -2
  175. package/types/sohl/document-subtypes.d.mts +1 -1
  176. package/types/sohl/items.d.mts +1 -2
  177. package/types/sohl/note-schemas.d.mts +1 -1
  178. package/MIGRATING.md +0 -608
@@ -5,7 +5,7 @@
5
5
  * note is one this build **refused** — it declares a retired frontmatter field
6
6
  * — and it is an error; a skipped one legitimately belongs to another pass, and
7
7
  * there are thousands of those. Folding the first into the second is what let a
8
- * whole tree be filtered out in silence (#56).
8
+ * whole tree be filtered out in silence.
9
9
  *
10
10
  * @typedef {object} PassStats
11
11
  * @property {number} compiled - Notes that became a document.
@@ -13,7 +13,7 @@
13
13
  * @property {number} skippedOther - Notes this pass does not claim.
14
14
  * @property {number} declined - Notes this pack **refused** — one declaring a
15
15
  * retired frontmatter field, or one routed to a system pack whose system it
16
- * says nothing about (#58). Counted as errors, never as skips.
16
+ * says nothing about. Counted as errors, never as skips.
17
17
  */
18
18
  /**
19
19
  * The shared walk → filter → expand → convert → build → write → count loop.
@@ -51,7 +51,7 @@ export class BasePackCompiler {
51
51
  * its generated tables expanded and its wikilinks converted.
52
52
  *
53
53
  * False for a pass whose output must be exactly what the author typed —
54
- * the macros pass, whose `command` is executable source (#1514). A pass
54
+ * the macros pass, whose `command` is executable source. A pass
55
55
  * that says so also skips building the content-wide link index it would
56
56
  * never read.
57
57
  *
@@ -67,7 +67,7 @@ export class BasePackCompiler {
67
67
  * passes wrote — so an Actor pass must run after every Item pass, and it
68
68
  * says so here.
69
69
  *
70
- * The generator derives the compile order from this (#73), so the order
70
+ * The generator derives the compile order from this, so the order
71
71
  * `packs:` declares is presentation only — it is the manifest's `packs`
72
72
  * array as well, and a consumer orders that for a reader. A pass that
73
73
  * reads another's output states the dependency once, in the class that
@@ -82,7 +82,7 @@ export class BasePackCompiler {
82
82
  static readsPackOutputOf: readonly string[];
83
83
  /**
84
84
  * Whether this pass's document **is** a system's data, and therefore takes
85
- * only notes that carry that system's block (#58).
85
+ * only notes that carry that system's block.
86
86
  *
87
87
  * A pack may declare a `system:` — `harn-ensemble` ships an `actors-hm3`
88
88
  * and an `actors-sohl` from one tree — and the note-side half of that is
@@ -112,7 +112,7 @@ export class BasePackCompiler {
112
112
  * legal on every note whatever its type, because
113
113
  * `BLOCK_DOCUMENT_PROPERTIES` maps it onto `document.img` — so a note whose
114
114
  * document has no such property authors it, validates, compiles, and loses
115
- * the value with nothing said. That is #349: `Parrot` in `sohl-thalorna`
115
+ * the value with nothing said: `Parrot` in `sohl-thalorna`
116
116
  * had declared `img:` since long before the art rule existed and compiled
117
117
  * `img: null` exactly as a note declaring nothing does. Naming the fields
118
118
  * here is what lets the lint tell an inert key from a live one.
@@ -134,7 +134,7 @@ export class BasePackCompiler {
134
134
  * never descends into. Required: see {@link assertStatedScope}.
135
135
  * @param {(address: string|null) => string|null} [options.folderResolver] -
136
136
  * Resolves a `packFolder` — a folder note's address — to the Foundry
137
- * folder id it materialises as in this pack (#255, #257).
137
+ * folder id it materialises as in this pack.
138
138
  * @param {string} [options.packName] - The pack this pass writes.
139
139
  * @param {string} [options.docType] - The Foundry document type it holds.
140
140
  * @param {{resolve: Function}} [options.router] - The pack router. Omit it
@@ -163,7 +163,7 @@ export class BasePackCompiler {
163
163
  /** @type {number} */
164
164
  errorCount: number;
165
165
  /**
166
- * Emitted-`system` findings, one per `documentType|subtype|field` (#155).
166
+ * Emitted-`system` findings, one per `documentType|subtype|field`.
167
167
  *
168
168
  * A key the compiler writes is on **every** document of a subtype, so
169
169
  * reporting it where it is found would print the same sentence 3,126 times
@@ -222,7 +222,7 @@ export class BasePackCompiler {
222
222
  packSystem: any;
223
223
  corpus: any;
224
224
  /**
225
- * The `_stats` block every entry this pass emits is stamped with (#48).
225
+ * The `_stats` block every entry this pass emits is stamped with.
226
226
  *
227
227
  * Per pack rather than per package, because a module may ship the same
228
228
  * content for two systems — `harn-ensemble` has an `actors-hm3` pack and an
@@ -252,8 +252,7 @@ export class BasePackCompiler {
252
252
  * routed *here* and carries nothing for this pack's system is an authoring
253
253
  * mistake with a hollow document at the end of it, not a note that belongs
254
254
  * to another pass. Skipping it quietly is how a whole tree compiles to
255
- * documents nobody can use — the failure mode #1502 and #56 are both
256
- * instances of.
255
+ * documents nobody can use.
257
256
  *
258
257
  * @param {object} fm - The note's frontmatter.
259
258
  * @returns {boolean} True when the note may be compiled here; `false` when
@@ -266,7 +265,7 @@ export class BasePackCompiler {
266
265
  eligibleFor(fm: object): boolean;
267
266
  /**
268
267
  * A refusal only this pass can make, because its subject is the note's
269
- * **type** (#330).
268
+ * **type**.
270
269
  *
271
270
  * The `assertNo*Field` family above it in the walk is type-agnostic by
272
271
  * construction: it runs before `selects`, so that a note declaring a
@@ -291,7 +290,7 @@ export class BasePackCompiler {
291
290
  * Whether this pass claims a note. **Required.**
292
291
  *
293
292
  * Called only for a note this build compiles — every note in the tree
294
- * belongs to the configured content package (#56) — so a subclass decides
293
+ * belongs to the configured content package — so a subclass decides
295
294
  * on `type` alone.
296
295
  *
297
296
  * @param {object} fm - The note's frontmatter.
@@ -368,8 +367,7 @@ export class BasePackCompiler {
368
367
  column?: number;
369
368
  }): void;
370
369
  /**
371
- * Report every `<system>.system` key the receiving subtype does not declare
372
- * (#58).
370
+ * Report every `<system>.system` key the receiving subtype does not declare.
373
371
  *
374
372
  * An **error**, not a warning: Foundry drops an unknown `system` key at
375
373
  * construction without a word, so the alternative is a document shipped
@@ -390,7 +388,7 @@ export class BasePackCompiler {
390
388
  reportUndeclaredSystemData(fm: object, block: string, documentType: string, subType: string): number;
391
389
  /**
392
390
  * Record every `system` key the *compiled document* carries that the
393
- * receiving subtype does not declare (#155).
391
+ * receiving subtype does not declare.
394
392
  *
395
393
  * The sibling of {@link BasePackCompiler#reportUndeclaredSystemData}, and
396
394
  * the half that sees what no declaration states. A compiler writes keys of
@@ -434,7 +432,7 @@ export class BasePackCompiler {
434
432
  /**
435
433
  * Emit the collected emitted-`system` findings, once each.
436
434
  *
437
- * An **error**, for the reason #60 made its sibling one: the value is gone
435
+ * An **error**, for the reason its sibling is one: the value is gone
438
436
  * at load and the build says nothing, and severity that varied by *which
439
437
  * part of the build wrote the key* would make the less fixable half the
440
438
  * quieter one. What varies is the message, which says whose fix it is —
@@ -529,7 +527,7 @@ export class BasePackCompiler {
529
527
  * note is one this build **refused** — it declares a retired frontmatter field
530
528
  * — and it is an error; a skipped one legitimately belongs to another pass, and
531
529
  * there are thousands of those. Folding the first into the second is what let a
532
- * whole tree be filtered out in silence (#56).
530
+ * whole tree be filtered out in silence.
533
531
  */
534
532
  export type PassStats = {
535
533
  /**
@@ -547,7 +545,7 @@ export type PassStats = {
547
545
  /**
548
546
  * - Notes this pack **refused** — one declaring a
549
547
  * retired frontmatter field, or one routed to a system pack whose system it
550
- * says nothing about (#58). Counted as errors, never as skips.
548
+ * says nothing about. Counted as errors, never as skips.
551
549
  */
552
550
  declined: number;
553
551
  };
@@ -35,7 +35,7 @@ export function bareAddress(value: unknown): string | null;
35
35
  * `### type: bundle` table puts it — the closed container, so a misspelled
36
36
  * `content` is a finding rather than a silently empty Adventure. It is accepted
37
37
  * at the top level too, exactly as a folder note's `parent` is: an author
38
- * following #259's own example rather than the specification should get a
38
+ * following the shipped example rather than the specification should get a
39
39
  * bundle, not a silent default.
40
40
  *
41
41
  * **Order is the author's**, and it is kept: an Adventure's `SetField` attaches
@@ -124,9 +124,9 @@ export function buildAdventure({ id, name, img, description, caption, folder, fl
124
124
  * world's collection already holds that `_id`, then creates or updates each.
125
125
  * Afterwards the documents live independently and the Adventure has no further
126
126
  * role. **It is an installer** — a set of document *copies* packaged for
127
- * one-shot import (#259).
127
+ * one-shot import.
128
128
  *
129
- * That is the whole difference from a folder (#256), which is a live grouping
129
+ * That is the whole difference from a folder, which is a live grouping
130
130
  * **by reference** that persists in the pack. A bundle carries copies and
131
131
  * exists to be imported once, so the two are not variations on one idea.
132
132
  *
@@ -8,7 +8,7 @@
8
8
  * the first.
9
9
  *
10
10
  * A **folder** document is skipped. It is emitted into every pack that holds
11
- * something filed in it (#257), so it is not one pack's document and has no
11
+ * something filed in it, so it is not one pack's document and has no
12
12
  * single note behind it; a bundle that wants folders is a question this pass
13
13
  * refuses rather than guesses at — see {@link Bundles#resolveAddress}.
14
14
  *
@@ -94,12 +94,12 @@ export function matchAllOutsideCode(markdown: string, pattern: RegExp, options?:
94
94
  * **Which runs count as code is {@link codeRegions}' rule, not a second copy of
95
95
  * it.** The knowledgebase build carried its own regex once, and it was weaker in
96
96
  * two ways that both corrupted the one page whose subject *is* link syntax — so
97
- * its examples were exactly the input a looser rule mangles (SoHL#1665). A
97
+ * its examples are exactly the input a looser rule mangles. A
98
98
  * single-backtick span was allowed to cross newlines, so one odd backtick paired
99
99
  * with another paragraphs away and every span after it paired wrongly: prose was
100
100
  * masked as code while real spans were left exposed. And only three-backtick
101
101
  * fences were recognised, so a four-backtick example holding a three-backtick
102
- * block — the documented "fences of any length" case (#1505) — leaked its
102
+ * block — the documented "fences of any length" case — leaked its
103
103
  * contents.
104
104
  *
105
105
  * @param {string} body - The markdown body.
@@ -114,7 +114,7 @@ export function protectCode(body: string, transform: (masked: string) => string)
114
114
  * written. Every build-time rewriter that pattern-matches a body therefore has
115
115
  * to know where code is — otherwise a source listing that happens to contain
116
116
  * the rewriter's syntax is silently corrupted. Wikilink conversion met this as
117
- * `[[0]]` inside a fence being turned into a link (#1505), and it depended on
117
+ * `[[0]]` inside a fence being turned into a link, and it depended on
118
118
  * the surrounding literal's shape (`[[1,2],[3,4]]` survived), so the corruption
119
119
  * looked arbitrary.
120
120
  *
@@ -6,7 +6,7 @@
6
6
  * @param {object} opts
7
7
  * @param {object} [opts.config] The resolved build configuration, which
8
8
  * the two path arguments below default from. Supplying one is how a caller
9
- * compiles a package other than this repository's (#1508).
9
+ * compiles a package other than this repository's.
10
10
  * @param {string[]} [opts.sourcePacks] Every pack compiled from the content
11
11
  * tree, in compile order. Defaults to the configured pack directories.
12
12
  * @param {string} [opts.stageDest] Directory the LevelDB packs are built
@@ -15,10 +15,10 @@
15
15
  * @throws {Error} If pack JSON generation reported any error. Packs compiled
16
16
  * from incomplete or empty JSON ship blank or short compendiums, and the
17
17
  * omission is invisible until a player looks for content that is not there
18
- * (#1502) — so this is fatal, not a warning, and the caller is expected to
18
+ * — so this is fatal, not a warning, and the caller is expected to
19
19
  * turn it into a failing exit code.
20
20
  * @throws {Error} If a compiled pack ships a Scene that has lost its embedded
21
- * Level (#1538). Fatal for the same reason: Foundry reads a missing Level
21
+ * Level. Fatal for the same reason: Foundry reads a missing Level
22
22
  * record as "no levels" and persists that on the next world launch, so the
23
23
  * map image is gone before anyone notices it was ever at risk. See
24
24
  * {@link verifyPackSceneLevels}.
@@ -4,7 +4,7 @@
4
4
  * @param {object} opts - Options.
5
5
  * @param {string} opts.contentBase - Root of the content tree.
6
6
  * @param {readonly string[]} opts.skipDirectories - The scope, stated by the
7
- * caller as every corpus read requires (#243).
7
+ * caller as every corpus read requires.
8
8
  * @param {object} opts.router - The pack router this compile resolved. Shared
9
9
  * by every pass, which is what makes one link index correct for all of them.
10
10
  * @param {object} [opts.config] - The resolved configuration.
@@ -6,7 +6,7 @@
6
6
  * key's **last two segments** — which is what makes a manifest entry's `path`
7
7
  * derivable from the key it is filed under rather than transported beside it.
8
8
  *
9
- * It was once the key's whole tail, and #59 ended that: the key gained a
9
+ * It is not the key's whole tail: the key carries a
10
10
  * `<system>` segment, so its tail is now `system-type-shortcode` and a slug is
11
11
  * the tail with that segment dropped. The behaviour here is unchanged, and
12
12
  * deliberately — a page has no system to name (see the module note above), so
@@ -50,9 +50,9 @@ export function addressSlug(fm: object): string;
50
50
  *
51
51
  * **It is a pure function of the frontmatter**, and takes no options. Nothing
52
52
  * about the file the note was read from reaches it: the `README.md` convention
53
- * that made one note address a whole section is retired with the section itself
54
- * (#204), so every note is addressed alike and there is one rule and no branch.
55
- * It took an address scheme until #215, to validate a `landing` rule it then
53
+ * that made one note address a whole section is retired with the section itself,
54
+ * so every note is addressed alike and there is one rule and no branch.
55
+ * It takes no address scheme; the `landing` rule it once validated is
56
56
  * discarded; with that key retired, `prefix` was the only thing left in the
57
57
  * scheme and the paragraph above is the reason it never applied.
58
58
  *
@@ -85,9 +85,9 @@ export function packageAddress(fm: object): string;
85
85
  * merge is a real conflict rather than an artefact of two packages sharing a
86
86
  * namespace. `(type, shortcode)` alone is unique only *within* a package, and
87
87
  * two independently authored packages reaching for the same short string is a
88
- * matter of time (#1499).
88
+ * matter of time.
89
89
  *
90
- * **The system segment (#59).** A package may ship content for more than one
90
+ * **The system segment.** A package may ship content for more than one
91
91
  * system, and one note then compiles into a document per system — an actor in
92
92
  * `actors-sohl` *and* an actor in `actors-hm3`. Without a system segment both
93
93
  * land on one key, so the address cannot name either of them. `harn-ensemble`
@@ -137,7 +137,7 @@ export function blockSystem(keyPath?: string): string;
137
137
  /**
138
138
  * Expand a written address to the one canonical address it names.
139
139
  *
140
- * **An omitted segment defaults from where the link is written** (#336) — it is
140
+ * **An omitted segment defaults from where the link is written** — it is
141
141
  * not a wildcard, and resolution is not a search. Package omitted means the
142
142
  * citing note's own; system omitted means {@link blockSystem} of the key path it
143
143
  * was written under. So every short form has exactly one expansion, computed
@@ -186,8 +186,8 @@ export function expandAddress(read: {
186
186
  * `^[A-Za-z0-9]+$` (`ADDRESS_SEGMENT_PATTERN` in `engine/address-charset.mjs`),
187
187
  * so the hyphen is purely a separator and the count alone determines every
188
188
  * field. That is enforced at each of the three sources rather than assumed of
189
- * the data: shortcodes by `content-lint.mjs` (#1397), `contentPackage` by
190
- * `defineConfig` (#59), and types are bare words. Were any of them free to
189
+ * the data: shortcodes by `content-lint.mjs`, `contentPackage` by
190
+ * `defineConfig`, and types are bare words. Were any of them free to
191
191
  * carry a hyphen, no amount of counting would recover the fields and the reader
192
192
  * would need a vocabulary to match against instead.
193
193
  *
@@ -251,7 +251,7 @@ export function packageRelative(url: string, base: string): string;
251
251
  export function resolvePackageUrl(rel: string, base: string): string;
252
252
  /**
253
253
  * The Foundry `_id` of the document a note compiles into, derived from its
254
- * canonical address (#270).
254
+ * canonical address.
255
255
  *
256
256
  * A note used to author this — an opaque 16-character string, one per note,
257
257
  * that said nothing its address did not and that no check guaranteed. The
@@ -278,7 +278,7 @@ export function resolvePackageUrl(rel: string, base: string): string;
278
278
  * @returns {string} A 16-character Foundry id.
279
279
  */
280
280
  export function documentId(pkg: string, system: string, type: string, shortcode: string): string;
281
- /** The knowledgebase's mount within this package's site (#1470). */
281
+ /** The knowledgebase's mount within this package's site. */
282
282
  export const KB_PREFIX: "kb/";
283
283
  /**
284
284
  * How many segments a canonical key has, and therefore how many the reader
@@ -22,7 +22,7 @@ export function declaredPaths(artifact: object): Set<string>;
22
22
  *
23
23
  * A shared row names no type, so it is placed rather than typed: "in the shared
24
24
  * mappings" instead of "on a `weapongear`". Reading `on a \`the shared
25
- * mappings\`` would be the alternative, and a diagnostic is prose (#275).
25
+ * mappings\`` would be the alternative, and a diagnostic is prose.
26
26
  *
27
27
  * @param {object} finding - `{system, systemVersion, noteType, source, target, shared}`.
28
28
  * @returns {string} The message.
@@ -79,16 +79,16 @@ export function measureNote(note: object, format: import("./content-format.mjs")
79
79
  /**
80
80
  * Measure a corpus, and count what it finds by class.
81
81
  *
82
- * The counts are the point as much as the findings: #127 promotes a class to
83
- * fatal when its count reaches zero, so a run that prints them is the epic's
84
- * progress bar.
82
+ * The counts are the point as much as the findings: a class is promoted to
83
+ * fatal when its count reaches zero, so a run that prints them is the
84
+ * migration's progress bar.
85
85
  *
86
86
  * @param {Iterable<object>} notes - `{file, raw, fm}` for each authored note.
87
87
  * @param {import("./content-format.mjs").ContentFormat} format - The parsed
88
88
  * specification.
89
89
  * @param {object} [opts]
90
90
  * @param {boolean} [opts.strict=false] - Report the findings as errors rather
91
- * than warnings. #127 turns this on one slice at a time.
91
+ * than warnings. Turned on one slice at a time.
92
92
  * @returns {{findings: object[], notes: number, byClass: Record<string, number>}}
93
93
  */
94
94
  export function measureCorpus(notes: Iterable<object>, format: import("./content-format.mjs").ContentFormat, { strict }?: {
@@ -107,7 +107,7 @@ export function measureCorpus(notes: Iterable<object>, format: import("./content
107
107
  export function fieldDriftMessage({ noteType, source, target, name, to }: object): string;
108
108
  /**
109
109
  * Check the specification's per-type tables against the field declarations that
110
- * compile them (#136).
110
+ * compile them.
111
111
  *
112
112
  * @param {object} opts
113
113
  * @param {import("./content-format.mjs").ContentFormat} opts.format - The
@@ -52,7 +52,7 @@ export const CONTENT_FORMAT_PATH: string;
52
52
  * `the shared mappings` for a row of the shared tables — see `shared`.
53
53
  * @property {boolean} [shared] - Whether the row came from a **shared** mapping
54
54
  * table, which stands before the first `### type:` heading and states what
55
- * every type maps identically (#275). Absent on a per-type row, so the two
55
+ * every type maps identically. Absent on a per-type row, so the two
56
56
  * never mix: only a per-type row has a field declaration to be checked
57
57
  * against.
58
58
  * @property {string} system - The system column it sits under, from the header.
@@ -121,7 +121,7 @@ export type MappingClaim = {
121
121
  /**
122
122
  * - Whether the row came from a **shared** mapping
123
123
  * table, which stands before the first `### type:` heading and states what
124
- * every type maps identically (#275). Absent on a per-type row, so the two
124
+ * every type maps identically. Absent on a per-type row, so the two
125
125
  * never mix: only a per-type row has a field declaration to be checked
126
126
  * against.
127
127
  */
@@ -0,0 +1,78 @@
1
+ /**
2
+ * What a note carrying raw HTML is told.
3
+ *
4
+ * It names the tag, because a file with several is fixed one at a time, and it
5
+ * says why rather than only what: an author who does not know the book cannot
6
+ * render it will read the finding as pedantry about a tag that plainly works.
7
+ *
8
+ * @param {string} tag - The matched markup, as written.
9
+ * @returns {string} The message, unpunctuated at the end as a finding is.
10
+ */
11
+ export function htmlMessage(tag: string): string;
12
+ /**
13
+ * Every raw HTML tag in one note's body.
14
+ *
15
+ * @param {string} body - The note's markdown, without its frontmatter.
16
+ * @param {string} file - The note's path, for the finding.
17
+ * @param {object} [opts]
18
+ * @param {number} [opts.bodyLine=1] - The 1-based file line the body starts on.
19
+ * @param {number} [opts.bodyColumn=1] - The 1-based file column it starts at.
20
+ * @returns {Array<{file: string, line: number, column: number,
21
+ * severity: "warning", message: string}>} One finding per tag, in source
22
+ * order.
23
+ */
24
+ export function checkHtml(body: string, file: string, { bodyLine, bodyColumn }?: {
25
+ bodyLine?: number | undefined;
26
+ bodyColumn?: number | undefined;
27
+ }): Array<{
28
+ file: string;
29
+ line: number;
30
+ column: number;
31
+ severity: "warning";
32
+ message: string;
33
+ }>;
34
+ /**
35
+ * Walk a content tree and report raw HTML in every note's prose.
36
+ *
37
+ * The frontmatter fence is taken off first, so what is scanned is the body and
38
+ * the positions are still the file's. A file with no frontmatter is scanned
39
+ * whole: it is not a note, but a stray `.md` in the tree carrying markup is the
40
+ * same problem for the same reason.
41
+ *
42
+ * @param {string} contentBase - Root of the content tree.
43
+ * @param {object} [opts]
44
+ * @param {readonly string[]} [opts.skipDirectories] - Directory names to ignore
45
+ * in addition to the dot-directories always skipped.
46
+ * @returns {{findings: Array<{file: string, line: number, column: number,
47
+ * severity: "warning", message: string}>, files: number}} The findings, and
48
+ * how many files were read.
49
+ */
50
+ export function lintContentHtml(contentBase: string, { skipDirectories }?: {
51
+ skipDirectories?: readonly string[] | undefined;
52
+ }): {
53
+ findings: Array<{
54
+ file: string;
55
+ line: number;
56
+ column: number;
57
+ severity: "warning";
58
+ message: string;
59
+ }>;
60
+ files: number;
61
+ };
62
+ /**
63
+ * A raw HTML tag, opening, closing or self-closing.
64
+ *
65
+ * The name must start a tag for the match to begin, which is what keeps
66
+ * markdown's own angle brackets out of it: an autolink is `<https://…>`, and
67
+ * `https` is followed by `:` rather than whitespace or `>`, so the pattern
68
+ * stops. A comparison written in prose — `a < b` — has no name after the
69
+ * bracket at all.
70
+ *
71
+ * Attributes are consumed as "anything but a bracket", deliberately loosely: a
72
+ * finding names the tag, and a pattern that tried to parse attribute syntax
73
+ * would be a second HTML parser with its own bugs, in a module whose whole
74
+ * point is that nothing here should be parsing HTML.
75
+ *
76
+ * @type {RegExp}
77
+ */
78
+ export const HTML_TAG: RegExp;