Turbopack: don't scope hoist modules using direct eval (#100308)
### What?
Turbopack scope hoisting no longer merges modules that contain a direct
`eval(...)` call. Such modules are emitted as their own module
factories, and the rest of the graph is still merged.
### Why?
Merging puts modules into one shared scope and renames colliding
top-level bindings. A direct `eval` resolves names at runtime against
its lexical scope, so after a rename it can read the wrong binding. For
example, `eval('local')` can return another module's `local`, or throw.
### How?
- **Detection:** while building the analyzer's variable graph, each call
expression is checked. If the callee (with parentheses stripped) is the
unresolved global `eval` identifier, a module-wide flag is set. Nested
functions, classes and IIFEs are covered.
- **What doesn't count:** indirect forms leave the module mergeable.
These are `(0, eval)(…)`, `globalThis.eval(…)`, `eval?.(…)`, aliases,
`new eval(…)`, and a locally bound `eval`.
- **Plumbing:** the flag is passed into the module analysis result, and
`EcmascriptModuleAsset::is_mergeable` returns `false` when it is set.
The existing rule that only ESM modules are mergeable is unchanged.
- **Split modules:** a module with exports can be split into a facade
plus a `<locals>` module. The `<locals>` module carries the original
code but used the trait's default `is_mergeable`, which is always
`true`, so it would have bypassed the opt-out. It now uses the original
module's answer.
### Tests
- **Analyzer unit test:** covers direct, indirect and shadowed `eval`
forms. It includes sloppy-script shadowing, which strict ESM can't
express.
- **Snapshot `scope-hoisting/direct-eval`:** the module with a direct
`eval` stays separate, while the module that only uses indirect `eval`
is still merged.
- **Execution test `scope-hoisting/direct-eval`:** a merge would rename
the `eval` module's colliding local. With the opt-out disabled, the test
fails (`"other"` instead of `"direct"`).
<!-- NEXT_JS_LLM -->
<!-- fleet 1ab5c143-50eb-4959-abe0-907ef30c1402 -->
Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>