mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(linter/eslint): implement func-names (#4618)
This commit is contained in:
parent
e78cba6464
commit
c296bc34bc
3 changed files with 982 additions and 0 deletions
|
|
@ -32,6 +32,7 @@ mod eslint {
|
|||
pub mod default_param_last;
|
||||
pub mod eqeqeq;
|
||||
pub mod for_direction;
|
||||
pub mod func_names;
|
||||
pub mod getter_return;
|
||||
pub mod guard_for_in;
|
||||
pub mod max_classes_per_file;
|
||||
|
|
@ -458,6 +459,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
eslint::default_param_last,
|
||||
eslint::eqeqeq,
|
||||
eslint::for_direction,
|
||||
eslint::func_names,
|
||||
eslint::getter_return,
|
||||
eslint::guard_for_in,
|
||||
eslint::max_classes_per_file,
|
||||
|
|
|
|||
672
crates/oxc_linter/src/rules/eslint/func_names.rs
Normal file
672
crates/oxc_linter/src/rules/eslint/func_names.rs
Normal file
|
|
@ -0,0 +1,672 @@
|
|||
use oxc_ast::ast::{
|
||||
AssignmentTarget, AssignmentTargetProperty, BindingPatternKind, Expression, Function,
|
||||
FunctionType, MethodDefinitionKind, PropertyKey, PropertyKind,
|
||||
};
|
||||
use oxc_ast::AstKind;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{Atom, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct FuncNames {
|
||||
default_config: FuncNamesConfig,
|
||||
generators_config: FuncNamesConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
enum FuncNamesConfig {
|
||||
#[default]
|
||||
Always,
|
||||
AsNeeded,
|
||||
Never,
|
||||
}
|
||||
|
||||
impl TryFrom<&serde_json::Value> for FuncNamesConfig {
|
||||
type Error = OxcDiagnostic;
|
||||
|
||||
fn try_from(raw: &serde_json::Value) -> Result<Self, Self::Error> {
|
||||
if !raw.is_string() {
|
||||
return Err(OxcDiagnostic::error(format!(
|
||||
"Expecting string for eslint/func-names configuration, got {raw}"
|
||||
)));
|
||||
}
|
||||
|
||||
match raw.as_str().unwrap() {
|
||||
"always" => Ok(FuncNamesConfig::Always),
|
||||
"as-needed" => Ok(FuncNamesConfig::AsNeeded),
|
||||
"never" => Ok(FuncNamesConfig::Never),
|
||||
v => Err(OxcDiagnostic::error(format!(
|
||||
"Expecting always, as-needed or never for eslint/func-names configuration, got {v}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Require or disallow named function expressions
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Leaving the name off a function will cause <anonymous> to appear
|
||||
/// in stack traces of errorsthrown in it or any function called within it.
|
||||
/// This makes it more difficult to find where an error is thrown.
|
||||
/// If you provide the optional name for a function expression
|
||||
/// then you will get the name of the function expression in the stack trace.
|
||||
///
|
||||
/// /// ### Example
|
||||
///
|
||||
/// Example of **incorrect** code for this rule:
|
||||
///
|
||||
/// ```javascript
|
||||
/// /*eslint func-names: "error" */
|
||||
///
|
||||
/// // default is "always" and there is an anonymous function
|
||||
/// Foo.prototype.bar = function() {};
|
||||
///
|
||||
/// /*eslint func-names: ["error", "always"] */
|
||||
///
|
||||
/// // there is an anonymous function
|
||||
/// Foo.prototype.bar = function() {};
|
||||
///
|
||||
/// /*eslint func-names: ["error", "as-needed"] */
|
||||
///
|
||||
/// // there is an anonymous function
|
||||
/// // where the name isn’t assigned automatically per the ECMAScript specs
|
||||
/// Foo.prototype.bar = function() {};
|
||||
///
|
||||
/// /*eslint func-names: ["error", "never"] */
|
||||
///
|
||||
/// // there is a named function
|
||||
/// Foo.prototype.bar = function bar() {};
|
||||
/// ```
|
||||
///
|
||||
/// Example of **correct* code for this rule:
|
||||
///
|
||||
/// ```javascript
|
||||
/// /*eslint func-names: "error" */
|
||||
///
|
||||
/// Foo.prototype.bar = function bar() {};
|
||||
///
|
||||
/// /*eslint func-names: ["error", "always"] */
|
||||
///
|
||||
/// Foo.prototype.bar = function bar() {};
|
||||
///
|
||||
/// /*eslint func-names: ["error", "as-needed"] */
|
||||
///
|
||||
/// var foo = function(){};
|
||||
///
|
||||
/// /*eslint func-names: ["error", "never"] */
|
||||
///
|
||||
/// Foo.prototype.bar = function() {};
|
||||
/// ```
|
||||
FuncNames,
|
||||
style,
|
||||
pending
|
||||
);
|
||||
/**
|
||||
* Determines whether the current FunctionExpression node is a get, set, or
|
||||
* shorthand method in an object literal or a class.
|
||||
*/
|
||||
fn is_object_or_class_method(parent_node: Option<&AstNode>) -> bool {
|
||||
if parent_node.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let unwrapped_kind = parent_node.unwrap().kind();
|
||||
|
||||
if matches!(unwrapped_kind, AstKind::MethodDefinition(_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let AstKind::ObjectProperty(property) = unwrapped_kind {
|
||||
return property.method
|
||||
|| property.kind == PropertyKind::Get
|
||||
|| property.kind == PropertyKind::Set;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
/**
|
||||
* Determines whether the current FunctionExpression node has a name that would be
|
||||
* inferred from context in a conforming ES6 environment.
|
||||
*/
|
||||
fn has_inferred_name(function: &Function, parent_node: Option<&AstNode>) -> bool {
|
||||
if is_object_or_class_method(parent_node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// unwrap is safe because of is_object_or_class_method
|
||||
match parent_node.unwrap().kind() {
|
||||
AstKind::VariableDeclarator(declarator) => {
|
||||
matches!(declarator.id.kind, BindingPatternKind::BindingIdentifier(_))
|
||||
&& matches!(declarator.init.as_ref().unwrap(), Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
}
|
||||
AstKind::ObjectProperty(property) => {
|
||||
matches!(&property.value, Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
}
|
||||
AstKind::PropertyDefinition(definition) => {
|
||||
matches!(&definition.value.as_ref().unwrap(), Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
}
|
||||
AstKind::AssignmentExpression(expression) => {
|
||||
matches!(expression.left, AssignmentTarget::AssignmentTargetIdentifier(_))
|
||||
&& matches!(&expression.right, Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
}
|
||||
AstKind::AssignmentTargetWithDefault(target) => {
|
||||
matches!(target.binding, AssignmentTarget::AssignmentTargetIdentifier(_))
|
||||
&& matches!(&target.init, Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
}
|
||||
AstKind::AssignmentPattern(pattern) => {
|
||||
matches!(pattern.left.kind, BindingPatternKind::BindingIdentifier(_))
|
||||
&& matches!(&pattern.right, Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
}
|
||||
AstKind::ObjectAssignmentTarget(target) => {
|
||||
for property in &target.properties {
|
||||
if matches!(property, AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(identifier)
|
||||
if matches!(identifier.init.as_ref().unwrap(), Expression::FunctionExpression(function_expression)
|
||||
if get_function_identifier(function_expression) == get_function_identifier(function)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier for the function
|
||||
*/
|
||||
fn get_function_identifier<'a>(func: &'a Function<'a>) -> Option<&'a Span> {
|
||||
func.id.as_ref().map(|id| &id.span)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier name of the function
|
||||
*/
|
||||
fn get_function_name<'a>(func: &'a Function<'a>) -> Option<&Atom<'a>> {
|
||||
func.id.as_ref().map(|id| &id.name)
|
||||
}
|
||||
|
||||
fn get_property_key_name<'a>(key: &'a PropertyKey<'a>) -> Option<String> {
|
||||
if matches!(key, PropertyKey::NullLiteral(_)) {
|
||||
return Some("null".to_string());
|
||||
}
|
||||
|
||||
match key {
|
||||
PropertyKey::RegExpLiteral(regex) => {
|
||||
Some(format!("/{}/{}", regex.regex.pattern, regex.regex.flags))
|
||||
}
|
||||
PropertyKey::BigIntLiteral(bigint) => Some(bigint.raw.to_string()),
|
||||
PropertyKey::TemplateLiteral(template) => {
|
||||
if template.expressions.len() == 0 && template.quasis.len() == 1 {
|
||||
if let Some(cooked) = &template.quasis[0].value.cooked {
|
||||
return Some(cooked.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_static_property_name<'a>(parent_node: Option<&'a AstNode<'a>>) -> Option<String> {
|
||||
parent_node?;
|
||||
|
||||
let result_key = match parent_node.unwrap().kind() {
|
||||
AstKind::PropertyDefinition(definition) => Some((&definition.key, definition.computed)),
|
||||
AstKind::MethodDefinition(method_definition) => {
|
||||
Some((&method_definition.key, method_definition.computed))
|
||||
}
|
||||
AstKind::ObjectProperty(property) => Some((&property.key, property.computed)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
result_key?;
|
||||
|
||||
let prop = result_key.unwrap().0;
|
||||
|
||||
if prop.is_identifier() && !result_key.unwrap().1 {
|
||||
prop.name()?;
|
||||
|
||||
return Some(prop.name().unwrap().to_string());
|
||||
}
|
||||
|
||||
get_property_key_name(prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name and kind of the given function node.
|
||||
* @see <https://github.com/eslint/eslint/blob/48117b27e98639ffe7e78a230bfad9a93039fb7f/lib/rules/utils/ast-utils.js#L1762>
|
||||
*/
|
||||
fn get_function_name_with_kind(func: &Function, parent_node: Option<&AstNode>) -> String {
|
||||
let mut tokens: Vec<String> = vec![];
|
||||
|
||||
if parent_node.is_some() {
|
||||
match parent_node.unwrap().kind() {
|
||||
AstKind::MethodDefinition(definition) => {
|
||||
if definition.r#static {
|
||||
tokens.push("static".to_owned());
|
||||
}
|
||||
|
||||
if !definition.computed && definition.key.is_private_identifier() {
|
||||
tokens.push("private".to_owned());
|
||||
}
|
||||
}
|
||||
AstKind::PropertyDefinition(definition) => {
|
||||
if definition.r#static {
|
||||
tokens.push("static".to_owned());
|
||||
}
|
||||
|
||||
if !definition.computed && definition.key.is_private_identifier() {
|
||||
tokens.push("private".to_owned());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if func.r#async {
|
||||
tokens.push("async".to_owned());
|
||||
}
|
||||
|
||||
if func.generator {
|
||||
tokens.push("generator".to_owned());
|
||||
}
|
||||
|
||||
if parent_node.is_some() {
|
||||
let kind = parent_node.unwrap().kind();
|
||||
|
||||
match kind {
|
||||
AstKind::MethodDefinition(method_definition) => match method_definition.kind {
|
||||
MethodDefinitionKind::Constructor => tokens.push("constructor".to_owned()),
|
||||
MethodDefinitionKind::Get => tokens.push("getter".to_owned()),
|
||||
MethodDefinitionKind::Set => tokens.push("setter".to_owned()),
|
||||
MethodDefinitionKind::Method => tokens.push("method".to_owned()),
|
||||
},
|
||||
AstKind::PropertyDefinition(_) => tokens.push("method".to_owned()),
|
||||
_ => tokens.push("function".to_owned()),
|
||||
}
|
||||
|
||||
match kind {
|
||||
AstKind::MethodDefinition(method_definition)
|
||||
if !method_definition.computed && method_definition.key.is_private_identifier() =>
|
||||
{
|
||||
if let Some(name) = method_definition.key.name() {
|
||||
tokens.push(name.to_string());
|
||||
}
|
||||
}
|
||||
AstKind::PropertyDefinition(definition) => {
|
||||
if !definition.computed && definition.key.is_private_identifier() {
|
||||
if let Some(name) = definition.key.name() {
|
||||
tokens.push(name.to_string());
|
||||
}
|
||||
} else if let Some(static_name) = get_static_property_name(parent_node) {
|
||||
tokens.push(static_name);
|
||||
} else if let Some(name) = get_function_name(func) {
|
||||
tokens.push(name.to_string());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(static_name) = get_static_property_name(parent_node) {
|
||||
tokens.push(static_name);
|
||||
} else if let Some(name) = get_function_name(func) {
|
||||
tokens.push(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tokens.join(" ")
|
||||
}
|
||||
|
||||
fn is_invalid_function(
|
||||
func: &Function,
|
||||
config: &FuncNamesConfig,
|
||||
parent_node: Option<&AstNode>,
|
||||
) -> bool {
|
||||
let func_name = get_function_name(func);
|
||||
|
||||
match *config {
|
||||
FuncNamesConfig::Never
|
||||
if func_name.is_some() && func.r#type != FunctionType::FunctionDeclaration =>
|
||||
{
|
||||
true
|
||||
}
|
||||
FuncNamesConfig::AsNeeded
|
||||
if func_name.is_none() && !has_inferred_name(func, parent_node) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
FuncNamesConfig::Always
|
||||
if func_name.is_none() && !is_object_or_class_method(parent_node) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl Rule for FuncNames {
|
||||
fn from_configuration(value: serde_json::Value) -> Self {
|
||||
let Some(default_value) = value.get(0) else {
|
||||
return Self {
|
||||
default_config: FuncNamesConfig::default(),
|
||||
generators_config: FuncNamesConfig::default(),
|
||||
};
|
||||
};
|
||||
|
||||
let default_config = FuncNamesConfig::try_from(default_value).unwrap();
|
||||
|
||||
let generators_value =
|
||||
value.get(1).and_then(|v| v.get("generators")).unwrap_or(default_value);
|
||||
|
||||
let generators_config = FuncNamesConfig::try_from(generators_value).unwrap();
|
||||
|
||||
Self { default_config, generators_config }
|
||||
}
|
||||
fn run_once(&self, ctx: &LintContext<'_>) {
|
||||
let mut invalid_funcs: Vec<(&Function, Option<&AstNode>)> = vec![];
|
||||
|
||||
for node in ctx.nodes().iter() {
|
||||
match node.kind() {
|
||||
// check function if it invalid, do not report it because maybe later the function is calling itself
|
||||
AstKind::Function(func) => {
|
||||
let parent_node = ctx.nodes().parent_node(node.id());
|
||||
let config =
|
||||
if func.generator { &self.generators_config } else { &self.default_config };
|
||||
|
||||
if is_invalid_function(func, config, parent_node) {
|
||||
invalid_funcs.push((func, parent_node));
|
||||
}
|
||||
}
|
||||
|
||||
// check if the calling function is inside of its own body
|
||||
// when yes remove it from invalid_funcs because recursion are always named
|
||||
AstKind::CallExpression(expression) => {
|
||||
if let Expression::Identifier(identifier) = &expression.callee {
|
||||
// check at first if the callee calls an invalid function
|
||||
if !invalid_funcs
|
||||
.iter()
|
||||
.any(|(func, _)| get_function_name(func) == Some(&identifier.name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// a function which is calling itself inside is always valid
|
||||
let ast_span = ctx.nodes().iter_parents(node.id()).skip(1).find_map(|p| {
|
||||
match p.kind() {
|
||||
AstKind::Function(func) => {
|
||||
let func_name = get_function_name(func);
|
||||
|
||||
func_name?;
|
||||
|
||||
if *func_name.unwrap() == identifier.name {
|
||||
return Some(func.span);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
|
||||
// we found a recursive function, remove it from the invalid list
|
||||
if let Some(span) = ast_span {
|
||||
invalid_funcs.retain(|(func, _)| func.span != span);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
for (func, parent_node) in &invalid_funcs {
|
||||
let func_name = get_function_name(func);
|
||||
let func_name_complete = get_function_name_with_kind(func, *parent_node);
|
||||
|
||||
if func_name.is_some() {
|
||||
ctx.diagnostic(
|
||||
OxcDiagnostic::warn(format!("Unexpected named {func_name_complete}."))
|
||||
.with_label(Span::new(func.span.start, func.params.span.start)),
|
||||
);
|
||||
} else {
|
||||
ctx.diagnostic(
|
||||
OxcDiagnostic::warn(format!("Unexpected unnamed {func_name_complete}."))
|
||||
.with_label(Span::new(func.span.start, func.params.span.start)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
("Foo.prototype.bar = function bar(){};", None),
|
||||
("Foo.prototype.bar = () => {}", None), // { "ecmaVersion": 6 },
|
||||
("function foo(){}", None),
|
||||
("function test(d, e, f) {}", None),
|
||||
("new function bar(){}", None),
|
||||
("exports = { get foo() { return 1; }, set bar(val) { return val; } };", None),
|
||||
("({ foo() { return 1; } });", None), // { "ecmaVersion": 6 },
|
||||
("class A { constructor(){} foo(){} get bar(){} set baz(value){} static qux(){}}", None), // { "ecmaVersion": 6 },
|
||||
("function foo() {}", Some(serde_json::json!(["always"]))),
|
||||
("var a = function foo() {};", Some(serde_json::json!(["always"]))),
|
||||
(
|
||||
"class A { constructor(){} foo(){} get bar(){} set baz(value){} static qux(){}}",
|
||||
Some(serde_json::json!(["as-needed"])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("({ foo() {} });", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("var foo = function(){};", Some(serde_json::json!(["as-needed"]))),
|
||||
("({foo: function(){}});", Some(serde_json::json!(["as-needed"]))),
|
||||
("(foo = function(){});", Some(serde_json::json!(["as-needed"]))),
|
||||
("({foo = function(){}} = {});", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("({key: foo = function(){}} = {});", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("[foo = function(){}] = [];", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("function fn(foo = function(){}) {}", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("function foo() {}", Some(serde_json::json!(["never"]))),
|
||||
("var a = function() {};", Some(serde_json::json!(["never"]))),
|
||||
("var a = function foo() { foo(); };", Some(serde_json::json!(["never"]))),
|
||||
("var foo = {bar: function() {}};", Some(serde_json::json!(["never"]))),
|
||||
("$('#foo').click(function() {});", Some(serde_json::json!(["never"]))),
|
||||
("Foo.prototype.bar = function() {};", Some(serde_json::json!(["never"]))),
|
||||
(
|
||||
"class A { constructor(){} foo(){} get bar(){} set baz(value){} static qux(){}}",
|
||||
Some(serde_json::json!(["never"])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("({ foo() {} });", Some(serde_json::json!(["never"]))), // { "ecmaVersion": 6 },
|
||||
("export default function foo() {}", Some(serde_json::json!(["always"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("export default function foo() {}", Some(serde_json::json!(["as-needed"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("export default function foo() {}", Some(serde_json::json!(["never"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("export default function() {}", Some(serde_json::json!(["never"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("var foo = bar(function *baz() {});", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["always", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["always", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["always", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("var foo = bar(function *baz() {});", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("var foo = function*() {};", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["never", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["never", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["never", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("var foo = bar(function *() {});", Some(serde_json::json!(["never"]))), // { "ecmaVersion": 6 },
|
||||
("var foo = function*() {};", Some(serde_json::json!(["never"]))), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["never"]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["never", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["never", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["never", { "generators": "never" }]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["always", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["always", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["always", { "generators": "never" }]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["as-needed", { "generators": "never" }]))), // { "ecmaVersion": 6 },
|
||||
("class C { foo = function() {}; }", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 2022 },
|
||||
("class C { [foo] = function() {}; }", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 2022 },
|
||||
("class C { #foo = function() {}; }", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 2022 }
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("Foo.prototype.bar = function() {};", None),
|
||||
("(function(){}())", None),
|
||||
("f(function(){})", None),
|
||||
("var a = new Date(function() {});", None),
|
||||
("var test = function(d, e, f) {};", None),
|
||||
("new function() {}", None),
|
||||
("Foo.prototype.bar = function() {};", Some(serde_json::json!(["as-needed"]))),
|
||||
("(function(){}())", Some(serde_json::json!(["as-needed"]))),
|
||||
("f(function(){})", Some(serde_json::json!(["as-needed"]))),
|
||||
("var a = new Date(function() {});", Some(serde_json::json!(["as-needed"]))),
|
||||
("new function() {}", Some(serde_json::json!(["as-needed"]))),
|
||||
("var {foo} = function(){};", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("({ a: obj.prop = function(){} } = foo);", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("[obj.prop = function(){}] = foo;", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("var { a: [b] = function(){} } = foo;", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("function foo({ a } = function(){}) {};", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("var x = function foo() {};", Some(serde_json::json!(["never"]))),
|
||||
("Foo.prototype.bar = function foo() {};", Some(serde_json::json!(["never"]))),
|
||||
("({foo: function foo() {}})", Some(serde_json::json!(["never"]))),
|
||||
("export default function() {}", Some(serde_json::json!(["always"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("export default function() {}", Some(serde_json::json!(["as-needed"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("export default (function(){});", Some(serde_json::json!(["as-needed"]))), // { "sourceType": "module", "ecmaVersion": 6 },
|
||||
("var foo = bar(function *() {});", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 6 },
|
||||
("var foo = function*() {};", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["always", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["always", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["always", { "generators": "always" }]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["always", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["always", { "generators": "as-needed" }]))), // { "ecmaVersion": 6 },
|
||||
("var foo = bar(function *() {});", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["as-needed", { "generators": "always" }]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"(function*() {}())",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["never", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = function*() {};",
|
||||
Some(serde_json::json!(["never", { "generators": "always" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["never", { "generators": "always" }]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *() {});",
|
||||
Some(serde_json::json!(["never", { "generators": "as-needed" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("(function*() {}())", Some(serde_json::json!(["never", { "generators": "as-needed" }]))), // { "ecmaVersion": 6 },
|
||||
("var foo = bar(function *baz() {});", Some(serde_json::json!(["never"]))), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["never", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["always", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
(
|
||||
"var foo = bar(function *baz() {});",
|
||||
Some(serde_json::json!(["as-needed", { "generators": "never" }])),
|
||||
), // { "ecmaVersion": 6 },
|
||||
("class C { foo = function() {} }", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 2022 },
|
||||
("class C { [foo] = function() {} }", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 2022 },
|
||||
("class C { #foo = function() {} }", Some(serde_json::json!(["always"]))), // { "ecmaVersion": 2022 },
|
||||
("class C { foo = bar(function() {}) }", Some(serde_json::json!(["as-needed"]))), // { "ecmaVersion": 2022 },
|
||||
("class C { foo = function bar() {} }", Some(serde_json::json!(["never"]))), // { "ecmaVersion": 2022 }
|
||||
];
|
||||
|
||||
Tester::new(FuncNames::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
308
crates/oxc_linter/src/snapshots/func_names.snap
Normal file
308
crates/oxc_linter/src/snapshots/func_names.snap
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
---
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:21]
|
||||
1 │ Foo.prototype.bar = function() {};
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function(){}())
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:3]
|
||||
1 │ f(function(){})
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:18]
|
||||
1 │ var a = new Date(function() {});
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:12]
|
||||
1 │ var test = function(d, e, f) {};
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:5]
|
||||
1 │ new function() {}
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:21]
|
||||
1 │ Foo.prototype.bar = function() {};
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function(){}())
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:3]
|
||||
1 │ f(function(){})
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:18]
|
||||
1 │ var a = new Date(function() {});
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:5]
|
||||
1 │ new function() {}
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:13]
|
||||
1 │ var {foo} = function(){};
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:18]
|
||||
1 │ ({ a: obj.prop = function(){} } = foo);
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:13]
|
||||
1 │ [obj.prop = function(){}] = foo;
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:16]
|
||||
1 │ var { a: [b] = function(){} } = foo;
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:22]
|
||||
1 │ function foo({ a } = function(){}) {};
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named function foo.
|
||||
╭─[func_names.tsx:1:9]
|
||||
1 │ var x = function foo() {};
|
||||
· ────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named function foo.
|
||||
╭─[func_names.tsx:1:21]
|
||||
1 │ Foo.prototype.bar = function foo() {};
|
||||
· ────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named function foo.
|
||||
╭─[func_names.tsx:1:8]
|
||||
1 │ ({foo: function foo() {}})
|
||||
· ────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:16]
|
||||
1 │ export default function() {}
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:16]
|
||||
1 │ export default function() {}
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:17]
|
||||
1 │ export default (function(){});
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:11]
|
||||
1 │ var foo = function*() {};
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:11]
|
||||
1 │ var foo = function*() {};
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:11]
|
||||
1 │ var foo = function*() {};
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:11]
|
||||
1 │ var foo = function*() {};
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *() {});
|
||||
· ──────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed generator function.
|
||||
╭─[func_names.tsx:1:2]
|
||||
1 │ (function*() {}())
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named generator function baz.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *baz() {});
|
||||
· ─────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named generator function baz.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *baz() {});
|
||||
· ─────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named generator function baz.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *baz() {});
|
||||
· ─────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named generator function baz.
|
||||
╭─[func_names.tsx:1:15]
|
||||
1 │ var foo = bar(function *baz() {});
|
||||
· ─────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed method foo.
|
||||
╭─[func_names.tsx:1:17]
|
||||
1 │ class C { foo = function() {} }
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed method.
|
||||
╭─[func_names.tsx:1:19]
|
||||
1 │ class C { [foo] = function() {} }
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed private method foo.
|
||||
╭─[func_names.tsx:1:18]
|
||||
1 │ class C { #foo = function() {} }
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected unnamed function.
|
||||
╭─[func_names.tsx:1:21]
|
||||
1 │ class C { foo = bar(function() {}) }
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
⚠ eslint(func-names): Unexpected named method foo.
|
||||
╭─[func_names.tsx:1:17]
|
||||
1 │ class C { foo = function bar() {} }
|
||||
· ────────────
|
||||
╰────
|
||||
Loading…
Reference in a new issue