Skip to content

Commit f2c8000

Browse files
committed
feat(model-api): INode now has an ID based API and the name based is deprecated
1 parent f4dc31d commit f2c8000

File tree

10 files changed

+181
-23
lines changed

10 files changed

+181
-23
lines changed

commitlint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ module.exports = {
1818
"ts-model-api",
1919
],
2020
],
21+
"subject-case": [0, 'never']
2122
},
2223
};

model-api/src/commonMain/kotlin/org/modelix/model/api/IChildLink.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,39 @@ interface IChildLink : ILink {
2626

2727
@Deprecated("use .targetConcept")
2828
val childConcept: IConcept
29+
30+
companion object {
31+
fun fromName(name: String): IChildLink = ChildLinkFromName(name)
32+
}
33+
}
34+
35+
data class ChildLinkFromName(override val name: String) : LinkFromName(), IChildLink {
36+
override val isMultiple: Boolean
37+
get() = throw UnsupportedOperationException()
38+
override val childConcept: IConcept
39+
get() = throw UnsupportedOperationException()
40+
}
41+
42+
object NullChildLink : IChildLink {
43+
override val isMultiple: Boolean
44+
get() = true
45+
override val childConcept: IConcept
46+
get() = throw UnsupportedOperationException()
47+
override val targetConcept: IConcept
48+
get() = throw UnsupportedOperationException()
49+
50+
override fun getConcept(): IConcept {
51+
throw UnsupportedOperationException()
52+
}
53+
54+
override fun getUID(): String {
55+
throw UnsupportedOperationException()
56+
}
57+
58+
override fun getSimpleName(): String {
59+
throw UnsupportedOperationException()
60+
}
61+
62+
override val isOptional: Boolean
63+
get() = true
2964
}

model-api/src/commonMain/kotlin/org/modelix/model/api/ILink.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ interface ILink : IRole {
1111
*/
1212
val targetConcept: IConcept
1313
}
14+
15+
abstract class LinkFromName : RoleFromName(), ILink {
16+
override val targetConcept: IConcept
17+
get() = throw UnsupportedOperationException()
18+
}

model-api/src/commonMain/kotlin/org/modelix/model/api/INode.kt

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ interface INode {
4141
/**
4242
* Role of this node in its parent node if it exists,or null otherwise.
4343
*/
44+
@Deprecated("use getContainmentLink()")
4445
val roleInParent: String?
4546

4647
/**
@@ -61,6 +62,7 @@ interface INode {
6162
* @param role the desired role
6263
* @return iterable over the child nodes
6364
*/
65+
@Deprecated("use IChildLink instead of String")
6466
fun getChildren(role: String?): Iterable<INode>
6567

6668
/**
@@ -76,6 +78,7 @@ interface INode {
7678
* @param index target index within the role
7779
* @param child child node to be moved
7880
*/
81+
@Deprecated("use IChildLink instead of String")
7982
fun moveChild(role: String?, index: Int, child: INode)
8083

8184
/**
@@ -90,6 +93,7 @@ interface INode {
9093
*
9194
* @see addNewChild
9295
*/
96+
@Deprecated("use IChildLink instead of String")
9397
fun addNewChild(role: String?, index: Int, concept: IConcept?): INode
9498

9599
/**
@@ -102,6 +106,7 @@ interface INode {
102106
* @param concept reference to a concept, of which the new node is instance of
103107
* @return new child node
104108
*/
109+
@Deprecated("use IChildLink instead of String")
105110
fun addNewChild(role: String?, index: Int, concept: IConceptReference?): INode {
106111
return addNewChild(role, index, concept?.resolve())
107112
}
@@ -119,6 +124,7 @@ interface INode {
119124
* @param role the desired reference role
120125
* @return target node, or null if the target could not be found
121126
*/
127+
@Deprecated("use IReferenceLink instead of String")
122128
fun getReferenceTarget(role: String): INode?
123129

124130
/**
@@ -127,6 +133,7 @@ interface INode {
127133
* @param role the desired reference role
128134
* @return node reference to the target, or null if the target could not be found
129135
*/
136+
@Deprecated("use IReferenceLink instead of String")
130137
fun getReferenceTargetRef(role: String): INodeReference? {
131138
return getReferenceTarget(role)?.reference
132139
}
@@ -137,6 +144,7 @@ interface INode {
137144
* @param role the desired reference role
138145
* @param target new target for this node's reference
139146
*/
147+
@Deprecated("use IReferenceLink instead of String")
140148
fun setReferenceTarget(role: String, target: INode?)
141149

142150
/**
@@ -146,9 +154,10 @@ interface INode {
146154
* @param role the desired reference role
147155
* @param target reference to the new target for this node's reference
148156
*/
157+
@Deprecated("use IReferenceLink instead of String")
149158
fun setReferenceTarget(role: String, target: INodeReference?) {
150159
// Default implementation for backward compatibility only.
151-
setReferenceTarget(role, target?.resolveNode(getArea()))
160+
setReferenceTarget(role, target?.resolveIn(getArea()!!))
152161
}
153162

154163
/**
@@ -157,6 +166,7 @@ interface INode {
157166
* @param role the desired property role
158167
* @return property value, or null if there is no value
159168
*/
169+
@Deprecated("use getPropertyValue(IProperty)")
160170
fun getPropertyValue(role: String): String?
161171

162172
/**
@@ -165,25 +175,27 @@ interface INode {
165175
* @param role the desired property role
166176
* @param value the new property value
167177
*/
178+
@Deprecated("use setPropertyValue(IProperty, String?)")
168179
fun setPropertyValue(role: String, value: String?)
169180

170181
/**
171182
* Returns all property roles of this node.
172183
*
173184
* @return list of all property roles
174185
*/
186+
@Deprecated("use getPropertyLinks()")
175187
fun getPropertyRoles(): List<String>
176188

177189
/**
178190
* Returns all reference roles of this node.
179191
*
180192
* @return list of all reference roles
181193
*/
194+
@Deprecated("use getReferenceLinks()")
182195
fun getReferenceRoles(): List<String>
183-
}
184196

185-
interface INodeEx : INode {
186-
fun usesRoleIds(): Boolean
197+
// <editor-fold desc="non-string based API">
198+
fun usesRoleIds(): Boolean = false
187199
fun getContainmentLink(): IChildLink? = roleInParent?.let { role ->
188200
parent?.concept?.getAllChildLinks()?.find { (if (usesRoleIds()) it.getUID() else it.getSimpleName()) == role }
189201
}
@@ -193,10 +205,54 @@ interface INodeEx : INode {
193205
fun addNewChild(role: IChildLink, index: Int, concept: IConceptReference?): INode = addNewChild(role.key(this), index, concept)
194206
fun getReferenceTarget(link: IReferenceLink): INode? = getReferenceTarget(link.key(this))
195207
fun setReferenceTarget(link: IReferenceLink, target: INode?) = setReferenceTarget(link.key(this), target)
196-
fun getReferenceTargetRef(role: IReferenceLink): INodeReference? = getReferenceTargetRef(role.key(this))
197208
fun setReferenceTarget(role: IReferenceLink, target: INodeReference?) = setReferenceTarget(role.key(this), target)
209+
fun removeReference(role: IReferenceLink) = setReferenceTarget(role, null as INodeReference?)
210+
fun getReferenceTargetRef(role: IReferenceLink): INodeReference? = getReferenceTargetRef(role.key(this))
198211
fun getPropertyValue(property: IProperty): String? = getPropertyValue(property.key(this))
199212
fun setPropertyValue(property: IProperty, value: String?) = setPropertyValue(property.key(this), value)
213+
214+
fun getReferenceLinks(): List<IReferenceLink> = getReferenceRoles().map { tryResolveReferenceLink(it) ?: ReferenceLinkFromName(it) }
215+
fun getPropertyLinks(): List<IProperty> = getPropertyRoles().map { tryResolveProperty(it) ?: PropertyFromName(it) }
216+
fun getAllProperties(): List<Pair<IProperty, String>> = getPropertyLinks().map { it to getPropertyValue(it) }.filterSecondNotNull()
217+
fun getAllReferenceTargets(): List<Pair<IReferenceLink, INode>> = getReferenceLinks().map { it to getReferenceTarget(it) }.filterSecondNotNull()
218+
fun getAllReferenceTargetRefs(): List<Pair<IReferenceLink, INodeReference>> = getReferenceLinks().map { it to getReferenceTargetRef(it) }.filterSecondNotNull()
219+
// </editor-fold>
220+
}
221+
222+
fun <T1, T2> List<Pair<T1, T2?>>.filterSecondNotNull(): List<Pair<T1, T2>> = filter { it.second != null } as List<Pair<T1, T2>>
223+
224+
@Deprecated("all members moved to INode", ReplaceWith("INode"))
225+
interface INodeEx : INode
226+
227+
interface IDeprecatedNodeDefaults : INode {
228+
override val roleInParent: String? get() = getContainmentLink()?.getUID()
229+
override fun getChildren(role: String?): Iterable<INode> = getChildren(resolveChildLinkOrFallback(role))
230+
override fun moveChild(role: String?, index: Int, child: INode) = moveChild(resolveChildLinkOrFallback(role), index, child)
231+
override fun addNewChild(role: String?, index: Int, concept: IConcept?): INode = addNewChild(resolveChildLinkOrFallback(role), index, concept)
232+
override fun addNewChild(role: String?, index: Int, concept: IConceptReference?): INode = addNewChild(resolveChildLinkOrFallback(role), index, concept)
233+
override fun getReferenceTarget(role: String): INode? = getReferenceTarget(resolveReferenceLinkOrFallback(role))
234+
override fun getReferenceTargetRef(role: String): INodeReference? = getReferenceTargetRef(resolveReferenceLinkOrFallback(role))
235+
override fun setReferenceTarget(role: String, target: INode?) = setReferenceTarget(resolveReferenceLinkOrFallback(role), target)
236+
override fun setReferenceTarget(role: String, target: INodeReference?) = setReferenceTarget(resolveReferenceLinkOrFallback(role), target)
237+
override fun getPropertyValue(role: String): String? = getPropertyValue(resolvePropertyOrFallback(role))
238+
override fun setPropertyValue(role: String, value: String?) = setPropertyValue(resolvePropertyOrFallback(role), value)
239+
override fun getPropertyRoles(): List<String> = getPropertyLinks().map { it.key(this) }
240+
override fun getReferenceRoles(): List<String> = getReferenceLinks().map { it.key(this) }
241+
242+
override fun usesRoleIds(): Boolean = true
243+
override fun getContainmentLink(): IChildLink?
244+
override fun getChildren(link: IChildLink): Iterable<INode>
245+
override fun moveChild(role: IChildLink, index: Int, child: INode)
246+
override fun addNewChild(role: IChildLink, index: Int, concept: IConcept?): INode
247+
override fun addNewChild(role: IChildLink, index: Int, concept: IConceptReference?): INode
248+
override fun getReferenceTarget(link: IReferenceLink): INode?
249+
override fun setReferenceTarget(link: IReferenceLink, target: INode?)
250+
override fun setReferenceTarget(role: IReferenceLink, target: INodeReference?)
251+
override fun getReferenceTargetRef(role: IReferenceLink): INodeReference?
252+
override fun getPropertyValue(property: IProperty): String?
253+
override fun setPropertyValue(property: IProperty, value: String?)
254+
override fun getPropertyLinks(): List<IProperty>
255+
override fun getReferenceLinks(): List<IReferenceLink>
200256
}
201257

202258
@Deprecated("Use .key(INode), .key(IBranch), .key(ITransaction) or .key(ITree)")
@@ -214,7 +270,7 @@ fun INode.getPropertyValue(property: IProperty): String? = if (this is INodeEx)
214270
fun INode.setPropertyValue(property: IProperty, value: String?): Unit = if (this is INodeEx) setPropertyValue(property, value) else setPropertyValue(property.key(this), value)
215271

216272
fun INode.getConcept(): IConcept? = getConceptReference()?.resolve()
217-
fun INode.getResolvedReferenceTarget(role: String): INode? = getReferenceTargetRef(role)?.resolveNode(getArea())
273+
fun INode.getResolvedReferenceTarget(role: String): INode? = getReferenceTargetRef(role)?.resolveIn(getArea()!!)
218274
fun INode.getResolvedConcept(): IConcept? = getConceptReference()?.resolve()
219275

220276
fun INode.addNewChild(role: String?, index: Int): INode = addNewChild(role, index, null as IConceptReference?)
@@ -238,6 +294,38 @@ fun INode.resolveProperty(role: String): IProperty {
238294
?: throw RuntimeException("Property '$role' not found in concept ${c.getLongName()}")
239295
}
240296

297+
fun INode.tryResolveChildLink(role: String): IChildLink? {
298+
val c = this.concept ?: return null
299+
val allLinks = c.getAllChildLinks()
300+
return allLinks.find { it.key(this) == role }
301+
?: allLinks.find { it.getSimpleName() == role }
302+
?: allLinks.find { it.getUID() == role }
303+
}
304+
fun INode.resolveChildLinkOrFallback(role: String?): IChildLink {
305+
if (role == null) return NullChildLink
306+
return tryResolveChildLink(role) ?: IChildLink.fromName(role)
307+
}
308+
fun INode.tryResolveReferenceLink(role: String): IReferenceLink? {
309+
val c = this.concept ?: return null
310+
val allLinks = c.getAllReferenceLinks()
311+
return allLinks.find { it.key(this) == role }
312+
?: allLinks.find { it.getSimpleName() == role }
313+
?: allLinks.find { it.getUID() == role }
314+
}
315+
fun INode.resolveReferenceLinkOrFallback(role: String): IReferenceLink {
316+
return tryResolveReferenceLink(role) ?: IReferenceLink.fromName(role)
317+
}
318+
fun INode.tryResolveProperty(role: String): IProperty? {
319+
val c = this.concept ?: return null
320+
val allLinks = c.getAllProperties()
321+
return allLinks.find { it.key(this) == role }
322+
?: allLinks.find { it.getSimpleName() == role }
323+
?: allLinks.find { it.getUID() == role }
324+
}
325+
fun INode.resolvePropertyOrFallback(role: String): IProperty {
326+
return tryResolveProperty(role) ?: IProperty.fromName(role)
327+
}
328+
241329
fun INode.remove() {
242330
parent?.removeChild(this)
243331
}

model-api/src/commonMain/kotlin/org/modelix/model/api/IProperty.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,13 @@ package org.modelix.model.api
1818
/**
1919
* Representation of a property within an [IConcept].
2020
*/
21-
interface IProperty : IRole
21+
interface IProperty : IRole {
22+
companion object {
23+
fun fromName(name: String): IProperty = PropertyFromName(name)
24+
}
25+
}
26+
27+
data class PropertyFromName(override val name: String) : RoleFromName(), IProperty {
28+
override val isOptional: Boolean
29+
get() = throw UnsupportedOperationException()
30+
}

model-api/src/commonMain/kotlin/org/modelix/model/api/IReferenceLink.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,10 @@ package org.modelix.model.api
1818
/**
1919
* Representation of a non-containment reference link between [IConcept]s.
2020
*/
21-
interface IReferenceLink : ILink
21+
interface IReferenceLink : ILink {
22+
companion object {
23+
fun fromName(name: String): IReferenceLink = ReferenceLinkFromName(name)
24+
}
25+
}
26+
27+
data class ReferenceLinkFromName(override val name: String) : LinkFromName(), IReferenceLink

model-api/src/commonMain/kotlin/org/modelix/model/api/IRole.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,20 @@ object RoleAccessContext {
6161
return value.getValue() ?: false
6262
}
6363
}
64+
65+
abstract class RoleFromName() : IRole {
66+
override fun getConcept(): IConcept {
67+
throw UnsupportedOperationException()
68+
}
69+
70+
override fun getUID(): String {
71+
return name
72+
}
73+
74+
override fun getSimpleName(): String {
75+
return name
76+
}
77+
78+
override val isOptional: Boolean
79+
get() = throw UnsupportedOperationException()
80+
}

model-api/src/commonMain/kotlin/org/modelix/model/api/SimpleChildLink.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ class SimpleChildLink(
1717
private val simpleName: String,
1818
override val isMultiple: Boolean,
1919
override val isOptional: Boolean,
20-
override val targetConcept: IConcept
20+
override val targetConcept: IConcept,
21+
private val uid: String? = null
2122
) : IChildLink {
2223
var owner: SimpleConcept? = null
2324
override val childConcept: IConcept = targetConcept
2425

2526
override fun getConcept(): IConcept = owner!!
2627

2728
override fun getUID(): String {
28-
val o = owner
29-
return (if (o == null) simpleName else o.getUID() + "." + simpleName)
29+
return uid
30+
?: owner?.let { it.getUID() + "." + simpleName }
31+
?: simpleName
3032
}
3133

3234
override fun getSimpleName(): String = simpleName

model-api/src/commonMain/kotlin/org/modelix/model/api/SimpleConcept.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,21 @@
1313
*/
1414
package org.modelix.model.api
1515

16-
class SimpleConcept(
16+
open class SimpleConcept(
1717
private val conceptName: String,
18-
private val is_abstract: Boolean,
19-
directSuperConcepts: Iterable<IConcept>
18+
private val is_abstract: Boolean = false,
19+
directSuperConcepts: Iterable<IConcept> = emptyList(),
20+
private val uid: String? = null
2021
) : IConcept {
2122
override var language: ILanguage? = null
2223
val properties: MutableList<SimpleProperty> = ArrayList()
2324
val childLinks: MutableList<IChildLink> = ArrayList()
2425
val referenceLinks: MutableList<IReferenceLink> = ArrayList()
2526
private val superConcepts: List<IConcept> = directSuperConcepts.toList()
2627

27-
constructor(name: String) : this(name, false, listOf())
28-
29-
constructor(name: String, isAbstract: Boolean) : this(name, isAbstract, listOf())
30-
31-
constructor(name: String, directSuperConcepts: Iterable<IConcept>) : this(name, false, directSuperConcepts)
32-
3328
override fun isAbstract(): Boolean = this.is_abstract
3429

35-
override fun getUID(): String = getLongName()
30+
override fun getUID(): String = uid ?: getLongName()
3631

3732
override fun getReference(): IConceptReference {
3833
return ConceptReference(getUID())

model-api/src/commonMain/kotlin/org/modelix/model/api/SimpleLanguage.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
package org.modelix.model.api
1515

16-
class SimpleLanguage(private val name: String) : ILanguage {
16+
open class SimpleLanguage(private val name: String, private val uid: String? = null) : ILanguage {
1717
private var registered: Boolean = false
1818
fun register() {
1919
if (registered) return
@@ -27,7 +27,7 @@ class SimpleLanguage(private val name: String) : ILanguage {
2727
registered = false
2828
}
2929

30-
override fun getUID(): String = name
30+
override fun getUID(): String = uid ?: name
3131

3232
private val concepts: MutableList<SimpleConcept> = ArrayList()
3333

0 commit comments

Comments
 (0)