-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
mermaidDiagram.js
70 lines (63 loc) · 2.7 KB
/
mermaidDiagram.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/* eslint-disable sonarjs/cognitive-complexity */
/**
* Disabled the rule for this function as there is no way to make it shorter in a meaningfull way
*/
/**
* Generate Mermaid Class Diagram from payload schemas with non-anonymous id's
*
* @param {AsyncAPIDocument} asyncapi parsed AsyncAPI document
*/
export function generateMermaidDiagram(asyncapi) {
if (!asyncapi || typeof asyncapi.version !== 'function') throw new Error('You need to pass entire parsed AsyncAPI document as an argument. Try this "{{ asyncapi | generateMermaidDiagram }}"');
let diagram = '';
//we need to store information about processed schemas, to later make sure we do not duplicate schema classes in the diagram
const seenSchema = [];
const generateDiagram = (schema) => {
const schemaId = schema.uid();
if (isAnonymousSchema(schemaId)) return;
let classContent = '';
let relations = '';
switch (schema.type()) {
//in case of object we need to traverse through all properties to list them in the class box
case 'object': {
for (const [propName, propValueMap] of Object.entries(schema.properties())) {
const circularProp = schema.circularProps() && schema.circularProps().includes(propName);
classContent += circularProp ? `${propName} [CIRCULAR] ${propValueMap.type()}\n` : `${propName} ${propValueMap.type()}\n`;
const propSchemaId = propValueMap.uid();
//if the schema id is not anonymous, this is how we figure out that it for sure has an individually defined model that we can set a relation too
if (!isAnonymousSchema(propSchemaId)) relations += `${schemaId} --|> ${propSchemaId}\n`;
}
break;
}
//in case of array we only want to indicate the type of the array items. So far support for object in items is supported
case 'array': {
classContent = schema.type();
if (Array.isArray(schema.items())) return;
const itemSchemaId = schema.items().uid();
if (!isAnonymousSchema(itemSchemaId)) relations += `${schema.uid()} --|> ${itemSchemaId}\n`;
break;
}
default:
classContent = schema.type();
}
//we add class to the diagram only if it is seen for the first time
if (!seenSchema.includes(schemaId)) {
diagram += `class ${schemaId} {
${classContent}}
${relations}\n`;
}
seenSchema.push(schemaId);
};
asyncapi.traverseSchemas(generateDiagram);
return diagram ? `classDiagram\n${ diagram}` : '';
}
/**
* Check if schema has anonymous id assigned during parsing of the asyncapi document
*
* @private
* @param {Schema} schema schema model
* @param {Function} callback
*/
function isAnonymousSchema(schemaId) {
return schemaId.startsWith('<anonymous-');
}