node-opcua-modeler 2.63.1 → 2.64.1
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/MyModel.NodeSet2.xml +125 -0
- package/dist/addExtensionObjectDataType.d.ts +21 -21
- package/dist/addExtensionObjectDataType.js +130 -130
- package/dist/buildModel.d.ts +16 -0
- package/dist/buildModel.js +91 -0
- package/dist/buildModel.js.map +1 -0
- package/dist/build_model_inner.d.ts +17 -17
- package/dist/build_model_inner.js +40 -40
- package/dist/display.d.ts +2 -0
- package/dist/display.js +96 -0
- package/dist/display.js.map +1 -0
- package/dist/displayNodeElement.d.ts +5 -5
- package/dist/displayNodeElement.js +191 -156
- package/dist/displayNodeElement.js.map +1 -1
- package/dist/dump_state_machine_to_graphviz.d.ts +6 -0
- package/dist/dump_state_machine_to_graphviz.js +120 -0
- package/dist/dump_state_machine_to_graphviz.js.map +1 -0
- package/dist/generate_markdown_doc.d.ts +6 -6
- package/dist/generate_markdown_doc.js +266 -155
- package/dist/generate_markdown_doc.js.map +1 -1
- package/dist/index.d.ts +24 -24
- package/dist/index.js +48 -48
- 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 -13
- package/dist/to_graphivz.js +294 -235
- package/dist/to_graphivz.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +2 -2
- package/distNodeJS/build_documentation_to_file.d.ts +2 -2
- package/distNodeJS/build_documentation_to_file.js +26 -26
- 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 +19 -19
- package/distNodeJS/symbol_cvs.d.ts +3 -3
- package/distNodeJS/symbol_cvs.js +63 -63
- package/examples/make_model.ts +4 -3
- package/package.json +19 -19
- package/source/displayNodeElement.ts +165 -112
- package/source/dump_state_machine_to_graphviz.ts +164 -0
- package/source/generate_markdown_doc.ts +217 -82
- package/source/to_graphivz.ts +129 -48
package/source/to_graphivz.ts
CHANGED
|
@@ -7,19 +7,26 @@ import {
|
|
|
7
7
|
UADataType,
|
|
8
8
|
UAObjectType,
|
|
9
9
|
UAVariableType,
|
|
10
|
-
UAMethod
|
|
10
|
+
UAMethod,
|
|
11
|
+
UAStateMachineEx,
|
|
12
|
+
promoteToStateMachine
|
|
11
13
|
} from "node-opcua-address-space";
|
|
14
|
+
import { UAStateMachineImpl } from "node-opcua-address-space/src/state_machine/finite_state_machine";
|
|
12
15
|
import { ReferenceTypeIds } from "node-opcua-constants";
|
|
13
16
|
import { BrowseDirection, NodeClass } from "node-opcua-data-model";
|
|
17
|
+
import { resolveNodeId } from "node-opcua-nodeid";
|
|
14
18
|
|
|
19
|
+
function e(str: string): string {
|
|
20
|
+
return str.replace(/</g, "<").replace(/>/g, ">");
|
|
21
|
+
}
|
|
15
22
|
function innerText(node: UAObject | UAVariable) {
|
|
16
23
|
const browseName = node.browseName.name;
|
|
17
24
|
const typeDefinition = node.typeDefinitionObj?.browseName?.name;
|
|
18
25
|
|
|
19
26
|
if (typeDefinition) {
|
|
20
|
-
return `[ label =< <FONT point-size="8" ><I>${typeDefinition}</I></FONT><BR/>${browseName} >]`;
|
|
27
|
+
return `[ label =< <FONT point-size="8" ><I>${typeDefinition}</I></FONT><BR/>${e(browseName!)} >]`;
|
|
21
28
|
} else {
|
|
22
|
-
return `[label =< ${browseName} >]`;
|
|
29
|
+
return `[label =< ${e(browseName!)} >]`;
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
32
|
function arrowHeadAttribute(reference: UAReference): string {
|
|
@@ -27,7 +34,7 @@ function arrowHeadAttribute(reference: UAReference): string {
|
|
|
27
34
|
case ReferenceTypeIds.HasTypeDefinition:
|
|
28
35
|
return "normalnormal";
|
|
29
36
|
case ReferenceTypeIds.HasComponent:
|
|
30
|
-
return "
|
|
37
|
+
return "noneteetee";
|
|
31
38
|
case ReferenceTypeIds.HasProperty:
|
|
32
39
|
return "nonetee";
|
|
33
40
|
case ReferenceTypeIds.HasSubtype:
|
|
@@ -45,16 +52,16 @@ function arrowHead(reference: UAReference): string {
|
|
|
45
52
|
const regularShapes: Record<string, string> = {
|
|
46
53
|
ObjectType: '[shape=rectangle, style="filled" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
47
54
|
VariableType: '[shape=rectangle, style="rounded,filled" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
48
|
-
Object: ' [shape=rectangle, style="
|
|
55
|
+
Object: ' [shape=rectangle, style="filled" fillcolor="#e8edf7"]',
|
|
49
56
|
Variable: '[shape=rectangle, style="filled,rounded" fillcolor="#e8edf7"]',
|
|
50
|
-
Method: '[shape=
|
|
57
|
+
Method: '[shape=oval, style="filled" fillcolor="#e8edf7"]'
|
|
51
58
|
};
|
|
52
59
|
const regularShapesOptionals: Record<string, string> = {
|
|
53
60
|
ObjectType: '[shape=rectangle, style="filled,dashed" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
54
61
|
VariableType: '[shape=rectangle, style="rounded,filled,dashed" fillcolor="#e8edf7;0.75:#d2def0" gradientangle=275]',
|
|
55
|
-
Object: ' [shape=rectangle, style="
|
|
62
|
+
Object: ' [shape=rectangle, style="filled,dashed" fillcolor="#e8edf7"]',
|
|
56
63
|
Variable: '[shape=rectangle, style="filled,rounded,dashed" fillcolor="#e8edf7"]',
|
|
57
|
-
Method: '[shape=
|
|
64
|
+
Method: '[shape=oval, style="filled,dashed" fillcolor="#e8edf7"]'
|
|
58
65
|
};
|
|
59
66
|
|
|
60
67
|
interface Options {
|
|
@@ -62,12 +69,17 @@ interface Options {
|
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
class NodeRegistry {
|
|
65
|
-
m: Record<string, BaseNode[]> = {};
|
|
72
|
+
m: Record<string, { name: string; node: BaseNode }[]> = {};
|
|
66
73
|
invisibleNodes: string[] = [];
|
|
67
|
-
|
|
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;
|
|
68
80
|
const nodeClass = NodeClass[node.nodeClass];
|
|
69
81
|
this.m[nodeClass] = this.m[nodeClass] || [];
|
|
70
|
-
this.m[nodeClass].push(node);
|
|
82
|
+
this.m[nodeClass].push({ name, node });
|
|
71
83
|
}
|
|
72
84
|
addInvisibleNode(name: string) {
|
|
73
85
|
this.invisibleNodes.push(name);
|
|
@@ -80,22 +92,22 @@ function dumpNodeByNodeClass(str: string[], nodeRegistry: NodeRegistry) {
|
|
|
80
92
|
}
|
|
81
93
|
str.push(` ## -> ${className}`);
|
|
82
94
|
|
|
83
|
-
const mandatoryNodes = listNode.filter((node) => !node.modellingRule || node.modellingRule.match(/Mandatory/));
|
|
84
|
-
const optionalNodes = listNode.filter((node) => node.modellingRule && node.modellingRule.match(/Optional/));
|
|
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/));
|
|
85
97
|
if (mandatoryNodes.length > 0) {
|
|
86
98
|
str.push(` node [];`);
|
|
87
99
|
const decoration = regularShapes[className] as string;
|
|
88
100
|
str.push(` node ${decoration};`);
|
|
89
|
-
for (const node of mandatoryNodes) {
|
|
90
|
-
str.push(` ${
|
|
101
|
+
for (const { name, node } of mandatoryNodes) {
|
|
102
|
+
str.push(` ${name} ${innerText(node as UAVariable | UAObject)}`);
|
|
91
103
|
}
|
|
92
104
|
}
|
|
93
105
|
if (optionalNodes.length > 0) {
|
|
94
106
|
const decoration2 = regularShapesOptionals[className] as string;
|
|
95
107
|
str.push(` node [];`);
|
|
96
108
|
str.push(` node ${decoration2};`);
|
|
97
|
-
for (const node of listNode) {
|
|
98
|
-
str.push(` ${
|
|
109
|
+
for (const { name, node } of listNode) {
|
|
110
|
+
str.push(` ${name} ${innerText(node as UAVariable | UAObject)}`);
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
}
|
|
@@ -106,10 +118,22 @@ function dumpNodeByNodeClass(str: string[], nodeRegistry: NodeRegistry) {
|
|
|
106
118
|
str.push(` ${nodeRegistry.invisibleNodes.join("\n ")};`);
|
|
107
119
|
}
|
|
108
120
|
}
|
|
121
|
+
|
|
122
|
+
import { dumpStateMachineToPlantUML } from "./dump_state_machine_to_graphviz";
|
|
123
|
+
|
|
109
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
|
+
}
|
|
110
135
|
options = options || { naked: false };
|
|
111
136
|
const nodeRegistry = new NodeRegistry();
|
|
112
|
-
nodeRegistry.add(node);
|
|
113
137
|
|
|
114
138
|
const str: string[] = [];
|
|
115
139
|
const str2: string[] = [];
|
|
@@ -120,71 +144,108 @@ export function opcuaToDot(node: UAObjectType | UAVariableType, options?: Option
|
|
|
120
144
|
str.push(" node [];");
|
|
121
145
|
}
|
|
122
146
|
|
|
147
|
+
function makeId(p: string, c: string) {
|
|
148
|
+
return `${p}_${c}`.replace(" ", "_").replace(/<|>/g, "_");
|
|
149
|
+
}
|
|
150
|
+
// eslint-disable-next-line max-params
|
|
123
151
|
// eslint-disable-next-line max-statements
|
|
124
152
|
function typeMemberAndSubTypeMember(
|
|
125
153
|
str: string[],
|
|
154
|
+
parentNode: string,
|
|
126
155
|
node: UAObjectType | UAVariableType | UAMethod | UAVariable | UAObject,
|
|
127
156
|
parent: UAObjectType | UAVariableType | UAMethod | UAVariable | UAObject | null,
|
|
128
157
|
offset: number,
|
|
129
158
|
prefix: string,
|
|
130
|
-
joinWithCaller: boolean
|
|
159
|
+
joinWithCaller: boolean,
|
|
160
|
+
visitorMap: Record<string, any>
|
|
131
161
|
): [number, string[]] {
|
|
132
162
|
let innerDepth = 0;
|
|
133
163
|
const browseName = (parent || node).browseName.name!.toString();
|
|
134
164
|
const r: string[] = [];
|
|
135
165
|
const r2: string[] = [];
|
|
136
|
-
|
|
137
|
-
const
|
|
166
|
+
|
|
167
|
+
const references = (parent || node).findReferencesEx("Aggregates", BrowseDirection.Forward);
|
|
168
|
+
const folderElements = (parent || node).findReferencesEx("Organizes", BrowseDirection.Forward);
|
|
138
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
|
+
}
|
|
139
179
|
for (let i = 0; i < childReferences.length; i++) {
|
|
140
180
|
const isLast = i === childReferences.length - 1;
|
|
141
|
-
innerDepth++;
|
|
142
181
|
const reference = childReferences[i];
|
|
143
182
|
|
|
144
183
|
const childNode = reference.node! as UAVariable | UAObject | UAMethod;
|
|
145
184
|
const childName = childNode.browseName.name!.toString();
|
|
146
|
-
|
|
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);
|
|
147
197
|
const edgeAttributes = arrowHead(reference);
|
|
148
198
|
|
|
149
|
-
const breakNode =
|
|
150
|
-
|
|
151
|
-
nodeRegistry.addInvisibleNode(breakNode);
|
|
152
|
-
const horizontalPart = `{ rank=same ${breakNode} -> ${childName} ${edgeAttributes} }`;
|
|
199
|
+
const breakNode = addInvisibleNode(prefix, i + offset);
|
|
200
|
+
const horizontalPart = `{ rank=same ${breakNode} -> ${fullChildName} ${edgeAttributes} }`;
|
|
153
201
|
r.push(horizontalPart);
|
|
154
202
|
|
|
155
203
|
// push children on same level
|
|
156
|
-
const [depth] = typeMemberAndSubTypeMember(str, childNode, null, 0, `${prefix}${i + offset}_`, false);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
+
}
|
|
163
213
|
}
|
|
214
|
+
innerDepth += depth;
|
|
164
215
|
}
|
|
165
|
-
innerDepth += depth;
|
|
166
216
|
}
|
|
167
217
|
|
|
168
218
|
if (node.nodeClass == NodeClass.ObjectType || node.nodeClass === NodeClass.VariableType) {
|
|
169
219
|
if (node.subtypeOfObj && node.subtypeOfObj.nodeId.namespace === node.nodeId.namespace) {
|
|
170
|
-
const [depth, rr2] = typeMemberAndSubTypeMember(
|
|
171
|
-
|
|
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;
|
|
172
231
|
r2.push(...rr2);
|
|
173
232
|
}
|
|
174
233
|
}
|
|
175
234
|
if (r.length) {
|
|
176
235
|
str.push(...r.map((x) => " " + x));
|
|
177
236
|
}
|
|
237
|
+
|
|
178
238
|
if (!joinWithCaller) {
|
|
179
239
|
if (r2.length) {
|
|
180
|
-
str.push(` ${
|
|
240
|
+
str.push(` ${id} -> ${r2.join(" -> ")} [arrowhead=none];`);
|
|
181
241
|
}
|
|
182
242
|
}
|
|
183
243
|
|
|
184
244
|
return [innerDepth, r2];
|
|
185
245
|
}
|
|
186
246
|
|
|
187
|
-
|
|
247
|
+
const visitorMap = {};
|
|
248
|
+
typeMemberAndSubTypeMember(str2, "", node, null, 0, "r", false, visitorMap);
|
|
188
249
|
|
|
189
250
|
if (!options.naked) {
|
|
190
251
|
dumpNodeByNodeClass(str, nodeRegistry);
|
|
@@ -206,7 +267,7 @@ export function dumpClassHierachry(
|
|
|
206
267
|
|
|
207
268
|
const str: string[] = [];
|
|
208
269
|
const nodeRegistry = new NodeRegistry();
|
|
209
|
-
nodeRegistry.add(typeNode);
|
|
270
|
+
nodeRegistry.add(typeNode.browseName.name!, typeNode);
|
|
210
271
|
str.push("digraph G {");
|
|
211
272
|
if (!options.naked) {
|
|
212
273
|
// str.push(" splines=ortho;");
|
|
@@ -219,10 +280,10 @@ export function dumpClassHierachry(
|
|
|
219
280
|
const references = typeNode.findReferencesEx("HasSubtype", BrowseDirection.Forward);
|
|
220
281
|
for (let i = 0; i < references.length; i++) {
|
|
221
282
|
const reference = references[i];
|
|
222
|
-
const childNode = reference.node! as
|
|
283
|
+
const childNode = reference.node! as UAVariableType | UAObjectType;
|
|
223
284
|
const nodeClass = NodeClass[childNode.nodeClass];
|
|
224
285
|
const childName = childNode.browseName.name!.toString();
|
|
225
|
-
nodeRegistry.add(
|
|
286
|
+
nodeRegistry.add(childName, childNode);
|
|
226
287
|
const edgeAttributes = arrowHead(reference);
|
|
227
288
|
str.push(` ${childName} -> ${parentName} ${edgeAttributes};`);
|
|
228
289
|
|
|
@@ -231,8 +292,27 @@ export function dumpClassHierachry(
|
|
|
231
292
|
}
|
|
232
293
|
}
|
|
233
294
|
}
|
|
234
|
-
|
|
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
|
+
}
|
|
235
311
|
const str2: string[] = [];
|
|
312
|
+
if (options.showBaseType) {
|
|
313
|
+
dumpBaseTypes(str2, typeNode, level);
|
|
314
|
+
}
|
|
315
|
+
/** */
|
|
236
316
|
if (options.showSubType) {
|
|
237
317
|
dumpSubtypes(str2, typeNode, level);
|
|
238
318
|
}
|
|
@@ -243,9 +323,10 @@ export function dumpClassHierachry(
|
|
|
243
323
|
str.push("}");
|
|
244
324
|
return str.join("\n");
|
|
245
325
|
}
|
|
246
|
-
|
|
326
|
+
|
|
327
|
+
export function graphVizToPlantUml(str: string): string {
|
|
247
328
|
const ttt = "```";
|
|
248
|
-
return `${ttt}plantuml\n@startuml\n${str
|
|
329
|
+
return `${ttt}plantuml\n@startuml\n${str}\n@enduml\n${ttt}`;
|
|
249
330
|
}
|
|
250
331
|
export function dumpTypeDiagram(namespace: any) {
|
|
251
332
|
const objectTypes = [...namespace._objectTypeIterator()];
|
|
@@ -257,14 +338,14 @@ export function dumpTypeDiagram(namespace: any) {
|
|
|
257
338
|
const str: string[] = [];
|
|
258
339
|
for (const type of [...objectTypes, ...variableTypes]) {
|
|
259
340
|
const d = opcuaToDot(type);
|
|
260
|
-
str.push(graphVizToPlantUml(
|
|
341
|
+
str.push(graphVizToPlantUml(d));
|
|
261
342
|
|
|
262
343
|
const d2 = dumpClassHierachry(type);
|
|
263
|
-
str.push(graphVizToPlantUml(
|
|
344
|
+
str.push(graphVizToPlantUml(d2));
|
|
264
345
|
}
|
|
265
346
|
for (const dataType of dataTypes) {
|
|
266
347
|
const d = opcuaToDot(dataType);
|
|
267
|
-
str.push(graphVizToPlantUml(
|
|
348
|
+
str.push(graphVizToPlantUml(d));
|
|
268
349
|
}
|
|
269
350
|
return str.join("\n");
|
|
270
351
|
}
|