feat(linter): add import/unambiguous rule (#7187)

This commit is contained in:
Dmitry Zakharov 2024-11-08 03:54:37 +03:00 committed by GitHub
parent 5ab1ff6f06
commit 9b8973f425
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 100 additions and 0 deletions

View file

@ -24,6 +24,7 @@ mod import {
pub mod no_named_as_default_member;
pub mod no_self_import;
pub mod no_webpack_loader_syntax;
pub mod unambiguous;
}
mod eslint {
@ -635,6 +636,7 @@ oxc_macros::declare_all_lint_rules! {
import::no_named_as_default_member,
import::no_self_import,
import::no_webpack_loader_syntax,
import::unambiguous,
jest::consistent_test_it,
jest::expect_expect,
jest::max_expects,

View file

@ -0,0 +1,82 @@
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
fn unambiguous_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("This module could be mistakenly parsed as script instead of module")
.with_help("Add at least one import or export statement to unambiguously mark this file as a module")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct Unambiguous;
declare_oxc_lint!(
/// ### What it does
///
/// Warn if a `module` could be mistakenly parsed as a `script` and not pure ESM module
///
/// ### Why is this bad?
///
/// For ESM-only environments helps to determine files that not pure ESM modules
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```js
/// function x() {}
///
/// (function x() { return 42 })()
/// ```
///
/// Examples of **correct** code for this rule:
/// ```js
/// import 'foo'
/// function x() { return 42 }
///
/// export function x() { return 42 }
///
/// (function x() { return 42 })()
/// export {} // simple way to mark side-effects-only file as 'module' without any imports/exports
/// ```
Unambiguous,
restriction
);
/// <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md>
impl Rule for Unambiguous {
fn run_once(&self, ctx: &LintContext<'_>) {
if ctx.semantic().module_record().not_esm {
ctx.diagnostic(unambiguous_diagnostic(Span::default()));
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
// looks like in original rule that should pass for ecmaVersion before 2015
// r"function x() {}",
// r#""use strict"; function y() {}"#,
r#"import y from "z"; function x() {}"#,
r#"import * as y from "z"; function x() {}"#,
r#"import { y } from "z"; function x() {}"#,
r#"import z, { y } from "z"; function x() {}"#,
"function x() {}; export {}",
"function x() {}; export { x }",
r#"function x() {}; export { y } from "z""#,
r#"function x() {}; export * as y from "z""#,
"export function x() {}",
];
let fail = vec![r"function x() {}", r"(function x() { return 42 })()"];
Tester::new(Unambiguous::NAME, pass, fail)
.change_rule_path("index.ts")
.with_import_plugin(true)
.test_and_snapshot();
}

View file

@ -0,0 +1,16 @@
---
source: crates/oxc_linter/src/tester.rs
---
⚠ eslint-plugin-import(unambiguous): This module could be mistakenly parsed as script instead of module
╭─[index.ts:1:1]
1 │ function x() {}
· ▲
╰────
help: Add at least one import or export statement to unambiguously mark this file as a module
⚠ eslint-plugin-import(unambiguous): This module could be mistakenly parsed as script instead of module
╭─[index.ts:1:1]
1 │ (function x() { return 42 })()
· ▲
╰────
help: Add at least one import or export statement to unambiguously mark this file as a module