Skip to content

Commit

Permalink
feat(linter): add eslint/new-cap
Browse files Browse the repository at this point in the history
  • Loading branch information
Sysix committed Dec 27, 2024
1 parent 6b51e6d commit ce5c356
Show file tree
Hide file tree
Showing 4 changed files with 455 additions and 44 deletions.
42 changes: 42 additions & 0 deletions crates/oxc_linter/src/ast_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use oxc_ecmascript::ToBoolean;
use oxc_semantic::{AstNode, IsGlobalReference, NodeId, ReferenceId, Semantic, SymbolId};
use oxc_span::{GetSpan, Span};
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator};
use std::borrow::Cow;

/// Test if an AST node is a boolean value that never changes. Specifically we
/// test for:
Expand Down Expand Up @@ -469,3 +470,44 @@ pub fn leftmost_identifier_reference<'a, 'b: 'a>(
_ => Err(expr),
}
}

fn get_property_key_name<'a>(key: &PropertyKey<'a>) -> Option<Cow<'a, str>> {
if matches!(key, PropertyKey::NullLiteral(_)) {
return Some("null".into());
}

match key {
PropertyKey::RegExpLiteral(regex) => {
Some(Cow::Owned(format!("/{}/{}", regex.regex.pattern, regex.regex.flags)))
}
PropertyKey::BigIntLiteral(bigint) => Some(Cow::Borrowed(bigint.raw.as_str())),
PropertyKey::TemplateLiteral(template) => {
if template.expressions.len() == 0 && template.quasis.len() == 1 {
if let Some(cooked) = &template.quasis[0].value.cooked {
return Some(Cow::Borrowed(cooked.as_str()));
}
}

None
}
_ => None,
}
}

pub fn get_static_property_name<'a>(kind: &AstKind<'a>) -> Option<Cow<'a, str>> {
let (key, computed) = match kind {
AstKind::PropertyDefinition(definition) => (&definition.key, definition.computed),
AstKind::MethodDefinition(method_definition) => {
(&method_definition.key, method_definition.computed)
}
AstKind::ObjectProperty(property) => (&property.key, property.computed),
// AstKind::MemberExpression(member) => (member., member.is_computed())
_ => return None,
};

if key.is_identifier() && !computed {
return key.name();
}

get_property_key_name(key)
}
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mod eslint {
pub mod max_classes_per_file;
pub mod max_lines;
pub mod max_params;
pub mod new_cap;
pub mod no_alert;
pub mod no_array_constructor;
pub mod no_async_promise_executor;
Expand Down Expand Up @@ -534,6 +535,7 @@ oxc_macros::declare_all_lint_rules! {
eslint::max_classes_per_file,
eslint::max_lines,
eslint::max_params,
eslint::new_cap,
eslint::no_restricted_imports,
eslint::no_object_constructor,
eslint::no_duplicate_imports,
Expand Down
48 changes: 4 additions & 44 deletions crates/oxc_linter/src/rules/eslint/func_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::borrow::Cow;
use oxc_ast::{
ast::{
AssignmentTarget, AssignmentTargetProperty, BindingPatternKind, Expression, Function,
FunctionType, MethodDefinitionKind, PropertyKey, PropertyKind,
FunctionType, MethodDefinitionKind, PropertyKind,
},
AstKind,
};
Expand All @@ -14,7 +14,7 @@ use oxc_span::{Atom, GetSpan, Span};
use oxc_syntax::identifier::is_identifier_name;
use phf::phf_set;

use crate::{context::LintContext, rule::Rule, AstNode};
use crate::{ast_util::get_static_property_name, context::LintContext, rule::Rule, AstNode};

fn named_diagnostic(function_name: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Unexpected named {function_name}."))
Expand Down Expand Up @@ -232,46 +232,6 @@ fn get_function_identifier<'a>(func: &'a Function<'a>) -> Option<&'a Span> {
func.id.as_ref().map(|id| &id.span)
}

fn get_property_key_name<'a>(key: &PropertyKey<'a>) -> Option<Cow<'a, str>> {
if matches!(key, PropertyKey::NullLiteral(_)) {
return Some("null".into());
}

match key {
PropertyKey::RegExpLiteral(regex) => {
Some(Cow::Owned(format!("/{}/{}", regex.regex.pattern, regex.regex.flags)))
}
PropertyKey::BigIntLiteral(bigint) => Some(Cow::Borrowed(bigint.raw.as_str())),
PropertyKey::TemplateLiteral(template) => {
if template.expressions.len() == 0 && template.quasis.len() == 1 {
if let Some(cooked) = &template.quasis[0].value.cooked {
return Some(Cow::Borrowed(cooked.as_str()));
}
}

None
}
_ => None,
}
}

fn get_static_property_name<'a>(parent_node: &AstNode<'a>) -> Option<Cow<'a, str>> {
let (key, computed) = match parent_node.kind() {
AstKind::PropertyDefinition(definition) => (&definition.key, definition.computed),
AstKind::MethodDefinition(method_definition) => {
(&method_definition.key, method_definition.computed)
}
AstKind::ObjectProperty(property) => (&property.key, property.computed),
_ => return None,
};

if key.is_identifier() && !computed {
return key.name();
}

get_property_key_name(key)
}

/// 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<'a>(func: &Function<'a>, parent_node: &AstNode<'a>) -> Cow<'a, str> {
Expand Down Expand Up @@ -335,14 +295,14 @@ fn get_function_name_with_kind<'a>(func: &Function<'a>, parent_node: &AstNode<'a
if let Some(name) = definition.key.name() {
tokens.push(name);
}
} else if let Some(static_name) = get_static_property_name(parent_node) {
} else if let Some(static_name) = get_static_property_name(&parent_node.kind()) {
tokens.push(static_name);
} else if let Some(name) = func.name() {
tokens.push(Cow::Borrowed(name.as_str()));
}
}
_ => {
if let Some(static_name) = get_static_property_name(parent_node) {
if let Some(static_name) = get_static_property_name(&parent_node.kind()) {
tokens.push(static_name);
} else if let Some(name) = func.name() {
tokens.push(Cow::Borrowed(name.as_str()));
Expand Down
Loading

0 comments on commit ce5c356

Please sign in to comment.