@arktype/schema
Advanced tools
Comparing version 0.0.1 to 0.0.2
1898
dist/main.js
@@ -1,1874 +0,24 @@ | ||
// node.ts | ||
import { | ||
CompiledFunction, | ||
DynamicBase, | ||
entriesOf as entriesOf3, | ||
hasDomain as hasDomain2, | ||
includes as includes2, | ||
isArray as isArray4, | ||
throwInternalError as throwInternalError6, | ||
throwParseError as throwParseError6 | ||
} from "@arktype/util"; | ||
// bases/basis.ts | ||
import { | ||
stringify as stringify3, | ||
throwParseError as throwParseError2 | ||
} from "@arktype/util"; | ||
// io/registry.ts | ||
import { domainOf, objectKindOf, throwInternalError } from "@arktype/util"; | ||
// io/compile.ts | ||
import { | ||
hasDomain, | ||
isArray, | ||
serializePrimitive | ||
} from "@arktype/util"; | ||
var In = "$arkRoot"; | ||
var CompilationState = class { | ||
constructor(config) { | ||
this.config = config; | ||
} | ||
path = []; | ||
discriminants = []; | ||
get data() { | ||
let result = In; | ||
for (const k of this.path) { | ||
if (typeof k === "string") { | ||
result += compilePropAccess(k); | ||
} else { | ||
result += `[${k[0]}]`; | ||
} | ||
} | ||
return result; | ||
} | ||
getNextIndex(prefix) { | ||
let name = prefix; | ||
let suffix = 2; | ||
for (const k of this.path) { | ||
if (isArray(k) && k[0].startsWith(prefix)) { | ||
name = `${prefix}${suffix++}`; | ||
} | ||
} | ||
return name; | ||
} | ||
pushNamedKey(name) { | ||
this.path.push(name); | ||
} | ||
getNextIndexKeyAndPush(prefix) { | ||
const k = this.getNextIndex(prefix); | ||
this.path.push([k]); | ||
return k; | ||
} | ||
popKey() { | ||
return this.path.pop(); | ||
} | ||
problem(code, rule) { | ||
return `state.addProblem("${code}", ${compileSerializedValue(rule)}, ${this.data}, [${this.path.map( | ||
(segment) => ( | ||
// if the segment is a variable reference, don't quote it | ||
typeof segment === "string" ? JSON.stringify(segment) : segment[0] | ||
) | ||
)}])`; | ||
} | ||
invalid(code, rule) { | ||
return this.config.failureKind === "problems" ? this.problem(code, rule) : "return false"; | ||
} | ||
check(code, rule, condition) { | ||
const pathString = this.path.join(); | ||
if (code === "domain" && rule === "object" && this.discriminants.some((d) => d.path.join().startsWith(pathString))) { | ||
return ""; | ||
} | ||
if ((code === "domain" || code === "value") && this.discriminants.some( | ||
(d) => d.path.join() === pathString && (code === "domain" ? d.kind === "domain" || d.kind === "value" : d.kind === "value") | ||
)) { | ||
return ""; | ||
} | ||
return `if (!(${condition})) { | ||
${this.invalid(code, rule)} | ||
}`; | ||
} | ||
}; | ||
var compileSerializedValue = (value) => { | ||
return hasDomain(value, "object") || typeof value === "symbol" ? registry().register(value) : serializePrimitive(value); | ||
}; | ||
var isDotAccessible = (name) => /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(name); | ||
var compilePropAccess = (name, optional = false) => isDotAccessible(name) ? `${optional ? "?" : ""}.${name}` : `${optional ? "?." : ""}[${JSON.stringify(name)}]`; | ||
// io/registry.ts | ||
var arkKind = Symbol("ArkTypeInternalKind"); | ||
var isNode = (o) => o?.[arkKind] === "node"; | ||
var registry = () => new Registry(); | ||
var Registry = class { | ||
constructor() { | ||
const global = globalThis; | ||
if (global.$ark) { | ||
return global.$ark; | ||
} | ||
global.$ark = this; | ||
} | ||
register(value, baseName = baseNameFor(value)) { | ||
let variableName = baseName; | ||
let suffix = 2; | ||
while (variableName in this && this[variableName] !== value) { | ||
variableName = `${baseName}${suffix++}`; | ||
} | ||
this[variableName] = value; | ||
return this.reference(variableName); | ||
} | ||
reference = (key) => `$ark.${key}`; | ||
}; | ||
var baseNameFor = (value) => { | ||
switch (typeof value) { | ||
case "object": | ||
if (value === null) { | ||
break; | ||
} | ||
const prefix = objectKindOf(value) ?? "object"; | ||
return prefix[0].toLowerCase() + prefix.slice(1); | ||
case "function": | ||
return isDotAccessible(value.name) ? value.name : "anonymousFunction"; | ||
case "symbol": | ||
return value.description && isDotAccessible(value.description) ? value.description : "anonymousSymbol"; | ||
} | ||
return throwInternalError( | ||
`Unexpected attempt to register serializable value of type ${domainOf( | ||
value | ||
)}` | ||
); | ||
}; | ||
// shared/define.ts | ||
var basisKinds = ["unit", "proto", "domain"]; | ||
var closedConstraintKinds = ["divisor", "max", "min"]; | ||
var openConstraintKinds = [ | ||
"pattern", | ||
"predicate", | ||
"required", | ||
"optional" | ||
]; | ||
var constraintKinds = [ | ||
...closedConstraintKinds, | ||
...openConstraintKinds | ||
]; | ||
var setKinds = ["union", "morph", "intersection"]; | ||
var rootKinds = [...setKinds, ...basisKinds]; | ||
var ruleKinds = [...basisKinds, ...constraintKinds]; | ||
var nodeKinds = [...setKinds, ...ruleKinds]; | ||
function defineNode(input) { | ||
Object.assign(input.keys, { | ||
alias: { | ||
meta: true | ||
}, | ||
description: { | ||
meta: true | ||
} | ||
}); | ||
return Object.assign(input, { | ||
defaultableKeys: Object.keys(input.keys).filter( | ||
(k) => input.keys[k].defaultable | ||
) | ||
}); | ||
} | ||
// shared/disjoint.ts | ||
import { | ||
entriesOf, | ||
fromEntries, | ||
stringify, | ||
throwInternalError as throwInternalError2, | ||
throwParseError, | ||
transform | ||
} from "@arktype/util"; | ||
var Disjoint = class _Disjoint { | ||
constructor(sources) { | ||
this.sources = sources; | ||
} | ||
static from(kind, l, r) { | ||
return new _Disjoint({ | ||
"[]": { | ||
[kind]: { | ||
l, | ||
r | ||
} | ||
} | ||
}); | ||
} | ||
static fromEntries(entries) { | ||
if (!entries.length) { | ||
return throwInternalError2( | ||
`Unexpected attempt to create a disjoint from no entries` | ||
); | ||
} | ||
return new _Disjoint({ "[]": fromEntries(entries) }); | ||
} | ||
get flat() { | ||
return entriesOf(this.sources).flatMap( | ||
([path, disjointKinds]) => entriesOf(disjointKinds).map(([kind, disjoint]) => ({ | ||
path, | ||
kind, | ||
disjoint | ||
})) | ||
); | ||
} | ||
describeReasons() { | ||
const reasons = this.flat; | ||
if (reasons.length === 1) { | ||
const { path, disjoint } = reasons[0]; | ||
const pathString = JSON.parse(path).join("."); | ||
return `Intersection${pathString && ` at ${pathString}`} of ${disjoint.l} and ${disjoint.r} results in an unsatisfiable type`; | ||
} | ||
return `The following intersections result in unsatisfiable types: | ||
\u2022 ${reasons.map(({ path, disjoint }) => `${path}: ${disjoint.l} and ${disjoint.r}`).join("\n\u2022 ")}`; | ||
} | ||
throw() { | ||
return throwParseError(this.describeReasons()); | ||
} | ||
invert() { | ||
const invertedEntries = entriesOf(this.sources).map( | ||
([path, disjoints]) => [ | ||
path, | ||
transform(disjoints, ([kind, disjoint]) => [ | ||
kind, | ||
{ l: disjoint.r, r: disjoint.l } | ||
]) | ||
] | ||
); | ||
return new _Disjoint(fromEntries(invertedEntries)); | ||
} | ||
withPrefixKey(key) { | ||
const entriesWithPrefix = entriesOf(this.sources).map( | ||
([path, disjoints]) => { | ||
const segments = JSON.parse(path); | ||
segments.unshift(key); | ||
const pathWithPrefix = JSON.stringify(segments); | ||
return [pathWithPrefix, disjoints]; | ||
} | ||
); | ||
return new _Disjoint(fromEntries(entriesWithPrefix)); | ||
} | ||
toString() { | ||
return stringify(this.sources); | ||
} | ||
}; | ||
// bases/domain.ts | ||
var DomainImplementation = defineNode({ | ||
kind: "domain", | ||
keys: { | ||
domain: {} | ||
}, | ||
intersections: { | ||
domain: (l, r) => Disjoint.from("domain", l, r) | ||
}, | ||
normalize: (input) => typeof input === "string" ? { domain: input } : input, | ||
writeDefaultDescription: (inner) => domainDescriptions[inner.domain], | ||
attach: (inner) => ({ | ||
basisName: inner.domain, | ||
condition: inner.domain === "object" ? `((typeof ${In} === "object" && ${In} !== null) || typeof ${In} === "function")` : `typeof ${In} === "${inner.domain}"` | ||
}) | ||
}); | ||
var enumerableDomainDescriptions = { | ||
boolean: "boolean", | ||
null: "null", | ||
undefined: "undefined" | ||
}; | ||
var nonEnumerableDomainDescriptions = { | ||
bigint: "a bigint", | ||
number: "a number", | ||
object: "an object", | ||
string: "a string", | ||
symbol: "a symbol" | ||
}; | ||
var domainDescriptions = { | ||
...nonEnumerableDomainDescriptions, | ||
...enumerableDomainDescriptions | ||
}; | ||
// bases/proto.ts | ||
import { | ||
constructorExtends, | ||
getExactBuiltinConstructorName, | ||
objectKindDescriptions, | ||
objectKindOf as objectKindOf2 | ||
} from "@arktype/util"; | ||
var ProtoImplementation = defineNode({ | ||
kind: "proto", | ||
keys: { | ||
proto: {} | ||
}, | ||
intersections: { | ||
proto: (l, r) => constructorExtends(l.proto, r.proto) ? l : constructorExtends(r.proto, l.proto) ? r : Disjoint.from("proto", l, r), | ||
domain: (l, r) => r.domain === "object" ? l : Disjoint.from("domain", l.cls.builtins.object, r) | ||
}, | ||
normalize: (input) => typeof input === "function" ? { proto: input } : input, | ||
writeDefaultDescription: (node2) => { | ||
const knownObjectKind = getExactBuiltinConstructorName(node2.proto); | ||
return knownObjectKind ? objectKindDescriptions[knownObjectKind] : `an instance of ${node2.proto.name}`; | ||
}, | ||
attach: (node2) => ({ | ||
basisName: `${node2.proto.name}`, | ||
domain: "object", | ||
condition: `${In} instanceof ${objectKindOf2(node2.proto) ?? compileSerializedValue(node2.proto)}` | ||
}) | ||
}); | ||
// bases/unit.ts | ||
import { domainOf as domainOf2, stringify as stringify2 } from "@arktype/util"; | ||
var UnitImplementation = defineNode({ | ||
kind: "unit", | ||
keys: { | ||
is: { | ||
preserveUndefined: true | ||
} | ||
}, | ||
intersections: { | ||
unit: (l, r) => Disjoint.from("unit", l, r), | ||
default: (l, r) => r.allows(l.is) ? l : Disjoint.from("assignability", l.is, r) | ||
}, | ||
writeDefaultDescription: (inner) => stringify2(inner.is), | ||
attach: (node2) => ({ | ||
basisName: stringify2(node2.is), | ||
domain: domainOf2(node2.is), | ||
condition: `${In} === ${compileSerializedValue(node2.is)}` | ||
}) | ||
}); | ||
// bases/basis.ts | ||
var BasisImplementations = { | ||
domain: DomainImplementation, | ||
proto: ProtoImplementation, | ||
unit: UnitImplementation | ||
}; | ||
var maybeGetBasisKind = (schema) => { | ||
switch (typeof schema) { | ||
case "string": | ||
return "domain"; | ||
case "function": | ||
return "proto"; | ||
case "object": | ||
if (schema === null) { | ||
return; | ||
} | ||
if (isNode(schema)) { | ||
if (schema.isBasis()) { | ||
return schema.kind; | ||
} | ||
} | ||
if ("domain" in schema) { | ||
return "domain"; | ||
} else if ("proto" in schema) { | ||
return "proto"; | ||
} else if ("is" in schema) { | ||
return "unit"; | ||
} | ||
} | ||
}; | ||
var getBasisKindOrThrow = (schema) => { | ||
const basisKind = maybeGetBasisKind(schema); | ||
if (basisKind === void 0) { | ||
return throwParseError2( | ||
`${stringify3( | ||
schema | ||
)} is not a valid basis schema. Please provide one of the following: | ||
- A string representing a non-enumerable domain ("string", "number", "object", "bigint", or "symbol") | ||
- A constructor like Array | ||
- A schema object with one of the following keys: | ||
- "domain" | ||
- "proto" | ||
- "is"` | ||
); | ||
} | ||
return basisKind; | ||
}; | ||
// sets/intersection.ts | ||
import { | ||
includes, | ||
isArray as isArray2, | ||
throwInternalError as throwInternalError3 | ||
} from "@arktype/util"; | ||
var IntersectionImplementation = defineNode({ | ||
kind: "intersection", | ||
keys: { | ||
basis: { | ||
// this gets parsed ahead of time in updateContext, so we just reuse that | ||
parse: (schema, ctx) => ctx.basis | ||
}, | ||
divisor: { | ||
parse: (schema, ctx) => ctx.base.parseSchema("divisor", schema, ctx) | ||
}, | ||
max: { | ||
parse: (schema, ctx) => ctx.base.parseSchema("max", schema, ctx) | ||
}, | ||
min: { | ||
parse: (schema, ctx) => ctx.base.parseSchema("min", schema, ctx) | ||
}, | ||
pattern: { | ||
parse: (schema, ctx) => parseOpenConstraints("pattern", schema, ctx) | ||
}, | ||
predicate: { | ||
parse: (schema, ctx) => parseOpenConstraints("predicate", schema, ctx) | ||
}, | ||
optional: { | ||
parse: (schema, ctx) => parseOpenConstraints("optional", schema, ctx) | ||
}, | ||
required: { | ||
parse: (schema, ctx) => parseOpenConstraints("required", schema, ctx) | ||
} | ||
}, | ||
updateContext: (schema, ctx) => { | ||
if (schema.basis === void 0) { | ||
return ctx; | ||
} | ||
const basisKind = getBasisKindOrThrow(schema.basis); | ||
return { | ||
...ctx, | ||
basis: ctx.base.parseSchema(basisKind, schema.basis, ctx) | ||
}; | ||
}, | ||
intersections: { | ||
intersection: (l, r) => { | ||
let result = l.rules; | ||
for (const constraint of r.constraints) { | ||
if (result instanceof Disjoint) { | ||
break; | ||
} | ||
result = addRule(result, constraint); | ||
} | ||
return result instanceof Disjoint ? result : unflattenRules(result); | ||
}, | ||
default: (l, r) => { | ||
const result = addRule(l.rules, r); | ||
return result instanceof Disjoint ? result : unflattenRules(result); | ||
} | ||
}, | ||
reduce: (inner, ctx) => { | ||
const { description, alias, ...rulesByKind } = inner; | ||
const inputRules = Object.values(rulesByKind).flat(); | ||
const reducedRules = reduceRules([], inputRules); | ||
if (reducedRules instanceof Disjoint) { | ||
return reducedRules.throw(); | ||
} | ||
if (reducedRules.length === 1 && reducedRules[0].isBasis()) { | ||
return reducedRules[0]; | ||
} | ||
if (reducedRules.length === inputRules.length) { | ||
return; | ||
} | ||
const reducedRulesByKind = unflattenRules( | ||
reducedRules | ||
); | ||
if (description) { | ||
reducedRulesByKind.description = description; | ||
} | ||
if (alias) { | ||
reducedRulesByKind.alias = alias; | ||
} | ||
return ctx.base.parsePrereduced("intersection", reducedRulesByKind); | ||
}, | ||
attach: (node2) => { | ||
const attachments = { | ||
rules: [], | ||
constraints: [], | ||
compile: (cfg) => attachments.rules.map( | ||
(rule) => `if(!(${rule.condition})) { | ||
return false | ||
}` | ||
).join("\n") + "\nreturn true" | ||
}; | ||
for (const [k, v] of node2.entries) { | ||
if (k === "basis") { | ||
attachments.rules.push(v); | ||
} else if (includes(constraintKinds, k)) { | ||
attachments.rules.push(v); | ||
attachments.constraints.push(v); | ||
} | ||
} | ||
return attachments; | ||
}, | ||
writeDefaultDescription: (node2) => { | ||
return node2.rules.length === 0 ? "an unknown value" : node2.rules.join(" and "); | ||
} | ||
}); | ||
var parseOpenConstraints = (kind, input, ctx) => { | ||
if (isArray2(input)) { | ||
if (input.length === 0) { | ||
return; | ||
} | ||
return input.map( | ||
(constraint) => ctx.base.parseSchema(kind, constraint, ctx) | ||
); | ||
} | ||
return [ctx.base.parseSchema(kind, input, ctx)]; | ||
}; | ||
var reduceRules = (l, r) => { | ||
let result = l; | ||
for (const constraint of r) { | ||
if (result instanceof Disjoint) { | ||
break; | ||
} | ||
result = addRule(result, constraint); | ||
} | ||
return result instanceof Disjoint ? result : result; | ||
}; | ||
var flattenRules = (inner) => Object.values(inner).flatMap( | ||
(v) => typeof v === "object" ? v : [] | ||
); | ||
var unflattenRules = (rules) => { | ||
const inner = {}; | ||
for (const rule of rules) { | ||
if (rule.isBasis()) { | ||
inner.basis = rule; | ||
} else if (rule.isOpenConstraint()) { | ||
inner[rule.kind] ??= []; | ||
inner[rule.kind].push(rule); | ||
} else if (rule.isClosedConstraint()) { | ||
if (inner[rule.kind]) { | ||
return throwInternalError3( | ||
`Unexpected intersection of closed constraints of kind ${rule.kind}` | ||
); | ||
} | ||
inner[rule.kind] = rule; | ||
} | ||
} | ||
return inner; | ||
}; | ||
var addRule = (base, rule) => { | ||
const result = []; | ||
let includesConstraint = false; | ||
for (let i = 0; i < base.length; i++) { | ||
const elementResult = rule.intersectClosed(base[i]); | ||
if (elementResult === null) { | ||
result.push(base[i]); | ||
} else if (elementResult instanceof Disjoint) { | ||
return elementResult; | ||
} else if (!includesConstraint) { | ||
result.push(elementResult); | ||
includesConstraint = true; | ||
} else if (!base.includes(elementResult)) { | ||
return throwInternalError3( | ||
`Unexpectedly encountered multiple distinct intersection results for constraint ${elementResult}` | ||
); | ||
} | ||
} | ||
if (!includesConstraint) { | ||
result.push(rule); | ||
} | ||
return result; | ||
}; | ||
// shared/builtins.ts | ||
function createBuiltins() { | ||
return { | ||
unknown: node({}), | ||
bigint: node("bigint"), | ||
number: node("number"), | ||
object: node("object"), | ||
string: node("string"), | ||
symbol: node("symbol"), | ||
array: node(Array), | ||
date: node(Date), | ||
false: node({ is: false }), | ||
null: node({ is: null }), | ||
undefined: node({ is: void 0 }), | ||
true: node({ is: true }), | ||
never: node(), | ||
// this is parsed as prereduced so we can compare future | ||
// unions to it to determine if they should be reduced to unknown | ||
unknownUnion: parsePrereduced("union", [ | ||
"string", | ||
"number", | ||
"object", | ||
"bigint", | ||
"symbol", | ||
{ is: true }, | ||
{ is: false }, | ||
{ is: null }, | ||
{ is: void 0 } | ||
]) | ||
}; | ||
} | ||
// shared/intersect.ts | ||
import { throwInternalError as throwInternalError4 } from "@arktype/util"; | ||
var leftOperandOf = (l, r) => { | ||
for (const kind of nodeKinds) { | ||
if (l.kind === kind) { | ||
return l; | ||
} else if (r.kind === kind) { | ||
return r; | ||
} | ||
} | ||
return throwInternalError4( | ||
`Unable to order unknown node kinds '${l.kind}' and '${r.kind}'.` | ||
); | ||
}; | ||
// constraints/bounds.ts | ||
import { constructorExtends as constructorExtends2, throwParseError as throwParseError3 } from "@arktype/util"; | ||
var MinImplementation = defineNode({ | ||
kind: "min", | ||
keys: { | ||
min: { | ||
parse: (_) => +_ | ||
}, | ||
exclusive: {}, | ||
boundKind: { | ||
parse: (_, ctx) => getBoundKind(ctx.basis), | ||
defaultable: true | ||
} | ||
}, | ||
intersections: { | ||
min: (l, r) => l.min > r.min || l.min === r.min && l.exclusive ? l : r | ||
}, | ||
normalize: (schema) => typeof schema === "object" ? schema : { min: schema }, | ||
writeDefaultDescription: (inner) => { | ||
const comparisonDescription = inner.boundKind === "date" ? inner.exclusive ? "after" : "at or after" : inner.exclusive ? "more than" : "at least"; | ||
return `${comparisonDescription} ${inner.min}`; | ||
}, | ||
attach: (node2) => { | ||
const comparator = `>${node2.exclusive ? "" : "="}`; | ||
return { | ||
comparator, | ||
condition: `${In} ${comparator} ${node2.min}`, | ||
implicitBasis: node2.cls.builtins[node2.boundKind] | ||
}; | ||
} | ||
}); | ||
var MaxImplementation = defineNode({ | ||
kind: "max", | ||
keys: { | ||
max: { | ||
parse: (_) => +_ | ||
}, | ||
exclusive: {}, | ||
boundKind: { | ||
parse: (_, ctx) => getBoundKind(ctx.basis), | ||
defaultable: true | ||
} | ||
}, | ||
intersections: { | ||
max: (l, r) => l.max > r.max || l.max === r.max && l.exclusive ? l : r, | ||
min: (l, r) => l.max < r.min || l.max === r.min && (l.exclusive || r.exclusive) ? Disjoint.from("bound", l, r) : null | ||
}, | ||
normalize: (schema) => typeof schema === "object" ? schema : { max: schema }, | ||
writeDefaultDescription: (inner) => { | ||
const comparisonDescription = inner.boundKind === "date" ? inner.exclusive ? "before" : "at or before" : inner.exclusive ? "less than" : "at most"; | ||
return `${comparisonDescription} ${inner.max}`; | ||
}, | ||
attach: (node2) => { | ||
const comparator = `<${node2.exclusive ? "" : "="}`; | ||
return { | ||
comparator, | ||
condition: `${In} ${comparator} ${node2.max}`, | ||
implicitBasis: node2.cls.builtins[node2.boundKind] | ||
}; | ||
} | ||
}); | ||
var getBoundKind = (basis) => { | ||
if (basis === void 0) { | ||
return throwParseError3(writeUnboundableMessage("unknown")); | ||
} | ||
if (basis.domain === "number" || basis.domain === "string") { | ||
return basis.domain; | ||
} | ||
if (basis.kind === "unit" && basis.is instanceof Array || basis.kind === "proto" && constructorExtends2(basis.proto, Array)) { | ||
return "array"; | ||
} | ||
if (basis.kind === "unit" && basis.is instanceof Date || basis.kind === "proto" && constructorExtends2(basis.proto, Date)) { | ||
return "date"; | ||
} | ||
return throwParseError3(writeUnboundableMessage(basis.basisName)); | ||
}; | ||
var writeIncompatibleRangeMessage = (l, r) => `Bound kinds ${l} and ${r} are incompatible`; | ||
var writeUnboundableMessage = (root) => `Bounded expression ${root} must be a number, string, Array, or Date`; | ||
// constraints/divisor.ts | ||
var DivisorImplementation = defineNode({ | ||
kind: "divisor", | ||
keys: { | ||
divisor: {} | ||
}, | ||
intersections: { | ||
divisor: (l, r) => ({ | ||
divisor: Math.abs( | ||
l.divisor * r.divisor / greatestCommonDivisor(l.divisor, r.divisor) | ||
) | ||
}) | ||
}, | ||
normalize: (schema) => typeof schema === "number" ? { divisor: schema } : schema, | ||
writeDefaultDescription: (inner) => inner.divisor === 1 ? "an integer" : `a multiple of ${inner.divisor}`, | ||
attach: (node2) => ({ | ||
implicitBasis: node2.cls.builtins.number, | ||
condition: `${In} % ${node2.divisor} === 0` | ||
}) | ||
}); | ||
var greatestCommonDivisor = (l, r) => { | ||
let previous; | ||
let greatestCommonDivisor2 = l; | ||
let current = r; | ||
while (current !== 0) { | ||
previous = current; | ||
current = greatestCommonDivisor2 % current; | ||
greatestCommonDivisor2 = previous; | ||
} | ||
return greatestCommonDivisor2; | ||
}; | ||
var writeIndivisibleMessage = (root) => `Divisibility operand ${root} must be a number`; | ||
// constraints/pattern.ts | ||
import { throwParseError as throwParseError4 } from "@arktype/util"; | ||
var PatternImplementation = defineNode({ | ||
kind: "pattern", | ||
keys: { | ||
pattern: {}, | ||
flags: {} | ||
}, | ||
intersections: { | ||
// For now, non-equal regex are naively intersected | ||
pattern: () => null | ||
}, | ||
normalize: (schema) => typeof schema === "string" ? parseRegexLiteral(schema) : schema instanceof RegExp ? schema.flags ? { pattern: schema.source, flags: schema.flags } : { pattern: schema.source } : schema, | ||
writeDefaultDescription: (inner) => `matched by ${inner.pattern}`, | ||
attach: (node2) => { | ||
return { | ||
implicitBasis: node2.cls.builtins.string, | ||
condition: `/${node2.pattern}/${node2.flags ?? ""}.test(${In})` | ||
}; | ||
} | ||
}); | ||
var serializeRegex = (regex) => `${regex}`; | ||
var regexLiteralMatcher = /^\/(.+)\/([a-z]*)$/; | ||
var parseRegexLiteral = (literal) => { | ||
const match = regexLiteralMatcher.exec(literal); | ||
if (!match || !match[1]) { | ||
return throwParseError4( | ||
`'${literal}' is not a valid RegexLiteral (should be /source/flags)` | ||
); | ||
} | ||
return match[2] ? { | ||
pattern: match[1], | ||
flags: match[2] | ||
} : { | ||
pattern: match[1] | ||
}; | ||
}; | ||
// constraints/predicate.ts | ||
var PredicateImplementation = defineNode({ | ||
kind: "predicate", | ||
keys: { | ||
predicate: {} | ||
}, | ||
intersections: { | ||
predicate: () => null | ||
}, | ||
normalize: (schema) => typeof schema === "function" ? { predicate: schema } : schema, | ||
writeDefaultDescription: (inner) => `valid according to ${inner.predicate.name}`, | ||
attach: (inner) => ({ | ||
implicitBasis: void 0, | ||
condition: `${compileSerializedValue(inner.predicate)}(${In})` | ||
}) | ||
}); | ||
// constraints/props/optional.ts | ||
var OptionalImplementation = defineNode({ | ||
kind: "optional", | ||
keys: { | ||
key: {}, | ||
value: { | ||
parse: (schema, ctx) => ctx.base.parseSchema(rootKinds, schema, ctx) | ||
} | ||
}, | ||
intersections: { | ||
optional: (l, r) => { | ||
if (l.key !== r.key) { | ||
return null; | ||
} | ||
const optional = l.key; | ||
const value = l.value.intersect(r.value); | ||
return { | ||
key: optional, | ||
value: value instanceof Disjoint ? l.cls.builtins.unknown : value | ||
}; | ||
} | ||
}, | ||
normalize: (schema) => schema, | ||
writeDefaultDescription: (inner) => `${String(inner.key)}?: ${inner.value}`, | ||
attach: (node2) => ({ | ||
implicitBasis: node2.cls.builtins.object, | ||
condition: "true" | ||
}) | ||
}); | ||
// constraints/props/required.ts | ||
var intersectNamed = (l, r) => { | ||
if (l.key !== r.key) { | ||
return null; | ||
} | ||
const required = l.key; | ||
const value = l.value.intersect(r.value); | ||
if (value instanceof Disjoint) { | ||
return value; | ||
} | ||
return { | ||
key: required, | ||
value | ||
}; | ||
}; | ||
var RequiredImplementation = defineNode({ | ||
kind: "required", | ||
keys: { | ||
key: {}, | ||
value: { | ||
parse: (schema, ctx) => ctx.base.parseSchema(rootKinds, schema, ctx) | ||
} | ||
}, | ||
intersections: { | ||
required: intersectNamed, | ||
optional: intersectNamed | ||
}, | ||
normalize: (schema) => schema, | ||
writeDefaultDescription: (inner) => `${String(inner.key)}: ${inner.value}`, | ||
attach: (node2) => ({ | ||
implicitBasis: node2.cls.builtins.object, | ||
condition: "true" | ||
}) | ||
}); | ||
// constraints/props/prop.ts | ||
var PropImplementations = { | ||
required: RequiredImplementation, | ||
optional: OptionalImplementation | ||
}; | ||
// constraints/constraint.ts | ||
var ConstraintImplementations = { | ||
divisor: DivisorImplementation, | ||
min: MinImplementation, | ||
max: MaxImplementation, | ||
pattern: PatternImplementation, | ||
predicate: PredicateImplementation, | ||
...PropImplementations | ||
}; | ||
// sets/morph.ts | ||
import { | ||
listFrom, | ||
throwParseError as throwParseError5 | ||
} from "@arktype/util"; | ||
var MorphImplementation = defineNode({ | ||
kind: "morph", | ||
keys: { | ||
in: { | ||
parse: (schema, ctx) => ctx.base.parseSchema(["intersection", ...basisKinds], schema, ctx) | ||
}, | ||
out: { | ||
parse: (schema, ctx) => ctx.base.parseSchema(["intersection", ...basisKinds], schema, ctx) | ||
}, | ||
morph: { | ||
parse: listFrom | ||
} | ||
}, | ||
intersections: { | ||
morph: (l, r) => { | ||
if (l.morph.some((morph, i) => morph !== r.morph[i])) { | ||
return throwParseError5(`Invalid intersection of morphs`); | ||
} | ||
const inTersection = l.in.intersect(r.in); | ||
if (inTersection instanceof Disjoint) { | ||
return inTersection; | ||
} | ||
const outTersection = l.out.intersect(r.out); | ||
if (outTersection instanceof Disjoint) { | ||
return outTersection; | ||
} | ||
return { | ||
morph: l.morph, | ||
in: inTersection, | ||
out: outTersection | ||
}; | ||
}, | ||
intersection: (l, r) => { | ||
const inTersection = l.in.intersect(r); | ||
return inTersection instanceof Disjoint ? inTersection : { | ||
...l.inner, | ||
in: inTersection | ||
}; | ||
}, | ||
default: (l, r) => { | ||
const constrainedInput = l.in.intersect(r); | ||
return constrainedInput instanceof Disjoint ? constrainedInput : { | ||
...l.inner, | ||
in: constrainedInput | ||
}; | ||
} | ||
}, | ||
writeDefaultDescription: (node2) => `a morph from ${node2.inner.in} to ${node2.inner.out}`, | ||
attach: (node2) => ({ | ||
compile: () => `return true`, | ||
inCache: node2.inner.in, | ||
outCache: node2.inner.out ?? node2.cls.builtins.unknown | ||
}) | ||
}); | ||
// sets/union.ts | ||
import { isArray as isArray3 } from "@arktype/util"; | ||
// sets/discriminate.ts | ||
import { | ||
entriesOf as entriesOf2, | ||
isKeyOf, | ||
throwInternalError as throwInternalError5 | ||
} from "@arktype/util"; | ||
var discriminantKinds = { | ||
domain: 1, | ||
value: 1 | ||
}; | ||
var parseDiscriminantKey = (key) => { | ||
const lastPathIndex = key.lastIndexOf("]"); | ||
return [ | ||
JSON.parse(key.slice(0, lastPathIndex + 1)), | ||
key.slice(lastPathIndex + 1) | ||
]; | ||
}; | ||
var discriminantCache = /* @__PURE__ */ new Map(); | ||
var discriminate = (branches) => { | ||
if (branches.length < 2) { | ||
return null; | ||
} | ||
const cached = discriminantCache.get(branches); | ||
if (cached !== void 0) { | ||
return cached; | ||
} | ||
const casesBySpecifier = {}; | ||
for (let lIndex = 0; lIndex < branches.length - 1; lIndex++) { | ||
const l = branches[lIndex]; | ||
for (let rIndex = lIndex + 1; rIndex < branches.length; rIndex++) { | ||
const r = branches[rIndex]; | ||
const result = l.intersect(r); | ||
if (!(result instanceof Disjoint)) { | ||
continue; | ||
} | ||
for (const { path: path2, kind: kind2, disjoint } of result.flat) { | ||
if (!isKeyOf(kind2, discriminantKinds)) { | ||
continue; | ||
} | ||
const qualifiedDiscriminant = `${path2}${kind2}`; | ||
let lSerialized; | ||
let rSerialized; | ||
if (kind2 === "domain") { | ||
lSerialized = disjoint.l; | ||
rSerialized = disjoint.r; | ||
} else if (kind2 === "value") { | ||
lSerialized = compileSerializedValue(disjoint.l); | ||
rSerialized = compileSerializedValue(disjoint.r); | ||
} else { | ||
return throwInternalError5( | ||
`Unexpected attempt to discriminate disjoint kind '${kind2}'` | ||
); | ||
} | ||
if (!casesBySpecifier[qualifiedDiscriminant]) { | ||
casesBySpecifier[qualifiedDiscriminant] = { | ||
[lSerialized]: [l], | ||
[rSerialized]: [r] | ||
}; | ||
continue; | ||
} | ||
const cases2 = casesBySpecifier[qualifiedDiscriminant]; | ||
if (!isKeyOf(lSerialized, cases2)) { | ||
cases2[lSerialized] = [l]; | ||
} else if (!cases2[lSerialized].includes(l)) { | ||
cases2[lSerialized].push(l); | ||
} | ||
if (!isKeyOf(rSerialized, cases2)) { | ||
cases2[rSerialized] = [r]; | ||
} else if (!cases2[rSerialized].includes(r)) { | ||
cases2[rSerialized].push(r); | ||
} | ||
} | ||
} | ||
} | ||
const bestDiscriminantEntry = entriesOf2(casesBySpecifier).sort((a, b) => Object.keys(a[1]).length - Object.keys(b[1]).length).at(-1); | ||
if (!bestDiscriminantEntry) { | ||
discriminantCache.set(branches, null); | ||
return null; | ||
} | ||
const [specifier, predicateCases] = bestDiscriminantEntry; | ||
const [path, kind] = parseDiscriminantKey(specifier); | ||
const cases = {}; | ||
for (const k in predicateCases) { | ||
const subdiscriminant = discriminate(predicateCases[k]); | ||
cases[k] = subdiscriminant ?? predicateCases[k]; | ||
} | ||
const discriminant = { | ||
kind, | ||
path, | ||
cases, | ||
isPureRootLiteral: false | ||
}; | ||
discriminantCache.set(branches, discriminant); | ||
return discriminant; | ||
}; | ||
var writeUndiscriminableMorphUnionMessage = (path) => `${path === "/" ? "A" : `At ${path}, a`} union including one or more morphs must be discriminable`; | ||
// sets/union.ts | ||
var intersectBranch = (l, r) => { | ||
const union = l.ordered ? l.union.flatMap((branch) => { | ||
const branchResult = branch.intersect(r); | ||
return branchResult instanceof Disjoint ? [] : branchResult; | ||
}) : intersectBranches(l.union, [r]); | ||
if (union instanceof Disjoint) { | ||
return union; | ||
} | ||
return l.ordered ? { union, ordered: true } : { union }; | ||
}; | ||
var UnionImplementation = defineNode({ | ||
kind: "union", | ||
keys: { | ||
union: { | ||
parse: (schema, ctx) => schema.map( | ||
(branch) => ctx.base.parseSchema( | ||
["morph", "intersection", ...basisKinds], | ||
branch, | ||
ctx | ||
) | ||
) | ||
}, | ||
ordered: {} | ||
}, | ||
intersections: { | ||
union: (l, r) => { | ||
if ((l.union.length === 0 || r.union.length === 0) && l.union.length !== r.union.length) { | ||
return Disjoint.from( | ||
"presence", | ||
l.union.length !== 0, | ||
r.union.length !== 0 | ||
); | ||
} | ||
let resultBranches; | ||
if (l.ordered) { | ||
if (r.ordered) { | ||
return Disjoint.from("indiscriminableMorphs", l, r); | ||
} | ||
resultBranches = intersectBranches(r.union, l.union); | ||
if (resultBranches instanceof Disjoint) { | ||
resultBranches.invert(); | ||
} | ||
} else { | ||
resultBranches = intersectBranches(l.union, r.union); | ||
} | ||
if (resultBranches instanceof Disjoint) { | ||
return resultBranches; | ||
} | ||
return l.ordered || r.ordered ? { | ||
union: resultBranches, | ||
ordered: true | ||
} : { union: resultBranches }; | ||
}, | ||
morph: intersectBranch, | ||
intersection: intersectBranch, | ||
default: (l, r) => { | ||
const union = []; | ||
for (const branch of l.union) { | ||
const branchResult = branch.intersect(r); | ||
if (!(branchResult instanceof Disjoint)) { | ||
union.push(branchResult); | ||
} | ||
} | ||
return union.length === 0 ? Disjoint.from("union", l.union, [r]) : l.ordered ? { | ||
union, | ||
ordered: true | ||
} : { union }; | ||
} | ||
}, | ||
normalize: (schema) => isArray3(schema) ? { union: schema } : schema, | ||
reduce: (inner, ctx) => { | ||
const reducedBranches = reduceBranches(inner); | ||
if (reducedBranches.length === 1) { | ||
return reducedBranches[0]; | ||
} | ||
if (reducedBranches.length !== inner.union.length) { | ||
return; | ||
} | ||
return ctx.base.parsePrereduced("union", { | ||
...inner, | ||
union: reducedBranches | ||
}); | ||
}, | ||
attach: (inner) => { | ||
return { | ||
compile: (cfg) => inner.union.map( | ||
(rule) => `if(${rule.alias}(${In})) { | ||
return true | ||
}` | ||
).join("\n") + "\nreturn false", | ||
discriminant: discriminate(inner.union) | ||
}; | ||
}, | ||
writeDefaultDescription: (inner) => inner.union.length === 0 ? "never" : inner.union.join(" or ") | ||
}); | ||
var intersectBranches = (l, r) => { | ||
const batchesByR = r.map(() => []); | ||
for (let lIndex = 0; lIndex < l.length; lIndex++) { | ||
let candidatesByR = {}; | ||
for (let rIndex = 0; rIndex < r.length; rIndex++) { | ||
if (batchesByR[rIndex] === null) { | ||
continue; | ||
} | ||
if (l[lIndex].equals(r[rIndex])) { | ||
batchesByR[rIndex] = null; | ||
candidatesByR = {}; | ||
break; | ||
} | ||
const branchIntersection = l[lIndex].intersect(r[rIndex]); | ||
if (branchIntersection instanceof Disjoint) { | ||
continue; | ||
} | ||
if (branchIntersection.equals(l[lIndex])) { | ||
batchesByR[rIndex].push(l[lIndex]); | ||
candidatesByR = {}; | ||
break; | ||
} | ||
if (branchIntersection.equals(r[rIndex])) { | ||
batchesByR[rIndex] = null; | ||
} else { | ||
candidatesByR[rIndex] = branchIntersection; | ||
} | ||
} | ||
for (const rIndex in candidatesByR) { | ||
batchesByR[rIndex][lIndex] = candidatesByR[rIndex]; | ||
} | ||
} | ||
const resultBranches = batchesByR.flatMap((batch, i) => batch ?? r[i]); | ||
return resultBranches.length === 0 ? Disjoint.from("union", l, r) : resultBranches; | ||
}; | ||
var reduceBranches = ({ union, ordered }) => { | ||
if (union.length < 2) { | ||
return union; | ||
} | ||
const uniquenessByIndex = union.map(() => true); | ||
for (let i = 0; i < union.length; i++) { | ||
for (let j = i + 1; j < union.length && uniquenessByIndex[i] && uniquenessByIndex[j]; j++) { | ||
if (union[i].equals(union[j])) { | ||
uniquenessByIndex[j] = false; | ||
continue; | ||
} | ||
const intersection = union[i].intersect(union[j]); | ||
if (intersection instanceof Disjoint) { | ||
continue; | ||
} | ||
if (intersection.equals(union[i])) { | ||
if (!ordered) { | ||
uniquenessByIndex[i] = false; | ||
} | ||
} else if (intersection.equals(union[j])) { | ||
uniquenessByIndex[j] = false; | ||
} | ||
} | ||
} | ||
return union.filter((_, i) => uniquenessByIndex[i]); | ||
}; | ||
// sets/set.ts | ||
var SetImplementationByKind = { | ||
union: UnionImplementation, | ||
morph: MorphImplementation, | ||
intersection: IntersectionImplementation | ||
}; | ||
// shared/node.ts | ||
var RuleImplementationByKind = { | ||
...BasisImplementations, | ||
...ConstraintImplementations | ||
}; | ||
var NodeImplementationByKind = { | ||
...SetImplementationByKind, | ||
...RuleImplementationByKind | ||
}; | ||
// shared/symbols.ts | ||
var inferred = Symbol("inferred"); | ||
// node.ts | ||
var $ark = registry(); | ||
var BaseNode = class _BaseNode extends DynamicBase { | ||
[arkKind] = "node"; | ||
cls = _BaseNode; | ||
implementation = NodeImplementationByKind[this.kind]; | ||
includesMorph = this.kind === "morph" || this.children.some((child) => child.includesMorph); | ||
references = this.children.flatMap( | ||
(child) => child.contributesReferences | ||
); | ||
contributesReferences = [ | ||
this, | ||
...this.references | ||
]; | ||
allows; | ||
alias = $ark.register(this, this.inner.alias); | ||
description; | ||
constructor(baseAttachments) { | ||
super(baseAttachments); | ||
for (const k in baseAttachments.inner) { | ||
if (k in this) { | ||
if (k !== "in" && k !== "out" && k !== "description") { | ||
throwInternalError6( | ||
`Unexpected attempt to overwrite existing node key ${k} from ${this.kind} inner` | ||
); | ||
} | ||
} else { | ||
this[k] = this.inner[k]; | ||
} | ||
} | ||
const attachments = this.implementation.attach(this); | ||
Object.assign(this, attachments); | ||
this.allows = new CompiledFunction( | ||
In, | ||
this.isRule() ? `return ${this.condition}` : this.compile({ | ||
successKind: "true", | ||
failureKind: "false" | ||
}) | ||
); | ||
this.description ??= this.implementation.writeDefaultDescription( | ||
this | ||
); | ||
} | ||
inCache; | ||
get in() { | ||
if (!this.inCache) { | ||
this.inCache = this.getIo("in"); | ||
} | ||
return this.inCache; | ||
} | ||
outCache; | ||
get out() { | ||
if (!this.outCache) { | ||
this.outCache = this.getIo("out"); | ||
} | ||
return this.outCache; | ||
} | ||
getIo(kind) { | ||
if (!this.includesMorph) { | ||
return this; | ||
} | ||
const ioInner = {}; | ||
for (const [k, v] of this.entries) { | ||
const keyDefinition = this.implementation.keys[k]; | ||
if (keyDefinition.meta) { | ||
continue; | ||
} | ||
if (v instanceof _BaseNode) { | ||
ioInner[k] = v[kind]; | ||
} else if (Array.isArray(v) && v.every((_) => _ instanceof _BaseNode)) { | ||
ioInner[k] = v.map((child) => child[kind]); | ||
} else { | ||
ioInner[k] = v; | ||
} | ||
} | ||
return parseSchema(this.kind, ioInner); | ||
} | ||
toJSON() { | ||
return this.json; | ||
} | ||
equals(other) { | ||
return this.typeId === other.typeId; | ||
} | ||
hasKind(kind) { | ||
return this.kind === kind; | ||
} | ||
isBasis() { | ||
return includes2(basisKinds, this.kind); | ||
} | ||
isClosedConstraint() { | ||
return includes2(closedConstraintKinds, this.kind); | ||
} | ||
isOpenConstraint() { | ||
return includes2(openConstraintKinds, this.kind); | ||
} | ||
isConstraint() { | ||
return includes2(constraintKinds, this.kind); | ||
} | ||
isRoot() { | ||
return includes2(rootKinds, this.kind); | ||
} | ||
isSet() { | ||
return includes2(setKinds, this.kind); | ||
} | ||
isRule() { | ||
return includes2(ruleKinds, this.kind); | ||
} | ||
toString() { | ||
return this.description; | ||
} | ||
intersect(other) { | ||
const closedResult = this.intersectClosed(other); | ||
if (closedResult !== null) { | ||
return closedResult; | ||
} | ||
if (!this.isRule() || !other.isRule()) { | ||
return throwInternalError6( | ||
`Unexpected null intersection between non-rules ${this.kind} and ${other.kind}` | ||
); | ||
} | ||
return parseSchema( | ||
"intersection", | ||
unflattenRules([this, other]) | ||
); | ||
} | ||
intersectClosed(other) { | ||
if (this.equals(other)) { | ||
return this; | ||
} | ||
const l = leftOperandOf(this, other); | ||
const thisIsLeft = l === this; | ||
const r = thisIsLeft ? other : this; | ||
const intersections = l.implementation.intersections; | ||
const intersector = intersections[r.kind] ?? intersections.default; | ||
const result = intersector?.(l, r); | ||
if (result) { | ||
if (result instanceof Disjoint) { | ||
return thisIsLeft ? result : result.invert(); | ||
} | ||
return parseSchema(l.kind, result); | ||
} | ||
return null; | ||
} | ||
static parseSchema = parseSchema; | ||
static parsePrereduced = parsePrereduced; | ||
static isInitialized = false; | ||
static #builtins; | ||
static get builtins() { | ||
if (!this.#builtins) { | ||
this.#builtins = createBuiltins(); | ||
this.isInitialized = true; | ||
} | ||
return this.#builtins; | ||
} | ||
}; | ||
var parseRoot = (...branches) => parseSchema("union", branches); | ||
var parseUnits = (...values) => { | ||
const uniqueValues = []; | ||
for (const value of values) { | ||
if (!uniqueValues.includes(value)) { | ||
uniqueValues.push(value); | ||
} | ||
} | ||
const union = uniqueValues.map( | ||
(unit) => parsePrereduced("unit", { is: unit }) | ||
); | ||
if (union.length === 1) { | ||
return union[0]; | ||
} | ||
return parsePrereduced("union", { | ||
union | ||
}); | ||
}; | ||
var node = Object.assign(parseRoot, { | ||
units: parseUnits | ||
}); | ||
function parsePrereduced(kind, schema) { | ||
return parseSchema(kind, schema, { | ||
prereduced: true | ||
}); | ||
} | ||
var RootNode = class extends BaseNode { | ||
branches = this.kind === "union" ? this.union : [this]; | ||
constrain(kind, schema) { | ||
const constrainedBranches = this.branches.map((branch) => { | ||
const constraint = parseConstraint( | ||
kind, | ||
schema, | ||
extractBasis(branch) | ||
); | ||
return branch.and(constraint); | ||
}); | ||
return parseSchema("union", { union: constrainedBranches }); | ||
} | ||
keyof() { | ||
return this; | ||
} | ||
// TODO: inferIntersection | ||
and(other) { | ||
const result = this.intersect(other); | ||
return result instanceof Disjoint ? result.throw() : result; | ||
} | ||
// TODO: limit input types | ||
or(other) { | ||
return parseSchema("union", [...this.branches, ...other.branches]); | ||
} | ||
isUnknown() { | ||
return this.equals(BaseNode.builtins.unknown); | ||
} | ||
isNever() { | ||
return this.equals(BaseNode.builtins.never); | ||
} | ||
getPath() { | ||
return this; | ||
} | ||
array() { | ||
return this; | ||
} | ||
extends(other) { | ||
const intersection = this.intersect(other); | ||
return !(intersection instanceof Disjoint) && this.equals(intersection); | ||
} | ||
}; | ||
function parseConstraint(kind, schema, basis) { | ||
return parseSchema(kind, schema, { basis }); | ||
} | ||
function parseSchema(allowedKinds, schema, ctxInput) { | ||
const ctx = { ...ctxInput, base: BaseNode }; | ||
const kind = typeof allowedKinds === "string" ? allowedKinds : rootKindOfSchema(schema); | ||
if (isArray4(allowedKinds) && !allowedKinds.includes(kind)) { | ||
return throwParseError6(`Schema of kind ${kind} should be ${allowedKinds}`); | ||
} | ||
if (isNode(schema)) { | ||
return schema; | ||
} | ||
const implementation = NodeImplementationByKind[kind]; | ||
const normalizedSchema = implementation.normalize?.(schema) ?? schema; | ||
const childContext = implementation.updateContext?.(normalizedSchema, ctx) ?? ctx; | ||
const schemaEntries = entriesOf3(normalizedSchema); | ||
const inner = {}; | ||
let json = {}; | ||
let typeJson = {}; | ||
const children = []; | ||
for (const [k, v] of schemaEntries) { | ||
const keyDefinition = implementation.keys[k]; | ||
if (!(k in implementation.keys)) { | ||
return throwParseError6(`Key ${k} is not valid on ${kind} schema`); | ||
} | ||
const innerValue = keyDefinition.parse ? keyDefinition.parse(v, childContext) : v; | ||
if (innerValue === void 0 && !keyDefinition.preserveUndefined) { | ||
continue; | ||
} | ||
inner[k] = innerValue; | ||
if (isNode(innerValue)) { | ||
json[k] = innerValue.collapsibleJson; | ||
children.push(innerValue); | ||
} else if (isArray4(innerValue) && innerValue.every((_) => isNode(_))) { | ||
json[k] = innerValue.map((node2) => node2.collapsibleJson); | ||
children.push(...innerValue); | ||
} else { | ||
json[k] = defaultValueSerializer(v); | ||
} | ||
if (!keyDefinition.meta) { | ||
typeJson[k] = json[k]; | ||
} | ||
} | ||
for (const k of implementation.defaultableKeys) { | ||
if (inner[k] === void 0) { | ||
const defaultableDefinition = implementation.keys[k]; | ||
inner[k] = defaultableDefinition.parse(void 0, childContext); | ||
json[k] = defaultValueSerializer(inner[k]); | ||
if (!defaultableDefinition.meta) { | ||
typeJson[k] = json[k]; | ||
} | ||
} | ||
} | ||
if (!ctx.prereduced) { | ||
if (implementation.reduce) { | ||
const reduced = implementation.reduce(inner, ctx); | ||
if (reduced) { | ||
return reduced; | ||
} | ||
} | ||
} | ||
const id = JSON.stringify(json); | ||
const typeId = JSON.stringify(typeJson); | ||
if (BaseNode.isInitialized && BaseNode.builtins.unknownUnion.typeId === typeId) { | ||
return BaseNode.builtins.unknown; | ||
} | ||
const innerEntries = entriesOf3(inner); | ||
let collapsibleJson = json; | ||
if (innerEntries.length === 1 && innerEntries[0][0] === kind) { | ||
collapsibleJson = json[kind]; | ||
if (hasDomain2(collapsibleJson, "object")) { | ||
json = collapsibleJson; | ||
typeJson = collapsibleJson; | ||
} | ||
} | ||
const attachments = { | ||
kind, | ||
inner, | ||
entries: innerEntries, | ||
json, | ||
typeJson, | ||
collapsibleJson, | ||
children, | ||
id, | ||
typeId | ||
}; | ||
return includes2(constraintKinds, kind) ? new BaseNode(attachments) : new RootNode(attachments); | ||
} | ||
var defaultValueSerializer = (v) => { | ||
if (typeof v === "string" || typeof v === "boolean" || typeof v === "number" || v === null) { | ||
return v; | ||
} | ||
return compileSerializedValue(v); | ||
}; | ||
function rootKindOfSchema(schema) { | ||
const basisKind = maybeGetBasisKind(schema); | ||
if (basisKind) { | ||
return basisKind; | ||
} | ||
if (typeof schema === "object" && schema !== null) { | ||
if (schema instanceof BaseNode) { | ||
if (schema.isRoot()) { | ||
return schema.kind; | ||
} | ||
} else if ("morph" in schema) { | ||
return "morph"; | ||
} else if ("union" in schema || isArray4(schema)) { | ||
return "union"; | ||
} else { | ||
return "intersection"; | ||
} | ||
} | ||
return throwParseError6(`${schema} is not a valid root schema type`); | ||
} | ||
var extractBasis = (branch) => branch.kind === "morph" ? extractValidatorBasis(branch.in) : extractValidatorBasis(branch); | ||
var extractValidatorBasis = (validator) => validator.kind === "intersection" ? validator.basis : validator; | ||
// io/problems.ts | ||
import { | ||
domainOf as domainOf3, | ||
getExactBuiltinConstructorName as getExactBuiltinConstructorName2, | ||
objectKindDescriptions as objectKindDescriptions2, | ||
stringify as stringify4 | ||
} from "@arktype/util"; | ||
var ArkTypeError = class extends TypeError { | ||
cause; | ||
constructor(problems) { | ||
super(`${problems}`); | ||
this.cause = problems; | ||
} | ||
}; | ||
var Problem = class { | ||
constructor(rule, data, path) { | ||
this.rule = rule; | ||
this.path = path; | ||
this.data = new DataWrapper(data); | ||
} | ||
data; | ||
hasCode(code) { | ||
return this.code === code; | ||
} | ||
get message() { | ||
return this.path.length === 0 ? capitalize(this.reason) : this.path.length === 1 && typeof this.path[0] === "number" ? `Item at index ${this.path[0]} ${this.reason}` : `${this.path.join(".")} ${this.reason}`; | ||
} | ||
get reason() { | ||
return `must be ${this.mustBe}${this.was ? ` (was ${this.was})` : ""}`; | ||
} | ||
get was() { | ||
return `${this.data}`; | ||
} | ||
toString() { | ||
return this.message; | ||
} | ||
}; | ||
var ProblemsArray = class extends Array { | ||
byPath = {}; | ||
count = 0; | ||
add(problem) { | ||
const pathKey = `${problem.path}`; | ||
const existing = this.byPath[pathKey]; | ||
if (existing) { | ||
if (existing.hasCode("intersection")) { | ||
existing.rule.push(problem); | ||
} else { | ||
const problemIntersection = new ProblemIntersection( | ||
[existing, problem], | ||
problem.data, | ||
problem.path | ||
); | ||
const existingIndex = this.indexOf(existing); | ||
this[existingIndex === -1 ? this.length : existingIndex] = problemIntersection; | ||
this.byPath[pathKey] = problemIntersection; | ||
} | ||
} else { | ||
this.byPath[pathKey] = problem; | ||
this.push(problem); | ||
} | ||
this.count++; | ||
return problem; | ||
} | ||
get summary() { | ||
return this.toString(); | ||
} | ||
toString() { | ||
return this.join("\n"); | ||
} | ||
throw() { | ||
throw new ArkTypeError(this); | ||
} | ||
}; | ||
var Problems = ProblemsArray; | ||
var capitalize = (s) => s[0].toUpperCase() + s.slice(1); | ||
var domainsToDescriptions = (domains) => domains.map((objectKind) => domainDescriptions[objectKind]); | ||
var objectKindsToDescriptions = (kinds) => kinds.map((objectKind) => objectKindDescriptions2[objectKind]); | ||
var describeBranches = (descriptions) => { | ||
if (descriptions.length === 0) { | ||
return "never"; | ||
} | ||
if (descriptions.length === 1) { | ||
return descriptions[0]; | ||
} | ||
let description = ""; | ||
for (let i = 0; i < descriptions.length - 1; i++) { | ||
description += descriptions[i]; | ||
if (i < descriptions.length - 2) { | ||
description += ", "; | ||
} | ||
} | ||
description += ` or ${descriptions[descriptions.length - 1]}`; | ||
return description; | ||
}; | ||
var ProblemIntersection = class extends Problem { | ||
code = "intersection"; | ||
get message() { | ||
return this.path.length ? `At ${this.path}, ${this.reason}` : this.reason; | ||
} | ||
get mustBe() { | ||
return "\u2022 " + this.rule.map(({ mustBe }) => mustBe).join("\n\u2022 "); | ||
} | ||
get reason() { | ||
return `${this.data} must be... | ||
${this.mustBe}`; | ||
} | ||
}; | ||
var DomainProblem = class extends Problem { | ||
code = "domain"; | ||
get mustBe() { | ||
return domainDescriptions[this.rule]; | ||
} | ||
get was() { | ||
return this.data.domain; | ||
} | ||
}; | ||
var ProblemUnion = class extends Problem { | ||
code = "union"; | ||
get mustBe() { | ||
return describeBranches( | ||
this.rule.map( | ||
(problem) => `${problem.path} must be ${problem.hasCode("intersection") ? describeBranches(problem.rule.map((part) => part.mustBe)) : problem.mustBe}` | ||
) | ||
); | ||
} | ||
get reason() { | ||
return this.path.length ? `At ${this.path}, ${this.mustBe} (was ${this.was})` : `${this.mustBe} (was ${this.was})`; | ||
} | ||
}; | ||
var CustomProblem = class extends Problem { | ||
code = "custom"; | ||
get mustBe() { | ||
return this.rule; | ||
} | ||
}; | ||
var defineProblemsCode = (problems) => problems; | ||
var KeyProblem = class extends Problem { | ||
code = "key"; | ||
mustBe = this.rule === "missing" ? "defined" : "extraneous"; | ||
}; | ||
var BoundProblem = class extends Problem { | ||
code = "bound"; | ||
get mustBe() { | ||
return "within bounds"; | ||
} | ||
get was() { | ||
return this.data.value instanceof Date ? this.data.value.toDateString() : `${this.data.size}`; | ||
} | ||
}; | ||
var RegexProblem = class extends Problem { | ||
code = "regex"; | ||
get mustBe() { | ||
return `a string matching /${this.rule}/`; | ||
} | ||
}; | ||
var ClassProblem = class extends Problem { | ||
code = "class"; | ||
get mustBe() { | ||
const possibleObjectKind = getExactBuiltinConstructorName2(this.rule); | ||
return possibleObjectKind ? objectKindDescriptions2[possibleObjectKind] : `an instance of ${this.rule.name}`; | ||
} | ||
get was() { | ||
return this.data.className; | ||
} | ||
}; | ||
var DivisorProblem = class extends Problem { | ||
code = "divisor"; | ||
get mustBe() { | ||
return this.rule === 1 ? `an integer` : `a multiple of ${this.rule}`; | ||
} | ||
}; | ||
var ValueProblem = class extends Problem { | ||
code = "value"; | ||
get mustBe() { | ||
return stringify4(this.rule); | ||
} | ||
}; | ||
var problemsByCode = defineProblemsCode({ | ||
domain: DomainProblem, | ||
divisor: DivisorProblem, | ||
class: ClassProblem, | ||
key: KeyProblem, | ||
bound: BoundProblem, | ||
regex: RegexProblem, | ||
value: ValueProblem, | ||
custom: CustomProblem, | ||
intersection: ProblemIntersection, | ||
union: ProblemUnion | ||
}); | ||
var sizeOf = (data) => typeof data === "string" || Array.isArray(data) ? data.length : typeof data === "number" ? data : data instanceof Date ? data.valueOf() : 0; | ||
var unitsOf = (data) => typeof data === "string" ? "characters" : Array.isArray(data) ? "items long" : ""; | ||
var DataWrapper = class { | ||
constructor(value) { | ||
this.value = value; | ||
} | ||
toString() { | ||
return stringify4(this.value); | ||
} | ||
get domain() { | ||
return domainOf3(this.value); | ||
} | ||
get size() { | ||
return sizeOf(this.value); | ||
} | ||
get units() { | ||
return unitsOf(this.value); | ||
} | ||
get className() { | ||
return Object(this.value).constructor.name; | ||
} | ||
}; | ||
// io/traverse.ts | ||
var CheckResult = class { | ||
constructor(result) { | ||
if (result?.$arkId === "problems") { | ||
this.problems = result; | ||
} else { | ||
this.data = result; | ||
} | ||
} | ||
}; | ||
var TraversalState = class { | ||
basePath = []; | ||
problemsStack = [new Problems()]; | ||
// TODO: add morphs here | ||
entriesToPrune = []; | ||
// Qualified | ||
seen = {}; | ||
constructor() { | ||
} | ||
get problems() { | ||
return this.problemsStack.at(-1); | ||
} | ||
pushUnion() { | ||
this.problemsStack.push(new Problems()); | ||
} | ||
popUnion(branchCount, data, path) { | ||
const branchProblems = this.problemsStack.pop(); | ||
if (branchProblems.count === branchCount) { | ||
this.addProblem("union", branchProblems, data, path); | ||
} | ||
} | ||
finalize(data) { | ||
if (this.problems.count) { | ||
return new CheckResult(this.problems); | ||
} | ||
for (const [o, k] of this.entriesToPrune) { | ||
delete o[k]; | ||
} | ||
return new CheckResult(data); | ||
} | ||
// TODO: add at custom path | ||
mustBe(mustBe, data, path) { | ||
return this.addProblem("custom", mustBe, data, path); | ||
} | ||
addProblem(code, ...args) { | ||
const problem = new problemsByCode[code](...args); | ||
return this.problems.add(problem); | ||
} | ||
}; | ||
// main.ts | ||
var builtins = BaseNode.builtins; | ||
export { | ||
ArkTypeError, | ||
BaseNode, | ||
BoundProblem, | ||
CheckResult, | ||
ClassProblem, | ||
CompilationState, | ||
CustomProblem, | ||
DataWrapper, | ||
Disjoint, | ||
DivisorImplementation, | ||
DivisorProblem, | ||
DomainProblem, | ||
In, | ||
IntersectionImplementation, | ||
KeyProblem, | ||
MaxImplementation, | ||
MinImplementation, | ||
MorphImplementation, | ||
NodeImplementationByKind, | ||
PatternImplementation, | ||
PredicateImplementation, | ||
Problem, | ||
ProblemIntersection, | ||
ProblemUnion, | ||
Problems, | ||
PropImplementations, | ||
RegexProblem, | ||
RootNode, | ||
RuleImplementationByKind, | ||
TraversalState, | ||
UnionImplementation, | ||
ValueProblem, | ||
addRule, | ||
arkKind, | ||
basisKinds, | ||
builtins, | ||
closedConstraintKinds, | ||
compilePropAccess, | ||
compileSerializedValue, | ||
constraintKinds, | ||
createBuiltins, | ||
defineNode, | ||
defineProblemsCode, | ||
describeBranches, | ||
discriminate, | ||
domainsToDescriptions, | ||
flattenRules, | ||
inferred, | ||
intersectBranches, | ||
isDotAccessible, | ||
isNode, | ||
node, | ||
nodeKinds, | ||
objectKindsToDescriptions, | ||
openConstraintKinds, | ||
parseConstraint, | ||
parseOpenConstraints, | ||
parsePrereduced, | ||
parseRegexLiteral, | ||
parseSchema, | ||
problemsByCode, | ||
reduceBranches, | ||
registry, | ||
rootKinds, | ||
ruleKinds, | ||
serializeRegex, | ||
setKinds, | ||
sizeOf, | ||
unflattenRules, | ||
unitsOf, | ||
writeIncompatibleRangeMessage, | ||
writeIndivisibleMessage, | ||
writeUnboundableMessage, | ||
writeUndiscriminableMorphUnionMessage | ||
}; | ||
import { BaseNode } from "./node.js"; | ||
export const builtins = BaseNode.builtins; | ||
export * from "./config.js"; | ||
export * from "./constraints/bounds.js"; | ||
export * from "./constraints/divisor.js"; | ||
export * from "./constraints/pattern.js"; | ||
export * from "./constraints/predicate.js"; | ||
export * from "./constraints/props/prop.js"; | ||
export * from "./io/compile.js"; | ||
export * from "./io/problems.js"; | ||
export * from "./io/registry.js"; | ||
export * from "./io/traverse.js"; | ||
export * from "./node.js"; | ||
export * from "./sets/discriminate.js"; | ||
export * from "./sets/intersection.js"; | ||
export * from "./sets/morph.js"; | ||
export * from "./sets/union.js"; | ||
export * from "./shared/builtins.js"; | ||
export * from "./shared/declare.js"; | ||
export * from "./shared/define.js"; | ||
export * from "./shared/disjoint.js"; | ||
export * from "./shared/node.js"; | ||
export * from "./shared/symbols.js"; | ||
//# sourceMappingURL=main.js.map |
{ | ||
"name": "@arktype/schema", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"license": "MIT", | ||
@@ -18,14 +18,19 @@ "author": { | ||
"arktype-repo": "./main.js", | ||
"import": "./dist/main.js" | ||
"types": "./dist/main.d.ts", | ||
"default": "./dist/main.js" | ||
}, | ||
"./internal/*": { | ||
"arktype-repo": "./*", | ||
"import": "./dist/*" | ||
"types": "./dist/*", | ||
"default": "./dist/*" | ||
} | ||
}, | ||
"files": [ | ||
"dist" | ||
"dist", | ||
"**/*.ts", | ||
"!**/*.tsBuildInfo", | ||
"!__tests__" | ||
], | ||
"scripts": { | ||
"build": "tsup --config ../repo/tsup.config.ts", | ||
"build": "tsc --build ./tsconfig.build.json", | ||
"bench": "ts ./__tests__/parse.bench.ts", | ||
@@ -35,4 +40,4 @@ "test": "ts ../repo/testPackage.ts" | ||
"dependencies": { | ||
"@arktype/util": "0.0.4" | ||
"@arktype/util": "0.0.5" | ||
} | ||
} |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
534584
166
10089
1
+ Added@arktype/util@0.0.5(transitive)
- Removed@arktype/util@0.0.4(transitive)
Updated@arktype/util@0.0.5