• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

node-opcua / node-opcua / 25848855345

14 May 2026 07:56AM UTC coverage: 92.029% (-0.1%) from 92.174%
25848855345

push

github

erossignon
fix(pnpm): make cross-workspace deps resolve correctly in pnpm 11

pnpm 11 no longer honors `link-workspace-packages=true` from .npmrc, so
plain-version cross-workspace deps (e.g. "2.171.0") fall through to the
registry and 404 on workspace-only packages like @sterfive/fix-tsconfigs
or any unpublished version bump.

- Set `linkWorkspacePackages: true` in pnpm-workspace.yaml (pnpm 11's
  preferred location for workspace-wide config).
- Switch the drift-check CI job to `--frozen-lockfile`. Strict-lockfile
  is the right mode for a verification job; `--no-frozen-lockfile` in
  non-recursive install was bypassing the existing `link:` resolution
  in the lockfile and was its own version of this same bug.

Includes the lockfile refresh that was blocked by this issue —
node-opcua-client-browser had 6 new specifiers (@types/ws, ws, plus
internal workspace deps) that couldn't be resolved.

18409 of 21711 branches covered (84.79%)

163854 of 178047 relevant lines covered (92.03%)

434321.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.81
/packages/node-opcua-schemas/source/parse_binary_xsd.ts
1
/**
3✔
2
 * @module node-opcua-schemas
2✔
3
 */
2✔
4
// tslint:disable:object-literal-sort-keys
2✔
5
// tslint:disable:no-empty
2✔
6

2✔
7
import chalk from "chalk";
2✔
8

2✔
9
import assert from "node-opcua-assert";
2✔
10
import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
2✔
11
import { EnumerationDefinitionSchema, FieldInterfaceOptions, StructuredTypeOptions } from "node-opcua-factory";
2✔
12
import { DataTypeFactory } from "node-opcua-factory";
2✔
13
import { NodeId } from "node-opcua-nodeid";
2✔
14
import { Xml2Json } from "node-opcua-xml2json";
2✔
15

2✔
16
import { getOrCreateStructuredTypeSchema } from "./tools";
2✔
17

2✔
18
const doDebug = checkDebugFlag(__filename);
2✔
19
const debugLog = make_debugLog(__filename);
2✔
20

2✔
21
function w(s: string, l: number): string {
×
22
    return s.padEnd(l).substring(0, l);
×
23
}
×
24

2✔
25
const predefinedType: any = {
2✔
26
    "opc:Bit": 1,
2✔
27
    "opc:Boolean": 1,
2✔
28
    "opc:Byte": 1,
2✔
29
    "opc:ByteString": 1,
2✔
30
    "opc:Char": 1,
2✔
31
    "opc:CharArray": 1,
2✔
32
    "opc:DateTime": 1,
2✔
33
    "opc:Double": 1,
2✔
34
    "opc:Float": 1,
2✔
35
    "opc:Guid": 1,
2✔
36
    "opc:Int16": 1,
2✔
37
    "opc:Int32": 1,
2✔
38
    "opc:Int64": 1,
2✔
39
    "opc:SByte": 1,
2✔
40
    "opc:String": 1,
2✔
41
    "opc:UInt16": 1,
2✔
42
    "opc:UInt32": 1,
2✔
43
    "opc:UInt64": 1,
2✔
44

2✔
45
    "ua:ByteStringNodeId": 1,
2✔
46
    "ua:DataValue": 1,
2✔
47
    "ua:DiagnosticInfo": 1,
2✔
48
    "ua:ExpandedNodeId": 1,
2✔
49
    "ua:ExtensionObject": 1,
2✔
50
    "ua:FourByteNodeId": 1,
2✔
51
    "ua:GuidNodeId": 1,
2✔
52
    "ua:LocalizedText": 1,
2✔
53
    "ua:NodeId": 1,
2✔
54
    "ua:NodeIdType": 1,
2✔
55
    "ua:NumericNodeId": 1,
2✔
56
    "ua:QualifiedName": 1,
2✔
57
    "ua:StatusCode": 1,
2✔
58
    "ua:StringNodeId": 1,
2✔
59
    "ua:TwoByteNodeId": 1,
2✔
60
    "ua:Variant": 1,
2✔
61
    "ua:XmlElement": 1,
2✔
62
};
2✔
63

2✔
64
export interface EnumeratedType {
2✔
65
    name: string;
2✔
66
    documentation?: string;
2✔
67
    enumeratedValues: any;
2✔
68
    lengthInBits?: number;
2✔
69
}
2✔
70

2✔
71
export interface StructureTypeRaw {
2✔
72
    name: string;
2✔
73
    baseType: string;
2✔
74
    base?: StructureTypeRaw;
2✔
75
    fields: any[];
2✔
76
}
2✔
77

2✔
78
export interface ITypeDictionary {
2✔
79
    targetNamespace: string;
2✔
80
    defaultByteOrder: string;
2✔
81
    imports: string[];
2✔
82
}
2✔
83

2✔
84
export class InternalTypeDictionary implements ITypeDictionary {
2✔
85
    public targetNamespace = "";
81✔
86
    public defaultByteOrder = "";
81✔
87
    public imports: string[] = [];
81✔
88

81✔
89
    private structuredTypesRaw: Record<string, StructureTypeRaw> = {};
81✔
90
    private enumeratedTypesRaw: Record<string, EnumeratedType> = {};
81✔
91

81✔
92
    // tns: "http://opcfoundation.org/a/b"
81✔
93
    public _namespaces: Record<string, string> = {};
81✔
94

81✔
95
    constructor() {
81✔
96
        /**  */
83✔
97
    }
83✔
98
    public addEnumeration(name: string, e: EnumeratedType): void {
81✔
99
        this.enumeratedTypesRaw[name] = e;
549✔
100
    }
549✔
101
    public getEnumerations(): EnumeratedType[] {
81✔
102
        return Object.values(this.enumeratedTypesRaw);
79✔
103
    }
79✔
104
    public getStructures(): StructureTypeRaw[] {
81✔
105
        return Object.values(this.structuredTypesRaw);
79✔
106
    }
79✔
107
    public addStructureRaw(structuredType: StructureTypeRaw): void {
81✔
108
        this.structuredTypesRaw[structuredType.name] = structuredType;
636✔
109
    }
636✔
110
    public getStructuredTypesRawByName(name: string): StructureTypeRaw {
81✔
111
        name = name.split(":")[1] || name;
4,322✔
112
        return this.structuredTypesRaw[name]! as StructureTypeRaw;
4,322✔
113
    }
4,322✔
114
}
81✔
115

2✔
116
interface _IParser {
2✔
117
    attrs: any;
2✔
118
    text?: string;
2✔
119
}
2✔
120
interface ITypeDefinitionParser extends _IParser {
2✔
121
    typeDictionary: InternalTypeDictionary;
2✔
122
    engine: { typeDictionary: InternalTypeDictionary };
2✔
123
}
2✔
124
interface IEnumeratedTypeParser extends _IParser {
2✔
125
    typescriptDefinition: string;
2✔
126
    enumeratedType: EnumeratedType;
2✔
127
    parent: { typeDictionary: InternalTypeDictionary };
2✔
128
}
2✔
129
interface IEnumeratedTypeDocumentParser extends _IParser {
2✔
130
    parent: IEnumeratedTypeParser;
2✔
131
}
2✔
132

2✔
133
interface IEnumeratedTypeEnumeratedValueParser extends _IParser {
2✔
134
    parent: IEnumeratedTypeParser;
2✔
135
}
2✔
136
interface IStructureTypeParser extends _IParser {
2✔
137
    structuredType: Omit<StructuredTypeOptions, "dataTypeFactory">;
2✔
138
    parent: { typeDictionary: InternalTypeDictionary };
2✔
139
}
2✔
140
interface IImportParser extends _IParser {
2✔
141
    parent: { typeDictionary: InternalTypeDictionary };
2✔
142
}
2✔
143
interface IStructureTypeFieldParser extends _IParser {
2✔
144
    parent: IStructureTypeParser;
2✔
145
}
2✔
146
/* tslint:disable:object-literal-shorthand */
2✔
147
const state0: any = {
2✔
148
    init: () => {
2✔
149
        const a = 1;
82✔
150
    },
3✔
151
    parser: {
2✔
152
        TypeDictionary: {
2✔
153
            init: function (this: ITypeDefinitionParser, name: string, attributes: Record<string, string>) {
2✔
154
                this.typeDictionary = this.engine.typeDictionary;
79✔
155
                this.typeDictionary.defaultByteOrder = attributes.DefaultByteOrder;
79✔
156
                this.typeDictionary.targetNamespace = attributes.TargetNamespace;
79✔
157

79✔
158
                for (const [k, v] of Object.entries(attributes)) {
79✔
159
                    if (k.match(/xmlns:/)) {
472✔
160
                        const ns = k.split(":")[1];
312✔
161
                        this.typeDictionary._namespaces[ns] = v;
312✔
162
                        this.typeDictionary._namespaces[v] = ns;
312✔
163
                    }
312✔
164
                }
472✔
165
            },
3✔
166
            parser: {
2✔
167
                Import: {
2✔
168
                    init: function (this: IImportParser, name: string, attributes: any) {
2✔
169
                        this.parent.typeDictionary.imports.push(attributes.Namespace);
83✔
170
                    },
3✔
171
                    finish: function (this: IImportParser) {
2✔
172
                        // _register_namespace_uri(this.text);
83✔
173
                        // c8 ignore next
83✔
174
                        if (doDebug) {
83!
175
                            debugLog("Import NameSpace = ", this.attrs.Namespace, " Location", this.attrs.Location);
×
176
                        }
×
177
                    }
83✔
178
                },
2✔
179

2✔
180
                EnumeratedType: {
2✔
181
                    init: function (this: IEnumeratedTypeParser) {
2✔
182
                        this.typescriptDefinition = "";
549✔
183
                        // c8 ignore next
549✔
184
                        if (doDebug) {
549!
185
                            debugLog(
×
186
                                chalk.cyan("EnumeratedType Name="),
×
187
                                w(this.attrs.Name, 40),
×
188
                                "LengthInBits=",
×
189
                                this.attrs.LengthInBits
×
190
                            );
×
191
                        }
×
192

549✔
193
                        this.enumeratedType = {
549✔
194
                            enumeratedValues: {},
549✔
195
                            lengthInBits: parseInt(this.attrs.LengthInBits, 10),
549✔
196
                            name: this.attrs.Name
549✔
197
                        };
549✔
198

549✔
199
                        this.typescriptDefinition += `enum ${this.enumeratedType.name} {`;
549✔
200
                    },
5✔
201
                    parser: {
2✔
202
                        Documentation: {
2✔
203
                            finish: function (this: IEnumeratedTypeDocumentParser) {
2✔
204
                                this.parent.enumeratedType.documentation = this.text;
10✔
205
                            }
10✔
206
                        },
2✔
207
                        EnumeratedValue: {
2✔
208
                            finish: function (this: IEnumeratedTypeEnumeratedValueParser) {
2✔
209
                                // c8 ignore next
4,095✔
210
                                if (doDebug) {
4,095!
211
                                    debugLog(" EnumeratedValue Name=", w(this.attrs.Name, 40), " Value=", this.attrs.Value);
×
212
                                }
×
213
                                const key = this.attrs.Name;
4,095✔
214
                                const value = parseInt(this.attrs.Value, 10);
4,095✔
215
                                const _enum = this.parent.enumeratedType.enumeratedValues;
4,095✔
216
                                _enum[(_enum[key] = value)] = key;
4,095✔
217
                                this.parent.typescriptDefinition += `\n  ${key} = ${value},`;
4,095✔
218
                            }
4,095✔
219
                        }
2✔
220
                    },
2✔
221
                    finish: function (this: IEnumeratedTypeParser) {
2✔
222
                        this.typescriptDefinition += `\n}`;
549✔
223
                        this.parent.typeDictionary.addEnumeration(this.attrs.Name, this.enumeratedType);
549✔
224
                        // c8 ignore next
549✔
225
                        if (doDebug) {
549!
226
                            debugLog(" this.typescriptDefinition  = ", this.typescriptDefinition);
×
227
                        }
×
228
                    }
549✔
229
                },
2✔
230
                StructuredType: {
2✔
231
                    init: function (this: IStructureTypeParser) {
2✔
232
                        // c8 ignore next
631✔
233
                        if (doDebug) {
631!
234
                            debugLog(
×
235
                                chalk.cyan("StructureType Name="),
×
236
                                chalk.green(this.attrs.Name),
×
237
                                " BaseType=",
×
238
                                this.attrs.BaseType
×
239
                            );
×
240
                        }
×
241

631✔
242
                        const baseType = this.attrs.BaseType;
631✔
243

631✔
244
                        const structuredType: Omit<StructuredTypeOptions, "dataTypeFactory"> = {
631✔
245
                            name: this.attrs.Name,
631✔
246
                            baseType,
631✔
247
                            fields: []
631✔
248
                        };
631✔
249
                        this.structuredType = structuredType;
631✔
250
                    },
25✔
251
                    parser: {
2✔
252
                        Field: {
2✔
253
                            finish: function (this: IStructureTypeFieldParser) {
2✔
254
                                if (this.attrs.SourceType) {
5,182✔
255
                                    // ignore  this field, This is a repetition of the base type field with same name
578✔
256
                                    return;
578✔
257
                                }
578✔
258
                                // c8 ignore next
4,614✔
259
                                if (doDebug) {
5,182!
260
                                    debugLog(
×
261
                                        chalk.yellow(" field Name="),
×
262
                                        w(this.attrs.Name, 40),
×
263
                                        chalk.yellow(" typeName="),
×
264
                                        w(this.attrs.TypeName, 40),
×
265
                                        this.attrs.LengthField
×
266
                                            ? chalk.yellow(" lengthField= ") + w(this.attrs.LengthField, 40)
×
267
                                            : "",
×
268
                                        this.attrs.SwitchField
×
269
                                            ? chalk.yellow(" SwitchField= ") + w(this.attrs.SwitchField, 40)
×
270
                                            : "",
×
271
                                        this.attrs.SwitchValue !== undefined
×
272
                                            ? chalk.yellow(" SwitchValue= ") + w(this.attrs.SwitchValue, 40)
×
273
                                            : ""
×
274
                                        // chalk.yellow(" lengthField="), w(this.attrs.LengthField, 40)
×
275
                                    );
×
276
                                }
×
277

4,614✔
278
                                const field: FieldInterfaceOptions = {
4,614✔
279
                                    name: this.attrs.Name,
4,604✔
280
                                    fieldType: this.attrs.TypeName
4,604✔
281
                                };
4,604✔
282

4,604✔
283
                                const structuredType = this.parent.structuredType;
4,604✔
284
                                if (field.fieldType === "opc:Bit") {
5,182✔
285
                                    // do something to collect bits but ignore them as field
1,444✔
286
                                    structuredType.bitFields = structuredType.bitFields || [];
1,444✔
287
                                    const length = this.attrs.Length || 1;
1,444✔
288
                                    structuredType.bitFields.push({ name: field.name, length });
1,444✔
289
                                    return;
1,444✔
290
                                }
1,444✔
291

3,219✔
292
                                if (this.attrs.LengthField) {
5,182✔
293
                                    field.isArray = true;
252✔
294
                                    const n = structuredType.fields.length - 1;
252✔
295
                                    structuredType.fields[n] = field;
252✔
296
                                } else {
5,182✔
297
                                    structuredType.fields.push(field);
2,908✔
298
                                }
2,908✔
299
                                if (this.attrs.SwitchField) {
5,182✔
300
                                    // field is optional and can be omitted
1,212✔
301
                                    const switchField = this.attrs.SwitchField;
1,212✔
302

1,212✔
303
                                    if (this.attrs.SwitchValue) {
1,212✔
304
                                        // we are in a union
176✔
305
                                        field.switchValue = parseInt(this.attrs.SwitchValue, 10);
176✔
306
                                        // c8 ignore next
176✔
307
                                        if (doDebug) {
176!
308
                                            debugLog(
×
309
                                                "field",
×
310
                                                field.name,
×
311
                                                " is part of a union  => ",
×
312
                                                switchField,
×
313
                                                " value #",
×
314
                                                field.switchValue
×
315
                                            );
×
316
                                        }
×
317
                                        // sometimes (like in Milo, baseType attribute is not specified)
176✔
318
                                        if (!this.parent.attrs.baseType) {
176✔
319
                                            this.parent.attrs.baseType = "Union";
45✔
320
                                            this.parent.structuredType.baseType = "Union";
45✔
321
                                        }
45✔
322
                                    } else {
1,212✔
323
                                        field.switchBit = structuredType.bitFields
1,036✔
324
                                            ? structuredType.bitFields!.findIndex((x) => x.name === switchField)
1,036✔
325
                                            : -2;
1,005!
326
                                        // c8 ignore next
1,036✔
327
                                        if (doDebug) {
1,036!
328
                                            debugLog(
×
329
                                                "field",
×
330
                                                field.name,
×
331
                                                " is optional => ",
×
332
                                                switchField,
×
333
                                                "bit #",
×
334
                                                field.switchBit
×
335
                                            );
×
336
                                        }
×
337
                                    }
1,036✔
338
                                }
1,212✔
339
                            }
5,182✔
340
                        }
2✔
341
                    },
2✔
342
                    finish: function (this: IStructureTypeParser) {
2✔
343
                        assert(this.attrs.Name === this.structuredType.name);
631✔
344
                        this.parent.typeDictionary.addStructureRaw(this.structuredType);
631✔
345
                    }
631✔
346
                }
2✔
347
            }
2✔
348
        }
2✔
349
    }
2✔
350
};
2✔
351

2✔
352
export interface DataTypeAndEncodingId {
2✔
353
    dataTypeNodeId: NodeId;
2✔
354
    binaryEncodingNodeId: NodeId;
2✔
355
    xmlEncodingNodeId: NodeId;
2✔
356
    jsonEncodingNodeId: NodeId;
2✔
357
}
2✔
358
export interface MapDataTypeAndEncodingIdProvider {
2✔
359
    // getDataTypeNodeId(key: string): NodeId;
2✔
360
    getDataTypeAndEncodingId(key: string): DataTypeAndEncodingId | null;
2✔
361
}
2✔
362
interface WithTypeDictionary extends Xml2Json {
2✔
363
    typeDictionary: InternalTypeDictionary;
2✔
364
}
2✔
365
export async function parseBinaryXSD(
3✔
366
    xmlString: string,
82✔
367
    idProvider: MapDataTypeAndEncodingIdProvider,
82✔
368
    dataTypeFactory: DataTypeFactory
82✔
369
): Promise<void> {
82✔
370
    const parser = new Xml2Json(state0) as WithTypeDictionary;
82✔
371
    const typeDictionary = new InternalTypeDictionary();
82✔
372
    parser.typeDictionary = typeDictionary;
82✔
373
    if (!xmlString || xmlString.length === 0) {
82✔
374
        return;
3✔
375
    }
3✔
376
    parser.parseString(xmlString);
79✔
377
    // resolve and prepare enumerations
79✔
378
    for (const enumeratedType of typeDictionary.getEnumerations()) {
82✔
379
        if (Object.keys(enumeratedType.enumeratedValues).length >= 1) {
549✔
380
            const e = new EnumerationDefinitionSchema(NodeId.nullNodeId, {
549✔
381
                lengthInBits: enumeratedType.lengthInBits || 32,
549!
382
                enumValues: enumeratedType.enumeratedValues,
549✔
383
                name: enumeratedType.name
549✔
384
            });
549✔
385
            dataTypeFactory.registerEnumeration(e);
549✔
386
        }
549✔
387
    }
549✔
388

79✔
389
    // c8 ignore next
79✔
390
    if (doDebug) {
82!
391
        debugLog("------------------------------- Resolving complex Type");
×
392
        typeDictionary.getStructures().map((x: any) => debugLog(x.name));
×
393
    }
×
394

79✔
395
    // create area in navigation order
79✔
396
    function createExplorationOrder(): StructureTypeRaw[] {
79✔
397
        const array: StructureTypeRaw[] = [];
79✔
398
        const _map: Record<string, string> = {};
79✔
399
        function alreadyVisited(name: string) {
79✔
400
            name = name.split(":")[1] || name;
1,238✔
401
            return !!_map[name];
1,238✔
402
        }
1,238✔
403
        function markAsVisited(name: string) {
79✔
404
            name = name.split(":")[1] || name;
3,063✔
405
            _map[name] = "1";
3,063✔
406
        }
3,063✔
407
        function visitStructure(structuredType: StructureTypeRaw) {
79✔
408
            if (!structuredType || structuredType.name === "ua:ExtensionObject") {
1,238!
409
                return;
×
410
            }
×
411
            if (alreadyVisited(structuredType.name)) {
1,238✔
412
                return;
607✔
413
            }
607✔
414
            markAsVisited(structuredType.name);
648✔
415
            if (structuredType.baseType && structuredType.baseType !== "ua:ExtensionObject") {
1,238✔
416
                const base = typeDictionary.getStructuredTypesRawByName(structuredType.baseType);
176✔
417
                if (base && base.baseType) {
176✔
418
                    doDebug && debugLog("  investigating  base", chalk.cyan(base.name));
131!
419
                    visitStructure(base);
131✔
420
                }
131✔
421
            }
176✔
422
            for (const f of structuredType.fields) {
1,238✔
423
                const s = typeDictionary.getStructuredTypesRawByName(f.fieldType);
2,908✔
424
                if (s !== structuredType && s) {
2,908✔
425
                    visitStructure(s);
476✔
426
                } else {
2,908✔
427
                    markAsVisited(f.fieldType);
2,432✔
428
                }
2,432✔
429
            }
2,908✔
430
            doDebug && debugLog("processing ", chalk.cyan(structuredType.name));
1,238!
431
            array.push(structuredType);
1,238✔
432
        }
1,238✔
433

79✔
434
        for (const structuredType of typeDictionary.getStructures()) {
79✔
435
            visitStructure(structuredType);
631✔
436
        }
631✔
437
        return array;
79✔
438
    }
79✔
439
    // resolve complex types
79✔
440
    const schemaInVisitingOrder = createExplorationOrder();
79✔
441
    for (const structuredType of schemaInVisitingOrder) {
82✔
442
        getOrCreateStructuredTypeSchema(structuredType.name, typeDictionary, dataTypeFactory, idProvider);
631✔
443
    }
631✔
444
}
79✔
445

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc