Skip to content

Metamodel plugin ​

Defines the structure of a domain: classes, properties, enums, inheritance and associations. Every other modelling language in the platform is written against a metamodel, which makes this the plugin you enable first.

At a glance ​

Plugin idmetamodel-service
Display nameMetamodel
DescriptionLanguage support for metamodel definitions (.mm files)
Default URL/plugin/metamodel
Sourceapp/packages/service-metamodel, app/packages/language-metamodel, app/packages/editor-metamodel
Depends onNothing

Languages contributed ​

Language idNameExtensionTextual editorGraphical editorGenerated
metamodelMetamodel.mm✅✅❌

The metamodel language ​

A .mm file declares enums, classes and associations at the top level, in any order.

mm
// Enumerations, abstract classes, inheritance, primitive types and multiplicities.

enum Colour {
    RED
    GREEN
    BLUE
}

abstract class Shape {
    name: string
    visible: boolean
    colour: Colour
    tags: string[*]
}

class Rectangle extends Shape {
    width: double
    height: double
}

class Circle extends Shape {
    radius: double
}

class Canvas {
    title: string
    revision: long
}

class Layer {
    index: int
}

class Annotation {
    text: string
}

// A canvas owns at least one layer; both ends are navigable.
Canvas.layers[1..*] *--> Layer.canvas

// A layer owns any number of shapes.
Layer.shapes[*] *--> Shape.layer

// Shapes and annotations reference each other.
Shape.annotations[*] <--> Annotation.shape

Classes and properties ​

mm
abstract class Shape {
    name: string
    tags: string[*]
}

class Circle extends Shape {
    radius: double
}
  • abstract marks a class that cannot be instantiated.
  • extends takes a comma-separated list, so multiple inheritance is allowed.
  • A property is name: type with an optional multiplicity in brackets.

The primitive types are int, long, float, double, string and boolean. A property may also have an enum type.

Multiplicities ​

FormMeaning
(omitted)Exactly one
[*]Any number
[+]At least one
[?]Zero or one
[n]Exactly n
[n..m]Between n and m
[n..*]At least n

Enums ​

mm
enum Colour {
    RED
    GREEN
    BLUE
}

Associations ​

Associations are declared at the top level, not inside a class. An end is a class, optionally followed by a property name and a multiplicity. A class only gets a property for an end that carries a name, and which ends may carry a name is determined by the operator:

OperatorMeaningProperty on the leftProperty on the right
-->Navigable from left to rightrequiredforbidden
<--Navigable from right to leftforbiddenrequired
<-->Navigable in both directionsrequiredrequired
*-->Composition, whole on the left, navigable both waysrequiredrequired
*--Composition, whole on the left, navigable from the partforbiddenrequired
<--*Composition, whole on the right, navigable both waysrequiredrequired
--*Composition, whole on the right, navigable from the partrequiredforbidden

One example of each:

mm
// One example per association operator. A class only gets a property for an end that
// carries a name, and the star always sits on the side that owns (contains) the other one.

class Whole {
    id: string
}

class Part {
    id: string
}

// Plain association, navigable from source to target only.
Whole.partsA[*] --> Part

// Plain association, navigable from target to source only.
Whole <-- Part.wholeB

// Plain association, navigable in both directions.
Whole.partsC[*] <--> Part.wholeC

// Composition with the whole on the left, navigable in both directions.
Whole.partsD[*] *--> Part.wholeD

// Composition with the whole on the left, navigable from the part only.
Whole *-- Part.wholeE

// Composition with the whole on the right, navigable in both directions.
Part.wholeF <--* Whole.partsF[*]

// Composition with the whole on the right, navigable from the part only.
Part.wholeG --* Whole

Composition means containment: an object may have at most one container, so the multiplicity on the end that points at the whole cannot be * or +, and must be optional when several compositions can contain the same class.

Splitting a metamodel across files ​

mm
import "./shapes.mm"

import makes every class and enum of the imported file — and of the files it imports — visible. Association ends may only carry a property name for classes declared in the current file:

mm
// A metamodel can be split across files. `import` pulls in every class and enum of the
// imported file, including the ones it imports itself.
import "./shapes.mm"

class Sticker extends Shape {
    url: string
}

// An association end may only carry a property name for a class declared in this file,
// so the imported `Layer` stays unnamed here.
Sticker.placedOn --> Layer

Graphical editor ​

.mm files open in a class-diagram editor as well as in the text editor. The palette creates classes, enums and associations; the connection type is chosen before drawing an edge, and labels are edited in place. Layout is computed with ELK.

Contribution plugins contributed ​

Target languageWhat it adds
configMetamodel type exports

Metamodel types for the config language ​

The metamodel plugin contributes no syntax to the config language. What it contributes is its AST types — Class, Property, Enum, Association, AssociationEnd, the multiplicity types, PrimitiveType, EnumTypeReference, EnumEntry, ClassExtension, ClassExtensions and FileImport.

Contribution plugins that do add syntax can then declare a dependency on this one and write grammar rules that reference metamodel classes. That is how Config Optimization can resolve refine Canvas.layers[1..4] against your metamodel, and how Config MDEO can resolve create Annotation inside a mutations block.

Contribution plugin idconfig-metamodel
Short namemetamodel
Sectionsnone
Exported types13 metamodel AST interfaces

Server-side capabilities ​

File data keyContents
astThe serialised AST of the metamodel
metamodelMetamodel-specific derived data used by dependent languages

The plugin has no execution handler: metamodels are not run, they are referenced.

Released under the terms of the repository licence.