Skip to content

Commit 6b1668c

Browse files
committed
feat(mps-model-adapters): implement MPSNode::replaceNode
1 parent f4d4b39 commit 6b1668c

File tree

2 files changed

+70
-0
lines changed
  • mps-model-adapters-plugin/src/test/kotlin/org/modelix/model/mpsadapters
  • mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters

2 files changed

+70
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2024.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.mpsadapters
18+
19+
import org.modelix.model.api.BuiltinLanguages
20+
import org.modelix.model.api.ConceptReference
21+
import org.modelix.model.api.INode
22+
23+
class ReplaceNodeTest : MpsAdaptersTestBase("SimpleProject") {
24+
25+
fun testReplaceNode() {
26+
readAction {
27+
assertEquals(1, mpsProject.projectModules.size)
28+
}
29+
30+
val repositoryNode: INode = MPSRepositoryAsNode(mpsProject.repository)
31+
32+
writeActionOnEdt {
33+
val module = repositoryNode.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Repository.modules)
34+
.single { it.getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name) == "Solution1" }
35+
val model = module.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Module.models).single()
36+
val rootNode = model.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Model.rootNodes).single()
37+
38+
val oldProperties = rootNode.getAllProperties().toSet()
39+
val oldReferences = rootNode.getAllReferenceTargetRefs().toSet()
40+
val oldChildren = rootNode.allChildren.toList()
41+
42+
val newConcept = ConceptReference("mps:f3061a53-9226-4cc5-a443-f952ceaf5816/1083245097125")
43+
val newNode = rootNode.replaceNode(newConcept)
44+
45+
assertEquals(oldProperties, newNode.getAllProperties().toSet())
46+
assertEquals(oldReferences, newNode.getAllReferenceTargetRefs().toSet())
47+
assertEquals(oldChildren, newNode.allChildren.toList())
48+
assertEquals(newConcept, newNode.getConceptReference())
49+
}
50+
}
51+
}

mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/MPSNode.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ package org.modelix.model.mpsadapters
1616
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations
1717
import jetbrains.mps.smodel.MPSModuleRepository
1818
import jetbrains.mps.smodel.adapter.MetaAdapterByDeclaration
19+
import jetbrains.mps.smodel.adapter.ids.SConceptId
1920
import jetbrains.mps.smodel.adapter.ids.SContainmentLinkId
2021
import jetbrains.mps.smodel.adapter.ids.SPropertyId
2122
import jetbrains.mps.smodel.adapter.ids.SReferenceLinkId
23+
import jetbrains.mps.smodel.adapter.structure.concept.SConceptAdapterById
2224
import jetbrains.mps.smodel.adapter.structure.link.SContainmentLinkAdapterById
2325
import jetbrains.mps.smodel.adapter.structure.property.SPropertyAdapterById
2426
import jetbrains.mps.smodel.adapter.structure.ref.SReferenceLinkAdapterById
@@ -71,6 +73,23 @@ data class MPSNode(val node: SNode) : IDefaultNodeAdapter {
7173
return node.children.map { MPSNode(it) }
7274
}
7375

76+
override fun replaceNode(concept: ConceptReference): INode {
77+
val id = node.nodeId
78+
val model = checkNotNull(node.model) { "Node is not part of a model" }
79+
val newNode = model.createNode(SConceptAdapterById(SConceptId.deserialize(concept.uid), ""), id)
80+
node.properties.forEach { newNode.setProperty(it, node.getProperty(it)) }
81+
node.references.forEach { newNode.setReference(it.link, it.targetNodeReference) }
82+
node.children.forEach { child ->
83+
val link = checkNotNull(child.containmentLink) { "Containment link of child node not found" }
84+
newNode.addChild(link, child)
85+
}
86+
87+
val parent = checkNotNull(node.parent) { "Cannot replace node without a parent" }
88+
parent.insertChildBefore(getMPSContainmentLink(getContainmentLink()), node, newNode)
89+
node.delete()
90+
return MPSNode(newNode)
91+
}
92+
7493
override fun removeChild(child: INode) {
7594
require(child is MPSNode) { "child must be an MPSNode" }
7695
node.removeChild(child.node)

0 commit comments

Comments
 (0)