effect 3.11.5 → 3.11.7
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 +357 -343
- package/dist/cjs/Arbitrary.js.map +1 -1
- package/dist/cjs/JSONSchema.js +157 -38
- package/dist/cjs/JSONSchema.js.map +1 -1
- package/dist/cjs/Schema.js +49 -33
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/internal/schema/filters.js +24 -18
- package/dist/cjs/internal/schema/filters.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Arbitrary.d.ts +21 -1
- package/dist/dts/Arbitrary.d.ts.map +1 -1
- package/dist/dts/JSONSchema.d.ts +11 -2
- package/dist/dts/JSONSchema.d.ts.map +1 -1
- package/dist/dts/Schema.d.ts +46 -18
- package/dist/dts/Schema.d.ts.map +1 -1
- package/dist/esm/Arbitrary.js +351 -335
- package/dist/esm/Arbitrary.js.map +1 -1
- package/dist/esm/JSONSchema.js +157 -38
- package/dist/esm/JSONSchema.js.map +1 -1
- package/dist/esm/Schema.js +49 -33
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/internal/schema/filters.js +23 -17
- package/dist/esm/internal/schema/filters.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +1 -1
- package/src/Arbitrary.ts +410 -361
- package/src/JSONSchema.ts +185 -40
- package/src/Schema.ts +161 -74
- package/src/internal/schema/filters.ts +32 -17
- package/src/internal/version.ts +1 -1
package/dist/esm/Arbitrary.js
CHANGED
|
@@ -26,39 +26,134 @@ export const makeLazy = schema => go(schema.ast, {
|
|
|
26
26
|
*/
|
|
27
27
|
export const make = schema => makeLazy(schema)(FastCheck);
|
|
28
28
|
const getArbitraryAnnotation = /*#__PURE__*/AST.getAnnotation(AST.ArbitraryAnnotationId);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Represents an arbitrary with optional filters.
|
|
31
|
+
*/
|
|
32
|
+
class Succeed {
|
|
33
|
+
lazyArbitrary;
|
|
34
|
+
filters;
|
|
35
|
+
_tag = "Succeed";
|
|
36
|
+
constructor(lazyArbitrary, filters = []) {
|
|
37
|
+
this.lazyArbitrary = lazyArbitrary;
|
|
38
|
+
this.filters = filters;
|
|
39
|
+
}
|
|
40
|
+
toLazyArbitrary() {
|
|
41
|
+
return fc => {
|
|
42
|
+
let out = this.lazyArbitrary(fc);
|
|
43
|
+
for (const f of this.filters) {
|
|
44
|
+
out = out.filter(f);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Represents a deferred arbitrary value generator with optional filters.
|
|
52
|
+
*/
|
|
53
|
+
class Deferred {
|
|
54
|
+
config;
|
|
55
|
+
filters;
|
|
56
|
+
_tag = "Deferred";
|
|
57
|
+
constructor(config, filters = []) {
|
|
58
|
+
this.config = config;
|
|
59
|
+
this.filters = filters;
|
|
60
|
+
}
|
|
61
|
+
toLazyArbitrary(ctx, path) {
|
|
62
|
+
const config = this.config;
|
|
63
|
+
switch (config._tag) {
|
|
64
|
+
case "StringConstraints":
|
|
65
|
+
{
|
|
66
|
+
const pattern = config.pattern;
|
|
67
|
+
return pattern !== undefined ? fc => fc.stringMatching(new RegExp(pattern)) : fc => fc.string(config.constraints);
|
|
68
|
+
}
|
|
69
|
+
case "NumberConstraints":
|
|
70
|
+
{
|
|
71
|
+
return config.isInteger ? fc => fc.integer(config.constraints) : fc => fc.float(config.constraints);
|
|
72
|
+
}
|
|
73
|
+
case "BigIntConstraints":
|
|
74
|
+
return fc => fc.bigInt(config.constraints);
|
|
75
|
+
case "ArrayConstraints":
|
|
76
|
+
return goTupleType(config.ast, ctx, path, config.constraints);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** @internal */
|
|
81
|
+
export const makeStringConstraints = options => {
|
|
82
|
+
const out = {
|
|
83
|
+
_tag: "StringConstraints",
|
|
84
|
+
constraints: {}
|
|
85
|
+
};
|
|
86
|
+
if (Predicate.isNumber(options.minLength)) {
|
|
87
|
+
out.constraints.minLength = options.minLength;
|
|
88
|
+
}
|
|
89
|
+
if (Predicate.isNumber(options.maxLength)) {
|
|
90
|
+
out.constraints.maxLength = options.maxLength;
|
|
91
|
+
}
|
|
92
|
+
if (Predicate.isString(options.pattern)) {
|
|
93
|
+
out.pattern = options.pattern;
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
35
96
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
97
|
+
/** @internal */
|
|
98
|
+
export const makeNumberConstraints = options => {
|
|
99
|
+
const out = {
|
|
100
|
+
_tag: "NumberConstraints",
|
|
101
|
+
constraints: {},
|
|
102
|
+
isInteger: options.isInteger ?? false
|
|
103
|
+
};
|
|
104
|
+
if (Predicate.isNumber(options.min)) {
|
|
105
|
+
out.constraints.min = Math.fround(options.min);
|
|
39
106
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
107
|
+
if (Predicate.isBoolean(options.minExcluded)) {
|
|
108
|
+
out.constraints.minExcluded = options.minExcluded;
|
|
109
|
+
}
|
|
110
|
+
if (Predicate.isNumber(options.max)) {
|
|
111
|
+
out.constraints.max = Math.fround(options.max);
|
|
112
|
+
}
|
|
113
|
+
if (Predicate.isBoolean(options.maxExcluded)) {
|
|
114
|
+
out.constraints.maxExcluded = options.maxExcluded;
|
|
115
|
+
}
|
|
116
|
+
if (Predicate.isBoolean(options.noNaN)) {
|
|
117
|
+
out.constraints.noNaN = options.noNaN;
|
|
118
|
+
}
|
|
119
|
+
if (Predicate.isBoolean(options.noDefaultInfinity)) {
|
|
120
|
+
out.constraints.noDefaultInfinity = options.noDefaultInfinity;
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
};
|
|
124
|
+
/** @internal */
|
|
125
|
+
export const makeBigIntConstraints = options => {
|
|
126
|
+
const out = {
|
|
127
|
+
_tag: "BigIntConstraints",
|
|
128
|
+
constraints: {}
|
|
44
129
|
};
|
|
130
|
+
if (Predicate.isBigInt(options.min)) {
|
|
131
|
+
out.constraints.min = options.min;
|
|
132
|
+
}
|
|
133
|
+
if (Predicate.isBigInt(options.max)) {
|
|
134
|
+
out.constraints.max = options.max;
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
45
137
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
138
|
+
/** @internal */
|
|
139
|
+
export const makeArrayConstraints = options => {
|
|
140
|
+
const out = {
|
|
141
|
+
_tag: "ArrayConstraints",
|
|
142
|
+
constraints: {}
|
|
143
|
+
};
|
|
144
|
+
if (Predicate.isNumber(options.minLength)) {
|
|
145
|
+
out.constraints.minLength = options.minLength;
|
|
54
146
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
147
|
+
if (Predicate.isNumber(options.maxLength)) {
|
|
148
|
+
out.constraints.maxLength = options.maxLength;
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
};
|
|
152
|
+
const makeArrayConfig = (options, ast) => {
|
|
153
|
+
return {
|
|
154
|
+
ast,
|
|
155
|
+
...makeArrayConstraints(options)
|
|
156
|
+
};
|
|
62
157
|
};
|
|
63
158
|
const go = (ast, ctx, path) => {
|
|
64
159
|
const hook = getArbitraryAnnotation(ast);
|
|
@@ -67,152 +162,120 @@ const go = (ast, ctx, path) => {
|
|
|
67
162
|
case "Declaration":
|
|
68
163
|
return hook.value(...ast.typeParameters.map(p => go(p, ctx, path)), ctx);
|
|
69
164
|
case "Refinement":
|
|
70
|
-
|
|
165
|
+
{
|
|
166
|
+
const op = toOp(ast, ctx, path);
|
|
167
|
+
ctx = op._tag === "Deferred" ? {
|
|
168
|
+
...ctx,
|
|
169
|
+
constraints: op.config
|
|
170
|
+
} : ctx;
|
|
171
|
+
const from = go(ast.from, ctx, path);
|
|
172
|
+
return new Succeed(hook.value(from, ctx), op.filters).toLazyArbitrary();
|
|
173
|
+
}
|
|
71
174
|
default:
|
|
72
175
|
return hook.value(ctx);
|
|
73
176
|
}
|
|
74
177
|
}
|
|
178
|
+
if (AST.isDeclaration(ast)) {
|
|
179
|
+
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
180
|
+
}
|
|
181
|
+
const op = toOp(ast, ctx, path);
|
|
182
|
+
switch (op._tag) {
|
|
183
|
+
case "Succeed":
|
|
184
|
+
return op.toLazyArbitrary();
|
|
185
|
+
case "Deferred":
|
|
186
|
+
return new Succeed(op.toLazyArbitrary(ctx, path), op.filters).toLazyArbitrary();
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const constStringConstraints = /*#__PURE__*/makeStringConstraints({});
|
|
190
|
+
const constNumberConstraints = /*#__PURE__*/makeNumberConstraints({});
|
|
191
|
+
const constBigIntConstraints = /*#__PURE__*/makeBigIntConstraints({});
|
|
192
|
+
/** @internal */
|
|
193
|
+
export const toOp = (ast, ctx, path) => {
|
|
75
194
|
switch (ast._tag) {
|
|
76
195
|
case "Declaration":
|
|
77
|
-
|
|
78
|
-
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
79
|
-
}
|
|
196
|
+
return new Succeed(go(ast, ctx, path));
|
|
80
197
|
case "Literal":
|
|
81
|
-
return fc => fc.constant(ast.literal);
|
|
198
|
+
return new Succeed(fc => fc.constant(ast.literal));
|
|
82
199
|
case "UniqueSymbol":
|
|
83
|
-
return fc => fc.constant(ast.symbol);
|
|
200
|
+
return new Succeed(fc => fc.constant(ast.symbol));
|
|
84
201
|
case "UndefinedKeyword":
|
|
85
|
-
return fc => fc.constant(undefined);
|
|
202
|
+
return new Succeed(fc => fc.constant(undefined));
|
|
86
203
|
case "NeverKeyword":
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
204
|
+
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
205
|
+
case "VoidKeyword":
|
|
90
206
|
case "UnknownKeyword":
|
|
91
207
|
case "AnyKeyword":
|
|
92
|
-
|
|
93
|
-
return fc => fc.anything();
|
|
208
|
+
return new Succeed(fc => fc.anything());
|
|
94
209
|
case "StringKeyword":
|
|
95
|
-
return
|
|
96
|
-
if (ctx.constraints) {
|
|
97
|
-
switch (ctx.constraints._tag) {
|
|
98
|
-
case "StringConstraints":
|
|
99
|
-
return fc.string(ctx.constraints.constraints);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return fc.string();
|
|
103
|
-
};
|
|
210
|
+
return new Deferred(constStringConstraints);
|
|
104
211
|
case "NumberKeyword":
|
|
105
|
-
return
|
|
106
|
-
if (ctx.constraints) {
|
|
107
|
-
switch (ctx.constraints._tag) {
|
|
108
|
-
case "NumberConstraints":
|
|
109
|
-
return fc.float(ctx.constraints.constraints);
|
|
110
|
-
case "IntegerConstraints":
|
|
111
|
-
return fc.integer(ctx.constraints.constraints);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return fc.float();
|
|
115
|
-
};
|
|
212
|
+
return new Deferred(constNumberConstraints);
|
|
116
213
|
case "BooleanKeyword":
|
|
117
|
-
return fc => fc.boolean();
|
|
214
|
+
return new Succeed(fc => fc.boolean());
|
|
118
215
|
case "BigIntKeyword":
|
|
119
|
-
return
|
|
120
|
-
if (ctx.constraints) {
|
|
121
|
-
switch (ctx.constraints._tag) {
|
|
122
|
-
case "BigIntConstraints":
|
|
123
|
-
return fc.bigInt(ctx.constraints.constraints);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return fc.bigInt();
|
|
127
|
-
};
|
|
216
|
+
return new Deferred(constBigIntConstraints);
|
|
128
217
|
case "SymbolKeyword":
|
|
129
|
-
return fc => fc.string().map(s => Symbol.for(s));
|
|
218
|
+
return new Succeed(fc => fc.string().map(s => Symbol.for(s)));
|
|
130
219
|
case "ObjectKeyword":
|
|
131
|
-
return fc => fc.oneof(fc.object(), fc.array(fc.anything()));
|
|
132
|
-
case "
|
|
220
|
+
return new Succeed(fc => fc.oneof(fc.object(), fc.array(fc.anything())));
|
|
221
|
+
case "Enums":
|
|
133
222
|
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const number = fc.float({
|
|
139
|
-
noDefaultInfinity: true
|
|
140
|
-
}).filter(n => !Number.isNaN(n));
|
|
141
|
-
const components = ast.head !== "" ? [fc.constant(ast.head)] : [];
|
|
142
|
-
const addArb = ast => {
|
|
143
|
-
switch (ast._tag) {
|
|
144
|
-
case "StringKeyword":
|
|
145
|
-
return components.push(string);
|
|
146
|
-
case "NumberKeyword":
|
|
147
|
-
return components.push(number);
|
|
148
|
-
case "Literal":
|
|
149
|
-
return components.push(fc.constant(String(ast.literal)));
|
|
150
|
-
case "Union":
|
|
151
|
-
return ast.types.forEach(addArb);
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
ast.spans.forEach(span => {
|
|
155
|
-
addArb(span.type);
|
|
156
|
-
if (span.literal !== "") {
|
|
157
|
-
components.push(fc.constant(span.literal));
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
return fc.tuple(...components).map(spans => spans.join(""));
|
|
161
|
-
};
|
|
223
|
+
if (ast.enums.length === 0) {
|
|
224
|
+
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path));
|
|
225
|
+
}
|
|
226
|
+
return new Succeed(fc => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value))));
|
|
162
227
|
}
|
|
163
|
-
case "
|
|
164
|
-
{
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
228
|
+
case "TemplateLiteral":
|
|
229
|
+
return new Succeed(fc => {
|
|
230
|
+
const string = fc.string({
|
|
231
|
+
maxLength: 5
|
|
232
|
+
});
|
|
233
|
+
const number = fc.float({
|
|
234
|
+
noDefaultInfinity: true
|
|
235
|
+
}).filter(n => !Number.isNaN(n));
|
|
236
|
+
const components = ast.head !== "" ? [fc.constant(ast.head)] : [];
|
|
237
|
+
const addArb = ast => {
|
|
238
|
+
switch (ast._tag) {
|
|
239
|
+
case "StringKeyword":
|
|
240
|
+
return components.push(string);
|
|
241
|
+
case "NumberKeyword":
|
|
242
|
+
return components.push(number);
|
|
243
|
+
case "Literal":
|
|
244
|
+
return components.push(fc.constant(String(ast.literal)));
|
|
245
|
+
case "Union":
|
|
246
|
+
return ast.types.forEach(addArb);
|
|
172
247
|
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// ---------------------------------------------
|
|
179
|
-
let output = fc.tuple(...elements.map(arb => arb(fc)));
|
|
180
|
-
if (hasOptionals) {
|
|
181
|
-
const indexes = fc.tuple(...ast.elements.map(element => element.isOptional ? fc.boolean() : fc.constant(true)));
|
|
182
|
-
output = output.chain(tuple => indexes.map(booleans => {
|
|
183
|
-
for (const [i, b] of booleans.reverse().entries()) {
|
|
184
|
-
if (!b) {
|
|
185
|
-
tuple.splice(booleans.length - i, 1);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return tuple;
|
|
189
|
-
}));
|
|
248
|
+
};
|
|
249
|
+
ast.spans.forEach(span => {
|
|
250
|
+
addArb(span.type);
|
|
251
|
+
if (span.literal !== "") {
|
|
252
|
+
components.push(fc.constant(span.literal));
|
|
190
253
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// handle post rest elements
|
|
203
|
-
// ---------------------------------------------
|
|
204
|
-
for (let j = 0; j < tail.length; j++) {
|
|
205
|
-
output = output.chain(as => tail[j](fc).map(a => [...as, a]));
|
|
254
|
+
});
|
|
255
|
+
return fc.tuple(...components).map(spans => spans.join(""));
|
|
256
|
+
});
|
|
257
|
+
case "Refinement":
|
|
258
|
+
{
|
|
259
|
+
const from = toOp(ast.from, ctx, path);
|
|
260
|
+
const filters = [...from.filters, a => Option.isNone(ast.filter(a, AST.defaultParseOption, ast))];
|
|
261
|
+
switch (from._tag) {
|
|
262
|
+
case "Succeed":
|
|
263
|
+
{
|
|
264
|
+
return new Succeed(from.lazyArbitrary, filters);
|
|
206
265
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
266
|
+
case "Deferred":
|
|
267
|
+
{
|
|
268
|
+
return new Deferred(merge(from.config, getConstraints(from.config._tag, ast)), filters);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
210
271
|
}
|
|
272
|
+
case "TupleType":
|
|
273
|
+
return new Deferred(makeArrayConfig({}, ast));
|
|
211
274
|
case "TypeLiteral":
|
|
212
275
|
{
|
|
213
276
|
const propertySignaturesTypes = ast.propertySignatures.map(ps => go(ps.type, ctx, path.concat(ps.name)));
|
|
214
277
|
const indexSignatures = ast.indexSignatures.map(is => [go(is.parameter, ctx, path), go(is.type, ctx, path)]);
|
|
215
|
-
return fc => {
|
|
278
|
+
return new Succeed(fc => {
|
|
216
279
|
const arbs = {};
|
|
217
280
|
const requiredKeys = [];
|
|
218
281
|
// ---------------------------------------------
|
|
@@ -245,238 +308,191 @@ const go = (ast, ctx, path) => {
|
|
|
245
308
|
});
|
|
246
309
|
}
|
|
247
310
|
return output;
|
|
248
|
-
};
|
|
311
|
+
});
|
|
249
312
|
}
|
|
250
313
|
case "Union":
|
|
251
314
|
{
|
|
252
315
|
const types = ast.types.map(member => go(member, ctx, path));
|
|
253
|
-
return fc => fc.oneof(...types.map(arb => arb(fc)));
|
|
254
|
-
}
|
|
255
|
-
case "Enums":
|
|
256
|
-
{
|
|
257
|
-
if (ast.enums.length === 0) {
|
|
258
|
-
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path));
|
|
259
|
-
}
|
|
260
|
-
return fc => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value)));
|
|
261
|
-
}
|
|
262
|
-
case "Refinement":
|
|
263
|
-
{
|
|
264
|
-
const from = getRefinementFromArbitrary(ast, ctx, path);
|
|
265
|
-
return fc => from(fc).filter(a => Option.isNone(ast.filter(a, AST.defaultParseOption, ast)));
|
|
316
|
+
return new Succeed(fc => fc.oneof(...types.map(arb => arb(fc))));
|
|
266
317
|
}
|
|
267
318
|
case "Suspend":
|
|
268
319
|
{
|
|
269
320
|
const get = util_.memoizeThunk(() => {
|
|
270
321
|
return go(ast.f(), getSuspendedContext(ctx, ast), path);
|
|
271
322
|
});
|
|
272
|
-
return fc => fc.constant(null).chain(() => get()(fc));
|
|
323
|
+
return new Succeed(fc => fc.constant(null).chain(() => get()(fc)));
|
|
273
324
|
}
|
|
274
325
|
case "Transformation":
|
|
275
|
-
return go(ast.to, ctx, path);
|
|
326
|
+
return new Succeed(go(ast.to, ctx, path));
|
|
276
327
|
}
|
|
277
328
|
};
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
if (Predicate.isNumber(options.max)) {
|
|
288
|
-
this.constraints.max = Math.fround(options.max);
|
|
289
|
-
}
|
|
290
|
-
if (Predicate.isBoolean(options.noNaN)) {
|
|
291
|
-
this.constraints.noNaN = options.noNaN;
|
|
292
|
-
}
|
|
293
|
-
if (Predicate.isBoolean(options.noDefaultInfinity)) {
|
|
294
|
-
this.constraints.noDefaultInfinity = options.noDefaultInfinity;
|
|
329
|
+
const goTupleType = (ast, ctx, path, constraints) => {
|
|
330
|
+
const elements = [];
|
|
331
|
+
let hasOptionals = false;
|
|
332
|
+
let i = 0;
|
|
333
|
+
for (const element of ast.elements) {
|
|
334
|
+
elements.push(go(element.type, ctx, path.concat(i++)));
|
|
335
|
+
if (element.isOptional) {
|
|
336
|
+
hasOptionals = true;
|
|
295
337
|
}
|
|
296
338
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
export class IntegerConstraints {
|
|
314
|
-
_tag = "IntegerConstraints";
|
|
315
|
-
constraints;
|
|
316
|
-
constructor(options) {
|
|
317
|
-
this.constraints = {};
|
|
318
|
-
if (Predicate.isNumber(options.min)) {
|
|
319
|
-
this.constraints.min = options.min;
|
|
320
|
-
}
|
|
321
|
-
if (Predicate.isNumber(options.max)) {
|
|
322
|
-
this.constraints.max = options.max;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
/** @internal */
|
|
327
|
-
export class ArrayConstraints {
|
|
328
|
-
_tag = "ArrayConstraints";
|
|
329
|
-
constraints;
|
|
330
|
-
constructor(options) {
|
|
331
|
-
this.constraints = {};
|
|
332
|
-
if (Predicate.isNumber(options.minLength)) {
|
|
333
|
-
this.constraints.minLength = options.minLength;
|
|
334
|
-
}
|
|
335
|
-
if (Predicate.isNumber(options.maxLength)) {
|
|
336
|
-
this.constraints.maxLength = options.maxLength;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
/** @internal */
|
|
341
|
-
export class BigIntConstraints {
|
|
342
|
-
_tag = "BigIntConstraints";
|
|
343
|
-
constraints;
|
|
344
|
-
constructor(options) {
|
|
345
|
-
this.constraints = {};
|
|
346
|
-
if (Predicate.isBigInt(options.min)) {
|
|
347
|
-
this.constraints.min = options.min;
|
|
339
|
+
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, ctx, path));
|
|
340
|
+
return fc => {
|
|
341
|
+
// ---------------------------------------------
|
|
342
|
+
// handle elements
|
|
343
|
+
// ---------------------------------------------
|
|
344
|
+
let output = fc.tuple(...elements.map(arb => arb(fc)));
|
|
345
|
+
if (hasOptionals) {
|
|
346
|
+
const indexes = fc.tuple(...ast.elements.map(element => element.isOptional ? fc.boolean() : fc.constant(true)));
|
|
347
|
+
output = output.chain(tuple => indexes.map(booleans => {
|
|
348
|
+
for (const [i, b] of booleans.reverse().entries()) {
|
|
349
|
+
if (!b) {
|
|
350
|
+
tuple.splice(booleans.length - i, 1);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return tuple;
|
|
354
|
+
}));
|
|
348
355
|
}
|
|
349
|
-
|
|
350
|
-
|
|
356
|
+
// ---------------------------------------------
|
|
357
|
+
// handle rest element
|
|
358
|
+
// ---------------------------------------------
|
|
359
|
+
if (Arr.isNonEmptyReadonlyArray(rest)) {
|
|
360
|
+
const [head, ...tail] = rest;
|
|
361
|
+
const item = head(fc);
|
|
362
|
+
output = output.chain(as => {
|
|
363
|
+
return (ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, constraints) : fc.array(item, constraints)).map(rest => [...as, ...rest]);
|
|
364
|
+
});
|
|
365
|
+
// ---------------------------------------------
|
|
366
|
+
// handle post rest elements
|
|
367
|
+
// ---------------------------------------------
|
|
368
|
+
for (let j = 0; j < tail.length; j++) {
|
|
369
|
+
output = output.chain(as => tail[j](fc).map(a => [...as, a]));
|
|
370
|
+
}
|
|
351
371
|
}
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
|
|
372
|
+
return output;
|
|
373
|
+
};
|
|
374
|
+
};
|
|
375
|
+
const getConstraints = (_tag, ast) => {
|
|
356
376
|
const TypeAnnotationId = ast.annotations[AST.SchemaIdAnnotationId];
|
|
357
|
-
const jsonSchema =
|
|
358
|
-
switch (
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
// number
|
|
363
|
-
case filters_.GreaterThanSchemaId:
|
|
364
|
-
case filters_.GreaterThanOrEqualToSchemaId:
|
|
365
|
-
case filters_.LessThanSchemaId:
|
|
366
|
-
case filters_.LessThanOrEqualToSchemaId:
|
|
367
|
-
case filters_.BetweenSchemaId:
|
|
368
|
-
return new NumberConstraints({
|
|
369
|
-
min: jsonSchema.exclusiveMinimum ?? jsonSchema.minimum,
|
|
370
|
-
max: jsonSchema.exclusiveMaximum ?? jsonSchema.maximum
|
|
371
|
-
});
|
|
372
|
-
// bigint
|
|
373
|
-
case filters_.GreaterThanBigintSchemaId:
|
|
374
|
-
case filters_.GreaterThanOrEqualToBigIntSchemaId:
|
|
375
|
-
case filters_.LessThanBigIntSchemaId:
|
|
376
|
-
case filters_.LessThanOrEqualToBigIntSchemaId:
|
|
377
|
-
case filters_.BetweenBigintSchemaId:
|
|
377
|
+
const jsonSchema = Option.getOrElse(AST.getJSONSchemaAnnotation(ast), () => ({}));
|
|
378
|
+
switch (_tag) {
|
|
379
|
+
case "StringConstraints":
|
|
380
|
+
return makeStringConstraints(jsonSchema);
|
|
381
|
+
case "NumberConstraints":
|
|
378
382
|
{
|
|
379
|
-
|
|
380
|
-
|
|
383
|
+
switch (TypeAnnotationId) {
|
|
384
|
+
case filters_.NonNaNSchemaId:
|
|
385
|
+
return makeNumberConstraints({
|
|
386
|
+
noNaN: true
|
|
387
|
+
});
|
|
388
|
+
default:
|
|
389
|
+
return makeNumberConstraints({
|
|
390
|
+
isInteger: "type" in jsonSchema && jsonSchema.type === "integer",
|
|
391
|
+
noNaN: "type" in jsonSchema && jsonSchema.type === "number" ? true : undefined,
|
|
392
|
+
noDefaultInfinity: "type" in jsonSchema && jsonSchema.type === "number" ? true : undefined,
|
|
393
|
+
min: jsonSchema.exclusiveMinimum ?? jsonSchema.minimum,
|
|
394
|
+
minExcluded: "exclusiveMinimum" in jsonSchema ? true : undefined,
|
|
395
|
+
max: jsonSchema.exclusiveMaximum ?? jsonSchema.maximum,
|
|
396
|
+
maxExcluded: "exclusiveMaximum" in jsonSchema ? true : undefined
|
|
397
|
+
});
|
|
398
|
+
}
|
|
381
399
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
case
|
|
385
|
-
|
|
386
|
-
return new StringConstraints(jsonSchema);
|
|
387
|
-
// array
|
|
388
|
-
case filters_.MinItemsSchemaId:
|
|
389
|
-
case filters_.MaxItemsSchemaId:
|
|
390
|
-
case filters_.ItemsCountSchemaId:
|
|
391
|
-
return new ArrayConstraints({
|
|
400
|
+
case "BigIntConstraints":
|
|
401
|
+
return makeBigIntConstraints(ast.annotations[TypeAnnotationId]);
|
|
402
|
+
case "ArrayConstraints":
|
|
403
|
+
return makeArrayConstraints({
|
|
392
404
|
minLength: jsonSchema.minItems,
|
|
393
405
|
maxLength: jsonSchema.maxItems
|
|
394
406
|
});
|
|
395
407
|
}
|
|
396
408
|
};
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
409
|
+
function getMax(n1, n2) {
|
|
410
|
+
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n2 : n1;
|
|
411
|
+
}
|
|
412
|
+
function getMin(n1, n2) {
|
|
413
|
+
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n1 : n2;
|
|
414
|
+
}
|
|
415
|
+
const getOr = (a, b) => {
|
|
416
|
+
return a === undefined ? b : b === undefined ? a : a || b;
|
|
417
|
+
};
|
|
418
|
+
const merge = (c1, c2) => {
|
|
419
|
+
if (c2) {
|
|
420
|
+
switch (c1._tag) {
|
|
421
|
+
case "StringConstraints":
|
|
422
|
+
{
|
|
423
|
+
if (c2._tag === "StringConstraints") {
|
|
424
|
+
return makeStringConstraints({
|
|
411
425
|
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
412
|
-
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength)
|
|
426
|
+
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength),
|
|
427
|
+
pattern: c1.pattern ?? c2.pattern
|
|
413
428
|
});
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
414
431
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
case "NumberConstraints":
|
|
421
|
-
return new NumberConstraints({
|
|
432
|
+
case "NumberConstraints":
|
|
433
|
+
{
|
|
434
|
+
if (c2._tag === "NumberConstraints") {
|
|
435
|
+
return makeNumberConstraints({
|
|
436
|
+
isInteger: c1.isInteger || c2.isInteger,
|
|
422
437
|
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
438
|
+
minExcluded: getOr(c1.constraints.minExcluded, c2.constraints.minExcluded),
|
|
423
439
|
max: getMin(c1.constraints.max, c2.constraints.max),
|
|
440
|
+
maxExcluded: getOr(c1.constraints.maxExcluded, c2.constraints.maxExcluded),
|
|
424
441
|
noNaN: getOr(c1.constraints.noNaN, c2.constraints.noNaN),
|
|
425
442
|
noDefaultInfinity: getOr(c1.constraints.noDefaultInfinity, c2.constraints.noDefaultInfinity)
|
|
426
443
|
});
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
430
|
-
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
431
|
-
});
|
|
444
|
+
}
|
|
445
|
+
break;
|
|
432
446
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
switch (c2._tag) {
|
|
438
|
-
case "BigIntConstraints":
|
|
439
|
-
return new BigIntConstraints({
|
|
447
|
+
case "BigIntConstraints":
|
|
448
|
+
{
|
|
449
|
+
if (c2._tag === "BigIntConstraints") {
|
|
450
|
+
return makeBigIntConstraints({
|
|
440
451
|
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
441
452
|
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
442
453
|
});
|
|
454
|
+
}
|
|
455
|
+
break;
|
|
443
456
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
switch (c2._tag) {
|
|
449
|
-
case "StringConstraints":
|
|
450
|
-
return new StringConstraints({
|
|
457
|
+
case "ArrayConstraints":
|
|
458
|
+
{
|
|
459
|
+
if (c2._tag === "ArrayConstraints") {
|
|
460
|
+
return makeArrayConfig({
|
|
451
461
|
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
452
462
|
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength)
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
457
|
-
case "IntegerConstraints":
|
|
458
|
-
{
|
|
459
|
-
switch (c2._tag) {
|
|
460
|
-
case "NumberConstraints":
|
|
461
|
-
case "IntegerConstraints":
|
|
462
|
-
{
|
|
463
|
-
return new IntegerConstraints({
|
|
464
|
-
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
465
|
-
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
466
|
-
});
|
|
467
|
-
}
|
|
463
|
+
}, c1.ast);
|
|
464
|
+
}
|
|
465
|
+
break;
|
|
468
466
|
}
|
|
469
|
-
|
|
470
|
-
}
|
|
467
|
+
}
|
|
471
468
|
}
|
|
469
|
+
return c1;
|
|
472
470
|
};
|
|
473
|
-
const
|
|
474
|
-
|
|
471
|
+
const getSuspendedArray = (fc, depthIdentifier, maxDepth, item, constraints) => {
|
|
472
|
+
let minLength = 1;
|
|
473
|
+
let maxLength = 2;
|
|
474
|
+
if (constraints && constraints.minLength !== undefined && constraints.minLength > minLength) {
|
|
475
|
+
minLength = constraints.minLength;
|
|
476
|
+
if (minLength > maxLength) {
|
|
477
|
+
maxLength = minLength;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return fc.oneof({
|
|
481
|
+
maxDepth,
|
|
482
|
+
depthIdentifier
|
|
483
|
+
}, fc.constant([]), fc.array(item, {
|
|
484
|
+
minLength,
|
|
485
|
+
maxLength
|
|
486
|
+
}));
|
|
487
|
+
};
|
|
488
|
+
const getSuspendedContext = (ctx, ast) => {
|
|
489
|
+
if (ctx.depthIdentifier !== undefined) {
|
|
490
|
+
return ctx;
|
|
491
|
+
}
|
|
492
|
+
const depthIdentifier = AST.getIdentifierAnnotation(ast).pipe(Option.orElse(() => AST.getIdentifierAnnotation(ast.f())), Option.getOrElse(() => "SuspendDefaultDepthIdentifier"));
|
|
493
|
+
return {
|
|
494
|
+
...ctx,
|
|
495
|
+
depthIdentifier
|
|
496
|
+
};
|
|
475
497
|
};
|
|
476
|
-
function getMax(n1, n2) {
|
|
477
|
-
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n2 : n1;
|
|
478
|
-
}
|
|
479
|
-
function getMin(n1, n2) {
|
|
480
|
-
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n1 : n2;
|
|
481
|
-
}
|
|
482
498
|
//# sourceMappingURL=Arbitrary.js.map
|