Skip to content

Commit

Permalink
Support custom properties in textual representation (#62)
Browse files Browse the repository at this point in the history
* Support custom properties in textual representation

- Add optional custom properties to most elements in the grammar

* Update macos-11 for CI run

From GitHub: The macos-11 label has been deprecated and will no longer
be available after 28 June 2024.
  • Loading branch information
martin-fleck-at authored Aug 9, 2024
1 parent 789eb75 commit 353fc84
Show file tree
Hide file tree
Showing 18 changed files with 691 additions and 150 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [windows-2019, ubuntu-latest, macos-11]
os: [windows-2019, ubuntu-latest, macos-12]

runs-on: ${{ matrix.os }}
timeout-minutes: 60
Expand Down
18 changes: 17 additions & 1 deletion examples/mapping-example/ExampleDWH/mappings/DWH.mapping.cm
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ mapping:
- Customer
conditions:
- CalcAgeSourceObject.BirthDate = Customer.BirthDate
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleMappingSource
target:
entity: CompleteCustomer
mappings:
Expand All @@ -52,4 +56,16 @@ mapping:
expression: "1337"
- attribute: FixedString
expression: "Fixed String"
- attribute: Today
- attribute: Today
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleEntityTargetAttribute
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleMappingTarget
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleMapping
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ systemDiagram:
y: 319
width: 159.649658203125
height: 96
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleNode
edges:
- id: CustomerToOrder
relationship: Order_Customer
Expand All @@ -29,4 +33,12 @@ systemDiagram:
- id: AddressToCustomer
relationship: ExampleCRM.Address_Customer
sourceNode: AddressNode
targetNode: CustomerNode
targetNode: CustomerNode
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleEdge
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleDiagram
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ entity:
datatype: "Text"
- id: CountryCode
name: "CountryCode"
datatype: "Text"
datatype: "Text"
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleEntityAttribute
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleEntity
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@ relationship:
type: "1:1"
attributes:
- parent: Customer.Id
child: ExampleCRM.Address.CustomerID
child: ExampleCRM.Address.CustomerID
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleRelationshipAttribute
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleRelationship
57 changes: 38 additions & 19 deletions extensions/crossmodel-lang/src/language-server/cross-model-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@
* Copyright (c) 2023 CrossBreeze.
********************************************************************************/

import { AstNode, AstNodeDescription, DefaultScopeComputation, LangiumDocument, PrecomputedScopes, streamAllContents } from 'langium';
import {
AstNode,
AstNodeDescription,
DefaultScopeComputation,
LangiumDocument,
PrecomputedScopes,
Reference,
streamAllContents
} from 'langium';
import { CancellationToken } from 'vscode-jsonrpc';
import { CrossModelServices } from './cross-model-module.js';
import { DefaultIdProvider, combineIds } from './cross-model-naming.js';
import { CrossModelPackageManager, UNKNOWN_PROJECT_ID, UNKNOWN_PROJECT_REFERENCE } from './cross-model-package-manager.js';
import {
Entity,
EntityNode,
EntityNodeAttribute,
SourceObject,
Expand All @@ -18,7 +27,7 @@ import {
isSourceObject,
isTargetObject
} from './generated/ast.js';
import { findDocument, setAttributes, setImplicitId, setOwner } from './util/ast-util.js';
import { fixDocument, setAttributes, setImplicitId, setOwner } from './util/ast-util.js';

/**
* Custom node description that wraps a given description under a potentially new name and also stores the package id for faster access.
Expand Down Expand Up @@ -123,43 +132,53 @@ export class CrossModelScopeComputation extends DefaultScopeComputation {
this.processSourceObject(node, id, document).forEach(description => scopes.add(container, description));
}
}
if (isTargetObject(node) && node.entity?.ref?.id) {
this.processTargetObject(node, node.entity?.ref.id, document).forEach(description => scopes.add(container, description));
if (isTargetObject(node)) {
const entity = this.getEntity(node, document);
if (entity?.id) {
this.processTargetObject(node, entity.id, document).forEach(description => scopes.add(container, description));
}
}
}
}

protected processEntityNode(node: EntityNode, nodeId: string, document: LangiumDocument): AstNodeDescription[] {
try {
// TODO: Check if this is still necessary
if (node.entity?.ref) {
findDocument(node.entity.ref);
}
} catch (error) {
console.error(error);
const entity = this.getEntity(node, document);
if (!entity) {
return [];
}
const attributes =
node.entity?.ref?.attributes.map<EntityNodeAttribute>(attribute => setOwner({ ...attribute, $type: EntityNodeAttribute }, node)) ??
[];
entity.attributes.map<EntityNodeAttribute>(attribute => setOwner({ ...attribute, $type: EntityNodeAttribute }, node)) ?? [];
setAttributes(node, attributes);
return attributes.map(attribute => this.descriptions.createDescription(attribute, combineIds(nodeId, attribute.id), document));
}

protected getEntity(node: AstNode & { entity: Reference<Entity> }, document: LangiumDocument): Entity | undefined {
try {
return fixDocument(node, document).entity?.ref;
} catch (error) {
console.error(error);
return undefined;
}
}

protected processSourceObject(node: SourceObject, nodeId: string, document: LangiumDocument): AstNodeDescription[] {
const entity = this.getEntity(node, document);
if (!entity) {
return [];
}
const attributes =
node.entity?.ref?.attributes.map<SourceObjectAttribute>(attribute =>
setOwner({ ...attribute, $type: SourceObjectAttribute }, node)
) ?? [];
entity.attributes.map<SourceObjectAttribute>(attribute => setOwner({ ...attribute, $type: SourceObjectAttribute }, node)) ?? [];
setAttributes(node, attributes);
return attributes.map(attribute => this.descriptions.createDescription(attribute, combineIds(nodeId, attribute.id), document));
}

protected processTargetObject(node: TargetObject, nodeId: string, document: LangiumDocument): AstNodeDescription[] {
const entity = this.getEntity(node, document);
if (!entity) {
return [];
}
const attributes =
node.entity?.ref?.attributes.map<TargetObjectAttribute>(attribute =>
setOwner({ ...attribute, $type: TargetObjectAttribute }, node)
) ?? [];
entity.attributes.map<TargetObjectAttribute>(attribute => setOwner({ ...attribute, $type: TargetObjectAttribute }, node)) ?? [];
setImplicitId(node, nodeId);
setAttributes(node, attributes);
// for target attributes, we use simple names and not object-qualified ones
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ const PROPERTY_ORDER = [
'mappings',
'source',
'conditions',
'expression'
'expression',
'customProperties'
];

const ID_OR_IDREF = [
Expand Down
6 changes: 4 additions & 2 deletions extensions/crossmodel-lang/src/language-server/entity.langium
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Entity:
('-' attributes+=EntityAttribute)+
DEDENT
)?
CustomProperties?
DEDENT
;

Expand All @@ -22,7 +23,7 @@ interface Attribute {
description?: string;
}

interface EntityAttribute extends Attribute {
interface EntityAttribute extends Attribute, WithCustomProperties {
identifier?: boolean;
}

Expand All @@ -31,4 +32,5 @@ EntityAttribute returns EntityAttribute:
'name' ':' name=STRING
'datatype' ':' datatype=STRING
(identifier?='identifier' ':' ('TRUE' | 'true'))?
('description' ':' description=STRING)?;
('description' ':' description=STRING)?
CustomProperties?;
Loading

0 comments on commit 353fc84

Please sign in to comment.