diff --git a/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSMetaModelExporter.kt b/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSMetaModelExporter.kt index 42db0305dd..8cc1fc886a 100644 --- a/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSMetaModelExporter.kt +++ b/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSMetaModelExporter.kt @@ -20,6 +20,8 @@ import org.jetbrains.mps.openapi.language.SInterfaceConcept import org.jetbrains.mps.openapi.language.SProperty import org.jetbrains.mps.openapi.language.SReferenceLink import org.jetbrains.mps.openapi.model.SNode +import org.modelix.metamodel.export.MPSModelExporter.Companion.exportNode +import org.modelix.model.data.AnnotationData import org.modelix.model.data.ChildLinkData import org.modelix.model.data.ConceptData import org.modelix.model.data.EnumData @@ -113,6 +115,9 @@ class MPSMetaModelExporter(private val outputFolder: File) { } fqName(it) } + val smodelAttributes = SNodeOperations + .getChildren(concept, LINKS.smodelAttribute) + .map(::exportAnnotation) val metaProperties: MutableMap = HashMap() if (SPropertyOperations.getString(concept, PROPS.conceptAlias) != null) { metaProperties[ConceptData.ALIAS_KEY] = @@ -127,6 +132,7 @@ class MPSMetaModelExporter(private val outputFolder: File) { referenceLinks, superConcepts, deprecationMsg(concept), + smodelAttributes, metaProperties, ) } @@ -172,6 +178,18 @@ class MPSMetaModelExporter(private val outputFolder: File) { jsonFile.writeText(languageData.toJson(), StandardCharsets.UTF_8) } + fun exportAnnotation(node: SNode): AnnotationData = + exportNode(node).let { + val annotationConcept = SNodeOperations.getConcept(node) + AnnotationData( + uid = MetaIdByDeclaration.getLinkId(node).toString(), + type = fqName(annotationConcept), + children = it.children, + properties = it.properties, + references = it.references, + ) + } + val output: List get() = producedData.values.toList() @@ -195,6 +213,10 @@ class MPSMetaModelExporter(private val outputFolder: File) { return fqName(target) } + private fun fqName(concept: SConcept?): String { + return concept?.let { concept.language.sourceModule?.moduleName + "." + concept.name } ?: "unknown" + } + private fun fqName(element: SNode?): String { return SNodeOperations.getModel(element).module.moduleName + "." + SPropertyOperations.getString(element, PROPS.name) } @@ -230,6 +252,13 @@ class MPSMetaModelExporter(private val outputFolder: File) { "jetbrains.mps.lang.structure.structure.InterfaceConceptDeclaration", ) + val AttributeInfoConceptDeclaration: SConcept = MetaAdapterFactory.getConcept( + -4094437568663370681, + -8968368868337559369, + 2992811758677295509, + "jetbrains.mps.lang.structure.structure.AttributeInfo", + ) + val INamedConcept: SInterfaceConcept = MetaAdapterFactory.getInterfaceConcept( -0x3154ae6ada15b0deL, -0x646defc46a3573f4L, @@ -295,6 +324,13 @@ class MPSMetaModelExporter(private val outputFolder: File) { 0xeeb344f63fe016cL, "defaultMember", ) + val smodelAttribute: SContainmentLink = MetaAdapterFactory.getContainmentLink( + -0x3154ae6ada15b0deL, + -0x646defc46a3573f4L, + 0x10802efe25aL, + 0x47bf8397520e5942L, + "smodelAttribute", + ) } private object PROPS { @@ -346,5 +382,12 @@ class MPSMetaModelExporter(private val outputFolder: File) { 0x13b8f6fdce540e38L, "memberId", ) + val attributeInfoRole: SProperty = MetaAdapterFactory.getProperty( + -4094437568663370681, + -8968368868337559369, + 2992811758677295509, + 7588428831955550663, + "role", + ) } } diff --git a/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSModelExporter.kt b/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSModelExporter.kt index 5a874624a6..df63ddc7ef 100644 --- a/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSModelExporter.kt +++ b/metamodel-export/src/main/kotlin/org/modelix/metamodel/export/MPSModelExporter.kt @@ -95,21 +95,23 @@ class MPSModelExporter(private val outputFolder: File) { return data } - private fun exportNode(node: SNode): NodeData { - val id: String = node.reference.toString() - val concept: String = "mps:" + MetaIdHelper.getConcept(SNodeOperations.getConcept(node)).serialize() - val role = node.containmentLink?.name ?: "rootNodes" - val children: List = SNodeOperations.getChildren(node).map { exportNode(it) } - val properties: MutableMap = LinkedHashMap() - val references: MutableMap = LinkedHashMap() - properties["#mpsNodeId#"] = node.nodeId.toString() - for (property: SProperty in node.properties) { - properties[property.name] = node.getProperty(property) ?: continue - } - for (reference: SReference in node.references) { - references[reference.link.name] = reference.targetNodeReference.toString() + companion object { + fun exportNode(node: SNode): NodeData { + val id: String = node.reference.toString() + val concept: String = "mps:" + MetaIdHelper.getConcept(SNodeOperations.getConcept(node)).serialize() + val role = node.containmentLink?.name ?: "rootNodes" + val children: List = SNodeOperations.getChildren(node).map { exportNode(it) } + val properties: MutableMap = LinkedHashMap() + val references: MutableMap = LinkedHashMap() + properties["#mpsNodeId#"] = node.nodeId.toString() + for (property: SProperty in node.properties) { + properties[property.name] = node.getProperty(property) ?: continue + } + for (reference: SReference in node.references) { + references[reference.link.name] = reference.targetNodeReference.toString() + } + return NodeData(id, concept, role, children, properties, references) } - return NodeData(id, concept, role, children, properties, references) } private object CONCEPTS { diff --git a/model-api/src/commonMain/kotlin/org/modelix/model/data/MetaModelData.kt b/model-api/src/commonMain/kotlin/org/modelix/model/data/MetaModelData.kt index df4a11a140..4ce3595eef 100644 --- a/model-api/src/commonMain/kotlin/org/modelix/model/data/MetaModelData.kt +++ b/model-api/src/commonMain/kotlin/org/modelix/model/data/MetaModelData.kt @@ -43,6 +43,7 @@ data class ConceptData( val references: List = emptyList(), val extends: List = emptyList(), override val deprecationMessage: String? = null, + val smodelAttributes: List = emptyList(), val metaProperties: MutableMap = mutableMapOf(), ) : IDeprecatable { companion object { @@ -133,3 +134,13 @@ data class ReferenceLinkData( val optional: Boolean = true, override val deprecationMessage: String? = null, ) : IConceptFeatureData, IDeprecatable + +@Serializable +data class AnnotationData( + val uid: String? = null, + val type: String, + val role: String? = null, + val children: List = emptyList(), + val properties: Map = emptyMap(), + val references: Map = emptyMap(), +)