fix(javascript): preserve effective child-process stdio options (#4336)

* fix(javascript): preserve effective child-process stdio options

* fix(javascript): retain proven callbacks and primitive stdio keys

* fix(javascript): preserve argv shapes and nullish spreads

* fix(javascript): bound callable proofs and retain exposed binding uncertainty

* test(javascript): keep callback acceptance within transport budget

* test(javascript): inspect application coverage for callback proof limits

* fix(javascript): keep spread command argument slots uncertain

* fix(javascript): bound mapped argument content proofs

* fix(javascript): distinguish erased declarations from runtime shadows

* fix(javascript): prove runtime module context before binding isolation

* fix(javascript): share erased declaration and opaque scope proofs

* fix(javascript): keep lowered enum scopes opaque

* fix(javascript): narrow stdio proofs and consolidate regressions

* perf(javascript): reuse lexical references for child shapes

* fix(javascript): retain CommonJS child argument context

* fix(javascript): keep Annex B affected child arguments unknown

* fix(javascript): recognize value import-equals runtime modules

* fix(javascript): retain exact stdio through module and primitive syntax

* fix(javascript): bound inline spread property resolution

* fix(javascript): distinguish copied methods from getters
This commit is contained in:
星闌
2026-10-17 15:51:55 +08:00
committed by GitHub
parent 0cd4eafd61
commit de9371b85d
18 changed files with 1114 additions and 93 deletions
@@ -0,0 +1,72 @@
import * as t from "@babel/types";
import { expect, it } from "vitest";
import {
semanticStaticPropertyKey,
staticObjectProperty,
} from "./javascriptAstValues.js";
import { SEMANTIC_EXPRESSION_DEPTH_LIMIT } from "./javascriptSemanticResourceLimits.js";
it("copies ordinary members without proving requested methods or getter effects", () => {
const method = (name: string, computed = false) =>
t.objectMethod(
"method",
t.identifier(name),
[],
t.blockStatement([]),
computed,
);
const getter = t.objectMethod(
"get",
t.identifier("helper"),
[],
t.blockStatement([]),
);
const setter = t.objectMethod(
"set",
t.identifier("helper"),
[t.identifier("value")],
t.blockStatement([]),
);
for (const [member, status] of [
[method("helper"), "explicit"],
[setter, "explicit"],
[method("stdio"), "dynamic"],
[getter, "dynamic"],
[method("key", true), "dynamic"],
] as const) {
const object = t.objectExpression([
t.objectProperty(t.identifier("stdio"), t.stringLiteral("inherit")),
t.spreadElement(t.objectExpression([member])),
]);
expect(staticObjectProperty(object, "stdio").status).toBe(status);
}
});
it("limits unary-plus keys to transparent numeric literals", () => {
const wrapped = t.tsAsExpression(t.numericLiteral(1), t.tsNumberKeyword());
expect(semanticStaticPropertyKey(t.unaryExpression("+", wrapped), true)).toBe(
"1",
);
for (const argument of [
t.stringLiteral("1"),
t.bigIntLiteral(1n),
t.identifier("input"),
])
expect(
semanticStaticPropertyKey(t.unaryExpression("+", argument), true),
).toBeNull();
});
it("bounds nested inline object spreads without losing a shallow final property", () => {
let object = t.objectExpression([
t.objectProperty(t.identifier("stdio"), t.stringLiteral("inherit")),
]);
for (let depth = 0; depth < SEMANTIC_EXPRESSION_DEPTH_LIMIT; depth++)
object = t.objectExpression([t.spreadElement(object)]);
expect(staticObjectProperty(object, "stdio").status).toBe("explicit");
expect(
staticObjectProperty(t.objectExpression([t.spreadElement(object)]), "stdio")
.status,
).toBe("dynamic");
});