Socket
Socket
Sign inDemoInstall

@arktype/schema

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@arktype/schema - npm Package Compare versions

Comparing version 0.1.4 to 0.1.5

out/package.json

1

out/api.d.ts

@@ -40,4 +40,5 @@ export * from "./ast.js";

export * from "./structure/index.js";
export * from "./structure/optional.js";
export * from "./structure/prop.js";
export * from "./structure/sequence.js";
export * from "./structure/structure.js";

@@ -40,4 +40,5 @@ export * from "./ast.js";

export * from "./structure/index.js";
export * from "./structure/optional.js";
export * from "./structure/prop.js";
export * from "./structure/sequence.js";
export * from "./structure/structure.js";

2

out/inference.d.ts

@@ -28,3 +28,3 @@ import type { Constructor, ErrorMessage, NonEnumerableDomain, array, conform, describe, inferDomain, instanceOf, isAny } from "@arktype/util";

type validateRootBranch<schema, $> = schema extends BaseNode ? schema : "morphs" extends keyof schema ? validateMorphRoot<schema, $> : validateMorphChild<schema, $>;
type inferRootBranch<schema, $> = schema extends type.cast<infer to> ? to : schema extends MorphSchema ? (In: schema["from"] extends {} ? inferMorphChild<schema["from"], $> : unknown) => schema["to"] extends {} ? Out<inferMorphChild<schema["to"], $>> : schema["morphs"] extends infer morph extends Morph ? Out<inferMorphOut<morph>> : schema["morphs"] extends (readonly [...unknown[], infer morph extends Morph]) ? Out<inferMorphOut<morph>> : never : schema extends MorphInputSchema ? inferMorphChild<schema, $> : unknown;
type inferRootBranch<schema, $> = schema extends type.cast<infer to> ? to : schema extends MorphSchema ? (In: schema["in"] extends {} ? inferMorphChild<schema["in"], $> : unknown) => schema["out"] extends {} ? Out<inferMorphChild<schema["out"], $>> : schema["morphs"] extends infer morph extends Morph ? Out<inferMorphOut<morph>> : schema["morphs"] extends (readonly [...unknown[], infer morph extends Morph]) ? Out<inferMorphOut<morph>> : never : schema extends MorphInputSchema ? inferMorphChild<schema, $> : unknown;
type NonIntersectableBasisRoot = NonEnumerableDomain | Constructor | UnitSchema;

@@ -31,0 +31,0 @@ type validateMorphChild<schema, $> = [

@@ -5,3 +5,3 @@ import { isWellFormedInteger, wellFormedIntegerMatcher, wellFormedNumberMatcher } from "@arktype/util";

const number = root.defineRoot({
from: {
in: {
domain: "string",

@@ -14,3 +14,3 @@ regex: wellFormedNumberMatcher,

const integer = root.defineRoot({
from: {
in: {
domain: "string",

@@ -27,3 +27,3 @@ regex: wellFormedIntegerMatcher

const url = root.defineRoot({
from: {
in: {
domain: "string",

@@ -42,3 +42,3 @@ description: "a valid URL"

const json = root.defineRoot({
from: {
in: {
domain: "string",

@@ -50,3 +50,3 @@ description: "a JSON-parsable string"

const date = root.defineRoot({
from: "string",
in: "string",
morphs: (s, ctx) => {

@@ -53,0 +53,0 @@ const result = tryParseDatePattern(s);

@@ -1,2 +0,1 @@

import { root } from "../../scope.js";
const dayDelimiterMatcher = /^[./-]$/;

@@ -3,0 +2,0 @@ // ISO 8601 date/time modernized from https://github.com/validatorjs/validator.js/blob/master/src/lib/isISO8601.js

@@ -33,9 +33,9 @@ import { Callable, type Guardable, type Json, type conform } from "@arktype/util";

traverse(data: d["prerequisite"]): unknown;
private inCache?;
private _in?;
get in(): BaseNode;
private outCache?;
private _out?;
get out(): BaseNode;
private _description?;
get description(): string;
getIo(kind: "in" | "out"): BaseNode;
private descriptionCache?;
get description(): string;
toJSON(): Json;

@@ -42,0 +42,0 @@ toString(): string;

@@ -24,3 +24,6 @@ import { Callable, flatMorph, includes, isArray, shallowClone, throwError } from "@arktype/util";

qualifiedId = `${this.$.id}${this.id}`;
includesMorph = this.kind === "morph" || this.children.some(child => child.includesMorph);
includesMorph = this.kind === "morph" ||
(this.hasKind("optional") && this.hasDefault()) ||
(this.hasKind("structure") && this.undeclared === "delete") ||
this.children.some(child => child.includesMorph);
allowsRequiresContext =

@@ -46,12 +49,22 @@ // if a predicate accepts exactly one arg, we can safely skip passing context

}
inCache;
// unfortunately we can't use the @cached
// decorator from @arktype/util on these for now
// as they cause a deopt in V8
_in;
get in() {
this.inCache ??= this.getIo("in");
return this.inCache;
this._in ??= this.getIo("in");
return this._in;
}
outCache;
_out;
get out() {
this.outCache ??= this.getIo("out");
return this.outCache;
this._out ??= this.getIo("out");
return this._out;
}
_description;
get description() {
this._description ??=
this.inner.description ??
this.$.resolvedConfig[this.kind].description?.(this);
return this._description;
}
getIo(kind) {

@@ -77,9 +90,2 @@ if (!this.includesMorph)

}
descriptionCache;
get description() {
this.descriptionCache ??=
this.inner.description ??
this.$.resolvedConfig[this.kind].description?.(this);
return this.descriptionCache;
}
toJSON() {

@@ -157,2 +163,3 @@ return this.json;

]);
delete ctx.seen[this.id];
const node = this.$.node(this.kind, mapper(this.kind, innerWithTransformedChildren, ctx));

@@ -159,0 +166,0 @@ return node;

@@ -1,2 +0,2 @@

import { entriesOf, hasDomain, isArray, printable, throwParseError } from "@arktype/util";
import { entriesOf, hasDomain, isArray, printable, throwParseError, unset } from "@arktype/util";
import { nodeClassesByKind, nodeImplementationsByKind } from "./kinds.js";

@@ -67,3 +67,3 @@ import { Disjoint } from "./shared/disjoint.js";

const v = keyImpl.parse ? keyImpl.parse(entry[1], ctx) : entry[1];
if (v !== undefined || keyImpl.preserveUndefined)
if (v !== unset && (v !== undefined || keyImpl.preserveUndefined))
inner[k] = v;

@@ -149,5 +149,6 @@ }

attachments.alias = ctx.alias;
for (const k in inner)
if (k !== "description")
for (const k in inner) {
if (k !== "description" && k !== "in" && k !== "out")
attachments[k] = inner[k];
}
const node = new nodeClassesByKind[kind](attachments);

@@ -154,0 +155,0 @@ nodeCache[innerHash] = node;

@@ -20,3 +20,2 @@ import type { NodeCompiler } from "../shared/compile.js";

readonly expression: string;
private _resolution;
get resolution(): BaseRoot;

@@ -23,0 +22,0 @@ rawKeyOf(): BaseRoot<RawRootDeclaration>;

@@ -1,2 +0,36 @@

import { append } from "@arktype/util";
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
import { append, cached } from "@arktype/util";
import { Disjoint } from "../shared/disjoint.js";

@@ -7,32 +41,42 @@ import { implementNode } from "../shared/implement.js";

import { defineRightwardIntersections } from "./utils.js";
export class AliasNode extends BaseRoot {
expression = this.alias;
_resolution;
get resolution() {
this._resolution ??= this.resolve?.() ?? this.$.resolveRoot(this.alias);
return this._resolution;
}
rawKeyOf() {
return this.resolution.keyof();
}
traverseAllows = (data, ctx) => {
const seen = ctx.seen[this.id];
if (seen?.includes(data))
return true;
ctx.seen[this.id] = append(seen, data);
return this.resolution.traverseAllows(data, ctx);
let AliasNode = (() => {
let _classSuper = BaseRoot;
let _instanceExtraInitializers = [];
let _get_resolution_decorators;
return class AliasNode extends _classSuper {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
_get_resolution_decorators = [cached];
__esDecorate(this, null, _get_resolution_decorators, { kind: "getter", name: "resolution", static: false, private: false, access: { has: obj => "resolution" in obj, get: obj => obj.resolution }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
expression = (__runInitializers(this, _instanceExtraInitializers), this.alias);
get resolution() {
return this.resolve?.() ?? this.$.resolveRoot(this.alias);
}
rawKeyOf() {
return this.resolution.keyof();
}
traverseAllows = (data, ctx) => {
const seen = ctx.seen[this.id];
if (seen?.includes(data))
return true;
ctx.seen[this.id] = append(seen, data);
return this.resolution.traverseAllows(data, ctx);
};
traverseApply = (data, ctx) => {
const seen = ctx.seen[this.id];
if (seen?.includes(data))
return;
ctx.seen[this.id] = append(seen, data);
this.resolution.traverseApply(data, ctx);
};
compile(js) {
js.if(`ctx.seen.${this.id}?.includes(data)`, () => js.return(true));
js.line(`ctx.seen.${this.id} ??= []`).line(`ctx.seen.${this.id}.push(data)`);
js.return(js.invoke(this.resolution));
}
};
traverseApply = (data, ctx) => {
const seen = ctx.seen[this.id];
if (seen?.includes(data))
return;
ctx.seen[this.id] = append(seen, data);
this.resolution.traverseApply(data, ctx);
};
compile(js) {
js.if(`ctx.seen.${this.id}?.includes(data)`, () => js.return(true));
js.line(`ctx.seen.${this.id} ??= []`).line(`ctx.seen.${this.id}.push(data)`);
js.return(js.invoke(this.resolution));
}
}
})();
export { AliasNode };
export const normalizeAliasSchema = (schema) => typeof schema === "string" ? { alias: schema.slice(1) } : schema;

@@ -39,0 +83,0 @@ export const aliasImplementation = implementNode({

@@ -9,3 +9,3 @@ import { type array, type listable, type show } from "@arktype/util";

import type { TraverseAllows, TraverseApply } from "../shared/traversal.js";
import type { ExtraneousKeyBehavior, StructureNode } from "../structure/structure.js";
import type { StructureNode, UndeclaredKeyBehavior } from "../structure/structure.js";
import type { DomainNode, DomainSchema } from "./domain.js";

@@ -26,3 +26,3 @@ import type { ProtoNode, ProtoSchema } from "./proto.js";

export type MutableIntersectionInner = MutableInner<"intersection">;
export type NormalizedIntersectionSchema = Omit<IntersectionSchema, StructuralKind | "onExtraneousKey">;
export type NormalizedIntersectionSchema = Omit<IntersectionSchema, StructuralKind | "undeclared">;
export type IntersectionSchema<inferredBasis = any> = show<BaseMeta & {

@@ -54,3 +54,3 @@ domain?: DomainSchema;

export type ConditionalTerminalIntersectionRoot = {
onExtraneousKey?: ExtraneousKeyBehavior;
undeclared?: UndeclaredKeyBehavior;
};

@@ -62,3 +62,3 @@ type ConditionalTerminalIntersectionKey = keyof ConditionalTerminalIntersectionRoot;

}[ConstraintKind];
type conditionalIntersectionKeyOf<t> = constraintKindOf<t> | (t extends object ? "onExtraneousKey" : never);
type conditionalIntersectionKeyOf<t> = constraintKindOf<t> | (t extends object ? "undeclared" : never);
type intersectionChildRootValueOf<k extends IntersectionChildKind> = k extends OpenNodeKind ? listable<NodeSchema<k> | Inner<k>> : NodeSchema<k> | Inner<k>;

@@ -65,0 +65,0 @@ type conditionalRootValueOfKey<k extends ConditionalIntersectionKey> = k extends IntersectionChildKind ? intersectionChildRootValueOf<k> : ConditionalTerminalIntersectionRoot[k & ConditionalTerminalIntersectionKey];

@@ -1,2 +0,2 @@

import { type BuiltinObjectKind, type BuiltinObjects, type Primitive, type array, type listable } from "@arktype/util";
import { type BuiltinObjectKind, type BuiltinObjects, type Primitive, type anyOrNever, type array, type listable, type show } from "@arktype/util";
import type { of } from "../ast.js";

@@ -6,3 +6,3 @@ import type { type } from "../inference.js";

import type { StaticArkOption } from "../scope.js";
import { NodeCompiler } from "../shared/compile.js";
import type { NodeCompiler } from "../shared/compile.js";
import type { BaseMeta, declareNode } from "../shared/declare.js";

@@ -13,2 +13,3 @@ import type { ArkError, ArkErrors } from "../shared/errors.js";

import type { TraversalContext, TraverseAllows, TraverseApply } from "../shared/traversal.js";
import type { DefaultableAst } from "../structure/optional.js";
import { BaseRoot, type schemaKindRightOf } from "./root.js";

@@ -22,9 +23,9 @@ export type MorphInputKind = schemaKindRightOf<"morph">;

export interface MorphInner extends BaseMeta {
readonly from: MorphInputNode;
readonly to?: BaseRoot;
readonly in: MorphInputNode;
readonly out?: BaseRoot;
readonly morphs: readonly Morph[];
}
export interface MorphSchema extends BaseMeta {
readonly from: MorphInputSchema;
readonly to?: RootSchema | undefined;
readonly in: MorphInputSchema;
readonly out?: RootSchema | undefined;
readonly morphs: listable<Morph>;

@@ -45,3 +46,4 @@ }

outValidator: TraverseApply | null;
outValidatorReference: string;
private queueArgs;
private queueArgsReference;
traverseAllows: TraverseAllows;

@@ -51,3 +53,4 @@ traverseApply: TraverseApply;

compile(js: NodeCompiler): void;
getIo(kind: "in" | "out"): BaseRoot;
get in(): BaseRoot;
get out(): BaseRoot;
rawKeyOf(): BaseRoot;

@@ -72,5 +75,14 @@ }

]) ? false : true;
type _distill<t, io extends "in" | "out", distilledKind extends "base" | "constrainable"> = unknown extends t ? unknown : t extends MorphAst<infer i, infer o> ? io extends "in" ? i : o : t extends of<infer base, any> ? distilledKind extends "base" ? _distill<base, io, distilledKind> : t : t extends TerminallyInferredObjectKind | Primitive ? t : t extends array ? distillArray<t, io, distilledKind, []> : {
type _distill<t, io extends "in" | "out", distilledKind extends "base" | "constrainable"> = t extends TerminallyInferredObjectKind | Primitive ? t : unknown extends t ? unknown : t extends MorphAst<infer i, infer o> ? io extends "in" ? _distill<i, io, distilledKind> : _distill<o, io, distilledKind> : t extends DefaultableAst<infer t> ? _distill<t, io, distilledKind> : t extends of<infer base, any> ? distilledKind extends "base" ? _distill<base, io, distilledKind> : t : t extends array ? distillArray<t, io, distilledKind, []> : t extends Function ? t : {
[k in keyof t]: t[k];
} extends t ? io extends "in" ? show<{
[k in keyof t as k extends defaultableKeyOf<t> ? never : k]: _distill<t[k], io, distilledKind>;
} & {
[k in defaultableKeyOf<t>]?: _distill<t[k], io, distilledKind>;
}> : {
[k in keyof t]: _distill<t[k], io, distilledKind>;
};
} : t;
type defaultableKeyOf<t> = {
[k in keyof t]: [t[k]] extends [anyOrNever] ? never : t[k] extends DefaultableAst ? k : never;
}[keyof t];
type distillArray<t extends array, io extends "in" | "out", constraints extends "base" | "constrainable", prefix extends array> = t extends readonly [infer head, ...infer tail] ? distillArray<tail, io, constraints, [

@@ -87,3 +99,3 @@ ...prefix,

/** Objects we don't want to expand during inference like Date or Promise */
type TerminallyInferredObjectKind = StaticArkOption<"preserve"> | BuiltinObjects[Exclude<BuiltinObjectKind, "Array">];
type TerminallyInferredObjectKind = StaticArkOption<"preserve"> | BuiltinObjects[Exclude<BuiltinObjectKind, "Array" | "Function">];
export {};
import { arrayFrom, registeredReference, throwParseError } from "@arktype/util";
import { NodeCompiler } from "../shared/compile.js";
import { Disjoint } from "../shared/disjoint.js";

@@ -18,7 +17,7 @@ import { implementNode } from "../shared/implement.js";

keys: {
from: {
in: {
child: true,
parse: (schema, ctx) => ctx.$.node(morphInputKinds, schema)
},
to: {
out: {
child: true,

@@ -28,7 +27,7 @@ parse: (schema, ctx) => {

return;
const to = ctx.$.schema(schema);
return to.kind === "intersection" && to.children.length === 0 ?
const out = ctx.$.schema(schema);
return out.kind === "intersection" && out.children.length === 0 ?
// ignore unknown as an output validator
undefined
: to;
: out;
}

@@ -43,3 +42,3 @@ },

defaults: {
description: node => `a morph from ${node.from.description} to ${node.to?.description ?? "unknown"}`
description: node => `a morph from ${node.in.description} to ${node.out?.description ?? "unknown"}`
},

@@ -51,31 +50,31 @@ intersections: {

return throwParseError("Invalid intersection of morphs");
const from = intersectNodes(l.from, r.from, ctx);
if (from instanceof Disjoint)
return from;
const to = l.to ?
r.to ?
intersectNodes(l.to, r.to, ctx)
: l.to
: r.to;
if (to instanceof Disjoint)
return to;
const inTersection = intersectNodes(l.in, r.in, ctx);
if (inTersection instanceof Disjoint)
return inTersection;
const out = l.out ?
r.out ?
intersectNodes(l.out, r.out, ctx)
: l.out
: r.out;
if (out instanceof Disjoint)
return out;
// in case from is a union, we need to distribute the branches
// to can be a union as any schema is allowed
return ctx.$.schema(from.branches.map(fromBranch => ctx.$.node("morph", {
return ctx.$.schema(inTersection.branches.map(inBranch => ctx.$.node("morph", {
morphs: l.morphs,
from: fromBranch,
to
in: inBranch,
out
})));
},
...defineRightwardIntersections("morph", (l, r, ctx) => {
const from = intersectNodes(l.from, r, ctx);
return (from instanceof Disjoint ? from
: from.kind === "union" ?
ctx.$.node("union", from.branches.map(branch => ({
const inTersection = intersectNodes(l.in, r, ctx);
return (inTersection instanceof Disjoint ? inTersection
: inTersection.kind === "union" ?
ctx.$.node("union", inTersection.branches.map(branch => ({
...l.inner,
from: branch
in: branch
})))
: ctx.$.node("morph", {
...l.inner,
from
in: inTersection
}));

@@ -88,28 +87,31 @@ })

compiledMorphs = `[${this.serializedMorphs}]`;
outValidator = this.to?.traverseApply ?? null;
outValidatorReference = this.to ?
new NodeCompiler("Apply").reference(this.to, { bind: "this" })
: "null";
traverseAllows = (data, ctx) => this.from.traverseAllows(data, ctx);
outValidator = this.inner.out?.traverseApply ?? null;
queueArgs = [
this.morphs,
this.outValidator ? { outValidator: this.outValidator } : {}
];
queueArgsReference = registeredReference(this.queueArgs);
traverseAllows = (data, ctx) => this.in.traverseAllows(data, ctx);
traverseApply = (data, ctx) => {
ctx.queueMorphs(this.morphs, this.outValidator);
this.from.traverseApply(data, ctx);
ctx.queueMorphs(...this.queueArgs);
this.in.traverseApply(data, ctx);
};
expression = `(In: ${this.from.expression}) => Out<${this.to?.expression ?? "unknown"}>`;
expression = `(In: ${this.in.expression}) => Out<${this.out?.expression ?? "unknown"}>`;
compile(js) {
if (js.traversalKind === "Allows") {
js.return(js.invoke(this.from));
js.return(js.invoke(this.in));
return;
}
js.line(`ctx.queueMorphs(${this.compiledMorphs}, ${this.outValidatorReference})`);
js.line(js.invoke(this.from));
js.line(`ctx.queueMorphs(...${this.queueArgsReference})`);
js.line(js.invoke(this.in));
}
getIo(kind) {
return kind === "in" ?
this.from
: this.to?.out ?? this.$.keywords.unknown.raw;
get in() {
return this.inner.in;
}
get out() {
return this.inner.out?.out ?? this.$.keywords.unknown.raw;
}
rawKeyOf() {
return this.from.rawKeyOf();
return this.in.rawKeyOf();
}
}

@@ -11,5 +11,6 @@ import { type Callable, type Json, type conform } from "@arktype/util";

import { ArkErrors } from "../shared/errors.js";
import type { NodeKind, RootKind, kindRightOf } from "../shared/implement.js";
import { type NodeKind, type RootKind, type kindRightOf } from "../shared/implement.js";
import { type inferIntersection } from "../shared/intersections.js";
import { arkKind, type inferred, type internalImplementationOf } from "../shared/utils.js";
import type { UndeclaredKeyBehavior } from "../structure/structure.js";
import type { constraintKindOf } from "./intersection.js";

@@ -49,2 +50,3 @@ import type { Morph, distillConstrainableIn, distillConstrainableOut, distillIn, distillOut, inferMorphOut, inferPipes } from "./morph.js";

constrain<kind extends PrimitiveConstraintKind>(kind: kind, schema: NodeSchema<kind>): BaseRoot;
onUndeclaredKey(undeclared: UndeclaredKeyBehavior): BaseRoot;
}

@@ -81,2 +83,3 @@ export declare abstract class InnerRoot<t = unknown, $ = any> extends Callable<(data: unknown) => distillOut<t> | ArkErrors> {

describe(description: string): this;
onUndeclaredKey(behavior: UndeclaredKeyBehavior): this;
create(literal: this["inferIn"]): this["infer"];

@@ -83,0 +86,0 @@ }

@@ -1,2 +0,2 @@

import { throwParseError } from "@arktype/util";
import { includes, omit, throwParseError } from "@arktype/util";
import { throwInvalidOperandError } from "../constraint.js";

@@ -6,2 +6,3 @@ import { BaseNode } from "../node.js";

import { ArkErrors } from "../shared/errors.js";
import { structuralKinds } from "../shared/implement.js";
import { intersectNodesRoot, pipeNodesRoot } from "../shared/intersections.js";

@@ -96,3 +97,3 @@ import { arkKind, hasArkKind } from "../shared/utils.js";

return this.$.node("morph", {
from: this,
in: this,
morphs: [morph]

@@ -115,2 +116,9 @@ });

}
onUndeclaredKey(undeclared) {
return this.transform((kind, inner) => kind === "structure" ?
undeclared === "ignore" ?
omit(inner, { undeclared: 1 })
: { ...inner, undeclared }
: inner, node => !includes(structuralKinds, node.kind));
}
}

@@ -35,2 +35,3 @@ import type { Node, NodeSchema } from "../kinds.js";

export declare class UnionNode extends BaseRoot<UnionDeclaration> {
isNever: boolean;
isBoolean: boolean;

@@ -37,0 +38,0 @@ discriminant: null;

@@ -64,6 +64,5 @@ import { appendUnique, groupBy, isArray } from "@arktype/util";

union: (l, r, ctx) => {
if ((l.branches.length === 0 || r.branches.length === 0) &&
l.branches.length !== r.branches.length) {
if (l.isNever !== r.isNever) {
// if exactly one operand is never, we can use it to discriminate based on presence
return Disjoint.from("presence", l.branches.length !== 0, r.branches.length !== 0);
return Disjoint.from("presence", l, r);
}

@@ -100,2 +99,3 @@ let resultBranches;

export class UnionNode extends BaseRoot {
isNever = this.branches.length === 0;
isBoolean = this.branches.length === 2 &&

@@ -105,3 +105,5 @@ this.branches[0].hasUnit(false) &&

discriminant = null;
expression = this.isBoolean ? "boolean" : (this.branches.map(branch => branch.nestableExpression).join(" | "));
expression = this.isNever ? "never"
: this.isBoolean ? "boolean"
: this.branches.map(branch => branch.nestableExpression).join(" | ");
traverseAllows = (data, ctx) => this.branches.some(b => b.traverseAllows(data, ctx));

@@ -108,0 +110,0 @@ traverseApply = (data, ctx) => {

@@ -95,5 +95,5 @@ import { DynamicBase, type Json, type array, type flattenListable, type requireKeys, type show } from "@arktype/util";

get raw(): this;
schema: (def: RootSchema, opts?: NodeParseOptions) => BaseRoot;
defineRoot: (def: RootSchema) => RootSchema;
units: (values: array, opts?: NodeParseOptions) => BaseRoot;
schema(def: RootSchema, opts?: NodeParseOptions): BaseRoot;
defineRoot(def: RootSchema): RootSchema;
units(values: array, opts?: NodeParseOptions): BaseRoot;
protected lazyResolutions: AliasNode[];

@@ -100,0 +100,0 @@ lazilyResolve(resolve: () => BaseRoot, syntheticAlias?: string): AliasNode;

@@ -1,2 +0,36 @@

import { CompiledFunction, DynamicBase, flatMorph, hasDomain, isArray, printable, throwInternalError, throwParseError } from "@arktype/util";
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
import { CompiledFunction, DynamicBase, bound, flatMorph, hasDomain, isArray, printable, throwInternalError, throwParseError } from "@arktype/util";
import { globalConfig, mergeConfigs } from "./config.js";

@@ -42,218 +76,239 @@ import { validateUninstantiatedGenericNode } from "./generic.js";

const scopesById = {};
export class RawRootScope {
config;
resolvedConfig;
id = `$${++scopeCount}`;
[arkKind] = "scope";
referencesById = {};
references = [];
resolutions = {};
json = {};
exportedNames;
aliases = {};
resolved = false;
// these allow builtin types to be accessed during parsing without cyclic imports
// they are populated as each scope is parsed with `registerKeywords` in its config
/** @internal */
static keywords = {};
/** @internal */
get keywords() {
return RawRootScope.keywords;
}
static ambient;
get ambient() {
return this.constructor.ambient;
}
constructor(
/** The set of names defined at the root-level of the scope mapped to their
* corresponding definitions.**/
def, config) {
this.config = config ?? {};
this.resolvedConfig = resolveConfig(config);
this.exportedNames = Object.keys(def).filter(k => {
if (k[0] === "#") {
const name = k.slice(1);
if (name in this.aliases)
throwParseError(writeDuplicateAliasError(name));
this.aliases[name] = def[k];
return false;
let RawRootScope = (() => {
let _instanceExtraInitializers = [];
let _schema_decorators;
let _defineRoot_decorators;
let _units_decorators;
return class RawRootScope {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
_schema_decorators = [bound];
_defineRoot_decorators = [bound];
_units_decorators = [bound];
__esDecorate(this, null, _schema_decorators, { kind: "method", name: "schema", static: false, private: false, access: { has: obj => "schema" in obj, get: obj => obj.schema }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _defineRoot_decorators, { kind: "method", name: "defineRoot", static: false, private: false, access: { has: obj => "defineRoot" in obj, get: obj => obj.defineRoot }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _units_decorators, { kind: "method", name: "units", static: false, private: false, access: { has: obj => "units" in obj, get: obj => obj.units }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
config = __runInitializers(this, _instanceExtraInitializers);
resolvedConfig;
id = `$${++scopeCount}`;
[arkKind] = "scope";
referencesById = {};
references = [];
resolutions = {};
json = {};
exportedNames;
aliases = {};
resolved = false;
// these allow builtin types to be accessed during parsing without cyclic imports
// they are populated as each scope is parsed with `registerKeywords` in its config
/** @internal */
static keywords = {};
/** @internal */
get keywords() {
return RawRootScope.keywords;
}
static ambient;
get ambient() {
return this.constructor.ambient;
}
constructor(
/** The set of names defined at the root-level of the scope mapped to their
* corresponding definitions.**/
def, config) {
this.config = config ?? {};
this.resolvedConfig = resolveConfig(config);
this.exportedNames = Object.keys(def).filter(k => {
if (k[0] === "#") {
const name = k.slice(1);
if (name in this.aliases)
throwParseError(writeDuplicateAliasError(name));
this.aliases[name] = def[k];
return false;
}
if (k in this.aliases)
throwParseError(writeDuplicateAliasError(k));
this.aliases[k] = def[k];
return true;
});
if (this.ambient) {
// ensure exportedResolutions is populated
this.ambient.export();
// TODO: generics and modules
this.resolutions = flatMorph(this.ambient.resolutions, (alias, resolution) => [
alias,
hasArkKind(resolution, "root") ?
resolution.bindScope(this)
: resolution
]);
}
if (k in this.aliases)
throwParseError(writeDuplicateAliasError(k));
this.aliases[k] = def[k];
return true;
});
if (this.ambient) {
// ensure exportedResolutions is populated
this.ambient.export();
// TODO: generics and modules
this.resolutions = flatMorph(this.ambient.resolutions, (alias, resolution) => [
alias,
hasArkKind(resolution, "root") ?
resolution.bindScope(this)
: resolution
]);
scopesById[this.id] = this;
}
scopesById[this.id] = this;
}
get raw() {
return this;
}
schema = (((def, opts) => this.node(schemaKindOf(def), def, opts))).bind(this);
defineRoot = ((def => def)).bind(this);
units = (((values, opts) => {
const uniqueValues = [];
for (const value of values)
if (!uniqueValues.includes(value))
uniqueValues.push(value);
const branches = uniqueValues.map(unit => this.node("unit", { unit }, opts));
return this.node("union", branches, {
...opts,
prereduced: true
});
})).bind(this);
lazyResolutions = [];
lazilyResolve(resolve, syntheticAlias) {
if (!syntheticAlias) {
nodeCountsByPrefix.synthetic ??= 0;
syntheticAlias = `synthetic${++nodeCountsByPrefix.synthetic}`;
get raw() {
return this;
}
const node = this.node("alias", {
alias: syntheticAlias,
resolve
}, { prereduced: true });
this.lazyResolutions.push(node);
return node;
}
node = (((kinds, nodeSchema, opts) => {
let kind = typeof kinds === "string" ? kinds : schemaKindOf(nodeSchema, kinds);
let schema = nodeSchema;
if (isNode(schema) && schema.kind === kind)
return schema.bindScope(this);
if (kind === "alias" && !opts?.prereduced) {
const resolution = this.resolveRoot(normalizeAliasSchema(schema).alias);
schema = resolution;
kind = resolution.kind;
schema(def, opts) {
return this.node(schemaKindOf(def), def, opts);
}
else if (kind === "union" && hasDomain(schema, "object")) {
const branches = schemaBranchesOf(schema);
if (branches?.length === 1) {
schema = branches[0];
kind = schemaKindOf(schema);
defineRoot(def) {
return def;
}
units(values, opts) {
const uniqueValues = [];
for (const value of values)
if (!uniqueValues.includes(value))
uniqueValues.push(value);
const branches = uniqueValues.map(unit => this.node("unit", { unit }, opts));
return this.node("union", branches, {
...opts,
prereduced: true
});
}
lazyResolutions = [];
lazilyResolve(resolve, syntheticAlias) {
if (!syntheticAlias) {
nodeCountsByPrefix.synthetic ??= 0;
syntheticAlias = `synthetic${++nodeCountsByPrefix.synthetic}`;
}
const node = this.node("alias", {
alias: syntheticAlias,
resolve
}, { prereduced: true });
this.lazyResolutions.push(node);
return node;
}
const impl = nodeImplementationsByKind[kind];
const normalizedSchema = impl.normalize?.(schema) ?? schema;
// check again after normalization in case a node is a valid collapsed
// schema for the kind (e.g. sequence can collapse to element accepting a Node)
if (isNode(normalizedSchema)) {
return normalizedSchema.kind === kind ?
normalizedSchema.bindScope(this)
: throwMismatchedNodeRootError(kind, normalizedSchema.kind);
node = (((kinds, nodeSchema, opts) => {
let kind = typeof kinds === "string" ? kinds : schemaKindOf(nodeSchema, kinds);
let schema = nodeSchema;
if (isNode(schema) && schema.kind === kind)
return schema.bindScope(this);
if (kind === "alias" && !opts?.prereduced) {
const resolution = this.resolveRoot(normalizeAliasSchema(schema).alias);
schema = resolution;
kind = resolution.kind;
}
else if (kind === "union" && hasDomain(schema, "object")) {
const branches = schemaBranchesOf(schema);
if (branches?.length === 1) {
schema = branches[0];
kind = schemaKindOf(schema);
}
}
const impl = nodeImplementationsByKind[kind];
const normalizedSchema = impl.normalize?.(schema) ?? schema;
// check again after normalization in case a node is a valid collapsed
// schema for the kind (e.g. sequence can collapse to element accepting a Node)
if (isNode(normalizedSchema)) {
return normalizedSchema.kind === kind ?
normalizedSchema.bindScope(this)
: throwMismatchedNodeRootError(kind, normalizedSchema.kind);
}
const prefix = opts?.alias ?? kind;
nodeCountsByPrefix[prefix] ??= 0;
const id = `${prefix}${++nodeCountsByPrefix[prefix]}`;
const node = parseNode(kind, {
...opts,
id,
$: this,
schema: normalizedSchema
}).bindScope(this);
nodesById[id] = node;
if (this.resolved) {
// this node was not part of the original scope, so compile an anonymous scope
// including only its references
if (!this.resolvedConfig.jitless)
bindCompiledScope(node.contributesReferences);
}
else {
// we're still parsing the scope itself, so defer compilation but
// add the node as a reference
Object.assign(this.referencesById, node.contributesReferencesById);
}
return node;
})).bind(this);
parseRoot(def, opts) {
return this.schema(def, opts);
}
const prefix = opts?.alias ?? kind;
nodeCountsByPrefix[prefix] ??= 0;
const id = `${prefix}${++nodeCountsByPrefix[prefix]}`;
const node = parseNode(kind, {
...opts,
id,
$: this,
schema: normalizedSchema
}).bindScope(this);
nodesById[id] = node;
if (this.resolved) {
// this node was not part of the original scope, so compile an anonymous scope
// including only its references
if (!this.resolvedConfig.jitless)
bindCompiledScope(node.contributesReferences);
resolveRoot(name) {
return (this.maybeResolveRoot(name) ??
throwParseError(writeUnresolvableMessage(name)));
}
else {
// we're still parsing the scope itself, so defer compilation but
// add the node as a reference
Object.assign(this.referencesById, node.contributesReferencesById);
maybeResolveRoot(name) {
const result = this.maybeResolveGenericOrRoot(name);
if (hasArkKind(result, "generic"))
return;
return result;
}
return node;
})).bind(this);
parseRoot(def, opts) {
return this.schema(def, opts);
}
resolveRoot(name) {
return (this.maybeResolveRoot(name) ??
throwParseError(writeUnresolvableMessage(name)));
}
maybeResolveRoot(name) {
const result = this.maybeResolveGenericOrRoot(name);
if (hasArkKind(result, "generic"))
return;
return result;
}
maybeResolveGenericOrRoot(name) {
const resolution = this.maybeResolve(name);
if (hasArkKind(resolution, "module"))
return throwParseError(writeMissingSubmoduleAccessMessage(name));
return resolution;
}
preparseRoot(def) {
return def;
}
maybeResolve(name) {
const resolution = this.maybeShallowResolve(name);
return typeof resolution === "string" ?
this.node("alias", { alias: resolution }, { prereduced: true })
: resolution;
}
maybeShallowResolve(name) {
const cached = this.resolutions[name];
if (cached)
return cached;
let def = this.aliases[name];
if (!def)
return this.maybeResolveSubalias(name);
def = this.preparseRoot(def);
if (hasArkKind(def, "generic"))
return (this.resolutions[name] = validateUninstantiatedGenericNode(def));
if (hasArkKind(def, "module"))
return (this.resolutions[name] = def);
this.resolutions[name] = name;
return (this.resolutions[name] = this.parseRoot(def));
}
/** If name is a valid reference to a submodule alias, return its resolution */
maybeResolveSubalias(name) {
return resolveSubalias(this.aliases, name);
}
import(...names) {
return new RootModule(flatMorph(this.export(...names), (alias, value) => [
`#${alias}`,
value
]));
}
_exportedResolutions;
_exports;
export(...names) {
if (!this._exports) {
this._exports = {};
for (const name of this.exportedNames)
this._exports[name] = this.maybeResolve(name);
this.lazyResolutions.forEach(node => node.resolution);
this._exportedResolutions = resolutionsOfModule(this, this._exports);
// TODO: add generic json
Object.assign(this.json, flatMorph(this._exportedResolutions, (k, v) => hasArkKind(v, "root") ? [k, v.json] : []));
Object.assign(this.resolutions, this._exportedResolutions);
if (this.config.registerKeywords)
Object.assign(RawRootScope.keywords, this._exportedResolutions);
this.references = Object.values(this.referencesById);
if (!this.resolvedConfig.jitless)
bindCompiledScope(this.references);
this.resolved = true;
maybeResolveGenericOrRoot(name) {
const resolution = this.maybeResolve(name);
if (hasArkKind(resolution, "module"))
return throwParseError(writeMissingSubmoduleAccessMessage(name));
return resolution;
}
const namesToExport = names.length ? names : this.exportedNames;
return new RootModule(flatMorph(namesToExport, (_, name) => [
name,
this._exports[name]
]));
}
resolve(name) {
return this.export()[name];
}
}
preparseRoot(def) {
return def;
}
maybeResolve(name) {
const resolution = this.maybeShallowResolve(name);
return typeof resolution === "string" ?
this.node("alias", { alias: resolution }, { prereduced: true })
: resolution;
}
maybeShallowResolve(name) {
const cached = this.resolutions[name];
if (cached)
return cached;
let def = this.aliases[name];
if (!def)
return this.maybeResolveSubalias(name);
def = this.preparseRoot(def);
if (hasArkKind(def, "generic"))
return (this.resolutions[name] = validateUninstantiatedGenericNode(def));
if (hasArkKind(def, "module"))
return (this.resolutions[name] = def);
this.resolutions[name] = name;
return (this.resolutions[name] = this.parseRoot(def));
}
/** If name is a valid reference to a submodule alias, return its resolution */
maybeResolveSubalias(name) {
return resolveSubalias(this.aliases, name);
}
import(...names) {
return new RootModule(flatMorph(this.export(...names), (alias, value) => [
`#${alias}`,
value
]));
}
_exportedResolutions;
_exports;
export(...names) {
if (!this._exports) {
this._exports = {};
for (const name of this.exportedNames)
this._exports[name] = this.maybeResolve(name);
this.lazyResolutions.forEach(node => node.resolution);
this._exportedResolutions = resolutionsOfModule(this, this._exports);
// TODO: add generic json
Object.assign(this.json, flatMorph(this._exportedResolutions, (k, v) => hasArkKind(v, "root") ? [k, v.json] : []));
Object.assign(this.resolutions, this._exportedResolutions);
if (this.config.registerKeywords)
Object.assign(RawRootScope.keywords, this._exportedResolutions);
this.references = Object.values(this.referencesById);
if (!this.resolvedConfig.jitless)
bindCompiledScope(this.references);
this.resolved = true;
}
const namesToExport = names.length ? names : this.exportedNames;
return new RootModule(flatMorph(namesToExport, (_, name) => [
name,
this._exports[name]
]));
}
resolve(name) {
return this.export()[name];
}
};
})();
export { RawRootScope };
const resolveSubalias = (base, name) => {

@@ -260,0 +315,0 @@ const dotIndex = name.indexOf(".");

@@ -25,3 +25,3 @@ import { CompiledFunction } from "@arktype/util";

returnIfFailFast(): this;
checkReferenceKey(keyExpression: string, node: BaseNode): this;
traverseKey(keyExpression: string, accessExpression: string, node: BaseNode): this;
check(node: BaseNode, opts?: InvokeOptions): this;

@@ -28,0 +28,0 @@ compilePrimitive(node: Node<PrimitiveKind>): this;

@@ -33,3 +33,3 @@ import { CompiledFunction } from "@arktype/util";

}
checkReferenceKey(keyExpression, node) {
traverseKey(keyExpression, accessExpression, node) {
const requiresContext = this.requiresContextFor(node);

@@ -39,3 +39,3 @@ if (requiresContext)

this.check(node, {
arg: `${this.data}${this.index(keyExpression)}`
arg: accessExpression
});

@@ -42,0 +42,0 @@ if (requiresContext)

@@ -19,7 +19,4 @@ import { type entryOf } from "@arktype/util";

presence?: {
l: true;
r: false;
} | {
l: false;
r: true;
l: BaseRoot;
r: BaseRoot;
};

@@ -59,6 +56,7 @@ range?: {

export type DisjointSourceEntry = entryOf<DisjointsSources>;
export type DisjointSource = Required<DisjointKinds>[DisjointKind];
export type FlatDisjointEntry = {
path: SerializedPath;
kind: DisjointKind;
disjoint: Required<DisjointKinds>[DisjointKind];
disjoint: DisjointSource;
};

@@ -65,0 +63,0 @@ export type DisjointKind = keyof DisjointKinds;

@@ -39,6 +39,6 @@ import { entriesOf, flatMorph, fromEntries, isArray, printable, register, throwInternalError, throwParseError } from "@arktype/util";

const pathString = JSON.parse(path).join(".");
return `Intersection${pathString && ` at ${pathString}`} of ${describeReason(disjoint.l)} and ${describeReason(disjoint.r)} results in an unsatisfiable type`;
return `Intersection${pathString && ` at ${pathString}`} of ${describeReasons(disjoint)} results in an unsatisfiable type`;
}
return `The following intersections result in unsatisfiable types:\n• ${reasons
.map(({ path, disjoint }) => `${path}: ${describeReason(disjoint.l)} and ${describeReason(disjoint.r)}`)
.map(({ path, disjoint }) => `${path}: ${describeReasons(disjoint)}`)
.join("\n• ")}`;

@@ -78,4 +78,5 @@ }

}
const describeReasons = (source) => `${describeReason(source.l)} and ${describeReason(source.r)}`;
const describeReason = (value) => hasArkKind(value, "root") ? value.expression
: isArray(value) ? value.map(describeReason).join(" | ")
: String(value);

@@ -1,2 +0,2 @@

import { CastableBase, ReadonlyArray, type show } from "@arktype/util";
import { CastableBase, ReadonlyArray, type propwiseXor, type show } from "@arktype/util";
import type { Prerequisite, errorContext } from "../kinds.js";

@@ -44,2 +44,7 @@ import type { NodeKind } from "./implement.js";

}
export type DerivableErrorContextInput<code extends ArkErrorCode = ArkErrorCode> = Partial<DerivableErrorContext<code>> & propwiseXor<{
path?: TraversalPath;
}, {
relativePath?: TraversalPath;
}>;
export type ArkErrorCode = {

@@ -49,3 +54,3 @@ [kind in NodeKind]: errorContext<kind> extends null ? never : kind;

type ArkErrorContextInputsByCode = {
[code in ArkErrorCode]: errorContext<code> & Partial<DerivableErrorContext<code>>;
[code in ArkErrorCode]: errorContext<code> & DerivableErrorContextInput<code>;
};

@@ -57,3 +62,3 @@ export type ArkErrorContextInput<code extends ArkErrorCode = ArkErrorCode> = ArkErrorContextInputsByCode[code];

code?: undefined;
} & Partial<DerivableErrorContext>>;
} & DerivableErrorContextInput>;
export type ArkErrorInput = string | ArkErrorContextInput | CustomErrorInput;

@@ -60,0 +65,0 @@ export type ProblemWriter<code extends ArkErrorCode = ArkErrorCode> = (context: ProblemContext<code>) => string;

@@ -20,2 +20,4 @@ import { CastableBase, ReadonlyArray, defineProperties } from "@arktype/util";

this.path = input.path ?? [...ctx.path];
if (input.relativePath)
this.path.push(...input.relativePath);
this.data = "data" in input ? input.data : data;

@@ -22,0 +24,0 @@ }

@@ -38,3 +38,3 @@ import { compileSerializedValue, flatMorph, printable, throwParseError } from "@arktype/util";

export const constraintKeys = flatMorph(constraintKinds, (i, kind) => [kind, 1]);
export const structureKeys = flatMorph([...structuralKinds, "onExtraneousKey"], (i, k) => [k, 1]);
export const structureKeys = flatMorph([...structuralKinds, "undeclared"], (i, k) => [k, 1]);
export const precedenceByKind = flatMorph(nodeKinds, (i, kind) => [kind, i]);

@@ -41,0 +41,0 @@ export const isNodeKind = (value) => typeof value === "string" && value in precedenceByKind;

@@ -65,3 +65,3 @@ import { Hkt } from "@arktype/util";

export const pipeFromMorph = (from, to, ctx) => {
const out = from?.to ? intersectNodes(from.to, to, ctx) : to;
const out = from?.out ? intersectNodes(from.out, to, ctx) : to;
if (out instanceof Disjoint)

@@ -71,8 +71,8 @@ return out;

morphs: from.morphs,
from: from.in,
to: out
in: from.in,
out
});
};
export const pipeToMorph = (from, to, ctx) => {
const result = intersectNodes(from, to.from, ctx);
const result = intersectNodes(from, to.in, ctx);
if (result instanceof Disjoint)

@@ -82,5 +82,5 @@ return result;

morphs: to.morphs,
from: result,
to: to.out
in: result,
out: to.out
});
};

@@ -9,3 +9,3 @@ import type { array } from "@arktype/util";

morphs: array<Morph>;
to: TraverseApply | null;
to?: TraverseApply;
};

@@ -16,2 +16,5 @@ export type BranchTraversalContext = {

};
export type QueueMorphOptions = {
outValidator?: TraverseApply;
};
export declare class TraversalContext {

@@ -29,3 +32,3 @@ root: unknown;

get currentBranch(): BranchTraversalContext | undefined;
queueMorphs(morphs: array<Morph>, outValidator: TraverseApply | null): void;
queueMorphs(morphs: array<Morph>, opts?: QueueMorphOptions): void;
finalize(): unknown;

@@ -32,0 +35,0 @@ get currentErrorCount(): number;

@@ -17,8 +17,9 @@ import { ArkError, ArkErrors } from "./errors.js";

}
queueMorphs(morphs, outValidator) {
queueMorphs(morphs, opts) {
const input = {
path: [...this.path],
morphs,
to: outValidator
morphs
};
if (opts?.outValidator)
input.to = opts?.outValidator;
this.currentBranch?.queuedMorphs.push(input) ??

@@ -25,0 +26,0 @@ this.queuedMorphs.push(input);

@@ -10,7 +10,7 @@ import { BaseConstraint } from "../constraint.js";

export interface IndexSchema extends BaseMeta {
readonly index: RootSchema<IndexKeyKind>;
readonly signature: RootSchema<IndexKeyKind>;
readonly value: RootSchema;
}
export interface IndexInner extends BaseMeta {
readonly index: IndexKeyNode;
readonly signature: IndexKeyNode;
readonly value: BaseRoot;

@@ -17,0 +17,0 @@ }

@@ -11,3 +11,3 @@ import { printable, stringAndSymbolicEntriesOf, throwParseError } from "@arktype/util";

keys: {
index: {
signature: {
child: true,

@@ -19,3 +19,2 @@ parse: (schema, ctx) => {

}
// TODO: explicit manual annotation once we can upgrade to 5.5
const enumerableBranches = key.branches.filter((b) => b.hasKind("unit"));

@@ -35,7 +34,7 @@ if (enumerableBranches.length) {

defaults: {
description: node => `[${node.index.expression}]: ${node.value.description}`
description: node => `[${node.signature.expression}]: ${node.value.description}`
},
intersections: {
index: (l, r, ctx) => {
if (l.index.equals(r.index)) {
if (l.signature.equals(r.signature)) {
const valueIntersection = intersectNodes(l.value, r.value, ctx);

@@ -45,9 +44,9 @@ const value = valueIntersection instanceof Disjoint ?

: valueIntersection;
return ctx.$.node("index", { index: l.index, value });
return ctx.$.node("index", { signature: l.signature, value });
}
// if r constrains all of l's keys to a subtype of l's value, r is a subtype of l
if (l.index.extends(r.index) && l.value.subsumes(r.value))
if (l.signature.extends(r.signature) && l.value.subsumes(r.value))
return r;
// if l constrains all of r's keys to a subtype of r's value, l is a subtype of r
if (r.index.extends(l.index) && r.value.subsumes(l.value))
if (r.signature.extends(l.signature) && r.value.subsumes(l.value))
return l;

@@ -61,5 +60,5 @@ // other relationships between index signatures can't be generally reduced

impliedBasis = this.$.keywords.object.raw;
expression = `[${this.index.expression}]: ${this.value.expression}`;
expression = `[${this.signature.expression}]: ${this.value.expression}`;
traverseAllows = (data, ctx) => stringAndSymbolicEntriesOf(data).every(entry => {
if (this.index.traverseAllows(entry[0], ctx)) {
if (this.signature.traverseAllows(entry[0], ctx)) {
// ctx will be undefined if this node isn't context-dependent

@@ -74,3 +73,3 @@ ctx?.path.push(entry[0]);

traverseApply = (data, ctx) => stringAndSymbolicEntriesOf(data).forEach(entry => {
if (this.index.traverseAllows(entry[0], ctx)) {
if (this.signature.traverseAllows(entry[0], ctx)) {
ctx.path.push(entry[0]);

@@ -77,0 +76,0 @@ this.value.traverseApply(entry[1], ctx);

import type { declareNode } from "../shared/declare.js";
import { type nodeImplementationOf } from "../shared/implement.js";
import { BaseProp, type BasePropDeclaration } from "./prop.js";
export type OptionalDeclaration = declareNode<BasePropDeclaration<"optional">>;
import { BaseProp, type BasePropDeclaration, type BasePropInner, type BasePropSchema } from "./prop.js";
export interface OptionalSchema extends BasePropSchema {
default?: unknown;
}
export interface OptionalInner extends BasePropInner {
default?: unknown;
}
export type Default<v = any> = ["=", v];
export type DefaultableAst<t = any, v = any> = (In?: t) => Default<v>;
export type OptionalDeclaration = declareNode<BasePropDeclaration<"optional"> & {
schema: OptionalSchema;
normalizedSchema: OptionalSchema;
inner: OptionalInner;
}>;
export declare const optionalImplementation: nodeImplementationOf<OptionalDeclaration>;

@@ -6,0 +18,0 @@ export declare class OptionalNode extends BaseProp<"optional"> {

@@ -12,2 +12,5 @@ import { implementNode } from "../shared/implement.js";

parse: (schema, ctx) => ctx.$.schema(schema)
},
default: {
preserveUndefined: true
}

@@ -14,0 +17,0 @@ },

@@ -10,11 +10,11 @@ import { type Key } from "@arktype/util";

import type { TraverseAllows, TraverseApply } from "../shared/traversal.js";
import type { OptionalDeclaration } from "./optional.js";
import type { OptionalDeclaration, OptionalNode } from "./optional.js";
import type { RequiredDeclaration } from "./required.js";
export type PropKind = "required" | "optional";
export type PropNode = Node<PropKind>;
export interface PropSchema extends BaseMeta {
export interface BasePropSchema extends BaseMeta {
readonly key: Key;
readonly value: RootSchema;
}
export interface PropInner extends PropSchema {
export interface BasePropInner extends BasePropSchema {
readonly value: BaseRoot;

@@ -24,5 +24,2 @@ }

kind: kind;
schema: PropSchema;
normalizedSchema: PropSchema;
inner: PropInner;
prerequisite: object;

@@ -38,2 +35,7 @@ intersectionIsOpen: true;

compiledKey: string;
private defaultValueMorphs;
private defaultValueMorphsReference;
hasDefault(): this is OptionalNode & {
default: unknown;
};
traverseAllows: TraverseAllows<object>;

@@ -40,0 +42,0 @@ traverseApply: TraverseApply<object>;

@@ -1,2 +0,2 @@

import { compileSerializedValue } from "@arktype/util";
import { compileSerializedValue, printable, registeredReference, throwParseError, unset } from "@arktype/util";
import { BaseConstraint } from "../constraint.js";

@@ -17,5 +17,21 @@ import { Disjoint } from "../shared/disjoint.js";

}
return ctx.$.node(kind, {
if (kind === "required") {
return ctx.$.node("required", {
key,
value
});
}
const defaultIntersection = l.hasDefault() ?
r.hasDefault() ?
l.default === r.default ?
l.default
: throwParseError(`Invalid intersection of default values ${printable(l.default)} & ${printable(r.default)}`)
: l.default
: r.hasDefault() ? r.default
: unset;
return ctx.$.node("optional", {
key,
value
value,
// unset is stripped during parsing
default: defaultIntersection
});

@@ -28,2 +44,12 @@ };

compiledKey = typeof this.key === "string" ? this.key : this.serializedKey;
defaultValueMorphs = [
data => {
data[this.key] = this.default;
return data;
}
];
defaultValueMorphsReference = registeredReference(this.defaultValueMorphs);
hasDefault() {
return "default" in this;
}
traverseAllows = (data, ctx) => {

@@ -40,16 +66,14 @@ if (this.key in data) {

traverseApply = (data, ctx) => {
ctx.path.push(this.key);
if (this.key in data)
if (this.key in data) {
ctx.path.push(this.key);
this.value.traverseApply(data[this.key], ctx);
ctx.path.pop();
}
else if (this.hasKind("required"))
ctx.error(this.errorContext);
ctx.path.pop();
else if (this.hasKind("optional") && this.hasDefault())
ctx.queueMorphs(this.defaultValueMorphs);
};
compile(js) {
const requiresContext = js.requiresContextFor(this.value);
if (requiresContext)
js.line(`ctx.path.push(${this.serializedKey})`);
js.if(`${this.serializedKey} in ${js.data}`, () => js.check(this.value, {
arg: `${js.data}${js.prop(this.key)}`
}));
js.if(`${this.serializedKey} in data`, () => js.traverseKey(this.serializedKey, `data${js.prop(this.key)}`, this.value));
if (this.hasKind("required")) {

@@ -59,11 +83,9 @@ js.else(() => {

return js.line(`ctx.error(${this.compiledErrorContext})`);
else {
if (requiresContext)
js.line(`ctx.path.pop()`);
else
return js.return(false);
}
});
}
if (requiresContext)
js.line(`ctx.path.pop()`);
else if (js.traversalKind === "Apply" && "default" in this) {
js.else(() => js.line(`ctx.queueMorphs(${this.defaultValueMorphsReference})`));
}
if (js.traversalKind === "Allows")

@@ -70,0 +92,0 @@ js.return(true);

import type { BaseErrorContext, declareNode } from "../shared/declare.js";
import type { ArkErrorContextInput } from "../shared/errors.js";
import { type nodeImplementationOf } from "../shared/implement.js";
import { BaseProp, type BasePropDeclaration } from "./prop.js";
import { BaseProp, type BasePropDeclaration, type BasePropInner, type BasePropSchema } from "./prop.js";
export interface RequiredErrorContext extends BaseErrorContext<"required"> {
missingValueDescription: string;
}
export interface RequiredSchema extends BasePropSchema {
}
export interface RequiredInner extends BasePropInner {
}
export type RequiredDeclaration = declareNode<BasePropDeclaration<"required"> & {
schema: RequiredSchema;
normalizedSchema: RequiredSchema;
inner: RequiredInner;
errorContext: RequiredErrorContext;

@@ -12,5 +20,5 @@ }>;

expression: string;
errorContext: RequiredErrorContext;
errorContext: ArkErrorContextInput<"required">;
compiledErrorContext: string;
}
export declare const requiredImplementation: nodeImplementationOf<RequiredDeclaration>;

@@ -7,3 +7,4 @@ import { compileErrorContext, implementNode } from "../shared/implement.js";

code: "required",
missingValueDescription: this.value.description
missingValueDescription: this.value.description,
relativePath: [this.key]
});

@@ -10,0 +11,0 @@ compiledErrorContext = compileErrorContext(this.errorContext);

@@ -165,5 +165,5 @@ import { append, throwInternalError, throwParseError } from "@arktype/util";

return this.prevariadic[index];
const postfixStartIndex = data.length - this.postfix.length;
if (index >= postfixStartIndex)
return this.postfix[index - postfixStartIndex];
const firstPostfixIndex = data.length - this.postfix.length;
if (index >= firstPostfixIndex)
return this.postfix[index - firstPostfixIndex];
return (this.variadic ??

@@ -188,12 +188,17 @@ throwInternalError(`Unexpected attempt to access index ${index} on ${this}`));

compile(js) {
this.prefix.forEach((node, i) => js.checkReferenceKey(`${i}`, node));
this.prefix.forEach((node, i) => js.traverseKey(`${i}`, `data[${i}]`, node));
this.optionals.forEach((node, i) => {
const dataIndex = `${i + this.prefix.length}`;
js.if(`${dataIndex} >= ${js.data}.length`, () => js.traversalKind === "Allows" ? js.return(true) : js.return());
js.checkReferenceKey(dataIndex, node);
js.traverseKey(dataIndex, `data[${dataIndex}]`, node);
});
if (this.variadic) {
js.const("lastVariadicIndex", `${js.data}.length${this.postfix ? `- ${this.postfix.length}` : ""}`);
js.for("i < lastVariadicIndex", () => js.checkReferenceKey("i", this.variadic), this.prevariadic.length);
this.postfix.forEach((node, i) => js.checkReferenceKey(`lastVariadicIndex + ${i + 1}`, node));
if (this.postfix.length) {
js.const("firstPostfixIndex", `${js.data}.length${this.postfix.length ? `- ${this.postfix.length}` : ""}`);
}
js.for(`i < ${this.postfix.length ? "firstPostfixIndex" : "data.length"}`, () => js.traverseKey("i", "data[i]", this.variadic), this.prevariadic.length);
this.postfix.forEach((node, i) => {
const keyExpression = `firstPostfixIndex + ${i}`;
js.traverseKey(keyExpression, `data[${keyExpression}]`, node);
});
}

@@ -200,0 +205,0 @@ if (js.traversalKind === "Allows")

import { type array, type Key, type RegisteredReference } from "@arktype/util";
import { BaseConstraint } from "../constraint.js";
import type { BaseRoot } from "../roots/root.js";
import type { RawRootScope } from "../scope.js";
import type { NodeCompiler } from "../shared/compile.js";
import type { BaseMeta, declareNode } from "../shared/declare.js";
import { type nodeImplementationOf, type StructuralKind } from "../shared/implement.js";
import type { TraverseAllows, TraverseApply } from "../shared/traversal.js";
import type { TraversalContext, TraversalKind, TraverseAllows, TraverseApply } from "../shared/traversal.js";
import type { IndexNode, IndexSchema } from "./index.js";
import type { OptionalNode } from "./optional.js";
import type { PropNode, PropSchema } from "./prop.js";
import type { RequiredNode } from "./required.js";
import type { OptionalNode, OptionalSchema } from "./optional.js";
import type { PropNode } from "./prop.js";
import type { RequiredNode, RequiredSchema } from "./required.js";
import type { SequenceNode, SequenceSchema } from "./sequence.js";
export type ExtraneousKeyBehavior = "ignore" | ExtraneousKeyRestriction;
export type ExtraneousKeyRestriction = "error" | "prune";
export type UndeclaredKeyBehavior = "ignore" | UndeclaredKeyHandling;
export type UndeclaredKeyHandling = "reject" | "delete";
export interface StructureSchema extends BaseMeta {
readonly optional?: readonly PropSchema[];
readonly required?: readonly PropSchema[];
readonly optional?: readonly OptionalSchema[];
readonly required?: readonly RequiredSchema[];
readonly index?: readonly IndexSchema[];
readonly sequence?: SequenceSchema;
readonly onExtraneousKey?: ExtraneousKeyBehavior;
readonly undeclared?: UndeclaredKeyBehavior;
}

@@ -27,3 +28,3 @@ export interface StructureInner extends BaseMeta {

readonly sequence?: SequenceNode;
readonly onExtraneousKey?: ExtraneousKeyRestriction;
readonly undeclared?: UndeclaredKeyHandling;
}

@@ -49,14 +50,18 @@ export interface StructureDeclaration extends declareNode<{

literalKeys: Key[];
private _keyof;
keyof(): BaseRoot;
readonly exhaustive: boolean;
omit(...keys: array<BaseRoot | Key>): StructureNode;
merge(r: StructureNode): StructureNode;
traverseAllows: TraverseAllows<object>;
traverseApply: TraverseApply<object>;
readonly exhaustive: boolean;
protected _traverse: (traversalKind: TraversalKind, data: object, ctx: TraversalContext) => boolean;
compile(js: NodeCompiler): void;
omit(...keys: array<BaseRoot | Key>): StructureNode;
merge(r: StructureNode): StructureNode;
protected compileEnumerable(js: NodeCompiler): void;
protected compileExhaustive(js: NodeCompiler): void;
protected compileExhaustiveEntry(js: NodeCompiler): NodeCompiler;
}
export declare const structureImplementation: nodeImplementationOf<StructureDeclaration>;
export type NormalizedIndex = {
index?: IndexNode;
required?: RequiredNode[];
};
/** extract enumerable named props from an index signature */
export declare const normalizeIndex: (signature: BaseRoot, value: BaseRoot, $: RawRootScope) => NormalizedIndex;

@@ -1,114 +0,231 @@

import { append, flatMorph, registeredReference } from "@arktype/util";
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
import { append, cached, flatMorph, registeredReference, spliterate } from "@arktype/util";
import { BaseConstraint, constraintKeyParser, flattenConstraints, intersectConstraints } from "../constraint.js";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { intersectNodesRoot } from "../shared/intersections.js";
import { makeRootAndArrayPropertiesMutable } from "../shared/utils.js";
import { arrayIndexMatcherReference } from "./shared.js";
export class StructureNode extends BaseConstraint {
impliedBasis = this.$.keywords.object.raw;
impliedSiblings = this.children.flatMap(n => n.impliedSiblings ?? []);
props = this.required ?
this.optional ?
[...this.required, ...this.optional]
: this.required
: this.optional ?? [];
propsByKey = flatMorph(this.props, (i, node) => [node.key, node]);
propsByKeyReference = registeredReference(this.propsByKey);
expression = structuralExpression(this);
requiredLiteralKeys = this.required?.map(node => node.key) ?? [];
optionalLiteralKeys = this.optional?.map(node => node.key) ?? [];
literalKeys = [
...this.requiredLiteralKeys,
...this.optionalLiteralKeys
];
_keyof;
keyof() {
if (!this._keyof) {
import { arrayIndexMatcher, arrayIndexMatcherReference } from "./shared.js";
let StructureNode = (() => {
let _classSuper = BaseConstraint;
let _instanceExtraInitializers = [];
let _keyof_decorators;
return class StructureNode extends _classSuper {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
_keyof_decorators = [cached];
__esDecorate(this, null, _keyof_decorators, { kind: "method", name: "keyof", static: false, private: false, access: { has: obj => "keyof" in obj, get: obj => obj.keyof }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
impliedBasis = (__runInitializers(this, _instanceExtraInitializers), this.$.keywords.object.raw);
impliedSiblings = this.children.flatMap(n => n.impliedSiblings ?? []);
props = this.required ?
this.optional ?
[...this.required, ...this.optional]
: this.required
: this.optional ?? [];
propsByKey = flatMorph(this.props, (i, node) => [node.key, node]);
propsByKeyReference = registeredReference(this.propsByKey);
expression = structuralExpression(this);
requiredLiteralKeys = this.required?.map(node => node.key) ?? [];
optionalLiteralKeys = this.optional?.map(node => node.key) ?? [];
literalKeys = [
...this.requiredLiteralKeys,
...this.optionalLiteralKeys
];
keyof() {
let branches = this.$.units(this.literalKeys).branches;
this.index?.forEach(({ index }) => {
this.index?.forEach(({ signature: index }) => {
branches = branches.concat(index.branches);
});
this._keyof = this.$.node("union", branches);
return this.$.node("union", branches);
}
return this._keyof;
}
// TODO: normalize this to match compiled check order
traverseAllows = (data, ctx) => this.children.every(prop => prop.traverseAllows(data, ctx));
traverseApply = (data, ctx) => {
const errorCount = ctx.currentErrorCount;
for (let i = 0; i < this.children.length - 1; i++) {
this.children[i].traverseApply(data, ctx);
if (ctx.failFast && ctx.currentErrorCount > errorCount)
return;
exhaustive = this.undeclared !== undefined || this.index !== undefined;
omit(...keys) {
return this.$.node("structure", omitFromInner(this.inner, keys));
}
this.children.at(-1)?.traverseApply(data, ctx);
};
exhaustive = this.onExtraneousKey !== undefined || this.index !== undefined;
compile(js) {
if (this.exhaustive)
this.compileExhaustive(js);
else
this.compileEnumerable(js);
}
omit(...keys) {
return this.$.node("structure", omitFromInner(this.inner, keys));
}
merge(r) {
const inner = makeRootAndArrayPropertiesMutable(omitFromInner(this.inner, [r.keyof()]));
if (r.required)
inner.required = append(inner.required, r.required);
if (r.optional)
inner.optional = append(inner.optional, r.optional);
if (r.index)
inner.index = append(inner.index, r.index);
if (r.sequence)
inner.sequence = r.sequence;
if (r.onExtraneousKey)
inner.onExtraneousKey = r.onExtraneousKey;
else
delete inner.onExtraneousKey;
return this.$.node("structure", inner);
}
compileEnumerable(js) {
if (js.traversalKind === "Allows") {
this.children.forEach(node => js.if(`!${js.invoke(node)}`, () => js.return(false)));
js.return(true);
merge(r) {
const inner = makeRootAndArrayPropertiesMutable(omitFromInner(this.inner, [r.keyof()]));
if (r.required)
inner.required = append(inner.required, r.required);
if (r.optional)
inner.optional = append(inner.optional, r.optional);
if (r.index)
inner.index = append(inner.index, r.index);
if (r.sequence)
inner.sequence = r.sequence;
if (r.undeclared)
inner.undeclared = r.undeclared;
else
delete inner.undeclared;
return this.$.node("structure", inner);
}
else {
js.initializeErrorCount();
this.children.forEach(node => js.line(js.invoke(node)).returnIfFailFast());
traverseAllows = (data, ctx) => this._traverse("Allows", data, ctx);
traverseApply = (data, ctx) => this._traverse("Apply", data, ctx);
_traverse = (traversalKind, data, ctx) => {
const errorCount = ctx?.currentErrorCount ?? 0;
for (let i = 0; i < this.props.length; i++) {
if (traversalKind === "Allows") {
if (!this.props[i].traverseAllows(data, ctx))
return false;
}
else {
this.props[i].traverseApply(data, ctx);
if (ctx.failFast && ctx.currentErrorCount > errorCount)
return false;
}
}
if (this.sequence) {
if (traversalKind === "Allows") {
if (!this.sequence.traverseAllows(data, ctx))
return false;
}
else {
this.sequence.traverseApply(data, ctx);
if (ctx.failFast && ctx.currentErrorCount > errorCount)
return false;
}
}
if (!this.exhaustive)
return true;
const keys = Object.keys(data);
keys.push(...Object.getOwnPropertySymbols(data));
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
let matched = false;
if (this.index) {
for (const node of this.index) {
if (node.signature.traverseAllows(k, ctx)) {
if (traversalKind === "Allows") {
ctx?.path.push(k);
const result = node.value.traverseAllows(data[k], ctx);
ctx?.path.pop();
if (!result)
return false;
}
else {
ctx.path.push(k);
node.value.traverseApply(data[k], ctx);
ctx.path.pop();
if (ctx.failFast && ctx.currentErrorCount > errorCount)
return false;
}
matched = true;
}
}
}
if (this.undeclared) {
matched ||= k in this.propsByKey;
matched ||=
this.sequence !== undefined &&
typeof k === "string" &&
arrayIndexMatcher.test(k);
if (!matched) {
if (traversalKind === "Allows")
return false;
if (this.undeclared === "reject")
ctx.error({ expected: "removed", actual: null, relativePath: [k] });
else {
ctx.queueMorphs([
data => {
delete data[k];
return data;
}
]);
}
if (ctx.failFast)
return false;
}
}
ctx?.path.pop();
}
return true;
};
compile(js) {
if (js.traversalKind === "Apply")
js.initializeErrorCount();
this.props.forEach(prop => {
js.check(prop);
if (js.traversalKind === "Apply")
js.returnIfFailFast();
});
if (this.sequence) {
js.check(this.sequence);
if (js.traversalKind === "Apply")
js.returnIfFailFast();
}
if (this.exhaustive) {
js.const("keys", "Object.keys(data)");
js.line("keys.push(...Object.getOwnPropertySymbols(data))");
js.for("i < keys.length", () => this.compileExhaustiveEntry(js));
}
if (js.traversalKind === "Allows")
js.return(true);
}
}
compileExhaustive(js) {
this.props.forEach(prop => js.check(prop));
if (this.sequence)
js.check(this.sequence);
js.const("keys", "Object.keys(data)");
js.const("symbols", "Object.getOwnPropertySymbols(data)");
js.if("symbols.length", () => js.line("keys.push(...symbols)"));
js.for("i < keys.length", () => this.compileExhaustiveEntry(js));
}
compileExhaustiveEntry(js) {
js.const("k", "keys[i]");
if (this.onExtraneousKey)
js.let("matched", false);
this.index?.forEach(node => {
js.if(`${js.invoke(node.index, { arg: "k", kind: "Allows" })}`, () => {
js.checkReferenceKey("k", node.value);
if (this.onExtraneousKey)
js.set("matched", true);
return js;
compileExhaustiveEntry(js) {
js.const("k", "keys[i]");
if (this.undeclared)
js.let("matched", false);
this.index?.forEach(node => {
js.if(`${js.invoke(node.signature, { arg: "k", kind: "Allows" })}`, () => {
js.traverseKey("k", "data[k]", node.value);
if (this.undeclared)
js.set("matched", true);
return js;
});
});
});
if (this.onExtraneousKey) {
if (this.props?.length !== 0)
js.line(`matched ||= k in ${this.propsByKeyReference}`);
if (this.sequence)
js.line(`matched ||= ${arrayIndexMatcherReference}.test(k)`);
// TODO: replace error
js.if("!matched", () => js.line(`throw new Error("strict")`));
if (this.undeclared) {
if (this.props?.length !== 0)
js.line(`matched ||= k in ${this.propsByKeyReference}`);
if (this.sequence) {
js.line(`matched ||= typeof k === "string" && ${arrayIndexMatcherReference}.test(k)`);
}
js.if("!matched", () => {
if (js.traversalKind === "Allows")
return js.return(false);
return this.undeclared === "reject" ?
js
.line(`ctx.error({ expected: "removed", actual: null, relativePath: [k] })`)
.if("ctx.failFast", () => js.return())
: js.line(`ctx.queueMorphs([data => { delete data[k]; return data }])`);
});
}
return js;
}
return js;
}
}
};
})();
export { StructureNode };
const omitFromInner = (inner, keys) => {

@@ -126,3 +243,3 @@ const result = { ...inner };

// literal keys should never subsume an index
result.index = result.index.filter(n => !n.index.extends(k));
result.index = result.index.filter(n => !n.signature.extends(k));
}

@@ -136,3 +253,5 @@ });

node.props.forEach(node => parts.push(node[childStringProp]));
const objectLiteralDescription = `${node.onExtraneousKey ? "exact " : ""}{ ${parts.join(", ")} }`;
if (node.undeclared)
parts.push(`+ (undeclared): ${node.undeclared}`);
const objectLiteralDescription = `{ ${parts.join(", ")} }`;
return node.sequence ?

@@ -167,3 +286,3 @@ `${objectLiteralDescription} & ${node.sequence.description}`

},
onExtraneousKey: {
undeclared: {
parse: behavior => (behavior === "ignore" ? undefined : behavior)

@@ -177,22 +296,62 @@ }

structure: (l, r, ctx) => {
if (l.onExtraneousKey) {
const lInner = { ...l.inner };
const rInner = { ...r.inner };
if (l.undeclared) {
const lKey = l.keyof();
const disjointRKeys = r.requiredLiteralKeys.filter(k => !lKey.allows(k));
if (disjointRKeys.length) {
return Disjoint.from("presence", true, false).withPrefixKey(disjointRKeys[0]);
return Disjoint.from("presence", ctx.$.keywords.never.raw, r.propsByKey[disjointRKeys[0]].value).withPrefixKey(disjointRKeys[0]);
}
if (rInner.optional)
rInner.optional = rInner.optional.filter(n => lKey.allows(n.key));
if (rInner.index) {
rInner.index = rInner.index.flatMap(n => {
if (n.signature.extends(lKey))
return n;
const indexOverlap = intersectNodesRoot(lKey, n.signature, ctx.$);
if (indexOverlap instanceof Disjoint)
return [];
const normalized = normalizeIndex(indexOverlap, n.value, ctx.$);
if (normalized.required) {
rInner.required =
rInner.required ?
[...rInner.required, ...normalized.required]
: normalized.required;
}
return normalized.index ?? [];
});
}
}
if (r.onExtraneousKey) {
if (r.undeclared) {
const rKey = r.keyof();
const disjointLKeys = l.requiredLiteralKeys.filter(k => !rKey.allows(k));
if (disjointLKeys.length) {
return Disjoint.from("presence", true, false).withPrefixKey(disjointLKeys[0]);
return Disjoint.from("presence", l.propsByKey[disjointLKeys[0]].value, ctx.$.keywords.never.raw).withPrefixKey(disjointLKeys[0]);
}
if (lInner.optional)
lInner.optional = lInner.optional.filter(n => rKey.allows(n.key));
if (lInner.index) {
lInner.index = lInner.index.flatMap(n => {
if (n.signature.extends(rKey))
return n;
const indexOverlap = intersectNodesRoot(rKey, n.signature, ctx.$);
if (indexOverlap instanceof Disjoint)
return [];
const normalized = normalizeIndex(indexOverlap, n.value, ctx.$);
if (normalized.required) {
lInner.required =
lInner.required ?
[...lInner.required, ...normalized.required]
: normalized.required;
}
return normalized.index ?? [];
});
}
}
const baseInner = {};
if (l.onExtraneousKey || r.onExtraneousKey) {
baseInner.onExtraneousKey =
l.onExtraneousKey === "error" || r.onExtraneousKey === "error" ?
"error"
: "prune";
if (l.undeclared || r.undeclared) {
baseInner.undeclared =
l.undeclared === "reject" || r.undeclared === "reject" ?
"reject"
: "delete";
}

@@ -202,4 +361,4 @@ return intersectConstraints({

baseInner,
l: flattenConstraints(l.inner),
r: flattenConstraints(r.inner),
l: flattenConstraints(lInner),
r: flattenConstraints(rInner),
roots: [],

@@ -211,1 +370,16 @@ ctx

});
/** extract enumerable named props from an index signature */
export const normalizeIndex = (signature, value, $) => {
const [enumerableBranches, nonEnumerableBranches] = spliterate(signature.branches, (k) => k.hasKind("unit"));
if (!enumerableBranches.length)
return { index: $.node("index", { signature, value }) };
const normalized = {};
normalized.required = enumerableBranches.map(n => $.node("required", { key: n.unit, value }));
if (nonEnumerableBranches.length) {
normalized.index = $.node("index", {
signature: nonEnumerableBranches,
value
});
}
return normalized;
};
{
"name": "@arktype/schema",
"version": "0.1.4",
"version": "0.1.5",
"license": "MIT",

@@ -18,13 +18,5 @@ "author": {

"exports": {
".": {
"types": "./out/api.d.ts",
"default": "./out/api.js"
},
"./config": {
"types": "./out/config.d.ts",
"default": "./out/config.js"
},
"./internal/*": {
"default": "./out/*"
}
".": "./out/api.js",
"./config": "./out/config.js",
"./internal/*": "./out/*"
},

@@ -41,4 +33,4 @@ "files": [

"dependencies": {
"@arktype/util": "0.0.41"
"@arktype/util": "0.0.42"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc