@heroiclands/package-build 20.4.0 → 20.6.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 (78) hide show
  1. package/CHANGELOG.md +288 -0
  2. package/CONTENT.md +213 -20
  3. package/README.md +19 -1
  4. package/bin/content-build.mjs +135 -32
  5. package/bin/package-build.mjs +46 -13
  6. package/content-config.mjs +345 -101
  7. package/docs/api.md +1352 -0
  8. package/docs/commands.md +1609 -0
  9. package/docs/configuration.md +1432 -0
  10. package/docs/content-format.md +16 -6
  11. package/docs/diagnostics.md +356 -0
  12. package/docs/getting-started.md +813 -0
  13. package/docs/project-setup.md +469 -0
  14. package/engine/actor-compiler.mjs +30 -27
  15. package/engine/address-diff.mjs +45 -41
  16. package/engine/base-compiler.mjs +6 -0
  17. package/engine/bundles.mjs +9 -0
  18. package/engine/content-address.mjs +9 -9
  19. package/engine/content-index.mjs +44 -23
  20. package/engine/content-links.mjs +44 -11
  21. package/engine/content-lint.mjs +44 -10
  22. package/engine/content-tables.mjs +32 -27
  23. package/engine/folder-notes.mjs +4 -2
  24. package/engine/frontmatter-lint.mjs +35 -38
  25. package/engine/generate.mjs +5 -0
  26. package/engine/helpers.mjs +86 -32
  27. package/engine/index.mjs +12 -2
  28. package/engine/journals.mjs +9 -0
  29. package/engine/note-claims.mjs +18 -10
  30. package/engine/note-schemas.mjs +0 -5
  31. package/engine/note-vocabulary.mjs +32 -31
  32. package/engine/pack-config.mjs +26 -12
  33. package/engine/pack-router.mjs +0 -0
  34. package/engine/pdf-build.mjs +464 -0
  35. package/engine/pdf-fonts.mjs +420 -0
  36. package/engine/pdf-render.mjs +876 -0
  37. package/engine/pdf-toc.mjs +525 -0
  38. package/engine/scenes.mjs +14 -5
  39. package/engine/schema-check.mjs +1 -1
  40. package/engine/site-build.mjs +21 -3
  41. package/engine/web-wikilinks.mjs +6 -3
  42. package/engine/wikilinks.mjs +2 -4
  43. package/hm3/actors.mjs +8 -0
  44. package/hm3/items.mjs +8 -0
  45. package/package.json +1 -1
  46. package/release.mjs +63 -3
  47. package/sohl/actors.mjs +8 -0
  48. package/sohl/items.mjs +8 -0
  49. package/sohl/note-schemas.mjs +5 -5
  50. package/types/content-config.d.mts +66 -15
  51. package/types/engine/actor-compiler.d.mts +34 -30
  52. package/types/engine/address-diff.d.mts +57 -3
  53. package/types/engine/base-compiler.d.mts +10 -2
  54. package/types/engine/bundles.d.mts +9 -0
  55. package/types/engine/content-address.d.mts +9 -9
  56. package/types/engine/content-index.d.mts +57 -13
  57. package/types/engine/content-lint.d.mts +6 -4
  58. package/types/engine/content-tables.d.mts +49 -18
  59. package/types/engine/frontmatter-lint.d.mts +3 -2
  60. package/types/engine/helpers.d.mts +105 -31
  61. package/types/engine/index.d.mts +4 -0
  62. package/types/engine/journals.d.mts +9 -0
  63. package/types/engine/note-claims.d.mts +17 -10
  64. package/types/engine/note-vocabulary.d.mts +23 -196
  65. package/types/engine/pack-config.d.mts +4 -4
  66. package/types/engine/pdf-build.d.mts +42 -0
  67. package/types/engine/pdf-fonts.d.mts +30 -0
  68. package/types/engine/pdf-render.d.mts +156 -0
  69. package/types/engine/pdf-toc.d.mts +114 -0
  70. package/types/engine/scenes.d.mts +10 -1
  71. package/types/engine/schema-check.d.mts +2 -2
  72. package/types/engine/site-build.d.mts +34 -6
  73. package/types/engine/wikilinks.d.mts +2 -3
  74. package/types/hm3/actors.d.mts +8 -0
  75. package/types/hm3/items.d.mts +8 -0
  76. package/types/release.d.mts +15 -4
  77. package/types/sohl/actors.d.mts +10 -2
  78. package/types/sohl/items.d.mts +8 -0
@@ -46,7 +46,8 @@ export function lintContentTree(contentBase: string, { skipDirectories, contentP
46
46
  keys: number;
47
47
  };
48
48
  /**
49
- * The shape every `shortcode` must match: ASCII letters and digits only.
49
+ * The shape every `shortcode` must match: lowercase ASCII letters and digits
50
+ * only.
50
51
  *
51
52
  * This is {@link ADDRESS_SEGMENT_PATTERN}, not a second copy of it. A shortcode
52
53
  * is the last segment of a canonical address, and the rule it is held to is the
@@ -54,9 +55,10 @@ export function lintContentTree(contentBase: string, { skipDirectories, contentP
54
55
  * free to drift apart. The name survives because this is where the rule
55
56
  * is applied to a note.
56
57
  *
57
- * Case is deliberately **not** constrained: hundreds of authored shortcodes are
58
- * mixed-case and collide with nothing, so tightening that is a separate
59
- * decision from this one.
58
+ * Case is held to that rule with no exception: two shortcodes differing only
59
+ * in case are two names nobody can tell apart, and `canonicalKey` lowercases
60
+ * every address it builds regardless, so a mixed-case shortcode addresses the
61
+ * same document as its lowercase spelling.
60
62
  *
61
63
  * A consuming system's *runtime* keeps its own copy of this pattern — it cannot
62
64
  * import a build-time dependency into shipped code — and is expected to pin the
@@ -73,34 +73,65 @@ export function selectRows(spec: object, docs: Array<ContentTableDoc>, self?: Co
73
73
  * @returns {string} The markdown table (no trailing newline).
74
74
  */
75
75
  export function renderContentTable(spec: object, rows: Array<ContentTableDoc>, linkable: (doc: ContentTableDoc) => boolean, self?: ContentTableDoc): string;
76
- export function expandContentTables(markdown: any, { docs, linkable, source, self, sqlTables, }?: {
77
- docs?: never[] | undefined;
78
- linkable?: (() => boolean) | undefined;
76
+ /**
77
+ * Expand every fenced `dataview` and `sql` block in a markdown body.
78
+ *
79
+ * A block that cannot be honoured — malformed or unsupported — is left in the
80
+ * body verbatim and reported in `errors`, so the failure is visible in the
81
+ * output as well as on the console. Every other code fence, and every code
82
+ * span, is left alone (that is how the syntax is documented).
83
+ *
84
+ * A query that selects **no** note is an error unless the fence says
85
+ * `allow-empty`, which states that an empty table is the intended result.
86
+ *
87
+ * @param {string} markdown - The note body, frontmatter already stripped.
88
+ * @param {object} ctx
89
+ * @param {Array<ContentTableDoc>} ctx.docs - The searchable universe: every
90
+ * content note the caller considers in scope.
91
+ * @param {(doc: ContentTableDoc) => boolean} [ctx.linkable] - Whether a note can
92
+ * be linked to from a cell; defaults to never.
93
+ * @param {string} [ctx.source] - The note being expanded, for error reports.
94
+ * @param {ContentTableDoc} [ctx.self] - The note being expanded, as a searchable
95
+ * doc: what a query's `this` reads.
96
+ * @param {object[]} [ctx.sqlTables] - This note's prepared `sql` results, in
97
+ * document order, from
98
+ * {@link module:engine/sql-tables.prepareSqlTables}. An `sql` directive with
99
+ * no prepared result is an error: nothing here runs a query.
100
+ * @returns {{markdown: string, errors: Array<{source: string, directive: string,
101
+ * reason: string, line: number, column?: number}>,
102
+ * warnings: Array<{source: string, line: number, column: number,
103
+ * reason: string}>, lineMap: Array<{line: number, generated: boolean}>}}
104
+ * `lineMap` is parallel to the emitted lines and says which authored line
105
+ * each came from, so a diagnostic about the expanded body can name an
106
+ * authored position. An `errors` entry carries the 0-based line of the
107
+ * directive that failed, for the same reason. `warnings` holds one entry per
108
+ * `dataview` directive the body still authors.
109
+ */
110
+ export function expandContentTables(markdown: string, { docs, linkable, source, self, sqlTables, }?: {
111
+ docs: Array<ContentTableDoc>;
112
+ linkable?: ((doc: ContentTableDoc) => boolean) | undefined;
79
113
  source?: string | undefined;
80
- self?: undefined;
81
- sqlTables?: undefined;
114
+ self?: ContentTableDoc | undefined;
115
+ sqlTables?: object[] | undefined;
82
116
  }): {
83
117
  markdown: string;
84
- errors: ({
85
- source: string;
86
- directive: string;
87
- reason: any;
88
- line: number;
89
- column: number;
90
- } | {
118
+ errors: Array<{
91
119
  source: string;
92
120
  directive: string;
93
- reason: any;
121
+ reason: string;
94
122
  line: number;
95
- column?: undefined;
96
- })[];
97
- warnings: {
123
+ column?: number;
124
+ }>;
125
+ warnings: Array<{
98
126
  source: string;
99
127
  line: number;
100
128
  column: number;
101
129
  reason: string;
102
- }[];
103
- lineMap: any[];
130
+ }>;
131
+ lineMap: Array<{
132
+ line: number;
133
+ generated: boolean;
134
+ }>;
104
135
  };
105
136
  /**
106
137
  * One content note as a content build hands it to the expander: its parsed
@@ -112,8 +112,9 @@ export function matchesKind(value: unknown, kind: string): boolean;
112
112
  * @param {object} note - A note from the link index (`{fm, file, raw, type}`).
113
113
  * @param {object} opts
114
114
  * @param {Record<string, readonly object[]>} opts.schemas - Type → declaration.
115
- * @param {object} [opts.index] - The link index, for the reference check. Its
116
- * absence skips that check rather than reporting every reference as dead.
115
+ * @param {object} [opts.index] - The link index, for the reference check, which
116
+ * runs through its `referenceHit`. Its absence skips that check rather than
117
+ * reporting every reference as dead.
117
118
  * @param {Record<string, object>} [opts.vocabulary] - Type → the closed regions
118
119
  * it declares, as `engine/note-vocabulary.mjs` states them. Supplied
119
120
  * by the caller for the same reason `schemas` is: this module validates a
@@ -23,24 +23,6 @@ export function parseMarkdownFile(filePath: any): {
23
23
  bodyLine: number;
24
24
  bodyColumn: number;
25
25
  };
26
- /**
27
- * Recursively yields every `.md` file under `rootDir`, parsed.
28
- * Yields `{ frontmatter, body, description, file, absPath, bodyLine,
29
- * bodyColumn }` for each match — the last two from
30
- * {@link parseMarkdownFile}, so a caller can report a position inside the
31
- * body as a position in the file.
32
- * Silently skips directories that don't exist.
33
- *
34
- * Directory names in `skipDirectories` are ignored wherever they appear. The
35
- * walk itself knows nothing about what they mean: `Templates/` is an Obsidian
36
- * templater convention this repository's vault happens to use, not a property
37
- * of a content tree, so it is configured rather than hard-coded.
38
- *
39
- * @param {string} rootDir - Root of the tree to walk.
40
- * @param {object} [opts]
41
- * @param {readonly string[]} [opts.skipDirectories] - Directory names to ignore.
42
- * Defaults to the configured list.
43
- */
44
26
  /**
45
27
  * Refuse a corpus read whose scope its caller did not state.
46
28
  *
@@ -78,8 +60,35 @@ export function assertStatedScope(skipDirectories: readonly string[] | undefined
78
60
  * @returns {void}
79
61
  */
80
62
  export function assertSuppliedCorpus(records: readonly object[] | undefined, who: string): void;
81
- export function walkMarkdownTree(rootDir: any, { skipDirectories }?: {}): Generator<{
82
- file: string;
63
+ /**
64
+ * Recursively yields every `.md` file under `rootDir`, parsed.
65
+ *
66
+ * Yields `{ frontmatter, body, description, file, absPath, bodyLine,
67
+ * bodyColumn }` for each match — the last from {@link parseMarkdownFile}, so a
68
+ * caller can report a position inside the body as a position in the file. A
69
+ * root that does not exist yields nothing, and a directory that cannot be read
70
+ * is warned about and skipped.
71
+ *
72
+ * Directory names in `skipDirectories` are ignored wherever they appear. The
73
+ * walk itself knows nothing about what they mean: `Templates/` is an Obsidian
74
+ * templater convention this repository's vault happens to use, not a property
75
+ * of a content tree, so it is stated by the caller rather than hard-coded.
76
+ *
77
+ * @param {string} rootDir - Root of the tree to walk.
78
+ * @param {object} opts
79
+ * @param {readonly string[]} opts.skipDirectories - Directory names to ignore.
80
+ * Required: the scope is the caller's to state, so two passes cannot
81
+ * disagree about which files are the corpus.
82
+ * @yields {{frontmatter: object|null, body: string, description: string,
83
+ * file: string, absPath: string, bodyLine?: number, bodyColumn?: number}}
84
+ * One entry per `.md` file found.
85
+ * @throws {Error} When `skipDirectories` is not stated — see
86
+ * {@link assertStatedScope}.
87
+ */
88
+ export function walkMarkdownTree(rootDir: string, { skipDirectories }?: {
89
+ skipDirectories: readonly string[];
90
+ }): Generator<{
91
+ file: string & NonSharedBuffer;
83
92
  absPath: string;
84
93
  frontmatter: null;
85
94
  body: string;
@@ -87,7 +96,7 @@ export function walkMarkdownTree(rootDir: any, { skipDirectories }?: {}): Genera
87
96
  bodyLine?: undefined;
88
97
  bodyColumn?: undefined;
89
98
  } | {
90
- file: string;
99
+ file: string & NonSharedBuffer;
91
100
  absPath: string;
92
101
  frontmatter: any;
93
102
  body: string;
@@ -240,14 +249,22 @@ export function makeFilename(name: any, id: any): string;
240
249
  * `itemArt()`, which runs the path back through this function so a registry
241
250
  * entry and a note's `img:` are spelled the same way (#7).
242
251
  *
252
+ * **A package with no asset root cannot answer at all.** `assetRoot` is derived
253
+ * from the package kind, and a `documentation` package has none: Foundry serves
254
+ * no files for it. Only a compiling pass reaches here, and a documentation
255
+ * package runs none, so a path arriving with no root to put it under is a pass
256
+ * running where it should not — reported as that, rather than emitted as
257
+ * `null/icons/relic.svg` into a document nobody would check.
258
+ *
243
259
  * @param {string | null | undefined} raw - content-relative path from frontmatter.
244
- * @param {{assetRoot: string}} [config] - The resolved build configuration.
260
+ * @param {{assetRoot: string|null}} [config] - The resolved build configuration.
245
261
  * Defaults to this repository's.
246
262
  * @returns {string | null} the Foundry-relative path; `""` for a deliberate
247
263
  * blank, and `null` when the note names no art at all.
264
+ * @throws {Error} When the configuration has no asset root.
248
265
  */
249
266
  export function resolveImg(raw: string | null | undefined, config?: {
250
- assetRoot: string;
267
+ assetRoot: string | null;
251
268
  }): string | null;
252
269
  /**
253
270
  * Resolves the display name from frontmatter, preferring `name.full`,
@@ -368,9 +385,23 @@ export function defaultStats(): object;
368
385
  * @param {object} [router] - The pack router. Supplied by the calling pass so
369
386
  * the index and the compile agree about where each note landed; defaults to
370
387
  * this repository's own.
388
+ * @param {object} [opts]
389
+ * @param {readonly string[]} [opts.skipDirectories] - Part of the options bag
390
+ * every corpus reader takes; the scope is already settled by `records`.
391
+ * @param {object} [opts.config] - The resolved build configuration; loaded when
392
+ * omitted.
393
+ * @param {readonly object[]} [opts.records] - The corpus, derived once per
394
+ * compile and handed in. Required: see {@link assertSuppliedCorpus}.
395
+ * @param {object[]} [opts.problems] - Part of the same options bag; the notes
396
+ * the index cannot record are collected where the corpus is derived.
371
397
  * @returns {{byShortcode: Map, types: Set}} From `buildWikilinkIndex`.
372
398
  */
373
- export function buildContentLinkIndex(contentBase: string, router?: object, { skipDirectories, config, records, problems }?: {}): {
399
+ export function buildContentLinkIndex(contentBase: string, router?: object, { skipDirectories, config, records, problems }?: {
400
+ skipDirectories?: readonly string[] | undefined;
401
+ config?: object | undefined;
402
+ records?: readonly object[] | undefined;
403
+ problems?: object[] | undefined;
404
+ }): {
374
405
  byShortcode: Map<any, any>;
375
406
  types: Set<any>;
376
407
  };
@@ -386,18 +417,42 @@ export function buildContentLinkIndex(contentBase: string, router?: object, { sk
386
417
  * inventing a position.
387
418
  *
388
419
  * @param {string} body - The note's markdown body, tables already expanded.
389
- * @param {object} ctx - `{ type, id, pack, docPack, index, name }` — `name` is
390
- * used in the message, and the two pack names address a `[[#slug]]`
391
- * self-link, whose target is the source note itself and so has no index
392
- * entry. Position is carried by `{ file, bodyLine, bodyColumn, lineMap }`,
393
- * the last from {@link expandNoteTables}.
420
+ * @param {object} ctx
421
+ * @param {string} ctx.type - The source note's content type.
422
+ * @param {string} ctx.id - The source note's document id.
423
+ * @param {string} ctx.pack - The pack the note's own document lands in, which
424
+ * addresses a `[[#slug]]` self-link: its target is the source note itself, so
425
+ * it has no index entry.
426
+ * @param {string} ctx.docPack - The pack the note's documentation journal lands
427
+ * in, addressing a self-link the same way.
428
+ * @param {object} ctx.index - The address index every link resolves through.
429
+ * @param {string} ctx.name - The note, for the message.
430
+ * @param {string} [ctx.file] - The note's file, so a report names it.
431
+ * @param {number} [ctx.bodyLine] - 1-based file line of the body's first line.
432
+ * @param {number} [ctx.bodyColumn] - 1-based file column of the same character.
433
+ * @param {Array<{line: number, generated: boolean}>} [ctx.lineMap] - Which
434
+ * authored line each body line came from, from {@link expandNoteTables}.
394
435
  * @returns {{markdown: string, unresolved: Array<object>}}
395
436
  * @throws {Error} On any link that does not resolve — an unlabelled one, a
396
437
  * target that is not an address, or an address nothing publishes. The error
397
438
  * carries `file` and `position`, so a caller reports it in the same form
398
439
  * rather than re-deriving one.
399
440
  */
400
- export function convertNoteWikilinks(body: string, { type, id, pack, docPack, index, name, file, bodyLine, bodyColumn, lineMap }: object): {
441
+ export function convertNoteWikilinks(body: string, { type, id, pack, docPack, index, name, file, bodyLine, bodyColumn, lineMap }: {
442
+ type: string;
443
+ id: string;
444
+ pack: string;
445
+ docPack: string;
446
+ index: object;
447
+ name: string;
448
+ file?: string | undefined;
449
+ bodyLine?: number | undefined;
450
+ bodyColumn?: number | undefined;
451
+ lineMap?: {
452
+ line: number;
453
+ generated: boolean;
454
+ }[] | undefined;
455
+ }): {
401
456
  markdown: string;
402
457
  unresolved: Array<object>;
403
458
  };
@@ -407,10 +462,24 @@ export function convertNoteWikilinks(body: string, { type, id, pack, docPack, in
407
462
  * a table that leaves rows tied still emits identically on every build.
408
463
  *
409
464
  * @param {string} contentBase - Root of the content tree.
465
+ * @param {object} [opts]
466
+ * @param {readonly string[]} [opts.skipDirectories] - Part of the options bag
467
+ * every corpus reader takes; the scope is already settled by `records`.
468
+ * @param {object} [opts.config] - The resolved build configuration; loaded when
469
+ * omitted.
470
+ * @param {readonly object[]} [opts.records] - The corpus, derived once per
471
+ * compile and handed in. Required: see {@link assertSuppliedCorpus}.
472
+ * @param {object[]} [opts.problems] - Part of the same options bag; the notes
473
+ * the walk cannot read are collected where the corpus is derived.
410
474
  * @returns {Array<{fm: object, path: string, tld: string, folder: string,
411
475
  * absPath: string}>}
412
476
  */
413
- export function collectContentDocs(contentBase: string, { skipDirectories, config, records, problems }?: {}): Array<{
477
+ export function collectContentDocs(contentBase: string, { skipDirectories, config, records, problems }?: {
478
+ skipDirectories?: readonly string[] | undefined;
479
+ config?: object | undefined;
480
+ records?: readonly object[] | undefined;
481
+ problems?: object[] | undefined;
482
+ }): Array<{
414
483
  fm: object;
415
484
  path: string;
416
485
  tld: string;
@@ -434,6 +503,10 @@ export function collectContentDocs(contentBase: string, { skipDirectories, confi
434
503
  * query's `this` reads. Its entry in `docs` supplies the path as well.
435
504
  * @param {number} [ctx.bodyLine] - 1-based file line of the body's first line,
436
505
  * so a failing directive can be reported at its position in the file.
506
+ * @param {object[]} [ctx.sqlTables] - This note's prepared `sql` results, in
507
+ * document order, from
508
+ * {@link module:engine/sql-tables.prepareSqlTables}. An `sql` directive with
509
+ * no prepared result fails the note: nothing here runs a query.
437
510
  * @returns {{markdown: string, lineMap: Array<{line: number,
438
511
  * generated: boolean}>}} The body with every table expanded, and where each
439
512
  * emitted line came from — which is what lets a diagnostic about the
@@ -447,6 +520,7 @@ export function expandNoteTables(body: string, { docs, name, fm, bodyLine, sqlTa
447
520
  name: string;
448
521
  fm?: object | undefined;
449
522
  bodyLine?: number | undefined;
523
+ sqlTables?: object[] | undefined;
450
524
  }): {
451
525
  markdown: string;
452
526
  lineMap: Array<{
@@ -39,6 +39,10 @@ export * as itemDocs from "./item-docs.mjs";
39
39
  export * as wikilinks from "./wikilinks.mjs";
40
40
  export * as wikilinkSyntax from "./wikilink-syntax.mjs";
41
41
  export * as siteIndex from "./site-index.mjs";
42
+ export * as pdfToc from "./pdf-toc.mjs";
43
+ export * as pdfRender from "./pdf-render.mjs";
44
+ export * as pdfFonts from "./pdf-fonts.mjs";
45
+ export * as pdfBuild from "./pdf-build.mjs";
42
46
  export * as baseCompiler from "./base-compiler.mjs";
43
47
  export * as journals from "./journals.mjs";
44
48
  export * as macros from "./macros.mjs";
@@ -147,6 +147,15 @@ export function buildJournalEntry({ id, name, markdown, leadName, folder, flags,
147
147
  flags?: object | undefined;
148
148
  stats?: object | undefined;
149
149
  }): object;
150
+ /**
151
+ * Journals pack compiler.
152
+ *
153
+ * Walks the content tree and compiles every `type: doc` note, and every note of
154
+ * a doc-carrying type, into one JournalEntry document: the body split into
155
+ * pages on its top-level H1 headings, each rendered to HTML. A doc-carrying
156
+ * note's entry is that document's documentation, filed in the document's own
157
+ * folder.
158
+ */
150
159
  export class Journals extends BasePackCompiler {
151
160
  /**
152
161
  * How many of the compiled entries were documentation for a document
@@ -7,10 +7,7 @@
7
7
  * pack from appearing to answer for any note.
8
8
  *
9
9
  * @param {string} docType - The Foundry document type a pack holds.
10
- * @param {ClaimSources} [sources] - What to answer from.
11
- * @param {object} [opts] - Options.
12
- * @param {readonly object[]} [opts.records] - The corpus, derived once by the
13
- * compile and handed in — required, for the reason above. Defaults to the
10
+ * @param {ClaimSources} [sources] - What to answer from. Defaults to the
14
11
  * configured registries and the systems this toolchain ships.
15
12
  * @returns {ReadonlySet<string>} The note types such a pass would claim.
16
13
  */
@@ -88,9 +85,6 @@ export function documentClassesFor(type: string, sources?: ClaimSources, { hasPr
88
85
  * @param {object} [config] - The resolved build configuration. Defaults to this
89
86
  * repository's.
90
87
  * @param {ClaimSources} [sources] - What to answer from.
91
- * @param {object} [opts] - Options.
92
- * @param {readonly object[]} [opts.records] - The corpus, derived once by the
93
- * compile and handed in — required, for the reason above.
94
88
  * @returns {ReadonlySet<string>} The claimed note types.
95
89
  */
96
90
  export function claimedNoteTypes(config?: object, sources?: ClaimSources): ReadonlySet<string>;
@@ -104,9 +98,6 @@ export function claimedNoteTypes(config?: object, sources?: ClaimSources): Reado
104
98
  * declare on top.
105
99
  *
106
100
  * @param {ClaimSources} [sources] - What to answer from.
107
- * @param {object} [opts] - Options.
108
- * @param {readonly object[]} [opts.records] - The corpus, derived once by the
109
- * compile and handed in — required, for the reason above.
110
101
  * @returns {ReadonlySet<string>} The vocabulary.
111
102
  */
112
103
  export function noteTypeVocabulary(sources?: ClaimSources): ReadonlySet<string>;
@@ -150,6 +141,22 @@ export function unclaimedNoteFindings(config?: object, sources?: ClaimSources, {
150
141
  * @type {ReadonlySet<string>}
151
142
  */
152
143
  export const NEVER_PACKED_TYPES: ReadonlySet<string>;
144
+ /**
145
+ * The whole note vocabulary of a package that compiles no Foundry documents.
146
+ *
147
+ * Every other type in the vocabulary exists to *become* a document: a `skill` is
148
+ * an Item, a `being` an Actor, a `place` a JournalEntry, a `folder` the Folder
149
+ * they are filed under. In a `documentation` package none of them has a
150
+ * destination, so a note carrying one would be authored, validated, walked and
151
+ * then published as a page of something that was meant to be a compendium
152
+ * entry — the plausible-looking result that reads as success.
153
+ *
154
+ * `doc` is prose whose single document *is* the prose, and `homepage` is the
155
+ * authored front page every package publishes. Both are already pages first.
156
+ *
157
+ * @type {ReadonlySet<string>}
158
+ */
159
+ export const DOCUMENTATION_NOTE_TYPES: ReadonlySet<string>;
153
160
  /**
154
161
  * Content types the specification states and this toolchain does not yet
155
162
  * compile.
@@ -105,17 +105,19 @@ export function dataFields(type: string, vocabulary?: Readonly<Record<string, Ty
105
105
  */
106
106
  export function subTypes(type: string, vocabulary?: Readonly<Record<string, TypeVocabulary>>): readonly string[] | null | undefined;
107
107
  /**
108
- * Every note type this toolchain compiles, and the closed vocabulary it
109
- * declares.
108
+ * The declared tag that marks a note as **unfinished**.
110
109
  *
111
- * Taken from the content-format specification, one `### type:` section per
112
- * entry. Where the specification and the shape notes are authored in today
113
- * disagree, the specification wins on the **name** that is what a `data:`
114
- * key will be called — and the disagreement is recorded on the field rather
115
- * than resolved silently.
110
+ * Named once and referenced from the declaration below, because a second
111
+ * spelling is how the two come apart: rename the tag in `DECLARED_TAGS` and a
112
+ * private copy elsewhere keeps matching the old word, silently.
116
113
  *
117
- * @type {Readonly<Record<string, TypeVocabulary>>}
114
+ * It is a **presentation** fact and nothing more. A draft note compiles,
115
+ * validates, publishes and resolves like any other; only a link *into* it
116
+ * renders marked. What it emphatically is not is the retired `draft:` field,
117
+ * whose entire effect was to move a note from published to unresolvable — see
118
+ * {@link draftRetiredMessage}.
118
119
  */
120
+ export const DRAFT_TAG: "draft";
119
121
  /**
120
122
  * The tags that **classify** a note, grouped by what they classify.
121
123
  *
@@ -142,20 +144,6 @@ export function subTypes(type: string, vocabulary?: Readonly<Record<string, Type
142
144
  * fishing village is a `village` that is `fishing`, and the single-valued field
143
145
  * this replaced had to spell it `Fishing Village` as a value of its own.
144
146
  */
145
- /**
146
- * The declared tag that marks a note as **unfinished**.
147
- *
148
- * Named once and referenced from the declaration below, because a second
149
- * spelling is how the two come apart: rename the tag in `DECLARED_TAGS` and a
150
- * private copy elsewhere keeps matching the old word, silently.
151
- *
152
- * It is a **presentation** fact and nothing more. A draft note compiles,
153
- * validates, publishes and resolves like any other; only a link *into* it
154
- * renders marked. What it emphatically is not is the retired `draft:` field,
155
- * whose entire effect was to move a note from published to unresolvable — see
156
- * {@link draftRetiredMessage}.
157
- */
158
- export const DRAFT_TAG: "draft";
159
147
  export const DECLARED_TAGS: Readonly<{
160
148
  /** What a place *is*. */
161
149
  placeKind: Readonly<{
@@ -183,180 +171,19 @@ export const DECLARED_TAGS: Readonly<{
183
171
  tags: readonly string[];
184
172
  }>;
185
173
  }>;
186
- export const NOTE_VOCABULARY: Readonly<{
187
- being: Readonly<{
188
- subTypes: null;
189
- data: readonly DataFieldSpec[];
190
- }>;
191
- vehicle: Readonly<{
192
- subTypes: null;
193
- data: readonly DataFieldSpec[];
194
- }>;
195
- affiliation: Readonly<{
196
- subTypes: readonly string[];
197
- data: readonly DataFieldSpec[];
198
- }>;
199
- affliction: Readonly<{
200
- subTypes: readonly string[];
201
- data: readonly DataFieldSpec[];
202
- }>;
203
- armorgear: Readonly<{
204
- data: readonly DataFieldSpec[];
205
- }>;
206
- armorlocation: Readonly<{
207
- subTypes: null;
208
- data: readonly DataFieldSpec[];
209
- }>;
210
- attribute: Readonly<{
211
- data: readonly DataFieldSpec[];
212
- }>;
213
- concoctiongear: Readonly<{
214
- subTypes: readonly string[];
215
- data: readonly (DataFieldSpec | Readonly<{
216
- describe: "How many of the thing there are; one when unstated.";
217
- shape: "number";
218
- kind: "number";
219
- name: "quantity";
220
- }>)[];
221
- }>;
222
- containergear: Readonly<{
223
- data: readonly DataFieldSpec[];
224
- }>;
225
- miscgear: Readonly<{
226
- data: readonly (DataFieldSpec | Readonly<{
227
- describe: "How many of the thing there are; one when unstated.";
228
- shape: "number";
229
- kind: "number";
230
- name: "quantity";
231
- }>)[];
232
- }>;
233
- mystery: Readonly<{
234
- subTypes: readonly string[];
235
- data: readonly DataFieldSpec[];
236
- }>;
237
- mysticalability: Readonly<{
238
- subTypes: readonly string[];
239
- data: readonly DataFieldSpec[];
240
- }>;
241
- projectilegear: Readonly<{
242
- subTypes: readonly string[];
243
- data: readonly (DataFieldSpec | Readonly<{
244
- describe: "How many of the thing there are; one when unstated.";
245
- shape: "number";
246
- kind: "number";
247
- name: "quantity";
248
- }>)[];
249
- }>;
250
- skill: Readonly<{
251
- subTypes: readonly string[];
252
- data: readonly DataFieldSpec[];
253
- }>;
254
- trauma: Readonly<{
255
- subTypes: readonly string[];
256
- data: readonly DataFieldSpec[];
257
- }>;
258
- weapongear: Readonly<{
259
- data: readonly DataFieldSpec[];
260
- }>;
261
- doc: Readonly<{
262
- subTypes: readonly string[];
263
- data: readonly never[];
264
- }>;
265
- macro: Readonly<{
266
- data: readonly never[];
267
- }>;
268
- folder: Readonly<{
269
- data: readonly ({
270
- describe: string;
271
- shape: "a wikilink, or a map of wikilinks keyed by pack";
272
- kind: "scalar-or-map";
273
- entryShape: "a wikilink";
274
- keys: "pack";
275
- name: string;
276
- } | {
277
- describe: string;
278
- shape: "string";
279
- kind: "string";
280
- name: string;
281
- })[];
282
- }>;
283
- bundle: Readonly<{
284
- data: readonly {
285
- describe: string;
286
- shape: "list of wikilinks";
287
- kind: "list";
288
- name: string;
289
- }[];
290
- }>;
291
- lore: Readonly<{
292
- subTypes: readonly string[];
293
- data: readonly never[];
294
- }>;
295
- place: Readonly<{
296
- subTypes: readonly string[];
297
- data: readonly ({
298
- describe: string;
299
- shape: "string";
300
- kind: "string";
301
- name: string;
302
- } | {
303
- describe: string;
304
- shape: "list of wikilinks";
305
- kind: "list";
306
- name: string;
307
- } | {
308
- describe: string;
309
- shape: "number";
310
- kind: "number";
311
- name: string;
312
- })[];
313
- }>;
314
- scenario: Readonly<{
315
- subTypes: readonly string[];
316
- data: readonly ({
317
- describe: string;
318
- shape: "list of wikilinks";
319
- kind: "list";
320
- name: string;
321
- } | {
322
- describe: string;
323
- shape: "string";
324
- kind: "string";
325
- name: string;
326
- } | {
327
- describe: string;
328
- shape: "list";
329
- kind: "list";
330
- name: string;
331
- })[];
332
- }>;
333
- homepage: Readonly<{
334
- data: readonly never[];
335
- }>;
336
- map: Readonly<{
337
- subTypes: readonly string[];
338
- data: readonly ({
339
- describe: string;
340
- shape: "string";
341
- kind: "string";
342
- name: string;
343
- } | {
344
- describe: string;
345
- shape: "list";
346
- kind: "list";
347
- name: string;
348
- } | {
349
- describe: string;
350
- shape: "number";
351
- kind: "number";
352
- name: string;
353
- } | {
354
- describe: string;
355
- shape: "as authored";
356
- name: string;
357
- })[];
358
- }>;
359
- }>;
174
+ /**
175
+ * Every note type this toolchain compiles, and the closed vocabulary it
176
+ * declares.
177
+ *
178
+ * Taken from the content-format specification, one `### type:` section per
179
+ * entry. Where the specification and the shape notes are authored in today
180
+ * disagree, the specification wins on the **name** — that is what a `data:`
181
+ * key will be called — and the disagreement is recorded on the field rather
182
+ * than resolved silently.
183
+ *
184
+ * @type {Readonly<Record<string, TypeVocabulary>>}
185
+ */
186
+ export const NOTE_VOCABULARY: Readonly<Record<string, TypeVocabulary>>;
360
187
  /**
361
188
  * One `data:` key a note type may carry.
362
189
  *