From c13a33e64237c9013cc56ed4be5a27e6467edd24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 27 May 2026 14:10:51 +0200 Subject: [PATCH 01/34] Renmae ParentType to --- .../shallow/re-tree-parent-container.ts | 16 ++++++++-------- .../container/tree/re-tree-children-container.ts | 2 +- .../container/tree/re-tree-list-container.ts | 4 ++-- .../container/tree/re-tree-single-container.ts | 4 ++-- .../referencing/referencable/referenceable.ts | 2 +- .../src/lib/serialization/json-deserializable.ts | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index db64e8b..a151b23 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -7,29 +7,29 @@ import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; export class ReTreeParentContainer> - extends ReContainer -implements ReSingleInterface, - ReShallowInterface{ + extends ReContainer +implements ReSingleInterface, + ReShallowInterface{ constructor(parent: T, referenceName: string, refMeta: ReferenceMeta) { super(parent, referenceName, refMeta); // referenceName is actually unused for this container type } - get(): T["ParentType"] | undefined { - return (this._parent.getParentReferencable() as T["ParentType"]) + get(): T["$ParentType"] | undefined { + return (this._parent.getParentReferencable() as T["$ParentType"]) } //todo rewrite without using item parent explicitly? - addWithoutTypeCheck(item: T["ParentType"]): boolean { + addWithoutTypeCheck(item: T["$ParentType"]): boolean { let me: T = this._parent const currentParentCont = this._parent.parent if(currentParentCont != undefined) { - currentParentCont.remove(this._parent as T["ParentType"], DeletionMode.RELAXED) + currentParentCont.remove(this._parent as T["$ParentType"], DeletionMode.RELAXED) } return item.addToReferencableContainer(this.inverseName, me) } - remove(item: T["ParentType"], mode: DeletionMode = DeletionMode.RELAXED): boolean { + remove(item: T["$ParentType"], mode: DeletionMode = DeletionMode.RELAXED): boolean { return item.removeFromReferencableContainer(this.inverseName, this._parent, mode) } diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts index d0c1039..d5060f1 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts @@ -6,7 +6,7 @@ import {JsonOf} from "../../../../serialization/json-deserializable"; export interface ReTreeChildrenContainer< T extends Referencable, -> extends ReContainer { +> extends ReContainer { // serialization assignRefs(ctx: SerializationContext, path: string) : void diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 640ece0..151c8a6 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -10,12 +10,12 @@ import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; export class ReTreeListContainer> - extends ReListContainer + extends ReListContainer implements ReTreeChildrenContainer { readonly defaultEClass?: string; - constructor(parent: T["ParentType"], name: string, refMeta: ReferenceMeta, eClass?: string) { + constructor(parent: T["$ParentType"], name: string, refMeta: ReferenceMeta, eClass?: string) { super(parent, name, refMeta); this.defaultEClass = eClass; this._parent.$treeChildren.push(this) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 702d1de..1978ffd 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -9,12 +9,12 @@ import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; export class ReTreeSingleContainer> - extends ReSingleContainer + extends ReSingleContainer implements ReTreeChildrenContainer { readonly defaultEClass?: string; - constructor(parent: T["ParentType"], referenceName: string, refMeta: ReferenceMeta, eClass?: string) { + constructor(parent: T["$ParentType"], referenceName: string, refMeta: ReferenceMeta, eClass?: string) { super(parent, referenceName, refMeta); this.defaultEClass = eClass; this._parent.$treeChildren.push(this) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 2e099a0..004d49b 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -22,7 +22,7 @@ export abstract class Referencable< $gId: string; //graphical ID - declare readonly ParentType: Parent; + declare readonly $ParentType: Parent; declare $classMeta: ClassMeta; declare $modelUri: string; //now inside modelMeta diff --git a/projects/emfular/src/lib/serialization/json-deserializable.ts b/projects/emfular/src/lib/serialization/json-deserializable.ts index 2db955f..e7e8c40 100644 --- a/projects/emfular/src/lib/serialization/json-deserializable.ts +++ b/projects/emfular/src/lib/serialization/json-deserializable.ts @@ -10,7 +10,7 @@ type IsReferencable = T extends Referencable ? true : false; type IsReferenceProp = - K extends "ParentType" ? false : + K extends "$ParentType" ? false : T extends object ? T extends MetaAwareModelList ? true : T extends SingleRef @@ -37,7 +37,7 @@ type StartsWithPrivate = type AttributeKeys = { [K in keyof T]: - K extends "ParentType" ? never : + K extends "$ParentType" ? never : StartsWithPrivate extends true ? never : T[K] extends Function ? never : IsReferenceProp extends true ? never : From b0e7a00cb3f56e461a225cb076aaca88aad077a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 27 May 2026 14:16:16 +0200 Subject: [PATCH 02/34] Replace internal $parent with _$, and also accessor parent with $ --- .../shallow/re-tree-parent-container.ts | 2 +- .../container/tree/re-tree-list-container.ts | 2 +- .../container/tree/re-tree-single-container.ts | 2 +- .../referencing/referencable/referenceable.ts | 16 ++++++++-------- .../test/re-containers-with-single-child.spec.ts | 6 +++--- projects/emfular/src/lib/utils/list-updater.ts | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index a151b23..8bfc2fd 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -22,7 +22,7 @@ implements ReSingleInterface, //todo rewrite without using item parent explicitly? addWithoutTypeCheck(item: T["$ParentType"]): boolean { let me: T = this._parent - const currentParentCont = this._parent.parent + const currentParentCont = this._parent.$parent if(currentParentCont != undefined) { currentParentCont.remove(this._parent as T["$ParentType"], DeletionMode.RELAXED) } diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 151c8a6..2c856b9 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -36,7 +36,7 @@ implements ReTreeChildrenContainer { //todo rewrite without using item parent explicitly? addWithoutTypeCheck(item: T): boolean { - const oldParent = item.parent; + const oldParent = item.$parent; if(oldParent == this) { return false; } else { diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 1978ffd..e50700c 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -57,7 +57,7 @@ implements ReTreeChildrenContainer { if (mode === DeletionMode.CASCADE) { this._instance?.destruct(mode) } else if (mode === DeletionMode.RELAXED) { - this._instance?.parent?.remove(this._instance, mode) + this._instance?.$parent?.remove(this._instance, mode) } } diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 004d49b..28a613a 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -28,7 +28,7 @@ export abstract class Referencable< declare $modelUri: string; //now inside modelMeta declare $modelMeta: ModelDefinition; - private $parent?: ReTreeChildrenContainer; + private _$parent?: ReTreeChildrenContainer; readonly $treeChildren: ReTreeChildrenContainer[] = []; readonly $otherReferences: ReLinkContainer[] = []; @@ -49,18 +49,18 @@ export abstract class Referencable< } setParent(parent: ReTreeChildrenContainer | undefined) { - if(this.$parent) { - this.$parent.remove(this) + if(this._$parent) { + this._$parent.remove(this) } - this.$parent = parent; + this._$parent = parent; } - get parent(): ReTreeChildrenContainer | undefined { - return this.$parent + get $parent(): ReTreeChildrenContainer | undefined { + return this._$parent } getParentReferencable(): Parent | undefined { - return this.$parent?._parent + return this._$parent?._parent } getEClass(): string { @@ -78,7 +78,7 @@ export abstract class Referencable< destruct(mode: DeletionMode = DeletionMode.RELAXED) { // removal from parent is always called with deletion mode RELAXED, otherwise infinite loops occur (see remove in re-tree-list/single-container.ts) // tests in files re-link-list/single-container.spec.ts and re-tree-list/single-container.spec.ts fail when not setting RELAXED mode explicitly - this.$parent?.remove(this, DeletionMode.RELAXED) + this._$parent?.remove(this, DeletionMode.RELAXED) this.$otherReferences.forEach(refContainer => { refContainer.removeFromInverse(this, mode) }) diff --git a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts index f2c1246..1eff08f 100644 --- a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts +++ b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts @@ -23,14 +23,14 @@ describe('ReContainersWithSingleChild tests', () => { it('should manage parent pointers correctly', () => { const root: ReContainersWithSingleChild = new ReContainersWithSingleChild(); - expect(root.parent).toBeUndefined() + expect(root.$parent).toBeUndefined() expect(root.child).toBeUndefined() const child: ReSingleChildExample = new ReSingleChildExample(); expect(child.myParent).toBeUndefined() - expect(child.parent).toBeUndefined() + expect(child.$parent).toBeUndefined() //set tree parent: child.myParent = root; - expect(child.parent).toBeDefined() + expect(child.$parent).toBeDefined() expect(child.myParent).toEqual(root); expect(root.child).toBe(child); diff --git a/projects/emfular/src/lib/utils/list-updater.ts b/projects/emfular/src/lib/utils/list-updater.ts index a09400d..5d9366a 100644 --- a/projects/emfular/src/lib/utils/list-updater.ts +++ b/projects/emfular/src/lib/utils/list-updater.ts @@ -31,7 +31,7 @@ export class ListUpdater { if (mode === DeletionMode.CASCADE) { list[0].destruct(mode) } else if (mode === DeletionMode.RELAXED) { - list[0].parent?.remove(list[0], mode) + list[0].$parent?.remove(list[0], mode) } } } From e071277180b0deb6735c31f0322d47b06a72557e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 27 May 2026 14:22:04 +0200 Subject: [PATCH 03/34] change setParent to real setter --- .../referencable/container/tree/re-tree-list-container.ts | 4 ++-- .../referencable/container/tree/re-tree-single-container.ts | 4 ++-- .../emfular/src/lib/referencing/referencable/referenceable.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 2c856b9..2a9bab6 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -40,7 +40,7 @@ implements ReTreeChildrenContainer { if(oldParent == this) { return false; } else { - item.setParent(this); + item.$parent = this; oldParent?.remove(item) return ListUpdater.addToListIfMissing(item, this._instance) } @@ -58,7 +58,7 @@ implements ReTreeChildrenContainer { } let removed = ListUpdater.removeFromList(item, this._instance) if(removed){ - item.setParent(undefined); + item.$parent = undefined; return true } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index e50700c..fb5950f 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -32,7 +32,7 @@ implements ReTreeChildrenContainer { if(item == this._instance) { return false; } else { - item.setParent(this); + item.$parent = this; this._instance = item; return true; } @@ -42,7 +42,7 @@ implements ReTreeChildrenContainer { if(this._instance == item) { if (mode === DeletionMode.RELAXED) { this._instance = undefined; - item.setParent(undefined); + item.$parent = undefined; return true; } // if remove is called on an items parent the CASCADE mode would cause an infinite loop, diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 28a613a..b0a17b8 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -48,7 +48,7 @@ export abstract class Referencable< } } - setParent(parent: ReTreeChildrenContainer | undefined) { + set $parent(parent: ReTreeChildrenContainer | undefined) { if(this._$parent) { this._$parent.remove(this) } From c00ba184dc8ba8c815323173922f7d2789a153d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 27 May 2026 14:55:10 +0200 Subject: [PATCH 04/34] Prefix more methods with $, only toJson() should stay without prefix and not hidden behind a symbol --- .../referencable/container/hide/list-proxy.ts | 2 +- .../container/link/re-link-single-container.ts | 2 +- .../referencable/container/re-container.ts | 2 +- .../container/shallow/re-tree-parent-container.ts | 2 +- .../container/tree/re-tree-list-container.ts | 2 +- .../container/tree/re-tree-single-container.ts | 4 ++-- .../lib/referencing/referencable/referenceable.ts | 12 ++++++------ projects/emfular/src/lib/utils/list-updater.ts | 2 +- .../src/lib/details/tree-details-service.ts | 2 +- .../src/lib/details/tree-model-details.service.ts | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/hide/list-proxy.ts b/projects/emfular/src/lib/referencing/referencable/container/hide/list-proxy.ts index 4040b29..62f3641 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/hide/list-proxy.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/hide/list-proxy.ts @@ -286,7 +286,7 @@ export function createListProxy< const index = Number(prop); const arr = container.get(); if (index < arr.length) { - arr[index].destruct(); + arr[index].$destruct(); return true; } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts index 7cb2fec..7d59e9f 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts @@ -49,7 +49,7 @@ implements ReLinkContainer { } override delete(mode: DeletionMode = DeletionMode.RELAXED) { - this._instance?.destruct(mode) + this._instance?.$destruct(mode) } removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { diff --git a/projects/emfular/src/lib/referencing/referencable/container/re-container.ts b/projects/emfular/src/lib/referencing/referencable/container/re-container.ts index 5cb5d5d..0a6864c 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/re-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/re-container.ts @@ -48,7 +48,7 @@ export abstract class ReContainer< abstract remove(item: T, mode?: DeletionMode): boolean; - //called to destruct all elements in the container (e.g. when destroying a parent + //called to $destruct all elements in the container (e.g. when destroying a parent abstract delete(mode?: DeletionMode): void abstract toJson(ctx: SerializationContext): any diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index 8bfc2fd..ab5c05b 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -16,7 +16,7 @@ implements ReSingleInterface, } get(): T["$ParentType"] | undefined { - return (this._parent.getParentReferencable() as T["$ParentType"]) + return (this._parent.$getParentReferencable() as T["$ParentType"]) } //todo rewrite without using item parent explicitly? diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 2a9bab6..2d5950b 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -51,7 +51,7 @@ implements ReTreeChildrenContainer { if (this._instance.indexOf(item) > -1) { // if remove is called on an items parent the CASCADE mode would cause an infinite loop, // however this can be easily avoided since parent removal does not require any kind of following cascading deletes - item.destruct(mode); + item.$destruct(mode); return true; } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index fb5950f..1a3461e 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -47,7 +47,7 @@ implements ReTreeChildrenContainer { } // if remove is called on an items parent the CASCADE mode would cause an infinite loop, // however this can be easily avoided since parent removal does not require any kind of following cascading deletes - this._instance?.destruct(mode); + this._instance?.$destruct(mode); return true; } return false; @@ -55,7 +55,7 @@ implements ReTreeChildrenContainer { delete(mode: DeletionMode = DeletionMode.RELAXED) { if (mode === DeletionMode.CASCADE) { - this._instance?.destruct(mode) + this._instance?.$destruct(mode) } else if (mode === DeletionMode.RELAXED) { this._instance?.$parent?.remove(this._instance, mode) } diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index b0a17b8..7701e55 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -59,23 +59,23 @@ export abstract class Referencable< return this._$parent } - getParentReferencable(): Parent | undefined { + $getParentReferencable(): Parent | undefined { return this._$parent?._parent } - getEClass(): string { + $getEClass(): string { return ModelRegistry.getEClassForInstance(this) } assignRefs(ctx: SerializationContext, path: string) { - const ref: Ref = RefHandler.createRef(path, this.getEClass()) + const ref: Ref = RefHandler.createRef(path, this.$getEClass()) ctx.put(this, ref) for(let child of this.$treeChildren) { child.assignRefs(ctx, path) } } - destruct(mode: DeletionMode = DeletionMode.RELAXED) { + $destruct(mode: DeletionMode = DeletionMode.RELAXED) { // removal from parent is always called with deletion mode RELAXED, otherwise infinite loops occur (see remove in re-tree-list/single-container.ts) // tests in files re-link-list/single-container.spec.ts and re-tree-list/single-container.spec.ts fail when not setting RELAXED mode explicitly this._$parent?.remove(this, DeletionMode.RELAXED) @@ -124,7 +124,7 @@ export abstract class Referencable< if (result && mode === DeletionMode.CASCADE && container.isRequired) { const instance = container.get() if (instance === undefined || (Array.isArray(instance) && instance.length === 0)) { - container._parent.destruct(mode) + container._parent.$destruct(mode) } } return result @@ -134,7 +134,7 @@ export abstract class Referencable< const ctx = ctxOPt ? ctxOPt : new SerializationContext(this) //todo: this creates one assuming that the current element is root, once we have all parent pointers we can walk up first and then start const json: any = {}; - json["eClass"] = this.getEClass(); //todo not always necessary + json["eClass"] = this.$getEClass(); //todo not always necessary this.attributesToJson(json); this.refContainersToJson(json, ctx); diff --git a/projects/emfular/src/lib/utils/list-updater.ts b/projects/emfular/src/lib/utils/list-updater.ts index 5d9366a..945872d 100644 --- a/projects/emfular/src/lib/utils/list-updater.ts +++ b/projects/emfular/src/lib/utils/list-updater.ts @@ -29,7 +29,7 @@ export class ListUpdater { static destructAllFromChangingList>(list: T[], mode: DeletionMode) { while(list?.length > 0){ if (mode === DeletionMode.CASCADE) { - list[0].destruct(mode) + list[0].$destruct(mode) } else if (mode === DeletionMode.RELAXED) { list[0].$parent?.remove(list[0], mode) } diff --git a/projects/ngx-emfular-integration/src/lib/details/tree-details-service.ts b/projects/ngx-emfular-integration/src/lib/details/tree-details-service.ts index 685403d..277130b 100644 --- a/projects/ngx-emfular-integration/src/lib/details/tree-details-service.ts +++ b/projects/ngx-emfular-integration/src/lib/details/tree-details-service.ts @@ -10,7 +10,7 @@ export interface TreeDetailsService> { modelService: ModelService ): void // instead of opening the generic ModeldetailsCompoennt you might like to consider opening a specific one - //by determining the eClass and switching based on elem.getEClass() + //by determining the eClass and switching based on elem.$getEClass() openModelChoice( modelService: ModelService diff --git a/projects/ngx-emfular-integration/src/lib/details/tree-model-details.service.ts b/projects/ngx-emfular-integration/src/lib/details/tree-model-details.service.ts index a156e8b..34d04fe 100644 --- a/projects/ngx-emfular-integration/src/lib/details/tree-model-details.service.ts +++ b/projects/ngx-emfular-integration/src/lib/details/tree-model-details.service.ts @@ -20,7 +20,7 @@ export class TreeModelDetailsService> implements Tre T extends Referencable >(elem: T, modelService: ModelService) { // instead of opening the generic ModeldetailsCompoennt you might like to consider opening a specific one - //by determining the eClass and switching based on elem.getEClass() + //by determining the eClass and switching based on elem.$getEClass() const overlayRef = this.overlay.create( { hasBackdrop: true, From d773ee831623134f0d2c5cc18c8a404589a5868b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 27 May 2026 15:23:46 +0200 Subject: [PATCH 05/34] Make another private method private, also define not exported symbol for first one --- .../src/lib/referencing/referencable/referenceable.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 7701e55..e31b4f2 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -13,6 +13,10 @@ import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; +//private, no export +const INIT_REFERENCES = Symbol("initReferences"); + + /** base class for CORE models. * */ @@ -35,10 +39,10 @@ export abstract class Referencable< protected constructor() { this.$gId = uuidv4(); - this.initReferences() + this[INIT_REFERENCES]() } - private initReferences() { + private [INIT_REFERENCES]() { const proto = Object.getPrototypeOf(this); const inits = proto.__referenceInitializers; if (inits) { @@ -87,7 +91,7 @@ export abstract class Referencable< }) } - protected getContainer>(refName: string): ReContainer { + private getContainer>(refName: string): ReContainer { let proto: any = Object.getPrototypeOf(this); let meta: ReferenceMeta | undefined; From f4822443ddee400be8d88b7e60a4f5f4cf58796e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 27 May 2026 15:46:55 +0200 Subject: [PATCH 06/34] All private methods are only via private symbols now --- .../referencing/referencable/referenceable.ts | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index e31b4f2..d52d2d1 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -14,7 +14,10 @@ import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-def import {DeletionMode} from "../../utils/deletion-mode"; //private, no export -const INIT_REFERENCES = Symbol("initReferences"); +const INIT_REFERENCES = Symbol("initReferences"); +const GET_CONTAINER = Symbol("getContainer"); +const REFERENCES_TO_JSON = Symbol("referenceToJson"); +const ATTRIBUTES_TO_JSON = Symbol("attributesToJson"); /** base class for CORE models. @@ -91,7 +94,7 @@ export abstract class Referencable< }) } - private getContainer>(refName: string): ReContainer { + private [GET_CONTAINER]>(refName: string): ReContainer { let proto: any = Object.getPrototypeOf(this); let meta: ReferenceMeta | undefined; @@ -119,11 +122,11 @@ export abstract class Referencable< } public addToReferencableContainer>(name: string, item: T): boolean { - return this.getContainer(name).add(item) + return this[GET_CONTAINER](name).add(item) } public removeFromReferencableContainer>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { - let container = this.getContainer(name) + let container = this[GET_CONTAINER](name) let result = container.remove(item, mode) if (result && mode === DeletionMode.CASCADE && container.isRequired) { const instance = container.get() @@ -139,21 +142,20 @@ export abstract class Referencable< //todo: this creates one assuming that the current element is root, once we have all parent pointers we can walk up first and then start const json: any = {}; json["eClass"] = this.$getEClass(); //todo not always necessary - this.attributesToJson(json); - this.refContainersToJson(json, ctx); + this[ATTRIBUTES_TO_JSON](json); + this[REFERENCES_TO_JSON](json, ctx); return json as JsonOf; } - private refContainersToJson(json: any, ctx: SerializationContext) { - this.$treeChildren.forEach(child => { - const jsc = child.toJson(ctx) - if (jsc != undefined && !(Array.isArray(jsc) && jsc.length == 0)) { - json[child.referenceName] = jsc - } - }) - this.$otherReferences.forEach(child => { + private [REFERENCES_TO_JSON](json: any, ctx: SerializationContext) { + const relevantReferences = [ + ...this.$treeChildren, + ...this.$otherReferences + ]; + + relevantReferences.forEach(child => { const jsc = child.toJson(ctx) if (jsc != undefined && !(Array.isArray(jsc) && jsc.length == 0)) { json[child.referenceName] = jsc @@ -161,7 +163,7 @@ export abstract class Referencable< }) } - private attributesToJson(json: any) { + private [ATTRIBUTES_TO_JSON](json: any) { const ctor = this.constructor as any; const attributes = getAllAttributes(ctor); attributes.forEach((options: AttributeOptions, key) => { From 6188cbf8983ce83fb78a8909b4a5587bb5bc6a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 08:41:06 +0200 Subject: [PATCH 07/34] replace assign refs by symbol SERIALIZE_ASSIGN_REFS --- .../referencable/container/tree/re-tree-list-container.ts | 3 ++- .../referencable/container/tree/re-tree-single-container.ts | 3 ++- .../src/lib/referencing/referencable/referencable-symbols.ts | 1 + .../emfular/src/lib/referencing/referencable/referenceable.ts | 3 ++- .../emfular/src/lib/serialization/serialization-context.ts | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 2d5950b..d6a1c51 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -8,6 +8,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {DeletionMode} from "../../../../utils/deletion-mode"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; +import {SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; export class ReTreeListContainer> extends ReListContainer @@ -24,7 +25,7 @@ implements ReTreeChildrenContainer { assignRefs(ctx: SerializationContext, path: string) { const ownPath = RefHandler.computePrefix(path, this.referenceName) this._instance.map((elem, index) => - elem.assignRefs(ctx, RefHandler.mixWithIndex(ownPath, index)) + elem[SERIALIZE_ASSIGN_REFS](ctx, RefHandler.mixWithIndex(ownPath, index)) ) } diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 1a3461e..2a04f18 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -7,6 +7,7 @@ import {ReTreeChildrenContainer} from "./re-tree-children-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; +import {SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; export class ReTreeSingleContainer> extends ReSingleContainer @@ -21,7 +22,7 @@ implements ReTreeChildrenContainer { } assignRefs(ctx: SerializationContext, path: string) { - this._instance?.assignRefs(ctx, RefHandler.computePrefix(path, this.referenceName)) + this._instance?.[SERIALIZE_ASSIGN_REFS](ctx, RefHandler.computePrefix(path, this.referenceName)) } toJson(ctx: SerializationContext): JsonOf|undefined { diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts new file mode 100644 index 0000000..7290ea3 --- /dev/null +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -0,0 +1 @@ +export const SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") \ No newline at end of file diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index d52d2d1..98ef7f6 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -12,6 +12,7 @@ import {ReLinkContainer} from "./container/link/re-link-container"; import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; +import {SERIALIZE_ASSIGN_REFS} from "./referencable-symbols"; //private, no export const INIT_REFERENCES = Symbol("initReferences"); @@ -74,7 +75,7 @@ export abstract class Referencable< return ModelRegistry.getEClassForInstance(this) } - assignRefs(ctx: SerializationContext, path: string) { + [SERIALIZE_ASSIGN_REFS](ctx: SerializationContext, path: string) { const ref: Ref = RefHandler.createRef(path, this.$getEClass()) ctx.put(this, ref) for(let child of this.$treeChildren) { diff --git a/projects/emfular/src/lib/serialization/serialization-context.ts b/projects/emfular/src/lib/serialization/serialization-context.ts index 34a1f67..0563c08 100644 --- a/projects/emfular/src/lib/serialization/serialization-context.ts +++ b/projects/emfular/src/lib/serialization/serialization-context.ts @@ -1,13 +1,14 @@ import {Referencable} from "../referencing/referencable/referenceable"; import {Ref} from "../referencing/ref/ref"; import {RefHandler} from "../referencing/ref/ref-handler"; +import {SERIALIZE_ASSIGN_REFS} from "../referencing/referencable/referencable-symbols"; export class SerializationContext { private refs = new Map, Ref>(); constructor(root: Referencable) { - root.assignRefs(this, RefHandler.rootPath) + root[SERIALIZE_ASSIGN_REFS](this, RefHandler.rootPath) } put>(obj: T, ref: Ref) { From ac99b75508c6147edf6ca0000e925523b52aa823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 09:10:03 +0200 Subject: [PATCH 08/34] Reorganize Referencable methods by purpose, to make more symbolized --- .../referencing/referencable/referenceable.ts | 109 +++++++++--------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 98ef7f6..26814ee 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -46,16 +46,7 @@ export abstract class Referencable< this[INIT_REFERENCES]() } - private [INIT_REFERENCES]() { - const proto = Object.getPrototypeOf(this); - const inits = proto.__referenceInitializers; - if (inits) { - for (const init of inits) { - init.call(this); - } - } - } - + // ************* public modeling API ******************** set $parent(parent: ReTreeChildrenContainer | undefined) { if(this._$parent) { this._$parent.remove(this) @@ -75,14 +66,6 @@ export abstract class Referencable< return ModelRegistry.getEClassForInstance(this) } - [SERIALIZE_ASSIGN_REFS](ctx: SerializationContext, path: string) { - const ref: Ref = RefHandler.createRef(path, this.$getEClass()) - ctx.put(this, ref) - for(let child of this.$treeChildren) { - child.assignRefs(ctx, path) - } - } - $destruct(mode: DeletionMode = DeletionMode.RELAXED) { // removal from parent is always called with deletion mode RELAXED, otherwise infinite loops occur (see remove in re-tree-list/single-container.ts) // tests in files re-link-list/single-container.spec.ts and re-tree-list/single-container.spec.ts fail when not setting RELAXED mode explicitly @@ -95,7 +78,26 @@ export abstract class Referencable< }) } - private [GET_CONTAINER]>(refName: string): ReContainer { + // ****************** inverse handling (called by link containers) ********************** + public addToReferencableContainer>(name: string, item: T): boolean { + return this[GET_CONTAINER](name).add(item) + } + + public removeFromReferencableContainer>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { + let container = this[GET_CONTAINER](name) + let result = container.remove(item, mode) + if (result && mode === DeletionMode.CASCADE && container.isRequired) { + const instance = container.get() + if (instance === undefined || (Array.isArray(instance) && instance.length === 0)) { + container._parent.$destruct(mode) + } + } + return result + } + + private [GET_CONTAINER]< + T extends Referencable + >(refName: string): ReContainer { let proto: any = Object.getPrototypeOf(this); let meta: ReferenceMeta | undefined; @@ -108,35 +110,18 @@ export abstract class Referencable< } proto = Object.getPrototypeOf(proto); } - if (!meta) { throw new Error(`Reference '${refName}' not found on class '${this.constructor.name}'`); } const key: symbol = meta.containerKey!; const container = (this as any)[key]; - if (!container) { throw new Error(`Container for reference '${refName}' not initialized`); } - return container as ReContainer; } - public addToReferencableContainer>(name: string, item: T): boolean { - return this[GET_CONTAINER](name).add(item) - } - - public removeFromReferencableContainer>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { - let container = this[GET_CONTAINER](name) - let result = container.remove(item, mode) - if (result && mode === DeletionMode.CASCADE && container.isRequired) { - const instance = container.get() - if (instance === undefined || (Array.isArray(instance) && instance.length === 0)) { - container._parent.$destruct(mode) - } - } - return result - } + //************** Serialization ************************* toJson(ctxOPt?: SerializationContext): JsonOf { const ctx = ctxOPt ? ctxOPt : new SerializationContext(this) @@ -149,21 +134,6 @@ export abstract class Referencable< return json as JsonOf; } - - private [REFERENCES_TO_JSON](json: any, ctx: SerializationContext) { - const relevantReferences = [ - ...this.$treeChildren, - ...this.$otherReferences - ]; - - relevantReferences.forEach(child => { - const jsc = child.toJson(ctx) - if (jsc != undefined && !(Array.isArray(jsc) && jsc.length == 0)) { - json[child.referenceName] = jsc - } - }) - } - private [ATTRIBUTES_TO_JSON](json: any) { const ctor = this.constructor as any; const attributes = getAllAttributes(ctor); @@ -182,6 +152,30 @@ export abstract class Referencable< }) } + private [REFERENCES_TO_JSON](json: any, ctx: SerializationContext) { + const relevantReferences = [ + ...this.$treeChildren, + ...this.$otherReferences + ]; + + relevantReferences.forEach(child => { + const jsc = child.toJson(ctx) + if (jsc != undefined && !(Array.isArray(jsc) && jsc.length == 0)) { + json[child.referenceName] = jsc + } + }) + } + + [SERIALIZE_ASSIGN_REFS](ctx: SerializationContext, path: string) { + const ref: Ref = RefHandler.createRef(path, this.$getEClass()) + ctx.put(this, ref) + for(let child of this.$treeChildren) { + child.assignRefs(ctx, path) + } + } + + //****************** Deserialization ************************ + createChildren>(context: Deserializer, parent: Ref, json: J) { this.$treeChildren.forEach(child => { child.fromJson(parent.$ref, context, json) @@ -217,4 +211,15 @@ export abstract class Referencable< } } + // ************* container construction ******************* + private [INIT_REFERENCES]() { + const proto = Object.getPrototypeOf(this); + const inits = proto.__referenceInitializers; + if (inits) { + for (const init of inits) { + init.call(this); + } + } + } + } From 30d0bb7ac3933e4bcb89f07cc212f40b93fa2132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 10:34:33 +0200 Subject: [PATCH 09/34] New symbols add to Reference and remove from reference --- .../container/link/re-link-list-container.ts | 7 +++--- .../link/re-link-single-container.ts | 9 ++++--- .../shallow/re-tree-parent-container.ts | 25 +++++++++++-------- .../referencable/referencable-symbols.ts | 3 +++ .../referencing/referencable/referenceable.ts | 6 ++--- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts index 161515b..5db71a3 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts @@ -6,6 +6,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; +import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; export class ReLinkListContainer< T extends Referencable, @@ -22,7 +23,7 @@ implements ReLinkContainer { let res = ListUpdater.addToListIfMissing(item, this._instance) if (res) { if(this.inverseName !== undefined) { - return item.addToReferencableContainer(this.inverseName, this._parent) + return item[ADD_TO_REFERENCE](this.inverseName, this._parent) } return true; } else { @@ -38,7 +39,7 @@ implements ReLinkContainer { const res = ListUpdater.removeFromList(item, this._instance) if (res) { if(this.inverseName !== undefined) { - item.removeFromReferencableContainer(this.inverseName, this._parent, mode) + item[REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) } } return res; //todo behaviour of flag different to add?? @@ -51,7 +52,7 @@ implements ReLinkContainer { removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { for (const child of [...this._instance]) { - child.removeFromReferencableContainer(this.inverseName, item, mode) + child[REMOVE_FROM_REFERENCE](this.inverseName, item, mode) } return true; // todo - refine? } diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts index 7d59e9f..c28a2ed 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts @@ -5,6 +5,7 @@ import {ReLinkContainer} from "./re-link-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; +import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; export class ReLinkSingleContainer< T extends Referencable, @@ -19,9 +20,9 @@ implements ReLinkContainer { protected set(instance: T): void { if(this.inverseName !== undefined) { - this._instance?.removeFromReferencableContainer(this.inverseName, this._parent, DeletionMode.RELAXED) + this._instance?.[REMOVE_FROM_REFERENCE](this.inverseName, this._parent, DeletionMode.RELAXED) this._instance = instance; - instance.addToReferencableContainer(this.inverseName, this._parent) + instance[ADD_TO_REFERENCE](this.inverseName, this._parent) } else { this._instance = instance; } @@ -40,7 +41,7 @@ implements ReLinkContainer { if(this._instance == item) { this._instance = undefined; if (this.inverseName != undefined) { - item.removeFromReferencableContainer(this.inverseName, this._parent, mode) + item[REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) } return true; } else { @@ -54,7 +55,7 @@ implements ReLinkContainer { removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { - this._instance?.removeFromReferencableContainer(this.inverseName, item, mode) + this._instance?.[REMOVE_FROM_REFERENCE](this.inverseName, item, mode) return true; // todo refine? } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index ab5c05b..3d1b26e 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -5,32 +5,35 @@ import {ReSingleInterface} from "../re-single-interface"; import {ReShallowInterface} from "./re-shallow-interface"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; +import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; -export class ReTreeParentContainer> - extends ReContainer -implements ReSingleInterface, - ReShallowInterface{ +export class ReTreeParentContainer< + T extends Referencable, + P extends Referencable = T["$ParentType"]> + extends ReContainer +implements ReSingleInterface, + ReShallowInterface{ constructor(parent: T, referenceName: string, refMeta: ReferenceMeta) { super(parent, referenceName, refMeta); // referenceName is actually unused for this container type } - get(): T["$ParentType"] | undefined { - return (this._parent.$getParentReferencable() as T["$ParentType"]) + get(): P | undefined { + return (this._parent.$getParentReferencable()) } //todo rewrite without using item parent explicitly? - addWithoutTypeCheck(item: T["$ParentType"]): boolean { + addWithoutTypeCheck(item: P): boolean { let me: T = this._parent const currentParentCont = this._parent.$parent if(currentParentCont != undefined) { - currentParentCont.remove(this._parent as T["$ParentType"], DeletionMode.RELAXED) + currentParentCont.remove(this._parent, DeletionMode.RELAXED) } - return item.addToReferencableContainer(this.inverseName, me) + return item[ADD_TO_REFERENCE](this.inverseName!, me) } - remove(item: T["$ParentType"], mode: DeletionMode = DeletionMode.RELAXED): boolean { - return item.removeFromReferencableContainer(this.inverseName, this._parent, mode) + remove(item: P, mode: DeletionMode = DeletionMode.RELAXED): boolean { + return item[REMOVE_FROM_REFERENCE](this.inverseName!, this._parent, mode) } delete(): void {} diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts index 7290ea3..c94392b 100644 --- a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -1 +1,4 @@ +export const ADD_TO_REFERENCE = Symbol("addToReference") +export const REMOVE_FROM_REFERENCE = Symbol("removeFromReference") + export const SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") \ No newline at end of file diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 26814ee..be42e02 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -12,7 +12,7 @@ import {ReLinkContainer} from "./container/link/re-link-container"; import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; -import {SERIALIZE_ASSIGN_REFS} from "./referencable-symbols"; +import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE, SERIALIZE_ASSIGN_REFS} from "./referencable-symbols"; //private, no export const INIT_REFERENCES = Symbol("initReferences"); @@ -79,11 +79,11 @@ export abstract class Referencable< } // ****************** inverse handling (called by link containers) ********************** - public addToReferencableContainer>(name: string, item: T): boolean { + public [ADD_TO_REFERENCE]>(name: string, item: T): boolean { return this[GET_CONTAINER](name).add(item) } - public removeFromReferencableContainer>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { + public [REMOVE_FROM_REFERENCE]>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { let container = this[GET_CONTAINER](name) let result = container.remove(item, mode) if (result && mode === DeletionMode.CASCADE && container.isRequired) { From 52c362c6cda9e15ccceda30787065cda31575fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 11:07:17 +0200 Subject: [PATCH 10/34] Remove explicit parent removal, maybe cause of circular on strict mode --- .../container/shallow/re-tree-parent-container.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index 3d1b26e..2a7b2ac 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -9,7 +9,7 @@ import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbol export class ReTreeParentContainer< T extends Referencable, - P extends Referencable = T["$ParentType"]> + P extends Referencable = T["$ParentType"]> extends ReContainer implements ReSingleInterface, ReShallowInterface{ @@ -24,12 +24,7 @@ implements ReSingleInterface, //todo rewrite without using item parent explicitly? addWithoutTypeCheck(item: P): boolean { - let me: T = this._parent - const currentParentCont = this._parent.$parent - if(currentParentCont != undefined) { - currentParentCont.remove(this._parent, DeletionMode.RELAXED) - } - return item[ADD_TO_REFERENCE](this.inverseName!, me) + return item[ADD_TO_REFERENCE](this.inverseName!, this._parent) } remove(item: P, mode: DeletionMode = DeletionMode.RELAXED): boolean { From 8f09bbdf083bbfef7f414d0da3b2961be6abd462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 11:15:40 +0200 Subject: [PATCH 11/34] Rename all referencable symbols to have the class Referencable explicit as first part --- .../container/link/re-link-list-container.ts | 8 ++++---- .../container/link/re-link-single-container.ts | 10 +++++----- .../container/shallow/re-tree-parent-container.ts | 6 +++--- .../container/tree/re-tree-list-container.ts | 4 ++-- .../container/tree/re-tree-single-container.ts | 4 ++-- .../referencing/referencable/referencable-symbols.ts | 6 +++--- .../src/lib/referencing/referencable/referenceable.ts | 8 ++++---- .../src/lib/serialization/serialization-context.ts | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts index 5db71a3..2bec9fc 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts @@ -6,7 +6,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; -import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; +import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; export class ReLinkListContainer< T extends Referencable, @@ -23,7 +23,7 @@ implements ReLinkContainer { let res = ListUpdater.addToListIfMissing(item, this._instance) if (res) { if(this.inverseName !== undefined) { - return item[ADD_TO_REFERENCE](this.inverseName, this._parent) + return item[REFERENCE__ADD_TO_REFERENCE](this.inverseName, this._parent) } return true; } else { @@ -39,7 +39,7 @@ implements ReLinkContainer { const res = ListUpdater.removeFromList(item, this._instance) if (res) { if(this.inverseName !== undefined) { - item[REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) + item[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) } } return res; //todo behaviour of flag different to add?? @@ -52,7 +52,7 @@ implements ReLinkContainer { removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { for (const child of [...this._instance]) { - child[REMOVE_FROM_REFERENCE](this.inverseName, item, mode) + child[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, item, mode) } return true; // todo - refine? } diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts index c28a2ed..672361d 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts @@ -5,7 +5,7 @@ import {ReLinkContainer} from "./re-link-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; -import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; +import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; export class ReLinkSingleContainer< T extends Referencable, @@ -20,9 +20,9 @@ implements ReLinkContainer { protected set(instance: T): void { if(this.inverseName !== undefined) { - this._instance?.[REMOVE_FROM_REFERENCE](this.inverseName, this._parent, DeletionMode.RELAXED) + this._instance?.[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, this._parent, DeletionMode.RELAXED) this._instance = instance; - instance[ADD_TO_REFERENCE](this.inverseName, this._parent) + instance[REFERENCE__ADD_TO_REFERENCE](this.inverseName, this._parent) } else { this._instance = instance; } @@ -41,7 +41,7 @@ implements ReLinkContainer { if(this._instance == item) { this._instance = undefined; if (this.inverseName != undefined) { - item[REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) + item[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) } return true; } else { @@ -55,7 +55,7 @@ implements ReLinkContainer { removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { - this._instance?.[REMOVE_FROM_REFERENCE](this.inverseName, item, mode) + this._instance?.[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, item, mode) return true; // todo refine? } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index 2a7b2ac..e6b8d94 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -5,7 +5,7 @@ import {ReSingleInterface} from "../re-single-interface"; import {ReShallowInterface} from "./re-shallow-interface"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; -import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; +import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; export class ReTreeParentContainer< T extends Referencable, @@ -24,11 +24,11 @@ implements ReSingleInterface, //todo rewrite without using item parent explicitly? addWithoutTypeCheck(item: P): boolean { - return item[ADD_TO_REFERENCE](this.inverseName!, this._parent) + return item[REFERENCE__ADD_TO_REFERENCE](this.inverseName!, this._parent) } remove(item: P, mode: DeletionMode = DeletionMode.RELAXED): boolean { - return item[REMOVE_FROM_REFERENCE](this.inverseName!, this._parent, mode) + return item[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName!, this._parent, mode) } delete(): void {} diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index d6a1c51..726cf15 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -8,7 +8,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {DeletionMode} from "../../../../utils/deletion-mode"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; -import {SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; +import {REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; export class ReTreeListContainer> extends ReListContainer @@ -25,7 +25,7 @@ implements ReTreeChildrenContainer { assignRefs(ctx: SerializationContext, path: string) { const ownPath = RefHandler.computePrefix(path, this.referenceName) this._instance.map((elem, index) => - elem[SERIALIZE_ASSIGN_REFS](ctx, RefHandler.mixWithIndex(ownPath, index)) + elem[REFERENCE__SERIALIZE_ASSIGN_REFS](ctx, RefHandler.mixWithIndex(ownPath, index)) ) } diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 2a04f18..61bb66d 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -7,7 +7,7 @@ import {ReTreeChildrenContainer} from "./re-tree-children-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; -import {SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; +import {REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; export class ReTreeSingleContainer> extends ReSingleContainer @@ -22,7 +22,7 @@ implements ReTreeChildrenContainer { } assignRefs(ctx: SerializationContext, path: string) { - this._instance?.[SERIALIZE_ASSIGN_REFS](ctx, RefHandler.computePrefix(path, this.referenceName)) + this._instance?.[REFERENCE__SERIALIZE_ASSIGN_REFS](ctx, RefHandler.computePrefix(path, this.referenceName)) } toJson(ctx: SerializationContext): JsonOf|undefined { diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts index c94392b..6830170 100644 --- a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -1,4 +1,4 @@ -export const ADD_TO_REFERENCE = Symbol("addToReference") -export const REMOVE_FROM_REFERENCE = Symbol("removeFromReference") +export const REFERENCE__ADD_TO_REFERENCE = Symbol("addToReference") +export const REFERENCE__REMOVE_FROM_REFERENCE = Symbol("removeFromReference") -export const SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") \ No newline at end of file +export const REFERENCE__SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") \ No newline at end of file diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index be42e02..36b0d8d 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -12,7 +12,7 @@ import {ReLinkContainer} from "./container/link/re-link-container"; import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; -import {ADD_TO_REFERENCE, REMOVE_FROM_REFERENCE, SERIALIZE_ASSIGN_REFS} from "./referencable-symbols"; +import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE, REFERENCE__SERIALIZE_ASSIGN_REFS} from "./referencable-symbols"; //private, no export const INIT_REFERENCES = Symbol("initReferences"); @@ -79,11 +79,11 @@ export abstract class Referencable< } // ****************** inverse handling (called by link containers) ********************** - public [ADD_TO_REFERENCE]>(name: string, item: T): boolean { + public [REFERENCE__ADD_TO_REFERENCE]>(name: string, item: T): boolean { return this[GET_CONTAINER](name).add(item) } - public [REMOVE_FROM_REFERENCE]>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { + public [REFERENCE__REMOVE_FROM_REFERENCE]>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { let container = this[GET_CONTAINER](name) let result = container.remove(item, mode) if (result && mode === DeletionMode.CASCADE && container.isRequired) { @@ -166,7 +166,7 @@ export abstract class Referencable< }) } - [SERIALIZE_ASSIGN_REFS](ctx: SerializationContext, path: string) { + [REFERENCE__SERIALIZE_ASSIGN_REFS](ctx: SerializationContext, path: string) { const ref: Ref = RefHandler.createRef(path, this.$getEClass()) ctx.put(this, ref) for(let child of this.$treeChildren) { diff --git a/projects/emfular/src/lib/serialization/serialization-context.ts b/projects/emfular/src/lib/serialization/serialization-context.ts index 0563c08..25fc0ba 100644 --- a/projects/emfular/src/lib/serialization/serialization-context.ts +++ b/projects/emfular/src/lib/serialization/serialization-context.ts @@ -1,14 +1,14 @@ import {Referencable} from "../referencing/referencable/referenceable"; import {Ref} from "../referencing/ref/ref"; import {RefHandler} from "../referencing/ref/ref-handler"; -import {SERIALIZE_ASSIGN_REFS} from "../referencing/referencable/referencable-symbols"; +import {REFERENCE__SERIALIZE_ASSIGN_REFS} from "../referencing/referencable/referencable-symbols"; export class SerializationContext { private refs = new Map, Ref>(); constructor(root: Referencable) { - root[SERIALIZE_ASSIGN_REFS](this, RefHandler.rootPath) + root[REFERENCE__SERIALIZE_ASSIGN_REFS](this, RefHandler.rootPath) } put>(obj: T, ref: Ref) { From 891492888c13c943d6b59e7a49c74b258031b4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 11:33:44 +0200 Subject: [PATCH 12/34] Deserialization symbols --- .../container/tree/re-tree-list-container.ts | 4 ++-- .../container/tree/re-tree-single-container.ts | 4 ++-- .../referencable/referencable-symbols.ts | 7 ++++++- .../lib/referencing/referencable/referenceable.ts | 14 +++++++++----- .../emfular/src/lib/serialization/deserializer.ts | 11 ++++++++--- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 726cf15..879108b 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -8,7 +8,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {DeletionMode} from "../../../../utils/deletion-mode"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; -import {REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; +import {REFERENCE__DESERIALIZE_OTHER_REFERENCES, REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; export class ReTreeListContainer> extends ReListContainer @@ -92,7 +92,7 @@ implements ReTreeChildrenContainer { let myJson: JsonOf[] = json[this.referenceName]; if(myJson && myJson.length == this._instance.length) { myJson.forEach((ref, index) => { - this._instance[index].deserializeLinks(context, ref) + this._instance[index][REFERENCE__DESERIALIZE_OTHER_REFERENCES](context, ref) }) } } diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 61bb66d..987d888 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -7,7 +7,7 @@ import {ReTreeChildrenContainer} from "./re-tree-children-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; -import {REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; +import {REFERENCE__DESERIALIZE_OTHER_REFERENCES, REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; export class ReTreeSingleContainer> extends ReSingleContainer @@ -81,7 +81,7 @@ implements ReTreeChildrenContainer { createRefsOnChildren(context: Deserializer, json: any) { let myJson: JsonOf = json[this.referenceName]; if(this._instance && myJson ) { - this._instance.deserializeLinks(context, myJson) + this._instance[REFERENCE__DESERIALIZE_OTHER_REFERENCES](context, myJson) } } } diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts index 6830170..a2833a4 100644 --- a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -1,4 +1,9 @@ export const REFERENCE__ADD_TO_REFERENCE = Symbol("addToReference") export const REFERENCE__REMOVE_FROM_REFERENCE = Symbol("removeFromReference") -export const REFERENCE__SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") \ No newline at end of file +//************** Serialization ************************* +export const REFERENCE__SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") +//****************** Deserialization ************************ +export const REFERENCE__DESERIALIZE_ATTRIBUTES = Symbol("deserialize_attributes") +export const REFERENCE__DESERIALIZE_CHILDREN = Symbol("deserialize_children") +export const REFERENCE__DESERIALIZE_OTHER_REFERENCES = Symbol("deserialize_other_references") diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 36b0d8d..4f74e33 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -12,7 +12,12 @@ import {ReLinkContainer} from "./container/link/re-link-container"; import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; -import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE, REFERENCE__SERIALIZE_ASSIGN_REFS} from "./referencable-symbols"; +import { + REFERENCE__ADD_TO_REFERENCE, REFERENCE__DESERIALIZE_ATTRIBUTES, + REFERENCE__DESERIALIZE_CHILDREN, REFERENCE__DESERIALIZE_OTHER_REFERENCES, + REFERENCE__REMOVE_FROM_REFERENCE, + REFERENCE__SERIALIZE_ASSIGN_REFS +} from "./referencable-symbols"; //private, no export const INIT_REFERENCES = Symbol("initReferences"); @@ -175,14 +180,13 @@ export abstract class Referencable< } //****************** Deserialization ************************ - - createChildren>(context: Deserializer, parent: Ref, json: J) { + [REFERENCE__DESERIALIZE_CHILDREN]>(context: Deserializer, parent: Ref, json: J) { this.$treeChildren.forEach(child => { child.fromJson(parent.$ref, context, json) }) } - attributesFromJson>(jsonTyped: J) { + [REFERENCE__DESERIALIZE_ATTRIBUTES]>(jsonTyped: J) { const json: any = jsonTyped as any const ctor = this.constructor as any; const attributes = getAllAttributes(ctor); @@ -195,7 +199,7 @@ export abstract class Referencable< }) } - public deserializeLinks>(context: Deserializer, jsonTyped: J) { + public [REFERENCE__DESERIALIZE_OTHER_REFERENCES]>(context: Deserializer, jsonTyped: J) { const json = jsonTyped as any for (let container of this.$otherReferences) { let jsonElem: Ref[] |Ref | undefined = json[container.referenceName] diff --git a/projects/emfular/src/lib/serialization/deserializer.ts b/projects/emfular/src/lib/serialization/deserializer.ts index fa60161..c8eb774 100644 --- a/projects/emfular/src/lib/serialization/deserializer.ts +++ b/projects/emfular/src/lib/serialization/deserializer.ts @@ -8,6 +8,11 @@ import {RefHandler} from "../referencing/ref/ref-handler"; import {Ref} from "../referencing/ref/ref"; import {JsonOf} from "./json-deserializable"; import {ModelRegistry} from "../binding/model-registry"; +import { + REFERENCE__DESERIALIZE_ATTRIBUTES, + REFERENCE__DESERIALIZE_CHILDREN, + REFERENCE__DESERIALIZE_OTHER_REFERENCES +} from "../referencing/referencable/referencable-symbols"; export class Deserializer { @@ -18,8 +23,8 @@ export class Deserializer { const entry = ModelRegistry.get(ref.eClass) const obj: T = new entry() this.put(ref,obj) - obj.attributesFromJson(json) - obj.createChildren(this, ref, json) + obj[REFERENCE__DESERIALIZE_ATTRIBUTES](json) + obj[REFERENCE__DESERIALIZE_CHILDREN](this, ref, json) return obj } @@ -54,7 +59,7 @@ export class Deserializer { eClass: rootEClass } const model: C = context.createTreeBackbone(ref, json); - model.deserializeLinks(context, json) + model[REFERENCE__DESERIALIZE_OTHER_REFERENCES](context, json) return model; } From e7c7743ec1497db82fd725eb77c8d53b9ed295ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 12:25:10 +0200 Subject: [PATCH 13/34] desinging an extra internal API instead of symbols to reinstall IDE navigation --- .../container/link/re-link-list-container.ts | 8 +- .../link/re-link-single-container.ts | 10 +- .../shallow/re-tree-parent-container.ts | 10 +- .../referencable/referencable-symbols.ts | 3 + .../referencing/referencable/referenceable.ts | 110 ++++++++++++++++-- 5 files changed, 118 insertions(+), 23 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts index 2bec9fc..4835059 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts @@ -6,7 +6,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; -import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; export class ReLinkListContainer< T extends Referencable, @@ -23,7 +23,7 @@ implements ReLinkContainer { let res = ListUpdater.addToListIfMissing(item, this._instance) if (res) { if(this.inverseName !== undefined) { - return item[REFERENCE__ADD_TO_REFERENCE](this.inverseName, this._parent) + return item[REFERENCE_INTERNAL_API].addToReference(this.inverseName, this._parent) } return true; } else { @@ -39,7 +39,7 @@ implements ReLinkContainer { const res = ListUpdater.removeFromList(item, this._instance) if (res) { if(this.inverseName !== undefined) { - item[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) + item[REFERENCE_INTERNAL_API].removeFromReference(this.inverseName, this._parent, mode) } } return res; //todo behaviour of flag different to add?? @@ -52,7 +52,7 @@ implements ReLinkContainer { removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { for (const child of [...this._instance]) { - child[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, item, mode) + child[REFERENCE_INTERNAL_API].removeFromReference(this.inverseName, item, mode) } return true; // todo - refine? } diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts index 672361d..585d669 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts @@ -5,7 +5,7 @@ import {ReLinkContainer} from "./re-link-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; -import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; export class ReLinkSingleContainer< T extends Referencable, @@ -20,9 +20,9 @@ implements ReLinkContainer { protected set(instance: T): void { if(this.inverseName !== undefined) { - this._instance?.[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, this._parent, DeletionMode.RELAXED) + this._instance?.[REFERENCE_INTERNAL_API].removeFromReference(this.inverseName, this._parent, DeletionMode.RELAXED) this._instance = instance; - instance[REFERENCE__ADD_TO_REFERENCE](this.inverseName, this._parent) + instance[REFERENCE_INTERNAL_API].addToReference(this.inverseName, this._parent) } else { this._instance = instance; } @@ -41,7 +41,7 @@ implements ReLinkContainer { if(this._instance == item) { this._instance = undefined; if (this.inverseName != undefined) { - item[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, this._parent, mode) + item[REFERENCE_INTERNAL_API].removeFromReference(this.inverseName, this._parent, mode) } return true; } else { @@ -55,7 +55,7 @@ implements ReLinkContainer { removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { - this._instance?.[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName, item, mode) + this._instance?.[REFERENCE_INTERNAL_API].removeFromReference(this.inverseName, item, mode) return true; // todo refine? } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index e6b8d94..10eb660 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -5,7 +5,11 @@ import {ReSingleInterface} from "../re-single-interface"; import {ReShallowInterface} from "./re-shallow-interface"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; -import {REFERENCE__ADD_TO_REFERENCE, REFERENCE__REMOVE_FROM_REFERENCE} from "../../referencable-symbols"; +import { + REFERENCE__ADD_TO_REFERENCE, + REFERENCE__REMOVE_FROM_REFERENCE, + REFERENCE_INTERNAL_API +} from "../../referencable-symbols"; export class ReTreeParentContainer< T extends Referencable, @@ -24,11 +28,11 @@ implements ReSingleInterface, //todo rewrite without using item parent explicitly? addWithoutTypeCheck(item: P): boolean { - return item[REFERENCE__ADD_TO_REFERENCE](this.inverseName!, this._parent) + return item[REFERENCE_INTERNAL_API].addToReference(this.inverseName!, this._parent) } remove(item: P, mode: DeletionMode = DeletionMode.RELAXED): boolean { - return item[REFERENCE__REMOVE_FROM_REFERENCE](this.inverseName!, this._parent, mode) + return item[REFERENCE_INTERNAL_API].removeFromReference(this.inverseName!, this._parent, mode) } delete(): void {} diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts index a2833a4..cc7aea2 100644 --- a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -7,3 +7,6 @@ export const REFERENCE__SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") export const REFERENCE__DESERIALIZE_ATTRIBUTES = Symbol("deserialize_attributes") export const REFERENCE__DESERIALIZE_CHILDREN = Symbol("deserialize_children") export const REFERENCE__DESERIALIZE_OTHER_REFERENCES = Symbol("deserialize_other_references") + + +export const REFERENCE_INTERNAL_API = Symbol("reference_internal_api"); \ No newline at end of file diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 4f74e33..5c01835 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -16,7 +16,7 @@ import { REFERENCE__ADD_TO_REFERENCE, REFERENCE__DESERIALIZE_ATTRIBUTES, REFERENCE__DESERIALIZE_CHILDREN, REFERENCE__DESERIALIZE_OTHER_REFERENCES, REFERENCE__REMOVE_FROM_REFERENCE, - REFERENCE__SERIALIZE_ASSIGN_REFS + REFERENCE__SERIALIZE_ASSIGN_REFS, REFERENCE_INTERNAL_API } from "./referencable-symbols"; //private, no export @@ -83,22 +83,83 @@ export abstract class Referencable< }) } - // ****************** inverse handling (called by link containers) ********************** - public [REFERENCE__ADD_TO_REFERENCE]>(name: string, item: T): boolean { - return this[GET_CONTAINER](name).add(item) - } + public [REFERENCE_INTERNAL_API]: ReferenceApi = { + + // ****************** inverse handling (called by link containers) ********************** + + addToReference: >(name: string, item: U): boolean => { + return this[GET_CONTAINER](name).add(item) + }, - public [REFERENCE__REMOVE_FROM_REFERENCE]>(name: string, item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { - let container = this[GET_CONTAINER](name) - let result = container.remove(item, mode) - if (result && mode === DeletionMode.CASCADE && container.isRequired) { + removeFromReference: >(name: string, item: U, mode: DeletionMode = DeletionMode.RELAXED): boolean => { + let container = this[GET_CONTAINER](name) + let result = container.remove(item, mode) + if (result && mode === DeletionMode.CASCADE && container.isRequired) { const instance = container.get() if (instance === undefined || (Array.isArray(instance) && instance.length === 0)) { container._parent.$destruct(mode) } } - return result - } + return result + }, + + //************** Serialization ************************* + + serialize_assignRefs: (ctx: SerializationContext, path: string): void => { + const ref: Ref = RefHandler.createRef(path, this.$getEClass()) + ctx.put(this, ref) + for(let child of this.$treeChildren) { + child.assignRefs(ctx, path) + } + }, + + deserializeChildren: >( + context: Deserializer, + parent: Ref, + json: J + ): void => { + this.$treeChildren.forEach(child => { + child.fromJson(parent.$ref, context, json); + }); + }, + + deserializeAttributes: >(jsonTyped: J): void => { + const json: any = jsonTyped as any; + const ctor = this.constructor as any; + const attributes = getAllAttributes(ctor); + attributes.forEach((options, key) => { + if (json[key] !== undefined) { + (this as any)[key] = json[key]; + } else if (options?.default !== undefined) { + (this as any)[key] = options.default; + } + }); + }, + + deserializeOtherReferences: >( + context: Deserializer, + jsonTyped: J + ): void => { + const json = jsonTyped as any; + + for (const container of this.$otherReferences) { + let jsonElem: Ref[] | Ref | undefined = json[container.referenceName]; + if (jsonElem != undefined) { + const refArray = Array.isArray(jsonElem) ? jsonElem : [jsonElem]; + refArray.map((ref: Ref) => { + container.add(context.get(ref.$ref)); + }); + } + } + + for (const container of this.$treeChildren) { + container.createRefsOnChildren(context, json); + } + } + }; + + + // ****************** inverse handling (called by link containers) ********************** private [GET_CONTAINER]< T extends Referencable @@ -227,3 +288,30 @@ export abstract class Referencable< } } + + +export interface ReferenceApi> { + + // ****************** inverse handling (called by link containers) ********************** + addToReference: >(name: string, item: U) => boolean; + removeFromReference: >( + name: string, + item: U, + mode?: DeletionMode + ) => boolean; + + //************** Serialization ************************* + serialize_assignRefs: (ctx: SerializationContext, path: string) => void; + + //****************** Deserialization ************************ + deserializeAttributes: >(json: J) => void; + deserializeChildren: >( + context: Deserializer, + parent: Ref, + json: J + ) => void; + deserializeOtherReferences: >( + context: Deserializer, + json: J + ) => void; +} \ No newline at end of file From fbb4d12779c90f83b269db0a038278725052875e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Thu, 28 May 2026 13:18:57 +0200 Subject: [PATCH 14/34] Inverse triggers moved to public api object to keep IDE working --- .../container/shallow/re-tree-parent-container.ts | 6 +----- .../lib/referencing/referencable/referencable-symbols.ts | 2 -- .../src/lib/referencing/referencable/referenceable.ts | 4 +--- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index 10eb660..98ea4ca 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -5,11 +5,7 @@ import {ReSingleInterface} from "../re-single-interface"; import {ReShallowInterface} from "./re-shallow-interface"; import {ReferenceMeta} from "../../../../binding/model-definition"; import { DeletionMode } from "../../../../utils/deletion-mode"; -import { - REFERENCE__ADD_TO_REFERENCE, - REFERENCE__REMOVE_FROM_REFERENCE, - REFERENCE_INTERNAL_API -} from "../../referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; export class ReTreeParentContainer< T extends Referencable, diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts index cc7aea2..c34b658 100644 --- a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -1,5 +1,3 @@ -export const REFERENCE__ADD_TO_REFERENCE = Symbol("addToReference") -export const REFERENCE__REMOVE_FROM_REFERENCE = Symbol("removeFromReference") //************** Serialization ************************* export const REFERENCE__SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 5c01835..2387605 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -13,9 +13,8 @@ import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; import { - REFERENCE__ADD_TO_REFERENCE, REFERENCE__DESERIALIZE_ATTRIBUTES, + REFERENCE__DESERIALIZE_ATTRIBUTES, REFERENCE__DESERIALIZE_CHILDREN, REFERENCE__DESERIALIZE_OTHER_REFERENCES, - REFERENCE__REMOVE_FROM_REFERENCE, REFERENCE__SERIALIZE_ASSIGN_REFS, REFERENCE_INTERNAL_API } from "./referencable-symbols"; @@ -86,7 +85,6 @@ export abstract class Referencable< public [REFERENCE_INTERNAL_API]: ReferenceApi = { // ****************** inverse handling (called by link containers) ********************** - addToReference: >(name: string, item: U): boolean => { return this[GET_CONTAINER](name).add(item) }, From 5e38ef69f43aa7a1d2c8aa2ce1dacbc66b54f293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 07:45:33 +0200 Subject: [PATCH 15/34] More methods just from Internal API of Referencable --- .../container/tree/re-tree-list-container.ts | 6 +- .../tree/re-tree-single-container.ts | 6 +- .../referencing/referencable/referenceable.ts | 73 +++---------------- .../src/lib/serialization/deserializer.ts | 12 +-- .../serialization/serialization-context.ts | 4 +- 5 files changed, 24 insertions(+), 77 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 879108b..3ed5b7f 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -8,7 +8,7 @@ import {ListUpdater} from "../../../../utils/list-updater"; import {DeletionMode} from "../../../../utils/deletion-mode"; import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; -import {REFERENCE__DESERIALIZE_OTHER_REFERENCES, REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; export class ReTreeListContainer> extends ReListContainer @@ -25,7 +25,7 @@ implements ReTreeChildrenContainer { assignRefs(ctx: SerializationContext, path: string) { const ownPath = RefHandler.computePrefix(path, this.referenceName) this._instance.map((elem, index) => - elem[REFERENCE__SERIALIZE_ASSIGN_REFS](ctx, RefHandler.mixWithIndex(ownPath, index)) + elem[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.mixWithIndex(ownPath, index)) ) } @@ -92,7 +92,7 @@ implements ReTreeChildrenContainer { let myJson: JsonOf[] = json[this.referenceName]; if(myJson && myJson.length == this._instance.length) { myJson.forEach((ref, index) => { - this._instance[index][REFERENCE__DESERIALIZE_OTHER_REFERENCES](context, ref) + this._instance[index][REFERENCE_INTERNAL_API].deserializeOtherReferences(context, ref) }) } } diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 987d888..6f89874 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -7,7 +7,7 @@ import {ReTreeChildrenContainer} from "./re-tree-children-container"; import {ReSingleContainer} from "../re-single-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; -import {REFERENCE__DESERIALIZE_OTHER_REFERENCES, REFERENCE__SERIALIZE_ASSIGN_REFS} from "../../referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; export class ReTreeSingleContainer> extends ReSingleContainer @@ -22,7 +22,7 @@ implements ReTreeChildrenContainer { } assignRefs(ctx: SerializationContext, path: string) { - this._instance?.[REFERENCE__SERIALIZE_ASSIGN_REFS](ctx, RefHandler.computePrefix(path, this.referenceName)) + this._instance?.[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.computePrefix(path, this.referenceName)) } toJson(ctx: SerializationContext): JsonOf|undefined { @@ -81,7 +81,7 @@ implements ReTreeChildrenContainer { createRefsOnChildren(context: Deserializer, json: any) { let myJson: JsonOf = json[this.referenceName]; if(this._instance && myJson ) { - this._instance[REFERENCE__DESERIALIZE_OTHER_REFERENCES](context, myJson) + this._instance[REFERENCE_INTERNAL_API].deserializeOtherReferences(context, myJson) } } } diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 2387605..bc69940 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -12,11 +12,7 @@ import {ReLinkContainer} from "./container/link/re-link-container"; import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; -import { - REFERENCE__DESERIALIZE_ATTRIBUTES, - REFERENCE__DESERIALIZE_CHILDREN, REFERENCE__DESERIALIZE_OTHER_REFERENCES, - REFERENCE__SERIALIZE_ASSIGN_REFS, REFERENCE_INTERNAL_API -} from "./referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; //private, no export const INIT_REFERENCES = Symbol("initReferences"); @@ -111,16 +107,7 @@ export abstract class Referencable< } }, - deserializeChildren: >( - context: Deserializer, - parent: Ref, - json: J - ): void => { - this.$treeChildren.forEach(child => { - child.fromJson(parent.$ref, context, json); - }); - }, - + //****************** Deserialization ************************ deserializeAttributes: >(jsonTyped: J): void => { const json: any = jsonTyped as any; const ctor = this.constructor as any; @@ -134,12 +121,21 @@ export abstract class Referencable< }); }, + deserializeChildren: >( + context: Deserializer, + parent: Ref, + json: J + ): void => { + this.$treeChildren.forEach(child => { + child.fromJson(parent.$ref, context, json); + }); + }, + deserializeOtherReferences: >( context: Deserializer, jsonTyped: J ): void => { const json = jsonTyped as any; - for (const container of this.$otherReferences) { let jsonElem: Ref[] | Ref | undefined = json[container.referenceName]; if (jsonElem != undefined) { @@ -149,7 +145,6 @@ export abstract class Referencable< }); } } - for (const container of this.$treeChildren) { container.createRefsOnChildren(context, json); } @@ -230,50 +225,6 @@ export abstract class Referencable< }) } - [REFERENCE__SERIALIZE_ASSIGN_REFS](ctx: SerializationContext, path: string) { - const ref: Ref = RefHandler.createRef(path, this.$getEClass()) - ctx.put(this, ref) - for(let child of this.$treeChildren) { - child.assignRefs(ctx, path) - } - } - - //****************** Deserialization ************************ - [REFERENCE__DESERIALIZE_CHILDREN]>(context: Deserializer, parent: Ref, json: J) { - this.$treeChildren.forEach(child => { - child.fromJson(parent.$ref, context, json) - }) - } - - [REFERENCE__DESERIALIZE_ATTRIBUTES]>(jsonTyped: J) { - const json: any = jsonTyped as any - const ctor = this.constructor as any; - const attributes = getAllAttributes(ctor); - attributes.forEach((options, key) => { - if (json[key] !== undefined) { - (this as any)[key] = json[key]; - } else if (options?.default !== undefined) { - (this as any)[key] = options.default; - } - }) - } - - public [REFERENCE__DESERIALIZE_OTHER_REFERENCES]>(context: Deserializer, jsonTyped: J) { - const json = jsonTyped as any - for (let container of this.$otherReferences) { - let jsonElem: Ref[] |Ref | undefined = json[container.referenceName] - if (jsonElem != undefined) { - const refArray = Array.isArray(jsonElem)? jsonElem : [jsonElem] - refArray.map((ref: Ref) => { - container.add(context.get(ref.$ref)); - }) - } - } - for (let container of this.$treeChildren) { - container.createRefsOnChildren(context, json) - } - } - // ************* container construction ******************* private [INIT_REFERENCES]() { const proto = Object.getPrototypeOf(this); diff --git a/projects/emfular/src/lib/serialization/deserializer.ts b/projects/emfular/src/lib/serialization/deserializer.ts index c8eb774..4bdf2ff 100644 --- a/projects/emfular/src/lib/serialization/deserializer.ts +++ b/projects/emfular/src/lib/serialization/deserializer.ts @@ -8,11 +8,7 @@ import {RefHandler} from "../referencing/ref/ref-handler"; import {Ref} from "../referencing/ref/ref"; import {JsonOf} from "./json-deserializable"; import {ModelRegistry} from "../binding/model-registry"; -import { - REFERENCE__DESERIALIZE_ATTRIBUTES, - REFERENCE__DESERIALIZE_CHILDREN, - REFERENCE__DESERIALIZE_OTHER_REFERENCES -} from "../referencing/referencable/referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../referencing/referencable/referencable-symbols"; export class Deserializer { @@ -23,8 +19,8 @@ export class Deserializer { const entry = ModelRegistry.get(ref.eClass) const obj: T = new entry() this.put(ref,obj) - obj[REFERENCE__DESERIALIZE_ATTRIBUTES](json) - obj[REFERENCE__DESERIALIZE_CHILDREN](this, ref, json) + obj[REFERENCE_INTERNAL_API].deserializeAttributes(json) + obj[REFERENCE_INTERNAL_API].deserializeChildren(this, ref, json) return obj } @@ -59,7 +55,7 @@ export class Deserializer { eClass: rootEClass } const model: C = context.createTreeBackbone(ref, json); - model[REFERENCE__DESERIALIZE_OTHER_REFERENCES](context, json) + model[REFERENCE_INTERNAL_API].deserializeOtherReferences(context, json) return model; } diff --git a/projects/emfular/src/lib/serialization/serialization-context.ts b/projects/emfular/src/lib/serialization/serialization-context.ts index 25fc0ba..79fca63 100644 --- a/projects/emfular/src/lib/serialization/serialization-context.ts +++ b/projects/emfular/src/lib/serialization/serialization-context.ts @@ -1,14 +1,14 @@ import {Referencable} from "../referencing/referencable/referenceable"; import {Ref} from "../referencing/ref/ref"; import {RefHandler} from "../referencing/ref/ref-handler"; -import {REFERENCE__SERIALIZE_ASSIGN_REFS} from "../referencing/referencable/referencable-symbols"; +import {REFERENCE_INTERNAL_API} from "../referencing/referencable/referencable-symbols"; export class SerializationContext { private refs = new Map, Ref>(); constructor(root: Referencable) { - root[REFERENCE__SERIALIZE_ASSIGN_REFS](this, RefHandler.rootPath) + root[REFERENCE_INTERNAL_API].serialize_assignRefs(this, RefHandler.rootPath) } put>(obj: T, ref: Ref) { From aa16b1d8730bf536a33aec1d0847d09d7e542ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 08:31:31 +0200 Subject: [PATCH 16/34] Change API signature to expose Self and Parent as types, to tighten the type bounds. Also include getContainer since it is only used in the API methods --- .../referencing/referencable/referenceable.ts | 118 +++++++++--------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index bc69940..1af6594 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -16,7 +16,6 @@ import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; //private, no export const INIT_REFERENCES = Symbol("initReferences"); -const GET_CONTAINER = Symbol("getContainer"); const REFERENCES_TO_JSON = Symbol("referenceToJson"); const ATTRIBUTES_TO_JSON = Symbol("attributesToJson"); @@ -78,24 +77,7 @@ export abstract class Referencable< }) } - public [REFERENCE_INTERNAL_API]: ReferenceApi = { - - // ****************** inverse handling (called by link containers) ********************** - addToReference: >(name: string, item: U): boolean => { - return this[GET_CONTAINER](name).add(item) - }, - - removeFromReference: >(name: string, item: U, mode: DeletionMode = DeletionMode.RELAXED): boolean => { - let container = this[GET_CONTAINER](name) - let result = container.remove(item, mode) - if (result && mode === DeletionMode.CASCADE && container.isRequired) { - const instance = container.get() - if (instance === undefined || (Array.isArray(instance) && instance.length === 0)) { - container._parent.$destruct(mode) - } - } - return result - }, + public [REFERENCE_INTERNAL_API]: ReferenceApi = { //************** Serialization ************************* @@ -148,37 +130,53 @@ export abstract class Referencable< for (const container of this.$treeChildren) { container.createRefsOnChildren(context, json); } - } - }; + }, + // ****************** inverse handling (called by link containers) ********************** + addToReference: >(name: string, item: U): boolean => { + return this[REFERENCE_INTERNAL_API].getContainer(name).add(item) + }, - // ****************** inverse handling (called by link containers) ********************** + removeFromReference: >(name: string, item: U, mode: DeletionMode = DeletionMode.RELAXED): boolean => { + let container = this[REFERENCE_INTERNAL_API].getContainer(name) + let result = container.remove(item, mode) + if (result && mode === DeletionMode.CASCADE && container.isRequired) { + const instance = container.get() + if (instance === undefined || (Array.isArray(instance) && instance.length === 0)) { + container._parent.$destruct(mode) + } + } + return result + }, - private [GET_CONTAINER]< - T extends Referencable - >(refName: string): ReContainer { - let proto: any = Object.getPrototypeOf(this); - let meta: ReferenceMeta | undefined; - - // Walk up the prototype chain until we find the reference - while (proto) { - const classMeta = proto.$classMeta; - if (classMeta && classMeta.references && refName in classMeta.references) { - meta = classMeta.references[refName]; - break; + getContainer: < + U extends Referencable + >(refName: string): ReContainer => { + let proto: any = Object.getPrototypeOf(this); + let meta: ReferenceMeta | undefined; + // Walk up the prototype chain until we find the reference + while (proto) { + const classMeta = proto.$classMeta; + if (classMeta && classMeta.references && refName in classMeta.references) { + meta = classMeta.references[refName]; + break; + } + proto = Object.getPrototypeOf(proto); } - proto = Object.getPrototypeOf(proto); - } - if (!meta) { - throw new Error(`Reference '${refName}' not found on class '${this.constructor.name}'`); - } - const key: symbol = meta.containerKey!; - const container = (this as any)[key]; - if (!container) { - throw new Error(`Container for reference '${refName}' not initialized`); + if (!meta) { + throw new Error(`Reference '${refName}' not found on class '${this.constructor.name}'`); + } + const key: symbol = meta.containerKey!; + const container = (this as any)[key]; + if (!container) { + throw new Error(`Container for reference '${refName}' not initialized`); + } + return container as ReContainer; } - return container as ReContainer; - } + + + }; + //************** Serialization ************************* @@ -239,28 +237,32 @@ export abstract class Referencable< } -export interface ReferenceApi> { - - // ****************** inverse handling (called by link containers) ********************** - addToReference: >(name: string, item: U) => boolean; - removeFromReference: >( - name: string, - item: U, - mode?: DeletionMode - ) => boolean; - +export interface ReferenceApi< + Self extends Referencable, + Parent extends Referencable +> { //************** Serialization ************************* serialize_assignRefs: (ctx: SerializationContext, path: string) => void; //****************** Deserialization ************************ - deserializeAttributes: >(json: J) => void; - deserializeChildren: >( + deserializeAttributes: >(json: J) => void; + deserializeChildren: >( context: Deserializer, parent: Ref, json: J ) => void; - deserializeOtherReferences: >( + deserializeOtherReferences: >( context: Deserializer, json: J ) => void; + + // ****************** inverse handling (called by link containers) ********************** + addToReference: >(name: string, item: U) => boolean; + removeFromReference: >( + name: string, + item: U, + mode?: DeletionMode + ) => boolean; + getContainer: >(refName: string) => ReContainer; + } \ No newline at end of file From 09c8c3637be3b5445747d1633d5f8a0051a71bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 08:49:39 +0200 Subject: [PATCH 17/34] Move construction of refs from context initialization to ref's toJson --- .../src/lib/referencing/referencable/referenceable.ts | 7 +++++-- .../referencing/test/referencables-with-children.spec.ts | 3 --- .../src/lib/serialization/serialization-context.spec.ts | 3 +-- .../emfular/src/lib/serialization/serialization-context.ts | 6 ------ 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 1af6594..c52b803 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -181,8 +181,11 @@ export abstract class Referencable< //************** Serialization ************************* toJson(ctxOPt?: SerializationContext): JsonOf { - const ctx = ctxOPt ? ctxOPt : new SerializationContext(this) - //todo: this creates one assuming that the current element is root, once we have all parent pointers we can walk up first and then start + const ctx = ctxOPt ?? new SerializationContext() + if(!ctxOPt) {//initialize new context + this[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.rootPath) + //todo: this fills ctx assuming that the current element is the root, once we have all parent pointers we can walk up first and then start + } const json: any = {}; json["eClass"] = this.$getEClass(); //todo not always necessary this[ATTRIBUTES_TO_JSON](json); diff --git a/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts b/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts index 4f7f15d..4455df6 100644 --- a/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts +++ b/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts @@ -7,7 +7,6 @@ import { RootWithChildren, RootWithChildrenJson } from "./referencables-with-children"; -import {SerializationContext} from "../../serialization/serialization-context"; import {RefHandler} from "../ref/ref-handler"; import {Ref} from "../ref/ref"; @@ -79,8 +78,6 @@ describe('ReContainersWithListChild tests', () => { r1.child2.push(r2_1, r2_2) r2_1.child3.push(r3_1) r3_1.link1.push(r1) - const ctx = new SerializationContext(r1) - expect(ctx.get(r3_1).$ref).toEqual("//@child2.0/@child3.0") const r3json: ReChild3Json = { name: 'referencable3', eClass: EClasses.ReChild3, diff --git a/projects/emfular/src/lib/serialization/serialization-context.spec.ts b/projects/emfular/src/lib/serialization/serialization-context.spec.ts index 55a5b92..c5e5261 100644 --- a/projects/emfular/src/lib/serialization/serialization-context.spec.ts +++ b/projects/emfular/src/lib/serialization/serialization-context.spec.ts @@ -1,8 +1,7 @@ import { SerializationContext } from './serialization-context'; -import {ReferencableTester} from "../referencing/test/referencable-tester"; describe('SerializationContext', () => { it('should create an instance', () => { - expect(new SerializationContext(new ReferencableTester())).toBeTruthy(); + expect(new SerializationContext()).toBeTruthy(); }); }); diff --git a/projects/emfular/src/lib/serialization/serialization-context.ts b/projects/emfular/src/lib/serialization/serialization-context.ts index 79fca63..3cd5ede 100644 --- a/projects/emfular/src/lib/serialization/serialization-context.ts +++ b/projects/emfular/src/lib/serialization/serialization-context.ts @@ -1,16 +1,10 @@ import {Referencable} from "../referencing/referencable/referenceable"; import {Ref} from "../referencing/ref/ref"; -import {RefHandler} from "../referencing/ref/ref-handler"; -import {REFERENCE_INTERNAL_API} from "../referencing/referencable/referencable-symbols"; export class SerializationContext { private refs = new Map, Ref>(); - constructor(root: Referencable) { - root[REFERENCE_INTERNAL_API].serialize_assignRefs(this, RefHandler.rootPath) - } - put>(obj: T, ref: Ref) { this.refs.set(obj, ref); } From 7d52e21579fd95ba8fe0515b3a53048a50b202e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 09:12:57 +0200 Subject: [PATCH 18/34] Reorganize referencable methods --- .../referencing/referencable/referenceable.ts | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index c52b803..9e8ed17 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -77,10 +77,57 @@ export abstract class Referencable< }) } + //************** Serialization ************************* + toJson(ctxOPt?: SerializationContext): JsonOf { + const ctx = ctxOPt ?? new SerializationContext() + if(!ctxOPt) {//initialize new context + this[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.rootPath) + //todo: this fills ctx assuming that the current element is the root, once we have all parent pointers we can walk up first and then start + } + const json: any = {}; + json["eClass"] = this.$getEClass(); //todo not always necessary + this[ATTRIBUTES_TO_JSON](json); + this[REFERENCES_TO_JSON](json, ctx); + + return json as JsonOf; + } + + private [ATTRIBUTES_TO_JSON](json: any) { + const ctor = this.constructor as any; + const attributes = getAllAttributes(ctor); + attributes.forEach((options: AttributeOptions, key) => { + if (this.hasOwnProperty(key)) { // skip sibling attributes that are on prototype + let value: any = (this as any)[key]; + //suppress defaults here: + if(value == undefined || value == "" || value ==false || value == options.default) return; + // use right name (jsonName) + if(options.jsonName) { + json[options.jsonName] = value; + } else { + json[key] = value; + } + } + }) + } + + private [REFERENCES_TO_JSON](json: any, ctx: SerializationContext) { + const relevantReferences = [ + ...this.$treeChildren, + ...this.$otherReferences + ]; + + relevantReferences.forEach(child => { + const jsc = child.toJson(ctx) + if (jsc != undefined && !(Array.isArray(jsc) && jsc.length == 0)) { + json[child.referenceName] = jsc + } + }) + } + + public [REFERENCE_INTERNAL_API]: ReferenceApi = { //************** Serialization ************************* - serialize_assignRefs: (ctx: SerializationContext, path: string): void => { const ref: Ref = RefHandler.createRef(path, this.$getEClass()) ctx.put(this, ref) @@ -178,54 +225,6 @@ export abstract class Referencable< }; - //************** Serialization ************************* - - toJson(ctxOPt?: SerializationContext): JsonOf { - const ctx = ctxOPt ?? new SerializationContext() - if(!ctxOPt) {//initialize new context - this[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.rootPath) - //todo: this fills ctx assuming that the current element is the root, once we have all parent pointers we can walk up first and then start - } - const json: any = {}; - json["eClass"] = this.$getEClass(); //todo not always necessary - this[ATTRIBUTES_TO_JSON](json); - this[REFERENCES_TO_JSON](json, ctx); - - return json as JsonOf; - } - - private [ATTRIBUTES_TO_JSON](json: any) { - const ctor = this.constructor as any; - const attributes = getAllAttributes(ctor); - attributes.forEach((options: AttributeOptions, key) => { - if (this.hasOwnProperty(key)) { // skip sibling attributes that are on prototype - let value: any = (this as any)[key]; - //suppress defaults here: - if(value == undefined || value == "" || value ==false || value == options.default) return; - // use right name (jsonName) - if(options.jsonName) { - json[options.jsonName] = value; - } else { - json[key] = value; - } - } - }) - } - - private [REFERENCES_TO_JSON](json: any, ctx: SerializationContext) { - const relevantReferences = [ - ...this.$treeChildren, - ...this.$otherReferences - ]; - - relevantReferences.forEach(child => { - const jsc = child.toJson(ctx) - if (jsc != undefined && !(Array.isArray(jsc) && jsc.length == 0)) { - json[child.referenceName] = jsc - } - }) - } - // ************* container construction ******************* private [INIT_REFERENCES]() { const proto = Object.getPrototypeOf(this); From caf046091d82ec63080f817f059ab9dee0e7f592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 09:34:14 +0200 Subject: [PATCH 19/34] Reove explicit URI since we have the whole modelMeta currently available --- projects/emfular/src/lib/binding/reference-creator.ts | 2 +- .../src/lib/referencing/referencable/container/re-container.ts | 2 +- .../emfular/src/lib/referencing/referencable/referenceable.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/projects/emfular/src/lib/binding/reference-creator.ts b/projects/emfular/src/lib/binding/reference-creator.ts index f38b445..d0cb808 100644 --- a/projects/emfular/src/lib/binding/reference-creator.ts +++ b/projects/emfular/src/lib/binding/reference-creator.ts @@ -35,7 +35,7 @@ export function createContainer< } if (meta.containment) { - const defaultEClass = parent.$modelUri + meta.target; + const defaultEClass = parent.$modelMeta.uri + meta.target; if (isList) { return new ReTreeListContainer(parent, propertyKey, meta, defaultEClass ) } else { diff --git a/projects/emfular/src/lib/referencing/referencable/container/re-container.ts b/projects/emfular/src/lib/referencing/referencable/container/re-container.ts index 0a6864c..837f19e 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/re-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/re-container.ts @@ -36,7 +36,7 @@ export abstract class ReContainer< isAcceptableItem(item: Referencable): boolean { const expectedType = this.meta.target - const targetEclass = this._parent.$modelUri+expectedType //eclass composition only works since we work inside one model + const targetEclass = this._parent.$modelMeta.uri+expectedType //eclass composition only works since we work inside one model let targetConstr = ModelRegistry.get(targetEclass) return item instanceof targetConstr; } diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 9e8ed17..2071944 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -32,7 +32,6 @@ export abstract class Referencable< declare readonly $ParentType: Parent; declare $classMeta: ClassMeta; - declare $modelUri: string; //now inside modelMeta declare $modelMeta: ModelDefinition; private _$parent?: ReTreeChildrenContainer; From d3ae249f1b288df813b26d2a81fd5ef2b19ce30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 10:54:57 +0200 Subject: [PATCH 20/34] Make treechildren private, only expose access on internal API, hence needing to change some tests that expose containers e.g. for removal - which other methods should handle --- .../container/tree/re-tree-single-container.spec.ts | 5 +++-- .../src/lib/referencing/referencable/referenceable.ts | 11 +++++++++-- .../test/re-containers-with-inheritance.spec.ts | 3 ++- .../test/re-containers-with-single-child.spec.ts | 5 +++-- .../test/referencables-with-children.spec.ts | 7 ++++--- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.spec.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.spec.ts index 96ea634..87353ee 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.spec.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.spec.ts @@ -2,6 +2,7 @@ import { ReTreeSingleContainer } from './re-tree-single-container'; import {ReferencableTester, refTesterRef} from "../../../test/referencable-tester"; import {ReContainersWithSingleChild, ReSingleChildExample} from "../../../test/re-containers-with-single-child"; import {DeletionMode} from "../../../../utils/deletion-mode"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; describe('ReferencableTreeSingletonContainer', () => { it('should create an instance', () => { @@ -23,7 +24,7 @@ describe('ReferencableTreeSingletonContainer', () => { expect(middle.otherLink).toEqual(elem1); expect(elem1.link).toBeDefined(); expect(elem1.link).toEqual(middle); - expect(tester.$treeChildren[0].remove(middle)).toBeTrue(); + expect(tester[REFERENCE_INTERNAL_API].treeChildren()[0].remove(middle)).toBeTrue(); expect(tester.child).toBeUndefined(); expect(middle.myParent).toBeUndefined(); expect(middle.otherLink).toBeDefined(); @@ -46,7 +47,7 @@ describe('ReferencableTreeSingletonContainer', () => { expect(middle.otherLink).toEqual(elem1); expect(elem1.link).toBeDefined(); expect(elem1.link).toEqual(middle); - expect(tester.$treeChildren[0].remove(middle, DeletionMode.CASCADE)).toBeTrue(); + expect(tester[REFERENCE_INTERNAL_API].treeChildren()[0].remove(middle, DeletionMode.CASCADE)).toBeTrue(); expect(tester.child).toBeUndefined(); expect(middle.myParent).toBeUndefined(); expect(middle.otherLink).toBeUndefined(); diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 2071944..6a72c98 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -36,7 +36,7 @@ export abstract class Referencable< private _$parent?: ReTreeChildrenContainer; - readonly $treeChildren: ReTreeChildrenContainer[] = []; + private $treeChildren: ReTreeChildrenContainer[] = []; readonly $otherReferences: ReLinkContainer[] = []; protected constructor() { @@ -195,6 +195,10 @@ export abstract class Referencable< return result }, + treeChildren: (): ReTreeChildrenContainer[] => { + return this.$treeChildren + }, + getContainer: < U extends Referencable >(refName: string): ReContainer => { @@ -257,6 +261,10 @@ export interface ReferenceApi< json: J ) => void; + // *************** container accessors ******************* + treeChildren: () => ReTreeChildrenContainer[]; + getContainer: >(refName: string) => ReContainer; + // ****************** inverse handling (called by link containers) ********************** addToReference: >(name: string, item: U) => boolean; removeFromReference: >( @@ -264,6 +272,5 @@ export interface ReferenceApi< item: U, mode?: DeletionMode ) => boolean; - getContainer: >(refName: string) => ReContainer; } \ No newline at end of file diff --git a/projects/emfular/src/lib/referencing/test/re-containers-with-inheritance.spec.ts b/projects/emfular/src/lib/referencing/test/re-containers-with-inheritance.spec.ts index f2177f0..f9a7c72 100644 --- a/projects/emfular/src/lib/referencing/test/re-containers-with-inheritance.spec.ts +++ b/projects/emfular/src/lib/referencing/test/re-containers-with-inheritance.spec.ts @@ -1,5 +1,6 @@ import {A, B, InheritanceRoot, ModelInheritance} from "./re-containers-with-inheritance"; import {ReContainer} from "../referencable/container/re-container"; +import {REFERENCE_INTERNAL_API} from "../referencable/referencable-symbols"; describe("ReferencablesWithInheritance", () => { @@ -29,7 +30,7 @@ describe("ReferencablesWithInheritance", () => { const root = new InheritanceRoot(); const root2 = new InheritanceRoot(); const a = new A(); - let ref = root.$treeChildren[0] as ReContainer; + const ref = root[REFERENCE_INTERNAL_API].treeChildren()[0] as ReContainer; expect(root.children.length).toBe(0); const res = ref.add(root2) expect(res).toBeFalse() diff --git a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts index 1eff08f..1ec8c52 100644 --- a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts +++ b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts @@ -5,6 +5,7 @@ import { } from "./re-containers-with-single-child"; import {Ref} from "../ref/ref"; import {JsonOf} from "../../serialization/json-deserializable"; +import {REFERENCE_INTERNAL_API} from "../referencable/referencable-symbols"; describe('ReContainersWithSingleChild tests', () => { @@ -14,10 +15,10 @@ describe('ReContainersWithSingleChild tests', () => { const child: ReSingleChildExample = new ReSingleChildExample() - expect(root.$treeChildren.length).toBe(1) + expect(root[REFERENCE_INTERNAL_API].treeChildren().length).toBe(1) expect(root.$otherReferences.length).toBe(1) - expect(child.$treeChildren.length).toBe(0) + expect(child[REFERENCE_INTERNAL_API].treeChildren().length).toBe(0) expect(child.$otherReferences.length).toBe(1) }) diff --git a/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts b/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts index 4455df6..8b1b653 100644 --- a/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts +++ b/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts @@ -9,6 +9,7 @@ import { } from "./referencables-with-children"; import {RefHandler} from "../ref/ref-handler"; import {Ref} from "../ref/ref"; +import {REFERENCE_INTERNAL_API} from "../referencable/referencable-symbols"; describe('ReContainersWithListChild tests', () => { @@ -112,13 +113,13 @@ describe('ReContainersWithListChild tests', () => { //todo deserialization test it("should register the containers correctly on the parent", () => { - expect(r1.$treeChildren.length).toBe(1) + expect(r1[REFERENCE_INTERNAL_API].treeChildren().length).toBe(1) expect(r1.$otherReferences.length).toBe(2) - expect(r2_1.$treeChildren.length).toBe(2) + expect(r2_1[REFERENCE_INTERNAL_API].treeChildren().length).toBe(2) expect(r2_1.$otherReferences.length).toBe(0) - expect(r3_1.$treeChildren.length).toBe(0) + expect(r3_1[REFERENCE_INTERNAL_API].treeChildren().length).toBe(0) expect(r1.$otherReferences.length).toBe(2) }) From b8ba06e0a3a161538bd93c5aa36080a4e41a099c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 11:03:52 +0200 Subject: [PATCH 21/34] Also make otherReferences private; on API as otherLinks, now only used in the single case where the proxy exposes no delete from a relationship option --- .../container/link/re-link-list-container.ts | 2 +- .../container/link/re-link-single-container.spec.ts | 9 +++++---- .../container/link/re-link-single-container.ts | 2 +- .../src/lib/referencing/referencable/referenceable.ts | 10 ++++++++-- .../test/re-containers-with-single-child.spec.ts | 5 ++--- .../test/referencables-with-children.spec.ts | 6 +++--- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts index 4835059..86232b5 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts @@ -16,7 +16,7 @@ implements ReLinkContainer { constructor(parent: P, name: string, refMeta: ReferenceMeta) { super(parent, name, refMeta); - this._parent.$otherReferences.push(this) + this._parent[REFERENCE_INTERNAL_API].otherLinks().push(this) } addWithoutTypeCheck(item: T): boolean { diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.spec.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.spec.ts index 5e282f5..4341f74 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.spec.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.spec.ts @@ -7,6 +7,7 @@ import { ReSingleChildExample2 } from "../../../test/re-containers-with-single-child"; import {DeletionMode} from "../../../../utils/deletion-mode"; +import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; describe('ReLinkSingleContainer', () => { it('should create an instance', () => { @@ -41,8 +42,8 @@ describe('ReLinkSingleContainer', () => { expect(elem1.link).toEqual(middle1); expect(elem2.link).toBeDefined(); expect(elem2.link).toEqual(middle2); - expect(elem1.$otherReferences[0].remove(middle1)).toBeTrue(); - expect(elem2.$otherReferences[0].remove(middle2)).toBeTrue(); + expect(elem1[REFERENCE_INTERNAL_API].otherLinks()[0].remove(middle1)).toBeTrue(); + expect(elem2[REFERENCE_INTERNAL_API].otherLinks()[0].remove(middle2)).toBeTrue(); expect(tester1.child).toBeDefined(); expect(tester1.child).toEqual(middle1); expect(tester2.child).toBeDefined(); @@ -84,8 +85,8 @@ describe('ReLinkSingleContainer', () => { expect(elem1.link).toEqual(middle1); expect(elem2.link).toBeDefined(); expect(elem2.link).toEqual(middle2); - expect(elem1.$otherReferences[0].remove(middle1, DeletionMode.CASCADE)).toBeTrue(); - expect(elem2.$otherReferences[0].remove(middle2, DeletionMode.CASCADE)).toBeTrue(); + expect(elem1[REFERENCE_INTERNAL_API].otherLinks()[0].remove(middle1, DeletionMode.CASCADE)).toBeTrue(); + expect(elem2[REFERENCE_INTERNAL_API].otherLinks()[0].remove(middle2, DeletionMode.CASCADE)).toBeTrue(); expect(tester1.child).toBeDefined(); expect(tester1.child).toEqual(middle1); expect(tester2.child).toBeUndefined(); diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts index 585d669..383ff67 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-single-container.ts @@ -15,7 +15,7 @@ implements ReLinkContainer { constructor(parent: P, referenceName: string, refMeta: ReferenceMeta) { super(parent, referenceName, refMeta); - this._parent.$otherReferences.push(this) + this._parent[REFERENCE_INTERNAL_API].otherLinks().push(this) } protected set(instance: T): void { diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 6a72c98..73ab2a1 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -37,7 +37,7 @@ export abstract class Referencable< private _$parent?: ReTreeChildrenContainer; private $treeChildren: ReTreeChildrenContainer[] = []; - readonly $otherReferences: ReLinkContainer[] = []; + private $otherReferences: ReLinkContainer[] = []; protected constructor() { this.$gId = uuidv4(); @@ -199,7 +199,12 @@ export abstract class Referencable< return this.$treeChildren }, - getContainer: < + otherLinks: (): ReLinkContainer[] => { + return this.$otherReferences + }, + + + getContainer: < U extends Referencable >(refName: string): ReContainer => { let proto: any = Object.getPrototypeOf(this); @@ -263,6 +268,7 @@ export interface ReferenceApi< // *************** container accessors ******************* treeChildren: () => ReTreeChildrenContainer[]; + otherLinks: () => ReLinkContainer[]; getContainer: >(refName: string) => ReContainer; // ****************** inverse handling (called by link containers) ********************** diff --git a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts index 1ec8c52..846be01 100644 --- a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts +++ b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts @@ -16,10 +16,10 @@ describe('ReContainersWithSingleChild tests', () => { expect(root[REFERENCE_INTERNAL_API].treeChildren().length).toBe(1) - expect(root.$otherReferences.length).toBe(1) + expect(root[REFERENCE_INTERNAL_API].otherLinks().length).toBe(1) expect(child[REFERENCE_INTERNAL_API].treeChildren().length).toBe(0) - expect(child.$otherReferences.length).toBe(1) + expect(child[REFERENCE_INTERNAL_API].otherLinks().length).toBe(1) }) it('should manage parent pointers correctly', () => { @@ -84,7 +84,6 @@ describe('ReContainersWithSingleChild tests', () => { //todo: must compile withoutcast for correct jsonOf: let ref: Ref|undefined = completeJson?.link as unknown as Ref expect(ref.eClass).toEqual(EClassesSingleChild.ReSingleChildExample) - const childJson: JsonOf |undefined = completeJson.child; const completeFromJson : ReContainersWithSingleChild = ReContainersWithSingleChild.fromJSON(completeJson) expect(completeFromJson.name).toEqual(root.name) expect(completeFromJson.link).toEqual(completeFromJson.child) diff --git a/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts b/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts index 8b1b653..a99fec0 100644 --- a/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts +++ b/projects/emfular/src/lib/referencing/test/referencables-with-children.spec.ts @@ -114,13 +114,13 @@ describe('ReContainersWithListChild tests', () => { it("should register the containers correctly on the parent", () => { expect(r1[REFERENCE_INTERNAL_API].treeChildren().length).toBe(1) - expect(r1.$otherReferences.length).toBe(2) + expect(r1[REFERENCE_INTERNAL_API].otherLinks().length).toBe(2) expect(r2_1[REFERENCE_INTERNAL_API].treeChildren().length).toBe(2) - expect(r2_1.$otherReferences.length).toBe(0) + expect(r2_1[REFERENCE_INTERNAL_API].otherLinks().length).toBe(0) expect(r3_1[REFERENCE_INTERNAL_API].treeChildren().length).toBe(0) - expect(r1.$otherReferences.length).toBe(2) + expect(r1[REFERENCE_INTERNAL_API].otherLinks().length).toBe(2) }) it('should allow swapping elements in a ModelList created via decorators', () => { From 9a11c4dfe15be47ad6700b0a1c63c0ff2cf19251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 11:43:12 +0200 Subject: [PATCH 22/34] private symbols for treeCHildren and links, now showing problem on tree containers with direct usage of push --- .../container/tree/re-tree-list-container.ts | 2 +- .../tree/re-tree-single-container.ts | 2 +- .../referencing/referencable/referenceable.ts | 42 +++++++++---------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 3ed5b7f..4339617 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -19,7 +19,7 @@ implements ReTreeChildrenContainer { constructor(parent: T["$ParentType"], name: string, refMeta: ReferenceMeta, eClass?: string) { super(parent, name, refMeta); this.defaultEClass = eClass; - this._parent.$treeChildren.push(this) + this._parent[REFERENCE_INTERNAL_API].treeChildren().push(this) } assignRefs(ctx: SerializationContext, path: string) { diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 6f89874..d3bdfa1 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -18,7 +18,7 @@ implements ReTreeChildrenContainer { constructor(parent: T["$ParentType"], referenceName: string, refMeta: ReferenceMeta, eClass?: string) { super(parent, referenceName, refMeta); this.defaultEClass = eClass; - this._parent.$treeChildren.push(this) + this._parent[REFERENCE_INTERNAL_API].treeChildren().push(this) } assignRefs(ctx: SerializationContext, path: string) { diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 73ab2a1..404f48b 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -15,9 +15,12 @@ import {DeletionMode} from "../../utils/deletion-mode"; import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; //private, no export -const INIT_REFERENCES = Symbol("initReferences"); +const TREE_CHILDREN = Symbol("treeChildren"); +const LINKS = Symbol("links"); + const REFERENCES_TO_JSON = Symbol("referenceToJson"); const ATTRIBUTES_TO_JSON = Symbol("attributesToJson"); +const INIT_REFERENCES = Symbol("initReferences"); /** base class for CORE models. @@ -36,8 +39,8 @@ export abstract class Referencable< private _$parent?: ReTreeChildrenContainer; - private $treeChildren: ReTreeChildrenContainer[] = []; - private $otherReferences: ReLinkContainer[] = []; + private [TREE_CHILDREN]: ReTreeChildrenContainer[] = []; + private [LINKS]: ReLinkContainer[] = []; protected constructor() { this.$gId = uuidv4(); @@ -45,17 +48,15 @@ export abstract class Referencable< } // ************* public modeling API ******************** + get $parent(): ReTreeChildrenContainer | undefined { + return this._$parent + } set $parent(parent: ReTreeChildrenContainer | undefined) { if(this._$parent) { this._$parent.remove(this) } this._$parent = parent; } - - get $parent(): ReTreeChildrenContainer | undefined { - return this._$parent - } - $getParentReferencable(): Parent | undefined { return this._$parent?._parent } @@ -68,10 +69,10 @@ export abstract class Referencable< // removal from parent is always called with deletion mode RELAXED, otherwise infinite loops occur (see remove in re-tree-list/single-container.ts) // tests in files re-link-list/single-container.spec.ts and re-tree-list/single-container.spec.ts fail when not setting RELAXED mode explicitly this._$parent?.remove(this, DeletionMode.RELAXED) - this.$otherReferences.forEach(refContainer => { + this[LINKS].forEach(refContainer => { refContainer.removeFromInverse(this, mode) }) - this.$treeChildren.forEach(child => { + this[TREE_CHILDREN].forEach(child => { child.delete(mode) }) } @@ -111,8 +112,8 @@ export abstract class Referencable< private [REFERENCES_TO_JSON](json: any, ctx: SerializationContext) { const relevantReferences = [ - ...this.$treeChildren, - ...this.$otherReferences + ...this[TREE_CHILDREN], + ...this[LINKS] ]; relevantReferences.forEach(child => { @@ -130,7 +131,7 @@ export abstract class Referencable< serialize_assignRefs: (ctx: SerializationContext, path: string): void => { const ref: Ref = RefHandler.createRef(path, this.$getEClass()) ctx.put(this, ref) - for(let child of this.$treeChildren) { + for(let child of this[TREE_CHILDREN]) { child.assignRefs(ctx, path) } }, @@ -154,7 +155,7 @@ export abstract class Referencable< parent: Ref, json: J ): void => { - this.$treeChildren.forEach(child => { + this[TREE_CHILDREN].forEach(child => { child.fromJson(parent.$ref, context, json); }); }, @@ -164,7 +165,7 @@ export abstract class Referencable< jsonTyped: J ): void => { const json = jsonTyped as any; - for (const container of this.$otherReferences) { + for (const container of this[LINKS]) { let jsonElem: Ref[] | Ref | undefined = json[container.referenceName]; if (jsonElem != undefined) { const refArray = Array.isArray(jsonElem) ? jsonElem : [jsonElem]; @@ -173,7 +174,7 @@ export abstract class Referencable< }); } } - for (const container of this.$treeChildren) { + for (const container of this[TREE_CHILDREN]) { container.createRefsOnChildren(context, json); } }, @@ -195,13 +196,8 @@ export abstract class Referencable< return result }, - treeChildren: (): ReTreeChildrenContainer[] => { - return this.$treeChildren - }, - - otherLinks: (): ReLinkContainer[] => { - return this.$otherReferences - }, + treeChildren: (): ReTreeChildrenContainer[] => this[TREE_CHILDREN], + otherLinks: (): ReLinkContainer[] => this[LINKS], getContainer: < From 3d336d5d453752a83935e356d6138f08b99ad0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 12:32:35 +0200 Subject: [PATCH 23/34] Precise typing to make sure that Referencable of P is kept as info --- .../referencable/container/tree/re-tree-list-container.ts | 6 ++++-- .../container/tree/re-tree-single-container.ts | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 4339617..e0faf8b 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -10,8 +10,10 @@ import {ReListContainer} from "../re-list-container"; import {ReferenceMeta} from "../../../../binding/model-definition"; import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; -export class ReTreeListContainer> - extends ReListContainer +export class ReTreeListContainer< + T extends Referencable

, + P extends Referencable =T["$ParentType"] +> extends ReListContainer implements ReTreeChildrenContainer { readonly defaultEClass?: string; diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index d3bdfa1..271fce6 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -9,13 +9,15 @@ import {ReferenceMeta} from "../../../../binding/model-definition"; import {DeletionMode} from "../../../../utils/deletion-mode"; import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; -export class ReTreeSingleContainer> - extends ReSingleContainer +export class ReTreeSingleContainer< + T extends Referencable

, + P extends Referencable =T["$ParentType"] +> extends ReSingleContainer implements ReTreeChildrenContainer { readonly defaultEClass?: string; - constructor(parent: T["$ParentType"], referenceName: string, refMeta: ReferenceMeta, eClass?: string) { + constructor(parent: P, referenceName: string, refMeta: ReferenceMeta, eClass?: string) { super(parent, referenceName, refMeta); this.defaultEClass = eClass; this._parent[REFERENCE_INTERNAL_API].treeChildren().push(this) From 3c96937ee6597b288888201f3a0e5268dc2bf77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 12:39:18 +0200 Subject: [PATCH 24/34] Apply same typing to tree interface --- .../referencable/container/tree/re-tree-children-container.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts index d5060f1..e38164b 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts @@ -5,7 +5,8 @@ import { ReContainer } from "../re-container"; import {JsonOf} from "../../../../serialization/json-deserializable"; export interface ReTreeChildrenContainer< - T extends Referencable, + T extends Referencable

, + P extends Referencable =T["$ParentType"] > extends ReContainer { // serialization From a918fc497748068e6d9785b657d1896b965d39fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Mon, 1 Jun 2026 12:45:43 +0200 Subject: [PATCH 25/34] Use P, not the T[Parent] for all wiring in order to keep the type explicit --- .../referencable/container/tree/re-tree-children-container.ts | 2 +- .../referencable/container/tree/re-tree-list-container.ts | 4 ++-- .../emfular/src/lib/referencing/referencable/referenceable.ts | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts index e38164b..247adc8 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-children-container.ts @@ -7,7 +7,7 @@ import {JsonOf} from "../../../../serialization/json-deserializable"; export interface ReTreeChildrenContainer< T extends Referencable

, P extends Referencable =T["$ParentType"] -> extends ReContainer { +> extends ReContainer { // serialization assignRefs(ctx: SerializationContext, path: string) : void diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index e0faf8b..b413d36 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -13,12 +13,12 @@ import {REFERENCE_INTERNAL_API} from "../../referencable-symbols"; export class ReTreeListContainer< T extends Referencable

, P extends Referencable =T["$ParentType"] -> extends ReListContainer +> extends ReListContainer implements ReTreeChildrenContainer { readonly defaultEClass?: string; - constructor(parent: T["$ParentType"], name: string, refMeta: ReferenceMeta, eClass?: string) { + constructor(parent: P, name: string, refMeta: ReferenceMeta, eClass?: string) { super(parent, name, refMeta); this.defaultEClass = eClass; this._parent[REFERENCE_INTERNAL_API].treeChildren().push(this) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 404f48b..f61bcce 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -32,11 +32,10 @@ export abstract class Referencable< $gId: string; //graphical ID - declare readonly $ParentType: Parent; - declare $classMeta: ClassMeta; declare $modelMeta: ModelDefinition; + declare readonly $ParentType: Parent; private _$parent?: ReTreeChildrenContainer; private [TREE_CHILDREN]: ReTreeChildrenContainer[] = []; From 0de5ef9dfd3f8498688dd4cee9085504bf5ff49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:07:20 +0200 Subject: [PATCH 26/34] parent containers on API but with less precise typing --- .../lib/referencing/referencable/referenceable.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index f61bcce..04a0f29 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -222,6 +222,16 @@ export abstract class Referencable< throw new Error(`Container for reference '${refName}' not initialized`); } return container as ReContainer; + }, + // parent + getParentContainer: (): ReTreeChildrenContainer | undefined => { + return this._$parent; + }, + setParentContainer: (parent: ReTreeChildrenContainer | undefined): void => { + if (this._$parent) { + this._$parent.remove(this); + } + this._$parent = parent; } @@ -265,6 +275,9 @@ export interface ReferenceApi< treeChildren: () => ReTreeChildrenContainer[]; otherLinks: () => ReLinkContainer[]; getContainer: >(refName: string) => ReContainer; + // parent + getParentContainer: () => ReTreeChildrenContainer|undefined, + setParentContainer: (parent: ReTreeChildrenContainer|undefined) => void; // ****************** inverse handling (called by link containers) ********************** addToReference: >(name: string, item: U) => boolean; From feb192dbd77b6eb0d52b709852e3b715ebd7f2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:12:20 +0200 Subject: [PATCH 27/34] Tight getter, still any on setter --- .../src/lib/referencing/referencable/referenceable.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 04a0f29..f6b8f74 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -13,6 +13,7 @@ import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; +import {Self} from "@angular/core"; //private, no export const TREE_CHILDREN = Symbol("treeChildren"); @@ -224,7 +225,7 @@ export abstract class Referencable< return container as ReContainer; }, // parent - getParentContainer: (): ReTreeChildrenContainer | undefined => { + getParentContainer: (): ReTreeChildrenContainer | undefined => { return this._$parent; }, setParentContainer: (parent: ReTreeChildrenContainer | undefined): void => { @@ -276,7 +277,7 @@ export interface ReferenceApi< otherLinks: () => ReLinkContainer[]; getContainer: >(refName: string) => ReContainer; // parent - getParentContainer: () => ReTreeChildrenContainer|undefined, + getParentContainer: () => ReTreeChildrenContainer|undefined, setParentContainer: (parent: ReTreeChildrenContainer|undefined) => void; // ****************** inverse handling (called by link containers) ********************** From 99fd01103ab2e3b28a808fab052691efece9b164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:20:04 +0200 Subject: [PATCH 28/34] Contravariance on set enforced via generic parameter on set --- .../src/lib/referencing/referencable/referenceable.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index f6b8f74..8e040f6 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -13,7 +13,6 @@ import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; -import {Self} from "@angular/core"; //private, no export const TREE_CHILDREN = Symbol("treeChildren"); @@ -228,17 +227,15 @@ export abstract class Referencable< getParentContainer: (): ReTreeChildrenContainer | undefined => { return this._$parent; }, - setParentContainer: (parent: ReTreeChildrenContainer | undefined): void => { + setParentContainer: (parent: ReTreeChildrenContainer | undefined): void => { if (this._$parent) { this._$parent.remove(this); } - this._$parent = parent; + this._$parent = (parent as (ReTreeChildrenContainer | undefined)); } - }; - // ************* container construction ******************* private [INIT_REFERENCES]() { const proto = Object.getPrototypeOf(this); @@ -278,7 +275,7 @@ export interface ReferenceApi< getContainer: >(refName: string) => ReContainer; // parent getParentContainer: () => ReTreeChildrenContainer|undefined, - setParentContainer: (parent: ReTreeChildrenContainer|undefined) => void; + setParentContainer: (parent: ReTreeChildrenContainer|undefined) => void; // ****************** inverse handling (called by link containers) ********************** addToReference: >(name: string, item: U) => boolean; From 19de7168c603c121d2f2ec7ac205dfcdda6b64df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:36:17 +0200 Subject: [PATCH 29/34] remove container methods from public API --- .../container/tree/re-tree-list-container.ts | 6 +++--- .../container/tree/re-tree-single-container.ts | 6 +++--- .../src/lib/referencing/referencable/referenceable.ts | 9 --------- .../test/re-containers-with-single-child.spec.ts | 6 +++--- projects/emfular/src/lib/utils/list-updater.ts | 3 ++- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index b413d36..25ee5e7 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -39,11 +39,11 @@ implements ReTreeChildrenContainer { //todo rewrite without using item parent explicitly? addWithoutTypeCheck(item: T): boolean { - const oldParent = item.$parent; + const oldParent = item[REFERENCE_INTERNAL_API].getParentContainer(); if(oldParent == this) { return false; } else { - item.$parent = this; + item[REFERENCE_INTERNAL_API].setParentContainer(this); oldParent?.remove(item) return ListUpdater.addToListIfMissing(item, this._instance) } @@ -61,7 +61,7 @@ implements ReTreeChildrenContainer { } let removed = ListUpdater.removeFromList(item, this._instance) if(removed){ - item.$parent = undefined; + item[REFERENCE_INTERNAL_API].setParentContainer(undefined); return true } return false; diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts index 271fce6..a4bc81e 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-single-container.ts @@ -35,7 +35,7 @@ implements ReTreeChildrenContainer { if(item == this._instance) { return false; } else { - item.$parent = this; + item[REFERENCE_INTERNAL_API].setParentContainer(this); this._instance = item; return true; } @@ -45,7 +45,7 @@ implements ReTreeChildrenContainer { if(this._instance == item) { if (mode === DeletionMode.RELAXED) { this._instance = undefined; - item.$parent = undefined; + item[REFERENCE_INTERNAL_API].setParentContainer(undefined); return true; } // if remove is called on an items parent the CASCADE mode would cause an infinite loop, @@ -60,7 +60,7 @@ implements ReTreeChildrenContainer { if (mode === DeletionMode.CASCADE) { this._instance?.$destruct(mode) } else if (mode === DeletionMode.RELAXED) { - this._instance?.$parent?.remove(this._instance, mode) + this._instance?.[REFERENCE_INTERNAL_API].getParentContainer()?.remove(this._instance, mode) } } diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 8e040f6..1b86d81 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -47,15 +47,6 @@ export abstract class Referencable< } // ************* public modeling API ******************** - get $parent(): ReTreeChildrenContainer | undefined { - return this._$parent - } - set $parent(parent: ReTreeChildrenContainer | undefined) { - if(this._$parent) { - this._$parent.remove(this) - } - this._$parent = parent; - } $getParentReferencable(): Parent | undefined { return this._$parent?._parent } diff --git a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts index 846be01..11515c5 100644 --- a/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts +++ b/projects/emfular/src/lib/referencing/test/re-containers-with-single-child.spec.ts @@ -24,14 +24,14 @@ describe('ReContainersWithSingleChild tests', () => { it('should manage parent pointers correctly', () => { const root: ReContainersWithSingleChild = new ReContainersWithSingleChild(); - expect(root.$parent).toBeUndefined() + expect(root[REFERENCE_INTERNAL_API].getParentContainer()).toBeUndefined() expect(root.child).toBeUndefined() const child: ReSingleChildExample = new ReSingleChildExample(); expect(child.myParent).toBeUndefined() - expect(child.$parent).toBeUndefined() + expect(child[REFERENCE_INTERNAL_API].getParentContainer()).toBeUndefined() //set tree parent: child.myParent = root; - expect(child.$parent).toBeDefined() + expect(child[REFERENCE_INTERNAL_API].getParentContainer()).toBeDefined() expect(child.myParent).toEqual(root); expect(root.child).toBe(child); diff --git a/projects/emfular/src/lib/utils/list-updater.ts b/projects/emfular/src/lib/utils/list-updater.ts index 945872d..b4357c4 100644 --- a/projects/emfular/src/lib/utils/list-updater.ts +++ b/projects/emfular/src/lib/utils/list-updater.ts @@ -1,5 +1,6 @@ import {Referencable} from "../referencing/referencable/referenceable"; import { DeletionMode } from "./deletion-mode"; +import {REFERENCE_INTERNAL_API} from "../referencing/referencable/referencable-symbols"; export class ListUpdater { @@ -31,7 +32,7 @@ export class ListUpdater { if (mode === DeletionMode.CASCADE) { list[0].$destruct(mode) } else if (mode === DeletionMode.RELAXED) { - list[0].$parent?.remove(list[0], mode) + list[0][REFERENCE_INTERNAL_API].getParentContainer()?.remove(list[0], mode) } } } From bb426e98b1720850433c0670d525dd155aea8e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:39:16 +0200 Subject: [PATCH 30/34] Remove overwrite that has same behaviour as base version --- .../referencable/container/link/re-link-list-container.ts | 4 ---- .../referencable/container/tree/re-tree-list-container.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts index 86232b5..2db6574 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/link/re-link-list-container.ts @@ -45,10 +45,6 @@ implements ReLinkContainer { return res; //todo behaviour of flag different to add?? } - override delete(mode: DeletionMode = DeletionMode.RELAXED) { - ListUpdater.destructAllFromChangingList(this._instance, mode) - } - removeFromInverse(item: T, mode: DeletionMode = DeletionMode.RELAXED): boolean { if(this.inverseName !== undefined) { for (const child of [...this._instance]) { diff --git a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts index 25ee5e7..c3b6257 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/tree/re-tree-list-container.ts @@ -67,10 +67,6 @@ implements ReTreeChildrenContainer { return false; } - override delete(mode: DeletionMode = DeletionMode.RELAXED) { - ListUpdater.destructAllFromChangingList(this._instance, mode) - } - //creates one child level plus calls next createChildren fromJson(formerPrefix: string, context: Deserializer, json: any) { let myJson: JsonOf[] = json[this.referenceName]; From ab354933068ce2e93109145cd7e7e14bc542080c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:44:26 +0200 Subject: [PATCH 31/34] rename user facing parent to getEParent to encode that it is the parent in the Ecore sense --- .../referencable/container/shallow/re-tree-parent-container.ts | 2 +- .../emfular/src/lib/referencing/referencable/referenceable.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts index 98ea4ca..ef626f3 100644 --- a/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts +++ b/projects/emfular/src/lib/referencing/referencable/container/shallow/re-tree-parent-container.ts @@ -19,7 +19,7 @@ implements ReSingleInterface, } get(): P | undefined { - return (this._parent.$getParentReferencable()) + return (this._parent.$getEParent()) } //todo rewrite without using item parent explicitly? diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 1b86d81..67e9121 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -47,7 +47,7 @@ export abstract class Referencable< } // ************* public modeling API ******************** - $getParentReferencable(): Parent | undefined { + $getEParent(): Parent | undefined { return this._$parent?._parent } From bd2924cbd6d7d76c16831513ccf946da8960265f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 09:47:20 +0200 Subject: [PATCH 32/34] hide internal paren container ref behind symbol --- .../lib/referencing/referencable/referenceable.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 67e9121..83dc9e5 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -17,6 +17,7 @@ import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; //private, no export const TREE_CHILDREN = Symbol("treeChildren"); const LINKS = Symbol("links"); +const PARENT = Symbol("parent"); const REFERENCES_TO_JSON = Symbol("referenceToJson"); const ATTRIBUTES_TO_JSON = Symbol("attributesToJson"); @@ -36,7 +37,7 @@ export abstract class Referencable< declare $modelMeta: ModelDefinition; declare readonly $ParentType: Parent; - private _$parent?: ReTreeChildrenContainer; + private [PARENT]?: ReTreeChildrenContainer; private [TREE_CHILDREN]: ReTreeChildrenContainer[] = []; private [LINKS]: ReLinkContainer[] = []; @@ -48,7 +49,7 @@ export abstract class Referencable< // ************* public modeling API ******************** $getEParent(): Parent | undefined { - return this._$parent?._parent + return this[PARENT]?._parent } $getEClass(): string { @@ -58,7 +59,7 @@ export abstract class Referencable< $destruct(mode: DeletionMode = DeletionMode.RELAXED) { // removal from parent is always called with deletion mode RELAXED, otherwise infinite loops occur (see remove in re-tree-list/single-container.ts) // tests in files re-link-list/single-container.spec.ts and re-tree-list/single-container.spec.ts fail when not setting RELAXED mode explicitly - this._$parent?.remove(this, DeletionMode.RELAXED) + this[PARENT]?.remove(this, DeletionMode.RELAXED) this[LINKS].forEach(refContainer => { refContainer.removeFromInverse(this, mode) }) @@ -216,13 +217,13 @@ export abstract class Referencable< }, // parent getParentContainer: (): ReTreeChildrenContainer | undefined => { - return this._$parent; + return this[PARENT]; }, setParentContainer: (parent: ReTreeChildrenContainer | undefined): void => { - if (this._$parent) { - this._$parent.remove(this); + if (this[PARENT]) { + this[PARENT].remove(this); } - this._$parent = (parent as (ReTreeChildrenContainer | undefined)); + this[PARENT] = (parent as (ReTreeChildrenContainer | undefined)); } }; From 337d77893e2106c54b43ed65ca6f2fb63711eac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Wed, 3 Jun 2026 10:02:19 +0200 Subject: [PATCH 33/34] use traversal to root to then strt assigning refs from there, instead of teh former assumption to be only called from there --- .../src/lib/referencing/referencable/referenceable.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index 83dc9e5..d9261c3 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -72,8 +72,15 @@ export abstract class Referencable< toJson(ctxOPt?: SerializationContext): JsonOf { const ctx = ctxOPt ?? new SerializationContext() if(!ctxOPt) {//initialize new context - this[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.rootPath) - //todo: this fills ctx assuming that the current element is the root, once we have all parent pointers we can walk up first and then start + //1) first find the root + let root: Referencable|undefined = this + let oldRoot: Referencable|undefined = this + while (root !== undefined) { + oldRoot = root + root = root.$getEParent() + } + //2) then assign refs from the root down + oldRoot[REFERENCE_INTERNAL_API].serialize_assignRefs(ctx, RefHandler.rootPath) } const json: any = {}; json["eClass"] = this.$getEClass(); //todo not always necessary From dbf708b734570e4c05b3fa6a27ffe9ecf5689f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Susanne=20G=C3=B6bel?= Date: Fri, 5 Jun 2026 08:58:46 +0200 Subject: [PATCH 34/34] Make __referenceInitializers symbol hidden, as suggested by @Noah1891 in https://github.com/softlang/EMFular/pull/32#pullrequestreview-4420907811_ --- .../emfular/src/lib/binding/reference-decorator.ts | 8 ++++---- .../referencable/referencable-symbols.ts | 14 ++++---------- .../lib/referencing/referencable/referenceable.ts | 4 ++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/projects/emfular/src/lib/binding/reference-decorator.ts b/projects/emfular/src/lib/binding/reference-decorator.ts index 1a5b759..16be0d7 100644 --- a/projects/emfular/src/lib/binding/reference-decorator.ts +++ b/projects/emfular/src/lib/binding/reference-decorator.ts @@ -4,6 +4,7 @@ import {createContainer} from "./reference-creator"; import {ReSingleInterface} from "../referencing/referencable/container/re-single-interface"; import {KindFromMeta, RefineReference} from "./reference-typing"; import {ReListInterface} from "../referencing/referencable/container/re-list-interface"; +import {REFERENCE_INITIALIZERS} from "../referencing/referencable/referencable-symbols"; export function reference, M extends ReferenceMeta>( meta: M @@ -65,11 +66,10 @@ export function reference, M extends ReferenceMeta>( } - if (!prototype.__referenceInitializers) { - prototype.__referenceInitializers = []; + if (!prototype[REFERENCE_INITIALIZERS]) { + prototype[REFERENCE_INITIALIZERS] = []; } - - (prototype.__referenceInitializers as Array<(this: any) => void>) + (prototype[REFERENCE_INITIALIZERS] as Array<(this: any) => void>) .push(function (this: any) { this[symbol] = createContainer( this, meta, String(propertyKey) diff --git a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts index c34b658..3aab504 100644 --- a/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts +++ b/projects/emfular/src/lib/referencing/referencable/referencable-symbols.ts @@ -1,10 +1,4 @@ - -//************** Serialization ************************* -export const REFERENCE__SERIALIZE_ASSIGN_REFS = Symbol("serialize_assignRefs") -//****************** Deserialization ************************ -export const REFERENCE__DESERIALIZE_ATTRIBUTES = Symbol("deserialize_attributes") -export const REFERENCE__DESERIALIZE_CHILDREN = Symbol("deserialize_children") -export const REFERENCE__DESERIALIZE_OTHER_REFERENCES = Symbol("deserialize_other_references") - - -export const REFERENCE_INTERNAL_API = Symbol("reference_internal_api"); \ No newline at end of file +// internal API of referencable +export const REFERENCE_INTERNAL_API = Symbol("reference_internal_api"); +// initialization hook for all hidden containers, called on Referencable construction +export const REFERENCE_INITIALIZERS = Symbol("referenceInitializers"); diff --git a/projects/emfular/src/lib/referencing/referencable/referenceable.ts b/projects/emfular/src/lib/referencing/referencable/referenceable.ts index d9261c3..2b4701c 100644 --- a/projects/emfular/src/lib/referencing/referencable/referenceable.ts +++ b/projects/emfular/src/lib/referencing/referencable/referenceable.ts @@ -12,7 +12,7 @@ import {ReLinkContainer} from "./container/link/re-link-container"; import {ModelRegistry} from "../../binding/model-registry"; import {ClassMeta, ModelDefinition, ReferenceMeta} from "../../binding/model-definition"; import {DeletionMode} from "../../utils/deletion-mode"; -import {REFERENCE_INTERNAL_API} from "./referencable-symbols"; +import {REFERENCE_INITIALIZERS, REFERENCE_INTERNAL_API} from "./referencable-symbols"; //private, no export const TREE_CHILDREN = Symbol("treeChildren"); @@ -238,7 +238,7 @@ export abstract class Referencable< // ************* container construction ******************* private [INIT_REFERENCES]() { const proto = Object.getPrototypeOf(this); - const inits = proto.__referenceInitializers; + const inits = proto[REFERENCE_INITIALIZERS]; if (inits) { for (const init of inits) { init.call(this);