@lionweb/class-core 0.7.0-beta.1 → 0.7.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/base-types.d.ts.map +1 -1
- package/dist/base-types.js.map +1 -1
- package/dist/convenience.d.ts.map +1 -1
- package/dist/deltas/appliers.d.ts +3 -2
- package/dist/deltas/appliers.d.ts.map +1 -1
- package/dist/deltas/appliers.js +362 -160
- package/dist/deltas/appliers.js.map +1 -1
- package/dist/deltas/handlers.d.ts.map +1 -1
- package/dist/deltas/inverters.d.ts.map +1 -1
- package/dist/deltas/inverters.js +65 -26
- package/dist/deltas/inverters.js.map +1 -1
- package/dist/deltas/serialization/deserializer.g.d.ts.map +1 -1
- package/dist/deltas/serialization/deserializer.g.js +168 -57
- package/dist/deltas/serialization/deserializer.g.js.map +1 -1
- package/dist/deltas/serialization/serializer-helpers.d.ts.map +1 -1
- package/dist/deltas/serialization/serializer.g.d.ts +2 -2
- package/dist/deltas/serialization/serializer.g.d.ts.map +1 -1
- package/dist/deltas/serialization/serializer.g.js +186 -47
- package/dist/deltas/serialization/serializer.g.js.map +1 -1
- package/dist/deltas/serialization/types.g.d.ts +156 -43
- package/dist/deltas/serialization/types.g.d.ts.map +1 -1
- package/dist/deltas/types.g.d.ts +155 -55
- package/dist/deltas/types.g.d.ts.map +1 -1
- package/dist/deltas/types.g.js +170 -57
- package/dist/deltas/types.g.js.map +1 -1
- package/dist/deserializer.d.ts.map +1 -1
- package/dist/deserializer.js +4 -4
- package/dist/deserializer.js.map +1 -1
- package/dist/duplicator.d.ts.map +1 -1
- package/dist/duplicator.js.map +1 -1
- package/dist/factory.d.ts +7 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +44 -0
- package/dist/factory.js.map +1 -0
- package/dist/id-mapping.d.ts +3 -0
- package/dist/id-mapping.d.ts.map +1 -1
- package/dist/id-mapping.js +3 -0
- package/dist/id-mapping.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/serializer.d.ts.map +1 -1
- package/dist/textualizer.d.ts +1 -1
- package/dist/textualizer.d.ts.map +1 -1
- package/dist/value-managers/annotations.d.ts +5 -0
- package/dist/value-managers/annotations.d.ts.map +1 -1
- package/dist/value-managers/annotations.js +30 -1
- package/dist/value-managers/annotations.js.map +1 -1
- package/dist/value-managers/base.d.ts.map +1 -1
- package/dist/value-managers/containments.d.ts +3 -0
- package/dist/value-managers/containments.d.ts.map +1 -1
- package/dist/value-managers/containments.js +78 -8
- package/dist/value-managers/containments.js.map +1 -1
- package/dist/value-managers/properties.js.map +1 -1
- package/dist/value-managers/references.d.ts +3 -0
- package/dist/value-managers/references.d.ts.map +1 -1
- package/dist/value-managers/references.js +26 -8
- package/dist/value-managers/references.js.map +1 -1
- package/package.json +7 -10
- package/src/base-types.ts +0 -1
- package/src/deltas/appliers.ts +380 -184
- package/src/deltas/inverters.ts +83 -35
- package/src/deltas/serialization/deserializer.g.ts +195 -66
- package/src/deltas/serialization/serializer.g.ts +246 -67
- package/src/deltas/serialization/types.g.ts +192 -53
- package/src/deltas/types.g.ts +192 -53
- package/src/deserializer.ts +7 -5
- package/src/duplicator.ts +1 -1
- package/src/factory.ts +49 -0
- package/src/id-mapping.ts +3 -0
- package/src/index.ts +1 -0
- package/src/value-managers/annotations.ts +27 -1
- package/src/value-managers/containments.ts +73 -8
- package/src/value-managers/references.ts +28 -8
package/src/factory.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Copyright 2025 TRUMPF Laser SE and other contributors
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License")
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-FileCopyrightText: 2025 TRUMPF Laser SE and other contributors
|
|
16
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
17
|
+
|
|
18
|
+
import { lazyMapGet } from "@lionweb/ts-utils"
|
|
19
|
+
import { ILanguageBase, NodeBaseFactory } from "./base-types.js"
|
|
20
|
+
import { DeltaHandler } from "./deltas/index.js"
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @return a {@link NodeBaseFactory factory function} that works for all given {@link ILanguageBase language bases}.
|
|
24
|
+
*/
|
|
25
|
+
export const combinedFactoryFor = (languageBases: ILanguageBase[], handleDelta?: DeltaHandler): NodeBaseFactory => {
|
|
26
|
+
// create lookup map:
|
|
27
|
+
const languageKey2version2factory: { [key: string]: { [version: string]: NodeBaseFactory } } = {}
|
|
28
|
+
languageBases.forEach((languageBase) => {
|
|
29
|
+
const {key, version} = languageBase.language
|
|
30
|
+
const version2factory = lazyMapGet(languageKey2version2factory, key, () => ({}))
|
|
31
|
+
lazyMapGet(version2factory, version, () => languageBase.factory(handleDelta))
|
|
32
|
+
// (Note: don't destructure factory from languageBase, as that will unbind it as "this"!)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return (classifier, id) => {
|
|
36
|
+
const {key, version, name} = classifier.language
|
|
37
|
+
const version2factory = languageKey2version2factory[key]
|
|
38
|
+
if (version2factory === undefined) {
|
|
39
|
+
throw new Error(`language ${name} with key=${key} not known`)
|
|
40
|
+
}
|
|
41
|
+
const factory = version2factory[version]
|
|
42
|
+
if (factory === undefined) {
|
|
43
|
+
const candidateVersions = Object.keys(version2factory)
|
|
44
|
+
throw new Error(`language ${name} with key=${key} and version=${version} not known${candidateVersions.length > 0 ? `- candidate version${candidateVersions.length > 1 ? `s` : ``}: ${candidateVersions.join(", ")}` : ``}`)
|
|
45
|
+
}
|
|
46
|
+
return factory(classifier, id)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
package/src/id-mapping.ts
CHANGED
|
@@ -51,6 +51,9 @@ export class IdMapping {
|
|
|
51
51
|
? null
|
|
52
52
|
: (this.nodesById[idOrUnresolved] ?? unresolved);
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Updates this {@link IdMapping} with the given `node` *and all its descendants* (recursively).
|
|
56
|
+
*/
|
|
54
57
|
updateWith(node: INodeBase) {
|
|
55
58
|
this.nodesById[node.id] = node;
|
|
56
59
|
node.children // recurse into all children
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from "./deltas/index.js";
|
|
|
21
21
|
export * from "./deserializer.js";
|
|
22
22
|
export { deepDuplicateWith } from "./duplicator.js";
|
|
23
23
|
export * from "./id-mapping.js";
|
|
24
|
+
export { combinedFactoryFor } from "./factory.js";
|
|
24
25
|
// skip linking.js: see comment there
|
|
25
26
|
export * from "./LionCore_builtins.g.js";
|
|
26
27
|
export {serializeNodeBases} from "./serializer.js";
|
|
@@ -18,14 +18,15 @@
|
|
|
18
18
|
import { action, observable } from "mobx"
|
|
19
19
|
|
|
20
20
|
import { INodeBase, removeFromParent } from "../base-types.js"
|
|
21
|
+
import { checkIndex, ValueManager } from "./base.js"
|
|
21
22
|
import {
|
|
22
23
|
AnnotationAddedDelta,
|
|
23
24
|
AnnotationDeletedDelta,
|
|
25
|
+
AnnotationMovedAndReplacedInSameParentDelta,
|
|
24
26
|
AnnotationMovedFromOtherParentDelta,
|
|
25
27
|
AnnotationMovedInSameParentDelta,
|
|
26
28
|
AnnotationReplacedDelta
|
|
27
29
|
} from "../deltas/index.js"
|
|
28
|
-
import { checkIndex, ValueManager } from "./base.js"
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -119,6 +120,31 @@ export class AnnotationsValueManager extends ValueManager {
|
|
|
119
120
|
this.emitDelta(() => new AnnotationReplacedDelta(this.container, index, replacedAnnotation, newAnnotation));
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
/**
|
|
124
|
+
* @return the moved and replaced annotations, as an array tuple.
|
|
125
|
+
*/
|
|
126
|
+
@action moveAndReplaceAtIndexDirectly(oldIndex: number, newIndex: number): [INodeBase, INodeBase] | undefined {
|
|
127
|
+
checkIndex(oldIndex, this.annotations.length, false);
|
|
128
|
+
checkIndex(newIndex, this.annotations.length, false);
|
|
129
|
+
if (oldIndex !== newIndex) {
|
|
130
|
+
const movedAnnotation = this.annotations[oldIndex];
|
|
131
|
+
const replacedAnnotation = this.annotations[newIndex];
|
|
132
|
+
this.annotations[newIndex] = movedAnnotation;
|
|
133
|
+
this.annotations.splice(oldIndex, 1);
|
|
134
|
+
replacedAnnotation.detach();
|
|
135
|
+
return [movedAnnotation, replacedAnnotation];
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@action moveAndReplaceAtIndex(oldIndex: number, newIndex: number) {
|
|
141
|
+
const participants = this.moveAndReplaceAtIndexDirectly(oldIndex, newIndex);
|
|
142
|
+
if (participants !== undefined) {
|
|
143
|
+
const [movedAnnotation, replacedAnnotation] = participants;
|
|
144
|
+
this.emitDelta(() => new AnnotationMovedAndReplacedInSameParentDelta(this.container, oldIndex, newIndex, replacedAnnotation, movedAnnotation));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
@action removeDirectly(annotationToRemove: INodeBase): number {
|
|
123
149
|
const index = this.annotations.indexOf(annotationToRemove);
|
|
124
150
|
if (index > -1) {
|
|
@@ -19,7 +19,14 @@ import { Containment } from "@lionweb/core"
|
|
|
19
19
|
import { action, observable } from "mobx"
|
|
20
20
|
|
|
21
21
|
import { INodeBase, removeFromParent } from "../base-types.js"
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
ChildAddedDelta,
|
|
24
|
+
ChildDeletedDelta,
|
|
25
|
+
ChildMovedAndReplacedFromOtherContainmentInSameParentDelta, ChildMovedAndReplacedInSameContainmentDelta,
|
|
26
|
+
ChildMovedFromOtherContainmentDelta,
|
|
27
|
+
ChildMovedInSameContainmentDelta,
|
|
28
|
+
ChildReplacedDelta
|
|
29
|
+
} from "../deltas/index.js"
|
|
23
30
|
import { checkIndex, FeatureValueManager } from "./base.js"
|
|
24
31
|
|
|
25
32
|
|
|
@@ -68,11 +75,33 @@ export abstract class SingleContainmentValueManager<T extends INodeBase> extends
|
|
|
68
75
|
@action addDirectly(newChild: T) {
|
|
69
76
|
const oldChild = this.getDirectly();
|
|
70
77
|
if (oldChild !== undefined) {
|
|
71
|
-
throw new Error(`replacing a child using addDirectly on a value manager for a single-valued containment isn't allowed`); //
|
|
78
|
+
throw new Error(`replacing a child using addDirectly on a value manager for a single-valued containment isn't allowed`); // TODO unit test this
|
|
72
79
|
}
|
|
73
80
|
this.child.set(newChild);
|
|
74
81
|
}
|
|
75
82
|
|
|
83
|
+
@action replaceWith(newChild: T) {
|
|
84
|
+
const oldChild = this.getDirectly();
|
|
85
|
+
if (oldChild === undefined) {
|
|
86
|
+
// not a proper replace, but an add-set => delegate to regular setter (— unfortunately, through necessarily “unfolding the hierarchy”):
|
|
87
|
+
if (this instanceof OptionalSingleContainmentValueManager) {
|
|
88
|
+
this.set(newChild);
|
|
89
|
+
}
|
|
90
|
+
if (this instanceof RequiredSingleContainmentValueManager) {
|
|
91
|
+
this.set(newChild);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
if (oldChild === newChild) {
|
|
95
|
+
// do nothing: nothing's changed
|
|
96
|
+
} else {
|
|
97
|
+
oldChild.detach();
|
|
98
|
+
this.setDirectly(newChild);
|
|
99
|
+
newChild.attachTo(this.container, this.feature);
|
|
100
|
+
this.emitDelta(() => new ChildReplacedDelta(this.container, this.feature, 0, oldChild, newChild));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
76
105
|
}
|
|
77
106
|
|
|
78
107
|
|
|
@@ -96,7 +125,7 @@ export class OptionalSingleContainmentValueManager<T extends INodeBase> extends
|
|
|
96
125
|
if (newChild.parent && newChild.containment) {
|
|
97
126
|
const oldParent = newChild.parent;
|
|
98
127
|
removeFromParent(oldParent, newChild);
|
|
99
|
-
this.emitDelta(() => new
|
|
128
|
+
this.emitDelta(() => new ChildMovedFromOtherContainmentDelta(oldParent, newChild.containment!, 0, this.container, this.feature, 0, newChild));
|
|
100
129
|
} else {
|
|
101
130
|
this.emitDelta(() => new ChildAddedDelta(this.container, this.feature, 0, newChild));
|
|
102
131
|
}
|
|
@@ -155,7 +184,7 @@ export class RequiredSingleContainmentValueManager<T extends INodeBase> extends
|
|
|
155
184
|
if (newChild.parent && newChild.containment) {
|
|
156
185
|
const oldParent = newChild.parent;
|
|
157
186
|
removeFromParent(oldParent, newChild);
|
|
158
|
-
this.emitDelta(() => new
|
|
187
|
+
this.emitDelta(() => new ChildMovedFromOtherContainmentDelta(oldParent, newChild.containment!, 0, this.container, this.feature, 0, newChild));
|
|
159
188
|
} else {
|
|
160
189
|
this.emitDelta(() => new ChildAddedDelta(this.container, this.feature, 0, newChild));
|
|
161
190
|
}
|
|
@@ -228,7 +257,7 @@ export abstract class MultiContainmentValueManager<T extends INodeBase> extends
|
|
|
228
257
|
this.emitDelta(() => new ChildAddedDelta(this.container, this.containment, index, newChild));
|
|
229
258
|
} else {
|
|
230
259
|
const oldIndex = removeFromParent(newChild.parent, newChild);
|
|
231
|
-
this.emitDelta(() => new
|
|
260
|
+
this.emitDelta(() => new ChildMovedFromOtherContainmentDelta(newChild.parent!, newChild.containment!, oldIndex, this.container, this.containment, index, newChild));
|
|
232
261
|
newChild.detach();
|
|
233
262
|
}
|
|
234
263
|
newChild.attachTo(this.container, this.containment);
|
|
@@ -236,7 +265,7 @@ export abstract class MultiContainmentValueManager<T extends INodeBase> extends
|
|
|
236
265
|
|
|
237
266
|
@action removeDirectly(childToRemove: T): number {
|
|
238
267
|
const children = this.getDirectly();
|
|
239
|
-
const index = children.
|
|
268
|
+
const index = children.indexOf(childToRemove);
|
|
240
269
|
if (index > -1) {
|
|
241
270
|
children.splice(index, 1);
|
|
242
271
|
return index;
|
|
@@ -244,6 +273,11 @@ export abstract class MultiContainmentValueManager<T extends INodeBase> extends
|
|
|
244
273
|
return -1;
|
|
245
274
|
}
|
|
246
275
|
|
|
276
|
+
@action removeAtIndexDirectly(index: number) {
|
|
277
|
+
checkIndex(index, this.children.length, false);
|
|
278
|
+
this.getDirectly().splice(index, 1);
|
|
279
|
+
}
|
|
280
|
+
|
|
247
281
|
@action moveDirectly(oldIndex: number, newIndex: number): T | undefined {
|
|
248
282
|
checkIndex(oldIndex, this.children.length, false);
|
|
249
283
|
checkIndex(newIndex, this.children.length, false);
|
|
@@ -262,6 +296,37 @@ export abstract class MultiContainmentValueManager<T extends INodeBase> extends
|
|
|
262
296
|
}
|
|
263
297
|
}
|
|
264
298
|
|
|
299
|
+
@action replaceAtIndex(movedChild: T, newIndex: number) {
|
|
300
|
+
checkIndex(newIndex, this.children.length, false);
|
|
301
|
+
const replacedChild = this.children[newIndex];
|
|
302
|
+
if (replacedChild === movedChild) {
|
|
303
|
+
// do nothing: nothing's changed
|
|
304
|
+
} else {
|
|
305
|
+
this.children.splice(newIndex, 1, movedChild);
|
|
306
|
+
if (replacedChild.parent) {
|
|
307
|
+
const oldValueManager = replacedChild.parent.getContainmentValueManager(replacedChild.containment!);
|
|
308
|
+
const oldIndex = oldValueManager instanceof SingleContainmentValueManager
|
|
309
|
+
? 0
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
311
|
+
: (oldValueManager as MultiContainmentValueManager<any>).children.indexOf(replacedChild);
|
|
312
|
+
replacedChild.detach();
|
|
313
|
+
if (replacedChild.parent === movedChild.parent) {
|
|
314
|
+
if (replacedChild.containment === movedChild.containment) {
|
|
315
|
+
this.emitDelta(() => new ChildMovedAndReplacedInSameContainmentDelta(this.container, this.containment, oldIndex, newIndex, movedChild, replacedChild));
|
|
316
|
+
} else {
|
|
317
|
+
this.emitDelta(() => new ChildMovedAndReplacedFromOtherContainmentInSameParentDelta(this.container, replacedChild.containment!, oldIndex, this.containment, newIndex, movedChild, replacedChild));
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
this.emitDelta(() => new ChildMovedFromOtherContainmentDelta(replacedChild.parent!, replacedChild.containment!, oldIndex, this.container, this.containment, newIndex, movedChild));
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
// not a move+replace, but a regular replace instead:
|
|
324
|
+
this.emitDelta(() => new ChildReplacedDelta(this.container, this.containment, newIndex, replacedChild, movedChild));
|
|
325
|
+
}
|
|
326
|
+
movedChild.attachTo(this.container, this.containment);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
265
330
|
}
|
|
266
331
|
|
|
267
332
|
|
|
@@ -274,7 +339,7 @@ export class OptionalMultiContainmentValueManager<T extends INodeBase> extends M
|
|
|
274
339
|
|
|
275
340
|
@action remove(childToRemove: T) {
|
|
276
341
|
const children = this.getDirectly();
|
|
277
|
-
const index = children.
|
|
342
|
+
const index = children.indexOf(childToRemove);
|
|
278
343
|
if (index > -1) {
|
|
279
344
|
children.splice(index, 1);
|
|
280
345
|
childToRemove.detach();
|
|
@@ -302,7 +367,7 @@ export class RequiredMultiContainmentValueManager<T extends INodeBase> extends M
|
|
|
302
367
|
|
|
303
368
|
@action remove(childToRemove: T) {
|
|
304
369
|
const children = this.getDirectly();
|
|
305
|
-
const index = children.
|
|
370
|
+
const index = children.indexOf(childToRemove);
|
|
306
371
|
if (index > -1) {
|
|
307
372
|
if (children.length === 1) {
|
|
308
373
|
this.throwOnUnset();
|
|
@@ -19,7 +19,12 @@ import { Reference, SingleRef } from "@lionweb/core"
|
|
|
19
19
|
import { action, observable } from "mobx"
|
|
20
20
|
|
|
21
21
|
import { INodeBase } from "../base-types.js"
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
EntryMovedInSameReferenceDelta,
|
|
24
|
+
ReferenceAddedDelta,
|
|
25
|
+
ReferenceChangedDelta,
|
|
26
|
+
ReferenceDeletedDelta
|
|
27
|
+
} from "../deltas/index.js"
|
|
23
28
|
import { checkIndex, FeatureValueManager } from "./base.js"
|
|
24
29
|
|
|
25
30
|
|
|
@@ -37,6 +42,7 @@ export abstract class ReferenceValueManager<T extends INodeBase> extends Feature
|
|
|
37
42
|
/**
|
|
38
43
|
* Adds the given target to the reference.
|
|
39
44
|
* For a single-valued reference, this replaces an already-present target.
|
|
45
|
+
* **Note**: this method predominantly exists for the benefit of the deserializer and duplicator!
|
|
40
46
|
*/
|
|
41
47
|
abstract addDirectly(newTarget: SingleRef<T> | undefined): void;
|
|
42
48
|
|
|
@@ -89,18 +95,18 @@ export class OptionalSingleReferenceValueManager<T extends INodeBase> extends Si
|
|
|
89
95
|
return
|
|
90
96
|
}
|
|
91
97
|
if (newTarget === undefined) {
|
|
92
|
-
this.
|
|
98
|
+
this.setDirectly(undefined);
|
|
93
99
|
if (oldTarget === undefined) {
|
|
94
100
|
// (nothing)
|
|
95
101
|
} else {
|
|
96
102
|
this.emitDelta(() => new ReferenceDeletedDelta(this.container, this.reference, 0, oldTarget));
|
|
97
103
|
}
|
|
98
104
|
} else {
|
|
99
|
-
this.
|
|
105
|
+
this.setDirectly(newTarget);
|
|
100
106
|
if (oldTarget === undefined) {
|
|
101
107
|
this.emitDelta(() => new ReferenceAddedDelta(this.container, this.reference, 0, newTarget));
|
|
102
108
|
} else {
|
|
103
|
-
this.emitDelta(() => new
|
|
109
|
+
this.emitDelta(() => new ReferenceChangedDelta(this.container, this.reference, 0, oldTarget, newTarget));
|
|
104
110
|
}
|
|
105
111
|
}
|
|
106
112
|
}
|
|
@@ -132,11 +138,11 @@ export class RequiredSingleReferenceValueManager<T extends INodeBase> extends Si
|
|
|
132
138
|
if (newTarget === undefined) {
|
|
133
139
|
this.throwOnUnset();
|
|
134
140
|
} else {
|
|
135
|
-
this.
|
|
141
|
+
this.setDirectly(newTarget);
|
|
136
142
|
if (oldTarget === undefined) {
|
|
137
143
|
this.emitDelta(() => new ReferenceAddedDelta(this.container, this.reference, 0, newTarget));
|
|
138
144
|
} else {
|
|
139
|
-
this.emitDelta(() => new
|
|
145
|
+
this.emitDelta(() => new ReferenceChangedDelta(this.container, this.reference, 0, oldTarget, newTarget));
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
148
|
}
|
|
@@ -158,7 +164,7 @@ export abstract class MultiReferenceValueManager<T extends INodeBase> extends Re
|
|
|
158
164
|
}
|
|
159
165
|
|
|
160
166
|
get(): SingleRef<T>[] {
|
|
161
|
-
return this.getDirectly().slice();
|
|
167
|
+
return this.getDirectly().slice(); // make defensive copy
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
isSet(): boolean {
|
|
@@ -194,6 +200,11 @@ export abstract class MultiReferenceValueManager<T extends INodeBase> extends Re
|
|
|
194
200
|
|
|
195
201
|
abstract remove(targetToRemove: SingleRef<T>): void;
|
|
196
202
|
|
|
203
|
+
@action removeAtIndexDirectly(index: number): SingleRef<T> {
|
|
204
|
+
checkIndex(index, this.targets.length, false);
|
|
205
|
+
return this.targets.splice(index, 1)[0];
|
|
206
|
+
}
|
|
207
|
+
|
|
197
208
|
@action moveDirectly(oldIndex: number, newIndex: number): SingleRef<T> | undefined {
|
|
198
209
|
checkIndex(oldIndex, this.targets.length, false);
|
|
199
210
|
checkIndex(newIndex, this.targets.length, false);
|
|
@@ -208,7 +219,16 @@ export abstract class MultiReferenceValueManager<T extends INodeBase> extends Re
|
|
|
208
219
|
@action move(oldIndex: number, newIndex: number) {
|
|
209
220
|
const target = this.moveDirectly(oldIndex, newIndex);
|
|
210
221
|
if (target !== undefined) {
|
|
211
|
-
this.emitDelta(() => new
|
|
222
|
+
this.emitDelta(() => new EntryMovedInSameReferenceDelta(this.container, this.reference, oldIndex, newIndex, target));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@action moveAndReplaceDirectly(oldIndex: number, newIndex: number) {
|
|
227
|
+
checkIndex(oldIndex, this.targets.length, false);
|
|
228
|
+
checkIndex(newIndex, this.targets.length, false);
|
|
229
|
+
if (oldIndex !== newIndex) {
|
|
230
|
+
this.targets.splice(newIndex, 1, this.targets[oldIndex]);
|
|
231
|
+
this.targets.splice(oldIndex, 1);
|
|
212
232
|
}
|
|
213
233
|
}
|
|
214
234
|
|