mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
refactor(linter): add MixedTupleRuleConfig (#23396)
Added a new struct for 3 rules:
- `eslint/func-name-matching`
- `import/extension`
- `react/jsx-no-script-url`
These rules accept an enum configuration like:
```rust
enum ConfigOptions {
First(Option1),
Second(Option2),
Both(Option1, Option2)
}
```
Added the new struct for `eslint/func-name-matching` to test if the expected result matches the upstream configuration.
Changed the rule schema generation code, so enums (`subschema with any_of`), will be folded, Allowing us to support the 3 rules.
This commit is contained in:
1 parent
a8dce46fcd
commit
fef29bdbce
6 files changed
+511
-237
No files matched your search
@@ -80,12 +80,13 @@ export type CurlyType = "all" | "multi" | "multi-line" | "multi-or-nest";
|
||||
export type CurlyConsistent = "consistent";
|
||||
export type CompareType = "always" | "smart";
|
||||
export type NullType = "always" | "never" | "ignore";
|
||||
export type DummyRule = AllowWarnDeny | [AllowWarnDeny, ...unknown[]];
|
||||
export type FuncNameMatchingMode = "always" | "never";
|
||||
export type FuncNamesConfigType = "always" | "as-needed" | "never";
|
||||
export type Style = "expression" | "declaration";
|
||||
export type NamedExports = "ignore" | "expression" | "declaration";
|
||||
export type PairOrder = "anyOrder" | "getBeforeSet" | "setBeforeGet";
|
||||
export type Mode = "prefer-top-level" | "prefer-inline";
|
||||
export type DummyRule = AllowWarnDeny | [AllowWarnDeny, ...unknown[]];
|
||||
export type AbsoluteFirst = "absolute-first" | "disable-absolute-first";
|
||||
export type MaxDependenciesConfigJson = number | MaxDependenciesConfig;
|
||||
export type Target = "single" | "any";
|
||||
@@ -829,7 +830,7 @@ export interface DummyRuleMap {
|
||||
"block-scoped-var"?: RuleNoConfig;
|
||||
"capitalized-comments"?: RuleNoConfig | [AllowWarnDeny, AlwaysNever] | [AllowWarnDeny, AlwaysNever, OptionsJsonEnum];
|
||||
"class-methods-use-this"?: RuleNoConfig | [AllowWarnDeny, ClassMethodsUseThisConfig];
|
||||
complexity?: RuleNoConfig | [AllowWarnDeny, number | ComplexityConfig];
|
||||
complexity?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, ComplexityConfig]);
|
||||
"constructor-super"?: RuleNoConfig;
|
||||
curly?: RuleNoConfig | [AllowWarnDeny, CurlyType] | [AllowWarnDeny, CurlyType, CurlyConsistent];
|
||||
"default-case"?: RuleNoConfig | [AllowWarnDeny, DefaultCaseConfig];
|
||||
@@ -837,7 +838,14 @@ export interface DummyRuleMap {
|
||||
"default-param-last"?: RuleNoConfig;
|
||||
eqeqeq?: RuleNoConfig | [AllowWarnDeny, CompareType] | [AllowWarnDeny, CompareType, EqeqeqOptions];
|
||||
"for-direction"?: RuleNoConfig;
|
||||
"func-name-matching"?: DummyRule;
|
||||
"func-name-matching"?:
|
||||
| RuleNoConfig
|
||||
| (
|
||||
| [AllowWarnDeny, FuncNameMatchingMode]
|
||||
| [AllowWarnDeny, FuncNameMatchingMode, FuncNameMatchingConfig]
|
||||
| [AllowWarnDeny, FuncNameMatchingMode]
|
||||
| [AllowWarnDeny, FuncNameMatchingConfig]
|
||||
);
|
||||
"func-names"?:
|
||||
| RuleNoConfig
|
||||
| [AllowWarnDeny, FuncNamesConfigType]
|
||||
@@ -1014,13 +1022,13 @@ export interface DummyRuleMap {
|
||||
| RuleNoConfig
|
||||
| [AllowWarnDeny, AlwaysNever]
|
||||
| [AllowWarnDeny, AlwaysNever, LogicalAssignmentOperatorsConfig];
|
||||
"max-classes-per-file"?: RuleNoConfig | [AllowWarnDeny, number | MaxClassesPerFileConfig];
|
||||
"max-depth"?: RuleNoConfig | [AllowWarnDeny, number | MaxDepth];
|
||||
"max-lines"?: RuleNoConfig | [AllowWarnDeny, number | MaxLinesConfig];
|
||||
"max-lines-per-function"?: RuleNoConfig | [AllowWarnDeny, number | MaxLinesPerFunctionConfig];
|
||||
"max-nested-callbacks"?: RuleNoConfig | [AllowWarnDeny, number | MaxNestedCallbacks];
|
||||
"max-params"?: RuleNoConfig | [AllowWarnDeny, number | MaxParamsConfig];
|
||||
"max-statements"?: RuleNoConfig | [AllowWarnDeny, number | MaxStatementsConfig];
|
||||
"max-classes-per-file"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxClassesPerFileConfig]);
|
||||
"max-depth"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxDepth]);
|
||||
"max-lines"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxLinesConfig]);
|
||||
"max-lines-per-function"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxLinesPerFunctionConfig]);
|
||||
"max-nested-callbacks"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxNestedCallbacks]);
|
||||
"max-params"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxParamsConfig]);
|
||||
"max-statements"?: RuleNoConfig | ([AllowWarnDeny, number] | [AllowWarnDeny, MaxStatementsConfig]);
|
||||
"new-cap"?: RuleNoConfig | [AllowWarnDeny, NewCapConfig];
|
||||
"nextjs/google-font-display"?: RuleNoConfig;
|
||||
"nextjs/google-font-preconnect"?: RuleNoConfig;
|
||||
@@ -1800,6 +1808,16 @@ export interface EqeqeqOptions {
|
||||
*/
|
||||
null?: NullType;
|
||||
}
|
||||
export interface FuncNameMatchingConfig {
|
||||
/**
|
||||
* If `considerPropertyDescriptor` is set to `true`, the check will take into account the use of `Object.create`, `Object.defineProperty`, `Object.defineProperties`, and `Reflect.defineProperty`.
|
||||
*/
|
||||
considerPropertyDescriptor?: boolean;
|
||||
/**
|
||||
* If `includeCommonJSModuleExports` is set to `true`, `module.exports` and `module["exports"]` will be checked by this rule.
|
||||
*/
|
||||
includeCommonJSModuleExports?: boolean;
|
||||
}
|
||||
export interface FuncNamesGeneratorsConfig {
|
||||
/**
|
||||
* Configuration for generator function expressions. If not specified, uses the
|
||||
|
||||
@@ -397,104 +397,123 @@ impl JsonSchema for OxlintRules {
|
||||
.into()
|
||||
}
|
||||
|
||||
fn append_allow_warn_deny_to_schema(
|
||||
config_schema: Schema,
|
||||
r#gen: &mut SchemaGenerator,
|
||||
) -> Schema {
|
||||
let Schema::Object(mut obj) = config_schema else {
|
||||
return SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<AllowWarnDeny>(),
|
||||
config_schema,
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into();
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
(u8::from(obj.array.is_some())
|
||||
+ u8::from(obj.object.is_some())
|
||||
+ u8::from(obj.reference.is_some()))
|
||||
<= 1,
|
||||
"Expected rule schema to be either an object, an array, or a reference, but not multiple"
|
||||
);
|
||||
|
||||
if let Some(reference) = obj.reference {
|
||||
return SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<AllowWarnDeny>(),
|
||||
Schema::Object(SchemaObject {
|
||||
reference: Some(reference),
|
||||
..Default::default()
|
||||
}),
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into();
|
||||
}
|
||||
|
||||
if let Some(array) = obj.array {
|
||||
let items = match array.items {
|
||||
None => vec![r#gen.subschema_for::<AllowWarnDeny>()],
|
||||
Some(SingleOrVec::Single(config)) => {
|
||||
vec![r#gen.subschema_for::<AllowWarnDeny>(), *config]
|
||||
}
|
||||
Some(SingleOrVec::Vec(configs)) => {
|
||||
let mut items =
|
||||
Vec::with_capacity(configs.len().saturating_add(1));
|
||||
items.push(r#gen.subschema_for::<AllowWarnDeny>());
|
||||
items.extend(configs);
|
||||
items
|
||||
}
|
||||
};
|
||||
|
||||
let config_length = items.len() as u32;
|
||||
|
||||
return SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(items)),
|
||||
min_items: Some(2),
|
||||
max_items: Some(config_length),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into();
|
||||
}
|
||||
|
||||
if let Some(subschemas) = &mut obj.subschemas
|
||||
&& let Some(any_of) = &subschemas.any_of
|
||||
{
|
||||
subschemas.any_of = Some(
|
||||
any_of
|
||||
.iter()
|
||||
.map(|schema| {
|
||||
append_allow_warn_deny_to_schema(schema.clone(), r#gen)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
|
||||
return obj.into();
|
||||
}
|
||||
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<AllowWarnDeny>(),
|
||||
Schema::Object(obj),
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
let Some(schema) = r.schema(r#gen) else {
|
||||
return r#gen.subschema_for::<RuleNoConfig>();
|
||||
};
|
||||
|
||||
let schema = resolve_references_in_schema(&schema, r#gen).clone();
|
||||
|
||||
let Schema::Object(obj) = schema else {
|
||||
let array_schema = SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<AllowWarnDeny>(),
|
||||
Schema::Bool(true),
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into();
|
||||
return with_default_rule_schema(array_schema, r#gen);
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
(u8::from(obj.array.is_some())
|
||||
+ u8::from(obj.object.is_some())
|
||||
+ u8::from(obj.reference.is_some()))
|
||||
<= 1,
|
||||
"Expected rule schema to be either an object, an array, or a reference, but not multiple"
|
||||
);
|
||||
|
||||
if let Some(reference) = obj.reference {
|
||||
let array_schema = SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<AllowWarnDeny>(),
|
||||
Schema::Object(SchemaObject {
|
||||
reference: Some(reference),
|
||||
..Default::default()
|
||||
}),
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into();
|
||||
return with_default_rule_schema(array_schema, r#gen);
|
||||
}
|
||||
|
||||
if let Some(array) = obj.array {
|
||||
let items = match array.items {
|
||||
None => vec![r#gen.subschema_for::<AllowWarnDeny>()],
|
||||
Some(SingleOrVec::Single(config)) => {
|
||||
vec![r#gen.subschema_for::<AllowWarnDeny>(), *config]
|
||||
}
|
||||
Some(SingleOrVec::Vec(configs)) => {
|
||||
let mut items = Vec::with_capacity(configs.len().saturating_add(1));
|
||||
items.push(r#gen.subschema_for::<AllowWarnDeny>());
|
||||
items.extend(configs);
|
||||
items
|
||||
}
|
||||
};
|
||||
|
||||
let config_length = items.len() as u32;
|
||||
|
||||
let array_schema = SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(items)),
|
||||
min_items: Some(2),
|
||||
max_items: Some(config_length),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into();
|
||||
return with_default_rule_schema(array_schema, r#gen);
|
||||
}
|
||||
|
||||
let array_schema = Schema::Object(SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<AllowWarnDeny>(),
|
||||
Schema::Object(obj),
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
with_default_rule_schema(array_schema, r#gen)
|
||||
let schema = append_allow_warn_deny_to_schema(schema, r#gen);
|
||||
with_default_rule_schema(schema, r#gen)
|
||||
}
|
||||
|
||||
let dummy_schema = r#gen.subschema_for::<DummyRule>();
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
use std::borrow::Cow;
|
||||
use std::{fmt, hash::Hash};
|
||||
|
||||
use schemars::{JsonSchema, SchemaGenerator, schema::Schema};
|
||||
use schemars::{
|
||||
JsonSchema, SchemaGenerator,
|
||||
schema::{InstanceType, Schema, SchemaObject},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use oxc_semantic::AstTypesBitset;
|
||||
@@ -226,6 +229,116 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper type for deserializing ESLint-style mixed tuple rule configurations, where the first configuration object can be skipped.
|
||||
///
|
||||
/// Some ESLint rules take configurations in tuple form, e.g. `["foo", "qux", { "bar": "baz" }]`
|
||||
/// where the first argument is optional and the second argument is the actual configuration object.
|
||||
/// This type deserializes the array as a tuple `(Option<T1>, Option<T2>) | (Option<T2>)`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MixedTupleRuleConfig<T1, T2>(pub T1, pub T2);
|
||||
|
||||
impl<T1: Default, T2: Default> Default for MixedTupleRuleConfig<T1, T2> {
|
||||
fn default() -> Self {
|
||||
Self(T1::default(), T2::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T1, T2> serde::Deserialize<'de> for MixedTupleRuleConfig<T1, T2>
|
||||
where
|
||||
T1: serde::de::DeserializeOwned + Default,
|
||||
T2: serde::de::DeserializeOwned + Default,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
let value = serde_json::Value::deserialize(deserializer)?;
|
||||
|
||||
if let serde_json::Value::Array(arr) = value {
|
||||
let config = match arr.len() {
|
||||
0 => Self(T1::default(), T2::default()),
|
||||
1 => {
|
||||
// If there's only one element, we need to determine whether it's T1 or T2.
|
||||
// We can try deserializing it as T2 first, and if that fails, try T1.
|
||||
let first_value = &arr[0];
|
||||
if let Ok(t2) = T2::deserialize(first_value) {
|
||||
Self(T1::default(), t2)
|
||||
} else if let Ok(t1) = T1::deserialize(first_value) {
|
||||
Self(t1, T2::default())
|
||||
} else {
|
||||
return Err(D::Error::custom(
|
||||
"Expected configuration to match either the first or second tuple type",
|
||||
));
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
let t1 = T1::deserialize(&arr[0]).map_err(|e| {
|
||||
D::Error::custom(format!("Error deserializing first tuple element: {e}"))
|
||||
})?;
|
||||
let t2 = T2::deserialize(&arr[1]).map_err(|e| {
|
||||
D::Error::custom(format!("Error deserializing second tuple element: {e}"))
|
||||
})?;
|
||||
Self(t1, t2)
|
||||
}
|
||||
_ => {
|
||||
return Err(D::Error::custom(
|
||||
"Expected at most 2 elements in the configuration array",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(config)
|
||||
} else if value == serde_json::Value::Null {
|
||||
// Missing configuration (null) is treated as default (no rule options provided)
|
||||
Ok(Self(T1::default(), T2::default()))
|
||||
} else {
|
||||
Err(D::Error::custom("Expected array for rule configuration"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2> JsonSchema for MixedTupleRuleConfig<T1, T2>
|
||||
where
|
||||
T1: JsonSchema,
|
||||
T2: JsonSchema,
|
||||
{
|
||||
fn schema_name() -> String {
|
||||
"MixedTupleRuleConfig".to_string()
|
||||
}
|
||||
|
||||
fn is_referenceable() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn json_schema(r#gen: &mut SchemaGenerator) -> Schema {
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
|
||||
any_of: Some(vec![
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(schemars::schema::ArrayValidation {
|
||||
items: Some(schemars::schema::SingleOrVec::Vec(vec![
|
||||
r#gen.subschema_for::<T1>(),
|
||||
r#gen.subschema_for::<T2>(),
|
||||
])),
|
||||
min_items: Some(2),
|
||||
max_items: Some(2),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into(),
|
||||
r#gen.subschema_for::<T1>(),
|
||||
r#gen.subschema_for::<T2>(),
|
||||
]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RuleRunner: Rule {
|
||||
/// `AstType`s that this rule acts on, or `None` if the codegen
|
||||
/// can't figure it out and the linter should call `run` on every node.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize, de};
|
||||
use serde_json::Value;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use oxc_ast::{
|
||||
AstKind,
|
||||
@@ -19,7 +18,7 @@ use oxc_syntax::{identifier::is_identifier_name, keyword::is_reserved_keyword};
|
||||
use crate::{
|
||||
AstNode,
|
||||
context::LintContext,
|
||||
rule::{Rule, TupleRuleConfig},
|
||||
rule::{MixedTupleRuleConfig, Rule},
|
||||
};
|
||||
|
||||
fn func_name_matching_diagnostic(
|
||||
@@ -68,41 +67,9 @@ struct FuncNameMatchingConfig {
|
||||
include_common_js_module_exports: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]
|
||||
/// This rule takes an optional string of `"always"` or `"never"` (when omitted, it defaults to `"always"`), and an optional options object with two properties `considerPropertyDescriptor` and `includeCommonJSModuleExports`.
|
||||
pub struct FuncNameMatching(FuncNameMatchingMode, FuncNameMatchingConfig);
|
||||
|
||||
impl<'de> Deserialize<'de> for FuncNameMatching {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let values = Vec::<Value>::deserialize(deserializer)?;
|
||||
let mut mode = FuncNameMatchingMode::Always;
|
||||
let mut options = FuncNameMatchingConfig::default();
|
||||
|
||||
match values.as_slice() {
|
||||
[] => {}
|
||||
[first] if first.is_string() => {
|
||||
mode = serde_json::from_value(first.clone()).map_err(de::Error::custom)?;
|
||||
}
|
||||
[first] if first.is_object() => {
|
||||
options = serde_json::from_value(first.clone()).map_err(de::Error::custom)?;
|
||||
}
|
||||
[first, second] if first.is_string() && second.is_object() => {
|
||||
mode = serde_json::from_value(first.clone()).map_err(de::Error::custom)?;
|
||||
options = serde_json::from_value(second.clone()).map_err(de::Error::custom)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(de::Error::custom(
|
||||
r#"expected [], ["always"|"never"], [options], or ["always"|"never", options]"#,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self(mode, options))
|
||||
}
|
||||
}
|
||||
pub struct FuncNameMatching(MixedTupleRuleConfig<FuncNameMatchingMode, FuncNameMatchingConfig>);
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
@@ -221,14 +188,16 @@ declare_oxc_lint!(
|
||||
eslint,
|
||||
style,
|
||||
none,
|
||||
config = FuncNameMatching,
|
||||
config = MixedTupleRuleConfig<FuncNameMatchingMode, FuncNameMatchingConfig>,
|
||||
version = "1.62.0",
|
||||
short_description = "Requires function expression names to match the variable or property names they are assigned to, or disallows such matches with `\"never\"`.",
|
||||
);
|
||||
|
||||
impl Rule for FuncNameMatching {
|
||||
fn from_configuration(value: serde_json::Value) -> Result<Self, serde_json::error::Error> {
|
||||
serde_json::from_value::<TupleRuleConfig<Self>>(value).map(TupleRuleConfig::into_inner)
|
||||
serde_json::from_value::<MixedTupleRuleConfig<FuncNameMatchingMode, FuncNameMatchingConfig>>(
|
||||
value,
|
||||
).map(Self)
|
||||
}
|
||||
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
@@ -250,7 +219,8 @@ impl Rule for FuncNameMatching {
|
||||
return;
|
||||
};
|
||||
|
||||
if !self.1.include_common_js_module_exports && is_module_exports(&assign_expr.left)
|
||||
if !self.0.1.include_common_js_module_exports
|
||||
&& is_module_exports(&assign_expr.left)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -274,7 +244,7 @@ impl Rule for FuncNameMatching {
|
||||
|
||||
impl FuncNameMatching {
|
||||
fn should_warn(&self, name: &str, func_name: &str) -> bool {
|
||||
match self.0 {
|
||||
match self.0.0 {
|
||||
FuncNameMatchingMode::Always => name != func_name,
|
||||
FuncNameMatchingMode::Never => name == func_name,
|
||||
}
|
||||
@@ -292,7 +262,7 @@ impl FuncNameMatching {
|
||||
name,
|
||||
func_name.name,
|
||||
is_property,
|
||||
self.0,
|
||||
self.0.0,
|
||||
func_name.span,
|
||||
));
|
||||
}
|
||||
@@ -310,7 +280,7 @@ impl FuncNameMatching {
|
||||
if property_key_is_identifier(&property.key) && !property.computed {
|
||||
let Some(property_name) = property.key.static_name() else { return };
|
||||
|
||||
if self.1.consider_property_descriptor && property_name == "value" {
|
||||
if self.0.1.consider_property_descriptor && property_name == "value" {
|
||||
match property_descriptor_name(node, ctx) {
|
||||
DescriptorName::Name(descriptor_name) => {
|
||||
self.report_if_should_warn(
|
||||
|
||||
@@ -13,22 +13,21 @@ use crate::rules::RuleEnum;
|
||||
/// These should return the DummyRule struct/schema instead of the actual rule struct/schema,
|
||||
/// until we verify that the rule's schema is valid and can be generated by schemars.
|
||||
#[cfg(feature = "ruledocs")]
|
||||
const NO_VERIFIED_VALID_SCHEMA: [&str; 16] = [
|
||||
"eslint/func-name-matching", // second config can be on first position like [AllowWarnDeny, Config1, Config2] | [AllowWarnDeny, Config1] | [AllowWarnDeny, Config2]
|
||||
const NO_VERIFIED_VALID_SCHEMA: [&str; 15] = [
|
||||
"eslint/no-restricted-globals", // uses spread syntax like [AllowWarnDeny, ...Config]
|
||||
"eslint/no-restricted-imports", // uses spread syntax like [AllowWarnDeny, ...Config]
|
||||
"eslint/no-restricted-properties", // uses spread syntax like [AllowWarnDeny, ...Config]
|
||||
"node/callback-return", // uses array syntax [AllowWarnDeny, string[]]
|
||||
"import/extensions", // second config can be on first position like[AllowWarnDeny, Config1, Config2] | [AllowWarnDeny, Config1] | [AllowWarnDeny, Config2]
|
||||
"jest/prefer-lowercase-title", // has options from other rule #23186
|
||||
"jest/valid-title", // has options from other rule #23186
|
||||
"node/callback-return", // uses array syntax [AllowWarnDeny, string[]]
|
||||
"jest/prefer-lowercase-title", // has options from other rule #23186
|
||||
"jest/valid-title", // has options from other rule #23186
|
||||
"vitest/prefer-lowercase-title", // has options from other rule #23186
|
||||
"vitest/valid-title", // has options from other rule #23186
|
||||
"jsdoc/require-param", // missing options #23356
|
||||
"unicorn/filename-case", // missing options #23248
|
||||
"vitest/valid-title", // has options from other rule #23186
|
||||
"jsdoc/require-param", // missing options #23356
|
||||
"unicorn/filename-case", // missing options #23248
|
||||
"unicorn/numeric-separators-style", // missing options #23383
|
||||
"jsx_a11y/no-noninteractive-element-interactions", // TS Generation generates ts 2411 error
|
||||
"eslint/prefer-destructuring",
|
||||
"import/extensions",
|
||||
"react/jsx-no-script-url",
|
||||
];
|
||||
|
||||
|
||||
@@ -2276,24 +2276,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/ComplexityConfig"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -2376,7 +2386,57 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
"func-name-matching": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/FuncNameMatchingMode"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/FuncNameMatchingConfig"
|
||||
}
|
||||
],
|
||||
"maxItems": 3,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/FuncNameMatchingMode"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/FuncNameMatchingConfig"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"func-names": {
|
||||
"anyOf": [
|
||||
@@ -3970,24 +4030,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxClassesPerFileConfig"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -3997,24 +4067,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxDepth"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -4024,24 +4104,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxLinesConfig"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -4051,24 +4141,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxLinesPerFunctionConfig"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -4078,24 +4178,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxNestedCallbacks"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -4105,24 +4215,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxParamsConfig"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -4132,24 +4252,34 @@
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/MaxStatementsConfig"
|
||||
}
|
||||
]
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -10671,6 +10801,31 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"FuncNameMatchingConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"considerPropertyDescriptor": {
|
||||
"description": "If `considerPropertyDescriptor` is set to `true`, the check will take into account the use of `Object.create`, `Object.defineProperty`, `Object.defineProperties`, and `Reflect.defineProperty`.",
|
||||
"default": false,
|
||||
"type": "boolean",
|
||||
"markdownDescription": "If `considerPropertyDescriptor` is set to `true`, the check will take into account the use of `Object.create`, `Object.defineProperty`, `Object.defineProperties`, and `Reflect.defineProperty`."
|
||||
},
|
||||
"includeCommonJSModuleExports": {
|
||||
"description": "If `includeCommonJSModuleExports` is set to `true`, `module.exports` and `module[\"exports\"]` will be checked by this rule.",
|
||||
"default": false,
|
||||
"type": "boolean",
|
||||
"markdownDescription": "If `includeCommonJSModuleExports` is set to `true`, `module.exports` and `module[\"exports\"]` will be checked by this rule."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FuncNameMatchingMode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"always",
|
||||
"never"
|
||||
]
|
||||
},
|
||||
"FuncNames": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
|
||||
Reference in new issue
Block a user