@heroiclands/package-build 17.2.0 → 18.0.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 +1711 -0
- package/CONTENT.md +288 -72
- package/README.md +1 -1
- package/bin/content-build.mjs +218 -137
- package/bin/package-build.mjs +43 -0
- package/content-config.mjs +62 -67
- package/docs/content-format.md +768 -58
- package/engine/actor-compiler.mjs +586 -0
- package/engine/address-charset.mjs +11 -8
- package/engine/address-diff.mjs +266 -22
- package/engine/anchored-sections.mjs +83 -0
- package/engine/anchors.mjs +83 -0
- package/engine/base-compiler.mjs +148 -18
- package/engine/bundle-notes.mjs +276 -0
- package/engine/bundles.mjs +307 -0
- package/engine/code-fences.mjs +103 -0
- package/engine/compile-corpus.mjs +89 -0
- package/engine/content-address.mjs +267 -5
- package/engine/content-format-check.mjs +54 -11
- package/engine/content-format.mjs +37 -5
- package/engine/content-index.mjs +225 -127
- package/engine/content-links.mjs +185 -77
- package/engine/content-lint.mjs +232 -14
- package/engine/content-package.mjs +2 -1
- package/engine/content-tables.mjs +99 -3
- package/engine/document-subtypes.mjs +49 -6
- package/engine/field-reference.mjs +1 -1
- package/engine/field-spec.mjs +56 -6
- package/engine/folder-notes.mjs +470 -0
- package/engine/foreign-catalog.mjs +195 -4
- package/engine/{manifest-emit.mjs → foundry-entries.mjs} +55 -83
- package/engine/frontmatter-lint.mjs +245 -19
- package/engine/frontmatter.mjs +88 -8
- package/engine/generate.mjs +304 -13
- package/engine/helpers.mjs +293 -64
- package/engine/ids.mjs +137 -2
- package/engine/index-records.mjs +126 -0
- package/engine/index.mjs +23 -5
- package/engine/item-compiler.mjs +349 -0
- package/engine/item-docs.mjs +7 -1
- package/engine/item-registry.mjs +6 -0
- package/engine/journals.mjs +93 -27
- package/engine/macros.mjs +4 -2
- package/engine/metadata-index.mjs +495 -0
- package/engine/note-claims.mjs +146 -25
- package/engine/note-ids.mjs +112 -0
- package/engine/note-renames.mjs +134 -0
- package/engine/note-schemas.mjs +25 -0
- package/engine/note-vocabulary.mjs +110 -27
- package/engine/pack-config.mjs +4 -0
- package/engine/pack-router.mjs +23 -0
- package/engine/retired-fields.mjs +137 -3
- package/engine/scenes.mjs +66 -34
- package/engine/schema-check.mjs +58 -17
- package/engine/site-build.mjs +71 -12
- package/engine/site-index.mjs +20 -7
- package/engine/sql-tables.mjs +485 -0
- package/engine/subtype-registry.mjs +102 -0
- package/engine/system-block.mjs +96 -12
- package/engine/systems.mjs +201 -0
- package/engine/web-wikilinks.mjs +50 -20
- package/engine/wikilink-syntax.mjs +17 -8
- package/engine/wikilinks.mjs +124 -51
- package/engine/yaml-lint.mjs +282 -0
- package/hm3/actors.mjs +352 -0
- package/hm3/default-item-art.mjs +75 -0
- package/hm3/document-subtypes.mjs +134 -0
- package/hm3/index.mjs +56 -0
- package/hm3/item-builders.mjs +84 -0
- package/hm3/item-fields.mjs +180 -0
- package/hm3/items.mjs +96 -0
- package/hm3/template-priority.mjs +85 -0
- package/manifest.mjs +43 -2
- package/package.json +18 -4
- package/release.mjs +62 -7
- package/sohl/actors.mjs +33 -487
- package/sohl/being-info.mjs +16 -7
- package/sohl/default-item-art.mjs +14 -3
- package/sohl/document-subtypes.mjs +16 -10
- package/sohl/item-builders.mjs +14 -5
- package/sohl/item-fields.mjs +68 -7
- package/sohl/items.mjs +44 -258
- package/sohl/note-schemas.mjs +2 -2
- package/types/content-config.d.mts +21 -42
- package/types/engine/actor-compiler.d.mts +204 -0
- package/types/engine/address-charset.d.mts +11 -8
- package/types/engine/address-diff.d.mts +53 -5
- package/types/engine/anchored-sections.d.mts +21 -0
- package/types/engine/anchors.d.mts +20 -0
- package/types/engine/base-compiler.d.mts +17 -17
- package/types/engine/bundle-notes.d.mts +173 -0
- package/types/engine/bundles.d.mts +60 -0
- package/types/engine/code-fences.d.mts +43 -0
- package/types/engine/compile-corpus.d.mts +32 -0
- package/types/engine/content-address.d.mts +205 -5
- package/types/engine/content-format-check.d.mts +6 -2
- package/types/engine/content-format.d.mts +57 -1
- package/types/engine/content-index.d.mts +54 -49
- package/types/engine/content-links.d.mts +52 -7
- package/types/engine/content-lint.d.mts +10 -1
- package/types/engine/content-package.d.mts +2 -1
- package/types/engine/content-tables.d.mts +21 -39
- package/types/engine/document-subtypes.d.mts +37 -3
- package/types/engine/field-spec.d.mts +76 -5
- package/types/engine/folder-notes.d.mts +159 -0
- package/types/engine/foreign-catalog.d.mts +53 -0
- package/types/engine/{manifest-emit.d.mts → foundry-entries.d.mts} +2 -43
- package/types/engine/frontmatter-lint.d.mts +10 -2
- package/types/engine/frontmatter.d.mts +64 -0
- package/types/engine/generate.d.mts +38 -0
- package/types/engine/helpers.d.mts +94 -30
- package/types/engine/ids.d.mts +96 -0
- package/types/engine/index-records.d.mts +68 -0
- package/types/engine/index.d.mts +9 -3
- package/types/engine/item-compiler.d.mts +131 -0
- package/types/engine/journals.d.mts +47 -9
- package/types/engine/metadata-index.d.mts +226 -0
- package/types/engine/note-claims.d.mts +57 -11
- package/types/engine/note-ids.d.mts +38 -0
- package/types/engine/note-renames.d.mts +102 -0
- package/types/engine/note-vocabulary.d.mts +44 -8
- package/types/engine/retired-fields.d.mts +75 -0
- package/types/engine/scenes.d.mts +3 -2
- package/types/engine/schema-check.d.mts +25 -4
- package/types/engine/site-build.d.mts +4 -4
- package/types/engine/site-index.d.mts +1 -1
- package/types/engine/sql-tables.d.mts +185 -0
- package/types/engine/subtype-registry.d.mts +49 -0
- package/types/engine/system-block.d.mts +40 -1
- package/types/engine/systems.d.mts +106 -0
- package/types/engine/web-wikilinks.d.mts +4 -2
- package/types/engine/wikilink-syntax.d.mts +10 -3
- package/types/engine/wikilinks.d.mts +41 -13
- package/types/engine/yaml-lint.d.mts +107 -0
- package/types/hm3/actors.d.mts +48 -0
- package/types/hm3/default-item-art.d.mts +42 -0
- package/types/hm3/document-subtypes.d.mts +24 -0
- package/types/hm3/index.d.mts +7 -0
- package/types/hm3/item-builders.d.mts +11 -0
- package/types/hm3/item-fields.d.mts +12 -0
- package/types/hm3/items.d.mts +23 -0
- package/types/hm3/template-priority.d.mts +21 -0
- package/types/manifest.d.mts +22 -1
- package/types/release.d.mts +9 -4
- package/types/sohl/actors.d.mts +7 -74
- package/types/sohl/being-info.d.mts +8 -27
- package/types/sohl/default-item-art.d.mts +5 -3
- package/types/sohl/items.d.mts +17 -32
- package/engine/foreign-manifests.mjs +0 -126
- package/engine/kb-manifest.mjs +0 -490
- package/types/engine/foreign-manifests.d.mts +0 -43
- package/types/engine/kb-manifest.d.mts +0 -241
package/types/engine/ids.d.mts
CHANGED
|
@@ -16,6 +16,39 @@ export function makeId(namespace: string, value: string): string;
|
|
|
16
16
|
* @throws {Error} Naming the replacement type.
|
|
17
17
|
*/
|
|
18
18
|
export function assertTypeNotRetired(type: string, where?: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* The current spelling of a content type: itself, or what it was renamed to.
|
|
21
|
+
*
|
|
22
|
+
* Every table keyed by note type is keyed by the **current** name, and every
|
|
23
|
+
* lookup goes through this — which is the whole of the window's behaviour, in
|
|
24
|
+
* one function, so no two readers can disagree about which vocabulary a note
|
|
25
|
+
* is held to.
|
|
26
|
+
*
|
|
27
|
+
* A non-string passes through untouched: callers hand this whatever the
|
|
28
|
+
* frontmatter carried, and inventing a type for a number would hide the
|
|
29
|
+
* missing-`type:` finding that belongs to the linter.
|
|
30
|
+
*
|
|
31
|
+
* @param {any} type - The type as authored, or as a link spells it.
|
|
32
|
+
* @returns {any} The current spelling.
|
|
33
|
+
*/
|
|
34
|
+
export function currentType(type: any): any;
|
|
35
|
+
/**
|
|
36
|
+
* What a note declaring a renamed type is told, in one place.
|
|
37
|
+
*
|
|
38
|
+
* Shared by every reporter, because an author meets whichever runs first and
|
|
39
|
+
* they should read the same. It names the type to write rather than a value to
|
|
40
|
+
* correct — no value makes the retired spelling right — and it says the note
|
|
41
|
+
* compiles either way, so a reader knows this is a rename to schedule rather
|
|
42
|
+
* than a build to unbreak.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} retired - The spelling the note used.
|
|
45
|
+
* @param {string} current - What to write instead.
|
|
46
|
+
* @param {string} [where] - What carries it — a file path, a link target —
|
|
47
|
+
* appended to the message. Omit it where the caller emits through a
|
|
48
|
+
* diagnostic, whose locator already starts the line.
|
|
49
|
+
* @returns {string} The message, unpunctuated at the end as a finding is.
|
|
50
|
+
*/
|
|
51
|
+
export function renamedTypeMessage(retired: string, current: string, where?: string): string;
|
|
19
52
|
/**
|
|
20
53
|
* The pack a type's documents live in, in the conventional one-pack-per-type
|
|
21
54
|
* layout.
|
|
@@ -94,6 +127,27 @@ export const MAP_TYPES: ReadonlySet<string>;
|
|
|
94
127
|
* @type {readonly string[]}
|
|
95
128
|
*/
|
|
96
129
|
export const MAP_SUBTYPES: readonly string[];
|
|
130
|
+
/**
|
|
131
|
+
* Content types whose whole document **is** a JournalEntry.
|
|
132
|
+
*
|
|
133
|
+
* Prose, and nothing else: each compiles into one journal entry of its own,
|
|
134
|
+
* with no second document to point at. That is what separates them from the
|
|
135
|
+
* doc-carrying types in `item-docs.mjs`, whose prose becomes a journal *beside*
|
|
136
|
+
* an item, a macro or a scene — those are two documents, and the pair is
|
|
137
|
+
* addressed as `<type>` and `doc<type>`. These are one, so there is no
|
|
138
|
+
* `docplace` and nothing synthesizes one.
|
|
139
|
+
*
|
|
140
|
+
* `doc` was the only member until #241. `place`, `lore` and `scenario` are in
|
|
141
|
+
* the published content format and were declared for validation in #233, but
|
|
142
|
+
* nothing routed them: a note of one lint-ed clean and then compiled into
|
|
143
|
+
* nothing, because {@link PACK_BY_TYPE} did not name it and the open-set
|
|
144
|
+
* default sent it to the items pack. `sohl-thalorna` could not compile a single
|
|
145
|
+
* pack for exactly this reason — 450 notes, and the same 450 the linter had
|
|
146
|
+
* reported before it learned the types.
|
|
147
|
+
*
|
|
148
|
+
* @type {ReadonlySet<string>}
|
|
149
|
+
*/
|
|
150
|
+
export const JOURNAL_TYPES: ReadonlySet<string>;
|
|
97
151
|
/**
|
|
98
152
|
* Content type → the pack its documents compile into, and the document type
|
|
99
153
|
* that pack holds.
|
|
@@ -129,6 +183,48 @@ export const PACK_BY_TYPE: Readonly<Record<string, {
|
|
|
129
183
|
* @type {Readonly<Record<string, string>>}
|
|
130
184
|
*/
|
|
131
185
|
export const RETIRED_TYPES: Readonly<Record<string, string>>;
|
|
186
|
+
/**
|
|
187
|
+
* Content types that were **renamed**, and what each is called now.
|
|
188
|
+
*
|
|
189
|
+
* A retired type and a renamed one are different cases, and only the first can
|
|
190
|
+
* be refused. `character` above was retired *outright* — nothing a note wrote
|
|
191
|
+
* made it right, so {@link assertTypeNotRetired} throws. A renamed type has a
|
|
192
|
+
* replacement, the two spellings mean the same thing, and a note carrying the
|
|
193
|
+
* old one compiles into exactly the document it always did: refusing it would
|
|
194
|
+
* fail a build over a note that is not wrong.
|
|
195
|
+
*
|
|
196
|
+
* So these retire in the three steps `package:` took (#56), and this table is
|
|
197
|
+
* the **first**: both spellings resolve, the current one is canonical, and the
|
|
198
|
+
* retired one is *reported* — never refused. The sweep of the content trees and
|
|
199
|
+
* the refusal come after, once no tree writes the old name. That is the same
|
|
200
|
+
* rule `RETIRED_FIELD_ALIASES` states for a renamed *field*, and for the same
|
|
201
|
+
* reason: a consumer must be able to adopt the new toolchain before its content
|
|
202
|
+
* moves, and there are some 31,000 references to move.
|
|
203
|
+
*
|
|
204
|
+
* **Why these three (#78).** `armorgear`, `concoctiongear` and `projectilegear`
|
|
205
|
+
* named the *SoHL document subtype* a note happened to compile into rather than
|
|
206
|
+
* the thing the note is about. A note's `type` sits outside the `sohl:` and
|
|
207
|
+
* `hm3:` blocks precisely because it belongs to no system, and HM3 already
|
|
208
|
+
* compiles a `projectile` into a `missilegear` — so the suffix was never a fact
|
|
209
|
+
* about the note. `weapongear` keeps its name: SoHL and HM3 both call the
|
|
210
|
+
* document that, and #78's table has no row for it.
|
|
211
|
+
*
|
|
212
|
+
* **Keyed by the retired spelling**, which is the opposite of
|
|
213
|
+
* `RETIRED_FIELD_ALIASES`. The direction follows the operation: a field alias
|
|
214
|
+
* is scoped by the schema that declares the *current* name, so that is what a
|
|
215
|
+
* reader asks with; a type alias is applied to a value read off a note, so what
|
|
216
|
+
* a reader has in hand is the retired spelling and what it needs is the
|
|
217
|
+
* replacement.
|
|
218
|
+
*
|
|
219
|
+
* **The address is not normalised.** A note's canonical address — and therefore
|
|
220
|
+
* its document id — carries its `type` as authored, so both spellings keep the
|
|
221
|
+
* addresses they already publish and a tree that has not swept compiles
|
|
222
|
+
* byte-identically. Renaming the type in a note *is* an address move, which is
|
|
223
|
+
* the sweep's business and not this table's.
|
|
224
|
+
*
|
|
225
|
+
* @type {Readonly<Record<string, string>>}
|
|
226
|
+
*/
|
|
227
|
+
export const RENAMED_TYPES: Readonly<Record<string, string>>;
|
|
132
228
|
/** Where every other content type compiles: the items pack. */
|
|
133
229
|
export const ITEM_PACK: Readonly<{
|
|
134
230
|
pack: "items";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file a record was read from, as an absolute path.
|
|
3
|
+
*
|
|
4
|
+
* **The one composition, because there were four.** `file.path` is recorded
|
|
5
|
+
* *relative* to the content root deliberately — an absolute one is a fact about
|
|
6
|
+
* the machine that built the index, would differ between two checkouts of the
|
|
7
|
+
* same tree, and would put someone's home directory in a published artifact. So
|
|
8
|
+
* every pass that reads the index and then needs to open a note has to compose
|
|
9
|
+
* the absolute form, and each of the readers converted for #243 had written its
|
|
10
|
+
* own `path.join(base, ...record.file.path.split("/"))`. Four copies of one
|
|
11
|
+
* rule is what #243 exists to remove, so here it is once.
|
|
12
|
+
*
|
|
13
|
+
* The split is on `"/"` rather than `path.sep` because the recorded path is
|
|
14
|
+
* always POSIX — that is what makes the index identical on every platform.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} contentBase - Root of the content tree the index was built from.
|
|
17
|
+
* @param {object} record - An index record.
|
|
18
|
+
* @returns {string} The note's absolute path.
|
|
19
|
+
*/
|
|
20
|
+
export function noteFile(contentBase: string, record: object): string;
|
|
21
|
+
/**
|
|
22
|
+
* The note's own frontmatter, as authored, from an index record.
|
|
23
|
+
*
|
|
24
|
+
* The inverse of the record's spread, and exact rather than best-effort: a
|
|
25
|
+
* record is the note's frontmatter plus {@link DERIVED_KEYS}, and a note that
|
|
26
|
+
* authors one of those keys fails the walk — so removing them cannot remove
|
|
27
|
+
* anything the note wrote. That enforced pairing is what lets a pass read the
|
|
28
|
+
* corpus from the index and still lint, route or compile what the *author*
|
|
29
|
+
* typed, rather than reasoning about `address:` and `anchors:` as though
|
|
30
|
+
* someone had written them.
|
|
31
|
+
*
|
|
32
|
+
* Lives beside the list it is the inverse of, so the two cannot drift.
|
|
33
|
+
*
|
|
34
|
+
* @param {Record<string, any>} record - An index record.
|
|
35
|
+
* @returns {Record<string, any>} The frontmatter, without the derived keys.
|
|
36
|
+
*/
|
|
37
|
+
export function authoredFrontmatter(record: Record<string, any>): Record<string, any>;
|
|
38
|
+
/**
|
|
39
|
+
* Whether a record is a note's, rather than a documentation journal's.
|
|
40
|
+
*
|
|
41
|
+
* An item note yields two records — itself and the JournalEntry its prose
|
|
42
|
+
* compiles into — and the second is a document, not a note: it has no file of
|
|
43
|
+
* its own to read, no frontmatter an author wrote, and its `type` is the
|
|
44
|
+
* virtual `doc<type>` that `readQualifier` resolves rather than a type any tree
|
|
45
|
+
* declares. A reader enumerating the corpus wants the notes; one resolving an
|
|
46
|
+
* address wants both.
|
|
47
|
+
*
|
|
48
|
+
* @param {Record<string, any>} record - An index record.
|
|
49
|
+
* @returns {boolean} True for a note's own record.
|
|
50
|
+
*/
|
|
51
|
+
export function isNoteRecord(record: Record<string, any>): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The keys the content index adds to a record, which a note therefore may not
|
|
54
|
+
* carry itself.
|
|
55
|
+
*
|
|
56
|
+
* `package` is the note's distribution unit — the configured `contentPackage`,
|
|
57
|
+
* since a note declaring its own is a hard error (#56) — and it matches what
|
|
58
|
+
* the content-table expander puts on the same field, so a query reads the same
|
|
59
|
+
* value from either. `file` namespaces the note's place in the tree, again
|
|
60
|
+
* matching the expander's `file.*`.
|
|
61
|
+
*
|
|
62
|
+
* Both are checked rather than assumed: `folder` is real frontmatter on most
|
|
63
|
+
* notes, so the neighbouring names are close enough to a real key that a silent
|
|
64
|
+
* overwrite is a plausible future rather than a hypothetical one.
|
|
65
|
+
*
|
|
66
|
+
* @type {ReadonlyArray<string>}
|
|
67
|
+
*/
|
|
68
|
+
export const DERIVED_KEYS: ReadonlyArray<string>;
|
package/types/engine/index.d.mts
CHANGED
|
@@ -6,17 +6,21 @@ export * as contentTree from "./content-tree.mjs";
|
|
|
6
6
|
export * as packConfig from "./pack-config.mjs";
|
|
7
7
|
export * as packRouter from "./pack-router.mjs";
|
|
8
8
|
export * as noteClaims from "./note-claims.mjs";
|
|
9
|
+
export * as folderNotes from "./folder-notes.mjs";
|
|
9
10
|
export * as contentPackage from "./content-package.mjs";
|
|
10
11
|
export * as notePackage from "./note-package.mjs";
|
|
11
12
|
export * as retiredFields from "./retired-fields.mjs";
|
|
12
13
|
export * as homepage from "./homepage.mjs";
|
|
13
14
|
export * as noteSchemas from "./note-schemas.mjs";
|
|
14
15
|
export * as noteVocabulary from "./note-vocabulary.mjs";
|
|
16
|
+
export * as systems from "./systems.mjs";
|
|
15
17
|
export * as contentSlug from "./content-slug.mjs";
|
|
16
18
|
export * as contentAddress from "./content-address.mjs";
|
|
17
|
-
export * as
|
|
18
|
-
export * as
|
|
19
|
-
export * as
|
|
19
|
+
export * as subtypeRegistry from "./subtype-registry.mjs";
|
|
20
|
+
export * as noteIds from "./note-ids.mjs";
|
|
21
|
+
export * as noteRenames from "./note-renames.mjs";
|
|
22
|
+
export * as metadataIndex from "./metadata-index.mjs";
|
|
23
|
+
export * as foundryEntries from "./foundry-entries.mjs";
|
|
20
24
|
export * as contentIndex from "./content-index.mjs";
|
|
21
25
|
export * as siteBuild from "./site-build.mjs";
|
|
22
26
|
export * as contentLint from "./content-lint.mjs";
|
|
@@ -35,6 +39,8 @@ export * as journals from "./journals.mjs";
|
|
|
35
39
|
export * as macros from "./macros.mjs";
|
|
36
40
|
export * as mapNotes from "./map-notes.mjs";
|
|
37
41
|
export * as scenes from "./scenes.mjs";
|
|
42
|
+
export * as bundleNotes from "./bundle-notes.mjs";
|
|
43
|
+
export * as bundles from "./bundles.mjs";
|
|
38
44
|
export * as sceneLevels from "./scene-levels.mjs";
|
|
39
45
|
export * as generate from "./generate.mjs";
|
|
40
46
|
export * as compendiums from "./compendiums.mjs";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The description an item carries: a pointer to its **item doc**, the
|
|
3
|
+
* JournalEntry the journals pass compiles this same body into (#1348).
|
|
4
|
+
*
|
|
5
|
+
* The prose is not rendered into the item at all. Carrying it would duplicate
|
|
6
|
+
* it onto every actor holding the item — 7.59 MB of copies across the actors
|
|
7
|
+
* pack, of which 133 KB was distinct — where a link is 60 bytes and always
|
|
8
|
+
* current. The two passes derive the target from the note's own id, so neither
|
|
9
|
+
* has to see the other's output; both split the *converted* markdown, so an H1
|
|
10
|
+
* carrying a wikilink names the same page on both sides.
|
|
11
|
+
*
|
|
12
|
+
* An item with no prose points at nothing, exactly as the journals pass writes
|
|
13
|
+
* no entry for it.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} markdown - The note body, tables expanded and wikilinks
|
|
16
|
+
* resolved.
|
|
17
|
+
* @param {object} fm - The note's frontmatter.
|
|
18
|
+
* @param {string} name - The item's name.
|
|
19
|
+
* @returns {string} The pointer, or "" for a note with no body.
|
|
20
|
+
*/
|
|
21
|
+
export function itemDescription(markdown: string, fm: object, name: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* The Item compile pass of one game system.
|
|
24
|
+
*
|
|
25
|
+
* A subclass declares its {@link SystemItemCompiler.documentSubtypes} and, if
|
|
26
|
+
* its system writes any, the {@link SystemItemCompiler#commonSystem} keys. It
|
|
27
|
+
* declares nothing else: the class is abstract only in the sense that a map is
|
|
28
|
+
* required, and instantiating it without one is a programming error rather than
|
|
29
|
+
* a configuration one.
|
|
30
|
+
*/
|
|
31
|
+
export class SystemItemCompiler extends BasePackCompiler {
|
|
32
|
+
/**
|
|
33
|
+
* The note-type → document-subtype map this pass compiles against.
|
|
34
|
+
*
|
|
35
|
+
* Stated by the class rather than reached for through a module import, so
|
|
36
|
+
* every decision the pass makes — which notes it claims, which subtype each
|
|
37
|
+
* becomes, which registry builds it, which block it reads — reads one
|
|
38
|
+
* declaration. A second system replaces that declaration and nothing else.
|
|
39
|
+
*
|
|
40
|
+
* @type {import("./document-subtypes.mjs").DocumentSubtypeMap|undefined}
|
|
41
|
+
*/
|
|
42
|
+
static documentSubtypes: import("./document-subtypes.mjs").DocumentSubtypeMap | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* The frontmatter block this pass reads, and the registry it addresses.
|
|
45
|
+
*
|
|
46
|
+
* @returns {string} The system's block name.
|
|
47
|
+
*/
|
|
48
|
+
get system(): string;
|
|
49
|
+
/**
|
|
50
|
+
* How many of each item type this pass wrote, for the summary. Every type
|
|
51
|
+
* is present from the start so the tally reads as a census of the
|
|
52
|
+
* whitelist rather than of what happened to compile.
|
|
53
|
+
*
|
|
54
|
+
* @type {Record<string, number>}
|
|
55
|
+
*/
|
|
56
|
+
counts: Record<string, number>;
|
|
57
|
+
/**
|
|
58
|
+
* The Foundry Item subtype a note compiles into.
|
|
59
|
+
*
|
|
60
|
+
* **Looked up, not inferred.** For every type this system declares, the
|
|
61
|
+
* emitted subtype is the map's, so the note vocabulary and the document
|
|
62
|
+
* vocabulary are two separately-stated things rather than one string
|
|
63
|
+
* written twice (#79).
|
|
64
|
+
*
|
|
65
|
+
* **A type the map does not name belongs to the consumer**, and its
|
|
66
|
+
* registry entry is the declaration: a repository shipping an item type of
|
|
67
|
+
* its own writes it once, in the `itemBuilders` table of its
|
|
68
|
+
* `package-build.config.yaml`, and that key is what the document is a
|
|
69
|
+
* subtype of. That is an authored statement in the consumer's own
|
|
70
|
+
* configuration, not a coincidence inside this package's source — and
|
|
71
|
+
* refusing it here would silently drop every document of a type this system
|
|
72
|
+
* has no opinion about (#7/#1563).
|
|
73
|
+
*
|
|
74
|
+
* @param {object} fm - The note's frontmatter.
|
|
75
|
+
* @returns {string} The document's `type`.
|
|
76
|
+
*/
|
|
77
|
+
itemSubtype(fm: object): string;
|
|
78
|
+
/** An item is named by its own type in the log, not by "item". */
|
|
79
|
+
noteLabel(fm: any): any;
|
|
80
|
+
/**
|
|
81
|
+
* The `system` keys this system's compiler writes on **every** item, beside
|
|
82
|
+
* whatever the type's declared fields emit.
|
|
83
|
+
*
|
|
84
|
+
* Nothing by default, which is the honest position for a system that has
|
|
85
|
+
* not said otherwise: a key written here lands on every document of every
|
|
86
|
+
* type, so inventing one that the receiving DataModel does not declare
|
|
87
|
+
* would be a finding on the whole pack (#155).
|
|
88
|
+
*
|
|
89
|
+
* @param {object} fm - The note's frontmatter.
|
|
90
|
+
* @param {object} at - What the pass already knows about this note.
|
|
91
|
+
* @param {string} at.description - The pointer to the note's item doc.
|
|
92
|
+
* @param {string} at.markdown - The note body, tables expanded and
|
|
93
|
+
* wikilinks resolved, for a system that reads an anchored section out of
|
|
94
|
+
* it.
|
|
95
|
+
* @param {string} at.label - Human-readable context for error messages.
|
|
96
|
+
* @returns {object} The shared `system` fields.
|
|
97
|
+
*/
|
|
98
|
+
commonSystem(fm: object, { description, markdown, label }: {
|
|
99
|
+
description: string;
|
|
100
|
+
markdown: string;
|
|
101
|
+
label: string;
|
|
102
|
+
}): object;
|
|
103
|
+
/**
|
|
104
|
+
* The document's `flags` — whatever the note authors, and whatever this
|
|
105
|
+
* system writes there of its own accord.
|
|
106
|
+
*
|
|
107
|
+
* The authored flags alone by default, which is the honest position for a
|
|
108
|
+
* system that has not said otherwise. A system whose data model has nowhere
|
|
109
|
+
* to record a shared fact keeps it here instead: HM3 writes the template
|
|
110
|
+
* priority as `flags.hm3.templatePriority`, because it declares no `system`
|
|
111
|
+
* field for it and an undeclared `system` key is discarded at load without
|
|
112
|
+
* a word.
|
|
113
|
+
*
|
|
114
|
+
* **This is the one emitted key nothing else can check** (#283). A `system`
|
|
115
|
+
* key this pass invents is caught by the emitted-`system` check against the
|
|
116
|
+
* receiving schema, but a flag is declared by no schema — so an omission
|
|
117
|
+
* here is silent, and was: the Actor pass wrote the priority and this one
|
|
118
|
+
* did not, for as long as there had been two passes.
|
|
119
|
+
*
|
|
120
|
+
* @param {object} fm - The note's frontmatter.
|
|
121
|
+
* @returns {object} The flags to emit.
|
|
122
|
+
*/
|
|
123
|
+
commonFlags(fm: object): object;
|
|
124
|
+
/** @inheritdoc */
|
|
125
|
+
onCompiled(fm: any): void;
|
|
126
|
+
/** @inheritdoc */
|
|
127
|
+
reportCompiled(stats: any): void;
|
|
128
|
+
/** @inheritdoc */
|
|
129
|
+
reportDetail(stats: any): void;
|
|
130
|
+
}
|
|
131
|
+
import { BasePackCompiler } from "./base-compiler.mjs";
|
|
@@ -21,35 +21,73 @@ export function splitPages(body: any, leadName?: string): {
|
|
|
21
21
|
markdown: string;
|
|
22
22
|
}[];
|
|
23
23
|
/**
|
|
24
|
-
* Two
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Two pages in one note that would derive the same id, which the LevelDB packer
|
|
25
|
+
* reports only as an opaque duplicate-key collision. Catch it here, where the
|
|
26
|
+
* note and the page can be named.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
28
|
+
* Both halves of {@link journalPageId} are checked, because each is now keyed
|
|
29
|
+
* on an identity alone:
|
|
30
|
+
*
|
|
31
|
+
* - **An anchor**, declared twice, has always collided.
|
|
32
|
+
* - **A name**, repeated among the unanchored pages, collides since #268 took
|
|
33
|
+
* the index out of the key. `MD024` with `siblings_only` already makes two
|
|
34
|
+
* sibling headings with the same text a lint error, so this is the same rule
|
|
35
|
+
* restated where the build can enforce it — a lint is a separate command, and
|
|
36
|
+
* the compile must not depend on someone having run it.
|
|
37
|
+
*
|
|
38
|
+
* The two are counted separately: an anchored page takes its id from the slug
|
|
39
|
+
* and an unanchored one from the name, so a page named for another's anchor is
|
|
40
|
+
* not a collision.
|
|
41
|
+
*
|
|
42
|
+
* @param {Array<{anchorSlug: string|null, name: string}>} rawPages - From
|
|
43
|
+
* {@link splitPages}.
|
|
44
|
+
* @param {string} noteName - The note, for the error message.
|
|
45
|
+
* @throws {Error} When two pages in one note share an anchor or a name.
|
|
46
|
+
*/
|
|
47
|
+
export function assertUniquePages(rawPages: Array<{
|
|
48
|
+
anchorSlug: string | null;
|
|
49
|
+
name: string;
|
|
50
|
+
}>, noteName: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* The anchor half of {@link assertUniquePages}, under its former name.
|
|
53
|
+
*
|
|
54
|
+
* @deprecated Call {@link assertUniquePages}, which checks page names too.
|
|
55
|
+
* @param {Array<{anchorSlug: string|null, name: string}>} rawPages - From
|
|
56
|
+
* {@link splitPages}.
|
|
29
57
|
* @param {string} noteName - The note, for the error message.
|
|
30
|
-
* @throws {Error} When an anchor is declared twice in the same note.
|
|
31
58
|
*/
|
|
32
59
|
export function assertUniqueAnchors(rawPages: Array<{
|
|
33
60
|
anchorSlug: string | null;
|
|
61
|
+
name: string;
|
|
34
62
|
}>, noteName: string): void;
|
|
35
63
|
/**
|
|
36
64
|
* The id of one page within its entry.
|
|
37
65
|
*
|
|
38
66
|
* An anchored page takes the id its inbound links compute from the note id and
|
|
39
67
|
* the slug, so link and page agree without shared state. Every other page is
|
|
40
|
-
* keyed by its
|
|
41
|
-
*
|
|
68
|
+
* keyed by its **name**, which is what lets the items pass address an item
|
|
69
|
+
* doc's first page without having compiled it (see
|
|
42
70
|
* {@link sohl.utils.packs.itemDocPointer}).
|
|
43
71
|
*
|
|
72
|
+
* **It takes no index** (#268). A page used to be keyed by position *and* name,
|
|
73
|
+
* so inserting a heading renumbered every page after it and a re-import created
|
|
74
|
+
* new pages beside the old ones — while nothing about those pages had changed.
|
|
75
|
+
* The anchored case above never took one, and is the shape this now shares.
|
|
76
|
+
*
|
|
77
|
+
* The name is a sound identity here in a way it is not for an embedded item: a
|
|
78
|
+
* page's name is its heading, and `MD024` with `siblings_only` is in the shared
|
|
79
|
+
* markdownlint rule set, so two sibling headings with the same text are already
|
|
80
|
+
* a lint error. {@link assertUniquePages} states the same thing at compile
|
|
81
|
+
* time, where the packer would otherwise report only an opaque duplicate key.
|
|
82
|
+
*
|
|
44
83
|
* @param {string} entryId - The owning JournalEntry's `_id`.
|
|
45
84
|
* @param {{anchorSlug: string|null, name: string}} page - From {@link splitPages}.
|
|
46
|
-
* @param {number} index - The page's position in the entry.
|
|
47
85
|
* @returns {string} A 16-character Foundry id.
|
|
48
86
|
*/
|
|
49
87
|
export function journalPageId(entryId: string, page: {
|
|
50
88
|
anchorSlug: string | null;
|
|
51
89
|
name: string;
|
|
52
|
-
}
|
|
90
|
+
}): string;
|
|
53
91
|
/**
|
|
54
92
|
* Compile split pages into JournalEntryPage documents.
|
|
55
93
|
*
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a package's content index is called, wherever it is written or fetched.
|
|
3
|
+
*
|
|
4
|
+
* **The local index and the published artifact are one file.** A package emits
|
|
5
|
+
* this, ships it as a release asset, and advertises it as `flags.metadataUrl`;
|
|
6
|
+
* a consumer fetches that same file into its cache and reads it. Naming it in
|
|
7
|
+
* one function is what keeps the emitter, the release and the fetcher from
|
|
8
|
+
* drifting into three spellings of one artifact.
|
|
9
|
+
*
|
|
10
|
+
* The `-metadata` suffix earns its place: a bare `<package>.jsonl` says nothing
|
|
11
|
+
* about what it holds, and these files land in a cache directory beside other
|
|
12
|
+
* packages' artifacts where the name is all a reader has.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} pkg - The content package name.
|
|
15
|
+
* @returns {string} The file name, e.g. `sohl-metadata.jsonl`.
|
|
16
|
+
*/
|
|
17
|
+
export function metadataFileName(pkg: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Every dependency whose published index this build resolves addresses through.
|
|
20
|
+
*
|
|
21
|
+
* **Every declared dependency, not only those supplying an item catalogue.**
|
|
22
|
+
* `itemCatalog: true` says a dependency supplies *items*; citing its
|
|
23
|
+
* *addresses* is a separate edge, and a package may have either without the
|
|
24
|
+
* other. `harn-ensemble` cites no foreign address and carries 324,016 embedded
|
|
25
|
+
* item references (`HeroicLands/harn-ensemble#42`); a package citing addresses
|
|
26
|
+
* and needing no items is the mirror of it. Gating the index on the catalogue
|
|
27
|
+
* flag would serve neither.
|
|
28
|
+
*
|
|
29
|
+
* The declaration is the one already in the emitted `system.json` /
|
|
30
|
+
* `module.json`, so it cannot drift from what Foundry itself installs, and
|
|
31
|
+
* there is no new configuration key to keep in step. Each entry carries the
|
|
32
|
+
* producer's own `manifest` URL, so the fetcher needs no address of its own:
|
|
33
|
+
* it reads that manifest and takes the `flags.metadataUrl` it advertises.
|
|
34
|
+
*
|
|
35
|
+
* @param {object} config - The resolved build configuration.
|
|
36
|
+
* @returns {Array<{id: string, manifest: string, kind: string,
|
|
37
|
+
* verified: string|undefined}>} The dependencies, in declaration order.
|
|
38
|
+
*/
|
|
39
|
+
export function metadataRelationships(config: object): Array<{
|
|
40
|
+
id: string;
|
|
41
|
+
manifest: string;
|
|
42
|
+
kind: string;
|
|
43
|
+
verified: string | undefined;
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* The cache directory for one dependency's index at one version.
|
|
47
|
+
*
|
|
48
|
+
* Keyed by version so that changing the pinned version is a different cache
|
|
49
|
+
* rather than a silent overwrite, and so a second build costs nothing — the
|
|
50
|
+
* same rule the item catalogue's cache follows, for the same reason.
|
|
51
|
+
*
|
|
52
|
+
* @param {object} config - The resolved build configuration.
|
|
53
|
+
* @param {string} id - The dependency's package id.
|
|
54
|
+
* @param {string} version - Its resolved version.
|
|
55
|
+
* @returns {string} The directory.
|
|
56
|
+
*/
|
|
57
|
+
export function metadataCacheDir(config: object, id: string, version: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Mark a dependency's cache complete.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} dir - The dependency's cache directory.
|
|
62
|
+
* @returns {void}
|
|
63
|
+
*/
|
|
64
|
+
export function markComplete(dir: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* The fetched index files this build resolves foreign addresses against.
|
|
67
|
+
*
|
|
68
|
+
* **Reads the cache only.** A cold cache is an error naming the command that
|
|
69
|
+
* fills it, rather than a download nobody asked for: a compile that reaches the
|
|
70
|
+
* network is not reproducible and fails strangely offline. That is the item
|
|
71
|
+
* catalogue's rule, and it holds here for the same reason.
|
|
72
|
+
*
|
|
73
|
+
* A half-finished fetch counts as cold. A partial index resolves some addresses
|
|
74
|
+
* and fails others with nothing to distinguish the two, which is worse than
|
|
75
|
+
* resolving none — the failure would read as a typo in whichever note happened
|
|
76
|
+
* to cite the missing half.
|
|
77
|
+
*
|
|
78
|
+
* @param {object} config - The resolved build configuration.
|
|
79
|
+
* @returns {string[]} One index file per declared dependency.
|
|
80
|
+
* @throws {Error} When a declared dependency has not been fetched.
|
|
81
|
+
*/
|
|
82
|
+
export function cachedMetadataFiles(config: object): string[];
|
|
83
|
+
/**
|
|
84
|
+
* The same fetched indexes, each paired with the package that published it.
|
|
85
|
+
*
|
|
86
|
+
* The id is what a SQL content table addresses a dependency's notes by
|
|
87
|
+
* (`FROM sohl.notes`, #246), so the pairing has to survive the lookup —
|
|
88
|
+
* {@link cachedMetadataFiles} drops it, and a caller reconstructing the id from
|
|
89
|
+
* the file name would be parsing a path to recover something the declaration
|
|
90
|
+
* already stated.
|
|
91
|
+
*
|
|
92
|
+
* @param {object} config - The resolved build configuration.
|
|
93
|
+
* @returns {Array<{id: string, file: string}>} One entry per declared
|
|
94
|
+
* dependency.
|
|
95
|
+
* @throws {Error} When a declared dependency has not been fetched.
|
|
96
|
+
*/
|
|
97
|
+
export function cachedMetadataIndexes(config: object): Array<{
|
|
98
|
+
id: string;
|
|
99
|
+
file: string;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* The newest cached version among several version-keyed cache directories.
|
|
103
|
+
*
|
|
104
|
+
* Versions are compared **numerically per segment**, not as strings: a plain
|
|
105
|
+
* sort puts `0.8.10` before `0.8.2`, so a build that had cached both would
|
|
106
|
+
* silently resolve against the older one. A fetch always writes the currently
|
|
107
|
+
* declared version, so several present at once means an earlier pin was left
|
|
108
|
+
* behind rather than that a choice is genuinely open.
|
|
109
|
+
*
|
|
110
|
+
* **Both version-keyed caches under `build/cache` choose this way** — the
|
|
111
|
+
* content index here and the item catalogue in
|
|
112
|
+
* {@link module:engine/foreign-catalog} — so the comparison lives in one place
|
|
113
|
+
* rather than being written once per cache. Two copies would be two chances to
|
|
114
|
+
* get it wrong, and the wrong answer is invisible: every cached version is a
|
|
115
|
+
* complete, stamped, perfectly valid artifact, so picking the older one reports
|
|
116
|
+
* nothing and simply resolves against stale data (#272).
|
|
117
|
+
*
|
|
118
|
+
* @param {string[]} dirs - Complete cache directories, named `<id>@<version>`.
|
|
119
|
+
* @returns {string} The newest one.
|
|
120
|
+
*/
|
|
121
|
+
export function newestVersionDir(dirs: string[]): string;
|
|
122
|
+
/**
|
|
123
|
+
* Resolve every foreign address this build can cite, from the fetched indexes.
|
|
124
|
+
*
|
|
125
|
+
* The replacement for the vendored link manifest, and deliberately the same
|
|
126
|
+
* return shape — a `Map` from canonical address to `{ url, name, uuid, … }` —
|
|
127
|
+
* so a foreign entry and a local one stay interchangeable at the point of use.
|
|
128
|
+
* What changed is where the data comes from: a file the producer published,
|
|
129
|
+
* not a copy a consumer committed.
|
|
130
|
+
*
|
|
131
|
+
* **A package this build publishes is skipped**, however it got into the cache.
|
|
132
|
+
* A build is authoritative in its own addresses, and reading them back from a
|
|
133
|
+
* fetched artifact would let a stale copy overrule the tree that is being
|
|
134
|
+
* compiled right now. It is also what stops a cycle forming: the mutual
|
|
135
|
+
* vendoring this replaces deadlocked because each package had to read the
|
|
136
|
+
* other's file before it could publish its own.
|
|
137
|
+
*
|
|
138
|
+
* **Nothing here can be stale.** The version gate the manifest needed existed
|
|
139
|
+
* because a vendored copy could sit at any age; a fetched index is pinned to
|
|
140
|
+
* the version the relationship declares, so `stale` now reports only what is
|
|
141
|
+
* genuinely unusable — an unreadable file, or a package with pages and no base
|
|
142
|
+
* to serve them from.
|
|
143
|
+
*
|
|
144
|
+
* @param {object} config - The resolved build configuration.
|
|
145
|
+
* @param {Iterable<string>} localPackages - Packages this build publishes.
|
|
146
|
+
* @param {Record<string, string>} [bases] - Where each package is served.
|
|
147
|
+
* @returns {{index: Map<string, object>, packages: Set<string>,
|
|
148
|
+
* stale: Array<{package: string, reason: string}>}} The resolved addresses,
|
|
149
|
+
* which packages contributed, and what could not be read.
|
|
150
|
+
*/
|
|
151
|
+
export function loadForeignIndexes(config: object, localPackages: Iterable<string>, bases?: Record<string, string>): {
|
|
152
|
+
index: Map<string, object>;
|
|
153
|
+
packages: Set<string>;
|
|
154
|
+
stale: Array<{
|
|
155
|
+
package: string;
|
|
156
|
+
reason: string;
|
|
157
|
+
}>;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Where a dependency's fetched index sits, for naming it in a diagnostic.
|
|
161
|
+
*
|
|
162
|
+
* Best effort: the newest complete cache for that package, or the directory it
|
|
163
|
+
* would occupy. A finding has to name *a* file even when the cache is in the
|
|
164
|
+
* state the finding is about.
|
|
165
|
+
*
|
|
166
|
+
* @param {object} config - The resolved build configuration.
|
|
167
|
+
* @param {string} pkg - The dependency's package id.
|
|
168
|
+
* @returns {string} A path to name in a diagnostic.
|
|
169
|
+
*/
|
|
170
|
+
export function cachedIndexPath(config: object, pkg: string): string;
|
|
171
|
+
/**
|
|
172
|
+
* Whether a fetched index can still be *addressed*, as distinct from read.
|
|
173
|
+
*
|
|
174
|
+
* A consumer resolves cross-package links by canonical key, so it needs both
|
|
175
|
+
* sides to agree on the key's shape. When they drift the lookup cannot match on
|
|
176
|
+
* *any* input — and because a miss is indistinguishable from a typo, the
|
|
177
|
+
* symptom is a pile of dead addresses blamed on the notes that cite them rather
|
|
178
|
+
* than on the index at fault. A package whose every key is unreadable is
|
|
179
|
+
* therefore reported against the index, once, instead of once per citing note.
|
|
180
|
+
*
|
|
181
|
+
* The realistic cause is a version skew: a dependency released before the
|
|
182
|
+
* address grammar gained its `<system>` segment (#59) ships three-segment keys.
|
|
183
|
+
* Re-fetching after that dependency releases is the fix.
|
|
184
|
+
*
|
|
185
|
+
* @param {Map<string, object>} foreignIndex - The resolved foreign index.
|
|
186
|
+
* @returns {Array<{package: string, entries: number, sampleKey: string}>} One
|
|
187
|
+
* finding per drifted package, in the order the index first names each.
|
|
188
|
+
*/
|
|
189
|
+
export function unaddressableForeignPackages(foreignIndex: Map<string, object>): Array<{
|
|
190
|
+
package: string;
|
|
191
|
+
entries: number;
|
|
192
|
+
sampleKey: string;
|
|
193
|
+
}>;
|
|
194
|
+
/**
|
|
195
|
+
* One finding, in the standard `file:line:column: severity: message` form.
|
|
196
|
+
*
|
|
197
|
+
* The position is recovered by locating the offending key in the index text:
|
|
198
|
+
* the finding is about a literal the reader can see in the file, so its
|
|
199
|
+
* position is implicit rather than absent. When the file cannot be read, or the
|
|
200
|
+
* key is not in it, the locator degrades to the file alone — a dropped field,
|
|
201
|
+
* never a guessed `1:1` that would send the reader to the top of a large file
|
|
202
|
+
* for a finding that is not there.
|
|
203
|
+
*
|
|
204
|
+
* @param {{package: string, entries: number, sampleKey: string}} finding - One
|
|
205
|
+
* finding from {@link unaddressableForeignPackages}.
|
|
206
|
+
* @param {object} config - The resolved build configuration.
|
|
207
|
+
* @returns {string} The formatted diagnostic, path first on the line.
|
|
208
|
+
*/
|
|
209
|
+
export function formatUnaddressableFinding(finding: {
|
|
210
|
+
package: string;
|
|
211
|
+
entries: number;
|
|
212
|
+
sampleKey: string;
|
|
213
|
+
}, config: object): string;
|
|
214
|
+
/**
|
|
215
|
+
* The relationship kinds that are dependencies, and therefore citable.
|
|
216
|
+
*
|
|
217
|
+
* A package may cite what it depends on and nothing else. `recommends` and
|
|
218
|
+
* `conflicts` are declarations *about* other packages rather than dependencies
|
|
219
|
+
* on them, so an address resolved through one would emit a link into a package
|
|
220
|
+
* the consumer does not require — a defect in the citing note, not a lookup to
|
|
221
|
+
* satisfy.
|
|
222
|
+
*
|
|
223
|
+
* @type {readonly string[]}
|
|
224
|
+
*/
|
|
225
|
+
export const METADATA_RELATIONSHIP_KINDS: readonly string[];
|
|
226
|
+
export function isComplete(dir: string): boolean;
|