Files
headroom/frontend/node_modules/@ark/util/out/traits.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

76 lines
2.8 KiB
JavaScript

import { hasDomain } from "./domain.js";
import { noSuggest } from "./errors.js";
import { ancestorsOf } from "./objectKinds.js";
import { NoopBase } from "./records.js";
// even though the value we attach will be identical, we use this so classes
// won't be treated as instanceof a Trait
const implementedTraits = noSuggest("implementedTraits");
export const hasTrait = (traitClass) => (o) => {
if (!hasDomain(o, "object"))
return false;
if (implementedTraits in o.constructor &&
o.constructor[implementedTraits].includes(traitClass))
return true;
// emulate standard instanceof behavior
return ancestorsOf(o).includes(traitClass);
};
/** @ts-ignore required to extend NoopBase */
export class Trait extends NoopBase {
static get [Symbol.hasInstance]() {
return hasTrait(this);
}
traitsOf() {
return implementedTraits in this.constructor ?
this.constructor[implementedTraits]
: [];
}
}
const collectPrototypeDescriptors = (trait) => {
let proto = trait.prototype;
let result = {};
do {
// ensure prototypes are sorted from lowest to highest precedence
result = Object.assign(Object.getOwnPropertyDescriptors(proto), result);
proto = Object.getPrototypeOf(proto);
} while (proto !== Object.prototype && proto !== null);
return result;
};
export const compose = ((...traits) => {
const base = function (...args) {
for (const trait of traits) {
const instance = Reflect.construct(trait, args, this.constructor);
Object.assign(this, instance);
}
};
const flatImplementedTraits = [];
for (const trait of traits) {
// copy static properties
Object.assign(base, trait);
// flatten and copy prototype
Object.defineProperties(base.prototype, collectPrototypeDescriptors(trait));
if (implementedTraits in trait) {
// add any ancestor traits from which the current trait was composed
for (const innerTrait of trait[implementedTraits]) {
if (!flatImplementedTraits.includes(innerTrait))
flatImplementedTraits.push(innerTrait);
}
}
if (!flatImplementedTraits.includes(trait))
flatImplementedTraits.push(trait);
}
Object.defineProperty(base, implementedTraits, {
value: flatImplementedTraits,
enumerable: false
});
return base;
});
export const implement = (...args) => {
if (args[args.length - 1] instanceof Trait)
return compose(...args);
const implementation = args[args.length - 1];
const base = compose(...args.slice(0, -1));
// copy implementation last since it overrides traits
Object.defineProperties(base.prototype, Object.getOwnPropertyDescriptors(implementation));
return base;
};