feat: Reinitialize frontend with SvelteKit and TypeScript

- Delete old Vite+Svelte frontend
- Initialize new SvelteKit project with TypeScript
- Configure Tailwind CSS v4 + DaisyUI
- Implement JWT authentication with auto-refresh
- Create login page with form validation (Zod)
- Add protected route guards
- Update Docker configuration for single-stage build
- Add E2E tests with Playwright (6/11 passing)
- Fix Svelte 5 reactivity with $state() runes

Known issues:
- 5 E2E tests failing (timing/async issues)
- Token refresh implementation needs debugging
- Validation error display timing
This commit is contained in:
2026-02-17 16:19:59 -05:00
parent 54df6018f5
commit de2d83092e
28274 changed files with 3816354 additions and 90 deletions

58
frontend/node_modules/@ark/schema/out/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
import type { ArkRegistry, requireKeys, show } from "@ark/util";
import type { intrinsic } from "./intrinsic.ts";
import type { nodesByRegisteredId } from "./parse.ts";
import type { TypeMeta } from "./shared/declare.ts";
import type { ActualConfig, ArkErrorCode, ArkErrors, ExpectedConfig, MessageConfig, ProblemConfig } from "./shared/errors.ts";
import { type DescriptionWriter, type NodeKind } from "./shared/implement.ts";
import { ToJsonSchema } from "./shared/toJsonSchema.ts";
import type { UndeclaredKeyBehavior } from "./structure/structure.ts";
export interface ArkSchemaRegistry extends ArkRegistry {
intrinsic: typeof intrinsic;
config: ArkSchemaConfig;
defaultConfig: ResolvedConfig;
resolvedConfig: ResolvedConfig;
nodesByRegisteredId: typeof nodesByRegisteredId;
}
type nodeConfigForKind<kind extends NodeKind> = Readonly<show<{
description?: DescriptionWriter<kind>;
} & (kind extends ArkErrorCode ? {
expected?: ExpectedConfig<kind>;
actual?: ActualConfig<kind>;
problem?: ProblemConfig<kind>;
message?: MessageConfig<kind>;
} : {})>>;
type NodeConfigsByKind = {
[kind in NodeKind]: nodeConfigForKind<kind>;
};
export type NodeConfig<kind extends NodeKind = NodeKind> = NodeConfigsByKind[kind];
export interface UnknownErrorConfigs {
expected?: ExpectedConfig;
actual?: ActualConfig;
problem?: ProblemConfig;
message?: MessageConfig;
}
interface UnknownNodeConfig extends UnknownErrorConfigs {
description?: DescriptionWriter;
}
export type ResolvedUnknownNodeConfig = requireKeys<UnknownNodeConfig, "description">;
export declare const configureSchema: (config: ArkSchemaConfig) => ArkSchemaConfig;
export declare const mergeConfigs: <base extends ArkSchemaConfig>(base: base, merged: ArkSchemaConfig | undefined) => base;
type MergeToJsonSchemaConfigs = <base extends ToJsonSchema.Options | undefined>(baseConfig: base, mergedConfig: ToJsonSchema.Options | undefined) => base extends ToJsonSchema.Context ? ToJsonSchema.Context : ToJsonSchema.Options;
export declare const mergeToJsonSchemaConfigs: MergeToJsonSchemaConfigs;
export type CloneImplementation = <original extends object>(original: original) => original;
export interface ArkSchemaConfig extends Partial<Readonly<NodeConfigsByKind>> {
readonly jitless?: boolean;
readonly clone?: boolean | CloneImplementation;
readonly onUndeclaredKey?: UndeclaredKeyBehavior;
readonly numberAllowsNaN?: boolean;
readonly dateAllowsInvalid?: boolean;
readonly exactOptionalPropertyTypes?: boolean;
readonly onFail?: ArkErrors.Handler | null;
readonly keywords?: Record<string, TypeMeta.Collapsible | undefined>;
readonly toJsonSchema?: ToJsonSchema.Options;
}
export type resolveConfig<config extends ArkSchemaConfig> = show<{
[k in keyof ArkSchemaConfig]-?: k extends NodeKind ? Required<config[k]> : k extends "clone" ? CloneImplementation | false : k extends "keywords" ? Record<string, TypeMeta | undefined> : k extends "toJsonSchema" ? ToJsonSchema.Context : config[k];
} & Omit<config, keyof ArkSchemaConfig>>;
export type ResolvedConfig = resolveConfig<ArkSchemaConfig>;
export {};

95
frontend/node_modules/@ark/schema/out/config.js generated vendored Normal file
View File

@@ -0,0 +1,95 @@
import { isNodeKind } from "./shared/implement.js";
import { $ark } from "./shared/registry.js";
import { ToJsonSchema } from "./shared/toJsonSchema.js";
// $ark.config could already be set if it were imported previously from the
// dedicated config entrypoint, in which case we don't want to reinitialize it
$ark.config ??= {};
export const configureSchema = (config) => {
const result = Object.assign($ark.config, mergeConfigs($ark.config, config));
if ($ark.resolvedConfig)
$ark.resolvedConfig = mergeConfigs($ark.resolvedConfig, result);
return result;
};
export const mergeConfigs = (base, merged) => {
if (!merged)
return base;
const result = { ...base };
let k;
for (k in merged) {
const keywords = { ...base.keywords };
if (k === "keywords") {
for (const flatAlias in merged[k]) {
const v = merged.keywords[flatAlias];
if (v === undefined)
continue;
keywords[flatAlias] = typeof v === "string" ? { description: v } : v;
}
result.keywords = keywords;
}
else if (k === "toJsonSchema") {
result[k] = mergeToJsonSchemaConfigs(base.toJsonSchema, merged.toJsonSchema);
}
else if (isNodeKind(k)) {
result[k] =
// not casting this makes TS compute a very inefficient
// type that is not needed
{
...base[k],
...merged[k]
};
}
else
result[k] = merged[k];
}
return result;
};
const jsonSchemaTargetToDialect = {
"draft-2020-12": "https://json-schema.org/draft/2020-12/schema",
"draft-07": "http://json-schema.org/draft-07/schema#"
};
export const mergeToJsonSchemaConfigs = ((baseConfig, mergedConfig) => {
if (!baseConfig)
return resolveTargetToDialect(mergedConfig ?? {}, undefined);
if (!mergedConfig)
return baseConfig;
const result = { ...baseConfig };
let k;
for (k in mergedConfig) {
if (k === "fallback") {
result.fallback = mergeFallbacks(baseConfig.fallback, mergedConfig.fallback);
}
else
result[k] = mergedConfig[k];
}
return resolveTargetToDialect(result, mergedConfig);
});
const resolveTargetToDialect = (opts, userOpts) => {
// If user explicitly provided a dialect, use it
// Otherwise, if user provided a target, resolve it to dialect
// If neither, use the default dialect from opts
if (userOpts?.dialect !== undefined)
return opts; // dialect was already merged
if (userOpts?.target !== undefined) {
return {
...opts,
dialect: jsonSchemaTargetToDialect[userOpts.target]
};
}
return opts;
};
const mergeFallbacks = (base, merged) => {
base = normalizeFallback(base);
merged = normalizeFallback(merged);
const result = {};
let code;
for (code in ToJsonSchema.defaultConfig.fallback) {
result[code] =
merged[code] ??
merged.default ??
base[code] ??
base.default ??
ToJsonSchema.defaultConfig.fallback[code];
}
return result;
};
const normalizeFallback = (fallback) => typeof fallback === "function" ? { default: fallback } : (fallback ?? {});

67
frontend/node_modules/@ark/schema/out/constraint.d.ts generated vendored Normal file
View File

@@ -0,0 +1,67 @@
import { type array, type describe, type listable, type satisfy } from "@ark/util";
import type { NodeSchema, Prerequisite, innerAttachedAs, nodeOfKind } from "./kinds.ts";
import { BaseNode } from "./node.ts";
import type { NodeParseContext } from "./parse.ts";
import type { Intersection } from "./roots/intersection.ts";
import type { BaseRoot } from "./roots/root.ts";
import type { BaseScope } from "./scope.ts";
import type { NodeCompiler } from "./shared/compile.ts";
import type { BaseNodeDeclaration } from "./shared/declare.ts";
import { Disjoint } from "./shared/disjoint.ts";
import { type ConstraintKind, type IntersectionContext, type NodeKind, type RootKind, type StructuralKind, type UnknownAttachments, type kindLeftOf } from "./shared/implement.ts";
import type { JsonSchema } from "./shared/jsonSchema.ts";
import type { ToJsonSchema } from "./shared/toJsonSchema.ts";
import type { TraverseAllows, TraverseApply } from "./shared/traversal.ts";
import { arkKind } from "./shared/utils.ts";
import type { Structure } from "./structure/structure.ts";
export declare namespace Constraint {
interface Declaration extends BaseNodeDeclaration {
kind: ConstraintKind;
}
type ReductionResult = BaseRoot | Disjoint | Intersection.Inner.mutable;
interface Attachments {
impliedBasis: BaseRoot | null;
impliedSiblings?: array<BaseConstraint> | null;
}
type PrimitiveKind = Exclude<ConstraintKind, StructuralKind>;
}
export declare abstract class BaseConstraint<
/** @ts-ignore allow instantiation assignment to the base type */
out d extends Constraint.Declaration = Constraint.Declaration> extends BaseNode<d> {
readonly [arkKind]: "constraint";
constructor(attachments: UnknownAttachments, $: BaseScope);
abstract readonly impliedBasis: BaseRoot | null;
readonly impliedSiblings?: array<BaseConstraint>;
intersect<r extends BaseConstraint>(r: r): intersectConstraintKinds<d["kind"], r["kind"]>;
}
export declare abstract class InternalPrimitiveConstraint<d extends Constraint.Declaration> extends BaseConstraint<d> {
abstract traverseAllows: TraverseAllows<d["prerequisite"]>;
abstract readonly compiledCondition: string;
abstract readonly compiledNegation: string;
abstract reduceJsonSchema(base: JsonSchema.Constrainable, ctx: ToJsonSchema.Context): JsonSchema.Constrainable;
traverseApply: TraverseApply<d["prerequisite"]>;
compile(js: NodeCompiler): void;
get errorContext(): d["errorContext"];
get compiledErrorContext(): string;
}
export declare const constraintKeyParser: <kind extends ConstraintKind>(kind: kind) => (schema: listable<NodeSchema<kind>>, ctx: NodeParseContext) => innerAttachedAs<kind> | undefined;
type ConstraintGroupKind = satisfy<NodeKind, "intersection" | "structure">;
interface ConstraintIntersectionState<kind extends ConstraintGroupKind = ConstraintGroupKind> {
kind: kind;
baseInner: Record<string, unknown>;
l: BaseConstraint[];
r: BaseConstraint[];
roots: BaseRoot[];
ctx: IntersectionContext;
}
export declare const intersectConstraints: <kind extends ConstraintGroupKind>(s: ConstraintIntersectionState<kind>) => nodeOfKind<RootKind | Extract<kind, "structure">> | Disjoint;
export declare const flattenConstraints: (inner: object) => BaseConstraint[];
type FlatIntersectionInner = Intersection.Inner & Structure.Inner;
export declare const unflattenConstraints: (constraints: array<BaseConstraint>) => FlatIntersectionInner;
export type constraintKindLeftOf<kind extends ConstraintKind> = ConstraintKind & kindLeftOf<kind>;
export type constraintKindOrLeftOf<kind extends ConstraintKind> = kind | constraintKindLeftOf<kind>;
export type intersectConstraintKinds<l extends ConstraintKind, r extends ConstraintKind> = nodeOfKind<l | r | "unit" | "union"> | Disjoint | null;
export declare const throwInvalidOperandError: (...args: Parameters<typeof writeInvalidOperandMessage>) => never;
export declare const writeInvalidOperandMessage: <kind extends ConstraintKind, expected extends BaseRoot, actual extends BaseRoot>(kind: kind, expected: expected, actual: actual) => string;
export type writeInvalidOperandMessage<kind extends ConstraintKind, actual> = `${Capitalize<kind>} operand must be ${describe<Prerequisite<kind>>} (was ${describe<Exclude<actual, Prerequisite<kind>>>})`;
export {};

136
frontend/node_modules/@ark/schema/out/constraint.js generated vendored Normal file
View File

@@ -0,0 +1,136 @@
import { append, appendUnique, capitalize, isArray, throwInternalError, throwParseError } from "@ark/util";
import { BaseNode } from "./node.js";
import { Disjoint } from "./shared/disjoint.js";
import { compileObjectLiteral, constraintKeys } from "./shared/implement.js";
import { intersectNodesRoot, intersectOrPipeNodes } from "./shared/intersections.js";
import { $ark } from "./shared/registry.js";
import { arkKind } from "./shared/utils.js";
export class BaseConstraint extends BaseNode {
constructor(attachments, $) {
super(attachments, $);
// define as a getter to avoid it being enumerable/spreadable
Object.defineProperty(this, arkKind, {
value: "constraint",
enumerable: false
});
}
impliedSiblings;
intersect(r) {
return intersectNodesRoot(this, r, this.$);
}
}
export class InternalPrimitiveConstraint extends BaseConstraint {
traverseApply = (data, ctx) => {
if (!this.traverseAllows(data, ctx))
ctx.errorFromNodeContext(this.errorContext);
};
compile(js) {
if (js.traversalKind === "Allows")
js.return(this.compiledCondition);
else {
js.if(this.compiledNegation, () => js.line(`ctx.errorFromNodeContext(${this.compiledErrorContext})`));
}
}
get errorContext() {
return {
code: this.kind,
description: this.description,
meta: this.meta,
...this.inner
};
}
get compiledErrorContext() {
return compileObjectLiteral(this.errorContext);
}
}
export const constraintKeyParser = (kind) => (schema, ctx) => {
if (isArray(schema)) {
if (schema.length === 0) {
// Omit empty lists as input
return;
}
const nodes = schema.map(schema => ctx.$.node(kind, schema));
// predicate order must be preserved to ensure inputs are narrowed
// and checked in the correct order
if (kind === "predicate")
return nodes;
return nodes.sort((l, r) => (l.hash < r.hash ? -1 : 1));
}
const child = ctx.$.node(kind, schema);
return (child.hasOpenIntersection() ? [child] : child);
};
export const intersectConstraints = (s) => {
const head = s.r.shift();
if (!head) {
let result = s.l.length === 0 && s.kind === "structure" ?
$ark.intrinsic.unknown.internal
: s.ctx.$.node(s.kind, Object.assign(s.baseInner, unflattenConstraints(s.l)), { prereduced: true });
for (const root of s.roots) {
if (result instanceof Disjoint)
return result;
result = intersectOrPipeNodes(root, result, s.ctx);
}
return result;
}
let matched = false;
for (let i = 0; i < s.l.length; i++) {
const result = intersectOrPipeNodes(s.l[i], head, s.ctx);
if (result === null)
continue;
if (result instanceof Disjoint)
return result;
if (result.isRoot()) {
s.roots.push(result);
s.l.splice(i);
return intersectConstraints(s);
}
if (!matched) {
s.l[i] = result;
matched = true;
}
else if (!s.l.includes(result)) {
return throwInternalError(`Unexpectedly encountered multiple distinct intersection results for refinement ${head}`);
}
}
if (!matched)
s.l.push(head);
if (s.kind === "intersection") {
if (head.impliedSiblings)
for (const node of head.impliedSiblings)
appendUnique(s.r, node);
}
return intersectConstraints(s);
};
export const flattenConstraints = (inner) => {
const result = Object.entries(inner)
.flatMap(([k, v]) => k in constraintKeys ? v : [])
.sort((l, r) => l.precedence < r.precedence ? -1
: l.precedence > r.precedence ? 1
// preserve order for predicates
: l.kind === "predicate" && r.kind === "predicate" ? 0
: l.hash < r.hash ? -1
: 1);
return result;
};
export const unflattenConstraints = (constraints) => {
const inner = {};
for (const constraint of constraints) {
if (constraint.hasOpenIntersection()) {
inner[constraint.kind] = append(inner[constraint.kind], constraint);
}
else {
if (inner[constraint.kind]) {
return throwInternalError(`Unexpected intersection of closed refinements of kind ${constraint.kind}`);
}
inner[constraint.kind] = constraint;
}
}
return inner;
};
export const throwInvalidOperandError = (...args) => throwParseError(writeInvalidOperandMessage(...args));
export const writeInvalidOperandMessage = (kind, expected, actual) => {
const actualDescription = actual.hasKind("morph") ? "a morph"
: actual.isUnknown() ? "unknown"
: actual.exclude(expected).defaultShortDescription;
return `${capitalize(kind)} operand must be ${expected.description} (was ${actualDescription})`;
};

73
frontend/node_modules/@ark/schema/out/generic.d.ts generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import { Callable, type array, type Hkt, type JsonStructure } from "@ark/util";
import type { RootSchema } from "./kinds.ts";
import type { BaseNode } from "./node.ts";
import type { BaseRoot } from "./roots/root.ts";
import type { BaseScope } from "./scope.ts";
import { arkKind } from "./shared/utils.ts";
export type GenericParamAst<name extends string = string, constraint = unknown> = [name: name, constraint: constraint];
export type GenericParamDef<name extends string = string> = name | readonly [name, unknown];
export declare const parseGeneric: (paramDefs: array<GenericParamDef>, bodyDef: unknown, $: BaseScope) => GenericRoot;
export type genericParamNames<params extends array<GenericParamAst>> = {
[i in keyof params]: params[i][0];
};
export type genericParamConstraints<params extends array<GenericParamAst>> = {
[i in keyof params]: params[i][1];
};
export type GenericArgResolutions<params extends array<GenericParamAst> = array<GenericParamAst>> = {
[i in keyof params as params[i & `${number}`][0]]: BaseRoot;
};
export declare class LazyGenericBody<argResolutions = {}, returns = unknown> extends Callable<(args: argResolutions) => returns> {
}
export interface GenericAst<params extends array<GenericParamAst> = array<GenericParamAst>, bodyDef = unknown, $ = unknown, arg$ = $> {
[arkKind]: "generic";
paramsAst: params;
bodyDef: bodyDef;
$: $;
arg$: arg$;
names: genericParamNames<params>;
t: this;
}
export declare class GenericRoot<params extends array<GenericParamAst> = array<GenericParamAst>, bodyDef = unknown> extends Callable<(...args: {
[i in keyof params]: BaseRoot;
}) => BaseRoot> {
readonly [arkKind] = "generic";
readonly paramsAst: params;
readonly t: GenericAst<params, bodyDef, {}, {}>;
paramDefs: array<GenericParamDef>;
bodyDef: bodyDef;
$: BaseScope;
arg$: BaseScope;
baseInstantiation: BaseRoot;
hkt: Hkt.constructor | null;
description: string;
constructor(paramDefs: array<GenericParamDef>, bodyDef: bodyDef, $: BaseScope, arg$: BaseScope, hkt: Hkt.constructor | null);
defIsLazy(): this is GenericRoot<params, LazyGenericBody>;
protected cacheGetter<name extends keyof this>(name: name, value: this[name]): this[name];
get json(): JsonStructure;
get params(): {
[i in keyof params]: [params[i][0], BaseRoot];
};
get names(): genericParamNames<params>;
get constraints(): {
[i in keyof params]: BaseRoot;
};
get internal(): this;
get referencesById(): Record<string, BaseNode>;
get references(): BaseNode[];
}
export type genericParamSchemasToAst<schemas extends readonly GenericParamDef[]> = {
[i in keyof schemas]: schemas[i] extends GenericParamDef<infer name> ? [
name,
unknown
] : never;
};
export type genericHktToConstraints<hkt extends abstract new () => Hkt> = InstanceType<hkt>["constraints"];
export type GenericRootParser = <const paramsDef extends readonly GenericParamDef[]>(...params: paramsDef) => GenericRootBodyParser<genericParamSchemasToAst<paramsDef>>;
export type GenericRootBodyParser<params extends array<GenericParamAst>> = {
<const body>(body: RootSchema): GenericRoot<params, body>;
<hkt extends Hkt.constructor>(instantiateDef: LazyGenericBody<GenericArgResolutions<params>>, hkt: hkt): GenericRoot<{
[i in keyof params]: [params[i][0], genericHktToConstraints<hkt>[i]];
}, InstanceType<hkt>>;
};
export declare const writeUnsatisfiedParameterConstraintMessage: <name extends string, constraint extends string, arg extends string>(name: name, constraint: constraint, arg: arg) => writeUnsatisfiedParameterConstraintMessage<name, constraint, arg>;
export type writeUnsatisfiedParameterConstraintMessage<name extends string, constraint extends string, arg extends string> = `${name} must be assignable to ${constraint} (was ${arg})`;

76
frontend/node_modules/@ark/schema/out/generic.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import { Callable, flatMorph, snapshot, throwParseError } from "@ark/util";
import { $ark } from "./shared/registry.js";
import { arkKind } from "./shared/utils.js";
export const parseGeneric = (paramDefs, bodyDef, $) => new GenericRoot(paramDefs, bodyDef, $, $, null);
export class LazyGenericBody extends Callable {
}
export class GenericRoot extends Callable {
[arkKind] = "generic";
paramDefs;
bodyDef;
$;
arg$;
baseInstantiation;
hkt;
description;
constructor(paramDefs, bodyDef, $, arg$, hkt) {
super((...args) => {
const argNodes = flatMorph(this.names, (i, name) => {
const arg = this.arg$.parse(args[i]);
if (!arg.extends(this.constraints[i])) {
throwParseError(writeUnsatisfiedParameterConstraintMessage(name, this.constraints[i].expression, arg.expression));
}
return [name, arg];
});
if (this.defIsLazy()) {
const def = this.bodyDef(argNodes);
return this.$.parse(def);
}
return this.$.parse(bodyDef, { args: argNodes });
});
this.paramDefs = paramDefs;
this.bodyDef = bodyDef;
this.$ = $;
this.arg$ = arg$;
this.hkt = hkt;
this.description =
hkt ?
(new hkt().description ?? `a generic type for ${hkt.constructor.name}`)
: "a generic type";
this.baseInstantiation = this(...this.constraints);
}
defIsLazy() {
return this.bodyDef instanceof LazyGenericBody;
}
cacheGetter(name, value) {
Object.defineProperty(this, name, { value });
return value;
}
get json() {
return this.cacheGetter("json", {
params: this.params.map(param => param[1].isUnknown() ? param[0] : [param[0], param[1].json]),
body: snapshot(this.bodyDef)
});
}
get params() {
return this.cacheGetter("params", this.paramDefs.map(param => typeof param === "string" ?
[param, $ark.intrinsic.unknown]
: [param[0], this.$.parse(param[1])]));
}
get names() {
return this.cacheGetter("names", this.params.map(e => e[0]));
}
get constraints() {
return this.cacheGetter("constraints", this.params.map(e => e[1]));
}
get internal() {
return this;
}
get referencesById() {
return this.baseInstantiation.internal.referencesById;
}
get references() {
return this.baseInstantiation.internal.references;
}
}
export const writeUnsatisfiedParameterConstraintMessage = (name, constraint, arg) => `${name} must be assignable to ${constraint} (was ${arg})`;

47
frontend/node_modules/@ark/schema/out/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,47 @@
export * from "./config.ts";
export * from "./constraint.ts";
export * from "./generic.ts";
export * from "./intrinsic.ts";
export * from "./kinds.ts";
export * from "./module.ts";
export * from "./node.ts";
export * from "./parse.ts";
export * from "./predicate.ts";
export * from "./refinements/after.ts";
export * from "./refinements/before.ts";
export * from "./refinements/divisor.ts";
export * from "./refinements/exactLength.ts";
export * from "./refinements/kinds.ts";
export * from "./refinements/max.ts";
export * from "./refinements/maxLength.ts";
export * from "./refinements/min.ts";
export * from "./refinements/minLength.ts";
export * from "./refinements/pattern.ts";
export * from "./refinements/range.ts";
export * from "./roots/domain.ts";
export * from "./roots/intersection.ts";
export * from "./roots/morph.ts";
export * from "./roots/proto.ts";
export * from "./roots/root.ts";
export * from "./roots/union.ts";
export * from "./roots/unit.ts";
export * from "./scope.ts";
export * from "./shared/compile.ts";
export * from "./shared/declare.ts";
export * from "./shared/disjoint.ts";
export * from "./shared/errors.ts";
export * from "./shared/implement.ts";
export * from "./shared/intersections.ts";
export * from "./shared/jsonSchema.ts";
export * from "./shared/registry.ts";
export * from "./shared/standardSchema.ts";
export * from "./shared/toJsonSchema.ts";
export * from "./shared/traversal.ts";
export * from "./shared/utils.ts";
export * from "./structure/index.ts";
export * from "./structure/optional.ts";
export * from "./structure/prop.ts";
export * from "./structure/required.ts";
export * from "./structure/sequence.ts";
export * from "./structure/structure.ts";
export { ParseError } from "@ark/util";

47
frontend/node_modules/@ark/schema/out/index.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
export * from "./config.js";
export * from "./constraint.js";
export * from "./generic.js";
export * from "./intrinsic.js";
export * from "./kinds.js";
export * from "./module.js";
export * from "./node.js";
export * from "./parse.js";
export * from "./predicate.js";
export * from "./refinements/after.js";
export * from "./refinements/before.js";
export * from "./refinements/divisor.js";
export * from "./refinements/exactLength.js";
export * from "./refinements/kinds.js";
export * from "./refinements/max.js";
export * from "./refinements/maxLength.js";
export * from "./refinements/min.js";
export * from "./refinements/minLength.js";
export * from "./refinements/pattern.js";
export * from "./refinements/range.js";
export * from "./roots/domain.js";
export * from "./roots/intersection.js";
export * from "./roots/morph.js";
export * from "./roots/proto.js";
export * from "./roots/root.js";
export * from "./roots/union.js";
export * from "./roots/unit.js";
export * from "./scope.js";
export * from "./shared/compile.js";
export * from "./shared/declare.js";
export * from "./shared/disjoint.js";
export * from "./shared/errors.js";
export * from "./shared/implement.js";
export * from "./shared/intersections.js";
export * from "./shared/jsonSchema.js";
export * from "./shared/registry.js";
export * from "./shared/standardSchema.js";
export * from "./shared/toJsonSchema.js";
export * from "./shared/traversal.js";
export * from "./shared/utils.js";
export * from "./structure/index.js";
export * from "./structure/optional.js";
export * from "./structure/prop.js";
export * from "./structure/required.js";
export * from "./structure/sequence.js";
export * from "./structure/structure.js";
export { ParseError } from "@ark/util";

24
frontend/node_modules/@ark/schema/out/intrinsic.d.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
export declare const intrinsic: {
emptyStructure: import("./index.ts").StructureNode;
jsonPrimitive: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
jsonObject: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
jsonData: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
integer: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
lengthBoundable: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
key: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
nonNegativeIntegerString: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
string: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
number: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
bigint: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
boolean: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
symbol: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
undefined: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
object: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
null: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
Array: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
Date: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
false: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
never: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
true: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
unknown: import("./index.ts").BaseRoot<import("./index.ts").InternalRootDeclaration>;
};

56
frontend/node_modules/@ark/schema/out/intrinsic.js generated vendored Normal file
View File

@@ -0,0 +1,56 @@
import { node, schemaScope } from "./scope.js";
import { $ark } from "./shared/registry.js";
import { arrayIndexSource } from "./structure/shared.js";
const intrinsicBases = schemaScope({
bigint: "bigint",
// since we know this won't be reduced, it can be safely cast to a union
boolean: [{ unit: false }, { unit: true }],
false: { unit: false },
never: [],
null: { unit: null },
number: "number",
object: "object",
string: "string",
symbol: "symbol",
true: { unit: true },
unknown: {},
undefined: { unit: undefined },
Array,
Date
}, { prereducedAliases: true }).export();
$ark.intrinsic = { ...intrinsicBases };
const intrinsicRoots = schemaScope({
integer: {
domain: "number",
divisor: 1
},
lengthBoundable: ["string", Array],
key: ["string", "symbol"],
nonNegativeIntegerString: { domain: "string", pattern: arrayIndexSource }
}, { prereducedAliases: true }).export();
// needed to parse index signatures for JSON
Object.assign($ark.intrinsic, intrinsicRoots);
const intrinsicJson = schemaScope({
jsonPrimitive: [
"string",
"number",
{ unit: true },
{ unit: false },
{ unit: null }
],
jsonObject: {
domain: "object",
index: {
signature: "string",
value: "$jsonData"
}
},
jsonData: ["$jsonPrimitive", "$jsonObject"]
}, { prereducedAliases: true }).export();
export const intrinsic = {
...intrinsicBases,
...intrinsicRoots,
...intrinsicJson,
emptyStructure: node("structure", {}, { prereduced: true })
};
$ark.intrinsic = { ...intrinsic };

73
frontend/node_modules/@ark/schema/out/kinds.d.ts generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import { type array, type listable } from "@ark/util";
import type { BaseNode } from "./node.ts";
import { Predicate } from "./predicate.ts";
import { Divisor } from "./refinements/divisor.ts";
import { type BoundDeclarations, type BoundNodesByKind } from "./refinements/kinds.ts";
import { Pattern } from "./refinements/pattern.ts";
import { Alias } from "./roots/alias.ts";
import { Domain } from "./roots/domain.ts";
import { Intersection } from "./roots/intersection.ts";
import { Morph } from "./roots/morph.ts";
import { Proto } from "./roots/proto.ts";
import { Union } from "./roots/union.ts";
import { Unit } from "./roots/unit.ts";
import type { BaseScope } from "./scope.ts";
import type { ConstraintKind, NodeKind, OpenNodeKind, RootKind, UnknownAttachments, UnknownNodeImplementation } from "./shared/implement.ts";
import type { makeRootAndArrayPropertiesMutable } from "./shared/utils.ts";
import { Index } from "./structure/index.ts";
import { Optional } from "./structure/optional.ts";
import { Required } from "./structure/required.ts";
import { Sequence } from "./structure/sequence.ts";
import { Structure } from "./structure/structure.ts";
export interface NodeDeclarationsByKind extends BoundDeclarations {
alias: Alias.Declaration;
domain: Domain.Declaration;
unit: Unit.Declaration;
proto: Proto.Declaration;
union: Union.Declaration;
morph: Morph.Declaration;
intersection: Intersection.Declaration;
sequence: Sequence.Declaration;
divisor: Divisor.Declaration;
required: Required.Declaration;
optional: Optional.Declaration;
index: Index.Declaration;
pattern: Pattern.Declaration;
predicate: Predicate.Declaration;
structure: Structure.Declaration;
}
export declare const nodeImplementationsByKind: Record<NodeKind, UnknownNodeImplementation>;
export declare const nodeClassesByKind: Record<NodeKind, new (attachments: UnknownAttachments, $: BaseScope) => BaseNode>;
interface NodesByKind extends BoundNodesByKind {
alias: Alias.Node;
union: Union.Node;
morph: Morph.Node;
intersection: Intersection.Node;
unit: Unit.Node;
proto: Proto.Node;
domain: Domain.Node;
divisor: Divisor.Node;
pattern: Pattern.Node;
predicate: Predicate.Node;
required: Required.Node;
optional: Optional.Node;
index: Index.Node;
sequence: Sequence.Node;
structure: Structure.Node;
}
export type nodeOfKind<kind extends NodeKind> = NodesByKind[kind];
export type Declaration<kind extends NodeKind> = NodeDeclarationsByKind[kind];
export type NodeSchema<kind extends NodeKind> = Declaration<kind>["schema"];
export type RootSchema<kind extends RootKind = RootKind> = NodeSchema<kind>;
export type NormalizedSchema<kind extends NodeKind> = Declaration<kind>["normalizedSchema"];
export type childKindOf<kind extends NodeKind> = Declaration<kind>["childKind"];
export type Prerequisite<kind extends NodeKind> = Declaration<kind>["prerequisite"];
export type reducibleKindOf<kind extends NodeKind> = Declaration<kind>["reducibleTo"] extends NodeKind ? Declaration<kind>["reducibleTo"] : kind;
export type Inner<kind extends NodeKind> = Declaration<kind>["inner"];
export type defAttachedAs<kind extends ConstraintKind> = kind extends OpenNodeKind ? listable<NodeSchema<kind>> : NodeSchema<kind>;
export type innerAttachedAs<kind extends ConstraintKind> = kind extends OpenNodeKind ? array<nodeOfKind<kind>> : nodeOfKind<kind>;
/** make nested arrays mutable while keeping nested nodes immutable */
export type mutableInnerOfKind<kind extends NodeKind> = makeRootAndArrayPropertiesMutable<Inner<kind>>;
export type mutableNormalizedRootOfKind<kind extends NodeKind> = makeRootAndArrayPropertiesMutable<NormalizedSchema<kind>>;
export type errorContext<kind extends NodeKind> = Declaration<kind>["errorContext"];
export {};

71
frontend/node_modules/@ark/schema/out/kinds.js generated vendored Normal file
View File

@@ -0,0 +1,71 @@
import { deepClone, envHasCsp, flatMorph, withAlphabetizedKeys } from "@ark/util";
import { mergeConfigs } from "./config.js";
import { Predicate } from "./predicate.js";
import { Divisor } from "./refinements/divisor.js";
import { boundClassesByKind, boundImplementationsByKind } from "./refinements/kinds.js";
import { Pattern } from "./refinements/pattern.js";
import { Alias } from "./roots/alias.js";
import { Domain } from "./roots/domain.js";
import { Intersection } from "./roots/intersection.js";
import { Morph } from "./roots/morph.js";
import { Proto } from "./roots/proto.js";
import { Union } from "./roots/union.js";
import { Unit } from "./roots/unit.js";
import { $ark } from "./shared/registry.js";
import { ToJsonSchema } from "./shared/toJsonSchema.js";
import { Index } from "./structure/index.js";
import { Optional } from "./structure/optional.js";
import { Required } from "./structure/required.js";
import { Sequence } from "./structure/sequence.js";
import { Structure } from "./structure/structure.js";
export const nodeImplementationsByKind = {
...boundImplementationsByKind,
alias: Alias.implementation,
domain: Domain.implementation,
unit: Unit.implementation,
proto: Proto.implementation,
union: Union.implementation,
morph: Morph.implementation,
intersection: Intersection.implementation,
divisor: Divisor.implementation,
pattern: Pattern.implementation,
predicate: Predicate.implementation,
required: Required.implementation,
optional: Optional.implementation,
index: Index.implementation,
sequence: Sequence.implementation,
structure: Structure.implementation
};
$ark.defaultConfig = withAlphabetizedKeys(Object.assign(flatMorph(nodeImplementationsByKind, (kind, implementation) => [
kind,
implementation.defaults
]), {
jitless: envHasCsp(),
clone: deepClone,
onUndeclaredKey: "ignore",
exactOptionalPropertyTypes: true,
numberAllowsNaN: false,
dateAllowsInvalid: false,
onFail: null,
keywords: {},
toJsonSchema: ToJsonSchema.defaultConfig
}));
$ark.resolvedConfig = mergeConfigs($ark.defaultConfig, $ark.config);
export const nodeClassesByKind = {
...boundClassesByKind,
alias: Alias.Node,
domain: Domain.Node,
unit: Unit.Node,
proto: Proto.Node,
union: Union.Node,
morph: Morph.Node,
intersection: Intersection.Node,
divisor: Divisor.Node,
pattern: Pattern.Node,
predicate: Predicate.Node,
required: Required.Node,
optional: Optional.Node,
index: Index.Node,
sequence: Sequence.Node,
structure: Structure.Node
};

24
frontend/node_modules/@ark/schema/out/module.d.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { DynamicBase, type anyOrNever } from "@ark/util";
import type { BaseRoot } from "./roots/root.ts";
import type { BaseScope, InternalResolution, InternalResolutions } from "./scope.ts";
import { arkKind } from "./shared/utils.ts";
export type PreparsedNodeResolution = {
[arkKind]: "generic" | "module";
};
export declare class RootModule<exports extends {} = {}> extends DynamicBase<exports> {
get [arkKind](): "module";
}
export interface InternalModule<exports extends InternalResolutions = InternalResolutions> extends RootModule<exports> {
root?: BaseRoot;
}
export declare const bindModule: (module: InternalModule, $: BaseScope) => InternalModule;
type exportSchemaScope<$> = {
[k in keyof $]: instantiateRoot<$[k]>;
};
export type instantiateRoot<t> = t extends InternalResolution ? [
t
] extends [anyOrNever] ? BaseRoot : t : BaseRoot;
export declare const SchemaModule: new <$ = {}>(types: exportSchemaScope<$>) => SchemaModule<$>;
export interface SchemaModule<$ = {}> extends RootModule<exportSchemaScope<$>> {
}
export {};

15
frontend/node_modules/@ark/schema/out/module.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import { DynamicBase, flatMorph } from "@ark/util";
import { arkKind, hasArkKind } from "./shared/utils.js";
export class RootModule extends DynamicBase {
// ensure `[arkKind]` is non-enumerable so it doesn't get spread on import/export
get [arkKind]() {
return "module";
}
}
export const bindModule = (module, $) => new RootModule(flatMorph(module, (alias, value) => [
alias,
hasArkKind(value, "module") ?
bindModule(value, $)
: $.bindReference(value)
]));
export const SchemaModule = RootModule;

154
frontend/node_modules/@ark/schema/out/node.d.ts generated vendored Normal file
View File

@@ -0,0 +1,154 @@
import { Callable, type GuardablePredicate, type JsonStructure, type Key, type array, type conform, type listable, type mutable, type requireKeys } from "@ark/util";
import type { BaseConstraint } from "./constraint.ts";
import type { Inner, NormalizedSchema, childKindOf, nodeOfKind, reducibleKindOf } from "./kinds.ts";
import type { BaseParseOptions } from "./parse.ts";
import type { Intersection } from "./roots/intersection.ts";
import type { Morph } from "./roots/morph.ts";
import type { BaseRoot } from "./roots/root.ts";
import type { Unit } from "./roots/unit.ts";
import type { BaseScope } from "./scope.ts";
import type { NodeCompiler } from "./shared/compile.ts";
import type { BaseNodeDeclaration, TypeMeta, attachmentsOf } from "./shared/declare.ts";
import type { ArkErrors } from "./shared/errors.ts";
import { type BasisKind, type NodeKind, type OpenNodeKind, type RefinementKind, type StructuralKind, type UnknownAttachments } from "./shared/implement.ts";
import { Traversal, type TraverseAllows, type TraverseApply } from "./shared/traversal.ts";
import type { UndeclaredKeyHandling } from "./structure/structure.ts";
export declare abstract class BaseNode<
/** @ts-ignore allow instantiation assignment to the base type */
out d extends BaseNodeDeclaration = BaseNodeDeclaration> extends Callable<(data: d["prerequisite"], ctx?: Traversal, onFail?: ArkErrors.Handler | null) => unknown, attachmentsOf<d>> {
attachments: UnknownAttachments;
$: BaseScope;
onFail: ArkErrors.Handler | null;
includesTransform: boolean;
includesContextualPredicate: boolean;
isCyclic: boolean;
allowsRequiresContext: boolean;
rootApplyStrategy: "allows" | "contextual" | "optimistic" | "branchedOptimistic";
contextFreeMorph: ((data: unknown) => unknown) | undefined;
rootApply: (data: unknown, onFail: ArkErrors.Handler | null) => unknown;
referencesById: Record<string, BaseNode>;
shallowReferences: BaseNode[];
flatRefs: FlatRef[];
flatMorphs: FlatRef<Morph.Node | Intersection.Node>[];
allows: (data: d["prerequisite"]) => boolean;
get shallowMorphs(): array<Morph>;
constructor(attachments: UnknownAttachments, $: BaseScope);
protected createRootApply(): this["rootApply"];
abstract traverseAllows: TraverseAllows<d["prerequisite"]>;
abstract traverseApply: TraverseApply<d["prerequisite"]>;
abstract expression: string;
abstract compile(js: NodeCompiler): void;
readonly compiledMeta: string;
protected cacheGetter<name extends keyof this>(name: name, value: this[name]): this[name];
get description(): string;
get references(): BaseNode[];
readonly precedence: number;
precompilation: string | undefined;
assert: (data: d["prerequisite"], pipedFromCtx?: Traversal) => unknown;
traverse(data: d["prerequisite"], pipedFromCtx?: Traversal): ArkErrors | {} | null | undefined;
/** 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;
toJSON(): JsonStructure;
toString(): string;
equals(r: unknown): boolean;
ifEquals(r: unknown): BaseNode | undefined;
hasKind<kind extends NodeKind>(kind: kind): this is nodeOfKind<kind>;
assertHasKind<kind extends NodeKind>(kind: kind): nodeOfKind<kind>;
hasKindIn<kinds extends NodeKind[]>(...kinds: kinds): this is nodeOfKind<kinds[number]>;
assertHasKindIn<kinds extends NodeKind[]>(...kinds: kinds): nodeOfKind<kinds[number]>;
isBasis(): this is nodeOfKind<BasisKind>;
isConstraint(): this is BaseConstraint;
isStructural(): this is nodeOfKind<StructuralKind>;
isRefinement(): this is nodeOfKind<RefinementKind>;
isRoot(): this is BaseRoot;
isUnknown(): boolean;
isNever(): boolean;
hasUnit<value>(value: unknown): this is Unit.Node & {
unit: value;
};
hasOpenIntersection(): this is nodeOfKind<OpenNodeKind>;
get nestableExpression(): string;
select<const selector extends NodeSelector.CompositeInput, predicate extends GuardablePredicate<NodeSelector.inferSelectKind<d["kind"], selector>>>(selector: NodeSelector.validateComposite<selector, predicate>): NodeSelector.infer<d["kind"], selector>;
select<const selector extends NodeSelector.Single>(selector: selector): NodeSelector.infer<d["kind"], selector>;
private _select;
transform<mapper extends DeepNodeTransformation>(mapper: mapper, opts?: DeepNodeTransformOptions): nodeOfKind<reducibleKindOf<this["kind"]>> | Extract<ReturnType<mapper>, null>;
protected _createTransformContext(opts: DeepNodeTransformOptions | undefined): DeepNodeTransformContext;
protected _transform(mapper: DeepNodeTransformation, ctx: DeepNodeTransformContext): BaseNode | null;
configureReferences(meta: TypeMeta.MappableInput.Internal, selector?: NodeSelector): this;
}
/** a literal key (named property) or a node (index signatures) representing part of a type structure */
export type KeyOrKeyNode = Key | BaseRoot;
export type GettableKeyOrNode = KeyOrKeyNode | number;
export type FlatRef<root extends BaseRoot = BaseRoot> = {
path: array<KeyOrKeyNode>;
node: root;
propString: string;
};
export type NodeSelector = NodeSelector.Single | NodeSelector.Composite;
export declare namespace NodeSelector {
type SelectableFn<input, returns, kind extends NodeKind = NodeKind> = {
<const selector extends NodeSelector.CompositeInput, predicate extends GuardablePredicate<NodeSelector.inferSelectKind<kind, selector>>>(input: input, selector?: NodeSelector.validateComposite<selector, predicate>): returns;
<const selector extends NodeSelector.Single>(input: input, selector?: selector): returns;
};
type Single = NodeSelector.Boundary | NodeSelector.Kind | GuardablePredicate<BaseNode>;
type Boundary = "self" | "child" | "shallow" | "references";
type Kind = NodeKind;
type Method = "filter" | "assertFilter" | "find" | "assertFind";
interface Composite {
method?: Method;
boundary?: Boundary;
kind?: Kind;
where?: GuardablePredicate<BaseNode>;
}
type Normalized = requireKeys<Composite, "method" | "boundary">;
type CompositeInput = Omit<Composite, "where">;
type BaseResult = BaseNode | BaseNode[] | undefined;
type validateComposite<selector, predicate> = {
[k in keyof selector]: k extends "where" ? predicate : conform<selector[k], CompositeInput[k & keyof CompositeInput]>;
};
type infer<selfKind extends NodeKind, selector> = applyMethod<selector extends NodeSelector.WhereCastInput<any, infer narrowed> ? narrowed : NodeSelector.inferSelectKind<selfKind, selector>, selector>;
type BoundaryInput<b extends Boundary> = b | {
boundary: b;
};
type KindInput<k extends Kind> = k | {
kind: k;
};
type WhereCastInput<kindNode extends BaseNode, narrowed extends kindNode> = ((In: kindNode) => In is narrowed) | {
where: (In: kindNode) => In is narrowed;
};
type inferSelectKind<selfKind extends NodeKind, selector> = selectKind<selfKind, selector> extends infer kind extends NodeKind ? NodeKind extends kind ? BaseNode : nodeOfKind<kind> : never;
type selectKind<selfKind extends NodeKind, selector> = selector extends BoundaryInput<"self"> ? selfKind : selector extends KindInput<infer kind> ? kind : selector extends BoundaryInput<"child"> ? selfKind | childKindOf<selfKind> : NodeKind;
type applyMethod<t, selector> = selector extends {
method: infer method extends Method;
} ? method extends "filter" ? t[] : method extends "assertFilter" ? [t, ...t[]] : method extends "find" ? t | undefined : method extends "assertFind" ? t : never : t[];
}
export declare const typePathToPropString: (path: array<KeyOrKeyNode>) => string;
export declare const flatRef: <node extends BaseRoot>(path: array<KeyOrKeyNode>, node: node) => FlatRef<node>;
export declare const flatRefsAreEqual: (l: FlatRef, r: FlatRef) => boolean;
export declare const appendUniqueFlatRefs: <node extends BaseRoot>(existing: FlatRef<node>[] | undefined, refs: listable<FlatRef<node>>) => FlatRef<node>[];
export declare const appendUniqueNodes: <node extends BaseNode>(existing: node[] | undefined, refs: listable<node>) => node[];
export type DeepNodeTransformOptions = {
shouldTransform?: ShouldTransformFn;
bindScope?: BaseScope;
prereduced?: boolean;
selected?: readonly BaseNode[] | undefined;
};
export type ShouldTransformFn = (node: BaseNode, ctx: DeepNodeTransformContext) => boolean;
export interface DeepNodeTransformContext extends DeepNodeTransformOptions {
root: BaseNode;
selected: readonly BaseNode[] | undefined;
path: mutable<array<KeyOrKeyNode>>;
seen: {
[originalId: string]: (() => BaseNode | undefined) | undefined;
};
parseOptions: BaseParseOptions;
undeclaredKeyHandling: UndeclaredKeyHandling | undefined;
}
export type DeepNodeTransformation = <kind extends NodeKind>(kind: kind, innerWithMeta: Inner<kind> & {
meta: ArkEnv.meta;
}, ctx: DeepNodeTransformContext) => NormalizedSchema<kind> | null;

438
frontend/node_modules/@ark/schema/out/node.js generated vendored Normal file
View File

@@ -0,0 +1,438 @@
import { Callable, appendUnique, flatMorph, includes, isArray, isEmptyObject, isKeyOf, liftArray, printable, stringifyPath, throwError, throwInternalError } from "@ark/util";
import { basisKinds, constraintKinds, precedenceOfKind, refinementKinds, rootKinds, structuralKinds } from "./shared/implement.js";
import { $ark } from "./shared/registry.js";
import { Traversal } from "./shared/traversal.js";
import { isNode } from "./shared/utils.js";
export class BaseNode extends Callable {
attachments;
$;
onFail;
includesTransform;
includesContextualPredicate;
isCyclic;
allowsRequiresContext;
rootApplyStrategy;
contextFreeMorph;
rootApply;
referencesById;
shallowReferences;
flatRefs;
flatMorphs;
allows;
get shallowMorphs() {
return [];
}
constructor(attachments, $) {
super((data, pipedFromCtx, onFail = this.onFail) => {
if (pipedFromCtx) {
this.traverseApply(data, pipedFromCtx);
return pipedFromCtx.hasError() ?
pipedFromCtx.errors
: pipedFromCtx.data;
}
return this.rootApply(data, onFail);
}, { attach: attachments });
this.attachments = attachments;
this.$ = $;
this.onFail = this.meta.onFail ?? this.$.resolvedConfig.onFail;
this.includesTransform =
this.hasKind("morph") ||
(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
// technically, a predicate could be written like `(data, ...[ctx]) => ctx.mustBe("malicious")`
// that would break here, but it feels like a pathological case and is better to let people optimize
this.includesContextualPredicate =
this.hasKind("predicate") && this.inner.predicate.length !== 1;
this.isCyclic = this.kind === "alias";
this.referencesById = { [this.id]: this };
this.shallowReferences =
this.hasKind("structure") ?
[this, ...this.children]
: this.children.reduce((acc, child) => appendUniqueNodes(acc, child.shallowReferences), [this]);
const isStructural = this.isStructural();
this.flatRefs = [];
this.flatMorphs = [];
for (let i = 0; i < this.children.length; i++) {
this.includesTransform ||= this.children[i].includesTransform;
this.includesContextualPredicate ||=
this.children[i].includesContextualPredicate;
this.isCyclic ||= this.children[i].isCyclic;
if (!isStructural) {
const childFlatRefs = this.children[i].flatRefs;
for (let j = 0; j < childFlatRefs.length; j++) {
const childRef = childFlatRefs[j];
if (!this.flatRefs.some(existing => flatRefsAreEqual(existing, childRef))) {
this.flatRefs.push(childRef);
for (const branch of childRef.node.branches) {
if (branch.hasKind("morph") ||
(branch.hasKind("intersection") &&
branch.structure?.structuralMorph !== undefined)) {
this.flatMorphs.push({
path: childRef.path,
propString: childRef.propString,
node: branch
});
}
}
}
}
}
Object.assign(this.referencesById, this.children[i].referencesById);
}
this.flatRefs.sort((l, r) => l.path.length > r.path.length ? 1
: l.path.length < r.path.length ? -1
: l.propString > r.propString ? 1
: l.propString < r.propString ? -1
: l.node.expression < r.node.expression ? -1
: 1);
this.allowsRequiresContext =
this.includesContextualPredicate || this.isCyclic;
this.rootApplyStrategy =
!this.allowsRequiresContext && this.flatMorphs.length === 0 ?
this.shallowMorphs.length === 0 ? "allows"
: (this.shallowMorphs.every(morph => morph.length === 1 || morph.name === "$arkStructuralMorph")) ?
this.hasKind("union") ?
// multiple morphs not yet supported for optimistic compilation
this.branches.some(branch => branch.shallowMorphs.length > 1) ?
"contextual"
: "branchedOptimistic"
: this.shallowMorphs.length > 1 ? "contextual"
: "optimistic"
: "contextual"
: "contextual";
this.rootApply = this.createRootApply();
this.allows =
this.allowsRequiresContext ?
data => this.traverseAllows(data, new Traversal(data, this.$.resolvedConfig))
: data => this.traverseAllows(data);
}
createRootApply() {
switch (this.rootApplyStrategy) {
case "allows":
return (data, onFail) => {
if (this.allows(data))
return data;
const ctx = new Traversal(data, this.$.resolvedConfig);
this.traverseApply(data, ctx);
return ctx.finalize(onFail);
};
case "contextual":
return (data, onFail) => {
const ctx = new Traversal(data, this.$.resolvedConfig);
this.traverseApply(data, ctx);
return ctx.finalize(onFail);
};
case "optimistic":
this.contextFreeMorph = this.shallowMorphs[0];
const clone = this.$.resolvedConfig.clone;
return (data, onFail) => {
if (this.allows(data)) {
return this.contextFreeMorph((clone &&
((typeof data === "object" && data !== null) ||
typeof data === "function")) ?
clone(data)
: data);
}
const ctx = new Traversal(data, this.$.resolvedConfig);
this.traverseApply(data, ctx);
return ctx.finalize(onFail);
};
case "branchedOptimistic":
return this.createBranchedOptimisticRootApply();
default:
this.rootApplyStrategy;
return throwInternalError(`Unexpected rootApplyStrategy ${this.rootApplyStrategy}`);
}
}
compiledMeta = compileMeta(this.metaJson);
cacheGetter(name, value) {
Object.defineProperty(this, name, { value });
return value;
}
get description() {
return this.cacheGetter("description", this.meta?.description ??
this.$.resolvedConfig[this.kind].description(this));
}
// we don't cache this currently since it can be updated once a scope finishes
// resolving cyclic references, although it may be possible to ensure it is cached safely
get references() {
return Object.values(this.referencesById);
}
precedence = precedenceOfKind(this.kind);
precompilation;
// defined as an arrow function since it is often detached, e.g. when passing to tRPC
// otherwise, would run into issues with this binding
assert = (data, pipedFromCtx) => this(data, pipedFromCtx, errors => errors.throw());
traverse(data, pipedFromCtx) {
return this(data, pipedFromCtx, null);
}
/** rawIn should be used internally instead */
get 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() {
// 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
// https://github.com/arktypeio/arktype/issues/1020
getIo(ioKind) {
if (!this.includesTransform)
return this;
const ioInner = {};
for (const [k, v] of this.innerEntries) {
const keySchemaImplementation = this.impl.keys[k];
if (keySchemaImplementation.reduceIo)
keySchemaImplementation.reduceIo(ioKind, ioInner, v);
else if (keySchemaImplementation.child) {
const childValue = v;
ioInner[k] =
isArray(childValue) ?
childValue.map(child => ioKind === "in" ? child.rawIn : child.rawOut)
: ioKind === "in" ? childValue.rawIn
: childValue.rawOut;
}
else
ioInner[k] = v;
}
return this.$.node(this.kind, ioInner);
}
toJSON() {
return this.json;
}
toString() {
return `Type<${this.expression}>`;
}
equals(r) {
const rNode = isNode(r) ? r : this.$.parseDefinition(r);
return this.innerHash === rNode.innerHash;
}
ifEquals(r) {
return this.equals(r) ? this : undefined;
}
hasKind(kind) {
return this.kind === kind;
}
assertHasKind(kind) {
if (this.kind !== kind)
throwError(`${this.kind} node was not of asserted kind ${kind}`);
return this;
}
hasKindIn(...kinds) {
return kinds.includes(this.kind);
}
assertHasKindIn(...kinds) {
if (!includes(kinds, this.kind))
throwError(`${this.kind} node was not one of asserted kinds ${kinds}`);
return this;
}
isBasis() {
return includes(basisKinds, this.kind);
}
isConstraint() {
return includes(constraintKinds, this.kind);
}
isStructural() {
return includes(structuralKinds, this.kind);
}
isRefinement() {
return includes(refinementKinds, this.kind);
}
isRoot() {
return includes(rootKinds, this.kind);
}
isUnknown() {
return this.hasKind("intersection") && this.children.length === 0;
}
isNever() {
return this.hasKind("union") && this.children.length === 0;
}
hasUnit(value) {
return this.hasKind("unit") && this.allows(value);
}
hasOpenIntersection() {
return this.impl.intersectionIsOpen;
}
get nestableExpression() {
return this.expression;
}
select(selector) {
const normalized = NodeSelector.normalize(selector);
return this._select(normalized);
}
_select(selector) {
let nodes = NodeSelector.applyBoundary[selector.boundary ?? "references"](this);
if (selector.kind)
nodes = nodes.filter(n => n.kind === selector.kind);
if (selector.where)
nodes = nodes.filter(selector.where);
return NodeSelector.applyMethod[selector.method ?? "filter"](nodes, this, selector);
}
transform(mapper, opts) {
return this._transform(mapper, this._createTransformContext(opts));
}
_createTransformContext(opts) {
return {
root: this,
selected: undefined,
seen: {},
path: [],
parseOptions: {
prereduced: opts?.prereduced ?? false
},
undeclaredKeyHandling: undefined,
...opts
};
}
_transform(mapper, ctx) {
const $ = ctx.bindScope ?? this.$;
if (ctx.seen[this.id])
// Cyclic handling needs to be made more robust
// https://github.com/arktypeio/arktype/issues/944
return this.$.lazilyResolve(ctx.seen[this.id]);
if (ctx.shouldTransform?.(this, ctx) === false)
return this;
let transformedNode;
ctx.seen[this.id] = () => transformedNode;
if (this.hasKind("structure") &&
this.undeclared !== ctx.undeclaredKeyHandling) {
ctx = {
...ctx,
undeclaredKeyHandling: this.undeclared
};
}
const innerWithTransformedChildren = flatMorph(this.inner, (k, v) => {
if (!this.impl.keys[k].child)
return [k, v];
const children = v;
if (!isArray(children)) {
const transformed = children._transform(mapper, ctx);
return transformed ? [k, transformed] : [];
}
// if the value was previously explicitly set to an empty list,
// (e.g. branches for `never`), ensure it is not pruned
if (children.length === 0)
return [k, v];
const transformed = children.flatMap(n => {
const transformedChild = n._transform(mapper, ctx);
return transformedChild ?? [];
});
return transformed.length ? [k, transformed] : [];
});
delete ctx.seen[this.id];
const innerWithMeta = Object.assign(innerWithTransformedChildren, {
meta: this.meta
});
const transformedInner = ctx.selected && !ctx.selected.includes(this) ?
innerWithMeta
: mapper(this.kind, innerWithMeta, ctx);
if (transformedInner === null)
return null;
if (isNode(transformedInner))
return (transformedNode = transformedInner);
const transformedKeys = Object.keys(transformedInner);
const hasNoTypedKeys = transformedKeys.length === 0 ||
(transformedKeys.length === 1 && transformedKeys[0] === "meta");
if (hasNoTypedKeys &&
// if inner was previously an empty object (e.g. unknown) ensure it is not pruned
!isEmptyObject(this.inner))
return null;
if ((this.kind === "required" ||
this.kind === "optional" ||
this.kind === "index") &&
!("value" in transformedInner)) {
return ctx.undeclaredKeyHandling ?
{ ...transformedInner, value: $ark.intrinsic.unknown }
: null;
}
if (this.kind === "morph") {
;
transformedInner.in ??= $ark.intrinsic
.unknown;
}
return (transformedNode = $.node(this.kind, transformedInner, ctx.parseOptions));
}
configureReferences(meta, selector = "references") {
const normalized = NodeSelector.normalize(selector);
const mapper = (typeof meta === "string" ?
(kind, inner) => ({
...inner,
meta: { ...inner.meta, description: meta }
})
: typeof meta === "function" ?
(kind, inner) => ({ ...inner, meta: meta(inner.meta) })
: (kind, inner) => ({
...inner,
meta: { ...inner.meta, ...meta }
}));
if (normalized.boundary === "self") {
return this.$.node(this.kind, mapper(this.kind, { ...this.inner, meta: this.meta }));
}
const rawSelected = this._select(normalized);
const selected = rawSelected && liftArray(rawSelected);
const shouldTransform = normalized.boundary === "child" ?
(node, ctx) => ctx.root.children.includes(node)
: normalized.boundary === "shallow" ? node => node.kind !== "structure"
: () => true;
return this.$.finalize(this.transform(mapper, {
shouldTransform,
selected
}));
}
}
const NodeSelector = {
applyBoundary: {
self: node => [node],
child: node => [...node.children],
shallow: node => [...node.shallowReferences],
references: node => [...node.references]
},
applyMethod: {
filter: nodes => nodes,
assertFilter: (nodes, from, selector) => {
if (nodes.length === 0)
throwError(writeSelectAssertionMessage(from, selector));
return nodes;
},
find: nodes => nodes[0],
assertFind: (nodes, from, selector) => {
if (nodes.length === 0)
throwError(writeSelectAssertionMessage(from, selector));
return nodes[0];
}
},
normalize: (selector) => typeof selector === "function" ?
{ boundary: "references", method: "filter", where: selector }
: typeof selector === "string" ?
isKeyOf(selector, NodeSelector.applyBoundary) ?
{ method: "filter", boundary: selector }
: { boundary: "references", method: "filter", kind: selector }
: { boundary: "references", method: "filter", ...selector }
};
const writeSelectAssertionMessage = (from, selector) => `${from} had no references matching ${printable(selector)}.`;
export const typePathToPropString = (path) => stringifyPath(path, {
stringifyNonKey: node => node.expression
});
const referenceMatcher = /"(\$ark\.[^"]+)"/g;
const compileMeta = (metaJson) => JSON.stringify(metaJson).replace(referenceMatcher, "$1");
export const flatRef = (path, node) => ({
path,
node,
propString: typePathToPropString(path)
});
export const flatRefsAreEqual = (l, r) => l.propString === r.propString && l.node.equals(r.node);
export const appendUniqueFlatRefs = (existing, refs) => appendUnique(existing, refs, {
isEqual: flatRefsAreEqual
});
export const appendUniqueNodes = (existing, refs) => appendUnique(existing, refs, {
isEqual: (l, r) => l.equals(r)
});

52
frontend/node_modules/@ark/schema/out/parse.d.ts generated vendored Normal file
View File

@@ -0,0 +1,52 @@
import { type Brand, type dict } from "@ark/util";
import { type NormalizedSchema } from "./kinds.ts";
import type { BaseNode } from "./node.ts";
import type { BaseRoot } from "./roots/root.ts";
import type { BaseScope } from "./scope.ts";
import { type NodeKind, type RootKind } from "./shared/implement.ts";
import { type arkKind } from "./shared/utils.ts";
export type ContextualArgs = Record<string, BaseRoot | NodeId>;
export type BaseParseOptions<prereduced extends boolean = boolean> = {
alias?: string;
prereduced?: prereduced;
args?: ContextualArgs;
id?: NodeId;
};
export interface BaseParseContextInput extends BaseParseOptions {
prefix: string;
def: unknown;
}
export interface AttachedParseContext {
[arkKind]: "context";
$: BaseScope;
id: NodeId;
phase: "unresolved" | "resolving" | "resolved";
}
export interface BaseParseContext extends BaseParseContextInput, AttachedParseContext {
id: NodeId;
}
export interface NodeParseContextInput<kind extends NodeKind = NodeKind> extends BaseParseContextInput {
kind: kind;
def: NormalizedSchema<kind>;
}
export interface NodeParseContext<kind extends NodeKind = NodeKind> extends NodeParseContextInput<kind>, AttachedParseContext {
id: NodeId;
}
export declare const schemaKindOf: <kind extends RootKind = RootKind>(schema: unknown, allowedKinds?: readonly kind[]) => kind;
export declare const writeInvalidSchemaMessage: (schema: unknown) => string;
export type NodeId = Brand<string, "NodeId">;
export type NodeResolver = (id: NodeId) => BaseNode;
export declare const nodesByRegisteredId: Record<NodeId, BaseNode | BaseParseContext | undefined>;
export declare const registerNodeId: (prefix: string) => NodeId;
export declare const parseNode: (ctx: NodeParseContext) => BaseNode;
export type CreateNodeInput = {
id: NodeId;
kind: NodeKind;
inner: dict;
meta: ArkEnv.meta;
$: BaseScope;
ignoreCache?: true;
};
export declare const createNode: ({ id, kind, inner, meta, $, ignoreCache }: CreateNodeInput) => BaseNode;
export declare const withId: <node extends BaseNode>(node: node, id: NodeId) => node;
export declare const withMeta: <node extends BaseNode>(node: node, meta: ArkEnv.meta, id?: NodeId) => node;

215
frontend/node_modules/@ark/schema/out/parse.js generated vendored Normal file
View File

@@ -0,0 +1,215 @@
import { domainDescriptions, entriesOf, flatMorph, hasDomain, isArray, isEmptyObject, printable, throwInternalError, throwParseError, unset } from "@ark/util";
import { nodeClassesByKind, nodeImplementationsByKind } from "./kinds.js";
import { Disjoint } from "./shared/disjoint.js";
import { constraintKeys, defaultValueSerializer, isNodeKind, precedenceOfKind } from "./shared/implement.js";
import { $ark } from "./shared/registry.js";
import { hasArkKind, isNode } from "./shared/utils.js";
export const schemaKindOf = (schema, allowedKinds) => {
const kind = discriminateRootKind(schema);
if (allowedKinds && !allowedKinds.includes(kind)) {
return throwParseError(`Root of kind ${kind} should be one of ${allowedKinds}`);
}
return kind;
};
const discriminateRootKind = (schema) => {
if (hasArkKind(schema, "root"))
return schema.kind;
if (typeof schema === "string") {
return (schema[0] === "$" ? "alias"
: schema in domainDescriptions ? "domain"
: "proto");
}
if (typeof schema === "function")
return "proto";
// throw at end of function
if (typeof schema !== "object" || schema === null)
return throwParseError(writeInvalidSchemaMessage(schema));
if ("morphs" in schema)
return "morph";
if ("branches" in schema || isArray(schema))
return "union";
if ("unit" in schema)
return "unit";
if ("reference" in schema)
return "alias";
const schemaKeys = Object.keys(schema);
if (schemaKeys.length === 0 || schemaKeys.some(k => k in constraintKeys))
return "intersection";
if ("proto" in schema)
return "proto";
if ("domain" in schema)
return "domain";
return throwParseError(writeInvalidSchemaMessage(schema));
};
export const writeInvalidSchemaMessage = (schema) => `${printable(schema)} is not a valid type schema`;
const nodeCountsByPrefix = {};
const serializeListableChild = (listableNode) => isArray(listableNode) ?
listableNode.map(node => node.collapsibleJson)
: listableNode.collapsibleJson;
export const nodesByRegisteredId = {};
$ark.nodesByRegisteredId = nodesByRegisteredId;
export const registerNodeId = (prefix) => {
nodeCountsByPrefix[prefix] ??= 0;
return `${prefix}${++nodeCountsByPrefix[prefix]}`;
};
export const parseNode = (ctx) => {
const impl = nodeImplementationsByKind[ctx.kind];
const configuredSchema = impl.applyConfig?.(ctx.def, ctx.$.resolvedConfig) ?? ctx.def;
const inner = {};
const { meta: metaSchema, ...innerSchema } = configuredSchema;
const meta = metaSchema === undefined ? {}
: typeof metaSchema === "string" ? { description: metaSchema }
: metaSchema;
// ensure node entries are parsed in order of precedence, with non-children
// parsed first
const innerSchemaEntries = entriesOf(innerSchema)
.sort(([lKey], [rKey]) => isNodeKind(lKey) ?
isNodeKind(rKey) ? precedenceOfKind(lKey) - precedenceOfKind(rKey)
: 1
: isNodeKind(rKey) ? -1
: lKey < rKey ? -1
: 1)
.filter(([k, v]) => {
// move meta. prefixed props to meta, overwriting existing nested
// props of the same name if they exist
if (k.startsWith("meta.")) {
const metaKey = k.slice(5);
meta[metaKey] = v;
return false;
}
return true;
});
for (const entry of innerSchemaEntries) {
const k = entry[0];
const keyImpl = impl.keys[k];
if (!keyImpl)
return throwParseError(`Key ${k} is not valid on ${ctx.kind} schema`);
const v = keyImpl.parse ? keyImpl.parse(entry[1], ctx) : entry[1];
if (v !== unset && (v !== undefined || keyImpl.preserveUndefined))
inner[k] = v;
}
if (impl.reduce && !ctx.prereduced) {
const reduced = impl.reduce(inner, ctx.$);
if (reduced) {
if (reduced instanceof Disjoint)
return reduced.throw();
// we can't cache this reduction for now in case the reduction involved
// impliedSiblings
return withMeta(reduced, meta);
}
}
const node = createNode({
id: ctx.id,
kind: ctx.kind,
inner,
meta,
$: ctx.$
});
return node;
};
export const createNode = ({ id, kind, inner, meta, $, ignoreCache }) => {
const impl = nodeImplementationsByKind[kind];
const innerEntries = entriesOf(inner);
const children = [];
let innerJson = {};
for (const [k, v] of innerEntries) {
const keyImpl = impl.keys[k];
const serialize = keyImpl.serialize ??
(keyImpl.child ? serializeListableChild : defaultValueSerializer);
innerJson[k] = serialize(v);
if (keyImpl.child === true) {
const listableNode = v;
if (isArray(listableNode))
children.push(...listableNode);
else
children.push(listableNode);
}
else if (typeof keyImpl.child === "function")
children.push(...keyImpl.child(v));
}
if (impl.finalizeInnerJson)
innerJson = impl.finalizeInnerJson(innerJson);
let json = { ...innerJson };
let metaJson = {};
if (!isEmptyObject(meta)) {
metaJson = flatMorph(meta, (k, v) => [
k,
k === "examples" ? v : defaultValueSerializer(v)
]);
json.meta = possiblyCollapse(metaJson, "description", true);
}
innerJson = possiblyCollapse(innerJson, impl.collapsibleKey, false);
const innerHash = JSON.stringify({ kind, ...innerJson });
json = possiblyCollapse(json, impl.collapsibleKey, false);
const collapsibleJson = possiblyCollapse(json, impl.collapsibleKey, true);
const hash = JSON.stringify({ kind, ...json });
// we have to wait until after reduction to return a cached entry,
// since reduction can add impliedSiblings
if ($.nodesByHash[hash] && !ignoreCache)
return $.nodesByHash[hash];
const attachments = {
id,
kind,
impl,
inner,
innerEntries,
innerJson,
innerHash,
meta,
metaJson,
json,
hash,
collapsibleJson: collapsibleJson,
children
};
if (kind !== "intersection") {
for (const k in inner)
if (k !== "in" && k !== "out")
attachments[k] = inner[k];
}
const node = new nodeClassesByKind[kind](attachments, $);
return ($.nodesByHash[hash] = node);
};
export const withId = (node, id) => {
if (node.id === id)
return node;
if (isNode(nodesByRegisteredId[id]))
throwInternalError(`Unexpected attempt to overwrite node id ${id}`);
// have to ignore cache to force creation of new potentially cyclic id
return createNode({
id,
kind: node.kind,
inner: node.inner,
meta: node.meta,
$: node.$,
ignoreCache: true
});
};
export const withMeta = (node, meta, id) => {
if (id && isNode(nodesByRegisteredId[id]))
throwInternalError(`Unexpected attempt to overwrite node id ${id}`);
return createNode({
id: id ?? registerNodeId(meta.alias ?? node.kind),
kind: node.kind,
inner: node.inner,
meta,
$: node.$
});
};
const possiblyCollapse = (json, toKey, allowPrimitive) => {
const collapsibleKeys = Object.keys(json);
if (collapsibleKeys.length === 1 && collapsibleKeys[0] === toKey) {
const collapsed = json[toKey];
if (allowPrimitive)
return collapsed;
if (
// if the collapsed value is still an object
hasDomain(collapsed, "object") &&
// and the JSON did not include any implied keys
(Object.keys(collapsed).length === 1 || Array.isArray(collapsed))) {
// we can replace it with its collapsed value
return collapsed;
}
}
return json;
};

52
frontend/node_modules/@ark/schema/out/predicate.d.ts generated vendored Normal file
View File

@@ -0,0 +1,52 @@
import { BaseConstraint } from "./constraint.ts";
import type { NodeCompiler } from "./shared/compile.ts";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "./shared/declare.ts";
import { type nodeImplementationOf } from "./shared/implement.ts";
import type { JsonSchema } from "./shared/jsonSchema.ts";
import { type RegisteredReference } from "./shared/registry.ts";
import type { ToJsonSchema } from "./shared/toJsonSchema.ts";
import type { Traversal, TraverseAllows, TraverseApply } from "./shared/traversal.ts";
export declare namespace Predicate {
type Schema<predicate extends Predicate = Predicate> = NormalizedSchema<predicate> | predicate;
interface NormalizedSchema<predicate extends Predicate = Predicate> extends BaseNormalizedSchema {
readonly predicate: predicate;
}
interface Inner<predicate extends Predicate = Predicate> {
readonly predicate: predicate;
}
interface ErrorContext extends BaseErrorContext<"predicate"> {
readonly predicate?: Predicate;
}
interface Declaration extends declareNode<{
kind: "predicate";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
intersectionIsOpen: true;
errorContext: ErrorContext;
}> {
}
type Node = PredicateNode;
}
export declare class PredicateNode extends BaseConstraint<Predicate.Declaration> {
serializedPredicate: RegisteredReference;
compiledCondition: string;
compiledNegation: string;
impliedBasis: null;
expression: string;
traverseAllows: TraverseAllows;
errorContext: Predicate.ErrorContext;
compiledErrorContext: string;
traverseApply: TraverseApply;
compile(js: NodeCompiler): void;
reduceJsonSchema(base: JsonSchema.Constrainable, ctx: ToJsonSchema.Context): JsonSchema;
}
export declare const Predicate: {
implementation: nodeImplementationOf<Predicate.Declaration>;
Node: typeof PredicateNode;
};
export type Predicate<data = any> = (data: data, ctx: Traversal) => boolean;
export declare namespace Predicate {
type Casted<input = never, narrowed extends input = input> = (input: input, ctx: Traversal) => input is narrowed;
type Castable<input = never, narrowed extends input = input> = Predicate<input> | Casted<input, narrowed>;
}

63
frontend/node_modules/@ark/schema/out/predicate.js generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import { BaseConstraint } from "./constraint.js";
import { compileObjectLiteral, implementNode } from "./shared/implement.js";
import { registeredReference } from "./shared/registry.js";
const implementation = implementNode({
kind: "predicate",
hasAssociatedError: true,
collapsibleKey: "predicate",
keys: {
predicate: {}
},
normalize: schema => typeof schema === "function" ? { predicate: schema } : schema,
defaults: {
description: node => `valid according to ${node.predicate.name || "an anonymous predicate"}`
},
intersectionIsOpen: true,
intersections: {
// as long as the narrows in l and r are individually safe to check
// in the order they're specified, checking them in the order
// resulting from this intersection should also be safe.
predicate: () => null
}
});
export class PredicateNode extends BaseConstraint {
serializedPredicate = registeredReference(this.predicate);
compiledCondition = `${this.serializedPredicate}(data, ctx)`;
compiledNegation = `!${this.compiledCondition}`;
impliedBasis = null;
expression = this.serializedPredicate;
traverseAllows = this.predicate;
errorContext = {
code: "predicate",
description: this.description,
meta: this.meta
};
compiledErrorContext = compileObjectLiteral(this.errorContext);
traverseApply = (data, ctx) => {
const errorCount = ctx.currentErrorCount;
if (!this.predicate(data, ctx.external) &&
ctx.currentErrorCount === errorCount)
ctx.errorFromNodeContext(this.errorContext);
};
compile(js) {
if (js.traversalKind === "Allows") {
js.return(this.compiledCondition);
return;
}
js.initializeErrorCount();
js.if(
// only add the default error if the predicate didn't add one itself
`${this.compiledNegation} && ctx.currentErrorCount === errorCount`, () => js.line(`ctx.errorFromNodeContext(${this.compiledErrorContext})`));
}
reduceJsonSchema(base, ctx) {
return ctx.fallback.predicate({
code: "predicate",
base,
predicate: this.predicate
});
}
}
export const Predicate = {
implementation,
Node: PredicateNode
};

View File

@@ -0,0 +1,41 @@
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { BaseRange, type BaseRangeInner, type LimitSchemaValue, type UnknownExpandedRangeSchema, type UnknownNormalizedRangeSchema } from "./range.ts";
export declare namespace After {
interface Inner extends BaseRangeInner {
rule: Date;
}
interface NormalizedSchema extends UnknownNormalizedRangeSchema {
rule: LimitSchemaValue;
}
interface ExpandedSchema extends UnknownExpandedRangeSchema {
rule: LimitSchemaValue;
}
type Schema = ExpandedSchema | LimitSchemaValue;
interface ErrorContext extends BaseErrorContext<"after">, Inner {
}
interface Declaration extends declareNode<{
kind: "after";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: Date;
errorContext: ErrorContext;
}> {
}
type Node = AfterNode;
}
export declare class AfterNode extends BaseRange<After.Declaration> {
impliedBasis: BaseRoot;
collapsibleLimitString: string;
traverseAllows: TraverseAllows<Date>;
reduceJsonSchema(base: JsonSchema, ctx: ToJsonSchema.Context): JsonSchema;
}
export declare const After: {
implementation: nodeImplementationOf<After.Declaration>;
Node: typeof AfterNode;
};

View File

@@ -0,0 +1,35 @@
import { describeCollapsibleDate } from "@ark/util";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { BaseRange, createDateSchemaNormalizer, parseDateLimit } from "./range.js";
const implementation = implementNode({
kind: "after",
collapsibleKey: "rule",
hasAssociatedError: true,
keys: {
rule: {
parse: parseDateLimit,
serialize: schema => schema.toISOString()
}
},
normalize: createDateSchemaNormalizer("after"),
defaults: {
description: node => `${node.collapsibleLimitString} or later`,
actual: describeCollapsibleDate
},
intersections: {
after: (l, r) => (l.isStricterThan(r) ? l : r)
}
});
export class AfterNode extends BaseRange {
impliedBasis = $ark.intrinsic.Date.internal;
collapsibleLimitString = describeCollapsibleDate(this.rule);
traverseAllows = data => data >= this.rule;
reduceJsonSchema(base, ctx) {
return ctx.fallback.date({ code: "date", base, after: this.rule });
}
}
export const After = {
implementation,
Node: AfterNode
};

View File

@@ -0,0 +1,41 @@
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { BaseRange, type BaseRangeInner, type LimitSchemaValue, type UnknownExpandedRangeSchema, type UnknownNormalizedRangeSchema } from "./range.ts";
export declare namespace Before {
interface Inner extends BaseRangeInner {
rule: Date;
}
interface NormalizedSchema extends UnknownNormalizedRangeSchema {
rule: LimitSchemaValue;
}
interface ExpandedSchema extends UnknownExpandedRangeSchema {
rule: LimitSchemaValue;
}
type Schema = ExpandedSchema | LimitSchemaValue;
interface ErrorContext extends BaseErrorContext<"before">, Inner {
}
interface Declaration extends declareNode<{
kind: "before";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: Date;
errorContext: ErrorContext;
}> {
}
type Node = BeforeNode;
}
export declare class BeforeNode extends BaseRange<Before.Declaration> {
collapsibleLimitString: string;
traverseAllows: TraverseAllows<Date>;
impliedBasis: BaseRoot;
reduceJsonSchema(base: JsonSchema, ctx: ToJsonSchema.Context): JsonSchema;
}
export declare const Before: {
implementation: nodeImplementationOf<Before.Declaration>;
Node: typeof BeforeNode;
};

View File

@@ -0,0 +1,41 @@
import { describeCollapsibleDate } from "@ark/util";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { BaseRange, createDateSchemaNormalizer, parseDateLimit } from "./range.js";
const implementation = implementNode({
kind: "before",
collapsibleKey: "rule",
hasAssociatedError: true,
keys: {
rule: {
parse: parseDateLimit,
serialize: schema => schema.toISOString()
}
},
normalize: createDateSchemaNormalizer("before"),
defaults: {
description: node => `${node.collapsibleLimitString} or earlier`,
actual: describeCollapsibleDate
},
intersections: {
before: (l, r) => (l.isStricterThan(r) ? l : r),
after: (before, after, ctx) => before.overlapsRange(after) ?
before.overlapIsUnit(after) ?
ctx.$.node("unit", { unit: before.rule })
: null
: Disjoint.init("range", before, after)
}
});
export class BeforeNode extends BaseRange {
collapsibleLimitString = describeCollapsibleDate(this.rule);
traverseAllows = data => data <= this.rule;
impliedBasis = $ark.intrinsic.Date.internal;
reduceJsonSchema(base, ctx) {
return ctx.fallback.date({ code: "date", base, before: this.rule });
}
}
export const Before = {
implementation,
Node: BeforeNode
};

View File

@@ -0,0 +1,43 @@
import { InternalPrimitiveConstraint, writeInvalidOperandMessage } from "../constraint.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
export declare namespace Divisor {
interface Inner {
readonly rule: number;
}
interface NormalizedSchema extends BaseNormalizedSchema {
readonly rule: number;
}
type Schema = NormalizedSchema | number;
interface ErrorContext extends BaseErrorContext<"divisor">, Inner {
}
interface Declaration extends declareNode<{
kind: "divisor";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: number;
errorContext: ErrorContext;
}> {
}
type Node = DivisorNode;
}
export declare class DivisorNode extends InternalPrimitiveConstraint<Divisor.Declaration> {
traverseAllows: TraverseAllows<number>;
readonly compiledCondition: string;
readonly compiledNegation: string;
readonly impliedBasis: BaseRoot;
readonly expression: string;
reduceJsonSchema(schema: JsonSchema.Numeric): JsonSchema.Numeric;
}
export declare const Divisor: {
implementation: nodeImplementationOf<Divisor.Declaration>;
Node: typeof DivisorNode;
};
export declare const writeIndivisibleMessage: (t: BaseRoot) => string;
export type writeIndivisibleMessage<actual> = writeInvalidOperandMessage<"divisor", actual>;
export declare const writeNonIntegerDivisorMessage: <divisor extends number>(divisor: divisor) => writeNonIntegerDivisorMessage<divisor>;
export type writeNonIntegerDivisorMessage<divisor extends number> = `divisor must be an integer (was ${divisor})`;

View File

@@ -0,0 +1,58 @@
import { throwParseError } from "@ark/util";
import { InternalPrimitiveConstraint, writeInvalidOperandMessage } from "../constraint.js";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
const implementation = implementNode({
kind: "divisor",
collapsibleKey: "rule",
keys: {
rule: {
parse: divisor => Number.isInteger(divisor) ? divisor : (throwParseError(writeNonIntegerDivisorMessage(divisor)))
}
},
normalize: schema => typeof schema === "number" ? { rule: schema } : schema,
hasAssociatedError: true,
defaults: {
description: node => node.rule === 1 ? "an integer"
: node.rule === 2 ? "even"
: `a multiple of ${node.rule}`
},
intersections: {
divisor: (l, r, ctx) => ctx.$.node("divisor", {
rule: Math.abs((l.rule * r.rule) / greatestCommonDivisor(l.rule, r.rule))
})
},
obviatesBasisDescription: true
});
export class DivisorNode extends InternalPrimitiveConstraint {
traverseAllows = data => data % this.rule === 0;
compiledCondition = `data % ${this.rule} === 0`;
compiledNegation = `data % ${this.rule} !== 0`;
impliedBasis = $ark.intrinsic.number.internal;
expression = `% ${this.rule}`;
reduceJsonSchema(schema) {
schema.type = "integer";
if (this.rule === 1)
return schema;
schema.multipleOf = this.rule;
return schema;
}
}
export const Divisor = {
implementation,
Node: DivisorNode
};
export const writeIndivisibleMessage = (t) => writeInvalidOperandMessage("divisor", $ark.intrinsic.number, t);
export const writeNonIntegerDivisorMessage = (divisor) => `divisor must be an integer (was ${divisor})`;
// https://en.wikipedia.org/wiki/Euclidean_algorithm
const greatestCommonDivisor = (l, r) => {
let previous;
let greatestCommonDivisor = l;
let current = r;
while (current !== 0) {
previous = current;
current = greatestCommonDivisor % current;
greatestCommonDivisor = previous;
}
return greatestCommonDivisor;
};

View File

@@ -0,0 +1,49 @@
import { InternalPrimitiveConstraint } from "../constraint.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { type LengthBoundableData } from "./range.ts";
export declare namespace ExactLength {
interface Inner {
readonly rule: number;
}
interface NormalizedSchema extends BaseNormalizedSchema {
readonly rule: number;
}
type Schema = NormalizedSchema | number;
interface ErrorContext extends BaseErrorContext<"exactLength">, Inner {
}
type Declaration = declareNode<{
kind: "exactLength";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: LengthBoundableData;
errorContext: ErrorContext;
}>;
type Node = ExactLengthNode;
}
export declare class ExactLengthNode extends InternalPrimitiveConstraint<ExactLength.Declaration> {
traverseAllows: TraverseAllows<LengthBoundableData>;
readonly compiledCondition: string;
readonly compiledNegation: string;
readonly impliedBasis: BaseRoot;
readonly expression: string;
reduceJsonSchema(schema: JsonSchema.LengthBoundable): JsonSchema.LengthBoundable;
}
export declare const ExactLength: {
implementation: nodeImplementationOf<{
intersectionIsOpen: false;
childKind: never;
reducibleTo: "exactLength";
kind: "exactLength";
schema: ExactLength.Schema;
normalizedSchema: ExactLength.NormalizedSchema;
inner: ExactLength.Inner;
prerequisite: LengthBoundableData;
errorContext: ExactLength.ErrorContext;
}>;
Node: typeof ExactLengthNode;
};

View File

@@ -0,0 +1,55 @@
import { InternalPrimitiveConstraint } from "../constraint.js";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { ToJsonSchema } from "../shared/toJsonSchema.js";
import { createLengthRuleParser } from "./range.js";
const implementation = implementNode({
kind: "exactLength",
collapsibleKey: "rule",
keys: {
rule: {
parse: createLengthRuleParser("exactLength")
}
},
normalize: schema => typeof schema === "number" ? { rule: schema } : schema,
hasAssociatedError: true,
defaults: {
description: node => `exactly length ${node.rule}`,
actual: data => `${data.length}`
},
intersections: {
exactLength: (l, r, ctx) => Disjoint.init("unit", ctx.$.node("unit", { unit: l.rule }), ctx.$.node("unit", { unit: r.rule }), { path: ["length"] }),
minLength: (exactLength, minLength) => exactLength.rule >= minLength.rule ?
exactLength
: Disjoint.init("range", exactLength, minLength),
maxLength: (exactLength, maxLength) => exactLength.rule <= maxLength.rule ?
exactLength
: Disjoint.init("range", exactLength, maxLength)
}
});
export class ExactLengthNode extends InternalPrimitiveConstraint {
traverseAllows = data => data.length === this.rule;
compiledCondition = `data.length === ${this.rule}`;
compiledNegation = `data.length !== ${this.rule}`;
impliedBasis = $ark.intrinsic.lengthBoundable.internal;
expression = `== ${this.rule}`;
reduceJsonSchema(schema) {
switch (schema.type) {
case "string":
schema.minLength = this.rule;
schema.maxLength = this.rule;
return schema;
case "array":
schema.minItems = this.rule;
schema.maxItems = this.rule;
return schema;
default:
return ToJsonSchema.throwInternalOperandError("exactLength", schema);
}
}
}
export const ExactLength = {
implementation,
Node: ExactLengthNode
};

View File

@@ -0,0 +1,34 @@
import type { BaseConstraint } from "../constraint.ts";
import type { nodeImplementationOf } from "../shared/implement.ts";
import { After } from "./after.ts";
import { Before } from "./before.ts";
import { ExactLength } from "./exactLength.ts";
import { Max } from "./max.ts";
import { MaxLength } from "./maxLength.ts";
import { Min } from "./min.ts";
import { MinLength } from "./minLength.ts";
export interface BoundDeclarations {
min: Min.Declaration;
max: Max.Declaration;
minLength: MinLength.Declaration;
maxLength: MaxLength.Declaration;
exactLength: ExactLength.Declaration;
after: After.Declaration;
before: Before.Declaration;
}
export interface BoundNodesByKind {
min: Min.Node;
max: Max.Node;
minLength: MinLength.Node;
maxLength: MaxLength.Node;
exactLength: ExactLength.Node;
after: After.Node;
before: Before.Node;
}
export type BoundKind = keyof BoundDeclarations;
export type RangeKind = Exclude<BoundKind, "exactLength">;
export type boundImplementationsByKind = {
[k in BoundKind]: nodeImplementationOf<BoundDeclarations[k]>;
};
export declare const boundImplementationsByKind: boundImplementationsByKind;
export declare const boundClassesByKind: Record<BoundKind, typeof BaseConstraint<any>>;

View File

@@ -0,0 +1,25 @@
import { After } from "./after.js";
import { Before } from "./before.js";
import { ExactLength } from "./exactLength.js";
import { Max } from "./max.js";
import { MaxLength } from "./maxLength.js";
import { Min } from "./min.js";
import { MinLength } from "./minLength.js";
export const boundImplementationsByKind = {
min: Min.implementation,
max: Max.implementation,
minLength: MinLength.implementation,
maxLength: MaxLength.implementation,
exactLength: ExactLength.implementation,
after: After.implementation,
before: Before.implementation
};
export const boundClassesByKind = {
min: Min.Node,
max: Max.Node,
minLength: MinLength.Node,
maxLength: MaxLength.Node,
exactLength: ExactLength.Node,
after: After.Node,
before: Before.Node
};

View File

@@ -0,0 +1,37 @@
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { BaseRange, type BaseRangeInner, type UnknownExpandedRangeSchema } from "./range.ts";
export declare namespace Max {
interface Inner extends BaseRangeInner {
rule: number;
exclusive?: true;
}
interface NormalizedSchema extends UnknownExpandedRangeSchema {
rule: number;
}
type Schema = NormalizedSchema | number;
interface ErrorContext extends BaseErrorContext<"max">, Inner {
}
interface Declaration extends declareNode<{
kind: "max";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: number;
errorContext: ErrorContext;
}> {
}
type Node = MaxNode;
}
export declare class MaxNode extends BaseRange<Max.Declaration> {
impliedBasis: BaseRoot;
traverseAllows: TraverseAllows<number>;
reduceJsonSchema(schema: JsonSchema.Numeric): JsonSchema.Numeric;
}
export declare const Max: {
implementation: nodeImplementationOf<Max.Declaration>;
Node: typeof MaxNode;
};

View File

@@ -0,0 +1,45 @@
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { BaseRange, parseExclusiveKey } from "./range.js";
const implementation = implementNode({
kind: "max",
collapsibleKey: "rule",
hasAssociatedError: true,
keys: {
rule: {},
exclusive: parseExclusiveKey
},
normalize: schema => typeof schema === "number" ? { rule: schema } : schema,
defaults: {
description: node => {
if (node.rule === 0)
return node.exclusive ? "negative" : "non-positive";
return `${node.exclusive ? "less than" : "at most"} ${node.rule}`;
}
},
intersections: {
max: (l, r) => (l.isStricterThan(r) ? l : r),
min: (max, min, ctx) => max.overlapsRange(min) ?
max.overlapIsUnit(min) ?
ctx.$.node("unit", { unit: max.rule })
: null
: Disjoint.init("range", max, min)
},
obviatesBasisDescription: true
});
export class MaxNode extends BaseRange {
impliedBasis = $ark.intrinsic.number.internal;
traverseAllows = this.exclusive ? data => data < this.rule : data => data <= this.rule;
reduceJsonSchema(schema) {
if (this.exclusive)
schema.exclusiveMaximum = this.rule;
else
schema.maximum = this.rule;
return schema;
}
}
export const Max = {
implementation,
Node: MaxNode
};

View File

@@ -0,0 +1,40 @@
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { BaseRange, type BaseRangeInner, type LengthBoundableData, type UnknownExpandedRangeSchema, type UnknownNormalizedRangeSchema } from "./range.ts";
export declare namespace MaxLength {
interface Inner extends BaseRangeInner {
rule: number;
}
interface NormalizedSchema extends UnknownNormalizedRangeSchema {
rule: number;
}
interface ExpandedSchema extends UnknownExpandedRangeSchema {
rule: number;
}
type Schema = ExpandedSchema | number;
interface ErrorContext extends BaseErrorContext<"maxLength">, Inner {
}
interface Declaration extends declareNode<{
kind: "maxLength";
schema: Schema;
reducibleTo: "exactLength";
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: LengthBoundableData;
errorContext: ErrorContext;
}> {
}
type Node = MaxLengthNode;
}
export declare class MaxLengthNode extends BaseRange<MaxLength.Declaration> {
readonly impliedBasis: BaseRoot;
traverseAllows: TraverseAllows<LengthBoundableData>;
reduceJsonSchema(schema: JsonSchema.LengthBoundable): JsonSchema.LengthBoundable;
}
export declare const MaxLength: {
implementation: nodeImplementationOf<MaxLength.Declaration>;
Node: typeof MaxLengthNode;
};

View File

@@ -0,0 +1,49 @@
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { ToJsonSchema } from "../shared/toJsonSchema.js";
import { BaseRange, createLengthRuleParser, createLengthSchemaNormalizer } from "./range.js";
const implementation = implementNode({
kind: "maxLength",
collapsibleKey: "rule",
hasAssociatedError: true,
keys: {
rule: {
parse: createLengthRuleParser("maxLength")
}
},
reduce: (inner, $) => inner.rule === 0 ? $.node("exactLength", inner) : undefined,
normalize: createLengthSchemaNormalizer("maxLength"),
defaults: {
description: node => `at most length ${node.rule}`,
actual: data => `${data.length}`
},
intersections: {
maxLength: (l, r) => (l.isStricterThan(r) ? l : r),
minLength: (max, min, ctx) => max.overlapsRange(min) ?
max.overlapIsUnit(min) ?
ctx.$.node("exactLength", { rule: max.rule })
: null
: Disjoint.init("range", max, min)
}
});
export class MaxLengthNode extends BaseRange {
impliedBasis = $ark.intrinsic.lengthBoundable.internal;
traverseAllows = data => data.length <= this.rule;
reduceJsonSchema(schema) {
switch (schema.type) {
case "string":
schema.maxLength = this.rule;
return schema;
case "array":
schema.maxItems = this.rule;
return schema;
default:
return ToJsonSchema.throwInternalOperandError("maxLength", schema);
}
}
}
export const MaxLength = {
implementation,
Node: MaxLengthNode
};

View File

@@ -0,0 +1,37 @@
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { BaseRange, type BaseRangeInner, type UnknownExpandedRangeSchema } from "./range.ts";
export declare namespace Min {
interface Inner extends BaseRangeInner {
rule: number;
exclusive?: true;
}
interface NormalizedSchema extends UnknownExpandedRangeSchema {
rule: number;
}
type Schema = NormalizedSchema | number;
interface ErrorContext extends BaseErrorContext<"min">, Inner {
}
interface Declaration extends declareNode<{
kind: "min";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: number;
errorContext: ErrorContext;
}> {
}
type Node = MinNode;
}
export declare class MinNode extends BaseRange<Min.Declaration> {
readonly impliedBasis: BaseRoot;
traverseAllows: TraverseAllows<number>;
reduceJsonSchema(schema: JsonSchema.Numeric): JsonSchema.Numeric;
}
export declare const Min: {
implementation: nodeImplementationOf<Min.Declaration>;
Node: typeof MinNode;
};

View File

@@ -0,0 +1,39 @@
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { BaseRange, parseExclusiveKey } from "./range.js";
const implementation = implementNode({
kind: "min",
collapsibleKey: "rule",
hasAssociatedError: true,
keys: {
rule: {},
exclusive: parseExclusiveKey
},
normalize: schema => typeof schema === "number" ? { rule: schema } : schema,
defaults: {
description: node => {
if (node.rule === 0)
return node.exclusive ? "positive" : "non-negative";
return `${node.exclusive ? "more than" : "at least"} ${node.rule}`;
}
},
intersections: {
min: (l, r) => (l.isStricterThan(r) ? l : r)
},
obviatesBasisDescription: true
});
export class MinNode extends BaseRange {
impliedBasis = $ark.intrinsic.number.internal;
traverseAllows = this.exclusive ? data => data > this.rule : data => data >= this.rule;
reduceJsonSchema(schema) {
if (this.exclusive)
schema.exclusiveMinimum = this.rule;
else
schema.minimum = this.rule;
return schema;
}
}
export const Min = {
implementation,
Node: MinNode
};

View File

@@ -0,0 +1,40 @@
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { BaseRange, type BaseRangeInner, type LengthBoundableData, type UnknownExpandedRangeSchema, type UnknownNormalizedRangeSchema } from "./range.ts";
export declare namespace MinLength {
interface Inner extends BaseRangeInner {
rule: number;
}
interface NormalizedSchema extends UnknownNormalizedRangeSchema {
rule: number;
}
interface ExpandedSchema extends UnknownExpandedRangeSchema {
rule: number;
}
type Schema = ExpandedSchema | number;
interface ErrorContext extends BaseErrorContext<"minLength">, Inner {
}
interface Declaration extends declareNode<{
kind: "minLength";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: LengthBoundableData;
reducibleTo: "intersection";
errorContext: ErrorContext;
}> {
}
type Node = MinLengthNode;
}
export declare class MinLengthNode extends BaseRange<MinLength.Declaration> {
readonly impliedBasis: BaseRoot;
traverseAllows: TraverseAllows<LengthBoundableData>;
reduceJsonSchema(schema: JsonSchema.LengthBoundable): JsonSchema.LengthBoundable;
}
export declare const MinLength: {
implementation: nodeImplementationOf<MinLength.Declaration>;
Node: typeof MinLengthNode;
};

View File

@@ -0,0 +1,47 @@
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { ToJsonSchema } from "../shared/toJsonSchema.js";
import { BaseRange, createLengthRuleParser, createLengthSchemaNormalizer } from "./range.js";
const implementation = implementNode({
kind: "minLength",
collapsibleKey: "rule",
hasAssociatedError: true,
keys: {
rule: {
parse: createLengthRuleParser("minLength")
}
},
reduce: inner => inner.rule === 0 ?
// a minimum length of zero is trivially satisfied
$ark.intrinsic.unknown
: undefined,
normalize: createLengthSchemaNormalizer("minLength"),
defaults: {
description: node => node.rule === 1 ? "non-empty" : `at least length ${node.rule}`,
// avoid default message like "must be non-empty (was 0)"
actual: data => (data.length === 0 ? "" : `${data.length}`)
},
intersections: {
minLength: (l, r) => (l.isStricterThan(r) ? l : r)
}
});
export class MinLengthNode extends BaseRange {
impliedBasis = $ark.intrinsic.lengthBoundable.internal;
traverseAllows = data => data.length >= this.rule;
reduceJsonSchema(schema) {
switch (schema.type) {
case "string":
schema.minLength = this.rule;
return schema;
case "array":
schema.minItems = this.rule;
return schema;
default:
return ToJsonSchema.throwInternalOperandError("minLength", schema);
}
}
}
export const MinLength = {
implementation,
Node: MinLengthNode
};

View File

@@ -0,0 +1,43 @@
import { InternalPrimitiveConstraint } from "../constraint.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
export declare namespace Pattern {
interface NormalizedSchema extends BaseNormalizedSchema {
readonly rule: string;
readonly flags?: string;
}
interface Inner {
readonly rule: string;
readonly flags?: string;
}
type Schema = NormalizedSchema | string | RegExp;
interface ErrorContext extends BaseErrorContext<"pattern">, Inner {
}
interface Declaration extends declareNode<{
kind: "pattern";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
intersectionIsOpen: true;
prerequisite: string;
errorContext: ErrorContext;
}> {
}
type Node = PatternNode;
}
export declare class PatternNode extends InternalPrimitiveConstraint<Pattern.Declaration> {
readonly instance: RegExp;
readonly expression: string;
traverseAllows: (string: string) => boolean;
readonly compiledCondition: string;
readonly compiledNegation: string;
readonly impliedBasis: BaseRoot;
reduceJsonSchema(base: JsonSchema.String, ctx: ToJsonSchema.Context): JsonSchema.String;
}
export declare const Pattern: {
implementation: nodeImplementationOf<Pattern.Declaration>;
Node: typeof PatternNode;
};

View File

@@ -0,0 +1,52 @@
import { InternalPrimitiveConstraint } from "../constraint.js";
import { implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
const implementation = implementNode({
kind: "pattern",
collapsibleKey: "rule",
keys: {
rule: {},
flags: {}
},
normalize: schema => typeof schema === "string" ? { rule: schema }
: schema instanceof RegExp ?
schema.flags ?
{ rule: schema.source, flags: schema.flags }
: { rule: schema.source }
: schema,
obviatesBasisDescription: true,
obviatesBasisExpression: true,
hasAssociatedError: true,
intersectionIsOpen: true,
defaults: {
description: node => `matched by ${node.rule}`
},
intersections: {
// for now, non-equal regex are naively intersected:
// https://github.com/arktypeio/arktype/issues/853
pattern: () => null
}
});
export class PatternNode extends InternalPrimitiveConstraint {
instance = new RegExp(this.rule, this.flags);
expression = `${this.instance}`;
traverseAllows = this.instance.test.bind(this.instance);
compiledCondition = `${this.expression}.test(data)`;
compiledNegation = `!${this.compiledCondition}`;
impliedBasis = $ark.intrinsic.string.internal;
reduceJsonSchema(base, ctx) {
if (base.pattern) {
return ctx.fallback.patternIntersection({
code: "patternIntersection",
base: base,
pattern: this.rule
});
}
base.pattern = this.rule;
return base;
}
}
export const Pattern = {
implementation,
Node: PatternNode
};

View File

@@ -0,0 +1,106 @@
import { type array, type propValueOf, type satisfy } from "@ark/util";
import { InternalPrimitiveConstraint } from "../constraint.ts";
import type { Declaration, nodeOfKind, NodeSchema, NormalizedSchema } from "../kinds.ts";
import type { BaseNodeDeclaration, BaseNormalizedSchema } from "../shared/declare.ts";
import type { keySchemaDefinitions } from "../shared/implement.ts";
import type { RangeKind } from "./kinds.ts";
export interface BaseRangeDeclaration extends BaseNodeDeclaration {
kind: RangeKind;
inner: BaseRangeInner;
normalizedSchema: UnknownExpandedRangeSchema;
}
export declare abstract class BaseRange<d extends BaseRangeDeclaration> extends InternalPrimitiveConstraint<d> {
readonly exclusive?: true;
readonly boundOperandKind: OperandKindsByBoundKind[d["kind"]];
readonly compiledActual: string;
readonly comparator: RelativeComparator;
readonly numericLimit: number;
readonly expression: string;
readonly compiledCondition: string;
readonly compiledNegation: string;
readonly stringLimit: string;
readonly limitKind: LimitKind;
isStricterThan(r: nodeOfKind<d["kind"] | pairedRangeKind<d["kind"]>>): boolean;
overlapsRange(r: nodeOfKind<pairedRangeKind<d["kind"]>>): boolean;
overlapIsUnit(r: nodeOfKind<pairedRangeKind<d["kind"]>>): boolean;
}
export interface BaseRangeInner {
readonly rule: LimitValue;
}
export type LimitValue = Date | number;
export type LimitSchemaValue = Date | number | string;
export type LimitInnerValue<kind extends RangeKind = RangeKind> = kind extends "before" | "after" ? Date : number;
export interface UnknownExpandedRangeSchema extends BaseNormalizedSchema {
readonly rule: LimitSchemaValue;
readonly exclusive?: boolean;
}
export interface UnknownNormalizedRangeSchema extends BaseNormalizedSchema {
readonly rule: LimitSchemaValue;
}
export type UnknownRangeSchema = LimitSchemaValue | UnknownExpandedRangeSchema;
export interface ExclusiveExpandedDateRangeSchema extends BaseNormalizedSchema {
rule: LimitSchemaValue;
exclusive?: true;
}
export type ExclusiveDateRangeSchema = LimitSchemaValue | ExclusiveExpandedDateRangeSchema;
export interface InclusiveExpandedDateRangeSchema extends BaseNormalizedSchema {
rule: LimitSchemaValue;
exclusive?: false;
}
export type InclusiveDateRangeSchema = LimitSchemaValue | InclusiveExpandedDateRangeSchema;
export interface ExclusiveNormalizedNumericRangeSchema extends BaseNormalizedSchema {
rule: number;
exclusive?: true;
}
export type ExclusiveNumericRangeSchema = number | ExclusiveNormalizedNumericRangeSchema;
export interface InclusiveNormalizedNumericRangeSchema extends BaseNormalizedSchema {
rule: number;
exclusive?: false;
}
export type InclusiveNumericRangeSchema = number | InclusiveNormalizedNumericRangeSchema;
export type LimitKind = "lower" | "upper";
export type RelativeComparator<kind extends LimitKind = LimitKind> = {
lower: ">" | ">=";
upper: "<" | "<=";
}[kind];
export declare const boundKindPairsByLower: BoundKindPairsByLower;
type BoundKindPairsByLower = {
min: "max";
minLength: "maxLength";
after: "before";
};
type BoundKindPairsByUpper = {
max: "min";
maxLength: "minLength";
before: "after";
};
export type pairedRangeKind<kind extends RangeKind> = kind extends LowerBoundKind ? BoundKindPairsByLower[kind] : BoundKindPairsByUpper[kind & UpperBoundKind];
export type LowerBoundKind = keyof typeof boundKindPairsByLower;
export type LowerNode = nodeOfKind<LowerBoundKind>;
export type UpperBoundKind = propValueOf<typeof boundKindPairsByLower>;
export type UpperNode = nodeOfKind<UpperBoundKind>;
export type NumericallyBoundable = string | number | array;
export type Boundable = NumericallyBoundable | Date;
export declare const parseExclusiveKey: keySchemaDefinitions<Declaration<"min" | "max">>["exclusive"];
export declare const createLengthSchemaNormalizer: <kind extends "minLength" | "maxLength">(kind: kind) => (schema: NodeSchema<kind>) => NormalizedSchema<kind>;
export declare const createDateSchemaNormalizer: <kind extends DateRangeKind>(kind: kind) => (schema: NodeSchema<kind>) => NormalizedSchema<kind>;
export declare const parseDateLimit: (limit: LimitSchemaValue) => Date;
export type LengthBoundKind = "minLength" | "maxLength" | "exactLength";
export declare const writeInvalidLengthBoundMessage: (kind: LengthBoundKind, limit: number) => string;
export declare const createLengthRuleParser: (kind: LengthBoundKind) => (limit: number) => number | undefined;
type OperandKindsByBoundKind = satisfy<Record<RangeKind, BoundOperandKind>, {
min: "value";
max: "value";
minLength: "length";
maxLength: "length";
after: "date";
before: "date";
}>;
export declare const compileComparator: (kind: RangeKind, exclusive: boolean | undefined) => RelativeComparator;
export type BoundOperandKind = "value" | "length" | "date";
export type LengthBoundableData = string | array;
export type DateRangeKind = "before" | "after";
export declare const dateLimitToString: (limit: LimitSchemaValue) => string;
export declare const writeUnboundableMessage: <root extends string>(root: root) => writeUnboundableMessage<root>;
export type writeUnboundableMessage<root extends string> = `Bounded expression ${root} must be exactly one of number, string, Array, or Date`;
export {};

View File

@@ -0,0 +1,103 @@
import { isKeyOf, throwParseError } from "@ark/util";
import { InternalPrimitiveConstraint } from "../constraint.js";
export class BaseRange extends InternalPrimitiveConstraint {
boundOperandKind = operandKindsByBoundKind[this.kind];
compiledActual = this.boundOperandKind === "value" ? `data`
: this.boundOperandKind === "length" ? `data.length`
: `data.valueOf()`;
comparator = compileComparator(this.kind, this.exclusive);
numericLimit = this.rule.valueOf();
expression = `${this.comparator} ${this.rule}`;
compiledCondition = `${this.compiledActual} ${this.comparator} ${this.numericLimit}`;
compiledNegation = `${this.compiledActual} ${negatedComparators[this.comparator]} ${this.numericLimit}`;
// we need to compute stringLimit before errorContext, which references it
// transitively through description for date bounds
stringLimit = this.boundOperandKind === "date" ?
dateLimitToString(this.numericLimit)
: `${this.numericLimit}`;
limitKind = this.comparator["0"] === "<" ? "upper" : "lower";
isStricterThan(r) {
const thisLimitIsStricter = this.limitKind === "upper" ?
this.numericLimit < r.numericLimit
: this.numericLimit > r.numericLimit;
return (thisLimitIsStricter ||
(this.numericLimit === r.numericLimit &&
this.exclusive === true &&
!r.exclusive));
}
overlapsRange(r) {
if (this.isStricterThan(r))
return false;
if (this.numericLimit === r.numericLimit && (this.exclusive || r.exclusive))
return false;
return true;
}
overlapIsUnit(r) {
return (this.numericLimit === r.numericLimit && !this.exclusive && !r.exclusive);
}
}
const negatedComparators = {
"<": ">=",
"<=": ">",
">": "<=",
">=": "<"
};
export const boundKindPairsByLower = {
min: "max",
minLength: "maxLength",
after: "before"
};
export const parseExclusiveKey = {
// omit key with value false since it is the default
parse: (flag) => flag || undefined
};
export const createLengthSchemaNormalizer = (kind) => (schema) => {
if (typeof schema === "number")
return { rule: schema };
const { exclusive, ...normalized } = schema;
return exclusive ?
{
...normalized,
rule: kind === "minLength" ? normalized.rule + 1 : normalized.rule - 1
}
: normalized;
};
export const createDateSchemaNormalizer = (kind) => (schema) => {
if (typeof schema === "number" ||
typeof schema === "string" ||
schema instanceof Date)
return { rule: schema };
const { exclusive, ...normalized } = schema;
if (!exclusive)
return normalized;
const numericLimit = typeof normalized.rule === "number" ? normalized.rule
: typeof normalized.rule === "string" ?
new Date(normalized.rule).valueOf()
: normalized.rule.valueOf();
return exclusive ?
{
...normalized,
rule: kind === "after" ? numericLimit + 1 : numericLimit - 1
}
: normalized;
};
export const parseDateLimit = (limit) => typeof limit === "string" || typeof limit === "number" ?
new Date(limit)
: limit;
export const writeInvalidLengthBoundMessage = (kind, limit) => `${kind} bound must be a positive integer (was ${limit})`;
export const createLengthRuleParser = (kind) => (limit) => {
if (!Number.isInteger(limit) || limit < 0)
throwParseError(writeInvalidLengthBoundMessage(kind, limit));
return limit;
};
const operandKindsByBoundKind = {
min: "value",
max: "value",
minLength: "length",
maxLength: "length",
after: "date",
before: "date"
};
export const compileComparator = (kind, exclusive) => `${isKeyOf(kind, boundKindPairsByLower) ? ">" : "<"}${exclusive ? "" : "="}`;
export const dateLimitToString = (limit) => typeof limit === "string" ? limit : new Date(limit).toLocaleString();
export const writeUnboundableMessage = (root) => `Bounded expression ${root} must be exactly one of number, string, Array, or Date`;

45
frontend/node_modules/@ark/schema/out/roots/alias.d.ts generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import { type NodeId } from "../parse.ts";
import type { NodeCompiler } from "../shared/compile.ts";
import type { BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows, TraverseApply } from "../shared/traversal.ts";
import { BaseRoot } from "./root.ts";
export declare namespace Alias {
type Schema<alias extends string = string> = `$${alias}` | NormalizedSchema<alias>;
interface NormalizedSchema<alias extends string = string> extends BaseNormalizedSchema {
readonly reference: alias;
readonly resolve?: () => BaseRoot;
}
interface Inner<alias extends string = string> {
readonly reference: alias;
readonly resolve?: () => BaseRoot;
}
interface Declaration extends declareNode<{
kind: "alias";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
}> {
}
type Node = AliasNode;
}
export declare const normalizeAliasSchema: (schema: Alias.Schema) => Alias.Inner;
export declare class AliasNode extends BaseRoot<Alias.Declaration> {
readonly expression: string;
readonly structure: undefined;
get resolution(): BaseRoot;
protected _resolve(): BaseRoot;
get resolutionId(): NodeId;
get defaultShortDescription(): string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
traverseAllows: TraverseAllows;
traverseApply: TraverseApply;
compile(js: NodeCompiler): void;
}
export declare const writeShallowCycleErrorMessage: (name: string, seen: string[]) => string;
export declare const Alias: {
implementation: nodeImplementationOf<Alias.Declaration>;
Node: typeof AliasNode;
};

115
frontend/node_modules/@ark/schema/out/roots/alias.js generated vendored Normal file
View File

@@ -0,0 +1,115 @@
import { append, domainDescriptions, printable, throwInternalError, throwParseError } from "@ark/util";
import { nodesByRegisteredId } from "../parse.js";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark } from "../shared/registry.js";
import { hasArkKind } from "../shared/utils.js";
import { BaseRoot } from "./root.js";
import { defineRightwardIntersections } from "./utils.js";
export const normalizeAliasSchema = (schema) => typeof schema === "string" ? { reference: schema } : schema;
const neverIfDisjoint = (result) => result instanceof Disjoint ? $ark.intrinsic.never.internal : result;
const implementation = implementNode({
kind: "alias",
hasAssociatedError: false,
collapsibleKey: "reference",
keys: {
reference: {
serialize: s => (s.startsWith("$") ? s : `$ark.${s}`)
},
resolve: {}
},
normalize: normalizeAliasSchema,
defaults: {
description: node => node.reference
},
intersections: {
alias: (l, r, ctx) => ctx.$.lazilyResolve(() => neverIfDisjoint(intersectOrPipeNodes(l.resolution, r.resolution, ctx)), `${l.reference}${ctx.pipe ? "=>" : "&"}${r.reference}`),
...defineRightwardIntersections("alias", (l, r, ctx) => {
if (r.isUnknown())
return l;
if (r.isNever())
return r;
if (r.isBasis() && !r.overlaps($ark.intrinsic.object)) {
// can be more robust as part of https://github.com/arktypeio/arktype/issues/1026
return Disjoint.init("assignability", $ark.intrinsic.object, r);
}
return ctx.$.lazilyResolve(() => neverIfDisjoint(intersectOrPipeNodes(l.resolution, r, ctx)), `${l.reference}${ctx.pipe ? "=>" : "&"}${r.id}`);
})
}
});
export class AliasNode extends BaseRoot {
expression = this.reference;
structure = undefined;
get resolution() {
const result = this._resolve();
return (nodesByRegisteredId[this.id] = result);
}
_resolve() {
if (this.resolve)
return this.resolve();
if (this.reference[0] === "$")
return this.$.resolveRoot(this.reference.slice(1));
const id = this.reference;
let resolution = nodesByRegisteredId[id];
const seen = [];
while (hasArkKind(resolution, "context")) {
if (seen.includes(resolution.id)) {
return throwParseError(writeShallowCycleErrorMessage(resolution.id, seen));
}
seen.push(resolution.id);
resolution = nodesByRegisteredId[resolution.id];
}
if (!hasArkKind(resolution, "root")) {
return throwInternalError(`Unexpected resolution for reference ${this.reference}
Seen: [${seen.join("->")}]
Resolution: ${printable(resolution)}`);
}
return resolution;
}
get resolutionId() {
if (this.reference.includes("&") || this.reference.includes("=>"))
return this.resolution.id;
if (this.reference[0] !== "$")
return this.reference;
const alias = this.reference.slice(1);
const resolution = this.$.resolutions[alias];
if (typeof resolution === "string")
return resolution;
if (hasArkKind(resolution, "root"))
return resolution.id;
return throwInternalError(`Unexpected resolution for reference ${this.reference}: ${printable(resolution)}`);
}
get defaultShortDescription() {
return domainDescriptions.object;
}
innerToJsonSchema(ctx) {
return this.resolution.toJsonSchemaRecurse(ctx);
}
traverseAllows = (data, ctx) => {
const seen = ctx.seen[this.reference];
if (seen?.includes(data))
return true;
ctx.seen[this.reference] = append(seen, data);
return this.resolution.traverseAllows(data, ctx);
};
traverseApply = (data, ctx) => {
const seen = ctx.seen[this.reference];
if (seen?.includes(data))
return;
ctx.seen[this.reference] = append(seen, data);
this.resolution.traverseApply(data, ctx);
};
compile(js) {
const id = this.resolutionId;
js.if(`ctx.seen.${id} && ctx.seen.${id}.includes(data)`, () => js.return(true));
js.if(`!ctx.seen.${id}`, () => js.line(`ctx.seen.${id} = []`));
js.line(`ctx.seen.${id}.push(data)`);
js.return(js.invoke(id));
}
}
export const writeShallowCycleErrorMessage = (name, seen) => `Alias '${name}' has a shallow resolution cycle: ${[...seen, name].join("->")}`;
export const Alias = {
implementation,
Node: AliasNode
};

12
frontend/node_modules/@ark/schema/out/roots/basis.d.ts generated vendored Normal file
View File

@@ -0,0 +1,12 @@
import type { NodeCompiler } from "../shared/compile.ts";
import type { TraverseApply } from "../shared/traversal.ts";
import { BaseRoot, type InternalRootDeclaration } from "./root.ts";
export declare abstract class InternalBasis<d extends InternalRootDeclaration = InternalRootDeclaration> extends BaseRoot<d> {
abstract compiledCondition: string;
abstract compiledNegation: string;
structure: undefined;
traverseApply: TraverseApply<d["prerequisite"]>;
get errorContext(): d["errorContext"];
get compiledErrorContext(): string;
compile(js: NodeCompiler): void;
}

26
frontend/node_modules/@ark/schema/out/roots/basis.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
import { compileObjectLiteral } from "../shared/implement.js";
import { BaseRoot } from "./root.js";
export class InternalBasis extends BaseRoot {
traverseApply = (data, ctx) => {
if (!this.traverseAllows(data, ctx))
ctx.errorFromNodeContext(this.errorContext);
};
get errorContext() {
return {
code: this.kind,
description: this.description,
meta: this.meta,
...this.inner
};
}
get compiledErrorContext() {
return compileObjectLiteral(this.errorContext);
}
compile(js) {
if (js.traversalKind === "Allows")
js.return(this.compiledCondition);
else {
js.if(this.compiledNegation, () => js.line(`ctx.errorFromNodeContext(${this.compiledErrorContext})`));
}
}
}

View File

@@ -0,0 +1,45 @@
import { type Domain as _Domain } from "@ark/util";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { InternalBasis } from "./basis.ts";
export type Domain = _Domain;
export declare namespace Domain {
type Enumerable = "undefined" | "null" | "boolean";
type NonEnumerable = Exclude<Domain, Enumerable>;
interface Inner<domain extends NonEnumerable = NonEnumerable> {
readonly domain: domain;
readonly numberAllowsNaN?: boolean;
}
interface NormalizedSchema<domain extends NonEnumerable = NonEnumerable> extends BaseNormalizedSchema, Inner<domain> {
}
type Schema<domain extends NonEnumerable = NonEnumerable> = domain | NormalizedSchema<domain>;
interface ErrorContext extends BaseErrorContext<"domain">, Inner {
}
interface Declaration extends declareNode<{
kind: "domain";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
errorContext: ErrorContext;
}> {
}
type Node = DomainNode;
}
export declare class DomainNode extends InternalBasis<Domain.Declaration> {
private readonly requiresNaNCheck;
readonly traverseAllows: TraverseAllows;
readonly compiledCondition: string;
readonly compiledNegation: string;
readonly expression: string;
get nestableExpression(): string;
get defaultShortDescription(): string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema.Constrainable;
}
export declare const Domain: {
implementation: nodeImplementationOf<Domain.Declaration>;
Node: typeof DomainNode;
writeBadAllowNanMessage: (actual: Exclude<Domain.NonEnumerable, "number">) => string;
};

72
frontend/node_modules/@ark/schema/out/roots/domain.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
import { domainDescriptions, domainOf, hasKey, throwParseError } from "@ark/util";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { InternalBasis } from "./basis.js";
const implementation = implementNode({
kind: "domain",
hasAssociatedError: true,
collapsibleKey: "domain",
keys: {
domain: {},
numberAllowsNaN: {}
},
normalize: schema => typeof schema === "string" ? { domain: schema }
: hasKey(schema, "numberAllowsNaN") && schema.domain !== "number" ?
throwParseError(Domain.writeBadAllowNanMessage(schema.domain))
: schema,
applyConfig: (schema, config) => (schema.numberAllowsNaN === undefined &&
schema.domain === "number" &&
config.numberAllowsNaN) ?
{ ...schema, numberAllowsNaN: true }
: schema,
defaults: {
description: node => domainDescriptions[node.domain],
actual: data => Number.isNaN(data) ? "NaN" : domainDescriptions[domainOf(data)]
},
intersections: {
domain: (l, r) =>
// since l === r is handled by default, remaining cases are disjoint
// outside those including options like numberAllowsNaN
l.domain === "number" && r.domain === "number" ?
l.numberAllowsNaN ?
r
: l
: Disjoint.init("domain", l, r)
}
});
export class DomainNode extends InternalBasis {
requiresNaNCheck = this.domain === "number" && !this.numberAllowsNaN;
traverseAllows = this.requiresNaNCheck ?
data => typeof data === "number" && !Number.isNaN(data)
: data => domainOf(data) === this.domain;
compiledCondition = this.domain === "object" ?
`((typeof data === "object" && data !== null) || typeof data === "function")`
: `typeof data === "${this.domain}"${this.requiresNaNCheck ? " && !Number.isNaN(data)" : ""}`;
compiledNegation = this.domain === "object" ?
`((typeof data !== "object" || data === null) && typeof data !== "function")`
: `typeof data !== "${this.domain}"${this.requiresNaNCheck ? " || Number.isNaN(data)" : ""}`;
expression = this.numberAllowsNaN ? "number | NaN" : this.domain;
get nestableExpression() {
return this.numberAllowsNaN ? `(${this.expression})` : this.expression;
}
get defaultShortDescription() {
return domainDescriptions[this.domain];
}
innerToJsonSchema(ctx) {
if (this.domain === "bigint" || this.domain === "symbol") {
return ctx.fallback.domain({
code: "domain",
base: {},
domain: this.domain
});
}
return {
type: this.domain
};
}
}
export const Domain = {
implementation,
Node: DomainNode,
writeBadAllowNanMessage: (actual) => `numberAllowsNaN may only be specified with domain "number" (was ${actual})`
};

View File

@@ -0,0 +1,98 @@
import { type array, type listable, type show } from "@ark/util";
import type { nodeOfKind, NodeSchema, Prerequisite, RootSchema } from "../kinds.ts";
import type { PredicateNode } from "../predicate.ts";
import type { NodeCompiler } from "../shared/compile.ts";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import type { ArkError } from "../shared/errors.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";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows, TraverseApply } from "../shared/traversal.ts";
import { type makeRootAndArrayPropertiesMutable } from "../shared/utils.ts";
import type { Structure, UndeclaredKeyBehavior } from "../structure/structure.ts";
import type { Domain } from "./domain.ts";
import type { Morph } from "./morph.ts";
import type { Proto } from "./proto.ts";
import { BaseRoot } from "./root.ts";
export declare namespace Intersection {
type BasisKind = "domain" | "proto";
type ChildKind = BasisKind | RefinementKind;
type FlattenedChildKind = ChildKind | StructuralKind;
type RefinementsInner = {
[k in RefinementKind]?: intersectionChildInnerValueOf<k>;
};
interface Inner extends RefinementsInner {
domain?: Domain.Node;
proto?: Proto.Node;
structure?: Structure.Node;
predicate?: array<PredicateNode>;
}
namespace Inner {
type mutable = makeRootAndArrayPropertiesMutable<Inner>;
}
type ConstraintsSchema<inferredBasis = any> = show<BaseNormalizedSchema & {
domain?: Domain.Schema;
proto?: Proto.Schema;
} & conditionalRootOf<inferredBasis>>;
type NormalizedSchema = Omit<ConstraintsSchema, StructuralKind | "undeclared">;
type Schema<inferredBasis = any> = ConstraintsSchema<inferredBasis>;
interface AstSchema extends BaseNormalizedSchema {
intersection: readonly RootSchema[];
}
interface ErrorContext extends BaseErrorContext<"intersection">, Inner {
errors: readonly ArkError[];
}
type Declaration = declareNode<{
kind: "intersection";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
reducibleTo: "intersection" | BasisKind;
errorContext: ErrorContext;
childKind: ChildKind;
}>;
type Node = IntersectionNode;
}
export declare class IntersectionNode extends BaseRoot<Intersection.Declaration> {
basis: nodeOfKind<Intersection.BasisKind> | null;
prestructurals: array<nodeOfKind<PrestructuralKind>>;
refinements: array<nodeOfKind<RefinementKind>>;
structure: Structure.Node | undefined;
expression: string;
get shallowMorphs(): array<Morph>;
get defaultShortDescription(): string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
traverseAllows: TraverseAllows;
traverseApply: TraverseApply;
compile(js: NodeCompiler): void;
}
export declare const Intersection: {
implementation: nodeImplementationOf<{
intersectionIsOpen: false;
prerequisite: unknown;
kind: "intersection";
schema: Intersection.Schema;
normalizedSchema: Intersection.NormalizedSchema;
inner: Intersection.Inner;
reducibleTo: "intersection" | Intersection.BasisKind;
errorContext: Intersection.ErrorContext;
childKind: Intersection.ChildKind;
}>;
Node: typeof IntersectionNode;
};
export type ConditionalTerminalIntersectionRoot = {
undeclared?: UndeclaredKeyBehavior;
};
type ConditionalTerminalIntersectionKey = keyof ConditionalTerminalIntersectionRoot;
type ConditionalIntersectionKey = ConstraintKind | ConditionalTerminalIntersectionKey;
export type constraintKindOf<t> = {
[k in ConstraintKind]: t extends Prerequisite<k> ? k : never;
}[ConstraintKind];
type conditionalIntersectionKeyOf<t> = constraintKindOf<t> | (t extends object ? "undeclared" : never);
type intersectionChildSchemaValueOf<k extends Intersection.FlattenedChildKind> = k extends OpenNodeKind ? listable<NodeSchema<k>> : NodeSchema<k>;
type conditionalSchemaValueOfKey<k extends ConditionalIntersectionKey> = k extends Intersection.FlattenedChildKind ? intersectionChildSchemaValueOf<k> : ConditionalTerminalIntersectionRoot[k & ConditionalTerminalIntersectionKey];
type intersectionChildInnerValueOf<k extends Intersection.FlattenedChildKind> = k extends OpenNodeKind ? readonly nodeOfKind<k>[] : nodeOfKind<k>;
export type conditionalRootOf<t> = {
[k in conditionalIntersectionKeyOf<t>]?: conditionalSchemaValueOfKey<k>;
};
export {};

View File

@@ -0,0 +1,292 @@
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, prestructuralKinds, structureKeys } from "../shared/implement.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { hasArkKind, isNode } from "../shared/utils.js";
import { BaseRoot } from "./root.js";
import { defineRightwardIntersections } from "./utils.js";
const implementation = implementNode({
kind: "intersection",
hasAssociatedError: true,
normalize: rawSchema => {
if (isNode(rawSchema))
return rawSchema;
const { structure, ...schema } = rawSchema;
const hasRootStructureKey = !!structure;
const normalizedStructure = structure ?? {};
const normalized = flatMorph(schema, (k, v) => {
if (isKeyOf(k, structureKeys)) {
if (hasRootStructureKey) {
throwParseError(`Flattened structure key ${k} cannot be specified alongside a root 'structure' key.`);
}
normalizedStructure[k] = v;
return [];
}
return [k, v];
});
if (hasArkKind(normalizedStructure, "constraint") ||
!isEmptyObject(normalizedStructure))
normalized.structure = normalizedStructure;
return normalized;
},
finalizeInnerJson: ({ structure, ...rest }) => hasDomain(structure, "object") ? { ...structure, ...rest } : rest,
keys: {
domain: {
child: true,
parse: (schema, ctx) => ctx.$.node("domain", schema)
},
proto: {
child: true,
parse: (schema, ctx) => ctx.$.node("proto", schema)
},
structure: {
child: true,
parse: (schema, ctx) => ctx.$.node("structure", schema),
serialize: node => {
if (!node.sequence?.minLength)
return node.collapsibleJson;
const { sequence, ...structureJson } = node.collapsibleJson;
const { minVariadicLength, ...sequenceJson } = sequence;
const collapsibleSequenceJson = sequenceJson.variadic && Object.keys(sequenceJson).length === 1 ?
sequenceJson.variadic
: sequenceJson;
return { ...structureJson, sequence: collapsibleSequenceJson };
}
},
divisor: {
child: true,
parse: constraintKeyParser("divisor")
},
max: {
child: true,
parse: constraintKeyParser("max")
},
min: {
child: true,
parse: constraintKeyParser("min")
},
maxLength: {
child: true,
parse: constraintKeyParser("maxLength")
},
minLength: {
child: true,
parse: constraintKeyParser("minLength")
},
exactLength: {
child: true,
parse: constraintKeyParser("exactLength")
},
before: {
child: true,
parse: constraintKeyParser("before")
},
after: {
child: true,
parse: constraintKeyParser("after")
},
pattern: {
child: true,
parse: constraintKeyParser("pattern")
},
predicate: {
child: true,
parse: constraintKeyParser("predicate")
}
},
// leverage reduction logic from intersection and identity to ensure initial
// parse result is reduced
reduce: (inner, $) =>
// we cast union out of the result here since that only occurs when intersecting two sequences
// that cannot occur when reducing a single intersection schema using unknown
intersectIntersections({}, inner, {
$,
invert: false,
pipe: false
}),
defaults: {
description: node => {
if (node.children.length === 0)
return "unknown";
if (node.structure)
return node.structure.description;
const childDescriptions = [];
if (node.basis &&
!node.prestructurals.some(r => r.impl.obviatesBasisDescription))
childDescriptions.push(node.basis.description);
if (node.prestructurals.length) {
const sortedRefinementDescriptions = node.prestructurals
.slice()
// override alphabetization to describe min before max
.sort((l, r) => (l.kind === "min" && r.kind === "max" ? -1 : 0))
.map(r => r.description);
childDescriptions.push(...sortedRefinementDescriptions);
}
if (node.inner.predicate) {
childDescriptions.push(...node.inner.predicate.map(p => p.description));
}
return childDescriptions.join(" and ");
},
expected: source => `${source.errors.map(e => e.expected).join("\n ◦ ")}`,
problem: ctx => `(${ctx.actual}) must be...\n${ctx.expected}`
},
intersections: {
intersection: (l, r, ctx) => intersectIntersections(l.inner, r.inner, ctx),
...defineRightwardIntersections("intersection", (l, r, ctx) => {
// if l is unknown, return r
if (l.children.length === 0)
return r;
const { domain, proto, ...lInnerConstraints } = l.inner;
const lBasis = proto ?? domain;
const basis = lBasis ? intersectOrPipeNodes(lBasis, r, ctx) : r;
return (basis instanceof Disjoint ? basis
: l?.basis?.equals(basis) ?
// if the basis doesn't change, return the original intesection
l
// given we've already precluded l being unknown, the result must
// be an intersection with the new basis result integrated
: l.$.node("intersection", { ...lInnerConstraints, [basis.kind]: basis }, { prereduced: true }));
})
}
});
export class IntersectionNode extends BaseRoot {
basis = this.inner.domain ?? this.inner.proto ?? null;
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;
expression = writeIntersectionExpression(this);
get shallowMorphs() {
return this.inner.structure?.structuralMorph ?
[this.inner.structure.structuralMorph]
: [];
}
get defaultShortDescription() {
return this.basis?.defaultShortDescription ?? "present";
}
innerToJsonSchema(ctx) {
return this.children.reduce(
// cast is required since TS doesn't know children have compatible schema prerequisites
(schema, child) => child.isBasis() ?
child.toJsonSchemaRecurse(ctx)
: child.reduceJsonSchema(schema, ctx), {});
}
traverseAllows = (data, ctx) => this.children.every(child => child.traverseAllows(data, ctx));
traverseApply = (data, ctx) => {
const errorCount = ctx.currentErrorCount;
if (this.basis) {
this.basis.traverseApply(data, ctx);
if (ctx.currentErrorCount > errorCount)
return;
}
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.prestructurals[this.prestructurals.length - 1].traverseApply(data, ctx);
if (ctx.currentErrorCount > errorCount)
return;
}
if (this.structure) {
this.structure.traverseApply(data, ctx);
if (ctx.currentErrorCount > errorCount)
return;
}
if (this.inner.predicate) {
for (let i = 0; i < this.inner.predicate.length - 1; i++) {
this.inner.predicate[i].traverseApply(data, ctx);
if (ctx.failFast && ctx.currentErrorCount > errorCount)
return;
}
this.inner.predicate[this.inner.predicate.length - 1].traverseApply(data, ctx);
}
};
compile(js) {
if (js.traversalKind === "Allows") {
for (const child of this.children)
js.check(child);
js.return(true);
return;
}
js.initializeErrorCount();
if (this.basis) {
js.check(this.basis);
// we only have to return conditionally if this is not the last check
if (this.children.length > 1)
js.returnIfFail();
}
if (this.prestructurals.length) {
for (let i = 0; i < this.prestructurals.length - 1; i++) {
js.check(this.prestructurals[i]);
js.returnIfFailFast();
}
js.check(this.prestructurals[this.prestructurals.length - 1]);
if (this.structure || this.inner.predicate)
js.returnIfFail();
}
if (this.structure) {
js.check(this.structure);
if (this.inner.predicate)
js.returnIfFail();
}
if (this.inner.predicate) {
for (let i = 0; i < this.inner.predicate.length - 1; i++) {
js.check(this.inner.predicate[i]);
// since predicates can be chained, we have to fail immediately
// if one fails
js.returnIfFail();
}
js.check(this.inner.predicate[this.inner.predicate.length - 1]);
}
}
}
export const Intersection = {
implementation,
Node: IntersectionNode
};
const writeIntersectionExpression = (node) => {
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";
};
const intersectIntersections = (l, r, ctx) => {
const baseInner = {};
const lBasis = l.proto ?? l.domain;
const rBasis = r.proto ?? r.domain;
const basisResult = lBasis ?
rBasis ?
intersectOrPipeNodes(lBasis, rBasis, ctx)
: lBasis
: rBasis;
if (basisResult instanceof Disjoint)
return basisResult;
if (basisResult)
baseInner[basisResult.kind] = basisResult;
return intersectConstraints({
kind: "intersection",
baseInner,
l: flattenConstraints(l),
r: flattenConstraints(r),
roots: [],
ctx
});
};

62
frontend/node_modules/@ark/schema/out/roots/morph.d.ts generated vendored Normal file
View File

@@ -0,0 +1,62 @@
import { type array, type listable } from "@ark/util";
import type { RootSchema } from "../kinds.ts";
import type { NodeCompiler } from "../shared/compile.ts";
import type { BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf, type RootKind } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { Traversal, TraverseAllows, TraverseApply } from "../shared/traversal.ts";
import { BaseRoot } from "./root.ts";
export declare namespace Morph {
interface Inner {
readonly in?: BaseRoot;
readonly morphs: array<Morph | BaseRoot>;
readonly declaredIn?: BaseRoot;
readonly declaredOut?: BaseRoot;
}
interface Schema extends BaseNormalizedSchema {
readonly in?: RootSchema;
readonly morphs: listable<Morph | BaseRoot>;
readonly declaredIn?: BaseRoot;
readonly declaredOut?: BaseRoot;
}
interface Declaration extends declareNode<{
kind: "morph";
schema: Schema;
normalizedSchema: Schema;
inner: Inner;
childKind: RootKind;
}> {
}
type Node = MorphNode;
type In<morph extends Morph> = morph extends Morph<infer i> ? i : never;
type Out<morph extends Morph> = morph extends Morph<never, infer o> ? o : never;
type ContextFree<i = never, o = unknown> = (In: i) => 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: Morph | BaseRoot | undefined;
lastMorphIfNode: BaseRoot | undefined;
introspectableIn: BaseRoot | undefined;
introspectableOut: BaseRoot | undefined;
get shallowMorphs(): array<Morph>;
get rawIn(): BaseRoot;
get rawOut(): BaseRoot;
declareIn(declaredIn: BaseRoot): MorphNode;
declareOut(declaredOut: BaseRoot): MorphNode;
expression: string;
get defaultShortDescription(): string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
compile(js: NodeCompiler): void;
traverseAllows: TraverseAllows;
traverseApply: TraverseApply;
/** Check if the morphs of r are equal to those of this node */
hasEqualMorphs(r: MorphNode): boolean;
}
export declare const Morph: {
implementation: nodeImplementationOf<Morph.Declaration>;
Node: typeof MorphNode;
};
export declare const writeMorphIntersectionMessage: (lDescription: string, rDescription: string) => string;

159
frontend/node_modules/@ark/schema/out/roots/morph.js generated vendored Normal file
View File

@@ -0,0 +1,159 @@
import { arrayEquals, liftArray, throwParseError } from "@ark/util";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark, registeredReference } from "../shared/registry.js";
import { hasArkKind } from "../shared/utils.js";
import { BaseRoot } from "./root.js";
import { defineRightwardIntersections } from "./utils.js";
const implementation = implementNode({
kind: "morph",
hasAssociatedError: false,
keys: {
in: {
child: true,
parse: (schema, ctx) => ctx.$.parseSchema(schema)
},
morphs: {
parse: liftArray,
serialize: morphs => morphs.map(m => hasArkKind(m, "root") ? m.json : registeredReference(m))
},
declaredIn: {
child: false,
serialize: node => node.json
},
declaredOut: {
child: false,
serialize: node => node.json
}
},
normalize: schema => schema,
defaults: {
description: node => `a morph from ${node.rawIn.description} to ${node.rawOut?.description ?? "unknown"}`
},
intersections: {
morph: (l, r, ctx) => {
if (!l.hasEqualMorphs(r)) {
return throwParseError(writeMorphIntersectionMessage(l.expression, r.expression));
}
const inTersection = intersectOrPipeNodes(l.rawIn, r.rawIn, ctx);
if (inTersection instanceof Disjoint)
return inTersection;
const baseInner = {
morphs: l.morphs
};
if (l.declaredIn || r.declaredIn) {
const declaredIn = intersectOrPipeNodes(l.rawIn, r.rawIn, ctx);
// we can't treat this as a normal Disjoint since it's just declared
// it should only happen if someone's essentially trying to create a broken type
if (declaredIn instanceof Disjoint)
return declaredIn.throw();
else
baseInner.declaredIn = declaredIn;
}
if (l.declaredOut || r.declaredOut) {
const declaredOut = intersectOrPipeNodes(l.rawOut, r.rawOut, ctx);
if (declaredOut instanceof Disjoint)
return declaredOut.throw();
else
baseInner.declaredOut = declaredOut;
}
// in case from is a union, we need to distribute the branches
// to can be a union as any schema is allowed
return inTersection.distribute(inBranch => ctx.$.node("morph", {
...baseInner,
in: inBranch
}), ctx.$.parseSchema);
},
...defineRightwardIntersections("morph", (l, r, ctx) => {
const inTersection = l.inner.in ? intersectOrPipeNodes(l.inner.in, r, ctx) : r;
return (inTersection instanceof Disjoint ? inTersection
: inTersection.equals(l.inner.in) ? l
: ctx.$.node("morph", {
...l.inner,
in: inTersection
}));
})
}
});
export class MorphNode extends BaseRoot {
serializedMorphs = this.morphs.map(registeredReference);
compiledMorphs = `[${this.serializedMorphs}]`;
lastMorph = this.inner.morphs[this.inner.morphs.length - 1];
lastMorphIfNode = hasArkKind(this.lastMorph, "root") ? this.lastMorph : undefined;
introspectableIn = this.inner.in;
introspectableOut = this.lastMorphIfNode ?
Object.assign(this.referencesById, this.lastMorphIfNode.referencesById) &&
this.lastMorphIfNode.rawOut
: undefined;
get shallowMorphs() {
// if the morph input is a union, it should not contain any other shallow morphs
return Array.isArray(this.inner.in?.shallowMorphs) ?
[...this.inner.in.shallowMorphs, ...this.morphs]
: this.morphs;
}
get rawIn() {
return (this.declaredIn ?? this.inner.in?.rawIn ?? $ark.intrinsic.unknown.internal);
}
get rawOut() {
return (this.declaredOut ??
this.introspectableOut ??
$ark.intrinsic.unknown.internal);
}
declareIn(declaredIn) {
return this.$.node("morph", {
...this.inner,
declaredIn
});
}
declareOut(declaredOut) {
return this.$.node("morph", {
...this.inner,
declaredOut
});
}
expression = `(In: ${this.rawIn.expression}) => ${this.lastMorphIfNode ? "To" : "Out"}<${this.rawOut.expression}>`;
get defaultShortDescription() {
return this.rawIn.meta.description ?? this.rawIn.defaultShortDescription;
}
innerToJsonSchema(ctx) {
return ctx.fallback.morph({
code: "morph",
base: this.rawIn.toJsonSchemaRecurse(ctx),
out: this.introspectableOut?.toJsonSchemaRecurse(ctx) ?? null
});
}
compile(js) {
if (js.traversalKind === "Allows") {
if (!this.introspectableIn)
return;
js.return(js.invoke(this.introspectableIn));
return;
}
if (this.introspectableIn)
js.line(js.invoke(this.introspectableIn));
js.line(`ctx.queueMorphs(${this.compiledMorphs})`);
}
traverseAllows = (data, ctx) => !this.introspectableIn || this.introspectableIn.traverseAllows(data, ctx);
traverseApply = (data, ctx) => {
if (this.introspectableIn)
this.introspectableIn.traverseApply(data, ctx);
ctx.queueMorphs(this.morphs);
};
/** Check if the morphs of r are equal to those of this node */
hasEqualMorphs(r) {
return arrayEquals(this.morphs, r.morphs, {
isEqual: (lMorph, rMorph) => lMorph === rMorph ||
(hasArkKind(lMorph, "root") &&
hasArkKind(rMorph, "root") &&
lMorph.equals(rMorph))
});
}
}
export const Morph = {
implementation,
Node: MorphNode
};
export const writeMorphIntersectionMessage = (lDescription, rDescription) => `The intersection of distinct morphs at a single path is indeterminate:
Left: ${lDescription}
Right: ${rDescription}`;

53
frontend/node_modules/@ark/schema/out/roots/proto.d.ts generated vendored Normal file
View File

@@ -0,0 +1,53 @@
import { type BuiltinObjectKind, type Constructor } from "@ark/util";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { InternalBasis } from "./basis.ts";
export declare namespace Proto {
type Reference = Constructor | BuiltinObjectKind;
type Schema<proto extends Reference = Reference> = proto | ExpandedSchema<proto>;
interface NormalizedSchema<proto extends Constructor = Constructor> extends BaseNormalizedSchema {
readonly proto: proto;
readonly dateAllowsInvalid?: boolean;
}
interface ExpandedSchema<proto extends Reference = Reference> {
readonly proto: proto;
readonly dateAllowsInvalid?: boolean;
}
interface Inner<proto extends Constructor = Constructor> {
readonly proto: proto;
readonly dateAllowsInvalid?: boolean;
}
interface ErrorContext extends BaseErrorContext<"proto">, Inner {
}
interface Declaration extends declareNode<{
kind: "proto";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
errorContext: ErrorContext;
}> {
}
type Node = ProtoNode;
}
export declare class ProtoNode extends InternalBasis<Proto.Declaration> {
builtinName: BuiltinObjectKind | null;
serializedConstructor: string;
private readonly requiresInvalidDateCheck;
traverseAllows: TraverseAllows;
compiledCondition: string;
compiledNegation: string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
expression: string;
get nestableExpression(): string;
readonly domain = "object";
get defaultShortDescription(): string;
}
export declare const Proto: {
implementation: nodeImplementationOf<Proto.Declaration>;
Node: typeof ProtoNode;
writeBadInvalidDateMessage: (actual: Constructor) => string;
writeInvalidSchemaMessage: (actual: unknown) => string;
};

101
frontend/node_modules/@ark/schema/out/roots/proto.js generated vendored Normal file
View File

@@ -0,0 +1,101 @@
import { builtinConstructors, constructorExtends, domainOf, getBuiltinNameOfConstructor, hasKey, objectKindDescriptions, objectKindOrDomainOf, throwParseError } from "@ark/util";
import { Disjoint } from "../shared/disjoint.js";
import { defaultValueSerializer, implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { isNode } from "../shared/utils.js";
import { InternalBasis } from "./basis.js";
const implementation = implementNode({
kind: "proto",
hasAssociatedError: true,
collapsibleKey: "proto",
keys: {
proto: {
serialize: ctor => getBuiltinNameOfConstructor(ctor) ?? defaultValueSerializer(ctor)
},
dateAllowsInvalid: {}
},
normalize: schema => {
const normalized = typeof schema === "string" ? { proto: builtinConstructors[schema] }
: typeof schema === "function" ?
isNode(schema) ? schema
: { proto: schema }
: typeof schema.proto === "string" ?
{ ...schema, proto: builtinConstructors[schema.proto] }
: schema;
if (typeof normalized.proto !== "function")
throwParseError(Proto.writeInvalidSchemaMessage(normalized.proto));
if (hasKey(normalized, "dateAllowsInvalid") && normalized.proto !== Date)
throwParseError(Proto.writeBadInvalidDateMessage(normalized.proto));
return normalized;
},
applyConfig: (schema, config) => {
if (schema.dateAllowsInvalid === undefined &&
schema.proto === Date &&
config.dateAllowsInvalid)
return { ...schema, dateAllowsInvalid: true };
return schema;
},
defaults: {
description: node => node.builtinName ?
objectKindDescriptions[node.builtinName]
: `an instance of ${node.proto.name}`,
actual: data => data instanceof Date && data.toString() === "Invalid Date" ?
"an invalid Date"
: objectKindOrDomainOf(data)
},
intersections: {
proto: (l, r) => l.proto === Date && r.proto === Date ?
// since l === r is handled by default,
// exactly one of l or r must have allow invalid dates
l.dateAllowsInvalid ?
r
: l
: constructorExtends(l.proto, r.proto) ? l
: constructorExtends(r.proto, l.proto) ? r
: Disjoint.init("proto", l, r),
domain: (proto, domain) => domain.domain === "object" ?
proto
: Disjoint.init("domain", $ark.intrinsic.object.internal, domain)
}
});
export class ProtoNode extends InternalBasis {
builtinName = getBuiltinNameOfConstructor(this.proto);
serializedConstructor = this.json.proto;
requiresInvalidDateCheck = this.proto === Date && !this.dateAllowsInvalid;
traverseAllows = this.requiresInvalidDateCheck ?
data => data instanceof Date && data.toString() !== "Invalid Date"
: data => data instanceof this.proto;
compiledCondition = `data instanceof ${this.serializedConstructor}${this.requiresInvalidDateCheck ? ` && data.toString() !== "Invalid Date"` : ""}`;
compiledNegation = `!(${this.compiledCondition})`;
innerToJsonSchema(ctx) {
switch (this.builtinName) {
case "Array":
return {
type: "array"
};
case "Date":
return (ctx.fallback.date?.({ code: "date", base: {} }) ??
ctx.fallback.proto({ code: "proto", base: {}, proto: this.proto }));
default:
return ctx.fallback.proto({
code: "proto",
base: {},
proto: this.proto
});
}
}
expression = this.dateAllowsInvalid ? "Date | InvalidDate" : this.proto.name;
get nestableExpression() {
return this.dateAllowsInvalid ? `(${this.expression})` : this.expression;
}
domain = "object";
get defaultShortDescription() {
return this.description;
}
}
export const Proto = {
implementation,
Node: ProtoNode,
writeBadInvalidDateMessage: (actual) => `dateAllowsInvalid may only be specified with constructor Date (was ${actual.name})`,
writeInvalidSchemaMessage: (actual) => `instanceOf operand must be a function (was ${domainOf(actual)})`
};

145
frontend/node_modules/@ark/schema/out/roots/root.d.ts generated vendored Normal file
View File

@@ -0,0 +1,145 @@
import { inferred, type array } from "@ark/util";
import { type Constraint } from "../constraint.ts";
import type { NodeSchema, nodeOfKind, reducibleKindOf } from "../kinds.ts";
import { BaseNode, type GettableKeyOrNode, type KeyOrKeyNode, type NodeSelector } from "../node.ts";
import type { Predicate } from "../predicate.ts";
import type { Divisor } from "../refinements/divisor.ts";
import type { ExactLength } from "../refinements/exactLength.ts";
import type { Pattern } from "../refinements/pattern.ts";
import type { ExclusiveDateRangeSchema, ExclusiveNumericRangeSchema, InclusiveDateRangeSchema, InclusiveNumericRangeSchema, LimitSchemaValue, UnknownRangeSchema } from "../refinements/range.ts";
import type { BaseScope } from "../scope.ts";
import type { BaseNodeDeclaration, TypeMeta } from "../shared/declare.ts";
import { Disjoint } from "../shared/disjoint.ts";
import { type NodeKind, type RootKind, type UnknownAttachments, type kindRightOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { StandardJSONSchemaV1, StandardSchemaV1 } from "../shared/standardSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import { arkKind } from "../shared/utils.ts";
import type { Prop } from "../structure/prop.ts";
import type { PropFlatMapper, UndeclaredKeyBehavior } from "../structure/structure.ts";
import type { Morph } from "./morph.ts";
import type { Union } from "./union.ts";
export interface InternalRootDeclaration extends BaseNodeDeclaration {
kind: RootKind;
}
export declare abstract class BaseRoot<
/** @ts-ignore cast variance */
out d extends InternalRootDeclaration = InternalRootDeclaration> extends BaseNode<d> implements StandardSchemaV1, StandardJSONSchemaV1 {
readonly [arkKind]: "root";
readonly [inferred]: unknown;
constructor(attachments: UnknownAttachments, $: BaseScope);
get rawIn(): BaseRoot;
get rawOut(): BaseRoot;
get internal(): this;
get "~standard"(): StandardSchemaV1.ArkTypeProps;
as(): this;
brand(name: string): this;
readonly(): this;
readonly branches: readonly nodeOfKind<Union.ChildKind>[];
distribute<mapOut, reduceOut = mapOut[]>(mapBranch: (branch: nodeOfKind<Union.ChildKind>, i: number, branches: array<nodeOfKind<Union.ChildKind>>) => mapOut, reduceMapped?: (mappedBranches: mapOut[]) => reduceOut): reduceOut;
abstract get defaultShortDescription(): string;
get shortDescription(): string;
toJsonSchema(opts?: ToJsonSchema.Options): JsonSchema;
toJsonSchemaRecurse(ctx: ToJsonSchema.Context): JsonSchema;
get alwaysExpandJsonSchema(): boolean;
protected toResolvedJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
protected abstract innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
intersect(r: unknown): BaseRoot | Disjoint;
rawIntersect(r: BaseRoot): BaseRoot;
toNeverIfDisjoint(): BaseRoot;
and(r: unknown): BaseRoot;
rawAnd(r: BaseRoot): BaseRoot;
or(r: unknown): BaseRoot;
rawOr(r: BaseRoot): BaseRoot;
map(flatMapEntry: PropFlatMapper): BaseRoot;
pick(...keys: KeyOrKeyNode[]): BaseRoot;
omit(...keys: KeyOrKeyNode[]): BaseRoot;
required(): BaseRoot;
partial(): BaseRoot;
private _keyof?;
keyof(): BaseRoot;
get props(): Prop.Node[];
merge(r: unknown): BaseRoot;
private applyStructuralOperation;
get(...path: GettableKeyOrNode[]): BaseRoot;
extract(r: unknown): BaseRoot;
exclude(r: unknown): BaseRoot;
array(): BaseRoot;
overlaps(r: unknown): boolean;
extends(r: unknown): boolean;
ifExtends(r: unknown): BaseRoot | undefined;
subsumes(r: unknown): boolean;
configure(meta: TypeMeta.MappableInput, selector?: NodeSelector): this;
describe(description: string, selector?: NodeSelector): this;
optional(): [this, "?"];
default(thunkableValue: unknown): [this, "=", unknown];
from(input: unknown): unknown;
protected _pipe(...morphs: Morph[]): BaseRoot;
protected tryPipe(...morphs: Morph[]): BaseRoot;
pipe: ((...morphs: Morph[]) => BaseRoot) & {
try: (...morphs: Morph[]) => BaseRoot;
};
to(def: unknown): BaseRoot;
private toNode;
rawPipeOnce(morph: Morph): BaseRoot;
narrow(predicate: Predicate): BaseRoot;
constrain<kind extends Constraint.PrimitiveKind>(kind: kind, schema: NodeSchema<kind>): BaseRoot;
constrainIn<kind extends Constraint.PrimitiveKind>(kind: kind, schema: NodeSchema<kind>): BaseRoot;
constrainOut<kind extends Constraint.PrimitiveKind>(kind: kind, schema: NodeSchema<kind>): BaseRoot;
private _constrain;
onUndeclaredKey(cfg: UndeclaredKeyBehavior | UndeclaredKeyConfig): BaseRoot;
hasEqualMorphs(r: BaseRoot): boolean;
onDeepUndeclaredKey(behavior: UndeclaredKeyBehavior): BaseRoot;
filter(predicate: Predicate): BaseRoot;
divisibleBy(schema: Divisor.Schema): BaseRoot;
matching(schema: Pattern.Schema): BaseRoot;
atLeast(schema: InclusiveNumericRangeSchema): BaseRoot;
atMost(schema: InclusiveNumericRangeSchema): BaseRoot;
moreThan(schema: ExclusiveNumericRangeSchema): BaseRoot;
lessThan(schema: ExclusiveNumericRangeSchema): BaseRoot;
atLeastLength(schema: InclusiveNumericRangeSchema): BaseRoot;
atMostLength(schema: InclusiveNumericRangeSchema): BaseRoot;
moreThanLength(schema: ExclusiveNumericRangeSchema): BaseRoot;
lessThanLength(schema: ExclusiveNumericRangeSchema): BaseRoot;
exactlyLength(schema: ExactLength.Schema): BaseRoot;
atOrAfter(schema: InclusiveDateRangeSchema): BaseRoot;
atOrBefore(schema: InclusiveDateRangeSchema): BaseRoot;
laterThan(schema: ExclusiveDateRangeSchema): BaseRoot;
earlierThan(schema: ExclusiveDateRangeSchema): BaseRoot;
}
export type UndeclaredKeyConfig = {
rule: UndeclaredKeyBehavior;
deep?: boolean;
};
export declare const emptyBrandNameMessage = "Expected a non-empty brand name after #";
export type emptyBrandNameMessage = typeof emptyBrandNameMessage;
export declare const writeInvalidJsonSchemaTargetMessage: (target: string) => string;
export declare const exclusivizeRangeSchema: <schema extends UnknownRangeSchema>(schema: schema) => schema;
export type exclusivizeRangeSchema<schema extends UnknownRangeSchema> = schema extends LimitSchemaValue ? {
rule: schema;
exclusive: true;
} : schema;
export declare const typeOrTermExtends: (t: unknown, base: unknown) => boolean;
export type intersectRoot<l extends RootKind, r extends NodeKind> = [
l,
r
] extends [r, l] ? l : asymmetricIntersectionOf<l, r> | asymmetricIntersectionOf<r, l>;
type asymmetricIntersectionOf<l extends NodeKind, r extends NodeKind> = l extends unknown ? r extends kindRightOf<l> ? l | reducibleKindOf<l> : never : never;
export type schemaKindRightOf<kind extends RootKind> = Extract<kindRightOf<kind>, RootKind>;
export type schemaKindOrRightOf<kind extends RootKind> = kind | schemaKindRightOf<kind>;
export type StructuralOperationBranchResultByName = {
keyof: Union.ChildNode;
pick: Union.ChildNode;
omit: Union.ChildNode;
get: Union.ChildNode;
map: Union.ChildNode;
required: Union.ChildNode;
partial: Union.ChildNode;
merge: Union.ChildNode;
props: array<Prop.Node>;
};
export type StructuralOperationName = keyof StructuralOperationBranchResultByName;
export declare const writeLiteralUnionEntriesMessage: (expression: string) => string;
export declare const writeNonStructuralOperandMessage: <operation extends StructuralOperationName, operand extends string>(operation: operation, operand: operand) => writeNonStructuralOperandMessage<operation, operand>;
export type writeNonStructuralOperandMessage<operation extends StructuralOperationName, operand extends string> = `${operation} operand must be an object (was ${operand})`;
export {};

455
frontend/node_modules/@ark/schema/out/roots/root.js generated vendored Normal file
View File

@@ -0,0 +1,455 @@
import { arrayEquals, flatMorph, includes, inferred, omit, throwInternalError, throwParseError } from "@ark/util";
import { mergeToJsonSchemaConfigs } from "../config.js";
import { throwInvalidOperandError } from "../constraint.js";
import { BaseNode } from "../node.js";
import { Disjoint, writeUnsatisfiableExpressionError } from "../shared/disjoint.js";
import { ArkErrors } from "../shared/errors.js";
import { structuralKinds } from "../shared/implement.js";
import { intersectNodesRoot, pipeNodesRoot } from "../shared/intersections.js";
import { $ark } from "../shared/registry.js";
import { arkKind, hasArkKind } from "../shared/utils.js";
import { assertDefaultValueAssignability } from "../structure/optional.js";
export class BaseRoot extends BaseNode {
constructor(attachments, $) {
super(attachments, $);
// define as a getter to avoid it being enumerable/spreadable
Object.defineProperty(this, arkKind, { value: "root", enumerable: false });
}
// 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() {
return this;
}
get "~standard"() {
return {
vendor: "arktype",
version: 1,
validate: input => {
const out = this(input);
if (out instanceof ArkErrors)
return out;
return { value: out };
},
jsonSchema: {
input: opts => this.rawIn.toJsonSchema({
target: validateStandardJsonSchemaTarget(opts.target),
...opts.libraryOptions
}),
output: opts => this.rawOut.toJsonSchema({
target: validateStandardJsonSchemaTarget(opts.target),
...opts.libraryOptions
})
}
};
}
as() {
return this;
}
brand(name) {
if (name === "")
return throwParseError(emptyBrandNameMessage);
return this;
}
readonly() {
return this;
}
branches = this.hasKind("union") ? this.inner.branches : [this];
distribute(mapBranch, reduceMapped) {
const mappedBranches = this.branches.map(mapBranch);
return reduceMapped?.(mappedBranches) ?? mappedBranches;
}
get shortDescription() {
return this.meta.description ?? this.defaultShortDescription;
}
toJsonSchema(opts = {}) {
const ctx = mergeToJsonSchemaConfigs(this.$.resolvedConfig.toJsonSchema, opts);
ctx.useRefs ||= this.isCyclic;
// ensure $schema is the first key if present
const schema = typeof ctx.dialect === "string" ? { $schema: ctx.dialect } : {};
Object.assign(schema, this.toJsonSchemaRecurse(ctx));
if (ctx.useRefs) {
const defs = flatMorph(this.references, (i, ref) => ref.isRoot() && !ref.alwaysExpandJsonSchema ?
[ref.id, ref.toResolvedJsonSchema(ctx)]
: []);
// draft-2020-12 uses $defs, draft-07 uses definitions
if (ctx.target === "draft-07")
Object.assign(schema, { definitions: defs });
else
schema.$defs = defs;
}
return schema;
}
toJsonSchemaRecurse(ctx) {
if (ctx.useRefs && !this.alwaysExpandJsonSchema) {
// draft-2020-12 uses $defs, draft-07 uses definitions
const defsKey = ctx.target === "draft-07" ? "definitions" : "$defs";
return { $ref: `#/${defsKey}/${this.id}` };
}
return this.toResolvedJsonSchema(ctx);
}
get alwaysExpandJsonSchema() {
return (this.isBasis() ||
this.kind === "alias" ||
(this.hasKind("union") && this.isBoolean));
}
toResolvedJsonSchema(ctx) {
const result = this.innerToJsonSchema(ctx);
return Object.assign(result, this.metaJson);
}
intersect(r) {
const rNode = this.$.parseDefinition(r);
const result = this.rawIntersect(rNode);
if (result instanceof Disjoint)
return result;
return this.$.finalize(result);
}
rawIntersect(r) {
return intersectNodesRoot(this, r, this.$);
}
toNeverIfDisjoint() {
return this;
}
and(r) {
const result = this.intersect(r);
return result instanceof Disjoint ? result.throw() : result;
}
rawAnd(r) {
const result = this.rawIntersect(r);
return result instanceof Disjoint ? result.throw() : result;
}
or(r) {
const rNode = this.$.parseDefinition(r);
return this.$.finalize(this.rawOr(rNode));
}
rawOr(r) {
const branches = [...this.branches, ...r.branches];
return this.$.node("union", branches);
}
map(flatMapEntry) {
return this.$.schema(this.applyStructuralOperation("map", [flatMapEntry]));
}
pick(...keys) {
return this.$.schema(this.applyStructuralOperation("pick", keys));
}
omit(...keys) {
return this.$.schema(this.applyStructuralOperation("omit", keys));
}
required() {
return this.$.schema(this.applyStructuralOperation("required", []));
}
partial() {
return this.$.schema(this.applyStructuralOperation("partial", []));
}
_keyof;
keyof() {
if (this._keyof)
return this._keyof;
const result = this.applyStructuralOperation("keyof", []).reduce((result, branch) => result.intersect(branch).toNeverIfDisjoint(), $ark.intrinsic.unknown.internal);
if (result.branches.length === 0) {
throwParseError(writeUnsatisfiableExpressionError(`keyof ${this.expression}`));
}
return (this._keyof = this.$.finalize(result));
}
get props() {
if (this.branches.length !== 1)
return throwParseError(writeLiteralUnionEntriesMessage(this.expression));
return [...this.applyStructuralOperation("props", [])[0]];
}
merge(r) {
const rNode = this.$.parseDefinition(r);
return this.$.schema(rNode.distribute(branch => this.applyStructuralOperation("merge", [
structureOf(branch) ??
throwParseError(writeNonStructuralOperandMessage("merge", branch.expression))
])));
}
applyStructuralOperation(operation, args) {
return this.distribute(branch => {
if (branch.equals($ark.intrinsic.object) && operation !== "merge")
// ideally this wouldn't be a special case, but for now it
// allows us to bypass `assertHasKeys` checks on base
// instantiations of generics like Pick and Omit. Could
// potentially be removed once constraints can reference each other:
// https://github.com/arktypeio/arktype/issues/1053
return branch;
const structure = structureOf(branch);
if (!structure) {
throwParseError(writeNonStructuralOperandMessage(operation, branch.expression));
}
if (operation === "keyof")
return structure.keyof();
if (operation === "get")
return structure.get(...args);
if (operation === "props")
return structure.props;
const structuralMethodName = operation === "required" ? "require"
: operation === "partial" ? "optionalize"
: operation;
return this.$.node("intersection", {
domain: "object",
structure: structure[structuralMethodName](...args)
});
});
}
get(...path) {
if (path[0] === undefined)
return this;
return this.$.schema(this.applyStructuralOperation("get", path));
}
extract(r) {
const rNode = this.$.parseDefinition(r);
return this.$.schema(this.branches.filter(branch => branch.extends(rNode)));
}
exclude(r) {
const rNode = this.$.parseDefinition(r);
return this.$.schema(this.branches.filter(branch => !branch.extends(rNode)));
}
array() {
return this.$.schema(this.isUnknown() ?
{ proto: Array }
: {
proto: Array,
sequence: this
}, { prereduced: true });
}
overlaps(r) {
const intersection = this.intersect(r);
return !(intersection instanceof Disjoint);
}
extends(r) {
if (this.isNever())
return true;
const intersection = this.intersect(r);
return (!(intersection instanceof Disjoint) && this.equals(intersection));
}
ifExtends(r) {
return this.extends(r) ? this : undefined;
}
subsumes(r) {
const rNode = this.$.parseDefinition(r);
return rNode.extends(this);
}
configure(meta, selector = "shallow") {
return this.configureReferences(meta, selector);
}
describe(description, selector = "shallow") {
return this.configure({ description }, selector);
}
// these should ideally be implemented in arktype since they use its syntax
// https://github.com/arktypeio/arktype/issues/1223
optional() {
return [this, "?"];
}
// these should ideally be implemented in arktype since they use its syntax
// https://github.com/arktypeio/arktype/issues/1223
default(thunkableValue) {
assertDefaultValueAssignability(this, thunkableValue, null);
return [this, "=", thunkableValue];
}
from(input) {
// ideally we might not validate here but for now we need to do determine
// which morphs to apply
return this.assert(input);
}
_pipe(...morphs) {
const result = morphs.reduce((acc, morph) => acc.rawPipeOnce(morph), this);
return this.$.finalize(result);
}
tryPipe(...morphs) {
const result = morphs.reduce((acc, morph) => acc.rawPipeOnce(hasArkKind(morph, "root") ? morph : ((In, ctx) => {
try {
return morph(In, ctx);
}
catch (e) {
return ctx.error({
code: "predicate",
predicate: morph,
actual: `aborted due to error:\n ${e}\n`
});
}
})), this);
return this.$.finalize(result);
}
pipe = Object.assign(this._pipe.bind(this), {
try: this.tryPipe.bind(this)
});
to(def) {
return this.$.finalize(this.toNode(this.$.parseDefinition(def)));
}
toNode(root) {
const result = pipeNodesRoot(this, root, this.$);
if (result instanceof Disjoint)
return result.throw();
return result;
}
rawPipeOnce(morph) {
if (hasArkKind(morph, "root"))
return this.toNode(morph);
return this.distribute(branch => branch.hasKind("morph") ?
this.$.node("morph", {
in: branch.inner.in,
morphs: [...branch.morphs, morph]
})
: this.$.node("morph", {
in: branch,
morphs: [morph]
}), this.$.parseSchema);
}
narrow(predicate) {
return this.constrainOut("predicate", predicate);
}
constrain(kind, schema) {
return this._constrain("root", kind, schema);
}
constrainIn(kind, schema) {
return this._constrain("in", kind, schema);
}
constrainOut(kind, schema) {
return this._constrain("out", kind, schema);
}
_constrain(io, kind, schema) {
const constraint = this.$.node(kind, schema);
if (constraint.isRoot()) {
// if the node reduces to `unknown`, nothing to do (e.g. minLength: 0)
return constraint.isUnknown() ? this : (throwInternalError(`Unexpected constraint node ${constraint}`));
}
const operand = io === "root" ? this
: io === "in" ? this.rawIn
: this.rawOut;
if (operand.hasKind("morph") ||
(constraint.impliedBasis && !operand.extends(constraint.impliedBasis))) {
return throwInvalidOperandError(kind, constraint.impliedBasis, this);
}
const partialIntersection = this.$.node("intersection", {
// important this is constraint.kind instead of kind in case
// the node was reduced during parsing
[constraint.kind]: constraint
});
const result = io === "out" ?
pipeNodesRoot(this, partialIntersection, this.$)
: intersectNodesRoot(this, partialIntersection, this.$);
if (result instanceof Disjoint)
result.throw();
return this.$.finalize(result);
}
onUndeclaredKey(cfg) {
const rule = typeof cfg === "string" ? cfg : cfg.rule;
const deep = typeof cfg === "string" ? false : cfg.deep;
return this.$.finalize(this.transform((kind, inner) => kind === "structure" ?
rule === "ignore" ?
omit(inner, { undeclared: 1 })
: { ...inner, undeclared: rule }
: inner, deep ? undefined : ({ shouldTransform: node => !includes(structuralKinds, node.kind) })));
}
hasEqualMorphs(r) {
if (!this.includesTransform && !r.includesTransform)
return true;
if (!arrayEquals(this.shallowMorphs, r.shallowMorphs))
return false;
if (!arrayEquals(this.flatMorphs, r.flatMorphs, {
isEqual: (l, r) => l.propString === r.propString &&
(l.node.hasKind("morph") && r.node.hasKind("morph") ?
l.node.hasEqualMorphs(r.node)
: l.node.hasKind("intersection") && r.node.hasKind("intersection") ?
l.node.structure?.structuralMorphRef ===
r.node.structure?.structuralMorphRef
: false)
}))
return false;
return true;
}
onDeepUndeclaredKey(behavior) {
return this.onUndeclaredKey({ rule: behavior, deep: true });
}
filter(predicate) {
return this.constrainIn("predicate", predicate);
}
divisibleBy(schema) {
return this.constrain("divisor", schema);
}
matching(schema) {
return this.constrain("pattern", schema);
}
atLeast(schema) {
return this.constrain("min", schema);
}
atMost(schema) {
return this.constrain("max", schema);
}
moreThan(schema) {
return this.constrain("min", exclusivizeRangeSchema(schema));
}
lessThan(schema) {
return this.constrain("max", exclusivizeRangeSchema(schema));
}
atLeastLength(schema) {
return this.constrain("minLength", schema);
}
atMostLength(schema) {
return this.constrain("maxLength", schema);
}
moreThanLength(schema) {
return this.constrain("minLength", exclusivizeRangeSchema(schema));
}
lessThanLength(schema) {
return this.constrain("maxLength", exclusivizeRangeSchema(schema));
}
exactlyLength(schema) {
return this.constrain("exactLength", schema);
}
atOrAfter(schema) {
return this.constrain("after", schema);
}
atOrBefore(schema) {
return this.constrain("before", schema);
}
laterThan(schema) {
return this.constrain("after", exclusivizeRangeSchema(schema));
}
earlierThan(schema) {
return this.constrain("before", exclusivizeRangeSchema(schema));
}
}
export const emptyBrandNameMessage = `Expected a non-empty brand name after #`;
const supportedJsonSchemaTargets = [
"draft-2020-12",
"draft-07"
];
export const writeInvalidJsonSchemaTargetMessage = (target) => `JSONSchema target '${target}' is not supported (must be ${supportedJsonSchemaTargets.map(t => `"${t}"`).join(" or ")})`;
const validateStandardJsonSchemaTarget = (target) => {
if (!includes(supportedJsonSchemaTargets, target))
throwParseError(writeInvalidJsonSchemaTargetMessage(target));
return target;
};
export const exclusivizeRangeSchema = (schema) => (typeof schema === "object" && !(schema instanceof Date) ?
{ ...schema, exclusive: true }
: {
rule: schema,
exclusive: true
});
export const typeOrTermExtends = (t, base) => hasArkKind(base, "root") ?
hasArkKind(t, "root") ? t.extends(base)
: base.allows(t)
: hasArkKind(t, "root") ? t.hasUnit(base)
: base === t;
const structureOf = (branch) => {
if (branch.hasKind("morph"))
return null;
if (branch.hasKind("intersection")) {
return (branch.inner.structure ??
(branch.basis?.domain === "object" ?
branch.$.bindReference($ark.intrinsic.emptyStructure)
: null));
}
if (branch.isBasis() && branch.domain === "object")
return branch.$.bindReference($ark.intrinsic.emptyStructure);
return null;
};
export const writeLiteralUnionEntriesMessage = (expression) => `Props cannot be extracted from a union. Use .distribute to extract props from each branch instead. Received:
${expression}`;
export const writeNonStructuralOperandMessage = (operation, operand) => `${operation} operand must be an object (was ${operand})`;

99
frontend/node_modules/@ark/schema/out/roots/union.d.ts generated vendored Normal file
View File

@@ -0,0 +1,99 @@
import { type JsonStructure, type SerializedPrimitive, type array, type show } from "@ark/util";
import type { NodeSchema, RootSchema, nodeOfKind } from "../kinds.ts";
import type { BaseNode } from "../node.ts";
import { type NodeCompiler } from "../shared/compile.ts";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { Disjoint } from "../shared/disjoint.ts";
import type { ArkError } from "../shared/errors.ts";
import { type IntersectionContext, type RootKind, type UnionChildKind, type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import { type RegisteredReference } from "../shared/registry.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import { type TraverseAllows, type TraverseApply } from "../shared/traversal.ts";
import type { Domain } from "./domain.ts";
import type { Morph } from "./morph.ts";
import { BaseRoot } from "./root.ts";
export declare namespace Union {
type ChildKind = UnionChildKind;
type ChildSchema = NodeSchema<ChildKind>;
type ChildNode = nodeOfKind<ChildKind>;
type Schema = NormalizedSchema | readonly RootSchema[];
interface NormalizedSchema extends BaseNormalizedSchema {
readonly branches: array<RootSchema>;
readonly ordered?: true;
}
interface Inner {
readonly branches: readonly ChildNode[];
readonly ordered?: true;
}
interface ErrorContext extends BaseErrorContext<"union"> {
errors: readonly ArkError[];
}
interface Declaration extends declareNode<{
kind: "union";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
errorContext: ErrorContext;
reducibleTo: RootKind;
childKind: UnionChildKind;
}> {
}
type Node = UnionNode;
}
export declare class UnionNode extends BaseRoot<Union.Declaration> {
isBoolean: boolean;
get branchGroups(): BaseRoot[];
unitBranches: (import("./morph.ts").MorphNode | import("./unit.ts").UnitNode)[];
discriminant: Discriminant<DiscriminantKind> | null;
discriminantJson: JsonStructure | null;
expression: string;
createBranchedOptimisticRootApply(): BaseNode["rootApply"];
get shallowMorphs(): array<Morph>;
get defaultShortDescription(): string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
traverseAllows: TraverseAllows;
traverseApply: TraverseApply;
traverseOptimistic: (data: unknown) => unknown;
compile(js: NodeCompiler): void;
private compileIndiscriminable;
get nestableExpression(): string;
discriminate(): Discriminant | null;
}
export declare const Union: {
implementation: nodeImplementationOf<Union.Declaration>;
Node: typeof UnionNode;
};
type DescribeBranchesOptions = {
delimiter?: string;
finalDelimiter?: string;
};
export declare const describeBranches: (descriptions: string[], opts?: DescribeBranchesOptions) => string;
export declare const intersectBranches: (l: readonly Union.ChildNode[], r: readonly Union.ChildNode[], ctx: IntersectionContext) => readonly Union.ChildNode[] | Disjoint;
export declare const reduceBranches: ({ branches, ordered }: Union.Inner) => readonly Union.ChildNode[];
export type CaseKey<kind extends DiscriminantKind = DiscriminantKind> = DiscriminantKind extends kind ? string : DiscriminantKinds[kind] | "default";
type DiscriminantLocation<kind extends DiscriminantKind = DiscriminantKind> = {
path: PropertyKey[];
optionallyChainedPropString: string;
kind: kind;
};
export interface Discriminant<kind extends DiscriminantKind = DiscriminantKind> extends DiscriminantLocation<kind> {
cases: DiscriminatedCases<kind>;
}
export type CaseContext = {
branchIndices: number[];
condition: nodeOfKind<DiscriminantKind> | Domain.Enumerable;
};
export type CaseDiscriminant = nodeOfKind<DiscriminantKind> | Domain.Enumerable;
export type DiscriminatedCases<kind extends DiscriminantKind = DiscriminantKind> = {
[caseKey in CaseKey<kind>]: BaseRoot | true;
};
export type DiscriminantKinds = {
domain: Domain;
unit: SerializedPrimitive | RegisteredReference;
};
export type DiscriminantKind = show<keyof DiscriminantKinds>;
export declare const pruneDiscriminant: (discriminantBranch: BaseRoot, discriminantCtx: DiscriminantLocation) => BaseRoot | null;
export declare const writeIndiscriminableMorphMessage: (lDescription: string, rDescription: string) => string;
export declare const writeOrderedIntersectionMessage: (lDescription: string, rDescription: string) => string;
export {};

718
frontend/node_modules/@ark/schema/out/roots/union.js generated vendored Normal file
View File

@@ -0,0 +1,718 @@
import { appendUnique, arrayEquals, domainDescriptions, flatMorph, groupBy, hasKey, isArray, jsTypeOfDescriptions, printable, range, throwParseError, unset } from "@ark/util";
import { compileLiteralPropAccess, compileSerializedValue } from "../shared/compile.js";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { intersectNodesRoot, intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark, registeredReference } from "../shared/registry.js";
import { Traversal } from "../shared/traversal.js";
import { hasArkKind } from "../shared/utils.js";
import { BaseRoot } from "./root.js";
import { defineRightwardIntersections } from "./utils.js";
const implementation = implementNode({
kind: "union",
hasAssociatedError: true,
collapsibleKey: "branches",
keys: {
ordered: {},
branches: {
child: true,
parse: (schema, ctx) => {
const branches = [];
for (const branchSchema of schema) {
const branchNodes = hasArkKind(branchSchema, "root") ?
branchSchema.branches
: ctx.$.parseSchema(branchSchema).branches;
for (const node of branchNodes) {
if (node.hasKind("morph")) {
const matchingMorphIndex = branches.findIndex(matching => matching.hasKind("morph") && matching.hasEqualMorphs(node));
if (matchingMorphIndex === -1)
branches.push(node);
else {
const matchingMorph = branches[matchingMorphIndex];
branches[matchingMorphIndex] = ctx.$.node("morph", {
...matchingMorph.inner,
in: matchingMorph.rawIn.rawOr(node.rawIn)
});
}
}
else
branches.push(node);
}
}
if (!ctx.def.ordered)
branches.sort((l, r) => (l.hash < r.hash ? -1 : 1));
return branches;
}
}
},
normalize: schema => (isArray(schema) ? { branches: schema } : schema),
reduce: (inner, $) => {
const reducedBranches = reduceBranches(inner);
if (reducedBranches.length === 1)
return reducedBranches[0];
if (reducedBranches.length === inner.branches.length)
return;
return $.node("union", {
...inner,
branches: reducedBranches
}, { prereduced: true });
},
defaults: {
description: node => node.distribute(branch => branch.description, describeBranches),
expected: ctx => {
const byPath = groupBy(ctx.errors, "propString");
const pathDescriptions = Object.entries(byPath).map(([path, errors]) => {
const branchesAtPath = [];
for (const errorAtPath of errors)
appendUnique(branchesAtPath, errorAtPath.expected);
const expected = describeBranches(branchesAtPath);
// if there are multiple actual descriptions that differ,
// just fall back to printable, which is the most specific
const actual = errors.every(e => e.actual === errors[0].actual) ?
errors[0].actual
: printable(errors[0].data);
return `${path && `${path} `}must be ${expected}${actual && ` (was ${actual})`}`;
});
return describeBranches(pathDescriptions);
},
problem: ctx => ctx.expected,
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;
}
},
intersections: {
union: (l, r, ctx) => {
if (l.isNever !== r.isNever) {
// if exactly one operand is never, we can use it to discriminate based on presence
return Disjoint.init("presence", l, r);
}
let resultBranches;
if (l.ordered) {
if (r.ordered) {
throwParseError(writeOrderedIntersectionMessage(l.expression, r.expression));
}
resultBranches = intersectBranches(r.branches, l.branches, ctx);
if (resultBranches instanceof Disjoint)
resultBranches.invert();
}
else
resultBranches = intersectBranches(l.branches, r.branches, ctx);
if (resultBranches instanceof Disjoint)
return resultBranches;
return ctx.$.parseSchema(l.ordered || r.ordered ?
{
branches: resultBranches,
ordered: true
}
: { branches: resultBranches });
},
...defineRightwardIntersections("union", (l, r, ctx) => {
const branches = intersectBranches(l.branches, [r], ctx);
if (branches instanceof Disjoint)
return branches;
if (branches.length === 1)
return branches[0];
return ctx.$.parseSchema(l.ordered ? { branches, ordered: true } : { branches });
})
}
});
export class UnionNode extends BaseRoot {
isBoolean = this.branches.length === 2 &&
this.branches[0].hasUnit(false) &&
this.branches[1].hasUnit(true);
get branchGroups() {
const branchGroups = [];
let firstBooleanIndex = -1;
for (const branch of this.branches) {
if (branch.hasKind("unit") && branch.domain === "boolean") {
if (firstBooleanIndex === -1) {
firstBooleanIndex = branchGroups.length;
branchGroups.push(branch);
}
else
branchGroups[firstBooleanIndex] = $ark.intrinsic.boolean;
continue;
}
branchGroups.push(branch);
}
return branchGroups;
}
unitBranches = this.branches.filter((n) => n.rawIn.hasKind("unit"));
discriminant = this.discriminate();
discriminantJson = this.discriminant ? discriminantToJson(this.discriminant) : null;
expression = this.distribute(n => n.nestableExpression, expressBranches);
createBranchedOptimisticRootApply() {
return (data, onFail) => {
const optimisticResult = this.traverseOptimistic(data);
if (optimisticResult !== unset)
return optimisticResult;
const ctx = new Traversal(data, this.$.resolvedConfig);
this.traverseApply(data, ctx);
return ctx.finalize(onFail);
};
}
get shallowMorphs() {
return this.branches.reduce((morphs, branch) => appendUnique(morphs, branch.shallowMorphs), []);
}
get defaultShortDescription() {
return this.distribute(branch => branch.defaultShortDescription, describeBranches);
}
innerToJsonSchema(ctx) {
// special case to simplify { const: true } | { const: false }
// to the canonical JSON Schema representation { type: "boolean" }
if (this.branchGroups.length === 1 &&
this.branchGroups[0].equals($ark.intrinsic.boolean))
return { type: "boolean" };
const jsonSchemaBranches = this.branchGroups.map(group => group.toJsonSchemaRecurse(ctx));
if (jsonSchemaBranches.every((branch) =>
// iff all branches are pure unit values with no metadata,
// we can simplify the representation to an enum
Object.keys(branch).length === 1 && hasKey(branch, "const"))) {
return {
enum: jsonSchemaBranches.map(branch => branch.const)
};
}
return {
anyOf: jsonSchemaBranches
};
}
traverseAllows = (data, ctx) => this.branches.some(b => b.traverseAllows(data, ctx));
traverseApply = (data, ctx) => {
const errors = [];
for (let i = 0; i < this.branches.length; i++) {
ctx.pushBranch();
this.branches[i].traverseApply(data, ctx);
if (!ctx.hasError()) {
if (this.branches[i].includesTransform)
return ctx.queuedMorphs.push(...ctx.popBranch().queuedMorphs);
return ctx.popBranch();
}
errors.push(ctx.popBranch().error);
}
ctx.errorFromNodeContext({ code: "union", errors, meta: this.meta });
};
traverseOptimistic = (data) => {
for (let i = 0; i < this.branches.length; i++) {
const branch = this.branches[i];
if (branch.traverseAllows(data)) {
if (branch.contextFreeMorph)
return branch.contextFreeMorph(data);
// if we're calling this function and the matching branch didn't have
// a context-free morph, it shouldn't have morphs at all
return data;
}
}
return unset;
};
compile(js) {
if (!this.discriminant ||
// if we have a union of two units like `boolean`, the
// undiscriminated compilation will be just as fast
(this.unitBranches.length === this.branches.length &&
this.branches.length === 2))
return this.compileIndiscriminable(js);
// we need to access the path as optional so we don't throw if it isn't present
let condition = this.discriminant.optionallyChainedPropString;
if (this.discriminant.kind === "domain")
condition = `typeof ${condition} === "object" ? ${condition} === null ? "null" : "object" : typeof ${condition} === "function" ? "object" : typeof ${condition}`;
const cases = this.discriminant.cases;
const caseKeys = Object.keys(cases);
const { optimistic } = js;
// only the first layer can be optimistic
js.optimistic = false;
js.block(`switch(${condition})`, () => {
for (const k in cases) {
const v = cases[k];
const caseCondition = k === "default" ? k : `case ${k}`;
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}`);
}
return js;
});
if (js.traversalKind === "Allows") {
js.return(optimistic ? `"${unset}"` : false);
return;
}
const expected = describeBranches(this.discriminant.kind === "domain" ?
caseKeys.map(k => {
const jsTypeOf = k.slice(1, -1);
return jsTypeOf === "function" ?
domainDescriptions.object
: domainDescriptions[jsTypeOf];
})
: caseKeys);
const serializedPathSegments = this.discriminant.path.map(k => typeof k === "symbol" ? registeredReference(k) : JSON.stringify(k));
const serializedExpected = JSON.stringify(expected);
const serializedActual = this.discriminant.kind === "domain" ?
`${serializedTypeOfDescriptions}[${condition}]`
: `${serializedPrintable}(${condition})`;
js.line(`ctx.errorFromNodeContext({
code: "predicate",
expected: ${serializedExpected},
actual: ${serializedActual},
relativePath: [${serializedPathSegments}],
meta: ${this.compiledMeta}
})`);
}
compileIndiscriminable(js) {
if (js.traversalKind === "Apply") {
js.const("errors", "[]");
for (const branch of this.branches) {
js.line("ctx.pushBranch()")
.line(js.invoke(branch))
.if("!ctx.hasError()", () => js.return(branch.includesTransform ?
"ctx.queuedMorphs.push(...ctx.popBranch().queuedMorphs)"
: "ctx.popBranch()"))
.line("errors.push(ctx.popBranch().error)");
}
js.line(`ctx.errorFromNodeContext({ code: "union", errors, meta: ${this.compiledMeta} })`);
}
else {
const { optimistic } = js;
// only the first layer can be optimistic
js.optimistic = false;
for (const branch of this.branches) {
js.if(`${js.invoke(branch)}`, () => js.return(optimistic ?
branch.contextFreeMorph ?
`${registeredReference(branch.contextFreeMorph)}(data)`
: "data"
: true));
}
js.return(optimistic ? `"${unset}"` : false);
}
}
get nestableExpression() {
// avoid adding unnecessary parentheses around boolean since it's
// already collapsed to a single keyword
return this.isBoolean ? "boolean" : `(${this.expression})`;
}
discriminate() {
if (this.branches.length < 2 || this.isCyclic)
return null;
if (this.unitBranches.length === this.branches.length) {
const cases = flatMorph(this.unitBranches, (i, n) => [
`${n.rawIn.serializedValue}`,
n.hasKind("morph") ? n : true
]);
return {
kind: "unit",
path: [],
optionallyChainedPropString: "data",
cases
};
}
const candidates = [];
for (let lIndex = 0; lIndex < this.branches.length - 1; lIndex++) {
const l = this.branches[lIndex];
for (let rIndex = lIndex + 1; rIndex < this.branches.length; rIndex++) {
const r = this.branches[rIndex];
const result = intersectNodesRoot(l.rawIn, r.rawIn, l.$);
if (!(result instanceof Disjoint))
continue;
for (const entry of result) {
if (!entry.kind || entry.optional)
continue;
let lSerialized;
let rSerialized;
if (entry.kind === "domain") {
const lValue = entry.l;
const rValue = entry.r;
lSerialized = `"${typeof lValue === "string" ? lValue : lValue.domain}"`;
rSerialized = `"${typeof rValue === "string" ? rValue : rValue.domain}"`;
}
else if (entry.kind === "unit") {
lSerialized = entry.l.serializedValue;
rSerialized = entry.r.serializedValue;
}
else
continue;
const matching = candidates.find(d => arrayEquals(d.path, entry.path) && d.kind === entry.kind);
if (!matching) {
candidates.push({
kind: entry.kind,
cases: {
[lSerialized]: {
branchIndices: [lIndex],
condition: entry.l
},
[rSerialized]: {
branchIndices: [rIndex],
condition: entry.r
}
},
path: entry.path
});
}
else {
if (matching.cases[lSerialized]) {
matching.cases[lSerialized].branchIndices = appendUnique(matching.cases[lSerialized].branchIndices, lIndex);
}
else {
matching.cases[lSerialized] ??= {
branchIndices: [lIndex],
condition: entry.l
};
}
if (matching.cases[rSerialized]) {
matching.cases[rSerialized].branchIndices = appendUnique(matching.cases[rSerialized].branchIndices, rIndex);
}
else {
matching.cases[rSerialized] ??= {
branchIndices: [rIndex],
condition: entry.r
};
}
}
}
}
}
const viableCandidates = this.ordered ?
viableOrderedCandidates(candidates, this.branches)
: candidates;
if (!viableCandidates.length)
return null;
const ctx = createCaseResolutionContext(viableCandidates, this);
const cases = {};
for (const k in ctx.best.cases) {
const resolution = resolveCase(ctx, k);
if (resolution === null) {
cases[k] = true;
continue;
}
// if all the branches ended up back in pruned, we'd loop if we continued
// so just bail out- nothing left to discriminate
if (resolution.length === this.branches.length)
return null;
if (this.ordered) {
// ensure the original order of the pruned branches is preserved
resolution.sort((l, r) => l.originalIndex - r.originalIndex);
}
const branches = resolution.map(entry => entry.branch);
const caseNode = branches.length === 1 ?
branches[0]
: this.$.node("union", this.ordered ? { branches, ordered: true } : branches);
Object.assign(this.referencesById, caseNode.referencesById);
cases[k] = caseNode;
}
if (ctx.defaultEntries.length) {
// we don't have to worry about order here as it is always preserved
// within defaultEntries
const branches = ctx.defaultEntries.map(entry => entry.branch);
cases.default = this.$.node("union", this.ordered ? { branches, ordered: true } : branches, {
prereduced: true
});
Object.assign(this.referencesById, cases.default.referencesById);
}
return Object.assign(ctx.location, {
cases
});
}
}
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 = {
kind: best.kind,
path: best.path,
optionallyChainedPropString: optionallyChainPropString(best.path)
};
const defaultEntries = node.branches.map((branch, originalIndex) => ({
originalIndex,
branch
}));
return {
best,
location,
defaultEntries,
node
};
};
const resolveCase = (ctx, key) => {
const caseCtx = ctx.best.cases[key];
const discriminantNode = discriminantCaseToNode(caseCtx.condition, ctx.location.path, ctx.node.$);
let resolvedEntries = [];
const nextDefaults = [];
for (let i = 0; i < ctx.defaultEntries.length; i++) {
const entry = ctx.defaultEntries[i];
if (caseCtx.branchIndices.includes(entry.originalIndex)) {
const pruned = pruneDiscriminant(ctx.node.branches[entry.originalIndex], ctx.location);
if (pruned === null) {
// if any branch of the union has no constraints (i.e. is
// unknown), the others won't affect the resolution type, but could still
// remove additional cases from defaultEntries
resolvedEntries = null;
}
else {
resolvedEntries?.push({
originalIndex: entry.originalIndex,
branch: pruned
});
}
}
else if (
// we shouldn't need a special case for alias to avoid the below
// once alias resolution issues are improved:
// https://github.com/arktypeio/arktype/issues/1026
entry.branch.hasKind("alias") &&
discriminantNode.hasKind("domain") &&
discriminantNode.domain === "object")
resolvedEntries?.push(entry);
else {
if (entry.branch.rawIn.overlaps(discriminantNode)) {
// include cases where an object not including the
// discriminant path might have that value present as an undeclared key
const overlapping = pruneDiscriminant(entry.branch, ctx.location);
resolvedEntries?.push({
originalIndex: entry.originalIndex,
branch: overlapping
});
}
nextDefaults.push(entry);
}
}
ctx.defaultEntries = nextDefaults;
return resolvedEntries;
};
const viableOrderedCandidates = (candidates, originalBranches) => {
const viableCandidates = candidates.filter(candidate => {
const caseGroups = Object.values(candidate.cases).map(caseCtx => caseCtx.branchIndices);
// compare each group against all subsequent groups.
for (let i = 0; i < caseGroups.length - 1; i++) {
const currentGroup = caseGroups[i];
for (let j = i + 1; j < caseGroups.length; j++) {
const nextGroup = caseGroups[j];
// for each group pair, check for branches whose order was reversed
for (const currentIndex of currentGroup) {
for (const nextIndex of nextGroup) {
if (currentIndex > nextIndex) {
if (originalBranches[currentIndex].overlaps(originalBranches[nextIndex])) {
// if the order was not preserved and the branches overlap,
// this is not a viable discriminant as it cannot guarantee the same behavior
return false;
}
}
}
}
}
}
// branch groups preserved order for non-disjoint pairs and is viable
return true;
});
return viableCandidates;
};
const discriminantCaseToNode = (caseDiscriminant, path, $) => {
let node = caseDiscriminant === "undefined" ? $.node("unit", { unit: undefined })
: caseDiscriminant === "null" ? $.node("unit", { unit: null })
: caseDiscriminant === "boolean" ? $.units([true, false])
: caseDiscriminant;
for (let i = path.length - 1; i >= 0; i--) {
const key = path[i];
node = $.node("intersection", typeof key === "number" ?
{
proto: "Array",
// create unknown for preceding elements (could be optimized with safe imports)
sequence: [...range(key).map(_ => ({})), node]
}
: {
domain: "object",
required: [{ key, value: node }]
});
}
return node;
};
const optionallyChainPropString = (path) => path.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), "data");
const serializedTypeOfDescriptions = registeredReference(jsTypeOfDescriptions);
const serializedPrintable = registeredReference(printable);
export const Union = {
implementation,
Node: UnionNode
};
const discriminantToJson = (discriminant) => ({
kind: discriminant.kind,
path: discriminant.path.map(k => typeof k === "string" ? k : compileSerializedValue(k)),
cases: flatMorph(discriminant.cases, (k, node) => [
k,
node === true ? node
: node.hasKind("union") && node.discriminantJson ? node.discriminantJson
: node.json
])
});
const describeExpressionOptions = {
delimiter: " | ",
finalDelimiter: " | "
};
const expressBranches = (expressions) => describeBranches(expressions, describeExpressionOptions);
export const describeBranches = (descriptions, opts) => {
const delimiter = opts?.delimiter ?? ", ";
const finalDelimiter = opts?.finalDelimiter ?? " or ";
if (descriptions.length === 0)
return "never";
if (descriptions.length === 1)
return descriptions[0];
if ((descriptions.length === 2 &&
descriptions[0] === "false" &&
descriptions[1] === "true") ||
(descriptions[0] === "true" && descriptions[1] === "false"))
return "boolean";
// keep track of seen descriptions to avoid duplication
const seen = {};
const unique = descriptions.filter(s => (seen[s] ? false : (seen[s] = true)));
const last = unique.pop();
return `${unique.join(delimiter)}${unique.length ? finalDelimiter : ""}${last}`;
};
export const intersectBranches = (l, r, ctx) => {
// If the corresponding r branch is identified as a subtype of an l branch, the
// value at rIndex is set to null so we can avoid including previous/future
// intersections in the reduced result.
const batchesByR = r.map(() => []);
for (let lIndex = 0; lIndex < l.length; lIndex++) {
let candidatesByR = {};
for (let rIndex = 0; rIndex < r.length; rIndex++) {
if (batchesByR[rIndex] === null) {
// rBranch is a subtype of an lBranch and
// will not yield any distinct intersection
continue;
}
if (l[lIndex].equals(r[rIndex])) {
// Combination of subtype and supertype cases
batchesByR[rIndex] = null;
candidatesByR = {};
break;
}
const branchIntersection = intersectOrPipeNodes(l[lIndex], r[rIndex], ctx);
if (branchIntersection instanceof Disjoint) {
// Doesn't tell us anything useful about their relationships
// with other branches
continue;
}
if (branchIntersection.equals(l[lIndex])) {
// If the current l branch is a subtype of r, intersections
// with previous and remaining branches of r won't lead to
// distinct intersections.
batchesByR[rIndex].push(l[lIndex]);
candidatesByR = {};
break;
}
if (branchIntersection.equals(r[rIndex])) {
// If the current r branch is a subtype of l, set its batch to
// null, removing any previous intersections and preventing any
// of its remaining intersections from being computed.
batchesByR[rIndex] = null;
}
else {
// If neither l nor r is a subtype of the other, add their
// intersection as a candidate (could still be removed if it is
// determined l or r is a subtype of a remaining branch).
candidatesByR[rIndex] = branchIntersection;
}
}
for (const rIndex in candidatesByR) {
// batchesByR at rIndex should never be null if it is in candidatesByR
batchesByR[rIndex][lIndex] = candidatesByR[rIndex];
}
}
// Compile the reduced intersection result, including:
// 1. Remaining candidates resulting from distinct intersections or strict subtypes of r
// 2. Original r branches corresponding to indices with a null batch (subtypes of l)
const resultBranches = batchesByR.flatMap(
// ensure unions returned from branchable intersections like sequence are flattened
(batch, i) => batch?.flatMap(branch => branch.branches) ?? r[i]);
return resultBranches.length === 0 ?
Disjoint.init("union", l, r)
: resultBranches;
};
export const reduceBranches = ({ branches, ordered }) => {
if (branches.length < 2)
return branches;
const uniquenessByIndex = branches.map(() => true);
for (let i = 0; i < branches.length; i++) {
for (let j = i + 1; j < branches.length && uniquenessByIndex[i] && uniquenessByIndex[j]; j++) {
if (branches[i].equals(branches[j])) {
// if the two branches are equal, only "j" is marked as
// redundant so at least one copy could still be included in
// the final set of branches.
uniquenessByIndex[j] = false;
continue;
}
const intersection = intersectNodesRoot(branches[i].rawIn, branches[j].rawIn, branches[0].$);
if (intersection instanceof Disjoint)
continue;
if (!ordered)
assertDeterminateOverlap(branches[i], branches[j]);
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].rawIn))
uniquenessByIndex[j] = false;
}
}
return branches.filter((_, i) => uniquenessByIndex[i]);
};
const assertDeterminateOverlap = (l, r) => {
if (!l.includesTransform && !r.includesTransform)
return;
if (!arrayEquals(l.shallowMorphs, r.shallowMorphs)) {
throwParseError(writeIndiscriminableMorphMessage(l.expression, r.expression));
}
if (!arrayEquals(l.flatMorphs, r.flatMorphs, {
isEqual: (l, r) => l.propString === r.propString &&
(l.node.hasKind("morph") && r.node.hasKind("morph") ?
l.node.hasEqualMorphs(r.node)
: l.node.hasKind("intersection") && r.node.hasKind("intersection") ?
l.node.structure?.structuralMorphRef ===
r.node.structure?.structuralMorphRef
: false)
})) {
throwParseError(writeIndiscriminableMorphMessage(l.expression, r.expression));
}
};
export const pruneDiscriminant = (discriminantBranch, discriminantCtx) => discriminantBranch.transform((nodeKind, inner) => {
if (nodeKind === "domain" || nodeKind === "unit")
return null;
return inner;
}, {
shouldTransform: (node, ctx) => {
// safe to cast here as index nodes are never discriminants
const propString = optionallyChainPropString(ctx.path);
if (!discriminantCtx.optionallyChainedPropString.startsWith(propString))
return false;
if (node.hasKind("domain") && node.domain === "object")
// if we've already checked a path at least as long as the current one,
// we don't need to revalidate that we're in an object
return true;
if ((node.hasKind("domain") || discriminantCtx.kind === "unit") &&
propString === discriminantCtx.optionallyChainedPropString)
// if the discriminant has already checked the domain at the current path
// (or a unit literal, implying a domain), we don't need to recheck it
return true;
// we don't need to recurse into index nodes as they will never
// have a required path therefore can't be used to discriminate
return node.children.length !== 0 && node.kind !== "index";
}
});
export const writeIndiscriminableMorphMessage = (lDescription, rDescription) => `An unordered union of a type including a morph and a type with overlapping input is indeterminate:
Left: ${lDescription}
Right: ${rDescription}`;
export const writeOrderedIntersectionMessage = (lDescription, rDescription) => `The intersection of two ordered unions is indeterminate:
Left: ${lDescription}
Right: ${rDescription}`;

41
frontend/node_modules/@ark/schema/out/roots/unit.d.ts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import { type Domain, type JsonPrimitive } from "@ark/util";
import type { BaseErrorContext, BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import type { TraverseAllows } from "../shared/traversal.ts";
import { InternalBasis } from "./basis.ts";
export declare namespace Unit {
interface Schema<value = unknown> extends BaseNormalizedSchema {
readonly unit: value;
}
interface Inner<value = unknown> {
readonly unit: value;
}
interface ErrorContext<value = unknown> extends BaseErrorContext<"unit">, Inner<value> {
}
interface Declaration extends declareNode<{
kind: "unit";
schema: Schema;
normalizedSchema: Schema;
inner: Inner;
errorContext: ErrorContext;
}> {
}
type Node = UnitNode;
}
export declare class UnitNode extends InternalBasis<Unit.Declaration> {
compiledValue: JsonPrimitive;
serializedValue: string;
compiledCondition: string;
compiledNegation: string;
expression: string;
domain: Domain;
get defaultShortDescription(): string;
protected innerToJsonSchema(ctx: ToJsonSchema.Context): JsonSchema;
traverseAllows: TraverseAllows;
}
export declare const Unit: {
implementation: nodeImplementationOf<Unit.Declaration>;
Node: typeof UnitNode;
};

86
frontend/node_modules/@ark/schema/out/roots/unit.js generated vendored Normal file
View File

@@ -0,0 +1,86 @@
import { domainDescriptions, domainOf, printable } from "@ark/util";
import { Disjoint } from "../shared/disjoint.js";
import { defaultValueSerializer, implementNode } from "../shared/implement.js";
import { $ark } from "../shared/registry.js";
import { InternalBasis } from "./basis.js";
import { defineRightwardIntersections } from "./utils.js";
const implementation = implementNode({
kind: "unit",
hasAssociatedError: true,
keys: {
unit: {
preserveUndefined: true,
serialize: schema => schema instanceof Date ?
schema.toISOString()
: defaultValueSerializer(schema)
}
},
normalize: schema => schema,
defaults: {
description: node => printable(node.unit),
problem: ({ expected, actual }) => `${expected === actual ? `must be reference equal to ${expected} (serialized to the same value)` : `must be ${expected} (was ${actual})`}`
},
intersections: {
unit: (l, r) => Disjoint.init("unit", l, r),
...defineRightwardIntersections("unit", (l, r) => {
if (r.allows(l.unit))
return l;
// will always be a disjoint at this point, but we try to use
// a domain Disjoint if possible since it's better for discrimination
const rBasis = r.hasKind("intersection") ? r.basis : r;
if (rBasis) {
const rDomain = rBasis.hasKind("domain") ? rBasis : $ark.intrinsic.object;
if (l.domain !== rDomain.domain) {
const lDomainDisjointValue = (l.domain === "undefined" ||
l.domain === "null" ||
l.domain === "boolean") ?
l.domain
: $ark.intrinsic[l.domain];
return Disjoint.init("domain", lDomainDisjointValue, rDomain);
}
}
return Disjoint.init("assignability", l, r.hasKind("intersection") ?
r.children.find(rConstraint => !rConstraint.allows(l.unit))
: r);
})
}
});
export class UnitNode extends InternalBasis {
compiledValue = this.json.unit;
serializedValue = typeof this.unit === "string" || this.unit instanceof Date ?
JSON.stringify(this.compiledValue)
: `${this.compiledValue}`;
compiledCondition = compileEqualityCheck(this.unit, this.serializedValue);
compiledNegation = compileEqualityCheck(this.unit, this.serializedValue, "negated");
expression = printable(this.unit);
domain = domainOf(this.unit);
get defaultShortDescription() {
return this.domain === "object" ?
domainDescriptions.object
: this.description;
}
innerToJsonSchema(ctx) {
return (
// this is the more standard JSON schema representation, especially for Open API
this.unit === null ? { type: "null" }
: $ark.intrinsic.jsonPrimitive.allows(this.unit) ? { const: this.unit }
: ctx.fallback.unit({ code: "unit", base: {}, unit: this.unit }));
}
traverseAllows = this.unit instanceof Date ?
data => data instanceof Date && data.toISOString() === this.compiledValue
: Number.isNaN(this.unit) ? data => Number.isNaN(data)
: data => data === this.unit;
}
export const Unit = {
implementation,
Node: UnitNode
};
const compileEqualityCheck = (unit, serializedValue, negated) => {
if (unit instanceof Date) {
const condition = `data instanceof Date && data.toISOString() === ${serializedValue}`;
return negated ? `!(${condition})` : condition;
}
if (Number.isNaN(unit))
return `${negated ? "!" : ""}Number.isNaN(data)`;
return `data ${negated ? "!" : "="}== ${serializedValue}`;
};

View File

@@ -0,0 +1,3 @@
import { type RootIntersection, type RootKind } from "../shared/implement.ts";
import type { schemaKindRightOf } from "./root.ts";
export declare const defineRightwardIntersections: <kind extends RootKind>(kind: kind, implementation: RootIntersection<kind, schemaKindRightOf<kind>>) => { [k in schemaKindRightOf<kind>]: RootIntersection<kind, k>; };

6
frontend/node_modules/@ark/schema/out/roots/utils.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
import { flatMorph } from "@ark/util";
import { schemaKindsRightOf } from "../shared/implement.js";
export const defineRightwardIntersections = (kind, implementation) => flatMorph(schemaKindsRightOf(kind), (i, kind) => [
kind,
implementation
]);

158
frontend/node_modules/@ark/schema/out/scope.d.ts generated vendored Normal file
View File

@@ -0,0 +1,158 @@
import { ParseError, type JsonStructure, type anyOrNever, type array, type conform, type flattenListable, type intersectUnion, type listable, type noSuggest, type satisfy, type show } from "@ark/util";
import { type ArkSchemaConfig, type ResolvedConfig } from "./config.ts";
import { GenericRoot, type GenericRootParser } from "./generic.ts";
import { type NodeSchema, type RootSchema, type nodeOfKind, type reducibleKindOf } from "./kinds.ts";
import { RootModule, type InternalModule, type PreparsedNodeResolution, type SchemaModule, type instantiateRoot } from "./module.ts";
import type { BaseNode } from "./node.ts";
import { type AttachedParseContext, type BaseParseContext, type BaseParseContextInput, type BaseParseOptions, type NodeId, type NodeParseContext, type NodeParseContextInput } from "./parse.ts";
import { Alias } from "./roots/alias.ts";
import type { BaseRoot } from "./roots/root.ts";
import type { NodeKind, RootKind } from "./shared/implement.ts";
import { $ark } from "./shared/registry.ts";
import { Traversal, type TraverseAllows, type TraverseApply } from "./shared/traversal.ts";
import { arkKind } from "./shared/utils.ts";
export type InternalResolutions = Record<string, InternalResolution | undefined>;
export type exportedNameOf<$> = Exclude<keyof $ & string, PrivateDeclaration>;
export type resolvableReferenceIn<$> = {
[k in keyof $]: k extends string ? k extends PrivateDeclaration<infer alias> ? alias : k extends noSuggest | "root" ? never : k : never;
}[keyof $];
export type resolveReference<reference extends resolvableReferenceIn<$>, $> = reference extends keyof $ ? $[reference] : $[`#${reference}` & keyof $];
export type flatResolutionsOf<$> = show<intersectUnion<resolvableReferenceIn<$> extends infer k ? k extends keyof $ & string ? resolutionsOfReference<k, $[k]> : unknown : unknown>>;
type resolutionsOfReference<k extends string, v> = [
v
] extends [{
[arkKind]: "module";
}] ? [
v
] extends [anyOrNever] ? {
[_ in k]: v;
} : prefixKeys<flatResolutionsOf<v>, k> & {
[innerKey in keyof v as innerKey extends "root" ? k : never]: v[innerKey];
} : {
[_ in k]: v;
};
type prefixKeys<o, prefix extends string> = {
[k in keyof o & string as `${prefix}.${k}`]: o[k];
} & unknown;
export type PrivateDeclaration<key extends string = string> = `#${key}`;
export type InternalResolution = BaseRoot | GenericRoot | InternalModule;
export type toInternalScope<$> = BaseScope<{
[k in keyof $]: $[k] extends {
[arkKind]: infer kind;
} ? [
$[k]
] extends [anyOrNever] ? BaseRoot : kind extends "generic" ? GenericRoot : kind extends "module" ? InternalModule : never : BaseRoot;
}>;
type CachedResolution = NodeId | BaseRoot | GenericRoot;
export declare const writeDuplicateAliasError: <alias extends string>(alias: alias) => writeDuplicateAliasError<alias>;
export type writeDuplicateAliasError<alias extends string> = `#${alias} duplicates public alias ${alias}`;
export type AliasDefEntry = [name: string, defValue: unknown];
export type GlobalOnlyConfigOptionName = satisfy<keyof ArkSchemaConfig, "dateAllowsInvalid" | "numberAllowsNaN" | "onUndeclaredKey" | "keywords">;
export interface ScopeOnlyConfigOptions {
name?: string;
prereducedAliases?: boolean;
}
export interface ArkSchemaScopeConfig extends Omit<ArkSchemaConfig, GlobalOnlyConfigOptionName>, ScopeOnlyConfigOptions {
}
export interface ResolvedScopeConfig extends ResolvedConfig, ScopeOnlyConfigOptions {
}
export type PrecompiledReferences = {
[k: `${string}Allows`]: TraverseAllows;
[k: `${string}Apply`]: TraverseApply;
[k: `${string}Optimistic`]: (data: unknown) => unknown;
};
export declare abstract class BaseScope<$ extends {} = {}> {
readonly config: ArkSchemaScopeConfig;
readonly resolvedConfig: ResolvedScopeConfig;
readonly name: string;
get [arkKind](): "scope";
readonly referencesById: {
[id: string]: BaseNode;
};
references: readonly BaseNode[];
readonly resolutions: {
[alias: string]: CachedResolution | undefined;
};
exportedNames: string[];
readonly aliases: Record<string, unknown>;
protected resolved: boolean;
readonly nodesByHash: Record<string, BaseNode>;
readonly intrinsic: Omit<typeof $ark.intrinsic, `json${string}`>;
constructor(
/** The set of names defined at the root-level of the scope mapped to their
* corresponding definitions.**/
def: Record<string, unknown>, config?: ArkSchemaScopeConfig);
protected cacheGetter<name extends keyof this>(name: name, value: this[name]): this[name];
get internal(): this;
private _json;
get json(): JsonStructure;
defineSchema<def extends RootSchema>(def: def): def;
generic: GenericRootParser;
units: (values: array, opts?: BaseParseOptions) => BaseRoot;
protected lazyResolutions: Alias.Node[];
lazilyResolve(resolve: () => BaseRoot, syntheticAlias?: string): Alias.Node;
schema: InternalSchemaParser;
parseSchema: InternalSchemaParser;
protected preparseNode(kinds: NodeKind | listable<RootKind>, schema: unknown, opts: BaseParseOptions): BaseNode | NodeParseContextInput;
bindReference<reference extends BaseNode | GenericRoot>(reference: reference): reference;
resolveRoot(name: string): BaseRoot;
maybeResolveRoot(name: string): BaseRoot | undefined;
/** If name is a valid reference to a submodule alias, return its resolution */
protected maybeResolveSubalias(name: string): BaseRoot | GenericRoot | undefined;
get ambient(): InternalModule;
maybeResolve(name: string): Exclude<CachedResolution, string> | undefined;
protected createParseContext<input extends BaseParseContextInput>(input: input): input & AttachedParseContext;
traversal(root: unknown): Traversal;
import(): SchemaModule<{
[k in exportedNameOf<$> as PrivateDeclaration<k>]: $[k];
}>;
import<names extends exportedNameOf<$>[]>(...names: names): SchemaModule<{
[k in names[number] as PrivateDeclaration<k>]: $[k];
} & unknown>;
precompilation: string | undefined;
private _exportedResolutions;
private _exports;
export(): SchemaModule<{
[k in exportedNameOf<$>]: $[k];
}>;
export<names extends exportedNameOf<$>[]>(...names: names): SchemaModule<{
[k in names[number]]: $[k];
} & unknown>;
resolve<name extends exportedNameOf<$>>(name: name): instantiateRoot<$[name]>;
node: <kinds extends NodeKind | array<RootKind>, prereduced extends boolean = false>(kinds: kinds, nodeSchema: NodeSchema<flattenListable<kinds>>, opts?: BaseParseOptions<prereduced>) => nodeOfKind<prereduced extends true ? flattenListable<kinds> : reducibleKindOf<flattenListable<kinds>>>;
parse: (def: unknown, opts?: BaseParseOptions) => BaseRoot;
parseDefinition(def: unknown, opts?: BaseParseOptions): BaseRoot;
finalize<node extends BaseRoot>(node: node): node;
protected abstract preparseOwnDefinitionFormat(def: unknown, opts: BaseParseOptions): BaseRoot | BaseParseContextInput;
abstract parseOwnDefinitionFormat(def: unknown, ctx: BaseParseContext): BaseRoot;
protected abstract preparseOwnAliasEntry(k: string, v: unknown): AliasDefEntry;
protected abstract normalizeRootScopeValue(resolution: unknown): unknown;
}
export declare class SchemaScope<$ extends {} = {}> extends BaseScope<$> {
parseOwnDefinitionFormat(def: unknown, ctx: NodeParseContext): BaseRoot;
protected preparseOwnDefinitionFormat(schema: RootSchema, opts: BaseParseOptions): BaseRoot | NodeParseContextInput;
protected preparseOwnAliasEntry(k: string, v: unknown): AliasDefEntry;
protected normalizeRootScopeValue(v: unknown): unknown;
}
type instantiateAliases<aliases> = {
[k in keyof aliases]: aliases[k] extends InternalResolution ? aliases[k] : BaseRoot;
} & unknown;
export type SchemaScopeParser = <const aliases>(aliases: {
[k in keyof aliases]: conform<aliases[k], RootSchema | PreparsedNodeResolution>;
}, config?: ArkSchemaScopeConfig) => BaseScope<instantiateAliases<aliases>>;
export declare const schemaScope: SchemaScopeParser;
export type InternalSchemaParser = (schema: RootSchema, opts?: BaseParseOptions) => BaseRoot;
export declare const rootSchemaScope: SchemaScope;
export declare const parseAsSchema: (def: unknown, opts?: BaseParseOptions) => BaseRoot | ParseError;
export type RootExportCache = Record<string, BaseRoot | GenericRoot | RootModule | undefined>;
export declare const writeUnresolvableMessage: <token extends string>(token: token) => writeUnresolvableMessage<token>;
export type writeUnresolvableMessage<token extends string> = `'${token}' is unresolvable`;
export declare const writeNonSubmoduleDotMessage: <name extends string>(name: name) => writeNonSubmoduleDotMessage<name>;
export type writeNonSubmoduleDotMessage<name extends string> = `'${name}' must reference a module to be accessed using dot syntax`;
export declare const writeMissingSubmoduleAccessMessage: <name extends string>(name: name) => writeMissingSubmoduleAccessMessage<name>;
export type writeMissingSubmoduleAccessMessage<name extends string> = `Reference to submodule '${name}' must specify an alias`;
export declare const rootSchema: BaseScope["schema"];
export declare const node: BaseScope["node"];
export declare const defineSchema: BaseScope["defineSchema"];
export declare const genericNode: BaseScope["generic"];
export {};

481
frontend/node_modules/@ark/schema/out/scope.js generated vendored Normal file
View File

@@ -0,0 +1,481 @@
import { ParseError, flatMorph, hasDomain, isArray, isThunk, printable, throwInternalError, throwParseError } from "@ark/util";
import { mergeConfigs } from "./config.js";
import { GenericRoot, LazyGenericBody } from "./generic.js";
import { nodeImplementationsByKind } from "./kinds.js";
import { RootModule, bindModule } from "./module.js";
import { nodesByRegisteredId, parseNode, registerNodeId, schemaKindOf, withId } from "./parse.js";
import { Alias } from "./roots/alias.js";
import { CompiledFunction, NodeCompiler } from "./shared/compile.js";
import { $ark } from "./shared/registry.js";
import { Traversal } from "./shared/traversal.js";
import { arkKind, hasArkKind, isNode } from "./shared/utils.js";
const schemaBranchesOf = (schema) => isArray(schema) ? schema
: "branches" in schema && isArray(schema.branches) ? schema.branches
: undefined;
const throwMismatchedNodeRootError = (expected, actual) => throwParseError(`Node of kind ${actual} is not valid as a ${expected} definition`);
export const writeDuplicateAliasError = (alias) => `#${alias} duplicates public alias ${alias}`;
const scopesByName = {};
$ark.ambient ??= {};
let rawUnknownUnion;
const rootScopeFnName = "function $";
const precompile = (references) => bindPrecompilation(references, precompileReferences(references));
const bindPrecompilation = (references, precompiler) => {
const precompilation = precompiler.write(rootScopeFnName, 4);
const compiledTraversals = precompiler.compile()();
for (const node of references) {
if (node.precompilation) {
// if node has already been bound to another scope or anonymous type, don't rebind it
continue;
}
node.traverseAllows =
compiledTraversals[`${node.id}Allows`].bind(compiledTraversals);
if (node.isRoot() && !node.allowsRequiresContext) {
// if the reference doesn't require context, we can assign over
// it directly to avoid having to initialize it
node.allows = node.traverseAllows;
}
node.traverseApply =
compiledTraversals[`${node.id}Apply`].bind(compiledTraversals);
if (compiledTraversals[`${node.id}Optimistic`]) {
;
node.traverseOptimistic =
compiledTraversals[`${node.id}Optimistic`].bind(compiledTraversals);
}
node.precompilation = precompilation;
}
};
const precompileReferences = (references) => new CompiledFunction().return(references.reduce((js, node) => {
const allowsCompiler = new NodeCompiler({ kind: "Allows" }).indent();
node.compile(allowsCompiler);
const allowsJs = allowsCompiler.write(`${node.id}Allows`);
const applyCompiler = new NodeCompiler({ kind: "Apply" }).indent();
node.compile(applyCompiler);
const applyJs = applyCompiler.write(`${node.id}Apply`);
const result = `${js}${allowsJs},\n${applyJs},\n`;
if (!node.hasKind("union"))
return result;
const optimisticCompiler = new NodeCompiler({
kind: "Allows",
optimistic: true
}).indent();
node.compile(optimisticCompiler);
const optimisticJs = optimisticCompiler.write(`${node.id}Optimistic`);
return `${result}${optimisticJs},\n`;
}, "{\n") + "}");
export class BaseScope {
config;
resolvedConfig;
name;
get [arkKind]() {
return "scope";
}
referencesById = {};
references = [];
resolutions = {};
exportedNames = [];
aliases = {};
resolved = false;
nodesByHash = {};
intrinsic;
constructor(
/** The set of names defined at the root-level of the scope mapped to their
* corresponding definitions.**/
def, config) {
this.config = mergeConfigs($ark.config, config);
this.resolvedConfig = mergeConfigs($ark.resolvedConfig, config);
this.name =
this.resolvedConfig.name ??
`anonymousScope${Object.keys(scopesByName).length}`;
if (this.name in scopesByName)
throwParseError(`A Scope already named ${this.name} already exists`);
scopesByName[this.name] = this;
const aliasEntries = Object.entries(def).map(entry => this.preparseOwnAliasEntry(...entry));
for (const [k, v] of aliasEntries) {
let name = k;
if (k[0] === "#") {
name = k.slice(1);
if (name in this.aliases)
throwParseError(writeDuplicateAliasError(name));
this.aliases[name] = v;
}
else {
if (name in this.aliases)
throwParseError(writeDuplicateAliasError(k));
this.aliases[name] = v;
this.exportedNames.push(name);
}
if (!hasArkKind(v, "module") &&
!hasArkKind(v, "generic") &&
!isThunk(v)) {
const preparsed = this.preparseOwnDefinitionFormat(v, { alias: name });
this.resolutions[name] =
hasArkKind(preparsed, "root") ?
this.bindReference(preparsed)
: this.createParseContext(preparsed).id;
}
}
// reduce union of all possible values reduces to unknown
rawUnknownUnion ??= this.node("union", {
branches: [
"string",
"number",
"object",
"bigint",
"symbol",
{ unit: true },
{ unit: false },
{ unit: undefined },
{ unit: null }
]
}, { prereduced: true });
this.nodesByHash[rawUnknownUnion.hash] = this.node("intersection", {}, { prereduced: true });
this.intrinsic =
$ark.intrinsic ?
flatMorph($ark.intrinsic, (k, v) =>
// don't include cyclic aliases from JSON scope
k.startsWith("json") ? [] : [k, this.bindReference(v)])
// intrinsic won't be available during bootstrapping, so we lie
// about the type here as an extrnal convenience
: {};
}
cacheGetter(name, value) {
Object.defineProperty(this, name, { value });
return value;
}
get internal() {
return this;
}
// json is populated when the scope is exported, so ensure it is populated
// before allowing external access
_json;
get json() {
if (!this._json)
this.export();
return this._json;
}
defineSchema(def) {
return def;
}
generic = (...params) => {
const $ = this;
return (def, possibleHkt) => new GenericRoot(params, possibleHkt ? new LazyGenericBody(def) : def, $, $, possibleHkt ?? null);
};
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) {
const node = this.node("alias", {
reference: syntheticAlias ?? "synthetic",
resolve
}, { prereduced: true });
if (!this.resolved)
this.lazyResolutions.push(node);
return node;
}
schema = (schema, opts) => this.finalize(this.parseSchema(schema, opts));
parseSchema = (schema, opts) => this.node(schemaKindOf(schema), schema, opts);
preparseNode(kinds, schema, opts) {
let kind = typeof kinds === "string" ? kinds : schemaKindOf(schema, kinds);
if (isNode(schema) && schema.kind === kind)
return schema;
if (kind === "alias" && !opts?.prereduced) {
const { reference } = Alias.implementation.normalize(schema, this);
if (reference.startsWith("$")) {
const resolution = this.resolveRoot(reference.slice(1));
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);
}
}
if (isNode(schema) && schema.kind === kind)
return schema;
const impl = nodeImplementationsByKind[kind];
const normalizedSchema = impl.normalize?.(schema, this) ?? 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
: throwMismatchedNodeRootError(kind, normalizedSchema.kind);
}
return {
...opts,
$: this,
kind,
def: normalizedSchema,
prefix: opts.alias ?? kind
};
}
bindReference(reference) {
let bound;
if (isNode(reference)) {
bound =
reference.$ === this ?
reference
: new reference.constructor(reference.attachments, this);
}
else {
bound =
reference.$ === this ?
reference
: new GenericRoot(reference.params, reference.bodyDef, reference.$, this, reference.hkt);
}
if (!this.resolved) {
// we're still parsing the scope itself, so defer compilation but
// add the node as a reference
Object.assign(this.referencesById, bound.referencesById);
}
return bound;
}
resolveRoot(name) {
return (this.maybeResolveRoot(name) ??
throwParseError(writeUnresolvableMessage(name)));
}
maybeResolveRoot(name) {
const result = this.maybeResolve(name);
if (hasArkKind(result, "generic"))
return;
return result;
}
/** If name is a valid reference to a submodule alias, return its resolution */
maybeResolveSubalias(name) {
return (maybeResolveSubalias(this.aliases, name) ??
maybeResolveSubalias(this.ambient, name));
}
get ambient() {
return $ark.ambient;
}
maybeResolve(name) {
const cached = this.resolutions[name];
if (cached) {
if (typeof cached !== "string")
return this.bindReference(cached);
const v = nodesByRegisteredId[cached];
if (hasArkKind(v, "root"))
return (this.resolutions[name] = v);
if (hasArkKind(v, "context")) {
if (v.phase === "resolving") {
return this.node("alias", { reference: `$${name}` }, { prereduced: true });
}
if (v.phase === "resolved") {
return throwInternalError(`Unexpected resolved context for was uncached by its scope: ${printable(v)}`);
}
v.phase = "resolving";
const node = this.bindReference(this.parseOwnDefinitionFormat(v.def, v));
v.phase = "resolved";
nodesByRegisteredId[node.id] = node;
nodesByRegisteredId[v.id] = node;
return (this.resolutions[name] = node);
}
return throwInternalError(`Unexpected nodesById entry for ${cached}: ${printable(v)}`);
}
let def = this.aliases[name] ?? this.ambient?.[name];
if (!def)
return this.maybeResolveSubalias(name);
def = this.normalizeRootScopeValue(def);
if (hasArkKind(def, "generic"))
return (this.resolutions[name] = this.bindReference(def));
if (hasArkKind(def, "module")) {
if (!def.root)
throwParseError(writeMissingSubmoduleAccessMessage(name));
return (this.resolutions[name] = this.bindReference(def.root));
}
return (this.resolutions[name] = this.parse(def, {
alias: name
}));
}
createParseContext(input) {
const id = input.id ?? registerNodeId(input.prefix);
return (nodesByRegisteredId[id] = Object.assign(input, {
[arkKind]: "context",
$: this,
id,
phase: "unresolved"
}));
}
traversal(root) {
return new Traversal(root, this.resolvedConfig);
}
import(...names) {
return new RootModule(flatMorph(this.export(...names), (alias, value) => [
`#${alias}`,
value
]));
}
precompilation;
_exportedResolutions;
_exports;
export(...names) {
if (!this._exports) {
this._exports = {};
for (const name of this.exportedNames) {
const def = this.aliases[name];
this._exports[name] =
hasArkKind(def, "module") ?
bindModule(def, this)
: bootstrapAliasReferences(this.maybeResolve(name));
}
// force node.resolution getter evaluation
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
for (const node of this.lazyResolutions)
node.resolution;
this._exportedResolutions = resolutionsOfModule(this, this._exports);
this._json = resolutionsToJson(this._exportedResolutions);
Object.assign(this.resolutions, this._exportedResolutions);
this.references = Object.values(this.referencesById);
if (!this.resolvedConfig.jitless) {
const precompiler = precompileReferences(this.references);
this.precompilation = precompiler.write(rootScopeFnName, 4);
bindPrecompilation(this.references, precompiler);
}
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];
}
node = (kinds, nodeSchema, opts = {}) => {
const ctxOrNode = this.preparseNode(kinds, nodeSchema, opts);
if (isNode(ctxOrNode))
return this.bindReference(ctxOrNode);
const ctx = this.createParseContext(ctxOrNode);
const node = parseNode(ctx);
const bound = this.bindReference(node);
return (nodesByRegisteredId[ctx.id] = bound);
};
parse = (def, opts = {}) => this.finalize(this.parseDefinition(def, opts));
parseDefinition(def, opts = {}) {
if (hasArkKind(def, "root"))
return this.bindReference(def);
const ctxInputOrNode = this.preparseOwnDefinitionFormat(def, opts);
if (hasArkKind(ctxInputOrNode, "root"))
return this.bindReference(ctxInputOrNode);
const ctx = this.createParseContext(ctxInputOrNode);
nodesByRegisteredId[ctx.id] = ctx;
let node = this.bindReference(this.parseOwnDefinitionFormat(def, ctx));
// if the node is recursive e.g. { box: "this" }, we need to make sure it
// has the original id from context so that its references compile correctly
if (node.isCyclic)
node = withId(node, ctx.id);
nodesByRegisteredId[ctx.id] = node;
return node;
}
finalize(node) {
bootstrapAliasReferences(node);
if (!node.precompilation && !this.resolvedConfig.jitless)
precompile(node.references);
return node;
}
}
export class SchemaScope extends BaseScope {
parseOwnDefinitionFormat(def, ctx) {
return parseNode(ctx);
}
preparseOwnDefinitionFormat(schema, opts) {
return this.preparseNode(schemaKindOf(schema), schema, opts);
}
preparseOwnAliasEntry(k, v) {
return [k, v];
}
normalizeRootScopeValue(v) {
return v;
}
}
const bootstrapAliasReferences = (resolution) => {
const aliases = resolution.references.filter(node => node.hasKind("alias"));
for (const aliasNode of aliases) {
Object.assign(aliasNode.referencesById, aliasNode.resolution.referencesById);
for (const ref of resolution.references) {
if (aliasNode.id in ref.referencesById)
Object.assign(ref.referencesById, aliasNode.referencesById);
}
}
return resolution;
};
const resolutionsToJson = (resolutions) => flatMorph(resolutions, (k, v) => [
k,
hasArkKind(v, "root") || hasArkKind(v, "generic") ? v.json
: hasArkKind(v, "module") ? resolutionsToJson(v)
: throwInternalError(`Unexpected resolution ${printable(v)}`)
]);
const maybeResolveSubalias = (base, name) => {
const dotIndex = name.indexOf(".");
if (dotIndex === -1)
return;
const dotPrefix = name.slice(0, dotIndex);
const prefixSchema = base[dotPrefix];
// if the name includes ".", but the prefix is not an alias, it
// might be something like a decimal literal, so just fall through to return
if (prefixSchema === undefined)
return;
if (!hasArkKind(prefixSchema, "module"))
return throwParseError(writeNonSubmoduleDotMessage(dotPrefix));
const subalias = name.slice(dotIndex + 1);
const resolution = prefixSchema[subalias];
if (resolution === undefined)
return maybeResolveSubalias(prefixSchema, subalias);
if (hasArkKind(resolution, "root") || hasArkKind(resolution, "generic"))
return resolution;
if (hasArkKind(resolution, "module")) {
return (resolution.root ??
throwParseError(writeMissingSubmoduleAccessMessage(name)));
}
throwInternalError(`Unexpected resolution for alias '${name}': ${printable(resolution)}`);
};
export const schemaScope = (aliases, config) => new SchemaScope(aliases, config);
export const rootSchemaScope = new SchemaScope({});
export const parseAsSchema = (def, opts) => {
try {
return rootSchema(def, opts);
}
catch (e) {
if (e instanceof ParseError)
return e;
throw e;
}
};
const resolutionsOfModule = ($, typeSet) => {
const result = {};
for (const k in typeSet) {
const v = typeSet[k];
if (hasArkKind(v, "module")) {
const innerResolutions = resolutionsOfModule($, v);
const prefixedResolutions = flatMorph(innerResolutions, (innerK, innerV) => [`${k}.${innerK}`, innerV]);
Object.assign(result, prefixedResolutions);
}
else if (hasArkKind(v, "root") || hasArkKind(v, "generic"))
result[k] = v;
else
throwInternalError(`Unexpected scope resolution ${printable(v)}`);
}
return result;
};
export const writeUnresolvableMessage = (token) => `'${token}' is unresolvable`;
export const writeNonSubmoduleDotMessage = (name) => `'${name}' must reference a module to be accessed using dot syntax`;
export const writeMissingSubmoduleAccessMessage = (name) => `Reference to submodule '${name}' must specify an alias`;
// ensure the scope is resolved so JIT will be applied to future types
rootSchemaScope.export();
export const rootSchema = rootSchemaScope.schema;
export const node = rootSchemaScope.node;
export const defineSchema = rootSchemaScope.defineSchema;
export const genericNode = rootSchemaScope.generic;

View File

@@ -0,0 +1,62 @@
import { CastableBase, type Fn } from "@ark/util";
import type { BaseNode } from "../node.ts";
import type { NodeId } from "../parse.ts";
import type { TraversalKind } from "./traversal.ts";
export type CoercibleValue = string | number | boolean | null | undefined;
export declare class CompiledFunction<compiledSignature = (...args: unknown[]) => unknown, args extends readonly string[] = readonly string[]> extends CastableBase<{
[k in args[number]]: k;
}> {
readonly argNames: args;
readonly body = "";
constructor(...args: args);
indentation: number;
indent(): this;
dedent(): this;
prop(key: PropertyKey, optional?: boolean): string;
index(key: string | number, optional?: boolean): string;
line(statement: string): this;
const(identifier: string, expression: CoercibleValue): this;
let(identifier: string, expression: CoercibleValue): this;
set(identifier: string, expression: CoercibleValue): this;
if(condition: string, then: (self: this) => this): this;
elseIf(condition: string, then: (self: this) => this): this;
else(then: (self: this) => this): this;
/** Current index is "i" */
for(until: string, body: (self: this) => this, initialValue?: CoercibleValue): this;
/** Current key is "k" */
forIn(object: string, body: (self: this) => this): this;
block(prefix: string, contents: (self: this) => this, suffix?: string): this;
return(expression?: CoercibleValue): this;
write(name?: string, indent?: number): string;
compile(): compiledSignature;
}
export declare const compileSerializedValue: (value: unknown) => string;
export declare const compileLiteralPropAccess: (key: PropertyKey, optional?: boolean) => string;
export declare const serializeLiteralKey: (key: PropertyKey) => string;
export declare const indexPropAccess: (key: string, optional?: boolean) => string;
export interface InvokeOptions extends ReferenceOptions {
arg?: string;
}
export interface ReferenceOptions {
kind?: TraversalKind;
bind?: string;
}
export declare namespace NodeCompiler {
interface Context {
kind: TraversalKind;
optimistic?: true;
}
}
export declare class NodeCompiler extends CompiledFunction<Fn, ["data", "ctx"]> {
traversalKind: TraversalKind;
optimistic: boolean;
constructor(ctx: NodeCompiler.Context);
invoke(node: BaseNode | NodeId, opts?: InvokeOptions): string;
referenceToId(id: NodeId, opts?: ReferenceOptions): string;
requiresContextFor(node: BaseNode): boolean;
initializeErrorCount(): this;
returnIfFail(): this;
returnIfFailFast(): this;
traverseKey(keyExpression: string, accessExpression: string, node: BaseNode): this;
check(node: BaseNode, opts?: InvokeOptions): this;
}

145
frontend/node_modules/@ark/schema/out/shared/compile.js generated vendored Normal file
View File

@@ -0,0 +1,145 @@
import { CastableBase, DynamicFunction, hasDomain, isDotAccessible, serializePrimitive } from "@ark/util";
import { registeredReference } from "./registry.js";
export class CompiledFunction extends CastableBase {
argNames;
body = "";
constructor(...args) {
super();
this.argNames = args;
for (const arg of args) {
if (arg in this) {
throw new Error(`Arg name '${arg}' would overwrite an existing property on FunctionBody`);
}
;
this[arg] = arg;
}
}
indentation = 0;
indent() {
this.indentation += 4;
return this;
}
dedent() {
this.indentation -= 4;
return this;
}
prop(key, optional = false) {
return compileLiteralPropAccess(key, optional);
}
index(key, optional = false) {
return indexPropAccess(`${key}`, optional);
}
line(statement) {
;
this.body += `${" ".repeat(this.indentation)}${statement}\n`;
return this;
}
const(identifier, expression) {
this.line(`const ${identifier} = ${expression}`);
return this;
}
let(identifier, expression) {
return this.line(`let ${identifier} = ${expression}`);
}
set(identifier, expression) {
return this.line(`${identifier} = ${expression}`);
}
if(condition, then) {
return this.block(`if (${condition})`, then);
}
elseIf(condition, then) {
return this.block(`else if (${condition})`, then);
}
else(then) {
return this.block("else", then);
}
/** Current index is "i" */
for(until, body, initialValue = 0) {
return this.block(`for (let i = ${initialValue}; ${until}; i++)`, body);
}
/** Current key is "k" */
forIn(object, body) {
return this.block(`for (const k in ${object})`, body);
}
block(prefix, contents, suffix = "") {
this.line(`${prefix} {`);
this.indent();
contents(this);
this.dedent();
return this.line(`}${suffix}`);
}
return(expression = "") {
return this.line(`return ${expression}`);
}
write(name = "anonymous", indent = 0) {
return `${name}(${this.argNames.join(", ")}) { ${indent ?
this.body
.split("\n")
.map(l => " ".repeat(indent) + `${l}`)
.join("\n")
: this.body} }`;
}
compile() {
return new DynamicFunction(...this.argNames, this.body);
}
}
export const compileSerializedValue = (value) => hasDomain(value, "object") || typeof value === "symbol" ?
registeredReference(value)
: serializePrimitive(value);
export const compileLiteralPropAccess = (key, optional = false) => {
if (typeof key === "string" && isDotAccessible(key))
return `${optional ? "?" : ""}.${key}`;
return indexPropAccess(serializeLiteralKey(key), optional);
};
export const serializeLiteralKey = (key) => typeof key === "symbol" ? registeredReference(key) : JSON.stringify(key);
export const indexPropAccess = (key, optional = false) => `${optional ? "?." : ""}[${key}]`;
export class NodeCompiler extends CompiledFunction {
traversalKind;
optimistic;
constructor(ctx) {
super("data", "ctx");
this.traversalKind = ctx.kind;
this.optimistic = ctx.optimistic === true;
}
invoke(node, opts) {
const arg = opts?.arg ?? this.data;
const requiresContext = typeof node === "string" ? true : this.requiresContextFor(node);
const id = typeof node === "string" ? node : node.id;
if (requiresContext)
return `${this.referenceToId(id, opts)}(${arg}, ${this.ctx})`;
return `${this.referenceToId(id, opts)}(${arg})`;
}
referenceToId(id, opts) {
const invokedKind = opts?.kind ?? this.traversalKind;
const base = `this.${id}${invokedKind}`;
return opts?.bind ? `${base}.bind(${opts?.bind})` : base;
}
requiresContextFor(node) {
return this.traversalKind === "Apply" || node.allowsRequiresContext;
}
initializeErrorCount() {
return this.const("errorCount", "ctx.currentErrorCount");
}
returnIfFail() {
return this.if("ctx.currentErrorCount > errorCount", () => this.return());
}
returnIfFailFast() {
return this.if("ctx.failFast && ctx.currentErrorCount > errorCount", () => this.return());
}
traverseKey(keyExpression, accessExpression, node) {
const requiresContext = this.requiresContextFor(node);
if (requiresContext)
this.line(`${this.ctx}.path.push(${keyExpression})`);
this.check(node, {
arg: accessExpression
});
if (requiresContext)
this.line(`${this.ctx}.path.pop()`);
return this;
}
check(node, opts) {
return this.traversalKind === "Allows" ?
this.if(`!${this.invoke(node, opts)}`, () => this.return(false))
: this.line(this.invoke(node, opts));
}
}

View File

@@ -0,0 +1,80 @@
import type { merge, show } from "@ark/util";
import type { UnknownErrorConfigs } from "../config.ts";
import type { nodeOfKind, reducibleKindOf } from "../kinds.ts";
import type { Disjoint } from "./disjoint.ts";
import type { ArkErrors } from "./errors.ts";
import type { NarrowedAttachments, NodeKind } from "./implement.ts";
import type { JsonSchema } from "./jsonSchema.ts";
type withMetaPrefixedKeys<o> = {
[k in keyof o as k extends string ? `meta.${k}` : never]: o[k];
};
export interface DefaultArkEnv {
meta(): {};
onFail(errors: ArkErrors): ArkErrors;
}
interface NodeMeta extends JsonSchema.UniversalMeta, UnknownErrorConfigs {
alias?: string;
onFail?: ArkErrors.Handler;
}
declare global {
export interface ArkEnv extends DefaultArkEnv {
}
export namespace ArkEnv {
type meta = show<NodeMeta & ReturnType<ArkEnv["meta"]>>;
type onFail = ReturnType<ArkEnv["onFail"]>;
}
}
export type TypeMeta = Omit<ArkEnv.meta, "onFail">;
export declare namespace TypeMeta {
type Collapsible<meta extends TypeMeta = TypeMeta> = meta | string;
type Mapper<meta extends TypeMeta = TypeMeta> = (existing: Readonly<meta>) => meta;
type MappableInput<meta extends TypeMeta = TypeMeta> = Collapsible<meta> | Mapper<meta>;
namespace MappableInput {
type Internal = MappableInput<ArkEnv.meta>;
}
}
export interface BaseNormalizedSchema extends withMetaPrefixedKeys<TypeMeta> {
readonly meta?: ArkEnv.meta | string;
}
interface DeclarationInput {
kind: NodeKind;
schema: unknown;
normalizedSchema: BaseNormalizedSchema;
inner: object;
errorContext?: BaseErrorContext;
reducibleTo?: NodeKind;
intersectionIsOpen?: true;
prerequisite?: unknown;
childKind?: NodeKind;
}
export interface BaseErrorContext<kind extends NodeKind = NodeKind> {
readonly description?: string;
readonly code: kind;
readonly meta: ArkEnv.meta;
}
export type defaultErrorContext<d extends DeclarationInput> = show<BaseErrorContext<d["kind"]> & d["inner"]>;
export type declareNode<d extends {
[k in keyof d]: k extends keyof DeclarationInput ? DeclarationInput[k] : never;
} & DeclarationInput> = merge<{
intersectionIsOpen: false;
prerequisite: prerequisiteOf<d>;
childKind: never;
reducibleTo: d["kind"];
errorContext: null;
}, d>;
type prerequisiteOf<d extends DeclarationInput> = "prerequisite" extends keyof d ? d["prerequisite"] : unknown;
export type attachmentsOf<d extends BaseNodeDeclaration> = NarrowedAttachments<d> & attachedInner<d>;
type attachedInner<d extends BaseNodeDeclaration> = "intersection" & d["kind"] extends never ? d["inner"] : {};
export interface BaseNodeDeclaration {
kind: NodeKind;
schema: unknown;
normalizedSchema: BaseNormalizedSchema;
inner: {};
reducibleTo: NodeKind;
prerequisite: any;
intersectionIsOpen: boolean;
childKind: NodeKind;
errorContext: BaseErrorContext | null;
}
export type ownIntersectionResult<d extends BaseNodeDeclaration> = nodeOfKind<reducibleKindOf<d["kind"]>> | Disjoint;
export {};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,41 @@
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";
export interface DisjointEntry<kind extends DisjointKind = DisjointKind> {
kind: kind;
l: OperandsByDisjointKind[kind];
r: OperandsByDisjointKind[kind];
path: Key[];
optional: boolean;
}
type OperandsByDisjointKind = {
domain: nodeOfKind<"domain"> | Domain.Enumerable;
unit: nodeOfKind<"unit">;
proto: nodeOfKind<"proto">;
presence: BaseRoot;
range: nodeOfKind<BoundKind>;
assignability: BaseNode;
union: readonly BaseRoot[];
};
export type DisjointEntryContext = {
path?: Key[];
optional?: true;
};
export declare class Disjoint extends Array<DisjointEntry> {
static init<kind extends DisjointKind>(kind: kind, l: OperandsByDisjointKind[kind], r: OperandsByDisjointKind[kind], ctx?: DisjointEntryContext): Disjoint;
add<kind extends DisjointKind>(kind: kind, l: OperandsByDisjointKind[kind], r: OperandsByDisjointKind[kind], ctx?: DisjointEntryContext): Disjoint;
get summary(): string;
describeReasons(): string;
throw(): never;
invert(): Disjoint;
withPrefixKey(key: PropertyKey, kind: Prop.Kind): Disjoint;
toNeverIfDisjoint(): BaseRoot;
}
export type DisjointKind = keyof OperandsByDisjointKind;
export declare const writeUnsatisfiableExpressionError: <expression extends string>(expression: expression) => writeUnsatisfiableExpressionError<expression>;
export type writeUnsatisfiableExpressionError<expression extends string> = `${expression} results in an unsatisfiable type`;
export {};

View File

@@ -0,0 +1,65 @@
import { isArray, stringifyPath, throwParseError } from "@ark/util";
import { $ark } from "./registry.js";
import { isNode } from "./utils.js";
export class Disjoint extends Array {
static init(kind, l, r, ctx) {
return new Disjoint({
kind,
l,
r,
path: ctx?.path ?? [],
optional: ctx?.optional ?? false
});
}
add(kind, l, r, ctx) {
this.push({
kind,
l,
r,
path: ctx?.path ?? [],
optional: ctx?.optional ?? false
});
return this;
}
get summary() {
return this.describeReasons();
}
describeReasons() {
if (this.length === 1) {
const { path, l, r } = this[0];
const pathString = stringifyPath(path);
return writeUnsatisfiableExpressionError(`Intersection${pathString && ` at ${pathString}`} of ${describeReasons(l, r)}`);
}
return `The following intersections result in unsatisfiable types:\n${this.map(({ path, l, r }) => `${path}: ${describeReasons(l, r)}`).join("\n• ")}`;
}
throw() {
return throwParseError(this.describeReasons());
}
invert() {
const result = this.map(entry => ({
...entry,
l: entry.r,
r: entry.l
}));
// Workaround for Static Hermes, which doesn't preserve the Array subclass here
// https://github.com/arktypeio/arktype/issues/1027
if (!(result instanceof Disjoint))
return new Disjoint(...result);
return result;
}
withPrefixKey(key, kind) {
return this.map(entry => ({
...entry,
path: [key, ...entry.path],
optional: entry.optional || kind === "optional"
}));
}
toNeverIfDisjoint() {
return $ark.intrinsic.never;
}
}
const describeReasons = (l, r) => `${describeReason(l)} and ${describeReason(r)}`;
const describeReason = (value) => isNode(value) ? value.expression
: isArray(value) ? value.map(describeReason).join(" | ") || "never"
: String(value);
export const writeUnsatisfiableExpressionError = (expression) => `${expression} results in an unsatisfiable type`;

View File

@@ -0,0 +1,145 @@
import { CastableBase, ReadonlyArray, ReadonlyPath, type JsonArray, type JsonObject, type array, type merge, type propwiseXor, type show } from "@ark/util";
import type { Prerequisite, errorContext } from "../kinds.ts";
import type { NodeKind } from "./implement.ts";
import type { StandardSchemaV1 } from "./standardSchema.ts";
import type { Traversal } from "./traversal.ts";
import { arkKind } from "./utils.ts";
export type ArkErrorResult = ArkError | ArkErrors;
export declare class ArkError<code extends ArkErrorCode = ArkErrorCode> extends CastableBase<ArkErrorContextInput<code>> {
readonly [arkKind] = "error";
path: ReadonlyPath;
data: Prerequisite<code>;
private nodeConfig;
protected input: ArkErrorContextInput<code>;
protected ctx: Traversal;
constructor(input: ArkErrorContextInput<code>, ctx: Traversal);
transform(f: (input: ArkErrorContextInput<code>) => ArkErrorContextInput): ArkError;
hasCode<code extends ArkErrorCode>(code: code): this is ArkError<code>;
get propString(): string;
get expected(): string;
get actual(): string;
get problem(): string;
get message(): string;
get flat(): ArkError[];
toJSON(): JsonObject;
toString(): string;
throw(): never;
}
export declare namespace ArkErrors {
type Handler<returns = unknown> = (errors: ArkErrors) => returns;
}
/**
* A ReadonlyArray of `ArkError`s returned by a Type on invalid input.
*
* Subsequent errors added at an existing path are merged into an
* ArkError intersection.
*/
export declare class ArkErrors extends ReadonlyArray<ArkError> implements StandardSchemaV1.FailureResult {
readonly [arkKind] = "errors";
protected ctx: Traversal;
constructor(ctx: Traversal);
/**
* Errors by a pathString representing their location.
*/
byPath: Record<string, ArkError>;
/**
* {@link byPath} flattened so that each value is an array of ArkError instances at that path.
*
* ✅ Since "intersection" errors will be flattened to their constituent `.errors`,
* they will never be directly present in this representation.
*/
get flatByPath(): Record<string, ArkError[]>;
/**
* {@link byPath} flattened so that each value is an array of problem strings at that path.
*/
get flatProblemsByPath(): Record<string, string[]>;
/**
* All pathStrings at which errors are present mapped to the errors occuring
* at that path or any nested path within it.
*/
byAncestorPath: Record<string, ArkError[]>;
count: number;
private mutable;
/**
* Throw a TraversalError based on these errors.
*/
throw(): never;
/**
* Converts ArkErrors to TraversalError, a subclass of `Error` suitable for throwing with nice
* formatting.
*/
toTraversalError(): TraversalError;
/**
* Append an ArkError to this array, ignoring duplicates.
*/
add(error: ArkError): void;
transform(f: (e: ArkError) => ArkError): ArkErrors;
/**
* Add all errors from an ArkErrors instance, ignoring duplicates and
* prefixing their paths with that of the current Traversal.
*/
merge(errors: ArkErrors): void;
/**
* @internal
*/
affectsPath(path: ReadonlyPath): boolean;
/**
* A human-readable summary of all errors.
*/
get summary(): string;
/**
* Alias of this ArkErrors instance for StandardSchema compatibility.
*/
get issues(): this;
toJSON(): JsonArray;
toString(): string;
private addAncestorPaths;
}
export declare class TraversalError extends Error {
readonly name = "TraversalError";
arkErrors: ArkErrors;
constructor(errors: ArkErrors);
}
export interface DerivableErrorContext<code extends ArkErrorCode = ArkErrorCode> {
expected: string;
actual: string;
problem: string;
message: string;
data: Prerequisite<code>;
path: array<PropertyKey>;
propString: string;
}
export type DerivableErrorContextInput<code extends ArkErrorCode = ArkErrorCode> = Partial<DerivableErrorContext<code>> & propwiseXor<{
path?: array<PropertyKey>;
}, {
relativePath?: array<PropertyKey>;
prefixPath?: array<PropertyKey>;
}>;
export type ArkErrorCode = {
[kind in NodeKind]: errorContext<kind> extends null ? never : kind;
}[NodeKind];
type ArkErrorContextInputsByCode = {
[code in ArkErrorCode]: errorContext<code> & DerivableErrorContextInput<code>;
};
export type ArkErrorContextInput<code extends ArkErrorCode = ArkErrorCode> = merge<ArkErrorContextInputsByCode[code], {
meta?: ArkEnv.meta;
}>;
export type NodeErrorContextInput<code extends ArkErrorCode = ArkErrorCode> = ArkErrorContextInputsByCode[code] & {
meta: ArkEnv.meta;
};
export type MessageContext<code extends ArkErrorCode = ArkErrorCode> = Omit<ArkError<code>, "message">;
export type ProblemContext<code extends ArkErrorCode = ArkErrorCode> = Omit<MessageContext<code>, "problem">;
export type CustomErrorInput = show<{
code?: undefined;
} & DerivableErrorContextInput>;
export type ArkErrorInput = string | ArkErrorContextInput | CustomErrorInput;
export type ProblemConfig<code extends ArkErrorCode = ArkErrorCode> = string | ProblemWriter<code>;
export type ProblemWriter<code extends ArkErrorCode = ArkErrorCode> = (context: ProblemContext<code>) => string;
export type MessageConfig<code extends ArkErrorCode = ArkErrorCode> = string | MessageWriter<code>;
export type MessageWriter<code extends ArkErrorCode = ArkErrorCode> = (context: MessageContext<code>) => string;
export type getAssociatedDataForError<code extends ArkErrorCode> = code extends NodeKind ? Prerequisite<code> : unknown;
export type ExpectedConfig<code extends ArkErrorCode = ArkErrorCode> = string | ExpectedWriter<code>;
export type ExpectedWriter<code extends ArkErrorCode = ArkErrorCode> = (source: errorContext<code>) => string;
export type ActualConfig<code extends ArkErrorCode = ArkErrorCode> = string | ActualWriter<code>;
export type ActualWriter<code extends ArkErrorCode = ArkErrorCode> = (data: getAssociatedDataForError<code>) => string;
export {};

252
frontend/node_modules/@ark/schema/out/shared/errors.js generated vendored Normal file
View File

@@ -0,0 +1,252 @@
import { CastableBase, ReadonlyArray, ReadonlyPath, append, conflatenateAll, defineProperties, flatMorph, stringifyPath } from "@ark/util";
import { arkKind } from "./utils.js";
export class ArkError extends CastableBase {
[arkKind] = "error";
path;
data;
nodeConfig;
input;
ctx;
// TS gets confused by <code>, so internally we just use the base type for input
constructor({ prefixPath, relativePath, ...input }, ctx) {
super();
this.input = input;
this.ctx = ctx;
defineProperties(this, input);
const data = ctx.data;
if (input.code === "union") {
input.errors = input.errors.flatMap(innerError => {
// flatten union errors to avoid repeating context like "foo must be foo must be"...
const flat = innerError.hasCode("union") ? innerError.errors : [innerError];
if (!prefixPath && !relativePath)
return flat;
return flat.map(e => e.transform(e => ({
...e,
path: conflatenateAll(prefixPath, e.path, relativePath)
})));
});
}
this.nodeConfig = ctx.config[this.code];
const basePath = [...(input.path ?? ctx.path)];
if (relativePath)
basePath.push(...relativePath);
if (prefixPath)
basePath.unshift(...prefixPath);
this.path = new ReadonlyPath(...basePath);
this.data = "data" in input ? input.data : data;
}
transform(f) {
return new ArkError(f({
data: this.data,
path: this.path,
...this.input
}), this.ctx);
}
hasCode(code) {
return this.code === code;
}
get propString() {
return stringifyPath(this.path);
}
get expected() {
if (this.input.expected)
return this.input.expected;
const config = this.meta?.expected ?? this.nodeConfig.expected;
return typeof config === "function" ? config(this.input) : config;
}
get actual() {
if (this.input.actual)
return this.input.actual;
const config = this.meta?.actual ?? this.nodeConfig.actual;
return typeof config === "function" ? config(this.data) : config;
}
get problem() {
if (this.input.problem)
return this.input.problem;
const config = this.meta?.problem ?? this.nodeConfig.problem;
return typeof config === "function" ? config(this) : config;
}
get message() {
if (this.input.message)
return this.input.message;
const config = this.meta?.message ?? this.nodeConfig.message;
return typeof config === "function" ? config(this) : config;
}
get flat() {
return this.hasCode("intersection") ? [...this.errors] : [this];
}
toJSON() {
return {
data: this.data,
path: this.path,
...this.input,
expected: this.expected,
actual: this.actual,
problem: this.problem,
message: this.message
};
}
toString() {
return this.message;
}
throw() {
throw this;
}
}
/**
* A ReadonlyArray of `ArkError`s returned by a Type on invalid input.
*
* Subsequent errors added at an existing path are merged into an
* ArkError intersection.
*/
export class ArkErrors extends ReadonlyArray {
[arkKind] = "errors";
ctx;
constructor(ctx) {
super();
this.ctx = ctx;
}
/**
* Errors by a pathString representing their location.
*/
byPath = Object.create(null);
/**
* {@link byPath} flattened so that each value is an array of ArkError instances at that path.
*
* ✅ Since "intersection" errors will be flattened to their constituent `.errors`,
* they will never be directly present in this representation.
*/
get flatByPath() {
return flatMorph(this.byPath, (k, v) => [k, v.flat]);
}
/**
* {@link byPath} flattened so that each value is an array of problem strings at that path.
*/
get flatProblemsByPath() {
return flatMorph(this.byPath, (k, v) => [k, v.flat.map(e => e.problem)]);
}
/**
* All pathStrings at which errors are present mapped to the errors occuring
* at that path or any nested path within it.
*/
byAncestorPath = Object.create(null);
count = 0;
mutable = this;
/**
* Throw a TraversalError based on these errors.
*/
throw() {
throw this.toTraversalError();
}
/**
* Converts ArkErrors to TraversalError, a subclass of `Error` suitable for throwing with nice
* formatting.
*/
toTraversalError() {
return new TraversalError(this);
}
/**
* Append an ArkError to this array, ignoring duplicates.
*/
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++;
}
transform(f) {
const result = new ArkErrors(this.ctx);
for (const e of this)
result.add(f(e));
return result;
}
/**
* Add all errors from an ArkErrors instance, ignoring duplicates and
* prefixing their paths with that of the current Traversal.
*/
merge(errors) {
for (const e of errors) {
this.add(new ArkError({ ...e, path: [...this.ctx.path, ...e.path] }, this.ctx));
}
}
/**
* @internal
*/
affectsPath(path) {
if (this.length === 0)
return false;
return (
// this would occur if there is an existing error at a prefix of path
// e.g. the path is ["foo", "bar"] and there is an error at ["foo"]
path.stringifyAncestors().some(s => s in this.byPath) ||
// this would occur if there is an existing error at a suffix of path
// e.g. the path is ["foo"] and there is an error at ["foo", "bar"]
path.stringify() in this.byAncestorPath);
}
/**
* A human-readable summary of all errors.
*/
get summary() {
return this.toString();
}
/**
* Alias of this ArkErrors instance for StandardSchema compatibility.
*/
get issues() {
return this;
}
toJSON() {
return [...this.map(e => e.toJSON())];
}
toString() {
return this.join("\n");
}
addAncestorPaths(error) {
for (const propString of error.path.stringifyAncestors()) {
this.byAncestorPath[propString] = append(this.byAncestorPath[propString], error);
}
}
}
export class TraversalError extends Error {
name = "TraversalError";
constructor(errors) {
if (errors.length === 1)
super(errors.summary);
else
super("\n" + errors.map(error => `${indent(error)}`).join("\n"));
Object.defineProperty(this, "arkErrors", {
value: errors,
enumerable: false
});
}
}
const indent = (error) => error.toString().split("\n").join("\n ");

View File

@@ -0,0 +1,151 @@
import { type Entry, type Json, type JsonStructure, type KeySet, type arrayIndexOf, type keySetOf, type listable, type requireKeys, type show } from "@ark/util";
import type { NodeConfig, ResolvedUnknownNodeConfig } from "../config.ts";
import type { Declaration, Inner, errorContext, nodeOfKind } from "../kinds.ts";
import type { BaseNode } from "../node.ts";
import type { NodeId, NodeParseContext } from "../parse.ts";
import type { BaseRoot, schemaKindOrRightOf, schemaKindRightOf } from "../roots/root.ts";
import type { BaseScope, ResolvedScopeConfig } from "../scope.ts";
import type { Structure } from "../structure/structure.ts";
import type { BaseErrorContext, BaseNodeDeclaration, BaseNormalizedSchema } from "./declare.ts";
import type { Disjoint } from "./disjoint.ts";
import { type makeRootAndArrayPropertiesMutable } from "./utils.ts";
export declare const basisKinds: readonly ["unit", "proto", "domain"];
export type BasisKind = (typeof basisKinds)[number];
export declare const structuralKinds: readonly ["required", "optional", "index", "sequence"];
export type StructuralKind = (typeof structuralKinds)[number];
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];
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];
export declare const rootKinds: readonly ["alias", "union", "morph", "unit", "intersection", "proto", "domain"];
export type RootKind = (typeof rootKinds)[number];
export type NodeKind = RootKind | ConstraintKind;
type orderedNodeKinds = [...typeof rootKinds, ...typeof constraintKinds];
export declare const nodeKinds: orderedNodeKinds;
export type OpenNodeKind = {
[k in NodeKind]: Declaration<k>["intersectionIsOpen"] extends true ? k : never;
}[NodeKind];
export type ClosedNodeKind = Exclude<NodeKind, OpenNodeKind>;
export type PrimitiveKind = Exclude<RefinementKind | BasisKind, "structure">;
export type CompositeKind = Exclude<NodeKind, PrimitiveKind>;
export type OrderedNodeKinds = typeof nodeKinds;
export declare const constraintKeys: KeySet<ConstraintKind>;
export declare const structureKeys: keySetOf<Structure.Inner>;
type RightsByKind = accumulateRightKinds<OrderedNodeKinds, {}>;
export type kindOrRightOf<kind extends NodeKind> = kind | kindRightOf<kind>;
export type kindLeftOf<kind extends NodeKind> = Exclude<NodeKind, kindOrRightOf<kind>>;
export type kindOrLeftOf<kind extends NodeKind> = kind | kindLeftOf<kind>;
type accumulateRightKinds<remaining extends readonly NodeKind[], result> = remaining extends (readonly [infer head extends NodeKind, ...infer tail extends NodeKind[]]) ? accumulateRightKinds<tail, result & {
[k in head]: tail[number];
}> : result;
export interface InternalIntersectionOptions {
pipe: boolean;
}
export interface IntersectionContext extends InternalIntersectionOptions {
$: BaseScope;
invert: boolean;
}
export type ConstraintIntersection<lKind extends ConstraintKind, rKind extends kindOrRightOf<lKind>> = (l: nodeOfKind<lKind>, r: nodeOfKind<rKind>, ctx: IntersectionContext) => BaseNode | Disjoint | null;
export type ConstraintIntersectionMap<kind extends ConstraintKind> = show<{
[_ in kind]: ConstraintIntersection<kind, kind>;
} & {
[rKind in kindRightOf<kind>]?: ConstraintIntersection<kind, rKind>;
}>;
export type RootIntersection<lKind extends RootKind, rKind extends schemaKindOrRightOf<lKind>> = (l: nodeOfKind<lKind>, r: nodeOfKind<rKind>, ctx: IntersectionContext) => BaseRoot | Disjoint;
export type TypeIntersectionMap<kind extends RootKind> = {
[rKind in schemaKindOrRightOf<kind>]: RootIntersection<kind, rKind>;
};
export type IntersectionMap<kind extends NodeKind> = kind extends RootKind ? TypeIntersectionMap<kind> : ConstraintIntersectionMap<kind & ConstraintKind>;
export type UnknownIntersectionMap = {
[k in NodeKind]?: (l: BaseNode, r: BaseNode, ctx: IntersectionContext) => UnknownIntersectionResult;
};
export type UnknownIntersectionResult = BaseNode | Disjoint | null;
type PrecedenceByKind = {
[i in arrayIndexOf<OrderedNodeKinds> as OrderedNodeKinds[i]]: i;
};
export declare const precedenceByKind: PrecedenceByKind;
export declare const isNodeKind: (value: unknown) => value is NodeKind;
export declare function assertNodeKind<kind extends NodeKind>(value: BaseNode, kind: kind): asserts value is nodeOfKind<kind>;
export type precedenceOfKind<kind extends NodeKind> = PrecedenceByKind[kind];
export declare const precedenceOfKind: <kind extends NodeKind>(kind: kind) => precedenceOfKind<kind>;
export type kindRightOf<kind extends NodeKind> = RightsByKind[kind];
export declare const schemaKindsRightOf: <kind extends RootKind>(kind: kind) => schemaKindRightOf<kind>[];
export declare const unionChildKinds: readonly [...("intersection" | "morph" | "unit" | "proto" | "domain")[], "alias"];
export type UnionChildKind = (typeof unionChildKinds)[number];
export declare const morphChildKinds: readonly [...("intersection" | "unit" | "proto" | "domain")[], "alias"];
export type MorphChildKind = (typeof morphChildKinds)[number];
export type keySchemaDefinitions<d extends BaseNodeDeclaration> = {
[k in keyRequiringSchemaDefinition<d>]: NodeKeyImplementation<d, k>;
};
type keyRequiringSchemaDefinition<d extends BaseNodeDeclaration> = Exclude<keyof d["normalizedSchema"], keyof BaseNormalizedSchema>;
export declare const defaultValueSerializer: (v: unknown) => Json;
export type NodeKeyImplementation<d extends BaseNodeDeclaration, k extends keyof d["normalizedSchema"], instantiated = k extends keyof d["inner"] ? Exclude<d["inner"][k], undefined> : never> = requireKeys<{
preserveUndefined?: true;
child?: boolean | ((value: instantiated) => BaseNode[]);
serialize?: (schema: instantiated) => Json;
reduceIo?: (ioKind: "in" | "out", inner: makeRootAndArrayPropertiesMutable<d["inner"]>, value: d["inner"][k]) => void;
parse?: (schema: Exclude<d["normalizedSchema"][k], undefined>, ctx: NodeParseContext<d["kind"]>) => instantiated | undefined;
}, (d["normalizedSchema"][k] extends instantiated | undefined ? never : "parse") | ([instantiated] extends [listable<BaseNode>] ? "child" : never)>;
interface CommonNodeImplementationInput<d extends BaseNodeDeclaration> {
kind: d["kind"];
keys: keySchemaDefinitions<d>;
normalize: (schema: d["schema"], $: BaseScope) => d["normalizedSchema"];
applyConfig?: (schema: d["normalizedSchema"], config: ResolvedScopeConfig) => d["normalizedSchema"];
hasAssociatedError: d["errorContext"] extends null ? false : true;
finalizeInnerJson?: (json: {
[k in keyof d["inner"]]: Json;
}) => JsonStructure;
collapsibleKey?: keyof d["inner"];
reduce?: (inner: d["inner"], $: BaseScope) => nodeOfKind<d["reducibleTo"]> | Disjoint | undefined;
obviatesBasisDescription?: d["kind"] extends RefinementKind ? true : never;
obviatesBasisExpression?: d["kind"] extends RefinementKind ? true : never;
}
export interface UnknownNodeImplementation extends CommonNodeImplementationInput<BaseNodeDeclaration> {
defaults: ResolvedUnknownNodeConfig;
intersectionIsOpen: boolean;
intersections: UnknownIntersectionMap;
keys: Record<string, NodeKeyImplementation<any, any>>;
}
export declare const compileObjectLiteral: (ctx: object) => string;
export type nodeImplementationOf<d extends BaseNodeDeclaration> = nodeImplementationInputOf<d> & {
intersections: IntersectionMap<d["kind"]>;
intersectionIsOpen: d["intersectionIsOpen"];
defaults: Required<NodeConfig<d["kind"]>>;
};
export type nodeImplementationInputOf<d extends BaseNodeDeclaration> = CommonNodeImplementationInput<d> & {
intersections: IntersectionMap<d["kind"]>;
defaults: nodeSchemaaultsImplementationInputFor<d["kind"]>;
} & (d["intersectionIsOpen"] extends true ? {
intersectionIsOpen: true;
} : {}) & (d["reducibleTo"] extends d["kind"] ? {} : {
reduce: {};
});
type nodeSchemaaultsImplementationInputFor<kind extends NodeKind> = requireKeys<NodeConfig<kind>, "description" | (Inner<kind> extends (Omit<errorContext<kind>, keyof BaseErrorContext | "description">) ? never : "expected" & keyof NodeConfig<kind>)>;
export type DescriptionWriter<kind extends NodeKind = NodeKind> = (node: nodeOfKind<kind>) => string;
export interface UnknownAttachments {
readonly kind: NodeKind;
readonly impl: UnknownNodeImplementation;
readonly id: NodeId;
readonly inner: Record<string, any>;
readonly innerEntries: readonly Entry<string>[];
readonly innerJson: object;
readonly innerHash: string;
readonly meta: ArkEnv.meta;
readonly metaJson: object;
readonly json: object;
readonly hash: string;
readonly collapsibleJson: Json;
readonly children: BaseNode[];
}
export interface NarrowedAttachments<d extends BaseNodeDeclaration> extends UnknownAttachments {
kind: d["kind"];
inner: d["inner"];
json: JsonStructure;
innerJson: JsonStructure;
collapsibleJson: Json;
children: nodeOfKind<d["childKind"]>[];
}
export declare const implementNode: <d extends BaseNodeDeclaration = never>(_: nodeImplementationInputOf<d>) => nodeImplementationOf<d>;
export {};

View File

@@ -0,0 +1,98 @@
import { flatMorph, printable, throwParseError } from "@ark/util";
import { compileSerializedValue } from "./compile.js";
import { isNode } from "./utils.js";
export const basisKinds = ["unit", "proto", "domain"];
export const structuralKinds = [
"required",
"optional",
"index",
"sequence"
];
export const prestructuralKinds = [
"pattern",
"divisor",
"exactLength",
"max",
"min",
"maxLength",
"minLength",
"before",
"after"
];
export const refinementKinds = [
...prestructuralKinds,
"structure",
"predicate"
];
export const constraintKinds = [...refinementKinds, ...structuralKinds];
export const rootKinds = [
"alias",
"union",
"morph",
"unit",
"intersection",
"proto",
"domain"
];
export const nodeKinds = [...rootKinds, ...constraintKinds];
export const constraintKeys = flatMorph(constraintKinds, (i, kind) => [kind, 1]);
export const structureKeys = flatMorph([...structuralKinds, "undeclared"], (i, k) => [k, 1]);
export const precedenceByKind = flatMorph(nodeKinds, (i, kind) => [kind, i]);
export const isNodeKind = (value) => typeof value === "string" && value in precedenceByKind;
export function assertNodeKind(value, kind) {
const valueIsNode = isNode(value);
if (!valueIsNode || value.kind !== kind) {
throwParseError(`Expected node of kind ${kind} (was ${valueIsNode ? `${value.kind} node` : printable(value)})`);
}
}
export const precedenceOfKind = (kind) => precedenceByKind[kind];
export const schemaKindsRightOf = (kind) => rootKinds.slice(precedenceOfKind(kind) + 1);
export const unionChildKinds = [
...schemaKindsRightOf("union"),
"alias"
];
export const morphChildKinds = [
...schemaKindsRightOf("morph"),
"alias"
];
export const defaultValueSerializer = (v) => {
if (typeof v === "string" || typeof v === "boolean" || v === null)
return v;
if (typeof v === "number") {
if (Number.isNaN(v))
return "NaN";
if (v === Number.POSITIVE_INFINITY)
return "Infinity";
if (v === Number.NEGATIVE_INFINITY)
return "-Infinity";
return v;
}
return compileSerializedValue(v);
};
export const compileObjectLiteral = (ctx) => {
let result = "{ ";
for (const [k, v] of Object.entries(ctx))
result += `${k}: ${compileSerializedValue(v)}, `;
return result + " }";
};
export const implementNode = (_) => {
const implementation = _;
if (implementation.hasAssociatedError) {
implementation.defaults.expected ??= ctx => "description" in ctx ?
ctx.description
: implementation.defaults.description(ctx);
implementation.defaults.actual ??= data => printable(data);
implementation.defaults.problem ??= ctx => `must be ${ctx.expected}${ctx.actual ? ` (was ${ctx.actual})` : ""}`;
implementation.defaults.message ??= ctx => {
if (ctx.path.length === 0)
return ctx.problem;
const problemWithLocation = `${ctx.propString} ${ctx.problem}`;
if (problemWithLocation[0] === "[") {
// clarify paths like [1], [0][1], and ["key!"] that could be confusing
return `value at ${problemWithLocation}`;
}
return problemWithLocation;
};
}
return implementation;
};

View File

@@ -0,0 +1,10 @@
import type { BaseNode } from "../node.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { BaseScope } from "../scope.ts";
import { Disjoint } from "./disjoint.ts";
import { type IntersectionContext, type RootKind } from "./implement.ts";
type InternalNodeIntersection<ctx> = <l extends BaseNode, r extends BaseNode>(l: l, r: r, ctx: ctx) => l["kind"] | r["kind"] extends RootKind ? BaseRoot | Disjoint : BaseNode | Disjoint | null;
export declare const intersectNodesRoot: InternalNodeIntersection<BaseScope>;
export declare const pipeNodesRoot: InternalNodeIntersection<BaseScope>;
export declare const intersectOrPipeNodes: InternalNodeIntersection<IntersectionContext>;
export {};

View File

@@ -0,0 +1,132 @@
import { Disjoint } from "./disjoint.js";
import { rootKinds } from "./implement.js";
import { isNode } from "./utils.js";
const intersectionCache = {};
export const intersectNodesRoot = (l, r, $) => intersectOrPipeNodes(l, r, {
$,
invert: false,
pipe: false
});
export const pipeNodesRoot = (l, r, $) => intersectOrPipeNodes(l, r, {
$,
invert: false,
pipe: true
});
export const intersectOrPipeNodes = ((l, r, ctx) => {
const operator = ctx.pipe ? "|>" : "&";
const lrCacheKey = `${l.hash}${operator}${r.hash}`;
if (intersectionCache[lrCacheKey] !== undefined)
return intersectionCache[lrCacheKey];
if (!ctx.pipe) {
// we can only use this for the commutative & operator
const rlCacheKey = `${r.hash}${operator}${l.hash}`;
if (intersectionCache[rlCacheKey] !== undefined) {
// if the cached result was a Disjoint and the operands originally
// appeared in the opposite order, we need to invert it to match
const rlResult = intersectionCache[rlCacheKey];
const lrResult = rlResult instanceof Disjoint ? rlResult.invert() : rlResult;
// add the lr result to the cache directly to bypass this check in the future
intersectionCache[lrCacheKey] = lrResult;
return lrResult;
}
}
const isPureIntersection = !ctx.pipe || (!l.includesTransform && !r.includesTransform);
if (isPureIntersection && l.equals(r))
return l;
let result = isPureIntersection ? _intersectNodes(l, r, ctx)
: l.hasKindIn(...rootKinds) ?
// if l is a RootNode, r will be as well
_pipeNodes(l, r, ctx)
: _intersectNodes(l, r, ctx);
if (isNode(result)) {
// if the result equals one of the operands, preserve its metadata by
// returning the original reference
if (l.equals(result))
result = l;
else if (r.equals(result))
result = r;
}
intersectionCache[lrCacheKey] = result;
return result;
});
const _intersectNodes = (l, r, ctx) => {
const leftmostKind = l.precedence < r.precedence ? l.kind : r.kind;
const implementation = l.impl.intersections[r.kind] ?? r.impl.intersections[l.kind];
if (implementation === undefined) {
// should be two ConstraintNodes that have no relation
// this could also happen if a user directly intersects a Type and a ConstraintNode,
// but that is not allowed by the external function signature
return null;
}
else if (leftmostKind === l.kind)
return implementation(l, r, ctx);
else {
let result = implementation(r, l, { ...ctx, invert: !ctx.invert });
if (result instanceof Disjoint)
result = result.invert();
return result;
}
};
const _pipeNodes = (l, r, ctx) => l.includesTransform || r.includesTransform ?
ctx.invert ?
pipeMorphed(r, l, ctx)
: pipeMorphed(l, r, ctx)
: _intersectNodes(l, r, ctx);
const pipeMorphed = (from, to, ctx) => from.distribute(fromBranch => _pipeMorphed(fromBranch, to, ctx), results => {
const viableBranches = results.filter(isNode);
if (viableBranches.length === 0)
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.rawIn.equals(viableBranches[i].rawIn)))
return ctx.$.parseSchema(viableBranches);
// otherwise, the input has not changed so preserve metadata
let meta;
if (viableBranches.length === 1) {
const onlyBranch = viableBranches[0];
if (!meta)
return onlyBranch;
return ctx.$.node("morph", {
...onlyBranch.inner,
in: onlyBranch.rawIn.configure(meta, "self")
});
}
const schema = {
branches: viableBranches
};
if (meta)
schema.meta = meta;
return ctx.$.parseSchema(schema);
});
const _pipeMorphed = (from, to, ctx) => {
const fromIsMorph = from.hasKind("morph");
if (fromIsMorph) {
const morphs = [...from.morphs];
if (from.lastMorphIfNode) {
// still piped from context, so allows appending additional morphs
const outIntersection = intersectOrPipeNodes(from.lastMorphIfNode, to, ctx);
if (outIntersection instanceof Disjoint)
return outIntersection;
morphs[morphs.length - 1] = outIntersection;
}
else
morphs.push(to);
return ctx.$.node("morph", {
morphs,
in: from.inner.in
});
}
if (to.hasKind("morph")) {
const inTersection = intersectOrPipeNodes(from, to.rawIn, ctx);
if (inTersection instanceof Disjoint)
return inTersection;
return ctx.$.node("morph", {
morphs: [to],
in: inTersection
});
}
return ctx.$.node("morph", {
morphs: [to],
in: from
});
};

View File

@@ -0,0 +1,93 @@
import type { array, autocomplete, JsonArray, JsonObject, listable } from "@ark/util";
export type JsonSchema = JsonSchema.NonBooleanBranch;
export type ListableJsonSchema = listable<JsonSchema>;
export type JsonSchemaOrBoolean = listable<JsonSchema.Branch>;
export declare namespace JsonSchema {
type TypeName = "string" | "integer" | "number" | "object" | "array" | "boolean" | "null";
/**
* a subset of JSON Schema's annotations, see:
* https://json-schema.org/understanding-json-schema/reference/annotations
**/
interface Meta<t = unknown> extends UniversalMeta<t> {
$schema?: string;
$defs?: Record<string, JsonSchema>;
}
type Format = autocomplete<"date-time" | "date" | "time" | "email" | "ipv4" | "ipv6" | "uri" | "uuid" | "regex">;
/**
* doesn't include root-only keys like $schema
*/
interface UniversalMeta<t = unknown> {
title?: string;
description?: string;
format?: Format;
deprecated?: true;
default?: t;
examples?: readonly t[];
}
type Composition = Union | OneOf | Intersection | Not;
type NonBooleanBranch = Constrainable | Const | Composition | Enum | String | Numeric | Object | Array | Ref;
type Branch = boolean | JsonSchema;
type RefString = `#/$defs/${string}`;
interface Ref extends Meta {
$ref: RefString;
type?: never;
}
interface Constrainable extends Meta {
type?: listable<TypeName>;
}
interface Intersection extends Meta {
allOf: readonly JsonSchema[];
}
interface Not extends Meta {
not: JsonSchema;
}
interface OneOf extends Meta {
oneOf: readonly JsonSchema[];
}
interface Union extends Meta {
anyOf: readonly JsonSchema[];
}
interface Const extends Meta {
const: unknown;
}
interface Enum extends Meta {
enum: array;
}
interface String extends Meta<string> {
type: "string";
minLength?: number;
maxLength?: number;
pattern?: string;
format?: string;
}
interface Numeric extends Meta<number> {
type: "number" | "integer";
multipleOf?: number;
minimum?: number;
exclusiveMinimum?: number;
maximum?: number;
exclusiveMaximum?: number;
}
interface Object extends Meta<JsonObject> {
type: "object";
properties?: Record<string, JsonSchema>;
required?: string[];
patternProperties?: Record<string, JsonSchema>;
additionalProperties?: JsonSchemaOrBoolean;
maxProperties?: number;
minProperties?: number;
propertyNames?: String;
}
interface Array extends Meta<JsonArray> {
type: "array";
additionalItems?: JsonSchemaOrBoolean;
contains?: JsonSchemaOrBoolean;
uniqueItems?: boolean;
minItems?: number;
maxItems?: number;
items?: JsonSchemaOrBoolean;
prefixItems?: readonly Branch[];
}
type LengthBoundable = String | Array;
type Structure = Object | Array;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,7 @@
import { type NonNegativeIntegerLiteral } from "@ark/util";
import type { ArkSchemaRegistry } from "../config.ts";
export declare const registryName: string;
export declare const $ark: ArkSchemaRegistry;
export declare const reference: (name: string) => RegisteredReference;
export declare const registeredReference: (value: object | symbol) => RegisteredReference;
export type RegisteredReference<to extends string = string> = `$ark${"" | NonNegativeIntegerLiteral}.${to}`;

View File

@@ -0,0 +1,10 @@
import { register, registry } from "@ark/util";
let _registryName = "$ark";
let suffix = 2;
while (_registryName in globalThis)
_registryName = `$ark${suffix++}`;
export const registryName = _registryName;
globalThis[registryName] = registry;
export const $ark = registry;
export const reference = (name) => `${registryName}.${name}`;
export const registeredReference = (value) => reference(register(value));

View File

@@ -0,0 +1,122 @@
/** From https://github.com/standard-schema/standard-schema */
/** The Standard Typed interface. This is a base type extended by other specs. */
export interface StandardTypedV1<Input = unknown, Output = Input> {
/** The Standard properties. */
readonly "~standard": StandardTypedV1.Props<Input, Output>;
}
export declare namespace StandardTypedV1 {
/** The Standard Typed properties interface. */
interface Props<Input = unknown, Output = Input> {
/** The version number of the standard. */
readonly version: 1;
/** The vendor name of the schema library. */
readonly vendor: string;
/** Inferred types associated with the schema. */
readonly types?: Types<Input, Output> | undefined;
}
/** The Standard Typed types interface. */
interface Types<Input = unknown, Output = Input> {
/** The input type of the schema. */
readonly input: Input;
/** The output type of the schema. */
readonly output: Output;
}
/** Infers the input type of a Standard Typed. */
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
/** Infers the output type of a Standard Typed. */
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
}
/** The Standard Schema interface. */
export interface StandardSchemaV1<Input = unknown, Output = Input> {
/** The Standard Schema properties. */
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
}
export declare namespace StandardSchemaV1 {
/** The Standard Schema properties interface. */
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
/** Validates unknown input values. */
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
}
/** The result interface of the validate function. */
type Result<Output> = SuccessResult<Output> | FailureResult;
/** The result interface if validation succeeds. */
interface SuccessResult<Output> {
/** The typed output value. */
readonly value: Output;
/** A falsy value for `issues` indicates success. */
readonly issues?: undefined;
}
interface Options {
/** Explicit support for additional vendor-specific parameters, if needed. */
readonly libraryOptions?: Record<string, unknown> | undefined;
}
/** The result interface if validation fails. */
interface FailureResult {
/** The issues of failed validation. */
readonly issues: ReadonlyArray<Issue>;
}
/** The issue interface of the failure output. */
interface Issue {
/** The error message of the issue. */
readonly message: string;
/** The path of the issue, if any. */
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
}
/** The path segment interface of the issue. */
interface PathSegment {
/** The key representing a path segment. */
readonly key: PropertyKey;
}
/** The Standard types interface. */
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {
}
/** Infers the input type of a Standard. */
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
/** Infers the output type of a Standard. */
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
/** ArkType-specific properties that extend the standard schema with JSON Schema support. */
interface ArkTypeProps<Input = unknown, Output = Input> extends Props<Input, Output>, StandardJSONSchemaV1.Props<Input, Output> {
vendor: "arktype";
}
}
/** The Standard JSON Schema interface. */
export interface StandardJSONSchemaV1<Input = unknown, Output = Input> {
/** The Standard JSON Schema properties. */
readonly "~standard": StandardJSONSchemaV1.Props<Input, Output>;
}
export declare namespace StandardJSONSchemaV1 {
/** The Standard JSON Schema properties interface. */
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
/** Methods for generating the input/output JSON Schema. */
readonly jsonSchema: StandardJSONSchemaV1.Converter;
}
/** The Standard JSON Schema converter interface. */
interface Converter {
/** Converts the input type to JSON Schema. May throw if conversion is not supported. */
readonly input: (options: StandardJSONSchemaV1.Options) => Record<string, unknown>;
/** Converts the output type to JSON Schema. May throw if conversion is not supported. */
readonly output: (options: StandardJSONSchemaV1.Options) => Record<string, unknown>;
}
/**
* The target version of the generated JSON Schema.
*
* It is *strongly recommended* that implementers support `"draft-2020-12"` and `"draft-07"`, as they are both in wide use. All other targets can be implemented on a best-effort basis. Libraries should throw if they don't support a specified target.
*
* The `"openapi-3.0"` target is intended as a standardized specifier for OpenAPI 3.0 which is a superset of JSON Schema `"draft-04"`.
*/
type Target = "draft-2020-12" | "draft-07" | "openapi-3.0" | ({} & string);
/** The options for the input/output methods. */
interface Options {
/** Specifies the target version of the generated JSON Schema. Support for all versions is on a best-effort basis. If a given version is not supported, the library should throw. */
readonly target: Target;
/** Explicit support for additional vendor-specific parameters, if needed. */
readonly libraryOptions?: Record<string, unknown> | undefined;
}
/** The Standard types interface. */
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {
}
/** Infers the input type of a Standard. */
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
/** Infers the output type of a Standard. */
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
}

View File

@@ -0,0 +1,2 @@
/** From https://github.com/standard-schema/standard-schema */
export {};

View File

@@ -0,0 +1,139 @@
import { type Constructor, type Domain, type Json, type requireKeys, type satisfy } from "@ark/util";
import type { Predicate } from "../predicate.ts";
import type { ConstraintKind } from "./implement.ts";
import type { JsonSchema } from "./jsonSchema.ts";
import type { StandardJSONSchemaV1 } from "./standardSchema.ts";
declare class ToJsonSchemaError<code extends ToJsonSchema.Code = ToJsonSchema.Code> extends Error {
readonly name = "ToJsonSchemaError";
readonly code: code;
readonly context: ToJsonSchema.ContextByCode[code];
constructor(code: code, context: ToJsonSchema.ContextByCode[code]);
hasCode<code extends ToJsonSchema.Code>(code: code): this is ToJsonSchemaError<code>;
}
export declare const ToJsonSchema: {
Error: typeof ToJsonSchemaError;
throw: (code: keyof ToJsonSchema.ContextByCode, context: ToJsonSchema.MorphContext | ToJsonSchema.UnitContext | ToJsonSchema.ProtoContext | ToJsonSchema.DomainContext | ToJsonSchema.PredicateContext | ToJsonSchema.DateContext | ToJsonSchema.ArrayObjectContext | ToJsonSchema.ArrayPostfixContext | ToJsonSchema.DefaultValueContext | ToJsonSchema.PatternIntersectionContext | ToJsonSchema.SymbolKeyContext) => never;
throwInternalOperandError: (kind: ConstraintKind, schema: JsonSchema) => never;
defaultConfig: ToJsonSchema.Context;
};
export declare namespace ToJsonSchema {
type Unjsonifiable = object | symbol | bigint | undefined;
type Error = InstanceType<typeof ToJsonSchema.Error>;
interface BaseContext<code extends Code, base extends JsonSchema = JsonSchema> {
code: code;
base: base;
}
interface ArrayObjectContext extends BaseContext<"arrayObject", JsonSchema.Array> {
object: JsonSchema.Object;
}
interface ArrayPostfixContext extends BaseContext<"arrayPostfix", VariadicArraySchema> {
elements: readonly JsonSchema[];
}
interface DefaultValueContext extends BaseContext<"defaultValue", JsonSchema> {
value: Unjsonifiable;
}
interface DomainContext extends BaseContext<"domain", JsonSchema> {
domain: satisfy<Domain, "symbol" | "bigint" | "undefined">;
}
interface MorphContext extends BaseContext<"morph", JsonSchema> {
out: JsonSchema | null;
}
interface PatternIntersectionContext extends BaseContext<"patternIntersection", StringSchemaWithPattern> {
pattern: string;
}
interface PredicateContext extends BaseContext<"predicate", JsonSchema> {
predicate: Predicate;
}
interface ProtoContext extends BaseContext<"proto", JsonSchema> {
proto: Constructor;
}
type SymbolKeyContext = IndexSymbolKeyContext | RequiredSymbolKeyContext | OptionalSymbolKeyContext;
interface IndexSymbolKeyContext extends BaseContext<"symbolKey", JsonSchema.Object> {
key: null;
value: JsonSchema;
optional: false;
}
interface RequiredSymbolKeyContext extends BaseContext<"symbolKey", JsonSchema.Object> {
key: symbol;
value: JsonSchema;
optional: false;
}
interface OptionalSymbolKeyContext extends BaseContext<"symbolKey", JsonSchema.Object> {
key: symbol;
value: JsonSchema;
optional: true;
default?: Json;
}
interface UnitContext extends BaseContext<"unit", JsonSchema> {
unit: Unjsonifiable;
}
interface DateContext extends BaseContext<"date", JsonSchema> {
before?: Date;
after?: Date;
}
interface ContextByCode {
arrayObject: ArrayObjectContext;
arrayPostfix: ArrayPostfixContext;
defaultValue: DefaultValueContext;
domain: DomainContext;
morph: MorphContext;
patternIntersection: PatternIntersectionContext;
predicate: PredicateContext;
proto: ProtoContext;
symbolKey: SymbolKeyContext;
unit: UnitContext;
date: DateContext;
}
type Code = keyof ContextByCode;
type FallbackContext = ContextByCode[Code];
type HandlerByCode = satisfy<{
[code in Code]: (ctx: ContextByCode[code]) => unknown;
}, {
arrayObject: (ctx: ArrayObjectContext) => JsonSchema.Structure;
arrayPostfix: (ctx: ArrayPostfixContext) => VariadicArraySchema;
defaultValue: (ctx: DefaultValueContext) => JsonSchema;
domain: (ctx: DomainContext) => JsonSchema;
morph: (ctx: MorphContext) => JsonSchema;
patternIntersection: (ctx: PatternIntersectionContext) => JsonSchema.String;
predicate: (ctx: PredicateContext) => JsonSchema;
proto: (ctx: ProtoContext) => JsonSchema;
symbolKey: (ctx: SymbolKeyContext) => JsonSchema.Object;
unit: (ctx: UnitContext) => JsonSchema;
date: (ctx: DateContext) => JsonSchema;
}>;
type VariadicArraySchema = requireKeys<JsonSchema.Array, "items">;
type StringSchemaWithPattern = requireKeys<JsonSchema.String, "pattern">;
type UniversalFallback = (ctx: FallbackContext) => JsonSchema;
interface FallbackObject extends Partial<HandlerByCode> {
default?: UniversalFallback;
}
type FallbackOption = UniversalFallback | FallbackObject;
type Target = satisfy<StandardJSONSchemaV1.Target, "draft-2020-12" | "draft-07">;
interface Options {
/** value to assign to the generated $schema key
*
* - set to `null` to omit the `$schema` key
* - does not affect the contents of the generated schema
* - if `target` is also specified, `dialect` takes precedence
*
* @default "https://json-schema.org/draft/2020-12/schema"
*/
dialect?: string | null;
/**
* Shorthand for specifying the target JSON Schema version.
* Maps to the appropriate `dialect` URL.
*
* - "draft-2020-12" -> "https://json-schema.org/draft/2020-12/schema"
* - "draft-07" -> "http://json-schema.org/draft-07/schema#"
*
* If `dialect` is also specified, `dialect` takes precedence.
*/
target?: Target;
useRefs?: boolean;
fallback?: FallbackOption;
}
interface Context extends Required<Options> {
fallback: HandlerByCode;
}
}
export {};

View File

@@ -0,0 +1,40 @@
import { printable, throwInternalError } from "@ark/util";
class ToJsonSchemaError extends Error {
name = "ToJsonSchemaError";
code;
context;
constructor(code, context) {
super(printable(context, { quoteKeys: false, indent: 4 }));
this.code = code;
this.context = context;
}
hasCode(code) {
return this.code === code;
}
}
const defaultConfig = {
target: "draft-2020-12",
dialect: "https://json-schema.org/draft/2020-12/schema",
useRefs: false,
fallback: {
arrayObject: ctx => ToJsonSchema.throw("arrayObject", ctx),
arrayPostfix: ctx => ToJsonSchema.throw("arrayPostfix", ctx),
defaultValue: ctx => ToJsonSchema.throw("defaultValue", ctx),
domain: ctx => ToJsonSchema.throw("domain", ctx),
morph: ctx => ToJsonSchema.throw("morph", ctx),
patternIntersection: ctx => ToJsonSchema.throw("patternIntersection", ctx),
predicate: ctx => ToJsonSchema.throw("predicate", ctx),
proto: ctx => ToJsonSchema.throw("proto", ctx),
symbolKey: ctx => ToJsonSchema.throw("symbolKey", ctx),
unit: ctx => ToJsonSchema.throw("unit", ctx),
date: ctx => ToJsonSchema.throw("date", ctx)
}
};
export const ToJsonSchema = {
Error: ToJsonSchemaError,
throw: (...args) => {
throw new ToJsonSchema.Error(...args);
},
throwInternalOperandError: (kind, schema) => throwInternalError(`Unexpected JSON Schema input for ${kind}: ${printable(schema)}`),
defaultConfig
};

View File

@@ -0,0 +1,117 @@
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, type NodeErrorContextInput } from "./errors.ts";
export type MorphsAtPath = {
path: ReadonlyPath;
morphs: array<Morph>;
};
export type BranchTraversal = {
error: ArkError | undefined;
queuedMorphs: MorphsAtPath[];
};
export type InternalTraversal = Omit<Traversal, "error" | "mustBe" | "reject">;
export declare class Traversal {
/**
* #### the path being validated or morphed
*
* ✅ array indices represented as numbers
* ⚠️ mutated during traversal - use `path.slice(0)` to snapshot
* 🔗 use {@link propString} for a stringified version
*/
path: PropertyKey[];
/**
* #### {@link ArkErrors} that will be part of this traversal's finalized result
*
* ✅ will always be an empty array for a valid traversal
*/
errors: ArkErrors;
/**
* #### the original value being traversed
*/
root: unknown;
/**
* #### configuration for this traversal
*
* ✅ options can affect traversal results and error messages
* ✅ defaults < global config < scope config
* ✅ does not include options configured on individual types
*/
config: ResolvedConfig;
queuedMorphs: MorphsAtPath[];
branches: BranchTraversal[];
seen: {
[id in string]?: unknown[];
};
constructor(root: unknown, config: ResolvedConfig);
/**
* #### the data being validated or morphed
*
* ✅ extracted from {@link root} at {@link path}
*/
get data(): unknown;
/**
* #### a string representing {@link path}
*
* ✅ uses `.access` {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#dot_notation | where allowed by JS}, falling back to `[indexAccess]`
* @example
* const path = ["key1", Symbol("key2"), "key3", 4, "~key5"]
* const propString = 'key1[Symbol(key2)].key3[4]["~key5"]'
*/
get propString(): string;
/**
* #### add an {@link ArkError} and return `false`
*
* ✅ useful for predicates like `.narrow`
*/
reject(input: ArkErrorInput): false;
/**
* #### add an {@link ArkError} from a description and return `false`
*
* ✅ useful for predicates like `.narrow`
* 🔗 equivalent to {@link reject}({ expected })
*/
mustBe(expected: string): false;
/**
* #### add and return an {@link ArkError}
*
* ✅ useful for morphs like `.pipe`
*/
error<input extends ArkErrorInput>(input: input): ArkError<input extends {
code: ArkErrorCode;
} ? input["code"] : "predicate">;
/**
* #### whether {@link currentBranch} (or the traversal root, outside a union) has one or more errors
*/
hasError(): boolean;
get currentBranch(): BranchTraversal | undefined;
queueMorphs(morphs: array<Morph>): void;
finalize(onFail?: ArkErrors.Handler | null): unknown;
get currentErrorCount(): number;
get failFast(): boolean;
pushBranch(): void;
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;
private applyQueuedMorphs;
private applyMorphsAtPath;
}
export declare const traverseKey: <result>(key: PropertyKey, fn: () => result, ctx: InternalTraversal | undefined) => result;
export type TraversalMethodsByKind<input = unknown> = {
Allows: TraverseAllows<input>;
Apply: TraverseApply<input>;
Optimistic: TraverseApply<input>;
};
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;

View File

@@ -0,0 +1,226 @@
import { ReadonlyPath, stringifyPath } from "@ark/util";
import { ArkError, ArkErrors } from "./errors.js";
import { isNode } from "./utils.js";
export class Traversal {
/**
* #### the path being validated or morphed
*
* ✅ array indices represented as numbers
* ⚠️ mutated during traversal - use `path.slice(0)` to snapshot
* 🔗 use {@link propString} for a stringified version
*/
path = [];
/**
* #### {@link ArkErrors} that will be part of this traversal's finalized result
*
* ✅ will always be an empty array for a valid traversal
*/
errors = new ArkErrors(this);
/**
* #### the original value being traversed
*/
root;
/**
* #### configuration for this traversal
*
* ✅ options can affect traversal results and error messages
* ✅ defaults < global config < scope config
* ✅ does not include options configured on individual types
*/
config;
queuedMorphs = [];
branches = [];
seen = {};
constructor(root, config) {
this.root = root;
this.config = config;
}
/**
* #### the data being validated or morphed
*
* ✅ extracted from {@link root} at {@link path}
*/
get data() {
let result = this.root;
for (const segment of this.path)
result = result?.[segment];
return result;
}
/**
* #### a string representing {@link path}
*
* @propString
*/
get propString() {
return stringifyPath(this.path);
}
/**
* #### add an {@link ArkError} and return `false`
*
* ✅ useful for predicates like `.narrow`
*/
reject(input) {
this.error(input);
return false;
}
/**
* #### add an {@link ArkError} from a description and return `false`
*
* ✅ useful for predicates like `.narrow`
* 🔗 equivalent to {@link reject}({ expected })
*/
mustBe(expected) {
this.error(expected);
return false;
}
error(input) {
const errCtx = typeof input === "object" ?
input.code ?
input
: { ...input, code: "predicate" }
: { code: "predicate", expected: input };
return this.errorFromContext(errCtx);
}
/**
* #### whether {@link currentBranch} (or the traversal root, outside a union) has one or more errors
*/
hasError() {
return this.currentErrorCount !== 0;
}
get currentBranch() {
return this.branches[this.branches.length - 1];
}
queueMorphs(morphs) {
const input = {
path: new ReadonlyPath(...this.path),
morphs
};
if (this.currentBranch)
this.currentBranch.queuedMorphs.push(input);
else
this.queuedMorphs.push(input);
}
finalize(onFail) {
if (this.queuedMorphs.length) {
if (typeof this.root === "object" &&
this.root !== null &&
this.config.clone)
this.root = this.config.clone(this.root);
this.applyQueuedMorphs();
}
if (this.hasError())
return onFail ? onFail(this.errors) : this.errors;
return this.root;
}
get currentErrorCount() {
return (this.currentBranch ?
this.currentBranch.error ?
1
: 0
: this.errors.count);
}
get failFast() {
return this.branches.length !== 0;
}
pushBranch() {
this.branches.push({
error: undefined,
queuedMorphs: []
});
}
popBranch() {
return this.branches.pop();
}
/**
* @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() {
return this;
}
errorFromNodeContext(input) {
return this.errorFromContext(input);
}
errorFromContext(errCtx) {
const error = new ArkError(errCtx, this);
if (this.currentBranch)
this.currentBranch.error = error;
else
this.errors.add(error);
return error;
}
applyQueuedMorphs() {
// invoking morphs that are Nodes will reuse this context, potentially
// adding additional morphs, so we have to continue looping until
// queuedMorphs is empty rather than iterating over the list once
while (this.queuedMorphs.length) {
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.errors.affectsPath(path))
continue;
this.applyMorphsAtPath(path, morphs);
}
}
}
applyMorphsAtPath(path, morphs) {
const key = path[path.length - 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]];
}
for (const morph of morphs) {
// 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);
if (result instanceof ArkError) {
// if an ArkError was returned, ensure it has been added to errors
// (it may have already been added via ctx.error() within the morph)
// Only add if it's not already in the errors collection
if (!this.errors.includes(result))
this.errors.add(result);
// skip any remaining morphs at the current path
break;
}
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);
}
// skip any remaining morphs at the current path
this.queuedMorphs = [];
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();
}
}
}
export const traverseKey = (key, fn,
// ctx will be undefined if this node isn't context-dependent
ctx) => {
if (!ctx)
return fn();
ctx.path.push(key);
const result = fn();
ctx.path.pop();
return result;
};

View File

@@ -0,0 +1,34 @@
import { type array, type mutable, type show, type Thunk } from "@ark/util";
import type { BaseConstraint } from "../constraint.ts";
import type { GenericRoot } from "../generic.ts";
import type { InternalModule } from "../module.ts";
import type { BaseNode } from "../node.ts";
import type { BaseParseContext } from "../parse.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { BaseScope } from "../scope.ts";
import type { ArkError, ArkErrors } from "./errors.ts";
export declare const makeRootAndArrayPropertiesMutable: <o extends object>(o: o) => makeRootAndArrayPropertiesMutable<o>;
export type makeRootAndArrayPropertiesMutable<inner> = {
-readonly [k in keyof inner]: inner[k] extends array | undefined ? mutable<inner[k]> : inner[k];
} & unknown;
export type internalImplementationOf<external, typeOnlyKey extends keyof external = never> = {
[k in Exclude<keyof external, typeOnlyKey>]: external[k] extends ((...args: infer args) => unknown) ? (...args: {
[i in keyof args]: never;
}) => unknown : unknown;
};
export type arkKind = typeof arkKind;
export declare const arkKind: " arkKind";
export interface ArkKinds {
constraint: BaseConstraint;
root: BaseRoot;
scope: BaseScope;
generic: GenericRoot;
module: InternalModule;
error: ArkError;
errors: ArkErrors;
context: BaseParseContext;
}
export type ArkKind = show<keyof ArkKinds>;
export declare const hasArkKind: <kind extends ArkKind>(value: unknown, kind: kind) => value is ArkKinds[kind];
export declare const isNode: (value: unknown) => value is BaseNode;
export type unwrapDefault<thunkableValue> = thunkableValue extends Thunk<infer returnValue> ? returnValue : thunkableValue;

View File

@@ -0,0 +1,8 @@
import { flatMorph, isArray, noSuggest } from "@ark/util";
export const makeRootAndArrayPropertiesMutable = (o) =>
// this cast should not be required, but it seems TS is referencing
// the wrong parameters here?
flatMorph(o, (k, v) => [k, isArray(v) ? [...v] : v]);
export const arkKind = noSuggest("arkKind");
export const hasArkKind = (value, kind) => value?.[arkKind] === kind;
export const isNode = (value) => hasArkKind(value, "root") || hasArkKind(value, "constraint");

View File

@@ -0,0 +1,46 @@
import { BaseConstraint } from "../constraint.ts";
import type { RootSchema, nodeOfKind } from "../kinds.ts";
import { type BaseNode, type DeepNodeTransformContext, type DeepNodeTransformation } from "../node.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type RootKind, type nodeImplementationOf } from "../shared/implement.ts";
import { type TraverseAllows, type TraverseApply } from "../shared/traversal.ts";
export declare namespace Index {
type KeyKind = Exclude<RootKind, "unit">;
type KeyNode = nodeOfKind<KeyKind>;
interface Schema extends BaseNormalizedSchema {
readonly signature: RootSchema<KeyKind>;
readonly value: RootSchema;
}
interface Inner {
readonly signature: KeyNode;
readonly value: BaseRoot;
}
interface Declaration extends declareNode<{
kind: "index";
schema: Schema;
normalizedSchema: Schema;
inner: Inner;
prerequisite: object;
intersectionIsOpen: true;
childKind: RootKind;
}> {
}
type Node = IndexNode;
}
export declare class IndexNode extends BaseConstraint<Index.Declaration> {
impliedBasis: BaseRoot;
expression: string;
flatRefs: import("../node.ts").FlatRef<BaseRoot<import("../roots/root.ts").InternalRootDeclaration>>[];
traverseAllows: TraverseAllows<object>;
traverseApply: TraverseApply<object>;
protected _transform(mapper: DeepNodeTransformation, ctx: DeepNodeTransformContext): BaseNode | null;
compile(): void;
}
export declare const Index: {
implementation: nodeImplementationOf<Index.Declaration>;
Node: typeof IndexNode;
};
export declare const writeEnumerableIndexBranches: (keys: string[]) => string;
export declare const writeInvalidPropertyKeyMessage: <indexSchema extends string>(indexSchema: indexSchema) => writeInvalidPropertyKeyMessage<indexSchema>;
export type writeInvalidPropertyKeyMessage<indexSchema extends string> = `Indexed key definition '${indexSchema}' must be a string or symbol`;

View File

@@ -0,0 +1,89 @@
import { append, printable, stringAndSymbolicEntriesOf, throwParseError } from "@ark/util";
import { BaseConstraint } from "../constraint.js";
import { flatRef } from "../node.js";
import { Disjoint } from "../shared/disjoint.js";
import { implementNode } from "../shared/implement.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark } from "../shared/registry.js";
import { traverseKey } from "../shared/traversal.js";
const implementation = implementNode({
kind: "index",
hasAssociatedError: false,
intersectionIsOpen: true,
keys: {
signature: {
child: true,
parse: (schema, ctx) => {
const key = ctx.$.parseSchema(schema);
if (!key.extends($ark.intrinsic.key)) {
return throwParseError(writeInvalidPropertyKeyMessage(key.expression));
}
const enumerableBranches = key.branches.filter(b => b.hasKind("unit"));
if (enumerableBranches.length) {
return throwParseError(writeEnumerableIndexBranches(enumerableBranches.map(b => printable(b.unit))));
}
return key;
}
},
value: {
child: true,
parse: (schema, ctx) => ctx.$.parseSchema(schema)
}
},
normalize: schema => schema,
defaults: {
description: node => `[${node.signature.expression}]: ${node.value.description}`
},
intersections: {
index: (l, r, ctx) => {
if (l.signature.equals(r.signature)) {
const valueIntersection = intersectOrPipeNodes(l.value, r.value, ctx);
const value = valueIntersection instanceof Disjoint ?
$ark.intrinsic.never.internal
: valueIntersection;
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.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.signature.extends(l.signature) && r.value.subsumes(l.value))
return l;
// other relationships between index signatures can't be generally reduced
return null;
}
}
});
export class IndexNode extends BaseConstraint {
impliedBasis = $ark.intrinsic.object.internal;
expression = `[${this.signature.expression}]: ${this.value.expression}`;
flatRefs = append(this.value.flatRefs.map(ref => flatRef([this.signature, ...ref.path], ref.node)), flatRef([this.signature], this.value));
traverseAllows = (data, ctx) => stringAndSymbolicEntriesOf(data).every(entry => {
if (this.signature.traverseAllows(entry[0], ctx)) {
return traverseKey(entry[0], () => this.value.traverseAllows(entry[1], ctx), ctx);
}
return true;
});
traverseApply = (data, ctx) => {
for (const entry of stringAndSymbolicEntriesOf(data)) {
if (this.signature.traverseAllows(entry[0], ctx)) {
traverseKey(entry[0], () => this.value.traverseApply(entry[1], ctx), ctx);
}
}
};
_transform(mapper, ctx) {
ctx.path.push(this.signature);
const result = super._transform(mapper, ctx);
ctx.path.pop();
return result;
}
compile() {
// this is currently handled by StructureNode
}
}
export const Index = {
implementation,
Node: IndexNode
};
export const writeEnumerableIndexBranches = (keys) => `Index keys ${keys.join(", ")} should be specified as named props.`;
export const writeInvalidPropertyKeyMessage = (indexSchema) => `Indexed key definition '${indexSchema}' must be a string or symbol`;

View File

@@ -0,0 +1,49 @@
import { type requireKeys } from "@ark/util";
import type { Morph } from "../roots/morph.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { declareNode } from "../shared/declare.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import { BaseProp, type Prop } from "./prop.ts";
export declare namespace Optional {
interface Schema extends Prop.Schema {
default?: unknown;
}
interface Inner extends Prop.Inner {
default?: unknown;
}
type Declaration = declareNode<Prop.Declaration<"optional"> & {
schema: Schema;
normalizedSchema: Schema;
inner: Inner;
}>;
type Node = OptionalNode;
namespace Node {
type withDefault = requireKeys<Node, "default" | "defaultValueMorph" | "defaultValueMorphRef">;
}
}
export declare class OptionalNode extends BaseProp<"optional"> {
constructor(...args: ConstructorParameters<typeof BaseProp>);
get rawIn(): OptionalNode;
get outProp(): Prop.Node;
expression: string;
defaultValueMorph: Morph | undefined;
defaultValueMorphRef: string | undefined;
}
export declare const Optional: {
implementation: nodeImplementationOf<{
reducibleTo: "optional";
errorContext: null;
kind: "optional";
prerequisite: object;
intersectionIsOpen: true;
childKind: import("../shared/implement.ts").RootKind;
schema: Optional.Schema;
normalizedSchema: Optional.Schema;
inner: Optional.Inner;
}>;
Node: typeof OptionalNode;
};
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;

View File

@@ -0,0 +1,127 @@
import { hasDomain, isThunk, omit, printable, throwParseError } from "@ark/util";
import { intrinsic } from "../intrinsic.js";
import { compileSerializedValue } from "../shared/compile.js";
import { ArkErrors } from "../shared/errors.js";
import { defaultValueSerializer, implementNode } from "../shared/implement.js";
import { registeredReference } from "../shared/registry.js";
import { traverseKey } from "../shared/traversal.js";
import { BaseProp, intersectProps } from "./prop.js";
const implementation = implementNode({
kind: "optional",
hasAssociatedError: false,
intersectionIsOpen: true,
keys: {
key: {},
value: {
child: true,
parse: (schema, ctx) => ctx.$.parseSchema(schema)
},
default: {
preserveUndefined: true
}
},
normalize: schema => schema,
reduce: (inner, $) => {
if ($.resolvedConfig.exactOptionalPropertyTypes === false) {
if (!inner.value.allows(undefined)) {
return $.node("optional", { ...inner, value: inner.value.or(intrinsic.undefined) }, { prereduced: true });
}
}
},
defaults: {
description: node => `${node.compiledKey}?: ${node.value.description}`
},
intersections: {
optional: intersectProps
}
});
export class OptionalNode extends BaseProp {
constructor(...args) {
super(...args);
if ("default" in this.inner)
assertDefaultValueAssignability(this.value, this.inner.default, this.key);
}
get rawIn() {
const baseIn = super.rawIn;
if (!this.hasDefault())
return baseIn;
return this.$.node("optional", omit(baseIn.inner, { default: true }), {
prereduced: true
});
}
get outProp() {
if (!this.hasDefault())
return this;
const { default: defaultValue, ...requiredInner } = this.inner;
return this.cacheGetter("outProp", this.$.node("required", requiredInner, { prereduced: true }));
}
expression = this.hasDefault() ?
`${this.compiledKey}: ${this.value.expression} = ${printable(this.inner.default)}`
: `${this.compiledKey}?: ${this.value.expression}`;
defaultValueMorph = getDefaultableMorph(this);
defaultValueMorphRef = this.defaultValueMorph && registeredReference(this.defaultValueMorph);
}
export const Optional = {
implementation,
Node: OptionalNode
};
const defaultableMorphCache = {};
const getDefaultableMorph = (node) => {
if (!node.hasDefault())
return;
const cacheKey = `{${node.compiledKey}: ${node.value.id} = ${defaultValueSerializer(node.default)}}`;
return (defaultableMorphCache[cacheKey] ??= computeDefaultValueMorph(node.key, node.value, node.default));
};
export const computeDefaultValueMorph = (key, value, defaultInput) => {
if (typeof defaultInput === "function") {
// if the value has a morph, pipe context through it
return value.includesTransform ?
(data, ctx) => {
traverseKey(key, () => value((data[key] = defaultInput()), ctx), ctx);
return data;
}
: data => {
data[key] = defaultInput();
return data;
};
}
// non-functional defaults can be safely cached as long as the morph is
// guaranteed to be pure and the output is primitive
const precomputedMorphedDefault = value.includesTransform ? value.assert(defaultInput) : defaultInput;
return hasDomain(precomputedMorphedDefault, "object") ?
// the type signature only allows this if the value was morphed
(data, ctx) => {
traverseKey(key, () => value((data[key] = defaultInput), ctx), ctx);
return data;
}
: data => {
data[key] = precomputedMorphedDefault;
return data;
};
};
export const assertDefaultValueAssignability = (node, value, key) => {
const wrapped = isThunk(value);
if (hasDomain(value, "object") && !wrapped)
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);
if (out instanceof ArkErrors) {
if (key === null) {
// e.g. "Default must be assignable to number (was string)"
throwParseError(`Default ${out.summary}`);
}
const atPath = out.transform(e => e.transform(input => ({ ...input, prefixPath: [key] })));
// e.g. "Default for bar must be assignable to number (was string)"
// e.g. "Default for value at [0] must be assignable to number (was string)"
throwParseError(`Default for ${atPath.summary}`);
}
return value;
};
export const writeNonPrimitiveNonFunctionDefaultValueMessage = (key) => {
const keyDescription = key === null ? ""
: typeof key === "number" ? `for value at [${key}] `
: `for ${compileSerializedValue(key)} `;
return `Non-primitive default ${keyDescription}must be specified as a function like () => ({my: 'object'})`;
};

View File

@@ -0,0 +1,45 @@
import { type Key } from "@ark/util";
import { BaseConstraint } from "../constraint.ts";
import type { nodeOfKind, RootSchema } from "../kinds.ts";
import { type BaseNode, type DeepNodeTransformation, type DeepNodeTransformContext, type FlatRef } from "../node.ts";
import type { BaseRoot } from "../roots/root.ts";
import { type NodeCompiler } from "../shared/compile.ts";
import type { BaseNormalizedSchema } from "../shared/declare.ts";
import { Disjoint } from "../shared/disjoint.ts";
import type { IntersectionContext, RootKind } from "../shared/implement.ts";
import { type TraverseAllows, type TraverseApply } from "../shared/traversal.ts";
import type { Optional } from "./optional.ts";
import type { Required } from "./required.ts";
export declare namespace Prop {
type Kind = "required" | "optional";
type Node = nodeOfKind<Kind>;
interface Schema extends BaseNormalizedSchema {
readonly key: Key;
readonly value: RootSchema;
}
interface Inner {
readonly key: Key;
readonly value: BaseRoot;
}
interface Declaration<kind extends Kind = Kind> {
kind: kind;
prerequisite: object;
intersectionIsOpen: true;
childKind: RootKind;
}
}
export declare const intersectProps: (l: nodeOfKind<Prop.Kind>, r: nodeOfKind<Prop.Kind>, ctx: IntersectionContext) => nodeOfKind<Prop.Kind> | Disjoint | null;
export declare abstract class BaseProp<kind extends Prop.Kind = Prop.Kind> extends BaseConstraint<kind extends "required" ? Required.Declaration : Optional.Declaration> {
required: boolean;
optional: boolean;
impliedBasis: BaseRoot;
serializedKey: string;
compiledKey: string;
flatRefs: FlatRef[];
protected _transform(mapper: DeepNodeTransformation, ctx: DeepNodeTransformContext): BaseNode | null;
hasDefault(): this is Optional.Node.withDefault;
traverseAllows: TraverseAllows<object>;
traverseApply: TraverseApply<object>;
compile(js: NodeCompiler): void;
}
export declare const writeDefaultIntersectionMessage: (lValue: unknown, rValue: unknown) => string;

View File

@@ -0,0 +1,85 @@
import { append, printable, throwParseError, unset } from "@ark/util";
import { BaseConstraint } from "../constraint.js";
import { flatRef } from "../node.js";
import { compileSerializedValue } from "../shared/compile.js";
import { Disjoint } from "../shared/disjoint.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark } from "../shared/registry.js";
import { traverseKey } from "../shared/traversal.js";
export const intersectProps = (l, r, ctx) => {
if (l.key !== r.key)
return null;
const key = l.key;
let value = intersectOrPipeNodes(l.value, r.value, ctx);
const kind = l.required || r.required ? "required" : "optional";
if (value instanceof Disjoint) {
if (kind === "optional")
value = $ark.intrinsic.never.internal;
else {
// if either operand was optional, the Disjoint has to be treated as optional
return value.withPrefixKey(l.key, l.required && r.required ? "required" : "optional");
}
}
if (kind === "required") {
return ctx.$.node("required", {
key,
value
});
}
const defaultIntersection = l.hasDefault() ?
r.hasDefault() ?
l.default === r.default ?
l.default
: throwParseError(writeDefaultIntersectionMessage(l.default, r.default))
: l.default
: r.hasDefault() ? r.default
: unset;
return ctx.$.node("optional", {
key,
value,
// unset is stripped during parsing
default: defaultIntersection
});
};
export class BaseProp extends BaseConstraint {
required = this.kind === "required";
optional = this.kind === "optional";
impliedBasis = $ark.intrinsic.object.internal;
serializedKey = compileSerializedValue(this.key);
compiledKey = typeof this.key === "string" ? this.key : this.serializedKey;
flatRefs = append(this.value.flatRefs.map(ref => flatRef([this.key, ...ref.path], ref.node)), flatRef([this.key], this.value));
_transform(mapper, ctx) {
ctx.path.push(this.key);
const result = super._transform(mapper, ctx);
ctx.path.pop();
return result;
}
hasDefault() {
return "default" in this.inner;
}
traverseAllows = (data, ctx) => {
if (this.key in data) {
// ctx will be undefined if this node isn't context-dependent
return traverseKey(this.key, () => this.value.traverseAllows(data[this.key], ctx), ctx);
}
return this.optional;
};
traverseApply = (data, ctx) => {
if (this.key in data) {
traverseKey(this.key, () => this.value.traverseApply(data[this.key], ctx), ctx);
}
else if (this.hasKind("required"))
ctx.errorFromNodeContext(this.errorContext);
};
compile(js) {
js.if(`${this.serializedKey} in data`, () => js.traverseKey(this.serializedKey, `data${js.prop(this.key)}`, this.value));
if (this.hasKind("required")) {
js.else(() => js.traversalKind === "Apply" ?
js.line(`ctx.errorFromNodeContext(${this.compiledErrorContext})`)
: js.return(false));
}
if (js.traversalKind === "Allows")
js.return(true);
}
}
export const writeDefaultIntersectionMessage = (lValue, rValue) => `Invalid intersection of default values ${printable(lValue)} & ${printable(rValue)}`;

View File

@@ -0,0 +1,39 @@
import type { BaseErrorContext, declareNode } from "../shared/declare.ts";
import type { NodeErrorContextInput } from "../shared/errors.ts";
import { type nodeImplementationOf } from "../shared/implement.ts";
import { BaseProp, type Prop } from "./prop.ts";
export declare namespace Required {
interface ErrorContext extends BaseErrorContext<"required"> {
missingValueDescription: string;
}
interface Schema extends Prop.Schema {
}
interface Inner extends Prop.Inner {
}
type Declaration = declareNode<Prop.Declaration<"required"> & {
schema: Schema;
normalizedSchema: Schema;
inner: Inner;
errorContext: ErrorContext;
}>;
type Node = RequiredNode;
}
export declare class RequiredNode extends BaseProp<"required"> {
expression: string;
errorContext: NodeErrorContextInput<"required">;
compiledErrorContext: string;
}
export declare const Required: {
implementation: nodeImplementationOf<{
reducibleTo: "required";
kind: "required";
prerequisite: object;
intersectionIsOpen: true;
childKind: import("../shared/implement.ts").RootKind;
schema: Required.Schema;
normalizedSchema: Required.Schema;
inner: Required.Inner;
errorContext: Required.ErrorContext;
}>;
Node: typeof RequiredNode;
};

View File

@@ -0,0 +1,38 @@
import { compileObjectLiteral, implementNode } from "../shared/implement.js";
import { BaseProp, intersectProps } from "./prop.js";
const implementation = implementNode({
kind: "required",
hasAssociatedError: true,
intersectionIsOpen: true,
keys: {
key: {},
value: {
child: true,
parse: (schema, ctx) => ctx.$.parseSchema(schema)
}
},
normalize: schema => schema,
defaults: {
description: node => `${node.compiledKey}: ${node.value.description}`,
expected: ctx => ctx.missingValueDescription,
actual: () => "missing"
},
intersections: {
required: intersectProps,
optional: intersectProps
}
});
export class RequiredNode extends BaseProp {
expression = `${this.compiledKey}: ${this.value.expression}`;
errorContext = Object.freeze({
code: "required",
missingValueDescription: this.value.defaultShortDescription,
relativePath: [this.key],
meta: this.meta
});
compiledErrorContext = compileObjectLiteral(this.errorContext);
}
export const Required = {
implementation,
Node: RequiredNode
};

View File

@@ -0,0 +1,110 @@
import { type array, type satisfy } from "@ark/util";
import { BaseConstraint } from "../constraint.ts";
import type { RootSchema } from "../kinds.ts";
import { type BaseNode, type DeepNodeTransformContext, type DeepNodeTransformation, type FlatRef } from "../node.ts";
import type { ExactLengthNode } from "../refinements/exactLength.ts";
import type { MaxLengthNode } from "../refinements/maxLength.ts";
import type { MinLengthNode } from "../refinements/minLength.ts";
import type { Morph } from "../roots/morph.ts";
import type { BaseRoot } from "../roots/root.ts";
import type { NodeCompiler } from "../shared/compile.ts";
import type { BaseNormalizedSchema, declareNode } from "../shared/declare.ts";
import { type RootKind, type nodeImplementationOf } from "../shared/implement.ts";
import type { JsonSchema } from "../shared/jsonSchema.ts";
import type { ToJsonSchema } from "../shared/toJsonSchema.ts";
import { type TraverseAllows, type TraverseApply } from "../shared/traversal.ts";
export declare namespace Sequence {
interface NormalizedSchema extends BaseNormalizedSchema {
readonly prefix?: array<RootSchema>;
readonly defaultables?: array<DefaultableSchema>;
readonly optionals?: array<RootSchema>;
readonly variadic?: RootSchema;
readonly minVariadicLength?: number;
readonly postfix?: array<RootSchema>;
}
type Schema = NormalizedSchema | RootSchema;
type DefaultableSchema = [schema: RootSchema, defaultValue: unknown];
type DefaultableElement = [node: BaseRoot, defaultValue: unknown];
interface Inner {
readonly prefix?: array<BaseRoot>;
readonly defaultables?: array<DefaultableElement>;
readonly optionals?: array<BaseRoot>;
readonly variadic?: BaseRoot;
readonly minVariadicLength?: number;
readonly postfix?: array<BaseRoot>;
}
interface Declaration extends declareNode<{
kind: "sequence";
schema: Schema;
normalizedSchema: NormalizedSchema;
inner: Inner;
prerequisite: array;
reducibleTo: "sequence";
childKind: RootKind;
}> {
}
type Node = SequenceNode;
}
export declare class SequenceNode extends BaseConstraint<Sequence.Declaration> {
impliedBasis: BaseRoot;
tuple: SequenceTuple;
prefixLength: number;
defaultablesLength: number;
optionalsLength: number;
postfixLength: number;
defaultablesAndOptionals: BaseRoot[];
prevariadic: array<PrevariadicSequenceElement>;
variadicOrPostfix: array<BaseRoot>;
flatRefs: FlatRef[];
protected addFlatRefs(): FlatRef[];
isVariadicOnly: boolean;
minVariadicLength: number;
minLength: number;
minLengthNode: MinLengthNode | null;
maxLength: number | null;
maxLengthNode: MaxLengthNode | ExactLengthNode | null;
impliedSiblings: array<MaxLengthNode | MinLengthNode | ExactLengthNode>;
defaultValueMorphs: Morph[];
defaultValueMorphsReference: `$ark.${string}` | `$ark0.${string}` | `$ark${`2${string}` & `${bigint}`}.${string}` | `$ark${`1${string}` & `${bigint}`}.${string}` | `$ark${`3${string}` & `${bigint}`}.${string}` | `$ark${`4${string}` & `${bigint}`}.${string}` | `$ark${`5${string}` & `${bigint}`}.${string}` | `$ark${`6${string}` & `${bigint}`}.${string}` | `$ark${`7${string}` & `${bigint}`}.${string}` | `$ark${`8${string}` & `${bigint}`}.${string}` | `$ark${`9${string}` & `${bigint}`}.${string}` | undefined;
protected elementAtIndex(data: array, index: number): SequenceElement;
traverseAllows: TraverseAllows<array>;
traverseApply: TraverseApply<array>;
get element(): BaseRoot;
compile(js: NodeCompiler): void;
protected _transform(mapper: DeepNodeTransformation, ctx: DeepNodeTransformContext): BaseNode | null;
expression: string;
reduceJsonSchema(schema: JsonSchema.Array, ctx: ToJsonSchema.Context): JsonSchema.Array;
}
export declare const Sequence: {
implementation: nodeImplementationOf<Sequence.Declaration>;
Node: typeof SequenceNode;
};
export declare const postfixAfterOptionalOrDefaultableMessage = "A postfix required element cannot follow an optional or defaultable element";
export type postfixAfterOptionalOrDefaultableMessage = typeof postfixAfterOptionalOrDefaultableMessage;
export declare const postfixWithoutVariadicMessage = "A postfix element requires a variadic element";
export type postfixWithoutVariadicMessage = typeof postfixWithoutVariadicMessage;
export type SequenceElement = PrevariadicSequenceElement | VariadicSequenceElement | PostfixSequenceElement;
export type SequenceElementKind = satisfy<keyof Sequence.Inner, SequenceElement["kind"]>;
export type PrevariadicSequenceElement = PrefixSequenceElement | DefaultableSequenceElement | OptionalSequenceElement;
export type PrefixSequenceElement = {
kind: "prefix";
node: BaseRoot;
};
export type OptionalSequenceElement = {
kind: "optionals";
node: BaseRoot;
};
export type PostfixSequenceElement = {
kind: "postfix";
node: BaseRoot;
};
export type VariadicSequenceElement = {
kind: "variadic";
node: BaseRoot;
};
export type DefaultableSequenceElement = {
kind: "defaultables";
node: BaseRoot;
default: unknown;
};
export type SequenceTuple = array<SequenceElement>;

View File

@@ -0,0 +1,521 @@
import { append, conflatenate, printable, throwInternalError, throwParseError } from "@ark/util";
import { BaseConstraint } from "../constraint.js";
import { appendUniqueFlatRefs, flatRef } from "../node.js";
import { Disjoint } from "../shared/disjoint.js";
import { defaultValueSerializer, implementNode } from "../shared/implement.js";
import { intersectOrPipeNodes } from "../shared/intersections.js";
import { $ark, registeredReference } from "../shared/registry.js";
import { traverseKey } from "../shared/traversal.js";
import { assertDefaultValueAssignability, computeDefaultValueMorph } from "./optional.js";
import { writeDefaultIntersectionMessage } from "./prop.js";
const implementation = implementNode({
kind: "sequence",
hasAssociatedError: false,
collapsibleKey: "variadic",
keys: {
prefix: {
child: true,
parse: (schema, ctx) => {
// empty affixes are omitted. an empty array should therefore
// be specified as `{ proto: Array, length: 0 }`
if (schema.length === 0)
return undefined;
return schema.map(element => ctx.$.parseSchema(element));
}
},
optionals: {
child: true,
parse: (schema, ctx) => {
if (schema.length === 0)
return undefined;
return schema.map(element => ctx.$.parseSchema(element));
}
},
defaultables: {
child: defaultables => defaultables.map(element => element[0]),
parse: (defaultables, ctx) => {
if (defaultables.length === 0)
return undefined;
return defaultables.map(element => {
const node = ctx.$.parseSchema(element[0]);
assertDefaultValueAssignability(node, element[1], null);
return [node, element[1]];
});
},
serialize: defaults => defaults.map(element => [
element[0].collapsibleJson,
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;
}
},
variadic: {
child: true,
parse: (schema, ctx) => ctx.$.parseSchema(schema, ctx)
},
minVariadicLength: {
// minVariadicLength is reflected in the id of this node,
// but not its IntersectionNode parent since it is superceded by the minLength
// node it implies
parse: min => (min === 0 ? undefined : min)
},
postfix: {
child: true,
parse: (schema, ctx) => {
if (schema.length === 0)
return undefined;
return schema.map(element => ctx.$.parseSchema(element));
}
}
},
normalize: schema => {
if (typeof schema === "string")
return { variadic: schema };
if ("variadic" in schema ||
"prefix" in schema ||
"defaultables" in schema ||
"optionals" in schema ||
"postfix" in schema ||
"minVariadicLength" in schema) {
if (schema.postfix?.length) {
if (!schema.variadic)
return throwParseError(postfixWithoutVariadicMessage);
if (schema.optionals?.length || schema.defaultables?.length)
return throwParseError(postfixAfterOptionalOrDefaultableMessage);
}
if (schema.minVariadicLength && !schema.variadic) {
return throwParseError("minVariadicLength may not be specified without a variadic element");
}
return schema;
}
return { variadic: schema };
},
reduce: (raw, $) => {
let minVariadicLength = raw.minVariadicLength ?? 0;
const prefix = raw.prefix?.slice() ?? [];
const defaultables = raw.defaultables?.slice() ?? [];
const optionals = raw.optionals?.slice() ?? [];
const postfix = raw.postfix?.slice() ?? [];
if (raw.variadic) {
// optional elements equivalent to the variadic parameter are redundant
while (optionals[optionals.length - 1]?.equals(raw.variadic))
optionals.pop();
if (optionals.length === 0 && defaultables.length === 0) {
// If there are no optional, normalize prefix
// elements adjacent and equivalent to variadic:
// { variadic: number, prefix: [string, number] }
// reduces to:
// { variadic: number, prefix: [string], minVariadicLength: 1 }
while (prefix[prefix.length - 1]?.equals(raw.variadic)) {
prefix.pop();
minVariadicLength++;
}
}
// Normalize postfix elements adjacent and equivalent to variadic:
// { variadic: number, postfix: [number, number, 5] }
// reduces to:
// { variadic: number, postfix: [5], minVariadicLength: 2 }
while (postfix[0]?.equals(raw.variadic)) {
postfix.shift();
minVariadicLength++;
}
}
else if (optionals.length === 0 && defaultables.length === 0) {
// if there's no variadic, optional or defaultable elements,
// postfix can just be appended to prefix
prefix.push(...postfix.splice(0));
}
if (
// if any variadic adjacent elements were moved to minVariadicLength
minVariadicLength !== raw.minVariadicLength ||
// or any postfix elements were moved to prefix
(raw.prefix && raw.prefix.length !== prefix.length)) {
// reparse the reduced def
return $.node("sequence", {
...raw,
// empty lists will be omitted during parsing
prefix,
defaultables,
optionals,
postfix,
minVariadicLength
}, { prereduced: true });
}
},
defaults: {
description: node => {
if (node.isVariadicOnly)
return `${node.variadic.nestableExpression}[]`;
const innerDescription = node.tuple
.map(element => element.kind === "defaultables" ?
`${element.node.nestableExpression} = ${printable(element.default)}`
: element.kind === "optionals" ?
`${element.node.nestableExpression}?`
: element.kind === "variadic" ?
`...${element.node.nestableExpression}[]`
: element.node.expression)
.join(", ");
return `[${innerDescription}]`;
}
},
intersections: {
sequence: (l, r, ctx) => {
const rootState = _intersectSequences({
l: l.tuple,
r: r.tuple,
disjoint: new Disjoint(),
result: [],
fixedVariants: [],
ctx
});
const viableBranches = rootState.disjoint.length === 0 ?
[rootState, ...rootState.fixedVariants]
: rootState.fixedVariants;
return (viableBranches.length === 0 ? rootState.disjoint
: viableBranches.length === 1 ?
ctx.$.node("sequence", sequenceTupleToInner(viableBranches[0].result))
: ctx.$.node("union", viableBranches.map(state => ({
proto: Array,
sequence: sequenceTupleToInner(state.result)
}))));
}
// exactLength, minLength, and maxLength don't need to be defined
// here since impliedSiblings guarantees they will be added
// directly to the IntersectionNode parent of the SequenceNode
// they exist on
}
});
export class SequenceNode extends BaseConstraint {
impliedBasis = $ark.intrinsic.Array.internal;
tuple = sequenceInnerToTuple(this.inner);
prefixLength = this.prefix?.length ?? 0;
defaultablesLength = this.defaultables?.length ?? 0;
optionalsLength = this.optionals?.length ?? 0;
postfixLength = this.postfix?.length ?? 0;
defaultablesAndOptionals = [];
prevariadic = this.tuple.filter((el) => {
if (el.kind === "defaultables" || el.kind === "optionals") {
// populate defaultablesAndOptionals while filtering prevariadic
this.defaultablesAndOptionals.push(el.node);
return true;
}
return el.kind === "prefix";
});
variadicOrPostfix = conflatenate(this.variadic && [this.variadic], this.postfix);
// have to wait until prevariadic and variadicOrPostfix are set to calculate
flatRefs = this.addFlatRefs();
addFlatRefs() {
appendUniqueFlatRefs(this.flatRefs, this.prevariadic.flatMap((element, i) => append(element.node.flatRefs.map(ref => flatRef([`${i}`, ...ref.path], ref.node)), flatRef([`${i}`], element.node))));
appendUniqueFlatRefs(this.flatRefs, this.variadicOrPostfix.flatMap(element =>
// a postfix index can't be directly represented as a type
// key, so we just use the same matcher for variadic
append(element.flatRefs.map(ref => flatRef([$ark.intrinsic.nonNegativeIntegerString.internal, ...ref.path], ref.node)), flatRef([$ark.intrinsic.nonNegativeIntegerString.internal], element))));
return this.flatRefs;
}
isVariadicOnly = this.prevariadic.length + this.postfixLength === 0;
minVariadicLength = this.inner.minVariadicLength ?? 0;
minLength = this.prefixLength + this.minVariadicLength + this.postfixLength;
minLengthNode = this.minLength === 0 ?
null
// cast is safe here as the only time this would not be a
// MinLengthNode would be when minLength is 0
: this.$.node("minLength", this.minLength);
maxLength = this.variadic ? null : this.tuple.length;
maxLengthNode = this.maxLength === null ? null : this.$.node("maxLength", this.maxLength);
impliedSiblings = this.minLengthNode ?
this.maxLengthNode ?
[this.minLengthNode, this.maxLengthNode]
: [this.minLengthNode]
: this.maxLengthNode ? [this.maxLengthNode]
: [];
defaultValueMorphs = getDefaultableMorphs(this);
defaultValueMorphsReference = this.defaultValueMorphs.length ?
registeredReference(this.defaultValueMorphs)
: undefined;
elementAtIndex(data, index) {
if (index < this.prevariadic.length)
return this.tuple[index];
const firstPostfixIndex = data.length - this.postfixLength;
if (index >= firstPostfixIndex)
return { kind: "postfix", node: this.postfix[index - firstPostfixIndex] };
return {
kind: "variadic",
node: this.variadic ??
throwInternalError(`Unexpected attempt to access index ${index} on ${this}`)
};
}
// minLength/maxLength should be checked by Intersection before either traversal
traverseAllows = (data, ctx) => {
for (let i = 0; i < data.length; i++) {
if (!this.elementAtIndex(data, i).node.traverseAllows(data[i], ctx))
return false;
}
return true;
};
traverseApply = (data, ctx) => {
let i = 0;
for (; i < data.length; i++) {
traverseKey(i, () => this.elementAtIndex(data, i).node.traverseApply(data[i], ctx), ctx);
}
};
get element() {
return this.cacheGetter("element", this.$.node("union", this.children));
}
// minLength/maxLength compilation should be handled by Intersection
compile(js) {
if (this.prefix) {
for (const [i, node] of this.prefix.entries())
js.traverseKey(`${i}`, `data[${i}]`, node);
}
for (const [i, node] of this.defaultablesAndOptionals.entries()) {
const dataIndex = `${i + this.prefixLength}`;
js.if(`${dataIndex} >= data.length`, () => js.traversalKind === "Allows" ? js.return(true) : js.return());
js.traverseKey(dataIndex, `data[${dataIndex}]`, node);
}
if (this.variadic) {
if (this.postfix) {
js.const("firstPostfixIndex", `data.length${this.postfix ? `- ${this.postfix.length}` : ""}`);
}
js.for(`i < ${this.postfix ? "firstPostfixIndex" : "data.length"}`, () => js.traverseKey("i", "data[i]", this.variadic), this.prevariadic.length);
if (this.postfix) {
for (const [i, node] of this.postfix.entries()) {
const keyExpression = `firstPostfixIndex + ${i}`;
js.traverseKey(keyExpression, `data[${keyExpression}]`, node);
}
}
}
if (js.traversalKind === "Allows")
js.return(true);
}
_transform(mapper, ctx) {
ctx.path.push($ark.intrinsic.nonNegativeIntegerString.internal);
const result = super._transform(mapper, ctx);
ctx.path.pop();
return result;
}
// this depends on tuple so needs to come after it
expression = this.description;
reduceJsonSchema(schema, ctx) {
const isDraft07 = ctx.target === "draft-07";
if (this.prevariadic.length) {
const prefixSchemas = this.prevariadic.map(el => {
const valueSchema = el.node.toJsonSchemaRecurse(ctx);
if (el.kind === "defaultables") {
const value = typeof el.default === "function" ? el.default() : el.default;
valueSchema.default =
$ark.intrinsic.jsonData.allows(value) ?
value
: ctx.fallback.defaultValue({
code: "defaultValue",
base: valueSchema,
value
});
}
return valueSchema;
});
// draft-07 uses items as array, draft-2020-12 uses prefixItems
if (isDraft07)
schema.items = prefixSchemas;
else
schema.prefixItems = prefixSchemas;
}
// by default JSON schema prefixElements are optional
// add minLength here if there are any required prefix elements
if (this.minLength)
schema.minItems = this.minLength;
if (this.variadic) {
const variadicItemSchema = this.variadic.toJsonSchemaRecurse(ctx);
// draft-07 uses additionalItems when items is an array (tuple),
// draft-2020-12 uses items
if (isDraft07 && this.prevariadic.length)
schema.additionalItems = variadicItemSchema;
else
schema.items = variadicItemSchema;
// maxLength constraint will be enforced by items: false
// for non-variadic arrays
if (this.maxLength)
schema.maxItems = this.maxLength;
// postfix can only be present if variadic is present so nesting this is fine
if (this.postfix) {
const elements = this.postfix.map(el => el.toJsonSchemaRecurse(ctx));
schema = ctx.fallback.arrayPostfix({
code: "arrayPostfix",
base: schema,
elements
});
}
}
else {
// For fixed-length tuples without variadic elements
// draft-07 uses additionalItems: false, draft-2020-12 uses items: false
if (isDraft07)
schema.additionalItems = false;
else
schema.items = false;
// delete maxItems constraint that will have been added by the
// base intersection node to enforce fixed length
delete schema.maxItems;
}
return schema;
}
}
const defaultableMorphsCache = {};
const getDefaultableMorphs = (node) => {
if (!node.defaultables)
return [];
const morphs = [];
let cacheKey = "[";
const lastDefaultableIndex = node.prefixLength + node.defaultablesLength - 1;
for (let i = node.prefixLength; i <= lastDefaultableIndex; i++) {
const [elementNode, defaultValue] = node.defaultables[i - node.prefixLength];
morphs.push(computeDefaultValueMorph(i, elementNode, defaultValue));
cacheKey += `${i}: ${elementNode.id} = ${defaultValueSerializer(defaultValue)}, `;
}
cacheKey += "]";
return (defaultableMorphsCache[cacheKey] ??= morphs);
};
export const Sequence = {
implementation,
Node: SequenceNode
};
const sequenceInnerToTuple = (inner) => {
const tuple = [];
if (inner.prefix)
for (const node of inner.prefix)
tuple.push({ kind: "prefix", node });
if (inner.defaultables) {
for (const [node, defaultValue] of inner.defaultables)
tuple.push({ kind: "defaultables", node, default: defaultValue });
}
if (inner.optionals)
for (const node of inner.optionals)
tuple.push({ kind: "optionals", node });
if (inner.variadic)
tuple.push({ kind: "variadic", node: inner.variadic });
if (inner.postfix)
for (const node of inner.postfix)
tuple.push({ kind: "postfix", node });
return tuple;
};
const sequenceTupleToInner = (tuple) => tuple.reduce((result, element) => {
if (element.kind === "variadic")
result.variadic = element.node;
else if (element.kind === "defaultables") {
result.defaultables = append(result.defaultables, [
[element.node, element.default]
]);
}
else
result[element.kind] = append(result[element.kind], element.node);
return result;
}, {});
export const postfixAfterOptionalOrDefaultableMessage = "A postfix required element cannot follow an optional or defaultable element";
export const postfixWithoutVariadicMessage = "A postfix element requires a variadic element";
const _intersectSequences = (s) => {
const [lHead, ...lTail] = s.l;
const [rHead, ...rTail] = s.r;
if (!lHead || !rHead)
return s;
const lHasPostfix = lTail[lTail.length - 1]?.kind === "postfix";
const rHasPostfix = rTail[rTail.length - 1]?.kind === "postfix";
const kind = lHead.kind === "prefix" || rHead.kind === "prefix" ? "prefix"
: lHead.kind === "postfix" || rHead.kind === "postfix" ? "postfix"
: lHead.kind === "variadic" && rHead.kind === "variadic" ? "variadic"
// if either operand has postfix elements, the full-length
// intersection can't include optional elements (though they may
// exist in some of the fixed length variants)
: lHasPostfix || rHasPostfix ? "prefix"
: lHead.kind === "defaultables" || rHead.kind === "defaultables" ?
"defaultables"
: "optionals";
if (lHead.kind === "prefix" && rHead.kind === "variadic" && rHasPostfix) {
const postfixBranchResult = _intersectSequences({
...s,
fixedVariants: [],
r: rTail.map(element => ({ ...element, kind: "prefix" }))
});
if (postfixBranchResult.disjoint.length === 0)
s.fixedVariants.push(postfixBranchResult);
}
else if (rHead.kind === "prefix" &&
lHead.kind === "variadic" &&
lHasPostfix) {
const postfixBranchResult = _intersectSequences({
...s,
fixedVariants: [],
l: lTail.map(element => ({ ...element, kind: "prefix" }))
});
if (postfixBranchResult.disjoint.length === 0)
s.fixedVariants.push(postfixBranchResult);
}
const result = intersectOrPipeNodes(lHead.node, rHead.node, s.ctx);
if (result instanceof Disjoint) {
if (kind === "prefix" || kind === "postfix") {
s.disjoint.push(...result.withPrefixKey(
// ideally we could handle disjoint paths more precisely here,
// but not trivial to serialize postfix elements as keys
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 }];
}
else if (kind === "optionals" || kind === "defaultables") {
// if the element result is optional and unsatisfiable, the
// intersection can still be satisfied as long as the tuple
// ends before the disjoint element would occur
return s;
}
else {
// if the element is variadic and unsatisfiable, the intersection
// can be satisfied with a fixed length variant including zero
// variadic elements
return _intersectSequences({
...s,
fixedVariants: [],
// if there were any optional elements, there will be no postfix elements
// so this mapping will never occur (which would be illegal otherwise)
l: lTail.map(element => ({ ...element, kind: "prefix" })),
r: lTail.map(element => ({ ...element, kind: "prefix" }))
});
}
}
else if (kind === "defaultables") {
if (lHead.kind === "defaultables" &&
rHead.kind === "defaultables" &&
lHead.default !== rHead.default) {
throwParseError(writeDefaultIntersectionMessage(lHead.default, rHead.default));
}
s.result = [
...s.result,
{
kind,
node: result,
default: lHead.kind === "defaultables" ? lHead.default
: rHead.kind === "defaultables" ? rHead.default
: throwInternalError(`Unexpected defaultable intersection from ${lHead.kind} and ${rHead.kind} elements.`)
}
];
}
else
s.result = [...s.result, { kind, node: result }];
const lRemaining = s.l.length;
const rRemaining = s.r.length;
if (lHead.kind !== "variadic" ||
(lRemaining >= rRemaining &&
(rHead.kind === "variadic" || rRemaining === 1)))
s.l = lTail;
if (rHead.kind !== "variadic" ||
(rRemaining >= lRemaining &&
(lHead.kind === "variadic" || lRemaining === 1)))
s.r = rTail;
return _intersectSequences(s);
};
const elementIsRequired = (el) => el.kind === "prefix" || el.kind === "postfix";

View File

@@ -0,0 +1,4 @@
import { type RegisteredReference } from "../shared/registry.ts";
export declare const arrayIndexSource = "^(?:0|[1-9]\\d*)$";
export declare const arrayIndexMatcher: RegExp;
export declare const arrayIndexMatcherReference: RegisteredReference;

View File

@@ -0,0 +1,4 @@
import { registeredReference } from "../shared/registry.js";
export const arrayIndexSource = `^(?:0|[1-9]\\d*)$`;
export const arrayIndexMatcher = new RegExp(arrayIndexSource);
export const arrayIndexMatcherReference = registeredReference(arrayIndexMatcher);

Some files were not shown because too many files have changed in this diff Show More