@heroiclands/package-build 22.9.2 → 22.11.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 (97) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/CONTENT.md +54 -0
  3. package/bin/content-build.mjs +3 -1
  4. package/docs/api.md +11 -6
  5. package/docs/commands.md +1 -1
  6. package/docs/content-format.md +411 -201
  7. package/engine/actor-compiler.mjs +20 -7
  8. package/engine/address-fields.mjs +426 -0
  9. package/engine/address-values.mjs +80 -0
  10. package/engine/address.mjs +769 -0
  11. package/engine/art-fields.mjs +112 -97
  12. package/engine/art-slots.mjs +81 -0
  13. package/engine/base-compiler.mjs +61 -7
  14. package/engine/bundle-notes.mjs +5 -2
  15. package/engine/bundles.mjs +17 -10
  16. package/engine/content-address.mjs +23 -186
  17. package/engine/content-embeds.mjs +18 -4
  18. package/engine/content-format-check.mjs +50 -22
  19. package/engine/content-index.mjs +85 -43
  20. package/engine/content-links.mjs +105 -104
  21. package/engine/content-lint.mjs +11 -1
  22. package/engine/content-tables.mjs +9 -1
  23. package/engine/field-spec.mjs +21 -4
  24. package/engine/folder-notes.mjs +44 -15
  25. package/engine/foundry-entries.mjs +3 -0
  26. package/engine/frontmatter-lint.mjs +150 -47
  27. package/engine/frontmatter.mjs +55 -10
  28. package/engine/generate.mjs +7 -1
  29. package/engine/helpers.mjs +37 -9
  30. package/engine/holdings.mjs +41 -12
  31. package/engine/index-records.mjs +2 -0
  32. package/engine/infobox-render.mjs +2 -1
  33. package/engine/infobox.mjs +26 -6
  34. package/engine/item-compiler.mjs +5 -0
  35. package/engine/item-docs.mjs +7 -44
  36. package/engine/map-dot.mjs +2 -0
  37. package/engine/map-notes.mjs +7 -2
  38. package/engine/map-places.mjs +42 -10
  39. package/engine/metadata-index.mjs +60 -5
  40. package/engine/note-addresses.mjs +325 -0
  41. package/engine/note-vocabulary.mjs +140 -28
  42. package/engine/pdf-build.mjs +1 -1
  43. package/engine/pdf-toc.mjs +17 -2
  44. package/engine/place-relations.mjs +160 -50
  45. package/engine/populations.mjs +17 -9
  46. package/engine/reference-targets.mjs +54 -0
  47. package/engine/scenes.mjs +5 -2
  48. package/engine/shortcode-references.mjs +68 -0
  49. package/engine/site-build.mjs +39 -15
  50. package/engine/site-index.mjs +57 -75
  51. package/engine/sql-tables.mjs +43 -9
  52. package/engine/system-block.mjs +21 -0
  53. package/engine/system-vocabulary.mjs +46 -0
  54. package/engine/web-wikilinks.mjs +11 -9
  55. package/engine/wikilink-syntax.mjs +21 -0
  56. package/engine/wikilinks.mjs +92 -306
  57. package/hm3/actors.mjs +8 -24
  58. package/hm3/item-fields.mjs +15 -5
  59. package/package.json +1 -1
  60. package/sohl/infobox.mjs +111 -17
  61. package/sohl/item-fields.mjs +131 -41
  62. package/types/engine/address-fields.d.mts +95 -0
  63. package/types/engine/address-values.d.mts +34 -0
  64. package/types/engine/address.d.mts +452 -0
  65. package/types/engine/art-fields.d.mts +59 -53
  66. package/types/engine/art-slots.d.mts +40 -0
  67. package/types/engine/base-compiler.d.mts +24 -2
  68. package/types/engine/bundle-notes.d.mts +2 -2
  69. package/types/engine/content-address.d.mts +3 -139
  70. package/types/engine/content-embeds.d.mts +1 -1
  71. package/types/engine/content-format-check.d.mts +25 -0
  72. package/types/engine/content-index.d.mts +2 -2
  73. package/types/engine/content-links.d.mts +6 -5
  74. package/types/engine/field-spec.d.mts +46 -9
  75. package/types/engine/folder-notes.d.mts +11 -10
  76. package/types/engine/frontmatter-lint.d.mts +7 -97
  77. package/types/engine/frontmatter.d.mts +16 -1
  78. package/types/engine/helpers.d.mts +2 -2
  79. package/types/engine/infobox.d.mts +6 -0
  80. package/types/engine/item-docs.d.mts +1 -35
  81. package/types/engine/map-notes.d.mts +2 -2
  82. package/types/engine/note-addresses.d.mts +41 -0
  83. package/types/engine/note-vocabulary.d.mts +20 -3
  84. package/types/engine/place-relations.d.mts +12 -1
  85. package/types/engine/populations.d.mts +17 -2
  86. package/types/engine/reference-targets.d.mts +9 -0
  87. package/types/engine/shortcode-references.d.mts +14 -0
  88. package/types/engine/site-build.d.mts +3 -3
  89. package/types/engine/site-index.d.mts +9 -30
  90. package/types/engine/sql-tables.d.mts +2 -2
  91. package/types/engine/system-block.d.mts +17 -0
  92. package/types/engine/system-vocabulary.d.mts +16 -0
  93. package/types/engine/wikilink-syntax.d.mts +7 -0
  94. package/types/engine/wikilinks.d.mts +6 -109
  95. package/types/hm3/item-fields.d.mts +5 -0
  96. package/types/sohl/infobox.d.mts +6 -5
  97. package/types/sohl/item-fields.d.mts +8 -0
@@ -1,97 +1,3 @@
1
- /**
2
- * What one system block accepts beyond the keys every block carries.
3
- *
4
- * @typedef {object} SystemBlockSpec
5
- * @property {readonly string[]} [known] - Keys stated outright.
6
- * @property {boolean} [fieldVocabulary] - Whether the note type's declared field
7
- * names, as the caller's `schemas` state them, are keys of this block.
8
- * @property {Readonly<Record<string, readonly object[]>>} [fields] - Type → this
9
- * system's own declared fields. A type it does not name is a type this system
10
- * says nothing about, and its block is left unchecked on such a note rather
11
- * than reported wholesale.
12
- */
13
- /**
14
- * Every system a configuration says its tree carries.
15
- *
16
- * **Which systems a package ships for is already declared**, in three places
17
- * that answer different questions, so this reads all three rather than asking a
18
- * new one:
19
- *
20
- * - `systems:` declares them without requiring one, which is how a
21
- * package ships for several;
22
- * - a **pack's** `system:` is the same statement made per pack, and it is the
23
- * one some trees make: `harn-ensemble` declares an `actors-sohl` and an
24
- * `actors-hm3` and nothing else about either system. It is already
25
- * authoritative elsewhere — `eligibleFor` fails a note for want of the block
26
- * a pack's `system:` names — so a lint that did not read it would refuse a
27
- * note at compile for a block it never checked;
28
- * - `stats.systemId` is the package-wide answer where there is one, and it has
29
- * already absorbed every way of spelling that: a system package is its own
30
- * system, and a module takes `requiresSystem`, its lone `systems:` entry, or
31
- * its lone system relationship.
32
- *
33
- * A package naming a system in none of them is system-agnostic on purpose — its
34
- * packs are core document types carrying no system data — so it carries no
35
- * system block and naming one would invent it.
36
- *
37
- * @param {object} [config] - A resolved configuration from `defineConfig`.
38
- * @returns {string[]} The system ids, deduplicated, in declared order.
39
- */
40
- export function declaredSystems(config?: object): string[];
41
- /**
42
- * The system blocks a configuration says its tree carries, and what each
43
- * accepts.
44
- *
45
- * The lint checks the blocks its caller names, and for as long as there was one
46
- * system the only caller named none — so every tree took the `sohl:` of
47
- * {@link DEFAULT_SYSTEM_BLOCKS}, a constant, in a module whose whole discipline
48
- * is that it states no vocabulary of its own. That is wrong in both directions
49
- * the moment a second system exists, and the second direction is the worse:
50
- *
51
- * - a package shipping for `hm3` had its `hm3:` block **never looked at**, so
52
- * every key in it was discarded at compile without a word — the silent-drop
53
- * family this check exists to close;
54
- * - and the block that *was* checked was named after a system that package does
55
- * not ship for, so the one finding it could make was about nothing.
56
- *
57
- * **A block's vocabulary has two sources, and a system may have both.**
58
- *
59
- * - The **note schemas** the caller hands in as `schemas`. Those belong to one
60
- * system — the CLI imports `sohl/note-schemas.mjs` — and `schemaSystem` is the
61
- * caller naming which, because only the caller knows. It is the only source
62
- * that reaches a type no item registry declares, which is to say `being`: the
63
- * 2,512 notes `harn-ensemble` is made of, and the reason this is not an
64
- * optional refinement.
65
- * - The system's **own registry**, `itemFieldsBySystem`, keyed by system and
66
- * until now read by nothing. This is what a *second* system's block is held
67
- * to, since the note schemas describe its neighbour.
68
- *
69
- * A system with neither is left out: nothing can state what its block may
70
- * carry, and holding it to an empty vocabulary would report every key in a
71
- * correct tree. **That is a check that does not run**, which is
72
- * indistinguishable from one that passed, so the caller says it out loud —
73
- * {@link declaredSystems} is the other half of that comparison. `harn-ensemble`
74
- * is the tree it names: two systems, and an `itemBuilders` registry for
75
- * neither, so its `hm3:` block is unchecked until it declares one.
76
- *
77
- * An earlier draft of this took the note schemas for a system's vocabulary only
78
- * where the package declared **one** system, on the reasoning that with several
79
- * there is nothing to say which one they describe. There is: the caller, which
80
- * chose them. The guess cost `harn-ensemble` its whole `sohl:` check — two
81
- * systems declared, so the fallback never fired — which is the coverage this
82
- * change exists to widen rather than narrow.
83
- *
84
- * @param {object} [config] - A resolved configuration from `defineConfig`.
85
- * @param {object} [options] - Options.
86
- * @param {string} [options.schemaSystem] - The system whose vocabulary the
87
- * caller's `schemas` state. There are two systems, not an open set, so this is
88
- * one word from the caller rather than a mechanism.
89
- * @returns {Readonly<Record<string, SystemBlockSpec>>} The blocks to check, in
90
- * declared order. A system nothing states the vocabulary of is absent.
91
- */
92
- export function systemBlocksFor(config?: object, { schemaSystem }?: {
93
- schemaSystem?: string | undefined;
94
- }): Readonly<Record<string, SystemBlockSpec>>;
95
1
  /**
96
2
  * Whether a value satisfies a declared {@link FieldSpec.kind}.
97
3
  *
@@ -103,9 +9,10 @@ export function systemBlocksFor(config?: object, { schemaSystem }?: {
103
9
  *
104
10
  * @param {unknown} value - The authored value.
105
11
  * @param {string} kind - The declared kind.
12
+ * @param {object} [context] - Complete Address defaults and known type vocabulary.
106
13
  * @returns {boolean} Whether it is acceptable.
107
14
  */
108
- export function matchesKind(value: unknown, kind: string): boolean;
15
+ export function matchesKind(value: unknown, kind: string, context?: object): boolean;
109
16
  /**
110
17
  * Check one note against its type's schema.
111
18
  *
@@ -113,7 +20,7 @@ export function matchesKind(value: unknown, kind: string): boolean;
113
20
  * @param {object} opts
114
21
  * @param {Record<string, readonly object[]>} opts.schemas - Type → declaration.
115
22
  * @param {object} [opts.index] - The link index, for the reference check, which
116
- * runs through its `referenceHit`. Its absence skips that check rather than
23
+ * runs through its `shortcodeHit`. Its absence skips that check rather than
117
24
  * reporting every reference as dead.
118
25
  * @param {Record<string, object>} [opts.vocabulary] - Type → the closed regions
119
26
  * it declares, as `engine/note-vocabulary.mjs` states them. Supplied
@@ -132,13 +39,14 @@ export function matchesKind(value: unknown, kind: string): boolean;
132
39
  * for the same reason `schemas` is — a build derives them from its
133
40
  * configuration through {@link systemBlocksFor}, and this module states no
134
41
  * system name of its own. See {@link DEFAULT_SYSTEM_BLOCKS} for the fallback.
42
+ * @param {object} [opts.addressContext] - Builder package and Address type vocabulary.
135
43
  * @param {readonly string[]} [opts.packs] - The pack names this package
136
44
  * declares, for a `data:` field whose map is keyed by pack. Supplied by the
137
45
  * caller like `schemas` and `vocabulary`, and absent it no claim is made
138
46
  * about those keys.
139
47
  * @returns {object[]} Findings, each with a locator where one is obtainable.
140
48
  */
141
- export function lintNote(note: object, { schemas, index, vocabulary, packs, emittedArt, systems }: {
49
+ export function lintNote(note: object, { schemas, index, vocabulary, packs, emittedArt, addressContext, systems, }: {
142
50
  schemas: Record<string, readonly object[]>;
143
51
  index?: object | undefined;
144
52
  vocabulary?: Record<string, object> | undefined;
@@ -147,6 +55,7 @@ export function lintNote(note: object, { schemas, index, vocabulary, packs, emit
147
55
  art: readonly string[];
148
56
  } | null) | undefined;
149
57
  systems?: Readonly<Record<string, SystemBlockSpec>> | undefined;
58
+ addressContext?: object | undefined;
150
59
  packs?: readonly string[] | undefined;
151
60
  }): object[];
152
61
  /**
@@ -280,3 +189,4 @@ export type SystemBlockSpec = {
280
189
  */
281
190
  fields?: Readonly<Record<string, readonly object[]>> | undefined;
282
191
  };
192
+ export { declaredSystems, systemBlocksFor } from "./system-vocabulary.mjs";
@@ -32,16 +32,31 @@ export function sohlField(fm: any, key: any, defaultValue?: undefined): any;
32
32
  * has to be told both. It is the same split `FieldSpec.name`/`legacyKey` makes,
33
33
  * for the same reason — one name cannot key two positions.
34
34
  *
35
+ * `shared` is the field's declared shared source, and it completes the order the
36
+ * three other positions are two thirds of. A field whose source is a path into
37
+ * `data:` is authored there by the specification's own mapping tables, and a
38
+ * reader that knew the destination, the block and the top level alone skipped
39
+ * straight past the container: every authored value read as unset, and the
40
+ * document shipped the field's default with nothing said. It sits **between**
41
+ * the block and the top level, exactly where
42
+ * {@link module:engine/system-block.resolveFieldValue} puts it — the block is the
43
+ * position a tree still writes and wins while it does, and the bare top-level
44
+ * key is the spelling `data:` gathered the fact off.
45
+ *
35
46
  * @param {object} fm - The note's frontmatter.
36
47
  * @param {string} to - The key at the destination, dotted for a nested one.
37
48
  * @param {any} [defaultValue] - What an unauthored field reads as.
38
49
  * @param {object} [options] - Options.
39
50
  * @param {string} [options.legacyKey] - The key the block still carries, when
40
51
  * it is not spelled `to`. Defaults to `to`.
52
+ * @param {string} [options.shared] - The field's declared shared source, when it
53
+ * is a path into a container (`data.relations`). Omitted by a field whose
54
+ * shared position is the note's top level, which `sohlField` already reads.
41
55
  * @returns {any} The value.
42
56
  */
43
- export function sohlSystemField(fm: object, to: string, defaultValue?: any, { legacyKey }?: {
57
+ export function sohlSystemField(fm: object, to: string, defaultValue?: any, { legacyKey, shared }?: {
44
58
  legacyKey?: string | undefined;
59
+ shared?: string | undefined;
45
60
  }): any;
46
61
  /**
47
62
  * Resolve the `charges` block shared by Mystery and Mystical Ability items.
@@ -10,7 +10,7 @@
10
10
  * `{ frontmatter: null, body: "", description: "" }` with a warn log, and no
11
11
  * position: there is no body to have one.
12
12
  */
13
- export function parseMarkdownFile(filePath: any): {
13
+ export function parseMarkdownFile(filePath: any, { addressContext }?: {}): {
14
14
  frontmatter: null;
15
15
  body: string;
16
16
  description: string;
@@ -85,7 +85,7 @@ export function assertSuppliedCorpus(records: readonly object[] | undefined, who
85
85
  * @throws {Error} When `skipDirectories` is not stated — see
86
86
  * {@link assertStatedScope}.
87
87
  */
88
- export function walkMarkdownTree(rootDir: string, { skipDirectories }?: {
88
+ export function walkMarkdownTree(rootDir: string, { skipDirectories, addressContext }?: {
89
89
  skipDirectories: readonly string[];
90
90
  }): Generator<{
91
91
  file: string & NonSharedBuffer;
@@ -5,6 +5,12 @@
5
5
  * `<type>.<field>` wins over the bare name, so a spelling two types use for two
6
6
  * quantities can be said differently on each without splitting the overlay.
7
7
  *
8
+ * **Keyed by the key an author writes, not by the path a declaration names.**
9
+ * One fact has two declarations — the note vocabulary's `weight` and an item
10
+ * field's `data.weight` — and the overlay says what a *reader* is shown, which
11
+ * is one word either way. So the container is dropped before the lookup, and
12
+ * `GEAR_UNITS` answers for both sides with one entry.
13
+ *
8
14
  * @param {Readonly<Record<string, object>>} presentation - The overlay.
9
15
  * @param {string|undefined} type - The note's type.
10
16
  * @param {string} name - The field's declared name.
@@ -1,38 +1,3 @@
1
- /**
2
- * Every content type whose **prose compiles into a JournalEntry of its own**,
3
- * addressed by the virtual `doc<type>` qualifier.
4
- *
5
- * Every item type, every actor type, every map type, plus `macro` — a macro
6
- * note's body documents the script the note also compiles into a Macro, which
7
- * is the same shape as an item and its description: one note, two documents,
8
- * the prose living in the journals pack.
9
- *
10
- * **One set, read by the compiler and the emitter alike.** The journals pass
11
- * decides what to compile from it, and the link manifest decides what to
12
- * publish a `doc<type>` entry for. Held apart, the two drift into a manifest
13
- * that asserts documentation nothing compiled — or a compiled entry no
14
- * consumer can address. It is composed exactly once, in `defineConfig`, and
15
- * read from there — never recomposed at a call site.
16
- *
17
- * `doc` notes are absent, for the reason that applies to them alone: a `doc`
18
- * note's single document *is* its prose, so there is no second document for a
19
- * `doc<type>` address to name.
20
- *
21
- * An accessor rather than a hoisted constant, so that importing this module
22
- * needs no configuration (#2).
23
- *
24
- * @returns {ReadonlySet<string>} The configured doc-carrying types.
25
- */
26
- export function docEntryTypes(): ReadonlySet<string>;
27
- /**
28
- * Whether a content note's type is one whose prose becomes a JournalEntry of
29
- * its own.
30
- *
31
- * @param {string} type - The note's `type` frontmatter.
32
- * @returns {boolean} True for an item type, an actor type, a map type and
33
- * `macro`; false for `doc`.
34
- */
35
- export function hasDocEntry(type: string): boolean;
36
1
  /**
37
2
  * The id of the JournalEntry a note's prose compiles into — an item's, or a
38
3
  * macro's.
@@ -72,3 +37,4 @@ export function itemDocEntryId(itemId: string): string;
72
37
  export function itemDocPointer(packageId: string, itemId: string, name: string, firstPageId: string): string;
73
38
  export { itemTypes };
74
39
  import { itemTypes } from "./item-registry.mjs";
40
+ export { docEntryTypes, hasDocEntry } from "./address.mjs";
@@ -161,12 +161,12 @@ export function buildScene(fm: object, ctx: object): object;
161
161
  * `bgImage` address by {@link buildScene}. Passed rather than resolved here,
162
162
  * because an address is answered by the compile's index and this function
163
163
  * takes none.
164
- * @param {(value: unknown, key: string, type: string) => string|null} [art] -
164
+ * @param {(value: unknown, key: string, type: string, accepts?: Iterable<string>) => string|null} [art] -
165
165
  * The art resolver, for the foreground overlay. Omitted, a note naming one
166
166
  * gets no overlay rather than a path nothing serves.
167
167
  * @returns {object} The Level document, keyed for the pack.
168
168
  */
169
- export function buildLevel(sohl: object, sceneId: string, img: string, art?: (value: unknown, key: string, type: string) => string | null): object;
169
+ export function buildLevel(sohl: object, sceneId: string, img: string, art?: (value: unknown, key: string, type: string, accepts?: Iterable<string>) => string | null): object;
170
170
  /**
171
171
  * Compile the `walls:` and `doors:` blocks into Wall documents.
172
172
  *
@@ -0,0 +1,41 @@
1
+ /**
2
+ * All declared Address positions of a note, including embedded notes.
3
+ * @param {object} fm - The note.
4
+ * @returns {object[]} Position descriptors with container shape and defaults.
5
+ */
6
+ export function addressPositions(fm: object, context?: {}): object[];
7
+ /**
8
+ * Decode declared properties at the note boundary. Raw mappings cannot impersonate tuples.
9
+ * @param {object} fm - Parsed YAML or an index record.
10
+ * @param {object} context - The builder's package and known types.
11
+ * @returns {object} The same note carrying typed Address properties.
12
+ */
13
+ export function decodeNoteAddresses(fm: object, context: object): object;
14
+ /**
15
+ * Read context supplied by the package configuration.
16
+ * @param {object} config - Resolved package configuration.
17
+ * @returns {object} Builder defaults and system declarations.
18
+ */
19
+ export function noteAddressContext(config: object): object;
20
+ /**
21
+ * Decode Address properties contributed by an index record.
22
+ * @param {object} record - The record.
23
+ * @param {object} context - Builder defaults.
24
+ * @returns {object} The typed record.
25
+ */
26
+ export function decodeIndexAddresses(record: object, context: object): object;
27
+ /** Structured positions whose Address is nested inside a declared container. */
28
+ export const STRUCTURED_ADDRESSES: readonly ({
29
+ path: string[];
30
+ shape: string;
31
+ type: string;
32
+ accepts: string[];
33
+ noteType?: undefined;
34
+ } | {
35
+ noteType: string;
36
+ path: string[];
37
+ shape: string;
38
+ type: string;
39
+ accepts: string[];
40
+ })[];
41
+ export { AddressEntries, encodeAddresses, cloneAddressState } from "./address-values.mjs";
@@ -279,7 +279,23 @@ export type DataFieldSpec = {
279
279
  * value — which is the honest answer wherever the specification's stated
280
280
  * shape and the shape notes are authored in today disagree.
281
281
  */
282
- kind?: "string" | "number" | "boolean" | "map" | "list" | "scalar-or-map" | undefined;
282
+ kind?: "string" | "number" | "boolean" | "map" | "list" | "scalar-or-map" | "address" | "shortcode" | undefined;
283
+ /**
284
+ * - Type of each list or pack-map value.
285
+ */
286
+ entryKind?: "address" | "shortcode" | undefined;
287
+ /**
288
+ * - Type of each map key.
289
+ */
290
+ keyKind?: "address" | "shortcode" | undefined;
291
+ /**
292
+ * - An alternative `subType:<skill-subtype>` key.
293
+ */
294
+ keySelector?: "subType" | undefined;
295
+ /**
296
+ * - Allowed Address types, separate from `ref`.
297
+ */
298
+ accepts?: readonly string[] | undefined;
283
299
  /**
284
300
  * - Human-readable shape, for a finding and for
285
301
  * documentation.
@@ -293,10 +309,11 @@ export type DataFieldSpec = {
293
309
  */
294
310
  entryShape?: string | undefined;
295
311
  /**
296
- * - The type a bare value takes. An art slot declares
312
+ * - The Address's default type, an art slot declares
297
313
  * one — `icon` for `icon` and `tokenIcon`, `image` for `bgImage` and
298
314
  * `banner` — so `icon: anvil` names `icon-anvil` while a value carrying the
299
- * separator states its own address.
315
+ * separator states its own address. Distinct from a `FieldSpec`'s `code`
316
+ * ({@link module :engine/field-spec}), which names a **Shortcode** instead.
300
317
  */
301
318
  ref?: string | undefined;
302
319
  /**
@@ -9,7 +9,7 @@ export function oppositeBearing(bearing: unknown): string | undefined;
9
9
  /**
10
10
  * Check a place note's `data.borders`.
11
11
  *
12
- * Every `to` is a shortcode a place declares, every `bearing` is one of the
12
+ * Every `to` is an Address a place declares, every `bearing` is one of the
13
13
  * eight, no pair is listed twice, no target is the note's own parent or child,
14
14
  * and the other end states the pair back at the opposite bearing — a missing
15
15
  * reciprocal is a warning naming both notes, a wrong one an error.
@@ -38,6 +38,17 @@ export function checkBorders(note: object, { index }?: {
38
38
  export function checkRoutes(note: object, { index }?: {
39
39
  index?: object | undefined;
40
40
  }): object[];
41
+ /**
42
+ * The type a border's or a route's `to` names.
43
+ *
44
+ * It is both the default its `<type>` segment takes when an author omits it and
45
+ * the whole of the set the position accepts, which is what makes `vylar` and
46
+ * `place-vylar` the same Address and a `to` naming a `lore` note an error rather
47
+ * than a lookup that quietly finds nothing.
48
+ *
49
+ * @type {string}
50
+ */
51
+ export const RELATION_TYPE: string;
41
52
  /**
42
53
  * The eight compass bearings, clockwise from north.
43
54
  *
@@ -1,3 +1,14 @@
1
+ /**
2
+ * Read a fetched index entry into a node, or `null` where it takes no part.
3
+ *
4
+ * A fetched entry carries the structure its record stated and no figure, so
5
+ * a dependency's place sits in the geography and counts nobody.
6
+ *
7
+ * @param {string} canonical - The entry's address.
8
+ * @param {object} entry - The entry.
9
+ * @returns {PopulationNode|null} The node.
10
+ */
11
+ export function foreignNode(canonical: string, entry: object): PopulationNode | null;
1
12
  /**
2
13
  * Check a place's population against the corpus around it.
3
14
  *
@@ -114,8 +125,12 @@ export type Corpus = {
114
125
  */
115
126
  holdersOf: Map<string, string[]>;
116
127
  /**
117
- * `type-shortcode` → the node,
118
- * for the citation rule.
128
+ * `type/shortcode` → the
129
+ * node, for the citation rule.
130
+ * Package-blind by design: a
131
+ * local note shadows a
132
+ * dependency's, so this is
133
+ * never a canonical Address.
119
134
  */
120
135
  byAddress: Map<string, PopulationNode>;
121
136
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Names and published destinations for reference presentation.
3
+ * Stubs contribute names, never pages or documents. The published index
4
+ * remains separate so body-link validation retains its publication rules.
5
+ * @param {readonly object[]} records - Decoded local or fetched records.
6
+ * @param {Map<string, object>} [published] - Actual published link destinations.
7
+ * @returns {Map<string, object>} Canonical lookup keys and presentation values.
8
+ */
9
+ export function buildReferenceTargets(records: readonly object[], published?: Map<string, object>): Map<string, object>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Present a native Shortcode using its unique system/type target.
3
+ * Address properties never use this lookup. Multiple packages claiming the
4
+ * same native identity remain ambiguous. Documentation supplies links; the
5
+ * native target supplies a name even when its documentation is unpublished.
6
+ * @param {readonly Map<string, object>[]} indexes - Published identity indexes.
7
+ * @param {unknown} code - Native Shortcode.
8
+ * @param {{type: string, system: string}} hint - Its declared native namespace.
9
+ * @returns {object|undefined} Documentation presentation, or no unique target.
10
+ */
11
+ export function resolveShortcodeReference(indexes: readonly Map<string, object>[], code: unknown, hint: {
12
+ type: string;
13
+ system: string;
14
+ }): object | undefined;
@@ -111,7 +111,7 @@ export function writeHomepages(outRoot: string, pages: readonly object[], config
111
111
  * @param {object} options.config - The resolved build configuration.
112
112
  * @returns {object} The gate results and, when they pass, the built index.
113
113
  */
114
- export function siteGates(pages: object[], findings: object, { config }: {
114
+ export function siteGates(pages: object[], findings: object, { config, records }: {
115
115
  config: object;
116
116
  }): object;
117
117
  /**
@@ -185,7 +185,7 @@ export function tableUniverse(pages: object[]): Map<string, object[]>;
185
185
  * @param {object} options
186
186
  * @param {(data: object, page: object) => void} [options.decorate] - Called
187
187
  * with each page's frontmatter, for whatever a consumer's own pass adds.
188
- * @param {(value: unknown, type: string) => string|null} [options.artSrc] -
188
+ * @param {(value: unknown, type: string, accepts?: Iterable<string>) => string|null} [options.artSrc] -
189
189
  * Translates an art address into the pathname the website resolver takes, or
190
190
  * `null` where nothing answers it.
191
191
  * @param {(src: string) => string} [options.webSrc] - Translates an authored
@@ -196,7 +196,7 @@ export function tableUniverse(pages: object[]): Map<string, object[]>;
196
196
  */
197
197
  export function pageFrontmatter(page: object, { decorate, webSrc, artSrc }: {
198
198
  decorate?: ((data: object, page: object) => void) | undefined;
199
- artSrc?: ((value: unknown, type: string) => string | null) | undefined;
199
+ artSrc?: ((value: unknown, type: string, accepts?: Iterable<string>) => string | null) | undefined;
200
200
  webSrc?: ((src: string) => string) | undefined;
201
201
  }): object;
202
202
  /**
@@ -13,7 +13,7 @@
13
13
  * ordinary dead address.
14
14
  * @returns {SiteIndex} The index, and what could not be addressed unambiguously.
15
15
  */
16
- export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, noIndexPackages }?: {
16
+ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, noIndexPackages, package: builderPackage, records, foreignReferences, }?: {
17
17
  foreignIndex?: Map<string, {
18
18
  package: string;
19
19
  type?: string;
@@ -62,36 +62,15 @@ export function wikiContext(built: SiteIndex, { src, file, type, errors, foreign
62
62
  resolved?: object[] | undefined;
63
63
  }): object;
64
64
  /**
65
- * Resolve one infobox reference against a site index.
66
- *
67
- * A note writes a reference three ways and all three reach here: a bare
68
- * **shortcode** (`slntlncmpny`), a short **address** (`affiliation-slntlncmpny`)
69
- * and a **canonical** one (`sohl-sohl-skill-melee`). The first is the ordinary
70
- * case and the ambiguous one — a shortcode is unique within a type and not
71
- * across a tree — so a caller that knows what it expects passes `hint.type`
72
- * and the lookup is narrowed to it.
73
- *
74
- * **Without a hint the types are tried in sorted order**, so two trees holding
75
- * the same note resolve it the same way. A shortcode two types both claim
76
- * answers with the first alphabetically, which is a stable wrong answer rather
77
- * than an unstable one; a caller that cares supplies the hint.
78
- *
79
- * The `address` on the answer is the slug form — `type-shortcode` — because
80
- * that is what the book's own link map is keyed by and what a wikilink is
81
- * written as.
82
- *
83
- * @param {SiteIndex} siteIndex - The index.
84
- * @param {unknown} ref - The reference, as authored.
85
- * @param {object} [hint] - `{type}`, where the caller knows it.
86
- * @returns {{name?: string, url?: string, address?: string, subType?: string}|undefined}
87
- * The page, or `undefined` where nothing answers.
65
+ * Resolve one Address against the site's canonical identity index.
66
+ * A bare Shortcode requires a declared default type. The returned Address is
67
+ * the complete tuple; URL and display name are presentation values.
68
+ * @param {SiteIndex} siteIndex - The site index.
69
+ * @param {unknown} ref - Tuple or authored reference.
70
+ * @param {object} [hint] - A declared default type.
71
+ * @returns {object|undefined} The matching page and tuple.
88
72
  */
89
- export function resolveInfoboxRef(siteIndex: SiteIndex, ref: unknown, hint?: object): {
90
- name?: string;
91
- url?: string;
92
- address?: string;
93
- subType?: string;
94
- } | undefined;
73
+ export function resolveInfoboxRef(siteIndex: SiteIndex, ref: unknown, hint?: object): object | undefined;
95
74
  /**
96
75
  * One page the site will publish, as the index needs to see it.
97
76
  */
@@ -63,7 +63,7 @@ export function findSqlBlocks(markdown: string): Array<{
63
63
  * @returns {Promise<{query: (sql: string) => Promise<object[]>,
64
64
  * close: () => Promise<void>}>} The open database.
65
65
  */
66
- export function openNotesDatabase(records: object[], { dir, dependencies }?: {
66
+ export function openNotesDatabase(records: object[], { dir, dependencies, addressContext }?: {
67
67
  dir?: string | undefined;
68
68
  dependencies?: {
69
69
  id: string;
@@ -111,7 +111,7 @@ export function runSqlQuery(db: object, sql: string): Promise<{
111
111
  export function renderSqlTable(result: {
112
112
  columns: string[];
113
113
  rows: object[];
114
- }, { linkable, sectionLevel }?: {
114
+ }, { linkable, sectionLevel, addressContext }?: {
115
115
  linkable?: ((ref: string) => boolean) | undefined;
116
116
  sectionLevel?: number | undefined;
117
117
  }): string;
@@ -140,6 +140,23 @@ export function legacyKeyOf(field: {
140
140
  export function retiredTopLevelKey(field: {
141
141
  name?: string;
142
142
  }): string | undefined;
143
+ /**
144
+ * A shared source as the key an author writes, without the container holding it.
145
+ *
146
+ * `data.weight` is authored as `weight:` one level inside `data:`, so every
147
+ * question about the *note* rather than about the resolution order asks it under
148
+ * that spelling: which presentation overlay a row takes, which key a finding
149
+ * names, and whether two statements of one fact are the same fact. The
150
+ * specification's mapping tables write the whole path and a `data:` vocabulary
151
+ * writes the key, and this is what makes the two comparable.
152
+ *
153
+ * It takes a **name** rather than a declaration because both sides of that
154
+ * comparison reach it: one holds a field, the other a row of a table.
155
+ *
156
+ * @param {string|undefined} name - The shared source, as either side spells it.
157
+ * @returns {string} The key, without the container.
158
+ */
159
+ export function authoredKey(name: string | undefined): string;
143
160
  /**
144
161
  * Where a declared field's value came from.
145
162
  *
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Systems named by package declarations and pack targets.
3
+ * @param {object} [config] - Resolved build configuration.
4
+ * @returns {string[]} Declared system identifiers.
5
+ */
6
+ export function declaredSystems(config?: object): string[];
7
+ /**
8
+ * System field vocabularies supplied by the configuration and caller.
9
+ * @param {object} [config] - Resolved build configuration.
10
+ * @param {object} [options] - Caller schema context.
11
+ * @param {string} [options.schemaSystem] - Owner of the caller's schemas.
12
+ * @returns {object} System block declarations.
13
+ */
14
+ export function systemBlocksFor(config?: object, { schemaSystem }?: {
15
+ schemaSystem?: string | undefined;
16
+ }): object;
@@ -167,6 +167,13 @@ export function linkFindingMessage({ reason, target, packages, anchor, type, stu
167
167
  * @returns {boolean} True when the link is same-page.
168
168
  */
169
169
  export function isSamePage({ target, anchor }: ParsedWikilink): boolean;
170
+ /**
171
+ * Read an operational link target in its enclosing Address context.
172
+ * @param {string} inner - Lexical link contents.
173
+ * @param {object} context - Builder defaults and type vocabulary.
174
+ * @returns {object} Typed target and diagnostic source spelling.
175
+ */
176
+ export function readWikilink(inner: string, context: object): object;
170
177
  /**
171
178
  * What a `[[…]]` **is**, before anything decides where it points.
172
179
  *