diff --git a/apps/oxlint/test/fixtures/languageOptions/output.snap.md b/apps/oxlint/test/fixtures/languageOptions/output.snap.md
index 4abc4cf6b799d..74125083ac3ae 100644
--- a/apps/oxlint/test/fixtures/languageOptions/output.snap.md
+++ b/apps/oxlint/test/fixtures/languageOptions/output.snap.md
@@ -4,9 +4,9 @@
# stdout
```
x language-options-plugin(lang): languageOptions:
- | sourceType: script
+ | sourceType: commonjs
| ecmaVersion: 2026
- | parserOptions: {"sourceType":"script"}
+ | parserOptions: {"sourceType":"commonjs"}
| globals: {}
| env: {"builtin":true}
,-[files/index.cjs:1:1]
diff --git a/crates/oxc_linter/src/loader/partial_loader/vue.rs b/crates/oxc_linter/src/loader/partial_loader/vue.rs
index 14804f6870666..c66b3510ee4bf 100644
--- a/crates/oxc_linter/src/loader/partial_loader/vue.rs
+++ b/crates/oxc_linter/src/loader/partial_loader/vue.rs
@@ -316,7 +316,10 @@ mod test {
let cases = [
("", Some(SourceType::mjs())),
("", Some(SourceType::tsx())),
- (r#""#, Some(SourceType::cjs())),
+ (
+ r#""#,
+ Some(SourceType::from_extension("cjs").unwrap()),
+ ),
("", Some(SourceType::tsx())),
("", None),
(r#""#, None),
diff --git a/crates/oxc_linter/src/rules/eslint/no_eval.rs b/crates/oxc_linter/src/rules/eslint/no_eval.rs
index b31affd1b8acd..fa966421209b5 100644
--- a/crates/oxc_linter/src/rules/eslint/no_eval.rs
+++ b/crates/oxc_linter/src/rules/eslint/no_eval.rs
@@ -200,7 +200,9 @@ impl Rule for NoEval {
}
let is_valid = if scope_flags.is_top() {
- ctx.semantic().source_type().is_script()
+ // In scripts and CommonJS, `this` at top level refers to the global object
+ // In ES modules, `this` at top level is undefined
+ !ctx.semantic().source_type().is_module()
} else {
let node = ctx.nodes().get_node(ctx.scoping().get_node_id(scope_id));
ast_util::is_default_this_binding(ctx, node, true)
diff --git a/crates/oxc_linter/src/rules/eslint/no_redeclare.rs b/crates/oxc_linter/src/rules/eslint/no_redeclare.rs
index caa0049a1bd48..ec188fcf016a9 100644
--- a/crates/oxc_linter/src/rules/eslint/no_redeclare.rs
+++ b/crates/oxc_linter/src/rules/eslint/no_redeclare.rs
@@ -2,7 +2,7 @@ use javascript_globals::GLOBALS;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
-use oxc_span::{ModuleKind, Span};
+use oxc_span::Span;
use schemars::JsonSchema;
use serde::Deserialize;
@@ -122,8 +122,8 @@ impl Rule for NoRedeclare {
}
fn should_run(&self, ctx: &ContextHost) -> bool {
- // Modules run in their own scope, and don't conflict with existing globals
- ctx.source_type().module_kind() == ModuleKind::Script
+ // ES modules run in their own scope, and don't conflict with existing globals
+ !ctx.source_type().is_module()
}
}
diff --git a/crates/oxc_span/src/source_type.rs b/crates/oxc_span/src/source_type.rs
index 04720dd960841..84ba3f7509014 100644
--- a/crates/oxc_span/src/source_type.rs
+++ b/crates/oxc_span/src/source_type.rs
@@ -194,7 +194,7 @@ impl From for SourceType {
let module_kind = match file_ext {
Js | Tsx | Ts | Jsx | Mts | Mjs => ModuleKind::Module,
- Cjs | Cts => ModuleKind::Script,
+ Cjs | Cts => ModuleKind::CommonJS,
};
let variant = match file_ext {
@@ -665,9 +665,14 @@ mod tests {
assert!(!ts.is_script());
assert!(!mts.is_script());
- assert!(cts.is_script());
+ assert!(!cts.is_script());
assert!(!tsx.is_script());
+ assert!(!ts.is_commonjs());
+ assert!(!mts.is_commonjs());
+ assert!(cts.is_commonjs());
+ assert!(!tsx.is_commonjs());
+
assert!(ts.is_strict());
assert!(mts.is_strict());
assert!(!cts.is_strict());
@@ -700,7 +705,11 @@ mod tests {
assert!(!dts.is_script());
assert!(!dmts.is_script());
- assert!(dcts.is_script());
+ assert!(!dcts.is_script());
+
+ assert!(!dts.is_commonjs());
+ assert!(!dmts.is_commonjs());
+ assert!(dcts.is_commonjs());
assert!(dts.is_strict());
assert!(dmts.is_strict());
diff --git a/tasks/coverage/snapshots/parser_misc.snap b/tasks/coverage/snapshots/parser_misc.snap
index 9d516d25503cf..f1dc25bcf3de6 100644
--- a/tasks/coverage/snapshots/parser_misc.snap
+++ b/tasks/coverage/snapshots/parser_misc.snap
@@ -1,47 +1,9 @@
parser_misc Summary:
AST Parsed : 59/59 (100.00%)
-Positive Passed: 55/59 (93.22%)
+Positive Passed: 59/59 (100.00%)
Negative Passed: 128/129 (99.22%)
Expect Syntax Error: tasks/coverage/misc/fail/script-top-level-using.js
-Expect to Parse: tasks/coverage/misc/pass/commonjs-top-level-new-target.cjs
-
- × Unexpected new.target expression
- ╭─[misc/pass/commonjs-top-level-new-target.cjs:2:1]
- 1 │ // CommonJS allows top-level new.target because the file is wrapped in a function
- 2 │ new.target;
- · ──────────
- ╰────
- help: new.target is only allowed in constructors and functions invoked using the `new` operator
-
-Expect to Parse: tasks/coverage/misc/pass/commonjs-top-level-new-target.cts
-
- × Unexpected new.target expression
- ╭─[misc/pass/commonjs-top-level-new-target.cts:2:1]
- 1 │ // TypeScript CommonJS allows top-level new.target
- 2 │ new.target;
- · ──────────
- ╰────
- help: new.target is only allowed in constructors and functions invoked using the `new` operator
-
-Expect to Parse: tasks/coverage/misc/pass/commonjs-top-level-return.cjs
-
- × TS(1108): A 'return' statement can only be used within a function body.
- ╭─[misc/pass/commonjs-top-level-return.cjs:2:1]
- 1 │ // CommonJS allows top-level return because the file is wrapped in a function
- 2 │ return 42;
- · ──────
- ╰────
-
-Expect to Parse: tasks/coverage/misc/pass/commonjs-top-level-return.cts
-
- × TS(1108): A 'return' statement can only be used within a function body.
- ╭─[misc/pass/commonjs-top-level-return.cts:2:1]
- 1 │ // TypeScript CommonJS allows top-level return
- 2 │ return 42;
- · ──────
- ╰────
-
× Cannot assign to 'arguments' in strict mode
╭─[misc/fail/arguments-eval.ts:1:10]
diff --git a/tasks/coverage/snapshots/semantic_misc.snap b/tasks/coverage/snapshots/semantic_misc.snap
index 4515290530afa..82e4ad41286a6 100644
--- a/tasks/coverage/snapshots/semantic_misc.snap
+++ b/tasks/coverage/snapshots/semantic_misc.snap
@@ -1,18 +1,6 @@
semantic_misc Summary:
AST Parsed : 59/59 (100.00%)
-Positive Passed: 36/59 (61.02%)
-semantic Error: tasks/coverage/misc/pass/commonjs-top-level-new-target.cjs
-Unexpected new.target expression
-
-semantic Error: tasks/coverage/misc/pass/commonjs-top-level-new-target.cts
-Unexpected new.target expression
-
-semantic Error: tasks/coverage/misc/pass/commonjs-top-level-return.cjs
-A 'return' statement can only be used within a function body.
-
-semantic Error: tasks/coverage/misc/pass/commonjs-top-level-return.cts
-A 'return' statement can only be used within a function body.
-
+Positive Passed: 40/59 (67.80%)
semantic Error: tasks/coverage/misc/pass/declare-let-private.ts
Bindings mismatch:
after transform: ScopeId(0): ["private"]