Latest Results
fix(es/parser): Retry ambiguous Program parsing (#12142)
**Description:**
`parse_program` could classify a source as a Module too early when a
top-level `await` token also had a valid Script interpretation.
For example, in the following code, `await` should be parsed as an
identifier and the second import argument should remain a normal call
expression:
```js
function await() {}
import("./fixture.js", await(undefined));
```
This PR updates unambiguous Program parsing to:
- initially parse using the Module `Await` grammar;
- retry as Script when `await` has a distinct valid Script
interpretation and no definitive module syntax was found;
- retain the Module result when imports, exports, or unambiguous
module-only syntax determine the parse goal;
- restore lexer diagnostics and token state when retrying;
- defer publishing comments until a parse result is selected, preventing
duplicated comments;
- preserve the grammar boundaries of functions, parameters, class
fields, and static blocks.
The regular lexer/parser checkpoint remains unchanged. Non-ambiguous
valid programs still use a single parsing pass; reparsing is limited to
ambiguous or failed probes.
Regression coverage includes:
- ambiguous `await` unary, binary, call, member, assignment, arrow, and
`for...of` forms;
- TypeScript `as` and `satisfies` expressions;
- nested function and class-field grammar contexts;
- comment preservation across retries;
- parser fixtures and resolver output for the dynamic-import case.
**Related issue (if exists):**
N/A fix(es/minifier): Don't replace value-used console.*.bind() calls with undefined (#12138)
**Description:**
With `drop_console`, every call rooted at `console` is replaced with
`undefined`, including calls whose result is used:
```js
// input
const err = console.error.bind(console);
err("boom");
// output with drop_console: true
const err = void 0;
err("boom"); // TypeError: err is not a function
```
This breaks real-world code at runtime, e.g. Emscripten prologues (`var
err = console.error.bind(console)`) and `@sqlite.org/sqlite-wasm`.
Now `bind`/`toString`/`valueOf` (written as `.bind` or `["bind"]`)
invoked directly on a known console method keep their result by
replacing only the console method, the same way terser does since
terser/terser#323: `console.error.bind(console)` -> `(()=>{}).bind()`.
With `ecma` >= 2015 the noop is an arrow, which - like the native
console methods - is not a constructor; ES5 keeps `function () {}`.
A `?.` in the callee keeps its per-hop short-circuiting:
- `console.debug?.bind(x)` -> `(console.debug && noop)?.bind()`: a
nullish method still yields `undefined`.
- `console?.error.bind(x)` -> `console == null ? void 0 : (console.error
&& noop).bind()`: a nullish `console` still yields `undefined`, while a
nullish `console.error` still throws at the `.bind` access.
Everything else is unchanged and still collapses to `undefined`: direct
calls, `.call`/`.apply` (whose results are `undefined` anyway), custom
properties on `console` or its methods (`console.state.valueOf(...)`,
`console.log.capture(...)`), and deeper chains like
`console.a.b.c(...)`.
Also, only the unresolved global `console` is matched now, so a local
binding that happens to be named `console` is no longer dropped (matches
terser's `is_undeclared_ref` guard).
Notes:
- A chained call in statement position (`console.error.bind(console);`)
now leaves `(()=>{}).bind();` instead of being erased, since value usage
isn't known at this site and the substitution must be safe in any
position.
- Local invariants beyond the documented assumptions, each with a code
comment per the AGENTS.md guidance: under ES5, constructing a dropped
bound method succeeds instead of throwing (non-constructibility is not
expressible in ES5); own overrides of `bind`/`toString`/`valueOf` on a
console method are not preserved (names are matched statically, as
terser does); and the hoisted `console == null` check reads the global
twice, assuming a stable binding rather than a side-effectful accessor.
All scenarios are covered by executing fixture suites
(`tests/fixture/issues/drop-console-*`) with checked-in
`expected.stdout`.
---------
Co-authored-by: Hugo Striedinger <6549408+striedinger@users.noreply.github.com> Latest Branches
0%
0%
0%
kdy1:kdy1/ci-detect-changes © 2026 CodSpeed Technology