fix(javascript): ignore erased TypeScript names in native-addon requests (#2766)

* fix(javascript): ignore erased TypeScript names in native-addon requests

Skip import type / export type declarations and per-binding type
specifiers when collecting .node addon members so only runtime value
imports request native exports (fixes #2667).

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(javascript): cover erased TypeScript re-export forms

* test(javascript): allow Inspector observation events to arrive

* test(inspector): emit events before enable responses

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
BeqaKs
2026-10-14 01:39:09 +04:00
committed by GitHub
parent bee73fcb67
commit 06739aeaf2
4 changed files with 186 additions and 6 deletions
@@ -2,6 +2,67 @@ import { describe, expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
describe("native addon type-only TypeScript imports", () => {
it("ignores declaration-wide import type and export type from .node modules", () => {
const analysis = analyzeJavaScriptStaticSource(`
import type { NativeThing } from "./addon.node";
export type { Extra } from "./addon.node";
`);
expect(analysis.parse_status).toBe("complete");
expect(analysis.electron.native_addon_bindings).toEqual([]);
});
it("keeps only value members from mixed type/value native imports", () => {
const analysis = analyzeJavaScriptStaticSource(`
import { type OtherThing, load } from "./addon.node";
load();
`);
expect(analysis.electron.native_addon_bindings).toEqual([
expect.objectContaining({
specifier: "./addon.node",
binding_kind: "import",
members: ["load"],
}),
]);
});
it("retains ordinary value imports of native addons", () => {
const analysis = analyzeJavaScriptStaticSource(`
import { load } from "./addon.node";
load();
`);
expect(analysis.electron.native_addon_bindings).toEqual([
expect.objectContaining({
specifier: "./addon.node",
binding_kind: "import",
members: ["load"],
}),
]);
});
});
describe("native addon type-only re-exports", () => {
it.each([
['export { type Extra, load } from "./addon.node";', ["load"]],
['export { type Extra } from "./addon.node";', []],
['export type * from "./addon.node";', []],
] as const)("retains only runtime members from %s", (source, members) => {
const analysis = analyzeJavaScriptStaticSource(source);
expect(analysis.parse_status).toBe("complete");
expect(analysis.electron.native_addon_bindings).toEqual(
members.length === 0
? []
: [
expect.objectContaining({
specifier: "./addon.node",
binding_kind: "re-export",
members: [...members],
}),
],
);
});
});
describe("native addon loader provenance", () => {
it("distinguishes CommonJS and ESM re-exports", () => {
const analysis = analyzeJavaScriptStaticSource(`