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.
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.toOp = exports.makeStringConstraints = exports.makeNumberConstraints = exports.makeLazy = exports.makeDateConstraints = exports.makeBigIntConstraints = exports.makeArrayConstraints = exports.make = void 0;
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 AST = _interopRequireWildcard(require("./SchemaAST.js"));
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 => go(schema.ast, {
29
- maxDepth: 2
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 makeArrayConfig = (options, ast) => {
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[AST.SchemaIdAnnotationId];
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 toOp = (ast, ctx, path) => {
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
- const TypeAnnotationId = ast.annotations[AST.SchemaIdAnnotationId];
246
- if (TypeAnnotationId === schemaId_.DateFromSelfSchemaId) {
247
- const c = getASTConstraints(ast);
248
- if (c !== undefined) {
249
- return new Deferred(makeDateConstraints(c));
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 new Succeed(go(ast, ctx, path));
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
- return new Succeed(fc => fc.constant(ast.literal));
255
+ {
256
+ return {
257
+ _tag: "Literal",
258
+ literal: ast.literal,
259
+ path,
260
+ refinements: [],
261
+ annotations: []
262
+ };
263
+ }
256
264
  case "UniqueSymbol":
257
- return new Succeed(fc => fc.constant(ast.symbol));
258
- case "UndefinedKeyword":
259
- return new Succeed(fc => fc.constant(undefined));
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
- throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast));
262
- case "VoidKeyword":
263
- case "UnknownKeyword":
264
- case "AnyKeyword":
265
- return new Succeed(fc => fc.anything());
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 new Deferred(constStringConstraints);
491
+ return buildStringConstraints(description);
268
492
  case "NumberKeyword":
269
- return new Deferred(constNumberConstraints);
270
- case "BooleanKeyword":
271
- return new Succeed(fc => fc.boolean());
493
+ return buildNumberConstraints(description);
272
494
  case "BigIntKeyword":
273
- return new Deferred(constBigIntConstraints);
274
- case "SymbolKeyword":
275
- return new Succeed(fc => fc.string().map(s => Symbol.for(s)));
276
- case "ObjectKeyword":
277
- return new Succeed(fc => fc.oneof(fc.object(), fc.array(fc.anything())));
278
- case "Enums":
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
- if (ast.enums.length === 0) {
281
- throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path));
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
- return new Succeed(fc => {
287
- const string = fc.string({
288
- maxLength: 5
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
- return fc.tuple(...components).map(spans => spans.join(""));
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
- return getTemplateLiteralArb(ast);
319
- });
320
- case "Refinement":
609
+ }
610
+ case "StringKeyword":
321
611
  {
322
- const from = toOp(ast.from, ctx, path);
323
- const filters = [...from.filters, a => Option.isNone(ast.filter(a, AST.defaultParseOption, ast))];
324
- switch (from._tag) {
325
- case "Succeed":
326
- {
327
- return new Succeed(from.lazyArbitrary, filters);
328
- }
329
- case "Deferred":
330
- {
331
- return new Deferred(merge(from.config, getRefinementConstraints(from.config._tag, ast)), filters);
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 propertySignaturesTypes = ast.propertySignatures.map(ps => go(ps.type, ctx, path.concat(ps.name)));
340
- const indexSignatures = ast.indexSignatures.map(is => [go(is.parameter, ctx, path), go(is.type, ctx, path)]);
341
- return new Succeed(fc => {
342
- const arbs = {};
343
- const requiredKeys = [];
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 property signatures
654
+ // handle rest element
346
655
  // ---------------------------------------------
347
- for (let i = 0; i < propertySignaturesTypes.length; i++) {
348
- const ps = ast.propertySignatures[i];
349
- const name = ps.name;
350
- if (!ps.isOptional) {
351
- requiredKeys.push(name);
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
- let output = fc.record(arbs, {
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
- `getSuspendedArray` is used to generate less key/value pairs in
368
- the context of a recursive schema. Without it, the following schema
369
- would generate an big amount of values possibly leading to a stack
370
- overflow:
371
- ```ts
372
- type A = { [_: string]: A }
373
- const schema = S.Record({ key: S.String, value: S.suspend((): S.Schema<A> => schema) })
374
- ```
375
- */
376
- const arr = ctx.depthIdentifier !== undefined ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, defaultSuspendedArrayConstraints) : fc.array(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 types = ast.types.map(member => go(member, ctx, path));
389
- return new Succeed(fc => fc.oneof(...types.map(arb => arb(fc))));
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 new Succeed(memo);
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(ast.f(), getSuspendedContext(ctx, ast), path);
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 new Succeed(out);
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
- exports.toOp = toOp;
409
- function subtractElementsLength(constraints, elementsLength) {
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 - elementsLength, 0);
788
+ out.minLength = Math.max(out.minLength - len, 0);
418
789
  }
419
790
  if (out.maxLength !== undefined) {
420
- out.maxLength = Math.max(out.maxLength - elementsLength, 0);
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