node-opcua-factory 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.
Files changed (54) hide show
  1. package/LICENSE +20 -0
  2. package/dist/constructor_type.d.ts +15 -0
  3. package/dist/constructor_type.js +3 -0
  4. package/dist/constructor_type.js.map +1 -0
  5. package/dist/datatype_factory.d.ts +40 -0
  6. package/dist/datatype_factory.js +330 -0
  7. package/dist/datatype_factory.js.map +1 -0
  8. package/dist/factories_baseobject.d.ts +56 -0
  9. package/dist/factories_baseobject.js +498 -0
  10. package/dist/factories_baseobject.js.map +1 -0
  11. package/dist/factories_basic_type.d.ts +40 -0
  12. package/dist/factories_basic_type.js +136 -0
  13. package/dist/factories_basic_type.js.map +1 -0
  14. package/dist/factories_builtin_types.d.ts +32 -0
  15. package/dist/factories_builtin_types.js +262 -0
  16. package/dist/factories_builtin_types.js.map +1 -0
  17. package/dist/factories_builtin_types_special.d.ts +5 -0
  18. package/dist/factories_builtin_types_special.js +46 -0
  19. package/dist/factories_builtin_types_special.js.map +1 -0
  20. package/dist/factories_enumerations.d.ts +31 -0
  21. package/dist/factories_enumerations.js +77 -0
  22. package/dist/factories_enumerations.js.map +1 -0
  23. package/dist/factories_factories.d.ts +17 -0
  24. package/dist/factories_factories.js +54 -0
  25. package/dist/factories_factories.js.map +1 -0
  26. package/dist/factories_id_generator.d.ts +3 -0
  27. package/dist/factories_id_generator.js +22 -0
  28. package/dist/factories_id_generator.js.map +1 -0
  29. package/dist/factories_schema_helpers.d.ts +26 -0
  30. package/dist/factories_schema_helpers.js +121 -0
  31. package/dist/factories_schema_helpers.js.map +1 -0
  32. package/dist/factories_structuredTypeSchema.d.ts +46 -0
  33. package/dist/factories_structuredTypeSchema.js +269 -0
  34. package/dist/factories_structuredTypeSchema.js.map +1 -0
  35. package/dist/index.d.ts +15 -0
  36. package/dist/index.js +28 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/types.d.ts +111 -0
  39. package/dist/types.js +56 -0
  40. package/dist/types.js.map +1 -0
  41. package/package.json +41 -0
  42. package/source/constructor_type.ts +18 -0
  43. package/source/datatype_factory.ts +368 -0
  44. package/source/factories_baseobject.ts +567 -0
  45. package/source/factories_basic_type.ts +168 -0
  46. package/source/factories_builtin_types.ts +381 -0
  47. package/source/factories_builtin_types_special.ts +55 -0
  48. package/source/factories_enumerations.ts +97 -0
  49. package/source/factories_factories.ts +58 -0
  50. package/source/factories_id_generator.ts +18 -0
  51. package/source/factories_schema_helpers.ts +125 -0
  52. package/source/factories_structuredTypeSchema.ts +330 -0
  53. package/source/index.ts +15 -0
  54. package/source/types.ts +180 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @module node-opcua-factory
3
+ */
4
+ // tslint:disable:no-console
5
+
6
+ import * as chalk from "chalk";
7
+
8
+ import { assert } from "node-opcua-assert";
9
+ import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
10
+ import { ExpandedNodeId, NodeId } from "node-opcua-nodeid";
11
+
12
+ import { DataTypeFactory } from "./datatype_factory";
13
+ import { ConstructorFuncWithSchema, ConstructorFunc } from "./constructor_type";
14
+
15
+ import { BaseUAObject } from "./factories_baseobject";
16
+ import { StructuredTypeSchema } from "./factories_structuredTypeSchema";
17
+
18
+ const debugLog = make_debugLog(__filename);
19
+ const doDebug = checkDebugFlag(__filename);
20
+
21
+ let globalFactory: DataTypeFactory;
22
+ export function getStandardDataTypeFactory(): DataTypeFactory {
23
+ if (!globalFactory) {
24
+ globalFactory = new DataTypeFactory([]);
25
+ globalFactory.targetNamespace = "http://opcfoundation.org/UA/";
26
+ }
27
+ return globalFactory;
28
+ }
29
+ export function getStructureTypeConstructor(typeName: string): ConstructorFuncWithSchema {
30
+ return getStandardDataTypeFactory().getStructureTypeConstructor(typeName);
31
+ }
32
+ export function hasStructuredType(typeName: string): boolean {
33
+ return getStandardDataTypeFactory().hasStructuredType(typeName);
34
+ }
35
+ export function getStructuredTypeSchema(typeName: string): StructuredTypeSchema {
36
+ return getStandardDataTypeFactory().getStructuredTypeSchema(typeName);
37
+ }
38
+
39
+ export function getConstructor(binaryEncodingNodeId: ExpandedNodeId): ConstructorFunc | null {
40
+ return getStandardDataTypeFactory().getConstructor(binaryEncodingNodeId);
41
+ }
42
+ export function hasConstructor(binaryEncodingNodeId: ExpandedNodeId): boolean {
43
+ return getStandardDataTypeFactory().hasConstructor(binaryEncodingNodeId);
44
+ }
45
+ export function constructObject(binaryEncodingNodeId: ExpandedNodeId): BaseUAObject {
46
+ return getStandardDataTypeFactory().constructObject(binaryEncodingNodeId);
47
+ }
48
+ export function registerClassDefinition(
49
+ dataTypeNodeId: NodeId,
50
+ className: string,
51
+ classConstructor: ConstructorFuncWithSchema
52
+ ): void {
53
+ return getStandardDataTypeFactory().registerClassDefinition(dataTypeNodeId, className, classConstructor);
54
+ }
55
+ /* istanbul ignore next */
56
+ export function dump(): void {
57
+ getStandardDataTypeFactory().dump();
58
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @module node-opcua-factory
3
+ */
4
+ const _FIRST_INTERNAL_ID = 0xFFFE0000;
5
+
6
+ let _nextAvailableId = _FIRST_INTERNAL_ID;
7
+
8
+ export function generate_new_id(): number {
9
+ _nextAvailableId += 1;
10
+ return _nextAvailableId;
11
+ }
12
+
13
+ export function next_available_id(): number {
14
+ return -1;
15
+ }
16
+ export function is_internal_id(value: number): boolean {
17
+ return value >= _FIRST_INTERNAL_ID;
18
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @module node-opcua-factory
3
+ */
4
+ import { assert } from "node-opcua-assert";
5
+ import { make_debugLog } from "node-opcua-debug";
6
+ import { CommonInterface, FieldCategory, FieldType, StructuredTypeField } from "./types";
7
+
8
+ const debugLog = make_debugLog(__filename);
9
+
10
+ export const parameters = {
11
+ debugSchemaHelper: !!process.env.DEBUG_CLASS
12
+ };
13
+
14
+ /**
15
+ * ensure correctness of a schema object.
16
+ *
17
+ * @method check_schema_correctness
18
+ * @param schema
19
+ *
20
+ */
21
+ export function check_schema_correctness(schema: any) {
22
+ assert(typeof schema.name === "string", " expecting schema to have a name");
23
+ assert(schema.fields instanceof Array, " expecting schema to provide a set of fields " + schema.name);
24
+ assert(schema.baseType === undefined || typeof schema.baseType === "string");
25
+ }
26
+
27
+ /**
28
+ * @method initialize_value
29
+ * @param value
30
+ * @param defaultValue
31
+ * @return {*}
32
+ */
33
+ export function initialize_field(field: StructuredTypeField, value: any): any {
34
+ const _t = field.schema;
35
+ if (!(_t !== null && typeof _t === "object")) {
36
+ throw new Error(
37
+ "initialize_field: expecting field.schema to be set field.name = '" + field.name + "' type = " + field.fieldType
38
+ );
39
+ }
40
+ if (field.category === FieldCategory.complex) {
41
+ if (field.fieldTypeConstructor) {
42
+ return new field.fieldTypeConstructor(value);
43
+ } else {
44
+ debugLog("xxxx => missing constructor for field type", field.fieldType);
45
+ }
46
+ }
47
+
48
+ if (value === undefined || value === null) {
49
+ const defaultValue = _t.computer_default_value ? _t.computer_default_value(field.defaultValue) : field.defaultValue;
50
+ if (value === undefined) {
51
+ if (_t.coerce) {
52
+ return _t.coerce(defaultValue);
53
+ }
54
+ return defaultValue;
55
+ }
56
+ if (defaultValue === null) {
57
+ if (value === null) {
58
+ return null;
59
+ }
60
+ }
61
+ }
62
+ if (_t.coerce) {
63
+ value = _t.coerce(value);
64
+ }
65
+ if (field.validate) {
66
+ if (!field.validate(value)) {
67
+ throw Error(" invalid value " + value + " for field " + field.name + " of type " + field.fieldType);
68
+ }
69
+ }
70
+ return value;
71
+ }
72
+
73
+ function initialize_value(value: any, defaultValue: any, _t: CommonInterface) {
74
+ if (value === undefined) {
75
+ return defaultValue;
76
+ }
77
+ if (defaultValue === null) {
78
+ if (value === null) {
79
+ return null;
80
+ }
81
+ }
82
+ if (_t.coerce) {
83
+ value = _t.coerce(value);
84
+ return value;
85
+ }
86
+ return value;
87
+ }
88
+ /**
89
+ * @method initialize_field_array
90
+ * @param field
91
+ * @param valueArray
92
+ * @return
93
+ */
94
+ export function initialize_field_array(field: FieldType, valueArray: any) {
95
+ const _t = field.schema;
96
+
97
+ let value;
98
+ let i;
99
+ assert(field !== null && typeof field === "object");
100
+ assert(field.isArray);
101
+
102
+ if (!valueArray && field.defaultValue === null) {
103
+ return null;
104
+ }
105
+
106
+ valueArray = valueArray || [];
107
+
108
+ let defaultValue: any;
109
+ if (_t.computer_default_value) {
110
+ defaultValue = _t.computer_default_value(field.defaultValue);
111
+ }
112
+ const arr = [];
113
+ for (i = 0; i < valueArray.length; i++) {
114
+ value = initialize_value(valueArray[i], defaultValue, _t);
115
+ arr.push(value);
116
+ }
117
+ if (field.validate) {
118
+ for (i = 0; i < arr.length; i++) {
119
+ if (!field.validate(arr[i])) {
120
+ throw Error(" invalid value " + arr[i] + " for field " + field.name + " of type " + field.fieldType);
121
+ }
122
+ }
123
+ }
124
+ return arr;
125
+ }
@@ -0,0 +1,330 @@
1
+ /**
2
+ * @module node-opcua-factory
3
+ */
4
+ import * as chalk from "chalk";
5
+ import { CommonInterface, FieldCategory, FieldInterfaceOptions, FieldType, StructuredTypeOptions, TypeSchemaBase } from "./types";
6
+
7
+ import { assert } from "node-opcua-assert";
8
+ import { BinaryStream } from "node-opcua-binary-stream";
9
+ import { ExpandedNodeId, NodeId } from "node-opcua-nodeid";
10
+ import { lowerFirstLetter } from "node-opcua-utils";
11
+
12
+ import { getBuildInType, hasBuiltInType } from "./factories_builtin_types";
13
+ import { getEnumeration, hasEnumeration } from "./factories_enumerations";
14
+ import { getStructuredTypeSchema, getStructureTypeConstructor, hasStructuredType } from "./factories_factories";
15
+ import { parameters } from "./factories_schema_helpers";
16
+ import { DataTypeFactory } from "./datatype_factory";
17
+
18
+ function figureOutFieldCategory(field: FieldInterfaceOptions): FieldCategory {
19
+ const fieldType = field.fieldType;
20
+
21
+ if (field.category) {
22
+ return field.category;
23
+ }
24
+
25
+ if (hasEnumeration(fieldType)) {
26
+ return FieldCategory.enumeration;
27
+ } else if (hasBuiltInType(fieldType)) {
28
+ return FieldCategory.basic;
29
+ } else if (hasStructuredType(fieldType)) {
30
+ assert(fieldType !== "LocalizedText"); // LocalizedText should be treated as BasicType!!!
31
+ return FieldCategory.complex;
32
+ }
33
+ return FieldCategory.basic;
34
+ }
35
+
36
+ const regExp = /((ns[0-9]+:)?)(.*)/;
37
+
38
+ function figureOutSchema(
39
+ underConstructSchema: StructuredTypeSchema,
40
+ field: FieldInterfaceOptions,
41
+ category: FieldCategory
42
+ ): CommonInterface {
43
+ if (field.schema) {
44
+ return field.schema;
45
+ }
46
+
47
+ if (underConstructSchema.name === field.fieldType) {
48
+ return underConstructSchema;
49
+ }
50
+
51
+ let returnValue: any = null;
52
+
53
+ // may be the field.type contains a ns<X>: prefix !! like the one found in Beckhoff PLC !
54
+ const m = field.fieldType.match(regExp);
55
+ /* istanbul ignore next */
56
+ if (!m) {
57
+ throw new Error("malformed fieldType ? : " + field.fieldType);
58
+ }
59
+ const fieldTypeWithoutNS = m[3];
60
+
61
+ switch (category) {
62
+ case FieldCategory.complex:
63
+ if (hasStructuredType(field.fieldType)) {
64
+ returnValue = getStructuredTypeSchema(fieldTypeWithoutNS);
65
+ } else {
66
+ // LocalizedText etc ...
67
+ returnValue = getBuildInType(fieldTypeWithoutNS);
68
+ }
69
+ break;
70
+ case FieldCategory.basic:
71
+ returnValue = getBuildInType(fieldTypeWithoutNS);
72
+ break;
73
+ case FieldCategory.enumeration:
74
+ returnValue = getEnumeration(fieldTypeWithoutNS);
75
+ break;
76
+ }
77
+ if (null === returnValue || undefined === returnValue) {
78
+ returnValue = getEnumeration(fieldTypeWithoutNS);
79
+ throw new Error(
80
+ "Cannot find Schema for field with name " +
81
+ field.name +
82
+ " fieldTypeWithoutNS= " +
83
+ fieldTypeWithoutNS +
84
+ " with type " +
85
+ field.fieldType +
86
+ " category = " +
87
+ category +
88
+ JSON.stringify(field, null, "\t")
89
+ );
90
+ }
91
+ return returnValue;
92
+ }
93
+
94
+ function buildField(underConstructSchema: StructuredTypeSchema, fieldLight: FieldInterfaceOptions): FieldType {
95
+ const category = figureOutFieldCategory(fieldLight);
96
+ const schema = figureOutSchema(underConstructSchema, fieldLight, category);
97
+
98
+ /* istanbul ignore next */
99
+ if (!schema) {
100
+ throw new Error(
101
+ "expecting a valid schema for field with name " +
102
+ fieldLight.name +
103
+ " with type " +
104
+ fieldLight.fieldType +
105
+ " category" +
106
+ category
107
+ );
108
+ }
109
+
110
+ return {
111
+ name: lowerFirstLetter(fieldLight.name),
112
+
113
+ category,
114
+ defaultValue: fieldLight.defaultValue,
115
+ isArray: fieldLight.isArray,
116
+
117
+ documentation: fieldLight.documentation,
118
+ fieldType: fieldLight.fieldType,
119
+
120
+ switchBit: fieldLight.switchBit,
121
+
122
+ switchValue: fieldLight.switchValue,
123
+
124
+ schema
125
+ };
126
+ }
127
+
128
+ export class StructuredTypeSchema extends TypeSchemaBase {
129
+ public fields: FieldType[];
130
+ public id: NodeId;
131
+ public dataTypeNodeId: NodeId;
132
+
133
+ public baseType: string;
134
+ public _possibleFields: string[];
135
+ public _baseSchema: StructuredTypeSchema | null;
136
+
137
+ public documentation?: string;
138
+
139
+ public isValid?: (options: any) => boolean;
140
+
141
+ public decodeDebug?: (stream: BinaryStream, options: any) => any;
142
+ public constructHook?: (options: any) => any;
143
+
144
+ public encodingDefaultBinary?: ExpandedNodeId;
145
+ public encodingDefaultXml?: ExpandedNodeId;
146
+ public encodingDefaultJson?: ExpandedNodeId;
147
+
148
+ public bitFields?: any[];
149
+
150
+ constructor(options: StructuredTypeOptions) {
151
+ super(options);
152
+
153
+ this.bitFields = options.bitFields;
154
+
155
+ this.baseType = options.baseType;
156
+ this.category = FieldCategory.complex;
157
+
158
+ if (hasBuiltInType(options.name)) {
159
+ this.category = FieldCategory.basic;
160
+ }
161
+ this.fields = options.fields.map(buildField.bind(null, this));
162
+ this.id = NodeId.nullNodeId;
163
+ this.dataTypeNodeId = NodeId.nullNodeId;
164
+
165
+ this._possibleFields = this.fields.map((field) => field.name);
166
+ this._baseSchema = null;
167
+ }
168
+ public toString() {
169
+ const str: string[] = [];
170
+ str.push("name = " + this.name);
171
+ str.push("baseType = " + this.baseType);
172
+ str.push("id = " + this.id.toString());
173
+ str.push("bitFields = " + (this.bitFields ? this.bitFields.map((b) => b.name).join(" ") : undefined));
174
+ str.push("dataTypeNodeId = " + (this.dataTypeNodeId ? this.dataTypeNodeId.toString() : undefined));
175
+ str.push("documentation = " + this.documentation);
176
+ str.push("encodingDefaultBinary = " + this.encodingDefaultBinary?.toString());
177
+ str.push("encodingDefaultXml = " + this.encodingDefaultXml?.toString());
178
+ str.push("encodingDefaultJson = " + this.encodingDefaultJson?.toString());
179
+ for (const f of this.fields) {
180
+ str.push(
181
+ " field = " +
182
+ f.name.padEnd(30) +
183
+ " isArray= " +
184
+ (f.isArray ? true : false) +
185
+ " " +
186
+ f.fieldType.toString().padEnd(30) +
187
+ (f.switchBit !== undefined ? " switchBit " + f.switchBit : "") +
188
+ (f.switchValue !== undefined ? " switchValue " + f.switchValue : "")
189
+ );
190
+ }
191
+ return str.join("\n");
192
+ }
193
+ }
194
+
195
+ /**
196
+ *
197
+ * @method get_base_schema
198
+ * @param schema
199
+ * @return {*}
200
+ *
201
+ */
202
+ export function get_base_schema(schema: StructuredTypeSchema) {
203
+ let baseSchema = schema._baseSchema;
204
+ if (baseSchema) {
205
+ return baseSchema;
206
+ }
207
+
208
+ if (schema.baseType === "ExtensionObject" || schema.baseType === "DataTypeDefinition") {
209
+ return null;
210
+ }
211
+ if (schema.baseType === "Union") {
212
+ return null;
213
+ }
214
+
215
+ if (schema.baseType && schema.baseType !== "BaseUAObject" && schema.baseType !== "DataTypeDefinition") {
216
+ if (!hasStructuredType(schema.baseType)) {
217
+ return null;
218
+ }
219
+ const baseType = getStructureTypeConstructor(schema.baseType);
220
+
221
+ // istanbul ignore next
222
+ if (!baseType) {
223
+ throw new Error(" cannot find factory for " + schema.baseType);
224
+ }
225
+ if (baseType.prototype.schema) {
226
+ baseSchema = baseType.prototype.schema;
227
+ }
228
+ }
229
+ // put in cache for speedup
230
+ schema._baseSchema = baseSchema;
231
+ return baseSchema;
232
+ }
233
+
234
+ /**
235
+ * extract a list of all possible fields for a schema
236
+ * (by walking up the inheritance chain)
237
+ * @method extract_all_fields
238
+ *
239
+ */
240
+ export function extract_all_fields(schema: StructuredTypeSchema) {
241
+ // returns cached result if any
242
+ // istanbul ignore next
243
+ if (schema._possibleFields) {
244
+ return schema._possibleFields;
245
+ }
246
+ // extract the possible fields from the schema.
247
+ let possibleFields = schema.fields.map((field) => field.name);
248
+
249
+ const baseSchema = get_base_schema(schema);
250
+
251
+ // istanbul ignore next
252
+ if (baseSchema) {
253
+ const fields = extract_all_fields(baseSchema);
254
+ possibleFields = fields.concat(possibleFields);
255
+ }
256
+
257
+ // put in cache to speed up
258
+ schema._possibleFields = possibleFields;
259
+ return possibleFields;
260
+ }
261
+
262
+ /**
263
+ * check correctness of option fields against scheme
264
+ *
265
+ * @method check_options_correctness_against_schema
266
+ *
267
+ */
268
+ export function check_options_correctness_against_schema(obj: any, schema: StructuredTypeSchema, options: any): boolean {
269
+ if (!parameters.debugSchemaHelper) {
270
+ return true; // ignoring set
271
+ }
272
+
273
+ options = options || {};
274
+
275
+ // istanbul ignore next
276
+ if (!(options !== null && typeof options === "object") && !(typeof options === "object")) {
277
+ let message = chalk.red(" Invalid options specified while trying to construct a ") + " " + chalk.yellow(schema.name);
278
+ message += "\n";
279
+ message += chalk.red(" expecting a ") + chalk.yellow(" Object ");
280
+ message += "\n";
281
+ message += chalk.red(" and got a ") + chalk.yellow(typeof options) + chalk.red(" instead ");
282
+ // console.log(" Schema = ", schema);
283
+ // console.log(" options = ", options);
284
+ throw new Error(message);
285
+ }
286
+
287
+ // istanbul ignore next
288
+ if (options instanceof obj.constructor) {
289
+ return true;
290
+ }
291
+
292
+ // extract the possible fields from the schema.
293
+ const possibleFields: string[] = obj.constructor.possibleFields || schema._possibleFields;
294
+
295
+ // extracts the fields exposed by the option object
296
+ const currentFields = Object.keys(options);
297
+
298
+ // get a list of field that are in the 'options' object but not in schema
299
+ // https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore
300
+ function difference<T>(a1: T[], a2: T[]) {
301
+ return [a1, a2].reduce((a, b) => a.filter((value) => !b.includes(value)));
302
+ }
303
+ const invalidOptionsFields = difference(currentFields, possibleFields);
304
+
305
+ /* istanbul ignore next */
306
+ if (invalidOptionsFields.length > 0) {
307
+ // tslint:disable:no-console
308
+ console.log("expected schema", schema.name);
309
+ console.log(chalk.yellow("possible fields= "), possibleFields.sort().join(" "));
310
+ console.log(chalk.red("current fields= "), currentFields.sort().join(" "));
311
+ console.log(chalk.cyan("invalid_options_fields= "), invalidOptionsFields.sort().join(" "));
312
+ console.log("options = ", options);
313
+ }
314
+ /* istanbul ignore next */
315
+ if (invalidOptionsFields.length !== 0) {
316
+ // tslint:disable:no-console
317
+ console.log(chalk.yellow("possible fields= "), possibleFields.sort().join(" "));
318
+ console.log(chalk.red("current fields= "), currentFields.sort().join(" "));
319
+ throw new Error(" invalid field found in option :" + JSON.stringify(invalidOptionsFields));
320
+ }
321
+ return true;
322
+ }
323
+
324
+ export function buildStructuredType2(dataTypeFactory: DataTypeFactory, schemaLight: StructuredTypeOptions): StructuredTypeSchema {
325
+ return new StructuredTypeSchema(schemaLight);
326
+ }
327
+
328
+ export function buildStructuredType(schemaLight: StructuredTypeOptions): StructuredTypeSchema {
329
+ return new StructuredTypeSchema(schemaLight);
330
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @module node-opcua-factory
3
+ */
4
+ export * from "./constructor_type";
5
+ export * from "./datatype_factory";
6
+ export * from "./factories_id_generator";
7
+ export * from "./factories_enumerations";
8
+ export * from "./factories_basic_type";
9
+ export * from "./factories_builtin_types";
10
+ export * from "./factories_builtin_types_special";
11
+ export * from "./factories_baseobject";
12
+ export * from "./types";
13
+ export * from "./factories_schema_helpers";
14
+ export * from "./factories_factories";
15
+ export * from "./factories_structuredTypeSchema";