diff --git a/crates/oxc_linter/src/context/mod.rs b/crates/oxc_linter/src/context/mod.rs index 3f57ce094773d..6076b8767dea7 100644 --- a/crates/oxc_linter/src/context/mod.rs +++ b/crates/oxc_linter/src/context/mod.rs @@ -341,7 +341,6 @@ const PLUGIN_PREFIXES: phf::Map<&'static str, &'static str> = phf::phf_map! { "promise" => "eslint-plugin-promise", "react_perf" => "eslint-plugin-react-perf", "react" => "eslint-plugin-react", - "tree_shaking" => "eslint-plugin-tree-shaking", "typescript" => "typescript-eslint", "unicorn" => "eslint-plugin-unicorn", "vitest" => "eslint-plugin-vitest", diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index da52c309ce71d..f9e39863d48f2 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -478,10 +478,6 @@ mod jsdoc { pub mod require_yields; } -mod tree_shaking { - pub mod no_side_effects_in_initialization; -} - mod promise { pub mod avoid_new; pub mod catch_or_return; @@ -830,7 +826,6 @@ oxc_macros::declare_all_lint_rules! { react_perf::jsx_no_new_function_as_prop, react_perf::jsx_no_new_object_as_prop, security::api_keys, - tree_shaking::no_side_effects_in_initialization, typescript::adjacent_overload_signatures, typescript::array_type, typescript::ban_ts_comment, diff --git a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs deleted file mode 100644 index 0e898d1fa1065..0000000000000 --- a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs +++ /dev/null @@ -1,1354 +0,0 @@ -use oxc_ast::{ - ast::{ - match_declaration, match_expression, match_member_expression, - match_simple_assignment_target, Argument, ArrayExpressionElement, ArrowFunctionExpression, - AssignmentTarget, BinaryExpression, BindingIdentifier, BindingPattern, BindingPatternKind, - CallExpression, Class, ClassBody, ClassElement, ComputedMemberExpression, - ConditionalExpression, Declaration, ExportSpecifier, Expression, ForStatementInit, - FormalParameter, Function, IdentifierReference, JSXAttribute, JSXAttributeItem, - JSXAttributeValue, JSXChild, JSXElement, JSXElementName, JSXExpression, - JSXExpressionContainer, JSXFragment, JSXMemberExpression, JSXOpeningElement, - LogicalExpression, MemberExpression, ModuleExportName, NewExpression, ObjectExpression, - ObjectPropertyKind, ParenthesizedExpression, PrivateFieldExpression, Program, PropertyKey, - SequenceExpression, SimpleAssignmentTarget, Statement, StaticMemberExpression, SwitchCase, - ThisExpression, UnaryExpression, VariableDeclarator, - }, - AstKind, -}; -use oxc_semantic::{AstNode, NodeId}; -use oxc_span::{GetSpan, Span}; -use oxc_syntax::operator::{LogicalOperator, UnaryOperator}; - -use crate::{ - ast_util::{get_declaration_of_variable, get_symbol_id_of_variable}, - utils::{ - calculate_binary_operation, calculate_logical_operation, calculate_unary_operation, - get_write_expr, has_comment_about_side_effect_check, has_pure_notation, - is_function_side_effect_free, is_local_variable_a_whitelisted_module, is_pure_function, - no_effects, FunctionName, NodeListenerOptions, Value, - }, -}; - -pub trait ListenerMap<'a> { - fn report_effects(&self, _options: &NodeListenerOptions<'a, '_>) {} - fn report_effects_when_assigned(&self, _options: &NodeListenerOptions<'a, '_>) {} - fn report_effects_when_called(&self, _options: &NodeListenerOptions<'a, '_>) {} - fn report_effects_when_mutated(&self, _options: &NodeListenerOptions<'a, '_>) {} - fn get_value_and_report_effects(&self, _options: &NodeListenerOptions<'a, '_>) -> Value { - Value::Unknown - } -} - -impl<'a> ListenerMap<'a> for Program<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.body.iter().for_each(|stmt| stmt.report_effects(options)); - } -} - -impl<'a> ListenerMap<'a> for Statement<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::ExpressionStatement(expr_stmt) => { - expr_stmt.expression.report_effects(options); - } - #[allow(clippy::match_same_arms)] - Self::BreakStatement(_) | Self::ContinueStatement(_) | Self::EmptyStatement(_) => { - no_effects(); - } - match_declaration!(Self) => self.to_declaration().report_effects(options), - Self::ReturnStatement(stmt) => { - if let Some(arg) = &stmt.argument { - arg.report_effects(options); - } - } - Self::ExportAllDeclaration(_) | Self::ImportDeclaration(_) => { - no_effects(); - } - Self::ExportDefaultDeclaration(stmt) => { - if let Some(expr) = &stmt.declaration.as_expression() { - if has_comment_about_side_effect_check(expr.span(), options.ctx) { - expr.report_effects_when_called(options); - } - expr.report_effects(options); - } - } - Self::ExportNamedDeclaration(stmt) => { - stmt.specifiers.iter().for_each(|specifier| { - specifier.report_effects(options); - }); - - if let Some(decl) = &stmt.declaration { - decl.report_effects(options); - } - } - Self::TryStatement(stmt) => { - stmt.block.body.iter().for_each(|stmt| stmt.report_effects(options)); - stmt.handler.iter().for_each(|handler| { - handler.body.body.iter().for_each(|stmt| stmt.report_effects(options)); - }); - stmt.finalizer.iter().for_each(|finalizer| { - finalizer.body.iter().for_each(|stmt| stmt.report_effects(options)); - }); - } - Self::ThrowStatement(stmt) => { - options.ctx.diagnostic(super::throw(stmt.span)); - } - Self::BlockStatement(stmt) => { - stmt.body.iter().for_each(|stmt| stmt.report_effects(options)); - } - Self::IfStatement(stmt) => { - let test_result = stmt.test.get_value_and_report_effects(options); - - if let Some(is_falsy) = test_result.get_falsy_value() { - if is_falsy { - if let Some(alternate) = &stmt.alternate { - alternate.report_effects(options); - } - } else { - stmt.consequent.report_effects(options); - } - } else { - stmt.consequent.report_effects(options); - if let Some(alternate) = &stmt.alternate { - alternate.report_effects(options); - } - } - } - Self::DoWhileStatement(stmt) => { - if stmt - .test - .get_value_and_report_effects(options) - .get_falsy_value() - .is_some_and(|is_falsy| is_falsy) - { - return; - } - stmt.body.report_effects(options); - } - Self::DebuggerStatement(stmt) => { - options.ctx.diagnostic(super::debugger(stmt.span)); - } - Self::ForStatement(stmt) => { - if let Some(init) = &stmt.init { - init.report_effects(options); - } - if let Some(test) = &stmt.test { - test.report_effects(options); - } - if let Some(update) = &stmt.update { - update.report_effects(options); - } - stmt.body.report_effects(options); - } - Self::ForInStatement(stmt) => { - if let Some(assign) = stmt.left.as_assignment_target() { - assign.report_effects_when_assigned(options); - } - stmt.right.report_effects(options); - stmt.body.report_effects(options); - } - Self::ForOfStatement(stmt) => { - if let Some(assign) = stmt.left.as_assignment_target() { - assign.report_effects_when_assigned(options); - } - stmt.right.report_effects(options); - stmt.body.report_effects(options); - } - Self::LabeledStatement(stmt) => { - stmt.body.report_effects(options); - } - Self::WhileStatement(stmt) => { - if stmt - .test - .get_value_and_report_effects(options) - .get_falsy_value() - .is_some_and(|is_falsy| is_falsy) - { - return; - } - stmt.body.report_effects(options); - } - Self::SwitchStatement(stmt) => { - stmt.discriminant.report_effects(options); - stmt.cases.iter().for_each(|case| { - case.report_effects(options); - }); - } - _ => {} - } - } -} - -impl<'a> ListenerMap<'a> for ForStatementInit<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - match_expression!(Self) => self.to_expression().report_effects(options), - Self::VariableDeclaration(decl) => { - decl.declarations.iter().for_each(|decl| decl.report_effects(options)); - } - } - } -} - -impl<'a> ListenerMap<'a> for ExportSpecifier<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - let ctx = options.ctx; - let symbol_table = ctx.symbols(); - if has_comment_about_side_effect_check(self.exported.span(), ctx) { - let ModuleExportName::IdentifierReference(ident) = &self.local else { - return; - }; - let Some(symbol_id) = get_symbol_id_of_variable(ident, ctx) else { - return; - }; - - for reference in symbol_table.get_resolved_references(symbol_id) { - if reference.is_write() { - let node_id = reference.node_id(); - if let Some(expr) = get_write_expr(node_id, ctx) { - expr.report_effects_when_called(options); - } - } - } - let symbol_table = ctx.semantic().symbols(); - let node = ctx.nodes().get_node(symbol_table.get_declaration(symbol_id)); - node.report_effects_when_called(options); - } - } -} - -// we don't need implement all AstNode -// it's same as `reportSideEffectsInDefinitionWhenCalled` in eslint-plugin-tree-shaking -// -impl<'a> ListenerMap<'a> for AstNode<'a> { - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - match self.kind() { - AstKind::VariableDeclarator(decl) => { - if let Some(init) = &decl.init { - init.report_effects_when_called(options); - } - } - AstKind::FormalParameter(param) => { - options.ctx.diagnostic(super::call_parameter(param.span)); - } - AstKind::BindingRestElement(rest) => { - let start = rest.span.start + 3; - let end = rest.span.end; - options.ctx.diagnostic(super::call_parameter(Span::new(start, end))); - } - AstKind::Function(function) => { - let old_val = options.has_valid_this.get(); - options.has_valid_this.set(options.called_with_new.get()); - function.report_effects_when_called(options); - options.has_valid_this.set(old_val); - } - AstKind::Class(class) => { - class.report_effects_when_called(options); - } - AstKind::ImportDefaultSpecifier(specifier) => { - report_on_imported_call( - specifier.local.span, - &specifier.local.name, - self.id(), - options, - ); - } - AstKind::ImportSpecifier(specifier) => { - report_on_imported_call( - specifier.local.span, - &specifier.local.name, - self.id(), - options, - ); - } - AstKind::ImportNamespaceSpecifier(specifier) => { - report_on_imported_call( - specifier.local.span, - &specifier.local.name, - self.id(), - options, - ); - } - _ => {} - } - } - - fn report_effects_when_mutated(&self, options: &NodeListenerOptions<'a, '_>) { - match self.kind() { - AstKind::VariableDeclarator(decl) => { - if let Some(init) = &decl.init { - init.report_effects_when_mutated(options); - } - } - AstKind::FormalParameter(param) => { - options.ctx.diagnostic(super::mutate_parameter(param.span)); - } - AstKind::BindingRestElement(rest) => { - let start = rest.span.start + 3; - let end = rest.span.end; - options.ctx.diagnostic(super::mutate_parameter(Span::new(start, end))); - } - AstKind::ImportDefaultSpecifier(specifier) => { - options.ctx.diagnostic(super::mutate_import(specifier.span)); - } - AstKind::ImportSpecifier(specifier) => { - options.ctx.diagnostic(super::mutate_import(specifier.local.span)); - } - AstKind::ImportNamespaceSpecifier(specifier) => { - options.ctx.diagnostic(super::mutate_import(specifier.local.span)); - } - _ => {} - } - } -} - -fn report_on_imported_call(span: Span, name: &str, node_id: NodeId, options: &NodeListenerOptions) { - if has_comment_about_side_effect_check(span, options.ctx) { - return; - } - let Some(AstKind::ImportDeclaration(decl)) = options.ctx.nodes().parent_kind(node_id) else { - return; - }; - if is_function_side_effect_free(name, &decl.source.value, options) { - return; - } - options.ctx.diagnostic(super::call_import(span)); -} - -impl<'a> ListenerMap<'a> for Declaration<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::VariableDeclaration(decl) => { - decl.declarations.iter().for_each(|decl| decl.report_effects(options)); - } - Self::ClassDeclaration(decl) => { - decl.report_effects(options); - } - Self::FunctionDeclaration(function) => { - if let Some(id) = &function.id { - if has_comment_about_side_effect_check(id.span, options.ctx) { - id.report_effects_when_called(options); - } - } - } - _ => {} - } - } -} - -impl<'a> ListenerMap<'a> for Class<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - if let Some(super_class) = &self.super_class { - super_class.report_effects(options); - } - self.body.report_effects(options); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - if let Some(super_class) = &self.super_class { - super_class.report_effects_when_called(options); - } - self.body.report_effects_when_called(options); - } -} - -impl<'a> ListenerMap<'a> for ClassBody<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.body.iter().for_each(|class_element| { - class_element.report_effects(options); - }); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - let constructor = self.body.iter().find(|class_element| { - if let ClassElement::MethodDefinition(definition) = class_element { - return definition.kind.is_constructor(); - } - false - }); - - if let Some(constructor) = constructor { - let old_val = options.has_valid_this.get(); - options.has_valid_this.set(options.called_with_new.get()); - constructor.report_effects_when_called(options); - options.has_valid_this.set(old_val); - } - - self.body - .iter() - .filter(|class_element| matches!(class_element, ClassElement::PropertyDefinition(_))) - .for_each(|property_definition| { - property_definition.report_effects_when_called(options); - }); - } -} - -impl<'a> ListenerMap<'a> for ClassElement<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::MethodDefinition(method) => { - method.key.report_effects(options); - } - Self::PropertyDefinition(prop) => { - prop.key.report_effects(options); - } - _ => {} - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::MethodDefinition(method) => { - method.value.report_effects_when_called(options); - } - Self::PropertyDefinition(prop) => { - if let Some(value) = &prop.value { - value.report_effects_when_called(options); - } - } - _ => {} - } - } -} - -impl<'a> ListenerMap<'a> for PropertyKey<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self.as_expression() { - Some(expr) => expr.report_effects(options), - None => no_effects(), - } - } -} - -impl<'a> ListenerMap<'a> for VariableDeclarator<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.id.report_effects(options); - if has_comment_about_side_effect_check(self.id.span(), options.ctx) { - self.id.report_effects_when_called(options); - } - - if let Some(init) = &self.init { - init.report_effects(options); - } - } -} - -impl<'a> ListenerMap<'a> for BindingPattern<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match &self.kind { - BindingPatternKind::BindingIdentifier(_) => {} - BindingPatternKind::ArrayPattern(array) => { - array.elements.iter().for_each(|el| { - if let Some(el) = el { - el.report_effects(options); - } - }); - } - BindingPatternKind::ObjectPattern(object) => { - object.properties.iter().for_each(|prop| { - prop.key.report_effects(options); - prop.value.report_effects(options); - }); - } - BindingPatternKind::AssignmentPattern(assign_p) => { - assign_p.left.report_effects(options); - assign_p.right.report_effects(options); - } - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - if let BindingPatternKind::BindingIdentifier(ident) = &self.kind { - ident.report_effects_when_called(options); - } - } -} - -impl<'a> ListenerMap<'a> for BindingIdentifier<'a> { - fn report_effects(&self, _options: &NodeListenerOptions<'a, '_>) { - no_effects(); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - let ctx = options.ctx; - if let Some(symbol_id) = self.symbol_id.get() { - let symbol_table = ctx.semantic().symbols(); - for reference in symbol_table.get_resolved_references(symbol_id) { - if reference.is_write() { - let node_id = reference.node_id(); - if let Some(expr) = get_write_expr(node_id, ctx) { - expr.report_effects_when_called(options); - } - } - } - let node = ctx.nodes().get_node(symbol_table.get_declaration(symbol_id)); - node.report_effects_when_called(options); - } - } -} - -impl<'a> ListenerMap<'a> for Expression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::ArrayExpression(array_expr) => { - array_expr.elements.iter().for_each(|el| el.report_effects(options)); - } - Self::AssignmentExpression(assign_expr) => { - assign_expr.left.report_effects_when_assigned(options); - assign_expr.right.report_effects(options); - } - Self::CallExpression(call_expr) => { - call_expr.report_effects(options); - } - Self::ParenthesizedExpression(expr) => { - expr.report_effects(options); - } - Self::NewExpression(expr) => { - expr.report_effects(options); - } - Self::AwaitExpression(expr) => { - expr.argument.report_effects(options); - } - Self::BinaryExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::ClassExpression(expr) => { - expr.report_effects(options); - } - Self::ConditionalExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::JSXElement(expr) => { - expr.report_effects(options); - } - Self::ObjectExpression(expr) => { - expr.report_effects(options); - } - Self::LogicalExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::StaticMemberExpression(expr) => { - expr.report_effects(options); - } - Self::ComputedMemberExpression(expr) => { - expr.report_effects(options); - } - Self::PrivateFieldExpression(expr) => { - expr.report_effects(options); - } - Self::UnaryExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::UpdateExpression(expr) => { - expr.argument.report_effects_when_assigned(options); - } - Self::SequenceExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::YieldExpression(expr) => { - expr.argument.iter().for_each(|arg| arg.report_effects(options)); - } - Self::TaggedTemplateExpression(expr) => { - expr.tag.report_effects_when_called(options); - expr.quasi.expressions.iter().for_each(|expr| { - expr.report_effects(options); - }); - } - Self::TemplateLiteral(expr) => { - expr.expressions.iter().for_each(|expr| { - expr.report_effects(options); - }); - } - Self::ArrowFunctionExpression(_) - | Self::FunctionExpression(_) - | Self::Identifier(_) - | Self::MetaProperty(_) - | Self::Super(_) - | Self::ThisExpression(_) => no_effects(), - _ => {} - } - } - - fn report_effects_when_mutated(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::Identifier(ident) => { - ident.report_effects_when_mutated(options); - } - Self::ArrowFunctionExpression(_) | Self::ObjectExpression(_) => no_effects(), - Self::ParenthesizedExpression(expr) => { - expr.report_effects_when_mutated(options); - } - Self::CallExpression(expr) => { - expr.report_effects_when_mutated(options); - } - Self::ThisExpression(expr) => { - expr.report_effects_when_mutated(options); - } - _ => { - // Default behavior - options.ctx.diagnostic(super::mutate(self.span())); - } - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::CallExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::Identifier(expr) => { - expr.report_effects_when_called(options); - } - Self::FunctionExpression(expr) => { - let old_val = options.has_valid_this.get(); - options.has_valid_this.set(options.called_with_new.get()); - expr.report_effects_when_called(options); - options.has_valid_this.set(old_val); - } - Self::ArrowFunctionExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::ParenthesizedExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::ClassExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::ConditionalExpression(expr) => expr.report_effects_when_called(options), - Self::StaticMemberExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::ComputedMemberExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::PrivateFieldExpression(expr) => { - expr.report_effects_when_called(options); - } - _ => { - // Default behavior - options.ctx.diagnostic(super::call(self.span())); - } - } - } - - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - match self { - Self::BooleanLiteral(_) - | Self::StringLiteral(_) - | Self::NumericLiteral(_) - | Self::TemplateLiteral(_) => Value::new(self), - Self::BinaryExpression(expr) => expr.get_value_and_report_effects(options), - Self::ConditionalExpression(expr) => expr.get_value_and_report_effects(options), - Self::LogicalExpression(expr) => expr.get_value_and_report_effects(options), - Self::SequenceExpression(expr) => expr.get_value_and_report_effects(options), - _ => { - self.report_effects(options); - Value::Unknown - } - } - } -} - -// which kind of Expression defines `report_effects_when_called` method. -fn defined_custom_report_effects_when_called(expr: &Expression) -> bool { - matches!( - expr.get_inner_expression(), - Expression::ArrowFunctionExpression(_) - | Expression::CallExpression(_) - | Expression::ClassExpression(_) - | Expression::ConditionalExpression(_) - | Expression::FunctionExpression(_) - | Expression::Identifier(_) - | Expression::ComputedMemberExpression(_) - | Expression::StaticMemberExpression(_) - | Expression::PrivateFieldExpression(_) - ) -} - -impl<'a> ListenerMap<'a> for SwitchCase<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - if let Some(test) = &self.test { - test.report_effects(options); - } - self.consequent.iter().for_each(|stmt| { - stmt.report_effects(options); - }); - } -} - -impl<'a> ListenerMap<'a> for SequenceExpression<'a> { - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - let mut val = Value::Unknown; - for expr in &self.expressions { - val = expr.get_value_and_report_effects(options); - } - val - } -} - -impl<'a> ListenerMap<'a> for UnaryExpression<'a> { - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - if self.operator == UnaryOperator::Delete { - match &self.argument { - Expression::StaticMemberExpression(expr) => { - expr.object.report_effects_when_mutated(options); - } - Expression::ComputedMemberExpression(expr) => { - expr.object.report_effects_when_mutated(options); - } - Expression::PrivateFieldExpression(expr) => { - expr.object.report_effects_when_mutated(options); - } - _ => options.ctx.diagnostic(super::delete(self.argument.span())), - } - return Value::Unknown; - } - - let value = self.argument.get_value_and_report_effects(options); - calculate_unary_operation(self.operator, value) - } -} - -impl<'a> ListenerMap<'a> for LogicalExpression<'a> { - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - let left = self.left.get_value_and_report_effects(options); - // `false && foo` - if self.operator == LogicalOperator::And - && left.get_falsy_value().is_some_and(|is_falsy| is_falsy) - { - return left; - } - // `true || foo` - if self.operator == LogicalOperator::Or - && left.get_falsy_value().is_some_and(|is_falsy| !is_falsy) - { - return left; - } - let right = self.right.get_value_and_report_effects(options); - calculate_logical_operation(self.operator, left, right) - } -} - -impl<'a> ListenerMap<'a> for ObjectExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.properties.iter().for_each(|property| match property { - ObjectPropertyKind::ObjectProperty(p) => { - p.key.report_effects(options); - p.value.report_effects(options); - } - ObjectPropertyKind::SpreadProperty(spreed) => { - spreed.argument.report_effects(options); - } - }); - } -} - -impl<'a> ListenerMap<'a> for JSXElement<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.opening_element.report_effects(options); - self.children.iter().for_each(|child| { - child.report_effects(options); - }); - } -} - -impl<'a> ListenerMap<'a> for JSXChild<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - JSXChild::Element(element) => { - element.report_effects(options); - } - JSXChild::Spread(spread) => { - spread.expression.report_effects(options); - } - JSXChild::Fragment(fragment) => { - fragment.report_effects(options); - } - JSXChild::ExpressionContainer(container) => { - container.report_effects(options); - } - JSXChild::Text(_) => { - no_effects(); - } - } - } -} - -impl<'a> ListenerMap<'a> for JSXOpeningElement<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.name.report_effects_when_called(options); - self.attributes.iter().for_each(|attr| attr.report_effects(options)); - } -} - -impl<'a> ListenerMap<'a> for JSXElementName<'a> { - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::Identifier(_) | Self::NamespacedName(_) => {} - Self::IdentifierReference(ident) => ident.report_effects_when_called(options), - Self::MemberExpression(member) => member.report_effects_when_called(options), - Self::ThisExpression(expr) => expr.report_effects_when_called(options), - } - } -} - -impl<'a> ListenerMap<'a> for JSXMemberExpression<'a> { - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - options.ctx.diagnostic(super::call_member(self.property.span())); - } -} - -impl<'a> ListenerMap<'a> for JSXAttributeItem<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::Attribute(attribute) => { - attribute.report_effects(options); - } - Self::SpreadAttribute(attribute) => { - attribute.argument.report_effects(options); - } - } - } -} - -impl<'a> ListenerMap<'a> for JSXAttribute<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - if let Some(value) = &self.value { - match value { - JSXAttributeValue::ExpressionContainer(container) => { - container.report_effects(options); - } - JSXAttributeValue::Element(element) => { - element.report_effects(options); - } - JSXAttributeValue::Fragment(fragment) => { - fragment.report_effects(options); - } - JSXAttributeValue::StringLiteral(_) => { - no_effects(); - } - } - } - } -} - -impl<'a> ListenerMap<'a> for JSXExpressionContainer<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.expression.report_effects(options); - } -} - -impl<'a> ListenerMap<'a> for JSXExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::ArrayExpression(array_expr) => { - array_expr.elements.iter().for_each(|el| el.report_effects(options)); - } - Self::AssignmentExpression(assign_expr) => { - assign_expr.left.report_effects_when_assigned(options); - assign_expr.right.report_effects(options); - } - Self::CallExpression(call_expr) => { - call_expr.report_effects(options); - } - Self::ParenthesizedExpression(expr) => { - expr.report_effects(options); - } - Self::NewExpression(expr) => { - expr.report_effects(options); - } - Self::AwaitExpression(expr) => { - expr.argument.report_effects(options); - } - Self::BinaryExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::ClassExpression(expr) => { - expr.report_effects(options); - } - Self::ConditionalExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::JSXElement(expr) => { - expr.report_effects(options); - } - Self::ObjectExpression(expr) => { - expr.report_effects(options); - } - Self::StaticMemberExpression(expr) => { - expr.report_effects(options); - } - Self::ComputedMemberExpression(expr) => { - expr.report_effects(options); - } - Self::PrivateFieldExpression(expr) => { - expr.report_effects(options); - } - Self::UnaryExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::SequenceExpression(expr) => { - expr.get_value_and_report_effects(options); - } - Self::ArrowFunctionExpression(_) - | Self::EmptyExpression(_) - | Self::FunctionExpression(_) - | Self::Identifier(_) - | Self::MetaProperty(_) - | Self::Super(_) - | Self::ThisExpression(_) => no_effects(), - _ => {} - } - } -} - -impl<'a> ListenerMap<'a> for JSXFragment<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.children.iter().for_each(|child| child.report_effects(options)); - } -} - -impl<'a> ListenerMap<'a> for ConditionalExpression<'a> { - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - let test_result = self.test.get_value_and_report_effects(options); - - if let Some(is_falsy) = test_result.get_falsy_value() { - if is_falsy { - self.alternate.get_value_and_report_effects(options) - } else { - self.consequent.get_value_and_report_effects(options) - } - } else { - self.consequent.report_effects(options); - self.alternate.report_effects(options); - test_result - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - let test_result = self.test.get_value_and_report_effects(options); - - if let Some(falsy) = test_result.get_falsy_value() { - if falsy { - self.alternate.report_effects_when_called(options); - } else { - self.consequent.report_effects_when_called(options); - } - } else { - self.consequent.report_effects_when_called(options); - self.alternate.report_effects_when_called(options); - } - } -} - -impl<'a> ListenerMap<'a> for BinaryExpression<'a> { - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - let left = self.left.get_value_and_report_effects(options); - let right = self.right.get_value_and_report_effects(options); - calculate_binary_operation(self.operator, left, right) - } -} - -impl<'a> ListenerMap<'a> for ThisExpression { - fn report_effects_when_mutated(&self, options: &NodeListenerOptions<'a, '_>) { - if !options.has_valid_this.get() { - options.ctx.diagnostic(super::mutate_of_this(self.span)); - } - } -} - -impl<'a> ListenerMap<'a> for NewExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - if has_pure_notation(self.span, options.ctx) { - return; - } - self.arguments.iter().for_each(|arg| arg.report_effects(options)); - let old_val = options.called_with_new.get(); - options.called_with_new.set(true); - self.callee.report_effects_when_called(options); - options.called_with_new.set(old_val); - } -} - -impl<'a> ListenerMap<'a> for ParenthesizedExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.expression.report_effects(options); - } - - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - self.expression.report_effects_when_assigned(options); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - self.expression.report_effects_when_called(options); - } - - fn report_effects_when_mutated(&self, options: &NodeListenerOptions<'a, '_>) { - self.expression.report_effects_when_mutated(options); - } - - fn get_value_and_report_effects(&self, options: &NodeListenerOptions<'a, '_>) -> Value { - self.expression.get_value_and_report_effects(options) - } -} - -impl<'a> ListenerMap<'a> for ArrowFunctionExpression<'a> { - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - self.params.items.iter().for_each(|param| param.report_effects(options)); - self.body.statements.iter().for_each(|stmt| stmt.report_effects(options)); - } -} - -impl<'a> ListenerMap<'a> for Function<'a> { - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - self.params.items.iter().for_each(|param| param.report_effects(options)); - - if let Some(body) = &self.body { - body.statements.iter().for_each(|stmt| stmt.report_effects(options)); - } - } -} - -impl<'a> ListenerMap<'a> for FormalParameter<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.pattern.report_effects(options); - } -} - -impl<'a> ListenerMap<'a> for CallExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.arguments.iter().for_each(|arg| arg.report_effects(options)); - if defined_custom_report_effects_when_called(&self.callee) { - let old_value = options.called_with_new.get(); - options.called_with_new.set(false); - self.callee.report_effects_when_called(options); - options.called_with_new.set(old_value); - } else { - options.ctx.diagnostic(super::call(self.callee.span())); - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - let ctx = options.ctx; - if let Expression::Identifier(ident) = &self.callee { - if let Some(node) = get_declaration_of_variable(ident, ctx) { - if is_local_variable_a_whitelisted_module(node, ident.name.as_str(), options) { - return; - } - options.ctx.diagnostic(super::call_return_value(self.span)); - } else { - options.ctx.diagnostic(super::call_return_value(self.span)); - } - } - } - - fn report_effects_when_mutated(&self, options: &NodeListenerOptions<'a, '_>) { - options.ctx.diagnostic(super::mutate_function_return_value(self.span)); - } -} - -impl<'a> ListenerMap<'a> for Argument<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - match_expression!(Self) => self.to_expression().report_effects(options), - Self::SpreadElement(spread) => { - spread.argument.report_effects(options); - } - } - } -} - -impl<'a> ListenerMap<'a> for AssignmentTarget<'a> { - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - match_simple_assignment_target!(Self) => { - self.to_simple_assignment_target().report_effects_when_assigned(options); - } - Self::ArrayAssignmentTarget(_) | Self::ObjectAssignmentTarget(_) => {} - } - } -} - -impl<'a> ListenerMap<'a> for SimpleAssignmentTarget<'a> { - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::AssignmentTargetIdentifier(ident) => { - ident.report_effects_when_assigned(options); - } - match_member_expression!(Self) => { - self.to_member_expression().report_effects_when_assigned(options); - } - _ => { - // For remain TypeScript AST, just visit its expression - if let Some(expr) = self.get_expression() { - expr.report_effects_when_assigned(options); - } - } - } - } -} - -impl<'a> ListenerMap<'a> for IdentifierReference<'a> { - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - if get_symbol_id_of_variable(self, options.ctx).is_none() { - options.ctx.diagnostic(super::assignment(self.name.as_str(), self.span)); - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - if is_pure_function(&FunctionName::Identifier(self), options) { - return; - } - - let ctx = options.ctx; - - if let Some(symbol_id) = get_symbol_id_of_variable(self, ctx) { - let is_used_in_jsx = matches!( - ctx.nodes().parent_kind( - ctx.symbols().get_reference(self.reference_id.get().unwrap()).node_id() - ), - Some(AstKind::JSXElementName(_) | AstKind::JSXMemberExpressionObject(_)) - ); - - if is_used_in_jsx { - for reference in options.ctx.symbols().get_resolved_references(symbol_id) { - if reference.is_write() { - let node_id = reference.node_id(); - if let Some(expr) = get_write_expr(node_id, options.ctx) { - let old_val = options.called_with_new.get(); - options.called_with_new.set(true); - expr.report_effects_when_called(options); - options.called_with_new.set(old_val); - } - } - } - let symbol_table = options.ctx.semantic().symbols(); - let node = options.ctx.nodes().get_node(symbol_table.get_declaration(symbol_id)); - let old_val = options.called_with_new.get(); - options.called_with_new.set(true); - node.report_effects_when_called(options); - options.called_with_new.set(old_val); - return; - } - - if options.insert_called_node(symbol_id) { - let symbol_table = ctx.semantic().symbols(); - for reference in symbol_table.get_resolved_references(symbol_id) { - if reference.is_write() { - let node_id = reference.node_id(); - if let Some(expr) = get_write_expr(node_id, ctx) { - expr.report_effects_when_called(options); - } - } - } - let symbol_table = ctx.semantic().symbols(); - let node = ctx.nodes().get_node(symbol_table.get_declaration(symbol_id)); - node.report_effects_when_called(options); - } - } else { - ctx.diagnostic(super::call_global(self.name.as_str(), self.span)); - } - } - - fn report_effects_when_mutated(&self, options: &NodeListenerOptions<'a, '_>) { - let ctx = options.ctx; - if let Some(symbol_id) = get_symbol_id_of_variable(self, ctx) { - if options.insert_mutated_node(symbol_id) { - for reference in ctx.symbols().get_resolved_references(symbol_id) { - if reference.is_write() { - let node_id = reference.node_id(); - if let Some(expr) = get_write_expr(node_id, ctx) { - expr.report_effects_when_mutated(options); - } - } - } - - let symbol_table = ctx.semantic().symbols(); - let node = ctx.nodes().get_node(symbol_table.get_declaration(symbol_id)); - node.report_effects_when_mutated(options); - } - } else { - ctx.diagnostic(super::mutate_with_name(self.name.as_str(), self.span)); - } - } -} - -impl<'a> ListenerMap<'a> for MemberExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::ComputedMemberExpression(expr) => { - expr.report_effects(options); - } - Self::StaticMemberExpression(expr) => { - expr.report_effects(options); - } - Self::PrivateFieldExpression(expr) => { - expr.report_effects(options); - } - } - } - - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::ComputedMemberExpression(expr) => { - expr.report_effects_when_assigned(options); - } - Self::StaticMemberExpression(expr) => { - expr.report_effects_when_assigned(options); - } - Self::PrivateFieldExpression(expr) => { - expr.report_effects_when_assigned(options); - } - } - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - Self::ComputedMemberExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::StaticMemberExpression(expr) => { - expr.report_effects_when_called(options); - } - Self::PrivateFieldExpression(expr) => { - expr.report_effects_when_called(options); - } - } - } -} - -impl<'a> ListenerMap<'a> for ComputedMemberExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.expression.report_effects(options); - self.object.report_effects(options); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - self.report_effects(options); - - let mut node = &self.object; - loop { - match node { - Expression::ComputedMemberExpression(expr) => { - node = &expr.object; - } - Expression::StaticMemberExpression(expr) => node = &expr.object, - Expression::PrivateInExpression(expr) => node = &expr.right, - _ => { - break; - } - } - } - - if let Expression::Identifier(ident) = node { - ident.report_effects_when_called(options); - } else { - options.ctx.diagnostic(super::call_member(node.span())); - } - } - - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - self.report_effects(options); - self.object.report_effects_when_mutated(options); - } -} - -impl<'a> ListenerMap<'a> for StaticMemberExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.object.report_effects(options); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - self.report_effects(options); - - let mut root_member_expr = &self.object; - loop { - match root_member_expr { - Expression::ComputedMemberExpression(expr) => { - root_member_expr = &expr.object; - } - Expression::StaticMemberExpression(expr) => root_member_expr = &expr.object, - Expression::PrivateInExpression(expr) => root_member_expr = &expr.right, - _ => { - break; - } - } - } - - let Expression::Identifier(ident) = root_member_expr else { - options.ctx.diagnostic(super::call_member(root_member_expr.span())); - return; - }; - - let Some(node) = get_declaration_of_variable(ident, options.ctx) else { - // If the variable is not declared, it is a global variable. - // `ext.x()` - if !is_pure_function(&FunctionName::StaticMemberExpr(self), options) { - options.ctx.diagnostic(super::call_member(self.span)); - } - return; - }; - - if is_local_variable_a_whitelisted_module(node, &ident.name, options) { - return; - }; - - if has_pure_notation(self.span, options.ctx) { - return; - } - - options.ctx.diagnostic(super::call_member(self.span)); - } - - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - self.report_effects(options); - self.object.report_effects_when_mutated(options); - } -} - -impl<'a> ListenerMap<'a> for PrivateFieldExpression<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - self.object.report_effects(options); - } - - fn report_effects_when_called(&self, options: &NodeListenerOptions<'a, '_>) { - self.report_effects(options); - - let mut node = &self.object; - loop { - match node { - Expression::ComputedMemberExpression(expr) => { - node = &expr.object; - } - Expression::StaticMemberExpression(expr) => node = &expr.object, - Expression::PrivateInExpression(expr) => node = &expr.right, - _ => { - break; - } - } - } - - if let Expression::Identifier(ident) = node { - ident.report_effects_when_called(options); - } else { - options.ctx.diagnostic(super::call_member(node.span())); - } - } - - fn report_effects_when_assigned(&self, options: &NodeListenerOptions<'a, '_>) { - self.report_effects(options); - self.object.report_effects_when_mutated(options); - } -} - -impl<'a> ListenerMap<'a> for ArrayExpressionElement<'a> { - fn report_effects(&self, options: &NodeListenerOptions<'a, '_>) { - match self { - match_expression!(Self) => self.to_expression().report_effects(options), - Self::SpreadElement(spreed) => { - spreed.argument.report_effects(options); - } - Self::Elision(_) => {} - } - } -} diff --git a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs deleted file mode 100644 index be2dab30c97f2..0000000000000 --- a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs +++ /dev/null @@ -1,896 +0,0 @@ -use oxc_ast::AstKind; -use oxc_diagnostics::OxcDiagnostic; -use oxc_macros::declare_oxc_lint; -use oxc_span::Span; -use serde_json::Value; - -use self::listener_map::ListenerMap; -use crate::{ - context::LintContext, - rule::Rule, - utils::{ModuleFunctions, NodeListenerOptions, WhitelistModule}, -}; - -mod listener_map; - -fn assignment(x0: &str, span1: Span) -> OxcDiagnostic { - OxcDiagnostic::warn(format!("Cannot determine side-effects of assignment to `{x0}`")) - .with_label(span1) -} - -fn mutate(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of mutating").with_label(span) -} - -fn mutate_with_name(x0: &str, span1: Span) -> OxcDiagnostic { - OxcDiagnostic::warn(format!("Cannot determine side-effects of mutating `{x0}`")) - .with_label(span1) -} - -fn mutate_function_return_value(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of mutating function return value") - .with_label(span) -} - -fn mutate_parameter(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of mutating function parameter") - .with_label(span) -} - -fn mutate_of_this(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of mutating unknown this value") - .with_label(span) -} - -fn mutate_import(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of mutating imported variable") - .with_label(span) -} - -fn call(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of calling").with_label(span) -} - -fn call_return_value(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of calling function return value") - .with_label(span) -} - -fn call_global(x0: &str, span1: Span) -> OxcDiagnostic { - OxcDiagnostic::warn(format!("Cannot determine side-effects of calling global function `{x0}`")) - .with_label(span1) -} - -fn call_parameter(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of calling function parameter") - .with_label(span) -} - -fn call_import(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of calling imported function") - .with_label(span) -} - -fn call_member(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of calling member function").with_label(span) -} - -fn debugger(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Debugger statements are side-effects").with_label(span) -} - -fn delete(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Cannot determine side-effects of deleting anything but a MemberExpression") - .with_label(span) -} - -fn throw(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Throwing an error is a side-effect").with_label(span) -} - -/// -#[derive(Debug, Default, Clone)] -pub struct NoSideEffectsInInitialization(Box); - -impl std::ops::Deref for NoSideEffectsInInitialization { - type Target = NoSideEffectsInInitiallizationOptions; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Default, Clone)] -pub struct NoSideEffectsInInitiallizationOptions { - functions: Vec, - modules: Vec, -} - -declare_oxc_lint!( - /// ### What it does - /// - /// Marks all side-effects in module initialization that will interfere with tree-shaking. - /// - /// This plugin is intended as a means for library developers to identify patterns that will - /// interfere with the tree-shaking algorithm of their module bundler (i.e. rollup or webpack). - /// - /// ### Why is this bad? - /// - /// Side-effects in module initialization can hinder tree-shaking, which aims to remove - /// unused code. If side-effects exist, it's harder for the bundler to safely eliminate - /// code, leading to larger bundles and potentially unexpected behavior. Ensuring minimal - /// side-effects allows bundlers to optimize code effectively. - /// - /// ### Examples - /// - /// Examples of **incorrect** code for this rule: - /// ```javascript - /// myGlobal = 17; // Cannot determine side-effects of assignment to global variable - /// const x = { [globalFunction()]: "myString" }; // Cannot determine side-effects of calling global function - /// ``` - /// - /// Examples of **correct** code for this rule: - /// ```javascript - /// const localVar = 17; // Local variable assignment, no global side-effects - /// export default 42; // Pure export with no side-effects - /// ``` - /// - /// ### Options - /// - /// ```json - /// { - /// "rules": { - /// "tree-shaking/no-side-effects-in-initialization": [ - /// 2, - /// { - /// "noSideEffectsWhenCalled": [ - /// // If you want to mark a function call as side-effect free - /// { "function": "Object.freeze" }, - /// { - /// "module": "react", - /// "functions": ["createContext", "createRef"] - /// }, - /// { - /// "module": "zod", - /// "functions": ["array", "string", "nativeEnum", "number", "object", "optional"] - /// }, - /// { - /// "module": "my/local/module", - /// "functions": ["foo", "bar", "baz"] - /// }, - /// // If you want to whitelist all functions of a module - /// { - /// "module": "lodash", - /// "functions": "*" - /// } - /// ] - /// } - /// ] - /// } - /// } - /// ``` - /// - /// ### Magic Comments - /// - /// Besides the configuration, you can also use magic comments to mark a function call as side effect free. - /// - /// By default, imported functions are assumed to have side-effects, unless they are marked with a magic comment: - /// - /// ```js - /// import { /* tree-shaking no-side-effects-when-called */ x } from "./some-file"; - /// x(); - /// ``` - /// - /// `@__PURE__` is also supported: - /// - /// ```js - /// import {x} from "./some-file"; - /// /*@__PURE__*/ x(); - /// ``` - NoSideEffectsInInitialization, - nursery -); - -impl Rule for NoSideEffectsInInitialization { - fn from_configuration(value: serde_json::Value) -> Self { - let mut functions = vec![]; - let mut modules = vec![]; - - if let Value::Array(arr) = value { - for obj in arr { - let Value::Object(obj) = obj else { - continue; - }; - - // { "function": "Object.freeze" } - if let Some(name) = obj.get("function").and_then(Value::as_str) { - functions.push(name.to_string()); - continue; - } - - // { "module": "react", "functions": ["createContext", "createRef"] } - // { "module": "react", "functions": "*" } - if let Some(name) = obj.get("module").and_then(Value::as_str) { - let functions = match obj.get("functions") { - Some(Value::Array(arr)) => { - let val = arr - .iter() - .filter_map(Value::as_str) - .map(String::from) - .collect::>(); - Some(ModuleFunctions::Specific(val)) - } - Some(Value::String(str)) => { - if str == "*" { - Some(ModuleFunctions::All) - } else { - None - } - } - _ => None, - }; - if let Some(functions) = functions { - modules.push(WhitelistModule { name: name.to_string(), functions }); - } - } - } - } - - Self(Box::new(NoSideEffectsInInitiallizationOptions { functions, modules })) - } - - fn run_once(&self, ctx: &LintContext) { - let Some(root) = ctx.nodes().root_node() else { - return; - }; - let AstKind::Program(program) = root.kind() else { unreachable!() }; - let node_listener_options = NodeListenerOptions::new(ctx) - .with_whitelist_functions(&self.functions) - .with_whitelist_modules(&self.modules); - program.report_effects(&node_listener_options); - } -} - -#[test] -fn test() { - use crate::tester::Tester; - - let pass = vec![ - // ArrayExpression - "[]", - "const x = []", - "const x = [ext,ext]", - "const x = [1,,2,]", - // ArrayPattern - "const [x] = []", - "const [,x,] = []", - // ArrowFunctionExpression - "const x = a=>{a(); ext()}", - // ArrowFunctionExpression when called - "(()=>{})()", - "(a=>{})()", - "((...a)=>{})()", - "(({a})=>{})()", - // ArrowFunctionExpression when mutated - "const x = ()=>{}; x.y = 1", - // AssignmentExpression - "var x;x = {}", - "var x;x += 1", - "const x = {}; x.y = 1", - r#"const x = {}; x["y"] = 1"#, - "function x(){this.y = 1}; const z = new x()", - "let x = 1; x = 2 + 3", - "let x; x = 2 + 3", - // AssignmentPattern - "const {x = ext} = {}", - "const {x: y = ext} = {}", - "const {[ext]: x = ext} = {}", - "const x = ()=>{}, {y = x()} = {}", - // BinaryExpression - "const x = 1 + 2", - "if (1-1) ext()", - // BlockStatement - "{}", - "const x = ()=>{};{const x = ext}x()", - "const x = ext;{const x = ()=>{}; x()}", - // BreakStatement - "while(true){break}", - // CallExpression - "(a=>{const y = a})(ext, ext)", - "const x = ()=>{}, y = ()=>{}; x(y())", - // CatchClause - "try {} catch (error) {}", - "const x = ()=>{}; try {} catch (error) {const x = ext}; x()", - "const x = ext; try {} catch (error) {const x = ()=>{}; x()}", - // ClassBody - "class x {a(){ext()}}", - // ClassBody when called - "class x {a(){ext()}}; const y = new x()", - "class x {constructor(){}}; const y = new x()", - "class y{}; class x extends y{}; const z = new x()", - // ClassDeclaration - "class x extends ext {}", - // ClassDeclaration when called - "class x {}; const y = new x()", - // ClassExpression - "const x = class extends ext {}", - // ClassExpression when called - "const x = new (class {})()", - // ClassProperty - "class x {y}", - "class x {y = 1}", - "class x {y = ext()}", - // ConditionalExpression - "const x = ext ? 1 : 2", - "const x = true ? 1 : ext()", - "const x = false ? ext() : 2", - "if (true ? false : true) ext()", - "ext ? 1 : ext.x", - "ext ? ext.x : 1", - // // ConditionalExpression when called - "const x = ()=>{}, y = ()=>{};(ext ? x : y)()", - "const x = ()=>{}; (true ? x : ext)()", - "const x = ()=>{}; (false ? ext : x)()", - // ContinueStatement - "while(true){continue}", - // DoWhileStatement - "do {} while(true)", - "do {} while(ext > 0)", - "const x = ()=>{}; do x(); while(true)", - // EmptyStatement - ";", - // ExportAllDeclaration - r#"export * from "import""#, - // ExportDefaultDeclaration - "export default ext", - "const x = ext; export default x", - "export default function(){}", - "export default (function(){})", - "const x = function(){}; export default /* tree-shaking no-side-effects-when-called */ x", - "export default /* tree-shaking no-side-effects-when-called */ function(){}", - // ExportNamedDeclaration - "export const x = ext", - "export function x(){ext()}", - "const x = ext; export {x}", - r#"export {x} from "import""#, - r#"export {x as y} from "import""#, - r#"export {x as default} from "import""#, - "export const /* tree-shaking no-side-effects-when-called */ x = function(){}", - "export function /* tree-shaking no-side-effects-when-called */ x(){}", - " - { let x = ext; } - let x = () => {} - export {/* tree-shaking no-side-effects-when-called */ x} - ", - "const x = function(){}; export {/* tree-shaking no-side-effects-when-called */ x}", - // ExpressionStatement - "const x = 1", - // ForInStatement - "for(const x in ext){x = 1}", - "let x; for(x in ext){}", - // ForStatement - "for(let i = 0; i < 3; i++){i++}", - "for(;;){}", - // FunctionDeclaration - "function x(a){a(); ext()}", - // FunctionDeclaration when called - "function x(){}; x()", - "function x(a){}; x()", - "function x(...a){}; x()", - "function x({a}){}; x()", - // FunctionDeclaration when mutated - "function x(){}; x.y = 1", - // FunctionExpression - "const x = function (a){a(); ext()}", - // FunctionExpression when called - "(function (){}())", - "(function (a){}())", - "(function (...a){}())", - "(function ({a}){}())", - // Identifier - "var x;x = 1", - // Identifier when called - "const x = ()=>{};x(ext)", - "function x(){};x(ext)", - "var x = ()=>{};x(ext)", - "const x = ()=>{}, y = ()=>{x()}; y()", - "const x = ext, y = ()=>{const x = ()=>{}; x()}; y()", - // Identifier when mutated - "const x = {}; x.y = ext", - // IfStatement - "let y;if (ext > 0) {y = 1} else {y = 2}", - "if (false) {ext()}", - "if (true) {} else {ext()}", - // ImportDeclaration - r#"import "import""#, - r#"import x from "import-default""#, - r#"import {x} from "import""#, - r#"import {x as y} from "import""#, - r#"import * as x from "import""#, - r#"import /* tree-shaking no-side-effects-when-called */ x from "import-default-no-effects"; x()"#, - r#"import /* test */ /*tree-shaking no-side-effects-when-called */ x from "import-default-no-effects"; x()"#, - // TODO: Current only support the comment next to code. - // r#"import /* tree-shaking no-side-effects-when-called*/ /* test */ x from "import-default-no-effects"; x()"#, - r#"import {/* tree-shaking no-side-effects-when-called */ x} from "import-no-effects"; x()"#, - r#"import {x as /* tree-shaking no-side-effects-when-called */ y} from "import-no-effects"; y()"#, - r#"import {x} from "import"; /*@__PURE__*/ x()"#, - r#"import {x} from "import"; /* @__PURE__ */ x()"#, - // JSXAttribute - r#"class X {}; const x = "#, - "class X {}; const x = ", - "class X {}; const x = />", - // JSXElement - "class X {}; const x = ", - "class X {}; const x = Text", - // JSXEmptyExpression - "class X {}; const x = {}", - // JSXExpressionContainer - "class X {}; const x = {3}", - // JSXIdentifier - "class X {}; const x = ", - "const X = class {constructor() {this.x = 1}}; const x = ", - // JSXOpeningElement - "class X {}; const x = ", - "class X {}; const x = ", - r#"class X {}; const x = "#, - // JSXSpreadAttribute - "class X {}; const x = ", - // LabeledStatement - "loop: for(;true;){continue loop}", - // Literal - "const x = 3", - "if (false) ext()", - r#""use strict""#, - // LogicalExpression - "const x = 3 || 4", - "true || ext()", - "false && ext()", - "if (false && false) ext()", - "if (true && false) ext()", - "if (false && true) ext()", - "if (false || false) ext()", - // MemberExpression - "const x = ext.y", - r#"const x = ext["y"]"#, - "let x = ()=>{}; x.y = 1", - // MemberExpression when called - "const x = Object.keys({})", - // MemberExpression when mutated - "const x = {};x.y = ext", - "const x = {y: 1};delete x.y", - // MetaProperty - "function x(){const y = new.target}; x()", - // MethodDefinition - "class x {a(){}}", - "class x {static a(){}}", - // NewExpression - "const x = new (function (){this.x = 1})()", - "function x(){this.y = 1}; const z = new x()", - "/*@__PURE__*/ new ext()", - // ObjectExpression - "const x = {y: ext}", - r#"const x = {["y"]: ext}"#, - "const x = {};x.y = ext", - // ObjectPattern - "const {x} = {}", - "const {[ext]: x} = {}", - // RestElement - "const [...x] = []", - // ReturnStatement - "(()=>{return})()", - "(()=>{return 1})()", - // SequenceExpression - "let x = 1; x++, x++", - "if (ext, false) ext()", - // SwitchCase - "switch(ext){case ext:const x = 1;break;default:}", - // SwitchStatement - "switch(ext){}", - "const x = ()=>{}; switch(ext){case 1:const x = ext}; x()", - "const x = ext; switch(ext){case 1:const x = ()=>{}; x()}", - // TaggedTemplateExpression - "const x = ()=>{}; const y = x``", - // TemplateLiteral - "const x = ``", - "const x = `Literal`", - "const x = `Literal ${ext}`", - r#"const x = ()=>"a"; const y = `Literal ${x()}`"#, - // ThisExpression - "const y = this.x", - // ThisExpression when mutated - "const y = new (function (){this.x = 1})()", - "const y = new (function (){{this.x = 1}})()", - "const y = new (function (){(()=>{this.x = 1})()})()", - "function x(){this.y = 1}; const y = new x()", - // TryStatement - "try {} catch (error) {}", - "try {} finally {}", - "try {} catch (error) {} finally {}", - // UnaryExpression - "!ext", - "const x = {};delete x.y", - r#"const x = {};delete x["y"]"#, - // UpdateExpression - "let x=1;x++", - "const x = {};x.y++", - // VariableDeclaration - "const x = 1", - // VariableDeclarator - "var x, y", - "var x = 1, y = 2", - "const x = 1, y = 2", - "let x = 1, y = 2", - "const {x} = {}", - // WhileStatement - "while(true){}", - "while(ext > 0){}", - "const x = ()=>{}; while(true)x()", - // YieldExpression - "function* x(){const a = yield}; x()", - "function* x(){yield ext}; x()", - // Supports TypeScript nodes - "interface Blub {}", - " - function a() { - a - } - function b() { - b - } - export { - a, - b - } - ", - " - const Comp = () => { -
- -
- } - ", - ]; - - let fail = vec![ - // ArrayExpression - "const x = [ext()]", - "const x = [,,ext(),]", - // ArrayPattern - "const [x = ext()] = []", - "const [,x = ext(),] = []", - // ArrowFunctionExpression when called - "(()=>{ext()})()", - "(({a = ext()})=>{})()", - "(a=>{a()})(ext)", - "((...a)=>{a()})(ext)", - "(({a})=>{a()})(ext)", - "(a=>{a.x = 1})(ext)", - "(a=>{const b = a;b.x = 1})(ext)", - "((...a)=>{a.x = 1})(ext)", - "(({a})=>{a.x = 1})(ext)", - // AssignmentExpression - "ext = 1", - "ext += 1", - "ext.x = 1", - "const x = {};x[ext()] = 1", - "this.x = 1", - // AssignmentPattern - "const {x = ext()} = {}", - "const {y: {x = ext()} = {}} = {}", - // AwaitExpression - "const x = async ()=>{await ext()}; x()", - // // BinaryExpression - "const x = 1 + ext()", - "const x = ext() + 1", - // BlockStatement - "{ext()}", - // "var x=()=>{};{var x=ext}x()", - "var x=ext;{x(); var x=()=>{}}", - // CallExpression - "(()=>{})(ext(), 1)", - "(()=>{})(1, ext())", - // CallExpression when called - "const x = ()=>ext; const y = x(); y()", - // CallExpression when mutated - "const x = ()=>ext; const y = x(); y.z = 1", - // CatchClause - "try {} catch (error) {ext()}", - // TODO: check global function `ext` call when called `x()` in no strict mode - // "var x=()=>{}; try {} catch (error) {var x=ext}; x()", - // ClassBody - "class x {[ext()](){}}", - // ClassBody when called - "class x {constructor(){ext()}}; new x()", - "class x {constructor(){ext()}}; const y = new x()", - "class x extends ext {}; const y = new x()", - "class y {constructor(){ext()}}; class x extends y {}; const z = new x()", - "class y {constructor(){ext()}}; class x extends y {constructor(){super()}}; const z = new x()", - "class y{}; class x extends y{constructor(){super()}}; const z = new x()", - // ClassDeclaration - "class x extends ext() {}", - "class x {[ext()](){}}", - // ClassDeclaration when called - "class x {constructor(){ext()}}; new x()", - "class x {constructor(){ext()}}; const y = new x()", - "class x extends ext {}; const y = new x()", - // ClassExpression - "const x = class extends ext() {}", - "const x = class {[ext()](){}}", - // ClassExpression when called - "new (class {constructor(){ext()}})()", - "const x = new (class {constructor(){ext()}})()", - "const x = new (class extends ext {})()", - // ClassProperty - "class x {[ext()] = 1}", - // ClassProperty when called - "class x {y = ext()}; new x()", - // ConditionalExpression - "const x = ext() ? 1 : 2", - "const x = ext ? ext() : 2", - "const x = ext ? 1 : ext()", - "if (false ? false : true) ext()", - // ConditionalExpression when called - "const x = ()=>{}; (true ? ext : x)()", - "const x = ()=>{}; (false ? x : ext)()", - "const x = ()=>{}; (ext ? x : ext)()", - // DebuggerStatement - "debugger", - // DoWhileStatement - "do {} while(ext())", - "do ext(); while(true)", - "do {ext()} while(true)", - // ExportDefaultDeclaration - "export default ext()", - "export default /* tree-shaking no-side-effects-when-called */ ext", - "const x = ext; export default /* tree-shaking no-side-effects-when-called */ x", - // ExportNamedDeclaration - "export const x = ext()", - "export const /* tree-shaking no-side-effects-when-called */ x = ext", - "export function /* tree-shaking no-side-effects-when-called */ x(){ext()}", - "const x = ext; export {/* tree-shaking no-side-effects-when-called */ x}", - " - { let x = () => {}; } - let x = ext - export {/* tree-shaking no-side-effects-when-called */ x} - ", - // ExpressionStatement - "ext()", - // ForInStatement - "for(ext in {a: 1}){}", - "for(const x in ext()){}", - "for(const x in {a: 1}){ext()}", - "for(const x in {a: 1}) ext()", - // ForOfStatement - "for(ext of {a: 1}){}", - "for(const x of ext()){}", - "for(const x of {a: 1}){ext()}", - "for(const x of {a: 1}) ext()", - // ForStatement - "for(ext();;){}", - "for(;ext();){}", - "for(;true;ext()){}", - "for(;true;) ext()", - "for(;true;){ext()}", - // FunctionDeclaration when called - "function x(){ext()}; x()", - "function x(){ext()}; const y = new x()", - "function x(){ext()}; new x()", - "function x(a = ext()){}; x()", - "function x(a){a()}; x(ext)", - "function x(...a){a()}; x(ext)", - "function x({a}){a()}; x(ext)", - "function x(a){a(); a(); a()}; x(ext)", - "function x(a){a.y = 1}; x(ext)", - "function x(...a){a.y = 1}; x(ext)", - "function x({a}){a.y = 1}; x(ext)", - "function x(a){a.y = 1; a.y = 2; a.y = 3}; x(ext)", - "function x(){ext = 1}; x(); x(); x()", - "function x(){ext = 1}; const y = new x(); y = new x(); y = new x()", - // FunctionExpression when called - "(function (){ext()}())", - "const x = new (function (){ext()})()", - "new (function (){ext()})()", - "(function ({a = ext()}){}())", - "(function (a){a()}(ext))", - "(function (...a){a()}(ext))", - "(function ({a}){a()}(ext))", - "(function (a){a.x = 1}(ext))", - "(function (a){const b = a;b.x = 1}(ext))", - "(function (...a){a.x = 1}(ext))", - "(function ({a}){a.x = 1}(ext))", - // Identifier when called - "ext()", - "const x = ext; x()", - "let x = ()=>{}; x = ext; x()", - // "var x = ()=>{}; var x = ext; x()", - "const x = ()=>{ext()}; x()", - "const x = ()=>{ext = 1}; x(); x(); x()", - // "let x = ()=>{}; const y = ()=>{x()}; x = ext; y()", - // "var x = ()=>{}; const y = ()=>{x()}; var x = ext; y()", - "const x = ()=>{}; const {y} = x(); y()", - "const x = ()=>{}; const [y] = x(); y()", - // // Identifier when mutated - "var x = ext; x.y = 1", - // "var x = {}; x = ext; x.y = 1", - // "var x = {}; var x = ext; x.y = 1", - // "var x = {}; x = ext; x.y = 1; x.y = 1; x.y = 1", - // "const x = {y:ext}; const {y} = x; y.z = 1", - // IfStatement - "if (ext()>0){}", - "if (1>0){ext()}", - "if (1<0){} else {ext()}", - "if (ext>0){ext()} else {ext()}", - // ImportDeclaration - r#"import x from "import-default"; x()"#, - r#"import x from "import-default"; x.z = 1"#, - r#"import {x} from "import"; x()"#, - r#"import {x} from "import"; x.z = 1"#, - r#"import {x as y} from "import"; y()"#, - r#"import {x as y} from "import"; y.a = 1"#, - r#"import * as y from "import"; y.x()"#, - r#"import * as y from "import"; y.x = 1"#, - // JSXAttribute - "class X {}; const x = ", - "class X {}; class Y {constructor(){ext()}}; const x = />", - // JSXElement - "class X {constructor(){ext()}}; const x = ", - "class X {}; const x = {ext()}", - // JSXExpressionContainer - "class X {}; const x = {ext()}", - // JSXIdentifier - "class X {constructor(){ext()}}; const x = ", - "const X = class {constructor(){ext()}}; const x = ", - "const x = ", - // JSXMemberExpression - "const X = {Y: ext}; const x = ", - // JSXOpeningElement - "class X {}; const x = ", - // JSXSpreadAttribute - "class X {}; const x = ", - // LabeledStatement - "loop: for(;true;){ext()}", - // Literal - "if (true) ext()", - // LogicalExpression - "ext() && true", - "true && ext()", - "false || ext()", - "if (true && true) ext()", - "if (false || true) ext()", - "if (true || false) ext()", - "if (true || true) ext()", - // MemberExpression - "const x = {};const y = x[ext()]", - // MemberExpression when called - "ext.x()", - "const x = {}; x.y()", - "const x = ()=>{}; x().y()", - "const Object = {}; const x = Object.keys({})", - "const x = {}; x[ext()]()", - // MemberExpression when mutated - "const x = {y: ext};x.y.z = 1", - "const x = {y:ext};const y = x.y; y.z = 1", - "const x = {y: ext};delete x.y.z", - // MethodDefinition - "class x {static [ext()](){}}", - // NewExpression - "const x = new ext()", - "new ext()", - // ObjectExpression - "const x = {y: ext()}", - r#"const x = {["y"]: ext()}"#, - "const x = {[ext()]: 1}", - // ObjectPattern - "const {[ext()]: x} = {}", - // ReturnStatement - "(()=>{return ext()})()", - // SequenceExpression - "ext(), 1", - "1, ext()", - "if (1, true) ext()", - "if (1, ext) ext()", - // Super when called - "class y {constructor(){ext()}}; class x extends y {constructor(){super()}}; const z = new x()", - "class y{}; class x extends y{constructor(){super(); super.test()}}; const z = new x()", - "class y{}; class x extends y{constructor(){super()}}; const z = new x()", - // SwitchCase - "switch(ext){case ext():}", - "switch(ext){case 1:ext()}", - // SwitchStatement - "switch(ext()){}", - // "var x=()=>{}; switch(ext){case 1:var x=ext}; x()", - // TaggedTemplateExpression - "const x = ext``", - "ext``", - "const x = ()=>{}; const y = x`${ext()}`", - // TemplateLiteral - "const x = `Literal ${ext()}`", - // ThisExpression when mutated - "this.x = 1", - "(()=>{this.x = 1})()", - "(function(){this.x = 1}())", - "const y = new (function (){(function(){this.x = 1}())})()", - "function x(){this.y = 1}; x()", - // ThrowStatement - r#"throw new Error("Hello Error")"#, - // TryStatement - "try {ext()} catch (error) {}", - "try {} finally {ext()}", - // UnaryExpression - "!ext()", - "delete ext.x", - r#"delete ext["x"]"#, - "const x = ()=>{};delete x()", - // UpdateExpression - "ext++", - "const x = {};x[ext()]++", - // VariableDeclaration - "const x = ext()", - // VariableDeclarator - "var x = ext(),y = ext()", - "const x = ext(),y = ext()", - "let x = ext(),y = ext()", - "const {x = ext()} = {}", - // WhileStatement - "while(ext()){}", - "while(true)ext()", - "while(true){ext()}", - // YieldExpression - "function* x(){yield ext()}; x()", - // YieldExpression when called - "function* x(){yield ext()}; x()", - " - function f() { - try { - f(); - } catch(e) { - a.map(v => v + 1); - } - } - f(); - ", - ]; - - // test options - let pass_with_options = vec![ - ( - "Object.freeze({})", - Some(serde_json::json!([ - { "function": "Object.freeze" }, - ])), - ), - ( - "import {createContext, createRef} from 'react'; createContext(); createRef();", - Some(serde_json::json!([ - { "module": "react", "functions": ["createContext", "createRef"] }, - ])), - ), - ( - "import _ from 'lodash'; _.cloneDeep({});", - Some(serde_json::json!([ - { "module": "lodash", "functions": "*" }, - ])), - ), - ( - "import * as React from 'react'; React.createRef();", - Some(serde_json::json!([ - { "module": "react", "functions": "*" }, - ])), - ), - ]; - - let fail_with_options = vec![ - ("Object.freeze({})", None), - ("import {createContext, createRef} from 'react'; createContext(); createRef();", None), - ("import _ from 'lodash'; _.cloneDeep({});", None), - ("import * as React from 'react'; React.createRef();", None), - ]; - - let pass = - pass.into_iter().map(|case| (case, None)).chain(pass_with_options).collect::>(); - - let fail = - fail.into_iter().map(|case| (case, None)).chain(fail_with_options).collect::>(); - - Tester::new(NoSideEffectsInInitialization::NAME, pass, fail).test_and_snapshot(); -} diff --git a/crates/oxc_linter/src/snapshots/adjacent_overload_signatures.snap b/crates/oxc_linter/src/snapshots/adjacent_overload_signatures.snap index e479260d484b3..1e43b227075dc 100644 --- a/crates/oxc_linter/src/snapshots/adjacent_overload_signatures.snap +++ b/crates/oxc_linter/src/snapshots/adjacent_overload_signatures.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(adjacent-overload-signatures): All "foo" signatures should be adjacent. ╭─[adjacent_overload_signatures.tsx:3:18] diff --git a/crates/oxc_linter/src/snapshots/alt_text.snap b/crates/oxc_linter/src/snapshots/alt_text.snap index 8abd61a0da3b7..e577f78693640 100644 --- a/crates/oxc_linter/src/snapshots/alt_text.snap +++ b/crates/oxc_linter/src/snapshots/alt_text.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(alt-text): Missing `alt` attribute. ╭─[alt_text.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/anchor_has_content.snap b/crates/oxc_linter/src/snapshots/anchor_has_content.snap index 1b95f380f53cf..11e218fa7169b 100644 --- a/crates/oxc_linter/src/snapshots/anchor_has_content.snap +++ b/crates/oxc_linter/src/snapshots/anchor_has_content.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(anchor-has-content): Missing accessible content when using `a` elements. ╭─[anchor_has_content.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/anchor_is_valid.snap b/crates/oxc_linter/src/snapshots/anchor_is_valid.snap index 2eb831732ff80..360e07ff3961d 100644 --- a/crates/oxc_linter/src/snapshots/anchor_is_valid.snap +++ b/crates/oxc_linter/src/snapshots/anchor_is_valid.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(anchor-is-valid): Missing `href` attribute for the `a` element. ╭─[anchor_is_valid.tsx:1:2] diff --git a/crates/oxc_linter/src/snapshots/api_keys@aws_access_token.snap b/crates/oxc_linter/src/snapshots/api_keys@aws_access_token.snap index 099f8cfbc8353..65c9da5091aa7 100644 --- a/crates/oxc_linter/src/snapshots/api_keys@aws_access_token.snap +++ b/crates/oxc_linter/src/snapshots/api_keys@aws_access_token.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc-security(api-keys/aws-access-token): Detected an AWS Access Key ID, which may lead to unauthorized access to AWS resources. ╭─[api_keys.tsx:1:11] diff --git a/crates/oxc_linter/src/snapshots/approx_constant.snap b/crates/oxc_linter/src/snapshots/approx_constant.snap index a445efde94f51..9b6675d836b81 100644 --- a/crates/oxc_linter/src/snapshots/approx_constant.snap +++ b/crates/oxc_linter/src/snapshots/approx_constant.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(approx-constant): Approximate value of `PI` found. ╭─[approx_constant.tsx:1:29] diff --git a/crates/oxc_linter/src/snapshots/aria_activedescendant_has_tabindex.snap b/crates/oxc_linter/src/snapshots/aria_activedescendant_has_tabindex.snap index 2a2e9f693ee82..8663b2625a4be 100644 --- a/crates/oxc_linter/src/snapshots/aria_activedescendant_has_tabindex.snap +++ b/crates/oxc_linter/src/snapshots/aria_activedescendant_has_tabindex.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(aria-activedescendant-has-tabindex): Elements with `aria-activedescendant` must be tabbable. ╭─[aria_activedescendant_has_tabindex.tsx:1:2] diff --git a/crates/oxc_linter/src/snapshots/aria_props.snap b/crates/oxc_linter/src/snapshots/aria_props.snap index 2b7a97035c20f..9d0317bcd35a3 100644 --- a/crates/oxc_linter/src/snapshots/aria_props.snap +++ b/crates/oxc_linter/src/snapshots/aria_props.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(aria-props): 'aria-' is not a valid ARIA attribute. ╭─[aria_props.tsx:1:6] diff --git a/crates/oxc_linter/src/snapshots/aria_role.snap b/crates/oxc_linter/src/snapshots/aria_role.snap index d107ef9f5990e..c1c33d5dcea50 100644 --- a/crates/oxc_linter/src/snapshots/aria_role.snap +++ b/crates/oxc_linter/src/snapshots/aria_role.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(aria-role): Elements with ARIA roles must use a valid, non-abstract ARIA role. ╭─[aria_role.tsx:1:11] diff --git a/crates/oxc_linter/src/snapshots/aria_unsupported_elements.snap b/crates/oxc_linter/src/snapshots/aria_unsupported_elements.snap index 9fd930a8a4061..97c79c7a285e8 100644 --- a/crates/oxc_linter/src/snapshots/aria_unsupported_elements.snap +++ b/crates/oxc_linter/src/snapshots/aria_unsupported_elements.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(aria-unsupported-elements): This element does not support ARIA roles, states and properties. ╭─[aria_unsupported_elements.tsx:1:7] diff --git a/crates/oxc_linter/src/snapshots/array_callback_return.snap b/crates/oxc_linter/src/snapshots/array_callback_return.snap index 6d2c209de3e9f..9c70c9abb1408 100644 --- a/crates/oxc_linter/src/snapshots/array_callback_return.snap +++ b/crates/oxc_linter/src/snapshots/array_callback_return.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(array-callback-return): Missing return on some path for array method "Array.from" ╭─[array_callback_return.tsx:1:26] diff --git a/crates/oxc_linter/src/snapshots/array_type.snap b/crates/oxc_linter/src/snapshots/array_type.snap index 13be26fb6c1f6..c4fec3865f49d 100644 --- a/crates/oxc_linter/src/snapshots/array_type.snap +++ b/crates/oxc_linter/src/snapshots/array_type.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'number[]' instead. ╭─[array_type.tsx:1:8] diff --git a/crates/oxc_linter/src/snapshots/autocomplete_valid.snap b/crates/oxc_linter/src/snapshots/autocomplete_valid.snap index 57c5204304a46..66cd850e8a002 100644 --- a/crates/oxc_linter/src/snapshots/autocomplete_valid.snap +++ b/crates/oxc_linter/src/snapshots/autocomplete_valid.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(autocomplete-valid): `foo` is not a valid value for autocomplete. ╭─[autocomplete_valid.tsx:1:20] diff --git a/crates/oxc_linter/src/snapshots/avoid_new.snap b/crates/oxc_linter/src/snapshots/avoid_new.snap index d023f7b19141d..a84e8cd3ec6bf 100644 --- a/crates/oxc_linter/src/snapshots/avoid_new.snap +++ b/crates/oxc_linter/src/snapshots/avoid_new.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-promise(avoid-new): Avoid creating new promises ╭─[avoid_new.tsx:1:9] diff --git a/crates/oxc_linter/src/snapshots/bad_array_method_on_arguments.snap b/crates/oxc_linter/src/snapshots/bad_array_method_on_arguments.snap index e028d76fc91ef..df0f80c6bcf38 100644 --- a/crates/oxc_linter/src/snapshots/bad_array_method_on_arguments.snap +++ b/crates/oxc_linter/src/snapshots/bad_array_method_on_arguments.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-array-method-on-arguments): Bad array method on arguments ╭─[bad_array_method_on_arguments.tsx:1:16] diff --git a/crates/oxc_linter/src/snapshots/bad_bitwise_operator.snap b/crates/oxc_linter/src/snapshots/bad_bitwise_operator.snap index e7f5ec0fd2306..c1dc5522cf656 100644 --- a/crates/oxc_linter/src/snapshots/bad_bitwise_operator.snap +++ b/crates/oxc_linter/src/snapshots/bad_bitwise_operator.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-bitwise-operator): Bad bitwise operator ╭─[bad_bitwise_operator.tsx:1:9] diff --git a/crates/oxc_linter/src/snapshots/bad_char_at_comparison.snap b/crates/oxc_linter/src/snapshots/bad_char_at_comparison.snap index 50b0e2e794bea..8d747338313dc 100644 --- a/crates/oxc_linter/src/snapshots/bad_char_at_comparison.snap +++ b/crates/oxc_linter/src/snapshots/bad_char_at_comparison.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-char-at-comparison): Invalid comparison with `charAt` method ╭─[bad_char_at_comparison.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/bad_comparison_sequence.snap b/crates/oxc_linter/src/snapshots/bad_comparison_sequence.snap index 7b1097b4d4ad7..b08afd5b1b1aa 100644 --- a/crates/oxc_linter/src/snapshots/bad_comparison_sequence.snap +++ b/crates/oxc_linter/src/snapshots/bad_comparison_sequence.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-comparison-sequence): Bad comparison sequence ╭─[bad_comparison_sequence.tsx:1:5] diff --git a/crates/oxc_linter/src/snapshots/bad_min_max_func.snap b/crates/oxc_linter/src/snapshots/bad_min_max_func.snap index 2ac4bf34cdeb8..94fc63ff1356f 100644 --- a/crates/oxc_linter/src/snapshots/bad_min_max_func.snap +++ b/crates/oxc_linter/src/snapshots/bad_min_max_func.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-min-max-func): Math.min and Math.max combination leads to constant result ╭─[bad_min_max_func.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/bad_object_literal_comparison.snap b/crates/oxc_linter/src/snapshots/bad_object_literal_comparison.snap index 0a97b36c0523c..32fb8def65849 100644 --- a/crates/oxc_linter/src/snapshots/bad_object_literal_comparison.snap +++ b/crates/oxc_linter/src/snapshots/bad_object_literal_comparison.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-object-literal-comparison): Unexpected object literal comparison. ╭─[bad_object_literal_comparison.tsx:1:5] diff --git a/crates/oxc_linter/src/snapshots/bad_replace_all_arg.snap b/crates/oxc_linter/src/snapshots/bad_replace_all_arg.snap index acd18e36c06ed..255783a83e350 100644 --- a/crates/oxc_linter/src/snapshots/bad_replace_all_arg.snap +++ b/crates/oxc_linter/src/snapshots/bad_replace_all_arg.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(bad-replace-all-arg): Global flag (g) is missing in the regular expression supplied to the `replaceAll` method. ╭─[bad_replace_all_arg.tsx:1:12] diff --git a/crates/oxc_linter/src/snapshots/ban_ts_comment.snap b/crates/oxc_linter/src/snapshots/ban_ts_comment.snap index db4d8272c03e6..03269d05e8e18 100644 --- a/crates/oxc_linter/src/snapshots/ban_ts_comment.snap +++ b/crates/oxc_linter/src/snapshots/ban_ts_comment.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(ban-ts-comment): Do not use @ts-expect-error because it alters compilation errors. ╭─[ban_ts_comment.tsx:1:3] diff --git a/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap b/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap index a0f87008fe826..e2b56bbd6d84d 100644 --- a/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap +++ b/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable" ╭─[ban_tslint_comment.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/ban_types.snap b/crates/oxc_linter/src/snapshots/ban_types.snap index 241168cb006a6..04124ce7af496 100644 --- a/crates/oxc_linter/src/snapshots/ban_types.snap +++ b/crates/oxc_linter/src/snapshots/ban_types.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(ban-types): Do not use "String" as a type. Use "string" instead ╭─[ban_types.tsx:1:8] diff --git a/crates/oxc_linter/src/snapshots/button_has_type.snap b/crates/oxc_linter/src/snapshots/button_has_type.snap index a42f06e32ab1a..84e35b62a4aca 100644 --- a/crates/oxc_linter/src/snapshots/button_has_type.snap +++ b/crates/oxc_linter/src/snapshots/button_has_type.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(button-has-type): `button` elements must have an explicit `type` attribute. ╭─[button_has_type.tsx:1:2] diff --git a/crates/oxc_linter/src/snapshots/catch_error_name.snap b/crates/oxc_linter/src/snapshots/catch_error_name.snap index 8d20046cae372..8ae65a0df4920 100644 --- a/crates/oxc_linter/src/snapshots/catch_error_name.snap +++ b/crates/oxc_linter/src/snapshots/catch_error_name.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(catch-error-name): The catch parameter "descriptiveError" should be named "exception" ╭─[catch_error_name.tsx:1:16] diff --git a/crates/oxc_linter/src/snapshots/catch_or_return.snap b/crates/oxc_linter/src/snapshots/catch_or_return.snap index 279b77ebe3813..99fb2191895b7 100644 --- a/crates/oxc_linter/src/snapshots/catch_or_return.snap +++ b/crates/oxc_linter/src/snapshots/catch_or_return.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-promise(catch-or-return): eslint-plugin-promise(catch-or-return): Expected catch or return ╭─[catch_or_return.tsx:1:37] diff --git a/crates/oxc_linter/src/snapshots/check_access.snap b/crates/oxc_linter/src/snapshots/check_access.snap index 3dfb116c11ed0..eee127a65aac6 100644 --- a/crates/oxc_linter/src/snapshots/check_access.snap +++ b/crates/oxc_linter/src/snapshots/check_access.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsdoc(check-access): Invalid access level is specified or missing. ╭─[check_access.tsx:3:25] diff --git a/crates/oxc_linter/src/snapshots/check_property_names.snap b/crates/oxc_linter/src/snapshots/check_property_names.snap index 3feab86da4fd3..ff2b2043374a3 100644 --- a/crates/oxc_linter/src/snapshots/check_property_names.snap +++ b/crates/oxc_linter/src/snapshots/check_property_names.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsdoc(check-property-names): No root defined for @property path. ╭─[check_property_names.tsx:4:27] diff --git a/crates/oxc_linter/src/snapshots/check_tag_names.snap b/crates/oxc_linter/src/snapshots/check_tag_names.snap index 230be91090cbb..c0a668ca18a00 100644 --- a/crates/oxc_linter/src/snapshots/check_tag_names.snap +++ b/crates/oxc_linter/src/snapshots/check_tag_names.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsdoc(check-tag-names): Invalid tag name found. ╭─[check_tag_names.tsx:2:24] diff --git a/crates/oxc_linter/src/snapshots/checked_requires_onchange_or_readonly.snap b/crates/oxc_linter/src/snapshots/checked_requires_onchange_or_readonly.snap index 9e4284fd0d950..2205f0abaf707 100644 --- a/crates/oxc_linter/src/snapshots/checked_requires_onchange_or_readonly.snap +++ b/crates/oxc_linter/src/snapshots/checked_requires_onchange_or_readonly.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(checked-requires-onchange-or-readonly): `checked` should be used with either `onChange` or `readOnly`. ╭─[checked_requires_onchange_or_readonly.tsx:1:21] diff --git a/crates/oxc_linter/src/snapshots/click_events_have_key_events.snap b/crates/oxc_linter/src/snapshots/click_events_have_key_events.snap index cafa8776febf4..9d02284a18bcc 100644 --- a/crates/oxc_linter/src/snapshots/click_events_have_key_events.snap +++ b/crates/oxc_linter/src/snapshots/click_events_have_key_events.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(click-events-have-key-events): Enforce a clickable non-interactive element has at least one keyboard event listener. ╭─[click_events_have_key_events.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/consistent_empty_array_spread.snap b/crates/oxc_linter/src/snapshots/consistent_empty_array_spread.snap index c9895f9863cc4..664933dec4b51 100644 --- a/crates/oxc_linter/src/snapshots/consistent_empty_array_spread.snap +++ b/crates/oxc_linter/src/snapshots/consistent_empty_array_spread.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(consistent-empty-array-spread): Prefer consistent types when spreading a ternary in an array literal. ╭─[consistent_empty_array_spread.tsx:1:24] diff --git a/crates/oxc_linter/src/snapshots/consistent_function_scoping.snap b/crates/oxc_linter/src/snapshots/consistent_function_scoping.snap index c449ccf26bb06..50b5406e32937 100644 --- a/crates/oxc_linter/src/snapshots/consistent_function_scoping.snap +++ b/crates/oxc_linter/src/snapshots/consistent_function_scoping.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(consistent-function-scoping): Function does not capture any variables from the outer scope. ╭─[consistent_function_scoping.tsx:3:30] diff --git a/crates/oxc_linter/src/snapshots/consistent_indexed_object_style.snap b/crates/oxc_linter/src/snapshots/consistent_indexed_object_style.snap index ff5ce7b7ae11e..f33ef8da85354 100644 --- a/crates/oxc_linter/src/snapshots/consistent_indexed_object_style.snap +++ b/crates/oxc_linter/src/snapshots/consistent_indexed_object_style.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(consistent-indexed-object-style): A record is preferred over an index signature. ╭─[consistent_indexed_object_style.tsx:3:12] diff --git a/crates/oxc_linter/src/snapshots/consistent_test_it.snap b/crates/oxc_linter/src/snapshots/consistent_test_it.snap index 1a71f34cdbe6d..8b05ea5c841b9 100644 --- a/crates/oxc_linter/src/snapshots/consistent_test_it.snap +++ b/crates/oxc_linter/src/snapshots/consistent_test_it.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-vitest(consistent-test-it): Enforce `test` and `it` usage conventions ╭─[consistent_test_it.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/consistent_type_definitions.snap b/crates/oxc_linter/src/snapshots/consistent_type_definitions.snap index caf9a49362022..5f6cf6ab08e97 100644 --- a/crates/oxc_linter/src/snapshots/consistent_type_definitions.snap +++ b/crates/oxc_linter/src/snapshots/consistent_type_definitions.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(consistent-type-definitions): Use an `interface` instead of a `type` ╭─[consistent_type_definitions.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/consistent_type_imports.snap b/crates/oxc_linter/src/snapshots/consistent_type_imports.snap index d3333cd4f9d8b..bed9424ce5ba9 100644 --- a/crates/oxc_linter/src/snapshots/consistent_type_imports.snap +++ b/crates/oxc_linter/src/snapshots/consistent_type_imports.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(consistent-type-imports): All imports in the declaration are only used as types. Use `import type`. ╭─[consistent_type_imports.tsx:2:15] diff --git a/crates/oxc_linter/src/snapshots/const_comparisons.snap b/crates/oxc_linter/src/snapshots/const_comparisons.snap index c392521e2a700..0a2c19fcd1fc9 100644 --- a/crates/oxc_linter/src/snapshots/const_comparisons.snap +++ b/crates/oxc_linter/src/snapshots/const_comparisons.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(const-comparisons): Unexpected constant comparison ╭─[const_comparisons.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/constructor_super.snap b/crates/oxc_linter/src/snapshots/constructor_super.snap index 2adf1447d2f84..03f218bf6f1cb 100644 --- a/crates/oxc_linter/src/snapshots/constructor_super.snap +++ b/crates/oxc_linter/src/snapshots/constructor_super.snap @@ -1,4 +1,5 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- diff --git a/crates/oxc_linter/src/snapshots/default.snap b/crates/oxc_linter/src/snapshots/default.snap index b85cc3452c597..ee9154a502a84 100644 --- a/crates/oxc_linter/src/snapshots/default.snap +++ b/crates/oxc_linter/src/snapshots/default.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-import(default): No default export found in imported module "./named-exports" ╭─[index.js:1:8] diff --git a/crates/oxc_linter/src/snapshots/default_case.snap b/crates/oxc_linter/src/snapshots/default_case.snap index 6144661844a54..0f3c5143449e1 100644 --- a/crates/oxc_linter/src/snapshots/default_case.snap +++ b/crates/oxc_linter/src/snapshots/default_case.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(default-case): Require default cases in switch statements. ╭─[default_case.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/default_case_last.snap b/crates/oxc_linter/src/snapshots/default_case_last.snap index cb2665ea19f62..1e991b83dc88f 100644 --- a/crates/oxc_linter/src/snapshots/default_case_last.snap +++ b/crates/oxc_linter/src/snapshots/default_case_last.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(default-case-last): Enforce default clauses in switch statements to be last ╭─[default_case_last.tsx:1:16] diff --git a/crates/oxc_linter/src/snapshots/default_param_last.snap b/crates/oxc_linter/src/snapshots/default_param_last.snap index 238a8dbec65d1..c0cd80f8183dd 100644 --- a/crates/oxc_linter/src/snapshots/default_param_last.snap +++ b/crates/oxc_linter/src/snapshots/default_param_last.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(default-param-last): Default parameters should be last ╭─[default_param_last.tsx:1:12] diff --git a/crates/oxc_linter/src/snapshots/double_comparisons.snap b/crates/oxc_linter/src/snapshots/double_comparisons.snap index 237b72f92c3f5..061094be4d11d 100644 --- a/crates/oxc_linter/src/snapshots/double_comparisons.snap +++ b/crates/oxc_linter/src/snapshots/double_comparisons.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(double-comparisons): Unexpected double comparisons. ╭─[double_comparisons.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/empty_brace_spaces.snap b/crates/oxc_linter/src/snapshots/empty_brace_spaces.snap index c17528fcbfc00..3717b95fa29f6 100644 --- a/crates/oxc_linter/src/snapshots/empty_brace_spaces.snap +++ b/crates/oxc_linter/src/snapshots/empty_brace_spaces.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(empty-brace-spaces): No spaces inside empty pair of braces allowed ╭─[empty_brace_spaces.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/empty_tags.snap b/crates/oxc_linter/src/snapshots/empty_tags.snap index 95966dd47223c..f573002336a8e 100644 --- a/crates/oxc_linter/src/snapshots/empty_tags.snap +++ b/crates/oxc_linter/src/snapshots/empty_tags.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsdoc(empty-tags): Expects the void tags to be empty of any content. ╭─[empty_tags.tsx:3:27] diff --git a/crates/oxc_linter/src/snapshots/eqeqeq.snap b/crates/oxc_linter/src/snapshots/eqeqeq.snap index 5c9da273e6251..7bd4eb8cf98d3 100644 --- a/crates/oxc_linter/src/snapshots/eqeqeq.snap +++ b/crates/oxc_linter/src/snapshots/eqeqeq.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(eqeqeq): Expected > and instead saw >= ╭─[eqeqeq.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/erasing_op.snap b/crates/oxc_linter/src/snapshots/erasing_op.snap index 553cff506667b..daa994246381c 100644 --- a/crates/oxc_linter/src/snapshots/erasing_op.snap +++ b/crates/oxc_linter/src/snapshots/erasing_op.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ oxc(erasing-op): Unexpected erasing operation. This expression will always evaluate to zero. ╭─[erasing_op.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/error_message.snap b/crates/oxc_linter/src/snapshots/error_message.snap index abed373adc43b..a73a63e911562 100644 --- a/crates/oxc_linter/src/snapshots/error_message.snap +++ b/crates/oxc_linter/src/snapshots/error_message.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(error-message): Pass a message to the Error constructor. ╭─[error_message.tsx:1:7] diff --git a/crates/oxc_linter/src/snapshots/escape_case.snap b/crates/oxc_linter/src/snapshots/escape_case.snap index 2d57ac5467eb4..34a4aae059ee2 100644 --- a/crates/oxc_linter/src/snapshots/escape_case.snap +++ b/crates/oxc_linter/src/snapshots/escape_case.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:13] diff --git a/crates/oxc_linter/src/snapshots/exhaustive_deps.snap b/crates/oxc_linter/src/snapshots/exhaustive_deps.snap index 12bc5b2b3644d..6be9889e18f36 100644 --- a/crates/oxc_linter/src/snapshots/exhaustive_deps.snap +++ b/crates/oxc_linter/src/snapshots/exhaustive_deps.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react-hooks(exhaustive-deps): React Hook useCallback has a missing dependency: 'props.foo.toString' ╭─[exhaustive_deps.tsx:4:14] diff --git a/crates/oxc_linter/src/snapshots/expect_expect.snap b/crates/oxc_linter/src/snapshots/expect_expect.snap index 9546945ba3e3a..0d55db374536d 100644 --- a/crates/oxc_linter/src/snapshots/expect_expect.snap +++ b/crates/oxc_linter/src/snapshots/expect_expect.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-vitest(expect-expect): Test has no assertions ╭─[expect_expect.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/explicit_function_return_type.snap b/crates/oxc_linter/src/snapshots/explicit_function_return_type.snap index 8db941e370cc4..ed17312b109dc 100644 --- a/crates/oxc_linter/src/snapshots/explicit_function_return_type.snap +++ b/crates/oxc_linter/src/snapshots/explicit_function_return_type.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ typescript-eslint(explicit-function-return-type): Missing return type on function. ╭─[explicit_function_return_type.tsx:2:10] diff --git a/crates/oxc_linter/src/snapshots/explicit_length_check.snap b/crates/oxc_linter/src/snapshots/explicit_length_check.snap index e3fb1306b7791..47636f49ed6e6 100644 --- a/crates/oxc_linter/src/snapshots/explicit_length_check.snap +++ b/crates/oxc_linter/src/snapshots/explicit_length_check.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(explicit-length-check): Use `.length > 0` when checking length is not zero. ╭─[explicit_length_check.tsx:1:11] diff --git a/crates/oxc_linter/src/snapshots/export.snap b/crates/oxc_linter/src/snapshots/export.snap index ab121c635b966..6df1bdc54aa42 100644 --- a/crates/oxc_linter/src/snapshots/export.snap +++ b/crates/oxc_linter/src/snapshots/export.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-import(export): Multiple exports of name 'foo'. ╭─[index.ts:1:19] diff --git a/crates/oxc_linter/src/snapshots/filename_case.snap b/crates/oxc_linter/src/snapshots/filename_case.snap index 283b383a9096b..f878e421f06c9 100644 --- a/crates/oxc_linter/src/snapshots/filename_case.snap +++ b/crates/oxc_linter/src/snapshots/filename_case.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-unicorn(filename-case): Filename should be in kebab case ╭─[filename_case.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/first.snap b/crates/oxc_linter/src/snapshots/first.snap index 3b0cc6fed1a6b..3c53ebe2ff302 100644 --- a/crates/oxc_linter/src/snapshots/first.snap +++ b/crates/oxc_linter/src/snapshots/first.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-import(first): Import statements must come first ╭─[index.ts:3:15] diff --git a/crates/oxc_linter/src/snapshots/for_direction.snap b/crates/oxc_linter/src/snapshots/for_direction.snap index 3daf0e7b89930..ae6a3a2a100b0 100644 --- a/crates/oxc_linter/src/snapshots/for_direction.snap +++ b/crates/oxc_linter/src/snapshots/for_direction.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(for-direction): The update clause in this loop moves the variable in the wrong direction ╭─[for_direction.tsx:1:17] diff --git a/crates/oxc_linter/src/snapshots/func_names.snap b/crates/oxc_linter/src/snapshots/func_names.snap index 7431077940895..346c0e52aab57 100644 --- a/crates/oxc_linter/src/snapshots/func_names.snap +++ b/crates/oxc_linter/src/snapshots/func_names.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(func-names): Unexpected unnamed function. ╭─[func_names.tsx:1:21] diff --git a/crates/oxc_linter/src/snapshots/getter_return.snap b/crates/oxc_linter/src/snapshots/getter_return.snap index 088647bfad4a6..b290f39a4ae25 100644 --- a/crates/oxc_linter/src/snapshots/getter_return.snap +++ b/crates/oxc_linter/src/snapshots/getter_return.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(getter-return): Expected to always return a value in getter. ╭─[getter_return.js:1:20] diff --git a/crates/oxc_linter/src/snapshots/google_font_display.snap b/crates/oxc_linter/src/snapshots/google_font_display.snap index 503e15679202c..8014f7b968292 100644 --- a/crates/oxc_linter/src/snapshots/google_font_display.snap +++ b/crates/oxc_linter/src/snapshots/google_font_display.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-next(google-font-display): A font-display parameter is missing (adding `&display=optional` is recommended). ╭─[google_font_display.tsx:6:7] diff --git a/crates/oxc_linter/src/snapshots/google_font_preconnect.snap b/crates/oxc_linter/src/snapshots/google_font_preconnect.snap index 4d2179090b4dd..de31bb1b3f35d 100644 --- a/crates/oxc_linter/src/snapshots/google_font_preconnect.snap +++ b/crates/oxc_linter/src/snapshots/google_font_preconnect.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-next(google-font-preconnect): `rel="preconnect"` is missing from Google Font. ╭─[google_font_preconnect.tsx:4:15] diff --git a/crates/oxc_linter/src/snapshots/guard_for_in.snap b/crates/oxc_linter/src/snapshots/guard_for_in.snap index e8d1a0a92fbb5..7180608298e4a 100644 --- a/crates/oxc_linter/src/snapshots/guard_for_in.snap +++ b/crates/oxc_linter/src/snapshots/guard_for_in.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(guard-for-in): Require `for-in` loops to include an `if` statement ╭─[guard_for_in.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/heading_has_content.snap b/crates/oxc_linter/src/snapshots/heading_has_content.snap index b963e03a91066..d27ecd7d878e9 100644 --- a/crates/oxc_linter/src/snapshots/heading_has_content.snap +++ b/crates/oxc_linter/src/snapshots/heading_has_content.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(heading-has-content): Headings must have content and the content must be accessible by a screen reader. ╭─[heading_has_content.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/html_has_lang.snap b/crates/oxc_linter/src/snapshots/html_has_lang.snap index 2337ea66fe8e1..c5a60e5f83ab7 100644 --- a/crates/oxc_linter/src/snapshots/html_has_lang.snap +++ b/crates/oxc_linter/src/snapshots/html_has_lang.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(html-has-lang): Missing lang attribute. ╭─[html_has_lang.tsx:1:2] diff --git a/crates/oxc_linter/src/snapshots/iframe_has_title.snap b/crates/oxc_linter/src/snapshots/iframe_has_title.snap index 652503ce7b7da..487208f9e1d82 100644 --- a/crates/oxc_linter/src/snapshots/iframe_has_title.snap +++ b/crates/oxc_linter/src/snapshots/iframe_has_title.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(iframe-has-title): Missing `title` attribute for the `iframe` element. ╭─[iframe_has_title.tsx:1:2] diff --git a/crates/oxc_linter/src/snapshots/iframe_missing_sandbox.snap b/crates/oxc_linter/src/snapshots/iframe_missing_sandbox.snap index 5020fd10abae0..f414c95a88a8e 100644 --- a/crates/oxc_linter/src/snapshots/iframe_missing_sandbox.snap +++ b/crates/oxc_linter/src/snapshots/iframe_missing_sandbox.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(iframe-missing-sandbox): An iframe element is missing a sandbox attribute ╭─[iframe_missing_sandbox.tsx:1:2] diff --git a/crates/oxc_linter/src/snapshots/img_redundant_alt.snap b/crates/oxc_linter/src/snapshots/img_redundant_alt.snap index bdbc7736b21a2..a58f65cdd8327 100644 --- a/crates/oxc_linter/src/snapshots/img_redundant_alt.snap +++ b/crates/oxc_linter/src/snapshots/img_redundant_alt.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(img-redundant-alt): Redundant alt attribute. ╭─[img_redundant_alt.tsx:1:6] diff --git a/crates/oxc_linter/src/snapshots/implements_on_classes.snap b/crates/oxc_linter/src/snapshots/implements_on_classes.snap index 77a2cbf0a1345..147c1f099f89b 100644 --- a/crates/oxc_linter/src/snapshots/implements_on_classes.snap +++ b/crates/oxc_linter/src/snapshots/implements_on_classes.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsdoc(implements-on-classes): `@implements` used on a non-constructor function ╭─[implements_on_classes.tsx:3:13] diff --git a/crates/oxc_linter/src/snapshots/import_no_namespace.snap b/crates/oxc_linter/src/snapshots/import_no_namespace.snap index af3286c677717..e14e1a57c37e4 100644 --- a/crates/oxc_linter/src/snapshots/import_no_namespace.snap +++ b/crates/oxc_linter/src/snapshots/import_no_namespace.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-import(import-no-namespace): Usage of namespaced aka wildcard "*" imports prohibited ╭─[index.js:1:13] diff --git a/crates/oxc_linter/src/snapshots/inline_script_id.snap b/crates/oxc_linter/src/snapshots/inline_script_id.snap index 357b786421f82..e4b6e3a044836 100644 --- a/crates/oxc_linter/src/snapshots/inline_script_id.snap +++ b/crates/oxc_linter/src/snapshots/inline_script_id.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-next(inline-script-id): `next/script` components with inline content must specify an `id` attribute. ╭─[inline_script_id.tsx:5:17] diff --git a/crates/oxc_linter/src/snapshots/jsx_boolean_value.snap b/crates/oxc_linter/src/snapshots/jsx_boolean_value.snap index 46bf714d8bfea..bf8a2dfc79769 100644 --- a/crates/oxc_linter/src/snapshots/jsx_boolean_value.snap +++ b/crates/oxc_linter/src/snapshots/jsx_boolean_value.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-boolean-value): Value must be omitted for boolean attribute "foo" ╭─[jsx_boolean_value.tsx:1:9] diff --git a/crates/oxc_linter/src/snapshots/jsx_curly_brace_presence.snap b/crates/oxc_linter/src/snapshots/jsx_curly_brace_presence.snap index 9d38b5b3e2856..b940ef90a1cd3 100644 --- a/crates/oxc_linter/src/snapshots/jsx_curly_brace_presence.snap +++ b/crates/oxc_linter/src/snapshots/jsx_curly_brace_presence.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-curly-brace-presence): Curly braces are unnecessary here. ╭─[jsx_curly_brace_presence.tsx:1:12] diff --git a/crates/oxc_linter/src/snapshots/jsx_key.snap b/crates/oxc_linter/src/snapshots/jsx_key.snap index 62f40cb899dca..e991b8c1c8a95 100644 --- a/crates/oxc_linter/src/snapshots/jsx_key.snap +++ b/crates/oxc_linter/src/snapshots/jsx_key.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-key): Missing "key" prop for element in array. ╭─[jsx_key.tsx:1:3] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_comment_textnodes.snap b/crates/oxc_linter/src/snapshots/jsx_no_comment_textnodes.snap index 6ffab88506555..8eb2797c87478 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_comment_textnodes.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_comment_textnodes.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-no-comment-textnodes): Comments inside children section of tag should be placed inside braces ╭─[jsx_no_comment_textnodes.tsx:4:29] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_duplicate_props.snap b/crates/oxc_linter/src/snapshots/jsx_no_duplicate_props.snap index a4e1417ac8098..a6ccdc1294d84 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_duplicate_props.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_duplicate_props.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-no-duplicate-props): No duplicate props allowed. The prop "a" is duplicated. ╭─[jsx_no_duplicate_props.tsx:1:6] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_jsx_as_prop.snap b/crates/oxc_linter/src/snapshots/jsx_no_jsx_as_prop.snap index 7f25083157cea..7398e3a45e004 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_jsx_as_prop.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_jsx_as_prop.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react-perf(jsx-no-jsx-as-prop): JSX attribute values should not contain other JSX. ╭─[jsx_no_jsx_as_prop.tsx:1:31] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_new_array_as_prop.snap b/crates/oxc_linter/src/snapshots/jsx_no_new_array_as_prop.snap index 3841422ccfb52..08d263bf240d2 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_new_array_as_prop.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_new_array_as_prop.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react-perf(jsx-no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope. ╭─[jsx_no_new_array_as_prop.tsx:1:32] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_new_function_as_prop.snap b/crates/oxc_linter/src/snapshots/jsx_no_new_function_as_prop.snap index 7ad4ce7042703..8ca86c7fa9aa4 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_new_function_as_prop.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_new_function_as_prop.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react-perf(jsx-no-new-function-as-prop): JSX attribute values should not contain functions created in the same scope. ╭─[jsx_no_new_function_as_prop.tsx:1:32] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_new_object_as_prop.snap b/crates/oxc_linter/src/snapshots/jsx_no_new_object_as_prop.snap index cbfe2e3f935b6..81b73ce70284b 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_new_object_as_prop.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_new_object_as_prop.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react-perf(jsx-no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope. ╭─[jsx_no_new_object_as_prop.tsx:1:33] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_target_blank.snap b/crates/oxc_linter/src/snapshots/jsx_no_target_blank.snap index 1ddef52dc8024..fe76d9cedc35b 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_target_blank.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_target_blank.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-no-target-blank): Using target=`_blank` without rel=`noreferrer` (which implies rel=`noopener`) is a security risk in older browsers: see https://mathiasbynens.github.io/rel-noopener/#recommendations ╭─[jsx_no_target_blank.tsx:1:11] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_undef.snap b/crates/oxc_linter/src/snapshots/jsx_no_undef.snap index 35bff1978aac6..5ac8fd34a17f0 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_undef.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_undef.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-no-undef): 'App' is not defined. ╭─[jsx_no_undef.tsx:1:26] diff --git a/crates/oxc_linter/src/snapshots/jsx_no_useless_fragment.snap b/crates/oxc_linter/src/snapshots/jsx_no_useless_fragment.snap index e3c2166139d0f..e2cc4df814c25 100644 --- a/crates/oxc_linter/src/snapshots/jsx_no_useless_fragment.snap +++ b/crates/oxc_linter/src/snapshots/jsx_no_useless_fragment.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-no-useless-fragment): Fragments should contain more than one child. ╭─[jsx_no_useless_fragment.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap b/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap index 8d3c78bec993a..020a53299a725 100644 --- a/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap +++ b/crates/oxc_linter/src/snapshots/jsx_props_no_spread_multi.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-react(jsx-props-no-spread-multi): Prop 'props' is spread multiple times. ╭─[jsx_props_no_spread_multi.tsx:3:16] diff --git a/crates/oxc_linter/src/snapshots/label_has_associated_control.snap b/crates/oxc_linter/src/snapshots/label_has_associated_control.snap index cb40285f0a682..d1d6c78b40ff8 100644 --- a/crates/oxc_linter/src/snapshots/label_has_associated_control.snap +++ b/crates/oxc_linter/src/snapshots/label_has_associated_control.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(label-has-associated-control): A form label must be associated with a control. ╭─[label_has_associated_control.tsx:1:1] diff --git a/crates/oxc_linter/src/snapshots/lang.snap b/crates/oxc_linter/src/snapshots/lang.snap index 9bc271ccb1310..d55ecb18bf2e3 100644 --- a/crates/oxc_linter/src/snapshots/lang.snap +++ b/crates/oxc_linter/src/snapshots/lang.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(lang): Lang attribute must have a valid value. ╭─[lang.tsx:1:7] diff --git a/crates/oxc_linter/src/snapshots/max_classes_per_file.snap b/crates/oxc_linter/src/snapshots/max_classes_per_file.snap index 64347a20cfdf9..4cbd4d776bca7 100644 --- a/crates/oxc_linter/src/snapshots/max_classes_per_file.snap +++ b/crates/oxc_linter/src/snapshots/max_classes_per_file.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(max-classes-per-file): File has too many classes (2). Maximum allowed is 1 ╭─[max_classes_per_file.tsx:2:4] diff --git a/crates/oxc_linter/src/snapshots/max_dependencies.snap b/crates/oxc_linter/src/snapshots/max_dependencies.snap index b545e447e5cfe..096a7d4edaee2 100644 --- a/crates/oxc_linter/src/snapshots/max_dependencies.snap +++ b/crates/oxc_linter/src/snapshots/max_dependencies.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-import(max-dependencies): File has too many dependencies (3). Maximum allowed is 1. ╭─[index.ts:3:31] diff --git a/crates/oxc_linter/src/snapshots/max_expects.snap b/crates/oxc_linter/src/snapshots/max_expects.snap index 1ff98d0a38c55..5f94658280d39 100644 --- a/crates/oxc_linter/src/snapshots/max_expects.snap +++ b/crates/oxc_linter/src/snapshots/max_expects.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jest(max-expects): Enforces a maximum number assertion calls in a test body. ╭─[max_expects.tsx:8:21] diff --git a/crates/oxc_linter/src/snapshots/max_lines.snap b/crates/oxc_linter/src/snapshots/max_lines.snap index 4c5d3d57a59f2..0464fdeb4c4db 100644 --- a/crates/oxc_linter/src/snapshots/max_lines.snap +++ b/crates/oxc_linter/src/snapshots/max_lines.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(max-lines): File has too many lines (3). ╭─[max_lines.tsx:3:8] diff --git a/crates/oxc_linter/src/snapshots/max_nested_describe.snap b/crates/oxc_linter/src/snapshots/max_nested_describe.snap index a5c9581c2f29d..47444b8b9d09b 100644 --- a/crates/oxc_linter/src/snapshots/max_nested_describe.snap +++ b/crates/oxc_linter/src/snapshots/max_nested_describe.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jest(max-nested-describe): Enforces a maximum depth to nested describe calls. ╭─[max_nested_describe.tsx:7:37] diff --git a/crates/oxc_linter/src/snapshots/max_params.snap b/crates/oxc_linter/src/snapshots/max_params.snap index b228f543ea5b4..d8290c6074e8f 100644 --- a/crates/oxc_linter/src/snapshots/max_params.snap +++ b/crates/oxc_linter/src/snapshots/max_params.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint(max-params): Function 'test' has too many parameters (3). Maximum allowed is 2. ╭─[max_params.tsx:1:14] diff --git a/crates/oxc_linter/src/snapshots/media_has_caption.snap b/crates/oxc_linter/src/snapshots/media_has_caption.snap index a5016a69be74e..39abc45d6fd8c 100644 --- a/crates/oxc_linter/src/snapshots/media_has_caption.snap +++ b/crates/oxc_linter/src/snapshots/media_has_caption.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +snapshot_kind: text --- ⚠ eslint-plugin-jsx-a11y(media-has-caption): Missing element with captions inside