@lionweb/core 0.7.0-beta.2 → 0.7.0-beta.21
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 +9 -0
- package/dist/deserializer.d.ts +2 -2
- package/dist/deserializer.d.ts.map +1 -1
- package/dist/deserializer.js +7 -10
- package/dist/deserializer.js.map +1 -1
- package/dist/extraction.d.ts.map +1 -1
- package/dist/functions.d.ts.map +1 -1
- package/dist/handler.d.ts +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/m1/reference-utils.d.ts +1 -1
- package/dist/m1/reference-utils.d.ts.map +1 -1
- package/dist/m3/builtins.d.ts.map +1 -1
- package/dist/m3/builtins.js +2 -1
- package/dist/m3/builtins.js.map +1 -1
- package/dist/m3/constraints.d.ts.map +1 -1
- package/dist/m3/constraints.js +2 -2
- package/dist/m3/constraints.js.map +1 -1
- package/dist/m3/deserializer.d.ts.map +1 -1
- package/dist/m3/feature-resolvers.d.ts +23 -0
- package/dist/m3/feature-resolvers.d.ts.map +1 -0
- package/dist/m3/feature-resolvers.js +48 -0
- package/dist/m3/feature-resolvers.js.map +1 -0
- package/dist/m3/functions.d.ts +17 -1
- package/dist/m3/functions.d.ts.map +1 -1
- package/dist/m3/functions.js +21 -5
- package/dist/m3/functions.js.map +1 -1
- package/dist/m3/index.d.ts +2 -0
- package/dist/m3/index.d.ts.map +1 -1
- package/dist/m3/index.js +2 -0
- package/dist/m3/index.js.map +1 -1
- package/dist/m3/reference-checker.d.ts.map +1 -1
- package/dist/m3/serializer.d.ts.map +1 -1
- package/dist/{symbol-table.d.ts → m3/symbol-table.d.ts} +14 -14
- package/dist/m3/symbol-table.d.ts.map +1 -0
- package/dist/m3/symbol-table.js +43 -0
- package/dist/m3/symbol-table.js.map +1 -0
- package/dist/m3/types.d.ts.map +1 -1
- package/dist/references.d.ts +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/serializer.d.ts +1 -1
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +20 -10
- package/dist/serializer.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/writing.js +1 -1
- package/package.json +31 -31
- package/src/deserializer.ts +224 -0
- package/src/dynamic-facade.ts +63 -0
- package/src/extraction.ts +31 -0
- package/src/functions.ts +28 -0
- package/src/handler.ts +57 -0
- package/src/index.ts +13 -0
- package/src/m1/reference-utils.ts +106 -0
- package/src/m3/README.md +16 -0
- package/src/m3/builtins.ts +170 -0
- package/src/m3/constraints.ts +109 -0
- package/src/m3/deserializer.ts +38 -0
- package/src/m3/facade.ts +130 -0
- package/src/m3/factory.ts +98 -0
- package/src/m3/feature-resolvers.ts +72 -0
- package/src/m3/functions.ts +379 -0
- package/src/m3/index.ts +12 -0
- package/src/m3/lioncore.ts +139 -0
- package/src/m3/reference-checker.ts +38 -0
- package/src/m3/serializer.ts +13 -0
- package/src/m3/symbol-table.ts +125 -0
- package/src/m3/types.ts +325 -0
- package/src/reading.ts +55 -0
- package/src/references.ts +31 -0
- package/src/serializer.ts +244 -0
- package/src/types.ts +11 -0
- package/src/version.ts +5 -0
- package/src/writing.ts +79 -0
- package/dist/symbol-table.d.ts.map +0 -1
- package/dist/symbol-table.js +0 -66
- package/dist/symbol-table.js.map +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { currentReleaseVersion } from "../version.js"
|
|
2
|
+
import { builtinClassifiers, builtinPrimitives } from "./builtins.js"
|
|
3
|
+
import { LanguageFactory } from "./factory.js"
|
|
4
|
+
|
|
5
|
+
const lioncoreKey = "LionCore-M3"
|
|
6
|
+
|
|
7
|
+
const factory = new LanguageFactory(
|
|
8
|
+
"LionCore_M3",
|
|
9
|
+
currentReleaseVersion,
|
|
10
|
+
(...names) => "-id-" + (names.length === 1 ? lioncoreKey : names.slice(1).join("-")),
|
|
11
|
+
(...names) => names.slice(1).join("-")
|
|
12
|
+
)
|
|
13
|
+
/*
|
|
14
|
+
* ID: `-id-${key}`
|
|
15
|
+
* key: qualified name _without_ "LionCore_M3", dash-separated
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Definition of LionCore in terms of itself.
|
|
20
|
+
*/
|
|
21
|
+
export const lioncore = factory.language.havingKey("LionCore-M3")
|
|
22
|
+
|
|
23
|
+
const { inamed } = builtinClassifiers
|
|
24
|
+
const { booleanDataType, stringDataType } = builtinPrimitives
|
|
25
|
+
|
|
26
|
+
const ikeyed = factory.interface("IKeyed").extending(inamed)
|
|
27
|
+
|
|
28
|
+
const ikeyed_key = factory.property(ikeyed, "key").ofType(stringDataType)
|
|
29
|
+
|
|
30
|
+
const feature = factory.concept("Feature", true).implementing(ikeyed)
|
|
31
|
+
|
|
32
|
+
const feature_optional = factory.property(feature, "optional").ofType(booleanDataType)
|
|
33
|
+
|
|
34
|
+
const property = factory.concept("Property", false, feature)
|
|
35
|
+
|
|
36
|
+
const property_type = factory.reference(property, "type")
|
|
37
|
+
|
|
38
|
+
const link = factory.concept("Link", true, feature)
|
|
39
|
+
|
|
40
|
+
const link_multiple = factory.property(link, "multiple").ofType(booleanDataType)
|
|
41
|
+
|
|
42
|
+
const link_type = factory.reference(link, "type")
|
|
43
|
+
|
|
44
|
+
const containment = factory.concept("Containment", false, link)
|
|
45
|
+
|
|
46
|
+
const reference = factory.concept("Reference", false, link)
|
|
47
|
+
|
|
48
|
+
const languageEntity = factory.concept("LanguageEntity", true).implementing(ikeyed)
|
|
49
|
+
|
|
50
|
+
const classifier = factory.concept("Classifier", true, languageEntity)
|
|
51
|
+
|
|
52
|
+
const classifier_features = factory.containment(classifier, "features").isOptional().isMultiple().ofType(feature)
|
|
53
|
+
|
|
54
|
+
link_type.ofType(classifier)
|
|
55
|
+
|
|
56
|
+
const annotation = factory.concept("Annotation", false, classifier)
|
|
57
|
+
|
|
58
|
+
const annotation_annotates = factory.reference(annotation, "annotates").isOptional().ofType(classifier)
|
|
59
|
+
|
|
60
|
+
const annotation_extends = factory.reference(annotation, "extends").isOptional().ofType(annotation)
|
|
61
|
+
|
|
62
|
+
const annotation_implements = factory.reference(annotation, "implements").isMultiple().isOptional()
|
|
63
|
+
|
|
64
|
+
const concept = factory.concept("Concept", false, classifier)
|
|
65
|
+
|
|
66
|
+
const concept_abstract = factory.property(concept, "abstract").ofType(booleanDataType)
|
|
67
|
+
|
|
68
|
+
const concept_partition = factory.property(concept, "partition").ofType(booleanDataType)
|
|
69
|
+
|
|
70
|
+
const concept_extends = factory.reference(concept, "extends").isOptional().ofType(concept)
|
|
71
|
+
|
|
72
|
+
const concept_implements = factory.reference(concept, "implements").isOptional().isMultiple()
|
|
73
|
+
|
|
74
|
+
const interface_ = factory.concept("Interface", false, classifier)
|
|
75
|
+
|
|
76
|
+
const interface_extends = factory.reference(interface_, "extends").isOptional().isMultiple().ofType(interface_)
|
|
77
|
+
|
|
78
|
+
annotation_implements.ofType(interface_)
|
|
79
|
+
concept_implements.ofType(interface_)
|
|
80
|
+
|
|
81
|
+
const dataType = factory.concept("DataType", true, languageEntity)
|
|
82
|
+
|
|
83
|
+
property_type.ofType(dataType)
|
|
84
|
+
|
|
85
|
+
const primitiveType = factory.concept("PrimitiveType", false, dataType)
|
|
86
|
+
|
|
87
|
+
const enumeration = factory.concept("Enumeration", false, dataType)
|
|
88
|
+
|
|
89
|
+
const enumeration_literals = factory.containment(enumeration, "literals").isMultiple().isOptional()
|
|
90
|
+
|
|
91
|
+
const enumerationLiteral = factory.concept("EnumerationLiteral", false).implementing(ikeyed)
|
|
92
|
+
|
|
93
|
+
enumeration_literals.ofType(enumerationLiteral)
|
|
94
|
+
|
|
95
|
+
const language = factory.concept("Language", false).implementing(ikeyed).isPartition()
|
|
96
|
+
|
|
97
|
+
const language_version = factory.property(language, "version").ofType(stringDataType)
|
|
98
|
+
|
|
99
|
+
const language_entities = factory.containment(language, "entities").isOptional().isMultiple().ofType(languageEntity)
|
|
100
|
+
|
|
101
|
+
const language_dependsOn = factory.reference(language, "dependsOn").isOptional().isMultiple().ofType(language)
|
|
102
|
+
|
|
103
|
+
export const metaConcepts = {
|
|
104
|
+
annotation,
|
|
105
|
+
classifier,
|
|
106
|
+
concept,
|
|
107
|
+
interface: interface_,
|
|
108
|
+
containment,
|
|
109
|
+
enumeration,
|
|
110
|
+
enumerationLiteral,
|
|
111
|
+
ikeyed,
|
|
112
|
+
language,
|
|
113
|
+
primitiveType,
|
|
114
|
+
property,
|
|
115
|
+
reference
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const metaFeatures = {
|
|
119
|
+
annotation_annotates,
|
|
120
|
+
annotation_extends,
|
|
121
|
+
annotation_implements,
|
|
122
|
+
classifier_features,
|
|
123
|
+
concept_abstract,
|
|
124
|
+
concept_partition,
|
|
125
|
+
concept_extends,
|
|
126
|
+
concept_implements,
|
|
127
|
+
interface_extends,
|
|
128
|
+
enumeration_literals,
|
|
129
|
+
feature_optional,
|
|
130
|
+
ikeyed_key,
|
|
131
|
+
language_dependsOn,
|
|
132
|
+
language_entities,
|
|
133
|
+
language_version,
|
|
134
|
+
link_multiple,
|
|
135
|
+
link_type,
|
|
136
|
+
property_type
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { lioncoreKey }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SingleRef, unresolved } from "../references.js"
|
|
2
|
+
import { flatMap, qualifiedNameOf } from "./functions.js"
|
|
3
|
+
import { Concept, Containment, Language, Property, Reference } from "./types.js"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Checks whether the metamodel of the given language contains unresolved references.
|
|
8
|
+
*/
|
|
9
|
+
export const checkReferences = (language: Language): string[] =>
|
|
10
|
+
flatMap(
|
|
11
|
+
language,
|
|
12
|
+
(thing) => {
|
|
13
|
+
|
|
14
|
+
const locations: string[] = []
|
|
15
|
+
const check = (ref: SingleRef<unknown>, location: string) => {
|
|
16
|
+
if (ref === unresolved) {
|
|
17
|
+
locations.push(location)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (thing instanceof Concept) {
|
|
22
|
+
check(thing.extends, `<Concept>${qualifiedNameOf(thing)}#extends`)
|
|
23
|
+
}
|
|
24
|
+
if (thing instanceof Containment) {
|
|
25
|
+
check(thing.type, `<Containment>${qualifiedNameOf(thing)}#type`)
|
|
26
|
+
}
|
|
27
|
+
if (thing instanceof Property) {
|
|
28
|
+
check(thing.type, `<Property>${qualifiedNameOf(thing)}#type`)
|
|
29
|
+
}
|
|
30
|
+
if (thing instanceof Reference) {
|
|
31
|
+
check(thing.type, `<Reference>${qualifiedNameOf(thing)}#type`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return locations
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
// TODO (#8) make this generic, parametrized by a {@link Metamodel}
|
|
38
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { LionWebJsonChunk } from "@lionweb/json"
|
|
2
|
+
import { nodeSerializer } from "../serializer.js"
|
|
3
|
+
import { lioncoreReader } from "./facade.js"
|
|
4
|
+
import { Language } from "./types.js"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Serializes languages (i.e., instances of the LionCore metametamodel, using {@link M3Concept these type definitions})
|
|
9
|
+
* into the LionWeb serialization JSON format.
|
|
10
|
+
*/
|
|
11
|
+
export const serializeLanguages = (...languages: Language[]): LionWebJsonChunk =>
|
|
12
|
+
nodeSerializer(lioncoreReader)(languages)
|
|
13
|
+
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { LionWebJsonMetaPointer, LionWebKey } from "@lionweb/json"
|
|
2
|
+
import { lazyMapGet } from "@lionweb/ts-utils"
|
|
3
|
+
import { allFeaturesOf } from "./functions.js"
|
|
4
|
+
import { Classifier, Feature, Language, LanguageEntity } from "./types.js"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Interface for objects that can look up within languages, based on given {@link LionWebJsonMetaPointer meta pointers}.
|
|
9
|
+
* This is meant to be able to properly encapsulate performance optimizations, also outside of the context
|
|
10
|
+
* of deserialization.
|
|
11
|
+
*/
|
|
12
|
+
interface SymbolTable {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Looks up the {@link Language}, as pointed to by the given language key and version.
|
|
16
|
+
*/
|
|
17
|
+
languageMatching(key: LionWebKey, version: string): Language | undefined
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Looks up the {@link LanguageEntity}, as pointed to by the given {@link LionWebJsonMetaPointer},
|
|
21
|
+
* or {@code undefined} if it couldn't be found.
|
|
22
|
+
*/
|
|
23
|
+
entityMatching(entityMetaPointer: LionWebJsonMetaPointer): LanguageEntity | undefined
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Looks up the {@link Feature}, as pointed to by the {@link LionWebJsonMetaPointer} given second,
|
|
27
|
+
* as a feature of the {@link Classifier}, as pointed to by the {@link LionWebJsonMetaPointer} given first,
|
|
28
|
+
* or {@code undefined} it it couldn't be found.
|
|
29
|
+
* *Note* that the {@code language} and {@code version} values of both {@link LionWebJsonMetaPointer}-typed arguments should coincide,
|
|
30
|
+
* although this is typically not checked!
|
|
31
|
+
*/
|
|
32
|
+
featureMatching(entityMetaPointer: LionWebJsonMetaPointer, featureMetaPointer: LionWebJsonMetaPointer): Feature | undefined
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
type EntityInfo = {
|
|
38
|
+
entity: LanguageEntity
|
|
39
|
+
allFeatures: Feature[] // === [] if entity is not a Classifier
|
|
40
|
+
featureKey2feature: { [featureKey: LionWebKey]: Feature } // populated through memoisation
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A {@link SymbolTable} implementation that *memoises* the items it has looked up.
|
|
46
|
+
* This helps with performance, because otherwise lookup might be linear in the (max.) number of languages,
|
|
47
|
+
* entities in a language, features in classifiers — taking inheritance into account.
|
|
48
|
+
*/
|
|
49
|
+
class MemoisingSymbolTable implements SymbolTable {
|
|
50
|
+
|
|
51
|
+
private readonly languages: Language[]
|
|
52
|
+
|
|
53
|
+
constructor(languages: Language[]) {
|
|
54
|
+
this.languages = languages
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private readonly languageKey2version2language: { [languageKey: LionWebKey]: { [version: string]: Language } } = {}
|
|
58
|
+
|
|
59
|
+
languageMatching = (languageKey: LionWebKey, version: string): Language | undefined =>
|
|
60
|
+
lazyMapGet(
|
|
61
|
+
lazyMapGet(this.languageKey2version2language, languageKey, () => ({})),
|
|
62
|
+
version,
|
|
63
|
+
() => this.languages.find((language) =>
|
|
64
|
+
language.key === languageKey
|
|
65
|
+
&& language.version === version
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
private readonly languageKey2version2entityKey2entityInfo: { [languageKey: LionWebKey]: { [version: string]: { [entityKey: LionWebKey]: (EntityInfo | undefined) } } } = {}
|
|
71
|
+
|
|
72
|
+
private entityInfoMatching = (entityMetaPointer: LionWebJsonMetaPointer): undefined | EntityInfo =>
|
|
73
|
+
lazyMapGet(
|
|
74
|
+
lazyMapGet(
|
|
75
|
+
lazyMapGet(this.languageKey2version2entityKey2entityInfo, entityMetaPointer.language, () => ({})),
|
|
76
|
+
entityMetaPointer.version,
|
|
77
|
+
() => ({})
|
|
78
|
+
),
|
|
79
|
+
entityMetaPointer.key,
|
|
80
|
+
() => {
|
|
81
|
+
const entity = this.languageMatching(entityMetaPointer.language, entityMetaPointer.version)
|
|
82
|
+
?.entities
|
|
83
|
+
.find((entity) => entity.key === entityMetaPointer.key)
|
|
84
|
+
return entity === undefined
|
|
85
|
+
? undefined
|
|
86
|
+
: {
|
|
87
|
+
entity,
|
|
88
|
+
allFeatures: entity instanceof Classifier ? allFeaturesOf(entity) : [], featureKey2feature: {}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
entityMatching = (entityMetaPointer: LionWebJsonMetaPointer): LanguageEntity | undefined =>
|
|
94
|
+
this.entityInfoMatching(entityMetaPointer)?.entity
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Looks up the {@link LanguageEntity}, as pointed to by the given {@link LionWebJsonMetaPointer},
|
|
98
|
+
* and @returns all its {@link Feature features} or an empty array if it couldn't be found.
|
|
99
|
+
*/
|
|
100
|
+
allFeaturesOfEntityMatching = (entityMetaPointer: LionWebJsonMetaPointer): Feature[] =>
|
|
101
|
+
this.entityInfoMatching(entityMetaPointer)?.allFeatures ?? []
|
|
102
|
+
|
|
103
|
+
featureMatching = (classifierMetaPointer: LionWebJsonMetaPointer, featureMetaPointer: LionWebJsonMetaPointer): Feature | undefined => {
|
|
104
|
+
const entityInfo = this.entityInfoMatching(classifierMetaPointer)
|
|
105
|
+
if (entityInfo === undefined || !(entityInfo.entity instanceof Classifier)) {
|
|
106
|
+
return undefined
|
|
107
|
+
}
|
|
108
|
+
return lazyMapGet(
|
|
109
|
+
entityInfo.featureKey2feature,
|
|
110
|
+
featureMetaPointer.key,
|
|
111
|
+
() => entityInfo.allFeatures.find((feature) => feature.key === featureMetaPointer.key)
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
export type {
|
|
119
|
+
SymbolTable
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
MemoisingSymbolTable
|
|
124
|
+
}
|
|
125
|
+
|
package/src/m3/types.ts
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for the `LionCore` M3 (=meta-meta) model.
|
|
3
|
+
* A LionWeb language (at the M2 meta level) can be represented as an instance of the {@link Language} type.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { LionWebId, LionWebJsonMetaPointer, LionWebKey } from "@lionweb/json"
|
|
7
|
+
import { ResolveInfoDeducer } from "../reading.js"
|
|
8
|
+
import { MultiRef, SingleRef, unresolved } from "../references.js"
|
|
9
|
+
import { Node } from "../types.js"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The key of the LionCore language containing the built-ins.
|
|
14
|
+
* (It's defined here because of instantiation order.)
|
|
15
|
+
*/
|
|
16
|
+
const lioncoreBuiltinsKey = "LionCore-builtins"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
// Types appear roughly in the order of top-to-down+left-to-right in the diagram at:
|
|
20
|
+
// https://lionweb-io.github.io/specification/metametamodel/metametamodel.html#_overview
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
interface INamed {
|
|
24
|
+
name: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const isINamed = (node: object): node is INamed =>
|
|
28
|
+
"name" in node && typeof node.name === "string"
|
|
29
|
+
|
|
30
|
+
const simpleNameDeducer: ResolveInfoDeducer<Node> =
|
|
31
|
+
(node: Node) => isINamed(node) ? node.name : undefined
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
interface IKeyed extends INamed {
|
|
35
|
+
key: LionWebId
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* An interface with one method to return a meta type,
|
|
41
|
+
* independent of the class's name obtained through `<node>.constructor.name`,
|
|
42
|
+
* which may be brittle when using bundlers.
|
|
43
|
+
*/
|
|
44
|
+
interface IMetaTyped {
|
|
45
|
+
metaType(): string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Abstract base class for nodes in an LionCore instance,
|
|
50
|
+
* providing an ID, a key, and the containment hierarchy.
|
|
51
|
+
*/
|
|
52
|
+
abstract class M3Node implements IKeyed, IMetaTyped {
|
|
53
|
+
metaType(): string {
|
|
54
|
+
throw new Error("#metaType() not implemented")
|
|
55
|
+
}
|
|
56
|
+
parent?: M3Node
|
|
57
|
+
/*
|
|
58
|
+
* Note: every parent in an M2 (i.e., a Language, Concept, Interface, Enumeration) implements IKeyed.
|
|
59
|
+
* Because that's just an interface and is implemented by {@link M3Node},
|
|
60
|
+
* we can type parent as M3Node?.
|
|
61
|
+
*/
|
|
62
|
+
readonly id: LionWebId
|
|
63
|
+
name: string
|
|
64
|
+
key: LionWebId
|
|
65
|
+
protected constructor(id: LionWebId, name: string, key: LionWebId, parent?: M3Node) {
|
|
66
|
+
this.id = id
|
|
67
|
+
this.name = name
|
|
68
|
+
this.key = key
|
|
69
|
+
this.parent = parent
|
|
70
|
+
}
|
|
71
|
+
havingKey(key: LionWebId) {
|
|
72
|
+
this.key = key
|
|
73
|
+
return this
|
|
74
|
+
}
|
|
75
|
+
annotations: Node[] = [] // (containment)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
abstract class Feature extends M3Node {
|
|
79
|
+
optional /*: boolean */ = false
|
|
80
|
+
// TODO look at order of constructors' arguments!
|
|
81
|
+
constructor(classifier: Classifier, name: string, key: LionWebKey, id: LionWebId) {
|
|
82
|
+
super(id, name, key, classifier)
|
|
83
|
+
}
|
|
84
|
+
isOptional() {
|
|
85
|
+
this.optional = true
|
|
86
|
+
return this
|
|
87
|
+
}
|
|
88
|
+
get classifier(): Classifier {
|
|
89
|
+
return this.parent! as Classifier
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class Property extends Feature {
|
|
94
|
+
metaType(): string {
|
|
95
|
+
return "Property"
|
|
96
|
+
}
|
|
97
|
+
type: SingleRef<DataType> = unresolved // (reference)
|
|
98
|
+
ofType(type: DataType): Property {
|
|
99
|
+
this.type = type
|
|
100
|
+
return this
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
abstract class Link extends Feature {
|
|
105
|
+
multiple /*: boolean */ = false
|
|
106
|
+
type: SingleRef<Classifier> = unresolved // (reference)
|
|
107
|
+
isMultiple() {
|
|
108
|
+
this.multiple = true
|
|
109
|
+
return this
|
|
110
|
+
}
|
|
111
|
+
ofType(type: Classifier) {
|
|
112
|
+
this.type = type
|
|
113
|
+
return this
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class Containment extends Link {
|
|
118
|
+
metaType(): string {
|
|
119
|
+
return "Containment"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
class Reference extends Link {
|
|
124
|
+
metaType(): string {
|
|
125
|
+
return "Reference"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
abstract class LanguageEntity extends M3Node {
|
|
130
|
+
constructor(language: Language, name: string, key: LionWebId, id: LionWebId) {
|
|
131
|
+
super(id, name, key, language)
|
|
132
|
+
}
|
|
133
|
+
get language(): Language {
|
|
134
|
+
return this.parent! as Language
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
abstract class Classifier extends LanguageEntity {
|
|
139
|
+
features: Feature[] = [] // (containment)
|
|
140
|
+
havingFeatures(...features: Feature[]) {
|
|
141
|
+
this.features.push(...features.filter((feature) => this.features.indexOf(feature) < 0))
|
|
142
|
+
return this
|
|
143
|
+
}
|
|
144
|
+
metaPointer(): LionWebJsonMetaPointer {
|
|
145
|
+
const {language} = this
|
|
146
|
+
return {
|
|
147
|
+
language: language.key,
|
|
148
|
+
version: language.version,
|
|
149
|
+
key: this.key
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
class Concept extends Classifier {
|
|
155
|
+
metaType(): string {
|
|
156
|
+
return "Concept"
|
|
157
|
+
}
|
|
158
|
+
abstract: boolean
|
|
159
|
+
partition: boolean
|
|
160
|
+
extends?: SingleRef<Concept> // (reference)
|
|
161
|
+
implements: MultiRef<Interface> = [] // (reference)
|
|
162
|
+
constructor(language: Language, name: string, key: LionWebKey, id: LionWebId, abstract: boolean, extends_?: SingleRef<Concept>) {
|
|
163
|
+
super(language, name, key, id)
|
|
164
|
+
this.abstract = abstract
|
|
165
|
+
this.extends = extends_
|
|
166
|
+
this.partition = false
|
|
167
|
+
}
|
|
168
|
+
implementing(...interfaces: Interface[]): Concept {
|
|
169
|
+
// TODO check actual types of interfaces, or use type shapes/interfaces
|
|
170
|
+
this.implements.push(...interfaces)
|
|
171
|
+
return this
|
|
172
|
+
}
|
|
173
|
+
isPartition(): Concept {
|
|
174
|
+
this.partition = true
|
|
175
|
+
return this
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
class Annotation extends Classifier {
|
|
180
|
+
metaType(): string {
|
|
181
|
+
return "Annotation"
|
|
182
|
+
}
|
|
183
|
+
extends?: SingleRef<Annotation> // (reference)
|
|
184
|
+
implements: MultiRef<Interface> = [] // (reference)
|
|
185
|
+
annotates: SingleRef<Classifier> = unresolved // (reference)
|
|
186
|
+
constructor(language: Language, name: string, key: LionWebKey, id: LionWebId, extends_?: SingleRef<Annotation>) {
|
|
187
|
+
super(language, name, key, id)
|
|
188
|
+
this.extends = extends_
|
|
189
|
+
}
|
|
190
|
+
implementing(...interfaces: Interface[]): Annotation {
|
|
191
|
+
// TODO check actual types of interfaces, or use type shapes/interfaces
|
|
192
|
+
this.implements.push(...interfaces)
|
|
193
|
+
return this
|
|
194
|
+
}
|
|
195
|
+
annotating(classifier: Classifier): Annotation {
|
|
196
|
+
this.annotates = classifier
|
|
197
|
+
return this
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
class Interface extends Classifier {
|
|
202
|
+
metaType(): string {
|
|
203
|
+
return "Interface"
|
|
204
|
+
}
|
|
205
|
+
extends: MultiRef<Interface> = [] // (reference)
|
|
206
|
+
extending(...interfaces: Interface[]): Interface {
|
|
207
|
+
// TODO check actual types of interfaces, or use type shapes/interfaces
|
|
208
|
+
this.extends.push(...interfaces)
|
|
209
|
+
return this
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
abstract class DataType extends LanguageEntity {}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Misspelled alias of {@link DataType}, kept for backward compatibility, and to be deprecated and removed later.
|
|
217
|
+
*/
|
|
218
|
+
abstract class Datatype extends DataType {}
|
|
219
|
+
|
|
220
|
+
class PrimitiveType extends DataType {
|
|
221
|
+
metaType(): string {
|
|
222
|
+
return "PrimitiveType"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
class Enumeration extends DataType {
|
|
227
|
+
metaType(): string {
|
|
228
|
+
return "Enumeration"
|
|
229
|
+
}
|
|
230
|
+
literals: EnumerationLiteral[] = [] // (containment)
|
|
231
|
+
havingLiterals(...literals: EnumerationLiteral[]) {
|
|
232
|
+
this.literals.push(...literals.filter((literal) => this.literals.indexOf(literal) < 0))
|
|
233
|
+
return this
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
class EnumerationLiteral extends M3Node {
|
|
238
|
+
metaType(): string {
|
|
239
|
+
return "EnumerationLiteral"
|
|
240
|
+
}
|
|
241
|
+
constructor(enumeration: Enumeration, name: string, key: LionWebKey, id: LionWebId) {
|
|
242
|
+
super(id, name, key, enumeration)
|
|
243
|
+
}
|
|
244
|
+
get enumeration(): Enumeration {
|
|
245
|
+
return this.parent! as Enumeration
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
class Language extends M3Node {
|
|
250
|
+
metaType(): string {
|
|
251
|
+
return "Language"
|
|
252
|
+
}
|
|
253
|
+
version: string
|
|
254
|
+
entities: LanguageEntity[] = [] // (containment)
|
|
255
|
+
dependsOn: MultiRef<Language> = [] // special (!) reference
|
|
256
|
+
// (!) special because deserializer needs to be aware of where to get the instance from
|
|
257
|
+
constructor(name: string, version: string, id: LionWebId, key: LionWebKey) {
|
|
258
|
+
super(id, name, key)
|
|
259
|
+
this.version = version
|
|
260
|
+
}
|
|
261
|
+
havingEntities(...entities: LanguageEntity[]): Language {
|
|
262
|
+
this.entities.push(...entities.filter((entity) => this.entities.indexOf(entity) < 0))
|
|
263
|
+
return this
|
|
264
|
+
}
|
|
265
|
+
dependingOn(...languages: Language[]): Language {
|
|
266
|
+
this.dependsOn.push(
|
|
267
|
+
...languages
|
|
268
|
+
.filter((language) => language.key !== lioncoreBuiltinsKey)
|
|
269
|
+
)
|
|
270
|
+
return this
|
|
271
|
+
}
|
|
272
|
+
equals(that: Language): boolean {
|
|
273
|
+
return this.key === that.key && this.version === that.version
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Sum type of all LionCore type definitions whose meta-type is a concrete (thus: instantiable) Concept.
|
|
280
|
+
* All the classes in this sum type extend (from) {@link M3Node},
|
|
281
|
+
* so they also implement {@link INamed} and {@link IKeyed}.
|
|
282
|
+
*/
|
|
283
|
+
type M3Concept =
|
|
284
|
+
| Annotation
|
|
285
|
+
| Concept
|
|
286
|
+
| Containment
|
|
287
|
+
| Enumeration
|
|
288
|
+
| EnumerationLiteral
|
|
289
|
+
| Interface
|
|
290
|
+
| Language
|
|
291
|
+
| PrimitiveType
|
|
292
|
+
| Property
|
|
293
|
+
| Reference
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
export {
|
|
297
|
+
Annotation,
|
|
298
|
+
Classifier,
|
|
299
|
+
Concept,
|
|
300
|
+
Containment,
|
|
301
|
+
DataType,
|
|
302
|
+
Datatype,
|
|
303
|
+
Enumeration,
|
|
304
|
+
EnumerationLiteral,
|
|
305
|
+
Feature,
|
|
306
|
+
Interface,
|
|
307
|
+
Language,
|
|
308
|
+
LanguageEntity,
|
|
309
|
+
Link,
|
|
310
|
+
PrimitiveType,
|
|
311
|
+
Property,
|
|
312
|
+
Reference,
|
|
313
|
+
isINamed,
|
|
314
|
+
lioncoreBuiltinsKey,
|
|
315
|
+
simpleNameDeducer
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export type {
|
|
319
|
+
IKeyed,
|
|
320
|
+
IMetaTyped,
|
|
321
|
+
INamed,
|
|
322
|
+
M3Concept,
|
|
323
|
+
M3Node
|
|
324
|
+
}
|
|
325
|
+
|
package/src/reading.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Classifier, Enumeration, EnumerationLiteral, Feature } from "./m3/index.js"
|
|
2
|
+
import { Node } from "./types.js"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Type def. for functions that deduce the {@link Classifier classifier} of a given {@link Node node}.
|
|
7
|
+
*/
|
|
8
|
+
export type ClassifierDeducer<NT extends Node> = (node: NT) => Classifier
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type def. for functions that deduce the string value of the `resolveInfo` field of a
|
|
12
|
+
* {@link LionWebJsonReferenceTarget serialized reference target}, or {@code undefined}
|
|
13
|
+
* to indicate that no `resolveInfo` could be derived.
|
|
14
|
+
*/
|
|
15
|
+
export type ResolveInfoDeducer<NT extends Node> = (node: NT) => string | undefined
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An interface that's used to parametrize generic serialization of
|
|
19
|
+
* (in-memory) nodes of the given type (parameter).
|
|
20
|
+
* Implementations of these interfaces {w|c}ould be:
|
|
21
|
+
* - specific to LionCore (so to match m3/types.ts)
|
|
22
|
+
* - generic to serialize {@link DynamicNode dynamic nodes}
|
|
23
|
+
*/
|
|
24
|
+
export interface Reader<NT extends Node> {
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @return The {@link Concept concept} of the given node
|
|
28
|
+
*/
|
|
29
|
+
classifierOf: ClassifierDeducer<NT>
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @return The value of the given {@link Feature feature} on the given node.
|
|
33
|
+
*/
|
|
34
|
+
getFeatureValue: (node: NT, feature: Feature) => unknown
|
|
35
|
+
// TODO split to getPropertyValue, &c.?
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @return The {@link EnumerationLiteral} corresponding to
|
|
39
|
+
* the given {@link Enumeration} and the runtime encoding of a literal of it,
|
|
40
|
+
*/
|
|
41
|
+
enumerationLiteralFrom: (encoding: unknown, enumeration: Enumeration) => EnumerationLiteral | null
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @return The string value of the `resolveInfo` field of a {@link LionWebJsonReferenceTarget serialized reference target},
|
|
45
|
+
* or {@code undefined} to indicate that no `resolveInfo` could be derived.
|
|
46
|
+
*/
|
|
47
|
+
resolveInfoFor?: ResolveInfoDeducer<NT>
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Alias for {@link Reader}, kept for backward compatibility, and to be deprecated and removed later.
|
|
53
|
+
*/
|
|
54
|
+
export interface ExtractionFacade<NT extends Node> extends Reader<NT> {}
|
|
55
|
+
|