EdgeAIG's picture
download
raw
29 kB
import * as Array from "../../Array.js";
import * as Boolean from "../../Boolean.js";
import * as Equal from "../../Equal.js";
import { memoize } from "../../Function.js";
import * as Number from "../../Number.js";
import * as Option from "../../Option.js";
import * as Order from "../../Order.js";
import * as Predicate from "../../Predicate.js";
import * as SchemaAST from "../../SchemaAST.js";
import * as Struct from "../../Struct.js";
import * as UndefinedOr from "../../UndefinedOr.js";
import { errorWithPath } from "../errors.js";
import * as InternalAnnotations from "./annotations.js";
const arbitraryMemoMap = /*#__PURE__*/new WeakMap();
const suspendDepthIdentifierMap = /*#__PURE__*/new WeakMap();
const emptyRecursionStack = [];
/** @internal */
export function makeReport() {
return {
warnings: []
};
}
/** @internal */
export function toReport(report) {
return {
warnings: report.warnings.slice()
};
}
function arbitraryError(what) {
return new Error(`Unable to derive an arbitrary for ${what}`);
}
const entryComparator = ([a], [b]) => Equal.equals(a, b);
function applyChecks(ast, filters, arbitrary) {
return filters.reduce((acc, filter) => acc.filter(a => filter.run(a, ast, SchemaAST.defaultParseOptions) === undefined), arbitrary);
}
function validateArrayConstraints(constraint, label) {
if (constraint?.minLength !== undefined && constraint.maxLength !== undefined && constraint.minLength > constraint.maxLength) {
throw arbitraryError(`${label} constraints`);
}
}
function lengthToFastCheckConstraints(constraint) {
return constraint === undefined || constraint.minLength === undefined && constraint.maxLength === undefined ? undefined : {
...(constraint.minLength !== undefined ? {
minLength: constraint.minLength
} : {}),
...(constraint.maxLength !== undefined ? {
maxLength: constraint.maxLength
} : {})
};
}
function arrayWithConstraints(fc, item, constraint, comparator) {
return comparator ? fc.uniqueArray(item, {
...constraint,
comparator
}) : fc.array(item, constraint);
}
function array(fc, ctx, item, terminal = false) {
const constraint = ctx.constraint;
const arrayConstraints = lengthToFastCheckConstraints(constraint);
validateArrayConstraints(arrayConstraints, "array");
return arrayWithConstraints(fc, item, terminal ? {
...arrayConstraints,
maxLength: arrayConstraints?.minLength ?? 0
} : arrayConstraints, constraint?.unique ? Equal.equals : undefined);
}
function appendArray(fc, out, len, rest) {
return out.chain(as => as.length < len ? fc.constant(as) : rest.map(rest => [...as, ...rest]));
}
function appendObjectEntries(out, entries) {
return out.chain(o => entries.map(entries => ({
...Object.fromEntries(entries),
...o
})));
}
const max = /*#__PURE__*/UndefinedOr.makeReducer(Number.ReducerMax);
const min = /*#__PURE__*/UndefinedOr.makeReducer(Number.ReducerMin);
const or = /*#__PURE__*/UndefinedOr.makeReducer(Boolean.ReducerOr);
const concat = /*#__PURE__*/UndefinedOr.makeReducer(/*#__PURE__*/Array.makeReducerConcat());
const combiner = /*#__PURE__*/Struct.makeCombiner({
integer: or,
maxLength: min,
minLength: max,
noInfinity: or,
noNaN: or,
patterns: concat,
unique: or,
valid: or
}, {
omitKeyWhen: Predicate.isUndefined
});
function mergeOrderedBound(order, self, selfExclusive, that, thatExclusive, takeComparison) {
if (that === undefined || self === undefined) {
return that === undefined ? [self, selfExclusive] : [that, thatExclusive];
}
const comparison = order(self, that);
return comparison === takeComparison ? [that, thatExclusive] : comparison === 0 ? [self, selfExclusive || thatExclusive] : [self, selfExclusive];
}
function mergeOrderedConstraints(self, that) {
if (self === undefined) {
return that;
}
if (self.order !== that.order) {
throw new Error("Cannot merge ordered arbitrary constraints with different Order instances");
}
const [minimum, exclusiveMinimum] = mergeOrderedBound(self.order, self.minimum, self.exclusiveMinimum, that.minimum, that.exclusiveMinimum, -1);
const [maximum, exclusiveMaximum] = mergeOrderedBound(self.order, self.maximum, self.exclusiveMaximum, that.maximum, that.exclusiveMaximum, 1);
return {
order: self.order,
...(minimum !== undefined ? {
minimum
} : {}),
...(exclusiveMinimum !== undefined ? {
exclusiveMinimum
} : {}),
...(maximum !== undefined ? {
maximum
} : {}),
...(exclusiveMaximum !== undefined ? {
exclusiveMaximum
} : {})
};
}
function mergeConstraint(self, that) {
const {
ordered: selfOrdered,
...selfRest
} = self ?? {};
const {
ordered: thatOrdered,
...thatRest
} = that;
const ordered = thatOrdered === undefined ? selfOrdered : mergeOrderedConstraints(selfOrdered, thatOrdered);
const out = combiner.combine(selfRest, thatRest);
return {
...out,
...(ordered === undefined ? {} : {
ordered
})
};
}
function collectChecks(checks) {
const filters = [];
const arbitraries = [];
function visit(check) {
if (check.annotations?.arbitrary) {
arbitraries.push(check.annotations.arbitrary);
}
if (check._tag !== "Filter") {
for (const child of check.checks) {
visit(child);
}
} else {
filters.push(check);
}
}
checks?.forEach(visit);
return {
filters,
arbitraries
};
}
function constraintContext(arbitraries) {
const constraintAnnotations = arbitraries.map(({
constraint
}) => constraint).filter(Predicate.isNotUndefined);
return ctx => {
const constraint = constraintAnnotations.reduce((acc, c) => mergeConstraint(acc, c), ctx.constraint);
return {
...ctx,
constraint
};
};
}
function resetContext(ctx) {
return {
...ctx,
constraint: undefined
};
}
function objectEntriesConstraints(ast, constraint, requiredKeys) {
if (constraint === undefined || constraint.minLength === undefined && constraint.maxLength === undefined) {
return undefined;
}
if (constraint.minLength !== undefined && ast.indexSignatures.length === 0 && constraint.minLength > ast.propertySignatures.length) {
throw arbitraryError("object property constraints");
}
const out = {};
if (constraint.minLength !== undefined) {
out.minLength = Math.max(0, constraint.minLength - requiredKeys);
}
if (constraint.maxLength !== undefined) {
out.maxLength = constraint.maxLength - requiredKeys;
if (out.maxLength < 0) {
throw arbitraryError("object property constraints");
}
}
validateArrayConstraints(out, "object property");
return out;
}
function objectWithOptionalCount(fc, pss, orderedNames, requiredKeys, optionalNames, constraint) {
const requiredCount = requiredKeys.length;
if (constraint.maxLength !== undefined && constraint.maxLength < requiredCount) {
throw arbitraryError("object property constraints");
}
const minOptional = constraint.minLength === undefined ? 0 : Math.max(0, constraint.minLength - requiredCount);
const maxOptional = constraint.maxLength === undefined ? optionalNames.length : Math.min(optionalNames.length, constraint.maxLength - requiredCount);
if (minOptional > maxOptional) {
throw arbitraryError("object property constraints");
}
const full = fc.record(pss, {
requiredKeys: [...requiredKeys, ...optionalNames]
});
const chosen = fc.shuffledSubarray([...optionalNames], {
minLength: minOptional,
maxLength: maxOptional
});
return fc.tuple(full, chosen).map(([base, names]) => {
const keep = new Set([...requiredKeys, ...names]);
const out = {};
for (const name of orderedNames) {
if (keep.has(name)) {
out[name] = base[name];
}
}
return out;
});
}
function toRangeConstraints(ordered, min, max, error) {
const out = {};
if (ordered?.minimum !== undefined) {
out.min = min(ordered.minimum, ordered.exclusiveMinimum === true);
}
if (ordered?.maximum !== undefined) {
out.max = max(ordered.maximum, ordered.exclusiveMaximum === true);
}
if (out.min !== undefined && out.max !== undefined && out.min > out.max) {
throw arbitraryError(error);
}
return out;
}
function toIntegerConstraints(ordered) {
return toRangeConstraints(ordered, (minimum, excluded) => excluded ? Math.floor(minimum) + 1 : Math.ceil(minimum), (maximum, excluded) => excluded ? Math.ceil(maximum) - 1 : Math.floor(maximum), "integer constraints");
}
function toFloatConstraints(constraint, ordered) {
const out = {
...(constraint?.noInfinity ? {
noDefaultInfinity: true
} : {}),
...(constraint?.noNaN ? {
noNaN: true
} : {}),
...(ordered?.minimum !== undefined ? {
min: ordered.minimum
} : {}),
...(ordered?.exclusiveMinimum !== undefined ? {
minExcluded: ordered.exclusiveMinimum
} : {}),
...(ordered?.maximum !== undefined ? {
max: ordered.maximum
} : {}),
...(ordered?.exclusiveMaximum !== undefined ? {
maxExcluded: ordered.exclusiveMaximum
} : {})
};
if (out.min !== undefined && out.max !== undefined && (out.min > out.max || out.min === out.max && (out.minExcluded || out.maxExcluded))) {
throw arbitraryError("number constraints");
}
return out;
}
function toBigIntConstraints(ordered) {
return toRangeConstraints(ordered, (minimum, excluded) => excluded ? minimum + BigInt(1) : minimum, (maximum, excluded) => excluded ? maximum - BigInt(1) : maximum, "the ordered bigint constraints");
}
function makeLazy(normal, terminal) {
const out = (fc, ctx, recursionStack = emptyRecursionStack) => normal(fc, ctx, recursionStack);
out.terminal = (fc, ctx, recursionStack = emptyRecursionStack) => terminal(fc, ctx, recursionStack);
return out;
}
function same(f) {
return makeLazy(f, f);
}
function getSuspendRecursion(fc, ast) {
const depthIdentifier = suspendDepthIdentifierMap.get(ast) ?? fc.createDepthIdentifier();
suspendDepthIdentifierMap.set(ast, depthIdentifier);
return {
maxDepth: 2,
depthIdentifier
};
}
function oneOf(fc, arbitraries) {
return arbitraries.length === 0 ? undefined : arbitraries.length === 1 ? arbitraries[0] : fc.oneof(...arbitraries);
}
function reportChecks(report, checks, path) {
function visit(check, covered) {
const arbitrary = check.annotations?.arbitrary;
const nextCovered = covered || arbitrary?.constraint !== undefined || arbitrary?.candidate !== undefined;
if (check._tag !== "Filter") {
for (const child of check.checks) {
visit(child, nextCovered);
}
} else if (!nextCovered) {
const meta = check.annotations?.meta;
const description = typeof meta === "object" && meta !== null && "_tag" in meta && typeof meta._tag === "string" ? meta._tag : check.annotations?.identifier ?? check.annotations?.expected;
report.warnings.push({
_tag: "OpaqueFilter",
path,
...(description === undefined ? {} : {
description
})
});
}
}
checks?.forEach(check => visit(check, false));
}
/** @internal */
export function collectReport(ast, report) {
const stack = new WeakSet();
function visit(ast, path) {
if (stack.has(ast)) {
return;
}
stack.add(ast);
reportChecks(report, ast.checks, path);
switch (ast._tag) {
case "Declaration":
ast.typeParameters.forEach(tp => visit(tp, path));
break;
case "Arrays":
{
for (const [i, type] of [...ast.elements, ...ast.rest].entries()) {
visit(type, [...path, i]);
}
break;
}
case "Objects":
ast.propertySignatures.forEach(ps => visit(ps.type, [...path, ps.name]));
ast.indexSignatures.forEach(is => {
visit(is.parameter, path);
visit(is.type, path);
});
break;
case "Union":
ast.types.forEach(type => visit(type, path));
break;
case "Suspend":
visit(ast.thunk(), path);
break;
}
stack.delete(ast);
}
visit(ast, []);
}
function applyCandidates(fc, ctx, arbitraries, base) {
const weighted = base === undefined ? [] : [{
arbitrary: base,
weight: 1
}];
for (const {
candidate
} of arbitraries) {
if (!candidate) {
continue;
}
const arbitrary = candidate.make(fc, ctx);
if (arbitrary === undefined) {
continue;
}
const weight = candidate.weight ?? 1;
if (!globalThis.Number.isInteger(weight) || weight <= 0) {
throw arbitraryError("a candidate with an invalid weight");
}
weighted.push({
arbitrary,
weight
});
}
return weighted.length === 0 ? undefined : weighted.length === 1 ? weighted[0].arbitrary : fc.oneof(...weighted);
}
function applyFilterLayer(ast, checks, fc, ctx, base) {
const out = applyCandidates(fc, ctx, checks.arbitraries, base);
return out === undefined ? undefined : applyChecks(ast, checks.filters, out);
}
function normalizeDerivation(output, hasTypeParameters) {
if (!(typeof output === "object" && output !== null && "arbitrary" in output)) {
return {
arbitrary: output,
terminal: hasTypeParameters ? undefined : output
};
}
const terminal = "terminal" in output ? output.terminal : hasTypeParameters ? undefined : output.arbitrary;
return {
arbitrary: output.arbitrary,
terminal
};
}
function makeTypeParameters(typeParameters, fc, ctx, recursionStack, lazyNormal) {
return typeParameters.map(tp => ({
arbitrary: lazyNormal ? fc.constant(null).chain(() => tp(fc, ctx, recursionStack)) : tp(fc, ctx, recursionStack),
terminal: tp.terminal(fc, ctx, recursionStack)
}));
}
function filterLayer(ast, checks, normalBase, terminalBase) {
const f = constraintContext(checks.arbitraries);
return makeLazy((fc, ctx, recursionStack) => {
const nextCtx = f(ctx);
return applyFilterLayer(ast, checks, fc, nextCtx, normalBase(fc, ctx, nextCtx, recursionStack));
}, (fc, ctx, recursionStack) => {
const nextCtx = f(ctx);
return applyFilterLayer(ast, checks, fc, nextCtx, terminalBase(fc, ctx, nextCtx, recursionStack));
});
}
/** @internal */
export const memoized = /*#__PURE__*/memoize(ast => recur(ast, []));
function recur(ast, path) {
// ---------------------------------------------
// handle annotations
// ---------------------------------------------
const annotation = InternalAnnotations.resolve(ast)?.toArbitrary;
if (annotation) {
const typeParameters = SchemaAST.isDeclaration(ast) ? ast.typeParameters.map(tp => recur(tp, path)) : [];
const checks = collectChecks(ast.checks);
const derive = lazyNormal => (fc, ctx, nextCtx, recursionStack) => normalizeDerivation(annotation(makeTypeParameters(typeParameters, fc, resetContext(ctx), recursionStack, lazyNormal))(fc, nextCtx), typeParameters.length > 0)[lazyNormal ? "terminal" : "arbitrary"];
return filterLayer(ast, checks, derive(false), derive(true));
}
if (ast.checks) {
const checks = collectChecks(ast.checks);
const lawc = recur(SchemaAST.replaceChecks(ast, undefined), path);
return filterLayer(ast, checks, (fc, _ctx, nextCtx, recursionStack) => lawc(fc, nextCtx, recursionStack), (fc, _ctx, nextCtx, recursionStack) => lawc.terminal(fc, nextCtx, recursionStack));
}
return base(ast, path);
}
function base(ast, path) {
switch (ast._tag) {
case "Never":
case "Declaration":
throw errorWithPath(`Unsupported AST ${ast._tag}`, path);
case "Null":
return same(fc => fc.constant(null));
case "Void":
case "Undefined":
return same(fc => fc.constant(undefined));
case "Unknown":
case "Any":
return same(fc => fc.anything());
case "String":
return same((fc, ctx) => {
const constraint = ctx.constraint;
const patterns = constraint?.patterns;
return patterns ? fc.oneof(...patterns.map(pattern => fc.stringMatching(new RegExp(pattern)))) : fc.string(lengthToFastCheckConstraints(constraint));
});
case "Number":
return same((fc, ctx) => {
const constraint = ctx.constraint;
const ordered = constraint?.ordered?.order === Order.Number ? constraint.ordered : undefined;
return constraint?.integer ? fc.integer(toIntegerConstraints(ordered)) : fc.float(toFloatConstraints(constraint, ordered));
});
case "Boolean":
return same(fc => fc.boolean());
case "BigInt":
return same((fc, ctx) => {
const ordered = ctx.constraint?.ordered?.order === Order.BigInt ? ctx.constraint.ordered : undefined;
return fc.bigInt(toBigIntConstraints(ordered));
});
case "Symbol":
return same(fc => fc.string().map(Symbol.for));
case "Literal":
return same(fc => fc.constant(ast.literal));
case "UniqueSymbol":
return same(fc => fc.constant(ast.symbol));
case "ObjectKeyword":
return same(fc => fc.oneof(fc.object(), fc.array(fc.anything())));
case "Enum":
return recur(SchemaAST.enumsToLiterals(ast), path);
case "TemplateLiteral":
return same(fc => fc.stringMatching(SchemaAST.getTemplateLiteralRegExp(ast)));
case "Arrays":
{
const elements = ast.elements.map((ast, i) => ({
ast,
arbitrary: recur(ast, [...path, i])
}));
const len = ast.elements.length;
const rest = ast.rest.map((ast, i) => ({
ast,
arbitrary: recur(ast, [...path, len + i])
}));
const terminal = (fc, ctx, recursionStack) => {
const reset = resetContext(ctx);
const elementArbitraries = [];
const optionals = [];
let length = 0;
for (const element of elements) {
const out = element.arbitrary.terminal(fc, reset, recursionStack);
if (SchemaAST.isOptional(element.ast)) {
optionals.push(out);
continue;
}
if (out === undefined) {
return undefined;
}
length++;
elementArbitraries.push(out.map(Option.some));
}
const minLength = ctx.constraint?.minLength ?? 0;
const needsRest = Array.isReadonlyArrayNonEmpty(rest) && minLength > length + optionals.length;
const optionalTarget = needsRest ? optionals.length : Math.max(0, minLength - length);
let includedOptionals = 0;
for (const out of optionals) {
if (includedOptionals >= optionalTarget || out === undefined) {
elementArbitraries.push(fc.constant(Option.none()));
continue;
}
includedOptionals++;
length++;
elementArbitraries.push(out.map(Option.some));
}
if (includedOptionals < optionalTarget) {
return undefined;
}
let out = fc.tuple(...elementArbitraries).map(Array.getSomes);
if (Array.isReadonlyArrayNonEmpty(rest)) {
const [head, ...tail] = rest;
const restCtx = ast.elements.length === 0 ? ctx : reset;
const minRestLength = Math.max(0, minLength - length - tail.length);
const headArbitrary = minRestLength === 0 ? undefined : head.arbitrary.terminal(fc, reset, recursionStack);
if (minRestLength > 0 && headArbitrary === undefined) {
return undefined;
}
const restArbitrary = minRestLength === 0 ? fc.constant([]) : array(fc, {
...restCtx,
constraint: {
...restCtx.constraint,
minLength: minRestLength
}
}, headArbitrary, true);
out = appendArray(fc, out, len, restArbitrary);
if (tail.length > 0) {
const tailArbitraries = [];
for (const element of tail) {
const out = element.arbitrary.terminal(fc, reset, recursionStack);
if (out === undefined) {
return undefined;
}
tailArbitraries.push(out);
}
const t = fc.tuple(...tailArbitraries);
out = appendArray(fc, out, len, t);
}
}
return out;
};
return makeLazy((fc, ctx, recursionStack) => {
const reset = resetContext(ctx);
// ---------------------------------------------
// handle elements
// ---------------------------------------------
const elementArbitraries = elements.map(({
ast,
arbitrary
}) => {
const out = arbitrary(fc, reset, recursionStack);
return SchemaAST.isOptional(ast) ? out.chain(a => fc.boolean().map(b => b ? Option.some(a) : Option.none())) : out.map(Option.some);
});
let out = fc.tuple(...elementArbitraries).map(Array.getSomes);
// ---------------------------------------------
// handle rest element
// ---------------------------------------------
if (Array.isReadonlyArrayNonEmpty(rest)) {
const [head, ...tail] = rest.map(({
arbitrary
}) => arbitrary(fc, reset, recursionStack));
const restArbitrary = array(fc, ast.elements.length === 0 ? ctx : reset, head);
out = appendArray(fc, out, len, restArbitrary);
// ---------------------------------------------
// handle post rest elements
// ---------------------------------------------
if (tail.length > 0) {
const t = fc.tuple(...tail);
out = appendArray(fc, out, len, t);
}
}
if (ctx.recursion) {
const terminalOut = terminal(fc, ctx, recursionStack);
if (terminalOut !== undefined) {
return fc.oneof(ctx.recursion, terminalOut, out);
}
}
return out;
}, terminal);
}
case "Objects":
{
const propertySignatures = ast.propertySignatures.map(ps => ({
ps,
arbitrary: recur(ps.type, [...path, ps.name])
}));
const indexSignatures = ast.indexSignatures.map(is => ({
is,
parameter: recur(is.parameter, path),
type: recur(is.type, path)
}));
const terminal = (fc, ctx, recursionStack) => {
const reset = resetContext(ctx);
const pss = {};
const requiredKeys = [];
const optionals = [];
for (const {
ps,
arbitrary
} of propertySignatures) {
const name = ps.name;
const out = arbitrary.terminal(fc, reset, recursionStack);
if (SchemaAST.isOptional(ps.type)) {
if (out !== undefined) {
optionals.push([name, out]);
}
continue;
}
if (out === undefined) {
return undefined;
}
requiredKeys.push(name);
pss[name] = out;
}
let optionalCount = Math.max(0, (ctx.constraint?.minLength ?? 0) - requiredKeys.length);
for (const [name, out] of optionals) {
if (optionalCount === 0) {
break;
}
optionalCount--;
requiredKeys.push(name);
pss[name] = out;
}
if (optionalCount > 0 && ast.indexSignatures.length === 0) {
return undefined;
}
let out = fc.record(pss, {
requiredKeys
});
const entriesConstraints = objectEntriesConstraints(ast, ctx.constraint, requiredKeys.length);
const minEntries = entriesConstraints?.minLength ?? 0;
for (const {
parameter,
type
} of indexSignatures) {
let entries;
if (minEntries === 0) {
entries = fc.constant([]);
} else {
const key = parameter.terminal(fc, reset, recursionStack);
const value = type.terminal(fc, reset, recursionStack);
if (key === undefined || value === undefined) {
return undefined;
}
entries = arrayWithConstraints(fc, fc.tuple(key, value), {
...entriesConstraints,
maxLength: minEntries
}, entryComparator);
}
out = appendObjectEntries(out, entries);
}
return out;
};
return makeLazy((fc, ctx, recursionStack) => {
const reset = resetContext(ctx);
// ---------------------------------------------
// handle property signatures
// ---------------------------------------------
const pss = {};
const orderedNames = [];
const requiredKeys = [];
const optionalNames = [];
for (const {
ps,
arbitrary
} of propertySignatures) {
const name = ps.name;
orderedNames.push(name);
if (SchemaAST.isOptional(ps.type)) {
optionalNames.push(name);
} else {
requiredKeys.push(name);
}
pss[name] = arbitrary(fc, reset, recursionStack);
}
// When property-count constraints must be satisfied by selecting
// optional keys (no index signatures are available to fill the gap),
// generate a count-controlled subset of optional keys instead of
// relying on fast-check's independent inclusion plus discards. This
// enforces both bounds precisely while still varying which optionals
// appear.
const constraint = ctx.constraint;
if (optionalNames.length > 0 && indexSignatures.length === 0 && constraint !== undefined && (constraint.minLength !== undefined || constraint.maxLength !== undefined)) {
return objectWithOptionalCount(fc, pss, orderedNames, requiredKeys, optionalNames, constraint);
}
let out = fc.record(pss, {
requiredKeys
});
const entriesConstraints = objectEntriesConstraints(ast, ctx.constraint, requiredKeys.length);
// ---------------------------------------------
// handle index signatures
// ---------------------------------------------
for (const {
parameter,
type
} of indexSignatures) {
const entry = fc.tuple(parameter(fc, reset, recursionStack), type(fc, reset, recursionStack));
const entries = arrayWithConstraints(fc, entry, entriesConstraints, entryComparator);
out = appendObjectEntries(out, entries);
}
return out;
}, terminal);
}
case "Union":
{
const types = ast.types.map(ast => recur(ast, path));
const terminal = (fc, ctx, recursionStack) => oneOf(fc, types.map(type => type.terminal(fc, ctx, recursionStack)).filter(Predicate.isNotUndefined));
return makeLazy((fc, ctx, recursionStack) => {
const arbitraries = types.map(type => type(fc, ctx, recursionStack));
if (ctx.recursion) {
const terminalOut = terminal(fc, ctx, recursionStack);
if (terminalOut !== undefined) {
return fc.oneof(ctx.recursion, terminalOut, ...arbitraries);
}
}
const out = oneOf(fc, arbitraries);
if (out === undefined) {
throw arbitraryError("a union with no members");
}
return out;
}, terminal);
}
case "Suspend":
{
const memo = arbitraryMemoMap.get(ast);
if (memo) return memo;
const get = SchemaAST.memoizeThunk(() => recur(ast.thunk(), path));
const out = makeLazy((fc, ctx, recursionStack) => {
const recursion = getSuspendRecursion(fc, ast);
const nextCtx = {
...ctx,
recursion
};
const nextStack = recursionStack.includes(ast) ? recursionStack : [...recursionStack, ast];
const terminal = get().terminal(fc, nextCtx, nextStack);
if (terminal === undefined) {
throw errorWithPath("Unable to derive an arbitrary for a recursive schema without a finite generation path", path);
}
return fc.oneof(recursion, terminal, fc.constant(null).chain(() => get()(fc, nextCtx, nextStack)));
}, (fc, ctx, recursionStack) => {
if (recursionStack.includes(ast)) {
return undefined;
}
const recursion = getSuspendRecursion(fc, ast);
return get().terminal(fc, {
...ctx,
recursion
}, [...recursionStack, ast]);
});
arbitraryMemoMap.set(ast, out);
return out;
}
}
}
//# sourceMappingURL=arbitrary.js.map

Xet Storage Details

Size:
29 kB
·
Xet hash:
e2ab60fa2cc2b6396b88e7a7646557b9f64227051e20fce4f5629fe48753e61f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.