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

RobotWebTools / rclnodejs / 18931458458

30 Oct 2025 06:01AM UTC coverage: 81.767% (-1.4%) from 83.209%
18931458458

push

github

minggangw
Pump to 1.6.0 (#1316)

858 of 1164 branches covered (73.71%)

Branch coverage included in aggregate %.

2057 of 2401 relevant lines covered (85.67%)

466.37 hits per line

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

72.7
/lib/parameter.js
1
// Copyright (c) 2020 Wayne Parrott. All rights reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
// Note: parameter api and function based on
16
// https://design.ros2.org/articles/ros_parameters.html
17
// https://github.com/ros2/rcl and
18
// https://github.com/ros2/rclpy
19

20
'use strict';
21

22
const { isClose } = require('./utils.js');
26✔
23

24
/**
25
 * The plus/minus tolerance for determining number equivalence.
26
 * @constant {number}
27
 *
28
 *  @see [FloatingPointRange]{@link FloatingPointRange}
29
 *  @see [IntegerRange]{@link IntegerRange}
30
 */
31
const DEFAULT_NUMERIC_RANGE_TOLERANCE = 1e-6;
26✔
32

33
const PARAMETER_SEPARATOR = '.';
26✔
34
const PARAMETER_BYTE = 10;
26✔
35

36
/**
37
 * Enum for ParameterType
38
 * @readonly
39
 * @enum {number}
40
 */
41
const ParameterType = {
26✔
42
  /** @member {number} */
43
  PARAMETER_NOT_SET: 0,
44
  /** @member {number} */
45
  PARAMETER_BOOL: 1,
46
  /** @member {number} */
47
  PARAMETER_INTEGER: 2,
48
  /** @member {number} */
49
  PARAMETER_DOUBLE: 3,
50
  /** @member {number} */
51
  PARAMETER_STRING: 4,
52
  /** @member {number} */
53
  PARAMETER_BYTE_ARRAY: 5,
54
  /** @member {number} */
55
  PARAMETER_BOOL_ARRAY: 6,
56
  /** @member {number} */
57
  PARAMETER_INTEGER_ARRAY: 7,
58
  /** @member {number} */
59
  PARAMETER_DOUBLE_ARRAY: 8,
60
  /** @member {number} */
61
  PARAMETER_STRING_ARRAY: 9,
62
};
63

64
/**
65
 * A node parameter.
66
 * @class
67
 */
68
class Parameter {
69
  /**
70
   * Create a Parameter instance from an rlc_interfaces/msg/Parameter message.
71
   * @constructs
72
   * @param {rcl_interfaces/msg/Parameter} parameterMsg - The message to convert to a parameter.
73
   * @return {Parameter} - The new instance.
74
   */
75
  static fromParameterMessage(parameterMsg) {
76
    const name = parameterMsg.name;
17✔
77
    const type = parameterMsg.value.type;
17✔
78
    let value;
79

80
    switch (type) {
17✔
81
      case ParameterType.PARAMETER_NOT_SET:
82
        break;
2✔
83
      case ParameterType.PARAMETER_BOOL:
84
        value = parameterMsg.value.bool_value;
2✔
85
        break;
2✔
86
      case ParameterType.PARAMETER_BOOL_ARRAY:
87
        value = parameterMsg.value.bool_array_value;
1✔
88
        break;
1✔
89
      case ParameterType.PARAMETER_BYTE_ARRAY:
90
        value = Array.from(parameterMsg.value.byte_array_value);
1✔
91
        break;
1✔
92
      case ParameterType.PARAMETER_DOUBLE:
93
        value = parameterMsg.value.double_value;
1✔
94
        break;
1✔
95
      case ParameterType.PARAMETER_DOUBLE_ARRAY:
96
        value = Array.from(parameterMsg.value.double_array_value);
1✔
97
        break;
1✔
98
      case ParameterType.PARAMETER_INTEGER:
99
        value = parameterMsg.value.integer_value;
1✔
100
        break;
1✔
101
      case ParameterType.PARAMETER_INTEGER_ARRAY:
102
        value = Array.from(parameterMsg.value.integer_array_value);
1✔
103
        break;
1✔
104
      case ParameterType.PARAMETER_STRING:
105
        value = parameterMsg.value.string_value;
6✔
106
        break;
6✔
107
      case ParameterType.PARAMETER_STRING_ARRAY:
108
        value = Array.from(parameterMsg.value.string_array_value);
1✔
109
        break;
1✔
110
    }
111

112
    return new Parameter(name, type, value);
17✔
113
  }
114

115
  /**
116
   * Create new parameter instances.
117
   * @constructor
118
   *
119
   * @param {string} name - The parameter name, must be a valid name.
120
   * @param {ParameterType} type - The type identifier.
121
   * @param {any} value - The parameter value.
122
   */
123
  constructor(name, type, value) {
124
    this._name = name;
1,259✔
125
    this._type = type;
1,259✔
126
    // Convert to bigint if it's type of `PARAMETER_INTEGER`.
127
    this._value =
1,259✔
128
      this._type == ParameterType.PARAMETER_INTEGER ? BigInt(value) : value;
1,259✔
129
    this._isDirty = true;
1,259✔
130

131
    this.validate();
1,259✔
132
  }
133

134
  /**
135
   * Get name
136
   *
137
   * @return {string} - The parameter name.
138
   */
139
  get name() {
140
    return this._name;
22,223✔
141
  }
142

143
  /**
144
   * Get type
145
   *
146
   * @return {ParameterType} - The parameter type.
147
   */
148
  get type() {
149
    return this._type;
15,349✔
150
  }
151

152
  /**
153
   * Get value.
154
   *
155
   * @return {any} - The parameter value.
156
   */
157
  get value() {
158
    return this._value;
6,170✔
159
  }
160

161
  /**
162
   * Set value.
163
   * Value must be compatible with the type property.
164
   * @param {any} newValue - The parameter name.
165
   */
166
  set value(newValue) {
167
    // no empty array value allowed
168
    this._value =
8✔
169
      Array.isArray(newValue) && newValue.length === 0 ? null : newValue;
16!
170

171
    this._dirty = true;
8✔
172
    this.validate();
8✔
173
  }
174

175
  /**
176
   * Check the state of this property.
177
   * Throw TypeError on first property with invalid type.
178
   * @return {undefined}
179
   */
180
  validate() {
181
    // validate name
182
    if (
3,720!
183
      !this.name ||
11,160✔
184
      typeof this.name !== 'string' ||
185
      this.name.trim().length === 0
186
    ) {
187
      throw new TypeError('Invalid name');
×
188
    }
189

190
    // validate type
191
    if (!validType(this.type)) {
3,720!
192
      throw new TypeError('Invalid type');
×
193
    }
194

195
    // validate value
196
    if (!validValue(this.value, this.type)) {
3,720✔
197
      throw new TypeError('Incompatible value.');
1✔
198
    }
199

200
    this._dirty = false;
3,719✔
201
  }
202

203
  /**
204
   * Create a rcl_interfaces.msg.Parameter from this instance.
205
   *
206
   * @return {rcl_interfaces.msg.Parameter} - The new instance.
207
   */
208
  toParameterMessage() {
209
    const msg = {
1,219✔
210
      name: this.name,
211
      value: this.toParameterValueMessage(),
212
    };
213
    return msg;
1,219✔
214
  }
215

216
  /**
217
   * Create a rcl_interfaces.msg.ParameterValue from this instance.
218
   *
219
   * @return {rcl_interfaces.msg.ParameterValue} - The new instance.
220
   */
221
  toParameterValueMessage() {
222
    const msg = {};
1,222✔
223
    msg.type = this.type;
1,222✔
224
    switch (this.type) {
1,222!
225
      case ParameterType.PARAMETER_NOT_SET:
226
        break;
1✔
227
      case ParameterType.PARAMETER_BOOL:
228
        msg.bool_value = this.value;
1,183✔
229
        break;
1,183✔
230
      case ParameterType.PARAMETER_BOOL_ARRAY:
231
        msg.bool_array_value = this.value;
×
232
        break;
×
233
      case ParameterType.PARAMETER_BYTE_ARRAY:
234
        msg.byte_array_value = this.value.map((val) => Math.trunc(val));
×
235
        break;
×
236
      case ParameterType.PARAMETER_DOUBLE:
237
        msg.double_value = this.value;
×
238
        break;
×
239
      case ParameterType.PARAMETER_DOUBLE_ARRAY:
240
        msg.double_array_value = this.value;
×
241
        break;
×
242
      case ParameterType.PARAMETER_INTEGER:
243
        msg.integer_value = this.value;
9✔
244
        break;
9✔
245
      case ParameterType.PARAMETER_INTEGER_ARRAY:
246
        msg.integer_array_value = this.value;
9✔
247
        break;
9✔
248
      case ParameterType.PARAMETER_STRING:
249
        msg.string_value = this.value;
20✔
250
        break;
20✔
251
      case ParameterType.PARAMETER_STRING_ARRAY:
252
        msg.string_array_value = this.value;
×
253
        break;
×
254
    }
255

256
    return msg;
1,222✔
257
  }
258
}
259

260
/**
261
 * A node parameter descriptor.
262
 * @class
263
 */
264
class ParameterDescriptor {
265
  /**
266
   * Create a new instance from a parameter.
267
   * @constructs
268
   * @param {Parameter} parameter - The parameter from which new instance is constructed.
269
   * @return {ParameterDescriptor} - The new instance.
270
   */
271
  static fromParameter(parameter) {
272
    const name = parameter.name;
600✔
273
    const type = parameter.type;
600✔
274
    return new ParameterDescriptor(name, type, 'Created from parameter.');
600✔
275
  }
276

277
  /**
278
   * Create new instances.
279
   * @constructor
280
   * @param {string} name - The descriptor name, must be a valid name.
281
   * @param {ParameterType} type - The type identifier.
282
   * @param {string} [description] - A descriptive string.
283
   * @param {boolean} [readOnly] - True indicates a parameter of this type can not be modified. Default = false.
284
   * @param {Range} [range] - An optional IntegerRange or FloatingPointRange.
285
   */
286
  constructor(
287
    name,
288
    type = ParameterType.PARAMETER_NOT_SET,
×
289
    description = 'no description',
29✔
290
    readOnly = false,
620✔
291
    range = null
1,234✔
292
  ) {
293
    this._name = name; // string
1,234✔
294
    this._type = type; // ParameterType
1,234✔
295
    this._description = description;
1,234✔
296
    this._readOnly = readOnly;
1,234✔
297
    this._additionalConstraints = '';
1,234✔
298
    this._range = range;
1,234✔
299

300
    this.validate();
1,234✔
301
  }
302

303
  /**
304
   * Get name.
305
   *
306
   * @return {string} - The name property.
307
   */
308
  get name() {
309
    return this._name;
13,454✔
310
  }
311

312
  /**
313
   * Get type.
314
   *
315
   * @return {ParameterType} - The type property.
316
   */
317
  get type() {
318
    return this._type;
4,912✔
319
  }
320

321
  /**
322
   * Get description.
323
   *
324
   * @return {string} - A descriptive string property.
325
   */
326
  get description() {
327
    return this._description;
7,346✔
328
  }
329

330
  /**
331
   * Get readOnly property.
332
   *
333
   * @return {boolean} - The readOnly property.
334
   */
335
  get readOnly() {
336
    return this._readOnly;
11✔
337
  }
338

339
  /**
340
   * Get additionalConstraints property.
341
   *
342
   * @return {string} - The additionalConstraints property.
343
   */
344
  get additionalConstraints() {
345
    return this._additionalConstraints;
2✔
346
  }
347

348
  /**
349
   * Set additionalConstraints property. .
350
   *
351
   * @param {string} constraintDescription - The new value.
352
   */
353
  set additionalConstraints(constraintDescription) {
354
    this._additionalConstraints = constraintDescription;
×
355
  }
356

357
  /**
358
   * Determine if rangeConstraint property has been set.
359
   *
360
   * @return {boolean} - The rangeConstraint property.
361
   */
362
  hasRange() {
363
    return !!this._range;
4,896✔
364
  }
365

366
  /**
367
   * Get range.
368
   *
369
   * @return {FloatingPointRange|IntegerRange} - The range property.
370
   */
371
  get range() {
372
    return this._range;
16✔
373
  }
374

375
  /**
376
   * Set range.
377
   * The range must be compatible with the type property.
378
   * @param {FloatingPointRange|IntegerRange} range - The new range.
379
   */
380
  set range(range) {
381
    if (!range) {
2!
382
      this._range = null;
×
383
      return;
×
384
    }
385
    if (!(range instanceof Range)) {
2!
386
      throw TypeError('Expected instance of Range.');
×
387
    }
388
    if (!range.isValidType(this.type)) {
2!
389
      throw TypeError('Incompatible Range');
×
390
    }
391

392
    this._range = range;
2✔
393
  }
394

395
  /**
396
   * Check the state and ensure it is valid.
397
   * Throw a TypeError if invalid state is detected.
398
   *
399
   * @return {undefined}
400
   */
401
  validate() {
402
    // validate name
403
    if (
3,671!
404
      !this.name ||
11,013✔
405
      typeof this.name !== 'string' ||
406
      this.name.trim().length === 0
407
    ) {
408
      throw new TypeError('Invalid name');
×
409
    }
410

411
    // validate type
412
    if (!validType(this.type)) {
3,671!
413
      throw new TypeError('Invalid type');
×
414
    }
415

416
    // validate description
417
    if (this.description && typeof this.description !== 'string') {
3,671!
418
      throw new TypeError('Invalid description');
×
419
    }
420

421
    // validate rangeConstraint
422
    if (this.hasRange() && !this.range.isValidType(this.type)) {
3,671!
423
      throw new TypeError('Incompatible Range');
×
424
    }
425
  }
426

427
  /**
428
   * Check a parameter for consistency with this descriptor.
429
   * Throw an Error if an inconsistent state is detected.
430
   *
431
   * @param {Parameter} parameter - The parameter to test for consistency.
432
   * @return {undefined}
433
   */
434
  validateParameter(parameter) {
435
    if (!parameter) {
1,225!
436
      throw new TypeError('Parameter is undefined');
×
437
    }
438

439
    // ensure parameter is valid
440
    try {
1,225✔
441
      parameter.validate();
1,225✔
442
    } catch {
443
      throw new TypeError('Parameter is invalid');
×
444
    }
445

446
    // ensure this descriptor is valid
447
    try {
1,225✔
448
      this.validate();
1,225✔
449
    } catch {
450
      throw new Error('Descriptor is invalid.');
×
451
    }
452

453
    if (this.name !== parameter.name) throw new Error('Name mismatch');
1,225!
454
    if (this.type !== parameter.type) throw new Error('Type mismatch');
1,225!
455
    if (this.hasRange() && !this.range.inRange(parameter.value)) {
1,225✔
456
      throw new RangeError('Parameter value is not in descriptor range');
4✔
457
    }
458
  }
459

460
  /**
461
   * Create a rcl_interfaces.msg.ParameterDescriptor from this descriptor.
462
   *
463
   * @return {rcl_interfaces.msg.ParameterDescriptor} - The new message.
464
   */
465
  toMessage() {
466
    const msg = {
2✔
467
      name: this.name,
468
      type: this.type,
469
      description: this.description,
470
      additional_constraints: this.additionalConstraints,
471
      read_only: this.readOnly,
472
    };
473
    if (
2!
474
      (this._type === ParameterType.PARAMETER_INTEGER ||
4✔
475
        this._type === ParameterType.PARAMETER_INTEGER_ARRAY) &&
476
      this._rangeConstraint instanceof IntegerRange
477
    ) {
478
      msg.integer_range = [this._rangeConstraint];
×
479
    } else if (
2!
480
      (this._type === ParameterType.PARAMETER_DOUBLE ||
4!
481
        this._type === ParameterType.PARAMETER_DOUBLE_ARRAY) &&
482
      this._rangeConstraint instanceof FloatingPointRange
483
    ) {
484
      msg.floating_point_range = [this._rangeConstraint];
×
485
    }
486

487
    return msg;
2✔
488
  }
489
}
490

491
/**
492
 * An abstract class defining a range of numbers between 2 points inclusively
493
 * divided by a step value.
494
 * @class
495
 */
496
class Range {
497
  /**
498
   * Create a new instance.
499
   * @constructor
500
   * @param {number} fromValue - The lowest inclusive value in range
501
   * @param {number} toValue - The highest inclusive value in range
502
   * @param {number} step - The internal unit size.
503
   */
504
  constructor(fromValue, toValue, step = 1) {
×
505
    this._fromValue = fromValue;
4✔
506
    this._toValue = toValue;
4✔
507
    this._step = step;
4✔
508
  }
509

510
  /**
511
   * Get fromValue.
512
   *
513
   * @return {number} - The lowest inclusive value in range.
514
   */
515
  get fromValue() {
516
    return this._fromValue;
35✔
517
  }
518

519
  /**
520
   * Get toValue.
521
   *
522
   * @return {number} - The highest inclusive value in range.
523
   */
524
  get toValue() {
525
    return this._toValue;
35✔
526
  }
527

528
  /**
529
   * Get step unit.
530
   *
531
   * @return {number} - The internal unit size.
532
   */
533
  get step() {
534
    return this._step;
31✔
535
  }
536

537
  /**
538
   * Determine if a value is within this range.
539
   * A TypeError is thrown when value is not a number or bigint.
540
   * Subclasses should override and call this method for basic type checking.
541
   *
542
   * @param {number|bigint} value - The number or bigint to check.
543
   * @return {boolean} - True if value satisfies the range; false otherwise.
544
   */
545
  inRange(value) {
546
    if (Array.isArray(value)) {
9!
547
      const valArr = value;
×
548
      return valArr.reduce(
×
549
        (inRange, val) => inRange && this.inRange(val),
×
550
        true
551
      );
552
    } else if (typeof value !== 'number' && typeof value !== 'bigint') {
9!
553
      throw new TypeError('Value must be a number or bigint');
×
554
    }
555

556
    return true;
9✔
557
  }
558

559
  /**
560
   * Abstract method that determines if a ParameterType is compatible.
561
   * Subclasses must implement this method.
562
   *
563
   * @param {ParameterType} parameterType - The parameter type to test.
564
   * @return {boolean} - True if parameterType is compatible; otherwise return false.
565
   */
566
  // eslint-disable-next-line no-unused-vars
567
  isValidType(parameterType) {
568
    return false;
×
569
  }
570
}
571

572
/**
573
 * Defines a range for floating point values.
574
 * @class
575
 */
576
class FloatingPointRange extends Range {
577
  /**
578
   * Create a new instance.
579
   * @constructor
580
   * @param {number} fromValue - The lowest inclusive value in range
581
   * @param {number} toValue - The highest inclusive value in range
582
   * @param {number} step - The internal unit size.
583
   * @param {number} tolerance - The plus/minus tolerance for number equivalence.
584
   */
585
  constructor(
586
    fromValue,
587
    toValue,
588
    step = 1,
×
589
    tolerance = DEFAULT_NUMERIC_RANGE_TOLERANCE
1✔
590
  ) {
591
    super(fromValue, toValue, step);
1✔
592
    this._tolerance = tolerance;
1✔
593
  }
594

595
  get tolerance() {
596
    return this._tolerance;
20✔
597
  }
598

599
  /**
600
   * Determine if a ParameterType is compatible.
601
   *
602
   * @param {ParameterType} parameterType - The parameter type to test.
603
   * @return {boolean} - True if parameterType is compatible; otherwise return false.
604
   */
605
  isValidType(parameterType) {
606
    const result =
607
      parameterType === ParameterType.PARAMETER_DOUBLE ||
×
608
      parameterType === ParameterType.PARAMETER_DOUBLE_ARRAY;
609
    return result;
×
610
  }
611

612
  /**
613
   * Determine if a value is within this range.
614
   * A TypeError is thrown when value is not a number.
615
   *
616
   * @param {number} value - The number to check.
617
   * @return {boolean} - True if value satisfies the range; false otherwise.
618
   */
619
  inRange(value) {
620
    if (!super.inRange(value)) return false;
9!
621

622
    const min = Math.min(this.fromValue, this.toValue);
9✔
623
    const max = Math.max(this.fromValue, this.toValue);
9✔
624

625
    if (
9✔
626
      isClose(value, min, this.tolerance) ||
17✔
627
      isClose(value, max, this.tolerance)
628
    ) {
629
      return true;
4✔
630
    }
631
    if (value < min || value > max) {
5✔
632
      return false;
2✔
633
    }
634
    if (this.step != 0.0) {
3!
635
      const distanceInSteps = Math.round((value - min) / this.step);
3✔
636
      if (!isClose(min + distanceInSteps * this.step, value, this.tolerance)) {
3!
637
        return false;
×
638
      }
639
    }
640

641
    return true;
3✔
642
  }
643
}
644

645
/**
646
 * Defines a range for integer values.
647
 * @class
648
 */
649
class IntegerRange extends Range {
650
  /**
651
   * Create a new instance.
652
   * @constructor
653
   * @param {bigint} fromValue - The lowest inclusive value in range
654
   * @param {bigint} toValue - The highest inclusive value in range
655
   * @param {bigint} step - The internal unit size.
656
   */
657
  constructor(fromValue, toValue, step = 1n) {
1✔
658
    super(fromValue, toValue, step);
3✔
659
  }
660

661
  /**
662
   * Determine if a ParameterType is compatible.
663
   *
664
   * @param {ParameterType} parameterType - The parameter type to test.
665
   * @return {boolean} - True if parameterType is compatible; otherwise return false.
666
   */
667
  isValidType(parameterType) {
668
    const result =
669
      parameterType === ParameterType.PARAMETER_INTEGER ||
10!
670
      parameterType === ParameterType.PARAMETER_INTEGER_ARRAY;
671
    return result;
10✔
672
  }
673

674
  inRange(value) {
675
    const min = this.fromValue;
15✔
676
    const max = this.toValue;
15✔
677
    if (value < min || value > max) {
15✔
678
      return false;
5✔
679
    }
680

681
    if (this.step != 0n && (value - min) % this.step !== 0n) {
10✔
682
      return false;
1✔
683
    }
684
    return true;
9✔
685
  }
686
}
687

688
/**
689
 * Infer a ParameterType for JS primitive types:
690
 * string, boolean, number and arrays of these types.
691
 * A TypeError is thrown for a value who's type is not one of
692
 * the set listed.
693
 * @param {any} value - The value to infer it's ParameterType
694
 * @returns {ParameterType} - The ParameterType that best scribes the value.
695
 */
696
// eslint-disable-next-line no-unused-vars
697
function parameterTypeFromValue(value) {
698
  if (!value) return ParameterType.PARAMETER_NOT_SET;
×
699
  if (typeof value === 'boolean') return ParameterType.PARAMETER_BOOL;
×
700
  if (typeof value === 'string') return ParameterType.PARAMETER_STRING;
×
701
  if (typeof value === 'number') return ParameterType.PARAMETER_DOUBLE;
×
702
  if (Array.isArray(value)) {
×
703
    if (value.length > 0) {
×
704
      const elementType = parameterTypeFromValue(value[0]);
×
705
      switch (elementType) {
×
706
        case ParameterType.PARAMETER_BOOL:
707
          return ParameterType.PARAMETER_BOOL_ARRAY;
×
708
        case ParameterType.PARAMETER_DOUBLE:
709
          return ParameterType.PARAMETER_DOUBLE_ARRAY;
×
710
        case ParameterType.PARAMETER_STRING:
711
          return ParameterType.PARAMETER_STRING_ARRAY;
×
712
      }
713
    }
714

715
    return ParameterType.PARAMETER_NOT_SET;
×
716
  }
717

718
  // otherwise unrecognized value
719
  throw new TypeError('Unrecognized parameter type.');
×
720
}
721

722
/**
723
 * Determine if a number maps to is a valid ParameterType.
724
 *
725
 * @param {ParameterType} parameterType - The value to test.
726
 * @return {boolean} - True if value is a valid ParameterType; false otherwise.
727
 */
728
function validType(parameterType) {
729
  let result =
730
    typeof parameterType === 'number' &&
7,391✔
731
    ParameterType.PARAMETER_NOT_SET <=
732
      parameterType <=
733
      ParameterType.PARAMETER_STRING_ARRAY;
734

735
  return result;
7,391✔
736
}
737

738
/**
739
 * Test if value can be represented by a ParameterType.
740
 *
741
 * @param {number} value - The value to test.
742
 * @param {ParameterType} type - The ParameterType to test value against.
743
 * @return {boolean} - True if value can be represented by type.
744
 */
745
function validValue(value, type) {
746
  if (value == null) {
3,822✔
747
    return type === ParameterType.PARAMETER_NOT_SET;
4✔
748
  }
749

750
  let result = true;
3,818✔
751
  switch (type) {
3,818!
752
    case ParameterType.PARAMETER_NOT_SET:
753
      result = !value;
×
754
      break;
×
755
    case ParameterType.PARAMETER_BOOL:
756
      result = typeof value === 'boolean';
3,563✔
757
      break;
3,563✔
758
    case ParameterType.PARAMETER_STRING:
759
      result = typeof value === 'string';
73✔
760
      break;
73✔
761
    case ParameterType.PARAMETER_DOUBLE:
762
    case PARAMETER_BYTE:
763
      result = typeof value === 'number';
10✔
764
      break;
10✔
765
    case ParameterType.PARAMETER_INTEGER:
766
      result = typeof value === 'bigint';
139✔
767
      break;
139✔
768
    case ParameterType.PARAMETER_BOOL_ARRAY:
769
    case ParameterType.PARAMETER_BYTE_ARRAY:
770
    case ParameterType.PARAMETER_INTEGER_ARRAY:
771
    case ParameterType.PARAMETER_DOUBLE_ARRAY:
772
    case ParameterType.PARAMETER_STRING_ARRAY:
773
      result = _validArray(value, type);
33✔
774
      break;
33✔
775
    default:
776
      result = false;
×
777
  }
778

779
  return result;
3,818✔
780
}
781

782
function _validArray(values, type) {
783
  if (!Array.isArray(values)) return false;
33!
784

785
  let arrayElementType;
786
  if (type === ParameterType.PARAMETER_BOOL_ARRAY) {
33✔
787
    arrayElementType = ParameterType.PARAMETER_BOOL;
2✔
788
  } else if (type === ParameterType.PARAMETER_BYTE_ARRAY) {
31✔
789
    arrayElementType = PARAMETER_BYTE;
1✔
790
  }
791
  if (type === ParameterType.PARAMETER_INTEGER_ARRAY) {
33✔
792
    arrayElementType = ParameterType.PARAMETER_INTEGER;
28✔
793
  }
794
  if (type === ParameterType.PARAMETER_DOUBLE_ARRAY) {
33✔
795
    arrayElementType = ParameterType.PARAMETER_DOUBLE;
1✔
796
  }
797
  if (type === ParameterType.PARAMETER_STRING_ARRAY) {
33✔
798
    arrayElementType = ParameterType.PARAMETER_STRING;
1✔
799
  }
800

801
  return values.reduce(
33✔
802
    (compatible, val) =>
803
      compatible &&
102✔
804
      !_isArrayParameterType(arrayElementType) &&
805
      validValue(val, arrayElementType),
806
    true
807
  );
808
}
809

810
function _isArrayParameterType(type) {
811
  return (
102✔
812
    type === ParameterType.PARAMETER_BOOL_ARRAY ||
510✔
813
    type === ParameterType.PARAMETER_BYTE_ARRAY ||
814
    type === ParameterType.PARAMETER_INTEGER_ARRAY ||
815
    type === ParameterType.PARAMETER_DOUBLE_ARRAY ||
816
    type === ParameterType.PARAMETER_STRING_ARRAY
817
  );
818
}
819

820
module.exports = {
26✔
821
  ParameterType,
822
  Parameter,
823
  ParameterDescriptor,
824
  PARAMETER_SEPARATOR,
825
  Range,
826
  FloatingPointRange,
827
  IntegerRange,
828
  DEFAULT_NUMERIC_RANGE_TOLERANCE,
829
};
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