@lionweb/class-core 0.7.0-beta.13 → 0.7.0-beta.15

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/base-types.d.ts +0 -4
  3. package/dist/base-types.d.ts.map +1 -1
  4. package/dist/base-types.js +0 -25
  5. package/dist/base-types.js.map +1 -1
  6. package/dist/deltas/appliers.d.ts.map +1 -1
  7. package/dist/deltas/appliers.js +2 -1
  8. package/dist/deltas/appliers.js.map +1 -1
  9. package/dist/deltas/inverters.d.ts.map +1 -1
  10. package/dist/deltas/inverters.js +33 -9
  11. package/dist/deltas/inverters.js.map +1 -1
  12. package/dist/deltas/receivers.d.ts.map +1 -1
  13. package/dist/deltas/receivers.js +2 -1
  14. package/dist/deltas/receivers.js.map +1 -1
  15. package/dist/deltas/serialization/deserializer.g.d.ts.map +1 -1
  16. package/dist/deltas/serialization/deserializer.g.js +16 -4
  17. package/dist/deltas/serialization/deserializer.g.js.map +1 -1
  18. package/dist/deserializer.d.ts.map +1 -1
  19. package/dist/deserializer.js +3 -14
  20. package/dist/deserializer.js.map +1 -1
  21. package/dist/factory.d.ts +8 -0
  22. package/dist/factory.d.ts.map +1 -1
  23. package/dist/factory.js +25 -16
  24. package/dist/factory.js.map +1 -1
  25. package/dist/id-mapping.d.ts +21 -3
  26. package/dist/id-mapping.d.ts.map +1 -1
  27. package/dist/id-mapping.js +37 -17
  28. package/dist/id-mapping.js.map +1 -1
  29. package/dist/textualizer.js +1 -1
  30. package/dist/textualizer.js.map +1 -1
  31. package/dist/value-managers/annotations.d.ts.map +1 -1
  32. package/dist/value-managers/annotations.js +1 -2
  33. package/dist/value-managers/annotations.js.map +1 -1
  34. package/dist/value-managers/containments.d.ts +2 -2
  35. package/dist/value-managers/containments.d.ts.map +1 -1
  36. package/dist/value-managers/containments.js +89 -27
  37. package/dist/value-managers/containments.js.map +1 -1
  38. package/dist/value-managers/references.js +2 -2
  39. package/package.json +34 -34
  40. package/src/base-types.ts +0 -25
  41. package/src/deltas/appliers.ts +2 -1
  42. package/src/deltas/inverters.ts +33 -9
  43. package/src/deltas/receivers.ts +2 -1
  44. package/src/deltas/serialization/deserializer.g.ts +19 -7
  45. package/src/deserializer.ts +3 -19
  46. package/src/factory.ts +30 -16
  47. package/src/id-mapping.ts +26 -5
  48. package/src/textualizer.ts +1 -1
  49. package/src/value-managers/annotations.ts +2 -2
  50. package/src/value-managers/containments.ts +87 -27
  51. package/src/value-managers/references.ts +2 -2
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
1
  {
2
- "name": "@lionweb/class-core",
3
- "version": "0.7.0-beta.13",
4
- "description": "Generic, language-aspecific base types for generated TypeScript APIs",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "typings": "dist/index.d.ts",
8
- "type": "module",
9
- "license": "Apache-2.0",
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/LionWeb-io/lionweb-typescript.git"
13
- },
14
- "bugs": {
15
- "url": "https://github.com/LionWeb-io/lionweb-typescript/issues"
16
- },
17
- "scripts": {
18
- "clean": "npx rimraf dist node_modules -g lionweb-class-core-*.tgz",
19
- "build": "npx rimraf dist && tsc",
20
- "lint": "eslint src",
21
- "prep:pre-release": "npm run clean && npm install && npm run build",
22
- "prerelease-alpha": "npm run prep:pre-release",
23
- "release-alpha": "npm publish --tag alpha",
24
- "prerelease-beta": "npm run prep:pre-release",
25
- "release-beta": "npm publish --tag beta",
26
- "prerelease": "npm run prep:pre-release",
27
- "release": "npm publish"
28
- },
29
- "dependencies": {
30
- "@lionweb/core": "0.7.0-beta.13",
31
- "@lionweb/json": "0.7.0-beta.13",
32
- "@lionweb/ts-utils": "0.7.0-beta.13",
33
- "littoral-templates": "0.5.0",
34
- "mobx": "6.13.7"
35
- }
2
+ "name": "@lionweb/class-core",
3
+ "version": "0.7.0-beta.15",
4
+ "description": "Generic, language-aspecific base types for generated TypeScript APIs",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "typings": "dist/index.d.ts",
8
+ "type": "module",
9
+ "license": "Apache-2.0",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/LionWeb-io/lionweb-typescript.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/LionWeb-io/lionweb-typescript/issues"
16
+ },
17
+ "scripts": {
18
+ "clean": "npx rimraf dist node_modules -g lionweb-class-core-*.tgz",
19
+ "build": "npx rimraf dist && tsc",
20
+ "lint": "eslint src",
21
+ "prep:pre-release": "npm run clean && npm install && npm run build",
22
+ "prerelease-alpha": "npm run prep:pre-release",
23
+ "release-alpha": "npm publish --tag alpha",
24
+ "prerelease-beta": "npm run prep:pre-release",
25
+ "release-beta": "npm publish --tag beta",
26
+ "prerelease": "npm run prep:pre-release",
27
+ "release": "npm publish"
28
+ },
29
+ "dependencies": {
30
+ "@lionweb/core": "0.7.0-beta.15",
31
+ "@lionweb/json": "0.7.0-beta.15",
32
+ "@lionweb/ts-utils": "0.7.0-beta.15",
33
+ "littoral-templates": "0.5.0",
34
+ "mobx": "6.13.7"
35
+ }
36
36
  }
package/src/base-types.ts CHANGED
@@ -351,28 +351,3 @@ export interface ILanguageBase {
351
351
  enumLiteralFrom<T>(enumerationLiteral: EnumerationLiteral): T;
352
352
  }
353
353
 
354
-
355
- /**
356
- * Removes the given child node from its parent, and returns its containment index.
357
- */
358
- export const removeFromParent = (parent: INodeBase | undefined, child: INodeBase): number => {
359
- if (parent === undefined) {
360
- throw new Error(`can't remove an orphan from its parent`);
361
- }
362
- if (child.containment instanceof Containment) {
363
- const valueManager = parent.getContainmentValueManager(child.containment);
364
- if (valueManager instanceof SingleContainmentValueManager) {
365
- valueManager.setDirectly(undefined);
366
- return 0;
367
- } else if (valueManager instanceof MultiContainmentValueManager) {
368
- return valueManager.removeDirectly(child);
369
- } else {
370
- throw new Error(`don't know how to remove a child that's contained through a value manager of type ${valueManager.constructor.name}`);
371
- }
372
- }
373
- if (child.containment === null) {
374
- return parent.annotationsValueManager.removeDirectly(child);
375
- }
376
- throw new Error(`not going to remove a child from its parent without knowing how it's contained`);
377
- }
378
-
@@ -66,7 +66,8 @@ import { IDelta } from "./base.js"
66
66
  * If an {@link IdMapping} is provided, the {@link INodeBase nodes} relevant for the delta are looked up from that;
67
67
  * otherwise, the delta is applied directly to (object-)referenced nodes.
68
68
  *
69
- * This is an internal function, solely meant to DRY the delta application with and without lookup in
69
+ * This is an internal function, solely meant to DRY the delta application
70
+ * with and without lookup in an {@link IdMapping ID mapping object}.
70
71
  */
71
72
  const deltaApplier = (idMapping?: IdMapping, updatablePartitions?: () => INodeBase[]) =>
72
73
  (delta: IDelta): void => {
@@ -91,13 +91,22 @@ export const invertDelta = (delta: IDelta): IDelta => {
91
91
  return new ChildMovedInSameContainmentDelta(delta.parent, delta.containment, delta.newIndex, delta.oldIndex, delta.movedChild);
92
92
  }
93
93
  if (delta instanceof ChildMovedAndReplacedFromOtherContainmentDelta) {
94
- // TODO implement
94
+ return new CompositeDelta([
95
+ new ChildMovedFromOtherContainmentDelta(delta.newParent, delta.newContainment, delta.newIndex, delta.oldParent, delta.oldContainment, delta.oldIndex, delta.movedChild),
96
+ new ChildAddedDelta(delta.newParent, delta.newContainment, delta.newIndex, delta.replacedChild)
97
+ ]);
95
98
  }
96
99
  if (delta instanceof ChildMovedAndReplacedFromOtherContainmentInSameParentDelta) {
97
- // TODO implement
100
+ return new CompositeDelta([
101
+ new ChildMovedFromOtherContainmentInSameParentDelta(delta.parent, delta.newContainment, delta.newIndex, delta.movedChild, delta.oldContainment, delta.oldIndex),
102
+ new ChildAddedDelta(delta.parent, delta.newContainment, delta.newIndex, delta.replacedChild)
103
+ ]);
98
104
  }
99
105
  if (delta instanceof ChildMovedAndReplacedInSameContainmentDelta) {
100
- // TODO implement
106
+ return new CompositeDelta([
107
+ new ChildMovedInSameContainmentDelta(delta.parent, delta.containment, delta.newIndex, delta.oldIndex, delta.movedChild),
108
+ new ChildAddedDelta(delta.parent, delta.containment, delta.newIndex, delta.replacedChild)
109
+ ]);
101
110
  }
102
111
  if (delta instanceof AnnotationAddedDelta) {
103
112
  return new AnnotationDeletedDelta(delta.parent, delta.index, delta.newAnnotation);
@@ -115,10 +124,16 @@ export const invertDelta = (delta: IDelta): IDelta => {
115
124
  return new AnnotationMovedInSameParentDelta(delta.parent, delta.newIndex, delta.oldIndex, delta.movedAnnotation);
116
125
  }
117
126
  if (delta instanceof AnnotationMovedAndReplacedFromOtherParentDelta) {
118
- // TODO implement
127
+ return new CompositeDelta([
128
+ new AnnotationMovedFromOtherParentDelta(delta.newParent, delta.newIndex, delta.oldParent, delta.oldIndex, delta.movedAnnotation),
129
+ new AnnotationAddedDelta(delta.newParent, delta.newIndex, delta.replacedAnnotation)
130
+ ]);
119
131
  }
120
132
  if (delta instanceof AnnotationMovedAndReplacedInSameParentDelta) {
121
- // TODO implement
133
+ return new CompositeDelta([
134
+ new AnnotationMovedInSameParentDelta(delta.parent, delta.newIndex, delta.oldIndex, delta.movedAnnotation),
135
+ new AnnotationAddedDelta(delta.parent, delta.newIndex, delta.replacedAnnotation)
136
+ ]);
122
137
  }
123
138
  if (delta instanceof ReferenceAddedDelta) {
124
139
  return new ReferenceDeletedDelta(delta.parent, delta.reference, delta.index, delta.newTarget);
@@ -133,19 +148,28 @@ export const invertDelta = (delta: IDelta): IDelta => {
133
148
  return new EntryMovedFromOtherReferenceDelta(delta.newParent, delta.newReference, delta.newIndex, delta.oldParent, delta.oldReference, delta.oldIndex, delta.movedTarget);
134
149
  }
135
150
  if (delta instanceof EntryMovedFromOtherReferenceInSameParentDelta) {
136
- // TODO implement
151
+ return new EntryMovedFromOtherReferenceInSameParentDelta(delta.parent, delta.newReference, delta.newIndex, delta.oldReference, delta.oldIndex, delta.movedTarget);
137
152
  }
138
153
  if (delta instanceof EntryMovedInSameReferenceDelta) {
139
154
  return new EntryMovedInSameReferenceDelta(delta.parent, delta.reference, delta.newIndex, delta.oldIndex, delta.movedTarget);
140
155
  }
141
156
  if (delta instanceof EntryMovedAndReplacedFromOtherReferenceDelta) {
142
- // TODO implement
157
+ return new CompositeDelta([
158
+ new EntryMovedFromOtherReferenceDelta(delta.newParent, delta.newReference, delta.newIndex, delta.oldParent, delta.oldReference, delta.oldIndex, delta.movedTarget),
159
+ new ReferenceAddedDelta(delta.newParent, delta.newReference, delta.newIndex, delta.replacedTarget)
160
+ ]);
143
161
  }
144
162
  if (delta instanceof EntryMovedAndReplacedFromOtherReferenceInSameParentDelta) {
145
- return new EntryMovedAndReplacedFromOtherReferenceInSameParentDelta(delta.parent, delta.newReference, delta.newIndex, delta.oldReference, delta.oldIndex, delta.replacedTarget, delta.movedTarget);
163
+ return new CompositeDelta([
164
+ new EntryMovedFromOtherReferenceInSameParentDelta(delta.parent, delta.newReference, delta.newIndex, delta.oldReference, delta.oldIndex, delta.movedTarget),
165
+ new ReferenceAddedDelta(delta.parent, delta.newReference, delta.newIndex, delta.replacedTarget)
166
+ ]);
146
167
  }
147
168
  if (delta instanceof EntryMovedAndReplacedInSameReferenceDelta) {
148
- // TODO implement
169
+ return new CompositeDelta([
170
+ new EntryMovedInSameReferenceDelta(delta.parent, delta.reference, delta.newIndex, delta.oldIndex, delta.movedTarget),
171
+ new ReferenceAddedDelta(delta.parent, delta.reference, delta.newIndex, delta.replacedTarget)
172
+ ]);
149
173
  }
150
174
  if (delta instanceof CompositeDelta) {
151
175
  return new CompositeDelta(delta.parts.map(invertDelta));
@@ -15,6 +15,7 @@
15
15
  // SPDX-FileCopyrightText: 2025 TRUMPF Laser SE and other contributors
16
16
  // SPDX-License-Identifier: Apache-2.0
17
17
 
18
+ import { asPrettyJsonString } from "@lionweb/ts-utils"
18
19
  import { IDelta } from "./base.js"
19
20
  import { serializeDelta } from "./serialization/index.js"
20
21
 
@@ -37,7 +38,7 @@ export const collectingDeltaReceiver = (printSerializations = false): [DeltaRece
37
38
  const receiveDelta: DeltaReceiver = (delta) => {
38
39
  deltas.push(delta);
39
40
  if (printSerializations) {
40
- console.log(JSON.stringify(serializeDelta(delta), null, 4));
41
+ console.log(asPrettyJsonString(serializeDelta(delta)));
41
42
  }
42
43
  };
43
44
  return [receiveDelta, deltas];
@@ -18,7 +18,7 @@
18
18
  // Warning: this file is generated!
19
19
  // Modifying it by hand is useless at best, and sabotage at worst.
20
20
 
21
- import { Containment, MemoisingSymbolTable, Property, Reference } from "@lionweb/core";
21
+ import { Containment, Feature, MemoisingSymbolTable, Property, Reference } from "@lionweb/core";
22
22
  import { LionWebJsonMetaPointer } from "@lionweb/json";
23
23
 
24
24
  import { ILanguageBase, INodeBase } from "../../base-types.js";
@@ -62,14 +62,26 @@ import {
62
62
  import { IDelta } from "../base.js";
63
63
 
64
64
 
65
+ type FeatureResolver<FT extends Feature> = (metaPointer: LionWebJsonMetaPointer, container: INodeBase) => FT;
66
+
65
67
  export const deltaDeserializer = (languageBases: ILanguageBase[], idMapping: IdMapping): DeltaDeserializer => {
66
68
  const symbolTable = new MemoisingSymbolTable(languageBases.map(({language}) => language));
67
- const resolvedPropertyFrom = (metaPointer: LionWebJsonMetaPointer, container: INodeBase): Property =>
68
- symbolTable.featureMatching(container.classifier.metaPointer(), metaPointer) as Property
69
- const resolvedContainmentFrom = (metaPointer: LionWebJsonMetaPointer, container: INodeBase): Containment =>
70
- symbolTable.featureMatching(container.classifier.metaPointer(), metaPointer) as Containment
71
- const resolvedReferenceFrom = (metaPointer: LionWebJsonMetaPointer, container: INodeBase): Reference =>
72
- symbolTable.featureMatching(container.classifier.metaPointer(), metaPointer) as Reference
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ const featureResolverFor = <FT extends Feature>(featureClazz: new (...args: any[]) => FT): FeatureResolver<FT> =>
71
+ (metaPointer, container) => {
72
+ const featureLocationMessage = () => `feature with meta-pointer ${JSON.stringify(metaPointer)} on instance with ID="${container.id}" with meta-pointer ${JSON.stringify(container.classifier.metaPointer())}`;
73
+ const feature = symbolTable.featureMatching(container.classifier.metaPointer(), metaPointer);
74
+ if (feature === undefined) {
75
+ throw new Error(`couldn't resolve ${featureLocationMessage()}`); // fail early <== unrecoverable
76
+ }
77
+ if (!(feature instanceof featureClazz)) {
78
+ throw new Error(`${featureLocationMessage()} is not a ${featureClazz.name} but a ${feature.constructor.name}`); // fail early <== unrecoverable
79
+ }
80
+ return feature as FT;
81
+ }
82
+ const resolvedPropertyFrom = featureResolverFor(Property);
83
+ const resolvedContainmentFrom = featureResolverFor(Containment);
84
+ const resolvedReferenceFrom = featureResolverFor(Reference);
73
85
  const deserializedDelta = (delta: SerializedDelta): IDelta => {
74
86
  switch (delta.kind) {
75
87
  case "PartitionAdded": {
@@ -21,7 +21,6 @@ import {
21
21
  Containment,
22
22
  defaultSimplisticHandler,
23
23
  Enumeration,
24
- Language,
25
24
  MemoisingSymbolTable,
26
25
  PrimitiveType,
27
26
  Property,
@@ -34,6 +33,7 @@ import { LionWebId, LionWebJsonChunk, LionWebJsonNode } from "@lionweb/json"
34
33
  import { byIdMap, keepDefineds } from "@lionweb/ts-utils"
35
34
 
36
35
  import { DeltaReceiver, IdMapping, ILanguageBase, INodeBase } from "./index.js"
36
+ import { combinedLanguageBaseLookupFor } from "./factory.js"
37
37
  import { NodesToInstall } from "./linking.js"
38
38
 
39
39
 
@@ -48,21 +48,6 @@ export type Deserializer<T> = (
48
48
  ) => T;
49
49
 
50
50
 
51
- const languageBaseLookupFor = (languageBases: ILanguageBase[]) =>
52
- (language: Language) => {
53
- const languageBase = languageBases.find((languageBase) => languageBase.language === language);
54
- if (languageBase === undefined) {
55
- throw new Error(`language ${language.name} (with key=${language.key} and version=${language.version}) not known`);
56
- }
57
- return languageBase;
58
- };
59
-
60
- const factoryLookupFor = (languageBases: ILanguageBase[], receiveDelta?: DeltaReceiver) => {
61
- const lookup = languageBaseLookupFor(languageBases);
62
- return (language: Language) => lookup(language).factory(receiveDelta);
63
- }
64
-
65
-
66
51
  /**
67
52
  * A quasi-tuple of the roots (of type {@link INodeBase}) of a model,
68
53
  * and its {@link IdMapping} instance.
@@ -78,8 +63,7 @@ export type RootsWithIdMapping = { roots: INodeBase[], idMapping: IdMapping };
78
63
  export const nodeBaseDeserializerWithIdMapping = (languageBases: ILanguageBase[], receiveDelta?: DeltaReceiver): Deserializer<RootsWithIdMapping> => {
79
64
 
80
65
  const symbolTable = new MemoisingSymbolTable(languageBases.map(({language}) => language));
81
- const languageBaseFor = languageBaseLookupFor(languageBases);
82
- const factoryFor = factoryLookupFor(languageBases, receiveDelta);
66
+ const languageBaseFor = combinedLanguageBaseLookupFor(languageBases);
83
67
 
84
68
  return (
85
69
  serializationChunk: LionWebJsonChunk,
@@ -98,7 +82,7 @@ export const nodeBaseDeserializerWithIdMapping = (languageBases: ILanguageBase[]
98
82
  return undefined;
99
83
  }
100
84
 
101
- const node = factoryFor(classifier.language)(classifier, id);
85
+ const node = languageBaseFor(classifier.language).factory(receiveDelta)(classifier, id);
102
86
 
103
87
  properties.forEach(({property: propertyMetaPointer, value}) => {
104
88
  const feature = symbolTable.featureMatching(classifierMetaPointer, propertyMetaPointer);
package/src/factory.ts CHANGED
@@ -15,35 +15,49 @@
15
15
  // SPDX-FileCopyrightText: 2025 TRUMPF Laser SE and other contributors
16
16
  // SPDX-License-Identifier: Apache-2.0
17
17
 
18
+ import { Language } from "@lionweb/core"
18
19
  import { lazyMapGet } from "@lionweb/ts-utils"
19
20
  import { ILanguageBase, NodeBaseFactory } from "./base-types.js"
20
21
  import { DeltaReceiver } from "./deltas/index.js"
21
22
 
23
+
22
24
  /**
23
- * @return a {@link NodeBaseFactory factory function} that works for all given {@link ILanguageBase language bases}.
25
+ * @return a function that looks up the {@link ILanguageBase language base} for the {@link Language language} passed to it,
26
+ * from among the given language bases.
27
+ * The returned function throws when the language wasn't among the languages the given bases were for.
28
+ * The lookup is hashmap-backed, so efficient.
24
29
  */
25
- export const combinedFactoryFor = (languageBases: ILanguageBase[], receiveDelta?: DeltaReceiver): NodeBaseFactory => {
30
+ export const combinedLanguageBaseLookupFor = (languageBases: ILanguageBase[]): ((language: Language) => ILanguageBase) => {
26
31
  // create lookup map:
27
- const languageKey2version2factory: { [key: string]: { [version: string]: NodeBaseFactory } } = {}
32
+ const languageKey2version2base: { [key: string]: { [version: string]: ILanguageBase } } = {}
28
33
  languageBases.forEach((languageBase) => {
29
34
  const {key, version} = languageBase.language
30
- const version2factory = lazyMapGet(languageKey2version2factory, key, () => ({}))
31
- lazyMapGet(version2factory, version, () => languageBase.factory(receiveDelta))
32
- // (Note: don't destructure factory from languageBase, as that will unbind it as "this"!)
35
+ const version2base = lazyMapGet(languageKey2version2base, key, () => ({}))
36
+ lazyMapGet(version2base, version, () => languageBase)
33
37
  })
34
38
 
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`)
39
+ return (language) => {
40
+ const {key, version, name} = language
41
+ const version2base = languageKey2version2base[key]
42
+ if (version2base === undefined) {
43
+ throw new Error(`language ${name} with key=${key} not registered`)
40
44
  }
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
+ const base = version2base[version]
46
+ if (base === undefined) {
47
+ const candidateVersions = Object.keys(version2base)
48
+ throw new Error(`language ${name} with key=${key} and version=${version} not registered${candidateVersions.length > 0 ? `- candidate version${candidateVersions.length > 1 ? `s` : ``}: ${candidateVersions.join(", ")}` : ``}`)
45
49
  }
46
- return factory(classifier, id)
50
+ return base
47
51
  }
48
52
  }
49
53
 
54
+
55
+ /**
56
+ * @return a {@link NodeBaseFactory factory function} that works for all given {@link ILanguageBase language bases}.
57
+ */
58
+ export const combinedFactoryFor = (languageBases: ILanguageBase[], receiveDelta?: DeltaReceiver): NodeBaseFactory => {
59
+ const baseOf = combinedLanguageBaseLookupFor(languageBases)
60
+ return (classifier, id) =>
61
+ baseOf(classifier.language).factory(receiveDelta)(classifier, id)
62
+ }
63
+
package/src/id-mapping.ts CHANGED
@@ -30,35 +30,56 @@ type NodesById = { [id: LionWebId]: INodeBase }
30
30
  */
31
31
  export class IdMapping {
32
32
 
33
- nodesById: NodesById;
33
+ private nodesById: NodesById;
34
34
  constructor(nodesById: NodesById) {
35
35
  this.nodesById = {...nodesById};
36
36
  }
37
37
  // TODO consider using an instance of Map<Id, INodeBase> instead
38
38
 
39
- fromId(id: LionWebId): INodeBase {
39
+ /**
40
+ * @return the {@link INodeBase node} with the given {@link LionWebId `id`}, or
41
+ * @throws an Error if no node with the given ID was registered.
42
+ */
43
+ fromId = (id: LionWebId): INodeBase => {
40
44
  if (!(id in this.nodesById)) {
41
45
  throw new Error(`node with id=${id} not in ID mapping`);
42
46
  }
43
47
  return this.nodesById[id];
44
48
  }
45
49
 
50
+ /**
51
+ * @return the {@link INodeBase node} with the given {@link LionWebId `id`},
52
+ * or `undefined` if no node with the given ID was registered.
53
+ */
46
54
  tryFromId = (id: LionWebId): (INodeBase | undefined) =>
47
55
  this.nodesById[id];
48
56
 
57
+ /**
58
+ * @return the {@link INodeBase node} referenced from the given {@link LionWebId ID},
59
+ * or `unresolved` if `unresolved` was passed in or no node with the given ID was registered.
60
+ */
49
61
  fromRefId = (idOrUnresolved: IdOrUnresolved): SingleRef<INodeBase> =>
50
- idOrUnresolved === null
51
- ? null
62
+ idOrUnresolved === unresolved
63
+ ? unresolved
52
64
  : (this.nodesById[idOrUnresolved] ?? unresolved);
53
65
 
54
66
  /**
55
67
  * Updates this {@link IdMapping} with the given `node` *and all its descendants* (recursively).
56
68
  */
57
- updateWith(node: INodeBase) {
69
+ updateWith= (node: INodeBase) => {
58
70
  this.nodesById[node.id] = node;
59
71
  node.children // recurse into all children
60
72
  .forEach((child) => this.updateWith(child));
61
73
  }
62
74
 
75
+ /**
76
+ * Re-initializes this {@link IdMapping ID mapping} with the given nodes-by-ID.
77
+ * This completely removes all registrations of nodes,
78
+ * and should only be used by components which are in complete control of the nodes being passed to this method.
79
+ */
80
+ reinitializeWith = (nodesById: NodesById) => {
81
+ this.nodesById = nodesById
82
+ }
83
+
63
84
  }
64
85
 
@@ -54,7 +54,7 @@ export const asTreeTextWith = (identificationFor: (node: INodeBase) => string):
54
54
  const valueManager = node.getPropertyValueManager(feature)
55
55
  const displayValue = (() => {
56
56
  if (!valueManager.isSet()) {
57
- return `$<not set>`
57
+ return `<not set>`
58
58
  }
59
59
  const value = valueManager.getDirectly()
60
60
  if (feature.type === LionCore_builtinsBase.INSTANCE.String) {
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { action, observable } from "mobx"
19
19
 
20
- import { INodeBase, removeFromParent } from "../base-types.js"
20
+ import { INodeBase } from "../base-types.js"
21
21
  import { checkIndex, ValueManager } from "./base.js"
22
22
  import {
23
23
  AnnotationAddedDelta,
@@ -67,7 +67,7 @@ export class AnnotationsValueManager extends ValueManager {
67
67
  newAnnotation.attachTo(this.container, null);
68
68
  return false;
69
69
  } else {
70
- const oldIndex = removeFromParent(oldParent, newAnnotation);
70
+ const oldIndex = oldParent.annotationsValueManager.removeDirectly(newAnnotation);
71
71
  newAnnotation.attachTo(this.container, null);
72
72
  return [oldParent, oldIndex];
73
73
  }