Files
headroom/frontend/node_modules/@ark/schema/out/node.js
Santhosh Janardhanan de2d83092e 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
2026-02-17 16:19:59 -05:00

439 lines
18 KiB
JavaScript

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)
});