Linux v69820.1blu.de 4.15.0 #1 SMP Mon Sep 30 15:36:27 MSK 2024 x86_64
Apache/2.4.58
Server IP : 195.90.215.149 & Your IP : 216.73.217.80
Domains :
Cant Read [ /etc/named.conf ]
User : www-data
Terminal
Auto Root
Create File
Create Folder
Localroot Suggester
Backdoor Destroyer
Readme
/
usr /
share /
nodejs /
eslint /
lib /
rules /
Delete
Unzip
Name
Size
Permission
Date
Action
utils
[ DIR ]
drwxr-xr-x
2024-07-10 10:55
accessor-pairs.js
12.41
KB
-rw-r--r--
2019-09-14 01:35
array-bracket-newline.js
9.43
KB
-rw-r--r--
2019-09-14 01:35
array-bracket-spacing.js
8.85
KB
-rw-r--r--
2019-09-14 01:35
array-callback-return.js
7.98
KB
-rw-r--r--
2019-09-14 01:35
array-element-newline.js
9.22
KB
-rw-r--r--
2023-12-15 20:21
arrow-body-style.js
10.27
KB
-rw-r--r--
2019-09-14 01:35
arrow-parens.js
6.38
KB
-rw-r--r--
2019-09-14 01:35
arrow-spacing.js
5.08
KB
-rw-r--r--
2019-09-14 01:35
block-scoped-var.js
3.58
KB
-rw-r--r--
2019-09-14 01:35
block-spacing.js
4.99
KB
-rw-r--r--
2019-09-14 01:35
brace-style.js
7.71
KB
-rw-r--r--
2019-09-14 01:35
callback-return.js
6.33
KB
-rw-r--r--
2019-09-14 01:35
camelcase.js
8.29
KB
-rw-r--r--
2019-09-14 01:35
capitalized-comments.js
10.68
KB
-rw-r--r--
2023-12-15 20:21
class-methods-use-this.js
3.81
KB
-rw-r--r--
2019-09-14 01:35
comma-dangle.js
11.75
KB
-rw-r--r--
2019-09-14 01:35
comma-spacing.js
6.53
KB
-rw-r--r--
2019-09-14 01:35
comma-style.js
11.78
KB
-rw-r--r--
2019-09-14 01:35
complexity.js
4.94
KB
-rw-r--r--
2019-09-14 01:35
computed-property-spacing.js
7.17
KB
-rw-r--r--
2019-09-14 01:35
consistent-return.js
6.59
KB
-rw-r--r--
2019-09-14 01:35
consistent-this.js
4.86
KB
-rw-r--r--
2019-09-14 01:35
constructor-super.js
13.49
KB
-rw-r--r--
2019-09-14 01:35
curly.js
16.24
KB
-rw-r--r--
2019-09-14 01:35
default-case.js
2.76
KB
-rw-r--r--
2019-09-14 01:35
default-param-last.js
1.5
KB
-rw-r--r--
2019-09-14 01:35
dot-location.js
3.34
KB
-rw-r--r--
2019-09-14 01:35
dot-notation.js
6.47
KB
-rw-r--r--
2019-09-14 01:35
eol-last.js
3.79
KB
-rw-r--r--
2019-09-14 01:35
eqeqeq.js
5.55
KB
-rw-r--r--
2023-12-15 20:21
for-direction.js
4.27
KB
-rw-r--r--
2019-09-14 01:35
func-call-spacing.js
7.29
KB
-rw-r--r--
2019-09-14 01:35
func-name-matching.js
9.84
KB
-rw-r--r--
2023-12-15 20:21
func-names.js
6.09
KB
-rw-r--r--
2023-12-15 20:21
func-style.js
2.84
KB
-rw-r--r--
2019-09-14 01:35
function-call-argument-newline.js
4.13
KB
-rw-r--r--
2019-09-14 01:35
function-paren-newline.js
11.15
KB
-rw-r--r--
2019-09-14 01:35
generator-star-spacing.js
6.98
KB
-rw-r--r--
2019-09-14 01:35
getter-return.js
6.02
KB
-rw-r--r--
2019-09-14 01:35
global-require.js
2.3
KB
-rw-r--r--
2019-09-14 01:35
guard-for-in.js
2.3
KB
-rw-r--r--
2019-09-14 01:35
handle-callback-err.js
2.92
KB
-rw-r--r--
2019-09-14 01:35
id-blacklist.js
4.05
KB
-rw-r--r--
2019-09-14 01:35
id-length.js
4.12
KB
-rw-r--r--
2019-09-14 01:35
id-match.js
8.14
KB
-rw-r--r--
2019-09-14 01:35
implicit-arrow-linebreak.js
2.79
KB
-rw-r--r--
2019-09-14 01:35
indent-legacy.js
44.45
KB
-rw-r--r--
2019-09-14 01:35
indent.js
68.68
KB
-rw-r--r--
2019-09-14 01:35
index.js
16.34
KB
-rw-r--r--
2019-09-14 01:35
init-declarations.js
4.37
KB
-rw-r--r--
2019-09-14 01:35
jsx-quotes.js
2.89
KB
-rw-r--r--
2019-09-14 01:35
key-spacing.js
24.82
KB
-rw-r--r--
2019-09-14 01:35
keyword-spacing.js
21.2
KB
-rw-r--r--
2019-09-14 01:35
line-comment-position.js
4.08
KB
-rw-r--r--
2019-09-14 01:35
linebreak-style.js
3.17
KB
-rw-r--r--
2019-09-14 01:35
lines-around-comment.js
15.54
KB
-rw-r--r--
2019-09-14 01:35
lines-around-directive.js
7.58
KB
-rw-r--r--
2019-09-14 01:35
lines-between-class-members.js
5.05
KB
-rw-r--r--
2019-09-14 01:35
max-classes-per-file.js
1.73
KB
-rw-r--r--
2019-09-14 01:35
max-depth.js
4.59
KB
-rw-r--r--
2019-09-14 01:35
max-len.js
13.8
KB
-rw-r--r--
2019-09-14 01:35
max-lines-per-function.js
6.89
KB
-rw-r--r--
2019-09-14 01:35
max-lines.js
4.59
KB
-rw-r--r--
2019-09-14 01:35
max-nested-callbacks.js
3.47
KB
-rw-r--r--
2019-09-14 01:35
max-params.js
3.07
KB
-rw-r--r--
2019-09-14 01:35
max-statements-per-line.js
7.31
KB
-rw-r--r--
2019-09-14 01:35
max-statements.js
5.4
KB
-rw-r--r--
2019-09-14 01:35
multiline-comment-style.js
14.42
KB
-rw-r--r--
2019-09-14 01:35
multiline-ternary.js
3.42
KB
-rw-r--r--
2019-09-14 01:35
new-cap.js
9.44
KB
-rw-r--r--
2019-09-14 01:35
new-parens.js
3.14
KB
-rw-r--r--
2019-09-14 01:35
newline-after-var.js
9.6
KB
-rw-r--r--
2019-09-14 01:35
newline-before-return.js
7.89
KB
-rw-r--r--
2019-09-14 01:35
newline-per-chained-call.js
3.56
KB
-rw-r--r--
2019-09-14 01:35
no-alert.js
3.96
KB
-rw-r--r--
2019-09-14 01:35
no-array-constructor.js
1.36
KB
-rw-r--r--
2019-09-14 01:35
no-async-promise-executor.js
1.1
KB
-rw-r--r--
2019-09-14 01:35
no-await-in-loop.js
2.72
KB
-rw-r--r--
2019-09-14 01:35
no-bitwise.js
3.51
KB
-rw-r--r--
2019-09-14 01:35
no-buffer-constructor.js
1.31
KB
-rw-r--r--
2019-09-14 01:35
no-caller.js
1.17
KB
-rw-r--r--
2019-09-14 01:35
no-case-declarations.js
1.82
KB
-rw-r--r--
2019-09-14 01:35
no-catch-shadow.js
2.44
KB
-rw-r--r--
2019-09-14 01:35
no-class-assign.js
1.67
KB
-rw-r--r--
2019-09-14 01:35
no-compare-neg-zero.js
1.9
KB
-rw-r--r--
2019-09-14 01:35
no-cond-assign.js
5.04
KB
-rw-r--r--
2019-09-14 01:35
no-confusing-arrow.js
2.55
KB
-rw-r--r--
2019-09-14 01:35
no-console.js
4.21
KB
-rw-r--r--
2019-09-14 01:35
no-const-assign.js
1.46
KB
-rw-r--r--
2019-09-14 01:35
no-constant-condition.js
8.48
KB
-rw-r--r--
2019-09-14 01:35
no-continue.js
875
B
-rw-r--r--
2019-09-14 01:35
no-control-regex.js
3.14
KB
-rw-r--r--
2019-09-14 01:35
no-debugger.js
947
B
-rw-r--r--
2019-09-14 01:35
no-delete-var.js
965
B
-rw-r--r--
2019-09-14 01:35
no-div-regex.js
1.42
KB
-rw-r--r--
2019-09-14 01:35
no-dupe-args.js
2.3
KB
-rw-r--r--
2019-09-14 01:35
no-dupe-class-members.js
3.58
KB
-rw-r--r--
2019-09-14 01:35
no-dupe-keys.js
3.87
KB
-rw-r--r--
2019-09-14 01:35
no-duplicate-case.js
1.36
KB
-rw-r--r--
2019-09-14 01:35
no-duplicate-imports.js
4.43
KB
-rw-r--r--
2019-09-14 01:35
no-else-return.js
15.74
KB
-rw-r--r--
2019-09-14 01:35
no-empty-character-class.js
1.91
KB
-rw-r--r--
2019-09-14 01:35
no-empty-function.js
4.61
KB
-rw-r--r--
2019-09-14 01:35
no-empty-pattern.js
1.15
KB
-rw-r--r--
2019-09-14 01:35
no-empty.js
2.44
KB
-rw-r--r--
2019-09-14 01:35
no-eq-null.js
1.21
KB
-rw-r--r--
2019-09-14 01:35
no-eval.js
9.31
KB
-rw-r--r--
2019-09-14 01:35
no-ex-assign.js
1.37
KB
-rw-r--r--
2019-09-14 01:35
no-extend-native.js
6.95
KB
-rw-r--r--
2019-09-14 01:35
no-extra-bind.js
5.71
KB
-rw-r--r--
2019-09-14 01:35
no-extra-boolean-cast.js
6.52
KB
-rw-r--r--
2019-09-14 01:35
no-extra-label.js
4.76
KB
-rw-r--r--
2019-09-14 01:35
no-extra-parens.js
39.11
KB
-rw-r--r--
2019-09-14 01:35
no-extra-semi.js
4.11
KB
-rw-r--r--
2019-09-14 01:35
no-fallthrough.js
4.78
KB
-rw-r--r--
2019-09-14 01:35
no-floating-decimal.js
2.33
KB
-rw-r--r--
2019-09-14 01:35
no-func-assign.js
1.96
KB
-rw-r--r--
2019-09-14 01:35
no-global-assign.js
2.76
KB
-rw-r--r--
2019-09-14 01:35
no-implicit-coercion.js
10.06
KB
-rw-r--r--
2019-09-14 01:35
no-implicit-globals.js
1.78
KB
-rw-r--r--
2019-09-14 01:35
no-implied-eval.js
5.99
KB
-rw-r--r--
2019-09-14 01:35
no-import-assign.js
6.92
KB
-rw-r--r--
2019-09-14 01:35
no-inline-comments.js
2.19
KB
-rw-r--r--
2019-09-14 01:35
no-inner-declarations.js
2.59
KB
-rw-r--r--
2019-09-14 01:35
no-invalid-regexp.js
4.01
KB
-rw-r--r--
2019-09-14 01:35
no-invalid-this.js
3.74
KB
-rw-r--r--
2019-09-14 01:35
no-irregular-whitespace.js
8.72
KB
-rw-r--r--
2019-09-14 01:35
no-iterator.js
1.08
KB
-rw-r--r--
2019-09-14 01:35
no-label-var.js
2.13
KB
-rw-r--r--
2019-09-14 01:35
no-labels.js
4.22
KB
-rw-r--r--
2019-09-14 01:35
no-lone-blocks.js
3.68
KB
-rw-r--r--
2019-09-14 01:35
no-lonely-if.js
3.62
KB
-rw-r--r--
2019-09-14 01:35
no-loop-func.js
6.16
KB
-rw-r--r--
2019-09-14 01:35
no-magic-numbers.js
5.8
KB
-rw-r--r--
2019-09-14 01:35
no-misleading-character-class.js
6.05
KB
-rw-r--r--
2019-09-14 01:35
no-mixed-operators.js
8.21
KB
-rw-r--r--
2019-09-14 01:35
no-mixed-requires.js
6.91
KB
-rw-r--r--
2019-09-14 01:35
no-mixed-spaces-and-tabs.js
4.54
KB
-rw-r--r--
2019-09-14 01:35
no-multi-assign.js
1.18
KB
-rw-r--r--
2019-09-14 01:35
no-multi-spaces.js
4.85
KB
-rw-r--r--
2019-09-14 01:35
no-multi-str.js
1.64
KB
-rw-r--r--
2019-09-14 01:35
no-multiple-empty-lines.js
5.75
KB
-rw-r--r--
2019-09-14 01:35
no-native-reassign.js
2.86
KB
-rw-r--r--
2019-09-14 01:35
no-negated-condition.js
2.68
KB
-rw-r--r--
2019-09-14 01:35
no-negated-in-lhs.js
1.08
KB
-rw-r--r--
2019-09-14 01:35
no-nested-ternary.js
986
B
-rw-r--r--
2019-09-14 01:35
no-new-func.js
1.24
KB
-rw-r--r--
2019-09-14 01:35
no-new-object.js
923
B
-rw-r--r--
2019-09-14 01:35
no-new-require.js
960
B
-rw-r--r--
2019-09-14 01:35
no-new-symbol.js
1.27
KB
-rw-r--r--
2019-09-14 01:35
no-new-wrappers.js
1.05
KB
-rw-r--r--
2019-09-14 01:35
no-new.js
913
B
-rw-r--r--
2019-09-14 01:35
no-obj-calls.js
1.84
KB
-rw-r--r--
2019-09-14 01:35
no-octal-escape.js
1.42
KB
-rw-r--r--
2019-09-14 01:35
no-octal.js
886
B
-rw-r--r--
2019-09-14 01:35
no-param-reassign.js
6.8
KB
-rw-r--r--
2019-09-14 01:35
no-path-concat.js
1.44
KB
-rw-r--r--
2019-09-14 01:35
no-plusplus.js
1.66
KB
-rw-r--r--
2019-09-14 01:35
no-process-env.js
1.01
KB
-rw-r--r--
2019-09-14 01:35
no-process-exit.js
1.08
KB
-rw-r--r--
2019-09-14 01:35
no-proto.js
1.07
KB
-rw-r--r--
2019-09-14 01:35
no-prototype-builtins.js
1.63
KB
-rw-r--r--
2019-09-14 01:35
no-redeclare.js
5.6
KB
-rw-r--r--
2019-09-14 01:35
no-regex-spaces.js
3.73
KB
-rw-r--r--
2019-09-14 01:35
no-restricted-globals.js
3.76
KB
-rw-r--r--
2019-09-14 01:35
no-restricted-imports.js
11.43
KB
-rw-r--r--
2023-12-15 20:21
no-restricted-modules.js
5.9
KB
-rw-r--r--
2023-12-15 20:21
no-restricted-properties.js
6.46
KB
-rw-r--r--
2019-09-14 01:35
no-restricted-syntax.js
1.97
KB
-rw-r--r--
2019-09-14 01:35
no-return-assign.js
2.49
KB
-rw-r--r--
2019-09-14 01:35
no-return-await.js
3.73
KB
-rw-r--r--
2019-09-14 01:35
no-script-url.js
1.05
KB
-rw-r--r--
2019-09-14 01:35
no-self-assign.js
6.79
KB
-rw-r--r--
2019-09-14 01:35
no-self-compare.js
1.72
KB
-rw-r--r--
2019-09-14 01:35
no-sequences.js
3.94
KB
-rw-r--r--
2019-09-14 01:35
no-shadow-restricted-names.js
2
KB
-rw-r--r--
2019-09-14 01:35
no-shadow.js
6.81
KB
-rw-r--r--
2019-09-14 01:35
no-spaced-func.js
2.34
KB
-rw-r--r--
2019-09-14 01:35
no-sparse-arrays.js
1.07
KB
-rw-r--r--
2019-09-14 01:35
no-sync.js
1.52
KB
-rw-r--r--
2019-09-14 01:35
no-tabs.js
2.01
KB
-rw-r--r--
2019-09-14 01:35
no-template-curly-in-string.js
1.04
KB
-rw-r--r--
2019-09-14 01:35
no-ternary.js
793
B
-rw-r--r--
2019-09-14 01:35
no-this-before-super.js
9.95
KB
-rw-r--r--
2019-09-14 01:35
no-throw-literal.js
1.26
KB
-rw-r--r--
2019-09-14 01:35
no-trailing-spaces.js
6.13
KB
-rw-r--r--
2019-09-14 01:35
no-undef-init.js
2.01
KB
-rw-r--r--
2019-09-14 01:35
no-undef.js
2.24
KB
-rw-r--r--
2019-09-14 01:35
no-undefined.js
2.07
KB
-rw-r--r--
2019-09-14 01:35
no-underscore-dangle.js
7.44
KB
-rw-r--r--
2019-09-14 01:35
no-unexpected-multiline.js
3.59
KB
-rw-r--r--
2019-09-14 01:35
no-unmodified-loop-condition.js
11.65
KB
-rw-r--r--
2019-09-14 01:35
no-unneeded-ternary.js
6.58
KB
-rw-r--r--
2019-09-14 01:35
no-unreachable.js
6.29
KB
-rw-r--r--
2019-09-14 01:35
no-unsafe-finally.js
3.87
KB
-rw-r--r--
2019-09-14 01:35
no-unsafe-negation.js
2.36
KB
-rw-r--r--
2019-09-14 01:35
no-unused-expressions.js
4.7
KB
-rw-r--r--
2019-09-14 01:35
no-unused-labels.js
3.22
KB
-rw-r--r--
2019-09-14 01:35
no-unused-vars.js
23.08
KB
-rw-r--r--
2019-09-14 01:35
no-use-before-define.js
7.45
KB
-rw-r--r--
2019-09-14 01:35
no-useless-call.js
2.78
KB
-rw-r--r--
2019-09-14 01:35
no-useless-catch.js
1.55
KB
-rw-r--r--
2019-09-14 01:35
no-useless-computed-key.js
3.19
KB
-rw-r--r--
2019-09-14 01:35
no-useless-concat.js
3.16
KB
-rw-r--r--
2019-09-14 01:35
no-useless-constructor.js
5.46
KB
-rw-r--r--
2019-09-14 01:35
no-useless-escape.js
8.98
KB
-rw-r--r--
2019-09-14 01:35
no-useless-rename.js
5.08
KB
-rw-r--r--
2019-09-14 01:35
no-useless-return.js
11.77
KB
-rw-r--r--
2019-09-14 01:35
no-var.js
12.13
KB
-rw-r--r--
2019-09-14 01:35
no-void.js
1.03
KB
-rw-r--r--
2019-09-14 01:35
no-warning-comments.js
5.4
KB
-rw-r--r--
2019-09-14 01:35
no-whitespace-before-property.js
3.33
KB
-rw-r--r--
2019-09-14 01:35
no-with.js
784
B
-rw-r--r--
2019-09-14 01:35
nonblock-statement-body-position.js
4.41
KB
-rw-r--r--
2023-12-15 20:21
object-curly-newline.js
10.69
KB
-rw-r--r--
2019-09-14 01:35
object-curly-spacing.js
11.27
KB
-rw-r--r--
2019-09-14 01:35
object-property-newline.js
3.59
KB
-rw-r--r--
2019-09-14 01:35
object-shorthand.js
20.66
KB
-rw-r--r--
2019-09-14 01:35
one-var-declaration-per-line.js
2.74
KB
-rw-r--r--
2019-09-14 01:35
one-var.js
21
KB
-rw-r--r--
2019-09-14 01:35
operator-assignment.js
7.73
KB
-rw-r--r--
2019-09-14 01:35
operator-linebreak.js
10.01
KB
-rw-r--r--
2019-09-14 01:35
padded-blocks.js
10.05
KB
-rw-r--r--
2019-09-14 01:35
padding-line-between-statements.js
20
KB
-rw-r--r--
2023-12-15 20:21
prefer-arrow-callback.js
11.17
KB
-rw-r--r--
2019-09-14 01:35
prefer-const.js
16.69
KB
-rw-r--r--
2019-09-14 01:35
prefer-destructuring.js
9.7
KB
-rw-r--r--
2019-09-14 01:35
prefer-named-capture-group.js
3.94
KB
-rw-r--r--
2019-09-14 01:35
prefer-numeric-literals.js
3.73
KB
-rw-r--r--
2019-09-14 01:35
prefer-object-spread.js
9.05
KB
-rw-r--r--
2019-09-14 01:35
prefer-promise-reject-errors.js
5.41
KB
-rw-r--r--
2019-09-14 01:35
prefer-reflect.js
4.5
KB
-rw-r--r--
2019-09-14 01:35
prefer-regex-literals.js
4.4
KB
-rw-r--r--
2019-09-14 01:35
prefer-rest-params.js
3.22
KB
-rw-r--r--
2019-09-14 01:35
prefer-spread.js
2.77
KB
-rw-r--r--
2019-09-14 01:35
prefer-template.js
11.18
KB
-rw-r--r--
2019-09-14 01:35
quote-props.js
11.41
KB
-rw-r--r--
2019-09-14 01:35
quotes.js
11.48
KB
-rw-r--r--
2019-09-14 01:35
radix.js
5.16
KB
-rw-r--r--
2019-09-14 01:35
require-atomic-updates.js
9.51
KB
-rw-r--r--
2019-09-14 01:35
require-await.js
3.04
KB
-rw-r--r--
2019-09-14 01:35
require-jsdoc.js
3.65
KB
-rw-r--r--
2019-09-14 01:35
require-unicode-regexp.js
1.94
KB
-rw-r--r--
2019-09-14 01:35
require-yield.js
2.01
KB
-rw-r--r--
2019-09-14 01:35
rest-spread-spacing.js
3.93
KB
-rw-r--r--
2019-09-14 01:35
semi-spacing.js
7.62
KB
-rw-r--r--
2019-09-14 01:35
semi-style.js
4.98
KB
-rw-r--r--
2019-09-14 01:35
semi.js
11.56
KB
-rw-r--r--
2019-09-14 01:35
sort-imports.js
9.08
KB
-rw-r--r--
2019-09-14 01:35
sort-keys.js
7.64
KB
-rw-r--r--
2023-12-15 20:21
sort-vars.js
3.97
KB
-rw-r--r--
2019-09-14 01:35
space-before-blocks.js
5.59
KB
-rw-r--r--
2019-09-14 01:35
space-before-function-paren.js
5.56
KB
-rw-r--r--
2019-09-14 01:35
space-in-parens.js
10.41
KB
-rw-r--r--
2019-09-14 01:35
space-infix-ops.js
5.35
KB
-rw-r--r--
2019-09-14 01:35
space-unary-ops.js
12.3
KB
-rw-r--r--
2019-09-14 01:35
spaced-comment.js
12.27
KB
-rw-r--r--
2019-09-14 01:35
strict.js
10.31
KB
-rw-r--r--
2019-09-14 01:35
switch-colon-spacing.js
5.2
KB
-rw-r--r--
2019-09-14 01:35
symbol-description.js
1.98
KB
-rw-r--r--
2019-09-14 01:35
template-curly-spacing.js
4.06
KB
-rw-r--r--
2019-09-14 01:35
template-tag-spacing.js
2.79
KB
-rw-r--r--
2019-09-14 01:35
unicode-bom.js
2.15
KB
-rw-r--r--
2019-09-14 01:35
use-isnan.js
1.01
KB
-rw-r--r--
2019-09-14 01:35
valid-jsdoc.js
20.04
KB
-rw-r--r--
2019-09-14 01:35
valid-typeof.js
2.97
KB
-rw-r--r--
2019-09-14 01:35
vars-on-top.js
4.94
KB
-rw-r--r--
2019-09-14 01:35
wrap-iife.js
5.91
KB
-rw-r--r--
2019-09-14 01:35
wrap-regex.js
1.86
KB
-rw-r--r--
2019-09-14 01:35
yield-star-spacing.js
4.22
KB
-rw-r--r--
2019-09-14 01:35
yoda.js
11.41
KB
-rw-r--r--
2019-09-14 01:35
Save
Rename
/** * @fileoverview Disallow parenthesising higher precedence subexpressions. * @author Michael Ficarra */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ const { isParenthesized: isParenthesizedRaw } = require("eslint-utils"); const astUtils = require("./utils/ast-utils.js"); module.exports = { meta: { type: "layout", docs: { description: "disallow unnecessary parentheses", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-extra-parens" }, fixable: "code", schema: { anyOf: [ { type: "array", items: [ { enum: ["functions"] } ], minItems: 0, maxItems: 1 }, { type: "array", items: [ { enum: ["all"] }, { type: "object", properties: { conditionalAssign: { type: "boolean" }, nestedBinaryExpressions: { type: "boolean" }, returnAssign: { type: "boolean" }, ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] }, enforceForArrowConditionals: { type: "boolean" }, enforceForSequenceExpressions: { type: "boolean" } }, additionalProperties: false } ], minItems: 0, maxItems: 2 } ] }, messages: { unexpected: "Unnecessary parentheses around expression." } }, create(context) { const sourceCode = context.getSourceCode(); const tokensToIgnore = new WeakSet(); const precedence = astUtils.getPrecedence; const ALL_NODES = context.options[0] !== "functions"; const EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false; const NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false; const EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false; const IGNORE_JSX = ALL_NODES && context.options[1] && context.options[1].ignoreJSX; const IGNORE_ARROW_CONDITIONALS = ALL_NODES && context.options[1] && context.options[1].enforceForArrowConditionals === false; const IGNORE_SEQUENCE_EXPRESSIONS = ALL_NODES && context.options[1] && context.options[1].enforceForSequenceExpressions === false; const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" }); const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" }); let reportsBuffer; /** * Determines if this rule should be enforced for a node given the current configuration. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the rule should be enforced for this node. * @private */ function ruleApplies(node) { if (node.type === "JSXElement" || node.type === "JSXFragment") { const isSingleLine = node.loc.start.line === node.loc.end.line; switch (IGNORE_JSX) { // Exclude this JSX element from linting case "all": return false; // Exclude this JSX element if it is multi-line element case "multi-line": return isSingleLine; // Exclude this JSX element if it is single-line element case "single-line": return !isSingleLine; // Nothing special to be done for JSX elements case "none": break; // no default } } if (node.type === "SequenceExpression" && IGNORE_SEQUENCE_EXPRESSIONS) { return false; } return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression"; } /** * Determines if a node is surrounded by parentheses. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is parenthesised. * @private */ function isParenthesised(node) { return isParenthesizedRaw(1, node, sourceCode); } /** * Determines if a node is surrounded by parentheses twice. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is doubly parenthesised. * @private */ function isParenthesisedTwice(node) { return isParenthesizedRaw(2, node, sourceCode); } /** * Determines if a node is surrounded by (potentially) invalid parentheses. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is incorrectly parenthesised. * @private */ function hasExcessParens(node) { return ruleApplies(node) && isParenthesised(node); } /** * Determines if a node that is expected to be parenthesised is surrounded by * (potentially) invalid extra parentheses. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is has an unexpected extra pair of parentheses. * @private */ function hasDoubleExcessParens(node) { return ruleApplies(node) && isParenthesisedTwice(node); } /** * Determines if a node test expression is allowed to have a parenthesised assignment * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the assignment can be parenthesised. * @private */ function isCondAssignException(node) { return EXCEPT_COND_ASSIGN && node.test.type === "AssignmentExpression"; } /** * Determines if a node is in a return statement * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is in a return statement. * @private */ function isInReturnStatement(node) { for (let currentNode = node; currentNode; currentNode = currentNode.parent) { if ( currentNode.type === "ReturnStatement" || (currentNode.type === "ArrowFunctionExpression" && currentNode.body.type !== "BlockStatement") ) { return true; } } return false; } /** * Determines if a constructor function is newed-up with parens * @param {ASTNode} newExpression - The NewExpression node to be checked. * @returns {boolean} True if the constructor is called with parens. * @private */ function isNewExpressionWithParens(newExpression) { const lastToken = sourceCode.getLastToken(newExpression); const penultimateToken = sourceCode.getTokenBefore(lastToken); return newExpression.arguments.length > 0 || astUtils.isOpeningParenToken(penultimateToken) && astUtils.isClosingParenToken(lastToken); } /** * Determines if a node is or contains an assignment expression * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is or contains an assignment expression. * @private */ function containsAssignment(node) { if (node.type === "AssignmentExpression") { return true; } if (node.type === "ConditionalExpression" && (node.consequent.type === "AssignmentExpression" || node.alternate.type === "AssignmentExpression")) { return true; } if ((node.left && node.left.type === "AssignmentExpression") || (node.right && node.right.type === "AssignmentExpression")) { return true; } return false; } /** * Determines if a node is contained by or is itself a return statement and is allowed to have a parenthesised assignment * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the assignment can be parenthesised. * @private */ function isReturnAssignException(node) { if (!EXCEPT_RETURN_ASSIGN || !isInReturnStatement(node)) { return false; } if (node.type === "ReturnStatement") { return node.argument && containsAssignment(node.argument); } if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") { return containsAssignment(node.body); } return containsAssignment(node); } /** * Determines if a node following a [no LineTerminator here] restriction is * surrounded by (potentially) invalid extra parentheses. * @param {Token} token - The token preceding the [no LineTerminator here] restriction. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is incorrectly parenthesised. * @private */ function hasExcessParensNoLineTerminator(token, node) { if (token.loc.end.line === node.loc.start.line) { return hasExcessParens(node); } return hasDoubleExcessParens(node); } /** * Determines whether a node should be preceded by an additional space when removing parens * @param {ASTNode} node node to evaluate; must be surrounded by parentheses * @returns {boolean} `true` if a space should be inserted before the node * @private */ function requiresLeadingSpace(node) { const leftParenToken = sourceCode.getTokenBefore(node); const tokenBeforeLeftParen = sourceCode.getTokenBefore(node, 1); const firstToken = sourceCode.getFirstToken(node); return tokenBeforeLeftParen && tokenBeforeLeftParen.range[1] === leftParenToken.range[0] && leftParenToken.range[1] === firstToken.range[0] && !astUtils.canTokensBeAdjacent(tokenBeforeLeftParen, firstToken); } /** * Determines whether a node should be followed by an additional space when removing parens * @param {ASTNode} node node to evaluate; must be surrounded by parentheses * @returns {boolean} `true` if a space should be inserted after the node * @private */ function requiresTrailingSpace(node) { const nextTwoTokens = sourceCode.getTokensAfter(node, { count: 2 }); const rightParenToken = nextTwoTokens[0]; const tokenAfterRightParen = nextTwoTokens[1]; const tokenBeforeRightParen = sourceCode.getLastToken(node); return rightParenToken && tokenAfterRightParen && !sourceCode.isSpaceBetweenTokens(rightParenToken, tokenAfterRightParen) && !astUtils.canTokensBeAdjacent(tokenBeforeRightParen, tokenAfterRightParen); } /** * Determines if a given expression node is an IIFE * @param {ASTNode} node The node to check * @returns {boolean} `true` if the given node is an IIFE */ function isIIFE(node) { return node.type === "CallExpression" && node.callee.type === "FunctionExpression"; } /** * Report the node * @param {ASTNode} node node to evaluate * @returns {void} * @private */ function report(node) { const leftParenToken = sourceCode.getTokenBefore(node); const rightParenToken = sourceCode.getTokenAfter(node); if (!isParenthesisedTwice(node)) { if (tokensToIgnore.has(sourceCode.getFirstToken(node))) { return; } if (isIIFE(node) && !isParenthesised(node.callee)) { return; } } /** * Finishes reporting * @returns {void} * @private */ function finishReport() { context.report({ node, loc: leftParenToken.loc.start, messageId: "unexpected", fix(fixer) { const parenthesizedSource = sourceCode.text.slice(leftParenToken.range[1], rightParenToken.range[0]); return fixer.replaceTextRange([ leftParenToken.range[0], rightParenToken.range[1] ], (requiresLeadingSpace(node) ? " " : "") + parenthesizedSource + (requiresTrailingSpace(node) ? " " : "")); } }); } if (reportsBuffer) { reportsBuffer.reports.push({ node, finishReport }); return; } finishReport(); } /** * Evaluate Unary update * @param {ASTNode} node node to evaluate * @returns {void} * @private */ function checkUnaryUpdate(node) { if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") { return; } if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) { report(node.argument); } } /** * Check if a member expression contains a call expression * @param {ASTNode} node MemberExpression node to evaluate * @returns {boolean} true if found, false if not */ function doesMemberExpressionContainCallExpression(node) { let currentNode = node.object; let currentNodeType = node.object.type; while (currentNodeType === "MemberExpression") { currentNode = currentNode.object; currentNodeType = currentNode.type; } return currentNodeType === "CallExpression"; } /** * Evaluate a new call * @param {ASTNode} node node to evaluate * @returns {void} * @private */ function checkCallNew(node) { const callee = node.callee; if (hasExcessParens(callee) && precedence(callee) >= precedence(node)) { const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee); if ( hasDoubleExcessParens(callee) || !isIIFE(node) && !hasNewParensException && !( /* * Allow extra parens around a new expression if * there are intervening parentheses. */ (callee.type === "MemberExpression" && doesMemberExpressionContainCallExpression(callee)) ) ) { report(node.callee); } } node.arguments .filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) .forEach(report); } /** * Evaluate binary logicals * @param {ASTNode} node node to evaluate * @returns {void} * @private */ function checkBinaryLogical(node) { const prec = precedence(node); const leftPrecedence = precedence(node.left); const rightPrecedence = precedence(node.right); const isExponentiation = node.operator === "**"; const shouldSkipLeft = (NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression")) || node.left.type === "UnaryExpression" && isExponentiation; const shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression"); if (!shouldSkipLeft && hasExcessParens(node.left) && (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation))) { report(node.left); } if (!shouldSkipRight && hasExcessParens(node.right) && (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation))) { report(node.right); } } /** * Check the parentheses around the super class of the given class definition. * @param {ASTNode} node The node of class declarations to check. * @returns {void} */ function checkClass(node) { if (!node.superClass) { return; } /* * If `node.superClass` is a LeftHandSideExpression, parentheses are extra. * Otherwise, parentheses are needed. */ const hasExtraParens = precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR ? hasExcessParens(node.superClass) : hasDoubleExcessParens(node.superClass); if (hasExtraParens) { report(node.superClass); } } /** * Check the parentheses around the argument of the given spread operator. * @param {ASTNode} node The node of spread elements/properties to check. * @returns {void} */ function checkSpreadOperator(node) { const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR ? hasExcessParens(node.argument) : hasDoubleExcessParens(node.argument); if (hasExtraParens) { report(node.argument); } } /** * Checks the parentheses for an ExpressionStatement or ExportDefaultDeclaration * @param {ASTNode} node The ExpressionStatement.expression or ExportDefaultDeclaration.declaration node * @returns {void} */ function checkExpressionOrExportStatement(node) { const firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node); const secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken); const thirdToken = secondToken ? sourceCode.getTokenAfter(secondToken) : null; const tokenAfterClosingParens = secondToken ? sourceCode.getTokenAfter(secondToken, astUtils.isNotClosingParenToken) : null; if ( astUtils.isOpeningParenToken(firstToken) && ( astUtils.isOpeningBraceToken(secondToken) || secondToken.type === "Keyword" && ( secondToken.value === "function" || secondToken.value === "class" || secondToken.value === "let" && tokenAfterClosingParens && ( astUtils.isOpeningBracketToken(tokenAfterClosingParens) || tokenAfterClosingParens.type === "Identifier" ) ) || secondToken && secondToken.type === "Identifier" && secondToken.value === "async" && thirdToken && thirdToken.type === "Keyword" && thirdToken.value === "function" ) ) { tokensToIgnore.add(secondToken); } if (hasExcessParens(node)) { report(node); } } /** * Finds the path from the given node to the specified ancestor. * @param {ASTNode} node First node in the path. * @param {ASTNode} ancestor Last node in the path. * @returns {ASTNode[]} Path, including both nodes. * @throws {Error} If the given node does not have the specified ancestor. */ function pathToAncestor(node, ancestor) { const path = [node]; let currentNode = node; while (currentNode !== ancestor) { currentNode = currentNode.parent; /* istanbul ignore if */ if (currentNode === null) { throw new Error("Nodes are not in the ancestor-descendant relationship."); } path.push(currentNode); } return path; } /** * Finds the path from the given node to the specified descendant. * @param {ASTNode} node First node in the path. * @param {ASTNode} descendant Last node in the path. * @returns {ASTNode[]} Path, including both nodes. * @throws {Error} If the given node does not have the specified descendant. */ function pathToDescendant(node, descendant) { return pathToAncestor(descendant, node).reverse(); } /** * Checks whether the syntax of the given ancestor of an 'in' expression inside a for-loop initializer * is preventing the 'in' keyword from being interpreted as a part of an ill-formed for-in loop. * * @param {ASTNode} node Ancestor of an 'in' expression. * @param {ASTNode} child Child of the node, ancestor of the same 'in' expression or the 'in' expression itself. * @returns {boolean} True if the keyword 'in' would be interpreted as the 'in' operator, without any parenthesis. */ function isSafelyEnclosingInExpression(node, child) { switch (node.type) { case "ArrayExpression": case "ArrayPattern": case "BlockStatement": case "ObjectExpression": case "ObjectPattern": case "TemplateLiteral": return true; case "ArrowFunctionExpression": case "FunctionExpression": return node.params.includes(child); case "CallExpression": case "NewExpression": return node.arguments.includes(child); case "MemberExpression": return node.computed && node.property === child; case "ConditionalExpression": return node.consequent === child; default: return false; } } /** * Starts a new reports buffering. Warnings will be stored in a buffer instead of being reported immediately. * An additional logic that requires multiple nodes (e.g. a whole subtree) may dismiss some of the stored warnings. * * @returns {void} */ function startNewReportsBuffering() { reportsBuffer = { upper: reportsBuffer, inExpressionNodes: [], reports: [] }; } /** * Ends the current reports buffering. * @returns {void} */ function endCurrentReportsBuffering() { const { upper, inExpressionNodes, reports } = reportsBuffer; if (upper) { upper.inExpressionNodes.push(...inExpressionNodes); upper.reports.push(...reports); } else { // flush remaining reports reports.forEach(({ finishReport }) => finishReport()); } reportsBuffer = upper; } /** * Checks whether the given node is in the current reports buffer. * @param {ASTNode} node Node to check. * @returns {boolean} True if the node is in the current buffer, false otherwise. */ function isInCurrentReportsBuffer(node) { return reportsBuffer.reports.some(r => r.node === node); } /** * Removes the given node from the current reports buffer. * @param {ASTNode} node Node to remove. * @returns {void} */ function removeFromCurrentReportsBuffer(node) { reportsBuffer.reports = reportsBuffer.reports.filter(r => r.node !== node); } return { ArrayExpression(node) { node.elements .filter(e => e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) .forEach(report); }, ArrowFunctionExpression(node) { if (isReturnAssignException(node)) { return; } if (node.body.type === "ConditionalExpression" && IGNORE_ARROW_CONDITIONALS && !isParenthesisedTwice(node.body) ) { return; } if (node.body.type !== "BlockStatement") { const firstBodyToken = sourceCode.getFirstToken(node.body, astUtils.isNotOpeningParenToken); const tokenBeforeFirst = sourceCode.getTokenBefore(firstBodyToken); if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) { tokensToIgnore.add(firstBodyToken); } if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { report(node.body); } } }, AssignmentExpression(node) { if (isReturnAssignException(node)) { return; } if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) { report(node.right); } }, BinaryExpression(node) { if (reportsBuffer && node.operator === "in") { reportsBuffer.inExpressionNodes.push(node); } checkBinaryLogical(node); }, CallExpression: checkCallNew, ClassBody(node) { node.body .filter(member => member.type === "MethodDefinition" && member.computed && member.key && hasExcessParens(member.key) && precedence(member.key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) .forEach(member => report(member.key)); }, ConditionalExpression(node) { if (isReturnAssignException(node)) { return; } if (hasExcessParens(node.test) && precedence(node.test) >= precedence({ type: "LogicalExpression", operator: "||" })) { report(node.test); } if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { report(node.consequent); } if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { report(node.alternate); } }, DoWhileStatement(node) { if (hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } }, ExportDefaultDeclaration: node => checkExpressionOrExportStatement(node.declaration), ExpressionStatement: node => checkExpressionOrExportStatement(node.expression), "ForInStatement, ForOfStatement"(node) { if (node.left.type !== "VariableDeclarator") { const firstLeftToken = sourceCode.getFirstToken(node.left, astUtils.isNotOpeningParenToken); if ( firstLeftToken.value === "let" && ( /* * If `let` is the only thing on the left side of the loop, it's the loop variable: `for ((let) of foo);` * Removing it will cause a syntax error, because it will be parsed as the start of a VariableDeclarator. */ (firstLeftToken.range[1] === node.left.range[1] || /* * If `let` is followed by a `[` token, it's a property access on the `let` value: `for ((let[foo]) of bar);` * Removing it will cause the property access to be parsed as a destructuring declaration of `foo` instead. */ astUtils.isOpeningBracketToken( sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken) )) ) ) { tokensToIgnore.add(firstLeftToken); } } if (!(node.type === "ForOfStatement" && node.right.type === "SequenceExpression") && hasExcessParens(node.right)) { report(node.right); } if (hasExcessParens(node.left)) { report(node.left); } }, ForStatement(node) { if (node.test && hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } if (node.update && hasExcessParens(node.update)) { report(node.update); } if (node.init) { startNewReportsBuffering(); if (hasExcessParens(node.init)) { report(node.init); } } }, "ForStatement > *.init:exit"(node) { /* * Removing parentheses around `in` expressions might change semantics and cause errors. * * For example, this valid for loop: * for (let a = (b in c); ;); * after removing parentheses would be treated as an invalid for-in loop: * for (let a = b in c; ;); */ if (reportsBuffer.reports.length) { reportsBuffer.inExpressionNodes.forEach(inExpressionNode => { const path = pathToDescendant(node, inExpressionNode); let nodeToExclude; for (let i = 0; i < path.length; i++) { const pathNode = path[i]; if (i < path.length - 1) { const nextPathNode = path[i + 1]; if (isSafelyEnclosingInExpression(pathNode, nextPathNode)) { // The 'in' expression in safely enclosed by the syntax of its ancestor nodes (e.g. by '{}' or '[]'). return; } } if (isParenthesised(pathNode)) { if (isInCurrentReportsBuffer(pathNode)) { // This node was supposed to be reported, but parentheses might be necessary. if (isParenthesisedTwice(pathNode)) { /* * This node is parenthesised twice, it certainly has at least one pair of `extra` parentheses. * If the --fix option is on, the current fixing iteration will remove only one pair of parentheses. * The remaining pair is safely enclosing the 'in' expression. */ return; } // Exclude the outermost node only. if (!nodeToExclude) { nodeToExclude = pathNode; } // Don't break the loop here, there might be some safe nodes or parentheses that will stay inside. } else { // This node will stay parenthesised, the 'in' expression in safely enclosed by '()'. return; } } } // Exclude the node from the list (i.e. treat parentheses as necessary) removeFromCurrentReportsBuffer(nodeToExclude); }); } endCurrentReportsBuffering(); }, IfStatement(node) { if (hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } }, ImportExpression(node) { const { source } = node; if (source.type === "SequenceExpression") { if (hasDoubleExcessParens(source)) { report(source); } } else if (hasExcessParens(source)) { report(source); } }, LogicalExpression: checkBinaryLogical, MemberExpression(node) { const nodeObjHasExcessParens = hasExcessParens(node.object); if ( nodeObjHasExcessParens && precedence(node.object) >= precedence(node) && ( node.computed || !( astUtils.isDecimalInteger(node.object) || // RegExp literal is allowed to have parens (#1589) (node.object.type === "Literal" && node.object.regex) ) ) ) { report(node.object); } if (nodeObjHasExcessParens && node.object.type === "CallExpression" && node.parent.type !== "NewExpression") { report(node.object); } if (node.computed && hasExcessParens(node.property)) { report(node.property); } }, NewExpression: checkCallNew, ObjectExpression(node) { node.properties .filter(property => { const value = property.value; return value && hasExcessParens(value) && precedence(value) >= PRECEDENCE_OF_ASSIGNMENT_EXPR; }).forEach(property => report(property.value)); }, Property(node) { if (node.computed) { const { key } = node; if (key && hasExcessParens(key) && precedence(key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { report(key); } } }, ReturnStatement(node) { const returnToken = sourceCode.getFirstToken(node); if (isReturnAssignException(node)) { return; } if (node.argument && hasExcessParensNoLineTerminator(returnToken, node.argument) && // RegExp literal is allowed to have parens (#1589) !(node.argument.type === "Literal" && node.argument.regex)) { report(node.argument); } }, SequenceExpression(node) { node.expressions .filter(e => hasExcessParens(e) && precedence(e) >= precedence(node)) .forEach(report); }, SwitchCase(node) { if (node.test && hasExcessParens(node.test)) { report(node.test); } }, SwitchStatement(node) { if (hasExcessParens(node.discriminant)) { report(node.discriminant); } }, ThrowStatement(node) { const throwToken = sourceCode.getFirstToken(node); if (hasExcessParensNoLineTerminator(throwToken, node.argument)) { report(node.argument); } }, UnaryExpression: checkUnaryUpdate, UpdateExpression: checkUnaryUpdate, AwaitExpression: checkUnaryUpdate, VariableDeclarator(node) { if (node.init && hasExcessParens(node.init) && precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR && // RegExp literal is allowed to have parens (#1589) !(node.init.type === "Literal" && node.init.regex)) { report(node.init); } }, WhileStatement(node) { if (hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } }, WithStatement(node) { if (hasExcessParens(node.object)) { report(node.object); } }, YieldExpression(node) { if (node.argument) { const yieldToken = sourceCode.getFirstToken(node); if ((precedence(node.argument) >= precedence(node) && hasExcessParensNoLineTerminator(yieldToken, node.argument)) || hasDoubleExcessParens(node.argument)) { report(node.argument); } } }, ClassDeclaration: checkClass, ClassExpression: checkClass, SpreadElement: checkSpreadOperator, SpreadProperty: checkSpreadOperator, ExperimentalSpreadProperty: checkSpreadOperator, TemplateLiteral(node) { node.expressions .filter(e => e && hasExcessParens(e)) .forEach(report); }, AssignmentPattern(node) { const { right } = node; if (right && hasExcessParens(right) && precedence(right) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { report(right); } } }; } };