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
@@ -1,8 +1,79 @@
import { parse, type ParserOptions, type ParserPlugin } from "@babel/parser";
import * as t from "@babel/types";
import {
hasOnlyInlineTypeExportSpecifiers,
hasOnlyInlineTypeImportSpecifiers,
isTypeOnlyExportDeclaration,
isTypeOnlyImportDeclaration,
isErasedJavaScriptDeclaration,
semanticImportEqualsSpecifier,
} from "./javascriptModuleDeclaration.js";
/** Babel AST produced by REA's inert JavaScript parser boundary. */
export type ParsedJavaScriptSource = ReturnType<typeof parse>;
// Babel's module classification includes erased TypeScript syntax. Keep the
// runtime proof separate, including explicit filename mode, for every parser entry.
type JavaScriptRuntimeContext = "module" | "commonjs" | "unknown";
const runtimeContextByProgram = new WeakMap<
t.Program,
JavaScriptRuntimeContext
>();
/** Only parser-owned facts establish module or CommonJS wrapper isolation. */
export const javaScriptRuntimeContext = (
program: t.Program,
): JavaScriptRuntimeContext =>
runtimeContextByProgram.get(program) ?? "unknown";
const hasRuntimeModuleDeclaration = (program: t.Program): boolean =>
program.body.some((node) => {
if (t.isTSImportEqualsDeclaration(node))
return semanticImportEqualsSpecifier(node) !== null;
if (t.isImportDeclaration(node))
return (
!isTypeOnlyImportDeclaration(node) &&
!hasOnlyInlineTypeImportSpecifiers(node)
);
if (t.isExportNamedDeclaration(node) || t.isExportAllDeclaration(node))
return (
!isTypeOnlyExportDeclaration(node) &&
(!t.isExportNamedDeclaration(node) ||
(!hasOnlyInlineTypeExportSpecifiers(node) &&
(node.declaration == null ||
!isErasedJavaScriptDeclaration(node.declaration))))
);
return (
t.isExportDefaultDeclaration(node) &&
!isErasedJavaScriptDeclaration(node.declaration)
);
});
const parseWithRuntimeContext = (
source: string,
sourcePath: string | undefined,
options: ParserOptions,
): ParsedJavaScriptSource => {
const file = parse(source, options);
runtimeContextByProgram.set(
file.program,
/\.c[jt]s$/iu.test(sourcePath ?? "")
? /\.d\.cts$/iu.test(sourcePath ?? "")
? "unknown"
: "commonjs"
: isExplicitModuleSourcePath(sourcePath)
? "module"
: file.program.body.some((node) => t.isTSExportAssignment(node))
? // CommonJS isolation does not establish strict ESM semantics.
"commonjs"
: file.program.sourceType === "module" &&
hasRuntimeModuleDeclaration(file.program)
? "module"
: "unknown",
);
return file;
};
/**
* Babel plugins for one source path. Single owner for TypeScript/JSX
* mode selection (tsc + Babel `typescript` plugin semantics).
@@ -82,7 +153,7 @@ export const parseRecoveredJavaScript = (
delete normalizedOptions.allowNewTargetOutsideFunction;
}
return {
file: parse(source, {
file: parseWithRuntimeContext(source, sourcePath, {
...normalizedOptions,
sourceType,
errorRecovery: true,
@@ -90,14 +161,14 @@ export const parseRecoveredJavaScript = (
moduleOnlyErrors: [],
};
}
const file = parse(source, {
const file = parseWithRuntimeContext(source, sourcePath, {
...options,
sourceType: "unambiguous",
errorRecovery: true,
});
if (file.program.sourceType !== "script" || file.errors.length === 0)
return { file, moduleOnlyErrors: [] };
const script = parse(source, {
const script = parseWithRuntimeContext(source, sourcePath, {
...options,
sourceType: "script",
errorRecovery: true,
@@ -124,7 +195,7 @@ export const parseJavaScriptSource = (
attachComment: false,
plugins: parserPluginsForPath(sourcePath),
};
const file = parse(source, {
const file = parseWithRuntimeContext(source, sourcePath, {
...options,
// Inert artifact analysis retains module declarations even in .cjs assets.
// Infer their syntax here; reference imports keep filename-mode diagnostics.
@@ -137,7 +208,10 @@ export const parseJavaScriptSource = (
return commonjs &&
file.program.sourceType === "script" &&
file.errors.length > 0
? parse(source, { ...options, sourceType: "commonjs" })
? parseWithRuntimeContext(source, sourcePath, {
...options,
sourceType: "commonjs",
})
: file;
} catch (cause: unknown) {
// Unparseable source is represented by the null return.