semantifold 0.8.0 → 0.10.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.
Files changed (171) hide show
  1. package/README.md +11 -5
  2. package/bin/semantifold.js +6 -0
  3. package/build/bin/semantifold.d.ts +3 -0
  4. package/build/bin/semantifold.d.ts.map +1 -0
  5. package/build/bin/semantifold.js +5 -0
  6. package/build/index.d.ts +9 -0
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +10 -1
  9. package/build/src/artifact-path.d.ts +16 -0
  10. package/build/src/artifact-path.d.ts.map +1 -1
  11. package/build/src/artifact-path.js +29 -3
  12. package/build/src/backends/c-check.d.ts +7 -0
  13. package/build/src/backends/c-check.d.ts.map +1 -0
  14. package/build/src/backends/c-check.js +65 -0
  15. package/build/src/backends/check-plan.d.ts +96 -0
  16. package/build/src/backends/check-plan.d.ts.map +1 -0
  17. package/build/src/backends/check-plan.js +135 -0
  18. package/build/src/backends/cpp-check.d.ts +7 -0
  19. package/build/src/backends/cpp-check.d.ts.map +1 -0
  20. package/build/src/backends/cpp-check.js +59 -0
  21. package/build/src/backends/csharp-check.d.ts +7 -0
  22. package/build/src/backends/csharp-check.d.ts.map +1 -0
  23. package/build/src/backends/csharp-check.js +125 -0
  24. package/build/src/backends/csharp.d.ts +1 -0
  25. package/build/src/backends/csharp.d.ts.map +1 -1
  26. package/build/src/backends/csharp.js +5 -4
  27. package/build/src/backends/dart-check.d.ts +7 -0
  28. package/build/src/backends/dart-check.d.ts.map +1 -0
  29. package/build/src/backends/dart-check.js +103 -0
  30. package/build/src/backends/dart.d.ts +2 -0
  31. package/build/src/backends/dart.d.ts.map +1 -1
  32. package/build/src/backends/dart.js +5 -5
  33. package/build/src/backends/go-check.d.ts +7 -0
  34. package/build/src/backends/go-check.d.ts.map +1 -0
  35. package/build/src/backends/go-check.js +77 -0
  36. package/build/src/backends/go.d.ts +1 -0
  37. package/build/src/backends/go.d.ts.map +1 -1
  38. package/build/src/backends/go.js +3 -3
  39. package/build/src/backends/java-check.d.ts +21 -0
  40. package/build/src/backends/java-check.d.ts.map +1 -0
  41. package/build/src/backends/java-check.js +73 -0
  42. package/build/src/backends/javascript-check.d.ts +7 -0
  43. package/build/src/backends/javascript-check.d.ts.map +1 -0
  44. package/build/src/backends/javascript-check.js +29 -0
  45. package/build/src/backends/kotlin-check.d.ts +7 -0
  46. package/build/src/backends/kotlin-check.d.ts.map +1 -0
  47. package/build/src/backends/kotlin-check.js +31 -0
  48. package/build/src/backends/php-check.d.ts +7 -0
  49. package/build/src/backends/php-check.d.ts.map +1 -0
  50. package/build/src/backends/php-check.js +21 -0
  51. package/build/src/backends/program.d.ts +7 -0
  52. package/build/src/backends/program.d.ts.map +1 -1
  53. package/build/src/backends/program.js +16 -1
  54. package/build/src/backends/python-check.d.ts +7 -0
  55. package/build/src/backends/python-check.d.ts.map +1 -0
  56. package/build/src/backends/python-check.js +28 -0
  57. package/build/src/backends/ruby-check.d.ts +7 -0
  58. package/build/src/backends/ruby-check.d.ts.map +1 -0
  59. package/build/src/backends/ruby-check.js +21 -0
  60. package/build/src/backends/rust-check.d.ts +7 -0
  61. package/build/src/backends/rust-check.d.ts.map +1 -0
  62. package/build/src/backends/rust-check.js +65 -0
  63. package/build/src/backends/swift-check.d.ts +7 -0
  64. package/build/src/backends/swift-check.d.ts.map +1 -0
  65. package/build/src/backends/swift-check.js +77 -0
  66. package/build/src/backends/typescript-check.d.ts +7 -0
  67. package/build/src/backends/typescript-check.d.ts.map +1 -0
  68. package/build/src/backends/typescript-check.js +33 -0
  69. package/build/src/backends/zig-check.d.ts +7 -0
  70. package/build/src/backends/zig-check.d.ts.map +1 -0
  71. package/build/src/backends/zig-check.js +70 -0
  72. package/build/src/diagnostic.d.ts +13 -1
  73. package/build/src/diagnostic.d.ts.map +1 -1
  74. package/build/src/diagnostic.js +14 -2
  75. package/build/src/frontends/program.d.ts +6 -0
  76. package/build/src/frontends/program.d.ts.map +1 -1
  77. package/build/src/frontends/program.js +9 -1
  78. package/build/src/language-registry.d.ts +54 -0
  79. package/build/src/language-registry.d.ts.map +1 -1
  80. package/build/src/language-registry.js +107 -5
  81. package/build/src/project-build.d.ts +172 -0
  82. package/build/src/project-build.d.ts.map +1 -0
  83. package/build/src/project-build.js +320 -0
  84. package/build/src/project-cli.d.ts +40 -0
  85. package/build/src/project-cli.d.ts.map +1 -0
  86. package/build/src/project-cli.js +145 -0
  87. package/build/src/project-manifest.d.ts +148 -0
  88. package/build/src/project-manifest.d.ts.map +1 -0
  89. package/build/src/project-manifest.js +432 -0
  90. package/build/src/project-reporter.d.ts +81 -0
  91. package/build/src/project-reporter.d.ts.map +1 -0
  92. package/build/src/project-reporter.js +293 -0
  93. package/build/src/project-snapshot.d.ts +129 -0
  94. package/build/src/project-snapshot.d.ts.map +1 -0
  95. package/build/src/project-snapshot.js +362 -0
  96. package/build/src/project-watch-reporter.d.ts +125 -0
  97. package/build/src/project-watch-reporter.d.ts.map +1 -0
  98. package/build/src/project-watch-reporter.js +280 -0
  99. package/build/src/project-watch.d.ts +133 -0
  100. package/build/src/project-watch.d.ts.map +1 -0
  101. package/build/src/project-watch.js +839 -0
  102. package/build/src/publication.d.ts +218 -0
  103. package/build/src/publication.d.ts.map +1 -0
  104. package/build/src/publication.js +1832 -0
  105. package/build/src/semantic/types.d.ts +613 -0
  106. package/build/src/semantic/types.d.ts.map +1 -1
  107. package/build/src/semantic/types.js +163 -1
  108. package/build/src/subprocess.d.ts +8 -0
  109. package/build/src/subprocess.d.ts.map +1 -1
  110. package/build/src/subprocess.js +50 -9
  111. package/build/src/target-check.d.ts +52 -0
  112. package/build/src/target-check.d.ts.map +1 -0
  113. package/build/src/target-check.js +796 -0
  114. package/build/src/toolchains.d.ts.map +1 -1
  115. package/build/src/toolchains.js +3 -3
  116. package/docs/architecture.md +3 -1
  117. package/docs/c.md +4 -0
  118. package/docs/cpp.md +4 -0
  119. package/docs/dart.md +4 -0
  120. package/docs/generated-artifact-publication.md +98 -0
  121. package/docs/kotlin.md +2 -2
  122. package/docs/language-support.md +29 -3
  123. package/docs/project-build-cli.md +147 -0
  124. package/docs/project-watch.md +60 -0
  125. package/docs/rust.md +4 -0
  126. package/docs/swift.md +2 -0
  127. package/docs/testing.md +70 -3
  128. package/docs/watch-build-pipeline.md +42 -26
  129. package/docs/zig.md +2 -0
  130. package/examples/jsdoc-java-watch/expected-output.txt +3 -0
  131. package/examples/jsdoc-java-watch/semantifold.json +23 -0
  132. package/examples/jsdoc-java-watch/src/main.js +21 -0
  133. package/index.js +9 -0
  134. package/package.json +6 -1
  135. package/src/artifact-path.js +31 -2
  136. package/src/backends/c-check.js +80 -0
  137. package/src/backends/check-plan.js +147 -0
  138. package/src/backends/cpp-check.js +73 -0
  139. package/src/backends/csharp-check.js +139 -0
  140. package/src/backends/csharp.js +4 -3
  141. package/src/backends/dart-check.js +117 -0
  142. package/src/backends/dart.js +4 -4
  143. package/src/backends/go-check.js +89 -0
  144. package/src/backends/go.js +2 -2
  145. package/src/backends/java-check.js +77 -0
  146. package/src/backends/javascript-check.js +33 -0
  147. package/src/backends/kotlin-check.js +41 -0
  148. package/src/backends/php-check.js +23 -0
  149. package/src/backends/program.js +17 -0
  150. package/src/backends/python-check.js +30 -0
  151. package/src/backends/ruby-check.js +23 -0
  152. package/src/backends/rust-check.js +78 -0
  153. package/src/backends/swift-check.js +89 -0
  154. package/src/backends/typescript-check.js +37 -0
  155. package/src/backends/zig-check.js +81 -0
  156. package/src/diagnostic.js +9 -1
  157. package/src/frontends/program.js +9 -0
  158. package/src/language-registry.js +113 -4
  159. package/src/project-build.js +353 -0
  160. package/src/project-cli.js +155 -0
  161. package/src/project-manifest.js +479 -0
  162. package/src/project-reporter.js +320 -0
  163. package/src/project-snapshot.js +403 -0
  164. package/src/project-watch-reporter.js +303 -0
  165. package/src/project-watch.js +870 -0
  166. package/src/publication.js +2071 -0
  167. package/src/semantic/types.js +184 -0
  168. package/src/subprocess.js +49 -8
  169. package/src/target-check.js +844 -0
  170. package/src/toolchains.js +3 -2
  171. package/tsconfig.json +1 -1
@@ -165,6 +165,13 @@
165
165
  * @property {readonly string[]} toolchains - Required canonical toolchain IDs.
166
166
  */
167
167
 
168
+ /**
169
+ * @typedef LanguageCheckCapabilities
170
+ * @property {boolean} supported - Whether the target owns a developer check plan.
171
+ * @property {readonly AcceptanceStage[]} stages - Ordered non-executing developer-check stages.
172
+ * @property {readonly string[]} toolchains - Exact canonical tools required to construct the plan.
173
+ */
174
+
168
175
  /**
169
176
  * @typedef LanguageFeatureCapabilities
170
177
  * @property {boolean} generalFunctionsAndCalls - Task 005 arbitrary required signatures, resolved direct calls, and void functions.
@@ -189,6 +196,7 @@
189
196
  * @property {Readonly<LanguageFeatureCapabilities>} features - Semantic feature capabilities.
190
197
  * @property {Readonly<LanguageMappingCapabilities>} mapping - Mapping forms.
191
198
  * @property {Readonly<LanguageAcceptanceCapabilities>} acceptance - Stages and toolchains.
199
+ * @property {Readonly<LanguageCheckCapabilities>} check - Non-executing developer-check capability.
192
200
  */
193
201
 
194
202
  /**
@@ -395,6 +403,109 @@
395
403
  * @property {Readonly<Record<string, unknown>>} [metadata] - Detached target-specific JSON metadata.
396
404
  */
397
405
 
406
+ /**
407
+ * @typedef PublicationBuildArtifactInput
408
+ * @property {string} path - Normalized path relative to the target build projection.
409
+ * @property {string} mediaType - Stable media type for the validator/compiler output.
410
+ * @property {string} role - Stable language-neutral role for the validator/compiler output.
411
+ */
412
+
413
+ /**
414
+ * @typedef PublicationValidatorContext
415
+ * @property {string} targetId - Explicit target identity.
416
+ * @property {string} sourcePath - Exact generation-scoped generated-source directory.
417
+ * @property {string} buildPath - Exact generation-scoped compiler-output directory.
418
+ */
419
+
420
+ /** @typedef {(context: Readonly<PublicationValidatorContext>) => Promise<PublicationBuildArtifactInput[] | void> | PublicationBuildArtifactInput[] | void} PublicationValidator */
421
+
422
+ /** @typedef {"text" | "binary" | "application"} PublicationTargetRole */
423
+
424
+ /**
425
+ * @typedef PublicationTargetInput
426
+ * @property {string} id - Explicit project target identity.
427
+ * @property {GeneratedArtifactSet} artifactSet - Complete already-validated generated artifacts.
428
+ * @property {PublicationTargetRole} role - Explicit language-neutral target role.
429
+ * @property {string} sourceProjection - Generation-relative generated-source projection.
430
+ * @property {string} buildProjection - Generation-relative compiler-output projection.
431
+ * @property {readonly PublicationValidator[]} [validators] - Ordered candidate validators.
432
+ */
433
+
434
+ /**
435
+ * @typedef PublicationRequest
436
+ * @property {string} generationId - Explicit generation/cycle identity, fresh or an exact retained validator-free candidate.
437
+ * @property {readonly PublicationTargetInput[]} targets - Complete ordered project targets.
438
+ */
439
+
440
+ /**
441
+ * @typedef PublicationOptions
442
+ * @property {AbortSignal} [signal] - Cancellation authority through the active-pointer commit boundary.
443
+ */
444
+
445
+ /**
446
+ * @typedef GenerationContentHash
447
+ * @property {"sha256"} algorithm - Hash algorithm.
448
+ * @property {string} value - Lowercase hexadecimal digest.
449
+ */
450
+
451
+ /**
452
+ * @typedef GenerationArtifactManifest
453
+ * @property {string} path - Artifact-set-relative path.
454
+ * @property {"text" | "binary"} contentKind - Original artifact content representation.
455
+ * @property {string} mediaType - Declared artifact media type.
456
+ * @property {GeneratedArtifactRole} role - Declared artifact role.
457
+ * @property {ArtifactProvenance} provenance - Complete persisted rich, byte, or synthetic provenance.
458
+ * @property {number} byteLength - Exact staged byte length.
459
+ * @property {GenerationContentHash} hash - Exact staged byte hash.
460
+ */
461
+
462
+ /**
463
+ * @typedef GenerationBuildArtifactManifest
464
+ * @property {string} path - Build-projection-relative path.
465
+ * @property {string} mediaType - Declared validator/compiler output media type.
466
+ * @property {string} role - Declared language-neutral validator/compiler output role.
467
+ * @property {number} byteLength - Exact staged byte length.
468
+ * @property {GenerationContentHash} hash - Exact staged byte hash.
469
+ */
470
+
471
+ /**
472
+ * @typedef GenerationTargetManifest
473
+ * @property {string} id - Explicit project target identity.
474
+ * @property {PublicationTargetRole} role - Explicit language-neutral target role.
475
+ * @property {string} target - Artifact-set backend target identity.
476
+ * @property {{source: string, build: string}} projections - Disjoint generation-relative projections.
477
+ * @property {readonly GenerationArtifactManifest[]} artifacts - Ordered generated artifacts.
478
+ * @property {readonly GenerationBuildArtifactManifest[]} buildArtifacts - Ordered validator/compiler outputs.
479
+ * @property {Readonly<Record<string, unknown>>} [metadata] - Persisted target-specific artifact-set metadata.
480
+ */
481
+
482
+ /**
483
+ * @typedef GenerationManifest
484
+ * @property {"SemantifoldGenerationManifest"} schema - Schema discriminator.
485
+ * @property {1} version - Manifest schema version.
486
+ * @property {string} projectId - Explicit project identity.
487
+ * @property {string} generationId - Explicit generation/cycle identity.
488
+ * @property {readonly GenerationTargetManifest[]} targets - Complete ordered target records.
489
+ */
490
+
491
+ /**
492
+ * @typedef PublishedTargetPaths
493
+ * @property {string} id - Explicit project target identity.
494
+ * @property {PublicationTargetRole} role - Explicit language-neutral target role.
495
+ * @property {string} sourcePath - Exact immutable generated-source directory.
496
+ * @property {string} buildPath - Exact immutable compiler-output directory.
497
+ */
498
+
499
+ /**
500
+ * @typedef PublishedGeneration
501
+ * @property {string} generationId - Resolved generation identity.
502
+ * @property {string} generationPath - Exact immutable generation directory.
503
+ * @property {string} manifestPath - Exact generation manifest path.
504
+ * @property {GenerationManifest} manifest - Verified immutable generation manifest.
505
+ * @property {readonly PublishedTargetPaths[]} targets - Exact generation-scoped target paths.
506
+ * @property {boolean} cleanupPending - Whether post-commit journal cleanup remains for recovery.
507
+ */
508
+
398
509
  /**
399
510
  * @typedef DiscoveredToolchain
400
511
  * @property {string} id - Toolchain ID.
@@ -406,6 +517,79 @@
406
517
  * @property {readonly string[]} versionArguments - Exact version argument array.
407
518
  */
408
519
 
520
+ /**
521
+ * @typedef TargetCheckPathArgument
522
+ * @property {number} index - Exact argv index containing the path.
523
+ * @property {"source" | "build"} ownership - Candidate subtree that owns the path.
524
+ * @property {string} [prefix] - Exact non-path argv prefix preceding an owned absolute path.
525
+ */
526
+
527
+ /**
528
+ * @typedef TargetCheckEnvironmentPath
529
+ * @property {string} name - Exact environment variable containing an owned absolute path.
530
+ * @property {"source" | "build" | "tool"} ownership - Candidate subtree or discovered tool that owns the path.
531
+ * @property {DiscoveredToolchain} [tool] - Exact tool executable bound by a tool-owned environment value.
532
+ */
533
+
534
+ /**
535
+ * @typedef TargetCheckOutputOwnership
536
+ * @property {"build"} ownership - Compiler outputs belong only to the candidate build subtree.
537
+ * @property {string} path - Exact generation-scoped build root.
538
+ * @property {string} mediaType - Media type assigned to every produced regular file.
539
+ * @property {string} role - Language-neutral compiler-output role.
540
+ */
541
+
542
+ /**
543
+ * @typedef TargetCheckStageRequest
544
+ * @property {AcceptanceStage} stage - Declared non-executing acceptance stage.
545
+ * @property {DiscoveredToolchain} tool - Exact immutable discovered tool record.
546
+ * @property {string} executable - Exact executable copied from the tool record.
547
+ * @property {readonly string[]} argv - Exact shell-free argument vector.
548
+ * @property {readonly TargetCheckPathArgument[]} pathArguments - Complete ownership declaration for argv paths.
549
+ * @property {string} cwd - Exact candidate-scoped working directory.
550
+ * @property {Readonly<Record<string, string>>} environment - Exact deterministic environment.
551
+ * @property {readonly TargetCheckEnvironmentPath[]} environmentPaths - Owned absolute environment paths.
552
+ * @property {string | null} inputHash - SHA-256 of declared restore inputs, or null for unconditional stages.
553
+ * @property {readonly string[]} inputs - Complete staged artifact inputs read by the stage.
554
+ * @property {Readonly<TargetCheckOutputOwnership> | null} output - Build output ownership, or null for non-producing checks.
555
+ * @property {readonly string[]} transientPaths - Candidate source/build cache or intermediate directories removed after checking.
556
+ */
557
+
558
+ /**
559
+ * @typedef TargetCheckPlan
560
+ * @property {"SemantifoldTargetCheckPlan"} schema - Plan schema discriminator.
561
+ * @property {1} version - Plan schema version.
562
+ * @property {"developer-check"} mode - Non-executing developer-check mode.
563
+ * @property {string} projectId - Exact project identity.
564
+ * @property {string} targetId - Exact project target identity.
565
+ * @property {string} target - Registered backend target identity.
566
+ * @property {string} sourcePath - Exact staged generated-source root.
567
+ * @property {string} buildPath - Exact staged compiler-output root.
568
+ * @property {readonly string[]} artifactPaths - Exact staged artifact paths.
569
+ * @property {readonly TargetCheckStageRequest[]} stages - Ordered target-owned requests.
570
+ */
571
+
572
+ /**
573
+ * @typedef TargetCheckStageResult
574
+ * @property {AcceptanceStage} stage - Completed stage identity.
575
+ * @property {Readonly<{command: string, executable: string, id: string, source: "override" | "canonical", version: string}>} tool - Exact tool identity.
576
+ * @property {readonly string[]} argv - Exact executed argument vector.
577
+ * @property {number} exitCode - Successful process exit code.
578
+ * @property {null} signal - Successful process signal state.
579
+ * @property {string} stdout - Bounded captured standard output.
580
+ * @property {string} stderr - Bounded captured standard error.
581
+ * @property {number} durationMs - Non-negative stage duration.
582
+ */
583
+
584
+ /**
585
+ * @typedef TargetCheckResult
586
+ * @property {string} projectId - Exact project identity.
587
+ * @property {string} targetId - Exact project target identity.
588
+ * @property {string} target - Registered backend target identity.
589
+ * @property {readonly TargetCheckStageResult[]} stages - Ordered successful stage evidence.
590
+ * @property {readonly PublicationBuildArtifactInput[]} outputs - Complete compiler-owned build files.
591
+ */
592
+
409
593
  /**
410
594
  * @typedef AcceptanceStageResult
411
595
  * @property {AcceptanceStage} stage - Completed stage.
package/src/subprocess.js CHANGED
@@ -6,6 +6,7 @@ import {StringDecoder} from "node:string_decoder"
6
6
  const forcedTerminationGraceMs = 250
7
7
  const retainedPipeGraceMs = 250
8
8
  const deadlineFailures = new WeakSet()
9
+ const cancellationFailures = new WeakSet()
9
10
 
10
11
  /**
11
12
  * Executes one exact file while owning its complete bounded lifecycle.
@@ -15,6 +16,7 @@ const deadlineFailures = new WeakSet()
15
16
  * @param {Readonly<Record<string, string>>} input.environment - Exact environment.
16
17
  * @param {string} input.executable - Exact executable path.
17
18
  * @param {number} input.maxBuffer - Maximum bytes captured per output stream.
19
+ * @param {AbortSignal} [input.signal] - Optional owned cancellation signal.
18
20
  * @param {number} input.timeoutMs - Deadline before termination begins.
19
21
  * @returns {Promise<{stderr: string, stdout: string}>} Output after the owned process group closes.
20
22
  */
@@ -38,7 +40,7 @@ export function createExecuteFileWithDeadline({registerSpawnListener}) {
38
40
  * @param {(child: import("node:child_process").ChildProcess, listener: () => void) => void} registerSpawnListener - Registers deadline initialization.
39
41
  * @returns {Promise<{stderr: string, stdout: string}>} Output after the owned process group closes.
40
42
  */
41
- function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environment, executable, maxBuffer, timeoutMs}, registerSpawnListener) {
43
+ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environment, executable, maxBuffer, signal, timeoutMs}, registerSpawnListener) {
42
44
  if (process.platform == "win32") {
43
45
  return Promise.reject(Object.assign(new Error("Owned process-tree termination is unavailable on this platform."), {
44
46
  code: "ENOTSUP",
@@ -46,6 +48,12 @@ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environ
46
48
  stdout: ""
47
49
  }))
48
50
  }
51
+ if (signal?.aborted) {
52
+ const cancellationError = Object.assign(new Error("Subprocess was cancelled before launch."), {stderr: "", stdout: ""})
53
+
54
+ cancellationFailures.add(cancellationError)
55
+ return Promise.reject(cancellationError)
56
+ }
49
57
 
50
58
  return new Promise((resolve, reject) => {
51
59
  /** @type {ReturnType<typeof setTimeout> | undefined} */
@@ -56,8 +64,10 @@ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environ
56
64
  let pipeTimer
57
65
  /** @type {Error | undefined} */
58
66
  let launchError
67
+ let cancellationRequested = false
59
68
  let deadlineExceeded = false
60
69
  let outputExceeded = false
70
+ let processGroupOwned = false
61
71
  let settled = false
62
72
  const stderr = outputCapture(maxBuffer, () => terminateForOutputLimit())
63
73
  const stdout = outputCapture(maxBuffer, () => terminateForOutputLimit())
@@ -68,9 +78,15 @@ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environ
68
78
  stdio: ["ignore", "pipe", "pipe"]
69
79
  })
70
80
  const processGroupId = child.pid
81
+ const cancel = () => {
82
+ if (settled || cancellationRequested || deadlineExceeded || outputExceeded) return
83
+ cancellationRequested = true
84
+ if (processGroupOwned && processGroupId != undefined) beginTermination(processGroupId)
85
+ }
71
86
 
72
87
  child.stderr.on("data", stderr.receive)
73
88
  child.stdout.on("data", stdout.receive)
89
+ signal?.addEventListener("abort", cancel, {once: true})
74
90
  child.once("error", (error) => {
75
91
  launchError = error
76
92
  })
@@ -80,18 +96,24 @@ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environ
80
96
  child.kill("SIGKILL")
81
97
  return
82
98
  }
99
+ processGroupOwned = true
100
+ if (cancellationRequested) {
101
+ beginTermination(processGroupId)
102
+ return
103
+ }
83
104
 
84
105
  deadlineTimer = setTimeout(() => {
85
- if (settled) return
106
+ if (settled || cancellationRequested || deadlineExceeded || outputExceeded) return
86
107
  deadlineExceeded = true
87
108
  beginTermination(processGroupId)
88
109
  }, timeoutMs)
89
110
  })
90
- child.once("close", (code, signal) => {
111
+ child.once("close", (code, closeSignal) => {
91
112
  settled = true
92
113
  if (deadlineTimer != undefined) clearTimeout(deadlineTimer)
93
114
  if (forceTimer != undefined) clearTimeout(forceTimer)
94
115
  if (pipeTimer != undefined) clearTimeout(pipeTimer)
116
+ signal?.removeEventListener("abort", cancel)
95
117
  const capturedStderr = stderr.finish()
96
118
  const capturedStdout = stdout.finish()
97
119
 
@@ -100,24 +122,34 @@ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environ
100
122
  } else if (outputExceeded) {
101
123
  reject(Object.assign(new Error(`Subprocess exceeded its ${maxBuffer}-byte output capture limit.`), {
102
124
  code: "ERR_CHILD_PROCESS_STDIO_MAXBUFFER",
103
- signal,
125
+ signal: closeSignal,
104
126
  stderr: capturedStderr,
105
127
  stdout: capturedStdout
106
128
  }))
129
+ } else if (cancellationRequested) {
130
+ const cancellationError = Object.assign(new Error("Subprocess was cancelled."), {
131
+ code,
132
+ signal: closeSignal,
133
+ stderr: capturedStderr,
134
+ stdout: capturedStdout
135
+ })
136
+
137
+ cancellationFailures.add(cancellationError)
138
+ reject(cancellationError)
107
139
  } else if (deadlineExceeded) {
108
140
  const timeoutError = Object.assign(new Error("Subprocess exceeded its owned deadline."), {
109
141
  code,
110
- signal,
142
+ signal: closeSignal,
111
143
  stderr: capturedStderr,
112
144
  stdout: capturedStdout
113
145
  })
114
146
 
115
147
  deadlineFailures.add(timeoutError)
116
148
  reject(timeoutError)
117
- } else if (code != 0 || signal != null) {
149
+ } else if (code != 0 || closeSignal != null) {
118
150
  reject(Object.assign(new Error("Subprocess failed after launch."), {
119
151
  code,
120
- signal,
152
+ signal: closeSignal,
121
153
  stderr: capturedStderr,
122
154
  stdout: capturedStdout
123
155
  }))
@@ -126,7 +158,7 @@ function executeFileWithDeadlineUsing({arguments: processArguments, cwd, environ
126
158
 
127
159
  /** Begins bounded termination after output capture crosses its limit. */
128
160
  function terminateForOutputLimit() {
129
- if (outputExceeded || settled) return
161
+ if (settled || cancellationRequested || deadlineExceeded || outputExceeded) return
130
162
  outputExceeded = true
131
163
  if (processGroupId != undefined) beginTermination(processGroupId)
132
164
  }
@@ -230,3 +262,12 @@ function signalOwnedProcessGroup(processGroupId, signal) {
230
262
  export function exceededOwnedDeadline(error) {
231
263
  return typeof error == "object" && error != null && deadlineFailures.has(error)
232
264
  }
265
+
266
+ /**
267
+ * Reports whether this module's cancellation signal initiated termination.
268
+ * @param {unknown} error - Subprocess failure.
269
+ * @returns {boolean} Whether the failure belongs to owned cancellation.
270
+ */
271
+ export function cancelledOwnedProcess(error) {
272
+ return typeof error == "object" && error != null && cancellationFailures.has(error)
273
+ }