@heroiclands/package-build 22.0.0 → 22.0.2
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 +24 -0
- package/docs/api.md +8 -7
- package/docs/content-format.md +17 -5
- package/engine/asset-index.mjs +50 -1
- package/package.json +1 -1
- package/packagebuild-metadata.jsonl +13 -13
- package/types/engine/asset-index.d.mts +20 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 83fa58e: **A record states `attribution` and `license`, or it is a finding.** The nearest
|
|
8
|
+
provenance record is the whole answer and is never merged with the one above it,
|
|
9
|
+
so a key left out is not inherited — it is absent, and a record stating neither
|
|
10
|
+
would leave every file beneath it with no rights holder and no terms. `source`,
|
|
11
|
+
`ai` and `notes` stay optional, because blank is a truthful answer for each.
|
|
12
|
+
|
|
13
|
+
## 22.0.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- d049b3e: **A provenance record may state `ai`.** It says whether the file is
|
|
18
|
+
machine-generated, and like every provenance key it is optional — a record that
|
|
19
|
+
omits it is unchanged, and nothing reads it yet. It exists so a package can
|
|
20
|
+
record the fact where the fact belongs, rather than in a key that means
|
|
21
|
+
something else.
|
|
22
|
+
|
|
23
|
+
**`attribution` is the person, not the tool.** It names whoever holds the rights
|
|
24
|
+
and is legally due the credit. Its description said a tool could go there, which
|
|
25
|
+
is what `ai` is for.
|
|
26
|
+
|
|
3
27
|
## 22.0.0
|
|
4
28
|
|
|
5
29
|
### Major Changes
|
package/docs/api.md
CHANGED
|
@@ -567,13 +567,14 @@ The asset types — `icon`, `image` and `audio` — and the three roots they are
|
|
|
567
567
|
|
|
568
568
|
The asset record: one line of the content index per addressable file. The record is emitted by the package holding the bytes, so its `path` is that package's path and each consumer joins its own root onto it — Foundry its data directory, the website its CDN prefix, the book its asset base.
|
|
569
569
|
|
|
570
|
-
| Export | Signature | Returns | Use it when
|
|
571
|
-
| --------------------------- | --------------------------------------------------------------- | ----------------------------- |
|
|
572
|
-
| `ASSET_RECORD_FIELDS` | `const ASSET_RECORD_FIELDS` | `readonly AssetRecordField[]` | reading what an `asset` block carries, and where each field comes from
|
|
573
|
-
| `PROVENANCE_KEYS` | `const PROVENANCE_KEYS` | `ReadonlySet<string>` | validating a provenance file, whose keys are derived from the record's own fields
|
|
574
|
-
| `
|
|
575
|
-
| `
|
|
576
|
-
| `
|
|
570
|
+
| Export | Signature | Returns | Use it when |
|
|
571
|
+
| --------------------------- | --------------------------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
572
|
+
| `ASSET_RECORD_FIELDS` | `const ASSET_RECORD_FIELDS` | `readonly AssetRecordField[]` | reading what an `asset` block carries, and where each field comes from |
|
|
573
|
+
| `PROVENANCE_KEYS` | `const PROVENANCE_KEYS` | `ReadonlySet<string>` | validating a provenance file, whose keys are derived from the record's own fields |
|
|
574
|
+
| `REQUIRED_PROVENANCE_KEYS` | `const REQUIRED_PROVENANCE_KEYS` | `ReadonlySet<string>` | the keys a provenance file must state — a record resolves wholesale, so one omitting them leaves every file it covers with no rights holder or no terms |
|
|
575
|
+
| `PROVENANCE_FILE` | `const PROVENANCE_FILE` | `string` — `provenance.yaml` | naming the file a directory records provenance for its subtree in |
|
|
576
|
+
| `PROVENANCE_SIDECAR_SUFFIX` | `const PROVENANCE_SIDECAR_SUFFIX` | `string` — `.yaml` | naming a per-file record, which replaces an inherited one wholesale |
|
|
577
|
+
| `collectAssetRecords` | `collectAssetRecords(assetsBase, { contentPackage, problems })` | `Array<Record<string, any>>` | reading a package's asset roots into index records, without walking its notes |
|
|
577
578
|
|
|
578
579
|
### `engine.packages`
|
|
579
580
|
|
package/docs/content-format.md
CHANGED
|
@@ -1465,8 +1465,9 @@ nothing about itself, compiles into no document, and publishes no page, so the
|
|
|
1465
1465
|
| `asset` field | Source | What it says |
|
|
1466
1466
|
| ------------- | ---------- | ------------------------------------------------------------------ |
|
|
1467
1467
|
| `path` | the walk | Where the file sits inside the emitting package's asset directory. |
|
|
1468
|
-
| `attribution` | provenance |
|
|
1468
|
+
| `attribution` | provenance | The person holding the rights, to whom attribution is legally due. |
|
|
1469
1469
|
| `source` | provenance | Where it came from — a URL, or a sentence. |
|
|
1470
|
+
| `ai` | provenance | Whether the file is machine-generated — `true` or `false`. |
|
|
1470
1471
|
| `license` | provenance | The licence it is used under — an SPDX identifier, or terms. |
|
|
1471
1472
|
| `notes` | provenance | Anything else a person reading the attribution needs. |
|
|
1472
1473
|
|
|
@@ -1490,10 +1491,10 @@ the two are distinct — they are equal in the system only by coincidence, and i
|
|
|
1490
1491
|
|
|
1491
1492
|
##### Where provenance comes from
|
|
1492
1493
|
|
|
1493
|
-
A `provenance.yaml` states
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1494
|
+
A `provenance.yaml` states the provenance fields in the table above, and nothing
|
|
1495
|
+
else: an unknown key is a finding rather than a silent drop, because `licence`
|
|
1496
|
+
beside `license` is otherwise an attribution record that looks complete and
|
|
1497
|
+
carries nothing.
|
|
1497
1498
|
|
|
1498
1499
|
One address resolves its record in this order:
|
|
1499
1500
|
|
|
@@ -1507,6 +1508,17 @@ One address resolves its record in this order:
|
|
|
1507
1508
|
3. Otherwise nothing, and the provenance fields are blank. A package that
|
|
1508
1509
|
records no attribution is a fact to state, not a walk to fail.
|
|
1509
1510
|
|
|
1511
|
+
**The nearest record is the whole answer.** It is never merged with the one
|
|
1512
|
+
above it, so a record states every key it means to claim — which is what lets a
|
|
1513
|
+
reader open one file and know what the tree beneath it carries, instead of
|
|
1514
|
+
resolving a chain by hand.
|
|
1515
|
+
|
|
1516
|
+
That is also why `attribution` and `license` are **required in any record that
|
|
1517
|
+
exists**: a key left out is not inherited from above, it is simply absent, so a
|
|
1518
|
+
record stating neither leaves every file it covers with no rights holder and no
|
|
1519
|
+
terms. Omitting one is a finding. `source`, `ai` and `notes` stay optional,
|
|
1520
|
+
because a blank is a truthful answer for each of them.
|
|
1521
|
+
|
|
1510
1522
|
#### A font is not an asset
|
|
1511
1523
|
|
|
1512
1524
|
`assets/fonts` is not a root, and a font has no address.
|
package/engine/asset-index.mjs
CHANGED
|
@@ -88,6 +88,10 @@ export const PROVENANCE_SIDECAR_SUFFIX = ".yaml";
|
|
|
88
88
|
* @property {string} name - The key inside `asset`.
|
|
89
89
|
* @property {"walk"|"provenance"} from - Where the value comes from: the walk
|
|
90
90
|
* itself, or the provenance record resolved for the address.
|
|
91
|
+
* @property {boolean} [required] - Whether a provenance record that exists must
|
|
92
|
+
* state this key. Omitting one is a finding rather than a blank, because a
|
|
93
|
+
* record resolves wholesale: the nearest one is the whole answer, so a key it
|
|
94
|
+
* leaves out is not inherited from above but simply absent.
|
|
91
95
|
* @property {string} describe - One line, for the author-facing reference.
|
|
92
96
|
*/
|
|
93
97
|
|
|
@@ -119,16 +123,23 @@ export const ASSET_RECORD_FIELDS = Object.freeze([
|
|
|
119
123
|
Object.freeze({
|
|
120
124
|
name: "attribution",
|
|
121
125
|
from: "provenance",
|
|
122
|
-
|
|
126
|
+
required: true,
|
|
127
|
+
describe: "The person holding the rights, to whom attribution is legally due.",
|
|
123
128
|
}),
|
|
124
129
|
Object.freeze({
|
|
125
130
|
name: "source",
|
|
126
131
|
from: "provenance",
|
|
127
132
|
describe: "Where it came from — a URL, or a sentence.",
|
|
128
133
|
}),
|
|
134
|
+
Object.freeze({
|
|
135
|
+
name: "ai",
|
|
136
|
+
from: "provenance",
|
|
137
|
+
describe: "Whether the file is machine-generated — `true` or `false`.",
|
|
138
|
+
}),
|
|
129
139
|
Object.freeze({
|
|
130
140
|
name: "license",
|
|
131
141
|
from: "provenance",
|
|
142
|
+
required: true,
|
|
132
143
|
describe: "The licence it is used under — an SPDX identifier, or terms.",
|
|
133
144
|
}),
|
|
134
145
|
Object.freeze({
|
|
@@ -154,6 +165,22 @@ export const PROVENANCE_KEYS = Object.freeze(
|
|
|
154
165
|
),
|
|
155
166
|
);
|
|
156
167
|
|
|
168
|
+
/**
|
|
169
|
+
* The keys a provenance file must state.
|
|
170
|
+
*
|
|
171
|
+
* Derived from {@link ASSET_RECORD_FIELDS} for the same reason the key set is:
|
|
172
|
+
* the rule and the record cannot disagree about which keys are required.
|
|
173
|
+
*
|
|
174
|
+
* @type {ReadonlySet<string>}
|
|
175
|
+
*/
|
|
176
|
+
export const REQUIRED_PROVENANCE_KEYS = Object.freeze(
|
|
177
|
+
new Set(
|
|
178
|
+
ASSET_RECORD_FIELDS.filter((field) => field.from === "provenance" && field.required).map(
|
|
179
|
+
(field) => field.name,
|
|
180
|
+
),
|
|
181
|
+
),
|
|
182
|
+
);
|
|
183
|
+
|
|
157
184
|
/**
|
|
158
185
|
* Read one provenance file, reporting every key that is not a provenance key.
|
|
159
186
|
*
|
|
@@ -213,6 +240,25 @@ function readProvenanceFile(file, findings) {
|
|
|
213
240
|
}
|
|
214
241
|
out[key] = value == null ? "" : String(value);
|
|
215
242
|
}
|
|
243
|
+
|
|
244
|
+
// A record resolves wholesale — the nearest one is the whole answer, and no
|
|
245
|
+
// ancestor fills a key it leaves out. So an omitted `attribution` or
|
|
246
|
+
// `license` is not a value inherited from above; it is a file with no stated
|
|
247
|
+
// rights holder and no stated terms, which is the one thing a provenance
|
|
248
|
+
// record exists to prevent. Reported against the file rather than a line,
|
|
249
|
+
// because the fault is an absence and has no position.
|
|
250
|
+
for (const key of REQUIRED_PROVENANCE_KEYS) {
|
|
251
|
+
if (out[key]) continue;
|
|
252
|
+
findings.push({
|
|
253
|
+
file,
|
|
254
|
+
severity: "error",
|
|
255
|
+
message:
|
|
256
|
+
`a provenance record states \`${key}\`, and this one does not. ` +
|
|
257
|
+
"A record replaces rather than extends the one above it, so every " +
|
|
258
|
+
"file it covers would carry no " +
|
|
259
|
+
(key === "license" ? "licence" : key),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
216
262
|
return out;
|
|
217
263
|
}
|
|
218
264
|
|
|
@@ -234,6 +280,9 @@ function inheritedProvenance(dir, root, cache, findings) {
|
|
|
234
280
|
const own = path.join(dir, PROVENANCE_FILE);
|
|
235
281
|
let answer;
|
|
236
282
|
if (fs.existsSync(own)) {
|
|
283
|
+
// The nearest record is the whole answer. It is not merged with the one
|
|
284
|
+
// above it, so a record states every key it means to claim and a reader
|
|
285
|
+
// needs only the file in front of them to know what a file carries.
|
|
237
286
|
answer = readProvenanceFile(own, findings);
|
|
238
287
|
} else if (path.resolve(dir) === path.resolve(root)) {
|
|
239
288
|
// The search stops at the type root: `assets/` above it is the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "22.0.
|
|
3
|
+
"version": "22.0.2",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
{"address":{"canonical":"packagebuild-none-image-afflictionbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/afflictionbnr.webp","source":""},"package":"packagebuild","shortcode":"afflictionbnr","type":"image"}
|
|
2
|
-
{"address":{"canonical":"packagebuild-none-image-armorclothingbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/armorclothingbnr.webp","source":""},"package":"packagebuild","shortcode":"armorclothingbnr","type":"image"}
|
|
3
|
-
{"address":{"canonical":"packagebuild-none-image-attributebnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/attributebnr.webp","source":""},"package":"packagebuild","shortcode":"attributebnr","type":"image"}
|
|
4
|
-
{"address":{"canonical":"packagebuild-none-image-containerbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/containerbnr.webp","source":""},"package":"packagebuild","shortcode":"containerbnr","type":"image"}
|
|
5
|
-
{"address":{"canonical":"packagebuild-none-image-devdocsbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/devdocsbnr.webp","source":""},"package":"packagebuild","shortcode":"devdocsbnr","type":"image"}
|
|
6
|
-
{"address":{"canonical":"packagebuild-none-image-miscgearbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/miscgearbnr.webp","source":""},"package":"packagebuild","shortcode":"miscgearbnr","type":"image"}
|
|
7
|
-
{"address":{"canonical":"packagebuild-none-image-mysticalabilitybnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/mysticalabilitybnr.webp","source":""},"package":"packagebuild","shortcode":"mysticalabilitybnr","type":"image"}
|
|
8
|
-
{"address":{"canonical":"packagebuild-none-image-projectilebnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/projectilebnr.webp","source":""},"package":"packagebuild","shortcode":"projectilebnr","type":"image"}
|
|
9
|
-
{"address":{"canonical":"packagebuild-none-image-rulesbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/rulesbnr.webp","source":""},"package":"packagebuild","shortcode":"rulesbnr","type":"image"}
|
|
10
|
-
{"address":{"canonical":"packagebuild-none-image-skillbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/skillbnr.webp","source":""},"package":"packagebuild","shortcode":"skillbnr","type":"image"}
|
|
11
|
-
{"address":{"canonical":"packagebuild-none-image-traumabnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/traumabnr.webp","source":""},"package":"packagebuild","shortcode":"traumabnr","type":"image"}
|
|
12
|
-
{"address":{"canonical":"packagebuild-none-image-userguidebnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/userguidebnr.webp","source":""},"package":"packagebuild","shortcode":"userguidebnr","type":"image"}
|
|
13
|
-
{"address":{"canonical":"packagebuild-none-image-weapongearbnr"},"asset":{"attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/weapongearbnr.webp","source":""},"package":"packagebuild","shortcode":"weapongearbnr","type":"image"}
|
|
1
|
+
{"address":{"canonical":"packagebuild-none-image-afflictionbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/afflictionbnr.webp","source":""},"package":"packagebuild","shortcode":"afflictionbnr","type":"image"}
|
|
2
|
+
{"address":{"canonical":"packagebuild-none-image-armorclothingbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/armorclothingbnr.webp","source":""},"package":"packagebuild","shortcode":"armorclothingbnr","type":"image"}
|
|
3
|
+
{"address":{"canonical":"packagebuild-none-image-attributebnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/attributebnr.webp","source":""},"package":"packagebuild","shortcode":"attributebnr","type":"image"}
|
|
4
|
+
{"address":{"canonical":"packagebuild-none-image-containerbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/containerbnr.webp","source":""},"package":"packagebuild","shortcode":"containerbnr","type":"image"}
|
|
5
|
+
{"address":{"canonical":"packagebuild-none-image-devdocsbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/devdocsbnr.webp","source":""},"package":"packagebuild","shortcode":"devdocsbnr","type":"image"}
|
|
6
|
+
{"address":{"canonical":"packagebuild-none-image-miscgearbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/miscgearbnr.webp","source":""},"package":"packagebuild","shortcode":"miscgearbnr","type":"image"}
|
|
7
|
+
{"address":{"canonical":"packagebuild-none-image-mysticalabilitybnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/mysticalabilitybnr.webp","source":""},"package":"packagebuild","shortcode":"mysticalabilitybnr","type":"image"}
|
|
8
|
+
{"address":{"canonical":"packagebuild-none-image-projectilebnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/projectilebnr.webp","source":""},"package":"packagebuild","shortcode":"projectilebnr","type":"image"}
|
|
9
|
+
{"address":{"canonical":"packagebuild-none-image-rulesbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/rulesbnr.webp","source":""},"package":"packagebuild","shortcode":"rulesbnr","type":"image"}
|
|
10
|
+
{"address":{"canonical":"packagebuild-none-image-skillbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/skillbnr.webp","source":""},"package":"packagebuild","shortcode":"skillbnr","type":"image"}
|
|
11
|
+
{"address":{"canonical":"packagebuild-none-image-traumabnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/traumabnr.webp","source":""},"package":"packagebuild","shortcode":"traumabnr","type":"image"}
|
|
12
|
+
{"address":{"canonical":"packagebuild-none-image-userguidebnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/userguidebnr.webp","source":""},"package":"packagebuild","shortcode":"userguidebnr","type":"image"}
|
|
13
|
+
{"address":{"canonical":"packagebuild-none-image-weapongearbnr"},"asset":{"ai":"","attribution":"Tom Rodriguez","license":"CC-BY-SA-4.0","notes":"","path":"images/banners/weapongearbnr.webp","source":""},"package":"packagebuild","shortcode":"weapongearbnr","type":"image"}
|
|
@@ -43,6 +43,10 @@ export const PROVENANCE_SIDECAR_SUFFIX: string;
|
|
|
43
43
|
* @property {string} name - The key inside `asset`.
|
|
44
44
|
* @property {"walk"|"provenance"} from - Where the value comes from: the walk
|
|
45
45
|
* itself, or the provenance record resolved for the address.
|
|
46
|
+
* @property {boolean} [required] - Whether a provenance record that exists must
|
|
47
|
+
* state this key. Omitting one is a finding rather than a blank, because a
|
|
48
|
+
* record resolves wholesale: the nearest one is the whole answer, so a key it
|
|
49
|
+
* leaves out is not inherited from above but simply absent.
|
|
46
50
|
* @property {string} describe - One line, for the author-facing reference.
|
|
47
51
|
*/
|
|
48
52
|
/**
|
|
@@ -72,6 +76,15 @@ export const ASSET_RECORD_FIELDS: readonly AssetRecordField[];
|
|
|
72
76
|
* @type {ReadonlySet<string>}
|
|
73
77
|
*/
|
|
74
78
|
export const PROVENANCE_KEYS: ReadonlySet<string>;
|
|
79
|
+
/**
|
|
80
|
+
* The keys a provenance file must state.
|
|
81
|
+
*
|
|
82
|
+
* Derived from {@link ASSET_RECORD_FIELDS} for the same reason the key set is:
|
|
83
|
+
* the rule and the record cannot disagree about which keys are required.
|
|
84
|
+
*
|
|
85
|
+
* @type {ReadonlySet<string>}
|
|
86
|
+
*/
|
|
87
|
+
export const REQUIRED_PROVENANCE_KEYS: ReadonlySet<string>;
|
|
75
88
|
/**
|
|
76
89
|
* One field of the `asset` block.
|
|
77
90
|
*/
|
|
@@ -85,6 +98,13 @@ export type AssetRecordField = {
|
|
|
85
98
|
* itself, or the provenance record resolved for the address.
|
|
86
99
|
*/
|
|
87
100
|
from: "walk" | "provenance";
|
|
101
|
+
/**
|
|
102
|
+
* - Whether a provenance record that exists must
|
|
103
|
+
* state this key. Omitting one is a finding rather than a blank, because a
|
|
104
|
+
* record resolves wholesale: the nearest one is the whole answer, so a key it
|
|
105
|
+
* leaves out is not inherited from above but simply absent.
|
|
106
|
+
*/
|
|
107
|
+
required?: boolean | undefined;
|
|
88
108
|
/**
|
|
89
109
|
* - One line, for the author-facing reference.
|
|
90
110
|
*/
|