mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 06:05:02 +03:00
feat(es/lints): Implement no-restricted-syntax
rule (#3607)
This commit is contained in:
parent
144b2c9f9f
commit
72343baf5b
@ -0,0 +1,17 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"noRestrictedSyntax": [
|
||||
"error",
|
||||
{
|
||||
"BinaryExpression": [
|
||||
{
|
||||
"message": "no 'in' expession",
|
||||
"operator": "in"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
'a' in { a: 10 };
|
||||
|
||||
|
||||
() => {
|
||||
// nested
|
||||
if ('a' in { a: 10 }) {}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error: no 'in' expession
|
||||
|
||||
|
|
||||
1 | 'a' in { a: 10 };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: no 'in' expession
|
||||
|
||||
|
|
||||
6 | if ('a' in { a: 10 }) {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"noRestrictedSyntax": [
|
||||
"error",
|
||||
{
|
||||
"ForInExpression": {
|
||||
"message": "no 'for-in' expession"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
for (var x in {}) {}
|
@ -0,0 +1,6 @@
|
||||
error: no 'for-in' expession
|
||||
|
||||
|
|
||||
1 | for (var x in {}) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"noRestrictedSyntax": [
|
||||
"error",
|
||||
{
|
||||
"ForOfExpression": {
|
||||
"message": "no 'for-of' expession"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
for (var x of {}) {}
|
@ -0,0 +1,6 @@
|
||||
error: no 'for-of' expession
|
||||
|
||||
|
|
||||
1 | for (var x of {}) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"noRestrictedSyntax": [
|
||||
"error",
|
||||
{
|
||||
"LabelStatement": [
|
||||
{
|
||||
"message": "no label statement"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
loop1:
|
||||
|
||||
while (true) {
|
||||
continue loop1;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
error: no label statement
|
||||
|
||||
|
|
||||
1 | / loop1:
|
||||
2 | |
|
||||
3 | | while (true) {
|
||||
4 | | continue loop1;
|
||||
5 | | }
|
||||
| |_^
|
||||
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
use crate::rules::non_critical_lints::{
|
||||
dot_notation::DotNotationConfig, eqeqeq::EqeqeqConfig, no_console::NoConsoleConfig,
|
||||
no_use_before_define::NoUseBeforeDefineConfig,
|
||||
no_restricted_syntax::NoRestrictedSyntaxConfig, no_use_before_define::NoUseBeforeDefineConfig,
|
||||
prefer_regex_literals::PreferRegexLiteralsConfig, quotes::QuotesConfig,
|
||||
};
|
||||
|
||||
@ -104,4 +104,8 @@ pub struct LintConfig {
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
#[serde(default)]
|
||||
pub eqeqeq: RuleConfig<EqeqeqConfig>,
|
||||
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
#[serde(default, alias = "noRestrictedSyntax")]
|
||||
pub no_restricted_syntax: RuleConfig<NoRestrictedSyntaxConfig>,
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ pub(crate) mod non_critical_lints {
|
||||
pub mod no_console;
|
||||
pub mod no_debugger;
|
||||
pub mod no_empty_pattern;
|
||||
pub mod no_restricted_syntax;
|
||||
pub mod no_use_before_define;
|
||||
pub mod prefer_regex_literals;
|
||||
pub mod quotes;
|
||||
@ -93,6 +94,10 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
|
||||
));
|
||||
|
||||
rules.extend(eqeqeq::eqeqeq(&lint_config.eqeqeq));
|
||||
|
||||
rules.extend(no_restricted_syntax::no_restricted_syntax(
|
||||
&lint_config.no_restricted_syntax,
|
||||
));
|
||||
}
|
||||
|
||||
rules
|
||||
|
153
crates/swc_ecma_lints/src/rules/no_restricted_syntax.rs
Normal file
153
crates/swc_ecma_lints/src/rules/no_restricted_syntax.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use swc_common::{errors::HANDLER, Span};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
|
||||
|
||||
use crate::{
|
||||
config::{LintRuleReaction, RuleConfig},
|
||||
rule::{visitor_rule, Rule},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BinaryExpression {
|
||||
message: String,
|
||||
operator: BinaryOp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ForInExpression {
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ForOfExpression {
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WithStatement {
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct LabelStatement {
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct NoRestrictedSyntaxConfig {
|
||||
binary_expression: Option<Vec<BinaryExpression>>,
|
||||
for_in_expression: Option<ForInExpression>,
|
||||
for_of_expression: Option<ForOfExpression>,
|
||||
with_statement: Option<Vec<WithStatement>>,
|
||||
label_statement: Option<Vec<LabelStatement>>,
|
||||
}
|
||||
|
||||
pub fn no_restricted_syntax(
|
||||
config: &RuleConfig<NoRestrictedSyntaxConfig>,
|
||||
) -> Option<Box<dyn Rule>> {
|
||||
match config.get_rule_reaction() {
|
||||
LintRuleReaction::Off => None,
|
||||
_ => Some(visitor_rule(NoRestrictedSyntax::new(config))),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct NoRestrictedSyntax {
|
||||
expected_reaction: LintRuleReaction,
|
||||
|
||||
binary_expr: Option<Vec<BinaryExpression>>,
|
||||
for_in_expression: Option<ForInExpression>,
|
||||
for_of_expression: Option<ForOfExpression>,
|
||||
with_statement: Option<Vec<WithStatement>>,
|
||||
label_statement: Option<Vec<LabelStatement>>,
|
||||
}
|
||||
|
||||
impl NoRestrictedSyntax {
|
||||
fn new(config: &RuleConfig<NoRestrictedSyntaxConfig>) -> Self {
|
||||
let rule_config = config.get_rule_config();
|
||||
|
||||
Self {
|
||||
expected_reaction: config.get_rule_reaction(),
|
||||
binary_expr: rule_config.binary_expression.clone(),
|
||||
for_in_expression: rule_config.for_in_expression.clone(),
|
||||
for_of_expression: rule_config.for_of_expression.clone(),
|
||||
with_statement: rule_config.with_statement.clone(),
|
||||
label_statement: rule_config.label_statement.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_report(&self, span: Span, message: &str) {
|
||||
HANDLER.with(|handler| match self.expected_reaction {
|
||||
LintRuleReaction::Error => {
|
||||
handler.struct_span_err(span, message).emit();
|
||||
}
|
||||
LintRuleReaction::Warning => {
|
||||
handler.struct_span_warn(span, message).emit();
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for NoRestrictedSyntax {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_expr(&mut self, expr: &Expr) {
|
||||
if let Expr::Bin(BinExpr { span, op, .. }) = expr {
|
||||
let op = *op;
|
||||
|
||||
if let Some(binary_expr) = &self.binary_expr {
|
||||
let rule = binary_expr.iter().find(|rule| rule.operator == op);
|
||||
|
||||
if let Some(BinaryExpression { message, .. }) = rule {
|
||||
self.emit_report(*span, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expr.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_for_in_stmt(&mut self, for_in: &ForInStmt) {
|
||||
if let Some(ForInExpression { message }) = &self.for_in_expression {
|
||||
self.emit_report(for_in.span, message);
|
||||
}
|
||||
|
||||
for_in.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_for_of_stmt(&mut self, for_of: &ForOfStmt) {
|
||||
if let Some(ForOfExpression { message }) = &self.for_of_expression {
|
||||
self.emit_report(for_of.span, message);
|
||||
}
|
||||
|
||||
for_of.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_with_stmt(&mut self, with_stmt: &WithStmt) {
|
||||
if let Some(rules) = &self.with_statement {
|
||||
rules.iter().for_each(|rule| {
|
||||
self.emit_report(with_stmt.span, &rule.message);
|
||||
});
|
||||
}
|
||||
|
||||
with_stmt.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_labeled_stmt(&mut self, labeled_stmt: &LabeledStmt) {
|
||||
if let Some(rules) = &self.label_statement {
|
||||
rules.iter().for_each(|rule| {
|
||||
self.emit_report(labeled_stmt.span, &rule.message);
|
||||
});
|
||||
}
|
||||
|
||||
labeled_stmt.visit_children_with(self);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user