-
I'm building a language server for our ERD syntax at Eraser.io. Here's a simple example, with two tables and one connection between them:
The problem I'm having right now is linking the table and field names in the connection. Ideally, in a connection, the field name would be linked to the field name in the declaration, and the table name linked to the table declaration. With my current code, the main connection is not linked at all, and the target is linked only to the field name. grammar:
classes: export class ErdReferences extends DefaultReferences {
findReferences(
targetNode: AstNode,
options: FindReferencesOptions
): Stream<ReferenceDescription> {
// console.log('findReferences', targetNode, options);
const refs: ReferenceDescription[] = [];
if (options.includeDeclaration) {
const ref = this.getReferenceToSelf(targetNode);
if (ref) {
refs.push(ref);
}
}
let indexReferences = this.index.findAllReferences(
targetNode,
this.nodeLocator.getAstNodePath(targetNode)
);
if (options.documentUri) {
indexReferences = indexReferences.filter((ref) =>
UriUtils.equals(ref.sourceUri, options.documentUri)
);
}
const filtered = indexReferences.filter((ref) => ref.segment.offset !== refs[0].segment.offset);
refs.push(...filtered);
return stream(refs);
}
}
export class ErdNameProvider extends DefaultNameProvider {
getName(node: AstNode): string | undefined {
if (isErdConnectionFieldName(node)) {
// console.log(
// 'isErdConnectionFieldName',
// node.$container.table.$refText + '.' + node.field.$refText
// );
return node.$container.table.$refText + '.' + node.field.$refText;
} else if (isErdConnection(node) || isErdConnectionTarget(node)) {
return node.table.$refText; // Use the reference text as the name of the node
} else if (isFieldDefinition(node)) {
// console.log('isFieldDefinition', node.$container.name + '.' + node.name);
return node.$container.name + '.' + node.name;
} else {
return super.getName(node);
}
}
getNameNode(node: AstNode): CstNode | undefined {
if (isErdConnectionFieldName(node)) {
// console.log('isErdConnectionFieldName', node);
return node.field.$refNode;
} else if (isErdConnection(node) || isErdConnectionTarget(node)) {
return node.table.$refNode;
} else {
return super.getNameNode(node);
}
}
}
// the goal of this is to flatten the document so connections can access fields
export class ErdScopeProvider extends DefaultScopeProvider {
getScope(context: ReferenceInfo): Scope {
const scopes: Array<Stream<AstNodeDescription>> = [];
const referenceType = this.reflection.getReferenceType(context);
const precomputed = AstUtils.getDocument(context.container).precomputedScopes;
if (precomputed) {
const nodeDescriptions: AstNodeDescription[] = [];
const found = new Set<string>();
for (const [node, nodeDescription] of precomputed) {
const name = isFieldDefinition(node)
? node.$container.name + '.' + nodeDescription.name
: nodeDescription.name;
if (!found.has(name)) {
nodeDescriptions.push(nodeDescription);
found.add(name);
}
}
scopes.push(stream(nodeDescriptions));
}
let result: Scope = this.getGlobalScope(referenceType, context);
for (let i = scopes.length - 1; i >= 0; i--) {
result = this.createScope(scopes[i], result);
}
return result;
}
} Thanks for your help |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 8 replies
-
Hey @stutrek, your It is enough to return Additionally, you need to adjust the scope provider for the getScope(context: ReferenceInfo): Scope {
if (context.property === 'field') {
const container = context.container.$container as ErdConnectionTarget | ErdConnection;
const table = container.ref.table;
if (table) {
return this.createScopeForNodes(table.fields);
}
return EMPTY_SCOPE;
}
return super.getScope(context);
} |
Beta Was this translation helpful? Give feedback.
See https://github.com/stutrek/eraser-dsl/compare/main...msujew:eraser-dsl:fix?expand=1 for all the necessary changes for this to work :)