Skip to content

fix(oxlint,oxfmt): Redirect JS stdout to stderr for LSP#20321

Merged
graphite-app[bot] merged 1 commit intomainfrom
03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp
Mar 16, 2026
Merged

fix(oxlint,oxfmt): Redirect JS stdout to stderr for LSP#20321
graphite-app[bot] merged 1 commit intomainfrom
03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp

Conversation

@leaysgur
Copy link
Member

@leaysgur leaysgur commented Mar 13, 2026

Fixes #20320

(It's fine to release this as scheduled one)

@leaysgur leaysgur requested a review from camc314 as a code owner March 13, 2026 02:24
Copilot AI review requested due to automatic review settings March 13, 2026 02:24
@leaysgur leaysgur requested a review from overlookmotel as a code owner March 13, 2026 02:24
Copy link
Member Author

leaysgur commented Mar 13, 2026


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@leaysgur leaysgur changed the title fix(oxlint,oxfmt): Suppress stdout while import(jsConfig) for LSP fix(oxlint,oxfmt): Suppress stdout while import(jsConfig) for LSP Mar 13, 2026
@github-actions github-actions bot added A-linter Area - Linter A-cli Area - CLI A-formatter Area - Formatter A-linter-plugins Area - Linter JS plugins C-bug Category - Bug labels Mar 13, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds coverage and implementation to prevent JavaScript/TypeScript config files from corrupting LSP communication by printing to stdout during config evaluation.

Changes:

  • Add LSP test fixtures and snapshots for config files that write to stdout (oxlint + oxfmt).
  • Wrap dynamic import() of config modules with temporary stdout suppression in both config loaders.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
apps/oxlint/test/lsp/lint/lint.test.ts Adds a new LSP lint fixture case for stdout-polluting TS config.
apps/oxlint/test/lsp/lint/fixtures/config-ts-stdout-pollution/test.js Fixture source to trigger a diagnostic under the loaded config.
apps/oxlint/test/lsp/lint/fixtures/config-ts-stdout-pollution/oxlint.config.ts Fixture config that intentionally logs to stdout.
apps/oxlint/test/lsp/lint/snapshots/lint.test.ts.snap Snapshot for the new lint fixture.
apps/oxlint/src-js/js_config.ts Implements stdout suppression during config import().
apps/oxfmt/test/lsp/format/format.test.ts Adds a new LSP format fixture case for stdout-polluting config.
apps/oxfmt/test/lsp/format/fixtures/config-js-stdout-pollution/test.ts Fixture input for formatting under the loaded config.
apps/oxfmt/test/lsp/format/fixtures/config-js-stdout-pollution/oxfmt.config.ts Fixture config that intentionally logs to stdout.
apps/oxfmt/test/lsp/format/snapshots/format.test.ts.snap Snapshot for the new format fixture.
apps/oxfmt/src-js/cli/js_config.ts Implements stdout suppression during config import().

You can also share your feedback on Copilot code review. Take the survey.

@leaysgur leaysgur force-pushed the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch 2 times, most recently from 3b41b1f to ed8cf42 Compare March 13, 2026 02:40
@leaysgur leaysgur force-pushed the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch from ed8cf42 to e1db09d Compare March 13, 2026 05:20
Copy link
Contributor

@camc314 camc314 left a comment

Choose a reason for hiding this comment

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

should we not block stdout writing for the entirity of the LS process?

else a console.log, during formatting for example will break the LSP

Copy link
Member

@Sysix Sysix left a comment

Choose a reason for hiding this comment

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

Thank you! This is not my code-ownership, but I found maybe one little improvement :)

@Sysix
Copy link
Member

Sysix commented Mar 13, 2026

should we not block stdout writing for the entirity of the LS process?

else a console.log, during formatting for example will break the LSP

This would probably the best, but I do not think this will break atm. The config loading happens at the start, after that there can be multiple formatting requests. And here we are only looking at the source text as &str?

Could maybe help to avoid third party outputs like: #18472

@leaysgur
Copy link
Member Author

Thanks to both of you. I'll take a look at it early next week. 👍🏻

Copy link
Contributor

@liangmiQwQ liangmiQwQ left a comment

Choose a reason for hiding this comment

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

I happened to meet the same problem while I forgot to check the issue and the PR, so I made a fix in my personal branch again. Silly me 😂.

Different from just disabling stdout, my approach is to redirect all stdout to stderr globally, this is actually a more common practice, make users can still able to find messages printed if they run it in terminal or VSCode's output console. And typescript language server did a similar thing as well.

// https://github.com/typescript-language-server/typescript-language-server
if (this.level >= level || options?.overrideLevel) {
// All messages logged to stderr as stdout is reserved for LSP communication.
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
console.error(`[${LogLevel.toString(level)}]`, ...this.toStrings(...args));

In this case, we can also solve the problem of Oxlint JS Plugin without worrying, because keeping the message visible to the user on stderr won't break any feature.

I don't know whether it is helpful to solve this issue, and I am willing to submit this branch as another PR if needed. Thanks.

@leaysgur
Copy link
Member Author

Actually, that's very helpful!

I was thinking about that at first, but I wasn't sure if it was the right approach.

I'll finish this PR in that direction. Thank you~ 🙌🏻

@leaysgur leaysgur force-pushed the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch from e1db09d to c25c60b Compare March 16, 2026 00:16
@leaysgur leaysgur changed the title fix(oxlint,oxfmt): Suppress stdout while import(jsConfig) for LSP fix(oxlint,oxfmt): Redirect stdout to stderr for LSP Mar 16, 2026
@leaysgur leaysgur requested a review from camc314 March 16, 2026 00:18
@leaysgur
Copy link
Member Author

UPDATED: When using --lsp, redirect all stdout to stderr for the JS main thread.

@leaysgur leaysgur changed the title fix(oxlint,oxfmt): Redirect stdout to stderr for LSP fix(oxlint,oxfmt): Redirect JS stdout to stderr for LSP Mar 16, 2026
@leaysgur leaysgur force-pushed the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch from c25c60b to 2ec8349 Compare March 16, 2026 05:39
@camc314 camc314 added the 0-merge Merge with Graphite Merge Queue label Mar 16, 2026
Copy link
Contributor

camc314 commented Mar 16, 2026

Merge activity

graphite-app bot pushed a commit that referenced this pull request Mar 16, 2026
Fixes #20320

(It's fine to release this as scheduled one)
@graphite-app graphite-app bot force-pushed the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch from 2ec8349 to 23fec48 Compare March 16, 2026 10:12
Fixes #20320

(It's fine to release this as scheduled one)
@graphite-app graphite-app bot force-pushed the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch from 23fec48 to 89ce30b Compare March 16, 2026 10:15
@graphite-app graphite-app bot merged commit 89ce30b into main Mar 16, 2026
19 checks passed
@graphite-app graphite-app bot deleted the 03-13-fix_oxlint_oxfmt_suppress_stdout_while_import_jsconfig_for_lsp branch March 16, 2026 10:27
@graphite-app graphite-app bot removed the 0-merge Merge with Graphite Merge Queue label Mar 16, 2026
@Sysix
Copy link
Member

Sysix commented Mar 16, 2026

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-cli Area - CLI A-formatter Area - Formatter A-linter Area - Linter A-linter-plugins Area - Linter JS plugins C-bug Category - Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JS/TS config file loading in LSP mode can corrupt the LSP protocol stream

5 participants