@rushstack/operation-graph 0.3.1 → 0.4.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.
package/CHANGELOG.json CHANGED
@@ -1,6 +1,41 @@
1
1
  {
2
2
  "name": "@rushstack/operation-graph",
3
3
  "entries": [
4
+ {
5
+ "version": "0.4.0",
6
+ "tag": "@rushstack/operation-graph_v0.4.0",
7
+ "date": "Tue, 30 Sep 2025 20:33:51 GMT",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "comment": "Require the \"requestor\" parameter and add a new \"detail\" parameter for watch-mode rerun requests. Make \"name\" a required field for operations."
12
+ },
13
+ {
14
+ "comment": "(BREAKING CHANGE) Revert the extensibility points for `(before/after)ExecuteOperation(Group)?Async` to be synchronous to signify that they are only meant for logging, not for expensive work."
15
+ }
16
+ ],
17
+ "dependency": [
18
+ {
19
+ "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`"
20
+ },
21
+ {
22
+ "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`"
23
+ }
24
+ ]
25
+ }
26
+ },
27
+ {
28
+ "version": "0.3.2",
29
+ "tag": "@rushstack/operation-graph_v0.3.2",
30
+ "date": "Thu, 11 Sep 2025 00:22:31 GMT",
31
+ "comments": {
32
+ "dependency": [
33
+ {
34
+ "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`"
35
+ }
36
+ ]
37
+ }
38
+ },
4
39
  {
5
40
  "version": "0.3.1",
6
41
  "tag": "@rushstack/operation-graph_v0.3.1",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
1
  # Change Log - @rushstack/operation-graph
2
2
 
3
- This log was last generated on Wed, 23 Jul 2025 20:55:57 GMT and should not be manually modified.
3
+ This log was last generated on Tue, 30 Sep 2025 20:33:51 GMT and should not be manually modified.
4
+
5
+ ## 0.4.0
6
+ Tue, 30 Sep 2025 20:33:51 GMT
7
+
8
+ ### Minor changes
9
+
10
+ - Require the "requestor" parameter and add a new "detail" parameter for watch-mode rerun requests. Make "name" a required field for operations.
11
+ - (BREAKING CHANGE) Revert the extensibility points for `(before/after)ExecuteOperation(Group)?Async` to be synchronous to signify that they are only meant for logging, not for expensive work.
12
+
13
+ ## 0.3.2
14
+ Thu, 11 Sep 2025 00:22:31 GMT
15
+
16
+ _Version update only_
4
17
 
5
18
  ## 0.3.1
6
19
  Wed, 23 Jul 2025 20:55:57 GMT
@@ -42,11 +42,11 @@ export declare interface IExecuteOperationContext extends Omit<IOperationRunnerC
42
42
  /**
43
43
  * Function to invoke before execution of an operation, for logging.
44
44
  */
45
- beforeExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
45
+ beforeExecute(operation: Operation, state: IOperationState): void;
46
46
  /**
47
47
  * Function to invoke after execution of an operation, for logging.
48
48
  */
49
- afterExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
49
+ afterExecute(operation: Operation, state: IOperationState): void;
50
50
  /**
51
51
  * Function used to schedule the concurrency-limited execution of an operation.
52
52
  *
@@ -56,8 +56,11 @@ export declare interface IExecuteOperationContext extends Omit<IOperationRunnerC
56
56
  /**
57
57
  * A callback to the overarching orchestrator to request that the operation be invoked again.
58
58
  * Used in watch mode to signal that inputs have changed.
59
+ *
60
+ * @param requestor - The name of the operation requesting a rerun.
61
+ * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.
59
62
  */
60
- requestRun?: (requestor?: string) => void;
63
+ requestRun?: OperationRequestRunCallback;
61
64
  /**
62
65
  * Terminal to write output to.
63
66
  */
@@ -82,11 +85,11 @@ export declare interface IOperationExecutionOptions<TOperationMetadata extends {
82
85
  abortSignal: AbortSignal;
83
86
  parallelism: number;
84
87
  terminal: ITerminal;
85
- requestRun?: (requestor?: string) => void;
86
- beforeExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
87
- afterExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
88
- beforeExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
89
- afterExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
88
+ requestRun?: OperationRequestRunCallback;
89
+ beforeExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
90
+ afterExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
91
+ beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
92
+ afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
90
93
  }
91
94
 
92
95
  /**
@@ -97,7 +100,7 @@ export declare interface IOperationOptions<TMetadata extends {} = {}, TGroupMeta
97
100
  /**
98
101
  * The name of this operation, for logging.
99
102
  */
100
- name?: string | undefined;
103
+ name: string;
101
104
  /**
102
105
  * The group that this operation belongs to. Will be used for logging and duration tracking.
103
106
  */
@@ -157,8 +160,10 @@ export declare interface IOperationRunnerContext {
157
160
  /**
158
161
  * A callback to the overarching orchestrator to request that the operation be invoked again.
159
162
  * Used in watch mode to signal that inputs have changed.
163
+ *
164
+ * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.
160
165
  */
161
- requestRun?: () => void;
166
+ requestRun?: (detail?: string) => void;
162
167
  }
163
168
 
164
169
  /**
@@ -215,7 +220,14 @@ export declare type IPCHost = Pick<typeof process, 'on' | 'send'>;
215
220
  */
216
221
  export declare interface IRequestRunEventMessage {
217
222
  event: 'requestRun';
218
- requestor?: string;
223
+ /**
224
+ * The name of the operation requesting a rerun.
225
+ */
226
+ requestor: string;
227
+ /**
228
+ * Optional detail about why the rerun is requested, e.g. the name of a changed file.
229
+ */
230
+ detail?: string;
219
231
  }
220
232
 
221
233
  /**
@@ -263,8 +275,11 @@ export declare interface IWatchLoopOptions {
263
275
  onBeforeExecute: () => void;
264
276
  /**
265
277
  * Logging callback when a run is requested (and hasn't already been).
278
+ *
279
+ * @param requestor - The name of the operation requesting a rerun.
280
+ * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.
266
281
  */
267
- onRequestRun: (requestor?: string) => void;
282
+ onRequestRun: OperationRequestRunCallback;
268
283
  /**
269
284
  * Logging callback when a run is aborted.
270
285
  */
@@ -278,7 +293,7 @@ export declare interface IWatchLoopOptions {
278
293
  */
279
294
  export declare interface IWatchLoopState {
280
295
  get abortSignal(): AbortSignal;
281
- requestRun: (requestor?: string) => void;
296
+ requestRun: OperationRequestRunCallback;
282
297
  }
283
298
 
284
299
  /**
@@ -306,7 +321,7 @@ export declare class Operation<TMetadata extends {} = {}, TGroupMetadata extends
306
321
  /**
307
322
  * The name of this operation, for logging.
308
323
  */
309
- readonly name: string | undefined;
324
+ readonly name: string;
310
325
  /**
311
326
  * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of
312
327
  * running the operation.
@@ -372,7 +387,7 @@ export declare class Operation<TMetadata extends {} = {}, TGroupMetadata extends
372
387
  */
373
388
  private _runPending;
374
389
  readonly metadata: TMetadata;
375
- constructor(options?: IOperationOptions<TMetadata, TGroupMetadata>);
390
+ constructor(options: IOperationOptions<TMetadata, TGroupMetadata>);
376
391
  addDependency(dependency: Operation<TMetadata, TGroupMetadata>): void;
377
392
  deleteDependency(dependency: Operation<TMetadata, TGroupMetadata>): void;
378
393
  reset(): void;
@@ -446,6 +461,12 @@ export declare class OperationGroupRecord<TMetadata extends {} = {}> {
446
461
  reset(): void;
447
462
  }
448
463
 
464
+ /**
465
+ * Type for the `requestRun` callback.
466
+ * @beta
467
+ */
468
+ export declare type OperationRequestRunCallback = (requestor: string, detail?: string) => void;
469
+
449
470
  /**
450
471
  * Enumeration defining potential states of an operation
451
472
  * @beta
@@ -561,7 +582,7 @@ export declare class WatchLoop implements IWatchLoopState {
561
582
  /**
562
583
  * Requests that a new run occur.
563
584
  */
564
- requestRun: (requestor?: string) => void;
585
+ requestRun: OperationRequestRunCallback;
565
586
  /**
566
587
  * The abort signal for the current iteration.
567
588
  */
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.52.8"
8
+ "packageVersion": "7.52.11"
9
9
  }
10
10
  ]
11
11
  }
@@ -19,8 +19,10 @@ export interface IOperationRunnerContext {
19
19
  /**
20
20
  * A callback to the overarching orchestrator to request that the operation be invoked again.
21
21
  * Used in watch mode to signal that inputs have changed.
22
+ *
23
+ * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.
22
24
  */
23
- requestRun?: () => void;
25
+ requestRun?: (detail?: string) => void;
24
26
  }
25
27
  /**
26
28
  * Interface contract for a single state of an operation.
@@ -1 +1 @@
1
- {"version":3,"file":"IOperationRunner.d.ts","sourceRoot":"","sources":["../src/IOperationRunner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC;IAEzB;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,MAAM,EAAE,eAAe,CAAC;IACxB;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,cAAc,GAAG,SAAS,CAAC;IAClC;;OAEG;IACH,SAAS,EAAE,SAAS,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;IACtD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;CAC3D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC1E"}
1
+ {"version":3,"file":"IOperationRunner.d.ts","sourceRoot":"","sources":["../src/IOperationRunner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC;IAEzB;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,MAAM,EAAE,eAAe,CAAC;IACxB;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,cAAc,GAAG,SAAS,CAAC;IAClC;;OAEG;IACH,SAAS,EAAE,SAAS,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;IACtD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;CAC3D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"IOperationRunner.js","sourceRoot":"","sources":["../src/IOperationRunner.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { OperationStatus } from './OperationStatus';\nimport type { OperationError } from './OperationError';\n\nimport type { Stopwatch } from './Stopwatch';\n\n/**\n * Information passed to the executing `IOperationRunner`\n *\n * @beta\n */\nexport interface IOperationRunnerContext {\n /**\n * An abort signal for the overarching execution. Runners should do their best to gracefully abort\n * as soon as possible if the signal is aborted.\n */\n abortSignal: AbortSignal;\n\n /**\n * If this is the first time this operation has been executed.\n */\n isFirstRun: boolean;\n\n /**\n * A callback to the overarching orchestrator to request that the operation be invoked again.\n * Used in watch mode to signal that inputs have changed.\n */\n requestRun?: () => void;\n}\n\n/**\n * Interface contract for a single state of an operation.\n *\n * @beta\n */\nexport interface IOperationState {\n /**\n * The status code for the operation.\n */\n status: OperationStatus;\n /**\n * Whether the operation has been run at least once.\n */\n hasBeenRun: boolean;\n /**\n * The error, if the status is `OperationStatus.Failure`.\n */\n error: OperationError | undefined;\n /**\n * Timing information for the operation.\n */\n stopwatch: Stopwatch;\n}\n\n/**\n * Interface contract for the current and past state of an operation.\n *\n * @beta\n */\nexport interface IOperationStates {\n /**\n * The current state of the operation.\n */\n readonly state: Readonly<IOperationState> | undefined;\n /**\n * The previous state of the operation.\n */\n readonly lastState: Readonly<IOperationState> | undefined;\n}\n\n/**\n * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the\n * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose\n * implementation manages the actual process for running a single operation.\n *\n * @beta\n */\nexport interface IOperationRunner {\n /**\n * Name of the operation, for logging.\n */\n readonly name: string;\n\n /**\n * Indicates that this runner is architectural and should not be reported on.\n */\n silent: boolean;\n\n /**\n * Method to be executed for the operation.\n */\n executeAsync(context: IOperationRunnerContext): Promise<OperationStatus>;\n}\n"]}
1
+ {"version":3,"file":"IOperationRunner.js","sourceRoot":"","sources":["../src/IOperationRunner.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { OperationStatus } from './OperationStatus';\nimport type { OperationError } from './OperationError';\n\nimport type { Stopwatch } from './Stopwatch';\n\n/**\n * Information passed to the executing `IOperationRunner`\n *\n * @beta\n */\nexport interface IOperationRunnerContext {\n /**\n * An abort signal for the overarching execution. Runners should do their best to gracefully abort\n * as soon as possible if the signal is aborted.\n */\n abortSignal: AbortSignal;\n\n /**\n * If this is the first time this operation has been executed.\n */\n isFirstRun: boolean;\n\n /**\n * A callback to the overarching orchestrator to request that the operation be invoked again.\n * Used in watch mode to signal that inputs have changed.\n *\n * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.\n */\n requestRun?: (detail?: string) => void;\n}\n\n/**\n * Interface contract for a single state of an operation.\n *\n * @beta\n */\nexport interface IOperationState {\n /**\n * The status code for the operation.\n */\n status: OperationStatus;\n /**\n * Whether the operation has been run at least once.\n */\n hasBeenRun: boolean;\n /**\n * The error, if the status is `OperationStatus.Failure`.\n */\n error: OperationError | undefined;\n /**\n * Timing information for the operation.\n */\n stopwatch: Stopwatch;\n}\n\n/**\n * Interface contract for the current and past state of an operation.\n *\n * @beta\n */\nexport interface IOperationStates {\n /**\n * The current state of the operation.\n */\n readonly state: Readonly<IOperationState> | undefined;\n /**\n * The previous state of the operation.\n */\n readonly lastState: Readonly<IOperationState> | undefined;\n}\n\n/**\n * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the\n * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose\n * implementation manages the actual process for running a single operation.\n *\n * @beta\n */\nexport interface IOperationRunner {\n /**\n * Name of the operation, for logging.\n */\n readonly name: string;\n\n /**\n * Indicates that this runner is architectural and should not be reported on.\n */\n silent: boolean;\n\n /**\n * Method to be executed for the operation.\n */\n executeAsync(context: IOperationRunnerContext): Promise<OperationStatus>;\n}\n"]}
@@ -10,7 +10,7 @@ export interface IOperationOptions<TMetadata extends {} = {}, TGroupMetadata ext
10
10
  /**
11
11
  * The name of this operation, for logging.
12
12
  */
13
- name?: string | undefined;
13
+ name: string;
14
14
  /**
15
15
  * The group that this operation belongs to. Will be used for logging and duration tracking.
16
16
  */
@@ -29,6 +29,11 @@ export interface IOperationOptions<TMetadata extends {} = {}, TGroupMetadata ext
29
29
  */
30
30
  metadata?: TMetadata | undefined;
31
31
  }
32
+ /**
33
+ * Type for the `requestRun` callback.
34
+ * @beta
35
+ */
36
+ export type OperationRequestRunCallback = (requestor: string, detail?: string) => void;
32
37
  /**
33
38
  * Information provided to `executeAsync` by the `OperationExecutionManager`.
34
39
  *
@@ -38,11 +43,11 @@ export interface IExecuteOperationContext extends Omit<IOperationRunnerContext,
38
43
  /**
39
44
  * Function to invoke before execution of an operation, for logging.
40
45
  */
41
- beforeExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
46
+ beforeExecute(operation: Operation, state: IOperationState): void;
42
47
  /**
43
48
  * Function to invoke after execution of an operation, for logging.
44
49
  */
45
- afterExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
50
+ afterExecute(operation: Operation, state: IOperationState): void;
46
51
  /**
47
52
  * Function used to schedule the concurrency-limited execution of an operation.
48
53
  *
@@ -52,8 +57,11 @@ export interface IExecuteOperationContext extends Omit<IOperationRunnerContext,
52
57
  /**
53
58
  * A callback to the overarching orchestrator to request that the operation be invoked again.
54
59
  * Used in watch mode to signal that inputs have changed.
60
+ *
61
+ * @param requestor - The name of the operation requesting a rerun.
62
+ * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.
55
63
  */
56
- requestRun?: (requestor?: string) => void;
64
+ requestRun?: OperationRequestRunCallback;
57
65
  /**
58
66
  * Terminal to write output to.
59
67
  */
@@ -84,7 +92,7 @@ export declare class Operation<TMetadata extends {} = {}, TGroupMetadata extends
84
92
  /**
85
93
  * The name of this operation, for logging.
86
94
  */
87
- readonly name: string | undefined;
95
+ readonly name: string;
88
96
  /**
89
97
  * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of
90
98
  * running the operation.
@@ -150,7 +158,7 @@ export declare class Operation<TMetadata extends {} = {}, TGroupMetadata extends
150
158
  */
151
159
  private _runPending;
152
160
  readonly metadata: TMetadata;
153
- constructor(options?: IOperationOptions<TMetadata, TGroupMetadata>);
161
+ constructor(options: IOperationOptions<TMetadata, TGroupMetadata>);
154
162
  addDependency(dependency: Operation<TMetadata, TGroupMetadata>): void;
155
163
  deleteDependency(dependency: Operation<TMetadata, TGroupMetadata>): void;
156
164
  reset(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"Operation.d.ts","sourceRoot":"","sources":["../src/Operation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Operation.d.ts","sourceRoot":"","sources":["../src/Operation.ts"],"names":[],"mappings":"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"}
package/lib/Operation.js CHANGED
@@ -77,11 +77,11 @@ class Operation {
77
77
  * This is used to track state from the `requestRun` callback passed to the runner.
78
78
  */
79
79
  this._runPending = true;
80
- this.group = options?.group;
81
- this.runner = options?.runner;
82
- this.weight = options?.weight || 1;
83
- this.name = options?.name;
84
- this.metadata = options?.metadata || {};
80
+ this.group = options.group;
81
+ this.runner = options.runner;
82
+ this.weight = options.weight ?? 1;
83
+ this.name = options.name;
84
+ this.metadata = options.metadata || {};
85
85
  if (this.group) {
86
86
  this.group.addOperation(this);
87
87
  }
@@ -141,7 +141,7 @@ class Operation {
141
141
  abortSignal,
142
142
  isFirstRun: !state.hasBeenRun,
143
143
  requestRun: requestRun
144
- ? () => {
144
+ ? (detail) => {
145
145
  switch (this.state?.status) {
146
146
  case OperationStatus_1.OperationStatus.Waiting:
147
147
  case OperationStatus_1.OperationStatus.Ready:
@@ -162,7 +162,7 @@ class Operation {
162
162
  // The requestRun callback is assumed to remain constant
163
163
  // throughout the lifetime of the process, so it is safe
164
164
  // to capture here.
165
- return requestRun(this.name);
165
+ return requestRun(this.name, detail);
166
166
  default:
167
167
  // This line is here to enforce exhaustiveness
168
168
  const currentStatus = this.state?.status;
@@ -179,7 +179,7 @@ class Operation {
179
179
  innerState.status = OperationStatus_1.OperationStatus.Aborted;
180
180
  return innerState.status;
181
181
  }
182
- await context.beforeExecuteAsync(this, innerState);
182
+ context.beforeExecute(this, innerState);
183
183
  innerState.stopwatch.start();
184
184
  innerState.status = OperationStatus_1.OperationStatus.Executing;
185
185
  // Mark that the operation has been started at least once.
@@ -212,7 +212,7 @@ class Operation {
212
212
  }
213
213
  }
214
214
  state.stopwatch.stop();
215
- await context.afterExecuteAsync(this, state);
215
+ context.afterExecute(this, state);
216
216
  return state.status;
217
217
  }, /* priority */ this.criticalPathLength ?? 0);
218
218
  return state.status;
@@ -1 +1 @@
1
- {"version":3,"file":"Operation.js","sourceRoot":"","sources":["../src/Operation.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport { Stopwatch } from './Stopwatch';\nimport type {\n IOperationRunner,\n IOperationRunnerContext,\n IOperationState,\n IOperationStates\n} from './IOperationRunner';\nimport type { OperationError } from './OperationError';\nimport { OperationStatus } from './OperationStatus';\nimport type { OperationGroupRecord } from './OperationGroupRecord';\n\n/**\n * Options for constructing a new Operation.\n * @beta\n */\nexport interface IOperationOptions<TMetadata extends {} = {}, TGroupMetadata extends {} = {}> {\n /**\n * The name of this operation, for logging.\n */\n name?: string | undefined;\n\n /**\n * The group that this operation belongs to. Will be used for logging and duration tracking.\n */\n group?: OperationGroupRecord<TGroupMetadata> | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n runner?: IOperationRunner | undefined;\n\n /**\n * The weight used by the scheduler to determine order of execution.\n */\n weight?: number | undefined;\n\n /**\n * The metadata for this operation.\n */\n metadata?: TMetadata | undefined;\n}\n\n/**\n * Information provided to `executeAsync` by the `OperationExecutionManager`.\n *\n * @beta\n */\nexport interface IExecuteOperationContext extends Omit<IOperationRunnerContext, 'isFirstRun' | 'requestRun'> {\n /**\n * Function to invoke before execution of an operation, for logging.\n */\n beforeExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;\n\n /**\n * Function to invoke after execution of an operation, for logging.\n */\n afterExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;\n\n /**\n * Function used to schedule the concurrency-limited execution of an operation.\n *\n * Will return OperationStatus.Aborted if execution is aborted before the task executes.\n */\n queueWork(workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus>;\n\n /**\n * A callback to the overarching orchestrator to request that the operation be invoked again.\n * Used in watch mode to signal that inputs have changed.\n */\n requestRun?: (requestor?: string) => void;\n\n /**\n * Terminal to write output to.\n */\n terminal: ITerminal;\n}\n\n/**\n * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the\n * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose\n * implementation manages the actual process of running a single operation.\n *\n * The graph of `Operation` instances will be cloned into a separate execution graph after processing.\n *\n * @beta\n */\nexport class Operation<TMetadata extends {} = {}, TGroupMetadata extends {} = {}>\n implements IOperationStates\n{\n /**\n * A set of all dependencies which must be executed before this operation is complete.\n */\n public readonly dependencies: Set<Operation<TMetadata, TGroupMetadata>> = new Set<\n Operation<TMetadata, TGroupMetadata>\n >();\n /**\n * A set of all operations that wait for this operation.\n */\n public readonly consumers: Set<Operation<TMetadata, TGroupMetadata>> = new Set<\n Operation<TMetadata, TGroupMetadata>\n >();\n /**\n * If specified, the name of a grouping to which this Operation belongs, for logging start and end times.\n */\n public readonly group: OperationGroupRecord<TGroupMetadata> | undefined;\n /**\n * The name of this operation, for logging.\n */\n public readonly name: string | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n public runner: IOperationRunner | undefined = undefined;\n\n /**\n * This number represents how far away this Operation is from the furthest \"root\" operation (i.e.\n * an operation with no consumers). This helps us to calculate the critical path (i.e. the\n * longest chain of projects which must be executed in order, thereby limiting execution speed\n * of the entire operation tree.\n *\n * This number is calculated via a memoized depth-first search, and when choosing the next\n * operation to execute, the operation with the highest criticalPathLength is chosen.\n *\n * Example:\n * (0) A\n * \\\\\n * (1) B C (0) (applications)\n * \\\\ /|\\\\\n * \\\\ / | \\\\\n * (2) D | X (1) (utilities)\n * | / \\\\\n * |/ \\\\\n * (2) Y Z (2) (other utilities)\n *\n * All roots (A & C) have a criticalPathLength of 0.\n * B has a score of 1, since A depends on it.\n * D has a score of 2, since we look at the longest chain (e.g D-\\>B-\\>A is longer than D-\\>C)\n * X has a score of 1, since the only package which depends on it is A\n * Z has a score of 2, since only X depends on it, and X has a score of 1\n * Y has a score of 2, since the chain Y-\\>X-\\>C is longer than Y-\\>C\n *\n * The algorithm is implemented in AsyncOperationQueue.ts as calculateCriticalPathLength()\n */\n public criticalPathLength: number | undefined = undefined;\n\n /**\n * The weight for this operation. This scalar is the contribution of this operation to the\n * `criticalPathLength` calculation above. Modify to indicate the following:\n * - `weight` === 1: indicates that this operation has an average duration\n * - `weight` &gt; 1: indicates that this operation takes longer than average and so the scheduler\n * should try to favor starting it over other, shorter operations. An example might be an operation that\n * bundles an entire application and runs whole-program optimization.\n * - `weight` &lt; 1: indicates that this operation takes less time than average and so the scheduler\n * should favor other, longer operations over it. An example might be an operation to unpack a cached\n * output, or an operation using NullOperationRunner, which might use a value of 0.\n */\n public weight: number;\n\n /**\n * The state of this operation the previous time a manager was invoked.\n */\n public lastState: IOperationState | undefined = undefined;\n\n /**\n * The current state of this operation\n */\n public state: IOperationState | undefined = undefined;\n\n /**\n * A cached execution promise for the current OperationExecutionManager invocation of this operation.\n */\n private _promise: Promise<OperationStatus> | undefined = undefined;\n\n /**\n * If true, then a run of this operation is currently wanted.\n * This is used to track state from the `requestRun` callback passed to the runner.\n */\n private _runPending: boolean = true;\n\n public readonly metadata: TMetadata;\n\n public constructor(options?: IOperationOptions<TMetadata, TGroupMetadata>) {\n this.group = options?.group;\n this.runner = options?.runner;\n this.weight = options?.weight || 1;\n this.name = options?.name;\n this.metadata = options?.metadata || ({} as TMetadata);\n\n if (this.group) {\n this.group.addOperation(this);\n }\n }\n\n public addDependency(dependency: Operation<TMetadata, TGroupMetadata>): void {\n this.dependencies.add(dependency);\n dependency.consumers.add(this);\n }\n\n public deleteDependency(dependency: Operation<TMetadata, TGroupMetadata>): void {\n this.dependencies.delete(dependency);\n dependency.consumers.delete(this);\n }\n\n public reset(): void {\n // Reset operation state\n this.lastState = this.state;\n\n this.state = {\n status: this.dependencies.size > 0 ? OperationStatus.Waiting : OperationStatus.Ready,\n hasBeenRun: this.lastState?.hasBeenRun ?? false,\n error: undefined,\n stopwatch: new Stopwatch()\n };\n\n this._promise = undefined;\n this._runPending = true;\n }\n\n /**\n * @internal\n */\n public async _executeAsync(context: IExecuteOperationContext): Promise<OperationStatus> {\n const { state } = this;\n if (!state) {\n throw new Error(`Operation state has not been initialized.`);\n }\n\n if (!this._promise) {\n this._promise = this._executeInnerAsync(context, state);\n }\n\n return this._promise;\n }\n\n private async _executeInnerAsync(\n context: IExecuteOperationContext,\n rawState: IOperationState\n ): Promise<OperationStatus> {\n const state: IOperationState = rawState;\n const { runner } = this;\n\n const dependencyResults: PromiseSettledResult<OperationStatus>[] = await Promise.allSettled(\n Array.from(this.dependencies, (dependency: Operation) => dependency._executeAsync(context))\n );\n\n const { abortSignal, requestRun, queueWork } = context;\n\n if (abortSignal.aborted) {\n state.status = OperationStatus.Aborted;\n return state.status;\n }\n\n for (const result of dependencyResults) {\n if (\n result.status === 'rejected' ||\n result.value === OperationStatus.Blocked ||\n result.value === OperationStatus.Failure\n ) {\n state.status = OperationStatus.Blocked;\n return state.status;\n }\n }\n\n state.status = OperationStatus.Ready;\n\n const innerContext: IOperationRunnerContext = {\n abortSignal,\n isFirstRun: !state.hasBeenRun,\n requestRun: requestRun\n ? () => {\n switch (this.state?.status) {\n case OperationStatus.Waiting:\n case OperationStatus.Ready:\n case OperationStatus.Executing:\n // If current status has not yet resolved to a fixed value,\n // re-executing this operation does not require a full rerun\n // of the operation graph. Simply mark that a run is requested.\n\n // This variable is on the Operation instead of the\n // containing closure to deal with scenarios in which\n // the runner hangs on to an old copy of the callback.\n this._runPending = true;\n return;\n\n case OperationStatus.Blocked:\n case OperationStatus.Aborted:\n case OperationStatus.Failure:\n case OperationStatus.NoOp:\n case OperationStatus.Success:\n // The requestRun callback is assumed to remain constant\n // throughout the lifetime of the process, so it is safe\n // to capture here.\n return requestRun(this.name);\n default:\n // This line is here to enforce exhaustiveness\n const currentStatus: undefined = this.state?.status;\n throw new InternalError(`Unexpected status: ${currentStatus}`);\n }\n }\n : undefined\n };\n\n // eslint-disable-next-line require-atomic-updates\n state.status = await queueWork(async (): Promise<OperationStatus> => {\n // Redundant variable to satisfy require-atomic-updates\n const innerState: IOperationState = state;\n\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n return innerState.status;\n }\n\n await context.beforeExecuteAsync(this, innerState);\n\n innerState.stopwatch.start();\n innerState.status = OperationStatus.Executing;\n // Mark that the operation has been started at least once.\n innerState.hasBeenRun = true;\n\n while (this._runPending) {\n this._runPending = false;\n try {\n // We don't support aborting in the middle of a runner's execution.\n innerState.status = runner ? await runner.executeAsync(innerContext) : OperationStatus.NoOp;\n } catch (error) {\n innerState.status = OperationStatus.Failure;\n innerState.error = error as OperationError;\n }\n\n // Since runner.executeAsync is async, a change could have occurred that requires re-execution\n // This operation is still active, so can re-execute immediately, rather than forcing a whole\n // new execution pass.\n\n // As currently written, this does mean that if a job is scheduled with higher priority while\n // this operation is still executing, it will still wait for this retry. This may not be desired\n // and if it becomes a problem, the retry loop will need to be moved outside of the `queueWork` call.\n // This introduces complexity regarding tracking of timing and start/end logging, however.\n\n if (this._runPending) {\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n break;\n } else {\n context.terminal.writeLine(`Immediate rerun requested. Executing.`);\n }\n }\n }\n\n state.stopwatch.stop();\n await context.afterExecuteAsync(this, state);\n\n return state.status;\n }, /* priority */ this.criticalPathLength ?? 0);\n\n return state.status;\n }\n}\n"]}
1
+ {"version":3,"file":"Operation.js","sourceRoot":"","sources":["../src/Operation.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport { Stopwatch } from './Stopwatch';\nimport type {\n IOperationRunner,\n IOperationRunnerContext,\n IOperationState,\n IOperationStates\n} from './IOperationRunner';\nimport type { OperationError } from './OperationError';\nimport { OperationStatus } from './OperationStatus';\nimport type { OperationGroupRecord } from './OperationGroupRecord';\n\n/**\n * Options for constructing a new Operation.\n * @beta\n */\nexport interface IOperationOptions<TMetadata extends {} = {}, TGroupMetadata extends {} = {}> {\n /**\n * The name of this operation, for logging.\n */\n name: string;\n\n /**\n * The group that this operation belongs to. Will be used for logging and duration tracking.\n */\n group?: OperationGroupRecord<TGroupMetadata> | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n runner?: IOperationRunner | undefined;\n\n /**\n * The weight used by the scheduler to determine order of execution.\n */\n weight?: number | undefined;\n\n /**\n * The metadata for this operation.\n */\n metadata?: TMetadata | undefined;\n}\n\n/**\n * Type for the `requestRun` callback.\n * @beta\n */\nexport type OperationRequestRunCallback = (requestor: string, detail?: string) => void;\n\n/**\n * Information provided to `executeAsync` by the `OperationExecutionManager`.\n *\n * @beta\n */\nexport interface IExecuteOperationContext extends Omit<IOperationRunnerContext, 'isFirstRun' | 'requestRun'> {\n /**\n * Function to invoke before execution of an operation, for logging.\n */\n beforeExecute(operation: Operation, state: IOperationState): void;\n\n /**\n * Function to invoke after execution of an operation, for logging.\n */\n afterExecute(operation: Operation, state: IOperationState): void;\n\n /**\n * Function used to schedule the concurrency-limited execution of an operation.\n *\n * Will return OperationStatus.Aborted if execution is aborted before the task executes.\n */\n queueWork(workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus>;\n\n /**\n * A callback to the overarching orchestrator to request that the operation be invoked again.\n * Used in watch mode to signal that inputs have changed.\n *\n * @param requestor - The name of the operation requesting a rerun.\n * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.\n */\n requestRun?: OperationRequestRunCallback;\n\n /**\n * Terminal to write output to.\n */\n terminal: ITerminal;\n}\n\n/**\n * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the\n * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose\n * implementation manages the actual process of running a single operation.\n *\n * The graph of `Operation` instances will be cloned into a separate execution graph after processing.\n *\n * @beta\n */\nexport class Operation<TMetadata extends {} = {}, TGroupMetadata extends {} = {}>\n implements IOperationStates\n{\n /**\n * A set of all dependencies which must be executed before this operation is complete.\n */\n public readonly dependencies: Set<Operation<TMetadata, TGroupMetadata>> = new Set<\n Operation<TMetadata, TGroupMetadata>\n >();\n /**\n * A set of all operations that wait for this operation.\n */\n public readonly consumers: Set<Operation<TMetadata, TGroupMetadata>> = new Set<\n Operation<TMetadata, TGroupMetadata>\n >();\n /**\n * If specified, the name of a grouping to which this Operation belongs, for logging start and end times.\n */\n public readonly group: OperationGroupRecord<TGroupMetadata> | undefined;\n /**\n * The name of this operation, for logging.\n */\n public readonly name: string;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n public runner: IOperationRunner | undefined = undefined;\n\n /**\n * This number represents how far away this Operation is from the furthest \"root\" operation (i.e.\n * an operation with no consumers). This helps us to calculate the critical path (i.e. the\n * longest chain of projects which must be executed in order, thereby limiting execution speed\n * of the entire operation tree.\n *\n * This number is calculated via a memoized depth-first search, and when choosing the next\n * operation to execute, the operation with the highest criticalPathLength is chosen.\n *\n * Example:\n * (0) A\n * \\\\\n * (1) B C (0) (applications)\n * \\\\ /|\\\\\n * \\\\ / | \\\\\n * (2) D | X (1) (utilities)\n * | / \\\\\n * |/ \\\\\n * (2) Y Z (2) (other utilities)\n *\n * All roots (A & C) have a criticalPathLength of 0.\n * B has a score of 1, since A depends on it.\n * D has a score of 2, since we look at the longest chain (e.g D-\\>B-\\>A is longer than D-\\>C)\n * X has a score of 1, since the only package which depends on it is A\n * Z has a score of 2, since only X depends on it, and X has a score of 1\n * Y has a score of 2, since the chain Y-\\>X-\\>C is longer than Y-\\>C\n *\n * The algorithm is implemented in AsyncOperationQueue.ts as calculateCriticalPathLength()\n */\n public criticalPathLength: number | undefined = undefined;\n\n /**\n * The weight for this operation. This scalar is the contribution of this operation to the\n * `criticalPathLength` calculation above. Modify to indicate the following:\n * - `weight` === 1: indicates that this operation has an average duration\n * - `weight` &gt; 1: indicates that this operation takes longer than average and so the scheduler\n * should try to favor starting it over other, shorter operations. An example might be an operation that\n * bundles an entire application and runs whole-program optimization.\n * - `weight` &lt; 1: indicates that this operation takes less time than average and so the scheduler\n * should favor other, longer operations over it. An example might be an operation to unpack a cached\n * output, or an operation using NullOperationRunner, which might use a value of 0.\n */\n public weight: number;\n\n /**\n * The state of this operation the previous time a manager was invoked.\n */\n public lastState: IOperationState | undefined = undefined;\n\n /**\n * The current state of this operation\n */\n public state: IOperationState | undefined = undefined;\n\n /**\n * A cached execution promise for the current OperationExecutionManager invocation of this operation.\n */\n private _promise: Promise<OperationStatus> | undefined = undefined;\n\n /**\n * If true, then a run of this operation is currently wanted.\n * This is used to track state from the `requestRun` callback passed to the runner.\n */\n private _runPending: boolean = true;\n\n public readonly metadata: TMetadata;\n\n public constructor(options: IOperationOptions<TMetadata, TGroupMetadata>) {\n this.group = options.group;\n this.runner = options.runner;\n this.weight = options.weight ?? 1;\n this.name = options.name;\n this.metadata = options.metadata || ({} as TMetadata);\n\n if (this.group) {\n this.group.addOperation(this);\n }\n }\n\n public addDependency(dependency: Operation<TMetadata, TGroupMetadata>): void {\n this.dependencies.add(dependency);\n dependency.consumers.add(this);\n }\n\n public deleteDependency(dependency: Operation<TMetadata, TGroupMetadata>): void {\n this.dependencies.delete(dependency);\n dependency.consumers.delete(this);\n }\n\n public reset(): void {\n // Reset operation state\n this.lastState = this.state;\n\n this.state = {\n status: this.dependencies.size > 0 ? OperationStatus.Waiting : OperationStatus.Ready,\n hasBeenRun: this.lastState?.hasBeenRun ?? false,\n error: undefined,\n stopwatch: new Stopwatch()\n };\n\n this._promise = undefined;\n this._runPending = true;\n }\n\n /**\n * @internal\n */\n public async _executeAsync(context: IExecuteOperationContext): Promise<OperationStatus> {\n const { state } = this;\n if (!state) {\n throw new Error(`Operation state has not been initialized.`);\n }\n\n if (!this._promise) {\n this._promise = this._executeInnerAsync(context, state);\n }\n\n return this._promise;\n }\n\n private async _executeInnerAsync(\n context: IExecuteOperationContext,\n rawState: IOperationState\n ): Promise<OperationStatus> {\n const state: IOperationState = rawState;\n const { runner } = this;\n\n const dependencyResults: PromiseSettledResult<OperationStatus>[] = await Promise.allSettled(\n Array.from(this.dependencies, (dependency: Operation) => dependency._executeAsync(context))\n );\n\n const { abortSignal, requestRun, queueWork } = context;\n\n if (abortSignal.aborted) {\n state.status = OperationStatus.Aborted;\n return state.status;\n }\n\n for (const result of dependencyResults) {\n if (\n result.status === 'rejected' ||\n result.value === OperationStatus.Blocked ||\n result.value === OperationStatus.Failure\n ) {\n state.status = OperationStatus.Blocked;\n return state.status;\n }\n }\n\n state.status = OperationStatus.Ready;\n\n const innerContext: IOperationRunnerContext = {\n abortSignal,\n isFirstRun: !state.hasBeenRun,\n requestRun: requestRun\n ? (detail?: string) => {\n switch (this.state?.status) {\n case OperationStatus.Waiting:\n case OperationStatus.Ready:\n case OperationStatus.Executing:\n // If current status has not yet resolved to a fixed value,\n // re-executing this operation does not require a full rerun\n // of the operation graph. Simply mark that a run is requested.\n\n // This variable is on the Operation instead of the\n // containing closure to deal with scenarios in which\n // the runner hangs on to an old copy of the callback.\n this._runPending = true;\n return;\n\n case OperationStatus.Blocked:\n case OperationStatus.Aborted:\n case OperationStatus.Failure:\n case OperationStatus.NoOp:\n case OperationStatus.Success:\n // The requestRun callback is assumed to remain constant\n // throughout the lifetime of the process, so it is safe\n // to capture here.\n return requestRun(this.name, detail);\n default:\n // This line is here to enforce exhaustiveness\n const currentStatus: undefined = this.state?.status;\n throw new InternalError(`Unexpected status: ${currentStatus}`);\n }\n }\n : undefined\n };\n\n // eslint-disable-next-line require-atomic-updates\n state.status = await queueWork(async (): Promise<OperationStatus> => {\n // Redundant variable to satisfy require-atomic-updates\n const innerState: IOperationState = state;\n\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n return innerState.status;\n }\n\n context.beforeExecute(this, innerState);\n\n innerState.stopwatch.start();\n innerState.status = OperationStatus.Executing;\n // Mark that the operation has been started at least once.\n innerState.hasBeenRun = true;\n\n while (this._runPending) {\n this._runPending = false;\n try {\n // We don't support aborting in the middle of a runner's execution.\n innerState.status = runner ? await runner.executeAsync(innerContext) : OperationStatus.NoOp;\n } catch (error) {\n innerState.status = OperationStatus.Failure;\n innerState.error = error as OperationError;\n }\n\n // Since runner.executeAsync is async, a change could have occurred that requires re-execution\n // This operation is still active, so can re-execute immediately, rather than forcing a whole\n // new execution pass.\n\n // As currently written, this does mean that if a job is scheduled with higher priority while\n // this operation is still executing, it will still wait for this retry. This may not be desired\n // and if it becomes a problem, the retry loop will need to be moved outside of the `queueWork` call.\n // This introduces complexity regarding tracking of timing and start/end logging, however.\n\n if (this._runPending) {\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n break;\n } else {\n context.terminal.writeLine(`Immediate rerun requested. Executing.`);\n }\n }\n }\n\n state.stopwatch.stop();\n context.afterExecute(this, state);\n\n return state.status;\n }, /* priority */ this.criticalPathLength ?? 0);\n\n return state.status;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { ITerminal } from '@rushstack/terminal';
2
- import type { Operation } from './Operation';
2
+ import type { Operation, OperationRequestRunCallback } from './Operation';
3
3
  import type { OperationGroupRecord } from './OperationGroupRecord';
4
4
  import { OperationStatus } from './OperationStatus';
5
5
  /**
@@ -11,11 +11,11 @@ export interface IOperationExecutionOptions<TOperationMetadata extends {} = {},
11
11
  abortSignal: AbortSignal;
12
12
  parallelism: number;
13
13
  terminal: ITerminal;
14
- requestRun?: (requestor?: string) => void;
15
- beforeExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
16
- afterExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
17
- beforeExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
18
- afterExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
14
+ requestRun?: OperationRequestRunCallback;
15
+ beforeExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
16
+ afterExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
17
+ beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
18
+ afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
19
19
  }
20
20
  /**
21
21
  * A class which manages the execution of a set of tasks with interdependencies.
@@ -1 +1 @@
1
- {"version":3,"file":"OperationExecutionManager.d.ts","sourceRoot":"","sources":["../src/OperationExecutionManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAA4B,SAAS,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;;GAIG;AACH,MAAM,WAAW,0BAA0B,CACzC,kBAAkB,SAAS,EAAE,GAAG,EAAE,EAClC,cAAc,SAAS,EAAE,GAAG,EAAE;IAE9B,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IAEpB,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAE1C,2BAA2B,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,cAAc,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1G,0BAA0B,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,cAAc,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzG,gCAAgC,CAAC,EAAE,CAAC,cAAc,EAAE,oBAAoB,CAAC,cAAc,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3G,+BAA+B,CAAC,EAAE,CAAC,cAAc,EAAE,oBAAoB,CAAC,cAAc,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3G;AAED;;;;;;;GAOG;AACH,qBAAa,yBAAyB,CAAC,kBAAkB,SAAS,EAAE,GAAG,EAAE,EAAE,cAAc,SAAS,EAAE,GAAG,EAAE;IACvG;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkD;IAC9E;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAEhD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4C;gBAEvD,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IA2BzF;;;OAGG;IACU,YAAY,CACvB,gBAAgB,EAAE,0BAA0B,CAAC,kBAAkB,EAAE,cAAc,CAAC,GAC/E,OAAO,CAAC,eAAe,CAAC;CAiI5B"}
1
+ {"version":3,"file":"OperationExecutionManager.d.ts","sourceRoot":"","sources":["../src/OperationExecutionManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAA4B,SAAS,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AACpG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;;GAIG;AACH,MAAM,WAAW,0BAA0B,CACzC,kBAAkB,SAAS,EAAE,GAAG,EAAE,EAClC,cAAc,SAAS,EAAE,GAAG,EAAE;IAE9B,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IAEpB,UAAU,CAAC,EAAE,2BAA2B,CAAC;IAEzC,sBAAsB,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,cAAc,CAAC,KAAK,IAAI,CAAC;IAC5F,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,cAAc,CAAC,KAAK,IAAI,CAAC;IAC3F,2BAA2B,CAAC,EAAE,CAAC,cAAc,EAAE,oBAAoB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAC7F,0BAA0B,CAAC,EAAE,CAAC,cAAc,EAAE,oBAAoB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;CAC7F;AAED;;;;;;;GAOG;AACH,qBAAa,yBAAyB,CAAC,kBAAkB,SAAS,EAAE,GAAG,EAAE,EAAE,cAAc,SAAS,EAAE,GAAG,EAAE;IACvG;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkD;IAC9E;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAEhD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4C;gBAEvD,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IA2BzF;;;OAGG;IACU,YAAY,CACvB,gBAAgB,EAAE,0BAA0B,CAAC,kBAAkB,EAAE,cAAc,CAAC,GAC/E,OAAO,CAAC,eAAe,CAAC;CA+H5B"}
@@ -68,7 +68,7 @@ class OperationExecutionManager {
68
68
  queueWork: (workFn, priority) => {
69
69
  return workQueue.pushAsync(workFn, priority);
70
70
  },
71
- beforeExecuteAsync: async (operation) => {
71
+ beforeExecute: (operation) => {
72
72
  // Initialize group if uninitialized and log the group name
73
73
  const { group, runner } = operation;
74
74
  if (group) {
@@ -76,14 +76,14 @@ class OperationExecutionManager {
76
76
  startedGroups.add(group);
77
77
  group.startTimer();
78
78
  terminal.writeLine(` ---- ${group.name} started ---- `);
79
- await executionOptions.beforeExecuteOperationGroupAsync?.(group);
79
+ executionOptions.beforeExecuteOperationGroup?.(group);
80
80
  }
81
81
  }
82
82
  if (!runner?.silent) {
83
- await executionOptions.beforeExecuteOperationAsync?.(operation);
83
+ executionOptions.beforeExecuteOperation?.(operation);
84
84
  }
85
85
  },
86
- afterExecuteAsync: async (operation, state) => {
86
+ afterExecute: (operation, state) => {
87
87
  const { group, runner } = operation;
88
88
  if (group) {
89
89
  group.setOperationAsComplete(operation, state);
@@ -99,7 +99,7 @@ class OperationExecutionManager {
99
99
  hasReportedFailures = true;
100
100
  }
101
101
  if (!runner?.silent) {
102
- await executionOptions.afterExecuteOperationAsync?.(operation);
102
+ executionOptions.afterExecuteOperation?.(operation);
103
103
  }
104
104
  if (group) {
105
105
  // Log out the group name and duration if it is the last operation in the group
@@ -111,7 +111,7 @@ class OperationExecutionManager {
111
111
  ? 'cancelled'
112
112
  : 'finished';
113
113
  terminal.writeLine(` ---- ${group.name} ${finishedLoggingWord} (${group.duration.toFixed(3)}s) ---- `);
114
- await executionOptions.afterExecuteOperationGroupAsync?.(group);
114
+ executionOptions.afterExecuteOperationGroup?.(group);
115
115
  }
116
116
  }
117
117
  }
@@ -1 +1 @@
1
- {"version":3,"file":"OperationExecutionManager.js","sourceRoot":"","sources":["../src/OperationExecutionManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Async } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport type { IOperationState } from './IOperationRunner';\nimport type { IExecuteOperationContext, Operation } from './Operation';\nimport type { OperationGroupRecord } from './OperationGroupRecord';\nimport { OperationStatus } from './OperationStatus';\nimport { calculateCriticalPathLengths } from './calculateCriticalPath';\nimport { WorkQueue } from './WorkQueue';\n\n/**\n * Options for the current run.\n *\n * @beta\n */\nexport interface IOperationExecutionOptions<\n TOperationMetadata extends {} = {},\n TGroupMetadata extends {} = {}\n> {\n abortSignal: AbortSignal;\n parallelism: number;\n terminal: ITerminal;\n\n requestRun?: (requestor?: string) => void;\n\n beforeExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;\n afterExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;\n beforeExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;\n afterExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;\n}\n\n/**\n * A class which manages the execution of a set of tasks with interdependencies.\n * Initially, and at the end of each task execution, all unblocked tasks\n * are added to a ready queue which is then executed. This is done continually until all\n * tasks are complete, or prematurely fails if any of the tasks fail.\n *\n * @beta\n */\nexport class OperationExecutionManager<TOperationMetadata extends {} = {}, TGroupMetadata extends {} = {}> {\n /**\n * The set of operations that will be executed\n */\n private readonly _operations: Operation<TOperationMetadata, TGroupMetadata>[];\n /**\n * The total number of non-silent operations in the graph.\n * Silent operations are generally used to simplify the construction of the graph.\n */\n private readonly _trackedOperationCount: number;\n\n private readonly _groupRecords: Set<OperationGroupRecord<TGroupMetadata>>;\n\n public constructor(operations: ReadonlySet<Operation<TOperationMetadata, TGroupMetadata>>) {\n let trackedOperationCount: number = 0;\n for (const operation of operations) {\n if (!operation.runner?.silent) {\n // Only count non-silent operations\n trackedOperationCount++;\n }\n }\n\n this._trackedOperationCount = trackedOperationCount;\n\n this._operations = calculateCriticalPathLengths(operations);\n\n this._groupRecords = new Set(Array.from(this._operations, (e) => e.group).filter((e) => e !== undefined));\n\n for (const consumer of operations) {\n for (const dependency of consumer.dependencies) {\n if (!operations.has(dependency)) {\n throw new Error(\n `Operation ${JSON.stringify(consumer.name)} declares a dependency on operation ` +\n `${JSON.stringify(dependency.name)} that is not in the set of operations to execute.`\n );\n }\n }\n }\n }\n\n /**\n * Executes all operations which have been registered, returning a promise which is resolved when all the\n * operations are completed successfully, or rejects when any operation fails.\n */\n public async executeAsync(\n executionOptions: IOperationExecutionOptions<TOperationMetadata, TGroupMetadata>\n ): Promise<OperationStatus> {\n let hasReportedFailures: boolean = false;\n\n const { abortSignal, parallelism, terminal, requestRun } = executionOptions;\n\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n const startedGroups: Set<OperationGroupRecord> = new Set();\n const finishedGroups: Set<OperationGroupRecord> = new Set();\n\n const maxParallelism: number = Math.min(this._operations.length, parallelism);\n\n for (const groupRecord of this._groupRecords) {\n groupRecord.reset();\n }\n\n for (const operation of this._operations) {\n operation.reset();\n }\n\n terminal.writeVerboseLine(`Executing a maximum of ${maxParallelism} simultaneous tasks...`);\n\n const workQueueAbortController: AbortController = new AbortController();\n const abortHandler: () => void = () => workQueueAbortController.abort();\n abortSignal.addEventListener('abort', abortHandler, { once: true });\n try {\n const workQueue: WorkQueue = new WorkQueue(workQueueAbortController.signal);\n\n const executionContext: IExecuteOperationContext = {\n terminal,\n abortSignal,\n\n requestRun,\n\n queueWork: (workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus> => {\n return workQueue.pushAsync(workFn, priority);\n },\n\n beforeExecuteAsync: async (\n operation: Operation<TOperationMetadata, TGroupMetadata>\n ): Promise<void> => {\n // Initialize group if uninitialized and log the group name\n const { group, runner } = operation;\n if (group) {\n if (!startedGroups.has(group)) {\n startedGroups.add(group);\n group.startTimer();\n terminal.writeLine(` ---- ${group.name} started ---- `);\n await executionOptions.beforeExecuteOperationGroupAsync?.(group);\n }\n }\n if (!runner?.silent) {\n await executionOptions.beforeExecuteOperationAsync?.(operation);\n }\n },\n\n afterExecuteAsync: async (\n operation: Operation<TOperationMetadata, TGroupMetadata>,\n state: IOperationState\n ): Promise<void> => {\n const { group, runner } = operation;\n if (group) {\n group.setOperationAsComplete(operation, state);\n }\n\n if (state.status === OperationStatus.Failure) {\n // This operation failed. Mark it as such and all reachable dependents as blocked.\n // Failed operations get reported, even if silent.\n // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure.\n const message: string | undefined = state.error?.message;\n if (message) {\n terminal.writeErrorLine(message);\n }\n hasReportedFailures = true;\n }\n\n if (!runner?.silent) {\n await executionOptions.afterExecuteOperationAsync?.(operation);\n }\n\n if (group) {\n // Log out the group name and duration if it is the last operation in the group\n if (group?.finished && !finishedGroups.has(group)) {\n finishedGroups.add(group);\n const finishedLoggingWord: string = group.hasFailures\n ? 'encountered an error'\n : group.hasCancellations\n ? 'cancelled'\n : 'finished';\n terminal.writeLine(\n ` ---- ${group.name} ${finishedLoggingWord} (${group.duration.toFixed(3)}s) ---- `\n );\n await executionOptions.afterExecuteOperationGroupAsync?.(group);\n }\n }\n }\n };\n\n const workQueuePromise: Promise<void> = Async.forEachAsync(\n workQueue,\n (workFn: () => Promise<void>) => workFn(),\n {\n concurrency: maxParallelism\n }\n );\n\n await Promise.all(this._operations.map((record: Operation) => record._executeAsync(executionContext)));\n\n // Terminate queue execution.\n workQueueAbortController.abort();\n await workQueuePromise;\n } finally {\n // Cleanup resources\n abortSignal.removeEventListener('abort', abortHandler);\n }\n\n const finalStatus: OperationStatus =\n this._trackedOperationCount === 0\n ? OperationStatus.NoOp\n : abortSignal.aborted\n ? OperationStatus.Aborted\n : hasReportedFailures\n ? OperationStatus.Failure\n : OperationStatus.Success;\n\n return finalStatus;\n }\n}\n"]}
1
+ {"version":3,"file":"OperationExecutionManager.js","sourceRoot":"","sources":["../src/OperationExecutionManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Async } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport type { IOperationState } from './IOperationRunner';\nimport type { IExecuteOperationContext, Operation, OperationRequestRunCallback } from './Operation';\nimport type { OperationGroupRecord } from './OperationGroupRecord';\nimport { OperationStatus } from './OperationStatus';\nimport { calculateCriticalPathLengths } from './calculateCriticalPath';\nimport { WorkQueue } from './WorkQueue';\n\n/**\n * Options for the current run.\n *\n * @beta\n */\nexport interface IOperationExecutionOptions<\n TOperationMetadata extends {} = {},\n TGroupMetadata extends {} = {}\n> {\n abortSignal: AbortSignal;\n parallelism: number;\n terminal: ITerminal;\n\n requestRun?: OperationRequestRunCallback;\n\n beforeExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;\n afterExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;\n beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;\n afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;\n}\n\n/**\n * A class which manages the execution of a set of tasks with interdependencies.\n * Initially, and at the end of each task execution, all unblocked tasks\n * are added to a ready queue which is then executed. This is done continually until all\n * tasks are complete, or prematurely fails if any of the tasks fail.\n *\n * @beta\n */\nexport class OperationExecutionManager<TOperationMetadata extends {} = {}, TGroupMetadata extends {} = {}> {\n /**\n * The set of operations that will be executed\n */\n private readonly _operations: Operation<TOperationMetadata, TGroupMetadata>[];\n /**\n * The total number of non-silent operations in the graph.\n * Silent operations are generally used to simplify the construction of the graph.\n */\n private readonly _trackedOperationCount: number;\n\n private readonly _groupRecords: Set<OperationGroupRecord<TGroupMetadata>>;\n\n public constructor(operations: ReadonlySet<Operation<TOperationMetadata, TGroupMetadata>>) {\n let trackedOperationCount: number = 0;\n for (const operation of operations) {\n if (!operation.runner?.silent) {\n // Only count non-silent operations\n trackedOperationCount++;\n }\n }\n\n this._trackedOperationCount = trackedOperationCount;\n\n this._operations = calculateCriticalPathLengths(operations);\n\n this._groupRecords = new Set(Array.from(this._operations, (e) => e.group).filter((e) => e !== undefined));\n\n for (const consumer of operations) {\n for (const dependency of consumer.dependencies) {\n if (!operations.has(dependency)) {\n throw new Error(\n `Operation ${JSON.stringify(consumer.name)} declares a dependency on operation ` +\n `${JSON.stringify(dependency.name)} that is not in the set of operations to execute.`\n );\n }\n }\n }\n }\n\n /**\n * Executes all operations which have been registered, returning a promise which is resolved when all the\n * operations are completed successfully, or rejects when any operation fails.\n */\n public async executeAsync(\n executionOptions: IOperationExecutionOptions<TOperationMetadata, TGroupMetadata>\n ): Promise<OperationStatus> {\n let hasReportedFailures: boolean = false;\n\n const { abortSignal, parallelism, terminal, requestRun } = executionOptions;\n\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n const startedGroups: Set<OperationGroupRecord> = new Set();\n const finishedGroups: Set<OperationGroupRecord> = new Set();\n\n const maxParallelism: number = Math.min(this._operations.length, parallelism);\n\n for (const groupRecord of this._groupRecords) {\n groupRecord.reset();\n }\n\n for (const operation of this._operations) {\n operation.reset();\n }\n\n terminal.writeVerboseLine(`Executing a maximum of ${maxParallelism} simultaneous tasks...`);\n\n const workQueueAbortController: AbortController = new AbortController();\n const abortHandler: () => void = () => workQueueAbortController.abort();\n abortSignal.addEventListener('abort', abortHandler, { once: true });\n try {\n const workQueue: WorkQueue = new WorkQueue(workQueueAbortController.signal);\n\n const executionContext: IExecuteOperationContext = {\n terminal,\n abortSignal,\n\n requestRun,\n\n queueWork: (workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus> => {\n return workQueue.pushAsync(workFn, priority);\n },\n\n beforeExecute: (operation: Operation<TOperationMetadata, TGroupMetadata>): void => {\n // Initialize group if uninitialized and log the group name\n const { group, runner } = operation;\n if (group) {\n if (!startedGroups.has(group)) {\n startedGroups.add(group);\n group.startTimer();\n terminal.writeLine(` ---- ${group.name} started ---- `);\n executionOptions.beforeExecuteOperationGroup?.(group);\n }\n }\n if (!runner?.silent) {\n executionOptions.beforeExecuteOperation?.(operation);\n }\n },\n\n afterExecute: (\n operation: Operation<TOperationMetadata, TGroupMetadata>,\n state: IOperationState\n ): void => {\n const { group, runner } = operation;\n if (group) {\n group.setOperationAsComplete(operation, state);\n }\n\n if (state.status === OperationStatus.Failure) {\n // This operation failed. Mark it as such and all reachable dependents as blocked.\n // Failed operations get reported, even if silent.\n // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure.\n const message: string | undefined = state.error?.message;\n if (message) {\n terminal.writeErrorLine(message);\n }\n hasReportedFailures = true;\n }\n\n if (!runner?.silent) {\n executionOptions.afterExecuteOperation?.(operation);\n }\n\n if (group) {\n // Log out the group name and duration if it is the last operation in the group\n if (group?.finished && !finishedGroups.has(group)) {\n finishedGroups.add(group);\n const finishedLoggingWord: string = group.hasFailures\n ? 'encountered an error'\n : group.hasCancellations\n ? 'cancelled'\n : 'finished';\n terminal.writeLine(\n ` ---- ${group.name} ${finishedLoggingWord} (${group.duration.toFixed(3)}s) ---- `\n );\n executionOptions.afterExecuteOperationGroup?.(group);\n }\n }\n }\n };\n\n const workQueuePromise: Promise<void> = Async.forEachAsync(\n workQueue,\n (workFn: () => Promise<void>) => workFn(),\n {\n concurrency: maxParallelism\n }\n );\n\n await Promise.all(this._operations.map((record: Operation) => record._executeAsync(executionContext)));\n\n // Terminate queue execution.\n workQueueAbortController.abort();\n await workQueuePromise;\n } finally {\n // Cleanup resources\n abortSignal.removeEventListener('abort', abortHandler);\n }\n\n const finalStatus: OperationStatus =\n this._trackedOperationCount === 0\n ? OperationStatus.NoOp\n : abortSignal.aborted\n ? OperationStatus.Aborted\n : hasReportedFailures\n ? OperationStatus.Failure\n : OperationStatus.Success;\n\n return finalStatus;\n }\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { OperationRequestRunCallback } from './Operation';
1
2
  import { OperationStatus } from './OperationStatus';
2
3
  import type { IPCHost } from './protocol.types';
3
4
  /**
@@ -16,8 +17,11 @@ export interface IWatchLoopOptions {
16
17
  onBeforeExecute: () => void;
17
18
  /**
18
19
  * Logging callback when a run is requested (and hasn't already been).
20
+ *
21
+ * @param requestor - The name of the operation requesting a rerun.
22
+ * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.
19
23
  */
20
- onRequestRun: (requestor?: string) => void;
24
+ onRequestRun: OperationRequestRunCallback;
21
25
  /**
22
26
  * Logging callback when a run is aborted.
23
27
  */
@@ -30,7 +34,7 @@ export interface IWatchLoopOptions {
30
34
  */
31
35
  export interface IWatchLoopState {
32
36
  get abortSignal(): AbortSignal;
33
- requestRun: (requestor?: string) => void;
37
+ requestRun: OperationRequestRunCallback;
34
38
  }
35
39
  /**
36
40
  * This class implements a watch loop.
@@ -61,7 +65,7 @@ export declare class WatchLoop implements IWatchLoopState {
61
65
  /**
62
66
  * Requests that a new run occur.
63
67
  */
64
- requestRun: (requestor?: string) => void;
68
+ requestRun: OperationRequestRunCallback;
65
69
  /**
66
70
  * The abort signal for the current iteration.
67
71
  */
@@ -1 +1 @@
1
- {"version":3,"file":"WatchLoop.d.ts","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAEV,OAAO,EAIR,MAAM,kBAAkB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE;;OAEG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B;;OAEG;IACH,YAAY,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,WAAW,IAAI,WAAW,CAAC;IAC/B,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED;;;;GAIG;AACH,qBAAa,SAAU,YAAW,eAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IAEvD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,kBAAkB,CAA8B;IACxD,OAAO,CAAC,kBAAkB,CAAgC;gBAEvC,OAAO,EAAE,iBAAiB;IAY7C;;OAEG;IACU,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IA0BpF;;OAEG;IACU,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAejG;;;OAGG;IACU,WAAW,CAAC,IAAI,GAAE,OAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgGhE;;OAEG;IACI,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAU7C;IAEF;;OAEG;IACH,IAAW,WAAW,IAAI,WAAW,CAEpC;IAED;;OAEG;IACH,OAAO,CAAC,aAAa,CAEnB;IAEF;;OAEG;IACH,OAAO,CAAC,MAAM;IAad;;;OAGG;YACW,kBAAkB;CAiBjC"}
1
+ {"version":3,"file":"WatchLoop.d.ts","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAEV,OAAO,EAIR,MAAM,kBAAkB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE;;OAEG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;;OAKG;IACH,YAAY,EAAE,2BAA2B,CAAC;IAC1C;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,WAAW,IAAI,WAAW,CAAC;IAC/B,UAAU,EAAE,2BAA2B,CAAC;CACzC;AAED;;;;GAIG;AACH,qBAAa,SAAU,YAAW,eAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IAEvD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,kBAAkB,CAAsC;gBAE7C,OAAO,EAAE,iBAAiB;IAY7C;;OAEG;IACU,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IA0BpF;;OAEG;IACU,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAejG;;;OAGG;IACU,WAAW,CAAC,IAAI,GAAE,OAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqGhE;;OAEG;IACI,UAAU,EAAE,2BAA2B,CAU5C;IAEF;;OAEG;IACH,IAAW,WAAW,IAAI,WAAW,CAEpC;IAED;;OAEG;IACH,OAAO,CAAC,aAAa,CAEnB;IAEF;;OAEG;IACH,OAAO,CAAC,MAAM;IAad;;;OAGG;YACW,kBAAkB;CAiBjC"}
package/lib/WatchLoop.js CHANGED
@@ -16,16 +16,16 @@ class WatchLoop {
16
16
  /**
17
17
  * Requests that a new run occur.
18
18
  */
19
- this.requestRun = (requestor) => {
19
+ this.requestRun = (requestor, detail) => {
20
20
  if (!this._runRequested) {
21
- this._options.onRequestRun(requestor);
21
+ this._options.onRequestRun(requestor, detail);
22
22
  this._runRequested = true;
23
23
  if (this._isRunning) {
24
24
  this._options.onAbort();
25
25
  this._abortCurrent();
26
26
  }
27
27
  }
28
- this._resolveRequestRun(requestor);
28
+ this._resolveRequestRun([requestor, detail]);
29
29
  };
30
30
  /**
31
31
  * Cancels the current iteration (if possible).
@@ -100,14 +100,15 @@ class WatchLoop {
100
100
  reject(new Error(`Unable to communicate with host: ${err}`));
101
101
  }
102
102
  }
103
- function requestRunFromHost(requestor) {
103
+ function requestRunFromHost(requestor, detail) {
104
104
  if (runRequestedFromHost) {
105
105
  return;
106
106
  }
107
107
  runRequestedFromHost = true;
108
108
  const requestRunMessage = {
109
109
  event: 'requestRun',
110
- requestor
110
+ requestor,
111
+ detail
111
112
  };
112
113
  tryMessageHost(requestRunMessage);
113
114
  }
@@ -137,8 +138,9 @@ class WatchLoop {
137
138
  try {
138
139
  status = await this.runUntilStableAsync(abortController.signal);
139
140
  // ESLINT: "Promises must be awaited, end with a call to .catch, end with a call to .then ..."
140
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
141
- this._requestRunPromise.finally(requestRunFromHost);
141
+ this._requestRunPromise.then(([requestor, detail]) => requestRunFromHost(requestor, detail), (error) => {
142
+ // Unreachable code. The promise will never be rejected.
143
+ });
142
144
  }
143
145
  catch (err) {
144
146
  status = OperationStatus_1.OperationStatus.Failure;
@@ -1 +1 @@
1
- {"version":3,"file":"WatchLoop.js","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { once } from 'node:events';\n\nimport { AlreadyReportedError } from '@rushstack/node-core-library';\n\nimport { OperationStatus } from './OperationStatus';\nimport type {\n IAfterExecuteEventMessage,\n IPCHost,\n CommandMessageFromHost,\n ISyncEventMessage,\n IRequestRunEventMessage\n} from './protocol.types';\n\n/**\n * Callbacks for the watch loop.\n *\n * @beta\n */\nexport interface IWatchLoopOptions {\n /**\n * Callback that performs the core work of a single iteration.\n */\n executeAsync: (state: IWatchLoopState) => Promise<OperationStatus>;\n /**\n * Logging callback immediately before execution occurs.\n */\n onBeforeExecute: () => void;\n /**\n * Logging callback when a run is requested (and hasn't already been).\n */\n onRequestRun: (requestor?: string) => void;\n /**\n * Logging callback when a run is aborted.\n */\n onAbort: () => void;\n}\n\n/**\n * The public API surface of the watch loop, for use in the `executeAsync` callback.\n *\n * @beta\n */\nexport interface IWatchLoopState {\n get abortSignal(): AbortSignal;\n requestRun: (requestor?: string) => void;\n}\n\n/**\n * This class implements a watch loop.\n *\n * @beta\n */\nexport class WatchLoop implements IWatchLoopState {\n private readonly _options: Readonly<IWatchLoopOptions>;\n\n private _abortController: AbortController;\n private _isRunning: boolean;\n private _runRequested: boolean;\n private _requestRunPromise: Promise<string | undefined>;\n private _resolveRequestRun!: (requestor?: string) => void;\n\n public constructor(options: IWatchLoopOptions) {\n this._options = options;\n\n this._abortController = new AbortController();\n this._isRunning = false;\n // Always start as true, so that any requests prior to first run are silenced.\n this._runRequested = true;\n this._requestRunPromise = new Promise<string | undefined>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n }\n\n /**\n * Runs the inner loop until the abort signal is cancelled or a run completes without a new run being requested.\n */\n public async runUntilStableAsync(abortSignal: AbortSignal): Promise<OperationStatus> {\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n abortSignal.addEventListener('abort', this._abortCurrent, { once: true });\n\n try {\n let result: OperationStatus = OperationStatus.Ready;\n\n do {\n // Always check the abort signal first, in case it was aborted in the async tick since the last executeAsync() call.\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n result = await this._runIterationAsync();\n } while (this._runRequested);\n\n // Even if the run has finished, if the abort signal was aborted, we should return `Aborted` just in case.\n return abortSignal.aborted ? OperationStatus.Aborted : result;\n } finally {\n abortSignal.removeEventListener('abort', this._abortCurrent);\n }\n }\n\n /**\n * Runs the inner loop until the abort signal is aborted. Will otherwise wait indefinitely for a new run to be requested.\n */\n public async runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise<void> {\n if (abortSignal.aborted) {\n return;\n }\n\n const abortPromise: Promise<unknown> = once(abortSignal, 'abort');\n\n while (!abortSignal.aborted) {\n await this.runUntilStableAsync(abortSignal);\n\n onWaiting();\n await Promise.race([this._requestRunPromise, abortPromise]);\n }\n }\n\n /**\n * Sets up an IPC handler that will run the inner loop when it receives a \"run\" message from the host.\n * Runs until receiving an \"exit\" message from the host, or aborts early if an unhandled error is thrown.\n */\n public async runIPCAsync(host: IPCHost = process): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n let abortController: AbortController = new AbortController();\n\n let runRequestedFromHost: boolean = true;\n let status: OperationStatus = OperationStatus.Ready;\n\n function tryMessageHost(\n message: ISyncEventMessage | IRequestRunEventMessage | IAfterExecuteEventMessage\n ): void {\n if (!host.send) {\n return reject(new Error('Host does not support IPC'));\n }\n\n try {\n host.send(message);\n } catch (err) {\n reject(new Error(`Unable to communicate with host: ${err}`));\n }\n }\n\n function requestRunFromHost(requestor?: string): void {\n if (runRequestedFromHost) {\n return;\n }\n\n runRequestedFromHost = true;\n\n const requestRunMessage: IRequestRunEventMessage = {\n event: 'requestRun',\n requestor\n };\n\n tryMessageHost(requestRunMessage);\n }\n\n function sendSync(): void {\n const syncMessage: ISyncEventMessage = {\n event: 'sync',\n status\n };\n tryMessageHost(syncMessage);\n }\n\n host.on('message', async (message: CommandMessageFromHost) => {\n switch (message.command) {\n case 'exit': {\n return resolve();\n }\n\n case 'cancel': {\n if (this._isRunning) {\n abortController.abort();\n abortController = new AbortController();\n // This will terminate the currently executing `runUntilStableAsync` call.\n }\n return;\n }\n\n case 'run': {\n runRequestedFromHost = false;\n\n status = OperationStatus.Executing;\n\n try {\n status = await this.runUntilStableAsync(abortController.signal);\n // ESLINT: \"Promises must be awaited, end with a call to .catch, end with a call to .then ...\"\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._requestRunPromise.finally(requestRunFromHost);\n } catch (err) {\n status = OperationStatus.Failure;\n return reject(err);\n } finally {\n const afterExecuteMessage: IAfterExecuteEventMessage = {\n event: 'after-execute',\n status\n };\n tryMessageHost(afterExecuteMessage);\n }\n return;\n }\n\n case 'sync': {\n return sendSync();\n }\n\n default: {\n return reject(new Error(`Unexpected command from host: ${message}`));\n }\n }\n });\n\n sendSync();\n });\n }\n\n /**\n * Requests that a new run occur.\n */\n public requestRun: (requestor?: string) => void = (requestor?: string) => {\n if (!this._runRequested) {\n this._options.onRequestRun(requestor);\n this._runRequested = true;\n if (this._isRunning) {\n this._options.onAbort();\n this._abortCurrent();\n }\n }\n this._resolveRequestRun(requestor);\n };\n\n /**\n * The abort signal for the current iteration.\n */\n public get abortSignal(): AbortSignal {\n return this._abortController.signal;\n }\n\n /**\n * Cancels the current iteration (if possible).\n */\n private _abortCurrent = (): void => {\n this._abortController.abort();\n };\n\n /**\n * Resets the abort signal and run request state.\n */\n private _reset(): void {\n if (this._abortController.signal.aborted) {\n this._abortController = new AbortController();\n }\n\n if (this._runRequested) {\n this._runRequested = false;\n this._requestRunPromise = new Promise<string | undefined>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n }\n }\n\n /**\n * Runs a single iteration of the loop.\n * @returns The status of the iteration.\n */\n private async _runIterationAsync(): Promise<OperationStatus> {\n this._reset();\n\n this._options.onBeforeExecute();\n try {\n this._isRunning = true;\n return await this._options.executeAsync(this);\n } catch (err) {\n if (!(err instanceof AlreadyReportedError)) {\n throw err;\n } else {\n return OperationStatus.Failure;\n }\n } finally {\n this._isRunning = false;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"WatchLoop.js","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { once } from 'node:events';\n\nimport { AlreadyReportedError } from '@rushstack/node-core-library';\n\nimport type { OperationRequestRunCallback } from './Operation';\nimport { OperationStatus } from './OperationStatus';\nimport type {\n IAfterExecuteEventMessage,\n IPCHost,\n CommandMessageFromHost,\n ISyncEventMessage,\n IRequestRunEventMessage\n} from './protocol.types';\n\n/**\n * Callbacks for the watch loop.\n *\n * @beta\n */\nexport interface IWatchLoopOptions {\n /**\n * Callback that performs the core work of a single iteration.\n */\n executeAsync: (state: IWatchLoopState) => Promise<OperationStatus>;\n /**\n * Logging callback immediately before execution occurs.\n */\n onBeforeExecute: () => void;\n /**\n * Logging callback when a run is requested (and hasn't already been).\n *\n * @param requestor - The name of the operation requesting a rerun.\n * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file.\n */\n onRequestRun: OperationRequestRunCallback;\n /**\n * Logging callback when a run is aborted.\n */\n onAbort: () => void;\n}\n\n/**\n * The public API surface of the watch loop, for use in the `executeAsync` callback.\n *\n * @beta\n */\nexport interface IWatchLoopState {\n get abortSignal(): AbortSignal;\n requestRun: OperationRequestRunCallback;\n}\n\n/**\n * This class implements a watch loop.\n *\n * @beta\n */\nexport class WatchLoop implements IWatchLoopState {\n private readonly _options: Readonly<IWatchLoopOptions>;\n\n private _abortController: AbortController;\n private _isRunning: boolean;\n private _runRequested: boolean;\n private _requestRunPromise: Promise<[string, string?]>;\n private _resolveRequestRun!: (value: [string, string?]) => void;\n\n public constructor(options: IWatchLoopOptions) {\n this._options = options;\n\n this._abortController = new AbortController();\n this._isRunning = false;\n // Always start as true, so that any requests prior to first run are silenced.\n this._runRequested = true;\n this._requestRunPromise = new Promise<[string, string?]>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n }\n\n /**\n * Runs the inner loop until the abort signal is cancelled or a run completes without a new run being requested.\n */\n public async runUntilStableAsync(abortSignal: AbortSignal): Promise<OperationStatus> {\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n abortSignal.addEventListener('abort', this._abortCurrent, { once: true });\n\n try {\n let result: OperationStatus = OperationStatus.Ready;\n\n do {\n // Always check the abort signal first, in case it was aborted in the async tick since the last executeAsync() call.\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n result = await this._runIterationAsync();\n } while (this._runRequested);\n\n // Even if the run has finished, if the abort signal was aborted, we should return `Aborted` just in case.\n return abortSignal.aborted ? OperationStatus.Aborted : result;\n } finally {\n abortSignal.removeEventListener('abort', this._abortCurrent);\n }\n }\n\n /**\n * Runs the inner loop until the abort signal is aborted. Will otherwise wait indefinitely for a new run to be requested.\n */\n public async runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise<void> {\n if (abortSignal.aborted) {\n return;\n }\n\n const abortPromise: Promise<unknown> = once(abortSignal, 'abort');\n\n while (!abortSignal.aborted) {\n await this.runUntilStableAsync(abortSignal);\n\n onWaiting();\n await Promise.race([this._requestRunPromise, abortPromise]);\n }\n }\n\n /**\n * Sets up an IPC handler that will run the inner loop when it receives a \"run\" message from the host.\n * Runs until receiving an \"exit\" message from the host, or aborts early if an unhandled error is thrown.\n */\n public async runIPCAsync(host: IPCHost = process): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n let abortController: AbortController = new AbortController();\n\n let runRequestedFromHost: boolean = true;\n let status: OperationStatus = OperationStatus.Ready;\n\n function tryMessageHost(\n message: ISyncEventMessage | IRequestRunEventMessage | IAfterExecuteEventMessage\n ): void {\n if (!host.send) {\n return reject(new Error('Host does not support IPC'));\n }\n\n try {\n host.send(message);\n } catch (err) {\n reject(new Error(`Unable to communicate with host: ${err}`));\n }\n }\n\n function requestRunFromHost(requestor: string, detail?: string): void {\n if (runRequestedFromHost) {\n return;\n }\n\n runRequestedFromHost = true;\n\n const requestRunMessage: IRequestRunEventMessage = {\n event: 'requestRun',\n requestor,\n detail\n };\n\n tryMessageHost(requestRunMessage);\n }\n\n function sendSync(): void {\n const syncMessage: ISyncEventMessage = {\n event: 'sync',\n status\n };\n tryMessageHost(syncMessage);\n }\n\n host.on('message', async (message: CommandMessageFromHost) => {\n switch (message.command) {\n case 'exit': {\n return resolve();\n }\n\n case 'cancel': {\n if (this._isRunning) {\n abortController.abort();\n abortController = new AbortController();\n // This will terminate the currently executing `runUntilStableAsync` call.\n }\n return;\n }\n\n case 'run': {\n runRequestedFromHost = false;\n\n status = OperationStatus.Executing;\n\n try {\n status = await this.runUntilStableAsync(abortController.signal);\n // ESLINT: \"Promises must be awaited, end with a call to .catch, end with a call to .then ...\"\n this._requestRunPromise.then(\n ([requestor, detail]) => requestRunFromHost(requestor, detail),\n (error: Error) => {\n // Unreachable code. The promise will never be rejected.\n }\n );\n } catch (err) {\n status = OperationStatus.Failure;\n return reject(err);\n } finally {\n const afterExecuteMessage: IAfterExecuteEventMessage = {\n event: 'after-execute',\n status\n };\n tryMessageHost(afterExecuteMessage);\n }\n return;\n }\n\n case 'sync': {\n return sendSync();\n }\n\n default: {\n return reject(new Error(`Unexpected command from host: ${message}`));\n }\n }\n });\n\n sendSync();\n });\n }\n\n /**\n * Requests that a new run occur.\n */\n public requestRun: OperationRequestRunCallback = (requestor: string, detail?: string) => {\n if (!this._runRequested) {\n this._options.onRequestRun(requestor, detail);\n this._runRequested = true;\n if (this._isRunning) {\n this._options.onAbort();\n this._abortCurrent();\n }\n }\n this._resolveRequestRun([requestor, detail]);\n };\n\n /**\n * The abort signal for the current iteration.\n */\n public get abortSignal(): AbortSignal {\n return this._abortController.signal;\n }\n\n /**\n * Cancels the current iteration (if possible).\n */\n private _abortCurrent = (): void => {\n this._abortController.abort();\n };\n\n /**\n * Resets the abort signal and run request state.\n */\n private _reset(): void {\n if (this._abortController.signal.aborted) {\n this._abortController = new AbortController();\n }\n\n if (this._runRequested) {\n this._runRequested = false;\n this._requestRunPromise = new Promise<[string, string?]>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n }\n }\n\n /**\n * Runs a single iteration of the loop.\n * @returns The status of the iteration.\n */\n private async _runIterationAsync(): Promise<OperationStatus> {\n this._reset();\n\n this._options.onBeforeExecute();\n try {\n this._isRunning = true;\n return await this._options.executeAsync(this);\n } catch (err) {\n if (!(err instanceof AlreadyReportedError)) {\n throw err;\n } else {\n return OperationStatus.Failure;\n }\n } finally {\n this._isRunning = false;\n }\n }\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" preserve="true" />
2
2
  export type { IOperationRunner, IOperationRunnerContext, IOperationState, IOperationStates } from './IOperationRunner';
3
3
  export type { IAfterExecuteEventMessage, ISyncEventMessage, IRequestRunEventMessage, EventMessageFromClient, ICancelCommandMessage, IExitCommandMessage, IRunCommandMessage, ISyncCommandMessage, CommandMessageFromHost, IPCHost } from './protocol.types';
4
- export { type IExecuteOperationContext, type IOperationOptions, Operation } from './Operation';
4
+ export { type IExecuteOperationContext, type IOperationOptions, Operation, type OperationRequestRunCallback } from './Operation';
5
5
  export { OperationError } from './OperationError';
6
6
  export { type IOperationExecutionOptions, OperationExecutionManager } from './OperationExecutionManager';
7
7
  export { OperationGroupRecord } from './OperationGroupRecord';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAKA,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,OAAO,EACR,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE/F,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,KAAK,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAEzG,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAKA,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,OAAO,EACR,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,SAAS,EACT,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,KAAK,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAEzG,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAwB3D,yCAA+F;AAA/B,sGAAA,SAAS,OAAA;AAEzE,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,yEAAyG;AAA/D,sIAAA,yBAAyB,OAAA;AAEnE,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AAExB,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAElB,yCAAsF;AAA/B,sGAAA,SAAS,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/// <reference types=\"node\" preserve=\"true\" />\n\nexport type {\n IOperationRunner,\n IOperationRunnerContext,\n IOperationState,\n IOperationStates\n} from './IOperationRunner';\n\nexport type {\n IAfterExecuteEventMessage,\n ISyncEventMessage,\n IRequestRunEventMessage,\n EventMessageFromClient,\n ICancelCommandMessage,\n IExitCommandMessage,\n IRunCommandMessage,\n ISyncCommandMessage,\n CommandMessageFromHost,\n IPCHost\n} from './protocol.types';\n\nexport { type IExecuteOperationContext, type IOperationOptions, Operation } from './Operation';\n\nexport { OperationError } from './OperationError';\n\nexport { type IOperationExecutionOptions, OperationExecutionManager } from './OperationExecutionManager';\n\nexport { OperationGroupRecord } from './OperationGroupRecord';\n\nexport { OperationStatus } from './OperationStatus';\n\nexport { Stopwatch } from './Stopwatch';\n\nexport { type IWatchLoopOptions, type IWatchLoopState, WatchLoop } from './WatchLoop';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAwB3D,yCAKqB;AAFnB,sGAAA,SAAS,OAAA;AAIX,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,yEAAyG;AAA/D,sIAAA,yBAAyB,OAAA;AAEnE,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AAExB,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAElB,yCAAsF;AAA/B,sGAAA,SAAS,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/// <reference types=\"node\" preserve=\"true\" />\n\nexport type {\n IOperationRunner,\n IOperationRunnerContext,\n IOperationState,\n IOperationStates\n} from './IOperationRunner';\n\nexport type {\n IAfterExecuteEventMessage,\n ISyncEventMessage,\n IRequestRunEventMessage,\n EventMessageFromClient,\n ICancelCommandMessage,\n IExitCommandMessage,\n IRunCommandMessage,\n ISyncCommandMessage,\n CommandMessageFromHost,\n IPCHost\n} from './protocol.types';\n\nexport {\n type IExecuteOperationContext,\n type IOperationOptions,\n Operation,\n type OperationRequestRunCallback\n} from './Operation';\n\nexport { OperationError } from './OperationError';\n\nexport { type IOperationExecutionOptions, OperationExecutionManager } from './OperationExecutionManager';\n\nexport { OperationGroupRecord } from './OperationGroupRecord';\n\nexport { OperationStatus } from './OperationStatus';\n\nexport { Stopwatch } from './Stopwatch';\n\nexport { type IWatchLoopOptions, type IWatchLoopState, WatchLoop } from './WatchLoop';\n"]}
@@ -6,7 +6,14 @@ import type { OperationStatus } from './OperationStatus';
6
6
  */
7
7
  export interface IRequestRunEventMessage {
8
8
  event: 'requestRun';
9
- requestor?: string;
9
+ /**
10
+ * The name of the operation requesting a rerun.
11
+ */
12
+ requestor: string;
13
+ /**
14
+ * Optional detail about why the rerun is requested, e.g. the name of a changed file.
15
+ */
16
+ detail?: string;
10
17
  }
11
18
  /**
12
19
  * A message sent to the host upon completion of a run of this task.
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.types.d.ts","sourceRoot":"","sources":["../src/protocol.types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,KAAK,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAC9B,qBAAqB,GACrB,mBAAmB,GACnB,kBAAkB,GAClB,mBAAmB,CAAC;AAExB;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,yBAAyB,GAAG,iBAAiB,CAAC;AAE7G;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"protocol.types.d.ts","sourceRoot":"","sources":["../src/protocol.types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,KAAK,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAC9B,qBAAqB,GACrB,mBAAmB,GACnB,kBAAkB,GAClB,mBAAmB,CAAC;AAExB;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,yBAAyB,GAAG,iBAAiB,CAAC;AAE7G;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.types.js","sourceRoot":"","sources":["../src/protocol.types.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { OperationStatus } from './OperationStatus';\n\n/**\n * A message sent to the host to ask it to run this task.\n *\n * @beta\n */\nexport interface IRequestRunEventMessage {\n event: 'requestRun';\n requestor?: string;\n}\n\n/**\n * A message sent to the host upon completion of a run of this task.\n *\n * @beta\n */\nexport interface IAfterExecuteEventMessage {\n event: 'after-execute';\n status: OperationStatus;\n}\n\n/**\n * A message sent to the host upon connection of the channel, to indicate\n * to the host that this task supports the protocol and to provide baseline status information.\n *\n * @beta\n */\nexport interface ISyncEventMessage {\n event: 'sync';\n status: OperationStatus;\n}\n\n/**\n * A message sent by the host to tell the watch loop to cancel the current run.\n *\n * @beta\n */\nexport interface ICancelCommandMessage {\n command: 'cancel';\n}\n\n/**\n * A message sent by the host to tell the watch loop to shutdown gracefully.\n *\n * @beta\n */\nexport interface IExitCommandMessage {\n command: 'exit';\n}\n\n/**\n * A message sent by the host to tell the watch loop to perform a single run.\n *\n * @beta\n */\nexport interface IRunCommandMessage {\n command: 'run';\n}\n\n/**\n * A message sent by the host to ask for to resync status information.\n *\n * @beta\n */\nexport interface ISyncCommandMessage {\n command: 'sync';\n}\n\n/**\n * The set of known messages from the host to the watch loop.\n * @beta\n */\nexport type CommandMessageFromHost =\n | ICancelCommandMessage\n | IExitCommandMessage\n | IRunCommandMessage\n | ISyncCommandMessage;\n\n/**\n * The set of known messages from the watch loop to the host.\n * @beta\n */\nexport type EventMessageFromClient = IRequestRunEventMessage | IAfterExecuteEventMessage | ISyncEventMessage;\n\n/**\n * The interface contract for IPC send/receive, to support alternate channels and unit tests.\n *\n * @beta\n */\nexport type IPCHost = Pick<typeof process, 'on' | 'send'>;\n"]}
1
+ {"version":3,"file":"protocol.types.js","sourceRoot":"","sources":["../src/protocol.types.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { OperationStatus } from './OperationStatus';\n\n/**\n * A message sent to the host to ask it to run this task.\n *\n * @beta\n */\nexport interface IRequestRunEventMessage {\n event: 'requestRun';\n /**\n * The name of the operation requesting a rerun.\n */\n requestor: string;\n /**\n * Optional detail about why the rerun is requested, e.g. the name of a changed file.\n */\n detail?: string;\n}\n\n/**\n * A message sent to the host upon completion of a run of this task.\n *\n * @beta\n */\nexport interface IAfterExecuteEventMessage {\n event: 'after-execute';\n status: OperationStatus;\n}\n\n/**\n * A message sent to the host upon connection of the channel, to indicate\n * to the host that this task supports the protocol and to provide baseline status information.\n *\n * @beta\n */\nexport interface ISyncEventMessage {\n event: 'sync';\n status: OperationStatus;\n}\n\n/**\n * A message sent by the host to tell the watch loop to cancel the current run.\n *\n * @beta\n */\nexport interface ICancelCommandMessage {\n command: 'cancel';\n}\n\n/**\n * A message sent by the host to tell the watch loop to shutdown gracefully.\n *\n * @beta\n */\nexport interface IExitCommandMessage {\n command: 'exit';\n}\n\n/**\n * A message sent by the host to tell the watch loop to perform a single run.\n *\n * @beta\n */\nexport interface IRunCommandMessage {\n command: 'run';\n}\n\n/**\n * A message sent by the host to ask for to resync status information.\n *\n * @beta\n */\nexport interface ISyncCommandMessage {\n command: 'sync';\n}\n\n/**\n * The set of known messages from the host to the watch loop.\n * @beta\n */\nexport type CommandMessageFromHost =\n | ICancelCommandMessage\n | IExitCommandMessage\n | IRunCommandMessage\n | ISyncCommandMessage;\n\n/**\n * The set of known messages from the watch loop to the host.\n * @beta\n */\nexport type EventMessageFromClient = IRequestRunEventMessage | IAfterExecuteEventMessage | ISyncEventMessage;\n\n/**\n * The interface contract for IPC send/receive, to support alternate channels and unit tests.\n *\n * @beta\n */\nexport type IPCHost = Pick<typeof process, 'on' | 'send'>;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rushstack/operation-graph",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Library for managing and executing operations in a directed acyclic graph.",
5
5
  "main": "lib/index.js",
6
6
  "typings": "dist/operation-graph.d.ts",
@@ -11,11 +11,11 @@
11
11
  "directory": "libraries/operation-graph"
12
12
  },
13
13
  "dependencies": {
14
- "@rushstack/node-core-library": "5.14.0",
15
- "@rushstack/terminal": "0.15.4"
14
+ "@rushstack/node-core-library": "5.15.0",
15
+ "@rushstack/terminal": "0.17.0"
16
16
  },
17
17
  "devDependencies": {
18
- "@rushstack/heft": "0.74.0",
18
+ "@rushstack/heft": "0.74.3",
19
19
  "eslint": "~9.25.1",
20
20
  "decoupled-local-node-rig": "1.0.0"
21
21
  },