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

7
frontend/node_modules/@ark/schema/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,7 @@
Copyright 2025 ArkType
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

18
frontend/node_modules/@ark/schema/README.md generated vendored Normal file
View File

@@ -0,0 +1,18 @@
# @ark/schema
Underlying schema language parsed from arktype syntax.
The parts of ArkType's type system that exist in TS (i.e. not runtime-only constraints like bounds, divisors, custom predicates, morphs etc.) are structured like this:
- Union: a set of intersections
- Intersection: a set of a basis and constraints
- Basis: this is the base type to which refinements like props are applied. It is one of three things, getting narrower as you move down the list:
- Domain: `"string" | "number" | "bigint" | "object" | "symbol"` parallels built-in TS keywords for non-enumerable value sets
- Proto: Must be an `instanceof` some class (implies domain `"object"`)
- Unit: Must `===` some value (can be intersected with any other constraint and reduced to itself or a disjoint)
- Constraint: an individual condition that must be satisfied:
- Required: must have a specified literal string or symbol key and a value that conforms to a specified union or intersection
- Optional: Required conditions met or the specified key is not present
- Index: all keys that satisfy an index type must have values satisfying the corresponding value type
In this system, `L` extends/subtypes/is assignable to `R` if and only if the intersection `L & R` is equal to `L`.

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";

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