Skip to content

Commit fb68954

Browse files
committed
feat(lint): support noReactDeps
1 parent 8cf36a8 commit fb68954

File tree

9 files changed

+286
-89
lines changed

9 files changed

+286
-89
lines changed

crates/biome_configuration/src/analyzer/linter/rules.rs

+107-88
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_diagnostics_categories/src/categories.rs

+1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ define_categories! {
172172
"lint/nursery/noPackagePrivateImports": "https://biomejs.dev/linter/rules/no-package-private-imports",
173173
"lint/nursery/noProcessEnv": "https://biomejs.dev/linter/rules/no-process-env",
174174
"lint/nursery/noProcessGlobal": "https://biomejs.dev/linter/rules/no-process-global",
175+
"lint/nursery/noReactDeps": "https://biomejs.dev/linter/rules/no-react-deps",
175176
"lint/nursery/noReactSpecificProps": "https://biomejs.dev/linter/rules/no-react-specific-props",
176177
"lint/nursery/noRestrictedImports": "https://biomejs.dev/linter/rules/no-restricted-imports",
177178
"lint/nursery/noRestrictedTypes": "https://biomejs.dev/linter/rules/no-restricted-types",

crates/biome_js_analyze/src/lint/nursery.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub mod no_octal_escape;
2727
pub mod no_package_private_imports;
2828
pub mod no_process_env;
2929
pub mod no_process_global;
30+
pub mod no_react_deps;
3031
pub mod no_restricted_imports;
3132
pub mod no_restricted_types;
3233
pub mod no_secrets;
@@ -59,4 +60,4 @@ pub mod use_strict_mode;
5960
pub mod use_symbol_description;
6061
pub mod use_trim_start_end;
6162
pub mod use_valid_autocomplete;
62-
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_await_in_loop :: NoAwaitInLoop , self :: no_bitwise_operators :: NoBitwiseOperators , self :: no_common_js :: NoCommonJs , self :: no_constant_binary_expression :: NoConstantBinaryExpression , self :: no_destructured_props :: NoDestructuredProps , self :: no_document_cookie :: NoDocumentCookie , self :: no_document_import_in_page :: NoDocumentImportInPage , self :: no_duplicate_else_if :: NoDuplicateElseIf , self :: no_dynamic_namespace_import_access :: NoDynamicNamespaceImportAccess , self :: no_enum :: NoEnum , self :: no_exported_imports :: NoExportedImports , self :: no_floating_promises :: NoFloatingPromises , self :: no_global_dirname_filename :: NoGlobalDirnameFilename , self :: no_head_element :: NoHeadElement , self :: no_head_import_in_document :: NoHeadImportInDocument , self :: no_img_element :: NoImgElement , self :: no_import_cycles :: NoImportCycles , self :: no_irregular_whitespace :: NoIrregularWhitespace , self :: no_nested_ternary :: NoNestedTernary , self :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions , self :: no_octal_escape :: NoOctalEscape , self :: no_package_private_imports :: NoPackagePrivateImports , self :: no_process_env :: NoProcessEnv , self :: no_process_global :: NoProcessGlobal , self :: no_restricted_imports :: NoRestrictedImports , self :: no_restricted_types :: NoRestrictedTypes , self :: no_secrets :: NoSecrets , self :: no_static_element_interactions :: NoStaticElementInteractions , self :: no_substr :: NoSubstr , self :: no_template_curly_in_string :: NoTemplateCurlyInString , self :: no_ts_ignore :: NoTsIgnore , self :: no_unwanted_polyfillio :: NoUnwantedPolyfillio , self :: no_useless_escape_in_regex :: NoUselessEscapeInRegex , self :: no_useless_escape_in_string :: NoUselessEscapeInString , self :: no_useless_string_raw :: NoUselessStringRaw , self :: no_useless_undefined :: NoUselessUndefined , self :: use_adjacent_overload_signatures :: UseAdjacentOverloadSignatures , self :: use_aria_props_supported_by_role :: UseAriaPropsSupportedByRole , self :: use_at_index :: UseAtIndex , self :: use_collapsed_if :: UseCollapsedIf , self :: use_component_export_only_modules :: UseComponentExportOnlyModules , self :: use_consistent_curly_braces :: UseConsistentCurlyBraces , self :: use_consistent_member_accessibility :: UseConsistentMemberAccessibility , self :: use_consistent_object_definition :: UseConsistentObjectDefinition , self :: use_explicit_type :: UseExplicitType , self :: use_exports_last :: UseExportsLast , self :: use_for_component :: UseForComponent , self :: use_google_font_display :: UseGoogleFontDisplay , self :: use_google_font_preconnect :: UseGoogleFontPreconnect , self :: use_guard_for_in :: UseGuardForIn , self :: use_parse_int_radix :: UseParseIntRadix , self :: use_sorted_classes :: UseSortedClasses , self :: use_strict_mode :: UseStrictMode , self :: use_symbol_description :: UseSymbolDescription , self :: use_trim_start_end :: UseTrimStartEnd , self :: use_valid_autocomplete :: UseValidAutocomplete ,] } }
63+
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_await_in_loop :: NoAwaitInLoop , self :: no_bitwise_operators :: NoBitwiseOperators , self :: no_common_js :: NoCommonJs , self :: no_constant_binary_expression :: NoConstantBinaryExpression , self :: no_destructured_props :: NoDestructuredProps , self :: no_document_cookie :: NoDocumentCookie , self :: no_document_import_in_page :: NoDocumentImportInPage , self :: no_duplicate_else_if :: NoDuplicateElseIf , self :: no_dynamic_namespace_import_access :: NoDynamicNamespaceImportAccess , self :: no_enum :: NoEnum , self :: no_exported_imports :: NoExportedImports , self :: no_floating_promises :: NoFloatingPromises , self :: no_global_dirname_filename :: NoGlobalDirnameFilename , self :: no_head_element :: NoHeadElement , self :: no_head_import_in_document :: NoHeadImportInDocument , self :: no_img_element :: NoImgElement , self :: no_import_cycles :: NoImportCycles , self :: no_irregular_whitespace :: NoIrregularWhitespace , self :: no_nested_ternary :: NoNestedTernary , self :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions , self :: no_octal_escape :: NoOctalEscape , self :: no_package_private_imports :: NoPackagePrivateImports , self :: no_process_env :: NoProcessEnv , self :: no_process_global :: NoProcessGlobal , self :: no_react_deps :: NoReactDeps , self :: no_restricted_imports :: NoRestrictedImports , self :: no_restricted_types :: NoRestrictedTypes , self :: no_secrets :: NoSecrets , self :: no_static_element_interactions :: NoStaticElementInteractions , self :: no_substr :: NoSubstr , self :: no_template_curly_in_string :: NoTemplateCurlyInString , self :: no_ts_ignore :: NoTsIgnore , self :: no_unwanted_polyfillio :: NoUnwantedPolyfillio , self :: no_useless_escape_in_regex :: NoUselessEscapeInRegex , self :: no_useless_escape_in_string :: NoUselessEscapeInString , self :: no_useless_string_raw :: NoUselessStringRaw , self :: no_useless_undefined :: NoUselessUndefined , self :: use_adjacent_overload_signatures :: UseAdjacentOverloadSignatures , self :: use_aria_props_supported_by_role :: UseAriaPropsSupportedByRole , self :: use_at_index :: UseAtIndex , self :: use_collapsed_if :: UseCollapsedIf , self :: use_component_export_only_modules :: UseComponentExportOnlyModules , self :: use_consistent_curly_braces :: UseConsistentCurlyBraces , self :: use_consistent_member_accessibility :: UseConsistentMemberAccessibility , self :: use_consistent_object_definition :: UseConsistentObjectDefinition , self :: use_explicit_type :: UseExplicitType , self :: use_exports_last :: UseExportsLast , self :: use_for_component :: UseForComponent , self :: use_google_font_display :: UseGoogleFontDisplay , self :: use_google_font_preconnect :: UseGoogleFontPreconnect , self :: use_guard_for_in :: UseGuardForIn , self :: use_parse_int_radix :: UseParseIntRadix , self :: use_sorted_classes :: UseSortedClasses , self :: use_strict_mode :: UseStrictMode , self :: use_symbol_description :: UseSymbolDescription , self :: use_trim_start_end :: UseTrimStartEnd , self :: use_valid_autocomplete :: UseValidAutocomplete ,] } }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use biome_analyze::{context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic};
2+
use biome_console::markup;
3+
use biome_js_syntax::JsIdentifierBinding;
4+
use biome_rowan::AstNode;
5+
6+
declare_lint_rule! {
7+
/// Disallow usage of dependency arrays in `createEffect` and `createMemo`.
8+
///
9+
///
10+
/// ## Examples
11+
///
12+
/// ### Invalid
13+
///
14+
/// ```js,expect_diagnostic
15+
/// createEffect(() => {
16+
/// console.log(signal());
17+
/// }, [signal()])
18+
/// ```
19+
///
20+
/// ```js,expect_diagnostic
21+
/// createEffect(() => {
22+
/// console.log(signal());
23+
/// }, [signal]);
24+
/// ```
25+
///
26+
/// ```js,expect_diagnostic
27+
/// const deps = [signal];
28+
/// createEffect(() => {
29+
/// console.log(signal());
30+
/// }, deps)
31+
/// ```
32+
///
33+
/// ### Valid
34+
///
35+
/// ```js
36+
/// createEffect(() => {
37+
/// console.log(signal());
38+
/// });
39+
/// ```
40+
///
41+
/// ```js
42+
/// createEffect((prev) => {
43+
/// console.log(signal());
44+
/// return prev + 1;
45+
/// }, 0);
46+
/// ```
47+
///
48+
/// ```js
49+
/// createEffect((prev) => {
50+
/// console.log(signal());
51+
/// return (prev || 0) + 1;
52+
/// });
53+
/// ```
54+
///
55+
/// ```js
56+
/// createEffect((prev) => {
57+
/// console.log(signal());
58+
/// return prev ? prev + 1 : 1;
59+
/// }, undefined);
60+
/// ```
61+
///
62+
/// ```js
63+
/// const value = createMemo(() => computeExpensiveValue(a(), b()));
64+
/// ```
65+
///
66+
/// ```js
67+
/// const sum = createMemo((prev) => input() + prev, 0);
68+
/// ```
69+
///
70+
/// ```js
71+
/// const args = [() => { console.log(signal()); }, [signal()]];
72+
/// createEffect(...args);
73+
/// ```
74+
///
75+
pub NoReactDeps {
76+
version: "next",
77+
name: "noReactDeps",
78+
language: "js",
79+
recommended: false,
80+
}
81+
}
82+
83+
impl Rule for NoReactDeps {
84+
type Query = Ast<JsIdentifierBinding>;
85+
type State = ();
86+
type Signals = Option<Self::State>;
87+
type Options = ();
88+
89+
fn run(ctx: &RuleContext<Self>) -> Self::Signals {
90+
let _binding = ctx.query();
91+
Some(())
92+
}
93+
94+
fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
95+
//
96+
// Read our guidelines to write great diagnostics:
97+
// https://docs.rs/biome_analyze/latest/biome_analyze/#what-a-rule-should-say-to-the-user
98+
//
99+
let node = ctx.query();
100+
Some(
101+
RuleDiagnostic::new(
102+
rule_category!(),
103+
node.range(),
104+
markup! {
105+
"Variable is read here."
106+
},
107+
)
108+
.note(markup! {
109+
"This note will give you more information."
110+
}),
111+
)
112+
}
113+
}

crates/biome_js_analyze/src/options.rs

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
createEffect(() => {
2+
console.log(signal());
3+
}, [signal()]);
4+
5+
createEffect(() => {
6+
console.log(signal());
7+
}, [signal]);
8+
9+
const deps = [signal];
10+
createEffect(() => {
11+
console.log(signal());
12+
}, deps);
13+
14+
const value = createMemo(() => computeExpensiveValue(a(), b()), [a(), b()]);
15+
16+
const value = createMemo(() => computeExpensiveValue(a(), b()), [a, b]);
17+
18+
const value = createMemo(() => computeExpensiveValue(a(), b()), [a, b()]);
19+
20+
const deps = [a, b];
21+
const value = createMemo(() => computeExpensiveValue(a(), b()), deps);
22+
23+
const deps = [a, b];
24+
const memoFn = () => computeExpensiveValue(a(), b());
25+
const value = createMemo(memoFn, deps);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
createEffect(() => {
2+
console.log(signal());
3+
});
4+
5+
createEffect((prev) => {
6+
console.log(signal());
7+
return prev + 1;
8+
}, 0);
9+
10+
createEffect((prev) => {
11+
console.log(signal());
12+
return (prev || 0) + 1;
13+
});
14+
15+
createEffect((prev) => {
16+
console.log(signal());
17+
return prev ? prev + 1 : 1;
18+
}, undefined);
19+
20+
const value = createMemo(() => computeExpensiveValue(a(), b()));
21+
22+
const sum = createMemo((prev) => input() + prev, 0);
23+
24+
const args = [() => { console.log(signal()); }, [signal()]];
25+
createEffect(...args);

packages/@biomejs/backend-jsonrpc/src/workspace.ts

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@biomejs/biome/configuration_schema.json

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)