/
default.rs
131 lines (120 loc) · 5.12 KB
/
default.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use oxc_syntax::module_record::ImportImportName;
use crate::{context::LintContext, rule::Rule};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-import(default): No default export found in imported module {0:?}")]
#[diagnostic(severity(warning), help("does {0:?} have the default export?"))]
struct DefaultDiagnostic(String, #[label] pub Span);
/// <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/default.md>
#[derive(Debug, Default, Clone)]
pub struct Default;
declare_oxc_lint!(
/// ### What it does
///
/// If a default import is requested, this rule will report if there is no default export in the imported module.
///
/// ### Example
///
/// ```javascript
/// // ./bar.js
/// export function bar() { return null }
///
/// // ./foo.js
/// import bar from './bar' // no default export found in ./bar
/// ```
Default,
correctness
);
impl Rule for Default {
fn run_once(&self, ctx: &LintContext<'_>) {
let module_record = ctx.semantic().module_record();
for import_entry in &module_record.import_entries {
let ImportImportName::Default(default_span) = import_entry.import_name else {
continue;
};
let specifier = import_entry.module_request.name();
let Some(remote_module_record_ref) = module_record.loaded_modules.get(specifier) else {
continue;
};
if remote_module_record_ref.not_esm {
continue;
}
if remote_module_record_ref.export_default.is_none()
&& !remote_module_record_ref.exported_bindings.contains_key("default")
{
ctx.diagnostic(DefaultDiagnostic(specifier.to_string(), default_span));
}
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
"import './malformed.js'",
r#"import foo from "./empty-folder""#,
r#"import { foo } from "./default-export""#,
r#"import foo from "./default-export""#,
r#"import foo from "./mixed-exports""#,
r#"import bar from "./default-export""#,
r#"import CoolClass from "./default-class""#,
r#"import bar, { baz } from "./default-export""#,
r#"import crypto from "crypto""#,
r#"import common from "./common""#,
// No longer valid syntax
// r#"export bar from "./bar""#,
// r#"export bar, { foo } from "./bar""#,
// r#"export bar, * as names from "./bar""#,
// r#"export bar from './default-export-from-ignored.js'"#,
r#"export { default as bar } from "./bar""#,
r#"export { default as bar, foo } from "./bar""#,
r#"export {a} from "./named-exports""#,
r#"import twofer from "./trampoline""#,
r#"import MyCoolComponent from "./jsx/MyCoolComponent.jsx""#,
r#"import foo from "./named-default-export""#,
r#"import connectedApp from "./redux""#,
r"import Foo from './jsx/FooES7.js'",
r"import bar from './default-export-from.js'",
r"import bar from './default-export-from-named.js'",
r"import bar from './default-export-from-ignored.js'",
r#"export { "default" as bar } from "./bar""#,
r#"import foo from "./jsx/MyUncoolComponent.jsx""#,
r#"import foobar from "./typescript-default""#,
r#"import foobar from "./typescript-export-assign-default""#,
r#"import foobar from "./typescript-export-assign-mixed""#,
r#"import Foo from "./typescript-export-as-default-namespace""#,
r#"import Foo from "./typescript-export-react-test-renderer""#,
r#"import Foo from "./typescript-extended-config""#,
// TODO: `export =`
// r#"import foobar from "./typescript-export-assign-function""#,
// r#"import foobar from "./typescript-export-assign-property""#,
// r#"import foobar from "./typescript-export-assign-default-reexport""#,
// r#"import React from "./typescript-export-assign-default-namespace"#,
];
let fail = vec![
r#"import baz from "./named-exports""#,
r#"export baz from "./named-exports""#,
r#"export baz, { bar } from "./named-exports""#,
r#"export baz, * as names from "./named-exports""#,
// broken-trampoline.js contains no longer valid syntax
// r#"import twofer from "./broken-trampoline""#,
r#"import barDefault from "./re-export""#,
// Ignore Case Sensitivity
// r#"import bar from "./Named-Exports""#,
r#"import foobar from "./typescript""#,
// TODO: `export =`
// r#"import React from "./typescript-export-assign-default-namespace""#,
// TODO: resolve index.d.ts
// r#"import FooBar from "./typescript-export-as-default-namespace""#,
// r#"import Foo from "./typescript-export-as-default-namespace""#,
];
Tester::new(Default::NAME, pass, fail)
.change_rule_path("index.js")
.with_import_plugin(true)
.test_and_snapshot();
}