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.
- package/README.md +11 -5
- package/bin/semantifold.js +6 -0
- package/build/bin/semantifold.d.ts +3 -0
- package/build/bin/semantifold.d.ts.map +1 -0
- package/build/bin/semantifold.js +5 -0
- package/build/index.d.ts +9 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10 -1
- package/build/src/artifact-path.d.ts +16 -0
- package/build/src/artifact-path.d.ts.map +1 -1
- package/build/src/artifact-path.js +29 -3
- package/build/src/backends/c-check.d.ts +7 -0
- package/build/src/backends/c-check.d.ts.map +1 -0
- package/build/src/backends/c-check.js +65 -0
- package/build/src/backends/check-plan.d.ts +96 -0
- package/build/src/backends/check-plan.d.ts.map +1 -0
- package/build/src/backends/check-plan.js +135 -0
- package/build/src/backends/cpp-check.d.ts +7 -0
- package/build/src/backends/cpp-check.d.ts.map +1 -0
- package/build/src/backends/cpp-check.js +59 -0
- package/build/src/backends/csharp-check.d.ts +7 -0
- package/build/src/backends/csharp-check.d.ts.map +1 -0
- package/build/src/backends/csharp-check.js +125 -0
- package/build/src/backends/csharp.d.ts +1 -0
- package/build/src/backends/csharp.d.ts.map +1 -1
- package/build/src/backends/csharp.js +5 -4
- package/build/src/backends/dart-check.d.ts +7 -0
- package/build/src/backends/dart-check.d.ts.map +1 -0
- package/build/src/backends/dart-check.js +103 -0
- package/build/src/backends/dart.d.ts +2 -0
- package/build/src/backends/dart.d.ts.map +1 -1
- package/build/src/backends/dart.js +5 -5
- package/build/src/backends/go-check.d.ts +7 -0
- package/build/src/backends/go-check.d.ts.map +1 -0
- package/build/src/backends/go-check.js +77 -0
- package/build/src/backends/go.d.ts +1 -0
- package/build/src/backends/go.d.ts.map +1 -1
- package/build/src/backends/go.js +3 -3
- package/build/src/backends/java-check.d.ts +21 -0
- package/build/src/backends/java-check.d.ts.map +1 -0
- package/build/src/backends/java-check.js +73 -0
- package/build/src/backends/javascript-check.d.ts +7 -0
- package/build/src/backends/javascript-check.d.ts.map +1 -0
- package/build/src/backends/javascript-check.js +29 -0
- package/build/src/backends/kotlin-check.d.ts +7 -0
- package/build/src/backends/kotlin-check.d.ts.map +1 -0
- package/build/src/backends/kotlin-check.js +31 -0
- package/build/src/backends/php-check.d.ts +7 -0
- package/build/src/backends/php-check.d.ts.map +1 -0
- package/build/src/backends/php-check.js +21 -0
- package/build/src/backends/program.d.ts +7 -0
- package/build/src/backends/program.d.ts.map +1 -1
- package/build/src/backends/program.js +16 -1
- package/build/src/backends/python-check.d.ts +7 -0
- package/build/src/backends/python-check.d.ts.map +1 -0
- package/build/src/backends/python-check.js +28 -0
- package/build/src/backends/ruby-check.d.ts +7 -0
- package/build/src/backends/ruby-check.d.ts.map +1 -0
- package/build/src/backends/ruby-check.js +21 -0
- package/build/src/backends/rust-check.d.ts +7 -0
- package/build/src/backends/rust-check.d.ts.map +1 -0
- package/build/src/backends/rust-check.js +65 -0
- package/build/src/backends/swift-check.d.ts +7 -0
- package/build/src/backends/swift-check.d.ts.map +1 -0
- package/build/src/backends/swift-check.js +77 -0
- package/build/src/backends/typescript-check.d.ts +7 -0
- package/build/src/backends/typescript-check.d.ts.map +1 -0
- package/build/src/backends/typescript-check.js +33 -0
- package/build/src/backends/zig-check.d.ts +7 -0
- package/build/src/backends/zig-check.d.ts.map +1 -0
- package/build/src/backends/zig-check.js +70 -0
- package/build/src/diagnostic.d.ts +13 -1
- package/build/src/diagnostic.d.ts.map +1 -1
- package/build/src/diagnostic.js +14 -2
- package/build/src/frontends/program.d.ts +6 -0
- package/build/src/frontends/program.d.ts.map +1 -1
- package/build/src/frontends/program.js +9 -1
- package/build/src/language-registry.d.ts +54 -0
- package/build/src/language-registry.d.ts.map +1 -1
- package/build/src/language-registry.js +107 -5
- package/build/src/project-build.d.ts +172 -0
- package/build/src/project-build.d.ts.map +1 -0
- package/build/src/project-build.js +320 -0
- package/build/src/project-cli.d.ts +40 -0
- package/build/src/project-cli.d.ts.map +1 -0
- package/build/src/project-cli.js +145 -0
- package/build/src/project-manifest.d.ts +148 -0
- package/build/src/project-manifest.d.ts.map +1 -0
- package/build/src/project-manifest.js +432 -0
- package/build/src/project-reporter.d.ts +81 -0
- package/build/src/project-reporter.d.ts.map +1 -0
- package/build/src/project-reporter.js +293 -0
- package/build/src/project-snapshot.d.ts +129 -0
- package/build/src/project-snapshot.d.ts.map +1 -0
- package/build/src/project-snapshot.js +362 -0
- package/build/src/project-watch-reporter.d.ts +125 -0
- package/build/src/project-watch-reporter.d.ts.map +1 -0
- package/build/src/project-watch-reporter.js +280 -0
- package/build/src/project-watch.d.ts +133 -0
- package/build/src/project-watch.d.ts.map +1 -0
- package/build/src/project-watch.js +839 -0
- package/build/src/publication.d.ts +218 -0
- package/build/src/publication.d.ts.map +1 -0
- package/build/src/publication.js +1832 -0
- package/build/src/semantic/types.d.ts +613 -0
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +163 -1
- package/build/src/subprocess.d.ts +8 -0
- package/build/src/subprocess.d.ts.map +1 -1
- package/build/src/subprocess.js +50 -9
- package/build/src/target-check.d.ts +52 -0
- package/build/src/target-check.d.ts.map +1 -0
- package/build/src/target-check.js +796 -0
- package/build/src/toolchains.d.ts.map +1 -1
- package/build/src/toolchains.js +3 -3
- package/docs/architecture.md +3 -1
- package/docs/c.md +4 -0
- package/docs/cpp.md +4 -0
- package/docs/dart.md +4 -0
- package/docs/generated-artifact-publication.md +98 -0
- package/docs/kotlin.md +2 -2
- package/docs/language-support.md +29 -3
- package/docs/project-build-cli.md +147 -0
- package/docs/project-watch.md +60 -0
- package/docs/rust.md +4 -0
- package/docs/swift.md +2 -0
- package/docs/testing.md +70 -3
- package/docs/watch-build-pipeline.md +42 -26
- package/docs/zig.md +2 -0
- package/examples/jsdoc-java-watch/expected-output.txt +3 -0
- package/examples/jsdoc-java-watch/semantifold.json +23 -0
- package/examples/jsdoc-java-watch/src/main.js +21 -0
- package/index.js +9 -0
- package/package.json +6 -1
- package/src/artifact-path.js +31 -2
- package/src/backends/c-check.js +80 -0
- package/src/backends/check-plan.js +147 -0
- package/src/backends/cpp-check.js +73 -0
- package/src/backends/csharp-check.js +139 -0
- package/src/backends/csharp.js +4 -3
- package/src/backends/dart-check.js +117 -0
- package/src/backends/dart.js +4 -4
- package/src/backends/go-check.js +89 -0
- package/src/backends/go.js +2 -2
- package/src/backends/java-check.js +77 -0
- package/src/backends/javascript-check.js +33 -0
- package/src/backends/kotlin-check.js +41 -0
- package/src/backends/php-check.js +23 -0
- package/src/backends/program.js +17 -0
- package/src/backends/python-check.js +30 -0
- package/src/backends/ruby-check.js +23 -0
- package/src/backends/rust-check.js +78 -0
- package/src/backends/swift-check.js +89 -0
- package/src/backends/typescript-check.js +37 -0
- package/src/backends/zig-check.js +81 -0
- package/src/diagnostic.js +9 -1
- package/src/frontends/program.js +9 -0
- package/src/language-registry.js +113 -4
- package/src/project-build.js +353 -0
- package/src/project-cli.js +155 -0
- package/src/project-manifest.js +479 -0
- package/src/project-reporter.js +320 -0
- package/src/project-snapshot.js +403 -0
- package/src/project-watch-reporter.js +303 -0
- package/src/project-watch.js +870 -0
- package/src/publication.js +2071 -0
- package/src/semantic/types.js +184 -0
- package/src/subprocess.js +49 -8
- package/src/target-check.js +844 -0
- package/src/toolchains.js +3 -2
- package/tsconfig.json +1 -1
package/src/semantic/types.js
CHANGED
|
@@ -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,
|
|
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 ||
|
|
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 (
|
|
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
|
+
}
|