Repository: oxc-project/oxc
Pull request #11038: fix(span)!: `SourceType::from_path(".js")` return js instead of jsx
Author: login: Boshen
Labels: name: C-bug
description: Category - Bug
name: A-linter
description: Area - Linter
name: A-cli
description: Area - CLI
name: A-transformer
description: Area - Transformer / Transpiler
name: 0-merge
description: Merge with Graphite Merge Queue
name: A-formatter
description: Area - Formatter
Created: 2025-05-14T15:06:08Z | Merged: 2025-05-15T08:58:00Z

closes #11020

Previously `SourceType::from_path(".js")` treats a `.js` file as `.jsx`
to maximize parse rate for the linter.

Force the `.jsx` change in the linter instead of a generic solution for `SourceType::from_path`.

Linked issue #11020: transformer: non-JSX file doesn't need to update options from comments
              > Weird, shouldn't have any performance impact in this benchmark, as it applies when the source type is JSX. Could you investigate why this is happening?

`SourceType::from_path` interprets `.js` extension as JSX, so `antd.js` benchmark is treated as JSX.

_Originally posted by @overlookmotel in https://github.com/oxc-project/oxc/issues/10983#issuecomment-2875965553_
            
Linked issue comments: user: login: Dunqing
created_at: 2025-05-14T01:48:13Z
body: I am not sure if this is incorrect in the benchmark or `SourceType::from_path`. Sometimes, indeed, some `.js` files include `JSX` syntax, but the benchmark `antd.js` definitely does not include it.
author_association: MEMBER
user: login: Boshen
created_at: 2025-05-14T02:18:19Z
body: `SourceType::from_path` treats `.js` as `.jsx` to maximize success rate for the linter.

I think we should only do this change in the linter.
author_association: MEMBER
user: login: overlookmotel
created_at: 2025-05-14T07:14:31Z
body: Isn't it quite common in React projects to have all your component files with extension `.js` even though they contain JSX?

I agree that we should not treat `.js` as JSX by default (ditto `.mjs` and `.cjs`). But just flagging that it's probably quite a large breaking change. I'm not sure how it'll affect Rolldown.

author_association: MEMBER
user: login: Dunqing
created_at: 2025-05-14T08:13:11Z
body: > Isn't it quite common in React projects to have all your component files with extension `.js` even though they contain JSX?

As far as I know, it should be quite uncommon.

> I agree that we should not treat `.js` as JSX by default (ditto `.mjs` and `.cjs`). But just flagging that it's probably quite a large breaking change. I'm not sure how it'll affect Rolldown.

I think this is configurable, so we don't need to worry about it. /cc @IWANABETHATGUY 
author_association: MEMBER
user: login: IWANABETHATGUY
created_at: 2025-05-14T08:21:33Z
body: We only use this api in tests and tasks(code generator), 

![Image](https://github.com/user-attachments/assets/6eed1d81-55d0-41ad-9961-d79ebddf25e0)
So it will not affect rolldown.
author_association: CONTRIBUTOR

Diff:
diff --git a/apps/oxlint/fixtures/linter/js_as_jsx.js b/apps/oxlint/fixtures/linter/js_as_jsx.js
new file mode 100644
index 0000000000000..e130e46d3f36f
--- /dev/null
+++ b/apps/oxlint/fixtures/linter/js_as_jsx.js
@@ -0,0 +1,2 @@
+debugger;
+<div /> // Should `.js` file pass as `.jsx`.
diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs
index 8208581bced80..c1cd57f404625 100644
--- a/apps/oxlint/src/lint.rs
+++ b/apps/oxlint/src/lint.rs
@@ -778,6 +778,12 @@ mod test {
         Tester::new().test_and_snapshot(args);
     }
 
+    #[test]
+    fn js_and_jsx() {
+        let args = &["fixtures/linter/js_as_jsx.js"];
+        Tester::new().test_and_snapshot(args);
+    }
+
     #[test]
     fn lint_vue_file() {
         let args = &["fixtures/vue/debugger.vue"];
diff --git a/apps/oxlint/src/snapshots/_-A all fixtures__linter@oxlint.snap b/apps/oxlint/src/snapshots/_-A all fixtures__linter@oxlint.snap
index fe6cd3391cc4d..5b9d90b549c4c 100644
--- a/apps/oxlint/src/snapshots/_-A all fixtures__linter@oxlint.snap	
+++ b/apps/oxlint/src/snapshots/_-A all fixtures__linter@oxlint.snap	
@@ -6,7 +6,7 @@ arguments: -A all fixtures/linter
 working directory: 
 ----------
 Found 0 warnings and 0 errors.
-Finished in <variable>ms on 3 files with 0 rules using 1 threads.
+Finished in <variable>ms on 4 files with 0 rules using 1 threads.
 ----------
 CLI result: LintSucceeded
 ----------
diff --git a/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap
index ba8feb6dd0a38..45cae04933d7d 100644
--- a/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap
+++ b/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap
@@ -20,6 +20,14 @@ working directory:
    `----
   help: Remove the debugger statement
 
+  ! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html\eslint(no-debugger)]8;;\: `debugger` statement is not allowed
+   ,-[fixtures/linter/js_as_jsx.js:1:1]
+ 1 | debugger;
+   : ^^^^^^^^^
+ 2 | <div /> // Should `.js` file pass as `.jsx`.
+   `----
+  help: Remove the debugger statement
+
   ! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/use-isnan.html\eslint(use-isnan)]8;;\: Requires calls to isNaN() when checking for NaN
    ,-[fixtures/linter/nan.js:1:8]
  1 | 123 == NaN;
@@ -27,8 +35,8 @@ working directory:
    `----
   help: Use the isNaN function to compare with NaN.
 
-Found 3 warnings and 0 errors.
-Finished in <variable>ms on 3 files with 101 rules using 1 threads.
+Found 4 warnings and 0 errors.
+Finished in <variable>ms on 4 files with 101 rules using 1 threads.
 ----------
 CLI result: LintSucceeded
 ----------
diff --git a/apps/oxlint/src/snapshots/_fixtures__linter__js_and_jsx.js@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter__js_and_jsx.js@oxlint.snap
new file mode 100644
index 0000000000000..dab8f41f46802
--- /dev/null
+++ b/apps/oxlint/src/snapshots/_fixtures__linter__js_and_jsx.js@oxlint.snap
@@ -0,0 +1,12 @@
+---
+source: apps/oxlint/src/tester.rs
+---
+########## 
+arguments: fixtures/linter/js_and_jsx.js
+working directory: 
+----------
+Found 0 warnings and 0 errors.
+Finished in <variable>ms on 0 files with 101 rules using 1 threads.
+----------
+CLI result: LintSucceeded
+----------
diff --git a/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap
new file mode 100644
index 0000000000000..185506f6ae6da
--- /dev/null
+++ b/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap
@@ -0,0 +1,21 @@
+---
+source: apps/oxlint/src/tester.rs
+---
+########## 
+arguments: fixtures/linter/js_as_jsx.js
+working directory: 
+----------
+
+  ! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html\eslint(no-debugger)]8;;\: `debugger` statement is not allowed
+   ,-[fixtures/linter/js_as_jsx.js:1:1]
+ 1 | debugger;
+   : ^^^^^^^^^
+ 2 | <div /> // Should `.js` file pass as `.jsx`.
+   `----
+  help: Remove the debugger statement
+
+Found 1 warning and 0 errors.
+Finished in <variable>ms on 1 file with 101 rules using 1 threads.
+----------
+CLI result: LintSucceeded
+----------
diff --git a/crates/oxc_linter/src/service/runtime.rs b/crates/oxc_linter/src/service/runtime.rs
index 17cb06ad141a1..60d5857c45a50 100644
--- a/crates/oxc_linter/src/service/runtime.rs
+++ b/crates/oxc_linter/src/service/runtime.rs
@@ -221,7 +221,12 @@ impl<'l> Runtime<'l> {
         if not_supported_yet {
             return None;
         }
-        let source_type = source_type.unwrap_or_default();
+
+        let mut source_type = source_type.unwrap_or_default();
+        // Treat JS and JSX files to maximize chance of parsing files.
+        if source_type.is_javascript() {
+            source_type = source_type.with_jsx(true);
+        }
 
         let file_result = self.file_system.read_to_string(path).map_err(|e| {
             Error::new(OxcDiagnostic::error(format!(
diff --git a/crates/oxc_span/src/source_type.rs b/crates/oxc_span/src/source_type.rs
index 9963f0b02639c..8581dcfda2d37 100644
--- a/crates/oxc_span/src/source_type.rs
+++ b/crates/oxc_span/src/source_type.rs
@@ -149,8 +149,8 @@ impl From<FileExtension> for SourceType {
         };
 
         let variant = match file_ext {
-            Js | Mjs | Cjs | Jsx | Tsx => LanguageVariant::Jsx,
-            Ts | Mts | Cts => LanguageVariant::Standard,
+            Jsx | Tsx => LanguageVariant::Jsx,
+            Js | Mjs | Cjs | Ts | Mts | Cts => LanguageVariant::Standard,
         };
 
         SourceType { language, module_kind, variant }
@@ -673,7 +673,7 @@ mod tests {
             assert!(!ty.is_typescript(), "{ty:?}");
         }
 
-        assert_eq!(SourceType::jsx(), js);
+        assert_eq!(SourceType::mjs(), js);
         assert_eq!(SourceType::jsx().with_module(true), jsx);
 
         assert!(js.is_module());
@@ -686,9 +686,9 @@ mod tests {
         assert!(!cjs.is_strict());
         assert!(jsx.is_strict());
 
-        assert!(js.is_jsx());
-        assert!(mjs.is_jsx());
-        assert!(cjs.is_jsx());
+        assert!(js.is_javascript());
+        assert!(mjs.is_javascript());
+        assert!(cjs.is_javascript());
         assert!(jsx.is_jsx());
     }
 }
diff --git a/crates/oxc_transformer/src/options/babel/mod.rs b/crates/oxc_transformer/src/options/babel/mod.rs
index 4fdce0da86e81..820e074f852c5 100644
--- a/crates/oxc_transformer/src/options/babel/mod.rs
+++ b/crates/oxc_transformer/src/options/babel/mod.rs
@@ -169,6 +169,9 @@ impl BabelOptions {
 
     pub fn is_jsx(&self) -> bool {
         self.plugins.syntax_jsx
+            || self.presets.jsx.is_some()
+            || self.plugins.react_jsx.is_some()
+            || self.plugins.react_jsx_dev.is_some()
     }
 
     pub fn is_typescript(&self) -> bool {
diff --git a/tasks/coverage/snapshots/parser_babel.snap b/tasks/coverage/snapshots/parser_babel.snap
index d872581e6ed67..562e5534441d6 100644
--- a/tasks/coverage/snapshots/parser_babel.snap
+++ b/tasks/coverage/snapshots/parser_babel.snap
@@ -1,9 +1,9 @@
 commit: 578ac4df
 
 parser_babel Summary:
-AST Parsed     : 2309/2322 (99.44%)
-Positive Passed: 2288/2322 (98.54%)
-Negative Passed: 1561/1673 (93.31%)
+AST Parsed     : 2311/2322 (99.53%)
+Positive Passed: 2290/2322 (98.62%)
+Negative Passed: 1565/1673 (93.54%)
 Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-startindex-and-startline-specified-without-startcolumn/input.js
 
 Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/startline-and-startcolumn-specified/input.js
@@ -48,14 +48,6 @@ Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/fl
 
 Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/flow/expect-plugin/export-type/input.js
 
-Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-fragment/input.js
-
-Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-jsx-expression/input.js
-
-Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no_plugin/input.js
-
-Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no_plugin-non-BMP-identifier/input.js
-
 Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/arrow-function/arrow-like-in-conditional-2/input.ts
 
 Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/cast/satisfies-const-error/input.ts
@@ -353,22 +345,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2022
  2 │ 
    ╰────
 
-Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-ts-type-param-no-flow/input.js
-
-  × Unexpected token. Did you mean `{'>'}` or `&gt;`?
-   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-ts-type-param-no-flow/input.js:1:10]
- 1 │ <div>() => {}
-   ·          ▲
-   ╰────
-
-Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-ts-type-param-no-flow-babel-7/input.js
-
-  × Unexpected token. Did you mean `{'>'}` or `&gt;`?
-   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-ts-type-param-no-flow-babel-7/input.js:1:10]
- 1 │ <div>() => {}
-   ·          ▲
-   ╰────
-
 Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/arrow-function/generic-tsx-babel-7/input.ts
 
   × Unexpected token. Did you mean `{'>'}` or `&gt;`?
@@ -3878,9 +3854,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
    ╰────
 
   × Unexpected token
-   ╭─[babel/packages/babel-parser/test/fixtures/es2015/modules/invalid-xml-comment-in-module/input.js:1:2]
+   ╭─[babel/packages/babel-parser/test/fixtures/es2015/modules/invalid-xml-comment-in-module/input.js:1:1]
  1 │ <!--bar-->
-   ·  ─
+   · ─
    ╰────
 
   × Expected `,` but found `Identifier`
@@ -11518,10 +11494,37 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
    ·             ─
    ╰────
 
-  × Unexpected token. Did you mean `{'>'}` or `&gt;`?
-   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-type-param/input.js:1:10]
+  × Unexpected token
+   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-fragment/input.js:3:5]
+ 2 │   return (
+ 3 │     <>Hello</>
+   ·     ─
+ 4 │   );
+   ╰────
+
+  × Unexpected token
+   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-jsx-expression/input.js:1:1]
+ 1 │ <div>{name}</div>
+   · ─
+   ╰────
+
+  × Unexpected token
+   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-type-param/input.js:1:1]
  1 │ <div>() => {}
-   ·          ▲
+   · ─
+   ╰────
+
+  × Unexpected token
+   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no_plugin/input.js:1:1]
+ 1 │ <div></div>
+   · ─
+   ╰────
+
+  × Unexpected token
+   ╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no_plugin-non-BMP-identifier/input.js:1:1]
+ 1 │ <
+   · ─
+ 2 │   𠮷
    ╰────
 
   × Unexpected token. Did you mean `{'>'}` or `&gt;`?
diff --git a/tasks/coverage/snapshots/parser_typescript.snap b/tasks/coverage/snapshots/parser_typescript.snap
index 5161c953cda9f..3a6176bec8527 100644
--- a/tasks/coverage/snapshots/parser_typescript.snap
+++ b/tasks/coverage/snapshots/parser_typescript.snap
@@ -15414,41 +15414,42 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
   help: Did you mean to write 'undefined | null | undefined'?
 
   × Unexpected token
-   ╭─[typescript/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash1.ts:1:4]
+   ╭─[typescript/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash1.ts:1:2]
  1 │ ~< <
-   ·    ─
+   ·  ─
    ╰────
 
   × Unexpected token
-   ╭─[typescript/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash2.ts:1:9]
+   ╭─[typescript/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash2.ts:1:2]
  1 │ ~<></> <
+   ·  ─
    ╰────
 
   × Unexpected token
-   ╭─[typescript/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash3.ts:1:4]
+   ╭─[typescript/tests/cases/compiler/parseJsxElementInUnaryExpressionNoCrash3.ts:1:2]
  1 │ !< {:>
-   ·    ─
+   ·  ─
    ╰────
 
   × Unexpected token
-   ╭─[typescript/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts:2:21]
+   ╭─[typescript/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts:2:13]
  1 │ const x = "oops";
  2 │ const y = + <number> x;
-   ·                     ───
+   ·             ─
    ╰────
 
   × Unexpected token
-   ╭─[typescript/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx2.ts:2:15]
+   ╭─[typescript/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx2.ts:2:13]
  1 │ const x = "oops";
  2 │ const y = + <> x;
-   ·               ───
+   ·             ─
    ╰────
 
   × Unexpected token
-   ╭─[typescript/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx3.ts:2:14]
+   ╭─[typescript/tests/cases/compiler/parseUnaryExpressionNoTypeAssertionInJsx3.ts:2:13]
  1 │ const x = "oops";
  2 │ const y = + <1234> x;
-   ·              ────
+   ·             ─
    ╰────
 
   × Unexpected token
diff --git a/tasks/coverage/snapshots/semantic_babel.snap b/tasks/coverage/snapshots/semantic_babel.snap
index ef8429c3430c5..217d4ece4a480 100644
--- a/tasks/coverage/snapshots/semantic_babel.snap
+++ b/tasks/coverage/snapshots/semantic_babel.snap
@@ -2,7 +2,7 @@ commit: 578ac4df
 
 semantic_babel Summary:
 AST Parsed     : 2322/2322 (100.00%)
-Positive Passed: 1905/2322 (82.04%)
+Positive Passed: 1907/2322 (82.13%)
 semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/annex-b/enabled/3.3-function-in-if-body/input.js
 Symbol scope ID mismatch for "f":
 after transform: SymbolId(0): ScopeId(4294967294)
@@ -236,12 +236,6 @@ Unresolved references mismatch:
 after transform: ["T", "foo"]
 rebuilt        : ["foo"]
 
-semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-ts-type-param-no-flow/input.js
-Unexpected token. Did you mean `{'>'}` or `&gt;`?
-
-semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-ts-type-param-no-flow-babel-7/input.js
-Unexpected token. Did you mean `{'>'}` or `&gt;`?
-
 semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/arrow-function/arrow-function-with-newline/input.ts
 Unresolved references mismatch:
 after transform: ["arguments", "t"]
diff --git a/tasks/prettier_conformance/src/lib.rs b/tasks/prettier_conformance/src/lib.rs
index 3dd2a3c5abe6b..f41dfce768c81 100644
--- a/tasks/prettier_conformance/src/lib.rs
+++ b/tasks/prettier_conformance/src/lib.rs
@@ -411,6 +411,7 @@ impl TestRunner {
         formatter_options: FormatOptions,
     ) -> String {
         let allocator = Allocator::default();
+        let source_type = source_type.with_jsx(source_type.is_javascript());
         let ret = Parser::new(&allocator, source_text, source_type)
             .with_options(ParseOptions {
                 preserve_parens: false,
diff --git a/tasks/prettier_conformance/src/spec.rs b/tasks/prettier_conformance/src/spec.rs
index f17b91f691ac3..68a4c321c9b01 100644
--- a/tasks/prettier_conformance/src/spec.rs
+++ b/tasks/prettier_conformance/src/spec.rs
@@ -36,7 +36,10 @@ impl SpecParser {
         self.source_text.clone_from(&spec_content);
 
         let allocator = Allocator::default();
-        let source_type = SourceType::from_path(spec).unwrap_or_default();
+        let mut source_type = SourceType::from_path(spec).unwrap_or_default();
+        if source_type.is_javascript() {
+            source_type = source_type.with_jsx(true);
+        }
 
         let mut ret = Parser::new(&allocator, &spec_content, source_type).parse();
         self.visit_program(&mut ret.program);
diff --git a/tasks/transform_conformance/src/test_case.rs b/tasks/transform_conformance/src/test_case.rs
index d4bad7884d0fe..74716ed078369 100644
--- a/tasks/transform_conformance/src/test_case.rs
+++ b/tasks/transform_conformance/src/test_case.rs
@@ -90,10 +90,8 @@ impl TestCase {
     fn source_type(path: &Path, options: &BabelOptions) -> SourceType {
         // Some babel test cases have a js extension, but contain typescript code.
         // Therefore, if the typescript plugin exists, enable typescript.
-        let mut source_type = SourceType::from_path(path)
-            .unwrap()
-            .with_script(true)
-            .with_jsx(options.plugins.syntax_jsx);
+        let mut source_type =
+            SourceType::from_path(path).unwrap().with_script(true).with_jsx(options.is_jsx());
         source_type = match options.source_type.as_deref() {
             Some("unambiguous") => source_type.with_unambiguous(true),
             Some("script") => source_type.with_script(true),


Reviews:
user: login: graphite-app[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T15:06:58Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR updates how `SourceType::from_path` classifies `.js` files as standard JavaScript rather than JSX, and moves the forced JSX promotion into the linter’s runtime. It also refreshes related tests and snapshots and adds a new fixture/test for JS treated as JSX.

- Refactor `SourceType` mapping to treat only `.jsx`/`.tsx` as JSX and all others (including `.js`) as standard.
- In the linter runtime, force `.js` files to parse as JSX via `with_jsx(true)`.
- Update tests, snapshots, and add a new `js_and_jsx` test and fixture.

### Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

<details>
<summary>Show a summary per file</summary>

| File                                             | Description                                                 |
|--------------------------------------------------|-------------------------------------------------------------|
| crates/oxc_span/src/source_type.rs               | Adjusted extension-to-variant mapping in `From<FileExtension>` |
| crates/oxc_span/src/source_type.rs (tests)       | Updated assertions for `js`, `mjs`, `cjs` to `is_javascript` |
| crates/oxc_linter/src/service/runtime.rs         | Added logic to force `.js` parsing as JSX; contains a typo in comment |
| apps/oxlint/src/snapshots/_fixtures__linter@*.snap | Updated snapshot counts and added new JS/JSX fixture output |
| apps/oxlint/src/snapshots/_fixtures__linter__js_and_jsx.js@oxlint.snap | New snapshot for the `js_and_jsx` test |
| apps/oxlint/src/lint.rs                          | Added `js_and_jsx` test, but path mismatches the fixture name |
| apps/oxlint/fixtures/linter/js_as_jsx.js         | New fixture (name mismatch with test)                       |
</details>





state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T15:08:47Z
user: login: camc314
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T15:11:05Z

Review comments:
diff_hunk: @@ -221,7 +221,12 @@ impl<'l> Runtime<'l> {
         if not_supported_yet {
             return None;
         }
-        let source_type = source_type.unwrap_or_default();
+
+        let mut source_type = source_type.unwrap_or_default();
+        // Treat JS and JSX files to maximizie chance of parsing files.
path: crates/oxc_linter/src/service/runtime.rs
user: login: graphite-app[bot]
body: There's a typo in the comment: `maximizie` should be `maximize`
```suggestion
        // Treat JS and JSX files to maximize chance of parsing files.
```
  

*Spotted by [Diamond](https://app.graphite.dev/diamond/?org=oxc-project&ref=ai-review-comment)*<i class='graphite__hidden'><br /><br />Is this helpful? React 👍 or 👎 to let us know.</i>
created_at: 2025-05-14T15:06:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -221,7 +221,12 @@ impl<'l> Runtime<'l> {
         if not_supported_yet {
             return None;
         }
-        let source_type = source_type.unwrap_or_default();
+
+        let mut source_type = source_type.unwrap_or_default();
+        // Treat JS and JSX files to maximizie chance of parsing files.
path: crates/oxc_linter/src/service/runtime.rs
user: login: Copilot
body: Fix typo in comment: 'maximizie' should be 'maximize'.
```suggestion
        // Treat JS and JSX files to maximize chance of parsing files.
```
created_at: 2025-05-14T15:08:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -778,6 +778,12 @@ mod test {
         Tester::new().test_and_snapshot(args);
     }
 
+    #[test]
+    fn js_and_jsx() {
+        let args = &["fixtures/linter/js_and_jsx.js"];
path: apps/oxlint/src/lint.rs
user: login: Copilot
body: The test references 'fixtures/linter/js_and_jsx.js' but the fixture file is named 'js_as_jsx.js'. Update the test path or rename the fixture to match.
```suggestion
        let args = &["fixtures/linter/js_as_jsx.js"];
```
created_at: 2025-05-14T15:08:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -221,7 +221,12 @@ impl<'l> Runtime<'l> {
         if not_supported_yet {
             return None;
         }
-        let source_type = source_type.unwrap_or_default();
+
+        let mut source_type = source_type.unwrap_or_default();
+        // Treat JS and JSX files to maximizie chance of parsing files.
path: crates/oxc_linter/src/service/runtime.rs
user: login: Copilot
body: [nitpick] The comment mentions 'JS and JSX' but the code only forces `.js` variants. Consider updating it to 'Treat JavaScript files to maximize parsing success.'
```suggestion
        // Treat JavaScript files to maximize parsing success.
```
created_at: 2025-05-14T15:08:47Z
author_association: CONTRIBUTOR

PR comments:
user: login: Boshen
created_at: 2025-05-14T15:06:24Z
body: * **#11038** <a href="https://app.graphite.dev/github/pr/oxc-project/oxc/11038?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈 <a href="https://app.graphite.dev/github/pr/oxc-project/oxc/11038?utm_source=stack-comment-view-in-graphite" target="_blank">(View in Graphite)</a>
* `main`
<hr />

## How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:
- <kbd>0-merge</kbd> - adds this PR to the back of the merge queue
- <kbd>hotfix</kbd> - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using [this link](https://app.graphite.dev/invite/github/oxc-project?ref=merge-queue-instructions-in-stack-comment&prId=11038).

<h2></h2>
<sub>

An organization admin has enabled the [Graphite Merge Queue](https://graphite.dev/docs/graphite-merge-queue) in this repository.

</sub>

<sub>

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

</sub>

<h2></h2>

This stack of pull requests is managed by <a href="https://graphite.dev?utm-source=stack-comment"><b>Graphite</b></a>. Learn more about <a href="https://stacking.dev/?utm_source=stack-comment">stacking</a>.
<!-- Current dependencies on/for this PR: -->
author_association: MEMBER
user: login: codspeed-hq[bot]
created_at: 2025-05-14T15:13:18Z
body: <!-- __CODSPEED_PERFORMANCE_REPORT_COMMENT__ -->
<!-- __CODSPEED_INSTRUMENTATION_PERFORMANCE_REPORT_COMMENT__ -->

## [CodSpeed Instrumentation Performance Report](https://codspeed.io/oxc-project/oxc/branches/05-14-fix_span_sourcetype_from_path_.js_return_js_instead_of_jsx)

### Merging #11038 will **not alter performance**

<sub>Comparing <code>05-14-fix_span_sourcetype_from_path_.js_return_js_instead_of_jsx</code> (00dcece) with <code>main</code> (7ad6cf8)</sub>



### Summary

`✅ 36` untouched benchmarks  




author_association: NONE
user: login: graphite-app[bot]
created_at: 2025-05-14T15:26:31Z
body: ### Merge activity

* **May 14, 11:26 AM EDT**: [Graphite](https://app.graphite.dev/github/pr/oxc-project/oxc/11038) disabled "merge when ready" on this PR due to: a merge conflict with the target branch; resolve the conflict and try again..
* **May 14, 11:27 AM EDT**: The merge label '0-merge' was detected. This PR will be added to the [Graphite merge queue](https://app.graphite.dev/merges?org=oxc-project&repo=oxc) once it meets the requirements.
* **May 14, 11:27 AM EDT**: The merge label '0-merge' was detected. This PR will be added to the [Graphite merge queue](https://app.graphite.dev/merges?org=oxc-project&repo=oxc) once it meets the requirements.
* **May 14, 11:29 AM EDT**: The merge label '0-merge' was detected. This PR will be added to the [Graphite merge queue](https://app.graphite.dev/merges?org=oxc-project&repo=oxc) once it meets the requirements.

author_association: CONTRIBUTOR
user: login: Dunqing
created_at: 2025-05-14T23:34:33Z
body: <img width="676" alt="image" src="https://github.com/user-attachments/assets/044034c0-71c1-42e0-af6b-01a8e91598fc" />

Nice! Just curious why it affects `*.tsx` benchmark
author_association: MEMBER