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

node-opcua / node-opcua / 25640124541

10 May 2026 09:22PM UTC coverage: 92.191% (-0.03%) from 92.22%
25640124541

push

github

erossignon
refactor(address-space): typed event emitters + biome conformance

Introduce a typed-event-emitter contract for the address-space class
hierarchy, and apply Biome 2.4.14 across the repo.

Typed events (address-space-base):
- Replace `declare class X extends EventEmitter` declarations with
  `interface X<T extends ListenerSignature<T>> extends ITypedEventEmitter<T>`
  for BaseNode, UAVariable, UAObject, UAMethod, UAObjectType,
  UAVariableType, UAReferenceType, UADataType, UAView.
- Add per-class event maps: BaseNodeEvents, UAVariableEvents,
  UAMethodEvents, etc., each extending the parent map.
- Introduce `ListenerSignature<L>` self-referential constraint and
  `ITypedEventEmitter<T>` so listeners are checked against the event
  map at compile time. `TypedEventEmitter` aliases Node's EventEmitter
  so listeners observe `this === <emitter>` (the previous
  composition-based wrapper broke that contract).
- Add ua_base_event_ex.ts (UABaseEventEx, UABaseEventEvents).

Tooling:
- Add biome.json (formatter + `useImportType` linter rule, lf line
  endings, 4-space indent, lineWidth 132, double quotes, no trailing
  commas) and @biomejs/biome 2.4.14 devDep.
- Set tsconfig.common.json `types: ["node"]`.

Mechanical biome cleanup across ~325 files in packages/* and tests:
- Convert type-only imports to `import type`.
- Use `node:` protocol for builtin imports (e.g. `node:events`).
- Reorganize/sort imports.
- Prefer `Number.isFinite` over global `isFinite`, `**` over
  `Math.pow`, prefix unused parameters with `_`.

18613 of 22121 branches covered (84.14%)

3162 of 3491 new or added lines in 174 files covered. (90.58%)

18 existing lines in 12 files now uncovered.

162931 of 176732 relevant lines covered (92.19%)

470530.53 hits per line

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

96.36
/packages/node-opcua-basic-types/source/integers.ts
1
/***
1✔
2
 * @module node-opcua-basic-types
1✔
3
 */
1✔
4
import { assert } from "node-opcua-assert";
1✔
5
import type { BinaryStream, OutputBinaryStream } from "node-opcua-binary-stream";
1✔
6
import { getRandomInt } from "./utils";
1✔
7

1✔
8
export function isValidUInt16(value: number): boolean {
72,975✔
9
    if (!Number.isFinite(value)) {
72,975✔
10
        return false;
1✔
11
    }
1✔
12
    return value >= 0 && value <= 0xffff;
72,975✔
13
}
72,975✔
14

1✔
15
export type UInt8 = number;
1✔
16
export type UInt16 = number;
1✔
17
export type UInt32 = number;
1✔
18
export type UInt64 = UInt32[];
1✔
19

1✔
20
export type Int8 = number;
1✔
21
export type Int16 = number;
1✔
22
export type Int32 = number;
1✔
23
export type Int64 = UInt32[];
1✔
24

1✔
25
export type Byte = UInt8;
1✔
26
export type SByte = Int8;
1✔
27

1✔
28
// ---------------------------------------
1✔
29

1✔
30
export function randomUInt16(): UInt16 {
566✔
31
    return getRandomInt(0, 0xffff) as UInt16;
566✔
32
}
566✔
33

1✔
34
export function encodeUInt16(value: UInt16, stream: OutputBinaryStream): void {
1,276,613✔
35
    stream.writeUInt16(value);
1,276,613✔
36
}
1,276,613✔
37

1✔
38
export function decodeUInt16(stream: BinaryStream, _value?: number): UInt16 {
635,467✔
39
    return stream.readUInt16() as UInt16;
635,467✔
40
}
635,467✔
41

1✔
42
export function isValidInt16(value: number): boolean {
1,245✔
43
    if (!Number.isFinite(value)) {
1,245✔
44
        return false;
1✔
45
    }
1✔
46
    return value >= -0x8000 && value <= 0x7fff;
1,245✔
47
}
1,245✔
48

1✔
49
export function randomInt16(): Int16 {
284✔
50
    return getRandomInt(-0x8000, 0x7fff);
284✔
51
}
284✔
52

1✔
53
export function encodeInt16(value: Int16, stream: OutputBinaryStream): void {
3,871✔
54
    assert(Number.isFinite(value));
3,871✔
55
    stream.writeInt16(value);
3,871✔
56
}
3,871✔
57

1✔
58
export function decodeInt16(stream: BinaryStream, _value?: number): Int16 {
1,029✔
59
    return stream.readInt16() as Int16;
1,029✔
60
}
1,029✔
61

1✔
62
export function isValidInt32(value: number): boolean {
197,012✔
63
    if (!Number.isFinite(value)) {
197,012✔
64
        return false;
1✔
65
    }
1✔
66
    return value >= -0x80000000 && value <= 0x7fffffff;
197,012✔
67
}
197,012✔
68

1✔
69
export function randomInt32(): Int32 {
284✔
70
    return getRandomInt(-0x80000000, 0x7fffffff) as Int32;
284✔
71
}
284✔
72

1✔
73
export function encodeInt32(value: Int32, stream: OutputBinaryStream): void {
110,254✔
74
    assert(Number.isFinite(value));
110,254✔
75
    stream.writeInteger(value);
110,254✔
76
}
110,254✔
77

1✔
78
export function decodeInt32(stream: BinaryStream, _value?: number): Int32 {
44,156✔
79
    return stream.readInteger() as Int32;
44,156✔
80
}
44,156✔
81

1✔
82
export function isValidUInt32(value: number): boolean {
1,986,774✔
83
    if (!Number.isFinite(value)) {
1,986,774✔
84
        return false;
1✔
85
    }
1✔
86
    return value >= 0 && value <= 0xffffffff;
1,986,774✔
87
}
1,986,774✔
88

1✔
89
export function randomUInt32(): UInt32 {
284✔
90
    return getRandomInt(0, 0xffffffff);
284✔
91
}
284✔
92

1✔
93
export function encodeUInt32(value: UInt32, stream: OutputBinaryStream): void {
10,547,220✔
94
    stream.writeUInt32(value);
10,547,220✔
95
}
10,547,220✔
96

1✔
97
export function decodeUInt32(stream: BinaryStream, _value?: number): UInt32 {
1,081,932✔
98
    return stream.readUInt32() as UInt32;
1,081,932✔
99
}
1,081,932✔
100

1✔
101
export function isValidInt8(value: number): boolean {
3,797✔
102
    if (!Number.isFinite(value)) {
3,797✔
103
        return false;
2✔
104
    }
2✔
105
    return value >= -0x80 && value <= 0x7f;
3,797✔
106
}
3,797✔
107

1✔
108
export function randomInt8(): Int8 {
286✔
109
    return getRandomInt(-0x7f, 0x7e);
286✔
110
}
286✔
111

1✔
112
export function encodeInt8(value: Int8, stream: OutputBinaryStream): void {
3,684✔
113
    assert(isValidInt8(value));
3,684✔
114
    stream.writeInt8(value);
3,684✔
115
}
3,684✔
116

1✔
117
export function decodeInt8(stream: BinaryStream, _value?: number): Int8 {
977✔
118
    return stream.readInt8();
977✔
119
}
977✔
120

1✔
121
export const isValidSByte = isValidInt8;
1✔
122
export const randomSByte = randomInt8;
1✔
123
export const encodeSByte = encodeInt8;
1✔
124
export const decodeSByte = decodeInt8;
1✔
125

1✔
126
export function isValidUInt8(value: number): boolean {
550,544✔
127
    if (!Number.isFinite(value)) {
550,544✔
128
        return false;
1✔
129
    }
1✔
130
    return value >= 0x00 && value <= 0xff;
550,544✔
131
}
550,544✔
132

1✔
133
export function randomUInt8(): UInt8 {
286✔
134
    return getRandomInt(0x00, 0xff);
286✔
135
}
286✔
136

1✔
137
export function encodeUInt8(value: UInt8, stream: OutputBinaryStream): void {
2,308,812✔
138
    stream.writeUInt8(value);
2,308,812✔
139
}
2,308,812✔
140

1✔
141
export function decodeUInt8(stream: BinaryStream, _value?: number): UInt8 {
1,098,743✔
142
    return stream.readUInt8();
1,098,743✔
143
}
1,098,743✔
144

1✔
145
export const isValidByte = isValidUInt8;
1✔
146
export const randomByte = randomUInt8;
1✔
147
export const encodeByte = encodeUInt8;
1✔
148
export const decodeByte = decodeUInt8;
1✔
149

1✔
150
export function isValidUInt64(value?: number | number[]): boolean {
11,903✔
151
    return Array.isArray(value) && value.length === 2;
11,903✔
152
}
11,903✔
153

1✔
154
export function randomUInt64(): UInt64 {
566✔
155
    return [getRandomInt(0, 0xffffffff), getRandomInt(0, 0xffffffff)];
566✔
156
}
566✔
157

1✔
158
export function encodeUInt64(value: UInt64 | number, stream: OutputBinaryStream): void {
2,067,121✔
159
    if (typeof value === "number") {
2,067,121✔
160
        const arr = coerceUInt64(value);
2✔
161
        stream.writeUInt32(arr[1]);
2✔
162
        stream.writeUInt32(arr[0]);
2✔
163
    } else {
2,067,121✔
164
        stream.writeUInt32((value as number[])[1]);
2,067,119✔
165
        stream.writeUInt32((value as number[])[0]);
2,067,119✔
166
    }
2,067,119✔
167
}
2,067,121✔
168

1✔
169
export function decodeUInt64(stream: BinaryStream, _value?: UInt64): UInt64 {
1,029,264✔
170
    const low = stream.readUInt32() as UInt32;
1,029,264✔
171
    const high = stream.readUInt32() as UInt32;
1,029,264✔
172
    return constructInt64(high, low);
1,029,264✔
173
}
1,029,264✔
174

1✔
175
export function constructInt64(high: UInt32, low: UInt32): Int64 {
2,539,735✔
176
    if (high === 0 && low < 0) {
2,539,735✔
177
        high = 0xffffffff;
75,428✔
178
        low = 0xffffffff + low + 1;
75,428✔
179
    }
75,428✔
180
    assert(low >= 0 && low <= 0xffffffff);
2,539,735✔
181
    assert(high >= 0 && high <= 0xffffffff);
2,539,735✔
182
    return [high, low];
2,539,735✔
183
}
2,539,735✔
184

1✔
185
export function coerceUInt64(value: number | UInt64 | Int32 | string | null): UInt64 {
7,958,834✔
186
    let high;
7,958,834✔
187
    let low;
7,958,834✔
188
    let v;
7,958,834✔
189
    if (value === null || value === undefined) {
7,958,834✔
190
        return [0, 0];
4✔
191
    }
4✔
192
    if (Array.isArray(value)) {
7,958,834✔
193
        assert(typeof value[0] === "number");
6,448,359✔
194
        assert(typeof value[1] === "number");
6,448,359✔
195
        return value;
6,448,359✔
196
    }
6,448,359✔
197
    if (typeof value === "string") {
7,958,834✔
198
        v = value.split(",");
43✔
199
        if (v.length === 1) {
43✔
200
            // was a single string, good news ! BigInt can be used with nodejs >=12
41✔
201
            let a = BigInt(value);
41✔
202
            if (a < BigInt(0)) {
41✔
203
                const mask = BigInt("0xFFFFFFFFFFFFFFFF");
6✔
204
                a = (mask + a + BigInt(1)) & mask;
6✔
205
            }
6✔
206
            high = Number(a >> BigInt(32));
41✔
207
            low = Number(a & BigInt(0xffffffff));
41✔
208
        } else {
43✔
209
            high = parseInt(v[0], 10);
2✔
210
            low = parseInt(v[1], 10);
2✔
211
        }
2✔
212
        return constructInt64(high, low);
43✔
213
    }
43✔
214
    if (value > 0xffffffff) {
7,958,834✔
215
        // beware : as per javascript, value is a double here !
3✔
216
        //          our conversion will suffer from some inaccuracy
3✔
217
        high = Math.floor(value / 0x100000000);
3✔
218
        low = value - high * 0x100000000;
3✔
219
        return constructInt64(high, low);
3✔
220
    }
3✔
221
    return constructInt64(0, value);
1,510,425✔
222
}
1,510,425✔
223

1✔
224
export function randomInt64(): Int64 {
566✔
225
    // High, low
566✔
226
    return [getRandomInt(0, 0xffffffff), getRandomInt(0, 0xffffffff)];
566✔
227
}
566✔
228

1✔
229
export const coerceInt64 = coerceUInt64;
1✔
230
export const isValidInt64 = isValidUInt64;
1✔
231
export const encodeInt64 = encodeUInt64;
1✔
232
export const decodeInt64 = decodeUInt64;
1✔
233

1✔
234
export function coerceInt8(value: number | string | null): Int8 {
17✔
235
    if (value === null || value === undefined) {
17✔
236
        return 0;
2✔
237
    }
2✔
238
    if (typeof value === "number") {
17✔
239
        return value;
14✔
240
    }
14✔
241
    return parseInt(value, 10);
1✔
242
}
1✔
243

1✔
244
export function coerceUInt8(value: number | string | null): UInt8 {
17✔
245
    if (value === null || value === undefined) {
17✔
246
        return 0;
2✔
247
    }
2✔
248
    if (typeof value === "number") {
17✔
249
        return value;
14✔
250
    }
14✔
251
    return parseInt(value, 10);
1✔
252
}
1✔
253

1✔
254
export function coerceByte(value: number | string | null): UInt8 {
627,064✔
255
    if (value === null || value === undefined) {
627,064✔
256
        return 0;
604,914✔
257
    }
604,914✔
258
    if (typeof value === "number") {
627,064✔
259
        return value;
21,438✔
260
    }
21,438✔
261
    return parseInt(value, 10);
712✔
262
}
712✔
263

1✔
264
export function coerceSByte(value: number | string | null): Int8 {
8✔
265
    if (value === null || value === undefined) {
8✔
266
        return 0;
2✔
267
    }
2✔
268
    if (typeof value === "number") {
8✔
269
        return value;
5✔
270
    }
5✔
271
    return parseInt(value, 10);
1✔
272
}
1✔
273

1✔
274
export function coerceUInt16(value: number | string | null): UInt16 {
1,393✔
275
    if (value === null || value === undefined) {
1,393✔
276
        return 0;
2✔
277
    }
2✔
278
    if (typeof value === "number") {
1,393✔
279
        return value;
1,390✔
280
    }
1,390✔
281
    return parseInt(value, 10);
1✔
282
}
1✔
283

1✔
284
export function coerceInt16(value: number | string | null): Int16 {
994✔
285
    if (value === null || value === undefined) {
994✔
286
        return 0;
2✔
287
    }
2✔
288
    if (typeof value === "number") {
994✔
289
        return value;
991✔
290
    }
991✔
291
    return parseInt(value, 10);
1✔
292
}
1✔
293

1✔
294
interface EnumItemLike {
1✔
295
    value: number;
1✔
296
}
1✔
297
export function coerceUInt32(value: null | string | number | EnumItemLike): UInt32 {
2,879,760✔
298
    if (value === null || value === undefined) {
2,879,760✔
299
        return 0;
2✔
300
    }
2✔
301
    if (value && typeof value === "object" && Object.hasOwn(value, "value")) {
2,879,760✔
302
        return coerceUInt32((value as EnumItemLike).value);
1✔
303
    }
1✔
304
    if (typeof value === "number") {
2,879,760✔
305
        return value;
2,879,755✔
306
    }
2,879,755✔
307
    return parseInt(value as string, 10);
2✔
308
}
2✔
309

1✔
310
export function coerceInt32(value: null | Int64 | UInt64 | number | string): Int32 {
2,188,800✔
311
    if (value === null || value === undefined) {
2,188,800✔
312
        return 0;
20,075✔
313
    }
20,075✔
314
    if (Array.isArray(value)) {
2,188,800✔
315
        // Int64 as a [high,low]
21✔
316
        return coerceInt64toInt32(value);
21✔
317
    }
21✔
318
    if (typeof value === "number") {
2,188,800✔
319
        return value;
1,708,442✔
320
    }
1,708,442✔
321
    return parseInt(value, 10);
460,262✔
322
}
460,262✔
323

1✔
324
const signMask = 1n << 31n;
1✔
325
const shiftHigh = 1n << 32n;
1✔
326
export function Int64ToBigInt(value: Int64): bigint {
1,863✔
327
    const h = BigInt(value[0]);
1,863✔
328
    const l = BigInt(value[1]);
1,863✔
329
    if ((h & signMask) === signMask) {
1,863✔
330
        const v = (h & ~signMask) * shiftHigh + l - 0x8000000000000000n;
218✔
331
        return v;
218✔
332
    } else {
1,863✔
333
        const v = h * shiftHigh + l;
1,645✔
334
        return v;
1,645✔
335
    }
1,645✔
336
}
1,863✔
337
export function UInt64ToBigInt(value: UInt64): bigint {
×
338
    const h = BigInt(value[0]);
×
339
    const l = BigInt(value[1]);
×
340
    const v = h * shiftHigh + l;
×
341
    return v;
×
342
}
×
343

1✔
344
export function coerceInt64toInt32(value: Int64 | Int32): Int32 {
2,059✔
345
    if (Array.isArray(value)) {
2,059✔
346
        const b = Int64ToBigInt(value);
1,863✔
347
        return Number(b);
1,863✔
348
    }
1,863✔
349
    return value;
196✔
350
}
196✔
351
export function coerceUInt64toInt32(value: UInt64 | UInt32): Int32 {
×
NEW
352
    if (Array.isArray(value)) {
×
353
        const b = UInt64ToBigInt(value);
×
354
        return Number(b);
×
355
    }
×
356
    return value;
×
357
}
×
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