node-opcua-modeler 2.64.1 → 2.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addExtensionObjectDataType.d.ts +21 -21
- package/dist/addExtensionObjectDataType.js +130 -130
- package/dist/build_model_inner.d.ts +17 -17
- package/dist/build_model_inner.js +40 -40
- package/dist/build_model_inner.js.map +1 -1
- package/dist/displayNodeElement.d.ts +5 -5
- package/dist/displayNodeElement.js +192 -191
- package/dist/displayNodeElement.js.map +1 -1
- package/dist/dump_state_machine_to_graphviz.d.ts +6 -6
- package/dist/dump_state_machine_to_graphviz.js +119 -119
- package/dist/generate_markdown_doc.d.ts +41 -6
- package/dist/generate_markdown_doc.js +314 -266
- package/dist/generate_markdown_doc.js.map +1 -1
- package/dist/index.d.ts +24 -24
- package/dist/index.js +52 -48
- package/dist/index.js.map +1 -1
- package/dist/promoteToMandatory.d.ts +8 -8
- package/dist/promoteToMandatory.js +97 -97
- package/dist/setNamespaceMetaData.d.ts +1 -1
- package/dist/setNamespaceMetaData.js +5 -5
- package/dist/symbol.d.ts +1 -1
- package/dist/symbol.js +2 -2
- package/dist/tableHelper.d.ts +9 -9
- package/dist/tableHelper.js +60 -60
- package/dist/to_cvs.d.ts +2 -2
- package/dist/to_cvs.js +11 -11
- package/dist/to_graphivz.d.ts +14 -14
- package/dist/to_graphivz.js +294 -294
- package/dist/types.d.ts +1 -1
- package/dist/types.js +2 -2
- package/distNodeJS/build_documentation_to_file.d.ts +3 -2
- package/distNodeJS/build_documentation_to_file.js +26 -26
- package/distNodeJS/build_documentation_to_file.js.map +1 -1
- package/distNodeJS/build_model.d.ts +7 -7
- package/distNodeJS/build_model.js +21 -21
- package/distNodeJS/index.d.ts +5 -5
- package/distNodeJS/index.js +23 -19
- package/distNodeJS/index.js.map +1 -1
- package/distNodeJS/symbol_cvs.d.ts +3 -3
- package/distNodeJS/symbol_cvs.js +63 -63
- package/package.json +20 -20
- package/source/build_model_inner.ts +3 -5
- package/source/displayNodeElement.ts +3 -3
- package/source/generate_markdown_doc.ts +88 -33
- package/source/index.ts +2 -1
- package/source_nodejs/build_documentation_to_file.ts +3 -3
- package/MyModel.NodeSet2.xml +0 -125
- package/dist/buildModel.d.ts +0 -16
- package/dist/buildModel.js +0 -91
- package/dist/buildModel.js.map +0 -1
- package/dist/display.d.ts +0 -2
- package/dist/display.js +0 -96
- package/dist/display.js.map +0 -1
- package/source/dump_state_machine_to_graphviz.ts +0 -164
- package/source/to_graphivz.ts +0 -351
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module node-opcua-address-space
|
|
3
|
-
*/
|
|
4
|
-
// tslint:disable:no-console
|
|
5
|
-
/*
|
|
6
|
-
* class Node {
|
|
7
|
-
* { browseName: "string", nodeId: NodeId}
|
|
8
|
-
* }
|
|
9
|
-
* Transition {
|
|
10
|
-
* browseName: "String"
|
|
11
|
-
* fromState: Node
|
|
12
|
-
* toState: Node
|
|
13
|
-
* }
|
|
14
|
-
* class SateMachineType {
|
|
15
|
-
* initialState: Node
|
|
16
|
-
* states: [ Node,Node, ...]
|
|
17
|
-
* transitions: [Transition]
|
|
18
|
-
* }
|
|
19
|
-
* @param stateMachineType
|
|
20
|
-
*/
|
|
21
|
-
import { BaseNode, UAState, UAStateMachineEx, UATransition, UAObject, UATransitionEx } from "node-opcua-address-space";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export function dumpStateMachineToPlantUML(stateMachineType: UAStateMachineEx): string {
|
|
25
|
-
|
|
26
|
-
const lines: string[] = [];
|
|
27
|
-
function w(str: string) {
|
|
28
|
-
lines.push(str);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function s(state: BaseNode) {
|
|
32
|
-
return state? state.nodeId.value.toString() : "";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function n(state: BaseNode) {
|
|
36
|
-
return state ? state.browseName.name!.toString() : "";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
//w("@startuml "); // + stateMachineType.browseName.toString() + ".png");
|
|
40
|
-
// initial state if any
|
|
41
|
-
|
|
42
|
-
if (stateMachineType.initialState) {
|
|
43
|
-
w(" [*] --> " + s(stateMachineType.initialState));
|
|
44
|
-
w(" " + s(stateMachineType.initialState) + ":" + n(stateMachineType.initialState));
|
|
45
|
-
} else {
|
|
46
|
-
w("[*] --> [*]");
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function t(transition: BaseNode) {
|
|
50
|
-
let name = n(transition);
|
|
51
|
-
name = name.replace(":", "");
|
|
52
|
-
name = name.replace("To", "\\nTo\\n");
|
|
53
|
-
name = name.replace("Transition", "\\nTransition");
|
|
54
|
-
return name;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
stateMachineType.states && stateMachineType.states.forEach((state: UAObject) => w(" " + s(state) + ": " + n(state)));
|
|
58
|
-
|
|
59
|
-
stateMachineType.transitions && stateMachineType.transitions.forEach((transition: UATransitionEx) =>
|
|
60
|
-
w(" " + s(transition.fromStateNode!) + " --> " + s(transition.toStateNode!) + " : " + t(transition))
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// w("@enduml");
|
|
64
|
-
return lines.join("\n");
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/*
|
|
69
|
-
@startuml
|
|
70
|
-
|
|
71
|
-
2930: Unshelved
|
|
72
|
-
|
|
73
|
-
2932: TimedShelved
|
|
74
|
-
|
|
75
|
-
2933: OneShotShelved
|
|
76
|
-
|
|
77
|
-
2930 --> 2932 : "2935\nUnshelvedToTimedShelved"
|
|
78
|
-
|
|
79
|
-
2930 --> 2933 : "2936\nUnshelvedToOneShotShelved"
|
|
80
|
-
|
|
81
|
-
2932 --> 2930 : "2940\nTimedShelvedToUnshelved"
|
|
82
|
-
|
|
83
|
-
2932 --> 2933 : "2942\nTimedShelvedToOneShotShelved"
|
|
84
|
-
|
|
85
|
-
2933 --> 2930 : "2943\nOneShotShelvedToUnshelved"
|
|
86
|
-
|
|
87
|
-
2933 --> 2932 : "2945\nOneShotShelvedToTimedShelved"
|
|
88
|
-
|
|
89
|
-
@enduml
|
|
90
|
-
|
|
91
|
-
*/
|
|
92
|
-
|
|
93
|
-
/*
|
|
94
|
-
digraph finite_state_machine {
|
|
95
|
-
rankdir=LR;
|
|
96
|
-
size="8,5"
|
|
97
|
-
node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8;
|
|
98
|
-
node [shape = circle];
|
|
99
|
-
LR_0 -> LR_2 [ label = "SS(B)" ];
|
|
100
|
-
LR_0 -> LR_1 [ label = "SS(S)" ];
|
|
101
|
-
LR_1 -> LR_3 [ label = "S($end)" ];
|
|
102
|
-
LR_2 -> LR_6 [ label = "SS(b)" ];
|
|
103
|
-
LR_2 -> LR_5 [ label = "SS(a)" ];
|
|
104
|
-
LR_2 -> LR_4 [ label = "S(A)" ];
|
|
105
|
-
LR_5 -> LR_7 [ label = "S(b)" ];
|
|
106
|
-
LR_5 -> LR_5 [ label = "S(a)" ];
|
|
107
|
-
LR_6 -> LR_6 [ label = "S(b)" ];
|
|
108
|
-
LR_6 -> LR_5 [ label = "S(a)" ];
|
|
109
|
-
LR_7 -> LR_8 [ label = "S(b)" ];
|
|
110
|
-
LR_7 -> LR_5 [ label = "S(a)" ];
|
|
111
|
-
LR_8 -> LR_6 [ label = "S(b)" ];
|
|
112
|
-
LR_8 -> LR_5 [ label = "S(a)" ];
|
|
113
|
-
}
|
|
114
|
-
*/
|
|
115
|
-
export function dumpStateMachineToGraphViz(
|
|
116
|
-
/*StateMachineProxy*/
|
|
117
|
-
stateMachineType: UAStateMachineEx
|
|
118
|
-
): string {
|
|
119
|
-
const lines: string[] = [];
|
|
120
|
-
function w(str: string) {
|
|
121
|
-
lines.push(str)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function s(state: BaseNode) {
|
|
125
|
-
return state.nodeId.value.toString();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function n(state: BaseNode) {
|
|
129
|
-
return state.browseName.name!.toString();
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function s_full(state: BaseNode) {
|
|
133
|
-
return s(state) + ' [ label = "' + n(state) + '" ]';
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
w("digraph finite_state_machine {");
|
|
137
|
-
// initial state if any
|
|
138
|
-
|
|
139
|
-
if (stateMachineType.initialState) {
|
|
140
|
-
w("node [ shape = doublecircle];");
|
|
141
|
-
w(" _" + s_full(stateMachineType.initialState!) + " ;");
|
|
142
|
-
}
|
|
143
|
-
w("node [ shape = circle];");
|
|
144
|
-
stateMachineType.states.forEach((state: UAState) => w(" _" + s_full(state)));
|
|
145
|
-
|
|
146
|
-
stateMachineType.transitions.forEach((transition) =>
|
|
147
|
-
w(
|
|
148
|
-
" _" +
|
|
149
|
-
s(transition.fromStateNode!) +
|
|
150
|
-
" -> _" +
|
|
151
|
-
s(transition.toStateNode!) +
|
|
152
|
-
" [ " +
|
|
153
|
-
// " labeltooltip = \"" + i(transition) + "\" " +
|
|
154
|
-
', label = "' +
|
|
155
|
-
n(transition) +
|
|
156
|
-
'" ];'
|
|
157
|
-
)
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
w("}");
|
|
161
|
-
|
|
162
|
-
return lines.join("\n");
|
|
163
|
-
|
|
164
|
-
}
|
package/source/to_graphivz.ts
DELETED
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BaseNode,
|
|
3
|
-
UAReference,
|
|
4
|
-
UAObject,
|
|
5
|
-
UAVariable,
|
|
6
|
-
UAReferenceType,
|
|
7
|
-
UADataType,
|
|
8
|
-
UAObjectType,
|
|
9
|
-
UAVariableType,
|
|
10
|
-
UAMethod,
|
|
11
|
-
UAStateMachineEx,
|
|
12
|
-
promoteToStateMachine
|
|
13
|
-
} from "node-opcua-address-space";
|
|
14
|
-
import { UAStateMachineImpl } from "node-opcua-address-space/src/state_machine/finite_state_machine";
|
|
15
|
-
import { ReferenceTypeIds } from "node-opcua-constants";
|
|
16
|
-
import { BrowseDirection, NodeClass } from "node-opcua-data-model";
|
|
17
|
-
import { resolveNodeId } from "node-opcua-nodeid";
|
|
18
|
-
|
|
19
|
-
function e(str: string): string {
|
|
20
|
-
return str.replace(/</g, "<").replace(/>/g, ">");
|
|
21
|
-
}
|
|
22
|
-
function innerText(node: UAObject | UAVariable) {
|
|
23
|
-
const browseName = node.browseName.name;
|
|
24
|
-
const typeDefinition = node.typeDefinitionObj?.browseName?.name;
|
|
25
|
-
|
|
26
|
-
if (typeDefinition) {
|
|
27
|
-
return `[ label =< <FONT point-size="8" ><I>${typeDefinition}</I></FONT><BR/>${e(browseName!)} >]`;
|
|
28
|
-
} else {
|
|
29
|
-
return `[label =< ${e(browseName!)} >]`;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function arrowHeadAttribute(reference: UAReference): string {
|
|
33
|
-
switch (reference.referenceType.value) {
|
|
34
|
-
case ReferenceTypeIds.HasTypeDefinition:
|
|
35
|
-
return "normalnormal";
|
|
36
|
-
case ReferenceTypeIds.HasComponent:
|
|
37
|
-
return "noneteetee";
|
|
38
|
-
case ReferenceTypeIds.HasProperty:
|
|
39
|
-
return "nonetee";
|
|
40
|
-
case ReferenceTypeIds.HasSubtype:
|
|
41
|
-
return "onormalonormal";
|
|
42
|
-
case ReferenceTypeIds.HasModellingRule:
|
|
43
|
-
return "none";
|
|
44
|
-
default:
|
|
45
|
-
return "normal";
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function arrowHead(reference: UAReference): string {
|
|
49
|
-
return `[arrowhead = ${arrowHeadAttribute(reference)}]`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const regularShapes: Record<string, string> = {
|
|
53
|
-
ObjectType: '[shape=rectangle, style="filled" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
54
|
-
VariableType: '[shape=rectangle, style="rounded,filled" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
55
|
-
Object: ' [shape=rectangle, style="filled" fillcolor="#e8edf7"]',
|
|
56
|
-
Variable: '[shape=rectangle, style="filled,rounded" fillcolor="#e8edf7"]',
|
|
57
|
-
Method: '[shape=oval, style="filled" fillcolor="#e8edf7"]'
|
|
58
|
-
};
|
|
59
|
-
const regularShapesOptionals: Record<string, string> = {
|
|
60
|
-
ObjectType: '[shape=rectangle, style="filled,dashed" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
61
|
-
VariableType: '[shape=rectangle, style="rounded,filled,dashed" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
62
|
-
Object: ' [shape=rectangle, style="filled,dashed" fillcolor="#e8edf7"]',
|
|
63
|
-
Variable: '[shape=rectangle, style="filled,rounded,dashed" fillcolor="#e8edf7"]',
|
|
64
|
-
Method: '[shape=oval, style="filled,dashed" fillcolor="#e8edf7"]'
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
interface Options {
|
|
68
|
-
naked: boolean;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
class NodeRegistry {
|
|
72
|
-
m: Record<string, { name: string; node: BaseNode }[]> = {};
|
|
73
|
-
invisibleNodes: string[] = [];
|
|
74
|
-
duplicated: { [key: string]: string } = {};
|
|
75
|
-
add(name: string, node: BaseNode) {
|
|
76
|
-
if (this.duplicated[name]) {
|
|
77
|
-
return; //throw new Error("Already included");
|
|
78
|
-
}
|
|
79
|
-
this.duplicated[name] = name;
|
|
80
|
-
const nodeClass = NodeClass[node.nodeClass];
|
|
81
|
-
this.m[nodeClass] = this.m[nodeClass] || [];
|
|
82
|
-
this.m[nodeClass].push({ name, node });
|
|
83
|
-
}
|
|
84
|
-
addInvisibleNode(name: string) {
|
|
85
|
-
this.invisibleNodes.push(name);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function dumpNodeByNodeClass(str: string[], nodeRegistry: NodeRegistry) {
|
|
89
|
-
for (const [className, listNode] of Object.entries(nodeRegistry.m)) {
|
|
90
|
-
if (listNode.length === 0) {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
str.push(` ## -> ${className}`);
|
|
94
|
-
|
|
95
|
-
const mandatoryNodes = listNode.filter(({ name, node }) => !node.modellingRule || node.modellingRule.match(/Mandatory/));
|
|
96
|
-
const optionalNodes = listNode.filter(({ name, node }) => node.modellingRule && node.modellingRule.match(/Optional/));
|
|
97
|
-
if (mandatoryNodes.length > 0) {
|
|
98
|
-
str.push(` node [];`);
|
|
99
|
-
const decoration = regularShapes[className] as string;
|
|
100
|
-
str.push(` node ${decoration};`);
|
|
101
|
-
for (const { name, node } of mandatoryNodes) {
|
|
102
|
-
str.push(` ${name} ${innerText(node as UAVariable | UAObject)}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (optionalNodes.length > 0) {
|
|
106
|
-
const decoration2 = regularShapesOptionals[className] as string;
|
|
107
|
-
str.push(` node [];`);
|
|
108
|
-
str.push(` node ${decoration2};`);
|
|
109
|
-
for (const { name, node } of listNode) {
|
|
110
|
-
str.push(` ${name} ${innerText(node as UAVariable | UAObject)}`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (nodeRegistry.invisibleNodes.length) {
|
|
115
|
-
str.push(" # invisible nodes");
|
|
116
|
-
str.push(" node []");
|
|
117
|
-
str.push(" node [width=0,height=0,shape=point,style=invis];");
|
|
118
|
-
str.push(` ${nodeRegistry.invisibleNodes.join("\n ")};`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
import { dumpStateMachineToPlantUML } from "./dump_state_machine_to_graphviz";
|
|
123
|
-
|
|
124
|
-
export function opcuaToDot(node: UAObjectType | UAVariableType, options?: Options): string {
|
|
125
|
-
if (node.nodeClass === NodeClass.ObjectType) {
|
|
126
|
-
const finitieStateMachineType = node.addressSpace.findObjectType("FiniteStateMachineType");
|
|
127
|
-
if (finitieStateMachineType) {
|
|
128
|
-
if ((node as UAObjectType).isSupertypeOf(finitieStateMachineType)) {
|
|
129
|
-
const stateMachine = node.instantiate({ browseName: "StateMachine" }) as UAObject;
|
|
130
|
-
promoteToStateMachine(stateMachine);
|
|
131
|
-
return dumpStateMachineToPlantUML(stateMachine as UAStateMachineEx);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
options = options || { naked: false };
|
|
136
|
-
const nodeRegistry = new NodeRegistry();
|
|
137
|
-
|
|
138
|
-
const str: string[] = [];
|
|
139
|
-
const str2: string[] = [];
|
|
140
|
-
str.push("digraph G {");
|
|
141
|
-
if (!options.naked) {
|
|
142
|
-
str.push(" rankdir=TB;");
|
|
143
|
-
str.push(" nodesep=0.5;");
|
|
144
|
-
str.push(" node [];");
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function makeId(p: string, c: string) {
|
|
148
|
-
return `${p}_${c}`.replace(" ", "_").replace(/<|>/g, "_");
|
|
149
|
-
}
|
|
150
|
-
// eslint-disable-next-line max-params
|
|
151
|
-
// eslint-disable-next-line max-statements
|
|
152
|
-
function typeMemberAndSubTypeMember(
|
|
153
|
-
str: string[],
|
|
154
|
-
parentNode: string,
|
|
155
|
-
node: UAObjectType | UAVariableType | UAMethod | UAVariable | UAObject,
|
|
156
|
-
parent: UAObjectType | UAVariableType | UAMethod | UAVariable | UAObject | null,
|
|
157
|
-
offset: number,
|
|
158
|
-
prefix: string,
|
|
159
|
-
joinWithCaller: boolean,
|
|
160
|
-
visitorMap: Record<string, any>
|
|
161
|
-
): [number, string[]] {
|
|
162
|
-
let innerDepth = 0;
|
|
163
|
-
const browseName = (parent || node).browseName.name!.toString();
|
|
164
|
-
const r: string[] = [];
|
|
165
|
-
const r2: string[] = [];
|
|
166
|
-
|
|
167
|
-
const references = (parent || node).findReferencesEx("Aggregates", BrowseDirection.Forward);
|
|
168
|
-
const folderElements = (parent || node).findReferencesEx("Organizes", BrowseDirection.Forward);
|
|
169
|
-
const childReferences = [...references, ...folderElements];
|
|
170
|
-
const id = makeId(parentNode, browseName);
|
|
171
|
-
nodeRegistry.add(id, node);
|
|
172
|
-
|
|
173
|
-
function addInvisibleNode(prefix: string, index: number) {
|
|
174
|
-
const breakNode = `${prefix}${index}`;
|
|
175
|
-
r2.push(breakNode);
|
|
176
|
-
nodeRegistry.addInvisibleNode(breakNode);
|
|
177
|
-
return breakNode;
|
|
178
|
-
}
|
|
179
|
-
for (let i = 0; i < childReferences.length; i++) {
|
|
180
|
-
const isLast = i === childReferences.length - 1;
|
|
181
|
-
const reference = childReferences[i];
|
|
182
|
-
|
|
183
|
-
const childNode = reference.node! as UAVariable | UAObject | UAMethod;
|
|
184
|
-
const childName = childNode.browseName.name!.toString();
|
|
185
|
-
|
|
186
|
-
const fullChildName = makeId(id, childName);
|
|
187
|
-
// avoid member duplication
|
|
188
|
-
if (visitorMap[fullChildName]) {
|
|
189
|
-
continue;
|
|
190
|
-
} else {
|
|
191
|
-
visitorMap[fullChildName] = 1;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
innerDepth++;
|
|
195
|
-
|
|
196
|
-
nodeRegistry.add(fullChildName, childNode);
|
|
197
|
-
const edgeAttributes = arrowHead(reference);
|
|
198
|
-
|
|
199
|
-
const breakNode = addInvisibleNode(prefix, i + offset);
|
|
200
|
-
const horizontalPart = `{ rank=same ${breakNode} -> ${fullChildName} ${edgeAttributes} }`;
|
|
201
|
-
r.push(horizontalPart);
|
|
202
|
-
|
|
203
|
-
// push children on same level
|
|
204
|
-
const [depth] = typeMemberAndSubTypeMember(str, id, childNode, null, 0, `${prefix}${i + offset}_`, false, visitorMap);
|
|
205
|
-
|
|
206
|
-
// add invisible nodes
|
|
207
|
-
{
|
|
208
|
-
for (let d = 0; d < depth; d++) {
|
|
209
|
-
offset++;
|
|
210
|
-
if (!isLast) {
|
|
211
|
-
addInvisibleNode(prefix, i + offset);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
innerDepth += depth;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (node.nodeClass == NodeClass.ObjectType || node.nodeClass === NodeClass.VariableType) {
|
|
219
|
-
if (node.subtypeOfObj && node.subtypeOfObj.nodeId.namespace === node.nodeId.namespace) {
|
|
220
|
-
const [depth, rr2] = typeMemberAndSubTypeMember(
|
|
221
|
-
str,
|
|
222
|
-
parentNode,
|
|
223
|
-
node.subtypeOfObj,
|
|
224
|
-
node,
|
|
225
|
-
r.length + offset + 1,
|
|
226
|
-
prefix,
|
|
227
|
-
true,
|
|
228
|
-
visitorMap
|
|
229
|
-
);
|
|
230
|
-
innerDepth += depth + 1;
|
|
231
|
-
r2.push(...rr2);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (r.length) {
|
|
235
|
-
str.push(...r.map((x) => " " + x));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (!joinWithCaller) {
|
|
239
|
-
if (r2.length) {
|
|
240
|
-
str.push(` ${id} -> ${r2.join(" -> ")} [arrowhead=none];`);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return [innerDepth, r2];
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const visitorMap = {};
|
|
248
|
-
typeMemberAndSubTypeMember(str2, "", node, null, 0, "r", false, visitorMap);
|
|
249
|
-
|
|
250
|
-
if (!options.naked) {
|
|
251
|
-
dumpNodeByNodeClass(str, nodeRegistry);
|
|
252
|
-
}
|
|
253
|
-
str.push(...str2);
|
|
254
|
-
str.push("}");
|
|
255
|
-
|
|
256
|
-
//
|
|
257
|
-
const dot = str.join("\n");
|
|
258
|
-
return dot;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export function dumpClassHierachry(
|
|
262
|
-
typeNode: UAObjectType | UAVariableType | UADataType | UAReferenceType,
|
|
263
|
-
options?: { naked?: boolean; depth?: number; showBaseType?: boolean; showSubType?: boolean }
|
|
264
|
-
) {
|
|
265
|
-
options = options || { naked: false, showBaseType: true, showSubType: true };
|
|
266
|
-
const level = options.depth || 50;
|
|
267
|
-
|
|
268
|
-
const str: string[] = [];
|
|
269
|
-
const nodeRegistry = new NodeRegistry();
|
|
270
|
-
nodeRegistry.add(typeNode.browseName.name!, typeNode);
|
|
271
|
-
str.push("digraph G {");
|
|
272
|
-
if (!options.naked) {
|
|
273
|
-
// str.push(" splines=ortho;");
|
|
274
|
-
str.push(" rankdir=BT;");
|
|
275
|
-
str.push(" nodesep=0.5;");
|
|
276
|
-
str.push(" node [];");
|
|
277
|
-
}
|
|
278
|
-
function dumpSubtypes(str: string[], typeNode: BaseNode, level: number) {
|
|
279
|
-
const parentName = typeNode.browseName.name!.toString();
|
|
280
|
-
const references = typeNode.findReferencesEx("HasSubtype", BrowseDirection.Forward);
|
|
281
|
-
for (let i = 0; i < references.length; i++) {
|
|
282
|
-
const reference = references[i];
|
|
283
|
-
const childNode = reference.node! as UAVariableType | UAObjectType;
|
|
284
|
-
const nodeClass = NodeClass[childNode.nodeClass];
|
|
285
|
-
const childName = childNode.browseName.name!.toString();
|
|
286
|
-
nodeRegistry.add(childName, childNode);
|
|
287
|
-
const edgeAttributes = arrowHead(reference);
|
|
288
|
-
str.push(` ${childName} -> ${parentName} ${edgeAttributes};`);
|
|
289
|
-
|
|
290
|
-
if (level > 0) {
|
|
291
|
-
dumpSubtypes(str, childNode, level - 1);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
function dumpBaseTypes(str: string[], typeNode: BaseNode, level: number) {
|
|
296
|
-
const parentName = typeNode.browseName.name!.toString();
|
|
297
|
-
const references = typeNode.findReferencesEx("HasSubtype", BrowseDirection.Inverse);
|
|
298
|
-
for (let i = 0; i < references.length; i++) {
|
|
299
|
-
const reference = references[i];
|
|
300
|
-
const childNode = reference.node! as UAVariableType | UAObjectType;
|
|
301
|
-
const nodeClass = NodeClass[childNode.nodeClass];
|
|
302
|
-
const childName = childNode.browseName.name!.toString();
|
|
303
|
-
nodeRegistry.add(childName, childNode);
|
|
304
|
-
const edgeAttributes = arrowHead(reference);
|
|
305
|
-
str.push(` ${parentName} -> ${childName} ${edgeAttributes};`);
|
|
306
|
-
if (level > 0) {
|
|
307
|
-
dumpBaseTypes(str, childNode, level - 1);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
const str2: string[] = [];
|
|
312
|
-
if (options.showBaseType) {
|
|
313
|
-
dumpBaseTypes(str2, typeNode, level);
|
|
314
|
-
}
|
|
315
|
-
/** */
|
|
316
|
-
if (options.showSubType) {
|
|
317
|
-
dumpSubtypes(str2, typeNode, level);
|
|
318
|
-
}
|
|
319
|
-
if (!options.naked) {
|
|
320
|
-
dumpNodeByNodeClass(str, nodeRegistry);
|
|
321
|
-
}
|
|
322
|
-
str.push(...str2);
|
|
323
|
-
str.push("}");
|
|
324
|
-
return str.join("\n");
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export function graphVizToPlantUml(str: string): string {
|
|
328
|
-
const ttt = "```";
|
|
329
|
-
return `${ttt}plantuml\n@startuml\n${str}\n@enduml\n${ttt}`;
|
|
330
|
-
}
|
|
331
|
-
export function dumpTypeDiagram(namespace: any) {
|
|
332
|
-
const objectTypes = [...namespace._objectTypeIterator()];
|
|
333
|
-
const variableTypes = [...namespace._variableTypeIterator()];
|
|
334
|
-
const dataTypes = [...namespace._dataTypeIterator()];
|
|
335
|
-
const referenceTypes = [...namespace._referenceTypeIterator()];
|
|
336
|
-
const addressSpace = namespace.addressSpace;
|
|
337
|
-
|
|
338
|
-
const str: string[] = [];
|
|
339
|
-
for (const type of [...objectTypes, ...variableTypes]) {
|
|
340
|
-
const d = opcuaToDot(type);
|
|
341
|
-
str.push(graphVizToPlantUml(d));
|
|
342
|
-
|
|
343
|
-
const d2 = dumpClassHierachry(type);
|
|
344
|
-
str.push(graphVizToPlantUml(d2));
|
|
345
|
-
}
|
|
346
|
-
for (const dataType of dataTypes) {
|
|
347
|
-
const d = opcuaToDot(dataType);
|
|
348
|
-
str.push(graphVizToPlantUml(d));
|
|
349
|
-
}
|
|
350
|
-
return str.join("\n");
|
|
351
|
-
}
|