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

node-opcua / node-opcua / 22636309940

03 Mar 2026 06:03PM UTC coverage: 92.756% (+1.9%) from 90.81%
22636309940

push

github

erossignon
test: disable ENOENT on overlapping trustCertificate invocations in test environments with concurrency tests

18684 of 22141 branches covered (84.39%)

23 of 37 new or added lines in 1 file covered. (62.16%)

5775 existing lines in 228 files now uncovered.

160668 of 173216 relevant lines covered (92.76%)

875869.8 hits per line

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

99.26
/packages/node-opcua-nodeid/source/nodeid.ts
1
/* eslint-disable complexity */
2✔
2
/**
2✔
3
 * @module node-opcua-nodeid
2✔
4
 */
2✔
5
import { assert } from "node-opcua-assert";
2✔
6
import {
2✔
7
    DataTypeIds,
2✔
8
    MethodIds,
2✔
9
    ObjectIds,
2✔
10
    ObjectTypeIds,
2✔
11
    ReferenceTypeIds,
2✔
12
    VariableIds,
2✔
13
    VariableTypeIds
2✔
14
} from "node-opcua-constants";
2✔
15
import { emptyGuid, Guid, isValidGuid, normalizeGuid } from "node-opcua-guid";
2✔
16

2✔
17
/**
2✔
18
 * `NodeIdType` an enumeration that specifies the possible types of a `NodeId` value.
2✔
19
 */
2✔
20
export enum NodeIdType {
10✔
21
    NUMERIC = 0x01,
10✔
22
    STRING = 0x02,
10✔
23
    GUID = 0x03,
10✔
24
    BYTESTRING = 0x04
10✔
25
}
10✔
26

2✔
27
// function defaultValue(identifierType: NodeIdType.BYTESTRING): null;
2✔
28
// function defaultValue(identifierType: NodeIdType.STRING): "";
2✔
29
// function defaultValue(identifierType: NodeIdType.NUMERIC): 0;
2✔
30
// function defaultValue(identifierType: NodeIdType.GUID): string;
2✔
31
function defaultValue(identifierType: NodeIdType): string | 0 | Buffer  {
2,974,130✔
32
    switch (identifierType) {
2,974,130✔
33
        case NodeIdType.GUID: return emptyGuid;
2,974,130✔
34
        case NodeIdType.BYTESTRING: return null as any as Buffer;// Buffer.alloc(0);
2,974,130✔
35
        case NodeIdType.STRING: return "";
2,974,130✔
36
        case NodeIdType.NUMERIC: return 0;
2,974,130✔
37
        default:
2,974,130!
38
            throw new Error("invalid identifierType");
×
39
    }
2,974,130✔
40
}
2,974,130✔
41
/**
2✔
42
 * `NodeId` specialization for numeric nodeIds.
2✔
43
 */
2✔
44
export interface INodeIdNumeric extends NodeId {
2✔
45
    identifierType: NodeIdType.NUMERIC;
2✔
46
    value: number;
2✔
47
}
2✔
48
/**
2✔
49
 * `NodeId` specialization for GUID  nodeIds.
2✔
50
 */
2✔
51
export interface INodeIdGuid extends NodeId {
2✔
52
    identifierType: NodeIdType.GUID;
2✔
53
    value: string;
2✔
54
}
2✔
55
/**
2✔
56
 * `NodeId` specialization for ByteString  nodeIds (opaque).
2✔
57
 */
2✔
58
export interface INodeIdByteString extends NodeId {
2✔
59
    identifierType: NodeIdType.BYTESTRING;
2✔
60
    value: Buffer;
2✔
61
}
2✔
62

2✔
63
/**
2✔
64
 * `NodeId` specialization for String  nodeId.
2✔
65
 */
2✔
66
export interface INodeIdString extends NodeId {
2✔
67
    identifierType: NodeIdType.STRING;
2✔
68
    value: string;
2✔
69
}
2✔
70
/**
2✔
71
 * `NodeId` specialization for all possible types of NodeIds.
2✔
72
 */
2✔
73
export type INodeId = INodeIdNumeric | INodeIdGuid | INodeIdString | INodeIdByteString;
2✔
74

2✔
75

2✔
76

2✔
77
/**
2✔
78
 * 
2✔
79
 * This class holds a OPC-UA node identifier.
2✔
80
 * 
2✔
81
 * Nodes are unambiguously identified using a constructed
2✔
82
 * identifier called the NodeId. Some Servers may accept
2✔
83
 * alternative NodeIds in addition to the canonical NodeId
2✔
84
 * represented in this Attribute. 
2✔
85
 * 
2✔
86
 * A Server shall persist the NodeId of a Node, that is,
2✔
87
 * it shall not generate new
2✔
88
 * NodeIds when rebooting. 
2✔
89
 *
2✔
90
 */
2✔
91
export class NodeId {
2✔
92
    public static NodeIdType = NodeIdType;
2✔
93
    public static nullNodeId: NodeId;
2✔
94
    public static resolveNodeId: (a: string | NodeId) => NodeId;
2✔
95

2✔
96
    /**
2✔
97
     */
2✔
98
    public static sameNodeId: (n1: NodeId, n2: NodeId) => boolean;
2✔
99

2✔
100
    public identifierType: NodeIdType;
2✔
101
    public value: number | string | Buffer | Guid;
2✔
102
    public namespace: number;
2✔
103

2✔
104
    /**
2✔
105
     * construct a node Id from a type, a value and a namespace index.
2✔
106
     *
2✔
107
     * @param identifierType   - the nodeID type
2✔
108
     * @param value            - the node id value. The type of Value depends on identifierType.
2✔
109
     * @param namespace        - the index of the related namespace (optional , default value = 0 )
2✔
110
     *  
2✔
111
     * @example
2✔
112
     *
2✔
113
     * ```javascript
2✔
114
     * const nodeId = new NodeId(NodeIdType.NUMERIC,123,1);
2✔
115
     * ```
2✔
116
     */
2✔
117
    constructor(identifierType?: NodeIdType | null, value?: number | string | Buffer | Guid, namespace?: number) {
2✔
118
        if (identifierType === null || identifierType === undefined) {
44,741,585✔
119
            this.identifierType = NodeIdType.NUMERIC;
3,145,907✔
120
            this.value = 0;
3,145,907✔
121
            this.namespace = 0;
3,145,907✔
122
            return;
3,145,907✔
123
        }
3,145,907✔
124

41,595,678✔
125
        this.identifierType = identifierType;
41,595,678✔
126
        this.value = value || defaultValue(identifierType as NodeIdType);
44,741,585✔
127
        this.namespace = namespace || 0;
44,741,585✔
128

44,741,585✔
129
        // namespace shall be a UInt16
44,741,585✔
130
        assert(this.namespace >= 0 && this.namespace <= 0xffff, "NodeId: invalid namespace value");
44,741,585✔
131
        assert(
44,741,585✔
132
            this.identifierType !== NodeIdType.NUMERIC ||
44,741,585✔
133
                (this.value !== null && (this.value as number) >= 0 && (this.value as number) <= 0xffffffff)
41,025,304✔
134
        );
44,741,585✔
135
        assert(this.identifierType !== NodeIdType.GUID || isValidGuid(this.value as string), "NodeId: Guid is invalid");
44,741,585✔
136
        assert(this.identifierType !== NodeIdType.STRING || typeof this.value === "string", "cannot  empty string");
44,741,585✔
137
        if (this.identifierType === NodeIdType.GUID) {
44,741,585✔
138
            this.value = normalizeGuid(value as string);
522,624✔
139
        }
522,624✔
140
    }
44,741,585✔
141

2✔
142
    /**
2✔
143
     * get the string representation of the nodeID.
2✔
144
     *
2✔
145
     * @example
2✔
146
     *
2✔
147
     * by default, toString will return the "ns=" representation
2✔
148
     *
2✔
149
     * ```javascript
2✔
150
     * const nodeid = new NodeId(NodeIdType.NUMERIC, 123,1);
2✔
151
     * console.log(nodeid.toString());
2✔
152
     * ```
2✔
153
     *
2✔
154
     *  ```
2✔
155
     *  >"ns=1;i=123"
2✔
156
     *  ```
2✔
157
     * @example
2✔
158
     *
2✔
159
     *  toString can also be used to make the nsu= version of the nodeid.
2✔
160
     *
2✔
161
     *  ```javascript
2✔
162
     *  const namespaceArray = ["http://opcfoundation.com/UA/","http://mynamespace2"];
2✔
163
     *  const nodeid = new NodeId(NodeIdType.STRING, "Hello",1);
2✔
164
     *  console.log(nodeid.toString({namespaceArray}));
2✔
165
     *  ```
2✔
166
     *  ```
2✔
167
     *  >"nsu=http://mynamespace;i=123"
2✔
168
     *  ```
2✔
169
     * @example
2✔
170
     *
2✔
171
     *  passing an addressSpace to the toString options will decorate the nodeId
2✔
172
     *  with the BrowseName of the node.
2✔
173
     *
2✔
174
     *  ```javascript
2✔
175
     * const addressSpace = getAddressSpace();
2✔
176
     * const nodeid = new NodeId(NodeIdType.NUMERIC, 123,1);
2✔
177
     * console.log(nodeid.toString({addressSpace}));
2✔
178
     * ```
2✔
179
     * ```
2✔
180
     * >"nsu=http://mynamespace;i=123 (MyBrowseName)"
2✔
181
     * ```
2✔
182
     *
2✔
183
     *
2✔
184
     * @param [options.addressSpace] {AddressSpace}
2✔
185
     * @return {String}
2✔
186
     */
2✔
187
    public toString(options?: { addressSpace?: any; namespaceArray?: string[] }): string {
2✔
188
        const addressSpace = options ? options.addressSpace : null;
310,954,870✔
189

310,954,870✔
190
        const namespacePart: string = options?.namespaceArray
310,954,870✔
191
            ? this.namespace == 0
310,954,870✔
192
                ? ""
12✔
193
                : `nsu=${options.namespaceArray[this.namespace] || `<unknown namespace with index ${this.namespace}>`};`
12✔
194
            : `ns=${this.namespace};`;
310,954,870✔
195

310,954,870✔
196
        let str;
310,954,870✔
197
        const _this = this as INodeId;
310,954,870✔
198
        switch (_this.identifierType) {
310,954,870✔
199
            case NodeIdType.NUMERIC:
310,954,870✔
200
                str = `${namespacePart}i=${_this.value}`;
309,996,404✔
201
                break;
309,996,404✔
202
            case NodeIdType.STRING:
310,954,870✔
203
                str = `${namespacePart}s=${_this.value}`;
219,842✔
204
                break;
219,842✔
205
            case NodeIdType.GUID:
310,954,870✔
206
                str = `${namespacePart}g=${normalizeGuid(_this.value)}`;
541,614✔
207
                break;
541,614✔
208
            default:
310,954,870✔
209
                assert(this.identifierType === NodeIdType.BYTESTRING, "invalid identifierType in NodeId : " + this.identifierType);
197,010✔
210
                if (this.value) {
197,010✔
211
                    str = `${namespacePart}b=${(this.value as Buffer).toString("base64")}`;
197,008✔
212
                } else {
197,010✔
213
                    str = `${namespacePart}b=<null>`;
2✔
214
                }
2✔
215
                break;
197,010✔
216
        }
310,954,870✔
217

310,954,870✔
218
        if (addressSpace) {
310,954,870✔
219
            if (this.namespace === 0 && _this.identifierType === NodeIdType.NUMERIC) {
110✔
220
                // find standard browse name
108✔
221
                const name = reverse_map((this.value || 0).toString()) || "<undefined>";
108!
222
                str += " " + name;
108✔
223
            } else if (addressSpace.findNode) {
110✔
224
                // let use the provided address space to figure out the browseNode of this node.
2✔
225
                // to make the message a little bit more useful.
2✔
226
                const n = addressSpace.findNode(this);
2✔
227
                str += " " + (n ? n.browseName.toString() : " (????)");
2!
228
            }
2✔
229
        }
110✔
230
        return str;
310,954,870✔
231
    }
310,954,870✔
232

2✔
233
    /**
2✔
234
     * convert nodeId to a JSON string. same as {@link NodeId.toString }
2✔
235
     */
2✔
236
    public toJSON(options?: { namespaceArray?: string[] }): string {
2✔
237
        return this.toString(options);
553,228✔
238
    }
553,228✔
239

2✔
240
    public displayText(): string {
2✔
241
        if (this.namespace === 0 && this.identifierType === NodeIdType.NUMERIC) {
382✔
242
            const name = reverse_map(this.value.toString());
330✔
243
            if (name) {
330✔
244
                return name + " (" + this.toString() + ")";
278✔
245
            }
278✔
246
        }
330✔
247
        return this.toString();
104✔
248
    }
104✔
249

2✔
250
    /**
2✔
251
     * returns true if the NodeId is null or empty
2✔
252
     */
2✔
253
    public isEmpty(): boolean {
2✔
254
        const _this = this as INodeId;
2,267,134✔
255
        switch (_this.identifierType) {
2,267,134✔
256
            case NodeIdType.NUMERIC:
2,267,134✔
257
                return _this.value === 0;
2,267,120✔
258
            case NodeIdType.STRING:
2,267,134✔
259
                return !_this.value;
4✔
260
            case NodeIdType.GUID:
2,267,134✔
261
                return !_this.value || _this.value === emptyGuid;
6✔
262
            default:
2,267,134✔
263
                return !_this.value || (_this.value as Buffer).length === 0;
4✔
264
        }
2,267,134✔
265
    }
2,267,134✔
266
}
2✔
267

2✔
268
/**
2✔
269
 * a fixed instance of a null NodeId 
2✔
270
 */
2✔
271
NodeId.nullNodeId = new Proxy(
2✔
272
    new NodeId(NodeIdType.NUMERIC, 0, 0),
2✔
273
    {
2✔
274
        get: (target: NodeId, prop: string) => {
2✔
275
            return (target as any)[prop];
2,225,025✔
276
        },
2✔
277
        set: () => {
2✔
278
            throw new Error("Cannot assign a value to constant NodeId.nullNodeId");
6✔
279
        }
6✔
280
    });
2✔
281

2✔
282

2✔
283
/**
2✔
284
 * anything that could be turned into a nodeId
2✔
285
 */
2✔
286
export type NodeIdLike = string | NodeId | number;
2✔
287

2✔
288
/**
2✔
289
 * @private
2✔
290
 */
2✔
291
const regexNamespaceI = /ns=([0-9]+);i=([0-9]+)/;
2✔
292
const regexNamespaceS = /ns=([0-9]+);s=(.*)/;
2✔
293
const regexNamespaceB = /ns=([0-9]+);b=(.*)/;
2✔
294
const regexNamespaceG = /ns=([0-9]+);g=([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})/;
2✔
295

2✔
296
const regexNSU = /nsu=(.*);(.*)/;
2✔
297

2✔
298
/**
2✔
299
 * 
2✔
300
 */
2✔
301
export interface ResolveNodeIdOptions {
2✔
302
    namespaceArray?: string[];
2✔
303
    defaultNamespaceIndex?: number ; 
2✔
304
}
2✔
305
/**
2✔
306
 * Convert a value into a nodeId:
2✔
307
 *
2✔
308
 * @description:
2✔
309
 *    - if nodeId is a string of form : "i=1234"  => nodeId({value=1234, identifierType: NodeIdType.NUMERIC})
2✔
310
 *    - if nodeId is a string of form : "s=foo"   => nodeId({value="foo", identifierType: NodeIdType.STRING})
2✔
311
 *    - if nodeId is a string of form : "b=ABCD=" => nodeId({value=decodeBase64("ABCD="), identifierType: NodeIdType.BYTESTRING})
2✔
312
 *    - if nodeId is a {@link NodeId} :  coerceNodeId returns value
2✔
313
 * 
2✔
314
 */
2✔
315
export function coerceNodeId(value: unknown, namespaceOptions?: number | ResolveNodeIdOptions): NodeId {
156,502,135✔
316
    let matches;
156,502,135✔
317
    let twoFirst;
156,502,135✔
318
    if (value instanceof NodeId) {
156,502,135✔
319
        return value;
122,995,100✔
320
    }
122,995,100✔
321

33,507,035✔
322
    value = value || 0;
156,502,135✔
323

156,502,135✔
324
    let namespace = (typeof namespaceOptions === "number" ? namespaceOptions as number : namespaceOptions?.defaultNamespaceIndex )|| 0;
156,502,135✔
325
    
156,502,135✔
326
    const namespaceArray: string[] | undefined = (namespaceOptions as { namespace?: number, namespaceArray: string[] }) ?.namespaceArray || undefined;
156,502,135✔
327

156,502,135✔
328
    let identifierType = NodeIdType.NUMERIC;
156,502,135✔
329

156,502,135✔
330
    if (typeof value === "string") {
156,502,135✔
331
        identifierType = NodeIdType.STRING;
29,122,812✔
332

29,122,812✔
333
        twoFirst = value.substring(0, 2);
29,122,812✔
334
        if (twoFirst === "i=") {
29,122,812✔
335
            identifierType = NodeIdType.NUMERIC;
27,611,712✔
336
            value = parseInt(value.substring(2), 10);
27,611,712✔
337
        } else if (twoFirst === "s=") {
29,122,812✔
338
            identifierType = NodeIdType.STRING;
22✔
339
            value = value.substring(2);
22✔
340
        } else if (twoFirst === "b=") {
1,511,100✔
341
            identifierType = NodeIdType.BYTESTRING;
2✔
342
            value = Buffer.from(value.substring(2), "base64");
2✔
343
        } else if (twoFirst === "g=") {
1,511,078✔
344
            identifierType = NodeIdType.GUID;
8✔
345
            value = normalizeGuid(value.substring(2));
8✔
346
            assert(isValidGuid(value as string));
8✔
347
        } else if (isValidGuid(value)) {
1,511,076✔
348
            identifierType = NodeIdType.GUID;
2✔
349
            value = normalizeGuid(value);
2✔
350
        } else if ((matches = regexNamespaceI.exec(value)) !== null) {
1,511,068✔
351
            identifierType = NodeIdType.NUMERIC;
1,492,238✔
352
            namespace = parseInt(matches[1], 10);
1,492,238✔
353
            value = parseInt(matches[2], 10);
1,492,238✔
354
        } else if ((matches = regexNamespaceS.exec(value)) !== null) {
1,511,066✔
355
            identifierType = NodeIdType.STRING;
18,326✔
356
            namespace = parseInt(matches[1], 10);
18,326✔
357
            value = matches[2];
18,326✔
358
        } else if ((matches = regexNamespaceB.exec(value)) !== null) {
18,828✔
359
            identifierType = NodeIdType.BYTESTRING;
78✔
360
            namespace = parseInt(matches[1], 10);
78✔
361
            value = Buffer.from(matches[2], "base64");
78✔
362
        } else if ((matches = regexNamespaceG.exec(value)) !== null) {
502✔
363
            identifierType = NodeIdType.GUID;
136✔
364
            namespace = parseInt(matches[1], 10);
136✔
365
            value = normalizeGuid(matches[2]);
136✔
366
        } else {
424✔
367

288✔
368
            // eslint-disable-next-line no-empty
288✔
369
            if (namespaceArray && (matches = regexNSU.exec(value))!==null) {
288✔
370
                const namespaceIndex = namespaceArray.indexOf(matches[1]);
4✔
371
                if (namespaceIndex === -1) {
4!
372
                    throw new Error("Cannot find namespace with index " + matches[1] + " in " + namespaceArray.join(","));
×
UNCOV
373
                }
×
374
                const nid = coerceNodeId(matches[2], namespace);
4✔
375
                nid.namespace = namespaceIndex;
4✔
376
                return nid;
4✔
377
            } else {
288✔
378
                throw new Error("String cannot be coerced to a nodeId : " + value);
284✔
379
            }
284✔
380
        }
288✔
381
    } else if (value instanceof Buffer) {
156,502,135✔
382
        identifierType = NodeIdType.BYTESTRING;
8✔
383
    } else if (value instanceof Object) {
4,384,223✔
384
        // it could be a Enum or a NodeId Like object
180✔
385
        const tmp = value as any;
180✔
386
        value = tmp.value;
180✔
387
        namespace = namespace || tmp.namespace;
180✔
388
        identifierType = tmp.identifierType || identifierType;
180!
389
        return new NodeId(identifierType, value as any, namespace);
180✔
390
    }
180✔
391
    return new NodeId(identifierType, value as any, namespace);
33,506,567✔
392
}
33,506,567✔
393

2✔
394
const regEx1 = /^(s|g|b|i|ns)=/;
2✔
395
/**
2✔
396
 * construct a node Id from a value and a namespace.
2✔
397
 *
2✔
398
 * @param {String|Buffer} value
2✔
399
 * @param [namespace]=0 {Number} optional (default=0), the node id namespace
2✔
400
 * @return {NodeId}
2✔
401
 */
2✔
402
export function makeNodeId(value: string | Buffer | number, namespace?: number): NodeId {
1,367,836✔
403
    value = value || 0;
1,367,836✔
404
    namespace = namespace || 0;
1,367,836✔
405

1,367,836✔
406
    let identifierType = NodeIdType.NUMERIC;
1,367,836✔
407
    if (typeof value === "string") {
1,367,836✔
408
        if (value.match(regEx1)) {
194✔
409
            throw new Error("please use coerce NodeId instead");
6✔
410
        }
6✔
411
        //            1         2         3
188✔
412
        //  012345678901234567890123456789012345
188✔
413
        // "72962B91-FA75-4AE6-8D28-B404DC7DAF63"
188✔
414
        if (isValidGuid(value)) {
194✔
415
            identifierType = NodeIdType.GUID;
132✔
416
            value = normalizeGuid(value);
132✔
417
        } else {
194✔
418
            identifierType = NodeIdType.STRING;
56✔
419
        }
56✔
420
    } else if (value instanceof Buffer) {
1,367,836✔
421
        identifierType = NodeIdType.BYTESTRING;
4✔
422
    }
4✔
423

1,367,830✔
424
    const nodeId = new NodeId(identifierType, value, namespace);
1,367,830✔
425
    return nodeId;
1,367,830✔
426
}
1,367,830✔
427

2✔
428
// reverse maps
2✔
429
let _nodeIdToNameIndex: any = {};
2✔
430
let _nameToNodeIdIndex: any = {};
2✔
431

2✔
432
const regName = /[a-zA-Z_].*/;
2✔
433

2✔
434
(function build_standard_nodeid_indexes() {
2✔
435
    function expand_map(directIndex: any) {
10✔
436
        for (const name in directIndex) {
70✔
437
            if (Object.prototype.hasOwnProperty.call(directIndex, name) && regName.exec(name) !== null) {
48,880✔
438
                const value = directIndex[name];
24,440✔
439
                _nodeIdToNameIndex[value] = name;
24,440✔
440
                _nameToNodeIdIndex[name] = new NodeId(NodeIdType.NUMERIC, value, 0);
24,440✔
441
            }
24,440✔
442
        }
48,880✔
443
    }
70✔
444

10✔
445
    _nodeIdToNameIndex = {};
10✔
446
    _nameToNodeIdIndex = {};
10✔
447
    expand_map(ObjectIds);
10✔
448
    expand_map(ObjectTypeIds);
10✔
449
    expand_map(VariableIds);
10✔
450
    expand_map(VariableTypeIds);
10✔
451
    expand_map(MethodIds);
10✔
452
    expand_map(ReferenceTypeIds);
10✔
453
    expand_map(DataTypeIds);
10✔
454
})();
2✔
455

2✔
456
function reverse_map(nodeId: string) {
438✔
457
    return _nodeIdToNameIndex[nodeId];
438✔
458
}
438✔
459

2✔
460
/**
2✔
461
 * resolveNodeId can be helpful to convert a wellknown Node Name to a nodeid
2✔
462
 * if a wellknown node name cannot be detected, the function falls back to
2✔
463
 * calling coerceNodeId {@link coerceNodeId}.
2✔
464
 * 
2✔
465
 * @example
2✔
466
 * ```javascript
2✔
467
 * const nodeId = resolveNodeId("ObjectsFolder");
2✔
468
 * console.log(nodeId.toString());
2✔
469
 * ```
2✔
470
 * ```text
2✔
471
 * >ns=0;i=85
2✔
472
 * ```
2✔
473
 * 
2✔
474
 * ```javascript
2✔
475
 * const nodeId = resolveNodeId("HasComponent");
2✔
476
 * console.log(nodeId.toString());
2✔
477
 * ```
2✔
478
 * ```text
2✔
479
 * >ns=0;i=33
2✔
480
 * ```
2✔
481
 * 
2✔
482
 * ```javascript
2✔
483
 * const nodeId = resolveNodeId("ns=1;i=4444");
2✔
484
 * console.log(nodeId.toString());
2✔
485
 * ```
2✔
486
 * ```text
2✔
487
 * >ns=1;i=4444
2✔
488
 * ```
2✔
489
 * 
2✔
490
 */
2✔
491
export function resolveNodeId(nodeIdOrString: NodeIdLike, options?: ResolveNodeIdOptions): NodeId {
94,332,990✔
492
    let nodeId;
94,332,990✔
493

94,332,990✔
494
    const rawId = typeof nodeIdOrString === "string" ? _nameToNodeIdIndex[nodeIdOrString] : undefined;
94,332,990✔
495
    if (rawId !== undefined) {
94,332,990✔
496
        return rawId;
4,996,968✔
497
    } else {
94,332,990✔
498
        nodeId = coerceNodeId(nodeIdOrString, options);
89,336,022✔
499
    }
89,336,022✔
500
    return nodeId;
89,335,748✔
501
}
89,335,748✔
502

2✔
503
NodeId.resolveNodeId = resolveNodeId;
2✔
504

2✔
505
/**
2✔
506
 * 
2✔
507
 * The sameNodeId function is used to compare two NodeId objects to
2✔
508
 * determine if they are identical. This comparison is based on the
2✔
509
 * identifier type, namespace, and value of the NodeId objects.
2✔
510
 *
2✔
511

2✔
512
 *
2✔
513
 * @return {boolean} Returns true if the two NodeId objects are
2✔
514
 * identical, otherwise returns false.
2✔
515
 * 
2✔
516
 * @example
2✔
517
 * ```javascript
2✔
518
 * const nodeId1: NodeId = new NodeId(NodeIdType.STRING, "example", 1);
2✔
519
 * const nodeId2: NodeId = coerceNodeId("ns=1;s=example");
2✔
520
 * const areSame = sameNodeId(nodeId1, nodeId2); // returns true
2✔
521
 * ```
2✔
522
 */
2✔
523
export function sameNodeId(n1: NodeId, n2: NodeId): boolean {
125,207,424✔
524
    if (n1.identifierType !== n2.identifierType) {
125,207,424✔
525
        return false;
49,484✔
526
    }
49,484✔
527
    if (n1.namespace !== n2.namespace) {
125,207,424✔
528
        return false;
158,596✔
529
    }
158,596✔
530
    switch (n1.identifierType) {
124,999,344✔
531
        case NodeIdType.NUMERIC:
125,207,424✔
532
        case NodeIdType.STRING:
125,207,424✔
533
        case NodeIdType.GUID:
125,207,424✔
534
            return n1.value === n2.value;
124,998,686✔
535
        case NodeIdType.BYTESTRING:
125,207,424✔
536
            return (n1.value as Buffer).toString("hex") === (n2.value as Buffer).toString("hex");
658✔
537
        default:
125,207,424!
538
            throw new Error("Invalid identifier type");
×
539
    }
125,207,424✔
540
}
125,207,424✔
541
NodeId.sameNodeId = sameNodeId;
2✔
542

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