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

RobotWebTools / rclnodejs / 20742259610

06 Jan 2026 08:04AM UTC coverage: 80.626% (-2.2%) from 82.843%
20742259610

push

github

minggangw
Add ClockEvent support (#1354)

This PR adds comprehensive ClockEvent support to rclnodejs, enabling clock-based sleep functionality for STEADY_TIME, SYSTEM_TIME, and ROS_TIME clocks.

### New Features

**ClockEvent Class**
- Thread-safe event synchronization for clock-based waiting
- Support for steady, system, and ROS clock types
- Async worker pattern for non-blocking sleep operations
- Clock epoch synchronization between RCL and std::chrono

**Clock Sleep Methods**
- `Clock.sleepUntil(until, context)` - Sleep until absolute time point
- `Clock.sleepFor(duration, context)` - Sleep for specified duration
- Clock jump callbacks to wake on time changes
- Context-aware early wakeup on shutdown
- Detects ROS time activation/deactivation

**ClockChange Enum**
- `ROS_TIME_NO_CHANGE`, `ROS_TIME_ACTIVATED`, `ROS_TIME_DEACTIVATED`, `SYSTEM_TIME_NO_CHANGE`
- Used in clock jump callback notifications

### Critical Fixes

**BigInt Precision Loss Prevention**
- Added lossless conversion checks for nanosecond timestamps
- Prevents silent data corruption when converting BigInt to int64_t

**Missing Module Imports**
- Fixed missing Context, ClockEvent, and ClockChange imports in clock.js

### Test Coverage

- **test-clock-event.js** - Basic ClockEvent operations (4 tests)
- **test-clock-sleep.js** - Sleep methods for all clock types (11 tests)
  - Includes comprehensive ROS time active scenario with TimeSource + simulated clock messages
- **test-clock-change.js** - ClockChange enum and integration tests (11 tests)

**Results**: 1055 passing, 6 pending

### Files Changed

**Added**: 
- `src/clock_event.{cpp,hpp}`, clock_event.js, clock_change.js
- `types/clock_event.d.ts`, `types/clock_change.d.ts`
- `test/test-clock-{event,sleep,change}.js`

**Modified**:
- clock.js - Added sleep methods and imports
- `types/clock.d.ts`, index.d.ts - Added type definitions
- `binding.gyp`, `index.js`, `src/addon.cpp` - Registered bindings

**Impact**: +1397 lines, fully backward co... (continued)

1268 of 1753 branches covered (72.33%)

Branch coverage included in aggregate %.

40 of 42 new or added lines in 3 files covered. (95.24%)

122 existing lines in 10 files now uncovered.

2727 of 3202 relevant lines covered (85.17%)

465.68 hits per line

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

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

14
'use strict';
15

16
const { Parameter } = require('./parameter.js');
26✔
17
/**
18
 * NodeOptions specify configuration choices during the
19
 * node instantiation process.
20
 * @class
21
 */
22
class NodeOptions {
23
  /**
24
   * Create a new instance with default property values.
25
   * @constructor
26
   * @param {boolean} [startParameterServices=true]
27
   * @param {array} [parameterOverrides=[]]
28
   * @param {boolean} [automaticallyDeclareParametersFromOverrides=false]
29
   * @param {boolean} [startTypeDescriptionService=true]
30
   * @param {boolean} [enableRosout=true]
31
   * @param {QoS} [rosoutQos=QoS.profileDefault]
32
   */
33
  constructor(
34
    startParameterServices = true,
831✔
35
    parameterOverrides = [],
831✔
36
    automaticallyDeclareParametersFromOverrides = false,
831✔
37
    startTypeDescriptionService = true,
832✔
38
    enableRosout = true,
832✔
39
    rosoutQos = null
832✔
40
  ) {
41
    this._startParameterServices = startParameterServices;
832✔
42
    this._parameterOverrides = parameterOverrides;
832✔
43
    this._automaticallyDeclareParametersFromOverrides =
832✔
44
      automaticallyDeclareParametersFromOverrides;
45
    this._startTypeDescriptionService = startTypeDescriptionService;
832✔
46
    this._enableRosout = enableRosout;
832✔
47
    this._rosoutQos = rosoutQos;
832✔
48
  }
49

50
  /**
51
   * Get the startParameterServices option.
52
   * Default value = true;
53
   * @returns {boolean} -
54
   */
55
  get startParameterServices() {
56
    return this._startParameterServices;
801✔
57
  }
58

59
  /**
60
   * Set startParameterServices.
61
   * @param {boolean} startFlag - True indicates for a node to start it's parameter_service.
62
   */
63
  set startParameterServices(startFlag) {
64
    this._startParameterServices = startFlag;
6✔
65
  }
66

67
  /**
68
   * Get the parameterOverrides.
69
   * @return {Parameter[]} - An array of Parameters that serve as overrides for a node's default
70
   *   parameters. Default = empty array [].
71
   */
72
  get parameterOverrides() {
73
    return this._parameterOverrides;
820✔
74
  }
75

76
  /**
77
   * Set the Parameters that will serve to override a node's default parameter settings.
78
   * Setting to null, reinitializes the parameterOverrides to an empty array.
79
   * @param {Parameter|Parameter[]} parameters - A single parameter or parameter[].
80
   *    Default is an empty array.
81
   */
82
  set parameterOverrides(parameters = []) {
×
83
    let povalue = parameters;
10✔
84

85
    if (!povalue) {
10✔
86
      povalue = [];
1✔
87
    } else if (povalue instanceof Parameter) {
9✔
88
      // a single parameter
89
      povalue = [povalue];
1✔
90
    } else if (!Array.isArray(parameters)) {
8✔
91
      throw TypeError('Expected Parameter[]');
1✔
92
    }
93

94
    this._parameterOverrides = povalue;
9✔
95
  }
96

97
  /**
98
   * Get the automaticallyDeclareParametersFromOverrides.
99
   *
100
   * @returns {boolean} - True indicates that a node should declare parameters from
101
   *    it's parameter-overrides
102
   */
103
  get automaticallyDeclareParametersFromOverrides() {
104
    return this._automaticallyDeclareParametersFromOverrides;
801✔
105
  }
106

107
  /**
108
   * Set automaticallyDeclareParametersFromOverrides.
109
   *
110
   * @param {boolean} declareParamsFlag - When true, a node will declare parameters from all
111
   * parameter-overrides.
112
   */
113
  set automaticallyDeclareParametersFromOverrides(declareParamsFlag) {
114
    this._automaticallyDeclareParametersFromOverrides = declareParamsFlag;
6✔
115
  }
116

117
  /**
118
   * Get the startTypeDescriptionService option, only available for ROS2 > Humble.
119
   * Default value = true;
120
   * @returns {boolean} - true if the type description service is enabled.
121
   */
122
  get startTypeDescriptionService() {
123
    return this._startTypeDescriptionService;
798✔
124
  }
125

126
  /**
127
   * Set startTypeDescriptionService, only available for ROS2 > Humble
128
   * @param {boolean} willStartTypeDescriptionService
129
   */
130
  set startTypeDescriptionService(willStartTypeDescriptionService) {
UNCOV
131
    this._startTypeDescriptionService = willStartTypeDescriptionService;
×
132
  }
133

134
  /**
135
   * Get the enableRosout option.
136
   * Default value = true;
137
   * @returns {boolean} - true if the rosout logging is enabled.
138
   */
139
  get enableRosout() {
140
    return this._enableRosout;
798✔
141
  }
142

143
  /**
144
   * Set enableRosout.
145
   * @param {boolean} enableRosout
146
   */
147
  set enableRosout(enableRosout) {
148
    this._enableRosout = enableRosout;
3✔
149
  }
150

151
  /**
152
   * Get the rosoutQos option.
153
   * @returns {QoS} - The QoS profile for rosout.
154
   */
155
  get rosoutQos() {
156
    return this._rosoutQos;
808✔
157
  }
158

159
  /**
160
   * Set rosoutQos.
161
   * @param {QoS} rosoutQos
162
   */
163
  set rosoutQos(rosoutQos) {
164
    this._rosoutQos = rosoutQos;
1✔
165
  }
166

167
  /**
168
   * Return an instance configured with default options.
169
   * @returns {NodeOptions} - An instance with default values.
170
   */
171
  static get defaultOptions() {
172
    return new NodeOptions();
818✔
173
  }
174
}
175

176
module.exports = NodeOptions;
26✔
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