• 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

96.67
/packages/node-opcua-numeric-range/source/numeric_range.ts
1
/**
2✔
2
 * @module node-opcua-numeric-range
2✔
3
 */
2✔
4
import { assert } from "node-opcua-assert";
2✔
5

2✔
6
import { decodeString, encodeString, UAString } from "node-opcua-basic-types";
2✔
7
import { BinaryStream, OutputBinaryStream } from "node-opcua-binary-stream";
2✔
8
import { registerBasicType } from "node-opcua-factory";
2✔
9
import { StatusCode, StatusCodes } from "node-opcua-status-code";
2✔
10

2✔
11
// OPC.UA Part 4 7.21 Numerical Range
2✔
12
// The syntax for the string contains one of the following two constructs. The first construct is the string
2✔
13
// representation of an individual integer. For example, '6' is   valid, but '6.0' and '3.2' are not. The
2✔
14
// minimum and maximum values that can be expressed are defined by the use of this parameter and
2✔
15
// not by this parameter type definition. The second construct is a range represented by two integers
2✔
16
// separated by the colon   (':') character. The first integer shall always have a lower value than the
2✔
17
// second. For example, '5:7' is valid, while '7:5' and '5:5' are not. The minimum and maximum values
2✔
18
// that can be expressed by these integers are defined by the use of this parameter , and not by this
2✔
19
// parameter type definition. No other characters, including white - space characters, are permitted.
2✔
20
// Multi- dimensional arrays can be indexed by specifying a range for each dimension separated by a ','.
2✔
21
//
2✔
22
// For example, a 2x2 block in a 4x4 matrix   could be selected with the range '1:2,0:1'. A single element
2✔
23
// in a multi - dimensional array can be selected by specifying a single number instead of a range.
2✔
24
// For example, '1,1' specifies selects the [1,1] element in a two dimensional array.
2✔
25
// Dimensions are specified in the order that they appear in the  ArrayDimensions Attribute.
2✔
26
// All dimensions shall be specified for a  NumericRange  to be valid.
2✔
27
//
2✔
28
// All indexes start with 0. The maximum value for any index is one less than the length of the
2✔
29
// dimension.
2✔
30

2✔
31
const NUMERIC_RANGE_EMPTY_STRING = "NumericRange:<Empty>";
2✔
32

2✔
33
// BNF of NumericRange
2✔
34
// The following BNF describes the syntax of the NumericRange parameter type.
2✔
35
// <numeric-range>    ::= <dimension> [',' <dimension>]
2✔
36
//     <dimension>    ::= <index> [':' <index>]
2✔
37
//         <index>    ::= <digit> [<digit>]
2✔
38
//         <digit>    ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' |9'
2✔
39
//
2✔
40
// tslint:disable:object-literal-shorthand
2✔
41
// tslint:disable:only-arrow-functions
2✔
42
export const schemaNumericRange = {
2✔
43
    name: "NumericRange",
2✔
44
    subType: "String",
2✔
45

2✔
46
    defaultValue: (): NumericRange => {
2✔
47
        return new NumericRange();
527,129✔
48
    },
2✔
49
    encode: encodeNumericRange,
2✔
50

2✔
51
    decode: decodeNumericRange,
2✔
52

2✔
53
    random: (): NumericRange => {
2✔
54
        function r() {
2✔
55
            return Math.ceil(Math.random() * 100);
4✔
56
        }
4✔
57

2✔
58
        const start = r();
2✔
59
        const end = start + r();
2✔
60
        return new NumericRange(start, end);
2✔
61
    },
2✔
62

2✔
63
    coerce: coerceNumericRange
2✔
64
};
2✔
65

2✔
66
registerBasicType(schemaNumericRange);
2✔
67

2✔
68
export enum NumericRangeType {
10✔
69
    Empty = 0,
10✔
70
    SingleValue = 1,
10✔
71
    ArrayRange = 2,
10✔
72
    MatrixRange = 3,
10✔
73
    InvalidRange = 4
10✔
74
}
10✔
75

2✔
76
// new Enum(["Empty", "SingleValue", "ArrayRange", "MatrixRange", "InvalidRange"]);
2✔
77

2✔
78
const regexNumericRange = /^[0-9:,]*$/;
2✔
79

2✔
80
function _valid_range(low: number, high: number): boolean {
426✔
81
    return !(low >= high || low < 0 || high < 0);
426✔
82
}
426✔
83

2✔
84
type NumericalRangeValueType = null | number | string | number[] | number[][];
2✔
85

2✔
86
export interface NumericalRangeSingleValue {
2✔
87
    type: NumericRangeType.SingleValue;
2✔
88
    value: number;
2✔
89
}
2✔
90

2✔
91
export interface NumericalRangeArrayRange {
2✔
92
    type: NumericRangeType.ArrayRange;
2✔
93
    value: number[];
2✔
94
}
2✔
95

2✔
96
export interface NumericalRangeMatrixRange {
2✔
97
    type: NumericRangeType.MatrixRange;
2✔
98
    value: number[][];
2✔
99
}
2✔
100

2✔
101
export interface NumericalRangeEmpty {
2✔
102
    type: NumericRangeType.Empty;
2✔
103
    value: null;
2✔
104
}
2✔
105

2✔
106
export interface NumericalRangeInvalid {
2✔
107
    type: NumericRangeType.InvalidRange;
2✔
108
    value: string;
2✔
109
}
2✔
110

2✔
111
export type NumericalRange0 =
2✔
112
    | NumericalRangeSingleValue
2✔
113
    | NumericalRangeArrayRange
2✔
114
    | NumericalRangeMatrixRange
2✔
115
    | NumericalRangeEmpty
2✔
116
    | NumericalRangeInvalid;
2✔
117

2✔
118
export interface NumericalRange1 {
2✔
119
    type: NumericRangeType;
2✔
120
    value: NumericalRangeValueType;
2✔
121
}
2✔
122

2✔
123
function construct_numeric_range_bit_from_string(str: string): NumericalRange0 {
592✔
124
    const values = str.split(":");
592✔
125

592✔
126
    if (values.length === 1) {
592✔
127
        return {
214✔
128
            type: NumericRangeType.SingleValue,
214✔
129
            value: parseInt(values[0], 10)
214✔
130
        };
214✔
131
    } else if (values.length === 2) {
592✔
132
        const array = values.map((a) => parseInt(a, 10));
376✔
133

376✔
134
        if (!_valid_range(array[0], array[1])) {
376✔
135
            return {
20✔
136
                type: NumericRangeType.InvalidRange,
20✔
137
                value: str
20✔
138
            };
20✔
139
        }
20✔
140
        return {
356✔
141
            type: NumericRangeType.ArrayRange,
356✔
142
            value: array
356✔
143
        };
356✔
144
    } else {
378✔
145
        return {
2✔
146
            type: NumericRangeType.InvalidRange,
2✔
147
            value: str
2✔
148
        };
2✔
149
    }
2✔
150
}
592✔
151

2✔
152
function _normalize(e: NumericalRange1): number | number[] {
208✔
153
    if (e.type === NumericRangeType.SingleValue) {
208✔
154
        const ee = e as NumericalRangeSingleValue;
134✔
155
        return [ee.value, ee.value];
134✔
156
    }
134✔
157
    return e.value as number;
74✔
158
}
74✔
159

2✔
160
function construct_numeric_range_from_string(str: string): NumericalRange0 {
548✔
161
    if (!regexNumericRange.test(str)) {
548✔
162
        return {
64✔
163
            type: NumericRangeType.InvalidRange,
64✔
164
            value: str
64✔
165
        };
64✔
166
    }
64✔
167
    /* detect multi dim range*/
484✔
168
    const values = str.split(",");
484✔
169

484✔
170
    if (values.length === 1) {
548✔
171
        return construct_numeric_range_bit_from_string(values[0]);
372✔
172
    } else if (values.length === 2) {
548✔
173
        const elements = values.map(construct_numeric_range_bit_from_string);
110✔
174
        let rowRange: any = elements[0];
110✔
175
        let colRange: any = elements[1];
110✔
176
        if (rowRange.type === NumericRangeType.InvalidRange || colRange.type === NumericRangeType.InvalidRange) {
110✔
177
            return { type: NumericRangeType.InvalidRange, value: str };
6✔
178
        }
6✔
179
        rowRange = _normalize(rowRange);
104✔
180
        colRange = _normalize(colRange);
104✔
181
        return {
104✔
182
            type: NumericRangeType.MatrixRange,
104✔
183
            value: [rowRange, colRange]
104✔
184
        };
104✔
185
    } else {
112✔
186
        // not supported yet
2✔
187
        return { type: NumericRangeType.InvalidRange, value: str };
2✔
188
    }
2✔
189
}
548✔
190

2✔
191
function construct_from_string(value: string): NumericalRange0 {
548✔
192
    return construct_numeric_range_from_string(value);
548✔
193
}
548✔
194

2✔
195
function _set_single_value(value: number | null): NumericalRange0 {
32✔
196
    if (value === null || value < 0 || !isFinite(value)) {
32✔
197
        return {
2✔
198
            type: NumericRangeType.InvalidRange,
2✔
199
            value: "" + value?.toString()
2✔
200
        };
2✔
201
    } else {
32✔
202
        return {
30✔
203
            type: NumericRangeType.SingleValue,
30✔
204
            value: value
30✔
205
        };
30✔
206
    }
30✔
207
}
32✔
208

2✔
209
function _check_range(numericalRange: NumericalRange0) {
50✔
210
    switch (numericalRange.type) {
50✔
211
        case NumericRangeType.ArrayRange:
50✔
212
            return _valid_range(numericalRange.value[0], numericalRange.value[1]);
50✔
213
    }
50✔
UNCOV
214
    // c8 ignore next
×
UNCOV
215
    throw new Error("unsupported case");
×
UNCOV
216
}
×
217

2✔
218
function _set_range_value(low: number, high: number): NumericalRangeSingleValue | NumericalRangeArrayRange | NumericalRangeInvalid {
62✔
219
    if (low === high) {
62✔
220
        return {
12✔
221
            type: NumericRangeType.SingleValue,
12✔
222
            value: low
12✔
223
        };
12✔
224
    }
12✔
225
    const numericalRange: NumericalRangeArrayRange = {
50✔
226
        type: NumericRangeType.ArrayRange,
50✔
227
        value: [low, high]
50✔
228
    };
50✔
229
    if (!_check_range(numericalRange as NumericalRangeArrayRange)) {
62✔
230
        return {
6✔
231
            type: NumericRangeType.InvalidRange,
6✔
232
            value: ""
6✔
233
        };
6✔
234
    }
6✔
235
    return numericalRange;
44✔
236
}
44✔
237

2✔
238
function construct_from_values(value: number, secondValue?: number): NumericalRange0 {
76✔
239
    if (secondValue === undefined) {
76✔
240
        return _set_single_value(value);
32✔
241
    } else {
76✔
242
        if (!isFinite(secondValue)) {
44!
243
            throw new Error(" invalid second argument, expecting a number");
×
UNCOV
244
        }
×
245
        return _set_range_value(value, secondValue);
44✔
246
    }
44✔
247
}
76✔
248

2✔
249
function _construct_from_array(value: number[], value2?: any): NumericalRange0 {
18✔
250
    assert(value.length === 2);
18✔
251

18✔
252
    // c8 ignore next
18✔
253
    if (!isFinite(value[0]) || !isFinite(value[1])) {
18!
UNCOV
254
        return { type: NumericRangeType.InvalidRange, value: "" + value };
×
UNCOV
255
    }
×
256
    let range1 = _set_range_value(value[0], value[1]);
18✔
257
    if (!value2) {
18✔
258
        return range1;
12✔
259
    }
12✔
260
    // we have a matrix
6✔
261
    const nr2 = new NumericRange(value2);
6✔
262
    // c8 ignore next
6✔
263
    if (
6✔
264
        nr2.type === NumericRangeType.InvalidRange ||
6✔
265
        nr2.type === NumericRangeType.MatrixRange ||
18✔
266
        nr2.type === NumericRangeType.Empty
6✔
267
    ) {
18!
UNCOV
268
        return { type: NumericRangeType.InvalidRange, value: "" + value };
×
UNCOV
269
    }
×
270
    if (range1.type === NumericRangeType.SingleValue) {
18✔
271
        range1 = {
4✔
272
            type: NumericRangeType.ArrayRange,
4✔
273
            value: [range1.value, range1.value]
4✔
274
        };
4✔
275
    }
4✔
276
    if (nr2.type === NumericRangeType.SingleValue) {
18✔
277
        nr2.type = NumericRangeType.ArrayRange;
4✔
278
        nr2.value = [nr2.value as number, nr2.value as number];
4✔
279
    }
4✔
280

6✔
281
    // c8 ignore next
6✔
282
    return {
6✔
283
        type: NumericRangeType.MatrixRange,
6✔
284
        value: [range1.value as number[], nr2.value as number[]]
6✔
285
    };
6✔
286
}
6✔
287

2✔
288
export class NumericRange implements NumericalRange1 {
2✔
289
    public static coerce = coerceNumericRange;
2✔
290

2✔
291
    public static schema = schemaNumericRange;
2✔
292
    // tslint:disable:variable-name
2✔
293
    public static NumericRangeType = NumericRangeType;
2✔
294

2✔
295
    public static readonly empty = new NumericRange() as NumericalRange0;
2✔
296

2✔
297
    public static overlap(nr1?: NumericalRange0, nr2?: NumericalRange0): boolean {
2✔
298
        nr1 = nr1 || NumericRange.empty;
190!
299
        nr2 = nr2 || NumericRange.empty;
190!
300

190✔
301
        if (NumericRangeType.Empty === nr1.type || NumericRangeType.Empty === nr2.type) {
190✔
302
            return true;
166✔
303
        }
166✔
304
        if (NumericRangeType.SingleValue === nr1.type && NumericRangeType.SingleValue === nr2.type) {
190✔
305
            return nr1.value === nr2.value;
4✔
306
        }
4✔
307
        if (NumericRangeType.ArrayRange === nr1.type && NumericRangeType.ArrayRange === nr2.type) {
190✔
308
            // +-----+        +------+     +---+       +------+
20✔
309
            //     +----+       +---+    +--------+  +---+
20✔
310
            const l1 = nr1.value[0];
20✔
311
            const h1 = nr1.value[1];
20✔
312
            const l2 = nr2.value[0];
20✔
313
            const h2 = nr2.value[1];
20✔
314
            return _overlap(l1, h1, l2, h2);
20✔
315
        }
20✔
UNCOV
316
        // c8 ignore next
×
UNCOV
317
        assert(false, "NumericalRange#overlap : case not implemented yet "); // TODO
×
UNCOV
318
        // c8 ignore next
×
UNCOV
319
        return false;
×
UNCOV
320
    }
×
321

2✔
322
    public type: NumericRangeType;
2✔
323
    public value: NumericalRangeValueType;
2✔
324

2✔
325
    constructor();
2✔
326
    // tslint:disable-next-line: unified-signatures
2✔
327
    constructor(value: string | null);
2✔
328
    // tslint:disable-next-line: unified-signatures
2✔
329
    constructor(value: number, secondValue?: number);
2✔
330
    // tslint:disable-next-line: unified-signatures
2✔
331
    constructor(value: number[]);
2✔
332
    // tslint:disable-next-line: unified-signatures
2✔
333
    constructor(value: number[], secondValue: number[]);
2✔
334
    constructor(value?: null | string | number | number[], secondValue?: number | number[]) {
2✔
335
        this.type = NumericRangeType.InvalidRange;
1,579,985✔
336
        this.value = null;
1,579,985✔
337

1,579,985✔
338
        assert(!value || !(value instanceof NumericRange), "use coerce to create a NumericRange");
1,579,985✔
339
        assert(!secondValue || typeof secondValue === "number" || Array.isArray(secondValue));
1,579,985✔
340
        if (typeof value === "string") {
1,579,985✔
341
            const a = construct_from_string(value as string);
548✔
342
            this.type = a.type;
548✔
343
            this.value = a.value;
548✔
344
        } else if (
1,579,985✔
345
            typeof value === "number" &&
1,579,433✔
346
            isFinite(value) &&
1,579,433✔
347
            (secondValue === undefined || (typeof secondValue === "number" && isFinite(secondValue)))
76✔
348
        ) {
1,579,433✔
349
            const a = construct_from_values(value, secondValue);
76✔
350
            this.type = a.type;
76✔
351
            this.value = a.value;
76✔
352
        } else if (Array.isArray(value)) {
1,579,433✔
353
            const a = _construct_from_array(value, secondValue);
18✔
354
            this.type = a.type;
18✔
355
            this.value = a.value;
18✔
356
        } else {
1,579,357✔
357
            this.value = "<invalid>";
1,579,339✔
358
            this.type = NumericRangeType.Empty;
1,579,339✔
359
        }
1,579,339✔
360

1,579,985✔
361
        // xx assert((this.type !== NumericRangeType.ArrayRange) || Array.isArray(this.value));
1,579,985✔
362
    }
1,579,985✔
363

2✔
364
    public isValid(): boolean {
2✔
365
        if (this.type === NumericRangeType.ArrayRange) {
169,611✔
366
            const value = this.value as number[];
98✔
367
            if (value[0] < 0 || value[1] < 0) {
98✔
368
                return false;
2✔
369
            }
2✔
370
        }
98✔
371
        if (this.type === NumericRangeType.SingleValue) {
169,611✔
372
            const value = this.value as number;
16✔
373
            // c8 ignore next
16✔
374
            if (value < 0) {
16!
UNCOV
375
                return false;
×
UNCOV
376
            }
×
377
        }
16✔
378
        return this.type !== NumericRangeType.InvalidRange;
169,609✔
379
    }
169,609✔
380

2✔
381
    public isEmpty(): boolean {
2✔
382
        return this.type === NumericRangeType.Empty;
649,430✔
383
    }
649,430✔
384

2✔
385
    public isDefined(): boolean {
2✔
386
        return this.type !== NumericRangeType.Empty && this.type !== NumericRangeType.InvalidRange;
361,418✔
387
    }
361,418✔
388

2✔
389
    public toString(): string {
2✔
390
        function array_range_to_string(values: number[]): string {
268✔
391
            assert(Array.isArray(values));
184✔
392
            if (values.length === 2 && values[0] === values[1]) {
184✔
393
                return values[0].toString();
48✔
394
            }
48✔
395
            return values.map((value) => value.toString(10)).join(":");
136✔
396
        }
136✔
397

268✔
398
        function matrix_range_to_string(values: any) {
268✔
399
            return values
58✔
400
                .map((value: any) => {
58✔
401
                    return Array.isArray(value) ? array_range_to_string(value) : value.toString(10);
116!
402
                })
58✔
403
                .join(",");
58✔
404
        }
58✔
405

268✔
406
        switch (this.type) {
268✔
407
            case NumericRangeType.SingleValue:
268✔
408
                return (this.value as any).toString(10);
26✔
409

268✔
410
            case NumericRangeType.ArrayRange:
268✔
411
                return array_range_to_string(this.value as number[]);
68✔
412

268✔
413
            case NumericRangeType.Empty:
268✔
414
                return NUMERIC_RANGE_EMPTY_STRING;
80✔
415

268✔
416
            case NumericRangeType.MatrixRange:
268✔
417
                return matrix_range_to_string(this.value);
58✔
418

268✔
419
            default:
268✔
420
                assert(this.type === NumericRangeType.InvalidRange);
36✔
421
                return "NumericRange:<Invalid>";
36✔
422
        }
268✔
423
    }
268✔
424

2✔
425
    public toJSON(): string {
2✔
426
        return this.toString();
72✔
427
    }
72✔
428

2✔
429
    public toEncodeableString(): UAString {
2✔
430
        switch (this.type) {
1,056,386✔
431
            case NumericRangeType.SingleValue:
1,056,386✔
432
            case NumericRangeType.ArrayRange:
1,056,386✔
433
            case NumericRangeType.MatrixRange:
1,056,386✔
434
                return this.toString();
98✔
435
            case NumericRangeType.InvalidRange:
1,056,386✔
436
                // c8 ignore next
40✔
437
                if (!(typeof this.value === "string")) {
40!
UNCOV
438
                    throw new Error("Internal Error");
×
UNCOV
439
                }
×
440
                return this.value; // value contains the original strings which was detected invalid
1,056,386✔
441
            default:
1,056,386✔
442
                return null;
1,056,248✔
443
        }
1,056,386✔
444
    }
1,056,386✔
445

2✔
446
    /**
2✔
447

2✔
448
     * @param array   flat array containing values or string
2✔
449
     * @param dimensions: of the matrix if data is a matrix
2✔
450
     * @return {*}
2✔
451
     */
2✔
452
    public extract_values<U, T extends ArrayLike<U>>(array: T, dimensions?: number[] | null): ExtractResult<T> {
2✔
453
        const self = this as NumericalRange0;
140,085✔
454

140,085✔
455
        if (!array) {
140,085✔
456
            return {
25,064✔
457
                array,
25,064✔
458
                statusCode: this.type === NumericRangeType.Empty ? StatusCodes.Good : StatusCodes.BadIndexRangeNoData
25,064✔
459
            };
25,064✔
460
        }
25,064✔
461

115,021✔
462
        let index;
115,021✔
463
        let low_index;
115,021✔
464
        let high_index;
115,021✔
465
        let rowRange;
115,021✔
466
        let colRange;
115,021✔
467
        switch (self.type) {
115,021✔
468
            case NumericRangeType.Empty:
140,085✔
469
                return extract_empty(array, dimensions);
114,383✔
470

140,085✔
471
            case NumericRangeType.SingleValue:
140,085✔
472
                index = self.value;
32✔
473
                return extract_single_value(array, index);
32✔
474

140,085✔
475
            case NumericRangeType.ArrayRange:
140,085✔
476
                low_index = self.value[0];
140✔
477
                high_index = self.value[1];
140✔
478
                return extract_array_range(array, low_index, high_index);
140✔
479

140,085✔
480
            case NumericRangeType.MatrixRange:
140,085✔
481
                rowRange = self.value[0];
446✔
482
                colRange = self.value[1];
446✔
483
                return extract_matrix_range(array, rowRange, colRange, dimensions);
446✔
484

140,085✔
485
            default:
140,085✔
486
                return { statusCode: StatusCodes.BadIndexRangeInvalid };
20✔
487
        }
140,085✔
488
    }
140,085✔
489

2✔
490
    public set_values_matrix(
2✔
491
        sourceToAlter: { matrix: Buffer | []; dimensions: number[] },
12✔
492
        newMatrix: Buffer | []
12✔
493
    ): { matrix: Buffer | []; statusCode: StatusCode } {
12✔
494
        const { matrix, dimensions } = sourceToAlter;
12✔
495
        const self = this as NumericalRange0;
12✔
496
        assert(dimensions, "expecting valid dimensions here");
12✔
497
        if (self.type !== NumericRangeType.MatrixRange) {
12!
UNCOV
498
            // c8 ignore next
×
UNCOV
499
            return { matrix, statusCode: StatusCodes.BadTypeMismatch };
×
UNCOV
500
        }
×
501

12✔
502
        assert(dimensions.length === 2);
12✔
503
        const nbRows = dimensions[0];
12✔
504
        const nbCols = dimensions[1];
12✔
505
        assert(sourceToAlter.matrix.length === nbRows * nbCols);
12✔
506
        const [rowStart, rowEnd] = self.value[0];
12✔
507
        const [colStart, colEnd] = self.value[1];
12✔
508

12✔
509
        const nbRowInNew = rowEnd - rowStart + 1;
12✔
510
        const nbColInNew = colEnd - colStart + 1;
12✔
511
        if (nbRowInNew * nbColInNew !== newMatrix.length) {
12!
512
            return { matrix, statusCode: StatusCodes.BadTypeMismatch };
×
UNCOV
513
        }
×
514
        // check if the sub-matrix is in th range of the initial matrix
12✔
515
        if (rowEnd >= nbRows || colEnd >= nbCols) {
12✔
516
            // debugLog("out of band range => ", { rowEnd, nbRows, colEnd, nbCols });
2✔
517
            return { matrix, statusCode: StatusCodes.BadTypeMismatch };
2✔
518
        }
2✔
519
        for (let row = rowStart; row <= rowEnd; row++) {
12✔
520
            const ri = row - rowStart;
16✔
521
            for (let col = colStart; col <= colEnd; col++) {
16✔
522
                const ci = col - colStart;
40✔
523
                matrix[row * nbCols + col] = newMatrix[ri * nbColInNew + ci];
40✔
524
            }
40✔
525
        }
16✔
526
        return {
10✔
527
            matrix,
10✔
528
            statusCode: StatusCodes.Good
10✔
529
        };
10✔
530
    }
10✔
531
    public set_values(arrayToAlter: Buffer | [], newValues: Buffer | []): { array: Buffer | [] | null; statusCode: StatusCode } {
2✔
532
        assert_array_or_buffer(arrayToAlter);
240✔
533
        assert_array_or_buffer(newValues);
240✔
534

240✔
535
        const self = this as NumericalRange0;
240✔
536

240✔
537
        let low_index;
240✔
538
        let high_index;
240✔
539
        switch (self.type) {
240✔
540
            case NumericRangeType.Empty:
240✔
541
                low_index = 0;
24✔
542
                high_index = arrayToAlter.length - 1;
24✔
543
                break;
24✔
544
            case NumericRangeType.SingleValue:
240✔
545
                low_index = self.value;
54✔
546
                high_index = self.value;
54✔
547
                break;
54✔
548
            case NumericRangeType.ArrayRange:
240✔
549
                low_index = self.value[0];
134✔
550
                high_index = self.value[1];
134✔
551
                break;
134✔
552
            case NumericRangeType.MatrixRange:
240✔
553
                // for the time being MatrixRange is not supported
20✔
554
                return { array: arrayToAlter, statusCode: StatusCodes.BadIndexRangeNoData };
20✔
555
            default:
240✔
556
                return { array: null, statusCode: StatusCodes.BadIndexRangeInvalid };
8✔
557
        }
240✔
558

212✔
559
        if (high_index >= arrayToAlter.length || low_index >= arrayToAlter.length) {
240✔
560
            return { array: null, statusCode: StatusCodes.BadIndexRangeNoData };
4✔
561
        }
4✔
562
        if (this.type !== NumericRangeType.Empty && newValues.length !== high_index - low_index + 1) {
240!
563
            return { array: null, statusCode: StatusCodes.BadIndexRangeInvalid };
×
UNCOV
564
        }
×
565
        const insertInPlace = Array.isArray(arrayToAlter)
208✔
566
            ? insertInPlaceStandardArray
240✔
567
            : arrayToAlter instanceof Buffer
240✔
568
            ? insertInPlaceBuffer
176✔
569
            : insertInPlaceTypedArray;
240✔
570
        return {
240✔
571
            array: insertInPlace(arrayToAlter, low_index, high_index, newValues),
240✔
572
            statusCode: StatusCodes.Good
240✔
573
        };
240✔
574
    }
240✔
575
}
2✔
576

2✔
577
function slice<U, T extends ArrayLike<U>>(arr: T, start: number, end: number): T {
114,541✔
578
    if (start === 0 && end === arr.length) {
114,541✔
579
        return arr;
114,385✔
580
    }
114,385✔
581

156✔
582
    let res;
156✔
583
    if ((arr as any).buffer instanceof ArrayBuffer) {
114,541✔
584
        res = (arr as any).subarray(start, end);
114✔
585
    } else if (arr instanceof Buffer) {
114,541!
586
        res = arr.subarray(start, end);
×
587
    } else {
42✔
588
        assert(typeof (arr as any).slice === "function");
42✔
589
        assert(arr instanceof Buffer || arr instanceof Array || typeof arr === "string");
42✔
590
        res = (arr as any).slice(start, end);
42✔
591
    }
42✔
592
    if (res instanceof Uint8Array && arr instanceof Buffer) {
114,541✔
593
        // note in io-js 3.00 onward standard Buffer are implemented differently and
16✔
594
        // provides a buffer member and a subarray method, in fact in io-js 3.0
16✔
595
        // it seems that Buffer acts as a Uint8Array. in this very special case
16✔
596
        // we need to make sure that we end up with a Buffer object and not a Uint8Array.
16✔
597
        res = Buffer.from(res);
16✔
598
    }
16✔
599
    return res;
156✔
600
}
156✔
601

2✔
602
export interface ExtractResult<T> {
2✔
603
    array?: T | null;
2✔
604
    statusCode: StatusCode;
2✔
605
    dimensions?: number[];
2✔
606
}
2✔
607

2✔
608
function extract_empty<U, T extends ArrayLike<U>>(array: T, dimensions: any): ExtractResult<T> {
114,383✔
609
    return {
114,383✔
610
        array: slice(array, 0, array.length),
114,383✔
611
        dimensions,
114,383✔
612
        statusCode: StatusCodes.Good
114,383✔
613
    };
114,383✔
614
}
114,383✔
615

2✔
616
function extract_single_value<U, T extends ArrayLike<U>>(array: T, index: number): ExtractResult<T> {
32✔
617
    if (index >= array.length) {
32✔
618
        if (typeof array === "string") {
4✔
619
            return { array: "" as any as T, statusCode: StatusCodes.BadIndexRangeNoData };
2✔
620
        }
2✔
621
        return { array: null as any as T, statusCode: StatusCodes.BadIndexRangeNoData };
2✔
622
    }
2✔
623
    return {
28✔
624
        array: slice(array, index, index + 1),
28✔
625
        statusCode: StatusCodes.Good
28✔
626
    };
28✔
627
}
28✔
628

2✔
629
function extract_array_range<U, T extends ArrayLike<U>>(array: T, low_index: number, high_index: number): ExtractResult<T> {
162✔
630
    assert(isFinite(low_index) && isFinite(high_index));
162✔
631
    assert(low_index >= 0);
162✔
632
    assert(low_index <= high_index);
162✔
633
    if (low_index >= array.length) {
162✔
634
        if (typeof array === "string") {
32✔
635
            return { array: "" as any as T, statusCode: StatusCodes.BadIndexRangeNoData };
4✔
636
        }
4✔
637
        return { array: null as any as T, statusCode: StatusCodes.BadIndexRangeNoData };
28✔
638
    }
28✔
639
    // clamp high index
130✔
640
    high_index = Math.min(high_index, array.length - 1);
130✔
641

130✔
642
    return {
130✔
643
        array: slice(array, low_index, high_index + 1),
130✔
644
        statusCode: StatusCodes.Good
130✔
645
    };
130✔
646
}
130✔
647

2✔
648
function isArrayLike(value: any): boolean {
444✔
649
    return typeof value.length === "number" || Object.prototype.hasOwnProperty.call(value, "length");
444✔
650
}
444✔
651

2✔
652
function extract_matrix_range<U, T extends ArrayLike<U>>(
446✔
653
    array: T,
446✔
654
    rowRange: number[],
446✔
655
    colRange: number[],
446✔
656
    dimension?: number[] | null
446✔
657
): ExtractResult<T> {
446✔
658
    assert(Array.isArray(rowRange) && Array.isArray(colRange));
446✔
659

446✔
660
    if (array.length === 0) {
446✔
661
        return {
2✔
662
            array: null,
2✔
663
            statusCode: StatusCodes.BadIndexRangeNoData
2✔
664
        };
2✔
665
    }
2✔
666
    if (isArrayLike((array as any)[0]) && !dimension) {
446✔
667
        // like extracting data from a one dimensional array of strings or byteStrings...
10✔
668
        const result = extract_array_range(array, rowRange[0], rowRange[1]);
10✔
669
        for (let i = 0; i < result.array!.length; i++) {
10✔
670
            const e = (result.array! as any)[i];
12✔
671
            (result.array as any)[i] = extract_array_range(e, colRange[0], colRange[1]).array;
12✔
672
        }
12✔
673
        return result;
8✔
674
    }
8✔
675
    if (!dimension) {
446✔
676
        return {
420✔
677
            array: null,
420✔
678
            statusCode: StatusCodes.BadIndexRangeNoData
420✔
679
        };
420✔
680
    }
420✔
681

14✔
682
    assert(dimension, "expecting dimension to know the shape of the matrix represented by the flat array");
14✔
683

14✔
684
    //
14✔
685
    const rowLow = rowRange[0];
14✔
686
    const rowHigh = rowRange[1];
14✔
687
    const colLow = colRange[0];
14✔
688
    const colHigh = colRange[1];
14✔
689

14✔
690
    const nbRow = dimension[0];
14✔
691
    const nbCol = dimension[1];
14✔
692

14✔
693
    const nbRowDest = rowHigh - rowLow + 1;
14✔
694
    const nbColDest = colHigh - colLow + 1;
14✔
695

14✔
696
    // construct an array of the same type with the appropriate length to
14✔
697
    // store the extracted matrix.
14✔
698
    const tmp = new (array as any).constructor(nbColDest * nbRowDest);
14✔
699

14✔
700
    let row;
14✔
701
    let col;
14✔
702
    let r;
14✔
703
    let c;
14✔
704
    r = 0;
14✔
705
    for (row = rowLow; row <= rowHigh; row++) {
446✔
706
        c = 0;
20✔
707
        for (col = colLow; col <= colHigh; col++) {
20✔
708
            const srcIndex = row * nbCol + col;
34✔
709
            const destIndex = r * nbColDest + c;
34✔
710
            tmp[destIndex] = (array as any)[srcIndex];
34✔
711
            c++;
34✔
712
        }
34✔
713
        r += 1;
20✔
714
    }
20✔
715
    return {
14✔
716
        array: tmp,
14✔
717
        dimensions: [nbRowDest, nbColDest],
14✔
718
        statusCode: StatusCodes.Good
14✔
719
    };
14✔
720
}
14✔
721

2✔
722
function assert_array_or_buffer(array: any) {
480✔
723
    assert(Array.isArray(array) || array.buffer instanceof ArrayBuffer || array instanceof Buffer);
480!
724
}
480✔
725

2✔
726
function insertInPlaceStandardArray(arrayToAlter: any, low: number, high: number, newValues: any): any {
32✔
727
    const args = [low, high - low + 1].concat(newValues);
32✔
728
    arrayToAlter.splice(...args);
32✔
729
    return arrayToAlter;
32✔
730
}
32✔
731

2✔
732
function insertInPlaceTypedArray(arrayToAlter: any, low: number, high: number, newValues: any): any {
144✔
733
    if (low === 0 && high === arrayToAlter.length - 1) {
144✔
734
        return new arrayToAlter.constructor(newValues);
32✔
735
    }
32✔
736
    assert(newValues.length === high - low + 1);
112✔
737
    arrayToAlter.subarray(low, high + 1).set(newValues);
112✔
738
    return arrayToAlter;
112✔
739
}
112✔
740

2✔
741
function insertInPlaceBuffer(bufferToAlter: Buffer | [], low: number, high: number, newValues: any): Buffer {
32✔
742
    // insertInPlaceBuffer with buffer is not really possible as existing Buffer cannot be resized
32✔
743
    if (!(bufferToAlter instanceof Buffer)) throw new Error("expecting a buffer");
32!
744
    if (low === 0 && high === bufferToAlter.length - 1) {
32✔
745
        bufferToAlter = Buffer.from(newValues);
8✔
746
        return bufferToAlter;
8✔
747
    }
8✔
748
    assert(newValues.length === high - low + 1);
24✔
749
    for (let i = 0; i < newValues.length; i++) {
32✔
750
        bufferToAlter[i + low] = newValues[i];
52✔
751
    }
52✔
752
    return bufferToAlter;
24✔
753
}
24✔
754

2✔
755
function _overlap(l1: number, h1: number, l2: number, h2: number): boolean {
20✔
756
    return Math.max(l1, l2) <= Math.min(h1, h2);
20✔
757
}
20✔
758

2✔
759
export function encodeNumericRange(numericRange: NumericRange, stream: OutputBinaryStream): void {
1,056,358✔
760
    assert(numericRange instanceof NumericRange);
1,056,358✔
761
    encodeString(numericRange.toEncodeableString(), stream);
1,056,358✔
762
}
1,056,358✔
763

2✔
764
export function decodeNumericRange(stream: BinaryStream, _value?: NumericRange): NumericRange {
526,013✔
765
    const str = decodeString(stream)!;
526,013✔
766
    return new NumericRange(str);
526,013✔
767
}
526,013✔
768

2✔
769
function coerceNumericRange(value: any | string | NumericRange | null | number[]): NumericRange {
569,105✔
770
    if (value instanceof NumericRange) {
569,105✔
771
        return value;
568,989✔
772
    }
568,989✔
773
    if (value === null || value === undefined) {
569,105✔
774
        return new NumericRange();
48✔
775
    }
48✔
776
    if (value === NUMERIC_RANGE_EMPTY_STRING) {
568,761✔
777
        return new NumericRange();
2✔
778
    }
2✔
779
    assert(typeof value === "string" || Array.isArray(value));
569,105!
780
    return new NumericRange(value);
569,105✔
781
}
569,105✔
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