effect 3.14.1 → 3.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Arbitrary.js +595 -426
- package/dist/cjs/Arbitrary.js.map +1 -1
- package/dist/cjs/Schema.js +3 -3
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/SchemaAST.js +7 -2
- package/dist/cjs/SchemaAST.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Arbitrary.d.ts.map +1 -1
- package/dist/dts/Schema.d.ts +1 -1
- package/dist/dts/Schema.d.ts.map +1 -1
- package/dist/dts/SchemaAST.d.ts +5 -0
- package/dist/dts/SchemaAST.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/Arbitrary.js +593 -423
- package/dist/esm/Arbitrary.js.map +1 -1
- package/dist/esm/Schema.js +3 -3
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/SchemaAST.js +5 -0
- package/dist/esm/SchemaAST.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +1 -1
- package/src/Arbitrary.ts +799 -477
- package/src/Schema.ts +4 -3
- package/src/SchemaAST.ts +6 -0
- package/src/index.ts +1 -0
- package/src/internal/version.ts +1 -1
package/dist/cjs/Arbitrary.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.makeStringConstraints = exports.makeNumberConstraints = exports.makeLazy = exports.makeDateConstraints = exports.makeBigIntConstraints = exports.makeArrayConstraints = exports.make = exports.getDescription = void 0;
|
|
7
7
|
var Arr = _interopRequireWildcard(require("./Array.js"));
|
|
8
8
|
var FastCheck = _interopRequireWildcard(require("./FastCheck.js"));
|
|
9
9
|
var _GlobalValue = require("./GlobalValue.js");
|
|
@@ -12,7 +12,7 @@ var schemaId_ = _interopRequireWildcard(require("./internal/schema/schemaId.js")
|
|
|
12
12
|
var util_ = _interopRequireWildcard(require("./internal/schema/util.js"));
|
|
13
13
|
var Option = _interopRequireWildcard(require("./Option.js"));
|
|
14
14
|
var Predicate = _interopRequireWildcard(require("./Predicate.js"));
|
|
15
|
-
var
|
|
15
|
+
var SchemaAST = _interopRequireWildcard(require("./SchemaAST.js"));
|
|
16
16
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
17
17
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
18
18
|
/**
|
|
@@ -25,9 +25,12 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
|
|
|
25
25
|
* @category arbitrary
|
|
26
26
|
* @since 3.10.0
|
|
27
27
|
*/
|
|
28
|
-
const makeLazy = schema =>
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const makeLazy = schema => {
|
|
29
|
+
const description = getDescription(schema.ast, []);
|
|
30
|
+
return go(description, {
|
|
31
|
+
maxDepth: 2
|
|
32
|
+
});
|
|
33
|
+
};
|
|
31
34
|
/**
|
|
32
35
|
* Returns a fast-check Arbitrary for the `A` type of the provided schema.
|
|
33
36
|
*
|
|
@@ -36,62 +39,8 @@ const makeLazy = schema => go(schema.ast, {
|
|
|
36
39
|
*/
|
|
37
40
|
exports.makeLazy = makeLazy;
|
|
38
41
|
const make = schema => makeLazy(schema)(FastCheck);
|
|
39
|
-
exports.make = make;
|
|
40
|
-
const getArbitraryAnnotation = /*#__PURE__*/AST.getAnnotation(AST.ArbitraryAnnotationId);
|
|
41
|
-
/**
|
|
42
|
-
* Represents an arbitrary with optional filters.
|
|
43
|
-
*/
|
|
44
|
-
class Succeed {
|
|
45
|
-
lazyArbitrary;
|
|
46
|
-
filters;
|
|
47
|
-
_tag = "Succeed";
|
|
48
|
-
constructor(lazyArbitrary, filters = []) {
|
|
49
|
-
this.lazyArbitrary = lazyArbitrary;
|
|
50
|
-
this.filters = filters;
|
|
51
|
-
}
|
|
52
|
-
toLazyArbitrary() {
|
|
53
|
-
return fc => {
|
|
54
|
-
let out = this.lazyArbitrary(fc);
|
|
55
|
-
for (const f of this.filters) {
|
|
56
|
-
out = out.filter(f);
|
|
57
|
-
}
|
|
58
|
-
return out;
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Represents a deferred arbitrary value generator with optional filters.
|
|
64
|
-
*/
|
|
65
|
-
class Deferred {
|
|
66
|
-
config;
|
|
67
|
-
filters;
|
|
68
|
-
_tag = "Deferred";
|
|
69
|
-
constructor(config, filters = []) {
|
|
70
|
-
this.config = config;
|
|
71
|
-
this.filters = filters;
|
|
72
|
-
}
|
|
73
|
-
toLazyArbitrary(ctx, path) {
|
|
74
|
-
const config = this.config;
|
|
75
|
-
switch (config._tag) {
|
|
76
|
-
case "StringConstraints":
|
|
77
|
-
{
|
|
78
|
-
const pattern = config.pattern;
|
|
79
|
-
return pattern !== undefined ? fc => fc.stringMatching(new RegExp(pattern)) : fc => fc.string(config.constraints);
|
|
80
|
-
}
|
|
81
|
-
case "NumberConstraints":
|
|
82
|
-
{
|
|
83
|
-
return config.isInteger ? fc => fc.integer(config.constraints) : fc => fc.float(config.constraints);
|
|
84
|
-
}
|
|
85
|
-
case "BigIntConstraints":
|
|
86
|
-
return fc => fc.bigInt(config.constraints);
|
|
87
|
-
case "DateConstraints":
|
|
88
|
-
return fc => fc.date(config.constraints);
|
|
89
|
-
case "ArrayConstraints":
|
|
90
|
-
return goTupleType(config.ast, ctx, path, config.constraints);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
42
|
/** @internal */
|
|
43
|
+
exports.make = make;
|
|
95
44
|
const makeStringConstraints = options => {
|
|
96
45
|
const out = {
|
|
97
46
|
_tag: "StringConstraints",
|
|
@@ -171,9 +120,7 @@ exports.makeArrayConstraints = makeArrayConstraints;
|
|
|
171
120
|
const makeDateConstraints = options => {
|
|
172
121
|
const out = {
|
|
173
122
|
_tag: "DateConstraints",
|
|
174
|
-
constraints: {
|
|
175
|
-
noInvalidDate: options.noInvalidDate ?? false
|
|
176
|
-
}
|
|
123
|
+
constraints: {}
|
|
177
124
|
};
|
|
178
125
|
if (Predicate.isDate(options.min)) {
|
|
179
126
|
out.constraints.min = options.min;
|
|
@@ -181,55 +128,15 @@ const makeDateConstraints = options => {
|
|
|
181
128
|
if (Predicate.isDate(options.max)) {
|
|
182
129
|
out.constraints.max = options.max;
|
|
183
130
|
}
|
|
131
|
+
if (Predicate.isBoolean(options.noInvalidDate)) {
|
|
132
|
+
out.constraints.noInvalidDate = options.noInvalidDate;
|
|
133
|
+
}
|
|
184
134
|
return out;
|
|
185
135
|
};
|
|
186
136
|
exports.makeDateConstraints = makeDateConstraints;
|
|
187
|
-
const
|
|
188
|
-
return {
|
|
189
|
-
ast,
|
|
190
|
-
...makeArrayConstraints(options)
|
|
191
|
-
};
|
|
192
|
-
};
|
|
193
|
-
const arbitraryMemoMap = /*#__PURE__*/(0, _GlobalValue.globalValue)( /*#__PURE__*/Symbol.for("effect/Arbitrary/arbitraryMemoMap"), () => new WeakMap());
|
|
194
|
-
const go = (ast, ctx, path) => {
|
|
195
|
-
const hook = getArbitraryAnnotation(ast);
|
|
196
|
-
if (Option.isSome(hook)) {
|
|
197
|
-
switch (ast._tag) {
|
|
198
|
-
case "Declaration":
|
|
199
|
-
return hook.value(...ast.typeParameters.map(p => go(p, ctx, path)), ctx);
|
|
200
|
-
case "Refinement":
|
|
201
|
-
{
|
|
202
|
-
const op = toOp(ast, ctx, path);
|
|
203
|
-
ctx = op._tag === "Deferred" ? {
|
|
204
|
-
...ctx,
|
|
205
|
-
constraints: op.config
|
|
206
|
-
} : ctx;
|
|
207
|
-
const from = go(ast.from, ctx, path);
|
|
208
|
-
return new Succeed(hook.value(from, ctx), op.filters).toLazyArbitrary();
|
|
209
|
-
}
|
|
210
|
-
default:
|
|
211
|
-
return hook.value(ctx);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (AST.isDeclaration(ast)) {
|
|
215
|
-
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
216
|
-
}
|
|
217
|
-
const op = toOp(ast, ctx, path);
|
|
218
|
-
switch (op._tag) {
|
|
219
|
-
case "Succeed":
|
|
220
|
-
return op.toLazyArbitrary();
|
|
221
|
-
case "Deferred":
|
|
222
|
-
return new Succeed(op.toLazyArbitrary(ctx, path), op.filters).toLazyArbitrary();
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
const constStringConstraints = /*#__PURE__*/makeStringConstraints({});
|
|
226
|
-
const constNumberConstraints = /*#__PURE__*/makeNumberConstraints({});
|
|
227
|
-
const constBigIntConstraints = /*#__PURE__*/makeBigIntConstraints({});
|
|
228
|
-
const defaultSuspendedArrayConstraints = {
|
|
229
|
-
maxLength: 2
|
|
230
|
-
};
|
|
137
|
+
const getArbitraryAnnotation = /*#__PURE__*/SchemaAST.getAnnotation(SchemaAST.ArbitraryAnnotationId);
|
|
231
138
|
const getASTConstraints = ast => {
|
|
232
|
-
const TypeAnnotationId = ast.annotations[
|
|
139
|
+
const TypeAnnotationId = ast.annotations[SchemaAST.SchemaIdAnnotationId];
|
|
233
140
|
if (Predicate.isPropertyKey(TypeAnnotationId)) {
|
|
234
141
|
const out = ast.annotations[TypeAnnotationId];
|
|
235
142
|
if (Predicate.isReadonlyRecord(out)) {
|
|
@@ -237,122 +144,573 @@ const getASTConstraints = ast => {
|
|
|
237
144
|
}
|
|
238
145
|
}
|
|
239
146
|
};
|
|
147
|
+
const idMemoMap = /*#__PURE__*/(0, _GlobalValue.globalValue)( /*#__PURE__*/Symbol.for("effect/Arbitrary/IdMemoMap"), () => new Map());
|
|
148
|
+
let counter = 0;
|
|
149
|
+
function wrapGetDescription(f, g) {
|
|
150
|
+
return (ast, path) => f(ast, g(ast, path));
|
|
151
|
+
}
|
|
152
|
+
function parseMeta(ast) {
|
|
153
|
+
const jsonSchema = SchemaAST.getJSONSchemaAnnotation(ast).pipe(Option.filter(Predicate.isReadonlyRecord), Option.getOrUndefined);
|
|
154
|
+
const schemaId = Option.getOrElse(SchemaAST.getSchemaIdAnnotation(ast), () => undefined);
|
|
155
|
+
const schemaParams = Option.fromNullable(schemaId).pipe(Option.map(id => ast.annotations[id]), Option.filter(Predicate.isReadonlyRecord), Option.getOrUndefined);
|
|
156
|
+
return [schemaId, {
|
|
157
|
+
...schemaParams,
|
|
158
|
+
...jsonSchema
|
|
159
|
+
}];
|
|
160
|
+
}
|
|
240
161
|
/** @internal */
|
|
241
|
-
const
|
|
162
|
+
const getDescription = exports.getDescription = /*#__PURE__*/wrapGetDescription((ast, description) => {
|
|
163
|
+
const annotation = getArbitraryAnnotation(ast);
|
|
164
|
+
if (Option.isSome(annotation)) {
|
|
165
|
+
return {
|
|
166
|
+
...description,
|
|
167
|
+
annotations: [...description.annotations, annotation.value]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return description;
|
|
171
|
+
}, (ast, path) => {
|
|
172
|
+
const [schemaId, meta] = parseMeta(ast);
|
|
242
173
|
switch (ast._tag) {
|
|
174
|
+
case "Refinement":
|
|
175
|
+
{
|
|
176
|
+
const from = getDescription(ast.from, path);
|
|
177
|
+
switch (from._tag) {
|
|
178
|
+
case "StringKeyword":
|
|
179
|
+
return {
|
|
180
|
+
...from,
|
|
181
|
+
constraints: [...from.constraints, makeStringConstraints(meta)],
|
|
182
|
+
refinements: [...from.refinements, ast]
|
|
183
|
+
};
|
|
184
|
+
case "NumberKeyword":
|
|
185
|
+
{
|
|
186
|
+
const c = schemaId === schemaId_.NonNaNSchemaId ? makeNumberConstraints({
|
|
187
|
+
noNaN: true
|
|
188
|
+
}) : makeNumberConstraints({
|
|
189
|
+
isInteger: "type" in meta && meta.type === "integer",
|
|
190
|
+
noNaN: "type" in meta && meta.type === "number" ? true : undefined,
|
|
191
|
+
noDefaultInfinity: "type" in meta && meta.type === "number" ? true : undefined,
|
|
192
|
+
min: meta.exclusiveMinimum ?? meta.minimum,
|
|
193
|
+
minExcluded: "exclusiveMinimum" in meta ? true : undefined,
|
|
194
|
+
max: meta.exclusiveMaximum ?? meta.maximum,
|
|
195
|
+
maxExcluded: "exclusiveMaximum" in meta ? true : undefined
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
...from,
|
|
199
|
+
constraints: [...from.constraints, c],
|
|
200
|
+
refinements: [...from.refinements, ast]
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
case "BigIntKeyword":
|
|
204
|
+
{
|
|
205
|
+
const c = getASTConstraints(ast);
|
|
206
|
+
return {
|
|
207
|
+
...from,
|
|
208
|
+
constraints: c !== undefined ? [...from.constraints, makeBigIntConstraints(c)] : from.constraints,
|
|
209
|
+
refinements: [...from.refinements, ast]
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
case "TupleType":
|
|
213
|
+
return {
|
|
214
|
+
...from,
|
|
215
|
+
constraints: [...from.constraints, makeArrayConstraints({
|
|
216
|
+
minLength: meta.minItems,
|
|
217
|
+
maxLength: meta.maxItems
|
|
218
|
+
})],
|
|
219
|
+
refinements: [...from.refinements, ast]
|
|
220
|
+
};
|
|
221
|
+
case "DateFromSelf":
|
|
222
|
+
return {
|
|
223
|
+
...from,
|
|
224
|
+
constraints: [...from.constraints, makeDateConstraints(meta)],
|
|
225
|
+
refinements: [...from.refinements, ast]
|
|
226
|
+
};
|
|
227
|
+
default:
|
|
228
|
+
return {
|
|
229
|
+
...from,
|
|
230
|
+
refinements: [...from.refinements, ast]
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
243
234
|
case "Declaration":
|
|
244
235
|
{
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
236
|
+
if (schemaId === schemaId_.DateFromSelfSchemaId) {
|
|
237
|
+
return {
|
|
238
|
+
_tag: "DateFromSelf",
|
|
239
|
+
constraints: [makeDateConstraints(meta)],
|
|
240
|
+
path,
|
|
241
|
+
refinements: [],
|
|
242
|
+
annotations: []
|
|
243
|
+
};
|
|
251
244
|
}
|
|
252
|
-
return
|
|
245
|
+
return {
|
|
246
|
+
_tag: "Declaration",
|
|
247
|
+
typeParameters: ast.typeParameters.map(ast => getDescription(ast, path)),
|
|
248
|
+
path,
|
|
249
|
+
refinements: [],
|
|
250
|
+
annotations: [],
|
|
251
|
+
ast
|
|
252
|
+
};
|
|
253
253
|
}
|
|
254
254
|
case "Literal":
|
|
255
|
-
|
|
255
|
+
{
|
|
256
|
+
return {
|
|
257
|
+
_tag: "Literal",
|
|
258
|
+
literal: ast.literal,
|
|
259
|
+
path,
|
|
260
|
+
refinements: [],
|
|
261
|
+
annotations: []
|
|
262
|
+
};
|
|
263
|
+
}
|
|
256
264
|
case "UniqueSymbol":
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
265
|
+
{
|
|
266
|
+
return {
|
|
267
|
+
_tag: "UniqueSymbol",
|
|
268
|
+
symbol: ast.symbol,
|
|
269
|
+
path,
|
|
270
|
+
refinements: [],
|
|
271
|
+
annotations: []
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
case "Enums":
|
|
275
|
+
{
|
|
276
|
+
return {
|
|
277
|
+
_tag: "Enums",
|
|
278
|
+
enums: ast.enums,
|
|
279
|
+
path,
|
|
280
|
+
refinements: [],
|
|
281
|
+
annotations: [],
|
|
282
|
+
ast
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
case "TemplateLiteral":
|
|
286
|
+
{
|
|
287
|
+
return {
|
|
288
|
+
_tag: "TemplateLiteral",
|
|
289
|
+
head: ast.head,
|
|
290
|
+
spans: ast.spans.map(span => ({
|
|
291
|
+
description: getDescription(span.type, path),
|
|
292
|
+
literal: span.literal
|
|
293
|
+
})),
|
|
294
|
+
path,
|
|
295
|
+
refinements: [],
|
|
296
|
+
annotations: []
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
case "StringKeyword":
|
|
300
|
+
return {
|
|
301
|
+
_tag: "StringKeyword",
|
|
302
|
+
constraints: [],
|
|
303
|
+
path,
|
|
304
|
+
refinements: [],
|
|
305
|
+
annotations: []
|
|
306
|
+
};
|
|
307
|
+
case "NumberKeyword":
|
|
308
|
+
return {
|
|
309
|
+
_tag: "NumberKeyword",
|
|
310
|
+
constraints: [],
|
|
311
|
+
path,
|
|
312
|
+
refinements: [],
|
|
313
|
+
annotations: []
|
|
314
|
+
};
|
|
315
|
+
case "BigIntKeyword":
|
|
316
|
+
return {
|
|
317
|
+
_tag: "BigIntKeyword",
|
|
318
|
+
constraints: [],
|
|
319
|
+
path,
|
|
320
|
+
refinements: [],
|
|
321
|
+
annotations: []
|
|
322
|
+
};
|
|
323
|
+
case "TupleType":
|
|
324
|
+
return {
|
|
325
|
+
_tag: "TupleType",
|
|
326
|
+
constraints: [],
|
|
327
|
+
elements: ast.elements.map((element, i) => ({
|
|
328
|
+
isOptional: element.isOptional,
|
|
329
|
+
description: getDescription(element.type, [...path, i])
|
|
330
|
+
})),
|
|
331
|
+
rest: ast.rest.map((element, i) => getDescription(element.type, [...path, i])),
|
|
332
|
+
path,
|
|
333
|
+
refinements: [],
|
|
334
|
+
annotations: []
|
|
335
|
+
};
|
|
336
|
+
case "TypeLiteral":
|
|
337
|
+
return {
|
|
338
|
+
_tag: "TypeLiteral",
|
|
339
|
+
propertySignatures: ast.propertySignatures.map(ps => ({
|
|
340
|
+
isOptional: ps.isOptional,
|
|
341
|
+
name: ps.name,
|
|
342
|
+
value: getDescription(ps.type, [...path, ps.name])
|
|
343
|
+
})),
|
|
344
|
+
indexSignatures: ast.indexSignatures.map(is => ({
|
|
345
|
+
parameter: getDescription(is.parameter, path),
|
|
346
|
+
value: getDescription(is.type, path)
|
|
347
|
+
})),
|
|
348
|
+
path,
|
|
349
|
+
refinements: [],
|
|
350
|
+
annotations: []
|
|
351
|
+
};
|
|
352
|
+
case "Union":
|
|
353
|
+
return {
|
|
354
|
+
_tag: "Union",
|
|
355
|
+
members: ast.types.map((member, i) => getDescription(member, [...path, i])),
|
|
356
|
+
path,
|
|
357
|
+
refinements: [],
|
|
358
|
+
annotations: []
|
|
359
|
+
};
|
|
360
|
+
case "Suspend":
|
|
361
|
+
{
|
|
362
|
+
const memoId = idMemoMap.get(ast);
|
|
363
|
+
if (memoId !== undefined) {
|
|
364
|
+
return {
|
|
365
|
+
_tag: "Ref",
|
|
366
|
+
id: memoId,
|
|
367
|
+
ast,
|
|
368
|
+
path,
|
|
369
|
+
refinements: [],
|
|
370
|
+
annotations: []
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
counter++;
|
|
374
|
+
const id = `__id-${counter}__`;
|
|
375
|
+
idMemoMap.set(ast, id);
|
|
376
|
+
return {
|
|
377
|
+
_tag: "Suspend",
|
|
378
|
+
id,
|
|
379
|
+
ast,
|
|
380
|
+
description: () => getDescription(ast.f(), path),
|
|
381
|
+
path,
|
|
382
|
+
refinements: [],
|
|
383
|
+
annotations: []
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
case "Transformation":
|
|
387
|
+
return getDescription(ast.to, path);
|
|
260
388
|
case "NeverKeyword":
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
389
|
+
return {
|
|
390
|
+
_tag: "NeverKeyword",
|
|
391
|
+
path,
|
|
392
|
+
refinements: [],
|
|
393
|
+
annotations: [],
|
|
394
|
+
ast
|
|
395
|
+
};
|
|
396
|
+
default:
|
|
397
|
+
{
|
|
398
|
+
return {
|
|
399
|
+
_tag: "Keyword",
|
|
400
|
+
value: ast._tag,
|
|
401
|
+
path,
|
|
402
|
+
refinements: [],
|
|
403
|
+
annotations: []
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
function getMax(n1, n2) {
|
|
409
|
+
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n2 : n1;
|
|
410
|
+
}
|
|
411
|
+
function getMin(n1, n2) {
|
|
412
|
+
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n1 : n2;
|
|
413
|
+
}
|
|
414
|
+
const getOr = (a, b) => {
|
|
415
|
+
return a === undefined ? b : b === undefined ? a : a || b;
|
|
416
|
+
};
|
|
417
|
+
function mergePattern(pattern1, pattern2) {
|
|
418
|
+
if (pattern1 === undefined) {
|
|
419
|
+
return pattern2;
|
|
420
|
+
}
|
|
421
|
+
if (pattern2 === undefined) {
|
|
422
|
+
return pattern1;
|
|
423
|
+
}
|
|
424
|
+
return `(?:${pattern1})|(?:${pattern2})`;
|
|
425
|
+
}
|
|
426
|
+
function mergeStringConstraints(c1, c2) {
|
|
427
|
+
return makeStringConstraints({
|
|
428
|
+
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
429
|
+
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength),
|
|
430
|
+
pattern: mergePattern(c1.pattern, c2.pattern)
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
function buildStringConstraints(description) {
|
|
434
|
+
return description.constraints.length === 0 ? undefined : description.constraints.reduce(mergeStringConstraints);
|
|
435
|
+
}
|
|
436
|
+
function mergeNumberConstraints(c1, c2) {
|
|
437
|
+
return makeNumberConstraints({
|
|
438
|
+
isInteger: c1.isInteger || c2.isInteger,
|
|
439
|
+
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
440
|
+
minExcluded: getOr(c1.constraints.minExcluded, c2.constraints.minExcluded),
|
|
441
|
+
max: getMin(c1.constraints.max, c2.constraints.max),
|
|
442
|
+
maxExcluded: getOr(c1.constraints.maxExcluded, c2.constraints.maxExcluded),
|
|
443
|
+
noNaN: getOr(c1.constraints.noNaN, c2.constraints.noNaN),
|
|
444
|
+
noDefaultInfinity: getOr(c1.constraints.noDefaultInfinity, c2.constraints.noDefaultInfinity)
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function buildNumberConstraints(description) {
|
|
448
|
+
return description.constraints.length === 0 ? undefined : description.constraints.reduce(mergeNumberConstraints);
|
|
449
|
+
}
|
|
450
|
+
function mergeBigIntConstraints(c1, c2) {
|
|
451
|
+
return makeBigIntConstraints({
|
|
452
|
+
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
453
|
+
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
function buildBigIntConstraints(description) {
|
|
457
|
+
return description.constraints.length === 0 ? undefined : description.constraints.reduce(mergeBigIntConstraints);
|
|
458
|
+
}
|
|
459
|
+
function mergeDateConstraints(c1, c2) {
|
|
460
|
+
return makeDateConstraints({
|
|
461
|
+
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
462
|
+
max: getMin(c1.constraints.max, c2.constraints.max),
|
|
463
|
+
noInvalidDate: getOr(c1.constraints.noInvalidDate, c2.constraints.noInvalidDate)
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
function buildDateConstraints(description) {
|
|
467
|
+
return description.constraints.length === 0 ? undefined : description.constraints.reduce(mergeDateConstraints);
|
|
468
|
+
}
|
|
469
|
+
const constArrayConstraints = /*#__PURE__*/makeArrayConstraints({});
|
|
470
|
+
function mergeArrayConstraints(c1, c2) {
|
|
471
|
+
return makeArrayConstraints({
|
|
472
|
+
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
473
|
+
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength)
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
function buildArrayConstraints(description) {
|
|
477
|
+
return description.constraints.length === 0 ? undefined : description.constraints.reduce(mergeArrayConstraints);
|
|
478
|
+
}
|
|
479
|
+
const arbitraryMemoMap = /*#__PURE__*/(0, _GlobalValue.globalValue)( /*#__PURE__*/Symbol.for("effect/Arbitrary/arbitraryMemoMap"), () => new WeakMap());
|
|
480
|
+
function applyFilters(filters, arb) {
|
|
481
|
+
return fc => filters.reduce((arb, filter) => arb.filter(filter), arb(fc));
|
|
482
|
+
}
|
|
483
|
+
function absurd(message) {
|
|
484
|
+
return () => {
|
|
485
|
+
throw new Error(message);
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
function getContextConstraints(description) {
|
|
489
|
+
switch (description._tag) {
|
|
266
490
|
case "StringKeyword":
|
|
267
|
-
return
|
|
491
|
+
return buildStringConstraints(description);
|
|
268
492
|
case "NumberKeyword":
|
|
269
|
-
return
|
|
270
|
-
case "BooleanKeyword":
|
|
271
|
-
return new Succeed(fc => fc.boolean());
|
|
493
|
+
return buildNumberConstraints(description);
|
|
272
494
|
case "BigIntKeyword":
|
|
273
|
-
return
|
|
274
|
-
case "
|
|
275
|
-
return
|
|
276
|
-
case "
|
|
277
|
-
return
|
|
278
|
-
|
|
495
|
+
return buildBigIntConstraints(description);
|
|
496
|
+
case "DateFromSelf":
|
|
497
|
+
return buildDateConstraints(description);
|
|
498
|
+
case "TupleType":
|
|
499
|
+
return buildArrayConstraints(description);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function wrapGo(f, g) {
|
|
503
|
+
return (description, ctx) => f(description, ctx, g(description, ctx));
|
|
504
|
+
}
|
|
505
|
+
const go = /*#__PURE__*/wrapGo((description, ctx, lazyArb) => {
|
|
506
|
+
const annotation = description.annotations[description.annotations.length - 1];
|
|
507
|
+
// error handling
|
|
508
|
+
if (annotation === undefined) {
|
|
509
|
+
switch (description._tag) {
|
|
510
|
+
case "Declaration":
|
|
511
|
+
case "NeverKeyword":
|
|
512
|
+
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(description.path, description.ast));
|
|
513
|
+
case "Enums":
|
|
514
|
+
if (description.enums.length === 0) {
|
|
515
|
+
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(description.path));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const filters = description.refinements.map(ast => a => Option.isNone(ast.filter(a, SchemaAST.defaultParseOption, ast)));
|
|
520
|
+
if (annotation === undefined) {
|
|
521
|
+
return applyFilters(filters, lazyArb);
|
|
522
|
+
}
|
|
523
|
+
const constraints = getContextConstraints(description);
|
|
524
|
+
if (constraints !== undefined) {
|
|
525
|
+
ctx = {
|
|
526
|
+
...ctx,
|
|
527
|
+
constraints
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
if (description._tag === "Declaration") {
|
|
531
|
+
return applyFilters(filters, annotation(...description.typeParameters.map(p => go(p, ctx)), ctx));
|
|
532
|
+
}
|
|
533
|
+
if (description.refinements.length > 0) {
|
|
534
|
+
// TODO(4.0): remove the `lazyArb` parameter
|
|
535
|
+
return applyFilters(filters, annotation(lazyArb, ctx));
|
|
536
|
+
}
|
|
537
|
+
return annotation(ctx);
|
|
538
|
+
}, (description, ctx) => {
|
|
539
|
+
switch (description._tag) {
|
|
540
|
+
case "DateFromSelf":
|
|
541
|
+
{
|
|
542
|
+
const constraints = buildDateConstraints(description);
|
|
543
|
+
return fc => fc.date(constraints?.constraints);
|
|
544
|
+
}
|
|
545
|
+
case "Declaration":
|
|
546
|
+
case "NeverKeyword":
|
|
547
|
+
return absurd(`BUG: cannot generate an arbitrary for ${description._tag}`);
|
|
548
|
+
case "Literal":
|
|
549
|
+
return fc => fc.constant(description.literal);
|
|
550
|
+
case "UniqueSymbol":
|
|
551
|
+
return fc => fc.constant(description.symbol);
|
|
552
|
+
case "Keyword":
|
|
279
553
|
{
|
|
280
|
-
|
|
281
|
-
|
|
554
|
+
switch (description.value) {
|
|
555
|
+
case "UndefinedKeyword":
|
|
556
|
+
return fc => fc.constant(undefined);
|
|
557
|
+
case "VoidKeyword":
|
|
558
|
+
case "UnknownKeyword":
|
|
559
|
+
case "AnyKeyword":
|
|
560
|
+
return fc => fc.anything();
|
|
561
|
+
case "BooleanKeyword":
|
|
562
|
+
return fc => fc.boolean();
|
|
563
|
+
case "SymbolKeyword":
|
|
564
|
+
return fc => fc.string().map(s => Symbol.for(s));
|
|
565
|
+
case "ObjectKeyword":
|
|
566
|
+
return fc => fc.oneof(fc.object(), fc.array(fc.anything()));
|
|
282
567
|
}
|
|
283
|
-
return new Succeed(fc => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value))));
|
|
284
568
|
}
|
|
569
|
+
case "Enums":
|
|
570
|
+
return fc => fc.oneof(...description.enums.map(([_, value]) => fc.constant(value)));
|
|
285
571
|
case "TemplateLiteral":
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const number = fc.float({
|
|
291
|
-
noDefaultInfinity: true,
|
|
292
|
-
noNaN: true
|
|
293
|
-
});
|
|
294
|
-
const getTemplateLiteralArb = ast => {
|
|
295
|
-
const components = ast.head !== "" ? [fc.constant(ast.head)] : [];
|
|
296
|
-
const getTemplateLiteralSpanTypeArb = ast => {
|
|
297
|
-
switch (ast._tag) {
|
|
298
|
-
case "StringKeyword":
|
|
299
|
-
return string;
|
|
300
|
-
case "NumberKeyword":
|
|
301
|
-
return number;
|
|
302
|
-
case "Literal":
|
|
303
|
-
return fc.constant(String(ast.literal));
|
|
304
|
-
case "Union":
|
|
305
|
-
return fc.oneof(...ast.types.map(getTemplateLiteralSpanTypeArb));
|
|
306
|
-
case "TemplateLiteral":
|
|
307
|
-
return getTemplateLiteralArb(ast);
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
ast.spans.forEach(span => {
|
|
311
|
-
components.push(getTemplateLiteralSpanTypeArb(span.type));
|
|
312
|
-
if (span.literal !== "") {
|
|
313
|
-
components.push(fc.constant(span.literal));
|
|
314
|
-
}
|
|
572
|
+
{
|
|
573
|
+
return fc => {
|
|
574
|
+
const string = fc.string({
|
|
575
|
+
maxLength: 5
|
|
315
576
|
});
|
|
316
|
-
|
|
577
|
+
const number = fc.float({
|
|
578
|
+
noDefaultInfinity: true,
|
|
579
|
+
noNaN: true
|
|
580
|
+
});
|
|
581
|
+
const getTemplateLiteralArb = description => {
|
|
582
|
+
const components = description.head !== "" ? [fc.constant(description.head)] : [];
|
|
583
|
+
const getTemplateLiteralSpanTypeArb = description => {
|
|
584
|
+
switch (description._tag) {
|
|
585
|
+
case "StringKeyword":
|
|
586
|
+
return string;
|
|
587
|
+
case "NumberKeyword":
|
|
588
|
+
return number;
|
|
589
|
+
case "Literal":
|
|
590
|
+
return fc.constant(String(description.literal));
|
|
591
|
+
case "Union":
|
|
592
|
+
return fc.oneof(...description.members.map(getTemplateLiteralSpanTypeArb));
|
|
593
|
+
case "TemplateLiteral":
|
|
594
|
+
return getTemplateLiteralArb(description);
|
|
595
|
+
default:
|
|
596
|
+
return fc.constant("");
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
description.spans.forEach(span => {
|
|
600
|
+
components.push(getTemplateLiteralSpanTypeArb(span.description));
|
|
601
|
+
if (span.literal !== "") {
|
|
602
|
+
components.push(fc.constant(span.literal));
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
return fc.tuple(...components).map(spans => spans.join(""));
|
|
606
|
+
};
|
|
607
|
+
return getTemplateLiteralArb(description);
|
|
317
608
|
};
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
case "Refinement":
|
|
609
|
+
}
|
|
610
|
+
case "StringKeyword":
|
|
321
611
|
{
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
612
|
+
const constraints = buildStringConstraints(description);
|
|
613
|
+
const pattern = constraints?.pattern;
|
|
614
|
+
return pattern !== undefined ? fc => fc.stringMatching(new RegExp(pattern)) : fc => fc.string(constraints?.constraints);
|
|
615
|
+
}
|
|
616
|
+
case "NumberKeyword":
|
|
617
|
+
{
|
|
618
|
+
const constraints = buildNumberConstraints(description);
|
|
619
|
+
return constraints?.isInteger ? fc => fc.integer(constraints.constraints) : fc => fc.float(constraints?.constraints);
|
|
620
|
+
}
|
|
621
|
+
case "BigIntKeyword":
|
|
622
|
+
{
|
|
623
|
+
const constraints = buildBigIntConstraints(description);
|
|
624
|
+
return fc => fc.bigInt(constraints?.constraints ?? {});
|
|
334
625
|
}
|
|
335
626
|
case "TupleType":
|
|
336
|
-
return new Deferred(makeArrayConfig({}, ast));
|
|
337
|
-
case "TypeLiteral":
|
|
338
627
|
{
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
628
|
+
const elements = [];
|
|
629
|
+
let hasOptionals = false;
|
|
630
|
+
for (const element of description.elements) {
|
|
631
|
+
elements.push(go(element.description, ctx));
|
|
632
|
+
if (element.isOptional) {
|
|
633
|
+
hasOptionals = true;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const rest = description.rest.map(d => go(d, ctx));
|
|
637
|
+
return fc => {
|
|
638
|
+
// ---------------------------------------------
|
|
639
|
+
// handle elements
|
|
640
|
+
// ---------------------------------------------
|
|
641
|
+
let output = fc.tuple(...elements.map(arb => arb(fc)));
|
|
642
|
+
if (hasOptionals) {
|
|
643
|
+
const indexes = fc.tuple(...description.elements.map(element => element.isOptional ? fc.boolean() : fc.constant(true)));
|
|
644
|
+
output = output.chain(tuple => indexes.map(booleans => {
|
|
645
|
+
for (const [i, b] of booleans.reverse().entries()) {
|
|
646
|
+
if (!b) {
|
|
647
|
+
tuple.splice(booleans.length - i, 1);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return tuple;
|
|
651
|
+
}));
|
|
652
|
+
}
|
|
344
653
|
// ---------------------------------------------
|
|
345
|
-
// handle
|
|
654
|
+
// handle rest element
|
|
346
655
|
// ---------------------------------------------
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
656
|
+
if (Arr.isNonEmptyReadonlyArray(rest)) {
|
|
657
|
+
const constraints = buildArrayConstraints(description) ?? constArrayConstraints;
|
|
658
|
+
const [head, ...tail] = rest;
|
|
659
|
+
const item = head(fc);
|
|
660
|
+
output = output.chain(as => {
|
|
661
|
+
const len = as.length;
|
|
662
|
+
// We must adjust the constraints for the rest element
|
|
663
|
+
// because the elements might have generated some values
|
|
664
|
+
const restArrayConstraints = subtractElementsLength(constraints.constraints, len);
|
|
665
|
+
if (restArrayConstraints.maxLength === 0) {
|
|
666
|
+
return fc.constant(as);
|
|
667
|
+
}
|
|
668
|
+
/*
|
|
669
|
+
`getSuspendedArray` is used to generate less values in
|
|
670
|
+
the context of a recursive schema. Without it, the following schema
|
|
671
|
+
would generate an big amount of values possibly leading to a stack
|
|
672
|
+
overflow:
|
|
673
|
+
```ts
|
|
674
|
+
type A = ReadonlyArray<A | null>
|
|
675
|
+
const schema = S.Array(
|
|
676
|
+
S.NullOr(S.suspend((): S.Schema<A> => schema))
|
|
677
|
+
)
|
|
678
|
+
```
|
|
679
|
+
*/
|
|
680
|
+
const arr = ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, restArrayConstraints) : fc.array(item, restArrayConstraints);
|
|
681
|
+
if (len === 0) {
|
|
682
|
+
return arr;
|
|
683
|
+
}
|
|
684
|
+
return arr.map(rest => [...as, ...rest]);
|
|
685
|
+
});
|
|
686
|
+
// ---------------------------------------------
|
|
687
|
+
// handle post rest elements
|
|
688
|
+
// ---------------------------------------------
|
|
689
|
+
for (let j = 0; j < tail.length; j++) {
|
|
690
|
+
output = output.chain(as => tail[j](fc).map(a => [...as, a]));
|
|
352
691
|
}
|
|
353
|
-
arbs[name] = propertySignaturesTypes[i](fc);
|
|
354
692
|
}
|
|
355
|
-
|
|
693
|
+
return output;
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
case "TypeLiteral":
|
|
697
|
+
{
|
|
698
|
+
const propertySignatures = [];
|
|
699
|
+
const requiredKeys = [];
|
|
700
|
+
for (const ps of description.propertySignatures) {
|
|
701
|
+
if (!ps.isOptional) {
|
|
702
|
+
requiredKeys.push(ps.name);
|
|
703
|
+
}
|
|
704
|
+
propertySignatures.push(go(ps.value, ctx));
|
|
705
|
+
}
|
|
706
|
+
const indexSignatures = description.indexSignatures.map(is => [go(is.parameter, ctx), go(is.value, ctx)]);
|
|
707
|
+
return fc => {
|
|
708
|
+
const pps = {};
|
|
709
|
+
for (let i = 0; i < propertySignatures.length; i++) {
|
|
710
|
+
const ps = description.propertySignatures[i];
|
|
711
|
+
pps[ps.name] = propertySignatures[i](fc);
|
|
712
|
+
}
|
|
713
|
+
let output = fc.record(pps, {
|
|
356
714
|
requiredKeys
|
|
357
715
|
});
|
|
358
716
|
// ---------------------------------------------
|
|
@@ -364,16 +722,18 @@ const toOp = (ast, ctx, path) => {
|
|
|
364
722
|
output = output.chain(o => {
|
|
365
723
|
const item = fc.tuple(key, value);
|
|
366
724
|
/*
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const arr = ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item,
|
|
725
|
+
`getSuspendedArray` is used to generate less key/value pairs in
|
|
726
|
+
the context of a recursive schema. Without it, the following schema
|
|
727
|
+
would generate an big amount of values possibly leading to a stack
|
|
728
|
+
overflow:
|
|
729
|
+
```ts
|
|
730
|
+
type A = { [_: string]: A }
|
|
731
|
+
const schema = S.Record({ key: S.String, value: S.suspend((): S.Schema<A> => schema) })
|
|
732
|
+
```
|
|
733
|
+
*/
|
|
734
|
+
const arr = ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, {
|
|
735
|
+
maxLength: 2
|
|
736
|
+
}) : fc.array(item);
|
|
377
737
|
return arr.map(tuples => ({
|
|
378
738
|
...Object.fromEntries(tuples),
|
|
379
739
|
...o
|
|
@@ -381,238 +741,57 @@ const toOp = (ast, ctx, path) => {
|
|
|
381
741
|
});
|
|
382
742
|
}
|
|
383
743
|
return output;
|
|
384
|
-
}
|
|
744
|
+
};
|
|
385
745
|
}
|
|
386
746
|
case "Union":
|
|
387
747
|
{
|
|
388
|
-
const
|
|
389
|
-
return
|
|
748
|
+
const members = description.members.map(member => go(member, ctx));
|
|
749
|
+
return fc => fc.oneof(...members.map(arb => arb(fc)));
|
|
390
750
|
}
|
|
391
751
|
case "Suspend":
|
|
392
752
|
{
|
|
393
|
-
const memo = arbitraryMemoMap.get(ast);
|
|
753
|
+
const memo = arbitraryMemoMap.get(description.ast);
|
|
394
754
|
if (memo) {
|
|
395
|
-
return
|
|
755
|
+
return memo;
|
|
756
|
+
}
|
|
757
|
+
if (ctx.depthIdentifier === undefined) {
|
|
758
|
+
ctx = {
|
|
759
|
+
...ctx,
|
|
760
|
+
depthIdentifier: description.id
|
|
761
|
+
};
|
|
396
762
|
}
|
|
397
763
|
const get = util_.memoizeThunk(() => {
|
|
398
|
-
return go(
|
|
764
|
+
return go(description.description(), ctx);
|
|
399
765
|
});
|
|
400
766
|
const out = fc => fc.constant(null).chain(() => get()(fc));
|
|
401
|
-
arbitraryMemoMap.set(ast, out);
|
|
402
|
-
return
|
|
767
|
+
arbitraryMemoMap.set(description.ast, out);
|
|
768
|
+
return out;
|
|
769
|
+
}
|
|
770
|
+
case "Ref":
|
|
771
|
+
{
|
|
772
|
+
const memo = arbitraryMemoMap.get(description.ast);
|
|
773
|
+
if (memo) {
|
|
774
|
+
return memo;
|
|
775
|
+
}
|
|
776
|
+
throw new Error(`BUG: Ref ${JSON.stringify(description.id)} not found`);
|
|
403
777
|
}
|
|
404
|
-
case "Transformation":
|
|
405
|
-
return toOp(ast.to, ctx, path);
|
|
406
778
|
}
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (elementsLength === 0 || constraints.minLength === undefined && constraints.maxLength === undefined) {
|
|
779
|
+
});
|
|
780
|
+
function subtractElementsLength(constraints, len) {
|
|
781
|
+
if (len === 0 || constraints.minLength === undefined && constraints.maxLength === undefined) {
|
|
411
782
|
return constraints;
|
|
412
783
|
}
|
|
413
784
|
const out = {
|
|
414
785
|
...constraints
|
|
415
786
|
};
|
|
416
787
|
if (out.minLength !== undefined) {
|
|
417
|
-
out.minLength = Math.max(out.minLength -
|
|
788
|
+
out.minLength = Math.max(out.minLength - len, 0);
|
|
418
789
|
}
|
|
419
790
|
if (out.maxLength !== undefined) {
|
|
420
|
-
out.maxLength = Math.max(out.maxLength -
|
|
791
|
+
out.maxLength = Math.max(out.maxLength - len, 0);
|
|
421
792
|
}
|
|
422
793
|
return out;
|
|
423
794
|
}
|
|
424
|
-
const goTupleType = (ast, ctx, path, constraints) => {
|
|
425
|
-
const elements = [];
|
|
426
|
-
let hasOptionals = false;
|
|
427
|
-
let i = 0;
|
|
428
|
-
for (const element of ast.elements) {
|
|
429
|
-
elements.push(go(element.type, ctx, path.concat(i++)));
|
|
430
|
-
if (element.isOptional) {
|
|
431
|
-
hasOptionals = true;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, ctx, path));
|
|
435
|
-
return fc => {
|
|
436
|
-
// ---------------------------------------------
|
|
437
|
-
// handle elements
|
|
438
|
-
// ---------------------------------------------
|
|
439
|
-
let output = fc.tuple(...elements.map(arb => arb(fc)));
|
|
440
|
-
if (hasOptionals) {
|
|
441
|
-
const indexes = fc.tuple(...ast.elements.map(element => element.isOptional ? fc.boolean() : fc.constant(true)));
|
|
442
|
-
output = output.chain(tuple => indexes.map(booleans => {
|
|
443
|
-
for (const [i, b] of booleans.reverse().entries()) {
|
|
444
|
-
if (!b) {
|
|
445
|
-
tuple.splice(booleans.length - i, 1);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return tuple;
|
|
449
|
-
}));
|
|
450
|
-
}
|
|
451
|
-
// ---------------------------------------------
|
|
452
|
-
// handle rest element
|
|
453
|
-
// ---------------------------------------------
|
|
454
|
-
if (Arr.isNonEmptyReadonlyArray(rest)) {
|
|
455
|
-
const [head, ...tail] = rest;
|
|
456
|
-
const item = head(fc);
|
|
457
|
-
output = output.chain(as => {
|
|
458
|
-
const len = as.length;
|
|
459
|
-
// We must adjust the constraints for the rest element
|
|
460
|
-
// because the elements might have generated some values
|
|
461
|
-
const restArrayConstraints = subtractElementsLength(constraints, len);
|
|
462
|
-
if (restArrayConstraints.maxLength === 0) {
|
|
463
|
-
return fc.constant(as);
|
|
464
|
-
}
|
|
465
|
-
/*
|
|
466
|
-
`getSuspendedArray` is used to generate less values in
|
|
467
|
-
the context of a recursive schema. Without it, the following schema
|
|
468
|
-
would generate an big amount of values possibly leading to a stack
|
|
469
|
-
overflow:
|
|
470
|
-
```ts
|
|
471
|
-
type A = ReadonlyArray<A | null>
|
|
472
|
-
const schema = S.Array(
|
|
473
|
-
S.NullOr(S.suspend((): S.Schema<A> => schema))
|
|
474
|
-
)
|
|
475
|
-
```
|
|
476
|
-
*/
|
|
477
|
-
const arr = ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, restArrayConstraints) : fc.array(item, restArrayConstraints);
|
|
478
|
-
if (len === 0) {
|
|
479
|
-
return arr;
|
|
480
|
-
}
|
|
481
|
-
return arr.map(rest => [...as, ...rest]);
|
|
482
|
-
});
|
|
483
|
-
// ---------------------------------------------
|
|
484
|
-
// handle post rest elements
|
|
485
|
-
// ---------------------------------------------
|
|
486
|
-
for (let j = 0; j < tail.length; j++) {
|
|
487
|
-
output = output.chain(as => tail[j](fc).map(a => [...as, a]));
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
return output;
|
|
491
|
-
};
|
|
492
|
-
};
|
|
493
|
-
const getRefinementConstraints = (_tag, ast) => {
|
|
494
|
-
const TypeAnnotationId = ast.annotations[AST.SchemaIdAnnotationId];
|
|
495
|
-
const jsonSchema = Option.getOrElse(AST.getJSONSchemaAnnotation(ast), () => ({}));
|
|
496
|
-
switch (_tag) {
|
|
497
|
-
case "StringConstraints":
|
|
498
|
-
return makeStringConstraints(jsonSchema);
|
|
499
|
-
case "NumberConstraints":
|
|
500
|
-
{
|
|
501
|
-
if (TypeAnnotationId === schemaId_.NonNaNSchemaId) {
|
|
502
|
-
return makeNumberConstraints({
|
|
503
|
-
noNaN: true
|
|
504
|
-
});
|
|
505
|
-
} else {
|
|
506
|
-
return makeNumberConstraints({
|
|
507
|
-
isInteger: "type" in jsonSchema && jsonSchema.type === "integer",
|
|
508
|
-
noNaN: "type" in jsonSchema && jsonSchema.type === "number" ? true : undefined,
|
|
509
|
-
noDefaultInfinity: "type" in jsonSchema && jsonSchema.type === "number" ? true : undefined,
|
|
510
|
-
min: jsonSchema.exclusiveMinimum ?? jsonSchema.minimum,
|
|
511
|
-
minExcluded: "exclusiveMinimum" in jsonSchema ? true : undefined,
|
|
512
|
-
max: jsonSchema.exclusiveMaximum ?? jsonSchema.maximum,
|
|
513
|
-
maxExcluded: "exclusiveMaximum" in jsonSchema ? true : undefined
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
case "BigIntConstraints":
|
|
518
|
-
{
|
|
519
|
-
const c = getASTConstraints(ast);
|
|
520
|
-
return c !== undefined ? makeBigIntConstraints(c) : undefined;
|
|
521
|
-
}
|
|
522
|
-
case "DateConstraints":
|
|
523
|
-
{
|
|
524
|
-
const c = getASTConstraints(ast);
|
|
525
|
-
return c !== undefined ? makeDateConstraints(c) : undefined;
|
|
526
|
-
}
|
|
527
|
-
case "ArrayConstraints":
|
|
528
|
-
return makeArrayConstraints({
|
|
529
|
-
minLength: jsonSchema.minItems,
|
|
530
|
-
maxLength: jsonSchema.maxItems
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
};
|
|
534
|
-
function getMax(n1, n2) {
|
|
535
|
-
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n2 : n1;
|
|
536
|
-
}
|
|
537
|
-
function getMin(n1, n2) {
|
|
538
|
-
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n1 : n2;
|
|
539
|
-
}
|
|
540
|
-
const getOr = (a, b) => {
|
|
541
|
-
return a === undefined ? b : b === undefined ? a : a || b;
|
|
542
|
-
};
|
|
543
|
-
function mergePattern(pattern1, pattern2) {
|
|
544
|
-
if (pattern1 === undefined) {
|
|
545
|
-
return pattern2;
|
|
546
|
-
}
|
|
547
|
-
if (pattern2 === undefined) {
|
|
548
|
-
return pattern1;
|
|
549
|
-
}
|
|
550
|
-
return `(?:${pattern1})|(?:${pattern2})`;
|
|
551
|
-
}
|
|
552
|
-
const merge = (c1, c2) => {
|
|
553
|
-
if (c2) {
|
|
554
|
-
switch (c1._tag) {
|
|
555
|
-
case "StringConstraints":
|
|
556
|
-
{
|
|
557
|
-
if (c2._tag === "StringConstraints") {
|
|
558
|
-
return makeStringConstraints({
|
|
559
|
-
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
560
|
-
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength),
|
|
561
|
-
pattern: mergePattern(c1.pattern, c2.pattern)
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
break;
|
|
565
|
-
}
|
|
566
|
-
case "NumberConstraints":
|
|
567
|
-
{
|
|
568
|
-
if (c2._tag === "NumberConstraints") {
|
|
569
|
-
return makeNumberConstraints({
|
|
570
|
-
isInteger: c1.isInteger || c2.isInteger,
|
|
571
|
-
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
572
|
-
minExcluded: getOr(c1.constraints.minExcluded, c2.constraints.minExcluded),
|
|
573
|
-
max: getMin(c1.constraints.max, c2.constraints.max),
|
|
574
|
-
maxExcluded: getOr(c1.constraints.maxExcluded, c2.constraints.maxExcluded),
|
|
575
|
-
noNaN: getOr(c1.constraints.noNaN, c2.constraints.noNaN),
|
|
576
|
-
noDefaultInfinity: getOr(c1.constraints.noDefaultInfinity, c2.constraints.noDefaultInfinity)
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
break;
|
|
580
|
-
}
|
|
581
|
-
case "BigIntConstraints":
|
|
582
|
-
{
|
|
583
|
-
if (c2._tag === "BigIntConstraints") {
|
|
584
|
-
return makeBigIntConstraints({
|
|
585
|
-
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
586
|
-
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
break;
|
|
590
|
-
}
|
|
591
|
-
case "DateConstraints":
|
|
592
|
-
{
|
|
593
|
-
if (c2._tag === "DateConstraints") {
|
|
594
|
-
return makeDateConstraints({
|
|
595
|
-
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
596
|
-
max: getMin(c1.constraints.max, c2.constraints.max),
|
|
597
|
-
noInvalidDate: getOr(c1.constraints.noInvalidDate, c2.constraints.noInvalidDate)
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
break;
|
|
601
|
-
}
|
|
602
|
-
case "ArrayConstraints":
|
|
603
|
-
{
|
|
604
|
-
if (c2._tag === "ArrayConstraints") {
|
|
605
|
-
return makeArrayConfig({
|
|
606
|
-
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
607
|
-
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength)
|
|
608
|
-
}, c1.ast);
|
|
609
|
-
}
|
|
610
|
-
break;
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
return c1;
|
|
615
|
-
};
|
|
616
795
|
const getSuspendedArray = (fc, depthIdentifier, maxDepth, item, constraints) => {
|
|
617
796
|
// In the context of a recursive schema, we don't want a `maxLength` greater than 2.
|
|
618
797
|
// The only exception is when `minLength` is also set, in which case we set
|
|
@@ -629,14 +808,4 @@ const getSuspendedArray = (fc, depthIdentifier, maxDepth, item, constraints) =>
|
|
|
629
808
|
depthIdentifier
|
|
630
809
|
}, fc.constant([]), fc.array(item, constraints));
|
|
631
810
|
};
|
|
632
|
-
const getSuspendedContext = (ctx, ast) => {
|
|
633
|
-
if (ctx.depthIdentifier !== undefined) {
|
|
634
|
-
return ctx;
|
|
635
|
-
}
|
|
636
|
-
const depthIdentifier = AST.getIdentifierAnnotation(ast).pipe(Option.orElse(() => AST.getIdentifierAnnotation(ast.f())), Option.getOrElse(() => "SuspendDefaultDepthIdentifier"));
|
|
637
|
-
return {
|
|
638
|
-
...ctx,
|
|
639
|
-
depthIdentifier
|
|
640
|
-
};
|
|
641
|
-
};
|
|
642
811
|
//# sourceMappingURL=Arbitrary.js.map
|