From 72d55c139b9220c6aabd221cd7c558680b209b70 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sat, 3 Feb 2024 10:24:35 +0800 Subject: [PATCH 01/17] feat: (wip) array-type config --- crates/oxc_linter/src/rules.rs | 2 + .../src/rules/typescript/array_type.rs | 98 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 crates/oxc_linter/src/rules/typescript/array_type.rs diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 0c0422b0b1bde..5880df7a2d67c 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -100,6 +100,7 @@ mod eslint { mod typescript { pub mod adjacent_overload_signatures; + pub mod array_type; pub mod ban_ts_comment; pub mod ban_types; pub mod no_duplicate_enum_values; @@ -389,6 +390,7 @@ oxc_macros::declare_all_lint_rules! { eslint::use_isnan, eslint::valid_typeof, typescript::adjacent_overload_signatures, + typescript::array_type, typescript::ban_ts_comment, typescript::ban_types, typescript::no_duplicate_enum_values, diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs new file mode 100644 index 0000000000000..1f8c12fa99f32 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -0,0 +1,98 @@ +use oxc_semantic::AstNode; +use oxc_span::{GetSpan, Span}; +use oxc_macros::declare_oxc_lint; + +use crate::{context::LintContext, rule::Rule}; + +#[derive(Debug, Default, Clone)] +pub struct ArrayType(Box); + +declare_oxc_lint!( + /// ### What it does + /// Require consistently using either `T[]` or `Array` for arrays. + /// + /// ### Why is this bad? + /// Using the `Array` type directly is not idiomatic. Instead, use the array type `T[]` or `Array`. + /// + /// ### Example + /// ```typescript + /// const arr: Array = new Array(); + /// const arr: number[] = new Array(); + /// ``` + ArrayType, + style, +); + +#[derive(Debug, Default, Clone)] +pub struct ArrayTypeConfig { + // The array type expected for mutable cases. + default: ArrayOption, + // The array type expected for readonly cases. If omitted, the value for `default` will be used. + readonly: Option, +} + +impl std::ops::Deref for ArrayType { + type Target = ArrayTypeConfig; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[derive(Debug, Default, Clone)] +pub enum ArrayOption { + ArraySimple, + #[default] + Array, + Generic, +} + +impl Rule for ArrayType { + fn from_configuration(value: serde_json::Value) -> Self { + Self(Box::new(ArrayTypeConfig { + default: value + .get(0) + .and_then(|v| v.get("default")) + .and_then(serde_json::Value::as_str) + .map_or_else(|| ArrayOption::Array, |s| match s { + "array" => ArrayOption::Array, + "generic" => ArrayOption::Generic, + _ => ArrayOption::ArraySimple, + }), + readonly: value + .get(0) + .and_then(|v| v.get("readonly")) + .and_then(serde_json::Value::as_str) + .map_or_else(|| None, |s| match s { + "array" => Some(ArrayOption::Array), + "generic" => Some(ArrayOption::Generic), + _ => Some(ArrayOption::ArraySimple), + }), + })) + } + fn run<'a>(&self, _node: &AstNode<'a>, _ctx: &LintContext<'a>) { + let default_config = &self.default; + let readonly_config = &self.readonly.clone().unwrap_or(default_config.clone()); + + println!("{:?} {:?}", default_config, readonly_config); + // if let ArrayOption::Array = default_config { + // println!("111"); + // } else { + // println!("222"); + // } + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass: Vec<(&str, Option)> = vec![ + ("let a: number[] = [];", None), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) + ]; + let fail: Vec<(&str, Option)> = vec![ + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ]; + + Tester::new(ArrayType::NAME, pass, fail).test(); +} From 22a31a71aaceaaeb31e54610e4fc74cbf534bbfd Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sat, 3 Feb 2024 14:20:10 +0800 Subject: [PATCH 02/17] feat: support check and report error generic --- .../src/rules/typescript/array_type.rs | 193 ++++++++++++++++-- 1 file changed, 174 insertions(+), 19 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index 1f8c12fa99f32..2da0c1d96efc9 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -1,8 +1,13 @@ +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::{self, Error}, +}; +use oxc_ast::{ast::{TSArrayType, TSType, TSTypeOperator}, AstKind}; use oxc_semantic::AstNode; -use oxc_span::{GetSpan, Span}; +use oxc_span::Span; use oxc_macros::declare_oxc_lint; -use crate::{context::LintContext, rule::Rule}; +use crate::{context::LintContext, fixer::Fix, rule::Rule}; #[derive(Debug, Default, Clone)] pub struct ArrayType(Box); @@ -23,6 +28,29 @@ declare_oxc_lint!( style, ); +#[derive(Debug, Diagnostic, Error)] +pub enum ArrayTypeDiagnostic { + #[error("Array type using '{0}{2}[]' is forbidden. Use '{1}<{2}>' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringGeneric(String, String, String, #[label] Span), + + #[error("Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringGenericSimple(String, String, String, #[label] Span), + + #[error("Array type using '{1}<{2}>' is forbidden. Use '{0}{2}[]' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringArray(String, String, String, #[label] Span), + + #[error("Array type using '{1}<{2}>' is forbidden for simple types. Use '{0}{2}[]' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringArraySimple(String, String, String, #[label] Span), +} + #[derive(Debug, Default, Clone)] pub struct ArrayTypeConfig { // The array type expected for mutable cases. @@ -40,9 +68,9 @@ impl std::ops::Deref for ArrayType { } #[derive(Debug, Default, Clone)] pub enum ArrayOption { - ArraySimple, #[default] Array, + ArraySimple, Generic, } @@ -69,30 +97,157 @@ impl Rule for ArrayType { }), })) } - fn run<'a>(&self, _node: &AstNode<'a>, _ctx: &LintContext<'a>) { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; let readonly_config = &self.readonly.clone().unwrap_or(default_config.clone()); - println!("{:?} {:?}", default_config, readonly_config); - // if let ArrayOption::Array = default_config { - // println!("111"); - // } else { - // println!("222"); - // } + match node.kind() { + AstKind::TSTypeAnnotation(ts_type_annotation) => { + if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + // Array 泛型 + if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { + println!("{:#?}", ts_type_reference); + } + }, + _ => {} + } + } +} + +fn check_and_report_error_generic( + config: &ArrayOption, + type_annotation_span: Span, + element_type: &TSType, + ctx: &LintContext, + is_readonly: bool, +) { + if let ArrayOption::Array = config { + return; + } + if let ArrayOption::ArraySimple = config { + if is_simple_type(element_type) { + return; + } + } + let source_text = ctx.source_text().to_string(); + + let readonly_prefix = if is_readonly { "readonly " } else { "" }; + let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; + let message_type = get_message_type(element_type, &source_text); + + let diagnostic = if let ArrayOption::Generic = config { + ArrayTypeDiagnostic::ErrorStringGeneric( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + type_annotation_span, + ) + } else { + ArrayTypeDiagnostic::ErrorStringGenericSimple( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + type_annotation_span, + ) + }; + let element_type_span = get_element_type_span(&element_type); + let Some(element_type_span) = element_type_span else { return }; + + ctx.diagnostic_with_fix(diagnostic, || { + let element_type_span = &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; + + Fix::new( + array_type_identifier.to_string() + "<" + element_type_span + ">", + Span { start: type_annotation_span.start, end: type_annotation_span.end } + ) + }) +} + +// Check whatever node can be considered as simple type +fn is_simple_type(element_type: &TSType) -> bool { + match element_type { + // TODO: miss TSThisType Identifier + TSType::TSAnyKeyword(_) => true, + TSType::TSBooleanKeyword(_) => true, + TSType::TSNeverKeyword(_) => true, + TSType::TSNumberKeyword(_) => true, + TSType::TSBigIntKeyword(_) => true, + TSType::TSObjectKeyword(_) => true, + TSType::TSStringKeyword(_) => true, + TSType::TSSymbolKeyword(_) => true, + TSType::TSUnknownKeyword(_) => true, + TSType::TSVoidKeyword(_) => true, + TSType::TSNullKeyword(_) => true, + TSType::TSArrayType(_) => true, + TSType::TSUndefinedKeyword(_) => true, + TSType::TSQualifiedName(_) => true, + TSType::TSTypeReference(_) => { + // TODO: + true + }, + _ => false, + } + +} + +fn get_message_type<'a>(element_type: &'a TSType, source_text: &'a str) -> &'a str { + if is_simple_type(element_type) { + let element_type_span = get_element_type_span(element_type); + let Some(element_type_span) = element_type_span else { return "T" }; + return &source_text[element_type_span.start as usize..element_type_span.end as usize]; + } + "T" +} + +fn get_element_type_span(element_type: &TSType) -> Option { + match element_type { + // TODO: add more type + TSType::TSNumberKeyword(t) => Some(t.span), + TSType::TSStringKeyword(t) => Some(t.span), + _ => None, } } #[test] fn test() { - use crate::tester::Tester; + use crate::tester::Tester; - let pass: Vec<(&str, Option)> = vec![ - ("let a: number[] = [];", None), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) - ]; - let fail: Vec<(&str, Option)> = vec![ - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), - ]; + let pass: Vec<(&str, Option)> = vec![ + ("let a: number[] = [];", None), + // ("const y: readonly string[] = ['a', 'b'];", None), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) + ]; + let fail: Vec<(&str, Option)> = vec![ + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ]; + let fix = vec![ + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ]; - Tester::new(ArrayType::NAME, pass, fail).test(); + Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); } From 7c2d9c35bce42afe92d7eb4507bb48df6689a817 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sat, 3 Feb 2024 18:52:53 +0800 Subject: [PATCH 03/17] feat: support fix string array --- .../src/rules/typescript/array_type.rs | 259 ++++++++++++++++-- 1 file changed, 237 insertions(+), 22 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index 2da0c1d96efc9..cef9ceb119b3b 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -2,7 +2,7 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::{self, Error}, }; -use oxc_ast::{ast::{TSArrayType, TSType, TSTypeOperator}, AstKind}; +use oxc_ast::{ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, AstKind}; use oxc_semantic::AstNode; use oxc_span::Span; use oxc_macros::declare_oxc_lint; @@ -99,7 +99,7 @@ impl Rule for ArrayType { } fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; - let readonly_config = &self.readonly.clone().unwrap_or(default_config.clone()); + let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { @@ -116,7 +116,7 @@ impl Rule for ArrayType { if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { if let TSTypeOperator::Readonly = &ts_operator_type.operator { if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( + check_and_report_error_generic( readonly_config, ts_operator_type.span, &array_type.element_type, @@ -127,9 +127,13 @@ impl Rule for ArrayType { } } - // Array 泛型 if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { - println!("{:#?}", ts_type_reference); + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); } }, _ => {} @@ -137,9 +141,29 @@ impl Rule for ArrayType { } } + +fn type_needs_parentheses(type_param: &TSType) -> bool { + match type_param { + TSType::TSTypeReference(node) => { + // TODO: + println!("node===> {:#?}", node); + // return type_needs_parentheses(ts_type_ref.type_name); + true + + }, + TSType::TSUnionType(_) => true, + TSType::TSFunctionType(_) => true, + TSType::TSIntersectionType(_) => true, + TSType::TSTypeOperatorType(_) => true, + TSType::TSInferType(_) => true, + TSType::TSConstructorType(_) => true, + _ => false, + } +} + fn check_and_report_error_generic( config: &ArrayOption, - type_annotation_span: Span, + type_reference_span: Span, element_type: &TSType, ctx: &LintContext, is_readonly: bool, @@ -163,34 +187,134 @@ fn check_and_report_error_generic( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), - type_annotation_span, + type_reference_span, ) } else { ArrayTypeDiagnostic::ErrorStringGenericSimple( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), - type_annotation_span, + type_reference_span, ) }; - let element_type_span = get_element_type_span(&element_type); + let element_type_span = get_ts_element_type_span(&element_type); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { - let element_type_span = &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let type_text = &source_text[element_type_span.start as usize..element_type_span.end as usize]; let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; Fix::new( - array_type_identifier.to_string() + "<" + element_type_span + ">", - Span { start: type_annotation_span.start, end: type_annotation_span.end } + array_type_identifier.to_string() + "<" + type_text + ">", + Span { start: type_reference_span.start, end: type_reference_span.end } ) }) } +fn check_and_report_error_array( + default_config: &ArrayOption, + readonly_config: &ArrayOption, + ts_type_reference: &TSTypeReference, + ctx: &LintContext, +) { + let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { return }; + + if ident_ref_type_name.name.as_str() != "ReadonlyArray" && ident_ref_type_name.name.as_str() != "Array" { + return; + } + let is_readonly_array_type = ident_ref_type_name.name == "ReadonlyArray"; + let config = if is_readonly_array_type { readonly_config } else { default_config }; + if let ArrayOption::Generic = config { + return; + } + let readonly_prefix: &str = if is_readonly_array_type { "readonly " } else { "" }; + let class_name = if is_readonly_array_type { "ReadonlyArray" } else { "Array" }; + let type_params = &ts_type_reference.type_parameters; + + if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { + let diagnostic = if let ArrayOption::Array = config { + ArrayTypeDiagnostic::ErrorStringArray( + readonly_prefix.to_string(), + class_name.to_string(), + "any".to_string(), + ts_type_reference.span, + ) + } else { + ArrayTypeDiagnostic::ErrorStringArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + "any".to_string(), + ts_type_reference.span, + ) + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new( + readonly_prefix.to_string() + "any[]", + ts_type_reference.span, + ) + }); + return; + } + if type_params.as_ref().unwrap().params.len() != 1 { + return; + } + let first_type_param = type_params.as_ref().unwrap().params.get(0).unwrap(); + if let ArrayOption::ArraySimple = config { + if !is_simple_type(first_type_param) { + return; + } + } + + let type_parens = type_needs_parentheses(first_type_param); + // TODO: support example: type Foo = ReadonlyArray[]; -> type Foo = (readonly object[])[]; + // let mut parent_parens: bool = readonly_prefix != ""; + // if let Some(parent) = ctx.nodes().parent_node(node.id()) { + // if let AstKind::TSTypeAnnotation(parent_node) = parent.kind() {} + // } else { + // parent_parens = false + // }; + let parent_parens = false; + + let element_type_span = get_ts_element_type_span(&first_type_param); + let Some(element_type_span) = element_type_span else { return }; + + let type_text = &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; + + let mut start = String::from(if parent_parens {"("} else {""}); + start.push_str(readonly_prefix); + start.push_str(if type_parens {"("} else {""}); + + let mut end = String::from(if type_parens {")"} else {""}); + end.push_str("[]"); + end.push_str(if parent_parens {")"} else {""}); + + let message_type = get_message_type(first_type_param, ctx.source_text()); + let diagnostic = if let ArrayOption::Array = config { + ArrayTypeDiagnostic::ErrorStringArray( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ) + } else { + ArrayTypeDiagnostic::ErrorStringArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ) + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new( + start + type_text + end.as_str(), + ts_type_reference.span, + ) + }); +} + // Check whatever node can be considered as simple type fn is_simple_type(element_type: &TSType) -> bool { match element_type { - // TODO: miss TSThisType Identifier TSType::TSAnyKeyword(_) => true, TSType::TSBooleanKeyword(_) => true, TSType::TSNeverKeyword(_) => true, @@ -205,7 +329,9 @@ fn is_simple_type(element_type: &TSType) -> bool { TSType::TSArrayType(_) => true, TSType::TSUndefinedKeyword(_) => true, TSType::TSQualifiedName(_) => true, - TSType::TSTypeReference(_) => { + TSType::TSThisKeyword(_) => true, + TSType::TSTypeReference(node) => { + println!("TSTypeReference ===> {:#?}", node); // TODO: true }, @@ -216,18 +342,49 @@ fn is_simple_type(element_type: &TSType) -> bool { fn get_message_type<'a>(element_type: &'a TSType, source_text: &'a str) -> &'a str { if is_simple_type(element_type) { - let element_type_span = get_element_type_span(element_type); + let element_type_span = get_ts_element_type_span(element_type); let Some(element_type_span) = element_type_span else { return "T" }; return &source_text[element_type_span.start as usize..element_type_span.end as usize]; } "T" } -fn get_element_type_span(element_type: &TSType) -> Option { - match element_type { - // TODO: add more type +fn get_ts_element_type_span(ts_type: &TSType) -> Option { + match ts_type { + TSType::TSAnyKeyword(t) => Some(t.span), TSType::TSNumberKeyword(t) => Some(t.span), TSType::TSStringKeyword(t) => Some(t.span), + TSType::TSBigIntKeyword(t) => Some(t.span), + TSType::TSBooleanKeyword(t) => Some(t.span), + TSType::TSNeverKeyword(t) => Some(t.span), + TSType::TSObjectKeyword(t) => Some(t.span), + TSType::TSSymbolKeyword(t) => Some(t.span), + TSType::TSUnknownKeyword(t) => Some(t.span), + TSType::TSVoidKeyword(t) => Some(t.span), + TSType::TSNullKeyword(t) => Some(t.span), + TSType::TSThisKeyword(t) => Some(t.span), + TSType::TSUndefinedKeyword(t) => Some(t.span), + + TSType::TSArrayType(t) => Some(t.span), + TSType::TSConditionalType(t) => Some(t.span), + TSType::TSConstructorType(t) => Some(t.span), + TSType::TSFunctionType(t) => Some(t.span), + TSType::TSImportType(t) => Some(t.span), + TSType::TSIndexedAccessType(t) => Some(t.span), + TSType::TSInferType(t) => Some(t.span), + TSType::TSIntersectionType(t) => Some(t.span), + TSType::TSLiteralType(t) => Some(t.span), + TSType::TSMappedType(t) => Some(t.span), + TSType::TSQualifiedName(t) => Some(t.span), + TSType::TSTemplateLiteralType(t) => Some(t.span), + TSType::TSTupleType(t) => Some(t.span), + TSType::TSTypeLiteral(t) => Some(t.span), + TSType::TSTypeOperatorType(t) => Some(t.span), + TSType::TSTypePredicate(t) => Some(t.span), + TSType::TSTypeQuery(t) => Some(t.span), + TSType::TSTypeReference(t) => Some(t.span), + TSType::TSUnionType(t) => Some(t.span), + _ => None, } } @@ -235,18 +392,76 @@ fn get_element_type_span(element_type: &TSType) -> Option { #[test] fn test() { use crate::tester::Tester; - let pass: Vec<(&str, Option)> = vec![ - ("let a: number[] = [];", None), - // ("const y: readonly string[] = ['a', 'b'];", None), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) + ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic",}]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic",}]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), ]; let fail: Vec<(&str, Option)> = vec![ // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), ]; let fix = vec![ + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{ "default": "array-simple" }]))), + ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{ "default": "array-simple" }]))), ]; Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); From 94ab857ed2a0d83169388bbade5f96bd123c4e60 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sun, 4 Feb 2024 15:27:56 +0800 Subject: [PATCH 04/17] feat: add test case --- .../src/rules/typescript/array_type.rs | 631 +++++++++++++++--- 1 file changed, 546 insertions(+), 85 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index cef9ceb119b3b..aa1881fd1d5d8 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -97,10 +97,10 @@ impl Rule for ArrayType { }), })) } + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); - match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { @@ -136,20 +136,86 @@ impl Rule for ArrayType { ); } }, + AstKind::TSTypeAliasDeclaration(ts_type_annotation) => { + if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); + } + }, + AstKind::TSAsExpression(ts_as_expression) => { + if let TSType::TSArrayType(array_type) = &ts_as_expression.type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_as_expression.type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &ts_as_expression.type_annotation { + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); + } + }, _ => {} } } } - fn type_needs_parentheses(type_param: &TSType) -> bool { match type_param { TSType::TSTypeReference(node) => { - // TODO: - println!("node===> {:#?}", node); - // return type_needs_parentheses(ts_type_ref.type_name); + if let TSTypeName::IdentifierReference(identifier_reference) = &node.type_name { + return identifier_reference.name.as_str() == "ReadonlyArray"; + } true - }, TSType::TSUnionType(_) => true, TSType::TSFunctionType(_) => true, @@ -164,7 +230,7 @@ fn type_needs_parentheses(type_param: &TSType) -> bool { fn check_and_report_error_generic( config: &ArrayOption, type_reference_span: Span, - element_type: &TSType, + type_param: &TSType, ctx: &LintContext, is_readonly: bool, ) { @@ -172,7 +238,7 @@ fn check_and_report_error_generic( return; } if let ArrayOption::ArraySimple = config { - if is_simple_type(element_type) { + if is_simple_type(type_param) { return; } } @@ -180,7 +246,7 @@ fn check_and_report_error_generic( let readonly_prefix = if is_readonly { "readonly " } else { "" }; let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; - let message_type = get_message_type(element_type, &source_text); + let message_type = get_message_type(type_param, &source_text); let diagnostic = if let ArrayOption::Generic = config { ArrayTypeDiagnostic::ErrorStringGeneric( @@ -197,7 +263,7 @@ fn check_and_report_error_generic( type_reference_span, ) }; - let element_type_span = get_ts_element_type_span(&element_type); + let element_type_span = get_ts_element_type_span(&type_param); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { @@ -313,8 +379,8 @@ fn check_and_report_error_array( } // Check whatever node can be considered as simple type -fn is_simple_type(element_type: &TSType) -> bool { - match element_type { +fn is_simple_type(ts_type: &TSType) -> bool { + match ts_type { TSType::TSAnyKeyword(_) => true, TSType::TSBooleanKeyword(_) => true, TSType::TSNeverKeyword(_) => true, @@ -331,18 +397,34 @@ fn is_simple_type(element_type: &TSType) -> bool { TSType::TSQualifiedName(_) => true, TSType::TSThisKeyword(_) => true, TSType::TSTypeReference(node) => { - println!("TSTypeReference ===> {:#?}", node); - // TODO: - true + let type_name = TSTypeName::get_first_name(&node.type_name); + if type_name.name.as_str() == "Array" { + if node.type_parameters.is_none() { + return true; + } + if node.type_parameters.as_ref().unwrap().params.len() == 1 { + return is_simple_type(node.type_parameters.as_ref().unwrap().params.get(0).unwrap()); + } + } else { + if node.type_parameters.is_some() { + return false; + } + if let TSTypeName::IdentifierReference(_) = &node.type_name { + return true; + } + return false + } + false }, _ => false, } } -fn get_message_type<'a>(element_type: &'a TSType, source_text: &'a str) -> &'a str { - if is_simple_type(element_type) { - let element_type_span = get_ts_element_type_span(element_type); +// Get the type name from the type node. for example: `Array` -> `string` +fn get_message_type<'a>(type_param: &'a TSType, source_text: &'a str) -> &'a str { + if is_simple_type(type_param) { + let element_type_span = get_ts_element_type_span(type_param); let Some(element_type_span) = element_type_span else { return "T" }; return &source_text[element_type_span.start as usize..element_type_span.end as usize]; } @@ -392,76 +474,455 @@ fn get_ts_element_type_span(ts_type: &TSType) -> Option { #[test] fn test() { use crate::tester::Tester; + let pass: Vec<(&str, Option)> = vec![ - ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic",}]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic",}]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a = new Array();", Some(serde_json::json!([{"default":"array"}]))), + ("let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"generic"}]))), + ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + }", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + namespace fooName { + type BarType = { bar: string }; + type BazType = Arr; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array"}]))), + ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"array"}]))), + ("function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); + }", Some(serde_json::json!([{"default":"array"}]))), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + }", Some(serde_json::json!([{"default":"array"}]))), + ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + ("let xx: Array> = [[1, 2], [3]];", Some(serde_json::json!([{"default":"generic"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", Some(serde_json::json!([{"default":"generic"}]))), + ("function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", Some(serde_json::json!([{"default":"generic"}]))), + ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), + ("type fooUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [[]];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly Array[] = [[]];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), ]; - let fail: Vec<(&str, Option)> = vec![ - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), + + let fail = vec![ + ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: { foo: Array }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array<{ foo: Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + // ("let a: Array<{ foo: Foo | Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let v: Array = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let w: fooName.BazType[] = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array"}]))), + ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"array"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"array"}]))), + (" + function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + } + ", Some(serde_json::json!([{"default":"array"}]))), + ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array"}]))), + ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array"}]))), + ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array<>;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array<>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [1] as number[];", Some(serde_json::json!([{"default":"generic"}]))), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), + ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"generic"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"generic"}]))), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"generic"}]))), + ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"generic"}]))), + ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + // ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Foo = ReadonlyArray[];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: Array void> = [];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: ReadonlyArray void> = [];", Some(serde_json::json!([{"default":"array"}]))), ]; - let fix = vec![ - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), - ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{ "default": "array-simple" }]))), - ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{ "default": "array-simple" }]))), + + let fix: Vec<(&str, &str, Option)> = vec![ + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: bigint[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly bigint[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | bigint)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: { foo: Array }[] = [];", "let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array<{ foo: Bar[] }> = [];", "let a: Array<{ foo: Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + // ("let a: Array<{ foo: Foo | Bar[] }> = [];", "let a: Array<{ foo: Foo | Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("function foo(a: Array): Array {}", "function foo(a: Bar[]): Bar[] {}", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array-simple"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr>>> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", " + interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", " + function barFunction(bar: Array>) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let v: Array = [{ bar: 'bar' }];", "let v: fooName.BarType[] = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let w: fooName.BazType[] = [['baz']];", "let w: Array> = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array"}]))), + ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), + ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr[][]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", " + interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"array"}]))), + (" + function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + } + ", " + function fooFunction(foo: ArrayClass[]) { + return foo.map(e => e.foo); + } + ", Some(serde_json::json!([{"default":"array"}]))), + ("let fooVar: Array<(c: number) => number>;", "let fooVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type fooUnion = Array;", "type fooUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type fooIntersection = Array;", "type fooIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [1] as number[];", "let x: Array = [1] as Array;", Some(serde_json::json!([{"default":"generic"}]))), + // ("let y: string[] = >['2'];", "let y: Array = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), + ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"generic"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr>>> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", " + interface ArrayClass { + foo: Array; + bar: Array; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", " + function barFunction(bar: Array>) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"generic"}]))), + ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), + ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + } + ", " + interface FooInterface { + '.bar': { baz: Array }; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Unwrap = T extends Array ? E : T;", "type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + // ("type Unwrap = T extends (infer E)[] ? E : T;", "type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Foo = ReadonlyArray[];", "type Foo = (readonly object[])[];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: Array void> = [];", "const foo: (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: ReadonlyArray void> = [];", "const foo: readonly (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), ]; Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); From f7e42346ade01a99365c92a725047cdbe9a74eb4 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sun, 4 Feb 2024 15:54:16 +0800 Subject: [PATCH 05/17] refactor: extract common function --- .../src/rules/typescript/array_type.rs | 144 ++++++------------ 1 file changed, 47 insertions(+), 97 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index aa1881fd1d5d8..a093462f36634 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -101,114 +101,64 @@ impl Rule for ArrayType { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); + match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { - if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { - check_and_report_error_generic( - default_config, - array_type.span, - &array_type.element_type, - ctx, - false, - ); - } - - if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( - readonly_config, - ts_operator_type.span, - &array_type.element_type, - ctx, - true, - ); - } - } - } - - if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); - } + check(&ts_type_annotation.type_annotation, default_config, readonly_config, ctx); }, - AstKind::TSTypeAliasDeclaration(ts_type_annotation) => { - if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { - check_and_report_error_generic( - default_config, - array_type.span, - &array_type.element_type, - ctx, - false, - ); - } - - if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( - readonly_config, - ts_operator_type.span, - &array_type.element_type, - ctx, - true, - ); - } - } - } - - if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); - } + // for example: type barUnion = (string | number | boolean)[]; + AstKind::TSTypeAliasDeclaration(ts_alias_annotation) => { + check(&ts_alias_annotation.type_annotation, default_config, readonly_config, ctx); }, + // for example: let ya = [[1, '2']] as [number, string][]; AstKind::TSAsExpression(ts_as_expression) => { - if let TSType::TSArrayType(array_type) = &ts_as_expression.type_annotation { - check_and_report_error_generic( - default_config, - array_type.span, - &array_type.element_type, - ctx, - false, - ); - } - - if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_as_expression.type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( - readonly_config, - ts_operator_type.span, - &array_type.element_type, - ctx, - true, - ); - } - } - } - - if let TSType::TSTypeReference(ts_type_reference) = &ts_as_expression.type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); - } + check(&ts_as_expression.type_annotation, default_config, readonly_config, ctx); }, _ => {} } } } +fn check( + type_annotation: &TSType, + default_config: &ArrayOption, + readonly_config: &ArrayOption, + ctx: &LintContext, +) { + if let TSType::TSArrayType(array_type) = &type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &type_annotation { + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); + } +} + fn type_needs_parentheses(type_param: &TSType) -> bool { match type_param { TSType::TSTypeReference(node) => { From d2fc8b273d35edd6d206425d8f627c971d7e10b5 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 09:21:11 +0800 Subject: [PATCH 06/17] feat: add snapshot --- .../src/rules/typescript/array_type.rs | 2 +- .../oxc_linter/src/snapshots/array_type.snap | 569 ++++++++++++++++++ 2 files changed, 570 insertions(+), 1 deletion(-) create mode 100644 crates/oxc_linter/src/snapshots/array_type.snap diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index a093462f36634..df107489c04b1 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -875,5 +875,5 @@ fn test() { ("const foo: ReadonlyArray void> = [];", "const foo: readonly (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), ]; - Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); + Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); } diff --git a/crates/oxc_linter/src/snapshots/array_type.snap b/crates/oxc_linter/src/snapshots/array_type.snap new file mode 100644 index 0000000000000..7e4d0d0e22c7a --- /dev/null +++ b/crates/oxc_linter/src/snapshots/array_type.snap @@ -0,0 +1,569 @@ +--- +source: crates/oxc_linter/src/tester.rs +assertion_line: 150 +expression: array_type +--- + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'bigint[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: bigint[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | bigint)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly bigint[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | bigint)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly bigint[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly bigint[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | bigint)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ let a: { foo: Array }[] = []; + · ────────── + ╰──── + + ⚠ Array type using 'Bar[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:21] + 1 │ let a: Array<{ foo: Bar[] }> = []; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:17] + 1 │ function foo(a: Array): Array {} + · ────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:30] + 1 │ function foo(a: Array): Array {} + · ────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'undefined[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array = [undefined] as undefined[]; + · ──────────────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let z: Array = [3, '4']; + · ───── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ let ya = [[1, '2']] as [number, string][]; + · ────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ type Arr = Array; + · ──────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. + ╭─[array_type.tsx:3:14] + 2 │ interface ArrayClass { + 3 │ foo: Array; + · ──────── + 4 │ bar: T[]; + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function barFunction(bar: ArrayClass[]) { + · ──────────────────── + 3 │ return bar.map(e => e.bar); + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:13] + 1 │ let barVar: ((c: number) => number)[]; + · ───────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:17] + 1 │ type barUnion = (string | number | boolean)[]; + · ───────────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ type barIntersection = (string & number)[]; + · ─────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'undefined[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array = [undefined] as undefined[]; + · ──────────────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let z: Array = [3, '4']; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ type Arr = Array; + · ──────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:3:14] + 2 │ interface ArrayClass { + 3 │ foo: Array; + · ──────── + 4 │ bar: T[]; + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function fooFunction(foo: Array>) { + · ───────────────────────── + 3 │ return foo.map(e => e.foo); + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:13] + 1 │ let fooVar: Array<(c: number) => number>; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:17] + 1 │ type fooUnion = Array; + · ──────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:24] + 1 │ type fooIntersection = Array; + · ────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array<>; + · ─────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array<>; + · ─────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:31] + 1 │ let x: Array = [1] as number[]; + · ──────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ let ya = [[1, '2']] as [number, string][]; + · ────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:4:14] + 3 │ foo: Array; + 4 │ bar: T[]; + · ─── + 5 │ baz: Arr; + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function barFunction(bar: ArrayClass[]) { + · ──────────────────── + 3 │ return bar.map(e => e.bar); + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:13] + 1 │ let barVar: ((c: number) => number)[]; + · ───────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:17] + 1 │ type barUnion = (string | number | boolean)[]; + · ───────────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ type barIntersection = (string & number)[]; + · ─────────────────── + ╰──── + + ⚠ Array type using 'string[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:3:24] + 2 │ interface FooInterface { + 3 │ '.bar': { baz: string[] }; + · ──────── + 4 │ } + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:12] + 1 │ const foo: Array void> = []; + · ─────────────────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:12] + 1 │ const foo: ReadonlyArray void> = []; + · ─────────────────────────────────────────── + ╰──── + From 37c83d5b92ff018d0e6539cea27911b1563882c0 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 10:27:50 +0800 Subject: [PATCH 07/17] fix: fmt --- .../src/rules/typescript/array_type.rs | 1515 +++++++++++++---- 1 file changed, 1143 insertions(+), 372 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index df107489c04b1..389db00571a81 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -1,11 +1,14 @@ +use oxc_ast::{ + ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, + AstKind, +}; use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::{self, Error}, }; -use oxc_ast::{ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, AstKind}; +use oxc_macros::declare_oxc_lint; use oxc_semantic::AstNode; use oxc_span::Span; -use oxc_macros::declare_oxc_lint; use crate::{context::LintContext, fixer::Fix, rule::Rule}; @@ -35,7 +38,9 @@ pub enum ArrayTypeDiagnostic { // readonlyPrefix className type ErrorStringGeneric(String, String, String, #[label] Span), - #[error("Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead.")] + #[error( + "Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead." + )] #[diagnostic(severity(warning))] // readonlyPrefix className type ErrorStringGenericSimple(String, String, String, #[label] Span), @@ -78,42 +83,49 @@ impl Rule for ArrayType { fn from_configuration(value: serde_json::Value) -> Self { Self(Box::new(ArrayTypeConfig { default: value - .get(0) - .and_then(|v| v.get("default")) - .and_then(serde_json::Value::as_str) - .map_or_else(|| ArrayOption::Array, |s| match s { - "array" => ArrayOption::Array, - "generic" => ArrayOption::Generic, - _ => ArrayOption::ArraySimple, - }), + .get(0) + .and_then(|v| v.get("default")) + .and_then(serde_json::Value::as_str) + .map_or_else( + || ArrayOption::Array, + |s| match s { + "array" => ArrayOption::Array, + "generic" => ArrayOption::Generic, + _ => ArrayOption::ArraySimple, + }, + ), readonly: value - .get(0) - .and_then(|v| v.get("readonly")) - .and_then(serde_json::Value::as_str) - .map_or_else(|| None, |s| match s { - "array" => Some(ArrayOption::Array), - "generic" => Some(ArrayOption::Generic), - _ => Some(ArrayOption::ArraySimple), - }), + .get(0) + .and_then(|v| v.get("readonly")) + .and_then(serde_json::Value::as_str) + .map_or_else( + || None, + |s| match s { + "array" => Some(ArrayOption::Array), + "generic" => Some(ArrayOption::Generic), + _ => Some(ArrayOption::ArraySimple), + }, + ), })) } fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; - let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); + let readonly_config: &ArrayOption = + &self.readonly.clone().unwrap_or_else(|| default_config.clone()); match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { check(&ts_type_annotation.type_annotation, default_config, readonly_config, ctx); - }, + } // for example: type barUnion = (string | number | boolean)[]; AstKind::TSTypeAliasDeclaration(ts_alias_annotation) => { check(&ts_alias_annotation.type_annotation, default_config, readonly_config, ctx); - }, + } // for example: let ya = [[1, '2']] as [number, string][]; AstKind::TSAsExpression(ts_as_expression) => { check(&ts_as_expression.type_annotation, default_config, readonly_config, ctx); - }, + } _ => {} } } @@ -136,9 +148,9 @@ fn check( } if let TSType::TSTypeOperatorType(ts_operator_type) = &type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( + if matches!(&ts_operator_type.operator, TSTypeOperator::Readonly) { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( readonly_config, ts_operator_type.span, &array_type.element_type, @@ -150,12 +162,7 @@ fn check( } if let TSType::TSTypeReference(ts_type_reference) = &type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); + check_and_report_error_array(default_config, readonly_config, ts_type_reference, ctx); } } @@ -166,13 +173,13 @@ fn type_needs_parentheses(type_param: &TSType) -> bool { return identifier_reference.name.as_str() == "ReadonlyArray"; } true - }, - TSType::TSUnionType(_) => true, - TSType::TSFunctionType(_) => true, - TSType::TSIntersectionType(_) => true, - TSType::TSTypeOperatorType(_) => true, - TSType::TSInferType(_) => true, - TSType::TSConstructorType(_) => true, + } + TSType::TSUnionType(_) + | TSType::TSFunctionType(_) + | TSType::TSIntersectionType(_) + | TSType::TSTypeOperatorType(_) + | TSType::TSInferType(_) + | TSType::TSConstructorType(_) => true, _ => false, } } @@ -180,7 +187,7 @@ fn type_needs_parentheses(type_param: &TSType) -> bool { fn check_and_report_error_generic( config: &ArrayOption, type_reference_span: Span, - type_param: &TSType, + type_param: &TSType, ctx: &LintContext, is_readonly: bool, ) { @@ -198,33 +205,33 @@ fn check_and_report_error_generic( let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; let message_type = get_message_type(type_param, &source_text); - let diagnostic = if let ArrayOption::Generic = config { - ArrayTypeDiagnostic::ErrorStringGeneric( + let diagnostic = match config { + ArrayOption::Generic => ArrayTypeDiagnostic::ErrorStringGeneric( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, - ) - } else { - ArrayTypeDiagnostic::ErrorStringGenericSimple( + ), + _ => ArrayTypeDiagnostic::ErrorStringGenericSimple( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, - ) + ), }; let element_type_span = get_ts_element_type_span(&type_param); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { - let type_text = &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let type_text = + &source_text[element_type_span.start as usize..element_type_span.end as usize]; let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; - + Fix::new( - array_type_identifier.to_string() + "<" + type_text + ">", - Span { start: type_reference_span.start, end: type_reference_span.end } + array_type_identifier.to_string() + "<" + type_text + ">", + Span { start: type_reference_span.start, end: type_reference_span.end }, ) - }) + }); } fn check_and_report_error_array( @@ -233,9 +240,13 @@ fn check_and_report_error_array( ts_type_reference: &TSTypeReference, ctx: &LintContext, ) { - let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { return }; + let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { + return; + }; - if ident_ref_type_name.name.as_str() != "ReadonlyArray" && ident_ref_type_name.name.as_str() != "Array" { + if ident_ref_type_name.name.as_str() != "ReadonlyArray" + && ident_ref_type_name.name.as_str() != "Array" + { return; } let is_readonly_array_type = ident_ref_type_name.name == "ReadonlyArray"; @@ -248,26 +259,22 @@ fn check_and_report_error_array( let type_params = &ts_type_reference.type_parameters; if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { - let diagnostic = if let ArrayOption::Array = config { - ArrayTypeDiagnostic::ErrorStringArray( + let diagnostic = match config { + ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( readonly_prefix.to_string(), class_name.to_string(), "any".to_string(), ts_type_reference.span, - ) - } else { - ArrayTypeDiagnostic::ErrorStringArraySimple( + ), + _ => ArrayTypeDiagnostic::ErrorStringArraySimple( readonly_prefix.to_string(), ident_ref_type_name.name.to_string(), "any".to_string(), ts_type_reference.span, - ) + ), }; ctx.diagnostic_with_fix(diagnostic, || { - Fix::new( - readonly_prefix.to_string() + "any[]", - ts_type_reference.span, - ) + Fix::new(readonly_prefix.to_string() + "any[]", ts_type_reference.span) }); return; } @@ -275,10 +282,8 @@ fn check_and_report_error_array( return; } let first_type_param = type_params.as_ref().unwrap().params.get(0).unwrap(); - if let ArrayOption::ArraySimple = config { - if !is_simple_type(first_type_param) { - return; - } + if matches!(config, ArrayOption::ArraySimple) && !is_simple_type(first_type_param) { + return; } let type_parens = type_needs_parentheses(first_type_param); @@ -290,62 +295,59 @@ fn check_and_report_error_array( // parent_parens = false // }; let parent_parens = false; - - let element_type_span = get_ts_element_type_span(&first_type_param); + + let element_type_span = get_ts_element_type_span(first_type_param); let Some(element_type_span) = element_type_span else { return }; - let type_text = &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; + let type_text = + &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; - let mut start = String::from(if parent_parens {"("} else {""}); + let mut start = String::from(if parent_parens { "(" } else { "" }); start.push_str(readonly_prefix); - start.push_str(if type_parens {"("} else {""}); + start.push_str(if type_parens { "(" } else { "" }); - let mut end = String::from(if type_parens {")"} else {""}); + let mut end = String::from(if type_parens { ")" } else { "" }); end.push_str("[]"); - end.push_str(if parent_parens {")"} else {""}); + end.push_str(if parent_parens { ")" } else { "" }); let message_type = get_message_type(first_type_param, ctx.source_text()); - let diagnostic = if let ArrayOption::Array = config { - ArrayTypeDiagnostic::ErrorStringArray( - readonly_prefix.to_string(), - class_name.to_string(), - message_type.to_string(), - ts_type_reference.span, - ) - } else { - ArrayTypeDiagnostic::ErrorStringArraySimple( - readonly_prefix.to_string(), - ident_ref_type_name.name.to_string(), - message_type.to_string(), - ts_type_reference.span, - ) - }; - ctx.diagnostic_with_fix(diagnostic, || { - Fix::new( - start + type_text + end.as_str(), - ts_type_reference.span, - ) - }); + let diagnostic = match config { + ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ), + _ => ArrayTypeDiagnostic::ErrorStringArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ), + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new(start + type_text + end.as_str(), ts_type_reference.span) + }); } // Check whatever node can be considered as simple type fn is_simple_type(ts_type: &TSType) -> bool { match ts_type { - TSType::TSAnyKeyword(_) => true, - TSType::TSBooleanKeyword(_) => true, - TSType::TSNeverKeyword(_) => true, - TSType::TSNumberKeyword(_) => true, - TSType::TSBigIntKeyword(_) => true, - TSType::TSObjectKeyword(_) => true, - TSType::TSStringKeyword(_) => true, - TSType::TSSymbolKeyword(_) => true, - TSType::TSUnknownKeyword(_) => true, - TSType::TSVoidKeyword(_) => true, - TSType::TSNullKeyword(_) => true, - TSType::TSArrayType(_) => true, - TSType::TSUndefinedKeyword(_) => true, - TSType::TSQualifiedName(_) => true, - TSType::TSThisKeyword(_) => true, + TSType::TSAnyKeyword(_) + | TSType::TSBooleanKeyword(_) + | TSType::TSNeverKeyword(_) + | TSType::TSNumberKeyword(_) + | TSType::TSBigIntKeyword(_) + | TSType::TSObjectKeyword(_) + | TSType::TSStringKeyword(_) + | TSType::TSSymbolKeyword(_) + | TSType::TSUnknownKeyword(_) + | TSType::TSVoidKeyword(_) + | TSType::TSNullKeyword(_) + | TSType::TSArrayType(_) + | TSType::TSUndefinedKeyword(_) + | TSType::TSQualifiedName(_) + | TSType::TSThisKeyword(_) => true, TSType::TSTypeReference(node) => { let type_name = TSTypeName::get_first_name(&node.type_name); if type_name.name.as_str() == "Array" { @@ -353,7 +355,9 @@ fn is_simple_type(ts_type: &TSType) -> bool { return true; } if node.type_parameters.as_ref().unwrap().params.len() == 1 { - return is_simple_type(node.type_parameters.as_ref().unwrap().params.get(0).unwrap()); + return is_simple_type( + node.type_parameters.as_ref().unwrap().params.get(0).unwrap(), + ); } } else { if node.type_parameters.is_some() { @@ -362,13 +366,12 @@ fn is_simple_type(ts_type: &TSType) -> bool { if let TSTypeName::IdentifierReference(_) = &node.type_name { return true; } - return false + return false; } false - }, + } _ => false, } - } // Get the type name from the type node. for example: `Array` -> `string` @@ -429,201 +432,585 @@ fn test() { ("let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), ("let a = new Array();", Some(serde_json::json!([{"default":"array"}]))), ("let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"generic"}]))), - ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("function fooFunction(foo: Array>) { + ( + "function foo(a: Array): Array {}", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let yy: number[][] = [[4, 5], [6]];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "function fooFunction(foo: Array>) { return foo.map(e => e.foo); - }", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + }", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " function bazFunction(baz: Arr>) { return baz.map(e => e.baz); } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " namespace fooName { type BarType = { bar: string }; type BazType = Arr; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array"}]))), - ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"array"}]))), - ("function bazFunction(baz: Arr>) { + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "function bazFunction(baz: Arr>) { return baz.map(e => e.baz); - }", Some(serde_json::json!([{"default":"array"}]))), + }", + Some(serde_json::json!([{"default":"array"}])), + ), ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; - }", Some(serde_json::json!([{"default":"array"}]))), - ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), - ("let xx: Array> = [[1, 2], [3]];", Some(serde_json::json!([{"default":"generic"}]))), + }", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type Unwrap = T extends (infer E)[] ? E : T;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let xx: Array> = [[1, 2], [3]];", + Some(serde_json::json!([{"default":"generic"}])), + ), ("type Arr = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", Some(serde_json::json!([{"default":"generic"}]))), - ("function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", Some(serde_json::json!([{"default":"generic"}]))), - ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), - ("type fooUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: ReadonlyArray = [[]];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly Array[] = [[]];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ( + "function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type Unwrap = T extends Array ? E : T;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: ReadonlyArray = [[]];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly Array[] = [[]];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), ]; - - let fail = vec![ + + let fail = vec![ ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), ("let a: { foo: Array }[] = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: Array<{ foo: Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), // ("let a: Array<{ foo: Foo | Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"array"}]))), - ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "function foo(a: Array): Array {}", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let x: Array = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let y: string[] = >['2'];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("type Arr = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; xyz: this[]; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // ("let v: Array = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), // ("let w: fooName.BazType[] = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let x: Array = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array"}])), + ), ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array"}]))), ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), ("type Arr = Array;", Some(serde_json::json!([{"default":"array"}]))), @@ -631,123 +1018,415 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", Some(serde_json::json!([{"default":"array"}]))), - (" + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " function fooFunction(foo: Array>) { return foo.map(e => e.foo); } - ", Some(serde_json::json!([{"default":"array"}]))), - ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array"}]))), - ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array"}]))), - ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array"}]))), + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"array"}])), + ), ("let x: Array;", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array<>;", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array;", Some(serde_json::json!([{"default":"array-simple"}]))), ("let x: Array<>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [1] as number[];", Some(serde_json::json!([{"default":"generic"}]))), - ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), - ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let x: Array = [1] as number[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let y: string[] = >['2'];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"generic"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"generic"}]))), - ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"generic"}]))), - ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"generic"}]))), - ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; } - ", Some(serde_json::json!([{"default":"generic"}]))), + ", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"array"}]))), // ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), // ("type Foo = ReadonlyArray[];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: Array void> = [];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: ReadonlyArray void> = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "const foo: Array void> = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "const foo: ReadonlyArray void> = [];", + Some(serde_json::json!([{"default":"array"}])), + ), ]; let fix: Vec<(&str, &str, Option)> = vec![ - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: bigint[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly bigint[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | bigint)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: { foo: Array }[] = [];", "let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array<{ foo: Bar[] }> = [];", "let a: Array<{ foo: Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: bigint[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly bigint[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: { foo: Array }[] = [];", + "let a: { foo: Bar[] }[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array<{ foo: Bar[] }> = [];", + "let a: Array<{ foo: Array }> = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("let a: Array<{ foo: Foo | Bar[] }> = [];", "let a: Array<{ foo: Foo | Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("function foo(a: Array): Array {}", "function foo(a: Bar[]): Bar[] {}", Some(serde_json::json!([{"default":"array"}]))), - ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "function foo(a: Array): Array {}", + "function foo(a: Bar[]): Bar[] {}", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let x: Array = [undefined] as undefined[];", + "let x: undefined[] = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let z: Array = [3, '4'];", + "let z: any[] = [3, '4'];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let ya = [[1, '2']] as [number, string][];", + "let ya = [[1, '2']] as Array<[number, string]>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type Arr = Array;", + "type Arr = T[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; @@ -755,39 +1434,71 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr>>> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; xyz: this[]; } - ", " + ", + " interface ArrayClass { foo: T[]; bar: T[]; baz: Arr; xyz: this[]; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", " + ", + " function barFunction(bar: Array>) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + "let barVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + "type barUnion = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barIntersection = (string & number)[];", + "type barIntersection = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // ("let v: Array = [{ bar: 'bar' }];", "let v: fooName.BarType[] = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), // ("let w: fooName.BazType[] = [['baz']];", "let w: Array> = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let x: Array = [undefined] as undefined[];", + "let x: undefined[] = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array"}])), + ), // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array"}]))), - ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), - ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let z: Array = [3, '4'];", + "let z: any[] = [3, '4'];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type Arr = Array;", + "type Arr = T[];", + Some(serde_json::json!([{"default":"array"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; @@ -795,38 +1506,66 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr[][]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", " + ", + " interface ArrayClass { foo: T[]; bar: T[]; baz: Arr; } - ", Some(serde_json::json!([{"default":"array"}]))), - (" + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " function fooFunction(foo: Array>) { return foo.map(e => e.foo); } - ", " + ", + " function fooFunction(foo: ArrayClass[]) { return foo.map(e => e.foo); } - ", Some(serde_json::json!([{"default":"array"}]))), - ("let fooVar: Array<(c: number) => number>;", "let fooVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type fooUnion = Array;", "type fooUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type fooIntersection = Array;", "type fooIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + "let fooVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooUnion = Array;", + "type fooUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooIntersection = Array;", + "type fooIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [1] as number[];", "let x: Array = [1] as Array;", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let x: Array = [1] as number[];", + "let x: Array = [1] as Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("let y: string[] = >['2'];", "let y: Array = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), - ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + "let ya = [[1, '2']] as Array<[number, string]>;", + Some(serde_json::json!([{"default":"generic"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; @@ -834,45 +1573,77 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr>>> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", " + ", + " interface ArrayClass { foo: Array; bar: Array; baz: Arr; } - ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", " + ", + " function barFunction(bar: Array>) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"generic"}]))), - ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), - ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + "let barVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + "type barUnion = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barIntersection = (string & number)[];", + "type barIntersection = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; } - ", " + ", + " interface FooInterface { '.bar': { baz: Array }; } - ", Some(serde_json::json!([{"default":"generic"}]))), + ", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("type Unwrap = T extends Array ? E : T;", "type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), // ("type Unwrap = T extends (infer E)[] ? E : T;", "type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), // ("type Foo = ReadonlyArray[];", "type Foo = (readonly object[])[];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: Array void> = [];", "const foo: (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: ReadonlyArray void> = [];", "const foo: readonly (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "const foo: Array void> = [];", + "const foo: (new (...args: any[]) => void)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "const foo: ReadonlyArray void> = [];", + "const foo: readonly (new (...args: any[]) => void)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), ]; Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); From c83923b0c0c2667e7a9db01242899b098331d1ff Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sat, 3 Feb 2024 10:24:35 +0800 Subject: [PATCH 08/17] feat: (wip) array-type config --- crates/oxc_linter/src/rules.rs | 2 + .../src/rules/typescript/array_type.rs | 98 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 crates/oxc_linter/src/rules/typescript/array_type.rs diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 8ec31b02f90cf..ec19595e5b184 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -100,6 +100,7 @@ mod eslint { mod typescript { pub mod adjacent_overload_signatures; + pub mod array_type; pub mod ban_ts_comment; pub mod ban_types; pub mod no_duplicate_enum_values; @@ -389,6 +390,7 @@ oxc_macros::declare_all_lint_rules! { eslint::use_isnan, eslint::valid_typeof, typescript::adjacent_overload_signatures, + typescript::array_type, typescript::ban_ts_comment, typescript::ban_types, typescript::no_duplicate_enum_values, diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs new file mode 100644 index 0000000000000..1f8c12fa99f32 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -0,0 +1,98 @@ +use oxc_semantic::AstNode; +use oxc_span::{GetSpan, Span}; +use oxc_macros::declare_oxc_lint; + +use crate::{context::LintContext, rule::Rule}; + +#[derive(Debug, Default, Clone)] +pub struct ArrayType(Box); + +declare_oxc_lint!( + /// ### What it does + /// Require consistently using either `T[]` or `Array` for arrays. + /// + /// ### Why is this bad? + /// Using the `Array` type directly is not idiomatic. Instead, use the array type `T[]` or `Array`. + /// + /// ### Example + /// ```typescript + /// const arr: Array = new Array(); + /// const arr: number[] = new Array(); + /// ``` + ArrayType, + style, +); + +#[derive(Debug, Default, Clone)] +pub struct ArrayTypeConfig { + // The array type expected for mutable cases. + default: ArrayOption, + // The array type expected for readonly cases. If omitted, the value for `default` will be used. + readonly: Option, +} + +impl std::ops::Deref for ArrayType { + type Target = ArrayTypeConfig; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[derive(Debug, Default, Clone)] +pub enum ArrayOption { + ArraySimple, + #[default] + Array, + Generic, +} + +impl Rule for ArrayType { + fn from_configuration(value: serde_json::Value) -> Self { + Self(Box::new(ArrayTypeConfig { + default: value + .get(0) + .and_then(|v| v.get("default")) + .and_then(serde_json::Value::as_str) + .map_or_else(|| ArrayOption::Array, |s| match s { + "array" => ArrayOption::Array, + "generic" => ArrayOption::Generic, + _ => ArrayOption::ArraySimple, + }), + readonly: value + .get(0) + .and_then(|v| v.get("readonly")) + .and_then(serde_json::Value::as_str) + .map_or_else(|| None, |s| match s { + "array" => Some(ArrayOption::Array), + "generic" => Some(ArrayOption::Generic), + _ => Some(ArrayOption::ArraySimple), + }), + })) + } + fn run<'a>(&self, _node: &AstNode<'a>, _ctx: &LintContext<'a>) { + let default_config = &self.default; + let readonly_config = &self.readonly.clone().unwrap_or(default_config.clone()); + + println!("{:?} {:?}", default_config, readonly_config); + // if let ArrayOption::Array = default_config { + // println!("111"); + // } else { + // println!("222"); + // } + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass: Vec<(&str, Option)> = vec![ + ("let a: number[] = [];", None), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) + ]; + let fail: Vec<(&str, Option)> = vec![ + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ]; + + Tester::new(ArrayType::NAME, pass, fail).test(); +} From 2118d8c2082154dfd48075882b7d0c68370ee4b6 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sat, 3 Feb 2024 14:20:10 +0800 Subject: [PATCH 09/17] feat: support check and report error generic --- .../src/rules/typescript/array_type.rs | 193 ++++++++++++++++-- 1 file changed, 174 insertions(+), 19 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index 1f8c12fa99f32..2da0c1d96efc9 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -1,8 +1,13 @@ +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::{self, Error}, +}; +use oxc_ast::{ast::{TSArrayType, TSType, TSTypeOperator}, AstKind}; use oxc_semantic::AstNode; -use oxc_span::{GetSpan, Span}; +use oxc_span::Span; use oxc_macros::declare_oxc_lint; -use crate::{context::LintContext, rule::Rule}; +use crate::{context::LintContext, fixer::Fix, rule::Rule}; #[derive(Debug, Default, Clone)] pub struct ArrayType(Box); @@ -23,6 +28,29 @@ declare_oxc_lint!( style, ); +#[derive(Debug, Diagnostic, Error)] +pub enum ArrayTypeDiagnostic { + #[error("Array type using '{0}{2}[]' is forbidden. Use '{1}<{2}>' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringGeneric(String, String, String, #[label] Span), + + #[error("Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringGenericSimple(String, String, String, #[label] Span), + + #[error("Array type using '{1}<{2}>' is forbidden. Use '{0}{2}[]' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringArray(String, String, String, #[label] Span), + + #[error("Array type using '{1}<{2}>' is forbidden for simple types. Use '{0}{2}[]' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ErrorStringArraySimple(String, String, String, #[label] Span), +} + #[derive(Debug, Default, Clone)] pub struct ArrayTypeConfig { // The array type expected for mutable cases. @@ -40,9 +68,9 @@ impl std::ops::Deref for ArrayType { } #[derive(Debug, Default, Clone)] pub enum ArrayOption { - ArraySimple, #[default] Array, + ArraySimple, Generic, } @@ -69,30 +97,157 @@ impl Rule for ArrayType { }), })) } - fn run<'a>(&self, _node: &AstNode<'a>, _ctx: &LintContext<'a>) { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; let readonly_config = &self.readonly.clone().unwrap_or(default_config.clone()); - println!("{:?} {:?}", default_config, readonly_config); - // if let ArrayOption::Array = default_config { - // println!("111"); - // } else { - // println!("222"); - // } + match node.kind() { + AstKind::TSTypeAnnotation(ts_type_annotation) => { + if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + // Array 泛型 + if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { + println!("{:#?}", ts_type_reference); + } + }, + _ => {} + } + } +} + +fn check_and_report_error_generic( + config: &ArrayOption, + type_annotation_span: Span, + element_type: &TSType, + ctx: &LintContext, + is_readonly: bool, +) { + if let ArrayOption::Array = config { + return; + } + if let ArrayOption::ArraySimple = config { + if is_simple_type(element_type) { + return; + } + } + let source_text = ctx.source_text().to_string(); + + let readonly_prefix = if is_readonly { "readonly " } else { "" }; + let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; + let message_type = get_message_type(element_type, &source_text); + + let diagnostic = if let ArrayOption::Generic = config { + ArrayTypeDiagnostic::ErrorStringGeneric( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + type_annotation_span, + ) + } else { + ArrayTypeDiagnostic::ErrorStringGenericSimple( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + type_annotation_span, + ) + }; + let element_type_span = get_element_type_span(&element_type); + let Some(element_type_span) = element_type_span else { return }; + + ctx.diagnostic_with_fix(diagnostic, || { + let element_type_span = &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; + + Fix::new( + array_type_identifier.to_string() + "<" + element_type_span + ">", + Span { start: type_annotation_span.start, end: type_annotation_span.end } + ) + }) +} + +// Check whatever node can be considered as simple type +fn is_simple_type(element_type: &TSType) -> bool { + match element_type { + // TODO: miss TSThisType Identifier + TSType::TSAnyKeyword(_) => true, + TSType::TSBooleanKeyword(_) => true, + TSType::TSNeverKeyword(_) => true, + TSType::TSNumberKeyword(_) => true, + TSType::TSBigIntKeyword(_) => true, + TSType::TSObjectKeyword(_) => true, + TSType::TSStringKeyword(_) => true, + TSType::TSSymbolKeyword(_) => true, + TSType::TSUnknownKeyword(_) => true, + TSType::TSVoidKeyword(_) => true, + TSType::TSNullKeyword(_) => true, + TSType::TSArrayType(_) => true, + TSType::TSUndefinedKeyword(_) => true, + TSType::TSQualifiedName(_) => true, + TSType::TSTypeReference(_) => { + // TODO: + true + }, + _ => false, + } + +} + +fn get_message_type<'a>(element_type: &'a TSType, source_text: &'a str) -> &'a str { + if is_simple_type(element_type) { + let element_type_span = get_element_type_span(element_type); + let Some(element_type_span) = element_type_span else { return "T" }; + return &source_text[element_type_span.start as usize..element_type_span.end as usize]; + } + "T" +} + +fn get_element_type_span(element_type: &TSType) -> Option { + match element_type { + // TODO: add more type + TSType::TSNumberKeyword(t) => Some(t.span), + TSType::TSStringKeyword(t) => Some(t.span), + _ => None, } } #[test] fn test() { - use crate::tester::Tester; + use crate::tester::Tester; - let pass: Vec<(&str, Option)> = vec![ - ("let a: number[] = [];", None), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) - ]; - let fail: Vec<(&str, Option)> = vec![ - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), - ]; + let pass: Vec<(&str, Option)> = vec![ + ("let a: number[] = [];", None), + // ("const y: readonly string[] = ['a', 'b'];", None), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) + ]; + let fail: Vec<(&str, Option)> = vec![ + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ]; + let fix = vec![ + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ]; - Tester::new(ArrayType::NAME, pass, fail).test(); + Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); } From 99bc6837f3e8e1758b0e3ba68ff28aa72f9efdf3 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sat, 3 Feb 2024 18:52:53 +0800 Subject: [PATCH 10/17] feat: support fix string array --- .../src/rules/typescript/array_type.rs | 259 ++++++++++++++++-- 1 file changed, 237 insertions(+), 22 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index 2da0c1d96efc9..cef9ceb119b3b 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -2,7 +2,7 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::{self, Error}, }; -use oxc_ast::{ast::{TSArrayType, TSType, TSTypeOperator}, AstKind}; +use oxc_ast::{ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, AstKind}; use oxc_semantic::AstNode; use oxc_span::Span; use oxc_macros::declare_oxc_lint; @@ -99,7 +99,7 @@ impl Rule for ArrayType { } fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; - let readonly_config = &self.readonly.clone().unwrap_or(default_config.clone()); + let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { @@ -116,7 +116,7 @@ impl Rule for ArrayType { if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { if let TSTypeOperator::Readonly = &ts_operator_type.operator { if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( + check_and_report_error_generic( readonly_config, ts_operator_type.span, &array_type.element_type, @@ -127,9 +127,13 @@ impl Rule for ArrayType { } } - // Array 泛型 if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { - println!("{:#?}", ts_type_reference); + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); } }, _ => {} @@ -137,9 +141,29 @@ impl Rule for ArrayType { } } + +fn type_needs_parentheses(type_param: &TSType) -> bool { + match type_param { + TSType::TSTypeReference(node) => { + // TODO: + println!("node===> {:#?}", node); + // return type_needs_parentheses(ts_type_ref.type_name); + true + + }, + TSType::TSUnionType(_) => true, + TSType::TSFunctionType(_) => true, + TSType::TSIntersectionType(_) => true, + TSType::TSTypeOperatorType(_) => true, + TSType::TSInferType(_) => true, + TSType::TSConstructorType(_) => true, + _ => false, + } +} + fn check_and_report_error_generic( config: &ArrayOption, - type_annotation_span: Span, + type_reference_span: Span, element_type: &TSType, ctx: &LintContext, is_readonly: bool, @@ -163,34 +187,134 @@ fn check_and_report_error_generic( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), - type_annotation_span, + type_reference_span, ) } else { ArrayTypeDiagnostic::ErrorStringGenericSimple( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), - type_annotation_span, + type_reference_span, ) }; - let element_type_span = get_element_type_span(&element_type); + let element_type_span = get_ts_element_type_span(&element_type); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { - let element_type_span = &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let type_text = &source_text[element_type_span.start as usize..element_type_span.end as usize]; let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; Fix::new( - array_type_identifier.to_string() + "<" + element_type_span + ">", - Span { start: type_annotation_span.start, end: type_annotation_span.end } + array_type_identifier.to_string() + "<" + type_text + ">", + Span { start: type_reference_span.start, end: type_reference_span.end } ) }) } +fn check_and_report_error_array( + default_config: &ArrayOption, + readonly_config: &ArrayOption, + ts_type_reference: &TSTypeReference, + ctx: &LintContext, +) { + let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { return }; + + if ident_ref_type_name.name.as_str() != "ReadonlyArray" && ident_ref_type_name.name.as_str() != "Array" { + return; + } + let is_readonly_array_type = ident_ref_type_name.name == "ReadonlyArray"; + let config = if is_readonly_array_type { readonly_config } else { default_config }; + if let ArrayOption::Generic = config { + return; + } + let readonly_prefix: &str = if is_readonly_array_type { "readonly " } else { "" }; + let class_name = if is_readonly_array_type { "ReadonlyArray" } else { "Array" }; + let type_params = &ts_type_reference.type_parameters; + + if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { + let diagnostic = if let ArrayOption::Array = config { + ArrayTypeDiagnostic::ErrorStringArray( + readonly_prefix.to_string(), + class_name.to_string(), + "any".to_string(), + ts_type_reference.span, + ) + } else { + ArrayTypeDiagnostic::ErrorStringArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + "any".to_string(), + ts_type_reference.span, + ) + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new( + readonly_prefix.to_string() + "any[]", + ts_type_reference.span, + ) + }); + return; + } + if type_params.as_ref().unwrap().params.len() != 1 { + return; + } + let first_type_param = type_params.as_ref().unwrap().params.get(0).unwrap(); + if let ArrayOption::ArraySimple = config { + if !is_simple_type(first_type_param) { + return; + } + } + + let type_parens = type_needs_parentheses(first_type_param); + // TODO: support example: type Foo = ReadonlyArray[]; -> type Foo = (readonly object[])[]; + // let mut parent_parens: bool = readonly_prefix != ""; + // if let Some(parent) = ctx.nodes().parent_node(node.id()) { + // if let AstKind::TSTypeAnnotation(parent_node) = parent.kind() {} + // } else { + // parent_parens = false + // }; + let parent_parens = false; + + let element_type_span = get_ts_element_type_span(&first_type_param); + let Some(element_type_span) = element_type_span else { return }; + + let type_text = &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; + + let mut start = String::from(if parent_parens {"("} else {""}); + start.push_str(readonly_prefix); + start.push_str(if type_parens {"("} else {""}); + + let mut end = String::from(if type_parens {")"} else {""}); + end.push_str("[]"); + end.push_str(if parent_parens {")"} else {""}); + + let message_type = get_message_type(first_type_param, ctx.source_text()); + let diagnostic = if let ArrayOption::Array = config { + ArrayTypeDiagnostic::ErrorStringArray( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ) + } else { + ArrayTypeDiagnostic::ErrorStringArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ) + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new( + start + type_text + end.as_str(), + ts_type_reference.span, + ) + }); +} + // Check whatever node can be considered as simple type fn is_simple_type(element_type: &TSType) -> bool { match element_type { - // TODO: miss TSThisType Identifier TSType::TSAnyKeyword(_) => true, TSType::TSBooleanKeyword(_) => true, TSType::TSNeverKeyword(_) => true, @@ -205,7 +329,9 @@ fn is_simple_type(element_type: &TSType) -> bool { TSType::TSArrayType(_) => true, TSType::TSUndefinedKeyword(_) => true, TSType::TSQualifiedName(_) => true, - TSType::TSTypeReference(_) => { + TSType::TSThisKeyword(_) => true, + TSType::TSTypeReference(node) => { + println!("TSTypeReference ===> {:#?}", node); // TODO: true }, @@ -216,18 +342,49 @@ fn is_simple_type(element_type: &TSType) -> bool { fn get_message_type<'a>(element_type: &'a TSType, source_text: &'a str) -> &'a str { if is_simple_type(element_type) { - let element_type_span = get_element_type_span(element_type); + let element_type_span = get_ts_element_type_span(element_type); let Some(element_type_span) = element_type_span else { return "T" }; return &source_text[element_type_span.start as usize..element_type_span.end as usize]; } "T" } -fn get_element_type_span(element_type: &TSType) -> Option { - match element_type { - // TODO: add more type +fn get_ts_element_type_span(ts_type: &TSType) -> Option { + match ts_type { + TSType::TSAnyKeyword(t) => Some(t.span), TSType::TSNumberKeyword(t) => Some(t.span), TSType::TSStringKeyword(t) => Some(t.span), + TSType::TSBigIntKeyword(t) => Some(t.span), + TSType::TSBooleanKeyword(t) => Some(t.span), + TSType::TSNeverKeyword(t) => Some(t.span), + TSType::TSObjectKeyword(t) => Some(t.span), + TSType::TSSymbolKeyword(t) => Some(t.span), + TSType::TSUnknownKeyword(t) => Some(t.span), + TSType::TSVoidKeyword(t) => Some(t.span), + TSType::TSNullKeyword(t) => Some(t.span), + TSType::TSThisKeyword(t) => Some(t.span), + TSType::TSUndefinedKeyword(t) => Some(t.span), + + TSType::TSArrayType(t) => Some(t.span), + TSType::TSConditionalType(t) => Some(t.span), + TSType::TSConstructorType(t) => Some(t.span), + TSType::TSFunctionType(t) => Some(t.span), + TSType::TSImportType(t) => Some(t.span), + TSType::TSIndexedAccessType(t) => Some(t.span), + TSType::TSInferType(t) => Some(t.span), + TSType::TSIntersectionType(t) => Some(t.span), + TSType::TSLiteralType(t) => Some(t.span), + TSType::TSMappedType(t) => Some(t.span), + TSType::TSQualifiedName(t) => Some(t.span), + TSType::TSTemplateLiteralType(t) => Some(t.span), + TSType::TSTupleType(t) => Some(t.span), + TSType::TSTypeLiteral(t) => Some(t.span), + TSType::TSTypeOperatorType(t) => Some(t.span), + TSType::TSTypePredicate(t) => Some(t.span), + TSType::TSTypeQuery(t) => Some(t.span), + TSType::TSTypeReference(t) => Some(t.span), + TSType::TSUnionType(t) => Some(t.span), + _ => None, } } @@ -235,18 +392,76 @@ fn get_element_type_span(element_type: &TSType) -> Option { #[test] fn test() { use crate::tester::Tester; - let pass: Vec<(&str, Option)> = vec![ - ("let a: number[] = [];", None), - // ("const y: readonly string[] = ['a', 'b'];", None), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))) + ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), + // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic",}]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic",}]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), ]; let fail: Vec<(&str, Option)> = vec![ // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), ]; let fix = vec![ + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), + ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{ "default": "array-simple" }]))), + ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{ "default": "array-simple" }]))), ]; Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); From 86726c8377c451f07dc214d69bba31d0024ec885 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sun, 4 Feb 2024 15:27:56 +0800 Subject: [PATCH 11/17] feat: add test case --- .../src/rules/typescript/array_type.rs | 631 +++++++++++++++--- 1 file changed, 546 insertions(+), 85 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index cef9ceb119b3b..aa1881fd1d5d8 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -97,10 +97,10 @@ impl Rule for ArrayType { }), })) } + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); - match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { @@ -136,20 +136,86 @@ impl Rule for ArrayType { ); } }, + AstKind::TSTypeAliasDeclaration(ts_type_annotation) => { + if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); + } + }, + AstKind::TSAsExpression(ts_as_expression) => { + if let TSType::TSArrayType(array_type) = &ts_as_expression.type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_as_expression.type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &ts_as_expression.type_annotation { + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); + } + }, _ => {} } } } - fn type_needs_parentheses(type_param: &TSType) -> bool { match type_param { TSType::TSTypeReference(node) => { - // TODO: - println!("node===> {:#?}", node); - // return type_needs_parentheses(ts_type_ref.type_name); + if let TSTypeName::IdentifierReference(identifier_reference) = &node.type_name { + return identifier_reference.name.as_str() == "ReadonlyArray"; + } true - }, TSType::TSUnionType(_) => true, TSType::TSFunctionType(_) => true, @@ -164,7 +230,7 @@ fn type_needs_parentheses(type_param: &TSType) -> bool { fn check_and_report_error_generic( config: &ArrayOption, type_reference_span: Span, - element_type: &TSType, + type_param: &TSType, ctx: &LintContext, is_readonly: bool, ) { @@ -172,7 +238,7 @@ fn check_and_report_error_generic( return; } if let ArrayOption::ArraySimple = config { - if is_simple_type(element_type) { + if is_simple_type(type_param) { return; } } @@ -180,7 +246,7 @@ fn check_and_report_error_generic( let readonly_prefix = if is_readonly { "readonly " } else { "" }; let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; - let message_type = get_message_type(element_type, &source_text); + let message_type = get_message_type(type_param, &source_text); let diagnostic = if let ArrayOption::Generic = config { ArrayTypeDiagnostic::ErrorStringGeneric( @@ -197,7 +263,7 @@ fn check_and_report_error_generic( type_reference_span, ) }; - let element_type_span = get_ts_element_type_span(&element_type); + let element_type_span = get_ts_element_type_span(&type_param); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { @@ -313,8 +379,8 @@ fn check_and_report_error_array( } // Check whatever node can be considered as simple type -fn is_simple_type(element_type: &TSType) -> bool { - match element_type { +fn is_simple_type(ts_type: &TSType) -> bool { + match ts_type { TSType::TSAnyKeyword(_) => true, TSType::TSBooleanKeyword(_) => true, TSType::TSNeverKeyword(_) => true, @@ -331,18 +397,34 @@ fn is_simple_type(element_type: &TSType) -> bool { TSType::TSQualifiedName(_) => true, TSType::TSThisKeyword(_) => true, TSType::TSTypeReference(node) => { - println!("TSTypeReference ===> {:#?}", node); - // TODO: - true + let type_name = TSTypeName::get_first_name(&node.type_name); + if type_name.name.as_str() == "Array" { + if node.type_parameters.is_none() { + return true; + } + if node.type_parameters.as_ref().unwrap().params.len() == 1 { + return is_simple_type(node.type_parameters.as_ref().unwrap().params.get(0).unwrap()); + } + } else { + if node.type_parameters.is_some() { + return false; + } + if let TSTypeName::IdentifierReference(_) = &node.type_name { + return true; + } + return false + } + false }, _ => false, } } -fn get_message_type<'a>(element_type: &'a TSType, source_text: &'a str) -> &'a str { - if is_simple_type(element_type) { - let element_type_span = get_ts_element_type_span(element_type); +// Get the type name from the type node. for example: `Array` -> `string` +fn get_message_type<'a>(type_param: &'a TSType, source_text: &'a str) -> &'a str { + if is_simple_type(type_param) { + let element_type_span = get_ts_element_type_span(type_param); let Some(element_type_span) = element_type_span else { return "T" }; return &source_text[element_type_span.start as usize..element_type_span.end as usize]; } @@ -392,76 +474,455 @@ fn get_ts_element_type_span(ts_type: &TSType) -> Option { #[test] fn test() { use crate::tester::Tester; + let pass: Vec<(&str, Option)> = vec![ - ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "array-simple" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array", "readonly": "generic" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "array-simple" }]))), - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "array-simple", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "generic" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "generic",}]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic",}]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: Array = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: readonly bigint[] = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), - // ("let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic", "readonly": "array-simple" }]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a = new Array();", Some(serde_json::json!([{"default":"array"}]))), + ("let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"generic"}]))), + ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + }", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + namespace fooName { + type BarType = { bar: string }; + type BazType = Arr; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array"}]))), + ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"array"}]))), + ("function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); + }", Some(serde_json::json!([{"default":"array"}]))), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + }", Some(serde_json::json!([{"default":"array"}]))), + ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + ("let xx: Array> = [[1, 2], [3]];", Some(serde_json::json!([{"default":"generic"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", Some(serde_json::json!([{"default":"generic"}]))), + ("function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", Some(serde_json::json!([{"default":"generic"}]))), + ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), + ("type fooUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [[]];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly Array[] = [[]];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), ]; - let fail: Vec<(&str, Option)> = vec![ - // ("let a: number[] = [];", Some(serde_json::json!([{ "default": "generic" }]))), + + let fail = vec![ + ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: { foo: Array }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array<{ foo: Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + // ("let a: Array<{ foo: Foo | Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let v: Array = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let w: fooName.BazType[] = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array"}]))), + ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"array"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"array"}]))), + (" + function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + } + ", Some(serde_json::json!([{"default":"array"}]))), + ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array"}]))), + ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array"}]))), + ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array<>;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array<>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [1] as number[];", Some(serde_json::json!([{"default":"generic"}]))), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), + ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"generic"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"generic"}]))), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"generic"}]))), + ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"generic"}]))), + ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + // ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Foo = ReadonlyArray[];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: Array void> = [];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: ReadonlyArray void> = [];", Some(serde_json::json!([{"default":"array"}]))), ]; - let fix = vec![ - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{ "default": "array" }]))), - - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{ "default": "generic" }]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{ "default": "generic" }]))), - ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{ "default": "array-simple" }]))), - ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{ "default": "array-simple" }]))), + + let fix: Vec<(&str, &str, Option)> = vec![ + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), + ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: bigint[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: ReadonlyArray = [];", "let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly bigint[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: readonly (string | bigint)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ("let a: { foo: Array }[] = [];", "let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array<{ foo: Bar[] }> = [];", "let a: Array<{ foo: Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + // ("let a: Array<{ foo: Foo | Bar[] }> = [];", "let a: Array<{ foo: Foo | Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("function foo(a: Array): Array {}", "function foo(a: Bar[]): Bar[] {}", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array-simple"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr>>> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", " + interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", " + function barFunction(bar: Array>) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let v: Array = [{ bar: 'bar' }];", "let v: fooName.BarType[] = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let w: fooName.BazType[] = [['baz']];", "let w: Array> = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array"}]))), + ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), + ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr[][]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", " + interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"array"}]))), + (" + function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + } + ", " + function fooFunction(foo: ArrayClass[]) { + return foo.map(e => e.foo); + } + ", Some(serde_json::json!([{"default":"array"}]))), + ("let fooVar: Array<(c: number) => number>;", "let fooVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type fooUnion = Array;", "type fooUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), + ("type fooIntersection = Array;", "type fooIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array = [1] as number[];", "let x: Array = [1] as Array;", Some(serde_json::json!([{"default":"generic"}]))), + // ("let y: string[] = >['2'];", "let y: Array = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), + ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"generic"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr>>> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", " + interface ArrayClass { + foo: Array; + bar: Array; + baz: Arr; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + (" + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", " + function barFunction(bar: Array>) { + return bar.map(e => e.bar); + } + ", Some(serde_json::json!([{"default":"generic"}]))), + ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), + ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), + (" + interface FooInterface { + '.bar': { baz: string[] }; + } + ", " + interface FooInterface { + '.bar': { baz: Array }; + } + ", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Unwrap = T extends Array ? E : T;", "type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + // ("type Unwrap = T extends (infer E)[] ? E : T;", "type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Foo = ReadonlyArray[];", "type Foo = (readonly object[])[];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: Array void> = [];", "const foo: (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("const foo: ReadonlyArray void> = [];", "const foo: readonly (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), ]; Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); From 7762ef08fdafa7dd09b215adc154119d6f3960de Mon Sep 17 00:00:00 2001 From: luhc228 Date: Sun, 4 Feb 2024 15:54:16 +0800 Subject: [PATCH 12/17] refactor: extract common function --- .../src/rules/typescript/array_type.rs | 144 ++++++------------ 1 file changed, 47 insertions(+), 97 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index aa1881fd1d5d8..a093462f36634 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -101,114 +101,64 @@ impl Rule for ArrayType { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); + match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { - if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { - check_and_report_error_generic( - default_config, - array_type.span, - &array_type.element_type, - ctx, - false, - ); - } - - if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( - readonly_config, - ts_operator_type.span, - &array_type.element_type, - ctx, - true, - ); - } - } - } - - if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); - } + check(&ts_type_annotation.type_annotation, default_config, readonly_config, ctx); }, - AstKind::TSTypeAliasDeclaration(ts_type_annotation) => { - if let TSType::TSArrayType(array_type) = &ts_type_annotation.type_annotation { - check_and_report_error_generic( - default_config, - array_type.span, - &array_type.element_type, - ctx, - false, - ); - } - - if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_type_annotation.type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( - readonly_config, - ts_operator_type.span, - &array_type.element_type, - ctx, - true, - ); - } - } - } - - if let TSType::TSTypeReference(ts_type_reference) = &ts_type_annotation.type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); - } + // for example: type barUnion = (string | number | boolean)[]; + AstKind::TSTypeAliasDeclaration(ts_alias_annotation) => { + check(&ts_alias_annotation.type_annotation, default_config, readonly_config, ctx); }, + // for example: let ya = [[1, '2']] as [number, string][]; AstKind::TSAsExpression(ts_as_expression) => { - if let TSType::TSArrayType(array_type) = &ts_as_expression.type_annotation { - check_and_report_error_generic( - default_config, - array_type.span, - &array_type.element_type, - ctx, - false, - ); - } - - if let TSType::TSTypeOperatorType(ts_operator_type) = &ts_as_expression.type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( - readonly_config, - ts_operator_type.span, - &array_type.element_type, - ctx, - true, - ); - } - } - } - - if let TSType::TSTypeReference(ts_type_reference) = &ts_as_expression.type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); - } + check(&ts_as_expression.type_annotation, default_config, readonly_config, ctx); }, _ => {} } } } +fn check( + type_annotation: &TSType, + default_config: &ArrayOption, + readonly_config: &ArrayOption, + ctx: &LintContext, +) { + if let TSType::TSArrayType(array_type) = &type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &type_annotation { + if let TSTypeOperator::Readonly = &ts_operator_type.operator { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &type_annotation { + check_and_report_error_array( + default_config, + readonly_config, + ts_type_reference, + ctx, + ); + } +} + fn type_needs_parentheses(type_param: &TSType) -> bool { match type_param { TSType::TSTypeReference(node) => { From 9231031a6dcd1fd2a478ce705de0fc836412294a Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 09:21:11 +0800 Subject: [PATCH 13/17] feat: add snapshot --- .../src/rules/typescript/array_type.rs | 2 +- .../oxc_linter/src/snapshots/array_type.snap | 569 ++++++++++++++++++ 2 files changed, 570 insertions(+), 1 deletion(-) create mode 100644 crates/oxc_linter/src/snapshots/array_type.snap diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index a093462f36634..df107489c04b1 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -875,5 +875,5 @@ fn test() { ("const foo: ReadonlyArray void> = [];", "const foo: readonly (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), ]; - Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test(); + Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); } diff --git a/crates/oxc_linter/src/snapshots/array_type.snap b/crates/oxc_linter/src/snapshots/array_type.snap new file mode 100644 index 0000000000000..7e4d0d0e22c7a --- /dev/null +++ b/crates/oxc_linter/src/snapshots/array_type.snap @@ -0,0 +1,569 @@ +--- +source: crates/oxc_linter/src/tester.rs +assertion_line: 150 +expression: array_type +--- + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'bigint[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: bigint[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | bigint)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly bigint[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | bigint)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly bigint[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly bigint[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | bigint)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ let a: { foo: Array }[] = []; + · ────────── + ╰──── + + ⚠ Array type using 'Bar[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:21] + 1 │ let a: Array<{ foo: Bar[] }> = []; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:17] + 1 │ function foo(a: Array): Array {} + · ────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:30] + 1 │ function foo(a: Array): Array {} + · ────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'undefined[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array = [undefined] as undefined[]; + · ──────────────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let z: Array = [3, '4']; + · ───── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ let ya = [[1, '2']] as [number, string][]; + · ────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ type Arr = Array; + · ──────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. + ╭─[array_type.tsx:3:14] + 2 │ interface ArrayClass { + 3 │ foo: Array; + · ──────── + 4 │ bar: T[]; + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function barFunction(bar: ArrayClass[]) { + · ──────────────────── + 3 │ return bar.map(e => e.bar); + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:13] + 1 │ let barVar: ((c: number) => number)[]; + · ───────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:17] + 1 │ type barUnion = (string | number | boolean)[]; + · ───────────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ type barIntersection = (string & number)[]; + · ─────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'undefined[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array = [undefined] as undefined[]; + · ──────────────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let z: Array = [3, '4']; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ type Arr = Array; + · ──────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:3:14] + 2 │ interface ArrayClass { + 3 │ foo: Array; + · ──────── + 4 │ bar: T[]; + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function fooFunction(foo: Array>) { + · ───────────────────────── + 3 │ return foo.map(e => e.foo); + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:13] + 1 │ let fooVar: Array<(c: number) => number>; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:17] + 1 │ type fooUnion = Array; + · ──────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:24] + 1 │ type fooIntersection = Array; + · ────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array<>; + · ─────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array<>; + · ─────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:31] + 1 │ let x: Array = [1] as number[]; + · ──────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ let ya = [[1, '2']] as [number, string][]; + · ────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:4:14] + 3 │ foo: Array; + 4 │ bar: T[]; + · ─── + 5 │ baz: Arr; + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function barFunction(bar: ArrayClass[]) { + · ──────────────────── + 3 │ return bar.map(e => e.bar); + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:13] + 1 │ let barVar: ((c: number) => number)[]; + · ───────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:17] + 1 │ type barUnion = (string | number | boolean)[]; + · ───────────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ type barIntersection = (string & number)[]; + · ─────────────────── + ╰──── + + ⚠ Array type using 'string[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:3:24] + 2 │ interface FooInterface { + 3 │ '.bar': { baz: string[] }; + · ──────── + 4 │ } + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:12] + 1 │ const foo: Array void> = []; + · ─────────────────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:12] + 1 │ const foo: ReadonlyArray void> = []; + · ─────────────────────────────────────────── + ╰──── + From 808fccbea293fb2b398125deeccc5c188ff6b328 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 10:27:50 +0800 Subject: [PATCH 14/17] fix: fmt --- .../src/rules/typescript/array_type.rs | 1515 +++++++++++++---- 1 file changed, 1143 insertions(+), 372 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index df107489c04b1..389db00571a81 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -1,11 +1,14 @@ +use oxc_ast::{ + ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, + AstKind, +}; use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::{self, Error}, }; -use oxc_ast::{ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, AstKind}; +use oxc_macros::declare_oxc_lint; use oxc_semantic::AstNode; use oxc_span::Span; -use oxc_macros::declare_oxc_lint; use crate::{context::LintContext, fixer::Fix, rule::Rule}; @@ -35,7 +38,9 @@ pub enum ArrayTypeDiagnostic { // readonlyPrefix className type ErrorStringGeneric(String, String, String, #[label] Span), - #[error("Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead.")] + #[error( + "Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead." + )] #[diagnostic(severity(warning))] // readonlyPrefix className type ErrorStringGenericSimple(String, String, String, #[label] Span), @@ -78,42 +83,49 @@ impl Rule for ArrayType { fn from_configuration(value: serde_json::Value) -> Self { Self(Box::new(ArrayTypeConfig { default: value - .get(0) - .and_then(|v| v.get("default")) - .and_then(serde_json::Value::as_str) - .map_or_else(|| ArrayOption::Array, |s| match s { - "array" => ArrayOption::Array, - "generic" => ArrayOption::Generic, - _ => ArrayOption::ArraySimple, - }), + .get(0) + .and_then(|v| v.get("default")) + .and_then(serde_json::Value::as_str) + .map_or_else( + || ArrayOption::Array, + |s| match s { + "array" => ArrayOption::Array, + "generic" => ArrayOption::Generic, + _ => ArrayOption::ArraySimple, + }, + ), readonly: value - .get(0) - .and_then(|v| v.get("readonly")) - .and_then(serde_json::Value::as_str) - .map_or_else(|| None, |s| match s { - "array" => Some(ArrayOption::Array), - "generic" => Some(ArrayOption::Generic), - _ => Some(ArrayOption::ArraySimple), - }), + .get(0) + .and_then(|v| v.get("readonly")) + .and_then(serde_json::Value::as_str) + .map_or_else( + || None, + |s| match s { + "array" => Some(ArrayOption::Array), + "generic" => Some(ArrayOption::Generic), + _ => Some(ArrayOption::ArraySimple), + }, + ), })) } fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let default_config = &self.default; - let readonly_config: &ArrayOption = &self.readonly.clone().unwrap_or(default_config.clone()); + let readonly_config: &ArrayOption = + &self.readonly.clone().unwrap_or_else(|| default_config.clone()); match node.kind() { AstKind::TSTypeAnnotation(ts_type_annotation) => { check(&ts_type_annotation.type_annotation, default_config, readonly_config, ctx); - }, + } // for example: type barUnion = (string | number | boolean)[]; AstKind::TSTypeAliasDeclaration(ts_alias_annotation) => { check(&ts_alias_annotation.type_annotation, default_config, readonly_config, ctx); - }, + } // for example: let ya = [[1, '2']] as [number, string][]; AstKind::TSAsExpression(ts_as_expression) => { check(&ts_as_expression.type_annotation, default_config, readonly_config, ctx); - }, + } _ => {} } } @@ -136,9 +148,9 @@ fn check( } if let TSType::TSTypeOperatorType(ts_operator_type) = &type_annotation { - if let TSTypeOperator::Readonly = &ts_operator_type.operator { - if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { - check_and_report_error_generic( + if matches!(&ts_operator_type.operator, TSTypeOperator::Readonly) { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( readonly_config, ts_operator_type.span, &array_type.element_type, @@ -150,12 +162,7 @@ fn check( } if let TSType::TSTypeReference(ts_type_reference) = &type_annotation { - check_and_report_error_array( - default_config, - readonly_config, - ts_type_reference, - ctx, - ); + check_and_report_error_array(default_config, readonly_config, ts_type_reference, ctx); } } @@ -166,13 +173,13 @@ fn type_needs_parentheses(type_param: &TSType) -> bool { return identifier_reference.name.as_str() == "ReadonlyArray"; } true - }, - TSType::TSUnionType(_) => true, - TSType::TSFunctionType(_) => true, - TSType::TSIntersectionType(_) => true, - TSType::TSTypeOperatorType(_) => true, - TSType::TSInferType(_) => true, - TSType::TSConstructorType(_) => true, + } + TSType::TSUnionType(_) + | TSType::TSFunctionType(_) + | TSType::TSIntersectionType(_) + | TSType::TSTypeOperatorType(_) + | TSType::TSInferType(_) + | TSType::TSConstructorType(_) => true, _ => false, } } @@ -180,7 +187,7 @@ fn type_needs_parentheses(type_param: &TSType) -> bool { fn check_and_report_error_generic( config: &ArrayOption, type_reference_span: Span, - type_param: &TSType, + type_param: &TSType, ctx: &LintContext, is_readonly: bool, ) { @@ -198,33 +205,33 @@ fn check_and_report_error_generic( let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; let message_type = get_message_type(type_param, &source_text); - let diagnostic = if let ArrayOption::Generic = config { - ArrayTypeDiagnostic::ErrorStringGeneric( + let diagnostic = match config { + ArrayOption::Generic => ArrayTypeDiagnostic::ErrorStringGeneric( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, - ) - } else { - ArrayTypeDiagnostic::ErrorStringGenericSimple( + ), + _ => ArrayTypeDiagnostic::ErrorStringGenericSimple( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, - ) + ), }; let element_type_span = get_ts_element_type_span(&type_param); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { - let type_text = &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let type_text = + &source_text[element_type_span.start as usize..element_type_span.end as usize]; let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; - + Fix::new( - array_type_identifier.to_string() + "<" + type_text + ">", - Span { start: type_reference_span.start, end: type_reference_span.end } + array_type_identifier.to_string() + "<" + type_text + ">", + Span { start: type_reference_span.start, end: type_reference_span.end }, ) - }) + }); } fn check_and_report_error_array( @@ -233,9 +240,13 @@ fn check_and_report_error_array( ts_type_reference: &TSTypeReference, ctx: &LintContext, ) { - let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { return }; + let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { + return; + }; - if ident_ref_type_name.name.as_str() != "ReadonlyArray" && ident_ref_type_name.name.as_str() != "Array" { + if ident_ref_type_name.name.as_str() != "ReadonlyArray" + && ident_ref_type_name.name.as_str() != "Array" + { return; } let is_readonly_array_type = ident_ref_type_name.name == "ReadonlyArray"; @@ -248,26 +259,22 @@ fn check_and_report_error_array( let type_params = &ts_type_reference.type_parameters; if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { - let diagnostic = if let ArrayOption::Array = config { - ArrayTypeDiagnostic::ErrorStringArray( + let diagnostic = match config { + ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( readonly_prefix.to_string(), class_name.to_string(), "any".to_string(), ts_type_reference.span, - ) - } else { - ArrayTypeDiagnostic::ErrorStringArraySimple( + ), + _ => ArrayTypeDiagnostic::ErrorStringArraySimple( readonly_prefix.to_string(), ident_ref_type_name.name.to_string(), "any".to_string(), ts_type_reference.span, - ) + ), }; ctx.diagnostic_with_fix(diagnostic, || { - Fix::new( - readonly_prefix.to_string() + "any[]", - ts_type_reference.span, - ) + Fix::new(readonly_prefix.to_string() + "any[]", ts_type_reference.span) }); return; } @@ -275,10 +282,8 @@ fn check_and_report_error_array( return; } let first_type_param = type_params.as_ref().unwrap().params.get(0).unwrap(); - if let ArrayOption::ArraySimple = config { - if !is_simple_type(first_type_param) { - return; - } + if matches!(config, ArrayOption::ArraySimple) && !is_simple_type(first_type_param) { + return; } let type_parens = type_needs_parentheses(first_type_param); @@ -290,62 +295,59 @@ fn check_and_report_error_array( // parent_parens = false // }; let parent_parens = false; - - let element_type_span = get_ts_element_type_span(&first_type_param); + + let element_type_span = get_ts_element_type_span(first_type_param); let Some(element_type_span) = element_type_span else { return }; - let type_text = &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; + let type_text = + &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; - let mut start = String::from(if parent_parens {"("} else {""}); + let mut start = String::from(if parent_parens { "(" } else { "" }); start.push_str(readonly_prefix); - start.push_str(if type_parens {"("} else {""}); + start.push_str(if type_parens { "(" } else { "" }); - let mut end = String::from(if type_parens {")"} else {""}); + let mut end = String::from(if type_parens { ")" } else { "" }); end.push_str("[]"); - end.push_str(if parent_parens {")"} else {""}); + end.push_str(if parent_parens { ")" } else { "" }); let message_type = get_message_type(first_type_param, ctx.source_text()); - let diagnostic = if let ArrayOption::Array = config { - ArrayTypeDiagnostic::ErrorStringArray( - readonly_prefix.to_string(), - class_name.to_string(), - message_type.to_string(), - ts_type_reference.span, - ) - } else { - ArrayTypeDiagnostic::ErrorStringArraySimple( - readonly_prefix.to_string(), - ident_ref_type_name.name.to_string(), - message_type.to_string(), - ts_type_reference.span, - ) - }; - ctx.diagnostic_with_fix(diagnostic, || { - Fix::new( - start + type_text + end.as_str(), - ts_type_reference.span, - ) - }); + let diagnostic = match config { + ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ), + _ => ArrayTypeDiagnostic::ErrorStringArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ), + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new(start + type_text + end.as_str(), ts_type_reference.span) + }); } // Check whatever node can be considered as simple type fn is_simple_type(ts_type: &TSType) -> bool { match ts_type { - TSType::TSAnyKeyword(_) => true, - TSType::TSBooleanKeyword(_) => true, - TSType::TSNeverKeyword(_) => true, - TSType::TSNumberKeyword(_) => true, - TSType::TSBigIntKeyword(_) => true, - TSType::TSObjectKeyword(_) => true, - TSType::TSStringKeyword(_) => true, - TSType::TSSymbolKeyword(_) => true, - TSType::TSUnknownKeyword(_) => true, - TSType::TSVoidKeyword(_) => true, - TSType::TSNullKeyword(_) => true, - TSType::TSArrayType(_) => true, - TSType::TSUndefinedKeyword(_) => true, - TSType::TSQualifiedName(_) => true, - TSType::TSThisKeyword(_) => true, + TSType::TSAnyKeyword(_) + | TSType::TSBooleanKeyword(_) + | TSType::TSNeverKeyword(_) + | TSType::TSNumberKeyword(_) + | TSType::TSBigIntKeyword(_) + | TSType::TSObjectKeyword(_) + | TSType::TSStringKeyword(_) + | TSType::TSSymbolKeyword(_) + | TSType::TSUnknownKeyword(_) + | TSType::TSVoidKeyword(_) + | TSType::TSNullKeyword(_) + | TSType::TSArrayType(_) + | TSType::TSUndefinedKeyword(_) + | TSType::TSQualifiedName(_) + | TSType::TSThisKeyword(_) => true, TSType::TSTypeReference(node) => { let type_name = TSTypeName::get_first_name(&node.type_name); if type_name.name.as_str() == "Array" { @@ -353,7 +355,9 @@ fn is_simple_type(ts_type: &TSType) -> bool { return true; } if node.type_parameters.as_ref().unwrap().params.len() == 1 { - return is_simple_type(node.type_parameters.as_ref().unwrap().params.get(0).unwrap()); + return is_simple_type( + node.type_parameters.as_ref().unwrap().params.get(0).unwrap(), + ); } } else { if node.type_parameters.is_some() { @@ -362,13 +366,12 @@ fn is_simple_type(ts_type: &TSType) -> bool { if let TSTypeName::IdentifierReference(_) = &node.type_name { return true; } - return false + return false; } false - }, + } _ => false, } - } // Get the type name from the type node. for example: `Array` -> `string` @@ -429,201 +432,585 @@ fn test() { ("let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), ("let a = new Array();", Some(serde_json::json!([{"default":"array"}]))), ("let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"generic"}]))), - ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("function fooFunction(foo: Array>) { + ( + "function foo(a: Array): Array {}", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let yy: number[][] = [[4, 5], [6]];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "function fooFunction(foo: Array>) { return foo.map(e => e.foo); - }", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + }", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " function bazFunction(baz: Arr>) { return baz.map(e => e.baz); } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " namespace fooName { type BarType = { bar: string }; type BazType = Arr; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array"}]))), - ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"array"}]))), - ("function bazFunction(baz: Arr>) { + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "function bazFunction(baz: Arr>) { return baz.map(e => e.baz); - }", Some(serde_json::json!([{"default":"array"}]))), + }", + Some(serde_json::json!([{"default":"array"}])), + ), ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; - }", Some(serde_json::json!([{"default":"array"}]))), - ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), - ("let xx: Array> = [[1, 2], [3]];", Some(serde_json::json!([{"default":"generic"}]))), + }", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type Unwrap = T extends (infer E)[] ? E : T;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let xx: Array> = [[1, 2], [3]];", + Some(serde_json::json!([{"default":"generic"}])), + ), ("type Arr = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", Some(serde_json::json!([{"default":"generic"}]))), - ("function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", Some(serde_json::json!([{"default":"generic"}]))), - ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), - ("type fooUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: ReadonlyArray = [[]];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly Array[] = [[]];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), + ( + "function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type Unwrap = T extends Array ? E : T;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: ReadonlyArray = [[]];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly Array[] = [[]];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), ]; - - let fail = vec![ + + let fail = vec![ ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | bigint)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), ("let a: { foo: Array }[] = [];", Some(serde_json::json!([{"default":"array"}]))), ("let a: Array<{ foo: Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), // ("let a: Array<{ foo: Foo | Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("function foo(a: Array): Array {}", Some(serde_json::json!([{"default":"array"}]))), - ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "function foo(a: Array): Array {}", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let x: Array = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let y: string[] = >['2'];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), ("type Arr = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; xyz: this[]; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // ("let v: Array = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), // ("let w: fooName.BazType[] = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let x: Array = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array"}])), + ), ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array"}]))), ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), ("type Arr = Array;", Some(serde_json::json!([{"default":"array"}]))), @@ -631,123 +1018,415 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", Some(serde_json::json!([{"default":"array"}]))), - (" + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " function fooFunction(foo: Array>) { return foo.map(e => e.foo); } - ", Some(serde_json::json!([{"default":"array"}]))), - ("let fooVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array"}]))), - ("type fooUnion = Array;", Some(serde_json::json!([{"default":"array"}]))), - ("type fooIntersection = Array;", Some(serde_json::json!([{"default":"array"}]))), + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"array"}])), + ), ("let x: Array;", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array<>;", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array;", Some(serde_json::json!([{"default":"array-simple"}]))), ("let x: Array<>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [1] as number[];", Some(serde_json::json!([{"default":"generic"}]))), - ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), - ("let ya = [[1, '2']] as [number, string][];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let x: Array = [1] as number[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let y: string[] = >['2'];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"generic"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"generic"}]))), - ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"generic"}]))), - ("type barUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"generic"}]))), - ("type barIntersection = (string & number)[];", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; } - ", Some(serde_json::json!([{"default":"generic"}]))), + ", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"array"}]))), // ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), // ("type Foo = ReadonlyArray[];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: Array void> = [];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: ReadonlyArray void> = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "const foo: Array void> = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "const foo: ReadonlyArray void> = [];", + Some(serde_json::json!([{"default":"array"}])), + ), ]; let fix: Vec<(&str, &str, Option)> = vec![ - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"array-simple"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: Array = [];", "let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array","readonly":"generic"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}]))), - ("let a: Array = [];", "let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly (string | number)[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: number[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: (string | number)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly number[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | number)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: bigint[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: ReadonlyArray = [];", "let a: readonly bigint[] = [];", Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}]))), - ("let a: (string | bigint)[] = [];", "let a: Array = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly bigint[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: readonly (string | bigint)[] = [];", "let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic","readonly":"generic"}]))), - ("let a: { foo: Array }[] = [];", "let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("let a: Array<{ foo: Bar[] }> = [];", "let a: Array<{ foo: Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: bigint[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly bigint[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: { foo: Array }[] = [];", + "let a: { foo: Bar[] }[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array<{ foo: Bar[] }> = [];", + "let a: Array<{ foo: Array }> = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("let a: Array<{ foo: Foo | Bar[] }> = [];", "let a: Array<{ foo: Foo | Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), - ("function foo(a: Array): Array {}", "function foo(a: Bar[]): Bar[] {}", Some(serde_json::json!([{"default":"array"}]))), - ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "function foo(a: Array): Array {}", + "function foo(a: Bar[]): Bar[] {}", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let x: Array = [undefined] as undefined[];", + "let x: undefined[] = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let z: Array = [3, '4'];", + "let z: any[] = [3, '4'];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let ya = [[1, '2']] as [number, string][];", + "let ya = [[1, '2']] as Array<[number, string]>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type Arr = Array;", + "type Arr = T[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; @@ -755,39 +1434,71 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr>>> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; xyz: this[]; } - ", " + ", + " interface ArrayClass { foo: T[]; bar: T[]; baz: Arr; xyz: this[]; } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - (" + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", " + ", + " function barFunction(bar: Array>) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), - ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + "let barVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + "type barUnion = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barIntersection = (string & number)[];", + "type barIntersection = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), // ("let v: Array = [{ bar: 'bar' }];", "let v: fooName.BarType[] = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), // ("let w: fooName.BazType[] = [['baz']];", "let w: Array> = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [undefined] as undefined[];", "let x: undefined[] = [undefined] as undefined[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let x: Array = [undefined] as undefined[];", + "let x: undefined[] = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array"}])), + ), // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array"}]))), - ("let z: Array = [3, '4'];", "let z: any[] = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), - ("type Arr = Array;", "type Arr = T[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let z: Array = [3, '4'];", + "let z: any[] = [3, '4'];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type Arr = Array;", + "type Arr = T[];", + Some(serde_json::json!([{"default":"array"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; @@ -795,38 +1506,66 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr[][]> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"array"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", " + ", + " interface ArrayClass { foo: T[]; bar: T[]; baz: Arr; } - ", Some(serde_json::json!([{"default":"array"}]))), - (" + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " function fooFunction(foo: Array>) { return foo.map(e => e.foo); } - ", " + ", + " function fooFunction(foo: ArrayClass[]) { return foo.map(e => e.foo); } - ", Some(serde_json::json!([{"default":"array"}]))), - ("let fooVar: Array<(c: number) => number>;", "let fooVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type fooUnion = Array;", "type fooUnion = (string | number | boolean)[];", Some(serde_json::json!([{"default":"array"}]))), - ("type fooIntersection = Array;", "type fooIntersection = (string & number)[];", Some(serde_json::json!([{"default":"array"}]))), + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + "let fooVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooUnion = Array;", + "type fooUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooIntersection = Array;", + "type fooIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), - ("let x: Array = [1] as number[];", "let x: Array = [1] as Array;", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let x: Array = [1] as number[];", + "let x: Array = [1] as Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("let y: string[] = >['2'];", "let y: Array = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), - ("let ya = [[1, '2']] as [number, string][];", "let ya = [[1, '2']] as Array<[number, string]>;", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + "let ya = [[1, '2']] as Array<[number, string]>;", + Some(serde_json::json!([{"default":"generic"}])), + ), // (" // // Ignore user defined aliases // let yyyy: Arr>[]> = [[[['2']]]]; @@ -834,45 +1573,77 @@ fn test() { // // Ignore user defined aliases // let yyyy: Arr>>> = [[[['2']]]]; // ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ( + " interface ArrayClass { foo: Array; bar: T[]; baz: Arr; } - ", " + ", + " interface ArrayClass { foo: Array; bar: Array; baz: Arr; } - ", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " function barFunction(bar: ArrayClass[]) { return bar.map(e => e.bar); } - ", " + ", + " function barFunction(bar: Array>) { return bar.map(e => e.bar); } - ", Some(serde_json::json!([{"default":"generic"}]))), - ("let barVar: ((c: number) => number)[];", "let barVar: Array<(c: number) => number>;", Some(serde_json::json!([{"default":"generic"}]))), - ("type barUnion = (string | number | boolean)[];", "type barUnion = Array;", Some(serde_json::json!([{"default":"generic"}]))), - ("type barIntersection = (string & number)[];", "type barIntersection = Array;", Some(serde_json::json!([{"default":"generic"}]))), - (" + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + "let barVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + "type barUnion = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barIntersection = (string & number)[];", + "type barIntersection = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " interface FooInterface { '.bar': { baz: string[] }; } - ", " + ", + " interface FooInterface { '.bar': { baz: Array }; } - ", Some(serde_json::json!([{"default":"generic"}]))), + ", + Some(serde_json::json!([{"default":"generic"}])), + ), // ("type Unwrap = T extends Array ? E : T;", "type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), // ("type Unwrap = T extends (infer E)[] ? E : T;", "type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), // ("type Foo = ReadonlyArray[];", "type Foo = (readonly object[])[];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: Array void> = [];", "const foo: (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), - ("const foo: ReadonlyArray void> = [];", "const foo: readonly (new (...args: any[]) => void)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "const foo: Array void> = [];", + "const foo: (new (...args: any[]) => void)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "const foo: ReadonlyArray void> = [];", + "const foo: readonly (new (...args: any[]) => void)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), ]; Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); From a6fed8c339a19032f0309925211e70e22c03341c Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 10:44:53 +0800 Subject: [PATCH 15/17] fix: lint --- .../src/rules/typescript/array_type.rs | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index 389db00571a81..4d6cbcccf1011 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -36,24 +36,24 @@ pub enum ArrayTypeDiagnostic { #[error("Array type using '{0}{2}[]' is forbidden. Use '{1}<{2}>' instead.")] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringGeneric(String, String, String, #[label] Span), + Generic(String, String, String, #[label] Span), #[error( "Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead." )] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringGenericSimple(String, String, String, #[label] Span), + GenericSimple(String, String, String, #[label] Span), #[error("Array type using '{1}<{2}>' is forbidden. Use '{0}{2}[]' instead.")] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringArray(String, String, String, #[label] Span), + Array(String, String, String, #[label] Span), #[error("Array type using '{1}<{2}>' is forbidden for simple types. Use '{0}{2}[]' instead.")] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringArraySimple(String, String, String, #[label] Span), + ArraySimple(String, String, String, #[label] Span), } #[derive(Debug, Default, Clone)] @@ -191,13 +191,11 @@ fn check_and_report_error_generic( ctx: &LintContext, is_readonly: bool, ) { - if let ArrayOption::Array = config { + if matches!(config, ArrayOption::Array) { return; } - if let ArrayOption::ArraySimple = config { - if is_simple_type(type_param) { - return; - } + if matches!(config, ArrayOption::ArraySimple) && is_simple_type(type_param) { + return; } let source_text = ctx.source_text().to_string(); @@ -206,20 +204,20 @@ fn check_and_report_error_generic( let message_type = get_message_type(type_param, &source_text); let diagnostic = match config { - ArrayOption::Generic => ArrayTypeDiagnostic::ErrorStringGeneric( + ArrayOption::Generic => ArrayTypeDiagnostic::Generic( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, ), - _ => ArrayTypeDiagnostic::ErrorStringGenericSimple( + _ => ArrayTypeDiagnostic::GenericSimple( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, ), }; - let element_type_span = get_ts_element_type_span(&type_param); + let element_type_span = get_ts_element_type_span(type_param); let Some(element_type_span) = element_type_span else { return }; ctx.diagnostic_with_fix(diagnostic, || { @@ -251,7 +249,7 @@ fn check_and_report_error_array( } let is_readonly_array_type = ident_ref_type_name.name == "ReadonlyArray"; let config = if is_readonly_array_type { readonly_config } else { default_config }; - if let ArrayOption::Generic = config { + if matches!(config, ArrayOption::Generic) { return; } let readonly_prefix: &str = if is_readonly_array_type { "readonly " } else { "" }; @@ -260,13 +258,13 @@ fn check_and_report_error_array( if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { let diagnostic = match config { - ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( + ArrayOption::Array => ArrayTypeDiagnostic::Array( readonly_prefix.to_string(), class_name.to_string(), "any".to_string(), ts_type_reference.span, ), - _ => ArrayTypeDiagnostic::ErrorStringArraySimple( + _ => ArrayTypeDiagnostic::ArraySimple( readonly_prefix.to_string(), ident_ref_type_name.name.to_string(), "any".to_string(), @@ -281,7 +279,7 @@ fn check_and_report_error_array( if type_params.as_ref().unwrap().params.len() != 1 { return; } - let first_type_param = type_params.as_ref().unwrap().params.get(0).unwrap(); + let first_type_param = type_params.as_ref().unwrap().params.first().unwrap(); if matches!(config, ArrayOption::ArraySimple) && !is_simple_type(first_type_param) { return; } @@ -312,13 +310,13 @@ fn check_and_report_error_array( let message_type = get_message_type(first_type_param, ctx.source_text()); let diagnostic = match config { - ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( + ArrayOption::Array => ArrayTypeDiagnostic::Array( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), ts_type_reference.span, ), - _ => ArrayTypeDiagnostic::ErrorStringArraySimple( + _ => ArrayTypeDiagnostic::ArraySimple( readonly_prefix.to_string(), ident_ref_type_name.name.to_string(), message_type.to_string(), @@ -356,7 +354,7 @@ fn is_simple_type(ts_type: &TSType) -> bool { } if node.type_parameters.as_ref().unwrap().params.len() == 1 { return is_simple_type( - node.type_parameters.as_ref().unwrap().params.get(0).unwrap(), + node.type_parameters.as_ref().unwrap().params.first().unwrap(), ); } } else { From 231a96de98360440420d546d6385f2565c0d8186 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 11:01:12 +0800 Subject: [PATCH 16/17] chore: use matches! instead of if let --- crates/oxc_linter/src/rules/typescript/array_type.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index d551aa63f20ec..a35770d1d0596 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -191,13 +191,11 @@ fn check_and_report_error_generic( ctx: &LintContext, is_readonly: bool, ) { - if let ArrayOption::Array = config { + if matches!(config, ArrayOption::Array) { return; } - if let ArrayOption::ArraySimple = config { - if is_simple_type(type_param) { - return; - } + if matches!(config, ArrayOption::ArraySimple) && is_simple_type(type_param) { + return; } let source_text = ctx.source_text().to_string(); From 8358945c4664a10aa235e1e67747a71722961b32 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Tue, 6 Feb 2024 11:09:25 +0800 Subject: [PATCH 17/17] fix: clippy --- .../src/rules/typescript/array_type.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index a35770d1d0596..4d6cbcccf1011 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -36,24 +36,24 @@ pub enum ArrayTypeDiagnostic { #[error("Array type using '{0}{2}[]' is forbidden. Use '{1}<{2}>' instead.")] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringGeneric(String, String, String, #[label] Span), + Generic(String, String, String, #[label] Span), #[error( "Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead." )] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringGenericSimple(String, String, String, #[label] Span), + GenericSimple(String, String, String, #[label] Span), #[error("Array type using '{1}<{2}>' is forbidden. Use '{0}{2}[]' instead.")] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringArray(String, String, String, #[label] Span), + Array(String, String, String, #[label] Span), #[error("Array type using '{1}<{2}>' is forbidden for simple types. Use '{0}{2}[]' instead.")] #[diagnostic(severity(warning))] // readonlyPrefix className type - ErrorStringArraySimple(String, String, String, #[label] Span), + ArraySimple(String, String, String, #[label] Span), } #[derive(Debug, Default, Clone)] @@ -204,13 +204,13 @@ fn check_and_report_error_generic( let message_type = get_message_type(type_param, &source_text); let diagnostic = match config { - ArrayOption::Generic => ArrayTypeDiagnostic::ErrorStringGeneric( + ArrayOption::Generic => ArrayTypeDiagnostic::Generic( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), type_reference_span, ), - _ => ArrayTypeDiagnostic::ErrorStringGenericSimple( + _ => ArrayTypeDiagnostic::GenericSimple( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), @@ -258,13 +258,13 @@ fn check_and_report_error_array( if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { let diagnostic = match config { - ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( + ArrayOption::Array => ArrayTypeDiagnostic::Array( readonly_prefix.to_string(), class_name.to_string(), "any".to_string(), ts_type_reference.span, ), - _ => ArrayTypeDiagnostic::ErrorStringArraySimple( + _ => ArrayTypeDiagnostic::ArraySimple( readonly_prefix.to_string(), ident_ref_type_name.name.to_string(), "any".to_string(), @@ -310,13 +310,13 @@ fn check_and_report_error_array( let message_type = get_message_type(first_type_param, ctx.source_text()); let diagnostic = match config { - ArrayOption::Array => ArrayTypeDiagnostic::ErrorStringArray( + ArrayOption::Array => ArrayTypeDiagnostic::Array( readonly_prefix.to_string(), class_name.to_string(), message_type.to_string(), ts_type_reference.span, ), - _ => ArrayTypeDiagnostic::ErrorStringArraySimple( + _ => ArrayTypeDiagnostic::ArraySimple( readonly_prefix.to_string(), ident_ref_type_name.name.to_string(), message_type.to_string(),