Skip to content

[compiler] Restore code frames in ESLint compiler error messages#36901

Merged
javache merged 1 commit into
react:mainfrom
javache:fix-compiler-eslint-error-printing
Jun 30, 2026
Merged

[compiler] Restore code frames in ESLint compiler error messages#36901
javache merged 1 commit into
react:mainfrom
javache:fix-compiler-eslint-error-printing

Conversation

@javache

@javache javache commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

The Rust port (#36173) changed CompileError LoggerEvents to carry plain serialized detail objects instead of CompilerError/CompilerDiagnostic class instances. As a result, the ESLint integrations could no longer call detail.printErrorMessage(source, {eslint: true}) and were given a replacement printErrorMessage() helper that only emitted the reason and description.

This regressed error printing: the source code frame(s) and file:line:column location that used to appear for each error detail were dropped from lint output.

This PR restores the previous behaviour:

  • Export printCodeFrame from CompilerError and reuse it from both ESLint integrations instead of duplicating it.

  • Rebuild the full message (reason, description, per-detail code frames, and hints) in printErrorMessage.

  • Handle both detail shapes that flow through LoggerEvents:

    • a details array (CompilerDiagnostic and the Rust compiler), and
    • a legacy flat loc (deprecated CompilerErrorDetail).

    formatDetailForLogging emits one or the other, so the previous unconditional iteration over error.details would have thrown TypeError: not iterable on the flat-loc path. Normalizing to a list fixes that and keeps the code working with both the TypeScript and Rust compilers.

Test plan

  • tsc --noEmit on both ESLint packages is clean (no new errors vs. baseline).
  • Verified the detail loop handles the Rust compiler's details array shape and the legacy flat loc shape.

@meta-cla meta-cla Bot added the CLA Signed label Jun 29, 2026
@react-sizebot

react-sizebot commented Jun 29, 2026

Copy link
Copy Markdown

Comparing: 68631c0...beb1164

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 7.11 kB 7.11 kB = 1.91 kB 1.90 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 614.35 kB 614.35 kB = 108.58 kB 108.58 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 7.12 kB 7.12 kB = 1.91 kB 1.91 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 680.28 kB 680.28 kB = 119.53 kB 119.53 kB
facebook-www/ReactDOM-prod.classic.js = 700.97 kB 700.97 kB = 123.13 kB 123.13 kB
facebook-www/ReactDOM-prod.modern.js = 691.29 kB 691.29 kB = 121.52 kB 121.52 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against beb1164

@javache
javache requested review from hoxyq, mofeiZ and mvitousek June 29, 2026 10:35
The Rust port (react#36173) changed CompileError events to carry plain
serialized detail objects instead of CompilerError class instances. The
ESLint integrations previously called detail.printErrorMessage(source,
{eslint: true}), which printed the source code frame(s) and location for
each error detail. The replacement printErrorMessage() only emitted the
reason and description, so code frames were dropped from lint output.

Restore the per-detail printing in both ESLint integrations by exporting
printCodeFrame from CompilerError and reusing it. The detail loop handles
both detail shapes that flow through LoggerEvents: a `details` array
(CompilerDiagnostic and the Rust compiler) and a legacy flat `loc`
(deprecated CompilerErrorDetail), so it works with the Rust compiler as
well as the TypeScript one.
@javache
javache force-pushed the fix-compiler-eslint-error-printing branch from dd10828 to beb1164 Compare June 29, 2026 10:37

@mvitousek mvitousek left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch!

@javache
javache merged commit 9c1f097 into react:main Jun 30, 2026
249 of 250 checks passed
github-actions Bot pushed a commit that referenced this pull request Jun 30, 2026
)

## Summary

The Rust port (#36173) changed `CompileError` `LoggerEvent`s to carry
plain serialized detail objects instead of
`CompilerError`/`CompilerDiagnostic` class instances. As a result, the
ESLint integrations could no longer call
`detail.printErrorMessage(source, {eslint: true})` and were given a
replacement `printErrorMessage()` helper that only emitted the `reason`
and `description`.

This regressed error printing: the **source code frame(s) and
`file:line:column` location** that used to appear for each error detail
were dropped from lint output.

This PR restores the previous behaviour:

- Export `printCodeFrame` from `CompilerError` and reuse it from both
ESLint integrations instead of duplicating it.
- Rebuild the full message (reason, description, per-detail code frames,
and hints) in `printErrorMessage`.
- Handle **both** detail shapes that flow through `LoggerEvent`s:
- a `details` array (`CompilerDiagnostic` and the **Rust** compiler),
and
  - a legacy flat `loc` (deprecated `CompilerErrorDetail`).

`formatDetailForLogging` emits one or the other, so the previous
unconditional iteration over `error.details` would have thrown
`TypeError: not iterable` on the flat-`loc` path. Normalizing to a list
fixes that and keeps the code working with both the TypeScript and Rust
compilers.

## Test plan

- `tsc --noEmit` on both ESLint packages is clean (no new errors vs.
baseline).
- Verified the detail loop handles the Rust compiler's `details` array
shape and the legacy flat `loc` shape.

DiffTrain build for [9c1f097](9c1f097)
github-actions Bot pushed a commit that referenced this pull request Jun 30, 2026
)

## Summary

The Rust port (#36173) changed `CompileError` `LoggerEvent`s to carry
plain serialized detail objects instead of
`CompilerError`/`CompilerDiagnostic` class instances. As a result, the
ESLint integrations could no longer call
`detail.printErrorMessage(source, {eslint: true})` and were given a
replacement `printErrorMessage()` helper that only emitted the `reason`
and `description`.

This regressed error printing: the **source code frame(s) and
`file:line:column` location** that used to appear for each error detail
were dropped from lint output.

This PR restores the previous behaviour:

- Export `printCodeFrame` from `CompilerError` and reuse it from both
ESLint integrations instead of duplicating it.
- Rebuild the full message (reason, description, per-detail code frames,
and hints) in `printErrorMessage`.
- Handle **both** detail shapes that flow through `LoggerEvent`s:
- a `details` array (`CompilerDiagnostic` and the **Rust** compiler),
and
  - a legacy flat `loc` (deprecated `CompilerErrorDetail`).

`formatDetailForLogging` emits one or the other, so the previous
unconditional iteration over `error.details` would have thrown
`TypeError: not iterable` on the flat-`loc` path. Normalizing to a list
fixes that and keeps the code working with both the TypeScript and Rust
compilers.

## Test plan

- `tsc --noEmit` on both ESLint packages is clean (no new errors vs.
baseline).
- Verified the detail loop handles the Rust compiler's `details` array
shape and the legacy flat `loc` shape.

DiffTrain build for [9c1f097](9c1f097)
@javache
javache deleted the fix-compiler-eslint-error-printing branch June 30, 2026 10:46
github-actions Bot pushed a commit to code/lib-react that referenced this pull request Jul 3, 2026
…ct#36901)

## Summary

The Rust port (react#36173) changed `CompileError` `LoggerEvent`s to carry
plain serialized detail objects instead of
`CompilerError`/`CompilerDiagnostic` class instances. As a result, the
ESLint integrations could no longer call
`detail.printErrorMessage(source, {eslint: true})` and were given a
replacement `printErrorMessage()` helper that only emitted the `reason`
and `description`.

This regressed error printing: the **source code frame(s) and
`file:line:column` location** that used to appear for each error detail
were dropped from lint output.

This PR restores the previous behaviour:

- Export `printCodeFrame` from `CompilerError` and reuse it from both
ESLint integrations instead of duplicating it.
- Rebuild the full message (reason, description, per-detail code frames,
and hints) in `printErrorMessage`.
- Handle **both** detail shapes that flow through `LoggerEvent`s:
- a `details` array (`CompilerDiagnostic` and the **Rust** compiler),
and
  - a legacy flat `loc` (deprecated `CompilerErrorDetail`).

`formatDetailForLogging` emits one or the other, so the previous
unconditional iteration over `error.details` would have thrown
`TypeError: not iterable` on the flat-`loc` path. Normalizing to a list
fixes that and keeps the code working with both the TypeScript and Rust
compilers.

## Test plan

- `tsc --noEmit` on both ESLint packages is clean (no new errors vs.
baseline).
- Verified the detail loop handles the Rust compiler's `details` array
shape and the legacy flat `loc` shape.

DiffTrain build for [9c1f097](react@9c1f097)
github-actions Bot pushed a commit to code/lib-react that referenced this pull request Jul 3, 2026
…ct#36901)

## Summary

The Rust port (react#36173) changed `CompileError` `LoggerEvent`s to carry
plain serialized detail objects instead of
`CompilerError`/`CompilerDiagnostic` class instances. As a result, the
ESLint integrations could no longer call
`detail.printErrorMessage(source, {eslint: true})` and were given a
replacement `printErrorMessage()` helper that only emitted the `reason`
and `description`.

This regressed error printing: the **source code frame(s) and
`file:line:column` location** that used to appear for each error detail
were dropped from lint output.

This PR restores the previous behaviour:

- Export `printCodeFrame` from `CompilerError` and reuse it from both
ESLint integrations instead of duplicating it.
- Rebuild the full message (reason, description, per-detail code frames,
and hints) in `printErrorMessage`.
- Handle **both** detail shapes that flow through `LoggerEvent`s:
- a `details` array (`CompilerDiagnostic` and the **Rust** compiler),
and
  - a legacy flat `loc` (deprecated `CompilerErrorDetail`).

`formatDetailForLogging` emits one or the other, so the previous
unconditional iteration over `error.details` would have thrown
`TypeError: not iterable` on the flat-`loc` path. Normalizing to a list
fixes that and keeps the code working with both the TypeScript and Rust
compilers.

## Test plan

- `tsc --noEmit` on both ESLint packages is clean (no new errors vs.
baseline).
- Verified the detail loop handles the Rust compiler's `details` array
shape and the legacy flat `loc` shape.

DiffTrain build for [9c1f097](react@9c1f097)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants