Skip to content

Commit

Permalink
Merge branch 'main' into feature/no-useless-undefined-initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
lutaok committed Apr 26, 2024
2 parents fc7d5f9 + ce4979d commit 0080714
Show file tree
Hide file tree
Showing 25 changed files with 752 additions and 241 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

Contributed by @Conaclos

- Import sorting now adds spaces where needed ([#1665](https://github.com/biomejs/biome/issues/1665))
Contributed by @Conaclos

### CLI

#### Bug fixes
Expand Down Expand Up @@ -79,6 +82,24 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

Contributed by @Conaclos

- Fix [useShorthandFunctionType](https://biomejs.dev/linter/rules/use-shorthand-function-type/) that suggested invalid code fixes when parentheses are required ([#2595](https://github.com/biomejs/biome/issues/2595)).

Previously, the rule didn't add parentheses when they were needed.
It now adds parentheses when the function signature is inside an array, a union, or an intersection.

```diff
- type Union = { (): number } | string;
+ type Union = (() => number) | string;
```

Contributed by @Conaclos

- Fix [useTemplate](https://biomejs.dev/linter/rules/use-template/) that wrongly escaped strings in some edge cases ([#2580](https://github.com/biomejs/biome/issues/2580)).

Previously, the rule didn't correctly escape characters preceded by an escaped character.

Contributed by @Conaclos

### Parser

## 1.7.1 (2024-04-22)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 25 additions & 6 deletions crates/biome_configuration/src/linter/rules.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/biome_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ define_categories! {
"lint/correctness/useValidForDirection": "https://biomejs.dev/linter/rules/use-valid-for-direction",
"lint/correctness/useYield": "https://biomejs.dev/linter/rules/use-yield",
"lint/nursery/colorNoInvalidHex": "https://biomejs.dev/linter/rules/color-no-invalid-hex",
"lint/nursery/useArrayLiterals": "https://biomejs.dev/linter/rules/use-array-literals",
"lint/nursery/noColorInvalidHex": "https://biomejs.dev/linter/rules/no-color-invalid-hex",
"lint/nursery/noConsole": "https://biomejs.dev/linter/rules/no-console",
"lint/nursery/noConstantMathMinMaxClamp": "https://biomejs.dev/linter/rules/no-constant-math-min-max-clamp",
Expand Down
10 changes: 9 additions & 1 deletion crates/biome_formatter_test/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use biome_fs::BiomePath;
use biome_parser::AnyParse;
use biome_rowan::{TextRange, TextSize};
use biome_service::settings::{ServiceLanguage, Settings};
use biome_service::workspace::{DocumentFileSource, FeaturesBuilder, SupportsFeatureParams};
use biome_service::workspace::{
DocumentFileSource, FeaturesBuilder, RegisterProjectFolderParams, SupportsFeatureParams,
};
use biome_service::App;
use std::ops::Range;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -40,6 +42,12 @@ impl<'a> SpecTestFile<'a> {
spec_input_file.display()
);

app.workspace
.register_project_folder(RegisterProjectFolderParams {
set_as_current_workspace: true,
path: None,
})
.unwrap();
let mut input_file = BiomePath::new(file_path);
let can_format = app
.workspace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,14 @@ impl ImportNode {
// If the node we're attaching this separator to has no trailing trivia, just create a simple comma token
let last_trailing_trivia = match node.syntax().last_trailing_trivia() {
Some(trivia) if !trivia.is_empty() => trivia,
_ => return make::token(T![,]),
_ => {
let sep = make::token(T![,]);
return if node.syntax().has_leading_newline() {
sep
} else {
sep.with_trailing_trivia([(TriviaPieceKind::Whitespace, " ")])
};
}
};

// Otherwise we need to clone the trailing trivia from the node to the separator
Expand Down
2 changes: 2 additions & 0 deletions crates/biome_js_analyze/src/lint/nursery.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

113 changes: 113 additions & 0 deletions crates/biome_js_analyze/src/lint/nursery/use_array_literals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use biome_analyze::{
context::RuleContext, declare_rule, Ast, FixKind, Rule, RuleDiagnostic, RuleSource,
};
use biome_console::markup;
use biome_js_syntax::{AnyJsCallArgument, AnyJsExpression, JsCallArguments, JsExpressionStatement};
use biome_rowan::AstNode;

declare_rule! {
/// Disallow Array constructors.
///
/// Use of the Array constructor to construct a new array is generally discouraged in favor of array literal notation because of the single-argument pitfall and because the Array global may be redefined.
/// The exception is when the Array constructor intentionally creates sparse arrays of a specified size by giving the constructor a single numeric argument.
///
/// ## Examples
///
/// ### Invalid
///
/// ```js,expect_diagnostic
/// Array();
/// ```
///
/// ```js,expect_diagnostic
/// Array(0, 1, 2);
/// ```
///
/// ```js,expect_diagnostic
/// new Array(0, 1, 2);
/// ```
///
/// ```js,expect_diagnostic
/// Array(...args);
/// ```
///
/// ### Valid
///
/// ```js
/// Array(500);
/// ```
///
/// ```js
/// [0, 1, 2];
/// ```
///
pub UseArrayLiterals {
version: "next",
name: "useArrayLiterals",
sources: &[RuleSource::Eslint("no-array-constructor")],
recommended: false,
fix_kind: FixKind::Unsafe,
}
}

impl Rule for UseArrayLiterals {
type Query = Ast<JsExpressionStatement>;
type State = ();
type Signals = Option<Self::State>;
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
let expression_statement = ctx.query();

let expression = expression_statement.expression().ok()?;

match expression {
AnyJsExpression::JsCallExpression(call_expression) => {
let callee = call_expression.callee().ok()?;
let arguments = call_expression.arguments().ok()?;
validate(&callee, &arguments)
}
AnyJsExpression::JsNewExpression(new_expression) => {
let callee = new_expression.callee().ok()?;
let arguments = new_expression.arguments()?;
validate(&callee, &arguments)
}
_ => None,
}
}

fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
let node = ctx.query();
Some(
RuleDiagnostic::new(
rule_category!(),
node.range(),
markup! {
"Don't use Array constructors."
},
)
.note(markup! {
"Use of the Array constructor is not allowed except creating sparse arrays of a specified size by giving a single numeric argument."
})
.note(markup! {
"The array literal notation [] is preferable."
}),
)
}
}

fn validate(callee: &AnyJsExpression, arguments: &JsCallArguments) -> Option<()> {
if callee.text() != "Array" {
return None;
}
let mut args_iter = arguments.args().into_iter();
let first_arg = args_iter.next();
let second_arg = args_iter.next();
if first_arg.is_some()
&& second_arg.is_none()
&& !matches!(first_arg?.ok()?, AnyJsCallArgument::JsSpread(_))
{
return None;
}
Some(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use biome_js_factory::make;
use biome_js_factory::make::ts_type_alias_declaration;
use biome_js_syntax::AnyTsType::TsThisType;
use biome_js_syntax::{
AnyJsDeclarationClause, AnyTsReturnType, AnyTsType, TsCallSignatureTypeMember, TsFunctionType,
TsInterfaceDeclaration, TsObjectType, TsTypeMemberList, T,
AnyJsDeclarationClause, AnyTsReturnType, AnyTsType, JsSyntaxKind, TsCallSignatureTypeMember,
TsFunctionType, TsInterfaceDeclaration, TsObjectType, TsTypeMemberList, T,
};
use biome_rowan::{AstNode, AstNodeList, BatchMutationExt, TriviaPieceKind};
use biome_rowan::{AstNode, AstNodeList, BatchMutationExt, SyntaxNodeOptionExt, TriviaPieceKind};

declare_rule! {
/// Enforce using function types instead of object type with call signatures.
Expand Down Expand Up @@ -152,7 +152,6 @@ impl Rule for UseShorthandFunctionType {
AnyJsDeclarationClause::from(interface_decl),
AnyJsDeclarationClause::from(type_alias_declaration),
);

return Some(JsRuleAction {
category: ActionCategory::QuickFix,
applicability: Applicability::Always,
Expand All @@ -163,12 +162,38 @@ impl Rule for UseShorthandFunctionType {

if let Some(ts_object_type) = ts_type_member_list.parent::<TsObjectType>() {
let new_function_type = convert_ts_call_signature_type_member_to_function_type(node)?;

mutation.replace_node(
AnyTsType::from(ts_object_type),
AnyTsType::from(new_function_type),
);

// This is a simplification of the `needs_parentheses`
// available in biome_js_formatter/src/ts/types/function_type.rs
let needs_parens = matches!(
ts_object_type.syntax().parent().kind(),
Some(
JsSyntaxKind::TS_RETURN_TYPE_ANNOTATION
| JsSyntaxKind::TS_CONDITIONAL_TYPE
| JsSyntaxKind::TS_ARRAY_TYPE
| JsSyntaxKind::TS_TYPE_OPERATOR_TYPE
| JsSyntaxKind::TS_REST_TUPLE_TYPE_ELEMENT
| JsSyntaxKind::TS_OPTIONAL_TUPLE_TYPE_ELEMENT
| JsSyntaxKind::TS_UNION_TYPE_VARIANT_LIST
| JsSyntaxKind::TS_INTERSECTION_TYPE_ELEMENT_LIST
)
) || matches!(new_function_type.return_type().map(|return_type| {
let AnyTsReturnType::AnyTsType(any_ts_type) = return_type else {
return None;
};
Some(any_ts_type)
}), Ok(Some(AnyTsType::TsInferType(infer_type))) if infer_type.constraint().is_some());
let new_function_type: AnyTsType = if needs_parens {
make::ts_parenthesized_type(
make::token(T!['(']),
new_function_type.trim_trivia()?.into(),
make::token(T![')']),
)
.into()
} else {
new_function_type.into()
};

mutation.replace_node(AnyTsType::from(ts_object_type), new_function_type);
return Some(JsRuleAction {
category: ActionCategory::QuickFix,
applicability: Applicability::Always,
Expand Down
Loading

0 comments on commit 0080714

Please sign in to comment.