semantifold 0.9.0 → 0.11.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 +6 -3
- 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 +8 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +9 -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/kotlin.d.ts +1 -1
- package/build/src/backends/kotlin.js +2 -2
- 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/shared.d.ts.map +1 -1
- package/build/src/backends/shared.js +29 -1
- 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/java.d.ts.map +1 -1
- package/build/src/frontends/java.js +23 -1
- package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
- package/build/src/frontends/javascript-typescript.js +45 -4
- package/build/src/frontends/php.d.ts.map +1 -1
- package/build/src/frontends/php.js +54 -3
- 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/frontends/ruby.d.ts.map +1 -1
- package/build/src/frontends/ruby.js +55 -5
- 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 +124 -10
- 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 +69 -5
- package/build/src/publication.d.ts.map +1 -1
- package/build/src/publication.js +246 -57
- package/build/src/semantic/effects.js +3 -1
- package/build/src/semantic/provenance.d.ts.map +1 -1
- package/build/src/semantic/provenance.js +11 -1
- package/build/src/semantic/types.d.ts +355 -4
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +92 -3
- package/build/src/semantic/validate.js +18 -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/adr-expression-breadth.md +186 -0
- 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 +11 -8
- package/docs/kotlin.md +2 -2
- package/docs/language-support.md +40 -6
- package/docs/parser-qualification.md +1 -1
- 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 +39 -23
- 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 +8 -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/kotlin.js +1 -1
- 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/shared.js +30 -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/java.js +24 -0
- package/src/frontends/javascript-typescript.js +49 -2
- package/src/frontends/php.js +61 -2
- package/src/frontends/program.js +9 -0
- package/src/frontends/ruby.js +62 -2
- package/src/language-registry.js +130 -9
- 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 +275 -58
- package/src/semantic/effects.js +1 -0
- package/src/semantic/provenance.js +8 -0
- package/src/semantic/types.js +101 -2
- package/src/semantic/validate.js +26 -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.
|
|
@@ -173,6 +180,8 @@
|
|
|
173
180
|
* @property {boolean} orderedListIteration - Task 008 ordered immutable-list iteration and nearest-loop control.
|
|
174
181
|
* @property {boolean} orderedMapIteration - Task 014 insertion-ordered immutable-map pair iteration.
|
|
175
182
|
* @property {boolean} conditionControlledLoops - Task 032 strict-Boolean pre-condition loops and resolved control.
|
|
183
|
+
* @property {boolean} conditionalExpressions - Task 048 strict-Boolean conditional expressions with joined arm types.
|
|
184
|
+
* @property {boolean} stringInterpolation - Task 048 parser-proved string interpolation lowered to checked string concatenation.
|
|
176
185
|
* @property {boolean} closedRecords - Task 009 nominal closed immutable records, construction, and member reads.
|
|
177
186
|
* @property {boolean} typedErrors - Task 011 nominal unchecked errors, raises, and exact typed catches.
|
|
178
187
|
* @property {boolean} typeParametersAndGenerics - Task 012 invariant unbounded type parameters and closed generic applications.
|
|
@@ -189,6 +198,7 @@
|
|
|
189
198
|
* @property {Readonly<LanguageFeatureCapabilities>} features - Semantic feature capabilities.
|
|
190
199
|
* @property {Readonly<LanguageMappingCapabilities>} mapping - Mapping forms.
|
|
191
200
|
* @property {Readonly<LanguageAcceptanceCapabilities>} acceptance - Stages and toolchains.
|
|
201
|
+
* @property {Readonly<LanguageCheckCapabilities>} check - Non-executing developer-check capability.
|
|
192
202
|
*/
|
|
193
203
|
|
|
194
204
|
/**
|
|
@@ -425,10 +435,15 @@
|
|
|
425
435
|
|
|
426
436
|
/**
|
|
427
437
|
* @typedef PublicationRequest
|
|
428
|
-
* @property {string} generationId -
|
|
438
|
+
* @property {string} generationId - Explicit generation/cycle identity, fresh or an exact retained validator-free candidate.
|
|
429
439
|
* @property {readonly PublicationTargetInput[]} targets - Complete ordered project targets.
|
|
430
440
|
*/
|
|
431
441
|
|
|
442
|
+
/**
|
|
443
|
+
* @typedef PublicationOptions
|
|
444
|
+
* @property {AbortSignal} [signal] - Cancellation authority through the active-pointer commit boundary.
|
|
445
|
+
*/
|
|
446
|
+
|
|
432
447
|
/**
|
|
433
448
|
* @typedef GenerationContentHash
|
|
434
449
|
* @property {"sha256"} algorithm - Hash algorithm.
|
|
@@ -504,6 +519,79 @@
|
|
|
504
519
|
* @property {readonly string[]} versionArguments - Exact version argument array.
|
|
505
520
|
*/
|
|
506
521
|
|
|
522
|
+
/**
|
|
523
|
+
* @typedef TargetCheckPathArgument
|
|
524
|
+
* @property {number} index - Exact argv index containing the path.
|
|
525
|
+
* @property {"source" | "build"} ownership - Candidate subtree that owns the path.
|
|
526
|
+
* @property {string} [prefix] - Exact non-path argv prefix preceding an owned absolute path.
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* @typedef TargetCheckEnvironmentPath
|
|
531
|
+
* @property {string} name - Exact environment variable containing an owned absolute path.
|
|
532
|
+
* @property {"source" | "build" | "tool"} ownership - Candidate subtree or discovered tool that owns the path.
|
|
533
|
+
* @property {DiscoveredToolchain} [tool] - Exact tool executable bound by a tool-owned environment value.
|
|
534
|
+
*/
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* @typedef TargetCheckOutputOwnership
|
|
538
|
+
* @property {"build"} ownership - Compiler outputs belong only to the candidate build subtree.
|
|
539
|
+
* @property {string} path - Exact generation-scoped build root.
|
|
540
|
+
* @property {string} mediaType - Media type assigned to every produced regular file.
|
|
541
|
+
* @property {string} role - Language-neutral compiler-output role.
|
|
542
|
+
*/
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* @typedef TargetCheckStageRequest
|
|
546
|
+
* @property {AcceptanceStage} stage - Declared non-executing acceptance stage.
|
|
547
|
+
* @property {DiscoveredToolchain} tool - Exact immutable discovered tool record.
|
|
548
|
+
* @property {string} executable - Exact executable copied from the tool record.
|
|
549
|
+
* @property {readonly string[]} argv - Exact shell-free argument vector.
|
|
550
|
+
* @property {readonly TargetCheckPathArgument[]} pathArguments - Complete ownership declaration for argv paths.
|
|
551
|
+
* @property {string} cwd - Exact candidate-scoped working directory.
|
|
552
|
+
* @property {Readonly<Record<string, string>>} environment - Exact deterministic environment.
|
|
553
|
+
* @property {readonly TargetCheckEnvironmentPath[]} environmentPaths - Owned absolute environment paths.
|
|
554
|
+
* @property {string | null} inputHash - SHA-256 of declared restore inputs, or null for unconditional stages.
|
|
555
|
+
* @property {readonly string[]} inputs - Complete staged artifact inputs read by the stage.
|
|
556
|
+
* @property {Readonly<TargetCheckOutputOwnership> | null} output - Build output ownership, or null for non-producing checks.
|
|
557
|
+
* @property {readonly string[]} transientPaths - Candidate source/build cache or intermediate directories removed after checking.
|
|
558
|
+
*/
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* @typedef TargetCheckPlan
|
|
562
|
+
* @property {"SemantifoldTargetCheckPlan"} schema - Plan schema discriminator.
|
|
563
|
+
* @property {1} version - Plan schema version.
|
|
564
|
+
* @property {"developer-check"} mode - Non-executing developer-check mode.
|
|
565
|
+
* @property {string} projectId - Exact project identity.
|
|
566
|
+
* @property {string} targetId - Exact project target identity.
|
|
567
|
+
* @property {string} target - Registered backend target identity.
|
|
568
|
+
* @property {string} sourcePath - Exact staged generated-source root.
|
|
569
|
+
* @property {string} buildPath - Exact staged compiler-output root.
|
|
570
|
+
* @property {readonly string[]} artifactPaths - Exact staged artifact paths.
|
|
571
|
+
* @property {readonly TargetCheckStageRequest[]} stages - Ordered target-owned requests.
|
|
572
|
+
*/
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* @typedef TargetCheckStageResult
|
|
576
|
+
* @property {AcceptanceStage} stage - Completed stage identity.
|
|
577
|
+
* @property {Readonly<{command: string, executable: string, id: string, source: "override" | "canonical", version: string}>} tool - Exact tool identity.
|
|
578
|
+
* @property {readonly string[]} argv - Exact executed argument vector.
|
|
579
|
+
* @property {number} exitCode - Successful process exit code.
|
|
580
|
+
* @property {null} signal - Successful process signal state.
|
|
581
|
+
* @property {string} stdout - Bounded captured standard output.
|
|
582
|
+
* @property {string} stderr - Bounded captured standard error.
|
|
583
|
+
* @property {number} durationMs - Non-negative stage duration.
|
|
584
|
+
*/
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* @typedef TargetCheckResult
|
|
588
|
+
* @property {string} projectId - Exact project identity.
|
|
589
|
+
* @property {string} targetId - Exact project target identity.
|
|
590
|
+
* @property {string} target - Registered backend target identity.
|
|
591
|
+
* @property {readonly TargetCheckStageResult[]} stages - Ordered successful stage evidence.
|
|
592
|
+
* @property {readonly PublicationBuildArtifactInput[]} outputs - Complete compiler-owned build files.
|
|
593
|
+
*/
|
|
594
|
+
|
|
507
595
|
/**
|
|
508
596
|
* @typedef AcceptanceStageResult
|
|
509
597
|
* @property {AcceptanceStage} stage - Completed stage.
|
|
@@ -897,6 +985,17 @@
|
|
|
897
985
|
* @property {SemanticNodeSourceProvenance} [sourceProvenance] - Node-associated provenance.
|
|
898
986
|
*/
|
|
899
987
|
|
|
988
|
+
/**
|
|
989
|
+
* @typedef ConditionalExpression
|
|
990
|
+
* @property {"ConditionalExpression"} kind - Node discriminator.
|
|
991
|
+
* @property {Expression} condition - Strict boolean test evaluated exactly once.
|
|
992
|
+
* @property {Expression} consequent - Arm evaluated when the test is true.
|
|
993
|
+
* @property {Expression} alternate - Arm evaluated when the test is false.
|
|
994
|
+
* @property {SemanticTypeName} type - Joined arm result type assigned by validation.
|
|
995
|
+
* @property {SourceLocation} location - Source location.
|
|
996
|
+
* @property {SemanticNodeSourceProvenance} [sourceProvenance] - Node-associated provenance.
|
|
997
|
+
*/
|
|
998
|
+
|
|
900
999
|
/**
|
|
901
1000
|
* @typedef CallExpression
|
|
902
1001
|
* @property {"CallExpression"} kind - Node discriminator.
|
|
@@ -996,7 +1095,7 @@
|
|
|
996
1095
|
* @property {SemanticNodeSourceProvenance} [sourceProvenance] - Parser-owned message-member range.
|
|
997
1096
|
*/
|
|
998
1097
|
|
|
999
|
-
/** @typedef {IdentifierExpression | ReceiverExpression | IntegerLiteral | BooleanLiteral | StringLiteral | OptionalNone | OptionalSome | OptionalIsPresent | OptionalUnwrap | ListLiteral | MapLiteral | OrderedMapLiteral | ListIndexExpression | MapLookupExpression | CollectionSizeExpression | UnaryExpression | BinaryExpression | CallExpression | EffectCallExpression | OwnedMoveExpression | OwnedBorrowExpression | MethodCallExpression | ReferenceConstruction | RecordConstruction | MemberRead | PrivateFieldRead | ErrorMessageRead} Expression */
|
|
1098
|
+
/** @typedef {IdentifierExpression | ReceiverExpression | IntegerLiteral | BooleanLiteral | StringLiteral | OptionalNone | OptionalSome | OptionalIsPresent | OptionalUnwrap | ListLiteral | MapLiteral | OrderedMapLiteral | ListIndexExpression | MapLookupExpression | CollectionSizeExpression | UnaryExpression | BinaryExpression | ConditionalExpression | CallExpression | EffectCallExpression | OwnedMoveExpression | OwnedBorrowExpression | MethodCallExpression | ReferenceConstruction | RecordConstruction | MemberRead | PrivateFieldRead | ErrorMessageRead} Expression */
|
|
1000
1099
|
|
|
1001
1100
|
/**
|
|
1002
1101
|
* @typedef LocalDeclaration
|
package/src/semantic/validate.js
CHANGED
|
@@ -2284,6 +2284,32 @@ function inferExpressionType(expression, scope, functions, records, fail, normal
|
|
|
2284
2284
|
}
|
|
2285
2285
|
return scalarType(signature.result)
|
|
2286
2286
|
}
|
|
2287
|
+
if (expression.kind == "ConditionalExpression") {
|
|
2288
|
+
const conditionType = inferValueExpressionType(expression.condition, scope, functions, records, fail,
|
|
2289
|
+
normalizeOperations, "a condition")
|
|
2290
|
+
|
|
2291
|
+
if (!isScalarType(conditionType, "boolean")) {
|
|
2292
|
+
fail("NON_BOOLEAN_CONDITION", `Conditional expression condition type ${typeDescription(conditionType)}; expected boolean.`,
|
|
2293
|
+
expression.condition.location)
|
|
2294
|
+
}
|
|
2295
|
+
const consequentScope = createScope(scope, [])
|
|
2296
|
+
const alternateScope = createScope(scope, [])
|
|
2297
|
+
|
|
2298
|
+
applyPresenceNarrowing(expression.condition, scope, consequentScope, true)
|
|
2299
|
+
applyPresenceNarrowing(expression.condition, scope, alternateScope, false)
|
|
2300
|
+
const consequentType = inferValueExpressionType(expression.consequent, consequentScope, functions, records, fail,
|
|
2301
|
+
normalizeOperations, "a conditional expression consequent")
|
|
2302
|
+
const alternateType = inferValueExpressionType(expression.alternate, alternateScope, functions, records, fail,
|
|
2303
|
+
normalizeOperations, "a conditional expression alternate")
|
|
2304
|
+
|
|
2305
|
+
if (!sameType(consequentType, alternateType)) {
|
|
2306
|
+
fail("TYPE_MISMATCH", `Conditional expression arms ${typeDescription(consequentType)} and ${typeDescription(alternateType)}; expected one joined type.`,
|
|
2307
|
+
expression.alternate.location)
|
|
2308
|
+
}
|
|
2309
|
+
Reflect.set(expression, "type", consequentType)
|
|
2310
|
+
|
|
2311
|
+
return consequentType
|
|
2312
|
+
}
|
|
2287
2313
|
if (expression.kind == "BinaryExpression") {
|
|
2288
2314
|
const left = inferValueExpressionType(expression.left, scope, functions, records, fail, normalizeOperations, "a binary operand")
|
|
2289
2315
|
const right = inferValueExpressionType(expression.right, scope, functions, records, fail, normalizeOperations, "a binary operand")
|
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
|
+
}
|