@wildwinter/toolkit 0.2.7 → 0.3.1
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 +21 -0
- package/conformance/extensions/defaults.json +1 -1
- package/conformance/extensions/manifest.json +321 -172
- package/conformance/extensions/values.json +0 -86
- package/dist/extensions.cjs +74 -132
- package/dist/extensions.cjs.map +1 -1
- package/dist/extensions.d.cts +10 -48
- package/dist/extensions.d.ts +10 -48
- package/dist/extensions.js +74 -129
- package/dist/extensions.js.map +1 -1
- package/extensions.md +28 -25
- package/package.json +1 -1
package/dist/extensions.d.cts
CHANGED
|
@@ -9,10 +9,8 @@ interface HostSpec {
|
|
|
9
9
|
readonly kinds: readonly string[];
|
|
10
10
|
/** The node kinds a `reference` may point at. */
|
|
11
11
|
readonly references: readonly string[];
|
|
12
|
-
/** The node kinds with host fields of their own, which a claim may present. */
|
|
13
|
-
readonly claimable: readonly string[];
|
|
14
12
|
}
|
|
15
|
-
/** Each host's node kinds
|
|
13
|
+
/** Each host's node kinds and references. */
|
|
16
14
|
declare const HOSTS: Readonly<Record<HostName, HostSpec>>;
|
|
17
15
|
/** The family's seven scalar types, spelled as the family spells them. */
|
|
18
16
|
declare const SCALAR_TYPES: readonly ["text", "multiline", "number", "boolean", "enum", "flags", "quality"];
|
|
@@ -82,26 +80,13 @@ interface FieldDecl extends TypeDecl {
|
|
|
82
80
|
readonly group?: string;
|
|
83
81
|
/** Stripped at compile: editor data, never in a bundle. A target's own fields only. */
|
|
84
82
|
readonly editorOnly?: boolean;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
readonly setting: string;
|
|
89
|
-
readonly label?: string;
|
|
90
|
-
readonly help?: string;
|
|
91
|
-
readonly required?: boolean;
|
|
83
|
+
/** One of the manifest's views, by id, that edits this field in the hosts it opens in: a target's own map of
|
|
84
|
+
* records only. */
|
|
85
|
+
readonly editor?: string;
|
|
92
86
|
}
|
|
93
87
|
/** What an extension declares for one node kind of one host. */
|
|
94
88
|
interface TargetDecl {
|
|
95
89
|
readonly fields?: readonly FieldDecl[];
|
|
96
|
-
readonly claims?: readonly ClaimDecl[];
|
|
97
|
-
}
|
|
98
|
-
/** A project setting, naming a host field a claim presents. */
|
|
99
|
-
interface SettingDecl {
|
|
100
|
-
readonly name: string;
|
|
101
|
-
readonly label?: string;
|
|
102
|
-
readonly help?: string;
|
|
103
|
-
/** The field name used when the project names none. */
|
|
104
|
-
readonly default: string;
|
|
105
90
|
}
|
|
106
91
|
interface Manifest {
|
|
107
92
|
readonly schema: string;
|
|
@@ -109,12 +94,13 @@ interface Manifest {
|
|
|
109
94
|
readonly name: string;
|
|
110
95
|
readonly version: string;
|
|
111
96
|
readonly docs?: string;
|
|
112
|
-
readonly settings?: readonly SettingDecl[];
|
|
113
97
|
readonly targets: Readonly<Partial<Record<HostName, Readonly<Record<string, TargetDecl>>>>>;
|
|
114
98
|
/** Views the extension's installed package supplies (tier 2), each a web component a host opens in a window. */
|
|
115
99
|
readonly views?: readonly ViewDecl[];
|
|
116
100
|
/** Other extensions whose data this one's views read, by id. */
|
|
117
101
|
readonly reads?: readonly string[];
|
|
102
|
+
/** Other extensions a project must take for this one to work, by id. */
|
|
103
|
+
readonly requires?: readonly string[];
|
|
118
104
|
}
|
|
119
105
|
/** A view: a web component in the extension's installed package, opened by a host in a floating window. */
|
|
120
106
|
interface ViewDecl {
|
|
@@ -164,38 +150,14 @@ declare function parseManifest(text: string): Manifest;
|
|
|
164
150
|
declare function manifestProblems(manifest: unknown): Problem[];
|
|
165
151
|
/** A package path a view's entry may name: relative, forward slashes, no `.` or `..` segment, a `.js` file. */
|
|
166
152
|
declare function isViewEntry(entry: unknown): entry is string;
|
|
153
|
+
/** The extensions a manifest requires that a project doesn't take, by id, in the manifest's order. An entry that
|
|
154
|
+
* fails its checks is left out. */
|
|
155
|
+
declare function missingRequirements(manifest: Manifest, taken: Iterable<string>): string[];
|
|
167
156
|
/** The views a host offers from a manifest: those naming the host, or every view when it names none and the
|
|
168
157
|
* manifest targets the host. A view that fails its checks is left out. */
|
|
169
158
|
declare function viewsFor(manifest: Manifest, host: HostName): ViewDecl[];
|
|
170
|
-
/** The host field each of a manifest's settings names, the project's choice
|
|
171
|
-
* first, else the setting's default. */
|
|
172
|
-
declare function settingValues(manifest: Manifest, chosen?: Readonly<Record<string, unknown>>): Record<string, string>;
|
|
173
|
-
/** A claim as a project resolves it: the host field it presents, by name. */
|
|
174
|
-
interface ResolvedClaim {
|
|
175
|
-
readonly extension: string;
|
|
176
|
-
readonly host: HostName;
|
|
177
|
-
readonly kind: string;
|
|
178
|
-
/** The host field's name, through the setting. */
|
|
179
|
-
readonly field: string;
|
|
180
|
-
readonly claim: ClaimDecl;
|
|
181
|
-
}
|
|
182
|
-
/** Every claim of a manifest for one host, resolved through the project's settings. */
|
|
183
|
-
declare function resolvedClaims(manifest: Manifest, host: HostName, chosen?: Readonly<Record<string, unknown>>): ResolvedClaim[];
|
|
184
|
-
/** Two extensions claiming one host field: an error naming both, once per pair. */
|
|
185
|
-
declare function claimClashes(claims: readonly ResolvedClaim[]): Problem[];
|
|
186
159
|
/** One manifest's declarations for one host and node kind, or undefined. */
|
|
187
160
|
declare function targetOf(manifest: Manifest | undefined, host: HostName, kind: string): TargetDecl | undefined;
|
|
188
|
-
/**
|
|
189
|
-
* A claim as a host draws and checks its field: the claim's label, help, value help and constraints, over the
|
|
190
|
-
* host's own declaration for what the claim leaves out (an enum's or flags' values, a quality's stages, the
|
|
191
|
-
* default). The host's vocabulary stands when the claim names none, as the host's ladder always does.
|
|
192
|
-
*/
|
|
193
|
-
declare function effectiveClaim<C extends ClaimDecl>(claim: C, hostDecl: {
|
|
194
|
-
readonly type?: string;
|
|
195
|
-
readonly values?: readonly string[];
|
|
196
|
-
readonly stages?: readonly string[];
|
|
197
|
-
readonly default?: unknown;
|
|
198
|
-
}): C;
|
|
199
161
|
|
|
200
162
|
/** What the host knows about its nodes, for references, and about the extension's project lists, for picks. */
|
|
201
163
|
interface ValueContext {
|
|
@@ -418,4 +380,4 @@ declare const atKey: (base: string, key: string) => string;
|
|
|
418
380
|
/** `base` and then list position `i`. */
|
|
419
381
|
declare const atIndex: (base: string, i: number) => string;
|
|
420
382
|
|
|
421
|
-
export { ATOMIC, COMMENTS, type
|
|
383
|
+
export { ATOMIC, COMMENTS, type Conflict, type ConflictKind, type DataMergeResult, type ExtensionData, type FieldDecl, HOSTS, type HostName, type HostSpec, type JsonValue, MANIFEST_FILE_SUFFIX, MANIFEST_SCHEMA, type Manifest, type MergeWarning, type PickChoice, type PickSource, type PickSources, type Problem, SCALAR_TYPES, SET, type ScalarType, type StageRename, type Strategy, type TargetDecl, type TreeMergeOptions, type TreeMergeResult, type TypeDecl, UNRESOLVED_KEY, type UnresolvedEntry, VALUE_TYPES, type ValueContext, type ValueType, type ViewDecl, atIndex, atKey, compileEntry, compiledTarget, defaultOf, entryProblems, extensionDataStrategy, isTextList, isViewEntry, keyedBy, manifestProblems, mapOf, markUnresolved, mergeComments, mergeExtensionData, mergeTree, missingRequirements, objectOf, orphanedEntries, parseManifest, pickChoices, pickClashes, pickLists, renameStages, stableStringify, strategyForTarget, strategyForType, targetOf, unresolvedOf, unresolvedProblems, valueProblems, viewsFor, withoutMark };
|
package/dist/extensions.d.ts
CHANGED
|
@@ -9,10 +9,8 @@ interface HostSpec {
|
|
|
9
9
|
readonly kinds: readonly string[];
|
|
10
10
|
/** The node kinds a `reference` may point at. */
|
|
11
11
|
readonly references: readonly string[];
|
|
12
|
-
/** The node kinds with host fields of their own, which a claim may present. */
|
|
13
|
-
readonly claimable: readonly string[];
|
|
14
12
|
}
|
|
15
|
-
/** Each host's node kinds
|
|
13
|
+
/** Each host's node kinds and references. */
|
|
16
14
|
declare const HOSTS: Readonly<Record<HostName, HostSpec>>;
|
|
17
15
|
/** The family's seven scalar types, spelled as the family spells them. */
|
|
18
16
|
declare const SCALAR_TYPES: readonly ["text", "multiline", "number", "boolean", "enum", "flags", "quality"];
|
|
@@ -82,26 +80,13 @@ interface FieldDecl extends TypeDecl {
|
|
|
82
80
|
readonly group?: string;
|
|
83
81
|
/** Stripped at compile: editor data, never in a bundle. A target's own fields only. */
|
|
84
82
|
readonly editorOnly?: boolean;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
readonly setting: string;
|
|
89
|
-
readonly label?: string;
|
|
90
|
-
readonly help?: string;
|
|
91
|
-
readonly required?: boolean;
|
|
83
|
+
/** One of the manifest's views, by id, that edits this field in the hosts it opens in: a target's own map of
|
|
84
|
+
* records only. */
|
|
85
|
+
readonly editor?: string;
|
|
92
86
|
}
|
|
93
87
|
/** What an extension declares for one node kind of one host. */
|
|
94
88
|
interface TargetDecl {
|
|
95
89
|
readonly fields?: readonly FieldDecl[];
|
|
96
|
-
readonly claims?: readonly ClaimDecl[];
|
|
97
|
-
}
|
|
98
|
-
/** A project setting, naming a host field a claim presents. */
|
|
99
|
-
interface SettingDecl {
|
|
100
|
-
readonly name: string;
|
|
101
|
-
readonly label?: string;
|
|
102
|
-
readonly help?: string;
|
|
103
|
-
/** The field name used when the project names none. */
|
|
104
|
-
readonly default: string;
|
|
105
90
|
}
|
|
106
91
|
interface Manifest {
|
|
107
92
|
readonly schema: string;
|
|
@@ -109,12 +94,13 @@ interface Manifest {
|
|
|
109
94
|
readonly name: string;
|
|
110
95
|
readonly version: string;
|
|
111
96
|
readonly docs?: string;
|
|
112
|
-
readonly settings?: readonly SettingDecl[];
|
|
113
97
|
readonly targets: Readonly<Partial<Record<HostName, Readonly<Record<string, TargetDecl>>>>>;
|
|
114
98
|
/** Views the extension's installed package supplies (tier 2), each a web component a host opens in a window. */
|
|
115
99
|
readonly views?: readonly ViewDecl[];
|
|
116
100
|
/** Other extensions whose data this one's views read, by id. */
|
|
117
101
|
readonly reads?: readonly string[];
|
|
102
|
+
/** Other extensions a project must take for this one to work, by id. */
|
|
103
|
+
readonly requires?: readonly string[];
|
|
118
104
|
}
|
|
119
105
|
/** A view: a web component in the extension's installed package, opened by a host in a floating window. */
|
|
120
106
|
interface ViewDecl {
|
|
@@ -164,38 +150,14 @@ declare function parseManifest(text: string): Manifest;
|
|
|
164
150
|
declare function manifestProblems(manifest: unknown): Problem[];
|
|
165
151
|
/** A package path a view's entry may name: relative, forward slashes, no `.` or `..` segment, a `.js` file. */
|
|
166
152
|
declare function isViewEntry(entry: unknown): entry is string;
|
|
153
|
+
/** The extensions a manifest requires that a project doesn't take, by id, in the manifest's order. An entry that
|
|
154
|
+
* fails its checks is left out. */
|
|
155
|
+
declare function missingRequirements(manifest: Manifest, taken: Iterable<string>): string[];
|
|
167
156
|
/** The views a host offers from a manifest: those naming the host, or every view when it names none and the
|
|
168
157
|
* manifest targets the host. A view that fails its checks is left out. */
|
|
169
158
|
declare function viewsFor(manifest: Manifest, host: HostName): ViewDecl[];
|
|
170
|
-
/** The host field each of a manifest's settings names, the project's choice
|
|
171
|
-
* first, else the setting's default. */
|
|
172
|
-
declare function settingValues(manifest: Manifest, chosen?: Readonly<Record<string, unknown>>): Record<string, string>;
|
|
173
|
-
/** A claim as a project resolves it: the host field it presents, by name. */
|
|
174
|
-
interface ResolvedClaim {
|
|
175
|
-
readonly extension: string;
|
|
176
|
-
readonly host: HostName;
|
|
177
|
-
readonly kind: string;
|
|
178
|
-
/** The host field's name, through the setting. */
|
|
179
|
-
readonly field: string;
|
|
180
|
-
readonly claim: ClaimDecl;
|
|
181
|
-
}
|
|
182
|
-
/** Every claim of a manifest for one host, resolved through the project's settings. */
|
|
183
|
-
declare function resolvedClaims(manifest: Manifest, host: HostName, chosen?: Readonly<Record<string, unknown>>): ResolvedClaim[];
|
|
184
|
-
/** Two extensions claiming one host field: an error naming both, once per pair. */
|
|
185
|
-
declare function claimClashes(claims: readonly ResolvedClaim[]): Problem[];
|
|
186
159
|
/** One manifest's declarations for one host and node kind, or undefined. */
|
|
187
160
|
declare function targetOf(manifest: Manifest | undefined, host: HostName, kind: string): TargetDecl | undefined;
|
|
188
|
-
/**
|
|
189
|
-
* A claim as a host draws and checks its field: the claim's label, help, value help and constraints, over the
|
|
190
|
-
* host's own declaration for what the claim leaves out (an enum's or flags' values, a quality's stages, the
|
|
191
|
-
* default). The host's vocabulary stands when the claim names none, as the host's ladder always does.
|
|
192
|
-
*/
|
|
193
|
-
declare function effectiveClaim<C extends ClaimDecl>(claim: C, hostDecl: {
|
|
194
|
-
readonly type?: string;
|
|
195
|
-
readonly values?: readonly string[];
|
|
196
|
-
readonly stages?: readonly string[];
|
|
197
|
-
readonly default?: unknown;
|
|
198
|
-
}): C;
|
|
199
161
|
|
|
200
162
|
/** What the host knows about its nodes, for references, and about the extension's project lists, for picks. */
|
|
201
163
|
interface ValueContext {
|
|
@@ -418,4 +380,4 @@ declare const atKey: (base: string, key: string) => string;
|
|
|
418
380
|
/** `base` and then list position `i`. */
|
|
419
381
|
declare const atIndex: (base: string, i: number) => string;
|
|
420
382
|
|
|
421
|
-
export { ATOMIC, COMMENTS, type
|
|
383
|
+
export { ATOMIC, COMMENTS, type Conflict, type ConflictKind, type DataMergeResult, type ExtensionData, type FieldDecl, HOSTS, type HostName, type HostSpec, type JsonValue, MANIFEST_FILE_SUFFIX, MANIFEST_SCHEMA, type Manifest, type MergeWarning, type PickChoice, type PickSource, type PickSources, type Problem, SCALAR_TYPES, SET, type ScalarType, type StageRename, type Strategy, type TargetDecl, type TreeMergeOptions, type TreeMergeResult, type TypeDecl, UNRESOLVED_KEY, type UnresolvedEntry, VALUE_TYPES, type ValueContext, type ValueType, type ViewDecl, atIndex, atKey, compileEntry, compiledTarget, defaultOf, entryProblems, extensionDataStrategy, isTextList, isViewEntry, keyedBy, manifestProblems, mapOf, markUnresolved, mergeComments, mergeExtensionData, mergeTree, missingRequirements, objectOf, orphanedEntries, parseManifest, pickChoices, pickClashes, pickLists, renameStages, stableStringify, strategyForTarget, strategyForType, targetOf, unresolvedOf, unresolvedProblems, valueProblems, viewsFor, withoutMark };
|
package/dist/extensions.js
CHANGED
|
@@ -8,13 +8,11 @@ var MANIFEST_FILE_SUFFIX = ".extension.json";
|
|
|
8
8
|
var HOSTS = {
|
|
9
9
|
patter: {
|
|
10
10
|
kinds: ["scene", "block", "snippet", "line", "text", "gameEvent", "option", "project"],
|
|
11
|
-
references: ["cast", "scene", "block", "snippet", "line"]
|
|
12
|
-
claimable: ["scene", "block", "snippet", "line", "text", "gameEvent", "option"]
|
|
11
|
+
references: ["cast", "scene", "block", "snippet", "line"]
|
|
13
12
|
},
|
|
14
13
|
storylets: {
|
|
15
14
|
kinds: ["box", "tagGroup", "tag", "deck", "card", "outcome", "handTemplate", "hand", "project"],
|
|
16
|
-
references: ["box", "deck", "card", "outcome", "tag"]
|
|
17
|
-
claimable: ["card", "outcome"]
|
|
15
|
+
references: ["box", "deck", "card", "outcome", "tag"]
|
|
18
16
|
}
|
|
19
17
|
};
|
|
20
18
|
var SCALAR_TYPES = ["text", "multiline", "number", "boolean", "enum", "flags", "quality"];
|
|
@@ -357,10 +355,15 @@ var ID = /^[a-z][a-z0-9-]*$/;
|
|
|
357
355
|
var VERSION = /^\d+\.\d+\.\d+$/;
|
|
358
356
|
var NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
359
357
|
var TYPE_KEYS = ["type", "values", "stages", "renamedStages", "to", "from", "fields", "key", "of", "id", "min", "max", "valueHelp", "default"];
|
|
360
|
-
var FIELD_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "name", "label", "help", "required", "group", "editorOnly"]);
|
|
361
|
-
var CLAIM_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "setting", "label", "help", "required"]);
|
|
358
|
+
var FIELD_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "name", "label", "help", "required", "group", "editorOnly", "editor"]);
|
|
362
359
|
var BARE_KEYS = new Set(TYPE_KEYS);
|
|
363
|
-
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "
|
|
360
|
+
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "targets", "views", "reads", "requires"]);
|
|
361
|
+
var REMOVED_MANIFEST_KEYS = {
|
|
362
|
+
settings: "settings were removed with claims; declare the extension's own fields, or a project field for a project-wide value"
|
|
363
|
+
};
|
|
364
|
+
var REMOVED_TARGET_KEYS = {
|
|
365
|
+
claims: "claims on host fields were removed; declare a field of the extension's own, which the runtimes hand the game"
|
|
366
|
+
};
|
|
364
367
|
var VIEW_KEYS = /* @__PURE__ */ new Set(["id", "name", "entry", "element", "hosts"]);
|
|
365
368
|
var ELEMENT = /^[a-z][a-z0-9._]*-[a-z0-9._-]*$/;
|
|
366
369
|
var err2 = (code, path, message) => ({ severity: "error", code, path, message });
|
|
@@ -371,7 +374,7 @@ function manifestProblems(manifest) {
|
|
|
371
374
|
const out = [];
|
|
372
375
|
if (!isObject(manifest)) return [err2("not-an-object", "", "a manifest is a JSON object")];
|
|
373
376
|
const m = manifest;
|
|
374
|
-
unknownKeys(m, MANIFEST_KEYS, "", out);
|
|
377
|
+
unknownKeys(m, MANIFEST_KEYS, "", out, REMOVED_MANIFEST_KEYS);
|
|
375
378
|
if (m["schema"] !== MANIFEST_SCHEMA) {
|
|
376
379
|
out.push(err2("schema", "schema", `the schema tag is ${JSON.stringify(m["schema"])}, not "${MANIFEST_SCHEMA}"`));
|
|
377
380
|
}
|
|
@@ -383,9 +386,9 @@ function manifestProblems(manifest) {
|
|
|
383
386
|
out.push(err2("version", "version", "the version is major.minor.patch, such as 1.0.0"));
|
|
384
387
|
}
|
|
385
388
|
if (m["docs"] !== void 0 && typeof m["docs"] !== "string") out.push(err2("docs", "docs", "docs is a link, as text"));
|
|
386
|
-
const settings = settingsProblems(m["settings"], out);
|
|
387
389
|
viewsProblems(m["views"], m["targets"], out);
|
|
388
390
|
readsProblems(m["reads"], m["id"], out);
|
|
391
|
+
requiresProblems(m["requires"], m["id"], out);
|
|
389
392
|
const targets = m["targets"];
|
|
390
393
|
if (!isObject(targets) || Object.keys(targets).length === 0) {
|
|
391
394
|
out.push(err2("no-targets", "targets", "the manifest targets no host"));
|
|
@@ -408,9 +411,10 @@ function manifestProblems(manifest) {
|
|
|
408
411
|
out.push(err2("unknown-kind", kindPath, `"${kind}" is not a node kind of ${host}; it has ${spec.kinds.join(", ")}`));
|
|
409
412
|
continue;
|
|
410
413
|
}
|
|
411
|
-
targetProblems(host,
|
|
414
|
+
targetProblems(host, target, kindPath, out);
|
|
412
415
|
}
|
|
413
416
|
pickListProblems(kinds, hostPath, out);
|
|
417
|
+
editorProblems(host, kinds, m["views"], Object.keys(targets), hostPath, out);
|
|
414
418
|
}
|
|
415
419
|
return out;
|
|
416
420
|
}
|
|
@@ -550,85 +554,75 @@ function readsProblems(reads, self, out) {
|
|
|
550
554
|
else seen.add(r);
|
|
551
555
|
});
|
|
552
556
|
}
|
|
557
|
+
function requiresProblems(requires, self, out) {
|
|
558
|
+
if (requires === void 0) return;
|
|
559
|
+
if (!Array.isArray(requires)) {
|
|
560
|
+
out.push(err2("not-a-list", "requires", "requires is a list of extension ids"));
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const seen = /* @__PURE__ */ new Set();
|
|
564
|
+
requires.forEach((r, i) => {
|
|
565
|
+
const at = atIndex("requires", i);
|
|
566
|
+
if (typeof r !== "string" || !ID.test(r)) out.push(err2("requires-id", at, "a required extension is named by its id: lower case letters, digits and hyphens"));
|
|
567
|
+
else if (r === self) out.push(err2("requires-self", at, "an extension can't require itself"));
|
|
568
|
+
else if (seen.has(r)) out.push(err2("requires-duplicate", at, `"${r}" is listed twice`));
|
|
569
|
+
else seen.add(r);
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
function missingRequirements(manifest, taken) {
|
|
573
|
+
const have = new Set(taken);
|
|
574
|
+
const out = [];
|
|
575
|
+
for (const r of Array.isArray(manifest.requires) ? manifest.requires : []) {
|
|
576
|
+
if (typeof r === "string" && ID.test(r) && r !== manifest.id && !have.has(r) && !out.includes(r)) out.push(r);
|
|
577
|
+
}
|
|
578
|
+
return out;
|
|
579
|
+
}
|
|
580
|
+
function editorProblems(host, kinds, views, targeted, hostPath, out) {
|
|
581
|
+
const declared = Array.isArray(views) ? views.filter((v) => isObject(v) && typeof v["id"] === "string") : [];
|
|
582
|
+
for (const [kind, target] of Object.entries(kinds)) {
|
|
583
|
+
if (!isObject(target) || !Array.isArray(target["fields"])) continue;
|
|
584
|
+
target["fields"].forEach((f, i) => {
|
|
585
|
+
if (!isObject(f) || f["editor"] === void 0) return;
|
|
586
|
+
const at = atKey(atIndex(atKey(atKey(hostPath, kind), "fields"), i), "editor");
|
|
587
|
+
const editor = f["editor"];
|
|
588
|
+
const view = typeof editor === "string" ? declared.find((v) => v["id"] === editor) : void 0;
|
|
589
|
+
if (view === void 0) {
|
|
590
|
+
out.push(err2("editor-view", at, typeof editor === "string" ? `the manifest declares no view called "${editor}"; an editor names one of its views by id` : "an editor names one of the manifest's views by its id"));
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
const opensIn = Array.isArray(view["hosts"]) ? view["hosts"] : targeted;
|
|
594
|
+
if (!opensIn.includes(host)) {
|
|
595
|
+
out.push(err2("editor-host", at, `the view "${editor}" doesn't open in ${host}`));
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const d = f;
|
|
599
|
+
if (!(d.type === "map" && isObject(d.of) && d.of.type === "record")) {
|
|
600
|
+
out.push({ severity: "warning", code: "editor-ignored", path: at, message: "only a map of records opens in an editor; this field is edited in place, so the editor is ignored" });
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
}
|
|
553
605
|
function viewsFor(manifest, host) {
|
|
554
606
|
const targeted = Object.keys(manifest.targets ?? {});
|
|
555
607
|
return (Array.isArray(manifest.views) ? manifest.views : []).filter((v) => isObject(v) && typeof v.id === "string" && ID.test(v.id) && typeof v.name === "string" && isViewEntry(v.entry) && typeof v.element === "string" && ELEMENT.test(v.element) && (v.hosts === void 0 ? targeted.includes(host) : Array.isArray(v.hosts) && v.hosts.includes(host)));
|
|
556
608
|
}
|
|
557
|
-
function unknownKeys(obj, known, path, out) {
|
|
609
|
+
function unknownKeys(obj, known, path, out, removed = {}) {
|
|
558
610
|
for (const k of Object.keys(obj)) {
|
|
559
|
-
if (
|
|
611
|
+
if (own(removed, k)) {
|
|
612
|
+
out.push({ severity: "warning", code: "removed-key", path: atKey(path, k), message: `"${k}" is ignored: ${removed[k]}` });
|
|
613
|
+
} else if (!known.has(k)) {
|
|
560
614
|
out.push({ severity: "warning", code: "unknown-key", path: atKey(path, k), message: `"${k}" means nothing here; it is ignored` });
|
|
561
615
|
}
|
|
562
616
|
}
|
|
563
617
|
}
|
|
564
|
-
function
|
|
565
|
-
const names = /* @__PURE__ */ new Set();
|
|
566
|
-
if (settings === void 0) return names;
|
|
567
|
-
if (!Array.isArray(settings)) {
|
|
568
|
-
out.push(err2("not-a-list", "settings", "settings are a list"));
|
|
569
|
-
return names;
|
|
570
|
-
}
|
|
571
|
-
settings.forEach((s, i) => {
|
|
572
|
-
const at = atIndex("settings", i);
|
|
573
|
-
if (!isObject(s)) {
|
|
574
|
-
out.push(err2("not-an-object", at, "a setting is an object"));
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
const name = s["name"];
|
|
578
|
-
if (typeof name !== "string" || !NAME.test(name)) {
|
|
579
|
-
out.push(err2("setting-name", atKey(at, "name"), "a setting's name is an identifier"));
|
|
580
|
-
} else if (names.has(name)) {
|
|
581
|
-
out.push(err2("setting-duplicate", atKey(at, "name"), `setting "${name}" is declared twice`));
|
|
582
|
-
} else {
|
|
583
|
-
names.add(name);
|
|
584
|
-
}
|
|
585
|
-
const dflt = s.default;
|
|
586
|
-
if (typeof dflt !== "string" || !NAME.test(dflt)) {
|
|
587
|
-
out.push(err2("setting-default", atKey(at, "default"), "a setting names a host field by default, so its default is a field name"));
|
|
588
|
-
}
|
|
589
|
-
});
|
|
590
|
-
return names;
|
|
591
|
-
}
|
|
592
|
-
function targetProblems(host, kind, target, path, settings, out) {
|
|
618
|
+
function targetProblems(host, target, path, out) {
|
|
593
619
|
if (!isObject(target)) {
|
|
594
620
|
out.push(err2("not-an-object", path, "a target is an object"));
|
|
595
621
|
return;
|
|
596
622
|
}
|
|
597
|
-
unknownKeys(target, /* @__PURE__ */ new Set(["fields"
|
|
623
|
+
unknownKeys(target, /* @__PURE__ */ new Set(["fields"]), path, out, REMOVED_TARGET_KEYS);
|
|
598
624
|
const t = target;
|
|
599
625
|
if (t.fields !== void 0) fieldListProblems(host, t.fields, atKey(path, "fields"), true, out);
|
|
600
|
-
if (t.claims === void 0) return;
|
|
601
|
-
if (!Array.isArray(t.claims)) {
|
|
602
|
-
out.push(err2("not-a-list", atKey(path, "claims"), "claims are a list"));
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
const claimable = HOSTS[host].claimable.includes(kind);
|
|
606
|
-
const claimed = /* @__PURE__ */ new Set();
|
|
607
|
-
t.claims.forEach((c, i) => {
|
|
608
|
-
const at = atIndex(atKey(path, "claims"), i);
|
|
609
|
-
if (!claimable) {
|
|
610
|
-
out.push(err2("claim-kind", at, `a ${kind} has no host fields to claim; ${host} has them on ${HOSTS[host].claimable.join(", ")}`));
|
|
611
|
-
return;
|
|
612
|
-
}
|
|
613
|
-
if (!isObject(c)) {
|
|
614
|
-
out.push(err2("not-an-object", at, "a claim is an object"));
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
const claim = c;
|
|
618
|
-
unknownKeys(c, CLAIM_KEYS, at, out);
|
|
619
|
-
if (!SCALAR_TYPES.includes(claim.type)) {
|
|
620
|
-
out.push(err2("claim-type", atKey(at, "type"), "a claim presents a host field, which is a scalar"));
|
|
621
|
-
} else {
|
|
622
|
-
typeProblems(host, claim, at, false, out, true);
|
|
623
|
-
}
|
|
624
|
-
if (typeof claim.setting !== "string" || !settings.has(claim.setting)) {
|
|
625
|
-
out.push(err2("claim-setting", atKey(at, "setting"), `a claim names its field through a setting, and "${String(claim.setting)}" is not one of the manifest's settings`));
|
|
626
|
-
} else if (claimed.has(claim.setting)) {
|
|
627
|
-
out.push(err2("claim-duplicate", atKey(at, "setting"), `setting "${claim.setting}" is claimed twice for one kind`));
|
|
628
|
-
} else {
|
|
629
|
-
claimed.add(claim.setting);
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
626
|
}
|
|
633
627
|
function fieldListProblems(host, fields, path, topLevel, out) {
|
|
634
628
|
if (!Array.isArray(fields)) {
|
|
@@ -655,6 +649,9 @@ function fieldListProblems(host, fields, path, topLevel, out) {
|
|
|
655
649
|
if (field.editorOnly !== void 0 && !topLevel) {
|
|
656
650
|
out.push(err2("editor-only-nested", atKey(at, "editorOnly"), "only a target's own fields can be editor-only, not a record's"));
|
|
657
651
|
}
|
|
652
|
+
if (field.editor !== void 0 && !topLevel) {
|
|
653
|
+
out.push(err2("editor-nested", atKey(at, "editor"), "only a target's own fields open in a view, not a record's"));
|
|
654
|
+
}
|
|
658
655
|
for (const flag of ["required", "editorOnly"]) {
|
|
659
656
|
if (field[flag] !== void 0 && typeof field[flag] !== "boolean") {
|
|
660
657
|
out.push(err2("not-a-boolean", atKey(at, flag), `${flag} is true or false`));
|
|
@@ -662,7 +659,7 @@ function fieldListProblems(host, fields, path, topLevel, out) {
|
|
|
662
659
|
}
|
|
663
660
|
});
|
|
664
661
|
}
|
|
665
|
-
function typeProblems(host, decl, path, named, out
|
|
662
|
+
function typeProblems(host, decl, path, named, out) {
|
|
666
663
|
const typeAt = atKey(path, "type");
|
|
667
664
|
if (decl.type === "string") {
|
|
668
665
|
out.push(err2("string-type", typeAt, 'the text type is spelled "text"'));
|
|
@@ -678,7 +675,6 @@ function typeProblems(host, decl, path, named, out, claim = false) {
|
|
|
678
675
|
case "enum":
|
|
679
676
|
case "flags": {
|
|
680
677
|
const values = decl.values;
|
|
681
|
-
if (claim && values === void 0) break;
|
|
682
678
|
if (!Array.isArray(values) || values.length === 0) {
|
|
683
679
|
out.push(err2("values-empty", at("values"), `an ${decl.type === "enum" ? "enum" : "flags field"} lists its values`));
|
|
684
680
|
sound = false;
|
|
@@ -697,7 +693,6 @@ function typeProblems(host, decl, path, named, out, claim = false) {
|
|
|
697
693
|
break;
|
|
698
694
|
}
|
|
699
695
|
case "quality": {
|
|
700
|
-
if (claim && decl.stages === void 0) break;
|
|
701
696
|
for (const p of qualityDeclarationProblems(decl.stages)) {
|
|
702
697
|
out.push(err2(
|
|
703
698
|
`quality-${p.kind === "default-not-a-stage" ? "default" : p.kind}`,
|
|
@@ -760,11 +755,7 @@ function typeProblems(host, decl, path, named, out, claim = false) {
|
|
|
760
755
|
}
|
|
761
756
|
}
|
|
762
757
|
if (decl.renamedStages !== void 0) renamedStagesProblems(decl, at("renamedStages"), out);
|
|
763
|
-
if (decl.valueHelp !== void 0
|
|
764
|
-
if (!isObject(decl.valueHelp) || !["enum", "flags", "quality"].includes(decl.type)) {
|
|
765
|
-
out.push(err2("value-help", at("valueHelp"), "value help describes the values of an enum or flags field, or a quality's stages"));
|
|
766
|
-
}
|
|
767
|
-
} else if (decl.valueHelp !== void 0) {
|
|
758
|
+
if (decl.valueHelp !== void 0) {
|
|
768
759
|
const vocabulary = decl.type === "quality" ? decl.stages : decl.type === "enum" || decl.type === "flags" ? decl.values : decl.type === "pick" ? pickWords(decl.from) : void 0;
|
|
769
760
|
if (vocabulary === void 0 || !isObject(decl.valueHelp)) {
|
|
770
761
|
out.push(err2("value-help", at("valueHelp"), "value help describes the values of an enum or flags field, a quality's stages, or a pick's words"));
|
|
@@ -805,56 +796,10 @@ function renamedStagesProblems(decl, path, out) {
|
|
|
805
796
|
}
|
|
806
797
|
}
|
|
807
798
|
}
|
|
808
|
-
function settingValues(manifest, chosen) {
|
|
809
|
-
const out = {};
|
|
810
|
-
for (const s of manifest.settings ?? []) {
|
|
811
|
-
const v = chosen !== void 0 && own(chosen, s.name) ? chosen[s.name] : void 0;
|
|
812
|
-
out[s.name] = typeof v === "string" && v !== "" ? v : s.default;
|
|
813
|
-
}
|
|
814
|
-
return out;
|
|
815
|
-
}
|
|
816
|
-
function resolvedClaims(manifest, host, chosen) {
|
|
817
|
-
const settings = settingValues(manifest, chosen);
|
|
818
|
-
const out = [];
|
|
819
|
-
for (const [kind, target] of Object.entries(manifest.targets[host] ?? {})) {
|
|
820
|
-
for (const claim of target.claims ?? []) {
|
|
821
|
-
const field = settings[claim.setting];
|
|
822
|
-
if (field !== void 0) out.push({ extension: manifest.id, host, kind, field, claim });
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return out;
|
|
826
|
-
}
|
|
827
|
-
function claimClashes(claims) {
|
|
828
|
-
const out = [];
|
|
829
|
-
const first = /* @__PURE__ */ new Map();
|
|
830
|
-
for (const c of claims) {
|
|
831
|
-
const key = `${c.host}\0${c.kind}\0${c.field}`;
|
|
832
|
-
const prior = first.get(key);
|
|
833
|
-
if (prior === void 0) {
|
|
834
|
-
first.set(key, c);
|
|
835
|
-
continue;
|
|
836
|
-
}
|
|
837
|
-
if (prior.extension === c.extension) continue;
|
|
838
|
-
out.push(err2(
|
|
839
|
-
"claim-clash",
|
|
840
|
-
`${c.kind}.${c.field}`,
|
|
841
|
-
`extensions "${prior.extension}" and "${c.extension}" both claim the ${c.kind} field "${c.field}"`
|
|
842
|
-
));
|
|
843
|
-
}
|
|
844
|
-
return out;
|
|
845
|
-
}
|
|
846
799
|
function targetOf(manifest, host, kind) {
|
|
847
800
|
const kinds = manifest?.targets[host];
|
|
848
801
|
return kinds !== void 0 && own(kinds, kind) ? kinds[kind] : void 0;
|
|
849
802
|
}
|
|
850
|
-
function effectiveClaim(claim, hostDecl) {
|
|
851
|
-
return {
|
|
852
|
-
...claim,
|
|
853
|
-
...claim.values === void 0 && hostDecl.values !== void 0 ? { values: hostDecl.values } : {},
|
|
854
|
-
...claim.stages === void 0 && hostDecl.stages !== void 0 ? { stages: hostDecl.stages } : {},
|
|
855
|
-
...claim.default === void 0 && hostDecl.default !== void 0 ? { default: hostDecl.default } : {}
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
803
|
|
|
859
804
|
// src/extensions/merge.ts
|
|
860
805
|
var ATOMIC = { kind: "atomic" };
|
|
@@ -1193,6 +1138,6 @@ function orphanedEntries(data, exists) {
|
|
|
1193
1138
|
return out;
|
|
1194
1139
|
}
|
|
1195
1140
|
|
|
1196
|
-
export { ATOMIC, COMMENTS, HOSTS, MANIFEST_FILE_SUFFIX, MANIFEST_SCHEMA, SCALAR_TYPES, SET, UNRESOLVED_KEY, VALUE_TYPES, atIndex, atKey,
|
|
1141
|
+
export { ATOMIC, COMMENTS, HOSTS, MANIFEST_FILE_SUFFIX, MANIFEST_SCHEMA, SCALAR_TYPES, SET, UNRESOLVED_KEY, VALUE_TYPES, atIndex, atKey, compileEntry, compiledTarget, defaultOf, entryProblems, extensionDataStrategy, isTextList, isViewEntry, keyedBy, manifestProblems, mapOf, markUnresolved, mergeComments, mergeExtensionData, mergeTree, missingRequirements, objectOf, orphanedEntries, parseManifest, pickChoices, pickClashes, pickLists, renameStages, stableStringify, strategyForTarget, strategyForType, targetOf, unresolvedOf, unresolvedProblems, valueProblems, viewsFor, withoutMark };
|
|
1197
1142
|
//# sourceMappingURL=extensions.js.map
|
|
1198
1143
|
//# sourceMappingURL=extensions.js.map
|