🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@ark/schema

Package Overview
Dependencies
Maintainers
1
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ark/schema - npm Package Compare versions

Comparing version
0.49.0
to
0.50.0
+7
-7
out/constraint.js

@@ -31,3 +31,3 @@ import { append, appendUnique, capitalize, isArray, throwInternalError, throwParseError } from "@ark/util";

else {
js.if(this.compiledNegation, () => js.line(`${js.ctx}.errorFromNodeContext(${this.compiledErrorContext})`));
js.if(this.compiledNegation, () => js.line(`ctx.errorFromNodeContext(${this.compiledErrorContext})`));
}

@@ -83,8 +83,8 @@ }

return result;
if (result.isRoot()) {
s.roots.push(result);
s.l.splice(i);
return intersectConstraints(s);
}
if (!matched) {
if (result.isRoot()) {
s.roots.push(result);
s.l.splice(i);
return intersectConstraints(s);
}
s.l[i] = result;

@@ -94,3 +94,3 @@ matched = true;

else if (!s.l.includes(result)) {
return throwInternalError(`Unexpectedly encountered multiple distinct intersection results for refinement ${result}`);
return throwInternalError(`Unexpectedly encountered multiple distinct intersection results for refinement ${head}`);
}

@@ -97,0 +97,0 @@ }

@@ -14,2 +14,3 @@ export * from "./config.ts";

export * from "./refinements/exactLength.ts";
export * from "./refinements/kinds.ts";
export * from "./refinements/max.ts";

@@ -16,0 +17,0 @@ export * from "./refinements/maxLength.ts";

@@ -14,2 +14,3 @@ export * from "./config.js";

export * from "./refinements/exactLength.js";
export * from "./refinements/kinds.js";
export * from "./refinements/max.js";

@@ -16,0 +17,0 @@ export * from "./refinements/maxLength.js";

@@ -15,3 +15,2 @@ import { Callable, type GuardablePredicate, type JsonStructure, type Key, type array, type conform, type listable, type mutable, type requireKeys } from "@ark/util";

import { Traversal, type TraverseAllows, type TraverseApply } from "./shared/traversal.ts";
import { type arkKind } from "./shared/utils.ts";
import type { UndeclaredKeyHandling } from "./structure/structure.ts";

@@ -51,8 +50,8 @@ export declare abstract class BaseNode<

traverse(data: d["prerequisite"], pipedFromCtx?: Traversal): ArkErrors | {} | null | undefined;
get in(): this extends {
[arkKind]: "root";
} ? BaseRoot : BaseNode;
get out(): this extends {
[arkKind]: "root";
} ? BaseRoot : BaseNode;
/** rawIn should be used internally instead */
get in(): unknown;
get rawIn(): BaseNode;
/** rawOut should be used internally instead */
get out(): unknown;
get rawOut(): BaseNode;
getIo(ioKind: "in" | "out"): BaseNode;

@@ -59,0 +58,0 @@ toJSON(): JsonStructure;

@@ -40,3 +40,4 @@ import { Callable, appendUnique, flatMorph, includes, isArray, isEmptyObject, isKeyOf, liftArray, printable, stringifyPath, throwError, throwInternalError } from "@ark/util";

this.hasKind("morph") ||
(this.hasKind("structure") && this.structuralMorph !== undefined);
(this.hasKind("structure") && this.structuralMorph !== undefined) ||
(this.hasKind("sequence") && this.inner.defaultables !== undefined);
// if a predicate accepts exactly one arg, we can safely skip passing context

@@ -170,8 +171,18 @@ // technically, a predicate could be written like `(data, ...[ctx]) => ctx.mustBe("malicious")`

}
/** rawIn should be used internally instead */
get in() {
return this.cacheGetter("in", this.getIo("in"));
// ensure the node has been finalized if in is being used externally
return this.cacheGetter("in", this.rawIn.isRoot() ? this.$.finalize(this.rawIn) : this.rawIn);
}
get rawIn() {
return this.cacheGetter("rawIn", this.getIo("in"));
}
/** rawOut should be used internally instead */
get out() {
return this.cacheGetter("out", this.getIo("out"));
// ensure the node has been finalized if out is being used externally
return this.cacheGetter("out", this.rawOut.isRoot() ? this.$.finalize(this.rawOut) : this.rawOut);
}
get rawOut() {
return this.cacheGetter("rawOut", this.getIo("out"));
}
// Should be refactored to use transform

@@ -191,4 +202,5 @@ // https://github.com/arktypeio/arktype/issues/1020

isArray(childValue) ?
childValue.map(child => child[ioKind])
: childValue[ioKind];
childValue.map(child => ioKind === "in" ? child.rawIn : child.rawOut)
: ioKind === "in" ? childValue.rawIn
: childValue.rawOut;
}

@@ -195,0 +207,0 @@ else

import type { BaseConstraint } from "../constraint.ts";
import type { BoundKind, nodeImplementationOf } from "../shared/implement.ts";
import type { nodeImplementationOf } from "../shared/implement.ts";
import { After } from "./after.ts";

@@ -28,2 +28,4 @@ import { Before } from "./before.ts";

}
export type BoundKind = keyof BoundDeclarations;
export type RangeKind = Exclude<BoundKind, "exactLength">;
export type boundImplementationsByKind = {

@@ -30,0 +32,0 @@ [k in BoundKind]: nodeImplementationOf<BoundDeclarations[k]>;

@@ -5,3 +5,4 @@ import { type array, type propValueOf, type satisfy } from "@ark/util";

import type { BaseNodeDeclaration, BaseNormalizedSchema } from "../shared/declare.ts";
import type { keySchemaDefinitions, RangeKind } from "../shared/implement.ts";
import type { keySchemaDefinitions } from "../shared/implement.ts";
import type { RangeKind } from "./kinds.ts";
export interface BaseRangeDeclaration extends BaseNodeDeclaration {

@@ -8,0 +9,0 @@ kind: RangeKind;

@@ -23,5 +23,5 @@ import { compileObjectLiteral } from "../shared/implement.js";

else {
js.if(this.compiledNegation, () => js.line(`${js.ctx}.errorFromNodeContext(${this.compiledErrorContext})`));
js.if(this.compiledNegation, () => js.line(`ctx.errorFromNodeContext(${this.compiledErrorContext})`));
}
}
}

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

import type { ArkError } from "../shared/errors.ts";
import { type ConstraintKind, type nodeImplementationOf, type OpenNodeKind, type RefinementKind, type StructuralKind } from "../shared/implement.ts";
import { type ConstraintKind, type nodeImplementationOf, type OpenNodeKind, type PrestructuralKind, type RefinementKind, type StructuralKind } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";

@@ -20,3 +20,3 @@ import type { ToJsonSchema } from "../shared/toJsonSchema.ts";

type BasisKind = "domain" | "proto";
type ChildKind = BasisKind | RefinementKind | "predicate" | "structure";
type ChildKind = BasisKind | RefinementKind;
type FlattenedChildKind = ChildKind | StructuralKind;

@@ -60,2 +60,3 @@ type RefinementsInner = {

basis: nodeOfKind<Intersection.BasisKind> | null;
prestructurals: array<nodeOfKind<PrestructuralKind>>;
refinements: array<nodeOfKind<RefinementKind>>;

@@ -62,0 +63,0 @@ structure: Structure.Node | undefined;

@@ -1,5 +0,5 @@

import { flatMorph, hasDomain, isEmptyObject, isKeyOf, throwParseError } from "@ark/util";
import { flatMorph, hasDomain, includes, isEmptyObject, isKeyOf, throwParseError } from "@ark/util";
import { constraintKeyParser, flattenConstraints, intersectConstraints } from "../constraint.js";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode, structureKeys } from "../shared/implement.js";
import { implementNode, prestructuralKinds, structureKeys } from "../shared/implement.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";

@@ -116,6 +116,6 @@ import { hasArkKind, isNode } from "../shared/utils.js";

if (node.basis &&
!node.refinements.some(r => r.impl.obviatesBasisDescription))
!node.prestructurals.some(r => r.impl.obviatesBasisDescription))
childDescriptions.push(node.basis.description);
if (node.refinements.length) {
const sortedRefinementDescriptions = node.refinements
if (node.prestructurals.length) {
const sortedRefinementDescriptions = node.prestructurals
// override alphabetization to describe min before max

@@ -155,3 +155,11 @@ .toSorted((l, r) => (l.kind === "min" && r.kind === "max" ? -1 : 0))

basis = this.inner.domain ?? this.inner.proto ?? null;
refinements = this.children.filter(node => node.isRefinement());
prestructurals = [];
refinements = this.children.filter((node) => {
if (!node.isRefinement())
return false;
if (includes(prestructuralKinds, node.kind))
// mutation is fine during initialization
this.prestructurals.push(node);
return true;
});
structure = this.inner.structure;

@@ -182,9 +190,9 @@ expression = writeIntersectionExpression(this);

}
if (this.refinements.length) {
for (let i = 0; i < this.refinements.length - 1; i++) {
this.refinements[i].traverseApply(data, ctx);
if (this.prestructurals.length) {
for (let i = 0; i < this.prestructurals.length - 1; i++) {
this.prestructurals[i].traverseApply(data, ctx);
if (ctx.failFast && ctx.currentErrorCount > errorCount)
return;
}
this.refinements.at(-1).traverseApply(data, ctx);
this.prestructurals.at(-1).traverseApply(data, ctx);
if (ctx.currentErrorCount > errorCount)

@@ -221,8 +229,8 @@ return;

}
if (this.refinements.length) {
for (let i = 0; i < this.refinements.length - 1; i++) {
js.check(this.refinements[i]);
if (this.prestructurals.length) {
for (let i = 0; i < this.prestructurals.length - 1; i++) {
js.check(this.prestructurals[i]);
js.returnIfFailFast();
}
js.check(this.refinements.at(-1));
js.check(this.prestructurals.at(-1));
if (this.structure || this.inner.predicate)

@@ -252,8 +260,15 @@ js.returnIfFail();

const writeIntersectionExpression = (node) => {
let expression = node.structure?.expression ||
`${node.basis && !node.refinements.some(n => n.impl.obviatesBasisExpression) ? node.basis.nestableExpression + " " : ""}${node.refinements.map(n => n.expression).join(" & ")}` ||
"unknown";
if (expression === "Array == 0")
expression = "[]";
return expression;
if (node.structure?.expression)
return node.structure.expression;
const basisExpression = (node.basis &&
!node.prestructurals.some(n => n.impl.obviatesBasisExpression)) ?
node.basis.nestableExpression
: "";
const refinementsExpression = node.prestructurals
.map(n => n.expression)
.join(" & ");
const fullExpression = `${basisExpression}${basisExpression ? " " : ""}${refinementsExpression}`;
if (fullExpression === "Array == 0")
return "[]";
return fullExpression || "unknown";
};

@@ -260,0 +275,0 @@ const intersectIntersections = (l, r, ctx) => {

@@ -34,9 +34,9 @@ import { type array, type listable } from "@ark/util";

type Out<morph extends Morph> = morph extends Morph<never, infer o> ? o : never;
type ContextFree<i = any, o = unknown> = (In: i) => o;
type ContextFree<i = never, o = unknown> = (In: i) => o;
}
export type Morph<i = any, o = unknown> = (In: i, ctx: Traversal) => o;
export type Morph<i = never, o = unknown> = (In: i, ctx: Traversal) => o;
export declare class MorphNode extends BaseRoot<Morph.Declaration> {
serializedMorphs: string[];
compiledMorphs: string;
lastMorph: BaseRoot<import("./root.ts").InternalRootDeclaration> | Morph<any, unknown> | undefined;
lastMorph: BaseRoot<import("./root.ts").InternalRootDeclaration> | Morph<never, unknown> | undefined;
lastMorphIfNode: BaseRoot | undefined;

@@ -46,4 +46,4 @@ introspectableIn: BaseRoot | undefined;

get shallowMorphs(): array<Morph>;
get in(): BaseRoot;
get out(): BaseRoot;
get rawIn(): BaseRoot;
get rawOut(): BaseRoot;
declareIn(declaredIn: BaseRoot): MorphNode;

@@ -50,0 +50,0 @@ declareOut(declaredOut: BaseRoot): MorphNode;

@@ -32,3 +32,3 @@ import { arrayEquals, liftArray, throwParseError } from "@ark/util";

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

@@ -40,3 +40,3 @@ intersections: {

}
const inTersection = intersectOrPipeNodes(l.in, r.in, ctx);
const inTersection = intersectOrPipeNodes(l.rawIn, r.rawIn, ctx);
if (inTersection instanceof Disjoint)

@@ -48,3 +48,3 @@ return inTersection;

if (l.declaredIn || r.declaredIn) {
const declaredIn = intersectOrPipeNodes(l.in, r.in, ctx);
const declaredIn = intersectOrPipeNodes(l.rawIn, r.rawIn, ctx);
// we can't treat this as a normal Disjoint since it's just declared

@@ -58,3 +58,3 @@ // it should only happen if someone's essentially trying to create a broken type

if (l.declaredOut || r.declaredOut) {
const declaredOut = intersectOrPipeNodes(l.out, r.out, ctx);
const declaredOut = intersectOrPipeNodes(l.rawOut, r.rawOut, ctx);
if (declaredOut instanceof Disjoint)

@@ -91,3 +91,3 @@ return declaredOut.throw();

Object.assign(this.referencesById, this.lastMorphIfNode.referencesById) &&
this.lastMorphIfNode.out
this.lastMorphIfNode.rawOut
: undefined;

@@ -100,6 +100,6 @@ get shallowMorphs() {

}
get in() {
return (this.declaredIn ?? this.inner.in?.in ?? $ark.intrinsic.unknown.internal);
get rawIn() {
return (this.declaredIn ?? this.inner.in?.rawIn ?? $ark.intrinsic.unknown.internal);
}
get out() {
get rawOut() {
return (this.declaredOut ??

@@ -121,5 +121,5 @@ this.introspectableOut ??

}
expression = `(In: ${this.in.expression}) => ${this.lastMorphIfNode ? "To" : "Out"}<${this.out.expression}>`;
expression = `(In: ${this.rawIn.expression}) => ${this.lastMorphIfNode ? "To" : "Out"}<${this.rawOut.expression}>`;
get defaultShortDescription() {
return this.in.meta.description ?? this.in.defaultShortDescription;
return this.rawIn.meta.description ?? this.rawIn.defaultShortDescription;
}

@@ -129,3 +129,3 @@ innerToJsonSchema(ctx) {

code: "morph",
base: this.in.toJsonSchemaRecurse(ctx),
base: this.rawIn.toJsonSchemaRecurse(ctx),
out: this.introspectableOut?.toJsonSchemaRecurse(ctx) ?? null

@@ -132,0 +132,0 @@ });

@@ -31,2 +31,4 @@ import { inferred, type array } from "@ark/util";

constructor(attachments: UnknownAttachments, $: BaseScope);
get rawIn(): BaseRoot;
get rawOut(): BaseRoot;
get internal(): this;

@@ -33,0 +35,0 @@ get "~standard"(): StandardSchemaV1.ArkTypeProps;

@@ -18,2 +18,10 @@ import { arrayEquals, flatMorph, includes, inferred, omit, throwInternalError, throwParseError } from "@ark/util";

}
// doesn't seem possible to override this at a type-level (e.g. via declare)
// without TS complaining about getters
get rawIn() {
return super.rawIn;
}
get rawOut() {
return super.rawOut;
}
get internal() {

@@ -37,4 +45,4 @@ return this;

if (opts.io === "input")
return this.in.toJsonSchema();
return this.out.toJsonSchema();
return this.rawIn.toJsonSchema();
return this.rawOut.toJsonSchema();
}

@@ -178,3 +186,3 @@ };

return this.$.node("intersection", {
...branch.inner,
domain: "object",
structure: structure[structuralMethodName](...args)

@@ -304,3 +312,5 @@ });

}
const operand = io === "root" ? this : this[io];
const operand = io === "root" ? this
: io === "in" ? this.rawIn
: this.rawOut;
if (operand.hasKind("morph") ||

@@ -307,0 +317,0 @@ (constraint.impliedBasis && !operand.extends(constraint.impliedBasis))) {

@@ -34,3 +34,3 @@ import { appendUnique, arrayEquals, domainDescriptions, flatMorph, groupBy, hasKey, isArray, jsTypeOfDescriptions, printable, range, throwParseError, unset } from "@ark/util";

...matchingMorph.inner,
in: matchingMorph.in.rawOr(node.in)
in: matchingMorph.rawIn.rawOr(node.rawIn)
});

@@ -80,3 +80,9 @@ }

problem: ctx => ctx.expected,
message: ctx => ctx.problem
message: ctx => {
if (ctx.problem[0] === "[") {
// clarify paths like [1], [0][1], and ["key!"] that could be confusing
return `value at ${ctx.problem}`;
}
return ctx.problem;
}
},

@@ -140,3 +146,3 @@ intersections: {

}
unitBranches = this.branches.filter((n) => n.in.hasKind("unit"));
unitBranches = this.branches.filter((n) => n.rawIn.hasKind("unit"));
discriminant = this.discriminate();

@@ -228,8 +234,16 @@ discriminantJson = this.discriminant ? discriminantToJson(this.discriminant) : null;

const caseCondition = k === "default" ? k : `case ${k}`;
js.line(`${caseCondition}: return ${v === true ?
optimistic ? js.data
: v
: optimistic ?
`${js.invoke(v)} ? ${v.contextFreeMorph ? `${registeredReference(v.contextFreeMorph)}(${js.data})` : js.data} : "${unset}"`
: js.invoke(v)}`);
let caseResult;
if (v === true)
caseResult = optimistic ? "data" : "true";
else if (optimistic) {
if (v.rootApplyStrategy === "branchedOptimistic")
caseResult = js.invoke(v, { kind: "Optimistic" });
else if (v.contextFreeMorph)
caseResult = `${js.invoke(v)} ? ${registeredReference(v.contextFreeMorph)}(data) : "${unset}"`;
else
caseResult = `${js.invoke(v)} ? data : "${unset}"`;
}
else
caseResult = js.invoke(v);
js.line(`${caseCondition}: return ${caseResult}`);
}

@@ -283,4 +297,4 @@ return js;

branch.contextFreeMorph ?
`${registeredReference(branch.contextFreeMorph)}(${js.data})`
: js.data
`${registeredReference(branch.contextFreeMorph)}(data)`
: "data"
: true));

@@ -301,3 +315,3 @@ }

const cases = flatMorph(this.unitBranches, (i, n) => [
`${n.in.serializedValue}`,
`${n.rawIn.serializedValue}`,
n.hasKind("morph") ? n : true

@@ -317,3 +331,3 @@ ]);

const r = this.branches[rIndex];
const result = intersectNodesRoot(l.in, r.in, l.$);
const result = intersectNodesRoot(l.rawIn, r.rawIn, l.$);
if (!(result instanceof Disjoint))

@@ -378,6 +392,8 @@ continue;

}
const orderedCandidates = this.ordered ? orderCandidates(candidates, this.branches) : candidates;
if (!orderedCandidates.length)
const viableCandidates = this.ordered ?
viableOrderedCandidates(candidates, this.branches)
: candidates;
if (!viableCandidates.length)
return null;
const ctx = createCaseResolutionContext(orderedCandidates, this);
const ctx = createCaseResolutionContext(viableCandidates, this);
const cases = {};

@@ -419,4 +435,8 @@ for (const k in ctx.best.cases) {

}
const createCaseResolutionContext = (orderedCandidates, node) => {
const best = orderedCandidates.sort((l, r) => Object.keys(r.cases).length - Object.keys(l.cases).length)[0];
const createCaseResolutionContext = (viableCandidates, node) => {
const ordered = viableCandidates.sort((l, r) => l.path.length === r.path.length ?
Object.keys(r.cases).length - Object.keys(l.cases).length
// prefer shorter paths first
: l.path.length - r.path.length);
const best = ordered[0];
const location = {

@@ -469,3 +489,3 @@ kind: best.kind,

else {
if (entry.branch.in.overlaps(discriminantNode)) {
if (entry.branch.rawIn.overlaps(discriminantNode)) {
// include cases where an object not including the

@@ -485,3 +505,3 @@ // discriminant path might have that value present as an undeclared key

};
const orderCandidates = (candidates, originalBranches) => {
const viableOrderedCandidates = (candidates, originalBranches) => {
const viableCandidates = candidates.filter(candidate => {

@@ -647,3 +667,3 @@ const caseGroups = Object.values(candidate.cases).map(caseCtx => caseCtx.branchIndices);

}
const intersection = intersectNodesRoot(branches[i].in, branches[j].in, branches[0].$);
const intersection = intersectNodesRoot(branches[i].rawIn, branches[j].rawIn, branches[0].$);
if (intersection instanceof Disjoint)

@@ -653,7 +673,7 @@ continue;

assertDeterminateOverlap(branches[i], branches[j]);
if (intersection.equals(branches[i].in)) {
if (intersection.equals(branches[i].rawIn)) {
// preserve ordered branches that are a subtype of a subsequent branch
uniquenessByIndex[i] = !!ordered;
}
else if (intersection.equals(branches[j].in))
else if (intersection.equals(branches[j].rawIn))
uniquenessByIndex[j] = false;

@@ -660,0 +680,0 @@ }

import { type Key } from "@ark/util";
import type { nodeOfKind } from "../kinds.ts";
import type { BaseNode } from "../node.ts";
import type { BoundKind } from "../refinements/kinds.ts";
import type { Domain } from "../roots/domain.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { Prop } from "../structure/prop.ts";
import type { BoundKind } from "./implement.ts";
export interface DisjointEntry<kind extends DisjointKind = DisjointKind> {

@@ -9,0 +9,0 @@ kind: kind;

@@ -84,2 +84,6 @@ import { CastableBase, ReadonlyArray, ReadonlyPath, type JsonArray, type JsonObject, type array, type merge, type propwiseXor, type show } from "@ark/util";

/**
* @internal
*/
affectsPath(path: ReadonlyPath): boolean;
/**
* A human-readable summary of all errors.

@@ -94,3 +98,2 @@ */

toString(): string;
private _add;
private addAncestorPaths;

@@ -97,0 +100,0 @@ }

@@ -152,5 +152,35 @@ import { CastableBase, ReadonlyArray, ReadonlyPath, append, conflatenateAll, defineProperties, flatMorph, stringifyPath } from "@ark/util";

add(error) {
if (this.includes(error))
return;
this._add(error);
const existing = this.byPath[error.propString];
if (existing) {
if (error === existing)
return;
// If the existing error is an error for a value constrained to "never",
// then we don't want to intersect the error messages.
if (existing.hasCode("union") && existing.errors.length === 0)
return;
// If the new error is an error for a value constrained to "never",
// then we want to override any existing errors.
const errorIntersection = error.hasCode("union") && error.errors.length === 0 ?
error
: new ArkError({
code: "intersection",
errors: existing.hasCode("intersection") ?
[...existing.errors, error]
: [existing, error]
}, this.ctx);
const existingIndex = this.indexOf(existing);
this.mutable[existingIndex === -1 ? this.length : existingIndex] =
errorIntersection;
this.byPath[error.propString] = errorIntersection;
// add the original error here rather than the intersection
// since the intersection is reflected by the array of errors at
// this path
this.addAncestorPaths(error);
}
else {
this.byPath[error.propString] = error;
this.addAncestorPaths(error);
this.mutable.push(error);
}
this.count++;
}

@@ -169,5 +199,3 @@ transform(f) {

for (const e of errors) {
if (this.includes(e))
continue;
this._add(new ArkError({ ...e, path: [...this.ctx.path, ...e.path] }, this.ctx));
this.add(new ArkError({ ...e, path: [...this.ctx.path, ...e.path] }, this.ctx));
}

@@ -207,35 +235,2 @@ }

}
_add(error) {
const existing = this.byPath[error.propString];
if (existing) {
// If the existing error is an error for a value constrained to "never",
// then we don't want to intersect the error messages.
if (existing.hasCode("union") && existing.errors.length === 0)
return;
// If the new error is an error for a value constrained to "never",
// then we want to override any existing errors.
const errorIntersection = error.hasCode("union") && error.errors.length === 0 ?
error
: new ArkError({
code: "intersection",
errors: existing.hasCode("intersection") ?
[...existing.errors, error]
: [existing, error]
}, this.ctx);
const existingIndex = this.indexOf(existing);
this.mutable[existingIndex === -1 ? this.length : existingIndex] =
errorIntersection;
this.byPath[error.propString] = errorIntersection;
// add the original error here rather than the intersection
// since the intersection is reflected by the array of errors at
// this path
this.addAncestorPaths(error);
}
else {
this.byPath[error.propString] = error;
this.addAncestorPaths(error);
this.mutable.push(error);
}
this.count++;
}
addAncestorPaths(error) {

@@ -242,0 +237,0 @@ for (const propString of error.path.stringifyAncestors()) {

@@ -16,13 +16,7 @@ import { type Entry, type Json, type JsonStructure, type KeySet, type arrayIndexOf, type keySetOf, type listable, type requireKeys, type show } from "@ark/util";

export type StructuralKind = (typeof structuralKinds)[number];
export type RangeKind = Exclude<BoundKind, "exactLength">;
export type BoundKind = Exclude<RefinementKind, "pattern" | "divisor">;
export declare const refinementKinds: readonly ["pattern", "divisor", "exactLength", "max", "min", "maxLength", "minLength", "before", "after"];
export declare const prestructuralKinds: readonly ["pattern", "divisor", "exactLength", "max", "min", "maxLength", "minLength", "before", "after"];
export type PrestructuralKind = (typeof prestructuralKinds)[number];
export declare const refinementKinds: readonly ["pattern", "divisor", "exactLength", "max", "min", "maxLength", "minLength", "before", "after", "structure", "predicate"];
export type RefinementKind = (typeof refinementKinds)[number];
type orderedConstraintKinds = [
...typeof refinementKinds,
...typeof structuralKinds,
"structure",
"predicate"
];
export declare const constraintKinds: orderedConstraintKinds;
export declare const constraintKinds: readonly ["pattern", "divisor", "exactLength", "max", "min", "maxLength", "minLength", "before", "after", "structure", "predicate", "required", "optional", "index", "sequence"];
export type ConstraintKind = (typeof constraintKinds)[number];

@@ -38,3 +32,3 @@ export declare const rootKinds: readonly ["alias", "union", "morph", "unit", "intersection", "proto", "domain"];

export type ClosedNodeKind = Exclude<NodeKind, OpenNodeKind>;
export type PrimitiveKind = RefinementKind | BasisKind | "predicate";
export type PrimitiveKind = Exclude<RefinementKind | BasisKind, "structure">;
export type CompositeKind = Exclude<NodeKind, PrimitiveKind>;

@@ -41,0 +35,0 @@ export type OrderedNodeKinds = typeof nodeKinds;

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

];
export const refinementKinds = [
export const prestructuralKinds = [
"pattern",

@@ -23,8 +23,8 @@ "divisor",

];
export const constraintKinds = [
...refinementKinds,
...structuralKinds,
export const refinementKinds = [
...prestructuralKinds,
"structure",
"predicate"
];
export const constraintKinds = [...refinementKinds, ...structuralKinds];
export const rootKinds = [

@@ -31,0 +31,0 @@ "alias",

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

if (viableBranches.length < from.branches.length ||
!from.branches.every((branch, i) => branch.in.equals(viableBranches[i].in)))
!from.branches.every((branch, i) => branch.rawIn.equals(viableBranches[i].rawIn)))
return ctx.$.parseSchema(viableBranches);

@@ -92,3 +92,3 @@ // otherwise, the input has not changed so preserve metadata

...onlyBranch.inner,
in: onlyBranch.in.configure(meta, "self")
in: onlyBranch.rawIn.configure(meta, "self")
});

@@ -122,3 +122,3 @@ }

if (to.hasKind("morph")) {
const inTersection = intersectOrPipeNodes(from, to.in, ctx);
const inTersection = intersectOrPipeNodes(from, to.rawIn, ctx);
if (inTersection instanceof Disjoint)

@@ -125,0 +125,0 @@ return inTersection;

import { ReadonlyPath, type array } from "@ark/util";
import type { ResolvedConfig } from "../config.ts";
import type { Morph } from "../roots/morph.ts";
import { ArkError, ArkErrors, type ArkErrorCode, type ArkErrorInput } from "./errors.ts";
import { ArkError, ArkErrors, type ArkErrorCode, type ArkErrorInput, type NodeErrorContextInput } from "./errors.ts";
export type MorphsAtPath = {

@@ -94,2 +94,13 @@ path: ReadonlyPath;

popBranch(): BranchTraversal | undefined;
/**
* @internal
* Convenience for casting from InternalTraversal to Traversal
* for cases where the extra methods on the external type are expected, e.g.
* a morph or predicate.
*/
get external(): this;
/**
* @internal
*/
errorFromNodeContext<input extends NodeErrorContextInput>(input: input): ArkError<input["code"]>;
private errorFromContext;

@@ -103,5 +114,6 @@ private applyQueuedMorphs;

Apply: TraverseApply<input>;
Optimistic: TraverseApply<input>;
};
export type TraversalKind = keyof TraversalMethodsByKind;
export type TraversalKind = keyof TraversalMethodsByKind & {};
export type TraverseAllows<data = unknown> = (data: data, ctx: InternalTraversal) => boolean;
export type TraverseApply<data = unknown> = (data: data, ctx: InternalTraversal) => void;

@@ -180,6 +180,7 @@ import { ReadonlyPath, stringifyPath } from "@ark/util";

for (const morph of morphs) {
// applyMorphsAtPath may be called recursively, so we need to reset the path here
// ensure morphs are applied relative to the correct path
// in case previous operations modified this.path
this.path = [...path];
const morphIsNode = isNode(morph);
const result = morph(parent === undefined ? this.root : parent[key], this);
const result = morph((parent === undefined ? this.root : parent[key]), this);
if (result instanceof ArkError) {

@@ -199,2 +200,3 @@ // if an ArkError was returned, ensure it has been added to errors

// skip any remaining morphs at the current path
this.queuedMorphs = [];
break;

@@ -201,0 +203,0 @@ }

@@ -26,2 +26,3 @@ import { type requireKeys } from "@ark/util";

constructor(...args: ConstructorParameters<typeof BaseProp>);
get rawIn(): OptionalNode;
get outProp(): Prop.Node;

@@ -46,5 +47,5 @@ expression: string;

};
export declare const computeDefaultValueMorph: (key: PropertyKey, value: BaseRoot, defaultInput: unknown) => Morph;
export declare const computeDefaultValueMorph: (key: PropertyKey, value: BaseRoot, defaultInput: unknown) => Morph<any>;
export declare const assertDefaultValueAssignability: (node: BaseRoot, value: unknown, key: PropertyKey | null) => unknown;
export type writeUnassignableDefaultValueMessage<baseDef extends string, defaultValue extends string> = `Default value ${defaultValue} must be assignable to ${baseDef}`;
export declare const writeNonPrimitiveNonFunctionDefaultValueMessage: (key: PropertyKey | null) => string;

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

import { hasDomain, isThunk, printable, throwParseError } from "@ark/util";
import { hasDomain, isThunk, omit, printable, throwParseError } from "@ark/util";
import { intrinsic } from "../intrinsic.js";

@@ -44,2 +44,10 @@ import { compileSerializedValue } from "../shared/compile.js";

}
get rawIn() {
const baseIn = super.rawIn;
if (!this.hasDefault())
return baseIn;
return this.$.node("optional", omit(baseIn.inner, { default: true }), {
prereduced: true
});
}
get outProp() {

@@ -99,2 +107,5 @@ if (!this.hasDefault())

throwParseError(writeNonPrimitiveNonFunctionDefaultValueMessage(key));
// if the node has a default value, finalize it and apply JIT optimizations
// if applicable to ensure behavior + error logging is externally consistent
// (using .in here insead of .rawIn triggers finalization)
const out = node.in(wrapped ? value() : value);

@@ -101,0 +112,0 @@ if (out instanceof ArkErrors) {

@@ -48,3 +48,11 @@ import { append, conflatenate, printable, throwInternalError, throwParseError } from "@ark/util";

defaultValueSerializer(element[1])
])
]),
reduceIo: (ioKind, inner, defaultables) => {
if (ioKind === "in") {
inner.optionals = defaultables.map(d => d[0].rawIn);
return;
}
inner.prefix = defaultables.map(d => d[0].rawOut);
return;
}
},

@@ -271,3 +279,3 @@ variadic: {

const dataIndex = `${i + this.prefixLength}`;
js.if(`${dataIndex} >= ${js.data}.length`, () => js.traversalKind === "Allows" ? js.return(true) : js.return());
js.if(`${dataIndex} >= data.length`, () => js.traversalKind === "Allows" ? js.return(true) : js.return());
js.traverseKey(dataIndex, `data[${dataIndex}]`, node);

@@ -277,3 +285,3 @@ }

if (this.postfix) {
js.const("firstPostfixIndex", `${js.data}.length${this.postfix ? `- ${this.postfix.length}` : ""}`);
js.const("firstPostfixIndex", `data.length${this.postfix ? `- ${this.postfix.length}` : ""}`);
}

@@ -444,3 +452,7 @@ js.for(`i < ${this.postfix ? "firstPostfixIndex" : "data.length"}`, () => js.traverseKey("i", "data[i]", this.variadic), this.prevariadic.length);

// but not trivial to serialize postfix elements as keys
kind === "prefix" ? s.result.length : `-${lTail.length + 1}`, "required"));
kind === "prefix" ? s.result.length : `-${lTail.length + 1}`,
// both operands must be required for the disjoint to be considered required
elementIsRequired(lHead) && elementIsRequired(rHead) ?
"required"
: "optional"));
s.result = [...s.result, { kind, node: $ark.intrinsic.never.internal }];

@@ -499,1 +511,2 @@ }

};
const elementIsRequired = (el) => el.kind === "prefix" || el.kind === "postfix";

@@ -63,3 +63,3 @@ import { append, conflatenate, flatMorph, printable, spliterate, throwInternalError, throwParseError } from "@ark/util";

// ensure we don't overwrite nodes added by optional
inner.required = append(inner.required, nodes.map(node => node[ioKind]));
inner.required = append(inner.required, nodes.map(node => (ioKind === "in" ? node.rawIn : node.rawOut)));
return;

@@ -73,7 +73,7 @@ }

if (ioKind === "in") {
inner.optional = nodes.map(node => node.in);
inner.optional = nodes.map(node => node.rawIn);
return;
}
for (const node of nodes) {
inner[node.outProp.kind] = append(inner[node.outProp.kind], node.outProp.out);
inner[node.outProp.kind] = append(inner[node.outProp.kind], node.outProp.rawOut);
}

@@ -93,4 +93,6 @@ }

reduceIo: (ioKind, inner, value) => {
if (value !== "delete")
if (value === "reject") {
inner.undeclared = "reject";
return;
}
// if base is "delete", undeclared keys are "ignore" (i.e. unconstrained)

@@ -593,4 +595,4 @@ // on input and "reject" on output

code: "morph",
base: keyBranch.in.toJsonSchemaRecurse(ctx),
out: keyBranch.out.toJsonSchemaRecurse(ctx)
base: keyBranch.rawIn.toJsonSchemaRecurse(ctx),
out: keyBranch.rawOut.toJsonSchemaRecurse(ctx)
});

@@ -597,0 +599,0 @@ }

{
"name": "@ark/schema",
"version": "0.49.0",
"version": "0.50.0",
"license": "MIT",

@@ -32,3 +32,3 @@ "author": {

"dependencies": {
"@ark/util": "0.49.0"
"@ark/util": "0.50.0"
},

@@ -35,0 +35,0 @@ "publishConfig": {