@heroiclands/package-build 23.9.0 → 23.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 (96) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +2 -0
  3. package/bin/content-commands.mjs +197 -68
  4. package/docs/api.md +365 -70
  5. package/docs/authoring/first-note.md +10 -0
  6. package/docs/authoring/frontmatter.md +1 -1
  7. package/docs/authoring/links-and-markup.md +186 -49
  8. package/docs/commands.md +92 -3
  9. package/docs/content-format.md +10 -3
  10. package/docs/design.md +18 -0
  11. package/docs/guides/book.md +7 -0
  12. package/docs/guides/site.md +7 -0
  13. package/docs/reference/format-details.md +186 -15
  14. package/docs/reference/note-types.md +4 -4
  15. package/engine/anchors.mjs +43 -9
  16. package/engine/base-compiler.mjs +6 -4
  17. package/engine/changelog-group.mjs +58 -34
  18. package/engine/changelog-lint.mjs +6 -2
  19. package/engine/compendiums.mjs +15 -1
  20. package/engine/compile-corpus.mjs +14 -1
  21. package/engine/content-charset.mjs +13 -1
  22. package/engine/content-html.mjs +18 -4
  23. package/engine/content-icons.mjs +15 -1
  24. package/engine/content-images.mjs +28 -9
  25. package/engine/content-index.mjs +102 -23
  26. package/engine/content-links.mjs +68 -30
  27. package/engine/content-session.mjs +247 -0
  28. package/engine/content-sources.mjs +110 -0
  29. package/engine/content-spans.mjs +118 -14
  30. package/engine/content-tables.mjs +1 -0
  31. package/engine/content-tasklists.mjs +20 -4
  32. package/engine/diagnostics.mjs +17 -6
  33. package/engine/extension-attributes.mjs +28 -5
  34. package/engine/first-use.mjs +371 -0
  35. package/engine/foundry-entries.mjs +12 -9
  36. package/engine/generate.mjs +13 -4
  37. package/engine/helpers.mjs +47 -16
  38. package/engine/index-records.mjs +1 -0
  39. package/engine/index.mjs +3 -0
  40. package/engine/journals.mjs +9 -5
  41. package/engine/language-data.mjs +2 -2
  42. package/engine/language-rows.mjs +4 -4
  43. package/engine/language-terms.mjs +4 -4
  44. package/engine/lexical-sections.mjs +5 -5
  45. package/engine/markup-validation.mjs +7 -2
  46. package/engine/metadata-index.mjs +1 -0
  47. package/engine/name-markup.mjs +114 -0
  48. package/engine/name-rows.mjs +70 -0
  49. package/engine/names.mjs +460 -0
  50. package/engine/note-addresses.mjs +25 -4
  51. package/engine/path-charset.mjs +24 -1
  52. package/engine/pdf-render.mjs +15 -1
  53. package/engine/site-index.mjs +25 -2
  54. package/engine/sql-tables.mjs +76 -15
  55. package/engine/stub-lint.mjs +4 -3
  56. package/engine/web-wikilinks.mjs +33 -12
  57. package/engine/wikilink-syntax.mjs +65 -8
  58. package/engine/wikilinks.mjs +29 -11
  59. package/engine/yaml-lint.mjs +3 -5
  60. package/hugo-theme/layouts/partials/footer.html +2 -0
  61. package/hugo-theme/static/css/style.css +20 -0
  62. package/hugo-theme/static/js/inline-spoilers.js +23 -0
  63. package/package.json +1 -1
  64. package/types/engine/anchors.d.mts +6 -3
  65. package/types/engine/compendiums.d.mts +5 -1
  66. package/types/engine/compile-corpus.d.mts +5 -2
  67. package/types/engine/content-charset.d.mts +5 -1
  68. package/types/engine/content-html.d.mts +5 -1
  69. package/types/engine/content-icons.d.mts +5 -1
  70. package/types/engine/content-images.d.mts +5 -1
  71. package/types/engine/content-index.d.mts +39 -19
  72. package/types/engine/content-links.d.mts +22 -8
  73. package/types/engine/content-session.d.mts +108 -0
  74. package/types/engine/content-sources.d.mts +32 -0
  75. package/types/engine/content-spans.d.mts +8 -6
  76. package/types/engine/content-tasklists.d.mts +5 -1
  77. package/types/engine/diagnostics.d.mts +10 -0
  78. package/types/engine/extension-attributes.d.mts +16 -2
  79. package/types/engine/first-use.d.mts +31 -0
  80. package/types/engine/foundry-entries.d.mts +11 -4
  81. package/types/engine/generate.d.mts +5 -1
  82. package/types/engine/helpers.d.mts +30 -7
  83. package/types/engine/index.d.mts +1 -0
  84. package/types/engine/journals.d.mts +5 -2
  85. package/types/engine/lexical-sections.d.mts +3 -2
  86. package/types/engine/markup-validation.d.mts +2 -1
  87. package/types/engine/name-markup.d.mts +176 -0
  88. package/types/engine/name-rows.d.mts +35 -0
  89. package/types/engine/names.d.mts +356 -0
  90. package/types/engine/note-addresses.d.mts +3 -3
  91. package/types/engine/path-charset.d.mts +16 -1
  92. package/types/engine/site-build.d.mts +2 -2
  93. package/types/engine/site-index.d.mts +3 -1
  94. package/types/engine/sql-tables.d.mts +7 -2
  95. package/types/engine/stub-lint.d.mts +3 -1
  96. package/types/engine/wikilink-syntax.d.mts +40 -3
@@ -0,0 +1,356 @@
1
+ /**
2
+ * An indexed whole-label match. Ambiguous labels retain every candidate.
3
+ * @typedef {object} NameMatch
4
+ * @property {string} key - Canonical page identity, or the ambiguous label identity.
5
+ * @property {string} full - Declared full name.
6
+ * @property {true} indexed - The identity belongs to the indexed catalog.
7
+ * @property {boolean} [fullUse] - The label is a full-name form rather than an alias.
8
+ * @property {NameMatch[]} [candidates] - Indexed identities sharing the label.
9
+ * @property {string} [destination] - Canonical Address used by a resolved link.
10
+ */
11
+ /**
12
+ * The prepared name and declared-alias lookup.
13
+ * @typedef {object} NameCatalog
14
+ * @property {(label: string, preferred?: {key: string}) => NameMatch|undefined} recognize - Match a whole visible label.
15
+ * @property {(target: string) => NameMatch|undefined} resolve - Resolve an Address target without its anchor to its indexed identity.
16
+ */
17
+ /**
18
+ * One captured marked-name occurrence.
19
+ * @typedef {object} MarkedName
20
+ * @property {string} name - Rendered visible text.
21
+ * @property {string|null} type - Supplied valid type, or null.
22
+ * @property {string|null} subType - Supplied valid subtype, or null.
23
+ * @property {number} line - Original 1-based file line.
24
+ * @property {number} column - Original 1-based UTF-16 file column.
25
+ */
26
+ /**
27
+ * One reported source use.
28
+ * @typedef {object} NameUse
29
+ * @property {string|null} owner - Canonical NOTE owner, or null for an unaddressed record.
30
+ * @property {string|undefined} file - Stored path relative to the content root.
31
+ * @property {number} line - Original 1-based file line.
32
+ * @property {number} column - Original 1-based UTF-16 file column.
33
+ */
34
+ /**
35
+ * Unwritten names sharing one supplied kind.
36
+ * @typedef {object} UnwrittenNameGroup
37
+ * @property {string|null} type - Supplied type, or null.
38
+ * @property {string|null} subType - Supplied subtype, or null.
39
+ * @property {Array<{name: string, uses: NameUse[]}>} names - Normalized labels and every source use.
40
+ */
41
+ /**
42
+ * A parsed span with its original source sites and visible text.
43
+ * @typedef {object} ParsedNameSpan
44
+ * @property {string} visible - Text from the actual parsed children.
45
+ * @property {ReadonlyArray<readonly [string, string]>} attrs - Retained permitted attributes.
46
+ * @property {number} line - Original 1-based file line of the opening bracket.
47
+ * @property {number} column - Original 1-based UTF-16 file column of the bracket.
48
+ * @property {Readonly<Record<string, {key: {line: number, column: number}}>>} [attributePositions] - Actual attribute-key sites.
49
+ */
50
+ /**
51
+ * One invalid supplied name kind.
52
+ * @typedef {object} NameKindFinding
53
+ * @property {string} [file] - Authored source file.
54
+ * @property {number} [line] - Actual attribute-key line when supplied by the parser.
55
+ * @property {number} [column] - Actual attribute-key UTF-16 column when known.
56
+ * @property {"error"} severity - Invalid supplied values fail validation.
57
+ * @property {string} message - The invalid value and the declaration it must follow.
58
+ */
59
+ /**
60
+ * A marked name whose supplied kinds disagree.
61
+ * @typedef {object} NameConflict
62
+ * @property {string} name - Normalized visible label.
63
+ * @property {Array<{type: string, subType: string|null, uses: NameUse[]}>} kinds - Every supplied typed use; untyped uses are excluded.
64
+ */
65
+ /**
66
+ * The current package's unwritten names and incompatible supplied facts.
67
+ * @typedef {object} NamesReport
68
+ * @property {string} package - Owning content package.
69
+ * @property {UnwrittenNameGroup[]} unwritten - Unresolved labels grouped by supplied kind.
70
+ * @property {NameConflict[]} conflicts - Labels with incompatible supplied kinds.
71
+ */
72
+ /**
73
+ * Normalize a whole visible label without folding its case.
74
+ * @param {string} text - Visible name or declared alias.
75
+ * @returns {string} NFC text with straight apostrophes and single spaces.
76
+ */
77
+ export function normalizeName(text: string): string;
78
+ /**
79
+ * Whole-label possessives and regular plurals; other forms are declared aliases.
80
+ * @param {string} text - Full name or declared alias.
81
+ * @returns {string[]} Supported whole-label forms.
82
+ */
83
+ export function nameForms(text: string): string[];
84
+ /**
85
+ * Prepare full names, declared aliases and link identities from captured records.
86
+ * @param {object} options - The invocation's existing corpus and link index.
87
+ * @param {readonly object[]} options.records - Captured local records.
88
+ * @param {ReturnType<typeof import("./content-links.mjs").buildLinkIndex>} options.index - Captured address space.
89
+ * @returns {NameCatalog} Pure whole-label and Address lookups.
90
+ */
91
+ export function createNameCatalog({ records, index }: {
92
+ records: readonly object[];
93
+ index: ReturnType<typeof import("./content-links.mjs").buildLinkIndex>;
94
+ }): NameCatalog;
95
+ /**
96
+ * Group unwritten marked names from captured record fields alone.
97
+ * @param {object} options - Current package records and prepared known names.
98
+ * @param {readonly object[]} options.records - Authored records carrying `names` entries.
99
+ * @param {NameCatalog} options.catalog - Invocation-owned indexed name lookup.
100
+ * @returns {{groups: UnwrittenNameGroup[], firstUse: NameUse|undefined}} Every use and the earliest located reported occurrence.
101
+ */
102
+ export function collectUnwrittenNames({ records, catalog }: {
103
+ records: readonly object[];
104
+ catalog: NameCatalog;
105
+ }): {
106
+ groups: UnwrittenNameGroup[];
107
+ firstUse: NameUse | undefined;
108
+ };
109
+ /**
110
+ * Analyze actual parsed name spans using one supplied-kind validation route.
111
+ * @param {readonly ParsedNameSpan[]} spans - Parsed spans at original file coordinates.
112
+ * @param {object} [options] - Existing note declarations and source context.
113
+ * @param {string} [options.file] - Authored source file.
114
+ * @param {Readonly<Record<string, {subTypes?: readonly string[]|null}>>} [options.vocabulary] - Actual note vocabulary.
115
+ * @param {Iterable<string>} [options.types] - Additional bare types from configured declarations.
116
+ * @returns {{names: MarkedName[], findings: NameKindFinding[]}} Valid occurrence fields and every invalid supplied attribute.
117
+ */
118
+ export function analyzeNameSpans(spans: readonly ParsedNameSpan[], { file, vocabulary, types }?: {
119
+ file?: string | undefined;
120
+ vocabulary?: Readonly<Record<string, {
121
+ subTypes?: readonly string[] | null;
122
+ }>> | undefined;
123
+ types?: Iterable<string> | undefined;
124
+ }): {
125
+ names: MarkedName[];
126
+ findings: NameKindFinding[];
127
+ };
128
+ /**
129
+ * Build one package report from captured explicit names and the prepared catalog.
130
+ * Untyped facts and matching parent/subtype refinements are compatible.
131
+ * @param {object} options - Existing package corpus and lookup.
132
+ * @param {string} options.package - Owning content package.
133
+ * @param {readonly object[]} options.records - Captured current-package records.
134
+ * @param {NameCatalog} options.catalog - Invocation-owned indexed name lookup.
135
+ * @returns {NamesReport} Deterministic structured groups without diagnostics or I/O.
136
+ */
137
+ export function createNamesReport({ package: contentPackage, records, catalog }: {
138
+ package: string;
139
+ records: readonly object[];
140
+ catalog: NameCatalog;
141
+ }): NamesReport;
142
+ /**
143
+ * Format one readable advisory containing every reported source use.
144
+ * @param {NamesReport} report - Structured package report.
145
+ * @param {object} [options] - Source-path context for the caller's diagnostics.
146
+ * @param {string} [options.contentBase] - Content root for stored relative paths.
147
+ * @returns {{file?: string, line?: number, column?: number, severity: "warning", message: string}|undefined} One advisory, or none when both groups are empty.
148
+ */
149
+ export function namesReportFinding(report: NamesReport, { contentBase }?: {
150
+ contentBase?: string | undefined;
151
+ }): {
152
+ file?: string;
153
+ line?: number;
154
+ column?: number;
155
+ severity: "warning";
156
+ message: string;
157
+ } | undefined;
158
+ /**
159
+ * An indexed whole-label match. Ambiguous labels retain every candidate.
160
+ */
161
+ export type NameMatch = {
162
+ /**
163
+ * - Canonical page identity, or the ambiguous label identity.
164
+ */
165
+ key: string;
166
+ /**
167
+ * - Declared full name.
168
+ */
169
+ full: string;
170
+ /**
171
+ * - The identity belongs to the indexed catalog.
172
+ */
173
+ indexed: true;
174
+ /**
175
+ * - The label is a full-name form rather than an alias.
176
+ */
177
+ fullUse?: boolean | undefined;
178
+ /**
179
+ * - Indexed identities sharing the label.
180
+ */
181
+ candidates?: NameMatch[] | undefined;
182
+ /**
183
+ * - Canonical Address used by a resolved link.
184
+ */
185
+ destination?: string | undefined;
186
+ };
187
+ /**
188
+ * The prepared name and declared-alias lookup.
189
+ */
190
+ export type NameCatalog = {
191
+ /**
192
+ * - Match a whole visible label.
193
+ */
194
+ recognize: (label: string, preferred?: {
195
+ key: string;
196
+ }) => NameMatch | undefined;
197
+ /**
198
+ * - Resolve an Address target without its anchor to its indexed identity.
199
+ */
200
+ resolve: (target: string) => NameMatch | undefined;
201
+ };
202
+ /**
203
+ * One captured marked-name occurrence.
204
+ */
205
+ export type MarkedName = {
206
+ /**
207
+ * - Rendered visible text.
208
+ */
209
+ name: string;
210
+ /**
211
+ * - Supplied valid type, or null.
212
+ */
213
+ type: string | null;
214
+ /**
215
+ * - Supplied valid subtype, or null.
216
+ */
217
+ subType: string | null;
218
+ /**
219
+ * - Original 1-based file line.
220
+ */
221
+ line: number;
222
+ /**
223
+ * - Original 1-based UTF-16 file column.
224
+ */
225
+ column: number;
226
+ };
227
+ /**
228
+ * One reported source use.
229
+ */
230
+ export type NameUse = {
231
+ /**
232
+ * - Canonical NOTE owner, or null for an unaddressed record.
233
+ */
234
+ owner: string | null;
235
+ /**
236
+ * - Stored path relative to the content root.
237
+ */
238
+ file: string | undefined;
239
+ /**
240
+ * - Original 1-based file line.
241
+ */
242
+ line: number;
243
+ /**
244
+ * - Original 1-based UTF-16 file column.
245
+ */
246
+ column: number;
247
+ };
248
+ /**
249
+ * Unwritten names sharing one supplied kind.
250
+ */
251
+ export type UnwrittenNameGroup = {
252
+ /**
253
+ * - Supplied type, or null.
254
+ */
255
+ type: string | null;
256
+ /**
257
+ * - Supplied subtype, or null.
258
+ */
259
+ subType: string | null;
260
+ /**
261
+ * - Normalized labels and every source use.
262
+ */
263
+ names: Array<{
264
+ name: string;
265
+ uses: NameUse[];
266
+ }>;
267
+ };
268
+ /**
269
+ * A parsed span with its original source sites and visible text.
270
+ */
271
+ export type ParsedNameSpan = {
272
+ /**
273
+ * - Text from the actual parsed children.
274
+ */
275
+ visible: string;
276
+ /**
277
+ * - Retained permitted attributes.
278
+ */
279
+ attrs: ReadonlyArray<readonly [string, string]>;
280
+ /**
281
+ * - Original 1-based file line of the opening bracket.
282
+ */
283
+ line: number;
284
+ /**
285
+ * - Original 1-based UTF-16 file column of the bracket.
286
+ */
287
+ column: number;
288
+ /**
289
+ * - Actual attribute-key sites.
290
+ */
291
+ attributePositions?: Readonly<Record<string, {
292
+ key: {
293
+ line: number;
294
+ column: number;
295
+ };
296
+ }>> | undefined;
297
+ };
298
+ /**
299
+ * One invalid supplied name kind.
300
+ */
301
+ export type NameKindFinding = {
302
+ /**
303
+ * - Authored source file.
304
+ */
305
+ file?: string | undefined;
306
+ /**
307
+ * - Actual attribute-key line when supplied by the parser.
308
+ */
309
+ line?: number | undefined;
310
+ /**
311
+ * - Actual attribute-key UTF-16 column when known.
312
+ */
313
+ column?: number | undefined;
314
+ /**
315
+ * - Invalid supplied values fail validation.
316
+ */
317
+ severity: "error";
318
+ /**
319
+ * - The invalid value and the declaration it must follow.
320
+ */
321
+ message: string;
322
+ };
323
+ /**
324
+ * A marked name whose supplied kinds disagree.
325
+ */
326
+ export type NameConflict = {
327
+ /**
328
+ * - Normalized visible label.
329
+ */
330
+ name: string;
331
+ /**
332
+ * - Every supplied typed use; untyped uses are excluded.
333
+ */
334
+ kinds: Array<{
335
+ type: string;
336
+ subType: string | null;
337
+ uses: NameUse[];
338
+ }>;
339
+ };
340
+ /**
341
+ * The current package's unwritten names and incompatible supplied facts.
342
+ */
343
+ export type NamesReport = {
344
+ /**
345
+ * - Owning content package.
346
+ */
347
+ package: string;
348
+ /**
349
+ * - Unresolved labels grouped by supplied kind.
350
+ */
351
+ unwritten: UnwrittenNameGroup[];
352
+ /**
353
+ * - Labels with incompatible supplied kinds.
354
+ */
355
+ conflicts: NameConflict[];
356
+ };
@@ -8,8 +8,8 @@ export function addressPositions(fm: object, context?: {}): object[];
8
8
  * Decode declared properties at the note boundary. Raw mappings cannot impersonate tuples.
9
9
  *
10
10
  * A declared Address is read as written. A shortcode spelled with a capital is
11
- * refused, and every such value in the note is collected before the decode
12
- * throws, so each reference is reported at its own position: the thrown error
11
+ * refused, as is a document Address in a language-note field. Every such value
12
+ * is collected before the decode throws, so each is reported at its own position: the thrown error
13
13
  * describes the first, and its `findings` carry all of them.
14
14
  *
15
15
  * @param {object} fm - Parsed YAML or an index record.
@@ -18,7 +18,7 @@ export function addressPositions(fm: object, context?: {}): object[];
18
18
  * refused shortcode when it is declared.
19
19
  * @returns {object} The same note carrying typed Address properties.
20
20
  * @throws {Error} When a declared Address is refused; `keyPath` locates it, and
21
- * `findings`, where present, lists every refused shortcode.
21
+ * `findings`, where present, lists every refused value.
22
22
  */
23
23
  export function decodeNoteAddresses(fm: object, context: object): object;
24
24
  /**
@@ -21,13 +21,28 @@ export function offendingPathCharacters(text: string): string[];
21
21
  * @param {string} opts.assetsBase - The package's asset directory, whose
22
22
  * picture roots are walked.
23
23
  * @param {readonly string[]} [opts.skipDirectories] - Directory names to ignore.
24
+ * @param {ReturnType<import("./content-sources.mjs").captureContentSources>} [opts.inventory] - Captured physical paths in root walk order.
24
25
  * @returns {{findings: Array<{file: string, severity: "error", message: string}>,
25
26
  * files: number}} The findings, and how many paths were checked.
26
27
  */
27
- export function lintPathCharset({ contentBase, assetsBase, skipDirectories }: {
28
+ export function lintPathCharset({ contentBase, assetsBase, skipDirectories, inventory }: {
28
29
  contentBase: string;
29
30
  assetsBase: string;
30
31
  skipDirectories?: readonly string[] | undefined;
32
+ inventory?: {
33
+ sources: Map<string, {
34
+ raw: string;
35
+ }>;
36
+ indexSources: Map<string, {
37
+ raw: string;
38
+ }>;
39
+ paths: Array<{
40
+ root: string;
41
+ file: string;
42
+ name: string;
43
+ directory: boolean;
44
+ }>;
45
+ } | undefined;
31
46
  }): {
32
47
  findings: Array<{
33
48
  file: string;
@@ -253,8 +253,8 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
253
253
  secretErrors: {
254
254
  file: any;
255
255
  line: number;
256
- column: any;
257
- message: any;
256
+ column: number;
257
+ message: string;
258
258
  }[];
259
259
  captionErrors: {
260
260
  file: any;
@@ -13,9 +13,10 @@
13
13
  * ordinary dead address.
14
14
  * @param {object[]} [options.records] - Content-index records.
15
15
  * @param {Map<string, object>} [options.foreignReferences] - Foreign reference targets.
16
+ * @param {import("./content-session.mjs").ContentSyntax} [options.syntax] - Exact-text scanner projections.
16
17
  * @returns {SiteIndex} The index, and what could not be addressed unambiguously.
17
18
  */
18
- export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, noIndexPackages, package: builderPackage, records, foreignReferences, }?: {
19
+ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, noIndexPackages, package: builderPackage, records, foreignReferences, syntax, }?: {
19
20
  foreignIndex?: Map<string, {
20
21
  package: string;
21
22
  type?: string;
@@ -23,6 +24,7 @@ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, no
23
24
  noIndexPackages?: Set<string> | undefined;
24
25
  records?: object[] | undefined;
25
26
  foreignReferences?: Map<string, object> | undefined;
27
+ syntax?: import("./content-session.mjs").ContentSyntax | undefined;
26
28
  }): SiteIndex;
27
29
  /**
28
30
  * The address keys one page's figures are reachable by — the same two forms
@@ -303,11 +303,12 @@ export function cachedDependencies(config?: object): Promise<Array<{
303
303
  * @param {Map<string, object>} [opts.foreignIndex] - The fetched indexes the
304
304
  * generated sections take in, where the caller holds them already; absent,
305
305
  * they are read from the cache.
306
+ * @param {import("./content-session.mjs").ContentSyntax} [opts.syntax] - Exact-text scanner projections.
306
307
  * @returns {Promise<Map<string, object[]>|undefined>} Results by note path,
307
308
  * carrying `inline` and `pageLists` beside them, or nothing when the tree
308
309
  * holds no such directive and no note is given a generated section.
309
310
  */
310
- export function prepareTreeSqlTables(contentBase: string, { config, skipDirectories, records, parsed, database, audience, foreignIndex }?: {
311
+ export function prepareTreeSqlTables(contentBase: string, { config, skipDirectories, records, parsed, database, audience, foreignIndex, syntax, }?: {
311
312
  config?: object | undefined;
312
313
  skipDirectories?: readonly string[] | undefined;
313
314
  records?: object[] | undefined;
@@ -318,6 +319,7 @@ export function prepareTreeSqlTables(contentBase: string, { config, skipDirector
318
319
  database?: object | undefined;
319
320
  audience?: "all" | "public" | undefined;
320
321
  foreignIndex?: Map<string, object> | undefined;
322
+ syntax?: import("./content-session.mjs").ContentSyntax | undefined;
321
323
  }): Promise<Map<string, object[]> | undefined>;
322
324
  /**
323
325
  * Prepare authored link-check tables in each source note's audience. Public
@@ -331,9 +333,11 @@ export function prepareTreeSqlTables(contentBase: string, { config, skipDirector
331
333
  * @param {object[]} [opts.records] - Complete index records already derived.
332
334
  * @param {Map<string, {body: string, frontmatter: object|null}>} [opts.parsed] - Parsed notes.
333
335
  * @param {Map<string, object>} [opts.foreignIndex] - Published dependency indexes.
336
+ * @param {(audience: "all"|"public") => Promise<Map<string, object[]>|undefined>} [opts.prepareAudience] -
337
+ * Context-bound preparation shared with other operations in the same session.
334
338
  * @returns {Promise<Map<string, object[]>|undefined>} Prepared tables by source.
335
339
  */
336
- export function prepareLinkSqlTables(contentBase: string, { config, skipDirectories, records, parsed, foreignIndex }?: {
340
+ export function prepareLinkSqlTables(contentBase: string, { config, skipDirectories, records, parsed, foreignIndex, prepareAudience }?: {
337
341
  config?: object | undefined;
338
342
  skipDirectories?: readonly string[] | undefined;
339
343
  records?: object[] | undefined;
@@ -342,6 +346,7 @@ export function prepareLinkSqlTables(contentBase: string, { config, skipDirector
342
346
  frontmatter: object | null;
343
347
  }> | undefined;
344
348
  foreignIndex?: Map<string, object> | undefined;
349
+ prepareAudience?: ((audience: "all" | "public") => Promise<Map<string, object[]> | undefined>) | undefined;
345
350
  }): Promise<Map<string, object[]> | undefined>;
346
351
  /**
347
352
  * Aliases the renderer reads rather than printing.
@@ -11,15 +11,17 @@
11
11
  * @param {object} opts
12
12
  * @param {readonly object[]} opts.records - Index records the caller derived.
13
13
  * @param {string} [opts.contentPackage] - Named in the counts line.
14
+ * @param {Map<string, import("./content-session.mjs").ContentNoteSource>} [opts.parsed] - Captured sources, with the file reader as fallback.
14
15
  * @returns {{findings: object[], counts: {full: number, draft: number,
15
16
  * stub: number}, byType: Array<{type: string, full: number, draft: number,
16
17
  * stub: number}>, oldestDrafts: Array<{file: string, modified: Date}>,
17
18
  * summary: string[]}} The findings, the ladder's counts, and the lines a
18
19
  * reader is shown as prose rather than as findings.
19
20
  */
20
- export function lintNoteStates(contentBase: string, { records, contentPackage }?: {
21
+ export function lintNoteStates(contentBase: string, { records, contentPackage, parsed }?: {
21
22
  records: readonly object[];
22
23
  contentPackage?: string | undefined;
24
+ parsed?: Map<string, import("./content-session.mjs").ContentNoteSource> | undefined;
23
25
  }): {
24
26
  findings: object[];
25
27
  counts: {
@@ -9,6 +9,7 @@
9
9
  * @property {string} anchor - The `#section` slug, `""` when there is none.
10
10
  * @property {string|null} display - The text after `|`, or `null` when the link
11
11
  * is unlabelled. `null` and `""` differ: an author may write `[[x|]]`.
12
+ * @property {ReturnType<typeof parseExtensionAttributes>} [attributes] - Trailing extension attributes.
12
13
  * @property {boolean} labelled - Whether a `|` was present at all. A link
13
14
  * without one addresses nothing and is a finding — see
14
15
  * {@link unlabelledLinkMessage} — so every reader has to be able to ask.
@@ -20,9 +21,10 @@
20
21
  * not the whole link, so a caller that has already matched does not re-match.
21
22
  *
22
23
  * @param {string} rawInner - The text between `[[` and `]]`.
24
+ * @param {string} [literal] - Whole matched link, including trailing attributes.
23
25
  * @returns {ParsedWikilink} The parts, each trimmed.
24
26
  */
25
- export function parseWikilink(rawInner: string): ParsedWikilink;
27
+ export function parseWikilink(rawInner: string, literal?: string): ParsedWikilink;
26
28
  /**
27
29
  * The label an author actually supplied, or `null` when they supplied none.
28
30
  *
@@ -158,13 +160,14 @@ export function ambiguousAddressMessage(target: string, packages?: Iterable<stri
158
160
  * @param {string} [finding.stub] - For `stub`, where the stub is.
159
161
  * @param {string} [finding.shortcode] - For `shortcode-not-lowercase`, the
160
162
  * shortcode as written.
163
+ * @param {string[]} [finding.problems] - Invalid attribute diagnostics.
161
164
  * @param {string} [finding.declared] - For `shortcode-not-lowercase`, the
162
165
  * lowercase spelling, when it is a declared shortcode.
163
166
  * @returns {string} The message.
164
167
  * @throws {Error} On a reason outside the closed set — a resolver inventing one
165
168
  * would otherwise report a link with no explanation at all.
166
169
  */
167
- export function linkFindingMessage({ reason, target, packages, anchor, type, stub, shortcode, declared, }: {
170
+ export function linkFindingMessage({ reason, target, packages, anchor, type, stub, shortcode, declared, problems, }: {
168
171
  reason: string;
169
172
  target: string;
170
173
  packages?: Iterable<string> | undefined;
@@ -172,6 +175,7 @@ export function linkFindingMessage({ reason, target, packages, anchor, type, stu
172
175
  type?: string | undefined;
173
176
  stub?: string | undefined;
174
177
  shortcode?: string | undefined;
178
+ problems?: string[] | undefined;
175
179
  declared?: string | undefined;
176
180
  }): string;
177
181
  /**
@@ -188,9 +192,23 @@ export function isSamePage({ target, anchor }: ParsedWikilink): boolean;
188
192
  * Read an operational link target in its enclosing Address context.
189
193
  * @param {string} inner - Lexical link contents.
190
194
  * @param {object} context - Builder defaults and type vocabulary.
195
+ * @param {string} [literal] - Whole matched link, including trailing attributes.
191
196
  * @returns {object} Typed target and diagnostic source spelling.
192
197
  */
193
- export function readWikilink(inner: string, context: object): object;
198
+ export function readWikilink(inner: string, context: object, literal?: string): object;
199
+ /** Whether the actual referenced destination needs spoiler presentation.
200
+ * @param {object} destination - Resolved note metadata.
201
+ * @param {string} [anchor] - Referenced prose anchor.
202
+ * @returns {boolean} Whole-note or section audience.
203
+ */
204
+ export function secretDestination(destination: object, anchor?: string): boolean;
205
+ /** Apply destination-derived presentation without changing its address.
206
+ * @param {string} reference - Rendered reference Markdown.
207
+ * @param {object} parsed - Shared parsed wikilink.
208
+ * @param {object} destination - Resolved target metadata.
209
+ * @returns {string} Inline spoiler or visible reference.
210
+ */
211
+ export function presentWikilink(reference: string, parsed: object, destination: object): string;
194
212
  /**
195
213
  * What a `[[…]]` **is**, before anything decides where it points.
196
214
  *
@@ -297,6 +315,25 @@ export type ParsedWikilink = {
297
315
  * is unlabelled. `null` and `""` differ: an author may write `[[x|]]`.
298
316
  */
299
317
  display: string | null;
318
+ /**
319
+ * - Trailing extension attributes.
320
+ */
321
+ attributes?: {
322
+ id: string;
323
+ classes: string[];
324
+ values: Record<string, string>;
325
+ problems: string[];
326
+ positions?: Record<string, {
327
+ key: {
328
+ start: number;
329
+ end: number;
330
+ };
331
+ value: {
332
+ start: number;
333
+ end: number;
334
+ };
335
+ }>;
336
+ } | undefined;
300
337
  /**
301
338
  * - Whether a `|` was present at all. A link
302
339
  * without one addresses nothing and is a finding — see