[PR #1827] [MERGED] fix(javascript): follow bundler namespace interop for Electron APIs #4842

Closed
opened 2026-10-31 00:55:51 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1827
Author: @kaoru0822-kitauji
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/electron-namespace-browser-window


📝 Commits (2)

  • 029767f fix(javascript): follow bundler namespace interop for Electron APIs
  • 87f3e6e fix(javascript): require emitted interop helper definitions

📊 Changes

5 files changed (+187 additions, -14 deletions)

View changed files

📝 docs/javascript-artifact-reconstruction.md (+9 -2)
📝 src/domain/javascript/electronStaticAnalysisIdentity.test.ts (+47 -0)
📝 src/domain/javascript/javascriptElectronMemberWrites.ts (+1 -1)
📝 src/domain/javascript/javascriptSemanticAnalysis.ts (+59 -11)
📝 src/domain/javascript/javascriptSemanticRequireOrigin.ts (+71 -0)

📄 Description

Summary

Fixes #1802.

Some bundled Electron main processes reported browser_windows: 0 and preload_entrypoints: 0 even though they plainly construct new electron.BrowserWindow(...). A plain const electron = require("electron") namespace already resolved. The miss comes from the CommonJS interop that bundlers emit for import * as Electron from "electron":

Emitter Output Why it was missed
Rolldown / tsdown (the T3 Code build in the issue) let electron = require("electron"); electron = __toESM(electron); The reassignment marked the binding as unresolved
esbuild var import_electron = __toESM(require("electron")); The helper call hid the require origin
tsc (esModuleInterop) const Electron = __importStar(require("electron")); Same as esbuild

Change

  • semanticNamespaceInteropOperand recognizes __toESM, __importStar, and _interopRequireWildcard by name. A call only counts when the helper is a locally declared binding that is never reassigned and its lexical resolution is not blocked. These helpers return an object that exposes every own member of the wrapped module, so member paths pass through unchanged.
  • Electron binding classification looks through those helpers. A plain = that rewraps the binding's own value (x = __toESM(x)) no longer counts as a reassignment. Any other write still leaves the binding unresolved, as before.
  • The Electron identity limitation text and docs/javascript-artifact-reconstruction.md now say that these helpers are recognized by name.

These cases still produce no finding and are covered by the test:

  • an unbound or global helper
  • a helper that is reassigned
  • a rewrap of a different operand
  • a rewrap followed by another write
  • ||=

Not in this PR: a webPreferences.preload written as a non-literal expression (e.g. environment.preloadPath) is already kept as a dynamic web preference and counted as unknown. It still does not appear in preload_entrypoints, and I left that as is.

Validation

  • I added a case to src/domain/javascript/electronStaticAnalysisIdentity.test.ts. It covers the Rolldown, esbuild, and tsc forms plus the negative forms, and it fails without the fix.
  • npm run test:focused passes on all src/domain/javascript tests, the Electron composition tests, the application acceptance tests, and the bundler runtime-scope boundary test: 68 files, 1001 tests.
  • npm run check:fast and npm run docs:check pass.
  • I ran rea analyze-javascript-application on hand-written source shaped like each bundler's output. I did not run it against the T3 Code AppImage itself.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1827 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/electron-namespace-browser-window` --- ### 📝 Commits (2) - [`029767f`](https://github.com/morluto/rea/commit/029767fde1a84b6308172fb4b8f61e9a0861e0a4) fix(javascript): follow bundler namespace interop for Electron APIs - [`87f3e6e`](https://github.com/morluto/rea/commit/87f3e6e6228b80efb11341fedea9004e84bd071d) fix(javascript): require emitted interop helper definitions ### 📊 Changes **5 files changed** (+187 additions, -14 deletions) <details> <summary>View changed files</summary> 📝 `docs/javascript-artifact-reconstruction.md` (+9 -2) 📝 `src/domain/javascript/electronStaticAnalysisIdentity.test.ts` (+47 -0) 📝 `src/domain/javascript/javascriptElectronMemberWrites.ts` (+1 -1) 📝 `src/domain/javascript/javascriptSemanticAnalysis.ts` (+59 -11) 📝 `src/domain/javascript/javascriptSemanticRequireOrigin.ts` (+71 -0) </details> ### 📄 Description ## Summary Fixes #1802. Some bundled Electron main processes reported `browser_windows: 0` and `preload_entrypoints: 0` even though they plainly construct `new electron.BrowserWindow(...)`. A plain `const electron = require("electron")` namespace already resolved. The miss comes from the CommonJS interop that bundlers emit for `import * as Electron from "electron"`: | Emitter | Output | Why it was missed | | --- | --- | --- | | Rolldown / tsdown (the T3 Code build in the issue) | `let electron = require("electron"); electron = __toESM(electron);` | The reassignment marked the binding as unresolved | | esbuild | `var import_electron = __toESM(require("electron"));` | The helper call hid the `require` origin | | tsc (`esModuleInterop`) | `const Electron = __importStar(require("electron"));` | Same as esbuild | ## Change - `semanticNamespaceInteropOperand` recognizes `__toESM`, `__importStar`, and `_interopRequireWildcard` by name. A call only counts when the helper is a locally declared binding that is never reassigned and its lexical resolution is not blocked. These helpers return an object that exposes every own member of the wrapped module, so member paths pass through unchanged. - Electron binding classification looks through those helpers. A plain `=` that rewraps the binding's own value (`x = __toESM(x)`) no longer counts as a reassignment. Any other write still leaves the binding unresolved, as before. - The Electron identity limitation text and `docs/javascript-artifact-reconstruction.md` now say that these helpers are recognized by name. These cases still produce no finding and are covered by the test: - an unbound or global helper - a helper that is reassigned - a rewrap of a different operand - a rewrap followed by another write - `||=` Not in this PR: a `webPreferences.preload` written as a non-literal expression (e.g. `environment.preloadPath`) is already kept as a dynamic web preference and counted as unknown. It still does not appear in `preload_entrypoints`, and I left that as is. ## Validation - I added a case to `src/domain/javascript/electronStaticAnalysisIdentity.test.ts`. It covers the Rolldown, esbuild, and tsc forms plus the negative forms, and it fails without the fix. - `npm run test:focused` passes on all `src/domain/javascript` tests, the Electron composition tests, the application acceptance tests, and the bundler runtime-scope boundary test: 68 files, 1001 tests. - `npm run check:fast` and `npm run docs:check` pass. - I ran `rea analyze-javascript-application` on hand-written source shaped like each bundler's output. I did not run it against the T3 Code AppImage itself. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:55:51 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4842
No description provided.