@lionweb/core 0.8.0-beta.3 → 0.8.0-beta.5
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 +7 -0
- package/dist/deserializer.d.ts +43 -6
- package/dist/deserializer.d.ts.map +1 -1
- package/dist/deserializer.js +142 -129
- package/dist/deserializer.js.map +1 -1
- package/dist/functions.d.ts +6 -1
- package/dist/functions.d.ts.map +1 -1
- package/dist/functions.js +11 -0
- package/dist/functions.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/m3/builtins.js +3 -3
- package/dist/m3/builtins.js.map +1 -1
- package/dist/m3/deserializer.d.ts +7 -3
- package/dist/m3/deserializer.d.ts.map +1 -1
- package/dist/m3/deserializer.js +14 -6
- package/dist/m3/deserializer.js.map +1 -1
- package/dist/m3/functions.d.ts +2 -2
- package/dist/m3/functions.d.ts.map +1 -1
- package/dist/m3/functions.js.map +1 -1
- package/dist/m3/reference-checker.js +2 -2
- package/dist/m3/reference-checker.js.map +1 -1
- package/dist/m3/serializer.d.ts.map +1 -1
- package/dist/m3/serializer.js +2 -2
- package/dist/m3/serializer.js.map +1 -1
- package/dist/m3/types.d.ts.map +1 -1
- package/dist/m3/types.js +4 -4
- package/dist/m3/types.js.map +1 -1
- package/dist/reading.d.ts +5 -4
- package/dist/reading.d.ts.map +1 -1
- package/dist/references.d.ts +14 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +9 -0
- package/dist/references.js.map +1 -1
- package/dist/reporter.d.ts +49 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/{handler.js → reporter.js} +15 -7
- package/dist/reporter.js.map +1 -0
- package/dist/serializer.d.ts +29 -7
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +14 -15
- package/dist/serializer.js.map +1 -1
- package/package.json +3 -3
- package/src/deserializer.ts +223 -168
- package/src/functions.ts +15 -1
- package/src/index.ts +1 -1
- package/src/m3/builtins.ts +3 -3
- package/src/m3/deserializer.ts +17 -12
- package/src/m3/functions.ts +2 -2
- package/src/m3/reference-checker.ts +2 -2
- package/src/m3/serializer.ts +2 -2
- package/src/m3/types.ts +4 -4
- package/src/reading.ts +5 -4
- package/src/references.ts +20 -1
- package/src/reporter.ts +78 -0
- package/src/serializer.ts +39 -23
- package/dist/handler.d.ts +0 -33
- package/dist/handler.d.ts.map +0 -1
- package/dist/handler.js.map +0 -1
- package/src/handler.ts +0 -57
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lionweb/core",
|
|
3
|
-
"version": "0.8.0-beta.
|
|
3
|
+
"version": "0.8.0-beta.5",
|
|
4
4
|
"description": "LionWeb core for {Java|Type}Script",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"release": "npm publish"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@lionweb/json": "0.8.0-beta.
|
|
31
|
-
"@lionweb/ts-utils": "0.8.0-beta.
|
|
30
|
+
"@lionweb/json": "0.8.0-beta.5",
|
|
31
|
+
"@lionweb/ts-utils": "0.8.0-beta.5"
|
|
32
32
|
}
|
|
33
33
|
}
|
package/src/deserializer.ts
CHANGED
|
@@ -7,12 +7,8 @@ import {
|
|
|
7
7
|
} from "@lionweb/json"
|
|
8
8
|
import { byIdMap, groupBy, keepDefineds } from "@lionweb/ts-utils"
|
|
9
9
|
import { Writer } from "./writing.js"
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
builtinPropertyValueDeserializer,
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
-
BuiltinPropertyValueDeserializer
|
|
15
|
-
} from "./m3/builtins.js"
|
|
10
|
+
import { consoleProblemReporter, ProblemReporter } from "./reporter.js"
|
|
11
|
+
import { builtinPropertyValueDeserializer } from "./m3/builtins.js"
|
|
16
12
|
import { MemoisingSymbolTable } from "./m3/symbol-table.js"
|
|
17
13
|
import { Classifier, Containment, Enumeration, Language, PrimitiveType, Property, Reference } from "./m3/types.js"
|
|
18
14
|
import { unresolved } from "./references.js"
|
|
@@ -30,199 +26,258 @@ export interface PropertyValueDeserializer {
|
|
|
30
26
|
*/
|
|
31
27
|
export interface PrimitiveTypeDeserializer extends PropertyValueDeserializer {}
|
|
32
28
|
|
|
29
|
+
|
|
33
30
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @param serializationChunk - a {@link SerializedModel model} from its LionWeb serialization JSON format
|
|
37
|
-
* @param writer - a {@link Writer} that is used to instantiate nodes and set values on them
|
|
38
|
-
* @param languages - a {@link Language language} that the serialized model is expected to conform to
|
|
39
|
-
* @param dependentNodes - a collection of nodes from dependent models against which all references in the serialized model are supposed to resolve against
|
|
40
|
-
* @param propertyValueDeserializer - a deserializer for values of properties (by default a {@link BuiltinPropertyValueDeserializer})
|
|
41
|
-
* @param problemHandler - a handler for reporting problems (by default a {@link defaultSimplisticHandler})
|
|
31
|
+
* Type definition for functions that deserialize a given {@link LionWebJsonChunk serialization chunk},
|
|
32
|
+
* being able to link to the given `dependentNodes` (as children/containments or reference targets).
|
|
42
33
|
*/
|
|
43
|
-
export
|
|
44
|
-
|
|
34
|
+
export type Deserializer<NT extends Node> = (serializationChunk: LionWebJsonChunk, dependentNodes?: Node[]) => NT[]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Configuration parameters for a deserializer that are unchanging per invocation of the deserializer
|
|
39
|
+
* (and partially optional).
|
|
40
|
+
*/
|
|
41
|
+
export type DeserializerConfiguration<NT extends Node> = {
|
|
42
|
+
/**
|
|
43
|
+
* A {@link Writer} that is used to instantiate nodes (with classifiers coming from the `languages` property) and set values on them.
|
|
44
|
+
*/
|
|
45
45
|
writer: Writer<NT>,
|
|
46
|
+
/**
|
|
47
|
+
* An array of {@link Language languages} that the serialization chunk is expected to conform to.
|
|
48
|
+
*/
|
|
46
49
|
languages: Language[],
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
/**
|
|
51
|
+
* A deserializer for values of properties.
|
|
52
|
+
* Default: {@link builtinPropertyValueDeserializer}.
|
|
53
|
+
*/
|
|
54
|
+
propertyValueDeserializer?: PropertyValueDeserializer,
|
|
55
|
+
/**
|
|
56
|
+
* An object for reporting problems to.
|
|
57
|
+
* Default: {@link consoleProblemReporter}.
|
|
58
|
+
*/
|
|
59
|
+
problemReporter?: ProblemReporter
|
|
60
|
+
}
|
|
58
61
|
|
|
59
|
-
const symbolTable = new MemoisingSymbolTable(languages)
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
/**
|
|
64
|
+
* @return a {@link Deserializer} function.
|
|
65
|
+
*
|
|
66
|
+
* @param configuration - a {@link DeserializerConfiguration} object to configure the deserializer to return with.
|
|
67
|
+
*/
|
|
68
|
+
export const deserializerWith = <NT extends Node>(configuration: DeserializerConfiguration<NT>): Deserializer<NT> => {
|
|
62
69
|
|
|
63
|
-
const
|
|
70
|
+
const symbolTable = new MemoisingSymbolTable(configuration.languages)
|
|
71
|
+
const { writer } = configuration
|
|
64
72
|
|
|
65
|
-
const
|
|
73
|
+
const propertyValueDeserializer = configuration.propertyValueDeserializer ?? builtinPropertyValueDeserializer
|
|
74
|
+
const problemReporter = configuration.problemReporter ?? consoleProblemReporter
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
* Instantiates a {@link Node} from the given {@link LionWebJsonNode},
|
|
69
|
-
* and stores it under its ID so references to it can be resolved.
|
|
70
|
-
* For every serialized node, only one instance will ever be constructed (through memoisation).
|
|
71
|
-
*/
|
|
72
|
-
const instantiateMemoised = (serNode: LionWebJsonNode, parent?: NT): NT | null => {
|
|
73
|
-
if (serNode.id in deserializedNodeById) {
|
|
74
|
-
return deserializedNodeById[serNode.id]
|
|
75
|
-
}
|
|
76
|
-
const node = instantiate(serNode, parent)
|
|
77
|
-
if (node !== null) {
|
|
78
|
-
deserializedNodeById[node.id] = node
|
|
79
|
-
}
|
|
80
|
-
return node
|
|
81
|
-
}
|
|
76
|
+
return (serializationChunk, dependentNodes = []) => {
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const tryInstantiate = (
|
|
87
|
-
parent: NT | undefined,
|
|
88
|
-
classifier: Classifier,
|
|
89
|
-
id: LionWebId,
|
|
90
|
-
propertySettings: { [propertyKey: LionWebKey]: unknown }
|
|
91
|
-
): NT | null => {
|
|
92
|
-
try {
|
|
93
|
-
return writer.nodeFor(parent, classifier, id, propertySettings)
|
|
94
|
-
} catch (e: unknown) {
|
|
95
|
-
problemHandler.reportProblem(
|
|
96
|
-
`error occurred during instantiation of a node for classifier ${classifier.name} with meta-pointer (${classifier.language.key}, ${classifier.language.version}, ${classifier.key}); reason:`
|
|
78
|
+
if (serializationChunk.serializationFormatVersion !== currentSerializationFormatVersion) {
|
|
79
|
+
problemReporter.reportProblem(
|
|
80
|
+
`can't deserialize from serialization format other than version "${currentSerializationFormatVersion}" - assuming that version`
|
|
97
81
|
)
|
|
98
|
-
problemHandler.reportProblem((e as Error).toString())
|
|
99
|
-
return null
|
|
100
82
|
}
|
|
101
|
-
}
|
|
102
83
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const instantiate = (
|
|
107
|
-
{ id, classifier: classifierMetaPointer, properties, containments, references, annotations }: LionWebJsonNode,
|
|
108
|
-
parent?: NT
|
|
109
|
-
): NT | null => {
|
|
110
|
-
const classifier = symbolTable.entityMatching(classifierMetaPointer)
|
|
111
|
-
|
|
112
|
-
if (classifier === undefined || !(classifier instanceof Classifier)) {
|
|
113
|
-
problemHandler.reportProblem(
|
|
114
|
-
`can't deserialize node with id=${id}: can't find the classifier with key ${classifierMetaPointer.key} in language (${classifierMetaPointer.language}, ${classifierMetaPointer.version})`
|
|
115
|
-
)
|
|
116
|
-
return null
|
|
117
|
-
}
|
|
84
|
+
const { nodes: serializedNodes } = serializationChunk
|
|
85
|
+
const serializedNodeById = byIdMap(serializedNodes)
|
|
86
|
+
const deserializedNodeById: { [id: LionWebId]: NT } = {}
|
|
118
87
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
value === null ? undefined : propertyValueDeserializer.deserializeValue(value, property as Property)
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
if (property.type instanceof Enumeration) {
|
|
137
|
-
const literal = property.type.literals.find(literal => literal.key === value)
|
|
138
|
-
if (literal !== undefined) {
|
|
139
|
-
propertySettings[property.key] = writer.encodingOf(literal)
|
|
140
|
-
}
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
// (property is not handled, because neither a primitive type nor of enumeration type)
|
|
144
|
-
}
|
|
145
|
-
})
|
|
88
|
+
/**
|
|
89
|
+
* Instantiates a {@link Node} from the given {@link LionWebJsonNode},
|
|
90
|
+
* and stores it under its ID so references to it can be resolved.
|
|
91
|
+
* For every serialized node, only one instance will ever be constructed (through memoisation).
|
|
92
|
+
*/
|
|
93
|
+
const instantiateMemoised = (serNode: LionWebJsonNode, parent?: NT): NT | null => {
|
|
94
|
+
if (serNode.id in deserializedNodeById) {
|
|
95
|
+
return deserializedNodeById[serNode.id]
|
|
96
|
+
}
|
|
97
|
+
const node = instantiate(serNode, parent)
|
|
98
|
+
if (node !== null) {
|
|
99
|
+
deserializedNodeById[node.id] = node
|
|
100
|
+
}
|
|
101
|
+
return node
|
|
146
102
|
}
|
|
147
103
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
104
|
+
type ReferenceToInstall = [node: NT, feature: Reference, refId: LionWebId]
|
|
105
|
+
const referencesToInstall: ReferenceToInstall[] = []
|
|
106
|
+
|
|
107
|
+
const tryInstantiate = (
|
|
108
|
+
parent: NT | undefined,
|
|
109
|
+
classifier: Classifier,
|
|
110
|
+
id: LionWebId,
|
|
111
|
+
propertySettings: { [propertyKey: LionWebKey]: unknown }
|
|
112
|
+
): NT | null => {
|
|
113
|
+
try {
|
|
114
|
+
return writer.nodeFor(parent, classifier, id, propertySettings)
|
|
115
|
+
} catch (e: unknown) {
|
|
116
|
+
problemReporter.reportProblem(
|
|
117
|
+
`error occurred during instantiation of a node for classifier ${classifier.name} with meta-pointer (${classifier.language.key}, ${classifier.language.version}, ${classifier.key}); reason:`
|
|
118
|
+
)
|
|
119
|
+
problemReporter.reportProblem((e as Error).toString())
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
151
122
|
}
|
|
152
123
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Instantiates a {@link Node} from its {@link LionWebJsonNode serialization}.
|
|
126
|
+
*/
|
|
127
|
+
const instantiate = (
|
|
128
|
+
{
|
|
129
|
+
id,
|
|
130
|
+
classifier: classifierMetaPointer,
|
|
131
|
+
properties,
|
|
132
|
+
containments,
|
|
133
|
+
references,
|
|
134
|
+
annotations
|
|
135
|
+
}: LionWebJsonNode,
|
|
136
|
+
parent?: NT
|
|
137
|
+
): NT | null => {
|
|
138
|
+
const classifier = symbolTable.entityMatching(classifierMetaPointer)
|
|
139
|
+
|
|
140
|
+
if (classifier === undefined || !(classifier instanceof Classifier)) {
|
|
141
|
+
problemReporter.reportProblem(
|
|
142
|
+
`can't deserialize node with id=${id}: can't find the classifier with key ${classifierMetaPointer.key} in language (${classifierMetaPointer.language}, ${classifierMetaPointer.version})`
|
|
143
|
+
)
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const allFeatures = symbolTable.allFeaturesOfEntityMatching(classifierMetaPointer)
|
|
148
|
+
|
|
149
|
+
const propertySettings: { [propertyKey: LionWebKey]: unknown } = {}
|
|
150
|
+
|
|
151
|
+
const serializedPropertiesPerKey = properties === undefined ? {} : groupBy(properties, sp => sp.property.key) // (this assumes no duplicate keys among properties!)
|
|
152
|
+
if (properties !== undefined) {
|
|
153
|
+
allFeatures
|
|
154
|
+
.filter(feature => feature instanceof Property)
|
|
155
|
+
.map(feature => feature as Property)
|
|
156
|
+
.forEach(property => {
|
|
157
|
+
if (property.key in serializedPropertiesPerKey) {
|
|
158
|
+
const value = serializedPropertiesPerKey[property.key][0].value
|
|
159
|
+
if (property.type instanceof PrimitiveType) {
|
|
160
|
+
propertySettings[property.key] =
|
|
161
|
+
value === null ? undefined : propertyValueDeserializer.deserializeValue(value, property as Property)
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
if (property.type instanceof Enumeration) {
|
|
165
|
+
const literal = property.type.literals.find(literal => literal.key === value)
|
|
166
|
+
if (literal !== undefined) {
|
|
167
|
+
propertySettings[property.key] = writer.encodingOf(literal)
|
|
168
|
+
}
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
problemReporter.reportProblem(`property ${property.name} on classifier ${classifier.name} is not handled, because its type is neither a primitive type nor an enumeration`)
|
|
165
172
|
}
|
|
166
173
|
})
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const node = tryInstantiate(parent, classifier, id, propertySettings)
|
|
177
|
+
if (node === null) {
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const serializedContainmentsPerKey = containments === undefined ? {} : groupBy(containments, sp => sp.containment.key) // (this assumes no duplicate keys among containments!)
|
|
182
|
+
const serializedReferencesPerKey = references === undefined ? {} : groupBy(references, sp => sp.reference.key) // (this assumes no duplicate keys among references!)
|
|
183
|
+
|
|
184
|
+
allFeatures.forEach(feature => {
|
|
185
|
+
if (feature instanceof Property && properties !== undefined && feature.key in serializedPropertiesPerKey) {
|
|
186
|
+
writer.setFeatureValue(node, feature, propertySettings[feature.key])
|
|
187
|
+
} else if (feature instanceof Containment && containments !== undefined && feature.key in serializedContainmentsPerKey) {
|
|
188
|
+
const childIds = serializedContainmentsPerKey[feature.key].flatMap(serChildren => serChildren.children) as LionWebId[]
|
|
189
|
+
if (feature.multiple) {
|
|
190
|
+
childIds.forEach(childId => {
|
|
191
|
+
if (childId in serializedNodeById) {
|
|
192
|
+
writer.setFeatureValue(node, feature, instantiateMemoised(serializedNodeById[childId], node))
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
} else {
|
|
196
|
+
if (childIds.length > 0) {
|
|
197
|
+
// just set the 1st one:
|
|
198
|
+
const firstChildId = childIds[0]
|
|
199
|
+
if (firstChildId in serializedNodeById) {
|
|
200
|
+
writer.setFeatureValue(node, feature, instantiateMemoised(serializedNodeById[firstChildId], node))
|
|
201
|
+
}
|
|
173
202
|
}
|
|
174
203
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
serReferences.targets.map(t => t.reference)
|
|
179
|
-
)
|
|
180
|
-
referencesToInstall.push(
|
|
181
|
-
...(serRefs.filter(serRef => typeof serRef === "string") as LionWebId[]).map(
|
|
182
|
-
refId => [node, feature, refId] as ReferenceToInstall
|
|
204
|
+
} else if (feature instanceof Reference && references !== undefined && feature.key in serializedReferencesPerKey) {
|
|
205
|
+
const serRefs = (serializedReferencesPerKey[feature.key] ?? []).flatMap(serReferences =>
|
|
206
|
+
serReferences.targets.map(t => t.reference)
|
|
183
207
|
)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
208
|
+
referencesToInstall.push(
|
|
209
|
+
...(serRefs.filter(serRef => typeof serRef === "string") as LionWebId[]).map(
|
|
210
|
+
refId => [node, feature, refId] as ReferenceToInstall
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
})
|
|
187
215
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
216
|
+
node.annotations = keepDefineds(
|
|
217
|
+
annotations
|
|
218
|
+
.filter(annotationId => annotationId in serializedNodeById)
|
|
219
|
+
.map(annotationId => instantiateMemoised(serializedNodeById[annotationId]))
|
|
220
|
+
)
|
|
221
|
+
.map(annotation => annotation!)
|
|
222
|
+
|
|
223
|
+
return node
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const rootLikeNodes = keepDefineds(
|
|
227
|
+
serializedNodes
|
|
228
|
+
.filter(({ parent }) => parent === null || !(parent in serializedNodeById))
|
|
229
|
+
.map(serializedNode => instantiateMemoised(serializedNode))
|
|
192
230
|
)
|
|
193
|
-
.map(
|
|
231
|
+
.map(node => node!)
|
|
194
232
|
|
|
195
|
-
|
|
196
|
-
}
|
|
233
|
+
const dependentNodesById = byIdMap(dependentNodes)
|
|
197
234
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return unresolved
|
|
216
|
-
}
|
|
217
|
-
return target
|
|
218
|
-
})()
|
|
219
|
-
writer.setFeatureValue(node, reference, value)
|
|
220
|
-
})
|
|
235
|
+
referencesToInstall.forEach(([node, reference, refId]) => {
|
|
236
|
+
const target = deserializedNodeById[refId] ?? dependentNodesById[refId]
|
|
237
|
+
const value = (() => {
|
|
238
|
+
if (target === undefined) {
|
|
239
|
+
const metaTypeMessage = "concept" in node ? ` and (meta-)type ${node.concept}` : ""
|
|
240
|
+
problemReporter.reportProblem(
|
|
241
|
+
`couldn't resolve the target with id=${refId} of a "${reference.name}" reference on the node with id=${node.id}${metaTypeMessage}`
|
|
242
|
+
)
|
|
243
|
+
return unresolved
|
|
244
|
+
}
|
|
245
|
+
return target
|
|
246
|
+
})()
|
|
247
|
+
writer.setFeatureValue(node, reference, value)
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
return rootLikeNodes
|
|
251
|
+
}
|
|
221
252
|
|
|
222
|
-
return rootLikeNodes
|
|
223
253
|
}
|
|
224
254
|
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @return a deserialization of a {@link LionWebJsonChunk}.
|
|
258
|
+
*
|
|
259
|
+
* @param serializationChunk - a {@link SerializedModel model} from its LionWeb serialization JSON format
|
|
260
|
+
* @param writer - a {@link Writer} that is used to instantiate nodes and set values on them
|
|
261
|
+
* @param languages - {@link Language languages} that the serialized model is expected to conform to
|
|
262
|
+
* @param dependentNodes - a collection of nodes from dependent models against which all references in the serialized model are supposed to resolve against
|
|
263
|
+
* @param propertyValueDeserializer - a deserializer for values of properties (by default a {@link BuiltinPropertyValueDeserializer})
|
|
264
|
+
* @param problemReporter - an object for reporting problems (by default a {@link consoleProblemReporter})
|
|
265
|
+
*
|
|
266
|
+
* This is a legacy variant of {@link deserializerWith}, kept for backward compatibility, and to be deprecated and removed later.
|
|
267
|
+
*/
|
|
268
|
+
export const deserializeSerializationChunk = <NT extends Node>(
|
|
269
|
+
serializationChunk: LionWebJsonChunk,
|
|
270
|
+
writer: Writer<NT>,
|
|
271
|
+
languages: Language[],
|
|
272
|
+
// TODO facades <--> languages, so it's weird that it looks split up like this
|
|
273
|
+
dependentNodes: Node[],
|
|
274
|
+
// TODO (#13) see if you can turn this into [nodes: Node[], writer: Writer<Node>][] after all
|
|
275
|
+
propertyValueDeserializer: PropertyValueDeserializer = builtinPropertyValueDeserializer,
|
|
276
|
+
problemReporter: ProblemReporter = consoleProblemReporter
|
|
277
|
+
): NT[] => deserializerWith({ writer, languages, propertyValueDeserializer, problemReporter: problemReporter })(serializationChunk, dependentNodes)
|
|
278
|
+
|
|
225
279
|
/**
|
|
226
280
|
* Alias for {@link deserializeSerializationChunk}.
|
|
227
281
|
*/
|
|
228
282
|
export const deserializeChunk = deserializeSerializationChunk
|
|
283
|
+
|
package/src/functions.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { LionWebId } from "@lionweb/json"
|
|
1
|
+
import { LionWebId, LionWebJsonMetaPointer } from "@lionweb/json"
|
|
2
2
|
import { flatMapNonCyclingFollowing, trivialFlatMapper } from "@lionweb/ts-utils"
|
|
3
3
|
import { Node } from "./types.js"
|
|
4
|
+
import { Feature } from "./m3/index.js"
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -26,3 +27,16 @@ export const asIds = (nodeOrNulls: (Node | null)[]): (LionWebId | null)[] =>
|
|
|
26
27
|
export const idOf = <T extends Node>({id}: T): LionWebId =>
|
|
27
28
|
id
|
|
28
29
|
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @return the {@link LionWebJsonMetaPointer} for the given {@link Feature}.
|
|
33
|
+
*/
|
|
34
|
+
export const metaPointerFor = (feature: Feature): LionWebJsonMetaPointer => {
|
|
35
|
+
const { language } = feature.classifier
|
|
36
|
+
return {
|
|
37
|
+
language: language.key,
|
|
38
|
+
version: language.version,
|
|
39
|
+
key: feature.key
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export * from "./deserializer.js"
|
|
2
2
|
export * from "./dynamic-facade.js"
|
|
3
3
|
export * from "./extraction.js"
|
|
4
|
-
export * from "./handler.js"
|
|
5
4
|
export * from "./functions.js"
|
|
6
5
|
export * from "./reading.js"
|
|
7
6
|
export * from "./references.js"
|
|
7
|
+
export * from "./reporter.js"
|
|
8
8
|
export * from "./serializer.js"
|
|
9
9
|
export * from "./types.js"
|
|
10
10
|
export * from "./version.js"
|
package/src/m3/builtins.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { PropertyValueSerializer } from "../serializer.js"
|
|
|
4
4
|
import { currentReleaseVersion } from "../version.js"
|
|
5
5
|
import { LanguageFactory } from "./factory.js"
|
|
6
6
|
import { Classifier, Concept, DataType, lioncoreBuiltinsKey, Property } from "./types.js"
|
|
7
|
-
import {
|
|
7
|
+
import { isUnresolvedReference } from "../references.js"
|
|
8
8
|
|
|
9
9
|
const lioncoreBuiltinsIdAndKeyGenerator: StringsMapper = (...names) => [lioncoreBuiltinsKey, ...names.slice(1)].join("-")
|
|
10
10
|
|
|
@@ -129,7 +129,7 @@ export class BuiltinPropertyValueDeserializer
|
|
|
129
129
|
throw new Error(`can't deserialize undefined as the value of required property "${property.name}" (on classifier "${property.classifier.name}" in language "${property.classifier.language.name}")`)
|
|
130
130
|
}
|
|
131
131
|
const { type } = property
|
|
132
|
-
if (type
|
|
132
|
+
if (isUnresolvedReference(type)) {
|
|
133
133
|
throw new Error(`can't deserialize property "${property.name}" (on classifier "${property.classifier.name}" in language "${property.classifier.language.name}") with unspecified type`)
|
|
134
134
|
}
|
|
135
135
|
const specificDeserializer = this.byType(type)
|
|
@@ -172,7 +172,7 @@ export class BuiltinPropertyValueSerializer extends DataTypeRegister<(value: unk
|
|
|
172
172
|
throw new Error(`can't serialize undefined as the value of required property "${property.name}" (on classifier "${property.classifier.name}" in language "${property.classifier.language.name}")`)
|
|
173
173
|
}
|
|
174
174
|
const { type } = property
|
|
175
|
-
if (type
|
|
175
|
+
if (isUnresolvedReference(type)) {
|
|
176
176
|
throw new Error(`can't serialize property "${property.name}" (on classifier "${property.classifier.name}" in language "${property.classifier.language.name}") with unspecified type`)
|
|
177
177
|
}
|
|
178
178
|
const specificSerializer = this.byType(type)
|
package/src/m3/deserializer.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LionWebJsonChunk } from "@lionweb/json"
|
|
2
|
-
import {
|
|
2
|
+
import { deserializerWith } from "../deserializer.js"
|
|
3
3
|
import { nodesExtractorUsing } from "../extraction.js"
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { consoleProblemReporter, ProblemReporter } from "../reporter.js"
|
|
5
|
+
import { lioncoreBuiltins } from "./builtins.js"
|
|
6
6
|
import { lioncoreReader, lioncoreWriter } from "./facade.js"
|
|
7
7
|
import { lioncore } from "./lioncore.js"
|
|
8
8
|
import { Language } from "./types.js"
|
|
@@ -13,26 +13,31 @@ import { Language } from "./types.js"
|
|
|
13
13
|
* as an instance of the LionCore metametamodel, using {@link _M3Concept these type definitions}.
|
|
14
14
|
*/
|
|
15
15
|
export const deserializeLanguages = (serializationChunk: LionWebJsonChunk, ...dependentLanguages: Language[]): Language[] =>
|
|
16
|
-
|
|
16
|
+
deserializeLanguagesWithReporter(serializationChunk, consoleProblemReporter, ...dependentLanguages)
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Deserializes languages that have been serialized into the LionWeb serialization JSON format
|
|
20
20
|
* as an instance of the LionCore metametamodel, using {@link _M3Concept these type definitions}.
|
|
21
|
-
* This function takes a
|
|
21
|
+
* This function takes a {@link ProblemReporter} to be able to see what problems occurred.
|
|
22
22
|
*/
|
|
23
|
-
export const
|
|
23
|
+
export const deserializeLanguagesWithReporter = (
|
|
24
24
|
serializationChunk: LionWebJsonChunk,
|
|
25
|
-
|
|
25
|
+
problemReporter: ProblemReporter,
|
|
26
26
|
...dependentLanguages: Language[]
|
|
27
27
|
): Language[] =>
|
|
28
|
-
|
|
28
|
+
deserializerWith({
|
|
29
|
+
writer: lioncoreWriter,
|
|
30
|
+
languages: [lioncore, ...dependentLanguages],
|
|
31
|
+
problemReporter: problemReporter
|
|
32
|
+
})(
|
|
29
33
|
serializationChunk,
|
|
30
|
-
lioncoreWriter,
|
|
31
|
-
[lioncore, ...dependentLanguages],
|
|
32
34
|
[lioncoreBuiltins, ...dependentLanguages].flatMap(nodesExtractorUsing(lioncoreReader)),
|
|
33
|
-
builtinPropertyValueDeserializer,
|
|
34
|
-
handler
|
|
35
35
|
)
|
|
36
36
|
.filter((rootNode) => rootNode instanceof Language)
|
|
37
37
|
.map((language) => (language as Language).dependingOn(...dependentLanguages))
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Legacy alias for {@link deserializeLanguagesWithReporter}, kept for backward compatibility, and to be deprecated and removed later.
|
|
41
|
+
*/
|
|
42
|
+
export const deserializeLanguagesWithHandler = deserializeLanguagesWithReporter
|
|
43
|
+
|
package/src/m3/functions.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { LionWebId, LionWebKey } from "@lionweb/json"
|
|
|
7
7
|
import { cycleWith, flatMapNonCyclingFollowing, sortByStringKey } from "@lionweb/ts-utils"
|
|
8
8
|
import { containmentChain } from "../functions.js"
|
|
9
9
|
import { ClassifierDeducer } from "../reading.js"
|
|
10
|
-
import { isRef,
|
|
10
|
+
import { isRef, UnresolvedReference } from "../references.js"
|
|
11
11
|
import { Node } from "../types.js"
|
|
12
12
|
import {
|
|
13
13
|
Annotation,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
/**
|
|
35
35
|
* @return The type of the given {@link Feature}
|
|
36
36
|
*/
|
|
37
|
-
const type = (feature: Feature): Classifier | DataType |
|
|
37
|
+
const type = (feature: Feature): Classifier | DataType | UnresolvedReference =>
|
|
38
38
|
(feature as (Link | Property)).type
|
|
39
39
|
|
|
40
40
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isUnresolvedReference, SingleRef } from "../references.js"
|
|
2
2
|
import { flatMap, qualifiedNameOf } from "./functions.js"
|
|
3
3
|
import { Concept, Containment, Language, Property, Reference } from "./types.js"
|
|
4
4
|
import { Node } from "../types.js"
|
|
@@ -14,7 +14,7 @@ export const checkReferences = (language: Language): string[] =>
|
|
|
14
14
|
|
|
15
15
|
const locations: string[] = []
|
|
16
16
|
const check = (location: string, ref?: SingleRef<Node>) => {
|
|
17
|
-
if (ref
|
|
17
|
+
if (isUnresolvedReference(ref)) {
|
|
18
18
|
locations.push(location)
|
|
19
19
|
}
|
|
20
20
|
}
|
package/src/m3/serializer.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LionWebJsonChunk } from "@lionweb/json"
|
|
2
|
-
import {
|
|
2
|
+
import { serializerWith } from "../serializer.js"
|
|
3
3
|
import { lioncoreReader } from "./facade.js"
|
|
4
4
|
import { Language } from "./types.js"
|
|
5
5
|
|
|
@@ -9,5 +9,5 @@ import { Language } from "./types.js"
|
|
|
9
9
|
* into the LionWeb serialization JSON format.
|
|
10
10
|
*/
|
|
11
11
|
export const serializeLanguages = (...languages: Language[]): LionWebJsonChunk =>
|
|
12
|
-
|
|
12
|
+
serializerWith({ reader: lioncoreReader })(languages)
|
|
13
13
|
|