-
At eraser.io, we're trying to adopt Langium for our diagram as code feature. Right now I'm working on our cloud architecture diagrams, and I'm running into an issue: nodes aren't automatically declared when they're being used. A very simple example of our code looks like this:
My current problem is that it's legal to make a new node in the connections, but I can't figure out how to do this. In this example, the ![]() This is my grammar, I have additional code that scopes all the nodes at the top level, since nesting comes automatically but is not desired for this use case.
Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Hey @stutrek, We had to solve a very similar issue in our Langium based implementation of SQL. Generally, Langium uses the For your use case, this requires essentially three parts:
Node:
name=ID ('[' (settings+=Setting)* ']')? ('{' Newline* (children+=Node*)+ '}')? Newline+;
InitialConnection:
(nodes+=[RefItem:ID] ','?) connectionType=ConnectionToken (to+=SecondConnection)+;
SecondConnection:
(nodes+=[RefItem:ID] ','?) (':'message=ID)? connectionType=ConnectionToken?;
type RefItem = Node | InitialConnection | SecondConnection;
export class EraserNameProvider extends DefaultNameProvider {
getName(node: AstNode): string | undefined {
if (isInitialConnection(node) || isSecondConnection(node)) {
return node.nodes.$refText; // Use the reference text as the name of the node
} else {
return super.getName(node);
}
}
getNameNode(node: AstNode): CstNode | undefined {
if (isInitialConnection(node) || isSecondConnection(node)) {
return node.nodes.$refNode;
} else {
return super.getNameNode(node);
}
}
}
export class EraserScopeProvider extends DefaultScopeProvider {
getScope(context: ReferenceInfo): Scope {
if (context.property === 'nodes') { // a reference for the `nodes` property
const superScope = super.getScope(context);
const allElements = superScope.getAllElements();
// Remove all element descriptions for `InitialConnection` and `SecondConnection`
// which already have a matching `Node` element
const filtered = filterWithPrecedence(allElements);
return new StreamScope(filtered);
} else {
return super.getScope(context);
}
}
} Don't forget to bind those services in the |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
Hey @stutrek,
We had to solve a very similar issue in our Langium based implementation of SQL. Generally, Langium uses the
name
property as a convention to make an element available for referencing. However, it doesn't actually have to be thename
property explicitly, you can use any property to make an element visible, even a self reference.For your use case, this requires essentially three parts:
InitialConnection
andSecondConnection
referencable: