effect 4.0.0-rc.113 → 4.0.0-rc.115
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/dist/Effect.d.ts +268 -7
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +33 -2
- package/dist/Effect.js.map +1 -1
- package/dist/Effectable.d.ts +1 -2
- package/dist/Effectable.d.ts.map +1 -1
- package/dist/Effectable.js.map +1 -1
- package/dist/FileSystem.d.ts +3 -4
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/Match.d.ts +1 -14
- package/dist/Match.d.ts.map +1 -1
- package/dist/Schema.d.ts +4 -4
- package/dist/Schema.d.ts.map +1 -1
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +43 -23
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaParser.d.ts.map +1 -1
- package/dist/SchemaParser.js +3 -2
- package/dist/SchemaParser.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +39 -24
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +37 -23
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/internal/arbitrary/schema.js.map +1 -1
- package/dist/internal/effect.js +16 -8
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +221 -230
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/make.js +8 -3
- package/dist/internal/schema/make.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +4 -4
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toEquivalence.js +2 -2
- package/dist/internal/schema/toEquivalence.js.map +1 -1
- package/dist/internal/schema/toFormatter.js +2 -2
- package/dist/internal/schema/toFormatter.js.map +1 -1
- package/dist/unstable/cli/Prompt.d.ts +6 -2
- package/dist/unstable/cli/Prompt.d.ts.map +1 -1
- package/dist/unstable/cli/Prompt.js +8 -7
- package/dist/unstable/cli/Prompt.js.map +1 -1
- package/dist/unstable/cli/internal/command.d.ts +1 -6
- package/dist/unstable/cli/internal/command.d.ts.map +1 -1
- package/dist/unstable/cli/internal/command.js +2 -0
- package/dist/unstable/cli/internal/command.js.map +1 -1
- package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
- package/dist/unstable/http/HttpEffect.js +6 -2
- package/dist/unstable/http/HttpEffect.js.map +1 -1
- package/dist/unstable/http/HttpServerResponse.d.ts +13 -2
- package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerResponse.js +19 -5
- package/dist/unstable/http/HttpServerResponse.js.map +1 -1
- package/dist/unstable/persistence/Persistence.d.ts.map +1 -1
- package/dist/unstable/persistence/Persistence.js +2 -10
- package/dist/unstable/persistence/Persistence.js.map +1 -1
- package/package.json +2 -2
- package/src/Effect.ts +271 -7
- package/src/Effectable.ts +2 -2
- package/src/FileSystem.ts +3 -4
- package/src/Match.ts +1 -1
- package/src/Schema.ts +4 -7
- package/src/SchemaAST.ts +48 -25
- package/src/SchemaParser.ts +3 -2
- package/src/SchemaRepresentation.ts +39 -24
- package/src/internal/arbitrary/schema.ts +16 -16
- package/src/internal/effect.ts +34 -11
- package/src/internal/schema/fromJsonSchemaDocument.ts +294 -268
- package/src/internal/schema/make.ts +9 -4
- package/src/internal/schema/toCodeDocument.ts +4 -4
- package/src/internal/schema/toEquivalence.ts +2 -2
- package/src/internal/schema/toFormatter.ts +2 -2
- package/src/unstable/cli/Prompt.ts +22 -11
- package/src/unstable/cli/internal/command.ts +2 -0
- package/src/unstable/http/HttpEffect.ts +5 -2
- package/src/unstable/http/HttpServerResponse.ts +21 -5
- package/src/unstable/persistence/Persistence.ts +6 -16
|
@@ -16,16 +16,23 @@ const string = {
|
|
|
16
16
|
_tag: "String",
|
|
17
17
|
checks: []
|
|
18
18
|
};
|
|
19
|
-
|
|
19
|
+
const unsupportedStructuredValue = "Only primitive values are supported in \"const\" and \"enum\".";
|
|
20
|
+
function isObject(input) {
|
|
21
|
+
return typeof input === "object" && input !== null && !Array.isArray(input);
|
|
22
|
+
}
|
|
23
|
+
function makeJsonLiteral(input, path) {
|
|
20
24
|
if (input === null) return {
|
|
21
25
|
_tag: "Null",
|
|
22
26
|
checks: []
|
|
23
27
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") {
|
|
29
|
+
return {
|
|
30
|
+
_tag: "Literal",
|
|
31
|
+
literal: input,
|
|
32
|
+
checks: []
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (typeof input === "object") throw errorWithPath(unsupportedStructuredValue, path);
|
|
29
36
|
}
|
|
30
37
|
const jsonSchemaValueTypes = ["null", "string", "number", "boolean", "object", "array"];
|
|
31
38
|
const jsonSchemaTypeSpecificKeys = ["minLength", "maxLength", "pattern", "minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf", "properties", "required", "additionalProperties", "patternProperties", "propertyNames", "minProperties", "maxProperties", "items", "prefixItems", "minItems", "maxItems", "uniqueItems"];
|
|
@@ -84,66 +91,77 @@ function jsonDeclaration(annotations) {
|
|
|
84
91
|
typeParameters: []
|
|
85
92
|
};
|
|
86
93
|
}
|
|
87
|
-
function unknownJsonSchemas(representation) {
|
|
88
|
-
switch (representation._tag) {
|
|
89
|
-
case "Unknown":
|
|
90
|
-
return jsonDeclaration(representation.annotations);
|
|
91
|
-
case "Suspend":
|
|
92
|
-
return {
|
|
93
|
-
...representation,
|
|
94
|
-
thunk: unknownJsonSchemas(representation.thunk)
|
|
95
|
-
};
|
|
96
|
-
case "Arrays":
|
|
97
|
-
return {
|
|
98
|
-
...representation,
|
|
99
|
-
elements: representation.elements.map(element => ({
|
|
100
|
-
...element,
|
|
101
|
-
type: unknownJsonSchemas(element.type)
|
|
102
|
-
})),
|
|
103
|
-
rest: representation.rest.map(unknownJsonSchemas)
|
|
104
|
-
};
|
|
105
|
-
case "Objects":
|
|
106
|
-
return {
|
|
107
|
-
...representation,
|
|
108
|
-
propertySignatures: representation.propertySignatures.map(property => ({
|
|
109
|
-
...property,
|
|
110
|
-
type: unknownJsonSchemas(property.type)
|
|
111
|
-
})),
|
|
112
|
-
indexSignatures: representation.indexSignatures.map(indexSignature => ({
|
|
113
|
-
parameter: unknownJsonSchemas(indexSignature.parameter),
|
|
114
|
-
type: unknownJsonSchemas(indexSignature.type)
|
|
115
|
-
})),
|
|
116
|
-
checks: representation.checks.map(unknownJsonSchemaCheck)
|
|
117
|
-
};
|
|
118
|
-
case "Union":
|
|
119
|
-
return {
|
|
120
|
-
...representation,
|
|
121
|
-
types: representation.types.map(unknownJsonSchemas)
|
|
122
|
-
};
|
|
123
|
-
default:
|
|
124
|
-
return representation;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function unknownJsonSchemaCheck(check) {
|
|
128
|
-
const representation = check.representation;
|
|
129
|
-
const schemas = representation?.schemas;
|
|
130
|
-
if (representation === undefined || schemas === undefined) {
|
|
131
|
-
return check;
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
...check,
|
|
135
|
-
representation: {
|
|
136
|
-
...representation,
|
|
137
|
-
schemas: schemas.map(unknownJsonSchemas)
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
94
|
function translateJsonSchemaMultiDocument(document, options, singleRoot = false) {
|
|
142
95
|
const definitionCache = new Map();
|
|
143
96
|
const reachableDefinitions = new Map();
|
|
144
97
|
const objectScopesByProperties = new WeakMap();
|
|
145
98
|
const annotatedReferences = [];
|
|
146
99
|
const resolvingChoices = new Set();
|
|
100
|
+
const finalReferences = new Set();
|
|
101
|
+
let inNestedResource = false;
|
|
102
|
+
function finalize(representation) {
|
|
103
|
+
switch (representation._tag) {
|
|
104
|
+
case "Unknown":
|
|
105
|
+
return jsonDeclaration(representation.annotations);
|
|
106
|
+
case "Reference":
|
|
107
|
+
finalReferences.add(representation.$ref);
|
|
108
|
+
return representation;
|
|
109
|
+
case "Suspend":
|
|
110
|
+
return {
|
|
111
|
+
...representation,
|
|
112
|
+
thunk: finalize(representation.thunk)
|
|
113
|
+
};
|
|
114
|
+
case "Arrays":
|
|
115
|
+
return {
|
|
116
|
+
...representation,
|
|
117
|
+
elements: representation.elements.map(element => ({
|
|
118
|
+
...element,
|
|
119
|
+
type: finalize(element.type)
|
|
120
|
+
})),
|
|
121
|
+
rest: representation.rest.map(finalize)
|
|
122
|
+
};
|
|
123
|
+
case "Objects":
|
|
124
|
+
// Intersections may reduce open patterns to fixed properties, so reject only
|
|
125
|
+
// if an open pattern remains in the final representation.
|
|
126
|
+
const [scopes, path] = objectScopesByProperties.get(representation.propertySignatures);
|
|
127
|
+
if (representation.indexSignatures[0]?.parameter === string && scopes.some(scope => scope.patterns.length > 0)) {
|
|
128
|
+
throw errorWithPath("Cannot import open \"patternProperties\": unmatched keys cannot be typed correctly.", path);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
...representation,
|
|
132
|
+
propertySignatures: representation.propertySignatures.map(property => ({
|
|
133
|
+
...property,
|
|
134
|
+
type: finalize(property.type)
|
|
135
|
+
})),
|
|
136
|
+
indexSignatures: representation.indexSignatures.map(indexSignature => ({
|
|
137
|
+
parameter: finalize(indexSignature.parameter),
|
|
138
|
+
type: finalize(indexSignature.type)
|
|
139
|
+
})),
|
|
140
|
+
checks: representation.checks.map(finalizeCheck)
|
|
141
|
+
};
|
|
142
|
+
case "Union":
|
|
143
|
+
return {
|
|
144
|
+
...representation,
|
|
145
|
+
types: representation.types.map(finalize)
|
|
146
|
+
};
|
|
147
|
+
default:
|
|
148
|
+
return representation;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function finalizeCheck(check) {
|
|
152
|
+
const representation = check.representation;
|
|
153
|
+
const schemas = representation?.schemas;
|
|
154
|
+
if (representation === undefined || schemas === undefined) {
|
|
155
|
+
return check;
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
...check,
|
|
159
|
+
representation: {
|
|
160
|
+
...representation,
|
|
161
|
+
schemas: schemas.map(finalize)
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
147
165
|
function annotate(representation, annotations) {
|
|
148
166
|
if (annotations === undefined) return representation;
|
|
149
167
|
if (representation._tag === "Reference") {
|
|
@@ -166,29 +184,26 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
166
184
|
const cached = definitionCache.get(key);
|
|
167
185
|
if (cached !== undefined) {
|
|
168
186
|
if (cached === null) {
|
|
169
|
-
throw errorWithPath(recursiveReferenceError ?? `
|
|
187
|
+
throw errorWithPath(recursiveReferenceError ?? `Definition ${JSON.stringify(key)} is a circular alias.`, [...path, "$ref"]);
|
|
170
188
|
}
|
|
171
189
|
return cached;
|
|
172
190
|
}
|
|
173
|
-
if (!Object.hasOwn(document.definitions, key)) {
|
|
174
|
-
throw errorWithPath(`Invalid reference ${key}`, [...path, "$ref"]);
|
|
175
|
-
}
|
|
176
191
|
definitionCache.set(key, null);
|
|
177
|
-
const representation =
|
|
192
|
+
const representation = translateSchema(document.definitions[key], ["definitions", key]);
|
|
178
193
|
definitionCache.set(key, representation);
|
|
179
194
|
return representation;
|
|
180
195
|
}
|
|
181
|
-
function resolveReference(reference, path,
|
|
196
|
+
function resolveReference(reference, path, recursiveReferenceError, seen = new Set()) {
|
|
182
197
|
if (seen.has(reference.$ref)) {
|
|
183
|
-
throw errorWithPath(`
|
|
198
|
+
throw errorWithPath(`Definition ${JSON.stringify(reference.$ref)} is a circular alias.`, [...path, "$ref"]);
|
|
184
199
|
}
|
|
185
200
|
seen.add(reference.$ref);
|
|
186
|
-
const representation = translateDefinition(reference.$ref, path,
|
|
201
|
+
const representation = translateDefinition(reference.$ref, path, recursiveReferenceError);
|
|
187
202
|
if (representation._tag === "Reference") {
|
|
188
|
-
return resolveReference(representation, path,
|
|
203
|
+
return resolveReference(representation, path, recursiveReferenceError, seen);
|
|
189
204
|
}
|
|
190
205
|
if (representation._tag === "Suspend" && representation.thunk._tag === "Reference") {
|
|
191
|
-
return annotate(resolveReference(representation.thunk, path,
|
|
206
|
+
return annotate(resolveReference(representation.thunk, path, recursiveReferenceError, seen), representation.annotations);
|
|
192
207
|
}
|
|
193
208
|
return representation;
|
|
194
209
|
}
|
|
@@ -200,35 +215,31 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
200
215
|
...right
|
|
201
216
|
};
|
|
202
217
|
}
|
|
203
|
-
function
|
|
218
|
+
function annotateIntersection(representation, left, right) {
|
|
204
219
|
return annotate(representation, mergeAnnotations(left._tag === "Reference" ? undefined : left.annotations, right._tag === "Reference" ? undefined : right.annotations));
|
|
205
220
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
208
|
-
if (annotations === undefined) return checks;
|
|
209
|
-
if (checks.length === 1 && checks[0].annotations === undefined) {
|
|
210
|
-
return [{
|
|
211
|
-
...checks[0],
|
|
212
|
-
annotations
|
|
213
|
-
}];
|
|
214
|
-
}
|
|
215
|
-
return [{
|
|
216
|
-
_tag: "FilterGroup",
|
|
217
|
-
checks: checks,
|
|
218
|
-
annotations
|
|
219
|
-
}];
|
|
220
|
-
}
|
|
221
|
-
function combineChecks(left, right, annotations, deduplicate = []) {
|
|
221
|
+
function intersectChecks(left, right, deduplicate = []) {
|
|
222
|
+
let checks = right.checks;
|
|
222
223
|
for (const id of deduplicate) {
|
|
223
|
-
if (left.some(check =>
|
|
224
|
-
|
|
224
|
+
if (left.checks.some(check => check._tag === "Filter" && check.representation?.id === id)) {
|
|
225
|
+
checks = checks.filter(check => check._tag !== "Filter" || check.representation?.id !== id);
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
if (checks.length === 0) {
|
|
229
|
+
const annotations = mergeAnnotations(left.annotations, right.annotations);
|
|
230
|
+
return [left.checks, annotations];
|
|
231
|
+
}
|
|
232
|
+
if (right.annotations !== undefined) {
|
|
233
|
+
checks = checks.length === 1 && checks[0].annotations === undefined ? [{
|
|
234
|
+
...checks[0],
|
|
235
|
+
annotations: right.annotations
|
|
236
|
+
}] : [{
|
|
237
|
+
_tag: "FilterGroup",
|
|
238
|
+
checks: checks,
|
|
239
|
+
annotations: right.annotations
|
|
240
|
+
}];
|
|
241
|
+
}
|
|
242
|
+
return [[...left.checks, ...checks], left.annotations];
|
|
232
243
|
}
|
|
233
244
|
function satisfiesPrimitiveCheck(check, value) {
|
|
234
245
|
if (check._tag === "FilterGroup") {
|
|
@@ -266,11 +277,11 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
266
277
|
}
|
|
267
278
|
return representation.checks.every(check => satisfiesPrimitiveCheck(check, value));
|
|
268
279
|
}
|
|
269
|
-
function
|
|
280
|
+
function intersectPrimitiveWithLiteral(primitive, literal) {
|
|
270
281
|
const satisfies = primitive._tag === "Boolean" ? typeof literal.literal === "boolean" : satisfiesLiteral(primitive, literal);
|
|
271
|
-
return satisfies ?
|
|
282
|
+
return satisfies ? annotateIntersection(literal, primitive, literal) : never;
|
|
272
283
|
}
|
|
273
|
-
function
|
|
284
|
+
function intersectArrays(left, right, path) {
|
|
274
285
|
const elements = [];
|
|
275
286
|
const length = Math.max(left.elements.length, right.elements.length);
|
|
276
287
|
for (let index = 0; index < length; index++) {
|
|
@@ -285,7 +296,7 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
285
296
|
rest: []
|
|
286
297
|
} : undefined;
|
|
287
298
|
}
|
|
288
|
-
const type =
|
|
299
|
+
const type = intersect(leftType, rightType, [...path, "elements", index, "type"]);
|
|
289
300
|
if (type._tag === "Never") {
|
|
290
301
|
return isOptional ? {
|
|
291
302
|
elements,
|
|
@@ -305,16 +316,16 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
305
316
|
rest: []
|
|
306
317
|
};
|
|
307
318
|
}
|
|
308
|
-
const rest =
|
|
319
|
+
const rest = intersect(leftRest, rightRest, [...path, "rest", 0]);
|
|
309
320
|
return {
|
|
310
321
|
elements,
|
|
311
322
|
rest: rest._tag === "Never" ? [] : [rest]
|
|
312
323
|
};
|
|
313
324
|
}
|
|
314
|
-
function
|
|
325
|
+
function intersectAll(types, path) {
|
|
315
326
|
let out = types[0] ?? unknown;
|
|
316
327
|
for (let index = 1; index < types.length; index++) {
|
|
317
|
-
out =
|
|
328
|
+
out = intersect(out, types[index], [...path, index]);
|
|
318
329
|
}
|
|
319
330
|
return out;
|
|
320
331
|
}
|
|
@@ -327,8 +338,9 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
327
338
|
hasFiniteKeyDomain ||= scope.additionalProperties._tag === "Never" && scope.patterns.length === 0;
|
|
328
339
|
requiresFiniteKeyDomain ||= scope.additionalProperties._tag === "Never" || scope.additionalProperties._tag !== "Unknown" && (scope.hasProperties || scope.patterns.length > 0);
|
|
329
340
|
}
|
|
330
|
-
|
|
331
|
-
|
|
341
|
+
const closedPattern = scopes.length === 1 && names.size === 0 && scopes[0].additionalProperties._tag === "Never" && scopes[0].patterns.length === 1 ? scopes[0].patterns[0] : undefined;
|
|
342
|
+
if (!hasFiniteKeyDomain && requiresFiniteKeyDomain && closedPattern === undefined) {
|
|
343
|
+
throw errorWithPath(scopes.some(scope => scope.additionalProperties._tag === "Never") ? "Cannot import this closed patterned object: only one pattern without properties is supported." : "Cannot combine typed \"additionalProperties\" with other property schemas: Effect index signatures also check excluded keys.", path);
|
|
332
344
|
}
|
|
333
345
|
const properties = [];
|
|
334
346
|
for (const name of names) {
|
|
@@ -349,7 +361,7 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
349
361
|
}
|
|
350
362
|
if (property?.type === undefined && !matches) types.push(scope.additionalProperties);
|
|
351
363
|
}
|
|
352
|
-
const type =
|
|
364
|
+
const type = intersectAll(types, [...path, "properties", name]);
|
|
353
365
|
if (!isOptional && type._tag === "Never") return never;
|
|
354
366
|
properties.push({
|
|
355
367
|
name,
|
|
@@ -358,46 +370,25 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
358
370
|
isMutable: false
|
|
359
371
|
});
|
|
360
372
|
}
|
|
361
|
-
const indexSignatures = [
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
for (const {
|
|
375
|
-
parameter,
|
|
376
|
-
type
|
|
377
|
-
} of patterns.values()) {
|
|
378
|
-
indexSignatures.push({
|
|
379
|
-
parameter,
|
|
380
|
-
type: combine(type, additionalProperties, [...path, "indexSignatures"])
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
indexSignatures.push({
|
|
384
|
-
parameter: string,
|
|
385
|
-
type: additionalProperties
|
|
386
|
-
});
|
|
387
|
-
} else if (properties.length === 0) {
|
|
388
|
-
indexSignatures.push({
|
|
389
|
-
parameter: string,
|
|
390
|
-
type: never
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
objectScopesByProperties.set(properties, scopes);
|
|
394
|
-
return {
|
|
373
|
+
const indexSignatures = closedPattern !== undefined ? [{
|
|
374
|
+
parameter: closedPattern.parameter,
|
|
375
|
+
type: closedPattern.type
|
|
376
|
+
}] : !hasFiniteKeyDomain ? [{
|
|
377
|
+
parameter: string,
|
|
378
|
+
type: intersectAll(scopes.map(scope => scope.additionalProperties), [...path, "additionalProperties"])
|
|
379
|
+
}] : properties.length === 0 ? [{
|
|
380
|
+
parameter: string,
|
|
381
|
+
type: never
|
|
382
|
+
}] : [];
|
|
383
|
+
const representation = {
|
|
395
384
|
_tag: "Objects",
|
|
396
385
|
propertySignatures: properties,
|
|
397
386
|
indexSignatures,
|
|
398
387
|
checks,
|
|
399
388
|
annotations
|
|
400
389
|
};
|
|
390
|
+
objectScopesByProperties.set(properties, [scopes, path]);
|
|
391
|
+
return representation;
|
|
401
392
|
}
|
|
402
393
|
const jsonRootTags = ["Null", "String", "Number", "Boolean", "Objects", "Arrays"];
|
|
403
394
|
const allMasks = (1 << jsonRootTags.length) - 1;
|
|
@@ -452,7 +443,7 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
452
443
|
case "Arrays":
|
|
453
444
|
return representation.elements.some(element => hasChoices(element.type)) || representation.rest.some(type => hasChoices(type));
|
|
454
445
|
case "Objects":
|
|
455
|
-
return representation.propertySignatures.some(property => hasChoices(property.type)) || representation.indexSignatures.some(indexSignature => hasChoices(indexSignature.parameter) || hasChoices(indexSignature.type)) || representation.checks.some(checkHasChoices);
|
|
446
|
+
return representation.propertySignatures.some(property => hasChoices(property.type)) || representation.indexSignatures.some(indexSignature => hasChoices(indexSignature.parameter) || hasChoices(indexSignature.type)) || objectScopesByProperties.get(representation.propertySignatures)[0].some(scope => scope.patterns.some(pattern => hasChoices(pattern.type))) || representation.checks.some(checkHasChoices);
|
|
456
447
|
default:
|
|
457
448
|
return false;
|
|
458
449
|
}
|
|
@@ -474,7 +465,7 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
474
465
|
const literal = representation.literal;
|
|
475
466
|
return typeof literal === "string" || typeof literal === "number" || typeof literal === "boolean" ? literal : undefined;
|
|
476
467
|
}
|
|
477
|
-
function
|
|
468
|
+
function intersectLiteralUnions(left, right, path) {
|
|
478
469
|
if ((left.options?.mode ?? "anyOf") !== "anyOf" || (right.options?.mode ?? "anyOf") !== "anyOf") {
|
|
479
470
|
return undefined;
|
|
480
471
|
}
|
|
@@ -491,11 +482,11 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
491
482
|
const value = literalValue(representation);
|
|
492
483
|
if (value === undefined) return undefined;
|
|
493
484
|
const match = rightByValue.get(value);
|
|
494
|
-
if (match !== undefined) types.push(
|
|
485
|
+
if (match !== undefined) types.push(intersect(representation, annotate(match, right.annotations), path));
|
|
495
486
|
}
|
|
496
487
|
return makeUnion(left, types);
|
|
497
488
|
}
|
|
498
|
-
function
|
|
489
|
+
function intersectUnionWithType(union, type, path, unionOnLeft) {
|
|
499
490
|
const mask = rootMask(type);
|
|
500
491
|
const members = union.types.map((member, index) => ({
|
|
501
492
|
index,
|
|
@@ -506,9 +497,9 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
506
497
|
}
|
|
507
498
|
if (members.length === 1 && union.checks.length === 0) {
|
|
508
499
|
const member = annotate(members[0].type, union.annotations);
|
|
509
|
-
return unionOnLeft ?
|
|
500
|
+
return unionOnLeft ? intersect(member, type, [...path, "types", members[0].index]) : intersect(type, member, [...path, "types", members[0].index]);
|
|
510
501
|
}
|
|
511
|
-
return makeUnion(union, members.map(member => unionOnLeft ?
|
|
502
|
+
return makeUnion(union, members.map(member => unionOnLeft ? intersect(member.type, type, [...path, "types", member.index]) : intersect(type, member.type, [...path, "types", member.index])).filter(type => type._tag !== "Never"));
|
|
512
503
|
}
|
|
513
504
|
function isTypePartition(union) {
|
|
514
505
|
let mask = 0;
|
|
@@ -520,9 +511,9 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
520
511
|
return true;
|
|
521
512
|
}
|
|
522
513
|
function unsupportedIntersection(path) {
|
|
523
|
-
throw errorWithPath("
|
|
514
|
+
throw errorWithPath("Cannot intersect these \"anyOf\" or \"oneOf\" alternatives without expanding their branches.", path);
|
|
524
515
|
}
|
|
525
|
-
function
|
|
516
|
+
function intersectPartition(partition, other, path, partitionOnLeft) {
|
|
526
517
|
const partitionTypes = partition.types;
|
|
527
518
|
const otherTypes = other.types;
|
|
528
519
|
for (const type of otherTypes) {
|
|
@@ -534,114 +525,112 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
534
525
|
const types = [];
|
|
535
526
|
for (let index = 0; index < partitionTypes.length; index++) {
|
|
536
527
|
const member = partitionTypes[index];
|
|
537
|
-
const type =
|
|
528
|
+
const type = intersectUnionWithType(other, member, [...path, "types", index], !partitionOnLeft);
|
|
538
529
|
if (type._tag !== "Never") types.push(type);
|
|
539
530
|
}
|
|
540
531
|
return makeUnion(partition, types);
|
|
541
532
|
}
|
|
542
|
-
function
|
|
543
|
-
const literals =
|
|
533
|
+
function intersectUnions(left, right, path) {
|
|
534
|
+
const literals = intersectLiteralUnions(left, right, path);
|
|
544
535
|
if (literals !== undefined) return literals;
|
|
545
|
-
if (isTypePartition(left)) return
|
|
546
|
-
if (isTypePartition(right)) return
|
|
536
|
+
if (isTypePartition(left)) return intersectPartition(left, right, path, true);
|
|
537
|
+
if (isTypePartition(right)) return intersectPartition(right, left, path, false);
|
|
547
538
|
return unsupportedIntersection(path);
|
|
548
539
|
}
|
|
549
|
-
function
|
|
540
|
+
function intersect(left, right, path) {
|
|
550
541
|
if (left._tag === "Never") return left;
|
|
551
542
|
if (right._tag === "Never") return right;
|
|
552
|
-
if (left._tag === "Unknown") return
|
|
553
|
-
if (right._tag === "Unknown") return
|
|
554
|
-
if (left._tag === "Reference") return
|
|
555
|
-
if (right._tag === "Reference") return
|
|
543
|
+
if (left._tag === "Unknown") return annotateIntersection(right, left, right);
|
|
544
|
+
if (right._tag === "Unknown") return annotateIntersection(left, left, right);
|
|
545
|
+
if (left._tag === "Reference") return intersect(resolveReference(left, path), right, path);
|
|
546
|
+
if (right._tag === "Reference") return intersect(left, resolveReference(right, path), path);
|
|
556
547
|
if (left._tag === "Suspend") {
|
|
557
|
-
return annotate(
|
|
548
|
+
return annotate(intersect(left.thunk, right, path), left.annotations);
|
|
558
549
|
}
|
|
559
550
|
if (right._tag === "Suspend") {
|
|
560
|
-
return annotate(
|
|
551
|
+
return annotate(intersect(left, right.thunk, path), right.annotations);
|
|
561
552
|
}
|
|
562
|
-
if (left._tag === "Union" && right._tag === "Union") return
|
|
563
|
-
if (left._tag === "Union") return
|
|
564
|
-
if (right._tag === "Union") return
|
|
553
|
+
if (left._tag === "Union" && right._tag === "Union") return intersectUnions(left, right, path);
|
|
554
|
+
if (left._tag === "Union") return intersectUnionWithType(left, right, path, true);
|
|
555
|
+
if (right._tag === "Union") return intersectUnionWithType(right, left, path, false);
|
|
565
556
|
switch (left._tag) {
|
|
566
557
|
case "Null":
|
|
567
|
-
return right._tag === "Null" ?
|
|
558
|
+
return right._tag === "Null" ? annotateIntersection({
|
|
568
559
|
_tag: "Null",
|
|
569
560
|
checks: [...left.checks, ...right.checks]
|
|
570
561
|
}, left, right) : never;
|
|
571
562
|
case "String":
|
|
572
563
|
if (right._tag === "Literal") {
|
|
573
|
-
return
|
|
564
|
+
return intersectPrimitiveWithLiteral(left, right);
|
|
574
565
|
}
|
|
575
566
|
if (right._tag !== "String") return never;
|
|
576
|
-
const stringChecks =
|
|
567
|
+
const [stringChecks, stringAnnotations] = intersectChecks(left, right);
|
|
577
568
|
return annotate({
|
|
578
569
|
_tag: "String",
|
|
579
|
-
checks: stringChecks
|
|
580
|
-
},
|
|
570
|
+
checks: stringChecks
|
|
571
|
+
}, stringAnnotations);
|
|
581
572
|
case "Number":
|
|
582
573
|
if (right._tag === "Literal") {
|
|
583
|
-
return
|
|
574
|
+
return intersectPrimitiveWithLiteral(left, right);
|
|
584
575
|
}
|
|
585
576
|
if (right._tag !== "Number") return never;
|
|
586
|
-
const numberChecks =
|
|
577
|
+
const [numberChecks, numberAnnotations] = intersectChecks(left, right, ["effect/schema/isFinite", "effect/schema/isInt"]);
|
|
587
578
|
return annotate({
|
|
588
579
|
_tag: "Number",
|
|
589
|
-
checks: numberChecks
|
|
590
|
-
},
|
|
580
|
+
checks: numberChecks
|
|
581
|
+
}, numberAnnotations);
|
|
591
582
|
case "Boolean":
|
|
592
583
|
if (right._tag === "Literal") {
|
|
593
|
-
return
|
|
584
|
+
return intersectPrimitiveWithLiteral(left, right);
|
|
594
585
|
}
|
|
595
|
-
return right._tag === "Boolean" ?
|
|
586
|
+
return right._tag === "Boolean" ? annotateIntersection({
|
|
596
587
|
_tag: "Boolean",
|
|
597
588
|
checks: [...left.checks, ...right.checks]
|
|
598
589
|
}, left, right) : never;
|
|
599
590
|
case "Literal":
|
|
600
591
|
if (right._tag === "Literal") {
|
|
601
|
-
return left.literal === right.literal ?
|
|
592
|
+
return left.literal === right.literal ? annotateIntersection({
|
|
602
593
|
...left,
|
|
603
594
|
checks: [...left.checks, ...right.checks]
|
|
604
595
|
}, left, right) : never;
|
|
605
596
|
}
|
|
606
597
|
if ((right._tag === "String" || right._tag === "Number") && satisfiesLiteral(right, left) || right._tag === "Boolean" && typeof left.literal === "boolean") {
|
|
607
|
-
return
|
|
598
|
+
return annotateIntersection(left, left, right);
|
|
608
599
|
}
|
|
609
600
|
return never;
|
|
610
601
|
case "Arrays":
|
|
611
602
|
{
|
|
612
603
|
if (right._tag !== "Arrays") return never;
|
|
613
|
-
const arrays =
|
|
604
|
+
const arrays = intersectArrays(left, right, path);
|
|
614
605
|
if (arrays === undefined) return never;
|
|
615
|
-
const
|
|
606
|
+
const [checks, annotations] = intersectChecks(left, right, ["effect/schema/isUnique"]);
|
|
616
607
|
return annotate({
|
|
617
608
|
_tag: "Arrays",
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
}, mergeAnnotations(left.annotations, arrayChecks === undefined ? right.annotations : undefined));
|
|
609
|
+
...arrays,
|
|
610
|
+
checks
|
|
611
|
+
}, annotations);
|
|
622
612
|
}
|
|
623
613
|
case "Objects":
|
|
624
614
|
{
|
|
625
615
|
if (right._tag !== "Objects") return never;
|
|
626
|
-
const
|
|
627
|
-
const scopes = [...objectScopesByProperties.get(left.propertySignatures), ...objectScopesByProperties.get(right.propertySignatures)];
|
|
628
|
-
return lowerObject(scopes,
|
|
616
|
+
const [checks, annotations] = intersectChecks(left, right);
|
|
617
|
+
const scopes = [...objectScopesByProperties.get(left.propertySignatures)[0], ...objectScopesByProperties.get(right.propertySignatures)[0]];
|
|
618
|
+
return lowerObject(scopes, checks, annotations, path);
|
|
629
619
|
}
|
|
630
620
|
}
|
|
631
621
|
}
|
|
632
|
-
function
|
|
622
|
+
function translateSchema(input, path, isRoot = false) {
|
|
633
623
|
if (input === false) {
|
|
634
624
|
return never;
|
|
635
625
|
}
|
|
636
|
-
if (
|
|
626
|
+
if (!isObject(input)) return unknown;
|
|
637
627
|
const schema = options?.onEnter === undefined ? input : options.onEnter(input);
|
|
638
628
|
if (schema === undefined) {
|
|
639
629
|
return unknown;
|
|
640
630
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
631
|
+
if (isObject(schema.not) && Object.keys(schema.not).length === 0) return annotate(never, jsonSchemaAnnotations(schema));
|
|
632
|
+
const wasInNestedResource = inNestedResource;
|
|
633
|
+
inNestedResource ||= !isRoot && typeof schema.$id === "string";
|
|
645
634
|
for (const keyword of Object.keys(schema)) {
|
|
646
635
|
if (keyword === "if" && !Object.hasOwn(schema, "then") && !Object.hasOwn(schema, "else")) continue;
|
|
647
636
|
switch (keyword) {
|
|
@@ -653,41 +642,40 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
653
642
|
case "not":
|
|
654
643
|
case "unevaluatedItems":
|
|
655
644
|
case "unevaluatedProperties":
|
|
656
|
-
throw errorWithPath(`
|
|
645
|
+
throw errorWithPath(`Cannot import JSON Schema keyword "${keyword}": Effect has no equivalent constraint.`, [...path, keyword]);
|
|
657
646
|
}
|
|
658
647
|
}
|
|
659
|
-
let representation =
|
|
648
|
+
let representation = translateType(schema, path);
|
|
660
649
|
if (Object.hasOwn(schema, "const")) {
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
if (literal !== undefined) representation = combine(representation, literal, [...path, "const"]);
|
|
650
|
+
const constPath = [...path, "const"];
|
|
651
|
+
const literal = makeJsonLiteral(schema.const, constPath);
|
|
652
|
+
if (literal !== undefined) representation = intersect(representation, literal, constPath);
|
|
666
653
|
}
|
|
667
654
|
if (Array.isArray(schema.enum)) {
|
|
668
|
-
const types = schema.enum.map(value => makeJsonLiteral(value) ?? unknown);
|
|
669
|
-
representation =
|
|
655
|
+
const types = schema.enum.map((value, index) => makeJsonLiteral(value, [...path, "enum", index]) ?? unknown);
|
|
656
|
+
representation = intersect(representation, types.length === 1 ? types[0] : {
|
|
670
657
|
_tag: "Union",
|
|
671
658
|
types,
|
|
672
659
|
checks: []
|
|
673
660
|
}, [...path, "enum"]);
|
|
674
661
|
}
|
|
675
662
|
if (typeof schema.$ref === "string") {
|
|
663
|
+
if (inNestedResource) {
|
|
664
|
+
throw errorWithPath("Cannot resolve $ref under a nested \"$id\". Resolve or flatten it first.", [...path, "$ref"]);
|
|
665
|
+
}
|
|
676
666
|
const $ref = JsonSchema.getReferenceKey(schema.$ref);
|
|
677
667
|
if ($ref === undefined) {
|
|
678
|
-
throw errorWithPath(`Unsupported
|
|
668
|
+
throw errorWithPath(`Unsupported $ref ${JSON.stringify(schema.$ref)}. Use "#/$defs/Name".`, [...path, "$ref"]);
|
|
679
669
|
}
|
|
680
670
|
if (!Object.hasOwn(document.definitions, $ref)) {
|
|
681
|
-
throw errorWithPath(`
|
|
671
|
+
throw errorWithPath(`Missing definition ${JSON.stringify($ref)} for $ref ${JSON.stringify(schema.$ref)}.`, [...path, "$ref"]);
|
|
682
672
|
}
|
|
683
673
|
if (!reachableDefinitions.has($ref)) reachableDefinitions.set($ref, path);
|
|
684
674
|
const reference = {
|
|
685
675
|
_tag: "Reference",
|
|
686
676
|
$ref
|
|
687
677
|
};
|
|
688
|
-
representation = representation._tag === "Unknown" ? reference : representation._tag === "Never" ? never :
|
|
689
|
-
recursiveReferenceError: `Unsupported assertion siblings on recursive reference ${reference.$ref}`
|
|
690
|
-
}), representation, path);
|
|
678
|
+
representation = representation._tag === "Unknown" ? reference : representation._tag === "Never" ? never : intersect(resolveReference(reference, path, `Recursive $ref ${JSON.stringify(reference.$ref)} cannot have sibling constraints.`), representation, path);
|
|
691
679
|
}
|
|
692
680
|
const annotations = jsonSchemaAnnotations(schema);
|
|
693
681
|
if (annotations !== undefined && representation._tag === "Reference") {
|
|
@@ -699,7 +687,7 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
699
687
|
representation = annotate(representation, annotations);
|
|
700
688
|
if (Array.isArray(schema.allOf)) {
|
|
701
689
|
for (let index = 0; index < schema.allOf.length; index++) {
|
|
702
|
-
representation =
|
|
690
|
+
representation = intersect(representation, translateSchema(schema.allOf[index], [...path, "allOf", index]), [...path, "allOf", index]);
|
|
703
691
|
}
|
|
704
692
|
}
|
|
705
693
|
for (const mode of ["anyOf", "oneOf"]) {
|
|
@@ -707,7 +695,7 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
707
695
|
if (Array.isArray(members)) {
|
|
708
696
|
const union = {
|
|
709
697
|
_tag: "Union",
|
|
710
|
-
types: members.map((member, index) =>
|
|
698
|
+
types: members.map((member, index) => translateSchema(member, [...path, mode, index])),
|
|
711
699
|
...(mode === "oneOf" ? {
|
|
712
700
|
options: {
|
|
713
701
|
mode
|
|
@@ -715,17 +703,18 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
715
703
|
} : {}),
|
|
716
704
|
checks: []
|
|
717
705
|
};
|
|
718
|
-
representation =
|
|
706
|
+
representation = intersect(union, representation, [...path, mode]);
|
|
719
707
|
}
|
|
720
708
|
}
|
|
709
|
+
inNestedResource = wasInNestedResource;
|
|
721
710
|
return representation;
|
|
722
711
|
}
|
|
723
|
-
function
|
|
712
|
+
function translateType(schema, path) {
|
|
724
713
|
const types = Array.isArray(schema.type) && schema.type.every(isImportedJsonSchemaType) ? schema.type : !isImportedJsonSchemaType(schema.type) && hasTypeSpecificKeywords(schema) ? jsonSchemaValueTypes : undefined;
|
|
725
714
|
if (types !== undefined) {
|
|
726
715
|
return {
|
|
727
716
|
_tag: "Union",
|
|
728
|
-
types: types.map(type =>
|
|
717
|
+
types: types.map(type => translateType({
|
|
729
718
|
...schema,
|
|
730
719
|
type
|
|
731
720
|
}, path)),
|
|
@@ -761,14 +750,14 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
761
750
|
const minItems = typeof schema.minItems === "number" ? schema.minItems : 0;
|
|
762
751
|
const elements = prefixItems?.map((element, index) => ({
|
|
763
752
|
isOptional: index + 1 > minItems,
|
|
764
|
-
type:
|
|
753
|
+
type: translateSchema(element, [...path, "prefixItems", index])
|
|
765
754
|
})) ?? [];
|
|
766
755
|
const isTupleClosed = schema.items === false || schema.items === undefined && prefixItems !== undefined && schema.maxItems === prefixItems.length;
|
|
767
756
|
const isMaxItemsRedundant = isTupleClosed && typeof schema.maxItems === "number" && schema.maxItems >= elements.length;
|
|
768
757
|
return {
|
|
769
758
|
_tag: "Arrays",
|
|
770
759
|
elements,
|
|
771
|
-
rest: isTupleClosed ? [] : [schema.items === undefined ? unknown :
|
|
760
|
+
rest: isTupleClosed ? [] : [schema.items === undefined ? unknown : translateSchema(schema.items, [...path, "items"])],
|
|
772
761
|
checks: collectArrayChecks(schema, isMaxItemsRedundant)
|
|
773
762
|
};
|
|
774
763
|
}
|
|
@@ -781,17 +770,17 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
781
770
|
return unknown;
|
|
782
771
|
}
|
|
783
772
|
}
|
|
784
|
-
function
|
|
773
|
+
function importPatternCheck(pattern, path) {
|
|
785
774
|
switch (options?.patterns ?? "error") {
|
|
786
775
|
case "error":
|
|
787
|
-
throw errorWithPath(
|
|
776
|
+
throw errorWithPath("Patterns may block validation and are disabled. Use patterns: \"apply\" for trusted schemas or \"ignore\" to discard them.", path);
|
|
788
777
|
case "ignore":
|
|
789
|
-
return
|
|
778
|
+
return undefined;
|
|
790
779
|
case "apply":
|
|
791
|
-
return
|
|
780
|
+
return jsonSchemaFilter("effect/schema/isPattern", {
|
|
792
781
|
source: pattern,
|
|
793
782
|
flags: ""
|
|
794
|
-
})
|
|
783
|
+
});
|
|
795
784
|
}
|
|
796
785
|
}
|
|
797
786
|
function collectStringChecks(schema, path) {
|
|
@@ -799,7 +788,8 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
799
788
|
addNumberCheck(checks, schema.minLength, "effect/schema/isMinLength", "minLength");
|
|
800
789
|
addNumberCheck(checks, schema.maxLength, "effect/schema/isMaxLength", "maxLength");
|
|
801
790
|
if (typeof schema.pattern === "string") {
|
|
802
|
-
|
|
791
|
+
const check = importPatternCheck(schema.pattern, [...path, "pattern"]);
|
|
792
|
+
if (check !== undefined) checks.push(check);
|
|
803
793
|
}
|
|
804
794
|
return checks;
|
|
805
795
|
}
|
|
@@ -826,20 +816,20 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
826
816
|
return checks;
|
|
827
817
|
}
|
|
828
818
|
function collectObjectScope(schema, path) {
|
|
829
|
-
const sourceProperties =
|
|
830
|
-
const required = Array.isArray(schema.required) ? schema.required.filter(key => typeof key === "string") : [];
|
|
819
|
+
const sourceProperties = isObject(schema.properties) ? schema.properties : {};
|
|
820
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required.filter(key => typeof key === "string") : []);
|
|
831
821
|
const propertyNames = Object.keys(sourceProperties);
|
|
832
822
|
const keys = new Set([...propertyNames, ...required]);
|
|
833
823
|
const properties = new Map(Array.from(keys, name => [name, {
|
|
834
|
-
type: Object.hasOwn(sourceProperties, name) ?
|
|
835
|
-
isOptional: !required.
|
|
824
|
+
type: Object.hasOwn(sourceProperties, name) ? translateSchema(sourceProperties[name], [...path, "properties", name]) : undefined,
|
|
825
|
+
isOptional: !required.has(name)
|
|
836
826
|
}]));
|
|
837
827
|
const hasProperties = propertyNames.length > 0;
|
|
838
828
|
const patterns = [];
|
|
839
|
-
if (
|
|
829
|
+
if (isObject(schema.patternProperties)) {
|
|
840
830
|
for (const [pattern, value] of Object.entries(schema.patternProperties)) {
|
|
841
|
-
const
|
|
842
|
-
if (
|
|
831
|
+
const check = importPatternCheck(pattern, [...path, "patternProperties", pattern]);
|
|
832
|
+
if (check === undefined) return {
|
|
843
833
|
properties,
|
|
844
834
|
hasProperties,
|
|
845
835
|
patterns: [],
|
|
@@ -849,13 +839,13 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
849
839
|
source: pattern,
|
|
850
840
|
parameter: {
|
|
851
841
|
_tag: "String",
|
|
852
|
-
checks
|
|
842
|
+
checks: [check]
|
|
853
843
|
},
|
|
854
|
-
type:
|
|
844
|
+
type: translateSchema(value, [...path, "patternProperties", pattern])
|
|
855
845
|
});
|
|
856
846
|
}
|
|
857
847
|
}
|
|
858
|
-
const additionalProperties = schema.additionalProperties === false ? never :
|
|
848
|
+
const additionalProperties = schema.additionalProperties === false ? never : isObject(schema.additionalProperties) ? translateSchema(schema.additionalProperties, [...path, "additionalProperties"]) : unknown;
|
|
859
849
|
return {
|
|
860
850
|
properties,
|
|
861
851
|
hasProperties,
|
|
@@ -869,14 +859,15 @@ function translateJsonSchemaMultiDocument(document, options, singleRoot = false)
|
|
|
869
859
|
addNumberCheck(checks, schema.maxProperties, "effect/schema/isMaxProperties", "maxProperties");
|
|
870
860
|
if (schema.propertyNames !== undefined) {
|
|
871
861
|
const propertyNamesPath = [...path, "propertyNames"];
|
|
872
|
-
checks.push(jsonSchemaFilter("effect/schema/isPropertyNames", null, [
|
|
862
|
+
checks.push(jsonSchemaFilter("effect/schema/isPropertyNames", null, [intersect(string, translateSchema(schema.propertyNames, propertyNamesPath), propertyNamesPath)]));
|
|
873
863
|
}
|
|
874
864
|
return checks;
|
|
875
865
|
}
|
|
876
866
|
const references = {};
|
|
877
|
-
const representations = document.schemas.map((schema, index) =>
|
|
878
|
-
|
|
879
|
-
|
|
867
|
+
const representations = document.schemas.map((schema, index) => finalize(translateSchema(schema, singleRoot ? ["schema"] : ["schemas", index], true)));
|
|
868
|
+
// Definitions expanded away by intersections do not need a standalone output schema.
|
|
869
|
+
for (const key of finalReferences) {
|
|
870
|
+
InternalRecord.assignProperty(references, key, finalize(translateDefinition(key, reachableDefinitions.get(key))));
|
|
880
871
|
}
|
|
881
872
|
for (const {
|
|
882
873
|
reference,
|