Skip to content

fix(linter/plugins): trim leading newline for partial sources#20928

Merged
camc314 merged 10 commits into
oxc-project:mainfrom
babu-ch:fix/js-plugin-false-bof-vue-script
May 5, 2026
Merged

fix(linter/plugins): trim leading newline for partial sources#20928
camc314 merged 10 commits into
oxc-project:mainfrom
babu-ch:fix/js-plugin-false-bof-vue-script

Conversation

@babu-ch

@babu-ch babu-ch commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

fixes #20896

Tested manually with a repro project. Happy to add tests if there's a good way to test this path

@babu-ch babu-ch requested a review from camc314 as a code owner April 1, 2026 09:15
@github-actions github-actions Bot added A-linter Area - Linter C-bug Category - Bug labels Apr 1, 2026
@codspeed-hq

codspeed-hq Bot commented Apr 1, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 4 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing babu-ch:fix/js-plugin-false-bof-vue-script (952b26d) with main (29ff6d9)2

Open in CodSpeed

Footnotes

  1. 47 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (2545d69) during the generation of this report, so 29ff6d9 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@camc314 camc314 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.

Hi, thanks for working on this, can you add a test inside:

/apps/oxlint/test/fixtures/

This will be a napi test, that tests the JS plugins, you'll need to configure it - vue file, oxlint config etc - look at the other folders in that repo for examples

@camc314 camc314 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.

See previous msg - needs test coverage.

@camc314 camc314 self-assigned this Apr 5, 2026
@babu-ch babu-ch requested a review from overlookmotel as a code owner April 6, 2026 00:54
@github-actions github-actions Bot added A-cli Area - CLI A-linter-plugins Area - Linter JS plugins labels Apr 6, 2026
@babu-ch

babu-ch commented Apr 6, 2026

Copy link
Copy Markdown
Contributor Author

@camc314 thanks for review! added!

@babu-ch babu-ch requested a review from camc314 April 6, 2026 00:55
@camc314

camc314 commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Thanks - mind fixing the CI failure?

@babu-ch

babu-ch commented Apr 6, 2026

Copy link
Copy Markdown
Contributor Author

@camc314 It took some effort, but the CI passed. I think the docs are a separate issue

JustFly1984 added a commit to JustFly1984/oxc that referenced this pull request Apr 10, 2026
Applied from oxc-project#20928. Fixes false positives in Vue/Svelte/Astro
files where the newline after `<script>` was included in the partial source.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@camc314 camc314 changed the title fix(linter): trim leading newline for JS plugins on partial sources fix(linter/plugins): trim leading newline for partial sources May 5, 2026
# Conflicts:
#	crates/oxc_linter/src/context/host.rs

@camc314 camc314 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!

@overlookmotel if you wouldn't mind taking a retrospective look that would be amazing!

@camc314 camc314 merged commit 46ab679 into oxc-project:main May 5, 2026
26 checks passed

Copilot AI 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.

Pull request overview

This PR fixes a false-positive from JS-plugin-based rules (notably @stylistic/no-multiple-empty-lines) when linting “partial sources” extracted from framework files (e.g. Vue <script> blocks), where an implicit leading newline was being treated as a blank line at BOF.

Changes:

  • Trim a single leading \n or \r\n from partial-source program.source_text before running JS plugins, and adjust UTF-8⇄UTF-16 span conversion offsets accordingly.
  • Expose ContextSubHost::source_text_offset() for use outside the context module.
  • Add an oxlint CLI fixture that runs a JS plugin against a .vue partial source and snapshots the output (ensuring no BOF blank-line diagnostic is reported).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
crates/oxc_linter/src/lib.rs Trims an implicit leading newline for partial sources before JS-plugin linting and updates span conversion offset logic.
crates/oxc_linter/src/context/host.rs Adds a crate-visible accessor for source_text_offset to support partial-source handling outside the module.
apps/oxlint/test/fixtures/js_config_js_plugins_vue_partial_source/plugin.ts Adds a minimal JS plugin fixture rule that detects BOF/consecutive blank lines via context.sourceCode.lines.
apps/oxlint/test/fixtures/js_config_js_plugins_vue_partial_source/oxlint.config.ts Configures the fixture to load the local JS plugin and enforce strict empty-line limits.
apps/oxlint/test/fixtures/js_config_js_plugins_vue_partial_source/files/test.vue Provides a Vue SFC input that previously triggered the BOF false-positive due to the implicit leading newline.
apps/oxlint/test/fixtures/js_config_js_plugins_vue_partial_source/output.snap.md Snapshots expected CLI output (no BOF error, only the intended blank-line errors inside the script).
Comments suppressed due to low confidence (1)

crates/oxc_linter/src/lib.rs:616

  • The comment says this trims the leading newline after <script>, but the actual condition is source_text_offset() > 0, which will also apply to other partial sections (e.g. Astro frontmatter) and doesn’t specifically detect <script> tags. Consider rewording the comment to describe the real behavior/intent (trim implicit leading newline for partial sources to match ESLint BOF handling), so future readers don’t assume it’s Vue-only or tag-specific.
        &self,
        external_rules: &[(ExternalRuleId, ExternalOptionsId, AllowWarnDeny)],
        path: &Path,

camc314 added a commit that referenced this pull request May 11, 2026
# Oxlint
### 💥 BREAKING CHANGES

- 00ce512 oxlint/lsp: [**BREAKING**] Don't fix suggestions on fixAll
code actions & command (#22195) (Sysix)

### 🚀 Features

- 0eeceaf linter/no-unused-vars: Rename parameter with initializer
(#22308) (camc314)
- fa0232b linter/no-unused-vars: Add param rename suggestion (#22285)
(Ryota Misumi)
- ae59305 linter/promise/no-promise-in-callback: Add
`exemptDeclarations` option (#22275) (Mikhail Baev)
- 60bed4a linter: Extends `no-redundant-roles` and
`prefer-tag-over-role` support roles (#22069) (mehm8128)
- 545c80f linter/eslint: Implement `prefer-regex-literals` rule (#22192)
(Mikhail Baev)
- cf86d7a linter: Bulk suppression (#19328) (Said Atrahouch)
- 23abd22 linter/jsx-a11y: Implement
no-noninteractive-element-to-interactive-role (#21264) (Pedro Tainha)
- fbb8f22 linter: Support `ignores` in overrides (#22148) (camc314)
- 5a4414d oxlint/lsp: Support `rulesCustomization` lsp option (#21858)
(Sysix)

### 🐛 Bug Fixes

- 610f4c7 linter/no-unused-vars: Avoid renaming captured vars (#22310)
(camc314)
- 6b50f23 oxlint/cli: Load root config by searching up parent
directories (#22272) (Sysix)
- 31a5de7 linter: Rename override `ignores` to `excludeFiles` (#22283)
(camc314)
- 26d5d7b linter: Add missing vitest/valid-describe-callback
functionality (#22279) (camchenry)
- 784530f linter: `valid-title`: detect `String.raw` strings (#22271)
(Sysix)
- 080d90e linter: Move `no-debugger` fix to suggestion (#22256) (Sysix)
- 25b7017 linter: Undocument override `ignores` option (#22213)
(camc314)
- 7bb00dd linter: Fix role-has-required-aria-props (#22097) (mehm8128)
- d25279e linter/disable-directives: Improve parsing of names,
descriptions (#22184) (camc314)
- a59e447 linter/disable-directives: Ignore invalid enable suffixes
(#22179) (camc314)
- aafef0f ci: Disable bulk supression test on big endian (#22175)
(camc314)
- 281daec linter/vue/define-props-destructuring: Add
`only-when-assigned` config opt (#22142) (camc314)
- 46ab679 linter/plugins: Trim leading newline for partial sources
(#20928) (bab)
- 29ff6d9 linter: Update docs for no_alias_methods rule to be
Vitest-specific and add toThrowError alias (#22129) (camchenry)

### ⚡ Performance

- 9414bee linter/role-has-required-aria-props: Avoid intermediate vec
(#22212) (camc314)
- 3883ea3 linter/no-useless-escape: Drop unnecessary Vec collect
(#22171) (connorshea)
- 42c3029 linter/check-property-names: Replace split-collect-pop-join
with rfind (#22172) (connorshea)
- 9551d53 linter: Remove unnecessary Vec collect in CFG edge traversal
(#22167) (connorshea)
- 26fa2fc linter/aria-role: Remove unnecessary string allocations in run
method (#22168) (connorshea)
- c9ce045 linter/getter-return: Remove unnecessary Vec collect in CFG
edge traversal (#22166) (connorshea)
- 72bd846 linter/no-this-in-sfc: Reorder cheap name check, avoid String
allocation (#22164) (connorshea)

### 📚 Documentation

- 4da212a linter/no-unused-vars: Add docs to
`rename_unused_function_parameter` (#22311) (camc314)
- 27c4628 linter/forbid-dom-props: Escape jsx examples in lint rule docs
(#22254) (4MBL)
- 3f81147 linter: Improve the `react/jsx-key` rule docs. (#22162)
(connorshea)
- 07f03cc linter/consistent-return: Add note about `noImplicitReturns`
coverage (#22156) (camc314)
- 7c1e049 oxlint/lsp: Improve autogenerated lsp docs (#22154) (Sysix)
- 87b3e38 linter: Update docs to be vitest-specific for
consistent-test-it (#22128) (camchenry)
# Oxfmt
### 💥 BREAKING CHANGES

- 5c6c390 oxfmt: [**BREAKING**] Respect more git ignore options, align
with Oxlint (#22210) (leaysgur)

### 🚀 Features

- 6e8e818 oxfmt: Experimental .svelte support (#21700) (leaysgur)

### 🐛 Bug Fixes

- e2a20b6 formatter: Add space after commas in import attributes
(#22274) (Leonabcd123)

### ⚡ Performance

- b756682 oxfmt: Optimize nested config prescan (#22232) (Jovi De
Croock)
- f14e81e formatter/sort_imports: Skip sort for single import runs
(#22204) (leaysgur)
- 32255b1 formatter: Process `ImportDeclaration`s in a run (#22079)
(overlookmotel)

### 📚 Documentation

- 4da6f4c formatter: Correct comment (#22217) (overlookmotel)
- ef3507d formatter/sort_imports: Refresh docs (#22203) (leaysgur)

Co-authored-by: Cameron <cameron.clark@hey.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-cli Area - CLI 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.

linter: jsPlugin @stylistic/no-multiple-empty-lines false positive in Vue script tag

3 participants