effect 3.11.4 → 3.11.6
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 +354 -343
- package/dist/cjs/Arbitrary.js.map +1 -1
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/JSONSchema.js +226 -134
- package/dist/cjs/JSONSchema.js.map +1 -1
- package/dist/cjs/Schema.js +67 -32
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/SchemaAST.js +34 -9
- package/dist/cjs/SchemaAST.js.map +1 -1
- package/dist/cjs/internal/core.js +6 -7
- package/dist/cjs/internal/core.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/Effect.d.ts +50 -19
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/JSONSchema.d.ts +57 -1
- package/dist/dts/JSONSchema.d.ts.map +1 -1
- package/dist/dts/Schema.d.ts +47 -19
- package/dist/dts/Schema.d.ts.map +1 -1
- package/dist/dts/SchemaAST.d.ts +1 -1
- package/dist/dts/SchemaAST.d.ts.map +1 -1
- package/dist/dts/internal/core.d.ts +5 -0
- package/dist/dts/internal/core.d.ts.map +1 -1
- package/dist/esm/Arbitrary.js +348 -335
- package/dist/esm/Arbitrary.js.map +1 -1
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/JSONSchema.js +224 -133
- package/dist/esm/JSONSchema.js.map +1 -1
- package/dist/esm/Schema.js +67 -32
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/SchemaAST.js +31 -7
- package/dist/esm/SchemaAST.js.map +1 -1
- package/dist/esm/internal/core.js +7 -6
- package/dist/esm/internal/core.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 +406 -360
- package/src/Effect.ts +68 -20
- package/src/JSONSchema.ts +233 -134
- package/src/Schema.ts +176 -74
- package/src/SchemaAST.ts +31 -7
- package/src/internal/core.ts +9 -6
- 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,117 @@ 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
|
+
const op = toOp(ast, ctx, path);
|
|
179
|
+
switch (op._tag) {
|
|
180
|
+
case "Succeed":
|
|
181
|
+
return op.toLazyArbitrary();
|
|
182
|
+
case "Deferred":
|
|
183
|
+
return new Succeed(op.toLazyArbitrary(ctx, path), op.filters).toLazyArbitrary();
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const constStringConstraints = /*#__PURE__*/makeStringConstraints({});
|
|
187
|
+
const constNumberConstraints = /*#__PURE__*/makeNumberConstraints({});
|
|
188
|
+
const constBigIntConstraints = /*#__PURE__*/makeBigIntConstraints({});
|
|
189
|
+
/** @internal */
|
|
190
|
+
export const toOp = (ast, ctx, path) => {
|
|
75
191
|
switch (ast._tag) {
|
|
76
192
|
case "Declaration":
|
|
77
|
-
|
|
78
|
-
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
79
|
-
}
|
|
193
|
+
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
80
194
|
case "Literal":
|
|
81
|
-
return fc => fc.constant(ast.literal);
|
|
195
|
+
return new Succeed(fc => fc.constant(ast.literal));
|
|
82
196
|
case "UniqueSymbol":
|
|
83
|
-
return fc => fc.constant(ast.symbol);
|
|
197
|
+
return new Succeed(fc => fc.constant(ast.symbol));
|
|
84
198
|
case "UndefinedKeyword":
|
|
85
|
-
return fc => fc.constant(undefined);
|
|
199
|
+
return new Succeed(fc => fc.constant(undefined));
|
|
86
200
|
case "NeverKeyword":
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
201
|
+
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
|
|
202
|
+
case "VoidKeyword":
|
|
90
203
|
case "UnknownKeyword":
|
|
91
204
|
case "AnyKeyword":
|
|
92
|
-
|
|
93
|
-
return fc => fc.anything();
|
|
205
|
+
return new Succeed(fc => fc.anything());
|
|
94
206
|
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
|
-
};
|
|
207
|
+
return new Deferred(constStringConstraints);
|
|
104
208
|
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
|
-
};
|
|
209
|
+
return new Deferred(constNumberConstraints);
|
|
116
210
|
case "BooleanKeyword":
|
|
117
|
-
return fc => fc.boolean();
|
|
211
|
+
return new Succeed(fc => fc.boolean());
|
|
118
212
|
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
|
-
};
|
|
213
|
+
return new Deferred(constBigIntConstraints);
|
|
128
214
|
case "SymbolKeyword":
|
|
129
|
-
return fc => fc.string().map(s => Symbol.for(s));
|
|
215
|
+
return new Succeed(fc => fc.string().map(s => Symbol.for(s)));
|
|
130
216
|
case "ObjectKeyword":
|
|
131
|
-
return fc => fc.oneof(fc.object(), fc.array(fc.anything()));
|
|
132
|
-
case "
|
|
217
|
+
return new Succeed(fc => fc.oneof(fc.object(), fc.array(fc.anything())));
|
|
218
|
+
case "Enums":
|
|
133
219
|
{
|
|
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
|
-
};
|
|
220
|
+
if (ast.enums.length === 0) {
|
|
221
|
+
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path));
|
|
222
|
+
}
|
|
223
|
+
return new Succeed(fc => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value))));
|
|
162
224
|
}
|
|
163
|
-
case "
|
|
164
|
-
{
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
225
|
+
case "TemplateLiteral":
|
|
226
|
+
return new Succeed(fc => {
|
|
227
|
+
const string = fc.string({
|
|
228
|
+
maxLength: 5
|
|
229
|
+
});
|
|
230
|
+
const number = fc.float({
|
|
231
|
+
noDefaultInfinity: true
|
|
232
|
+
}).filter(n => !Number.isNaN(n));
|
|
233
|
+
const components = ast.head !== "" ? [fc.constant(ast.head)] : [];
|
|
234
|
+
const addArb = ast => {
|
|
235
|
+
switch (ast._tag) {
|
|
236
|
+
case "StringKeyword":
|
|
237
|
+
return components.push(string);
|
|
238
|
+
case "NumberKeyword":
|
|
239
|
+
return components.push(number);
|
|
240
|
+
case "Literal":
|
|
241
|
+
return components.push(fc.constant(String(ast.literal)));
|
|
242
|
+
case "Union":
|
|
243
|
+
return ast.types.forEach(addArb);
|
|
172
244
|
}
|
|
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
|
-
}));
|
|
245
|
+
};
|
|
246
|
+
ast.spans.forEach(span => {
|
|
247
|
+
addArb(span.type);
|
|
248
|
+
if (span.literal !== "") {
|
|
249
|
+
components.push(fc.constant(span.literal));
|
|
190
250
|
}
|
|
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]));
|
|
251
|
+
});
|
|
252
|
+
return fc.tuple(...components).map(spans => spans.join(""));
|
|
253
|
+
});
|
|
254
|
+
case "Refinement":
|
|
255
|
+
{
|
|
256
|
+
const from = toOp(ast.from, ctx, path);
|
|
257
|
+
const filters = [...from.filters, a => Option.isNone(ast.filter(a, AST.defaultParseOption, ast))];
|
|
258
|
+
switch (from._tag) {
|
|
259
|
+
case "Succeed":
|
|
260
|
+
{
|
|
261
|
+
return new Succeed(from.lazyArbitrary, filters);
|
|
206
262
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
263
|
+
case "Deferred":
|
|
264
|
+
{
|
|
265
|
+
return new Deferred(merge(from.config, getConstraints(from.config._tag, ast)), filters);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
210
268
|
}
|
|
269
|
+
case "TupleType":
|
|
270
|
+
return new Deferred(makeArrayConfig({}, ast));
|
|
211
271
|
case "TypeLiteral":
|
|
212
272
|
{
|
|
213
273
|
const propertySignaturesTypes = ast.propertySignatures.map(ps => go(ps.type, ctx, path.concat(ps.name)));
|
|
214
274
|
const indexSignatures = ast.indexSignatures.map(is => [go(is.parameter, ctx, path), go(is.type, ctx, path)]);
|
|
215
|
-
return fc => {
|
|
275
|
+
return new Succeed(fc => {
|
|
216
276
|
const arbs = {};
|
|
217
277
|
const requiredKeys = [];
|
|
218
278
|
// ---------------------------------------------
|
|
@@ -245,238 +305,191 @@ const go = (ast, ctx, path) => {
|
|
|
245
305
|
});
|
|
246
306
|
}
|
|
247
307
|
return output;
|
|
248
|
-
};
|
|
308
|
+
});
|
|
249
309
|
}
|
|
250
310
|
case "Union":
|
|
251
311
|
{
|
|
252
312
|
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)));
|
|
313
|
+
return new Succeed(fc => fc.oneof(...types.map(arb => arb(fc))));
|
|
266
314
|
}
|
|
267
315
|
case "Suspend":
|
|
268
316
|
{
|
|
269
317
|
const get = util_.memoizeThunk(() => {
|
|
270
318
|
return go(ast.f(), getSuspendedContext(ctx, ast), path);
|
|
271
319
|
});
|
|
272
|
-
return fc => fc.constant(null).chain(() => get()(fc));
|
|
320
|
+
return new Succeed(fc => fc.constant(null).chain(() => get()(fc)));
|
|
273
321
|
}
|
|
274
322
|
case "Transformation":
|
|
275
|
-
return go(ast.to, ctx, path);
|
|
323
|
+
return new Succeed(go(ast.to, ctx, path));
|
|
276
324
|
}
|
|
277
325
|
};
|
|
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;
|
|
326
|
+
const goTupleType = (ast, ctx, path, constraints) => {
|
|
327
|
+
const elements = [];
|
|
328
|
+
let hasOptionals = false;
|
|
329
|
+
let i = 0;
|
|
330
|
+
for (const element of ast.elements) {
|
|
331
|
+
elements.push(go(element.type, ctx, path.concat(i++)));
|
|
332
|
+
if (element.isOptional) {
|
|
333
|
+
hasOptionals = true;
|
|
295
334
|
}
|
|
296
335
|
}
|
|
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;
|
|
336
|
+
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, ctx, path));
|
|
337
|
+
return fc => {
|
|
338
|
+
// ---------------------------------------------
|
|
339
|
+
// handle elements
|
|
340
|
+
// ---------------------------------------------
|
|
341
|
+
let output = fc.tuple(...elements.map(arb => arb(fc)));
|
|
342
|
+
if (hasOptionals) {
|
|
343
|
+
const indexes = fc.tuple(...ast.elements.map(element => element.isOptional ? fc.boolean() : fc.constant(true)));
|
|
344
|
+
output = output.chain(tuple => indexes.map(booleans => {
|
|
345
|
+
for (const [i, b] of booleans.reverse().entries()) {
|
|
346
|
+
if (!b) {
|
|
347
|
+
tuple.splice(booleans.length - i, 1);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return tuple;
|
|
351
|
+
}));
|
|
348
352
|
}
|
|
349
|
-
|
|
350
|
-
|
|
353
|
+
// ---------------------------------------------
|
|
354
|
+
// handle rest element
|
|
355
|
+
// ---------------------------------------------
|
|
356
|
+
if (Arr.isNonEmptyReadonlyArray(rest)) {
|
|
357
|
+
const [head, ...tail] = rest;
|
|
358
|
+
const item = head(fc);
|
|
359
|
+
output = output.chain(as => {
|
|
360
|
+
return (ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, constraints) : fc.array(item, constraints)).map(rest => [...as, ...rest]);
|
|
361
|
+
});
|
|
362
|
+
// ---------------------------------------------
|
|
363
|
+
// handle post rest elements
|
|
364
|
+
// ---------------------------------------------
|
|
365
|
+
for (let j = 0; j < tail.length; j++) {
|
|
366
|
+
output = output.chain(as => tail[j](fc).map(a => [...as, a]));
|
|
367
|
+
}
|
|
351
368
|
}
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
|
|
369
|
+
return output;
|
|
370
|
+
};
|
|
371
|
+
};
|
|
372
|
+
const getConstraints = (_tag, ast) => {
|
|
356
373
|
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:
|
|
374
|
+
const jsonSchema = Option.getOrElse(AST.getJSONSchemaAnnotation(ast), () => ({}));
|
|
375
|
+
switch (_tag) {
|
|
376
|
+
case "StringConstraints":
|
|
377
|
+
return makeStringConstraints(jsonSchema);
|
|
378
|
+
case "NumberConstraints":
|
|
378
379
|
{
|
|
379
|
-
|
|
380
|
-
|
|
380
|
+
switch (TypeAnnotationId) {
|
|
381
|
+
case filters_.NonNaNSchemaId:
|
|
382
|
+
return makeNumberConstraints({
|
|
383
|
+
noNaN: true
|
|
384
|
+
});
|
|
385
|
+
default:
|
|
386
|
+
return makeNumberConstraints({
|
|
387
|
+
isInteger: "type" in jsonSchema && jsonSchema.type === "integer",
|
|
388
|
+
noNaN: "type" in jsonSchema && jsonSchema.type === "number" ? true : undefined,
|
|
389
|
+
noDefaultInfinity: "type" in jsonSchema && jsonSchema.type === "number" ? true : undefined,
|
|
390
|
+
min: jsonSchema.exclusiveMinimum ?? jsonSchema.minimum,
|
|
391
|
+
minExcluded: "exclusiveMinimum" in jsonSchema ? true : undefined,
|
|
392
|
+
max: jsonSchema.exclusiveMaximum ?? jsonSchema.maximum,
|
|
393
|
+
maxExcluded: "exclusiveMaximum" in jsonSchema ? true : undefined
|
|
394
|
+
});
|
|
395
|
+
}
|
|
381
396
|
}
|
|
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({
|
|
397
|
+
case "BigIntConstraints":
|
|
398
|
+
return makeBigIntConstraints(ast.annotations[TypeAnnotationId]);
|
|
399
|
+
case "ArrayConstraints":
|
|
400
|
+
return makeArrayConstraints({
|
|
392
401
|
minLength: jsonSchema.minItems,
|
|
393
402
|
maxLength: jsonSchema.maxItems
|
|
394
403
|
});
|
|
395
404
|
}
|
|
396
405
|
};
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
406
|
+
function getMax(n1, n2) {
|
|
407
|
+
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n2 : n1;
|
|
408
|
+
}
|
|
409
|
+
function getMin(n1, n2) {
|
|
410
|
+
return n1 === undefined ? n2 : n2 === undefined ? n1 : n1 <= n2 ? n1 : n2;
|
|
411
|
+
}
|
|
412
|
+
const getOr = (a, b) => {
|
|
413
|
+
return a === undefined ? b : b === undefined ? a : a || b;
|
|
414
|
+
};
|
|
415
|
+
const merge = (c1, c2) => {
|
|
416
|
+
if (c2) {
|
|
417
|
+
switch (c1._tag) {
|
|
418
|
+
case "StringConstraints":
|
|
419
|
+
{
|
|
420
|
+
if (c2._tag === "StringConstraints") {
|
|
421
|
+
return makeStringConstraints({
|
|
411
422
|
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
412
|
-
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength)
|
|
423
|
+
maxLength: getMin(c1.constraints.maxLength, c2.constraints.maxLength),
|
|
424
|
+
pattern: c1.pattern ?? c2.pattern
|
|
413
425
|
});
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
414
428
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
case "NumberConstraints":
|
|
421
|
-
return new NumberConstraints({
|
|
429
|
+
case "NumberConstraints":
|
|
430
|
+
{
|
|
431
|
+
if (c2._tag === "NumberConstraints") {
|
|
432
|
+
return makeNumberConstraints({
|
|
433
|
+
isInteger: c1.isInteger || c2.isInteger,
|
|
422
434
|
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
435
|
+
minExcluded: getOr(c1.constraints.minExcluded, c2.constraints.minExcluded),
|
|
423
436
|
max: getMin(c1.constraints.max, c2.constraints.max),
|
|
437
|
+
maxExcluded: getOr(c1.constraints.maxExcluded, c2.constraints.maxExcluded),
|
|
424
438
|
noNaN: getOr(c1.constraints.noNaN, c2.constraints.noNaN),
|
|
425
439
|
noDefaultInfinity: getOr(c1.constraints.noDefaultInfinity, c2.constraints.noDefaultInfinity)
|
|
426
440
|
});
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
430
|
-
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
431
|
-
});
|
|
441
|
+
}
|
|
442
|
+
break;
|
|
432
443
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
switch (c2._tag) {
|
|
438
|
-
case "BigIntConstraints":
|
|
439
|
-
return new BigIntConstraints({
|
|
444
|
+
case "BigIntConstraints":
|
|
445
|
+
{
|
|
446
|
+
if (c2._tag === "BigIntConstraints") {
|
|
447
|
+
return makeBigIntConstraints({
|
|
440
448
|
min: getMax(c1.constraints.min, c2.constraints.min),
|
|
441
449
|
max: getMin(c1.constraints.max, c2.constraints.max)
|
|
442
450
|
});
|
|
451
|
+
}
|
|
452
|
+
break;
|
|
443
453
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
switch (c2._tag) {
|
|
449
|
-
case "StringConstraints":
|
|
450
|
-
return new StringConstraints({
|
|
454
|
+
case "ArrayConstraints":
|
|
455
|
+
{
|
|
456
|
+
if (c2._tag === "ArrayConstraints") {
|
|
457
|
+
return makeArrayConfig({
|
|
451
458
|
minLength: getMax(c1.constraints.minLength, c2.constraints.minLength),
|
|
452
459
|
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
|
-
}
|
|
460
|
+
}, c1.ast);
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
468
463
|
}
|
|
469
|
-
|
|
470
|
-
}
|
|
464
|
+
}
|
|
471
465
|
}
|
|
466
|
+
return c1;
|
|
472
467
|
};
|
|
473
|
-
const
|
|
474
|
-
|
|
468
|
+
const getSuspendedArray = (fc, depthIdentifier, maxDepth, item, constraints) => {
|
|
469
|
+
let minLength = 1;
|
|
470
|
+
let maxLength = 2;
|
|
471
|
+
if (constraints && constraints.minLength !== undefined && constraints.minLength > minLength) {
|
|
472
|
+
minLength = constraints.minLength;
|
|
473
|
+
if (minLength > maxLength) {
|
|
474
|
+
maxLength = minLength;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return fc.oneof({
|
|
478
|
+
maxDepth,
|
|
479
|
+
depthIdentifier
|
|
480
|
+
}, fc.constant([]), fc.array(item, {
|
|
481
|
+
minLength,
|
|
482
|
+
maxLength
|
|
483
|
+
}));
|
|
484
|
+
};
|
|
485
|
+
const getSuspendedContext = (ctx, ast) => {
|
|
486
|
+
if (ctx.depthIdentifier !== undefined) {
|
|
487
|
+
return ctx;
|
|
488
|
+
}
|
|
489
|
+
const depthIdentifier = AST.getIdentifierAnnotation(ast).pipe(Option.orElse(() => AST.getIdentifierAnnotation(ast.f())), Option.getOrElse(() => "SuspendDefaultDepthIdentifier"));
|
|
490
|
+
return {
|
|
491
|
+
...ctx,
|
|
492
|
+
depthIdentifier
|
|
493
|
+
};
|
|
475
494
|
};
|
|
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
495
|
//# sourceMappingURL=Arbitrary.js.map
|