node-opcua-modeler 2.51.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/.mocharc.js +13 -0
- package/LICENSE +20 -0
- package/MyModelIds.csv +151 -0
- package/dist/addExtensionObjectDataType.d.ts +24 -0
- package/dist/addExtensionObjectDataType.js +198 -0
- package/dist/addExtensionObjectDataType.js.map +1 -0
- package/dist/build_model_inner.d.ts +17 -0
- package/dist/build_model_inner.js +41 -0
- package/dist/build_model_inner.js.map +1 -0
- package/dist/displayNodeElement.d.ts +5 -0
- package/dist/displayNodeElement.js +157 -0
- package/dist/displayNodeElement.js.map +1 -0
- package/dist/generate_markdown_doc.d.ts +6 -0
- package/dist/generate_markdown_doc.js +148 -0
- package/dist/generate_markdown_doc.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/promoteToMandatory.d.ts +8 -0
- package/dist/promoteToMandatory.js +98 -0
- package/dist/promoteToMandatory.js.map +1 -0
- package/dist/setNamespaceMetaData.d.ts +1 -0
- package/dist/setNamespaceMetaData.js +6 -0
- package/dist/setNamespaceMetaData.js.map +1 -0
- package/dist/symbol.d.ts +1 -0
- package/dist/symbol.js +3 -0
- package/dist/symbol.js.map +1 -0
- package/dist/tableHelper.d.ts +9 -0
- package/dist/tableHelper.js +61 -0
- package/dist/tableHelper.js.map +1 -0
- package/dist/to_cvs.d.ts +2 -0
- package/dist/to_cvs.js +12 -0
- package/dist/to_cvs.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/distNodeJS/build_documentation_to_file.d.ts +2 -0
- package/distNodeJS/build_documentation_to_file.js +27 -0
- package/distNodeJS/build_documentation_to_file.js.map +1 -0
- package/distNodeJS/build_model.d.ts +7 -0
- package/distNodeJS/build_model.js +22 -0
- package/distNodeJS/build_model.js.map +1 -0
- package/distNodeJS/index.d.ts +5 -0
- package/distNodeJS/index.js +20 -0
- package/distNodeJS/index.js.map +1 -0
- package/distNodeJS/symbol_cvs.d.ts +3 -0
- package/distNodeJS/symbol_cvs.js +64 -0
- package/distNodeJS/symbol_cvs.js.map +1 -0
- package/examples/make_model.ts +152 -0
- package/nodeJS.d.ts +1 -0
- package/nodeJS.js +1 -0
- package/package.json +53 -0
- package/readme.md +43 -0
- package/source/addExtensionObjectDataType.ts +241 -0
- package/source/build_model_inner.ts +45 -0
- package/source/displayNodeElement.ts +178 -0
- package/source/generate_markdown_doc.ts +156 -0
- package/source/index.ts +31 -0
- package/source/promoteToMandatory.ts +137 -0
- package/source/setNamespaceMetaData.ts +1 -0
- package/source/symbol.ts +1 -0
- package/source/tableHelper.ts +64 -0
- package/source/to_cvs.ts +9 -0
- package/source/types.ts +1 -0
- package/source_nodejs/build_documentation_to_file.ts +13 -0
- package/source_nodejs/build_model.ts +12 -0
- package/source_nodejs/index.ts +5 -0
- package/source_nodejs/symbol_cvs.ts +52 -0
- package/tsconfig_common.json +55 -0
- package/tsconfig_nodejs.json +25 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseNode,
|
|
3
|
+
UAReference,
|
|
4
|
+
UAObjectType,
|
|
5
|
+
UAVariable,
|
|
6
|
+
resolveReferenceNode,
|
|
7
|
+
resolveReferenceType
|
|
8
|
+
} from "node-opcua-address-space";
|
|
9
|
+
import { NodeClass } from "node-opcua-data-model";
|
|
10
|
+
import { NodeId, resolveNodeId } from "node-opcua-nodeid";
|
|
11
|
+
import { DataType } from "node-opcua-variant";
|
|
12
|
+
import { TableHelper } from "./tableHelper";
|
|
13
|
+
|
|
14
|
+
const a = "ⓂⓄⓋⓥⓇ❗⟵ ⟶⟷";
|
|
15
|
+
function symbol(nodeClass: NodeClass) {
|
|
16
|
+
switch (nodeClass) {
|
|
17
|
+
case NodeClass.DataType:
|
|
18
|
+
return "Ⓓ";
|
|
19
|
+
case NodeClass.ObjectType:
|
|
20
|
+
return "ⓄT";
|
|
21
|
+
case NodeClass.VariableType:
|
|
22
|
+
return "ⓋT";
|
|
23
|
+
case NodeClass.Method:
|
|
24
|
+
return "Ⓜ";
|
|
25
|
+
case NodeClass.Object:
|
|
26
|
+
return "Ⓞ";
|
|
27
|
+
case NodeClass.Variable:
|
|
28
|
+
return "Ⓥ";
|
|
29
|
+
case NodeClass.View:
|
|
30
|
+
return "⦖";
|
|
31
|
+
default:
|
|
32
|
+
return "?";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const hasSubtypeNodeId = resolveNodeId("HasSubtype");
|
|
36
|
+
|
|
37
|
+
export interface DisplayNodeOptions {
|
|
38
|
+
format: "cli" | "markdown";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function displayNodeElement(node: BaseNode, options?: DisplayNodeOptions): string {
|
|
42
|
+
const head: string[] = ["ReferenceType", "NodeId", "BrowseName", "ModellingRule", "TypeDefinition", "DataType", "Value"];
|
|
43
|
+
const table = new TableHelper(head);
|
|
44
|
+
|
|
45
|
+
table.push(["BrowseName: ", { colSpan: 6, content: node.browseName.toString() }]);
|
|
46
|
+
|
|
47
|
+
const superType = (node as UAObjectType).subtypeOfObj;
|
|
48
|
+
if (superType) {
|
|
49
|
+
table.push(["Base", superType.browseName.toString(), { colSpan: 6, content: node.browseName.toString() }]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (node.description) {
|
|
53
|
+
table.push(["Description", node.description.toString(), { colSpan: 6, content: node.browseName.toString() }]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const alreadyDumped: any = {};
|
|
57
|
+
|
|
58
|
+
const descriptions: any = [];
|
|
59
|
+
|
|
60
|
+
function dumpReference(ref: UAReference, filter?: string) {
|
|
61
|
+
resolveReferenceNode(node.addressSpace, ref);
|
|
62
|
+
if (!ref.isForward) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (NodeId.sameNodeId(ref.referenceType, hasSubtypeNodeId)) {
|
|
66
|
+
return; // ignore forward HasSubtype
|
|
67
|
+
}
|
|
68
|
+
// ignore subtype references
|
|
69
|
+
/* istanbul ignore next */
|
|
70
|
+
if (!ref.node) {
|
|
71
|
+
// tslint:disable-next-line: no-console
|
|
72
|
+
console.log(" Halt ", ref.toString({ addressSpace: node.addressSpace }));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const dir = ref.isForward ? " " : " ";
|
|
76
|
+
const refNode = ref.node!;
|
|
77
|
+
|
|
78
|
+
const refType = resolveReferenceType(node.addressSpace, ref);
|
|
79
|
+
if (filter) {
|
|
80
|
+
if (refType.browseName.toString() !== filter) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (alreadyDumped[refNode.nodeId.toString()]) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// xx const r = refNode.findReferencesAsObject("HasModellingRule", true);
|
|
88
|
+
const modelingRule = refNode.modellingRule || ""; // r[0] ? r[0].browseName.toString() : "/";
|
|
89
|
+
|
|
90
|
+
let value = "";
|
|
91
|
+
let dataType = "";
|
|
92
|
+
if (refNode.nodeClass === NodeClass.Variable) {
|
|
93
|
+
const v = refNode as UAVariable;
|
|
94
|
+
|
|
95
|
+
const val = v.readValue().value.value;
|
|
96
|
+
if (v.isExtensionObject()) {
|
|
97
|
+
// don't do anything
|
|
98
|
+
} else if (v.isEnumeration() && val !== null) {
|
|
99
|
+
const enumValue = v.readEnumValue();
|
|
100
|
+
value = enumValue.value + " (" + enumValue.name + ")";
|
|
101
|
+
} else if (val instanceof Date) {
|
|
102
|
+
value = val ? val.toUTCString() : "";
|
|
103
|
+
} else {
|
|
104
|
+
value = val ? val.toString() : "null";
|
|
105
|
+
}
|
|
106
|
+
const actualDataType = DataType[v.readValue().value.dataType];
|
|
107
|
+
const basicDataType = DataType[v.dataTypeObj.basicDataType];
|
|
108
|
+
dataType = v.dataTypeObj.browseName.toString();
|
|
109
|
+
if (basicDataType !== dataType) {
|
|
110
|
+
dataType = dataType + "(" + basicDataType + ")";
|
|
111
|
+
}
|
|
112
|
+
// findBasicDataType(v.dataTypeObj);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const row = [
|
|
116
|
+
refType.browseName.toString() + dir + symbol(refNode.nodeClass),
|
|
117
|
+
refNode.nodeId.toString(),
|
|
118
|
+
refNode.browseName.toString(),
|
|
119
|
+
modelingRule,
|
|
120
|
+
(refNode as any).typeDefinitionObj ? (refNode as any).typeDefinitionObj.browseName.toString() : "",
|
|
121
|
+
dataType,
|
|
122
|
+
value
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
table.push(row);
|
|
126
|
+
|
|
127
|
+
descriptions.push({
|
|
128
|
+
description: refNode.description ? refNode.description.toString() : "",
|
|
129
|
+
name: refNode.browseName.name!,
|
|
130
|
+
type: dataType
|
|
131
|
+
});
|
|
132
|
+
alreadyDumped[refNode.nodeId.toString()] = 1;
|
|
133
|
+
}
|
|
134
|
+
const references = node.allReferences();
|
|
135
|
+
|
|
136
|
+
const m = {};
|
|
137
|
+
|
|
138
|
+
function dumpReferences(_references: UAReference[]) {
|
|
139
|
+
// xx for (const ref of references) {
|
|
140
|
+
// xx dumpReference(ref, "HasSubtype");
|
|
141
|
+
// xx }
|
|
142
|
+
for (const ref of _references) {
|
|
143
|
+
dumpReference(ref, "HasTypeDefinition");
|
|
144
|
+
}
|
|
145
|
+
for (const ref of _references) {
|
|
146
|
+
dumpReference(ref, "HasEncoding");
|
|
147
|
+
}
|
|
148
|
+
for (const ref of _references) {
|
|
149
|
+
dumpReference(ref, "HasComponent");
|
|
150
|
+
}
|
|
151
|
+
for (const ref of _references) {
|
|
152
|
+
dumpReference(ref, "HasProperty");
|
|
153
|
+
}
|
|
154
|
+
for (const ref of _references) {
|
|
155
|
+
dumpReference(ref, "Organizes");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
dumpReferences(references);
|
|
159
|
+
|
|
160
|
+
// add property from base object/variable type
|
|
161
|
+
if (node.nodeClass === NodeClass.ObjectType || node.nodeClass === NodeClass.VariableType) {
|
|
162
|
+
const curNode = node;
|
|
163
|
+
|
|
164
|
+
let subtypeOf = (curNode as UAObjectType).subtypeOfObj;
|
|
165
|
+
while (subtypeOf) {
|
|
166
|
+
table.push([subtypeOf.browseName.toString() + ":", "--", "--", "--"]);
|
|
167
|
+
const references2 = subtypeOf.allReferences();
|
|
168
|
+
dumpReferences(references2);
|
|
169
|
+
subtypeOf = (subtypeOf as UAObjectType).subtypeOfObj;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (options && options.format === "markdown") {
|
|
174
|
+
return table.toMarkdownTable();
|
|
175
|
+
} else {
|
|
176
|
+
return table.toString();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BaseNode, Namespace, UADataType, UAObjectType, UAReferenceType, UAVariableType } from "node-opcua-address-space";
|
|
2
|
+
import { coerceUInt32 } from "node-opcua-basic-types";
|
|
3
|
+
import { DataTypeDefinition, EnumDefinition, StructureDefinition, StructureField } from "node-opcua-types";
|
|
4
|
+
import { DataType } from "node-opcua-variant";
|
|
5
|
+
import { displayNodeElement } from "./displayNodeElement";
|
|
6
|
+
import { TableHelper } from "./tableHelper";
|
|
7
|
+
|
|
8
|
+
interface NamespacePriv2 {
|
|
9
|
+
nodeIterator(): IterableIterator<BaseNode>;
|
|
10
|
+
_objectTypeIterator(): IterableIterator<UAObjectType>;
|
|
11
|
+
_objectTypeCount(): number;
|
|
12
|
+
_variableTypeIterator(): IterableIterator<UAVariableType>;
|
|
13
|
+
_variableTypeCount(): number;
|
|
14
|
+
_dataTypeIterator(): IterableIterator<UADataType>;
|
|
15
|
+
_dataTypeCount(): number;
|
|
16
|
+
_referenceTypeIterator(): IterableIterator<UAReferenceType>;
|
|
17
|
+
_referenceTypeCount(): number;
|
|
18
|
+
_aliasCount(): number;
|
|
19
|
+
}
|
|
20
|
+
export interface IWriter {
|
|
21
|
+
writeLine(...args: any[]): void;
|
|
22
|
+
}
|
|
23
|
+
class Writer implements IWriter {
|
|
24
|
+
private readonly stream: string[] = [];
|
|
25
|
+
constructor() {
|
|
26
|
+
/* empty */
|
|
27
|
+
}
|
|
28
|
+
public writeLine(str: string) {
|
|
29
|
+
this.stream.push(str);
|
|
30
|
+
}
|
|
31
|
+
public toString(): string {
|
|
32
|
+
return this.stream.join("\n");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function buildDocumentationToString(namespace: Namespace): Promise<string> {
|
|
37
|
+
const writer = new Writer();
|
|
38
|
+
await buildDocumentation(namespace, writer);
|
|
39
|
+
return writer.toString();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function dataTypeToMarkdown(dataType: UADataType): string {
|
|
43
|
+
const addressSpace = dataType.addressSpace;
|
|
44
|
+
|
|
45
|
+
const writer = new Writer();
|
|
46
|
+
const definition: DataTypeDefinition = (dataType as any).$definition;
|
|
47
|
+
|
|
48
|
+
writer.writeLine("\nisAbstract: " + (dataType.isAbstract ? "Yes" : "No"));
|
|
49
|
+
if (dataType.subtypeOfObj) {
|
|
50
|
+
writer.writeLine("\nSubtype of " + dataType.subtypeOfObj?.browseName.toString());
|
|
51
|
+
}
|
|
52
|
+
writer.writeLine("");
|
|
53
|
+
|
|
54
|
+
if (definition instanceof EnumDefinition) {
|
|
55
|
+
writer.writeLine("\nBasic Type: " + (DataType as any)[DataType.UInt32]);
|
|
56
|
+
writer.writeLine("");
|
|
57
|
+
|
|
58
|
+
const table = new TableHelper(["Name", "Value", "Description"]);
|
|
59
|
+
for (const f of definition.fields || []) {
|
|
60
|
+
table.push([f.name, coerceUInt32(f.value[1]), f.description.text || ""]);
|
|
61
|
+
}
|
|
62
|
+
writer.writeLine(table.toMarkdownTable());
|
|
63
|
+
} else if (definition instanceof StructureDefinition) {
|
|
64
|
+
writer.writeLine("\nBasic Type: " + (DataType as any)[dataType.basicDataType]);
|
|
65
|
+
|
|
66
|
+
const table = new TableHelper(["Name", "data type", "value rank", "maxStringLength", "Dimensions", "Description"]);
|
|
67
|
+
|
|
68
|
+
for (const f of definition.fields || []) {
|
|
69
|
+
const dataTypeString = addressSpace.findDataType(f.dataType)!.browseName.toString();
|
|
70
|
+
table.push([
|
|
71
|
+
f.name,
|
|
72
|
+
dataTypeString,
|
|
73
|
+
f.valueRank ? f.valueRank : "",
|
|
74
|
+
f.maxStringLength ? f.maxStringLength : "",
|
|
75
|
+
f.arrayDimensions ? f.arrayDimensions : "",
|
|
76
|
+
f.description.text || ""
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
writer.writeLine(table.toMarkdownTable());
|
|
80
|
+
} else {
|
|
81
|
+
writer.writeLine("\nBasic Type: " + (DataType as any)[dataType.basicDataType]);
|
|
82
|
+
writer.writeLine("");
|
|
83
|
+
}
|
|
84
|
+
return writer.toString();
|
|
85
|
+
}
|
|
86
|
+
export async function buildDocumentation(namespace: Namespace, writer: IWriter) {
|
|
87
|
+
const addressSpace = namespace.addressSpace;
|
|
88
|
+
|
|
89
|
+
const namespaceUri = namespace.namespaceUri;
|
|
90
|
+
// -------- Documentation
|
|
91
|
+
|
|
92
|
+
const nsIndex = addressSpace.getNamespaceIndex(namespaceUri);
|
|
93
|
+
|
|
94
|
+
writer.writeLine("");
|
|
95
|
+
writer.writeLine("# Namespace " + namespaceUri);
|
|
96
|
+
writer.writeLine("");
|
|
97
|
+
// -------------- writeReferences
|
|
98
|
+
const namespacePriv = (namespace as unknown) as NamespacePriv2;
|
|
99
|
+
writer.writeLine("");
|
|
100
|
+
writer.writeLine("## References ");
|
|
101
|
+
writer.writeLine("");
|
|
102
|
+
for (const referenceType of namespacePriv._referenceTypeIterator()) {
|
|
103
|
+
writer.writeLine("\n\n### reference " + referenceType.browseName.name!);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function d(node: BaseNode): string {
|
|
107
|
+
return node.description ? node.description!.text!.toString() : "";
|
|
108
|
+
}
|
|
109
|
+
// -------------- writeDataType
|
|
110
|
+
writer.writeLine("");
|
|
111
|
+
writer.writeLine("## DataTypes");
|
|
112
|
+
writer.writeLine("");
|
|
113
|
+
for (const dataType of namespacePriv._dataTypeIterator()) {
|
|
114
|
+
writer.writeLine("\n\n### " + dataType.browseName.name!.toString());
|
|
115
|
+
writer.writeLine("");
|
|
116
|
+
writer.writeLine(dataTypeToMarkdown(dataType));
|
|
117
|
+
}
|
|
118
|
+
// -------------- writeObjectType
|
|
119
|
+
writer.writeLine("");
|
|
120
|
+
writer.writeLine("## ObjectTypes");
|
|
121
|
+
writer.writeLine("");
|
|
122
|
+
for (const objectType of namespacePriv._objectTypeIterator()) {
|
|
123
|
+
writer.writeLine("\n\n### " + objectType.browseName.name!.toString());
|
|
124
|
+
writer.writeLine(d(objectType));
|
|
125
|
+
// enumerate components
|
|
126
|
+
writer.writeLine(displayNodeElement(objectType, { format: "markdown" }));
|
|
127
|
+
|
|
128
|
+
for (const comp of objectType.getComponents()) {
|
|
129
|
+
writer.writeLine("\n\n#### " + comp.browseName.name!.toString());
|
|
130
|
+
writer.writeLine("");
|
|
131
|
+
writer.writeLine(d(comp));
|
|
132
|
+
}
|
|
133
|
+
for (const comp of objectType.getProperties()) {
|
|
134
|
+
writer.writeLine("\n\n#### " + comp.browseName.name!.toString());
|
|
135
|
+
writer.writeLine("");
|
|
136
|
+
writer.writeLine(d(comp));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// -------------- writeVariableType
|
|
140
|
+
writer.writeLine("");
|
|
141
|
+
writer.writeLine("## VariableTypes");
|
|
142
|
+
writer.writeLine("");
|
|
143
|
+
for (const variableType of namespacePriv._variableTypeIterator()) {
|
|
144
|
+
writer.writeLine("\n\n### " + variableType.browseName.name!.toString());
|
|
145
|
+
writer.writeLine(d(variableType));
|
|
146
|
+
writer.writeLine("");
|
|
147
|
+
// enumerate components
|
|
148
|
+
writer.writeLine(displayNodeElement(variableType, { format: "markdown" }));
|
|
149
|
+
for (const reference of variableType.allReferences()) {
|
|
150
|
+
const n = reference.node!;
|
|
151
|
+
writer.writeLine("\n\n#### " + n.browseName.name!.toString());
|
|
152
|
+
writer.writeLine("");
|
|
153
|
+
writer.writeLine(d(n));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
package/source/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export * from "./displayNodeElement";
|
|
3
|
+
export * from "./promoteToMandatory";
|
|
4
|
+
export * from "./setNamespaceMetaData";
|
|
5
|
+
export * from "./build_model_inner";
|
|
6
|
+
export * from "./addExtensionObjectDataType";
|
|
7
|
+
export * from "./symbol";
|
|
8
|
+
export * from "./to_cvs";
|
|
9
|
+
export * from "./generate_markdown_doc";
|
|
10
|
+
//
|
|
11
|
+
export * from "node-opcua-address-space";
|
|
12
|
+
export * from "node-opcua-nodesets";
|
|
13
|
+
export * from "node-opcua-variant";
|
|
14
|
+
export * from "node-opcua-assert";
|
|
15
|
+
export * from "node-opcua-data-model";
|
|
16
|
+
export * from "node-opcua-nodeid";
|
|
17
|
+
export * from "node-opcua-numeric-range";
|
|
18
|
+
export * from "node-opcua-status-code";
|
|
19
|
+
export * from "node-opcua-basic-types";
|
|
20
|
+
export * from "node-opcua-constants";
|
|
21
|
+
export * from "node-opcua-assert";
|
|
22
|
+
export * from "node-opcua-service-translate-browse-path";
|
|
23
|
+
export { MethodIds, DataTypeIds, ReferenceTypeIds, VariableIds, VariableTypeIds, ObjectTypeIds, ObjectIds } from "node-opcua-constants";
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
DataTypeDefinition,
|
|
27
|
+
EnumDefinition,
|
|
28
|
+
EnumDefinitionOptions,
|
|
29
|
+
StructureDefinition,
|
|
30
|
+
StructureDefinitionOptions
|
|
31
|
+
} from "node-opcua-types";
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseNode,
|
|
3
|
+
UADataType,
|
|
4
|
+
UAMethod,
|
|
5
|
+
UAObject,
|
|
6
|
+
UAObjectType,
|
|
7
|
+
UAReference,
|
|
8
|
+
UAReferenceType,
|
|
9
|
+
UAVariable,
|
|
10
|
+
UAVariableType,
|
|
11
|
+
ModellingRuleType,
|
|
12
|
+
} from "node-opcua-address-space";
|
|
13
|
+
import { NodeClass } from "node-opcua-data-model";
|
|
14
|
+
import { makeBrowsePath } from "node-opcua-service-translate-browse-path";
|
|
15
|
+
|
|
16
|
+
import { displayNodeElement } from "./displayNodeElement";
|
|
17
|
+
|
|
18
|
+
type UAType = UAObjectType | UAVariableType | UAReferenceType | UADataType;
|
|
19
|
+
|
|
20
|
+
export type UAConcrete = UAVariable | UAObject | UAMethod;
|
|
21
|
+
|
|
22
|
+
// find the reference that links node1 to node2
|
|
23
|
+
function findReferenceToNode(node1: BaseNode, node2: BaseNode): UAReference {
|
|
24
|
+
const references = node1.allReferences();
|
|
25
|
+
const r = references.filter((reference: UAReference) => {
|
|
26
|
+
return reference.nodeId.toString() === node2.nodeId.toString();
|
|
27
|
+
});
|
|
28
|
+
const ref = r ? r[0] : null;
|
|
29
|
+
/* istanbul ignore next */
|
|
30
|
+
if (!ref) {
|
|
31
|
+
// may be from subtype
|
|
32
|
+
if (
|
|
33
|
+
node1.nodeClass === NodeClass.ObjectType ||
|
|
34
|
+
node1.nodeClass === NodeClass.ReferenceType ||
|
|
35
|
+
node1.nodeClass === NodeClass.VariableType
|
|
36
|
+
) {
|
|
37
|
+
const uaType = node1 as UAType;
|
|
38
|
+
if (uaType.subtypeOfObj) {
|
|
39
|
+
return findReferenceToNode(uaType.subtypeOfObj, node2);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
throw new Error("Internal Error cannot find ref from node " + node1.nodeId.toString() + " " + node2.nodeId.toString());
|
|
44
|
+
}
|
|
45
|
+
return ref;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function getChildInTypeOrBaseType(
|
|
49
|
+
node: UAObjectType | UAVariableType,
|
|
50
|
+
propertyName: string,
|
|
51
|
+
namespaceIndex: number
|
|
52
|
+
): { propInSuperType: UAConcrete; reference: UAReference } {
|
|
53
|
+
const addressSpace = node.addressSpace;
|
|
54
|
+
|
|
55
|
+
const subtypeOf = node.subtypeOfObj!;
|
|
56
|
+
/* istanbul ignore next */
|
|
57
|
+
if (!subtypeOf) {
|
|
58
|
+
throw new Error("Expecting a super type");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const browseResult = addressSpace.browsePath(makeBrowsePath(subtypeOf.nodeId, `.${namespaceIndex}:${propertyName}`));
|
|
62
|
+
const propNodeId = !browseResult.targets || !browseResult.targets[0] ? null : browseResult.targets[0].targetId!;
|
|
63
|
+
|
|
64
|
+
/* istanbul ignore next */
|
|
65
|
+
if (!propNodeId) {
|
|
66
|
+
displayNodeElement(subtypeOf);
|
|
67
|
+
throw new Error("property " + propertyName + " do not exists on " + subtypeOf.browseName.toString() + " or any superType");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const propInSuperType = addressSpace.findNode(propNodeId)! as UAVariable | UAMethod | UAObject;
|
|
71
|
+
|
|
72
|
+
/* istanbul ignore next */
|
|
73
|
+
if (!propInSuperType) {
|
|
74
|
+
throw new Error("cannot find " + propNodeId.toString());
|
|
75
|
+
}
|
|
76
|
+
// replicate property
|
|
77
|
+
const reference = findReferenceToNode(subtypeOf, propInSuperType);
|
|
78
|
+
|
|
79
|
+
/* istanbul ignore next */
|
|
80
|
+
if (!reference) {
|
|
81
|
+
throw new Error("cannot find reference");
|
|
82
|
+
}
|
|
83
|
+
return { propInSuperType, reference };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function promoteToMandatory(node: UAObjectType | UAVariableType, propertyName: string, namespaceIndex: number): UAConcrete {
|
|
87
|
+
// get base node
|
|
88
|
+
|
|
89
|
+
const { propInSuperType, reference } = getChildInTypeOrBaseType(node, propertyName, namespaceIndex);
|
|
90
|
+
|
|
91
|
+
// check mandatory
|
|
92
|
+
/* istanbul ignore next */
|
|
93
|
+
if (propInSuperType.modellingRule === "Mandatory") {
|
|
94
|
+
// tslint:disable-next-line: no-console
|
|
95
|
+
console.log("Warning property " + propertyName + " is already Mandatory in super type");
|
|
96
|
+
return propInSuperType;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const newRef = {
|
|
100
|
+
isForward: false,
|
|
101
|
+
nodeId: node.nodeId,
|
|
102
|
+
referenceType: reference.referenceType
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const newProp = (propInSuperType as UAConcrete).clone({
|
|
106
|
+
namespace: node.namespace,
|
|
107
|
+
modellingRule: "Mandatory",
|
|
108
|
+
references: [newRef]
|
|
109
|
+
});
|
|
110
|
+
return newProp;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function promoteChild(
|
|
114
|
+
node: UAObjectType | UAVariableType,
|
|
115
|
+
propertyName: string,
|
|
116
|
+
namespaceIndex: number,
|
|
117
|
+
modellingRule: ModellingRuleType
|
|
118
|
+
): UAConcrete {
|
|
119
|
+
const { propInSuperType, reference } = getChildInTypeOrBaseType(node, propertyName, namespaceIndex);
|
|
120
|
+
|
|
121
|
+
if (!modellingRule) {
|
|
122
|
+
modellingRule = propInSuperType.modellingRule || null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const newRef: UAReference = {
|
|
126
|
+
isForward: false,
|
|
127
|
+
nodeId: node.nodeId,
|
|
128
|
+
referenceType: reference.referenceType
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const newProp = (propInSuperType as UAConcrete).clone({
|
|
132
|
+
namespace: node.namespace,
|
|
133
|
+
modellingRule,
|
|
134
|
+
references: [{...newRef}]
|
|
135
|
+
});
|
|
136
|
+
return newProp;
|
|
137
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { setNamespaceMetaData } from "node-opcua-address-space";
|
package/source/symbol.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Symbols = [string, number, string][];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// tslint:disable-next-line: no-var-requires
|
|
2
|
+
const Table = require("cli-table3");
|
|
3
|
+
|
|
4
|
+
const chars1 = {
|
|
5
|
+
// tslint:disable-next-line: object-literal-sort-keys
|
|
6
|
+
"top": "-", "top-mid": "+", "top-left": "+", "top-right": "+"
|
|
7
|
+
, "bottom": "-", "bottom-mid": "+", "bottom-left": "+", "bottom-right": "+"
|
|
8
|
+
, "left": "|", "left-mid": "+", "mid": "-", "mid-mid": "+"
|
|
9
|
+
, "right": "|", "right-mid": "+", "middle": "|"
|
|
10
|
+
};
|
|
11
|
+
const chars2 = {
|
|
12
|
+
// tslint:disable-next-line: object-literal-sort-keys
|
|
13
|
+
"top": " ", "top-mid": " ", "top-left": " ", "top-right": " "
|
|
14
|
+
, "bottom": " ", "bottom-mid": " ", "bottom-left": " ", "bottom-right": " "
|
|
15
|
+
, "left": "| ", "left-mid": "| ", "mid": "-", "mid-mid": " | "
|
|
16
|
+
, "right": " |", "right-mid": "| ", "middle": " | "
|
|
17
|
+
};
|
|
18
|
+
const chars3 = {
|
|
19
|
+
// tslint:disable-next-line: object-literal-sort-keys
|
|
20
|
+
"top": "", "top-mid": "", "top-left": "", "top-right": ""
|
|
21
|
+
, "bottom": "", "bottom-mid": "", "bottom-left": "", "bottom-right": ""
|
|
22
|
+
, "left": "| ", "left-mid": "", "mid": "-", "mid-mid": " | "
|
|
23
|
+
, "right": " |", "right-mid": "", "middle": " | "
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function toMarkdownTable(table: { head: string[], rows: string[][] }): string {
|
|
27
|
+
|
|
28
|
+
const t = [];
|
|
29
|
+
|
|
30
|
+
t.push("| " + table.head.join(" | ") + " |");
|
|
31
|
+
t.push("| " + table.head.map(() => "---").join(" | ") + " |");
|
|
32
|
+
for (const r of table.rows) {
|
|
33
|
+
t.push("| " + r.join(" | ") + " |");
|
|
34
|
+
}
|
|
35
|
+
return t.join("\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class TableHelper {
|
|
39
|
+
|
|
40
|
+
private readonly rows: string[][] = [];
|
|
41
|
+
private readonly table: typeof Table;
|
|
42
|
+
private readonly head: string[];
|
|
43
|
+
constructor(head: string[]) {
|
|
44
|
+
this.rows = [];
|
|
45
|
+
// instantiate
|
|
46
|
+
this.table = new Table({
|
|
47
|
+
// chars,
|
|
48
|
+
head,
|
|
49
|
+
// colWidths: [100, 200, 50, 50,]
|
|
50
|
+
});
|
|
51
|
+
this.head = head;
|
|
52
|
+
}
|
|
53
|
+
public push(row: any) {
|
|
54
|
+
this.table.push(row);
|
|
55
|
+
const row2 = row.map((c: any) => (c.content) ? c.content : c);
|
|
56
|
+
this.rows.push(row2);
|
|
57
|
+
}
|
|
58
|
+
public toString() {
|
|
59
|
+
return this.table.toString();
|
|
60
|
+
}
|
|
61
|
+
public toMarkdownTable() {
|
|
62
|
+
return toMarkdownTable({ head: this.head, rows: this.rows });
|
|
63
|
+
}
|
|
64
|
+
}
|
package/source/to_cvs.ts
ADDED
package/source/types.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { UANamespaceMetadata } from "node-opcua-address-space";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { Namespace } from "node-opcua-address-space";
|
|
3
|
+
import { buildDocumentationToString } from "..";
|
|
4
|
+
|
|
5
|
+
export async function buildDocumentationToFile(namespace: Namespace, filename: string) {
|
|
6
|
+
const str = await buildDocumentationToString(namespace);
|
|
7
|
+
const stream = fs.createWriteStream("documentation.md");
|
|
8
|
+
stream.write(str);
|
|
9
|
+
await new Promise((resolve) => {
|
|
10
|
+
stream.on("finish", resolve);
|
|
11
|
+
stream.end();
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readNodeSet2XmlFile } from "node-opcua-address-space/nodeJS";
|
|
2
|
+
|
|
3
|
+
import { buildModelInner, BuildModelOptionsBase } from "..";
|
|
4
|
+
import { Symbols } from "..";
|
|
5
|
+
|
|
6
|
+
export async function buildModel(data: BuildModelOptionsBase): Promise<{ markdown: string; xmlModel: string; symbols: Symbols }> {
|
|
7
|
+
const option1 = {
|
|
8
|
+
...data,
|
|
9
|
+
xmlLoader: readNodeSet2XmlFile
|
|
10
|
+
};
|
|
11
|
+
return buildModelInner(option1);
|
|
12
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import * as parse from "csv-parse";
|
|
4
|
+
import { Parser } from "csv-parse";
|
|
5
|
+
|
|
6
|
+
import { Symbols } from "..";
|
|
7
|
+
import { toCSV } from "..";
|
|
8
|
+
|
|
9
|
+
// node 14 onward : import { readFile, writeFile } from "fs/promises";
|
|
10
|
+
const { readFile, writeFile } = fs.promises;
|
|
11
|
+
|
|
12
|
+
export async function saveSymbolsToCSV(csvFilename: string, symbols: Symbols): Promise<void> {
|
|
13
|
+
await writeFile(csvFilename, toCSV(symbols), "utf-8");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function getPresetSymbolsFromCSV(csvFilename: string): Promise<Symbols> {
|
|
17
|
+
if (!fs.existsSync(csvFilename)) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const data = await readFile(csvFilename, "utf-8");
|
|
22
|
+
|
|
23
|
+
const records = await new Promise((resolve) => {
|
|
24
|
+
const output: any[] = [];
|
|
25
|
+
parse(data, {
|
|
26
|
+
cast: (value, context) => {
|
|
27
|
+
if (context.index === 1) {
|
|
28
|
+
return parseInt(value, 10);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.on("readable", function (this: Parser) {
|
|
34
|
+
let record = this.read();
|
|
35
|
+
while (record) {
|
|
36
|
+
output.push(record);
|
|
37
|
+
record = this.read();
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
.on("end", () => {
|
|
41
|
+
resolve(output);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return records as Symbols;
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (err instanceof Error) {
|
|
47
|
+
// tslint:disable-next-line: no-console
|
|
48
|
+
console.log("getPresetSymbols err = ", err.message);
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|