From 3319e1844bbbdf97c3d02de1cb611940eccead7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Marie=20De=20Mey?= Date: Sun, 3 Nov 2024 14:44:00 +0200 Subject: [PATCH] buildingDiamond mgt --- src/diamond.ts | 10 +-- test/construction.test.ts | 124 +++++++++++++++++++++++++------------- 2 files changed, 88 insertions(+), 46 deletions(-) diff --git a/src/diamond.ts b/src/diamond.ts index 767f87d..98c72a4 100644 --- a/src/diamond.ts +++ b/src/diamond.ts @@ -45,6 +45,7 @@ export function hasInstanceManager(cls: Class) { } function forwardTempTo(target: any, temp: any) { + if (target === temp) return Object.defineProperties(target, Object.getOwnPropertyDescriptors(temp)) for (const p of Object.getOwnPropertyNames(temp)) delete temp[p] Object.setPrototypeOf(temp, new Proxy(target, forwardProxyHandler)) @@ -84,19 +85,20 @@ export default function Diamond( built: this, strategy: buildingStrategy } // It will be set to `null` on purpose in the process and needs to be restored - const locallyStoredDiamond = buildingDiamond!.built + const locallyStoredDiamond = buildingDiamond! try { // `super()`: Builds the temporary objects and import all their properties for (const subs of responsibility) { + buildingDiamond = fLegs(subs) ? locallyStoredDiamond : null const temp = new (subs as any)(...args) // `any` because declared as an abstract class // Even if `Diamond` managed: property initializers do not go through proxy - if (locallyStoredDiamond !== temp) forwardTempTo(locallyStoredDiamond, temp) + forwardTempTo(locallyStoredDiamond.built, temp) } } finally { - if (locallyStoredDiamond !== this) forwardTempTo(locallyStoredDiamond, this) + forwardTempTo(locallyStoredDiamond.built, this) buildingDiamond = null } - return locallyStoredDiamond + return locallyStoredDiamond.built } static [Symbol.hasInstance] = hasInstanceManager(Diamond) } diff --git a/test/construction.test.ts b/test/construction.test.ts index ea53d23..49bd0e5 100644 --- a/test/construction.test.ts +++ b/test/construction.test.ts @@ -1,58 +1,57 @@ import D from '../src' import { log, logs } from './logger' -class End1 { - constructor(aValue: string) { - log('End1:', aValue) +beforeAll(() => { + logs() //make sure logs are cleared +}) +test('construction', () => { + class End1 { + constructor(aValue: string) { + log('End1:', aValue) + } } -} -class End2 { - constructor(aValue: string) { - log('End2:', aValue) - // A global value is used: test lack of interference - new Y('End2...') + class End2 { + constructor(aValue: string) { + log('End2:', aValue) + // A global value is used: test lack of interference + new Y('End2...') + } } -} -class X { - constructor(aValue: string) { - log('X:', aValue) + class X { + constructor(aValue: string) { + log('X:', aValue) + } } -} -class Y extends D(X) { - constructor(aValue: string) { - super(aValue + ' and Y') - log('Y:', aValue) + class Y extends D(X) { + constructor(aValue: string) { + super(aValue + ' and Y') + log('Y:', aValue) + } } -} -let constructedObjectFromA: any = null -class A extends D() { - constructor(aValue: string) { - super(aValue + ' and A') - constructedObjectFromA = this - log('A:', aValue) + let constructedObjectFromA: any = null + class A extends D() { + constructor(aValue: string) { + super(aValue + ' and A') + constructedObjectFromA = this + log('A:', aValue) + } } -} -class B extends D(End2, A) { - constructor(aValue: string) { - super(aValue + ' and B') - log('B:', aValue) - new Y('B...') + class B extends D(End2, A) { + constructor(aValue: string) { + super(aValue + ' and B') + log('B:', aValue) + new Y('B...') + } } -} -class C extends D(B, End1, A) { - constructor(aValue: string) { - super(aValue + ' and C') - log('C:', aValue) + class C extends D(B, End1, A) { + constructor(aValue: string) { + super(aValue + ' and C') + log('C:', aValue) + } } -} - -beforeAll(() => { - logs() //make sure logs are cleared -}) -test('construction', () => { const c = new C('X') expect(logs()).toEqual([ 'End1: X and C and B and A', @@ -67,3 +66,44 @@ test('construction', () => { ]) expect(c).toBe(constructedObjectFromA) }) + +test('sub-diamond', () => { + class X extends D() { + constructor() { + const o = new Object() + super() + } + } + class Y { + x1: X = new X() + x2: any + + constructor() { + this.x2 = new X() + } + } + class A extends D(Y) { + y1: Y = new Y() + y2: any + constructor() { + super() + //this.x2 = new X() + this.y2 = new Y() + } + } + const a = new A() + const distinct: any = { + a: a, + //aX1: a.x1, + //aX2: a.x2, + aY1X1: a.y1.x1, + aY1X2: a.y1.x2, + aY2X1: a.y2.x1, + aY2X2: a.y2.x2 + }, + distinctMap = new Map() + for (let k in distinct) { + expect(distinctMap.has(distinct[k]) && k + '=' + distinctMap.get(distinct[k])).toBe(false) + distinctMap.set(distinct[k], k) + } +})