- 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
116 lines
4.7 KiB
JavaScript
116 lines
4.7 KiB
JavaScript
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
|
|
};
|