diff --git a/README.md b/README.md index 4ddfc8f..cbf523c 100644 --- a/README.md +++ b/README.md @@ -103,15 +103,9 @@ When constructing `Xb`, the constructor of `B` will be invoked with `this` being We can of course `extend Diamond(A, B, C, D, E, ...theRest)`. -### `instanceof` does not work anymore! +### `instanceof` does not work anymore!? -It still works. Well, it indeed works - but only if the class being tested is a `Diamond` one (if it inherits from `Diamond(...)` or if one of its direct ancestor does). - -If not, there is a helper function for the super-generic case. - -```ts -import Diamond, { instanceOf } from 'flat-diamond' -``` +Yes, it does. Classes involved in the `Diamond` process even have their `[Symbol.hasInstance]` overridden in order to be sure. ### But I modify my prototypes dynamically... @@ -134,6 +128,11 @@ Here, the flat legacy of `D2` will be `D1 - X1 - X3 - X2 - X4`. The fact that `D A real order conflict would imply circular reference who is impossible. +> For the details if interested - using the vertical analogy that "classes are built upon an ancestor" (high=descendant) : +> +> - Inheritance is promised (if a class is built upon another one, it will appear higher in the flat legacy) +> - When two classes are given in a list (knowing each classes are flat lineage), the highest class of the first lineage will appear before the lowest class of the second one. + ### Dealing with non-`Diamond`-ed classes ```ts @@ -187,6 +186,10 @@ D2(0) X2(2) ``` +#### Non diamond vs diamond constructors + +> Diamond' constructors du not really matter if a class is "descendant" somehow in the 2D hierarchy, only in the 1D (flat) one. It means that any constructor transforming the arguments transform it for _all_ the classes that comes afterward in the flat hierarchy. Thus, classes that are no `Diamond`ed will not modify the constructor' arguments, but only for their direct descendants. Also, if their descendants appear twice (inherited directly twice in the hierarchy), their constructors will be called twice, each time for each argument. + ### Construction concern Building another diamond in the constructor before calling `super(...)` will break the game. (Fields are initialized when `super` returns - no worries there) diff --git a/src/helpers.ts b/src/helpers.ts deleted file mode 100644 index 0fd5796..0000000 --- a/src/helpers.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Ctor } from './types' -import { fLegs } from './utils' - -/** - * `instanceof` substitute for diamonds - * @param obj Object to test - * @param ctor Class to test - * @returns If by a mean or another, `obj` is an instance of `ctor` - */ -export function instanceOf(obj: any, ctor: Ctor) { - if (obj instanceof ctor) return true - if (!obj || typeof obj !== 'object') return false - - for (const base of fLegs(obj.constructor) || []) - if (base === ctor || base.prototype instanceof ctor) return true - return false -} diff --git a/src/index.ts b/src/index.ts index 80248b4..d238f20 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ import Diamond from './diamond' export default Diamond -export * from './helpers' export * from './seclude' export * from './types' diff --git a/test/abcd.test.ts b/test/abcd.test.ts index cd4c2cb..2ff2df5 100644 --- a/test/abcd.test.ts +++ b/test/abcd.test.ts @@ -2,7 +2,7 @@ import Diamond from '../src' import { log, logs } from './logger' abstract class A { - constructor() { + constructor(public arg: string) { this.log('construct A') } log(...args: any[]) { @@ -16,8 +16,8 @@ abstract class A { abstract absFunc(x: number): number } abstract class B extends Diamond(A) { - constructor() { - super() + constructor(arg: string) { + super(arg + 'B') this.log('construct B') } absFunc(x: number): number { @@ -30,8 +30,8 @@ abstract class B extends Diamond(A) { } } abstract class C extends Diamond(A) { - constructor() { - super() + constructor(arg: string) { + super(arg + 'C') this.log('construct C') } fieldC = true @@ -42,8 +42,8 @@ abstract class C extends Diamond(A) { } //@ts-expect-error Here, if D extends diamond(B, C), then it's not considered abstract - cf README.md#abstraction class D extends Diamond(C, B) { - constructor() { - super() + constructor(arg: string) { + super(arg + 'D') this.log('construct D') } fieldD = true @@ -58,7 +58,7 @@ beforeEach(() => { }) test('call orders', () => { - const obj = new D() + const obj = new D('o') expect(logs()).toEqual([ '[class=A] construct A', '[class=D] construct B', @@ -67,6 +67,7 @@ test('call orders', () => { ]) expect([obj.fieldA, obj.fieldB, obj.fieldC, obj.fieldD]).toEqual([true, true, true, true]) expect(obj.func(0)).toBe(6) + expect(obj.arg).toBe('oDCB') expect(logs()).toEqual([ '[class=D] func D', '[class=D] func C', diff --git a/test/instanceOf.test.ts b/test/instanceOf.test.ts index 8bd238a..514f4c2 100644 --- a/test/instanceOf.test.ts +++ b/test/instanceOf.test.ts @@ -1,4 +1,4 @@ -import D, { instanceOf, Seclude } from '../src' +import D, { Seclude } from '../src' class A1 {} class A2 extends A1 {} class B1 {} @@ -15,7 +15,6 @@ const x1 = new X1(), x2 = new X2() test('instanceof', () => { - /* expect(x1 instanceof X1).toBe(true) expect(x1 instanceof X2).toBe(false) expect(x2 instanceof X1).toBe(false) @@ -25,7 +24,7 @@ test('instanceof', () => { expect(x1 instanceof B1).toBe(true) expect(x1 instanceof C1).toBe(false) expect(x2 instanceof A1).toBe(true) - expect(x2 instanceof B1).toBe(true)*/ + expect(x2 instanceof B1).toBe(true) expect(x2 instanceof A2).toBe(false) expect(x2 instanceof B2).toBe(false) expect(x2 instanceof C1).toBe(true)