@arktype/schema
Advanced tools
Comparing version 0.4.0 to 0.5.0
@@ -27,4 +27,5 @@ import { type array, type propValueOf, type satisfy } from "@ark/util"; | ||
export interface BaseRangeInner { | ||
readonly rule: number | Date; | ||
readonly rule: LimitValue; | ||
} | ||
export type LimitValue = Date | number; | ||
export type LimitSchemaValue = Date | number | string; | ||
@@ -31,0 +32,0 @@ export type LimitInnerValue<kind extends RangeKind = RangeKind> = kind extends "before" | "after" ? Date : number; |
@@ -1,2 +0,2 @@ | ||
import { builtinConstructors, constructorExtends, getExactBuiltinConstructorName, objectKindDescriptions, objectKindOrDomainOf, prototypeKeysOf, throwParseError } from "@ark/util"; | ||
import { builtinConstructors, constructorExtends, getBuiltinNameOfConstructor, objectKindDescriptions, objectKindOrDomainOf, prototypeKeysOf, throwParseError } from "@ark/util"; | ||
import { Disjoint } from "../shared/disjoint.js"; | ||
@@ -13,3 +13,3 @@ import { defaultValueSerializer, implementNode } from "../shared/implement.js"; | ||
proto: { | ||
serialize: ctor => getExactBuiltinConstructorName(ctor) ?? defaultValueSerializer(ctor) | ||
serialize: ctor => getBuiltinNameOfConstructor(ctor) ?? defaultValueSerializer(ctor) | ||
} | ||
@@ -38,3 +38,3 @@ }, | ||
export class ProtoNode extends InternalBasis { | ||
builtinName = getExactBuiltinConstructorName(this.proto); | ||
builtinName = getBuiltinNameOfConstructor(this.proto); | ||
serializedConstructor = this.json.proto; | ||
@@ -41,0 +41,0 @@ compiledCondition = `data instanceof ${this.serializedConstructor}`; |
@@ -1,2 +0,2 @@ | ||
import { type JsTypeOf, type Json, type Key, type SerializedPrimitive, type show } from "@ark/util"; | ||
import { type Json, type Key, type SerializedPrimitive, type show } from "@ark/util"; | ||
import type { NodeSchema, nodeOfKind } from "../kinds.ts"; | ||
@@ -11,2 +11,3 @@ import { type NodeCompiler } from "../shared/compile.ts"; | ||
import type { TraverseAllows, TraverseApply } from "../shared/traversal.ts"; | ||
import type { Domain } from "./domain.ts"; | ||
import { BaseRoot } from "./root.ts"; | ||
@@ -67,3 +68,3 @@ export declare namespace Union { | ||
path: Key[]; | ||
propString: string; | ||
optionallyChainedPropString: string; | ||
kind: kind; | ||
@@ -78,4 +79,4 @@ }; | ||
export type DiscriminantKinds = { | ||
typeOf: JsTypeOf; | ||
identity: SerializedPrimitive | RegisteredReference; | ||
domain: Domain; | ||
unit: SerializedPrimitive | RegisteredReference; | ||
}; | ||
@@ -82,0 +83,0 @@ export type DiscriminantKind = show<keyof DiscriminantKinds>; |
@@ -1,3 +0,2 @@ | ||
import { appendUnique, arrayEquals, domainDescriptions, domainToJsTypesOf, flatMorph, groupBy, isArray, jsTypeOfDescriptions, printable, throwInternalError, throwParseError } from "@ark/util"; | ||
import { typePathToPropString } from "../node.js"; | ||
import { appendUnique, arrayEquals, domainDescriptions, flatMorph, groupBy, isArray, jsTypeOfDescriptions, printable, throwParseError } from "@ark/util"; | ||
import { compileLiteralPropAccess, compileSerializedValue } from "../shared/compile.js"; | ||
@@ -8,3 +7,3 @@ import { Disjoint } from "../shared/disjoint.js"; | ||
import { $ark, registeredReference } from "../shared/registry.js"; | ||
import { hasArkKind, pathToPropString } from "../shared/utils.js"; | ||
import { hasArkKind } from "../shared/utils.js"; | ||
import { BaseRoot } from "./root.js"; | ||
@@ -159,6 +158,5 @@ import { defineRightwardIntersections } from "./utils.js"; | ||
// we need to access the path as optional so we don't throw if it isn't present | ||
const condition = this.discriminant.path.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), | ||
// eventually, we should calculate the discriminant based on native typeof | ||
// to avoid this overhead | ||
this.discriminant.kind === "typeOf" ? "typeof data" : "data"); | ||
let condition = this.discriminant.optionallyChainedPropString; | ||
if (this.discriminant.kind === "domain") | ||
condition = `typeof ${condition} === "object" ? ${condition} === null ? "null" : "object" : typeof ${condition} === "function" ? "object" : typeof ${condition}`; | ||
const cases = this.discriminant.cases; | ||
@@ -178,3 +176,3 @@ const caseKeys = Object.keys(cases); | ||
} | ||
const expected = describeBranches(this.discriminant.kind === "typeOf" ? | ||
const expected = describeBranches(this.discriminant.kind === "domain" ? | ||
caseKeys.map(k => { | ||
@@ -189,3 +187,3 @@ const jsTypeOf = k.slice(1, -1); | ||
const serializedExpected = JSON.stringify(expected); | ||
const serializedActual = this.discriminant.kind === "typeOf" ? | ||
const serializedActual = this.discriminant.kind === "domain" ? | ||
`${serializedTypeOfDescriptions}[${condition}]` | ||
@@ -228,5 +226,5 @@ : `${serializedPrintable}(${condition})`; | ||
return { | ||
kind: "identity", | ||
kind: "unit", | ||
path: [], | ||
propString: "", | ||
optionallyChainedPropString: "data", | ||
cases | ||
@@ -244,41 +242,33 @@ }; | ||
for (const entry of result) { | ||
if (!entry.discriminantKind || entry.optional) | ||
if (!entry.kind || entry.optional) | ||
continue; | ||
let lSerialized; | ||
let rSerialized; | ||
switch (entry.discriminantKind) { | ||
case "typeOf": { | ||
const lValue = entry.l; | ||
const rValue = entry.r; | ||
const lDomain = typeof lValue === "string" ? lValue : lValue.domain; | ||
const rDomain = typeof rValue === "string" ? rValue : rValue.domain; | ||
if ((lDomain === "null" && rDomain === "object") || | ||
(rDomain === "null" && lDomain === "object")) | ||
// since we use typeof as a discriminant, we can't use this domain disjoint | ||
continue; | ||
lSerialized = domainToJsTypesOf(lDomain).map(typeOf => `"${typeOf}"`); | ||
rSerialized = domainToJsTypesOf(rDomain).map(typeOf => `"${typeOf}"`); | ||
break; | ||
} | ||
case "identity": { | ||
lSerialized = [entry.l.serializedValue]; | ||
rSerialized = [entry.r.serializedValue]; | ||
break; | ||
} | ||
default: | ||
entry.discriminantKind; | ||
throwInternalError(`Unexpected discriminant kind ${entry.discriminantKind}`); | ||
if (entry.kind === "domain") { | ||
const lValue = entry.l; | ||
const rValue = entry.r; | ||
lSerialized = `"${typeof lValue === "string" ? lValue : lValue.domain}"`; | ||
rSerialized = `"${typeof rValue === "string" ? rValue : rValue.domain}"`; | ||
} | ||
const matching = candidates.find(d => arrayEquals(d.path, entry.path) && | ||
d.kind === entry.discriminantKind); | ||
else if (entry.kind === "unit") { | ||
lSerialized = entry.l.serializedValue; | ||
rSerialized = entry.r.serializedValue; | ||
} | ||
else | ||
continue; | ||
const matching = candidates.find(d => arrayEquals(d.path, entry.path) && d.kind === entry.kind); | ||
if (!matching) { | ||
candidates.push({ | ||
kind: entry.discriminantKind, | ||
cases: Object.assign(flatMorph(lSerialized, (i, k) => [k, [l]]), flatMorph(rSerialized, (i, k) => [k, [r]])), | ||
kind: entry.kind, | ||
cases: { | ||
[lSerialized]: [l], | ||
[rSerialized]: [r] | ||
}, | ||
path: entry.path | ||
}); | ||
continue; | ||
} | ||
lSerialized.forEach(lSerialized => (matching.cases[lSerialized] = appendUnique(matching.cases[lSerialized], l))); | ||
rSerialized.forEach(rSerialized => (matching.cases[rSerialized] = appendUnique(matching.cases[rSerialized], r))); | ||
else { | ||
matching.cases[lSerialized] = appendUnique(matching.cases[lSerialized], l); | ||
matching.cases[rSerialized] = appendUnique(matching.cases[rSerialized], r); | ||
} | ||
} | ||
@@ -296,3 +286,3 @@ } | ||
path: best.path, | ||
propString: pathToPropString(best.path) | ||
optionallyChainedPropString: optionallyChainPropString(best.path) | ||
}; | ||
@@ -322,10 +312,8 @@ const cases = flatMorph(best.cases, (k, caseBranches) => { | ||
} | ||
return { | ||
kind: best.kind, | ||
path: best.path, | ||
propString: pathToPropString(best.path), | ||
return Object.assign(bestCtx, { | ||
cases | ||
}; | ||
}); | ||
} | ||
} | ||
const optionallyChainPropString = (path) => path.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), "data"); | ||
const serializedTypeOfDescriptions = registeredReference(jsTypeOfDescriptions); | ||
@@ -470,22 +458,25 @@ const serializedPrintable = registeredReference(printable); | ||
}; | ||
export const pruneDiscriminant = (discriminantBranch, discriminantCtx) => discriminantBranch.transform((nodeKind, inner, ctx) => { | ||
// if we've already checked a path at least as long as the current one, | ||
// we don't need to revalidate that we're in an object | ||
if (nodeKind === "domain" && | ||
inner.domain === "object" && | ||
discriminantCtx.path.length >= ctx.path.length) | ||
export const pruneDiscriminant = (discriminantBranch, discriminantCtx) => discriminantBranch.transform((nodeKind, inner) => { | ||
if (nodeKind === "domain" || nodeKind === "unit") | ||
return null; | ||
// if the discriminant has already checked the domain at the current path | ||
// (or a unit literal, implying a domain), we don't need to recheck it | ||
if ((nodeKind === "domain" || discriminantCtx.kind === "identity") && | ||
typePathToPropString(ctx.path) === discriminantCtx.propString) | ||
return null; | ||
return inner; | ||
}, { | ||
shouldTransform: node => | ||
// we don't need to recurse into index nodes as they will never | ||
// have a required path therefore can't be used to discriminate | ||
(node.children.length !== 0 && node.kind !== "index") || | ||
node.kind === "domain" || | ||
node.kind === "unit" | ||
shouldTransform: (node, ctx) => { | ||
// safe to cast here as index nodes are never discriminants | ||
const propString = optionallyChainPropString(ctx.path); | ||
if (!discriminantCtx.optionallyChainedPropString.startsWith(propString)) | ||
return false; | ||
if (node.hasKind("domain") && node.domain === "object") | ||
// if we've already checked a path at least as long as the current one, | ||
// we don't need to revalidate that we're in an object | ||
return true; | ||
if ((node.hasKind("domain") || discriminantCtx.kind === "unit") && | ||
propString === discriminantCtx.optionallyChainedPropString) | ||
// if the discriminant has already checked the domain at the current path | ||
// (or a unit literal, implying a domain), we don't need to recheck it | ||
return true; | ||
// we don't need to recurse into index nodes as they will never | ||
// have a required path therefore can't be used to discriminate | ||
return node.children.length !== 0 && node.kind !== "index"; | ||
} | ||
}); | ||
@@ -492,0 +483,0 @@ export const writeIndiscriminableMorphMessage = (lDescription, rDescription) => `An unordered union of a type including a morph and a type with overlapping input is indeterminate: |
@@ -6,3 +6,2 @@ import { type Key } from "@ark/util"; | ||
import type { BaseRoot } from "../roots/root.ts"; | ||
import type { DiscriminantKind } from "../roots/union.ts"; | ||
import type { Prop } from "../structure/prop.ts"; | ||
@@ -12,3 +11,2 @@ import type { BoundKind } from "./implement.ts"; | ||
kind: kind; | ||
discriminantKind: DiscriminantKind | undefined; | ||
l: OperandsByDisjointKind[kind]; | ||
@@ -15,0 +13,0 @@ r: OperandsByDisjointKind[kind]; |
@@ -8,3 +8,2 @@ import { isArray, throwParseError } from "@ark/util"; | ||
kind, | ||
discriminantKind: discriminatKindsByDisjointKind[kind], | ||
l, | ||
@@ -19,3 +18,2 @@ r, | ||
kind, | ||
discriminantKind: discriminatKindsByDisjointKind[kind], | ||
l, | ||
@@ -62,5 +60,1 @@ r, | ||
export const writeUnsatisfiableExpressionError = (expression) => `${expression} results in an unsatisfiable type`; | ||
const discriminatKindsByDisjointKind = { | ||
domain: "typeOf", | ||
unit: "identity" | ||
}; |
@@ -23,3 +23,6 @@ import { type array, type mutable, type requireKeys, type show } from "@ark/util"; | ||
}, stringifiable extends PropertyKey ? never : "stringifyNonKey">; | ||
export declare const pathToPropString: <stringifiable>(path: array<stringifiable>, ...[opts]: [stringifiable] extends [PropertyKey] ? [opts?: PathToPropStringOptions] : NoInfer<[opts: PathToPropStringOptions<stringifiable>]>) => string; | ||
export type PathToPropStringFn = <stringifiable>(path: array<stringifiable>, ...[opts]: [stringifiable] extends [PropertyKey] ? [ | ||
opts?: PathToPropStringOptions | ||
] : NoInfer<[opts: PathToPropStringOptions<stringifiable>]>) => string; | ||
export declare const pathToPropString: PathToPropStringFn; | ||
export type arkKind = typeof arkKind; | ||
@@ -26,0 +29,0 @@ export declare const arkKind: " arkKind"; |
{ | ||
"name": "@arktype/schema", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"license": "MIT", | ||
@@ -32,3 +32,3 @@ "author": { | ||
"dependencies": { | ||
"@ark/util": "0.3.0" | ||
"@ark/util": "0.5.0" | ||
}, | ||
@@ -35,0 +35,0 @@ "publishConfig": { |
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
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
325584
7657
+ Added@ark/util@0.5.0(transitive)
- Removed@ark/util@0.3.0(transitive)
Updated@ark/util@0.5.0