eslint 8.50.0 → 8.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -80,7 +80,9 @@ class CodePath {
80
80
  }
81
81
 
82
82
  /**
83
- * The initial code path segment.
83
+ * The initial code path segment. This is the segment that is at the head
84
+ * of the code path.
85
+ * This is a passthrough to the underlying `CodePathState`.
84
86
  * @type {CodePathSegment}
85
87
  */
86
88
  get initialSegment() {
@@ -88,8 +90,10 @@ class CodePath {
88
90
  }
89
91
 
90
92
  /**
91
- * Final code path segments.
92
- * This array is a mix of `returnedSegments` and `thrownSegments`.
93
+ * Final code path segments. These are the terminal (tail) segments in the
94
+ * code path, which is the combination of `returnedSegments` and `thrownSegments`.
95
+ * All segments in this array are reachable.
96
+ * This is a passthrough to the underlying `CodePathState`.
93
97
  * @type {CodePathSegment[]}
94
98
  */
95
99
  get finalSegments() {
@@ -97,9 +101,14 @@ class CodePath {
97
101
  }
98
102
 
99
103
  /**
100
- * Final code path segments which is with `return` statements.
101
- * This array contains the last path segment if it's reachable.
102
- * Since the reachable last path returns `undefined`.
104
+ * Final code path segments that represent normal completion of the code path.
105
+ * For functions, this means both explicit `return` statements and implicit returns,
106
+ * such as the last reachable segment in a function that does not have an
107
+ * explicit `return` as this implicitly returns `undefined`. For scripts,
108
+ * modules, class field initializers, and class static blocks, this means
109
+ * all lines of code have been executed.
110
+ * These segments are also present in `finalSegments`.
111
+ * This is a passthrough to the underlying `CodePathState`.
103
112
  * @type {CodePathSegment[]}
104
113
  */
105
114
  get returnedSegments() {
@@ -107,7 +116,9 @@ class CodePath {
107
116
  }
108
117
 
109
118
  /**
110
- * Final code path segments which is with `throw` statements.
119
+ * Final code path segments that represent `throw` statements.
120
+ * This is a passthrough to the underlying `CodePathState`.
121
+ * These segments are also present in `finalSegments`.
111
122
  * @type {CodePathSegment[]}
112
123
  */
113
124
  get thrownSegments() {
@@ -115,7 +126,12 @@ class CodePath {
115
126
  }
116
127
 
117
128
  /**
118
- * Current code path segments.
129
+ * Tracks the traversal of the code path through each segment. This array
130
+ * starts empty and segments are added or removed as the code path is
131
+ * traversed. This array always ends up empty at the end of a code path
132
+ * traversal. The `CodePathState` uses this to track its progress through
133
+ * the code path.
134
+ * This is a passthrough to the underlying `CodePathState`.
119
135
  * @type {CodePathSegment[]}
120
136
  * @deprecated
121
137
  */
@@ -126,46 +142,70 @@ class CodePath {
126
142
  /**
127
143
  * Traverses all segments in this code path.
128
144
  *
129
- * codePath.traverseSegments(function(segment, controller) {
145
+ * codePath.traverseSegments((segment, controller) => {
130
146
  * // do something.
131
147
  * });
132
148
  *
133
149
  * This method enumerates segments in order from the head.
134
150
  *
135
- * The `controller` object has two methods.
151
+ * The `controller` argument has two methods:
136
152
  *
137
- * - `controller.skip()` - Skip the following segments in this branch.
138
- * - `controller.break()` - Skip all following segments.
139
- * @param {Object} [options] Omittable.
140
- * @param {CodePathSegment} [options.first] The first segment to traverse.
141
- * @param {CodePathSegment} [options.last] The last segment to traverse.
153
+ * - `skip()` - skips the following segments in this branch
154
+ * - `break()` - skips all following segments in the traversal
155
+ *
156
+ * A note on the parameters: the `options` argument is optional. This means
157
+ * the first argument might be an options object or the callback function.
158
+ * @param {Object} [optionsOrCallback] Optional first and last segments to traverse.
159
+ * @param {CodePathSegment} [optionsOrCallback.first] The first segment to traverse.
160
+ * @param {CodePathSegment} [optionsOrCallback.last] The last segment to traverse.
142
161
  * @param {Function} callback A callback function.
143
162
  * @returns {void}
144
163
  */
145
- traverseSegments(options, callback) {
164
+ traverseSegments(optionsOrCallback, callback) {
165
+
166
+ // normalize the arguments into a callback and options
146
167
  let resolvedOptions;
147
168
  let resolvedCallback;
148
169
 
149
- if (typeof options === "function") {
150
- resolvedCallback = options;
170
+ if (typeof optionsOrCallback === "function") {
171
+ resolvedCallback = optionsOrCallback;
151
172
  resolvedOptions = {};
152
173
  } else {
153
- resolvedOptions = options || {};
174
+ resolvedOptions = optionsOrCallback || {};
154
175
  resolvedCallback = callback;
155
176
  }
156
177
 
178
+ // determine where to start traversing from based on the options
157
179
  const startSegment = resolvedOptions.first || this.internal.initialSegment;
158
180
  const lastSegment = resolvedOptions.last;
159
181
 
160
- let item = null;
182
+ // set up initial location information
183
+ let record = null;
161
184
  let index = 0;
162
185
  let end = 0;
163
186
  let segment = null;
164
- const visited = Object.create(null);
187
+
188
+ // segments that have already been visited during traversal
189
+ const visited = new Set();
190
+
191
+ // tracks the traversal steps
165
192
  const stack = [[startSegment, 0]];
193
+
194
+ // tracks the last skipped segment during traversal
166
195
  let skippedSegment = null;
196
+
197
+ // indicates if we exited early from the traversal
167
198
  let broken = false;
199
+
200
+ /**
201
+ * Maintains traversal state.
202
+ */
168
203
  const controller = {
204
+
205
+ /**
206
+ * Skip the following segments in this branch.
207
+ * @returns {void}
208
+ */
169
209
  skip() {
170
210
  if (stack.length <= 1) {
171
211
  broken = true;
@@ -173,32 +213,52 @@ class CodePath {
173
213
  skippedSegment = stack[stack.length - 2][0];
174
214
  }
175
215
  },
216
+
217
+ /**
218
+ * Stop traversal completely - do not traverse to any
219
+ * other segments.
220
+ * @returns {void}
221
+ */
176
222
  break() {
177
223
  broken = true;
178
224
  }
179
225
  };
180
226
 
181
227
  /**
182
- * Checks a given previous segment has been visited.
228
+ * Checks if a given previous segment has been visited.
183
229
  * @param {CodePathSegment} prevSegment A previous segment to check.
184
230
  * @returns {boolean} `true` if the segment has been visited.
185
231
  */
186
232
  function isVisited(prevSegment) {
187
233
  return (
188
- visited[prevSegment.id] ||
234
+ visited.has(prevSegment) ||
189
235
  segment.isLoopedPrevSegment(prevSegment)
190
236
  );
191
237
  }
192
238
 
239
+ // the traversal
193
240
  while (stack.length > 0) {
194
- item = stack[stack.length - 1];
195
- segment = item[0];
196
- index = item[1];
241
+
242
+ /*
243
+ * This isn't a pure stack. We use the top record all the time
244
+ * but don't always pop it off. The record is popped only if
245
+ * one of the following is true:
246
+ *
247
+ * 1) We have already visited the segment.
248
+ * 2) We have not visited *all* of the previous segments.
249
+ * 3) We have traversed past the available next segments.
250
+ *
251
+ * Otherwise, we just read the value and sometimes modify the
252
+ * record as we traverse.
253
+ */
254
+ record = stack[stack.length - 1];
255
+ segment = record[0];
256
+ index = record[1];
197
257
 
198
258
  if (index === 0) {
199
259
 
200
260
  // Skip if this segment has been visited already.
201
- if (visited[segment.id]) {
261
+ if (visited.has(segment)) {
202
262
  stack.pop();
203
263
  continue;
204
264
  }
@@ -212,18 +272,29 @@ class CodePath {
212
272
  continue;
213
273
  }
214
274
 
215
- // Reset the flag of skipping if all branches have been skipped.
275
+ // Reset the skipping flag if all branches have been skipped.
216
276
  if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
217
277
  skippedSegment = null;
218
278
  }
219
- visited[segment.id] = true;
279
+ visited.add(segment);
220
280
 
221
- // Call the callback when the first time.
281
+ /*
282
+ * If the most recent segment hasn't been skipped, then we call
283
+ * the callback, passing in the segment and the controller.
284
+ */
222
285
  if (!skippedSegment) {
223
286
  resolvedCallback.call(this, segment, controller);
287
+
288
+ // exit if we're at the last segment
224
289
  if (segment === lastSegment) {
225
290
  controller.skip();
226
291
  }
292
+
293
+ /*
294
+ * If the previous statement was executed, or if the callback
295
+ * called a method on the controller, we might need to exit the
296
+ * loop, so check for that and break accordingly.
297
+ */
227
298
  if (broken) {
228
299
  break;
229
300
  }
@@ -233,12 +304,35 @@ class CodePath {
233
304
  // Update the stack.
234
305
  end = segment.nextSegments.length - 1;
235
306
  if (index < end) {
236
- item[1] += 1;
307
+
308
+ /*
309
+ * If we haven't yet visited all of the next segments, update
310
+ * the current top record on the stack to the next index to visit
311
+ * and then push a record for the current segment on top.
312
+ *
313
+ * Setting the current top record's index lets us know how many
314
+ * times we've been here and ensures that the segment won't be
315
+ * reprocessed (because we only process segments with an index
316
+ * of 0).
317
+ */
318
+ record[1] += 1;
237
319
  stack.push([segment.nextSegments[index], 0]);
238
320
  } else if (index === end) {
239
- item[0] = segment.nextSegments[index];
240
- item[1] = 0;
321
+
322
+ /*
323
+ * If we are at the last next segment, then reset the top record
324
+ * in the stack to next segment and set its index to 0 so it will
325
+ * be processed next.
326
+ */
327
+ record[0] = segment.nextSegments[index];
328
+ record[1] = 0;
241
329
  } else {
330
+
331
+ /*
332
+ * If index > end, that means we have no more segments that need
333
+ * processing. So, we pop that record off of the stack in order to
334
+ * continue traversing at the next level up.
335
+ */
242
336
  stack.pop();
243
337
  }
244
338
  }
@@ -21,8 +21,8 @@ const assert = require("assert"),
21
21
  //------------------------------------------------------------------------------
22
22
 
23
23
  /**
24
- * Gets whether or not a given segment is reachable.
25
- * @param {CodePathSegment} segment A segment to get.
24
+ * Determines whether or not a given segment is reachable.
25
+ * @param {CodePathSegment} segment The segment to check.
26
26
  * @returns {boolean} `true` if the segment is reachable.
27
27
  */
28
28
  function isReachable(segment) {
@@ -30,32 +30,64 @@ function isReachable(segment) {
30
30
  }
31
31
 
32
32
  /**
33
- * Creates new segments from the specific range of `context.segmentsList`.
33
+ * Creates a new segment for each fork in the given context and appends it
34
+ * to the end of the specified range of segments. Ultimately, this ends up calling
35
+ * `new CodePathSegment()` for each of the forks using the `create` argument
36
+ * as a wrapper around special behavior.
37
+ *
38
+ * The `startIndex` and `endIndex` arguments specify a range of segments in
39
+ * `context` that should become `allPrevSegments` for the newly created
40
+ * `CodePathSegment` objects.
34
41
  *
35
42
  * When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and
36
- * `end` is `-1`, this creates `[g, h]`. This `g` is from `a`, `c`, and `e`.
37
- * This `h` is from `b`, `d`, and `f`.
38
- * @param {ForkContext} context An instance.
39
- * @param {number} begin The first index of the previous segments.
40
- * @param {number} end The last index of the previous segments.
41
- * @param {Function} create A factory function of new segments.
42
- * @returns {CodePathSegment[]} New segments.
43
+ * `end` is `-1`, this creates two new segments, `[g, h]`. This `g` is appended to
44
+ * the end of the path from `a`, `c`, and `e`. This `h` is appended to the end of
45
+ * `b`, `d`, and `f`.
46
+ * @param {ForkContext} context An instance from which the previous segments
47
+ * will be obtained.
48
+ * @param {number} startIndex The index of the first segment in the context
49
+ * that should be specified as previous segments for the newly created segments.
50
+ * @param {number} endIndex The index of the last segment in the context
51
+ * that should be specified as previous segments for the newly created segments.
52
+ * @param {Function} create A function that creates new `CodePathSegment`
53
+ * instances in a particular way. See the `CodePathSegment.new*` methods.
54
+ * @returns {Array<CodePathSegment>} An array of the newly-created segments.
43
55
  */
44
- function makeSegments(context, begin, end, create) {
56
+ function createSegments(context, startIndex, endIndex, create) {
57
+
58
+ /** @type {Array<Array<CodePathSegment>>} */
45
59
  const list = context.segmentsList;
46
60
 
47
- const normalizedBegin = begin >= 0 ? begin : list.length + begin;
48
- const normalizedEnd = end >= 0 ? end : list.length + end;
61
+ /*
62
+ * Both `startIndex` and `endIndex` work the same way: if the number is zero
63
+ * or more, then the number is used as-is. If the number is negative,
64
+ * then that number is added to the length of the segments list to
65
+ * determine the index to use. That means -1 for either argument
66
+ * is the last element, -2 is the second to last, and so on.
67
+ *
68
+ * So if `startIndex` is 0, `endIndex` is -1, and `list.length` is 3, the
69
+ * effective `startIndex` is 0 and the effective `endIndex` is 2, so this function
70
+ * will include items at indices 0, 1, and 2.
71
+ *
72
+ * Therefore, if `startIndex` is -1 and `endIndex` is -1, that means we'll only
73
+ * be using the last segment in `list`.
74
+ */
75
+ const normalizedBegin = startIndex >= 0 ? startIndex : list.length + startIndex;
76
+ const normalizedEnd = endIndex >= 0 ? endIndex : list.length + endIndex;
49
77
 
78
+ /** @type {Array<CodePathSegment>} */
50
79
  const segments = [];
51
80
 
52
81
  for (let i = 0; i < context.count; ++i) {
82
+
83
+ // this is passed into `new CodePathSegment` to add to code path.
53
84
  const allPrevSegments = [];
54
85
 
55
86
  for (let j = normalizedBegin; j <= normalizedEnd; ++j) {
56
87
  allPrevSegments.push(list[j][i]);
57
88
  }
58
89
 
90
+ // note: `create` is just a wrapper that augments `new CodePathSegment`.
59
91
  segments.push(create(context.idGenerator.next(), allPrevSegments));
60
92
  }
61
93
 
@@ -63,28 +95,57 @@ function makeSegments(context, begin, end, create) {
63
95
  }
64
96
 
65
97
  /**
66
- * `segments` becomes doubly in a `finally` block. Then if a code path exits by a
67
- * control statement (such as `break`, `continue`) from the `finally` block, the
68
- * destination's segments may be half of the source segments. In that case, this
69
- * merges segments.
70
- * @param {ForkContext} context An instance.
71
- * @param {CodePathSegment[]} segments Segments to merge.
72
- * @returns {CodePathSegment[]} The merged segments.
98
+ * Inside of a `finally` block we end up with two parallel paths. If the code path
99
+ * exits by a control statement (such as `break` or `continue`) from the `finally`
100
+ * block, then we need to merge the remaining parallel paths back into one.
101
+ * @param {ForkContext} context The fork context to work on.
102
+ * @param {Array<CodePathSegment>} segments Segments to merge.
103
+ * @returns {Array<CodePathSegment>} The merged segments.
73
104
  */
74
105
  function mergeExtraSegments(context, segments) {
75
106
  let currentSegments = segments;
76
107
 
108
+ /*
109
+ * We need to ensure that the array returned from this function contains no more
110
+ * than the number of segments that the context allows. `context.count` indicates
111
+ * how many items should be in the returned array to ensure that the new segment
112
+ * entries will line up with the already existing segment entries.
113
+ */
77
114
  while (currentSegments.length > context.count) {
78
115
  const merged = [];
79
116
 
80
- for (let i = 0, length = currentSegments.length / 2 | 0; i < length; ++i) {
117
+ /*
118
+ * Because `context.count` is a factor of 2 inside of a `finally` block,
119
+ * we can divide the segment count by 2 to merge the paths together.
120
+ * This loops through each segment in the list and creates a new `CodePathSegment`
121
+ * that has the segment and the segment two slots away as previous segments.
122
+ *
123
+ * If `currentSegments` is [a,b,c,d], this will create new segments e and f, such
124
+ * that:
125
+ *
126
+ * When `i` is 0:
127
+ * a->e
128
+ * c->e
129
+ *
130
+ * When `i` is 1:
131
+ * b->f
132
+ * d->f
133
+ */
134
+ for (let i = 0, length = Math.floor(currentSegments.length / 2); i < length; ++i) {
81
135
  merged.push(CodePathSegment.newNext(
82
136
  context.idGenerator.next(),
83
137
  [currentSegments[i], currentSegments[i + length]]
84
138
  ));
85
139
  }
140
+
141
+ /*
142
+ * Go through the loop condition one more time to see if we have the
143
+ * number of segments for the context. If not, we'll keep merging paths
144
+ * of the merged segments until we get there.
145
+ */
86
146
  currentSegments = merged;
87
147
  }
148
+
88
149
  return currentSegments;
89
150
  }
90
151
 
@@ -93,25 +154,55 @@ function mergeExtraSegments(context, segments) {
93
154
  //------------------------------------------------------------------------------
94
155
 
95
156
  /**
96
- * A class to manage forking.
157
+ * Manages the forking of code paths.
97
158
  */
98
159
  class ForkContext {
99
160
 
100
161
  /**
162
+ * Creates a new instance.
101
163
  * @param {IdGenerator} idGenerator An identifier generator for segments.
102
- * @param {ForkContext|null} upper An upper fork context.
103
- * @param {number} count A number of parallel segments.
164
+ * @param {ForkContext|null} upper The preceding fork context.
165
+ * @param {number} count The number of parallel segments in each element
166
+ * of `segmentsList`.
104
167
  */
105
168
  constructor(idGenerator, upper, count) {
169
+
170
+ /**
171
+ * The ID generator that will generate segment IDs for any new
172
+ * segments that are created.
173
+ * @type {IdGenerator}
174
+ */
106
175
  this.idGenerator = idGenerator;
176
+
177
+ /**
178
+ * The preceding fork context.
179
+ * @type {ForkContext|null}
180
+ */
107
181
  this.upper = upper;
182
+
183
+ /**
184
+ * The number of elements in each element of `segmentsList`. In most
185
+ * cases, this is 1 but can be 2 when there is a `finally` present,
186
+ * which forks the code path outside of normal flow. In the case of nested
187
+ * `finally` blocks, this can be a multiple of 2.
188
+ * @type {number}
189
+ */
108
190
  this.count = count;
191
+
192
+ /**
193
+ * The segments within this context. Each element in this array has
194
+ * `count` elements that represent one step in each fork. For example,
195
+ * when `segmentsList` is `[[a, b], [c, d], [e, f]]`, there is one path
196
+ * a->c->e and one path b->d->f, and `count` is 2 because each element
197
+ * is an array with two elements.
198
+ * @type {Array<Array<CodePathSegment>>}
199
+ */
109
200
  this.segmentsList = [];
110
201
  }
111
202
 
112
203
  /**
113
- * The head segments.
114
- * @type {CodePathSegment[]}
204
+ * The segments that begin this fork context.
205
+ * @type {Array<CodePathSegment>}
115
206
  */
116
207
  get head() {
117
208
  const list = this.segmentsList;
@@ -120,7 +211,7 @@ class ForkContext {
120
211
  }
121
212
 
122
213
  /**
123
- * A flag which shows empty.
214
+ * Indicates if the context contains no segments.
124
215
  * @type {boolean}
125
216
  */
126
217
  get empty() {
@@ -128,7 +219,7 @@ class ForkContext {
128
219
  }
129
220
 
130
221
  /**
131
- * A flag which shows reachable.
222
+ * Indicates if there are any segments that are reachable.
132
223
  * @type {boolean}
133
224
  */
134
225
  get reachable() {
@@ -138,75 +229,82 @@ class ForkContext {
138
229
  }
139
230
 
140
231
  /**
141
- * Creates new segments from this context.
142
- * @param {number} begin The first index of previous segments.
143
- * @param {number} end The last index of previous segments.
144
- * @returns {CodePathSegment[]} New segments.
232
+ * Creates new segments in this context and appends them to the end of the
233
+ * already existing `CodePathSegment`s specified by `startIndex` and
234
+ * `endIndex`.
235
+ * @param {number} startIndex The index of the first segment in the context
236
+ * that should be specified as previous segments for the newly created segments.
237
+ * @param {number} endIndex The index of the last segment in the context
238
+ * that should be specified as previous segments for the newly created segments.
239
+ * @returns {Array<CodePathSegment>} An array of the newly created segments.
145
240
  */
146
- makeNext(begin, end) {
147
- return makeSegments(this, begin, end, CodePathSegment.newNext);
241
+ makeNext(startIndex, endIndex) {
242
+ return createSegments(this, startIndex, endIndex, CodePathSegment.newNext);
148
243
  }
149
244
 
150
245
  /**
151
- * Creates new segments from this context.
152
- * The new segments is always unreachable.
153
- * @param {number} begin The first index of previous segments.
154
- * @param {number} end The last index of previous segments.
155
- * @returns {CodePathSegment[]} New segments.
246
+ * Creates new unreachable segments in this context and appends them to the end of the
247
+ * already existing `CodePathSegment`s specified by `startIndex` and
248
+ * `endIndex`.
249
+ * @param {number} startIndex The index of the first segment in the context
250
+ * that should be specified as previous segments for the newly created segments.
251
+ * @param {number} endIndex The index of the last segment in the context
252
+ * that should be specified as previous segments for the newly created segments.
253
+ * @returns {Array<CodePathSegment>} An array of the newly created segments.
156
254
  */
157
- makeUnreachable(begin, end) {
158
- return makeSegments(this, begin, end, CodePathSegment.newUnreachable);
255
+ makeUnreachable(startIndex, endIndex) {
256
+ return createSegments(this, startIndex, endIndex, CodePathSegment.newUnreachable);
159
257
  }
160
258
 
161
259
  /**
162
- * Creates new segments from this context.
163
- * The new segments don't have connections for previous segments.
164
- * But these inherit the reachable flag from this context.
165
- * @param {number} begin The first index of previous segments.
166
- * @param {number} end The last index of previous segments.
167
- * @returns {CodePathSegment[]} New segments.
260
+ * Creates new segments in this context and does not append them to the end
261
+ * of the already existing `CodePathSegment`s specified by `startIndex` and
262
+ * `endIndex`. The `startIndex` and `endIndex` are only used to determine if
263
+ * the new segments should be reachable. If any of the segments in this range
264
+ * are reachable then the new segments are also reachable; otherwise, the new
265
+ * segments are unreachable.
266
+ * @param {number} startIndex The index of the first segment in the context
267
+ * that should be considered for reachability.
268
+ * @param {number} endIndex The index of the last segment in the context
269
+ * that should be considered for reachability.
270
+ * @returns {Array<CodePathSegment>} An array of the newly created segments.
168
271
  */
169
- makeDisconnected(begin, end) {
170
- return makeSegments(this, begin, end, CodePathSegment.newDisconnected);
272
+ makeDisconnected(startIndex, endIndex) {
273
+ return createSegments(this, startIndex, endIndex, CodePathSegment.newDisconnected);
171
274
  }
172
275
 
173
276
  /**
174
- * Adds segments into this context.
175
- * The added segments become the head.
176
- * @param {CodePathSegment[]} segments Segments to add.
277
+ * Adds segments to the head of this context.
278
+ * @param {Array<CodePathSegment>} segments The segments to add.
177
279
  * @returns {void}
178
280
  */
179
281
  add(segments) {
180
282
  assert(segments.length >= this.count, `${segments.length} >= ${this.count}`);
181
-
182
283
  this.segmentsList.push(mergeExtraSegments(this, segments));
183
284
  }
184
285
 
185
286
  /**
186
- * Replaces the head segments with given segments.
287
+ * Replaces the head segments with the given segments.
187
288
  * The current head segments are removed.
188
- * @param {CodePathSegment[]} segments Segments to add.
289
+ * @param {Array<CodePathSegment>} replacementHeadSegments The new head segments.
189
290
  * @returns {void}
190
291
  */
191
- replaceHead(segments) {
192
- assert(segments.length >= this.count, `${segments.length} >= ${this.count}`);
193
-
194
- this.segmentsList.splice(-1, 1, mergeExtraSegments(this, segments));
292
+ replaceHead(replacementHeadSegments) {
293
+ assert(
294
+ replacementHeadSegments.length >= this.count,
295
+ `${replacementHeadSegments.length} >= ${this.count}`
296
+ );
297
+ this.segmentsList.splice(-1, 1, mergeExtraSegments(this, replacementHeadSegments));
195
298
  }
196
299
 
197
300
  /**
198
301
  * Adds all segments of a given fork context into this context.
199
- * @param {ForkContext} context A fork context to add.
302
+ * @param {ForkContext} otherForkContext The fork context to add from.
200
303
  * @returns {void}
201
304
  */
202
- addAll(context) {
203
- assert(context.count === this.count);
204
-
205
- const source = context.segmentsList;
206
-
207
- for (let i = 0; i < source.length; ++i) {
208
- this.segmentsList.push(source[i]);
209
- }
305
+ addAll(otherForkContext) {
306
+ assert(otherForkContext.count === this.count);
307
+ this.segmentsList.push(...otherForkContext.segmentsList);
210
308
  }
211
309
 
212
310
  /**
@@ -218,7 +316,8 @@ class ForkContext {
218
316
  }
219
317
 
220
318
  /**
221
- * Creates the root fork context.
319
+ * Creates a new root context, meaning that there are no parent
320
+ * fork contexts.
222
321
  * @param {IdGenerator} idGenerator An identifier generator for segments.
223
322
  * @returns {ForkContext} New fork context.
224
323
  */
@@ -233,14 +332,16 @@ class ForkContext {
233
332
  /**
234
333
  * Creates an empty fork context preceded by a given context.
235
334
  * @param {ForkContext} parentContext The parent fork context.
236
- * @param {boolean} forkLeavingPath A flag which shows inside of `finally` block.
335
+ * @param {boolean} shouldForkLeavingPath Indicates that we are inside of
336
+ * a `finally` block and should therefore fork the path that leaves
337
+ * `finally`.
237
338
  * @returns {ForkContext} New fork context.
238
339
  */
239
- static newEmpty(parentContext, forkLeavingPath) {
340
+ static newEmpty(parentContext, shouldForkLeavingPath) {
240
341
  return new ForkContext(
241
342
  parentContext.idGenerator,
242
343
  parentContext,
243
- (forkLeavingPath ? 2 : 1) * parentContext.count
344
+ (shouldForkLeavingPath ? 2 : 1) * parentContext.count
244
345
  );
245
346
  }
246
347
  }