@effected/schemastore 0.9.1 → 0.11.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/CanonicalJson.js +38 -3
- package/CatalogEntry.js +6 -2
- package/DocumentDiff.js +8 -20
- package/DocumentLint.js +47 -14
- package/README.md +10 -2
- package/SchemaPipeline.js +4 -2
- package/SchemaTarget.js +2 -1
- package/SchemaVersioning.js +41 -19
- package/SchemastoreConfig.js +183 -67
- package/StoreDocument.js +55 -3
- package/index.d.ts +276 -52
- package/index.js +2 -2
- package/package.json +1 -1
package/SchemastoreConfig.js
CHANGED
|
@@ -1,42 +1,147 @@
|
|
|
1
1
|
import { SchemaVersioning } from "./SchemaVersioning.js";
|
|
2
2
|
import { CatalogEntry } from "./CatalogEntry.js";
|
|
3
3
|
import { DriftPolicy } from "./DriftPolicy.js";
|
|
4
|
-
import {
|
|
4
|
+
import { SchemaTarget } from "./SchemaTarget.js";
|
|
5
|
+
import { Option, Predicate, Result, Schema } from "effect";
|
|
5
6
|
|
|
6
7
|
//#region src/SchemastoreConfig.ts
|
|
7
8
|
const ConfigBrand = Symbol.for("@effected/schemastore/SchemastoreConfig");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
path: Schema.String.check(Schema.isMinLength(1))
|
|
22
|
-
});
|
|
23
|
-
const decodeOrThrow = (schema, value, what) => {
|
|
24
|
-
const result = Schema.decodeUnknownResult(schema)(value);
|
|
25
|
-
if (result._tag === "Failure") throw new Error(`defineConfig: invalid ${what}: ${String(result.failure)}`);
|
|
26
|
-
return result.success;
|
|
9
|
+
/** The host SchemaStore-hosted documents declare in `$id`. @public */
|
|
10
|
+
const SCHEMASTORE_ID_BASE = "https://json.schemastore.org";
|
|
11
|
+
/** The host SchemaStore's `catalog.json` points `url` at. @public */
|
|
12
|
+
const SCHEMASTORE_CATALOG_BASE = "https://www.schemastore.org";
|
|
13
|
+
const DRIFT_TOLERANCES = [
|
|
14
|
+
"strict",
|
|
15
|
+
"semantic",
|
|
16
|
+
"allow"
|
|
17
|
+
];
|
|
18
|
+
const ON_DRIFT = ["error", "warn"];
|
|
19
|
+
const LAYOUTS = ["flat", "versioned"];
|
|
20
|
+
const fail = (message) => {
|
|
21
|
+
throw new Error(`defineConfig: ${message}`);
|
|
27
22
|
};
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
const trimSlashes = (dir) => {
|
|
24
|
+
let end = dir.length;
|
|
25
|
+
while (end > 1 && dir.charCodeAt(end - 1) === 47) end -= 1;
|
|
26
|
+
return dir.slice(0, end);
|
|
27
|
+
};
|
|
28
|
+
const resolveHosting = (name, baseUrl, layout) => {
|
|
29
|
+
if (baseUrl === void 0) return fail(`schema "${name}" has no baseUrl and the config declares no default`);
|
|
30
|
+
if (typeof baseUrl !== "string") return fail(`schema "${name}" has a baseUrl that is not a string`);
|
|
31
|
+
if (baseUrl.length === 0) return fail(`schema "${name}" has no baseUrl and the config declares no default`);
|
|
32
|
+
if (layout !== void 0 && !LAYOUTS.includes(layout)) return fail(`schema "${name}" has an invalid layout "${String(layout)}"; expected "flat" or "versioned"`);
|
|
33
|
+
if (baseUrl === "schemastore") {
|
|
34
|
+
if (layout !== void 0) return fail(`schema "${name}" declares layout "${layout}" under baseUrl "schemastore", which serves only the flat layout`);
|
|
35
|
+
return {
|
|
36
|
+
idBase: SCHEMASTORE_ID_BASE,
|
|
37
|
+
catalogBase: SCHEMASTORE_CATALOG_BASE,
|
|
38
|
+
layout: "flat"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (!baseUrl.startsWith("https://") || baseUrl.length === 8) return fail(`schema "${name}" has baseUrl "${baseUrl}"; expected "schemastore" or an https:// URL`);
|
|
42
|
+
return {
|
|
43
|
+
idBase: baseUrl,
|
|
44
|
+
catalogBase: baseUrl,
|
|
45
|
+
layout: layout ?? "versioned"
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
const parseLabel = (name, label) => {
|
|
49
|
+
if (typeof label !== "string") return fail(`schema "${name}" has a version label that is not a string: ${String(label)}`);
|
|
50
|
+
return Result.getOrThrowWith(SchemaVersioning.parseResult(label), (error) => /* @__PURE__ */ new Error(`defineConfig: schema "${name}" has an invalid version label "${label}": ${error.message}`));
|
|
51
|
+
};
|
|
52
|
+
const resolveVersions = (name, entry) => {
|
|
53
|
+
if (entry.versions === void 0) {
|
|
54
|
+
if (entry.current !== void 0) return fail(`schema "${name}" declares current "${entry.current}" without versions`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!Array.isArray(entry.versions)) return fail(`schema "${name}" declares versions that is not an array`);
|
|
58
|
+
if (entry.versions.length === 0) return fail(`schema "${name}" declares versions as an empty array; omit versions for an unversioned schema`);
|
|
59
|
+
const versions = [];
|
|
60
|
+
for (const label of entry.versions) {
|
|
61
|
+
const version = parseLabel(name, label);
|
|
34
62
|
const duplicate = versions.find((v) => SchemaVersioning.Order(v, version) === 0);
|
|
35
|
-
if (duplicate !== void 0)
|
|
63
|
+
if (duplicate !== void 0) return fail(`schema "${name}" declares the same version twice, as "${duplicate}" and "${version}"`);
|
|
36
64
|
versions.push(version);
|
|
37
|
-
map.set(target.name, versions);
|
|
38
65
|
}
|
|
39
|
-
|
|
66
|
+
const newest = Option.getOrThrow(SchemaVersioning.latest(versions));
|
|
67
|
+
if (entry.current === void 0) return {
|
|
68
|
+
versions,
|
|
69
|
+
current: newest
|
|
70
|
+
};
|
|
71
|
+
const current = parseLabel(name, entry.current);
|
|
72
|
+
const match = versions.find((v) => SchemaVersioning.Order(v, current) === 0);
|
|
73
|
+
if (match === void 0) return fail(`schema "${name}" declares current "${entry.current}" which is not one of its versions`);
|
|
74
|
+
return {
|
|
75
|
+
versions,
|
|
76
|
+
current: match
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
const isDriftTolerance = (value) => DRIFT_TOLERANCES.includes(value);
|
|
80
|
+
const resolveConfigDrift = (value) => {
|
|
81
|
+
if (value === void 0) return DriftPolicy.defaults.policy;
|
|
82
|
+
return isDriftTolerance(value) ? value : fail(`config has an invalid drift tolerance "${String(value)}"`);
|
|
83
|
+
};
|
|
84
|
+
const resolveSchemaDrift = (name, value, fallback) => {
|
|
85
|
+
if (value === void 0) return fallback;
|
|
86
|
+
return isDriftTolerance(value) ? value : fail(`schema "${name}" has an invalid drift tolerance "${String(value)}"`);
|
|
87
|
+
};
|
|
88
|
+
const resolveEntry = (name, entry, defaults, outputDir) => {
|
|
89
|
+
if (!SchemaVersioning.isSimpleName(name)) return fail(`schema "${name}" must be keyed by a simple file base name (no separators, no whitespace)`);
|
|
90
|
+
if (!Predicate.isObject(entry)) return fail(`schema "${name}" must be an object`);
|
|
91
|
+
if (!Schema.isSchema(entry.schema)) return fail(`schema "${name}" has a schema that is not an Effect Schema`);
|
|
92
|
+
if (entry.published !== void 0 && typeof entry.published !== "boolean") return fail(`schema "${name}" has a published that is not a boolean`);
|
|
93
|
+
const baseUrl = entry.baseUrl ?? defaults.baseUrl;
|
|
94
|
+
const hosting = resolveHosting(name, baseUrl, entry.layout);
|
|
95
|
+
const versioned = resolveVersions(name, entry);
|
|
96
|
+
if (baseUrl === "schemastore" && entry.catalog === void 0) return fail(`schema "${name}" must declare a catalog block under baseUrl "schemastore"`);
|
|
97
|
+
if (entry.catalog !== void 0 && (!Predicate.isObject(entry.catalog) || !Array.isArray(entry.catalog.fileMatch) || typeof entry.catalog.description !== "string")) return fail(`schema "${name}" declares an invalid catalog block (expected { description, fileMatch[] })`);
|
|
98
|
+
if (entry.catalog !== void 0 && entry.catalog.fileMatch.length === 0) return fail(`schema "${name}" declares a catalog with an empty fileMatch`);
|
|
99
|
+
const file = (version) => `${outputDir}/${SchemaVersioning.fileName(name, version, hosting.layout)}`;
|
|
100
|
+
const urlOf = (base) => (version) => SchemaVersioning.schemaUrl(base, name, version, hosting.layout);
|
|
101
|
+
const idOf = urlOf(hosting.idBase);
|
|
102
|
+
const catalogUrlOf = urlOf(hosting.catalogBase);
|
|
103
|
+
const current = versioned?.current;
|
|
104
|
+
const target = current === void 0 ? SchemaTarget.make({
|
|
105
|
+
schema: entry.schema,
|
|
106
|
+
$id: idOf(current),
|
|
107
|
+
name,
|
|
108
|
+
path: file(current),
|
|
109
|
+
published: entry.published ?? false,
|
|
110
|
+
...entry.jsonSchema !== void 0 ? { jsonSchema: entry.jsonSchema } : {},
|
|
111
|
+
...entry.rootAnnotations !== void 0 ? { rootAnnotations: entry.rootAnnotations } : {}
|
|
112
|
+
}) : SchemaTarget.make({
|
|
113
|
+
schema: entry.schema,
|
|
114
|
+
$id: idOf(current),
|
|
115
|
+
name,
|
|
116
|
+
path: file(current),
|
|
117
|
+
version: current,
|
|
118
|
+
published: entry.published ?? false,
|
|
119
|
+
...entry.jsonSchema !== void 0 ? { jsonSchema: entry.jsonSchema } : {},
|
|
120
|
+
...entry.rootAnnotations !== void 0 ? { rootAnnotations: entry.rootAnnotations } : {}
|
|
121
|
+
});
|
|
122
|
+
const frozen = versioned === void 0 ? [] : versioned.versions.filter((v) => v !== versioned.current).map((version) => ({
|
|
123
|
+
version,
|
|
124
|
+
path: file(version),
|
|
125
|
+
url: catalogUrlOf(version)
|
|
126
|
+
}));
|
|
127
|
+
const catalog = entry.catalog === void 0 ? void 0 : CatalogEntry.assemble({
|
|
128
|
+
name,
|
|
129
|
+
description: entry.catalog.description,
|
|
130
|
+
fileMatch: entry.catalog.fileMatch,
|
|
131
|
+
baseUrl: hosting.catalogBase,
|
|
132
|
+
layout: hosting.layout,
|
|
133
|
+
...versioned !== void 0 ? {
|
|
134
|
+
versions: versioned.versions,
|
|
135
|
+
current: versioned.current
|
|
136
|
+
} : {}
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
name,
|
|
140
|
+
target,
|
|
141
|
+
frozen,
|
|
142
|
+
drift: resolveSchemaDrift(name, entry.drift, defaults.drift),
|
|
143
|
+
...catalog !== void 0 ? { catalog } : {}
|
|
144
|
+
};
|
|
40
145
|
};
|
|
41
146
|
const normalizePath = (raw) => {
|
|
42
147
|
const absolute = raw.startsWith("/");
|
|
@@ -52,11 +157,11 @@ const normalizePath = (raw) => {
|
|
|
52
157
|
}
|
|
53
158
|
return `${absolute ? "/" : ""}${out.join("/")}`;
|
|
54
159
|
};
|
|
55
|
-
const assertUniquePaths = (
|
|
160
|
+
const assertUniquePaths = (paths) => {
|
|
56
161
|
const seen = /* @__PURE__ */ new Set();
|
|
57
|
-
for (const p of
|
|
162
|
+
for (const p of paths) {
|
|
58
163
|
const normalized = normalizePath(p);
|
|
59
|
-
if (seen.has(normalized))
|
|
164
|
+
if (seen.has(normalized)) fail(`output path "${p}" is declared twice`);
|
|
60
165
|
seen.add(normalized);
|
|
61
166
|
}
|
|
62
167
|
};
|
|
@@ -64,46 +169,57 @@ const assertUniquePaths = (schemas, catalog) => {
|
|
|
64
169
|
* Validate and assemble a `schemastore.config.ts` value.
|
|
65
170
|
*
|
|
66
171
|
* @remarks
|
|
67
|
-
* Pure: no IO, no Effect.
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
172
|
+
* Pure: no IO, no Effect. `$id`, the write `path` and every catalog URL are
|
|
173
|
+
* derived from ONE layout (`outputDir`, `baseUrl` and `layout`) so they
|
|
174
|
+
* cannot disagree with each other. `versions` names every label a schema
|
|
175
|
+
* advertises; `current` (default: the newest under
|
|
176
|
+
* {@link SchemaVersioning.Order}) is the one generated at `target`, and every
|
|
177
|
+
* other label becomes a {@link FrozenVersion} the CLI verifies but does not
|
|
178
|
+
* regenerate. `baseUrl: "schemastore"` expands to
|
|
179
|
+
* {@link SCHEMASTORE_ID_BASE} for `$id` and {@link SCHEMASTORE_CATALOG_BASE}
|
|
180
|
+
* for the catalog URL, forcing the `"flat"` layout; any other `baseUrl` is
|
|
181
|
+
* used as one base for both, defaulting to the `"versioned"` layout.
|
|
182
|
+
*
|
|
183
|
+
* Throws a plain `Error` (never a raw `TypeError`) naming the offending
|
|
184
|
+
* schema on: a non-object `input`; an empty `schemas` record; a
|
|
185
|
+
* missing/empty `outputDir`; a schema key that is not a simple file base
|
|
186
|
+
* name; a schema whose `schema` is not an Effect Schema; a schema with no
|
|
187
|
+
* `baseUrl` anywhere, or a `baseUrl` that is not a string; a `baseUrl` that
|
|
188
|
+
* is neither `"schemastore"` nor an `https://` URL; a `versions` that is not
|
|
189
|
+
* an array, or an empty `versions` array; a version label (or `current`)
|
|
190
|
+
* that is not a string, or an otherwise invalid version label; two labels
|
|
191
|
+
* spelling the same version; `current` given without `versions`, or naming
|
|
192
|
+
* one not among them; a non-boolean `published`; `layout` declared under
|
|
193
|
+
* `baseUrl: "schemastore"`; a missing `catalog` under
|
|
194
|
+
* `baseUrl: "schemastore"`, or one with an empty `fileMatch`; an invalid
|
|
195
|
+
* `drift` or top-level `onDrift`; and an output path (a target, a frozen
|
|
196
|
+
* file, or the catalog path) declared twice, compared after a lexical
|
|
197
|
+
* normalisation (`./`, `..`, trailing `/`) — the CLI's loader re-checks on
|
|
198
|
+
* the resolved absolute paths. Branding the result lets a loader recognise a
|
|
199
|
+
* config module's default export via {@link isSchemastoreConfig}.
|
|
76
200
|
*
|
|
77
201
|
* @public
|
|
78
202
|
*/
|
|
79
203
|
const defineConfig = (input) => {
|
|
80
|
-
if (!
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
baseUrl: config.baseUrl,
|
|
94
|
-
versions: found
|
|
95
|
-
})
|
|
96
|
-
};
|
|
97
|
-
});
|
|
98
|
-
assertUniquePaths(input.schemas, catalog.map((c) => c.config));
|
|
204
|
+
if (!Predicate.isObject(input)) return fail("expected a config object");
|
|
205
|
+
if (typeof input.outputDir !== "string" || input.outputDir.length === 0) return fail("outputDir is required");
|
|
206
|
+
const outputDir = trimSlashes(input.outputDir);
|
|
207
|
+
if (!Predicate.isObject(input.schemas) || Object.keys(input.schemas).length === 0) return fail("at least one schema is required");
|
|
208
|
+
if (input.onDrift !== void 0 && !ON_DRIFT.includes(input.onDrift)) return fail(`invalid onDrift "${String(input.onDrift)}"`);
|
|
209
|
+
if (input.catalogPath !== void 0 && (typeof input.catalogPath !== "string" || input.catalogPath.length === 0)) return fail("catalogPath must be a non-empty string when given");
|
|
210
|
+
const defaults = {
|
|
211
|
+
baseUrl: input.baseUrl,
|
|
212
|
+
drift: resolveConfigDrift(input.drift)
|
|
213
|
+
};
|
|
214
|
+
const schemas = Object.entries(input.schemas).map(([name, entry]) => resolveEntry(name, entry, defaults, outputDir));
|
|
215
|
+
const catalogPath = input.catalogPath ?? `${outputDir}/catalog.json`;
|
|
216
|
+
assertUniquePaths([...schemas.flatMap((s) => [s.target.path, ...s.frozen.map((f) => f.path)]), catalogPath]);
|
|
99
217
|
return {
|
|
100
218
|
[ConfigBrand]: true,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
onDrift: drift.onDrift ?? DriftPolicy.defaults.onDrift
|
|
106
|
-
}
|
|
219
|
+
outputDir,
|
|
220
|
+
onDrift: input.onDrift ?? DriftPolicy.defaults.onDrift,
|
|
221
|
+
catalogPath,
|
|
222
|
+
schemas
|
|
107
223
|
};
|
|
108
224
|
};
|
|
109
225
|
/**
|
|
@@ -115,4 +231,4 @@ const defineConfig = (input) => {
|
|
|
115
231
|
const isSchemastoreConfig = (value) => typeof value === "object" && value !== null && value[ConfigBrand] === true;
|
|
116
232
|
|
|
117
233
|
//#endregion
|
|
118
|
-
export { defineConfig, isSchemastoreConfig };
|
|
234
|
+
export { SCHEMASTORE_CATALOG_BASE, SCHEMASTORE_ID_BASE, defineConfig, isSchemastoreConfig };
|
package/StoreDocument.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CanonicalJson } from "./CanonicalJson.js";
|
|
2
2
|
import { KeywordFamilies } from "./KeywordFamilies.js";
|
|
3
|
-
import { Effect, JsonSchema, Result, Schema } from "effect";
|
|
3
|
+
import { Effect, JsonPointer, JsonSchema, Result, Schema } from "effect";
|
|
4
4
|
|
|
5
5
|
//#region src/StoreDocument.ts
|
|
6
6
|
/**
|
|
@@ -36,7 +36,10 @@ var SchemaConversionError = class extends Schema.TaggedError()("SchemaConversion
|
|
|
36
36
|
/**
|
|
37
37
|
* Indicates that a caller-supplied `includeAnnotationKey` admitted an
|
|
38
38
|
* annotation key outside the declared keyword families
|
|
39
|
-
* ({@link KeywordFamilies})
|
|
39
|
+
* ({@link KeywordFamilies}), or that a
|
|
40
|
+
* {@link StoreDocumentOptions.rootAnnotations} override names a key outside
|
|
41
|
+
* the admitted set (the standard annotation keywords plus the declared
|
|
42
|
+
* families).
|
|
40
43
|
*
|
|
41
44
|
* Raised by {@link StoreDocument.fromSchema}. This package emits
|
|
42
45
|
* SchemaStore-compatible documents only, so the declared families are the
|
|
@@ -47,7 +50,8 @@ var SchemaConversionError = class extends Schema.TaggedError()("SchemaConversion
|
|
|
47
50
|
*
|
|
48
51
|
* The predicate itself cannot be introspected, so the offending keys are
|
|
49
52
|
* the ones it actually admitted while the document was being generated: a
|
|
50
|
-
* key the source schema never annotates cannot appear here.
|
|
53
|
+
* key the source schema never annotates cannot appear here. Override keys,
|
|
54
|
+
* by contrast, are checked up front, before anything is generated.
|
|
51
55
|
*
|
|
52
56
|
* @public
|
|
53
57
|
*/
|
|
@@ -63,6 +67,48 @@ var UndeclaredAnnotationKeyError = class extends Schema.TaggedError()("Undeclare
|
|
|
63
67
|
}
|
|
64
68
|
};
|
|
65
69
|
const DEFINITIONS_REF_PREFIX = /^#\/definitions(?=\/|$)/;
|
|
70
|
+
const STANDARD_ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
71
|
+
"title",
|
|
72
|
+
"description",
|
|
73
|
+
"$comment",
|
|
74
|
+
"default",
|
|
75
|
+
"examples",
|
|
76
|
+
"readOnly",
|
|
77
|
+
"writeOnly",
|
|
78
|
+
"contentMediaType",
|
|
79
|
+
"contentEncoding"
|
|
80
|
+
]);
|
|
81
|
+
const countRefs = (node, ref) => {
|
|
82
|
+
if (Array.isArray(node)) {
|
|
83
|
+
let count = 0;
|
|
84
|
+
for (const item of node) count += countRefs(item, ref);
|
|
85
|
+
return count;
|
|
86
|
+
}
|
|
87
|
+
if (typeof node === "object" && node !== null) {
|
|
88
|
+
let count = 0;
|
|
89
|
+
for (const [key, value] of Object.entries(node)) {
|
|
90
|
+
if (KeywordFamilies.isDeclared(key)) continue;
|
|
91
|
+
count += key === "$ref" && value === ref ? 1 : countRefs(value, ref);
|
|
92
|
+
}
|
|
93
|
+
return count;
|
|
94
|
+
}
|
|
95
|
+
return 0;
|
|
96
|
+
};
|
|
97
|
+
const applyRootAnnotations = (root, defs, annotations) => {
|
|
98
|
+
const keys = Object.keys(root);
|
|
99
|
+
const ref = keys.length === 1 && keys[0] === "$ref" ? root.$ref : void 0;
|
|
100
|
+
const path = typeof ref === "string" ? JsonPointer.parseUriFragment(ref) : void 0;
|
|
101
|
+
const pool = path !== void 0 && path.length === 2 && path[0] === "$defs" ? defs[path[1]] : void 0;
|
|
102
|
+
const entry = typeof pool === "object" && pool !== null && !Array.isArray(pool) ? pool : void 0;
|
|
103
|
+
const shared = entry !== void 0 && typeof ref === "string" && countRefs(defs, ref) > 0;
|
|
104
|
+
if (shared) delete root.$ref;
|
|
105
|
+
const target = entry !== void 0 && !shared ? entry : root;
|
|
106
|
+
for (const [key, value] of Object.entries(annotations)) {
|
|
107
|
+
if (value === void 0) continue;
|
|
108
|
+
target[key] = value;
|
|
109
|
+
}
|
|
110
|
+
if (shared) root.allOf = [{ $ref: ref }];
|
|
111
|
+
};
|
|
66
112
|
var RewriteDepthExceeded = class {
|
|
67
113
|
_tag = "RewriteDepthExceeded";
|
|
68
114
|
};
|
|
@@ -153,6 +199,11 @@ var StoreDocument = class StoreDocument extends Schema.Class("StoreDocument")({
|
|
|
153
199
|
*/
|
|
154
200
|
static fromSchemaResult(source, options) {
|
|
155
201
|
try {
|
|
202
|
+
const refusedOverrides = Object.keys(options.rootAnnotations ?? {}).filter((key) => !STANDARD_ANNOTATION_KEYWORDS.has(key) && !KeywordFamilies.isDeclared(key));
|
|
203
|
+
if (refusedOverrides.length > 0) return Result.fail(UndeclaredAnnotationKeyError.make({
|
|
204
|
+
$id: options.$id,
|
|
205
|
+
keys: [...refusedOverrides].sort()
|
|
206
|
+
}));
|
|
156
207
|
const userIncludes = options.jsonSchema?.includeAnnotationKey;
|
|
157
208
|
const undeclared = /* @__PURE__ */ new Set();
|
|
158
209
|
const document = Schema.toJsonSchemaDocument(source, {
|
|
@@ -171,6 +222,7 @@ var StoreDocument = class StoreDocument extends Schema.Class("StoreDocument")({
|
|
|
171
222
|
const root = restoreDefsRefs(lowered.schema, 0);
|
|
172
223
|
const defs = Object.create(null);
|
|
173
224
|
for (const [name, definition] of Object.entries(lowered.definitions)) defs[name] = restoreDefsRefs(definition, 1);
|
|
225
|
+
if (options.rootAnnotations !== void 0) applyRootAnnotations(root, defs, options.rootAnnotations);
|
|
174
226
|
return Result.succeed(StoreDocument.make({
|
|
175
227
|
$schema: DRAFT_07_META_SCHEMA,
|
|
176
228
|
$id: options.$id,
|