node-opcua-address-space 2.115.0 → 2.117.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.
Files changed (35) hide show
  1. package/dist/source/helpers/call_helpers.d.ts +1 -2
  2. package/dist/source/helpers/call_helpers.js +15 -0
  3. package/dist/source/helpers/call_helpers.js.map +1 -1
  4. package/dist/source/index.d.ts +1 -0
  5. package/dist/source/index.js +3 -1
  6. package/dist/source/index.js.map +1 -1
  7. package/dist/source/loader/generateAddressSpaceRaw.d.ts +19 -1
  8. package/dist/source/loader/generateAddressSpaceRaw.js +157 -4
  9. package/dist/source/loader/generateAddressSpaceRaw.js.map +1 -1
  10. package/dist/source/loader/load_nodeset2.js +3 -10
  11. package/dist/source/loader/load_nodeset2.js.map +1 -1
  12. package/dist/src/index_current.d.ts +1 -0
  13. package/dist/src/index_current.js +1 -0
  14. package/dist/src/index_current.js.map +1 -1
  15. package/dist/src/nodeset_tools/construct_namespace_dependency.d.ts +27 -3
  16. package/dist/src/nodeset_tools/construct_namespace_dependency.js +210 -81
  17. package/dist/src/nodeset_tools/construct_namespace_dependency.js.map +1 -1
  18. package/dist/src/nodeset_tools/nodeset_to_xml.js +15 -23
  19. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  20. package/dist/src/ua_variable_impl.js +2 -74
  21. package/dist/src/ua_variable_impl.js.map +1 -1
  22. package/dist/src/validate_data_type_correctness.d.ts +6 -0
  23. package/dist/src/validate_data_type_correctness.js +98 -0
  24. package/dist/src/validate_data_type_correctness.js.map +1 -0
  25. package/dist/tsconfig_common.tsbuildinfo +1 -1
  26. package/package.json +38 -38
  27. package/source/helpers/call_helpers.ts +1 -1
  28. package/source/index.ts +1 -1
  29. package/source/loader/generateAddressSpaceRaw.ts +180 -5
  30. package/source/loader/load_nodeset2.ts +3 -9
  31. package/src/index_current.ts +1 -1
  32. package/src/nodeset_tools/construct_namespace_dependency.ts +232 -91
  33. package/src/nodeset_tools/nodeset_to_xml.ts +19 -27
  34. package/src/ua_variable_impl.ts +2 -89
  35. package/src/validate_data_type_correctness.ts +115 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-address-space",
3
- "version": "2.115.0",
3
+ "version": "2.117.0",
4
4
  "description": "pure nodejs OPCUA SDK - module address-space",
5
5
  "main": "./dist/src/index_current.js",
6
6
  "types": "./dist/source/index.d.ts",
@@ -16,42 +16,42 @@
16
16
  "c": "mocha --version"
17
17
  },
18
18
  "dependencies": {
19
- "@types/lodash": "4.14.199",
20
- "@types/semver": "^7.5.3",
21
- "async": "^3.2.4",
19
+ "@types/lodash": "4.14.201",
20
+ "@types/semver": "^7.5.5",
21
+ "async": "^3.2.5",
22
22
  "chalk": "4.1.2",
23
23
  "dequeue": "^1.0.5",
24
24
  "lodash": "4.17.21",
25
- "node-opcua-address-space-base": "2.114.0",
25
+ "node-opcua-address-space-base": "2.117.0",
26
26
  "node-opcua-assert": "2.105.0",
27
- "node-opcua-basic-types": "2.114.0",
28
- "node-opcua-binary-stream": "2.114.0",
29
- "node-opcua-client-dynamic-extension-object": "2.114.0",
27
+ "node-opcua-basic-types": "2.117.0",
28
+ "node-opcua-binary-stream": "2.117.0",
29
+ "node-opcua-client-dynamic-extension-object": "2.117.0",
30
30
  "node-opcua-constants": "2.114.0",
31
31
  "node-opcua-crypto": "4.5.0",
32
- "node-opcua-data-access": "2.114.0",
33
- "node-opcua-data-model": "2.114.0",
34
- "node-opcua-data-value": "2.114.0",
35
- "node-opcua-date-time": "2.114.0",
36
- "node-opcua-debug": "2.114.0",
37
- "node-opcua-enum": "2.114.0",
38
- "node-opcua-extension-object": "2.114.0",
39
- "node-opcua-factory": "2.114.0",
40
- "node-opcua-nodeid": "2.114.0",
41
- "node-opcua-nodeset-ua": "2.114.0",
42
- "node-opcua-numeric-range": "2.114.0",
43
- "node-opcua-object-registry": "2.114.0",
44
- "node-opcua-pseudo-session": "2.114.0",
45
- "node-opcua-service-browse": "2.114.0",
46
- "node-opcua-service-call": "2.114.0",
47
- "node-opcua-service-history": "2.114.0",
48
- "node-opcua-service-translate-browse-path": "2.114.0",
49
- "node-opcua-service-write": "2.114.0",
50
- "node-opcua-status-code": "2.114.0",
51
- "node-opcua-types": "2.114.0",
52
- "node-opcua-utils": "2.114.0",
53
- "node-opcua-variant": "2.114.0",
54
- "node-opcua-xml2json": "2.114.0",
32
+ "node-opcua-data-access": "2.117.0",
33
+ "node-opcua-data-model": "2.117.0",
34
+ "node-opcua-data-value": "2.117.0",
35
+ "node-opcua-date-time": "2.117.0",
36
+ "node-opcua-debug": "2.117.0",
37
+ "node-opcua-enum": "2.117.0",
38
+ "node-opcua-extension-object": "2.117.0",
39
+ "node-opcua-factory": "2.117.0",
40
+ "node-opcua-nodeid": "2.117.0",
41
+ "node-opcua-nodeset-ua": "2.117.0",
42
+ "node-opcua-numeric-range": "2.117.0",
43
+ "node-opcua-object-registry": "2.117.0",
44
+ "node-opcua-pseudo-session": "2.117.0",
45
+ "node-opcua-service-browse": "2.117.0",
46
+ "node-opcua-service-call": "2.117.0",
47
+ "node-opcua-service-history": "2.117.0",
48
+ "node-opcua-service-translate-browse-path": "2.117.0",
49
+ "node-opcua-service-write": "2.117.0",
50
+ "node-opcua-status-code": "2.117.0",
51
+ "node-opcua-types": "2.117.0",
52
+ "node-opcua-utils": "2.117.0",
53
+ "node-opcua-variant": "2.117.0",
54
+ "node-opcua-xml2json": "2.117.0",
55
55
  "semver": "^7.5.4",
56
56
  "set-prototype-of": "^1.0.0",
57
57
  "thenify": "^3.3.1",
@@ -59,14 +59,14 @@
59
59
  },
60
60
  "devDependencies": {
61
61
  "mocha": "^10.2.0",
62
- "node-opcua-benchmarker": "2.114.0",
63
- "node-opcua-leak-detector": "2.114.0",
62
+ "node-opcua-benchmarker": "2.117.0",
63
+ "node-opcua-leak-detector": "2.117.0",
64
64
  "node-opcua-nodesets": "2.110.0",
65
- "node-opcua-packet-analyzer": "2.114.0",
66
- "node-opcua-service-filter": "2.114.0",
67
- "node-opcua-test-fixtures": "2.114.0",
65
+ "node-opcua-packet-analyzer": "2.117.0",
66
+ "node-opcua-service-filter": "2.117.0",
67
+ "node-opcua-test-fixtures": "2.117.0",
68
68
  "should": "^13.2.3",
69
- "sinon": "^16.0.0",
69
+ "sinon": "^17.0.1",
70
70
  "source-map-support": "^0.5.21"
71
71
  },
72
72
  "author": "Etienne Rossignon",
@@ -84,7 +84,7 @@
84
84
  "internet of things"
85
85
  ],
86
86
  "homepage": "http://node-opcua.github.io/",
87
- "gitHead": "2a65943304091de9876f69db24b289c157612880",
87
+ "gitHead": "99ed7589a203923985c25be8907b36485c798bbe",
88
88
  "files": [
89
89
  "dist",
90
90
  "distHelpers",
@@ -8,6 +8,7 @@ import { CallMethodRequest } from "node-opcua-service-call";
8
8
  import { StatusCode, StatusCodes } from "node-opcua-status-code";
9
9
  import { CallMethodResultOptions } from "node-opcua-types";
10
10
  import { Variant } from "node-opcua-variant";
11
+ import { ResponseCallback } from "node-opcua-pseudo-session";
11
12
  import { ISessionContext, IAddressSpace, UAMethod, UAObject } from "node-opcua-address-space-base";
12
13
 
13
14
  import { getMethodDeclaration_ArgumentList, verifyArguments_ArgumentList } from "./argument_list";
@@ -28,7 +29,6 @@ import { resolveOpaqueOnAddressSpace } from "./resolve_opaque_on_address_space";
28
29
  // A ByteString is structurally the same as a one dimensional array of Byte.
29
30
  // A server shall accept a ByteString if an array of Byte is expected.
30
31
  // BadNoCommunication
31
- type ResponseCallback<T> = (err: Error | null, result?: T) => void;
32
32
 
33
33
  export function callMethodHelper(
34
34
  context: ISessionContext,
package/source/index.ts CHANGED
@@ -41,7 +41,7 @@ export { promoteToMultiStateDiscrete } from "../src/data_access/ua_multistate_di
41
41
  export { promoteToMultiStateValueDiscrete } from "../src/data_access/ua_multistate_value_discrete_impl";
42
42
  export { promoteToTwoStateDiscrete } from "../src/data_access/ua_two_state_discrete_impl";
43
43
  export { validateDataType } from "../src/data_access/ua_multistate_value_discrete_impl";
44
-
44
+ export { validateDataTypeCorrectness } from "../src/validate_data_type_correctness";
45
45
  export * from "./ua_root_folder";
46
46
  export * from "./session_context";
47
47
  export * from "./pseudo_session";
@@ -1,15 +1,173 @@
1
1
  import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
2
2
  import { CallbackT } from "node-opcua-status-code";
3
- import { IAddressSpace } from "node-opcua-address-space-base";
4
-
3
+ import { IAddressSpace, RequiredModel } from "node-opcua-address-space-base";
4
+ import { ReaderStateParserLike, Xml2Json } from "node-opcua-xml2json";
5
+ import { minDate } from "node-opcua-date-time";
5
6
  import { adjustNamespaceArray } from "../../src/nodeset_tools/adjust_namespace_array";
6
7
  import { NodeSetLoaderOptions } from "../interfaces/nodeset_loader_options";
8
+ import { NamespacePrivate } from "../../src/namespace_private";
7
9
  import { NodeSetLoader } from "./load_nodeset2";
8
10
 
9
11
  const doDebug = checkDebugFlag(__filename);
10
12
  const debugLog = make_debugLog(__filename);
11
13
  const errorLog = make_errorLog(__filename);
12
14
 
15
+ interface Model extends RequiredModel {
16
+ requiredModel: RequiredModel[];
17
+ }
18
+ interface NodesetInfo {
19
+ namespaceUris: string[];
20
+ models: Model[];
21
+ }
22
+
23
+ async function parseDependencies(xmlData: string): Promise<NodesetInfo> {
24
+ const namespaceUris: string[] = [];
25
+
26
+ const models: Model[] = [];
27
+ let currentModel: Model | undefined = undefined;
28
+ const state0: ReaderStateParserLike = {
29
+ parser: {
30
+ UANodeSet: {
31
+ parser: {
32
+ NamespaceUris: {
33
+ parser: {
34
+ Uri: {
35
+ finish() {
36
+ namespaceUris.push(this.text);
37
+ }
38
+ }
39
+ }
40
+ },
41
+ Models: {
42
+ parser: {
43
+ Model: {
44
+ init(elementName: string, attrs: any) {
45
+ const modelUri = attrs.ModelUri;
46
+ const version = attrs.Version;
47
+ const publicationDate = new Date(Date.parse(attrs.PublicationDate));
48
+ currentModel = {
49
+ modelUri,
50
+ version,
51
+ publicationDate,
52
+ requiredModel: []
53
+ };
54
+ doDebug && console.log(`currentModel = ${JSON.stringify(currentModel)}`);
55
+ models.push(currentModel);
56
+ },
57
+ parser: {
58
+ RequiredModel: {
59
+ init(elementName: string, attrs: any) {
60
+ const modelUri = attrs.ModelUri;
61
+ const version = attrs.Version;
62
+ const publicationDate = new Date(Date.parse(attrs.PublicationDate));
63
+
64
+ if (!currentModel) {
65
+ throw new Error("Internal Error");
66
+ }
67
+ currentModel.requiredModel.push({
68
+ modelUri,
69
+ version,
70
+ publicationDate
71
+ });
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ };
82
+ const parser = new Xml2Json(state0);
83
+ parser.parseStringSync(xmlData);
84
+ if (models.length === 0 && namespaceUris.length >= 1) {
85
+ models.push({
86
+ modelUri: namespaceUris[0],
87
+ version: "1",
88
+ publicationDate: minDate,
89
+ requiredModel: []
90
+ });
91
+ }
92
+ return { models, namespaceUris: namespaceUris };
93
+ }
94
+ interface NodesetDesc {
95
+ index: number;
96
+ xmlData: string;
97
+ namespaceModel: NodesetInfo;
98
+ }
99
+ /**
100
+ * Detect order of namespace loading
101
+ */
102
+ export async function preLoad(xmlFiles: string[], xmlLoader: (nodeset2xmlUri: string) => Promise<string>): Promise<NodesetDesc[]> {
103
+ // a nodeset2 file may define multiple namespaces
104
+ const namespaceDesc: NodesetDesc[] = [];
105
+ for (let index = 0; index < xmlFiles.length; index++) {
106
+ doDebug && console.log("---------------------------------------------", xmlFiles[index]);
107
+ const xmlData = await xmlLoader(xmlFiles[index]);
108
+
109
+ const indexStart = xmlData.match(/<UANodeSet/m)?.index;
110
+ const i1 = (xmlData.match(/<\/Models>/m)?.index || 0) + "</Models>".length;
111
+ const i2 = (xmlData.match(/<\/NamespaceUris>/m)?.index || 0) + "</NamespaceUris>".length;
112
+
113
+ const indexEnd = Math.max(i1, i2);
114
+ if (indexStart === undefined || indexEnd === undefined) {
115
+ throw new Error("Internal Error");
116
+ }
117
+ const xmlData2 = xmlData.substring(indexStart, indexEnd);
118
+ doDebug &&
119
+ console.log(
120
+ xmlData2
121
+ .split("\n")
122
+ .splice(0, 46)
123
+ .map((x, i) => `${i + 0} ${x}`)
124
+ .join("\n")
125
+ );
126
+ const namespaceModel = await parseDependencies(xmlData2);
127
+ namespaceDesc.push({ xmlData, namespaceModel, index });
128
+ }
129
+ return namespaceDesc;
130
+ }
131
+ export function findOrder(nodesetDescs: NodesetDesc[]): number[] {
132
+ // compute the order of loading of the namespaces
133
+ const order: number[] = [];
134
+ const visited: Set<string> = new Set<string>();
135
+
136
+ const findNodesetIndex = (namespaceUri: string) => {
137
+ const index = nodesetDescs.findIndex((x) => x.namespaceModel.models.findIndex((e) => e.modelUri === namespaceUri) !== -1);
138
+ return index;
139
+ };
140
+ const visit = (model: Model) => {
141
+ const key = model.modelUri;
142
+ if (visited.has(key)) {
143
+ return;
144
+ }
145
+ visited.add(key);
146
+ for (const requiredModel of model.requiredModel) {
147
+ const requiredModelIndex = findNodesetIndex(requiredModel.modelUri);
148
+ if (requiredModelIndex === -1) {
149
+ throw new Error("Cannot find namespace for " + requiredModel.modelUri);
150
+ }
151
+ const nd = nodesetDescs[requiredModelIndex];
152
+ for (const n of nd.namespaceModel.models) {
153
+ visit(n);
154
+ }
155
+ }
156
+ const nodesetIndex = findNodesetIndex(model.modelUri);
157
+ const alreadyIn = order.findIndex((x) => x === nodesetIndex) !== -1;
158
+ if (!alreadyIn) order.push(nodesetIndex);
159
+ };
160
+ const visit2 = (nodesetDesc: NodesetDesc) => {
161
+ for (const model of nodesetDesc.namespaceModel.models.values()) {
162
+ visit(model);
163
+ }
164
+ };
165
+ for (let index = 0; index < nodesetDescs.length; index++) {
166
+ const nodesetDesc = nodesetDescs[index];
167
+ visit2(nodesetDesc);
168
+ }
169
+ return order;
170
+ }
13
171
  /**
14
172
  * @param addressSpace the addressSpace to populate
15
173
  * @xmlFiles: a lis of xml files
@@ -26,15 +184,32 @@ export async function generateAddressSpaceRaw(
26
184
  if (!Array.isArray(xmlFiles)) {
27
185
  xmlFiles = [xmlFiles];
28
186
  }
29
- for (let index = 0; index < xmlFiles.length; index++) {
30
- const xmlData = await xmlLoader(xmlFiles[index]);
187
+
188
+ const nodesetDesc = await preLoad(xmlFiles, xmlLoader);
189
+ const order = findOrder(nodesetDesc);
190
+
191
+ // register namespace in the same order as specified in the xmlFiles array
192
+ for (let index = 0; index < order.length; index++) {
193
+ const n = nodesetDesc[index];
194
+ for (const model of n.namespaceModel.models) {
195
+ const ns = addressSpace.registerNamespace(model.modelUri) as NamespacePrivate;
196
+ ns.setRequiredModels(model.requiredModel);
197
+ }
198
+ }
199
+
200
+
201
+ for (let index = 0; index < order.length; index++) {
202
+ const nodesetIndex = order[index];
203
+ const nodeset = nodesetDesc[nodesetIndex];
204
+ debugLog(" loading ", nodesetIndex, nodeset.xmlData.length);
31
205
  try {
32
- await nodesetLoader.addNodeSetAsync(xmlData);
206
+ await nodesetLoader.addNodeSetAsync(nodeset.xmlData);
33
207
  } catch (err) {
34
208
  errorLog("generateAddressSpace: Loading xml file ", xmlFiles[index], " failed with error ", (err as Error).message);
35
209
  throw err;
36
210
  }
37
211
  }
212
+
38
213
  await nodesetLoader.terminateAsync();
39
214
  adjustNamespaceArray(addressSpace);
40
215
  // however process them in series
@@ -194,8 +194,8 @@ function makeNodeSetParserEngine(addressSpace: IAddressSpace, options: NodeSetLo
194
194
 
195
195
  // istanbul ignore next
196
196
  if (namespaceIndex === undefined) {
197
- debugLog("Warning: namespace_uri_translation = ", namespace_uri_translation);
198
- errorLog("namespace_uri_translation", namespace_uri_translation);
197
+ errorLog("Warning: namespace_uri_translation = ", namespace_uri_translation);
198
+ errorLog("Error; namespace_uri_translation", namespace_uri_translation);
199
199
  throw new Error("_translateNamespaceIndex() ! Cannot find namespace definition for index " + innerIndex);
200
200
  }
201
201
  return namespaceIndex;
@@ -306,13 +306,7 @@ function makeNodeSetParserEngine(addressSpace: IAddressSpace, options: NodeSetLo
306
306
  // Model must not be already registered
307
307
  const existingNamespace = addressSpace1.getNamespace(model.modelUri);
308
308
  if (existingNamespace) {
309
- // special treatment for namespace 0
310
- // istanbul ignore else
311
- if (model.modelUri === "http://opcfoundation.org/UA/") {
312
- namespace = existingNamespace;
313
- } else {
314
- throw new Error(" namespace already registered " + model.modelUri);
315
- }
309
+ namespace = existingNamespace;
316
310
  } else {
317
311
  namespace = addressSpace1.registerNamespace(model.modelUri);
318
312
  namespace.setRequiredModels(model.requiredModels);
@@ -12,8 +12,8 @@ export * from "../source/helpers/call_helpers";
12
12
  export * from "../source/helpers/ensure_secure_access";
13
13
  export * from "../source/helpers/resolve_opaque_on_address_space";
14
14
  export * from "../source/interfaces/alarms_and_conditions/condition_info_i";
15
-
16
15
  export * from "../src/nodeset_tools/construct_namespace_dependency";
16
+ export * from "../src/validate_data_type_correctness";
17
17
 
18
18
 
19
19
  export * from "../source/set_namespace_meta_data";