Socket
Socket
Sign inDemoInstall

@arktype/util

Package Overview
Dependencies
Maintainers
1
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@arktype/util - npm Package Compare versions

Comparing version 0.0.10 to 0.0.11

66

__tests__/traits.test.ts

@@ -72,2 +72,68 @@ import { attest } from "@arktype/attest"

})
it("works with subclasses", () => {
abstract class Foo extends Boundable<number> {
getFoo() {
return "foo"
}
}
class Bar extends compose(Foo) {
sizeOf(data: number) {
return data
}
}
const b = new Bar({ limit: 2 })
attest(b.check(1)).equals(true)
attest(b.check(3)).equals(false)
attest(b.getFoo()).equals("foo")
})
it("preserves static", () => {
abstract class A extends Trait {
static readonly a = "a"
readonly a = "a"
}
abstract class B extends Trait {
static readonly b = "b"
readonly b = "b"
}
class C extends compose(A, B) {
static readonly c = "c"
readonly c = "c"
}
attest<"a">(C.a).equals("a")
attest<"b">(C.b).equals("b")
attest<"c">(C.c).equals("c")
const c = new C()
attest<"a">(c.a).equals("a")
attest<"b">(c.b).equals("b")
attest<"c">(c.c).equals("c")
})
it("trait from trait", () => {
abstract class A extends Trait {
readonly a = "a"
}
abstract class B extends Trait {
readonly b = "b"
}
class C extends compose(A, B) {
readonly c = "c"
}
class D extends Trait {
readonly d = "d"
}
class E extends compose(C, D) {
readonly e = "e"
}
const e = new E()
attest<"a">(e.a).equals("a")
attest<"b">(e.b).equals("b")
attest<"c">(e.c).equals("c")
attest<"d">(e.d).equals("d")
attest<"e">(e.e).equals("e")
attest(e.traitsOf()).equals([A, B, C, D])
})
})

12

out/traits.d.ts
import type { intersectParameters } from "./intersections.js";
import type { Constructor } from "./objectKinds.js";
export type TraitComposition = <traits extends readonly Constructor[]>(...traits: traits) => compose<traits>;
export declare const traitsOf: unique symbol;
export declare abstract class Trait {
static [Symbol.hasInstance](o: any): boolean;
static [Symbol.hasInstance](o: object): boolean;
traitsOf(): readonly Function[];
}
export declare const compose: TraitComposition;
export type compose<traits extends readonly Constructor[]> = composeRecurse<traits, [
], {}>;
export type composeRecurse<traits extends readonly unknown[], parameters extends readonly unknown[], instance extends {}> = traits extends readonly [
], {}, {}>;
export type composeRecurse<traits extends readonly unknown[], parameters extends readonly unknown[], statics extends {}, instance extends {}> = traits extends readonly [
abstract new (...args: infer nextArgs) => infer nextInstance,
...infer tail
] ? composeRecurse<tail, intersectParameters<parameters, nextArgs>, instance & nextInstance> : abstract new (...args: parameters) => instance;
] ? composeRecurse<tail, intersectParameters<parameters, nextArgs>, statics & {
[k in keyof traits[0]]: traits[0][k];
}, instance & nextInstance> : statics & (abstract new (...args: parameters) => instance);
//# sourceMappingURL=traits.d.ts.map

@@ -1,6 +0,14 @@

export const traitsOf = Symbol("hasTraits");
// even though the value we attach will be identical, we use this so classes
// won't be treated as instanceof a Trait
const implementedTraits = Symbol("implementedTraits");
export class Trait {
static [Symbol.hasInstance](o) {
return Array.isArray(o[traitsOf]) && o[traitsOf].includes(this);
return (implementedTraits in o.constructor &&
o.constructor[implementedTraits].includes(this));
}
traitsOf() {
return implementedTraits in this.constructor
? this.constructor[implementedTraits]
: [];
}
}

@@ -18,13 +26,38 @@ const collectPrototypeDescriptors = (trait) => {

export const compose = ((...traits) => {
if (traits.length === 0) {
return Object;
}
if (traits.length === 1) {
return traits[0];
}
const base = function (...args) {
for (const trait of traits) {
Object.assign(this, Reflect.construct(trait, args, this.constructor));
const instance = Reflect.construct(trait, args, this.constructor);
Object.assign(this, instance);
}
Object.defineProperty(this, traitsOf, { value: traits, enumerable: false });
};
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;
});
//# sourceMappingURL=traits.js.map
{
"name": "@arktype/util",
"version": "0.0.10",
"version": "0.0.11",
"author": {

@@ -5,0 +5,0 @@ "name": "David Blass",

@@ -8,8 +8,19 @@ import type { intersectParameters } from "./intersections.js"

export const traitsOf = Symbol("hasTraits")
// even though the value we attach will be identical, we use this so classes
// won't be treated as instanceof a Trait
const implementedTraits = Symbol("implementedTraits")
export abstract class Trait {
static [Symbol.hasInstance](o: any) {
return Array.isArray(o[traitsOf]) && o[traitsOf].includes(this)
static [Symbol.hasInstance](o: object) {
return (
implementedTraits in o.constructor &&
(o.constructor[implementedTraits] as Function[]).includes(this)
)
}
traitsOf(): readonly Function[] {
return implementedTraits in this.constructor
? (this.constructor[implementedTraits] as Function[])
: []
}
}

@@ -30,12 +41,36 @@

export const compose = ((...traits: Function[]) => {
if (traits.length === 0) {
return Object
}
if (traits.length === 1) {
return traits[0]
}
const base: any = function (this: any, ...args: any[]) {
for (const trait of traits) {
Object.assign(this, Reflect.construct(trait, args, this.constructor))
const instance = Reflect.construct(trait, args, this.constructor)
Object.assign(this, instance)
}
Object.defineProperty(this, traitsOf, { value: traits, enumerable: false })
}
const flatImplementedTraits: Function[] = []
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] as Function[]) {
if (!flatImplementedTraits.includes(innerTrait)) {
flatImplementedTraits.push(innerTrait)
}
}
}
if (!flatImplementedTraits.includes(trait)) {
flatImplementedTraits.push(trait)
}
}
Object.defineProperty(base, implementedTraits, {
value: flatImplementedTraits,
enumerable: false
})
return base

@@ -47,2 +82,3 @@ }) as TraitComposition

[],
{},
{}

@@ -54,2 +90,3 @@ >

parameters extends readonly unknown[],
statics extends {},
instance extends {}

@@ -63,4 +100,5 @@ > = traits extends readonly [

intersectParameters<parameters, nextArgs>,
statics & { [k in keyof traits[0]]: traits[0][k] },
instance & nextInstance
>
: abstract new (...args: parameters) => instance
: statics & (abstract new (...args: parameters) => instance)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc