Skip to content

Commit

Permalink
refactoring in annotation analyzer; also started to make typed nodes …
Browse files Browse the repository at this point in the history
…independent of how they are created
  • Loading branch information
xndlnk committed Jun 6, 2019
1 parent 5c06aed commit 1168bb5
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 32 deletions.
1 change: 0 additions & 1 deletion sources/acmi-analyzer-custom-example/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"target": "es2018",
"module": "commonjs",
"moduleResolution": "node",
"declaration": true,
"allowJs": true,
"noImplicitAny": false,
// "strict": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe(CabinetTransformer.name, () => {
expect(system.edges[0].source.id).toEqual(serviceA.id)
expect(system.edges[0].target.id).toEqual(serviceB.id)

const cabinetX = system.findNodeWithNameInPayload<System>(System, 'X')
const cabinetX = system.findTypedNodeWithName<System>(System, 'X')
expect(cabinetX.edges).toHaveLength(1)
expect(cabinetX.edges[0].source.id).toEqual(serviceA.id)
expect(cabinetX.edges[0].target.id).toEqual(serviceC.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class CabinetTransformer {
}

private getOrElseCreateCabinetNode(system: System, cabinetName: string): System {
const existingNode = system.findNodeWithNameInPayload<System>(System, cabinetName)
const existingNode = system.findTypedNodeWithName<System>(System, cabinetName)
if (existingNode) return existingNode

const newNode = new System(cabinetName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ describe(AnnotationAnalyzer.name, () => {

const elementMappings: ElementMapping[] = [
{
elementName: 'sendToExchange',
elementToDeriveNodeFrom: 'sendToExchange',
nodeTypeToCreate: 'MessageExchange',
nodeTypeDirection: 'target',
edgeType: 'AsyncEventFlow'
},
{
elementName: 'receiveFromExchange',
elementToDeriveNodeFrom: 'receiveFromExchange',
nodeTypeToCreate: 'MessageExchange',
nodeTypeDirection: 'source',
edgeType: 'AsyncEventFlow'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,16 @@ export class AnnotationAnalyzer {
}
}

/**
* Specifies a mapping of an annotation element to nodes and edges.
*/
export type ElementMapping = {
/**
* name of the annotation element that defines the node name as its value
* name of the annotation element from which a node is derived.
* the value of the annotation element defines the name of the node.
* the node will be created if it does not already exist or else an existing node will be re-used.
*/
elementName: string
elementToDeriveNodeFrom: string

/**
* class name of the node to create for the element
Expand Down Expand Up @@ -90,12 +95,12 @@ function transformEachElement(system: System, service: MicroService, fileContent
logger.log('analyzing annotation body in service ' + service.getName() + ':\n' + annotationBody)

for (const elementMapping of elementMappings) {
const elementPattern = elementMapping.elementName + '\\s*=\\s*([^\\),]+)'
const elementPattern = elementMapping.elementToDeriveNodeFrom + '\\s*=\\s*([^\\),]+)'
const elementRegExp = new RegExp(elementPattern, 'g')
const elementValues = getAllPatternMatches<string>(elementRegExp, annotationBody,
const matchingElementValues = getAllPatternMatches<string>(elementRegExp, annotationBody,
(matchArray: RegExpExecArray) => matchArray[1])

elementValues.forEach(value => transformElementValueExpression(system, service, fileContent,
matchingElementValues.forEach(value => transformElementValueExpression(system, service, fileContent,
elementMapping, value))
}
}
Expand Down Expand Up @@ -130,16 +135,9 @@ function executeMappingForNode(system: System, service: MicroService,
transformer: AnnotationAnalyzer.name,
context: 'service ' + service.id
}
const node = system.addOrExtendTypedNode(elementMapping.nodeTypeToCreate, nodeName, undefined, metadata)

const payload = { name: nodeName }
// TODO: better use system.addOrExtendNamedNode() but without type annotations
// TODO: check for types to be present

// TODO: same node must be created twice
// const node = new ms[elementMapping.nodeTypeToCreate](nodeName, payload, AnnotationAnalyzer.name)
// system.nodes.push(node)
const node = system.addMessageExchange(nodeName, undefined, metadata)
logger.log('added ' + elementMapping.nodeTypeToCreate + ' with name ' + nodeName)
logger.log('ensured node of type ' + elementMapping.nodeTypeToCreate + ' and name ' + nodeName + ' exists.')

if (elementMapping.nodeTypeDirection === 'target') {
const edge = new ms[elementMapping.edgeType](service, node, undefined, metadata)
Expand Down
19 changes: 16 additions & 3 deletions sources/acmi-analyzer/src/model/core-typed.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { System } from './ms'
import { System, NamePayload, MessageExchange } from './ms'
import { TypedNode } from './core-typed'
import { Metadata, Content } from './core'

class TestNode extends TypedNode<{ name: string }> {
class TestNode extends TypedNode<NamePayload> {
constructor(id: string, payload: NamePayload, metadata: Metadata) {
super(id, payload, metadata, TestNode.name)
}
}

describe('core-typed', () => {
Expand All @@ -15,9 +19,18 @@ describe('core-typed', () => {

expect(system.nodes).toHaveLength(1)
expect(node.getPayload().name).toEqual('name')
expect(system.findNodeWithNameInPayload<TestNode>(TestNode, 'name')).toBeDefined()
expect(system.findTypedNodeWithName<TestNode>(TestNode, 'name')).toBeDefined()

expect(node.content.payload.p1).toEqual('1')
expect(node.content.payload.p2).toEqual('2')
})

it.skip('adds nodes with an object of the given type', () => {
const system = new System('test')

const node = system.addOrExtendTypedNode(MessageExchange.name, 'name', undefined)

expect(node.getName()).toEqual('name')
expect((node as TypedNode<NamePayload>).getPayload().name).toEqual('name')
})
})
26 changes: 18 additions & 8 deletions sources/acmi-analyzer/src/model/core-typed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { Logger } from '@nestjs/common'

import { Node, Content, Edge, Metadata } from './core'

// tslint:disable-next-line
import * as ms from './ms'

const logger = new Logger('core-typed')

export class TypedNode<Payload> extends Node {
Expand All @@ -16,19 +19,21 @@ export class TypedNode<Payload> extends Node {
.map(node => node as NodeType)
}

public findNodeWithNameInPayload<NodeType extends Node>(type: Type<NodeType>, name: string): NodeType {
const node = this.nodes
.find(node => node.content.type === type.name && node.content.payload.name === name)
if (node) {
return node as NodeType
}
return undefined
public addOrExtendTypedNode(
type: string, name: string, extraPayload: any = {}, metadata?: Metadata): Node {

const node = this.ensureContainsNodeOfTypeAndName(type, name, extraPayload, metadata)

// TODO: does not work for methods inherited from TypedNode
Object.assign(node, new ms[type](node.id, node.content.payload, metadata))

return node
}

public addOrExtendNamedNode<NodeType extends TypedNode<Payload>>(
type: TypeExtendsTypedNode<NodeType, Payload>, name: string, extraPayload: any = {}, metadata?: Metadata): NodeType {

const existingNode = this.findNodeWithNameInPayload<NodeType>(type, name)
const existingNode = this.findTypedNodeWithName<NodeType>(type, name)
if (existingNode) {
if (extraPayload) {
Object.getOwnPropertyNames(extraPayload)
Expand All @@ -48,6 +53,11 @@ export class TypedNode<Payload> extends Node {
return node
}

public findTypedNodeWithName<NodeType extends TypedNode<Payload>>(
type: Type<NodeType>, name: string): NodeType {
return this.findNodeOfTypeWithName(type.name, name) as NodeType
}

public getEdges<EdgeType extends Edge>(type: Type<EdgeType>): EdgeType[] {
return this.edges
.filter(edge => edge.content.type === type.name)
Expand Down
35 changes: 35 additions & 0 deletions sources/acmi-analyzer/src/model/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,41 @@ export class Node {
this.edges = edges || []
}

ensureContainsNodeOfTypeAndName(typeName: string, nodeName: string, extraPayload: any = {}, metadata?: Metadata): Node {

const existingNode = this.findNodeOfTypeWithName(typeName, nodeName)
if (existingNode) {
if (extraPayload) {
Object.getOwnPropertyNames(extraPayload)
.forEach(payloadPropertyName => existingNode.content.payload[payloadPropertyName] = extraPayload[payloadPropertyName])
}
return existingNode
}

const id = this.id + '__' + typeName + '_' + nodeName
const content = {
type: typeName,
metadata,
payload: {
name: nodeName,
...extraPayload
}
}

const node = new Node(id, content)
this.nodes.push(node)
return node
}

findNodeOfTypeWithName(typeName: string, nodeName: string): Node {
const node = this.nodes
.find(node => node.content.type === typeName && node.content.payload && node.content.payload.name === nodeName)
if (node) {
return node
}
return undefined
}

findContainedNodeByIdRecursive(nodeId: string): Node | undefined {
if (this.id === nodeId) {
return this
Expand Down
4 changes: 2 additions & 2 deletions sources/acmi-analyzer/src/model/ms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class System extends TypedNode<NamePayload> {
}

public findMicroService(name: string): MicroService {
return this.findNodeWithNameInPayload<MicroService>(MicroService, name)
return this.findTypedNodeWithName<MicroService>(MicroService, name)
}

public addMessageExchange(name: string, extraPayload: any = {}, metadata?: Metadata): MessageExchange {
Expand All @@ -34,7 +34,7 @@ export class System extends TypedNode<NamePayload> {
}

public findMessageExchange(name: string): MessageExchange {
return this.findNodeWithNameInPayload<MessageExchange>(MessageExchange, name)
return this.findTypedNodeWithName<MessageExchange>(MessageExchange, name)
}

public getSyncDataFlows(): SyncDataFlow[] {
Expand Down

0 comments on commit 1168bb5

Please sign in to comment.