Skip to content

Commit 25f0445

Browse files
shulaodaikkz
authored andcommitted
refactor: improve the documentation and diagnostic
1 parent b8330c1 commit 25f0445

4 files changed

Lines changed: 265 additions & 265 deletions

File tree

crates/oxc_linter/src/ast_util.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use oxc_ast::{
24
ast::{BindingIdentifier, *},
35
AstKind,
@@ -770,3 +772,129 @@ pub fn is_default_this_binding<'a>(
770772
}
771773
}
772774
}
775+
776+
pub fn get_static_property_name<'a>(parent_node: &AstNode<'a>) -> Option<Cow<'a, str>> {
777+
let (key, computed) = match parent_node.kind() {
778+
AstKind::PropertyDefinition(definition) => (&definition.key, definition.computed),
779+
AstKind::MethodDefinition(method_definition) => {
780+
(&method_definition.key, method_definition.computed)
781+
}
782+
AstKind::ObjectProperty(property) => (&property.key, property.computed),
783+
_ => return None,
784+
};
785+
786+
if key.is_identifier() && !computed {
787+
return key.name();
788+
}
789+
790+
if matches!(key, PropertyKey::NullLiteral(_)) {
791+
return Some("null".into());
792+
}
793+
794+
match key {
795+
PropertyKey::RegExpLiteral(regex) => {
796+
Some(Cow::Owned(format!("/{}/{}", regex.regex.pattern, regex.regex.flags)))
797+
}
798+
PropertyKey::BigIntLiteral(bigint) => Some(Cow::Borrowed(bigint.raw.as_str())),
799+
PropertyKey::TemplateLiteral(template) => {
800+
if template.expressions.len() == 0 && template.quasis.len() == 1 {
801+
if let Some(cooked) = &template.quasis[0].value.cooked {
802+
return Some(Cow::Borrowed(cooked.as_str()));
803+
}
804+
}
805+
806+
None
807+
}
808+
_ => None,
809+
}
810+
}
811+
812+
/// Gets the name and kind of the given function node.
813+
/// @see <https://github.com/eslint/eslint/blob/48117b27e98639ffe7e78a230bfad9a93039fb7f/lib/rules/utils/ast-utils.js#L1762>
814+
pub fn get_function_name_with_kind<'a>(
815+
node: &AstNode<'a>,
816+
parent_node: &AstNode<'a>,
817+
) -> Cow<'a, str> {
818+
let (name, is_async, is_generator) = match node.kind() {
819+
AstKind::Function(func) => (func.name(), func.r#async, func.generator),
820+
AstKind::ArrowFunctionExpression(arrow_func) => (None, arrow_func.r#async, false),
821+
_ => (None, false, false),
822+
};
823+
824+
let mut tokens: Vec<Cow<'a, str>> = vec![];
825+
826+
match parent_node.kind() {
827+
AstKind::MethodDefinition(definition) => {
828+
if !definition.computed && definition.key.is_private_identifier() {
829+
tokens.push(Cow::Borrowed("private"));
830+
} else if let Some(accessibility) = definition.accessibility {
831+
tokens.push(Cow::Borrowed(accessibility.as_str()));
832+
}
833+
834+
if definition.r#static {
835+
tokens.push(Cow::Borrowed("static"));
836+
}
837+
}
838+
AstKind::PropertyDefinition(definition) => {
839+
if !definition.computed && definition.key.is_private_identifier() {
840+
tokens.push(Cow::Borrowed("private"));
841+
} else if let Some(accessibility) = definition.accessibility {
842+
tokens.push(Cow::Borrowed(accessibility.as_str()));
843+
}
844+
845+
if definition.r#static {
846+
tokens.push(Cow::Borrowed("static"));
847+
}
848+
}
849+
_ => {}
850+
}
851+
852+
if is_async {
853+
tokens.push(Cow::Borrowed("async"));
854+
}
855+
856+
if is_generator {
857+
tokens.push(Cow::Borrowed("generator"));
858+
}
859+
860+
match parent_node.kind() {
861+
AstKind::MethodDefinition(method_definition) => match method_definition.kind {
862+
MethodDefinitionKind::Constructor => tokens.push(Cow::Borrowed("constructor")),
863+
MethodDefinitionKind::Get => tokens.push(Cow::Borrowed("getter")),
864+
MethodDefinitionKind::Set => tokens.push(Cow::Borrowed("setter")),
865+
MethodDefinitionKind::Method => tokens.push(Cow::Borrowed("method")),
866+
},
867+
AstKind::PropertyDefinition(_) => tokens.push(Cow::Borrowed("method")),
868+
_ => tokens.push(Cow::Borrowed("function")),
869+
}
870+
871+
match parent_node.kind() {
872+
AstKind::MethodDefinition(method_definition)
873+
if !method_definition.computed && method_definition.key.is_private_identifier() =>
874+
{
875+
if let Some(name) = method_definition.key.name() {
876+
tokens.push(name);
877+
}
878+
}
879+
AstKind::PropertyDefinition(definition) => {
880+
if !definition.computed && definition.key.is_private_identifier() {
881+
if let Some(name) = definition.key.name() {
882+
tokens.push(name);
883+
}
884+
} else if let Some(static_name) = get_static_property_name(parent_node) {
885+
tokens.push(static_name);
886+
} else if let Some(name) = name {
887+
tokens.push(Cow::Borrowed(name.as_str()));
888+
}
889+
}
890+
_ => {
891+
if let Some(static_name) = get_static_property_name(parent_node) {
892+
tokens.push(static_name);
893+
} else if let Some(name) = name {
894+
tokens.push(Cow::Borrowed(name.as_str()));
895+
}
896+
}
897+
}
898+
899+
Cow::Owned(tokens.join(" "))
900+
}

crates/oxc_linter/src/rules/eslint/func_names.rs

Lines changed: 8 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::borrow::Cow;
33
use oxc_ast::{
44
ast::{
55
AssignmentTarget, AssignmentTargetProperty, BindingPatternKind, Expression, Function,
6-
FunctionType, MethodDefinitionKind, PropertyKey, PropertyKind,
6+
FunctionType, PropertyKind,
77
},
88
AstKind,
99
};
@@ -14,7 +14,7 @@ use oxc_span::{Atom, GetSpan, Span};
1414
use oxc_syntax::identifier::is_identifier_name;
1515
use phf::phf_set;
1616

17-
use crate::{context::LintContext, rule::Rule, AstNode};
17+
use crate::{ast_util::get_function_name_with_kind, context::LintContext, rule::Rule, AstNode};
1818

1919
fn named_diagnostic(function_name: &str, span: Span) -> OxcDiagnostic {
2020
OxcDiagnostic::warn(format!("Unexpected named {function_name}."))
@@ -233,127 +233,6 @@ fn get_function_identifier<'a>(func: &'a Function<'a>) -> Option<&'a Span> {
233233
func.id.as_ref().map(|id| &id.span)
234234
}
235235

236-
fn get_property_key_name<'a>(key: &PropertyKey<'a>) -> Option<Cow<'a, str>> {
237-
if matches!(key, PropertyKey::NullLiteral(_)) {
238-
return Some("null".into());
239-
}
240-
241-
match key {
242-
PropertyKey::RegExpLiteral(regex) => {
243-
Some(Cow::Owned(format!("/{}/{}", regex.regex.pattern, regex.regex.flags)))
244-
}
245-
PropertyKey::BigIntLiteral(bigint) => Some(Cow::Borrowed(bigint.raw.as_str())),
246-
PropertyKey::TemplateLiteral(template) => {
247-
if template.expressions.len() == 0 && template.quasis.len() == 1 {
248-
if let Some(cooked) = &template.quasis[0].value.cooked {
249-
return Some(Cow::Borrowed(cooked.as_str()));
250-
}
251-
}
252-
253-
None
254-
}
255-
_ => None,
256-
}
257-
}
258-
259-
fn get_static_property_name<'a>(parent_node: &AstNode<'a>) -> Option<Cow<'a, str>> {
260-
let (key, computed) = match parent_node.kind() {
261-
AstKind::PropertyDefinition(definition) => (&definition.key, definition.computed),
262-
AstKind::MethodDefinition(method_definition) => {
263-
(&method_definition.key, method_definition.computed)
264-
}
265-
AstKind::ObjectProperty(property) => (&property.key, property.computed),
266-
_ => return None,
267-
};
268-
269-
if key.is_identifier() && !computed {
270-
return key.name();
271-
}
272-
273-
get_property_key_name(key)
274-
}
275-
276-
/// Gets the name and kind of the given function node.
277-
/// @see <https://github.com/eslint/eslint/blob/48117b27e98639ffe7e78a230bfad9a93039fb7f/lib/rules/utils/ast-utils.js#L1762>
278-
fn get_function_name_with_kind<'a>(func: &Function<'a>, parent_node: &AstNode<'a>) -> Cow<'a, str> {
279-
let mut tokens: Vec<Cow<'a, str>> = vec![];
280-
281-
match parent_node.kind() {
282-
AstKind::MethodDefinition(definition) => {
283-
if !definition.computed && definition.key.is_private_identifier() {
284-
tokens.push(Cow::Borrowed("private"));
285-
} else if let Some(accessibility) = definition.accessibility {
286-
tokens.push(Cow::Borrowed(accessibility.as_str()));
287-
}
288-
289-
if definition.r#static {
290-
tokens.push(Cow::Borrowed("static"));
291-
}
292-
}
293-
AstKind::PropertyDefinition(definition) => {
294-
if !definition.computed && definition.key.is_private_identifier() {
295-
tokens.push(Cow::Borrowed("private"));
296-
} else if let Some(accessibility) = definition.accessibility {
297-
tokens.push(Cow::Borrowed(accessibility.as_str()));
298-
}
299-
300-
if definition.r#static {
301-
tokens.push(Cow::Borrowed("static"));
302-
}
303-
}
304-
_ => {}
305-
}
306-
307-
if func.r#async {
308-
tokens.push(Cow::Borrowed("async"));
309-
}
310-
311-
if func.generator {
312-
tokens.push(Cow::Borrowed("generator"));
313-
}
314-
315-
match parent_node.kind() {
316-
AstKind::MethodDefinition(method_definition) => match method_definition.kind {
317-
MethodDefinitionKind::Constructor => tokens.push(Cow::Borrowed("constructor")),
318-
MethodDefinitionKind::Get => tokens.push(Cow::Borrowed("getter")),
319-
MethodDefinitionKind::Set => tokens.push(Cow::Borrowed("setter")),
320-
MethodDefinitionKind::Method => tokens.push(Cow::Borrowed("method")),
321-
},
322-
AstKind::PropertyDefinition(_) => tokens.push(Cow::Borrowed("method")),
323-
_ => tokens.push(Cow::Borrowed("function")),
324-
}
325-
326-
match parent_node.kind() {
327-
AstKind::MethodDefinition(method_definition)
328-
if !method_definition.computed && method_definition.key.is_private_identifier() =>
329-
{
330-
if let Some(name) = method_definition.key.name() {
331-
tokens.push(name);
332-
}
333-
}
334-
AstKind::PropertyDefinition(definition) => {
335-
if !definition.computed && definition.key.is_private_identifier() {
336-
if let Some(name) = definition.key.name() {
337-
tokens.push(name);
338-
}
339-
} else if let Some(static_name) = get_static_property_name(parent_node) {
340-
tokens.push(static_name);
341-
} else if let Some(name) = func.name() {
342-
tokens.push(Cow::Borrowed(name.as_str()));
343-
}
344-
}
345-
_ => {
346-
if let Some(static_name) = get_static_property_name(parent_node) {
347-
tokens.push(static_name);
348-
} else if let Some(name) = func.name() {
349-
tokens.push(Cow::Borrowed(name.as_str()));
350-
}
351-
}
352-
}
353-
354-
Cow::Owned(tokens.join(" "))
355-
}
356-
357236
impl Rule for FuncNames {
358237
fn from_configuration(value: serde_json::Value) -> Self {
359238
let Some(default_value) = value.get(0) else {
@@ -371,7 +250,7 @@ impl Rule for FuncNames {
371250
}
372251

373252
fn run_once(&self, ctx: &LintContext<'_>) {
374-
let mut invalid_funcs: Vec<(&Function, &AstNode)> = vec![];
253+
let mut invalid_funcs: Vec<(&Function, &AstNode, &AstNode)> = vec![];
375254

376255
for node in ctx.nodes() {
377256
match node.kind() {
@@ -384,7 +263,7 @@ impl Rule for FuncNames {
384263
if func.generator { &self.generators_config } else { &self.default_config };
385264

386265
if config.is_invalid_function(func, parent_node) {
387-
invalid_funcs.push((func, parent_node));
266+
invalid_funcs.push((func, node, parent_node));
388267
}
389268
}
390269

@@ -395,7 +274,7 @@ impl Rule for FuncNames {
395274
// check at first if the callee calls an invalid function
396275
if !invalid_funcs
397276
.iter()
398-
.filter_map(|(func, _)| func.name())
277+
.filter_map(|(func, _, _)| func.name())
399278
.any(|func_name| func_name == identifier.name)
400279
{
401280
continue;
@@ -418,16 +297,16 @@ impl Rule for FuncNames {
418297

419298
// we found a recursive function, remove it from the invalid list
420299
if let Some(span) = ast_span {
421-
invalid_funcs.retain(|(func, _)| func.span != span);
300+
invalid_funcs.retain(|(func, _, _)| func.span != span);
422301
}
423302
}
424303
}
425304
_ => {}
426305
}
427306
}
428307

429-
for (func, parent_node) in &invalid_funcs {
430-
let func_name_complete = get_function_name_with_kind(func, parent_node);
308+
for (func, node, parent_node) in invalid_funcs {
309+
let func_name_complete = get_function_name_with_kind(node, parent_node);
431310

432311
let report_span = Span::new(func.span.start, func.params.span.start);
433312
let replace_span = Span::new(

0 commit comments

Comments
 (0)