@heroiclands/package-build 22.21.0 → 22.22.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.
- package/CHANGELOG.md +191 -0
- package/assets/styles/content-base.css +162 -0
- package/bin/content-commands.mjs +26 -3
- package/bin/package-build.mjs +15 -2
- package/ci/content-format-reference.mjs +68 -1
- package/config.mjs +26 -0
- package/content-config.mjs +73 -4
- package/docs/api.md +36 -18
- package/docs/authoring/dates-and-calendars.md +4 -2
- package/docs/authoring/frontmatter.md +2 -2
- package/docs/authoring/links-and-markup.md +237 -28
- package/docs/configuration.md +27 -1
- package/docs/content-format.md +3 -1
- package/docs/guides/reference-pages.md +15 -0
- package/docs/reference/format-details.md +224 -46
- package/docs/reference/note-types.md +21 -4
- package/engine/actor-compiler.mjs +23 -0
- package/engine/anchored-sections.mjs +35 -4
- package/engine/anchors.mjs +10 -20
- package/engine/base-compiler.mjs +86 -21
- package/engine/base-styles.mjs +149 -0
- package/engine/bundles.mjs +0 -1
- package/engine/compendiums.mjs +8 -1
- package/engine/content-blocks.mjs +410 -0
- package/engine/content-captions.mjs +57 -8
- package/engine/content-footnotes.mjs +189 -0
- package/engine/content-format-check.mjs +15 -12
- package/engine/content-index.mjs +2 -2
- package/engine/content-links.mjs +14 -6
- package/engine/content-tables.mjs +45 -4
- package/engine/content-tasklists.mjs +189 -0
- package/engine/docs-checks.mjs +4 -4
- package/engine/extension-attributes.mjs +48 -2
- package/engine/frontmatter-lint.mjs +47 -64
- package/engine/frontmatter.mjs +3 -3
- package/engine/heading-attributes.mjs +308 -0
- package/engine/helpers.mjs +14 -13
- package/engine/homepage.mjs +8 -8
- package/engine/index.mjs +3 -0
- package/engine/infobox-render.mjs +15 -3
- package/engine/infobox.mjs +83 -8
- package/engine/journals.mjs +36 -17
- package/engine/macros.mjs +1 -1
- package/engine/markdown-expressions.mjs +178 -53
- package/engine/note-dates.mjs +49 -0
- package/engine/note-frontmatter.mjs +7 -16
- package/engine/note-vocabulary.mjs +172 -37
- package/engine/page-lists.mjs +358 -0
- package/engine/pdf-build.mjs +76 -42
- package/engine/pdf-render.mjs +422 -49
- package/engine/rank-ladder.mjs +198 -0
- package/engine/reckoning-markers.mjs +1 -1
- package/engine/retired-fields.mjs +8 -13
- package/engine/scenes.mjs +10 -3
- package/engine/site-build.mjs +41 -12
- package/engine/site-config.mjs +10 -1
- package/engine/site-index.mjs +18 -2
- package/engine/site-preview.mjs +18 -7
- package/engine/social-ties.mjs +52 -14
- package/engine/sql-tables.mjs +66 -9
- package/engine/standings.mjs +89 -6
- package/engine/system-block.mjs +12 -14
- package/engine/web-wikilinks.mjs +48 -1
- package/hm3/actors.mjs +6 -3
- package/manifest.mjs +13 -0
- package/package.json +1 -1
- package/sohl/actors.mjs +22 -99
- package/sohl/item-fields.mjs +4 -5
- package/sohl/items.mjs +1 -1
- package/sohl/note-schemas.mjs +11 -21
- package/types/config.d.mts +9 -0
- package/types/engine/actor-compiler.d.mts +11 -0
- package/types/engine/anchored-sections.d.mts +24 -0
- package/types/engine/base-compiler.d.mts +19 -0
- package/types/engine/base-styles.d.mts +93 -0
- package/types/engine/content-blocks.d.mts +87 -0
- package/types/engine/content-captions.d.mts +14 -1
- package/types/engine/content-footnotes.d.mts +73 -0
- package/types/engine/content-format-check.d.mts +8 -6
- package/types/engine/content-tables.d.mts +12 -4
- package/types/engine/content-tasklists.d.mts +72 -0
- package/types/engine/extension-attributes.d.mts +22 -1
- package/types/engine/frontmatter.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +174 -0
- package/types/engine/helpers.d.mts +7 -4
- package/types/engine/homepage.d.mts +7 -7
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox-render.d.mts +6 -1
- package/types/engine/journals.d.mts +14 -7
- package/types/engine/markdown-expressions.d.mts +23 -0
- package/types/engine/note-frontmatter.d.mts +1 -4
- package/types/engine/note-vocabulary.d.mts +82 -6
- package/types/engine/page-lists.d.mts +126 -0
- package/types/engine/pdf-render.d.mts +72 -2
- package/types/engine/rank-ladder.d.mts +32 -0
- package/types/engine/retired-fields.d.mts +4 -6
- package/types/engine/site-build.d.mts +13 -1
- package/types/engine/site-config.d.mts +9 -0
- package/types/engine/site-index.d.mts +13 -1
- package/types/engine/site-preview.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +31 -7
- package/types/engine/standings.d.mts +21 -3
- package/types/engine/system-block.d.mts +11 -12
- package/types/engine/web-wikilinks.d.mts +3 -1
- package/types/hm3/actors.d.mts +3 -3
- package/types/sohl/actors.d.mts +6 -7
- package/engine/content-admonitions.mjs +0 -114
- package/engine/content-secrets.mjs +0 -112
- package/types/engine/content-admonitions.d.mts +0 -24
- package/types/engine/content-secrets.d.mts +0 -17
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every `pagelist` fence in a markdown body, with the position each occupies.
|
|
3
|
+
*
|
|
4
|
+
* Positions are 0-based lines into the body as given, which is what a
|
|
5
|
+
* diagnostic about a directive needs and what the expander uses to splice
|
|
6
|
+
* results back in.
|
|
7
|
+
*
|
|
8
|
+
* **A malformed directive is still a directive.** It is returned carrying its
|
|
9
|
+
* problems rather than skipped, so the expander finds a prepared answer at its
|
|
10
|
+
* ordinal and reports the fault where the fence sits. That includes a fence
|
|
11
|
+
* nobody closed, which the author meant as a directive and which would
|
|
12
|
+
* otherwise swallow the rest of the note into a code block.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} markdown - The note body, frontmatter already stripped.
|
|
15
|
+
* @returns {Array<{line: number, close: number, indent: string, tag: string,
|
|
16
|
+
* type: string, sort: string, descriptions: boolean, allowEmpty: boolean,
|
|
17
|
+
* problems: string[], block: string}>} One entry per fence, in document order.
|
|
18
|
+
*/
|
|
19
|
+
export function findPageListBlocks(markdown: string): Array<{
|
|
20
|
+
line: number;
|
|
21
|
+
close: number;
|
|
22
|
+
indent: string;
|
|
23
|
+
tag: string;
|
|
24
|
+
type: string;
|
|
25
|
+
sort: string;
|
|
26
|
+
descriptions: boolean;
|
|
27
|
+
allowEmpty: boolean;
|
|
28
|
+
problems: string[];
|
|
29
|
+
block: string;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* The pages a directive selects, as index records.
|
|
33
|
+
*
|
|
34
|
+
* A **stub** is left out: an empty body publishes no page, which the index says
|
|
35
|
+
* by holding no address, so there is nothing for the list to link to. A
|
|
36
|
+
* documentation journal and an asset are not pages an author tagged, which
|
|
37
|
+
* {@link module:engine/index-records.isNoteRecord} already answers.
|
|
38
|
+
*
|
|
39
|
+
* @param {object[]} records - Content-index records.
|
|
40
|
+
* @param {{tag: string, type: string}} directive - From {@link findPageListBlocks}.
|
|
41
|
+
* @returns {object[]} The selected records, unordered.
|
|
42
|
+
*/
|
|
43
|
+
export function pagesForList(records: object[], { tag, type }: {
|
|
44
|
+
tag: string;
|
|
45
|
+
type: string;
|
|
46
|
+
}): object[];
|
|
47
|
+
/**
|
|
48
|
+
* Render one directive's answer as markdown.
|
|
49
|
+
*
|
|
50
|
+
* **The emitted link is the page's `address.slug`** — the `type-shortcode`
|
|
51
|
+
* form a wikilink resolves — which is exactly what a table's `_ref` cell
|
|
52
|
+
* writes. A short form names the package the link is written in, so it is
|
|
53
|
+
* unambiguous for a list of this package's own pages, and it resolves to the
|
|
54
|
+
* note's **page** on each surface: a compendium journal in Foundry, a URL on
|
|
55
|
+
* the web and in the book. An item note's page is its documentation journal,
|
|
56
|
+
* and the short form reaches it the way prose does.
|
|
57
|
+
*
|
|
58
|
+
* @param {object[]} records - Content-index records.
|
|
59
|
+
* @param {object} directive - From {@link findPageListBlocks}.
|
|
60
|
+
* @returns {{markdown: string, pages: number}} The list, and how many pages
|
|
61
|
+
* are in it.
|
|
62
|
+
*/
|
|
63
|
+
export function renderPageList(records: object[], directive: object): {
|
|
64
|
+
markdown: string;
|
|
65
|
+
pages: number;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Answer every `pagelist` directive in a set of note bodies, ahead of expansion.
|
|
69
|
+
*
|
|
70
|
+
* **Why a separate pass.** The same reason the SQL tables have one:
|
|
71
|
+
* {@link module:engine/content-tables.expandContentTables} is synchronous and
|
|
72
|
+
* exported, and the corpus is enumerated once by whoever already holds it
|
|
73
|
+
* rather than derived again inside a renderer. A page list needs no database —
|
|
74
|
+
* it is a filter over the records — so preparing one costs a walk of what the
|
|
75
|
+
* caller already has.
|
|
76
|
+
*
|
|
77
|
+
* **Keyed by note, then by the directive's ordinal within it**, not by its
|
|
78
|
+
* line: the passes do not agree on what a body is, and trim it differently,
|
|
79
|
+
* but a directive's position in the sequence of fences is the same in each.
|
|
80
|
+
*
|
|
81
|
+
* A malformed directive is recorded rather than thrown, so one bad fence costs
|
|
82
|
+
* its own list and not the whole build's report.
|
|
83
|
+
*
|
|
84
|
+
* @param {object[]} records - Content-index records, already narrowed to the
|
|
85
|
+
* audience the surface publishes to.
|
|
86
|
+
* @param {Array<{source: string, markdown: string}>} sources - The bodies to scan.
|
|
87
|
+
* @returns {Map<string, Array<{markdown?: string, pages?: number, empty?: string,
|
|
88
|
+
* reason?: string, allowEmpty: boolean}>>} Note to results, in document order.
|
|
89
|
+
*/
|
|
90
|
+
export function preparePageLists(records: object[], sources: Array<{
|
|
91
|
+
source: string;
|
|
92
|
+
markdown: string;
|
|
93
|
+
}>): Map<string, Array<{
|
|
94
|
+
markdown?: string;
|
|
95
|
+
pages?: number;
|
|
96
|
+
empty?: string;
|
|
97
|
+
reason?: string;
|
|
98
|
+
allowEmpty: boolean;
|
|
99
|
+
}>>;
|
|
100
|
+
/** The fence language that opens a page list. */
|
|
101
|
+
export const PAGE_LIST_LANGUAGE: "pagelist";
|
|
102
|
+
/**
|
|
103
|
+
* The orders a page list may come out in.
|
|
104
|
+
*
|
|
105
|
+
* Ordering is about output rather than about the pages, so it is an attribute
|
|
106
|
+
* rather than something read off a note. `name` is alphabetical, case and
|
|
107
|
+
* accents folded; `type` groups the note types and orders by name inside each.
|
|
108
|
+
*
|
|
109
|
+
* @type {readonly string[]}
|
|
110
|
+
*/
|
|
111
|
+
export const PAGE_LIST_SORTS: readonly string[];
|
|
112
|
+
/**
|
|
113
|
+
* The attributes a page-list fence takes, with what each one is for.
|
|
114
|
+
*
|
|
115
|
+
* **This is the one list.** The fence is validated against it, the authoring
|
|
116
|
+
* document's table is generated from it, and the reference is checked against
|
|
117
|
+
* it — so an attribute added here is one both documents describe, and anything
|
|
118
|
+
* else an author writes is reported by name.
|
|
119
|
+
*
|
|
120
|
+
* @type {Readonly<Record<string, Readonly<{value: string, default: string, summary: string}>>>}
|
|
121
|
+
*/
|
|
122
|
+
export const PAGE_LIST_ATTRIBUTES: Readonly<Record<string, Readonly<{
|
|
123
|
+
value: string;
|
|
124
|
+
default: string;
|
|
125
|
+
summary: string;
|
|
126
|
+
}>>>;
|
|
@@ -37,6 +37,24 @@ export function labelFor(anchor: string): string;
|
|
|
37
37
|
* @returns {object} A markdown-it instance.
|
|
38
38
|
*/
|
|
39
39
|
export function createParser(registry?: object): object;
|
|
40
|
+
/**
|
|
41
|
+
* A markdown body with its HTML comments taken out.
|
|
42
|
+
*
|
|
43
|
+
* A comment is an author's aside to the next author — a `markdownlint` pragma, a
|
|
44
|
+
* note recording why a notice is quoted verbatim — and no surface shows one: the
|
|
45
|
+
* packs and the website emit it into HTML, where it is a comment still. Typst
|
|
46
|
+
* has nowhere to put it, so markdown-it hands the delimiters over as prose and
|
|
47
|
+
* the aside is typeset. It comes out here instead, and a comment inside a fence
|
|
48
|
+
* or a code span stays, because there it is an example of a comment.
|
|
49
|
+
*
|
|
50
|
+
* **The line count is preserved.** Every finding this module reports is located
|
|
51
|
+
* in the markdown it was handed, so a pass that removed a line would move every
|
|
52
|
+
* position after it.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} markdown - The body, as authored.
|
|
55
|
+
* @returns {string} The same body, its comments replaced by their own newlines.
|
|
56
|
+
*/
|
|
57
|
+
export function stripHtmlComments(markdown: string): string;
|
|
40
58
|
/**
|
|
41
59
|
* Render markdown as Typst content.
|
|
42
60
|
*
|
|
@@ -55,8 +73,26 @@ export function createParser(registry?: object): object;
|
|
|
55
73
|
* note's own `##` nests beneath the entry heading the book gave it.
|
|
56
74
|
* @param {string} [opts.anchorPrefix] - The entry's anchor, which namespaces
|
|
57
75
|
* every `{#slug}` the body declares.
|
|
58
|
-
*
|
|
59
|
-
*
|
|
76
|
+
* @param {object[]} [opts.findings] - Collected here rather than thrown. Every
|
|
77
|
+
* construct this pass cannot render is reported into it — see
|
|
78
|
+
* {@link reportUnrenderable} — and a caller that passes none renders the same
|
|
79
|
+
* Typst and is told nothing.
|
|
80
|
+
* @param {string} [opts.file] - The file the markdown came from, named in every
|
|
81
|
+
* finding.
|
|
82
|
+
* @param {number} [opts.bodyLine] - The 1-based file line the body starts on, so
|
|
83
|
+
* a finding's line is the file's rather than the body's.
|
|
84
|
+
* @param {number} [opts.bodyColumn] - The 1-based column the body starts at.
|
|
85
|
+
* @param {Array<{line: number, generated: boolean}>} [opts.lineMap] - From
|
|
86
|
+
* table expansion, mapping each line handed in back to the line an author
|
|
87
|
+
* wrote.
|
|
88
|
+
* @param {boolean} [opts.prepared] - Whether this body has been through the
|
|
89
|
+
* passes that resolve a wikilink, an embed and an inline expression. A note's
|
|
90
|
+
* has; a front-matter file's and a prose file's have not, and markup of theirs
|
|
91
|
+
* left in one is reported rather than typeset in silence.
|
|
92
|
+
* @param {string} [opts.url] - The absolute address this book's pages are served
|
|
93
|
+
* at. Every link the book sets as a URL is resolved against it, because a
|
|
94
|
+
* reader holding a PDF has no page to resolve a path against — see
|
|
95
|
+
* {@link renderLink}.
|
|
60
96
|
* @returns {string} Typst markup.
|
|
61
97
|
*/
|
|
62
98
|
export function markdownToTypst(markdown: string, opts?: {
|
|
@@ -67,7 +103,41 @@ export function markdownToTypst(markdown: string, opts?: {
|
|
|
67
103
|
images?: Map<string, string> | undefined;
|
|
68
104
|
headingOffset?: number | undefined;
|
|
69
105
|
anchorPrefix?: string | undefined;
|
|
106
|
+
findings?: object[] | undefined;
|
|
107
|
+
file?: string | undefined;
|
|
108
|
+
bodyLine?: number | undefined;
|
|
109
|
+
bodyColumn?: number | undefined;
|
|
110
|
+
lineMap?: {
|
|
111
|
+
line: number;
|
|
112
|
+
generated: boolean;
|
|
113
|
+
}[] | undefined;
|
|
114
|
+
prepared?: boolean | undefined;
|
|
115
|
+
url?: string | undefined;
|
|
70
116
|
}): string;
|
|
117
|
+
/**
|
|
118
|
+
* A page address as a reader of the book can follow it.
|
|
119
|
+
*
|
|
120
|
+
* **Every link the book sets as a URL is absolute.** A page's address is written
|
|
121
|
+
* from the root of the site that serves it — `/sohl/skill-guil/` — because on the
|
|
122
|
+
* website that is the shortest form that is right wherever the page is read
|
|
123
|
+
* from. A PDF is read from nowhere: a viewer handed a path has no document to
|
|
124
|
+
* resolve it against, so it either does nothing or looks for a file on the
|
|
125
|
+
* reader's own disk, and a book of a thousand pages carries a thousand links
|
|
126
|
+
* that do neither.
|
|
127
|
+
*
|
|
128
|
+
* So a root-relative address is resolved against the site's own, which is the
|
|
129
|
+
* one absolute address a build already holds. A **dependency's** page keeps its
|
|
130
|
+
* own package prefix, from the registry in
|
|
131
|
+
* {@link module:engine/content-address.PACKAGE_BASE}, so it resolves to the host
|
|
132
|
+
* serving that package — and where the registry names a host of its own the
|
|
133
|
+
* address is already absolute and is left exactly as it is.
|
|
134
|
+
*
|
|
135
|
+
* @param {string} url - The address, as the link pass resolved it.
|
|
136
|
+
* @param {string} [site] - The absolute address this book's pages are served at.
|
|
137
|
+
* @returns {string} An absolute URL, or the address unchanged when there is no
|
|
138
|
+
* site to resolve it against or it is already absolute.
|
|
139
|
+
*/
|
|
140
|
+
export function absolutePageUrl(url: string, site?: string): string;
|
|
71
141
|
/**
|
|
72
142
|
* The Typst definitions the book's page furniture is drawn with.
|
|
73
143
|
*
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check one affiliation's `data.governance.ranks` against the rung contract.
|
|
3
|
+
*
|
|
4
|
+
* Each problem is its own finding, so a rung missing all three of its required
|
|
5
|
+
* keys reports three rather than the first: a reader fixing a ladder wants the
|
|
6
|
+
* whole of it in one pass.
|
|
7
|
+
*
|
|
8
|
+
* **A finding is located by the node it is about**, through the frontmatter's
|
|
9
|
+
* own YAML tree — a present-but-wrong value points at that value, and an absent
|
|
10
|
+
* key points at the rung that should have carried it, since a key that was
|
|
11
|
+
* never written has no position of its own. Where even the rung cannot be
|
|
12
|
+
* located the position is dropped rather than guessed, and the finding names
|
|
13
|
+
* the file alone.
|
|
14
|
+
*
|
|
15
|
+
* @param {object} note - The note being checked.
|
|
16
|
+
* @param {string} note.file - Its path, as a diagnostic spells it.
|
|
17
|
+
* @param {string} [note.raw] - Its source, for the position.
|
|
18
|
+
* @param {object} [note.fm] - Its parsed frontmatter.
|
|
19
|
+
* @returns {Array<{file: string, line?: number, column?: number,
|
|
20
|
+
* severity: string, message: string}>} The findings, in authored order.
|
|
21
|
+
*/
|
|
22
|
+
export function checkRankLadder(note: {
|
|
23
|
+
file: string;
|
|
24
|
+
raw?: string | undefined;
|
|
25
|
+
fm?: object | undefined;
|
|
26
|
+
}): Array<{
|
|
27
|
+
file: string;
|
|
28
|
+
line?: number;
|
|
29
|
+
column?: number;
|
|
30
|
+
severity: string;
|
|
31
|
+
message: string;
|
|
32
|
+
}>;
|
|
@@ -256,12 +256,10 @@ export function legacyKeyMessage(block: string, field: {
|
|
|
256
256
|
* What a note writing a field at the **top-level key `data:` gathered it off**
|
|
257
257
|
* is told.
|
|
258
258
|
*
|
|
259
|
-
* {@link legacyKeyMessage}'s counterpart for the other retiring position.
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* of `data.portrait`, and both are read for the same reason both in-block
|
|
264
|
-
* spellings are: a package moves its corpus when it is ready, not on a flag day.
|
|
259
|
+
* {@link legacyKeyMessage}'s counterpart for the other retiring position.
|
|
260
|
+
* `portrait:` beside `img:` is the bare spelling of `data.portrait`, and both
|
|
261
|
+
* are read for the same reason both in-block spellings are: a package moves its
|
|
262
|
+
* corpus when it is ready, not on a flag day.
|
|
265
263
|
*
|
|
266
264
|
* It says nothing about which value is emitted, because that is not what an
|
|
267
265
|
* author needs from it. The value is the same either way; what the finding
|
|
@@ -249,7 +249,7 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
|
|
|
249
249
|
artIndex: any;
|
|
250
250
|
}): {
|
|
251
251
|
page: any;
|
|
252
|
-
body:
|
|
252
|
+
body: string;
|
|
253
253
|
data: object;
|
|
254
254
|
resolved: any[];
|
|
255
255
|
tableErrors: object[];
|
|
@@ -266,6 +266,18 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
|
|
|
266
266
|
column: number;
|
|
267
267
|
message: string;
|
|
268
268
|
}[];
|
|
269
|
+
headingErrors: {
|
|
270
|
+
line: number;
|
|
271
|
+
column: number;
|
|
272
|
+
message: string;
|
|
273
|
+
file: any;
|
|
274
|
+
}[];
|
|
275
|
+
footnoteErrors: {
|
|
276
|
+
file: any;
|
|
277
|
+
line: number;
|
|
278
|
+
column: number;
|
|
279
|
+
message: string;
|
|
280
|
+
}[];
|
|
269
281
|
wikiErrors: any[];
|
|
270
282
|
imageErrors: any[];
|
|
271
283
|
};
|
|
@@ -178,12 +178,21 @@ export const DISABLE_KINDS: readonly string[];
|
|
|
178
178
|
* `<span>` marking an unresolved link — and Goldmark drops raw HTML unless
|
|
179
179
|
* told otherwise. A theme cannot supply this: Hugo does not merge a theme's
|
|
180
180
|
* `markup` block.
|
|
181
|
+
*
|
|
182
|
+
* `extensions.taskList` is off because the format has no checkbox: Goldmark
|
|
183
|
+
* enables it by default, which is the only reason a list item opened with
|
|
184
|
+
* `[ ]` renders a `<input type="checkbox">` here and the same two characters as
|
|
185
|
+
* plain text in the pack and the book. Off, a list item's text begins right
|
|
186
|
+
* after its marker on every surface.
|
|
181
187
|
*/
|
|
182
188
|
export const MARKUP: Readonly<{
|
|
183
189
|
goldmark: Readonly<{
|
|
184
190
|
renderer: Readonly<{
|
|
185
191
|
unsafe: true;
|
|
186
192
|
}>;
|
|
193
|
+
extensions: Readonly<{
|
|
194
|
+
taskList: false;
|
|
195
|
+
}>;
|
|
187
196
|
}>;
|
|
188
197
|
}>;
|
|
189
198
|
/** Where the navigation is published. */
|
|
@@ -106,6 +106,12 @@ export type SiteEntry = {
|
|
|
106
106
|
* The page's published address.
|
|
107
107
|
*/
|
|
108
108
|
url: string;
|
|
109
|
+
/**
|
|
110
|
+
* The note's markdown body, for its anchors. A
|
|
111
|
+
* content entry always carries one; absent, the
|
|
112
|
+
* page is indexed as declaring none.
|
|
113
|
+
*/
|
|
114
|
+
body?: string | undefined;
|
|
109
115
|
};
|
|
110
116
|
/**
|
|
111
117
|
* The resolved index and everything a wikilink resolver reads beside it.
|
|
@@ -114,12 +120,18 @@ export type SiteIndex = {
|
|
|
114
120
|
/**
|
|
115
121
|
* Address → page. `draft` says the page
|
|
116
122
|
* carries the `draft` tag, which marks a
|
|
117
|
-
* link *into* it.
|
|
123
|
+
* link *into* it. `anchors` names the
|
|
124
|
+
* `{#slug}` sections it declares — a
|
|
125
|
+
* `Set` for a local page, or the
|
|
126
|
+
* `{slug: uuid}` map a foreign manifest
|
|
127
|
+
* publishes — and is absent where
|
|
128
|
+
* neither build recorded one.
|
|
118
129
|
*/
|
|
119
130
|
index: Map<string, {
|
|
120
131
|
url: string;
|
|
121
132
|
name?: string;
|
|
122
133
|
draft?: boolean;
|
|
134
|
+
anchors?: Set<string> | Record<string, string>;
|
|
123
135
|
}>;
|
|
124
136
|
/**
|
|
125
137
|
* Short addresses claimed by two
|
|
@@ -142,6 +142,10 @@ export function renderSqlTable(result: {
|
|
|
142
142
|
* @param {object} [opts]
|
|
143
143
|
* @param {(ref: string) => boolean} [opts.linkable] - Passed to
|
|
144
144
|
* {@link renderSqlTable}.
|
|
145
|
+
* @param {object[]} [opts.records] - Content-index records, narrowed to the
|
|
146
|
+
* audience this surface publishes to. Given them, the result also carries
|
|
147
|
+
* `pageLists`, so one prepared object answers every corpus-reading directive
|
|
148
|
+
* a body can hold and a caller looks results up in one place.
|
|
145
149
|
* **Keyed by note, then by the directive's ordinal within it** — not by its
|
|
146
150
|
* line. The passes do not agree on what a body is: `walkMarkdownTree` trims it,
|
|
147
151
|
* while the link checker strips the frontmatter fence and leaves the newlines
|
|
@@ -154,8 +158,9 @@ export function renderSqlTable(result: {
|
|
|
154
158
|
export function prepareSqlTables(db: object, sources: Array<{
|
|
155
159
|
source: string;
|
|
156
160
|
markdown: string;
|
|
157
|
-
}>, { linkable }?: {
|
|
161
|
+
}>, { linkable, records }?: {
|
|
158
162
|
linkable?: ((ref: string) => boolean) | undefined;
|
|
163
|
+
records?: object[] | undefined;
|
|
159
164
|
}): Promise<Map<string, object[]>>;
|
|
160
165
|
/** Evaluate scalar SQL calls before synchronous Markdown renderers run. */
|
|
161
166
|
export function prepareInlineSqlExpressions(db: any, sources: any): Promise<Map<any, any>>;
|
|
@@ -167,10 +172,14 @@ export function prepareInlineSqlExpressions(db: any, sources: any): Promise<Map<
|
|
|
167
172
|
* shared index
|
|
168
173
|
* describes, where N passes each derive the corpus their own way.
|
|
169
174
|
*
|
|
170
|
-
* **
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
175
|
+
* **Every corpus-reading directive is answered here**, which is why one call
|
|
176
|
+
* precedes every pass: the `sql` tables, the inline scalar queries, and the
|
|
177
|
+
* page lists, whose results ride on the same object as `pageLists`.
|
|
178
|
+
*
|
|
179
|
+
* **Nothing is opened for a tree that asks no query.** A tree with no `sql`
|
|
180
|
+
* directive costs one walk and no database at all, and so does one whose only
|
|
181
|
+
* directive is a page list — a page list is a filter over the records. That is
|
|
182
|
+
* what lets every pass call this unconditionally.
|
|
174
183
|
*
|
|
175
184
|
* @param {string} contentBase - Root of the content tree.
|
|
176
185
|
* @param {object} [opts]
|
|
@@ -180,8 +189,9 @@ export function prepareInlineSqlExpressions(db: any, sources: any): Promise<Map<
|
|
|
180
189
|
* A command that also builds a link index holds them already, and deriving
|
|
181
190
|
* them twice is the duplicated-corpus failure this closes.
|
|
182
191
|
* @param {"all"|"public"} [opts.audience] - Whether to exclude GM notes.
|
|
183
|
-
* @returns {Promise<Map<string, object[]>|undefined>} Results by note path,
|
|
184
|
-
* nothing when the tree
|
|
192
|
+
* @returns {Promise<Map<string, object[]>|undefined>} Results by note path,
|
|
193
|
+
* carrying `inline` and `pageLists` beside them, or nothing when the tree
|
|
194
|
+
* holds no such directive.
|
|
185
195
|
*/
|
|
186
196
|
export function prepareTreeSqlTables(contentBase: string, { config, skipDirectories, records, audience }?: {
|
|
187
197
|
config?: object | undefined;
|
|
@@ -200,3 +210,17 @@ export const RENDER_ALIASES: Readonly<{
|
|
|
200
210
|
ref: "_ref";
|
|
201
211
|
section: "_section";
|
|
202
212
|
}>;
|
|
213
|
+
/**
|
|
214
|
+
* The attributes an SQL fence takes, with what each one is for.
|
|
215
|
+
*
|
|
216
|
+
* **This is the one list.** The fence is validated against it and the authoring
|
|
217
|
+
* document is checked against it, so an attribute added here is one the document
|
|
218
|
+
* must describe, and anything else an author writes is reported by name.
|
|
219
|
+
*
|
|
220
|
+
* @type {Readonly<Record<string, Readonly<{value: string, default: string, summary: string}>>>}
|
|
221
|
+
*/
|
|
222
|
+
export const SQL_FENCE_ATTRIBUTES: Readonly<Record<string, Readonly<{
|
|
223
|
+
value: string;
|
|
224
|
+
default: string;
|
|
225
|
+
summary: string;
|
|
226
|
+
}>>>;
|
|
@@ -37,6 +37,10 @@ export function readStandings(value: unknown): {
|
|
|
37
37
|
* than by its position in the list: a body may write its rungs in any order,
|
|
38
38
|
* and several start at zero.
|
|
39
39
|
*
|
|
40
|
+
* One title per level, which is what the rung check holds a ladder to: two
|
|
41
|
+
* rungs claiming one level is a finding on the second, so a ladder that reaches
|
|
42
|
+
* here carries at most one title for any number a member's `rank` can hold.
|
|
43
|
+
*
|
|
40
44
|
* @param {unknown} ranks - An affiliation's `data.governance.ranks`.
|
|
41
45
|
* @returns {Map<number, string>} Level → the title that level is called.
|
|
42
46
|
*/
|
|
@@ -66,6 +70,18 @@ export function officeRoster(offices: unknown): Map<string, string>;
|
|
|
66
70
|
* @returns {string} The anchor, or `""` where the name carries nothing.
|
|
67
71
|
*/
|
|
68
72
|
export function officeAnchor(office: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* The anchor a rung's row is addressed by.
|
|
75
|
+
*
|
|
76
|
+
* The ladder's parallel to {@link officeAnchor}, prefixed apart from it so a
|
|
77
|
+
* body naming an office the same word as one of its ranks still gets two
|
|
78
|
+
* destinations rather than one row answering for both.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} title - The rung's title, as the body wrote it.
|
|
81
|
+
* @returns {string} The anchor, or `""` where the title carries nothing
|
|
82
|
+
* URL-safe.
|
|
83
|
+
*/
|
|
84
|
+
export function rankAnchor(title: string): string;
|
|
69
85
|
/**
|
|
70
86
|
* What an affiliation lends to a reference to it.
|
|
71
87
|
*
|
|
@@ -106,12 +122,14 @@ export function standingPhrase(standing: object, body: string, digest?: {
|
|
|
106
122
|
/**
|
|
107
123
|
* Validate a being's memberships and the standing it holds in each.
|
|
108
124
|
*
|
|
109
|
-
*
|
|
125
|
+
* Five questions, and the last three are what keying the entry by its body
|
|
126
|
+
* buys:
|
|
110
127
|
*
|
|
111
128
|
* 1. the value is a map keyed by Address (or the list this window still takes);
|
|
112
129
|
* 2. every key names an affiliation that resolves, once;
|
|
113
|
-
* 3.
|
|
114
|
-
* 4.
|
|
130
|
+
* 3. the entry states a `rank`;
|
|
131
|
+
* 4. a `rank` is a level the named body's `governance.ranks` declares;
|
|
132
|
+
* 5. an `office` is a key of that body's `governance.offices`.
|
|
115
133
|
*
|
|
116
134
|
* Both of the last two are read from the named body's own frontmatter as the
|
|
117
135
|
* lint runs, so a renamed rung or a renamed post fails on every being pointing
|
|
@@ -79,17 +79,18 @@ export function blockField(fm: object, block: string, key: string, defaultValue?
|
|
|
79
79
|
*/
|
|
80
80
|
export function sharedProperty(fm: object, source: string, defaultValue?: any): any;
|
|
81
81
|
/**
|
|
82
|
-
* A property a system block
|
|
82
|
+
* A property a system block declares, else the default.
|
|
83
83
|
*
|
|
84
|
-
* This is what gives `
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* in
|
|
84
|
+
* This is what gives `effects` and `flags` their per-system form without
|
|
85
|
+
* inventing a mechanism for each: a note states them inside the block whose
|
|
86
|
+
* document carries them, which is the only position the format accepts for
|
|
87
|
+
* either. A note needing one value for both systems writes it in both blocks —
|
|
88
|
+
* they are properties of a document, and there are two documents.
|
|
88
89
|
*
|
|
89
90
|
* @param {object} fm - The note's frontmatter.
|
|
90
91
|
* @param {string} block - The block key.
|
|
91
92
|
* @param {string} key - The property.
|
|
92
|
-
* @param {any} [defaultValue] - Returned when
|
|
93
|
+
* @param {any} [defaultValue] - Returned when the block does not declare it.
|
|
93
94
|
* @returns {any} The value.
|
|
94
95
|
*/
|
|
95
96
|
export function blockProperty(fm: object, block: string, key: string, defaultValue?: any): any;
|
|
@@ -128,12 +129,10 @@ export function legacyKeyOf(field: {
|
|
|
128
129
|
/**
|
|
129
130
|
* The bare top-level key a `data:`-sourced field is being swept off — step 3b.
|
|
130
131
|
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* every other key that move relocated. Deriving it is what keeps the two
|
|
136
|
-
* spellings of one field from disagreeing the way two declarations would.
|
|
132
|
+
* The retiring spelling of `data.portrait` is not a second declaration anyone
|
|
133
|
+
* has to write — it is `portrait`, mechanically, and the same holds for every
|
|
134
|
+
* other key the container gathered. Deriving it is what keeps the two spellings
|
|
135
|
+
* of one field from disagreeing the way two declarations would.
|
|
137
136
|
*
|
|
138
137
|
* **Only a `data.` source has one.** `protection.blunt` and `impact.die` are
|
|
139
138
|
* paths into containers a note has always written at the top level; they were
|
|
@@ -97,7 +97,9 @@ export function frontmatterWikilinks(fm: unknown): Array<{
|
|
|
97
97
|
* resolves against. `src` is the page's display
|
|
98
98
|
* path and `file` the source file a diagnostic should name — absent, `src`
|
|
99
99
|
* stands in. `resolved`, when supplied, is the array every resolved
|
|
100
|
-
* target's index entry is appended to.
|
|
100
|
+
* target's index entry is appended to. `anchors` is the `{#slug}` set
|
|
101
|
+
* *this* page declares, which a `[[#slug]]` self-link is checked against;
|
|
102
|
+
* absent, a self-link is not checked, exactly as before this existed.
|
|
101
103
|
* @returns {string} The body with embeds and wikilinks rewritten.
|
|
102
104
|
*/
|
|
103
105
|
export function resolveWebWikilinks(body: string, ctx: object): string;
|
package/types/hm3/actors.d.mts
CHANGED
|
@@ -27,9 +27,9 @@ export class Hm3Actors extends SystemActorCompiler {
|
|
|
27
27
|
/**
|
|
28
28
|
* Build every embedded item an HM3 actor carries, from `hm3.items`.
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* HM3 keeps a character's abilities in `system.abilities` rather than as
|
|
31
|
+
* embedded documents, so an ability reaches the document through the
|
|
32
|
+
* `hm3.system` passthrough and never through this list.
|
|
33
33
|
*
|
|
34
34
|
* @param {Map<string, object>} itemsMap - The predefined items, by address.
|
|
35
35
|
* @param {string} actorId - The owning actor's id, seeding embedded ids.
|
package/types/sohl/actors.d.mts
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
* SoHL's Actor compile pass.
|
|
3
3
|
*
|
|
4
4
|
* Declares SoHL's note-type → document-subtype map and builds a `being` note's
|
|
5
|
-
* document: the
|
|
6
|
-
*
|
|
7
|
-
* Everything else is {@link module:engine/actor-compiler}'s.
|
|
5
|
+
* document: the embedded item documents the frontmatter names, and the `system`
|
|
6
|
+
* block. Everything else is {@link module:engine/actor-compiler}'s.
|
|
8
7
|
*/
|
|
9
8
|
export class Actors extends SystemActorCompiler {
|
|
10
9
|
/**
|
|
@@ -17,8 +16,8 @@ export class Actors extends SystemActorCompiler {
|
|
|
17
16
|
*/
|
|
18
17
|
static documentSubtypes: import("../engine/document-subtypes.mjs").DocumentSubtypeMap;
|
|
19
18
|
/**
|
|
20
|
-
* Build all embedded items for an actor: one per `sohl.
|
|
21
|
-
*
|
|
19
|
+
* Build all embedded items for an actor: one per `sohl.items` entry, plus
|
|
20
|
+
* one per body the being belongs to.
|
|
22
21
|
*/
|
|
23
22
|
buildEmbeddedItems(itemsMap: any, actorId: any, fm: any, ctx: any): object[];
|
|
24
23
|
/**
|
|
@@ -57,8 +56,8 @@ export class Actors extends SystemActorCompiler {
|
|
|
57
56
|
*
|
|
58
57
|
* **The scores used are the ones just written.** `SkillLogic` resolves
|
|
59
58
|
* `attr.<code>` to an attribute's *effective* score, after active effects;
|
|
60
|
-
* all this pass has is the `scoreBase`
|
|
61
|
-
* compiled being carrying no attribute-altering effects the two agree,
|
|
59
|
+
* all this pass has is the `scoreBase` on each embedded attribute item. For
|
|
60
|
+
* a compiled being carrying no attribute-altering effects the two agree,
|
|
62
61
|
* which is every being in content today. One that did carry such an effect
|
|
63
62
|
* would bake a Skill Base its client then disagrees with — that is the
|
|
64
63
|
* limit of doing this at build time, and the point to revisit if it bites.
|