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.15.0 to 0.16.0

6

out/constraint.js

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

import { compileErrorContext, constraintKeys } from "./shared/implement.js";
import { intersectNodes, intersectNodesRoot } from "./shared/intersections.js";
import { intersectNodesRoot, intersectOrPipeNodes } from "./shared/intersections.js";
import { $ark } from "./shared/registry.js";

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

return result;
result = intersectNodes(root, result, s.ctx);
result = intersectOrPipeNodes(root, result, s.ctx);
}

@@ -74,3 +74,3 @@ return result;

for (let i = 0; i < s.l.length; i++) {
const result = intersectNodes(s.l[i], head, s.ctx);
const result = intersectOrPipeNodes(s.l[i], head, s.ctx);
if (result === null)

@@ -77,0 +77,0 @@ continue;

@@ -27,8 +27,5 @@ import { Callable, appendUnique, flatMorph, includes, isArray, isEmptyObject, throwError } from "@ark/util";

withMeta(meta) {
const newMeta = typeof meta === "function" ?
meta({ ...this.meta })
: { ...this.meta, ...meta };
return this.$.node(this.kind, {
...this.inner,
meta: newMeta
meta: typeof meta === "function" ? meta({ ...this.meta }) : meta
});

@@ -35,0 +32,0 @@ }

@@ -5,3 +5,3 @@ import { append, domainDescriptions, printable, throwInternalError, throwParseError } from "@ark/util";

import { implementNode } from "../shared/implement.js";
import { intersectNodes } from "../shared/intersections.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { writeCyclicJsonSchemaMessage } from "../shared/jsonSchema.js";

@@ -29,3 +29,3 @@ import { $ark } from "../shared/registry.js";

intersections: {
alias: (l, r, ctx) => ctx.$.lazilyResolve(() => neverIfDisjoint(intersectNodes(l.resolution, r.resolution, ctx)), `${l.reference}${ctx.pipe ? "=>" : "&"}${r.reference}`),
alias: (l, r, ctx) => ctx.$.lazilyResolve(() => neverIfDisjoint(intersectOrPipeNodes(l.resolution, r.resolution, ctx)), `${l.reference}${ctx.pipe ? "=>" : "&"}${r.reference}`),
...defineRightwardIntersections("alias", (l, r, ctx) => {

@@ -36,3 +36,3 @@ if (r.isUnknown())

return r;
return ctx.$.lazilyResolve(() => neverIfDisjoint(intersectNodes(l.resolution, r, ctx)), `${l.reference}${ctx.pipe ? "=>" : "&"}${r.id}`);
return ctx.$.lazilyResolve(() => neverIfDisjoint(intersectOrPipeNodes(l.resolution, r, ctx)), `${l.reference}${ctx.pipe ? "=>" : "&"}${r.id}`);
})

@@ -39,0 +39,0 @@ }

@@ -5,3 +5,3 @@ import { flatMorph, hasDomain, isEmptyObject, isKeyOf, throwParseError } from "@ark/util";

import { implementNode, structureKeys } from "../shared/implement.js";
import { intersectNodes } from "../shared/intersections.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { hasArkKind, isNode } from "../shared/utils.js";

@@ -123,3 +123,3 @@ import { BaseRoot } from "./root.js";

return r;
const basis = l.basis ? intersectNodes(l.basis, r, ctx) : r;
const basis = l.basis ? intersectOrPipeNodes(l.basis, r, ctx) : r;
return (basis instanceof Disjoint ? basis

@@ -241,3 +241,3 @@ : l?.basis?.equals(basis) ?

rBasis ?
intersectNodes(lBasis, rBasis, ctx)
intersectOrPipeNodes(lBasis, rBasis, ctx)
: lBasis

@@ -244,0 +244,0 @@ : rBasis;

import { arrayEquals, liftArray, throwParseError } from "@ark/util";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { intersectNodes } from "../shared/intersections.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { writeJsonSchemaMorphMessage } from "../shared/jsonSchema.js";

@@ -40,3 +40,3 @@ import { $ark, registeredReference } from "../shared/registry.js";

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

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

if (l.declaredIn || r.declaredIn) {
const declaredIn = intersectNodes(l.in, r.in, ctx);
const declaredIn = intersectOrPipeNodes(l.in, r.in, 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 = intersectNodes(l.out, r.out, ctx);
const declaredOut = intersectOrPipeNodes(l.out, r.out, ctx);
if (declaredOut instanceof Disjoint)

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

...defineRightwardIntersections("morph", (l, r, ctx) => {
const inTersection = intersectNodes(l.in, r, ctx);
const inTersection = intersectOrPipeNodes(l.in, r, ctx);
return inTersection instanceof Disjoint ? inTersection : (inTersection.distribute(branch => ({

@@ -76,0 +76,0 @@ ...l.inner,

@@ -6,2 +6,3 @@ import { builtinConstructors, constructorExtends, getBuiltinNameOfConstructor, objectKindDescriptions, objectKindOrDomainOf, throwParseError } from "@ark/util";

import { $ark } from "../shared/registry.js";
import { isNode } from "../shared/utils.js";
import { InternalBasis } from "./basis.js";

@@ -18,3 +19,5 @@ const implementation = implementNode({

normalize: schema => typeof schema === "string" ? { proto: builtinConstructors[schema] }
: typeof schema === "function" ? { proto: schema }
: typeof schema === "function" ?
isNode(schema) ? schema
: { proto: schema }
: typeof schema.proto === "string" ?

@@ -21,0 +24,0 @@ { ...schema, proto: builtinConstructors[schema.proto] }

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

get defaultMeta(): unknown;
withoutOptionalOrDefaultMeta(): this;
as(): this;

@@ -36,0 +37,0 @@ brand(name: string): this;

@@ -34,2 +34,17 @@ import { includes, inferred, omit, throwInternalError, throwParseError, unset } from "@ark/util";

}
withoutOptionalOrDefaultMeta() {
if (!this.optionalMeta && this.defaultMeta === unset)
return this;
const meta = { ...this.meta };
delete meta.default;
delete meta.optional;
if (!this.hasKind("morph") ||
(!this.in.optionalMeta && this.in.defaultMeta === unset))
return this.withMeta(meta);
return this.$.node("morph", {
...this.inner,
in: this.in.withoutOptionalOrDefaultMeta(),
meta
});
}
as() {

@@ -36,0 +51,0 @@ return this;

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

import { implementNode } from "../shared/implement.js";
import { intersectNodes, intersectNodesRoot } from "../shared/intersections.js";
import { intersectNodesRoot, intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark, registeredReference } from "../shared/registry.js";

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

}
const branchIntersection = intersectNodes(l[lIndex], r[rIndex], ctx);
const branchIntersection = intersectOrPipeNodes(l[lIndex], r[rIndex], ctx);
if (branchIntersection instanceof Disjoint) {

@@ -397,0 +397,0 @@ // Doesn't tell us anything useful about their relationships

@@ -30,2 +30,3 @@ import { CastableBase, ReadonlyArray, type propwiseXor, type show } from "@ark/util";

add(error: ArkError): void;
private _add;
merge(errors: ArkErrors): void;

@@ -32,0 +33,0 @@ get summary(): string;

@@ -59,2 +59,7 @@ import { CastableBase, ReadonlyArray, defineProperties } from "@ark/util";

add(error) {
if (this.includes(error))
return;
this._add(error);
}
_add(error) {
const existing = this.byPath[error.propString];

@@ -83,3 +88,7 @@ if (existing) {

merge(errors) {
errors.forEach(e => this.add(new ArkError({ ...e, path: [...e.path, ...this.ctx.path] }, this.ctx)));
errors.forEach(e => {
if (this.includes(e))
return;
this._add(new ArkError({ ...e, path: [...e.path, ...this.ctx.path] }, this.ctx));
});
}

@@ -86,0 +95,0 @@ get summary() {

@@ -9,3 +9,3 @@ import type { BaseNode } from "../node.ts";

export declare const pipeNodesRoot: InternalNodeIntersection<BaseScope>;
export declare const intersectNodes: InternalNodeIntersection<IntersectionContext>;
export declare const intersectOrPipeNodes: InternalNodeIntersection<IntersectionContext>;
export {};

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

const intersectionCache = {};
export const intersectNodesRoot = (l, r, $) => intersectNodes(l, r, {
export const intersectNodesRoot = (l, r, $) => intersectOrPipeNodes(l, r, {
$,

@@ -11,3 +11,3 @@ invert: false,

});
export const pipeNodesRoot = (l, r, $) => intersectNodes(l, r, {
export const pipeNodesRoot = (l, r, $) => intersectOrPipeNodes(l, r, {
$,

@@ -17,3 +17,3 @@ invert: false,

});
export const intersectNodes = (l, r, ctx) => {
export const intersectOrPipeNodes = ((l, r, ctx) => {
const operator = ctx.pipe ? "|>" : "&";

@@ -36,7 +36,18 @@ const lrCacheKey = `${l.hash}${operator}${r.hash}`;

}
if (l.equals(r))
const isPureIntersection = !ctx.pipe || (!l.includesMorph && !r.includesMorph);
if (isPureIntersection && l.equals(r))
return l;
let result = ctx.pipe && l.hasKindIn(...rootKinds) && r.hasKindIn(...rootKinds) ?
_pipeNodes(l, r, ctx)
: _intersectNodes(l, r, ctx);
let result;
if (isPureIntersection) {
if (l.equals(r))
return l;
result = _intersectNodes(l, r, ctx);
}
else {
result =
l.hasKindIn(...rootKinds) ?
// if l is a RootNode, r will be as well
_pipeNodes(l, r, ctx)
: _intersectNodes(l, r, ctx);
}
if (isNode(result)) {

@@ -52,3 +63,3 @@ // if the result equals one of the operands, preserve its metadata by

return result;
};
});
const _intersectNodes = (l, r, ctx) => {

@@ -72,11 +83,7 @@ const leftmostKind = l.precedence < r.precedence ? l.kind : r.kind;

};
const _pipeNodes = (l, r, ctx) => l.includesMorph ?
const _pipeNodes = (l, r, ctx) => l.includesMorph || r.includesMorph ?
ctx.invert ?
pipeMorphed(r, l, ctx)
: pipeMorphed(l, r, ctx)
: r.includesMorph ?
ctx.invert ?
pipeMorphed(r, l, ctx)
: pipeMorphed(l, r, ctx)
: _intersectNodes(l, r, ctx);
: _intersectNodes(l, r, ctx);
const pipeMorphed = (from, to, ctx) => from.distribute(fromBranch => _pipeMorphed(fromBranch, to, ctx), results => {

@@ -86,5 +93,7 @@ const viableBranches = results.filter(isNode);

return Disjoint.init("union", from.branches, to.branches);
// if the input type has changed, create a new node without preserving metadata
if (viableBranches.length < from.branches.length ||
!from.branches.every((branch, i) => branch.in.equals(viableBranches[i].in)))
return ctx.$.parseSchema(viableBranches);
// otherwise, the input has not changed so preserve metadata
let meta;

@@ -117,3 +126,3 @@ if ("default" in from.meta)

// still piped from context, so allows appending additional morphs
const outIntersection = intersectNodes(from.lastMorphIfNode, to, ctx);
const outIntersection = intersectOrPipeNodes(from.lastMorphIfNode, to, ctx);
if (outIntersection instanceof Disjoint)

@@ -131,3 +140,3 @@ return outIntersection;

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

@@ -134,0 +143,0 @@ return inTersection;

@@ -28,4 +28,7 @@ import type { array } from "@ark/util";

finalize(): unknown;
private applyQueuedMorphs;
private applyMorphsAtPath;
get currentErrorCount(): number;
hasError(): boolean;
pathHasError(path: TraversalPath): boolean;
get failFast(): boolean;

@@ -32,0 +35,0 @@ error<input extends ArkErrorInput>(input: input): ArkError<input extends {

import { ArkError, ArkErrors } from "./errors.js";
import { pathToPropString } from "./utils.js";
import { isNode, pathToPropString } from "./utils.js";
export class TraversalContext {

@@ -35,2 +35,6 @@ path = [];

this.root = this.config.clone(this.root);
this.applyQueuedMorphs();
return this.hasError() ? this.errors : this.root;
}
applyQueuedMorphs() {
// invoking morphs that are Nodes will reuse this context, potentially

@@ -40,40 +44,52 @@ // adding additional morphs, so we have to continue looping until

while (this.queuedMorphs.length) {
const { path, morphs } = this.queuedMorphs.shift();
// even if we already have an error, apply morphs that are not at a path
// with errors to capture potential validation errors
if (this.hasError()) {
const morphPropString = pathToPropString(path);
if (this.errors.some(e => morphPropString.startsWith(e.propString)))
const queuedMorphs = this.queuedMorphs;
this.queuedMorphs = [];
for (const { path, morphs } of queuedMorphs) {
// even if we already have an error, apply morphs that are not at a path
// with errors to capture potential validation errors
if (this.pathHasError(path))
continue;
this.applyMorphsAtPath(path, morphs);
}
const key = path.at(-1);
let parent;
if (key !== undefined) {
// find the object on which the key to be morphed exists
parent = this.root;
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++)
parent = parent[path[pathIndex]];
}
}
applyMorphsAtPath(path, morphs) {
const key = path.at(-1);
let parent;
if (key !== undefined) {
// find the object on which the key to be morphed exists
parent = this.root;
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++)
parent = parent[path[pathIndex]];
}
this.path = path;
for (const morph of morphs) {
const morphIsNode = isNode(morph);
const result = morph(parent === undefined ? this.root : parent[key], this);
if (result instanceof ArkError) {
// if an ArkError was returned, ensure it has been added to errors
this.errors.add(result);
// skip any remaining morphs at the current path
break;
}
this.path = path;
for (const morph of morphs) {
const result = morph(parent === undefined ? this.root : parent[key], this);
if (result instanceof ArkError) {
// if an ArkError was returned but wasn't added to these
// errors, add it
if (!this.errors.includes(result))
this.error(result);
if (result instanceof ArkErrors) {
// if the morph was a direct reference to another node,
// errors will have been added directly via this piped context
if (!morphIsNode) {
// otherwise, we have to ensure each error has been added
this.errors.merge(result);
}
else if (!(result instanceof ArkErrors)) {
// if the morph was successful, assign the result to the
// corresponding property, or to root if path is empty
if (parent === undefined)
this.root = result;
else
parent[key] = result;
}
// if ArkErrors was returned, the morph itself was likely a type
// and the errors will have been added directly via this piped context
// skip any remaining morphs at the current path
break;
}
// if the morph was successful, assign the result to the
// corresponding property, or to root if path is empty
if (parent === undefined)
this.root = result;
else
parent[key] = result;
// if the current morph queued additional morphs,
// applying them before subsequent morphs
this.applyQueuedMorphs();
}
return this.hasError() ? this.errors : this.root;
}

@@ -90,2 +106,8 @@ get currentErrorCount() {

}
pathHasError(path) {
if (!this.hasError())
return false;
const propString = pathToPropString(path);
return this.errors.some(e => propString.startsWith(e.propString));
}
get failFast() {

@@ -92,0 +114,0 @@ return this.branches.length !== 0;

@@ -6,3 +6,3 @@ import { append, printable, stringAndSymbolicEntriesOf, throwParseError } from "@ark/util";

import { implementNode } from "../shared/implement.js";
import { intersectNodes } from "../shared/intersections.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark } from "../shared/registry.js";

@@ -40,3 +40,3 @@ const implementation = implementNode({

if (l.signature.equals(r.signature)) {
const valueIntersection = intersectNodes(l.value, r.value, ctx);
const valueIntersection = intersectOrPipeNodes(l.value, r.value, ctx);
const value = valueIntersection instanceof Disjoint ?

@@ -43,0 +43,0 @@ $ark.intrinsic.never.internal

@@ -6,3 +6,3 @@ import { append, printable, throwParseError, unset } from "@ark/util";

import { Disjoint } from "../shared/disjoint.js";
import { intersectNodes } from "../shared/intersections.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark } from "../shared/registry.js";

@@ -13,3 +13,3 @@ export const intersectProps = (l, r, ctx) => {

const key = l.key;
let value = intersectNodes(l.value, r.value, ctx);
let value = intersectOrPipeNodes(l.value, r.value, ctx);
const kind = l.required || r.required ? "required" : "optional";

@@ -16,0 +16,0 @@ if (value instanceof Disjoint) {

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

import { implementNode } from "../shared/implement.js";
import { intersectNodes } from "../shared/intersections.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { writeUnsupportedJsonSchemaTypeMessage } from "../shared/jsonSchema.js";

@@ -323,3 +323,3 @@ import { $ark } from "../shared/registry.js";

}
const result = intersectNodes(lHead.node, rHead.node, s.ctx);
const result = intersectOrPipeNodes(lHead.node, rHead.node, s.ctx);
if (result instanceof Disjoint) {

@@ -326,0 +326,0 @@ if (kind === "prefix" || kind === "postfix") {

@@ -277,6 +277,12 @@ import { append, conflatenate, flatMorph, printable, spliterate, throwParseError } from "@ark/util";

...inner,
required: this.props.map(prop => prop.hasKind("optional") ?
// don't include keys like default that don't exist on required
this.$.node("required", { key: prop.key, value: prop.value })
: prop)
required: this.props.map(prop => {
if (prop.hasKind("required"))
return prop;
// strip default/optional meta from the value so that it
// isn't reduced back to an optional prop
return this.$.node("required", {
key: prop.key,
value: prop.value.withoutOptionalOrDefaultMeta()
});
})
});

@@ -283,0 +289,0 @@ }

{
"name": "@arktype/schema",
"version": "0.15.0",
"version": "0.16.0",
"license": "MIT",

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

"dependencies": {
"@ark/util": "0.15.0"
"@ark/util": "0.16.0"
},

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

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