eslint-plugin-unicorn 70.0.0 → 71.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/package.json +26 -25
  2. package/readme.md +5 -1
  3. package/rules/ast/call-or-new-expression.js +2 -8
  4. package/rules/ast/is-member-expression.js +2 -8
  5. package/rules/comment-content.js +4 -4
  6. package/rules/consistent-boolean-name.js +94 -10
  7. package/rules/consistent-compound-words.js +1 -2
  8. package/rules/consistent-json-file-read.js +2 -5
  9. package/rules/dom-node-dataset.js +3 -7
  10. package/rules/escape-case.js +4 -4
  11. package/rules/expiring-todo-comments.js +2 -2
  12. package/rules/explicit-length-check.js +3 -3
  13. package/rules/filename-case.js +4 -4
  14. package/rules/fix/remove-argument.js +34 -8
  15. package/rules/fix/remove-statement.js +1 -3
  16. package/rules/id-match.js +2 -2
  17. package/rules/isolated-functions.js +47 -7
  18. package/rules/name-replacements.js +1 -2
  19. package/rules/no-anonymous-default-export.js +1 -3
  20. package/rules/no-array-callback-reference.js +2 -10
  21. package/rules/no-chained-comparison.js +1 -1
  22. package/rules/no-computed-property-existence-check.js +1 -4
  23. package/rules/no-declarations-before-early-exit.js +6 -5
  24. package/rules/no-error-property-assignment.js +3 -3
  25. package/rules/no-for-loop.js +4 -4
  26. package/rules/no-keyword-prefix.js +2 -2
  27. package/rules/no-mismatched-map-key.js +13 -20
  28. package/rules/no-named-default.js +2 -5
  29. package/rules/no-negated-array-predicate.js +4 -11
  30. package/rules/no-negated-comparison.js +7 -10
  31. package/rules/no-negation-in-equality-check.js +2 -5
  32. package/rules/no-process-exit.js +6 -6
  33. package/rules/no-static-only-class.js +2 -8
  34. package/rules/no-thenable.js +9 -15
  35. package/rules/no-undeclared-class-members.js +1 -5
  36. package/rules/no-unnecessary-array-flat-map.js +6 -5
  37. package/rules/no-unnecessary-global-this.js +5 -9
  38. package/rules/no-unused-properties.js +0 -1
  39. package/rules/no-useless-coercion.js +1 -2
  40. package/rules/no-useless-undefined.js +2 -2
  41. package/rules/prefer-array-find.js +2 -5
  42. package/rules/prefer-bigint-literals.js +1 -0
  43. package/rules/prefer-boolean-return.js +20 -3
  44. package/rules/prefer-default-parameters.js +2 -2
  45. package/rules/prefer-else-if.js +5 -9
  46. package/rules/prefer-has-check.js +6 -3
  47. package/rules/prefer-https.js +3 -3
  48. package/rules/prefer-identifier-import-export-specifiers.js +1 -3
  49. package/rules/prefer-minimal-ternary.js +4 -4
  50. package/rules/prefer-object-define-properties.js +1 -3
  51. package/rules/prefer-observer-apis.js +2 -5
  52. package/rules/prefer-private-class-fields.js +1 -3
  53. package/rules/prefer-simple-sort-comparator.js +6 -6
  54. package/rules/prefer-single-object-destructuring.js +2 -5
  55. package/rules/prefer-single-replace.js +2 -2
  56. package/rules/prefer-spread.js +22 -32
  57. package/rules/prefer-string-pad-start-end.js +1 -6
  58. package/rules/prefer-string-repeat.js +16 -9
  59. package/rules/prefer-string-replace-all.js +1 -1
  60. package/rules/prefer-ternary.js +5 -5
  61. package/rules/prefer-toggle-attribute.js +3 -3
  62. package/rules/prefer-top-level-await.js +6 -1
  63. package/rules/prefer-uint8array-base64.js +3 -1
  64. package/rules/require-proxy-trap-boolean-return.js +2 -2
  65. package/rules/rule/to-eslint-create.js +1 -2
  66. package/rules/rule/to-eslint-listener.js +1 -3
  67. package/rules/rule/to-eslint-problem.js +1 -3
  68. package/rules/rule/to-eslint-rule-fixer.js +1 -3
  69. package/rules/rule/to-eslint-rule.js +1 -3
  70. package/rules/rule/to-eslint-rules.js +1 -3
  71. package/rules/rule/unicorn-context.js +1 -3
  72. package/rules/rule/unicorn-listeners.js +1 -3
  73. package/rules/shared/no-array-mutate-rule.js +1 -3
  74. package/rules/shared/regexp-escape.js +4 -4
  75. package/rules/utils/can-tokens-be-adjacent.js +95 -0
  76. package/rules/utils/escape-string.js +2 -8
  77. package/rules/utils/get-available-variable-name.js +2 -13
  78. package/rules/utils/get-precedence.js +112 -0
  79. package/rules/utils/get-token-store.js +1 -3
  80. package/rules/utils/global-reference-tracker.js +3 -6
  81. package/rules/utils/index.js +4 -0
  82. package/rules/utils/is-boolean.js +90 -32
  83. package/rules/utils/is-identifier-name.js +5 -0
  84. package/rules/utils/is-promise-type.js +1 -3
  85. package/rules/utils/is-react-hook-name.js +5 -0
  86. package/rules/utils/parentheses/get-parent-syntax-opening-parenthesis.js +1 -3
  87. package/rules/utils/parentheses/iterate-surrounding-parentheses.js +1 -1
  88. package/rules/utils/should-add-parentheses-to-await-expression-argument.js +4 -9
  89. package/rules/utils/should-add-parentheses-to-call-expression-callee.js +6 -12
  90. package/rules/utils/should-add-parentheses-to-unary-expression.js +7 -14
  91. package/rules/utils/to-location.js +1 -3
@@ -224,15 +224,15 @@ const create = context => {
224
224
  }
225
225
 
226
226
  const setCall = consequentCall.method === 'setAttribute' ? consequentCall : alternateCall;
227
- const setWhenTrue = consequentCall === setCall;
227
+ const isSetWhenTrue = consequentCall === setCall;
228
228
  const hasAttributeCondition = getHasAttributeCondition(node.test, setCall, context);
229
229
 
230
230
  if (hasAttributeCondition?.isKnownNonDom) {
231
231
  return;
232
232
  }
233
233
 
234
- const shouldToggleWithoutForce = Boolean(hasAttributeCondition) && setWhenTrue === hasAttributeCondition.isNegative;
235
- const conditionText = shouldToggleWithoutForce ? '' : getConditionText(node.test, context, !setWhenTrue);
234
+ const shouldToggleWithoutForce = Boolean(hasAttributeCondition) && isSetWhenTrue === hasAttributeCondition.isNegative;
235
+ const conditionText = shouldToggleWithoutForce ? '' : getConditionText(node.test, context, !isSetWhenTrue);
236
236
  const hasSafeAttributeValue = setCall.hasEmptyAttributeValue || getStaticStringValue(setCall.attributeValue) !== undefined;
237
237
  const shouldReportOnly = (Boolean(conditionText) && setCall.isOptional) || !hasSafeAttributeValue;
238
238
 
@@ -205,7 +205,12 @@ const isInPromiseMethods = node => {
205
205
 
206
206
  /** @param {import('eslint').Rule.RuleContext} context */
207
207
  function create(context) {
208
- if (context.filename.toLowerCase().endsWith('.cjs')) {
208
+ // Use the real file path so processors or code blocks cannot hide file-level opt-outs.
209
+ const filename = context.physicalFilename.toLowerCase();
210
+ if (
211
+ filename.endsWith('.cjs')
212
+ || filename.endsWith('.svelte')
213
+ ) {
209
214
  return;
210
215
  }
211
216
 
@@ -152,7 +152,9 @@ const config = {
152
152
  type: 'suggestion',
153
153
  docs: {
154
154
  description: 'Prefer `Uint8Array#toBase64()` and `Uint8Array.fromBase64()` over `atob()`, `btoa()`, and `Buffer` base64 conversions.',
155
- recommended: 'unopinionated',
155
+ // eslint-disable-next-line no-warning-comments
156
+ // TODO: Enable in the `recommended` and `unopinionated` configs when targeting Node.js 26.
157
+ recommended: false,
156
158
  },
157
159
  hasSuggestions: true,
158
160
  messages,
@@ -277,8 +277,8 @@ const create = context => {
277
277
  return;
278
278
  }
279
279
 
280
- const allUnreachable = [...currentSegments()].every(segment => !segment.reachable);
281
- functionBodyAlwaysExits.set(body.parent, allUnreachable);
280
+ const isAllUnreachable = [...currentSegments()].every(segment => !segment.reachable);
281
+ functionBodyAlwaysExits.set(body.parent, isAllUnreachable);
282
282
  });
283
283
 
284
284
  function * checkCallOrNewExpression(node) {
@@ -26,7 +26,7 @@ Convert Unicorn style of `create` to ESLint style
26
26
  @param {UnicornCreate} unicornCreate
27
27
  @returns {EslintCreate}
28
28
  */
29
- function toEslintCreate(unicornCreate) {
29
+ export default function toEslintCreate(unicornCreate) {
30
30
  if (wrappedFunctions.has(unicornCreate)) {
31
31
  return unicornCreate;
32
32
  }
@@ -45,5 +45,4 @@ function toEslintCreate(unicornCreate) {
45
45
  };
46
46
  }
47
47
 
48
- export default toEslintCreate;
49
48
  export {markFunctionWrapped};
@@ -19,7 +19,7 @@ import toEslintProblem from './to-eslint-problem.js';
19
19
  @param {UnicornRuleListen} listener
20
20
  @returns {Listener}
21
21
  */
22
- function toEslintListener(context, listener) {
22
+ export default function toEslintListener(context, listener) {
23
23
  // Listener arguments can be `codePath, node` or `node`
24
24
 
25
25
  /**
@@ -38,5 +38,3 @@ function toEslintListener(context, listener) {
38
38
  }
39
39
  };
40
40
  }
41
-
42
- export default toEslintListener;
@@ -14,7 +14,7 @@ import toEslintFixer from './to-eslint-rule-fixer.js';
14
14
  @param {UnicornProblem} unicornProblem
15
15
  @returns {EslintProblem}
16
16
  */
17
- function toEslintProblem(unicornProblem) {
17
+ export default function toEslintProblem(unicornProblem) {
18
18
  const eslintProblem = {...unicornProblem};
19
19
 
20
20
  if (unicornProblem.fix) {
@@ -34,5 +34,3 @@ function toEslintProblem(unicornProblem) {
34
34
 
35
35
  return eslintProblem;
36
36
  }
37
-
38
- export default toEslintProblem;
@@ -26,7 +26,7 @@ Convert Unicorn style fix function to ESLint style fix function
26
26
  @param {UnicornRuleFixer} fix
27
27
  @returns {ESLint.Rule.RuleFixer}
28
28
  */
29
- function toEslintRuleFixer(fix) {
29
+ export default function toEslintRuleFixer(fix) {
30
30
  /** @param {UnicornReportFixer} fixer */
31
31
  return fixer => {
32
32
  const unicornReport = fix(fixer, fixOptions);
@@ -45,5 +45,3 @@ function toEslintRuleFixer(fix) {
45
45
  }
46
46
  };
47
47
  }
48
-
49
- export default toEslintRuleFixer;
@@ -19,7 +19,7 @@ Convert Unicorn rule to ESLint rule
19
19
  @param {UnicornRule} unicornRule
20
20
  @returns {ESLint.Rule.RuleModule}
21
21
  */
22
- function toEslintRule(ruleId, unicornRule) {
22
+ export default function toEslintRule(ruleId, unicornRule) {
23
23
  return {
24
24
  meta: {
25
25
  // If there is are, options add `[]` so ESLint can validate that no data is passed to the rule.
@@ -34,5 +34,3 @@ function toEslintRule(ruleId, unicornRule) {
34
34
  create: toEslintCreate(unicornRule.create),
35
35
  };
36
36
  }
37
-
38
- export default toEslintRule;
@@ -1,11 +1,9 @@
1
1
  import toEslintRule from './to-eslint-rule.js';
2
2
 
3
- function toEslintRules(rules) {
3
+ export default function toEslintRules(rules) {
4
4
  return Object.fromEntries(Object.entries(rules).map(([ruleId, rule]) => [
5
5
  ruleId,
6
6
  toEslintRule(ruleId, rule),
7
7
  ]));
8
8
  }
9
9
 
10
- export default toEslintRules;
11
-
@@ -18,7 +18,7 @@ Create a better `Context` object with `on` and `onExit` method to add listeners
18
18
  @param {UnicornListeners} listeners
19
19
  @returns {UnicornContext}
20
20
  */
21
- function createUnicornContext(eslintContext, listeners) {
21
+ export default function createUnicornContext(eslintContext, listeners) {
22
22
  /** @type {UnicornContext} */
23
23
  const context = new Proxy(eslintContext, {
24
24
  get(target, property, receiver) {
@@ -32,5 +32,3 @@ function createUnicornContext(eslintContext, listeners) {
32
32
 
33
33
  return context;
34
34
  }
35
-
36
- export default createUnicornContext;
@@ -4,7 +4,7 @@ import toEslintListener from './to-eslint-listener.js';
4
4
  @import {EslintListers, ListenerType, Listener} from './to-eslint-create.js'
5
5
  */
6
6
 
7
- class UnicornListeners {
7
+ export default class UnicornListeners {
8
8
  #context;
9
9
  #listeners = new Map();
10
10
 
@@ -61,5 +61,3 @@ class UnicornListeners {
61
61
  return eslintListeners;
62
62
  }
63
63
  }
64
-
65
- export default UnicornListeners;
@@ -50,7 +50,7 @@ const schema = [
50
50
  },
51
51
  ];
52
52
 
53
- function noArrayMutateRule(methodName) {
53
+ export default function noArrayMutateRule(methodName) {
54
54
  const {
55
55
  replacement,
56
56
  predicate,
@@ -159,5 +159,3 @@ function noArrayMutateRule(methodName) {
159
159
 
160
160
  return config;
161
161
  }
162
-
163
- export default noArrayMutateRule;
@@ -19,12 +19,12 @@ const getCharacterClassCharacters = pattern => {
19
19
 
20
20
  for (let index = 0; index < characterClass.length; index++) {
21
21
  let character = characterClass[index];
22
- let escaped = false;
22
+ let isEscaped = false;
23
23
 
24
24
  if (character === '\\') {
25
25
  index++;
26
26
  character = characterClass[index];
27
- escaped = true;
27
+ isEscaped = true;
28
28
 
29
29
  if (!character) {
30
30
  return;
@@ -33,7 +33,7 @@ const getCharacterClassCharacters = pattern => {
33
33
 
34
34
  if (
35
35
  character === '-'
36
- && !escaped
36
+ && !isEscaped
37
37
  && index !== 0
38
38
  && index !== characterClass.length - 1
39
39
  ) {
@@ -42,7 +42,7 @@ const getCharacterClassCharacters = pattern => {
42
42
 
43
43
  if (
44
44
  character === ']'
45
- && !escaped
45
+ && !isEscaped
46
46
  && index !== 0
47
47
  ) {
48
48
  return;
@@ -0,0 +1,95 @@
1
+ /**
2
+ @import * as ESLint from 'eslint';
3
+ */
4
+
5
+ const WORD_CHARACTER = /[\w$]/u;
6
+ const DECIMAL_INTEGER_LITERAL = /^\d(?:_?\d)*$/u;
7
+ const TRAILING_DECIMAL_INTEGER_LITERAL = /(?:^|[^\w$])\d(?:_?\d)*$/u;
8
+ const TRAILING_DIGIT_DOT = /\d\.$/u;
9
+
10
+ /**
11
+ @param {ESLint.AST.Token | string} value
12
+ @returns {string}
13
+ */
14
+ function getText(value) {
15
+ return typeof value === 'string' ? value : value.value;
16
+ }
17
+
18
+ /**
19
+ @param {ESLint.AST.Token | string} value
20
+ @returns {boolean}
21
+ */
22
+ function isLineCommentOrShebang(value) {
23
+ return typeof value === 'object' && ['Line', 'Shebang', 'Hashbang'].includes(value.type);
24
+ }
25
+
26
+ /**
27
+ @param {ESLint.AST.Token | string} value
28
+ @returns {boolean}
29
+ */
30
+ function isComment(value) {
31
+ return typeof value === 'object' && ['Line', 'Block'].includes(value.type);
32
+ }
33
+
34
+ /**
35
+ @param {ESLint.AST.Token | string} value
36
+ @returns {boolean}
37
+ */
38
+ function isUnsafeNumericDotLeft(value) {
39
+ return typeof value === 'object' ? value.type === 'Numeric' && DECIMAL_INTEGER_LITERAL.test(value.value) : TRAILING_DECIMAL_INTEGER_LITERAL.test(value);
40
+ }
41
+
42
+ /**
43
+ Checks whether `left` and `right` can be placed directly next to each other without the last character of `left` and the first character of `right` merging into a token that changes the meaning of the code (for example two identifiers becoming one, `+` and `+` becoming `++`, or `2` and `.2` becoming `2.2`).
44
+
45
+ This is a lightweight, character-boundary check, not a full tokenizer, inspired by ESLint's own (more thorough) `canTokensBeAdjacent`: https://github.com/eslint/eslint/blob/b23015955c8d6e6516076190730f538c86927f26/lib/rules/utils/ast-utils.js#L2522-L2529
46
+ It only guards against the adjacency hazards that come up when building fixer replacement text in this codebase: identifiers/keywords/numbers merging, `+`/`-` doubling into `++`/`--`, a numeric literal absorbing a following decimal point, and a `/` being swallowed into a following comment. It intentionally doesn't try to detect hazards that require a real tokenizer, like an already-open `//` comment inside `left`, or malformed token text.
47
+
48
+ @param {ESLint.AST.Token | string} left - The left token or text.
49
+ @param {ESLint.AST.Token | string} right - The right token or text.
50
+ @returns {boolean} `false` if a space is needed between `left` and `right` to keep them from merging. `true` if they can safely be adjacent.
51
+ */
52
+ export default function canTokensBeAdjacent(left, right) {
53
+ if (isLineCommentOrShebang(left)) {
54
+ return false;
55
+ }
56
+
57
+ const leftText = getText(left);
58
+
59
+ if (leftText === '') {
60
+ return true;
61
+ }
62
+
63
+ const rightText = getText(right);
64
+ const lastCharacter = leftText.at(-1);
65
+
66
+ if (lastCharacter === '/' && isComment(right)) {
67
+ return false;
68
+ }
69
+
70
+ if (rightText === '') {
71
+ return true;
72
+ }
73
+
74
+ const firstCharacter = rightText[0];
75
+
76
+ if (WORD_CHARACTER.test(lastCharacter) && WORD_CHARACTER.test(firstCharacter)) {
77
+ return false;
78
+ }
79
+
80
+ if (
81
+ (lastCharacter === '+' && firstCharacter === '+')
82
+ || (lastCharacter === '-' && firstCharacter === '-')
83
+ ) {
84
+ return false;
85
+ }
86
+
87
+ if (
88
+ (isUnsafeNumericDotLeft(left) && firstCharacter === '.')
89
+ || (TRAILING_DIGIT_DOT.test(leftText) && WORD_CHARACTER.test(firstCharacter))
90
+ ) {
91
+ return false;
92
+ }
93
+
94
+ return !(lastCharacter === '/' && (firstCharacter === '/' || firstCharacter === '*'));
95
+ }
@@ -1,4 +1,4 @@
1
- import jsesc from 'jsesc';
1
+ import quoteJsString from 'quote-js-string';
2
2
 
3
3
  /**
4
4
  Escape string and wrap the result in quotes.
@@ -14,11 +14,5 @@ export default function escapeString(string, quote = '\'') {
14
14
  }
15
15
  /* c8 ignore end */
16
16
 
17
- return jsesc(string, {
18
- quotes: quote === '"' ? 'double' : 'single',
19
- wrap: true,
20
- es6: true,
21
- minimal: true,
22
- lowercaseHex: false,
23
- });
17
+ return quoteJsString(string, quote);
24
18
  }
@@ -1,13 +1,7 @@
1
- import helperValidatorIdentifier from '@babel/helper-validator-identifier';
1
+ import isIdentifier from 'is-identifier';
2
2
  import resolveVariableName from './resolve-variable-name.js';
3
3
  import getReferences from './get-references.js';
4
4
 
5
- const {
6
- isIdentifierName,
7
- isStrictReservedWord,
8
- isKeyword,
9
- } = helperValidatorIdentifier;
10
-
11
5
  // https://github.com/microsoft/TypeScript/issues/2536#issuecomment-87194347
12
6
  const typescriptReservedWords = new Set([
13
7
  'break',
@@ -72,14 +66,9 @@ const typescriptReservedWords = new Set([
72
66
  'of',
73
67
  ]);
74
68
 
75
- // Copied from https://github.com/babel/babel/blob/fce35af69101c6b316557e28abf60bdbf77d6a36/packages/babel-types/src/validators/isValidIdentifier.ts#L7
76
- // Use this function instead of `require('@babel/types').isIdentifier`, since `@babel/helper-validator-identifier` package is much smaller
77
69
  const isValidIdentifier = name =>
78
70
  typeof name === 'string'
79
- && !isKeyword(name)
80
- && !isStrictReservedWord(name, true)
81
- && isIdentifierName(name)
82
- && name !== 'arguments'
71
+ && isIdentifier(name)
83
72
  && !typescriptReservedWords.has(name);
84
73
 
85
74
  /*
@@ -0,0 +1,112 @@
1
+ /**
2
+ @import {TSESTree as ESTree} from '@typescript-eslint/types';
3
+ */
4
+
5
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
6
+ // Copied from https://github.com/eslint/eslint/blob/b23015955c8d6e6516076190730f538c86927f26/lib/rules/utils/ast-utils.js#L1879-L1971
7
+ // and extended with TypeScript node types, following https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/util/getOperatorPrecedence.ts
8
+
9
+ const logicalOperatorPrecedence = {
10
+ '??': 4,
11
+ '||': 4,
12
+ '&&': 5,
13
+ };
14
+
15
+ const binaryOperatorPrecedence = {
16
+ '|': 6,
17
+ '^': 7,
18
+ '&': 8,
19
+ '==': 9,
20
+ '!=': 9,
21
+ '===': 9,
22
+ '!==': 9,
23
+ '<': 10,
24
+ '<=': 10,
25
+ '>': 10,
26
+ '>=': 10,
27
+ in: 10,
28
+ instanceof: 10,
29
+ '<<': 11,
30
+ '>>': 11,
31
+ '>>>': 11,
32
+ '+': 12,
33
+ '-': 12,
34
+ '*': 13,
35
+ '/': 13,
36
+ '%': 13,
37
+ '**': 15,
38
+ };
39
+
40
+ // Precedence boundaries the `should-add-parentheses-to-*` helpers compare against. Exported so those
41
+ // callers can name the boundary instead of hardcoding a bare number that only makes sense against the
42
+ // table below.
43
+ // `UnaryExpression`, `AwaitExpression`, `TSTypeAssertion`, `TSNonNullExpression`, prefix `UpdateExpression`.
44
+ export const PRECEDENCE_UNARY = 16;
45
+ // `CallExpression`, `ChainExpression`, `ImportExpression`.
46
+ export const PRECEDENCE_CALL = 18;
47
+
48
+ /**
49
+ Get the operator precedence level of a given node. A higher number binds tighter.
50
+
51
+ This only covers node types that can appear as an operand of another expression (the kind of nodes these `should-add-parentheses-to-*` helpers compare against a surrounding operator); node types that can't (statements, patterns, etc) are not meaningful to compare and are not included.
52
+
53
+ This is only safe to use for a "is this operand's precedence lower than the precedence required by its new position" check (`getPrecedence(node) < requiredPrecedence`). It's not enough on its own to decide whether an operand needs parentheses *within a `BinaryExpression`/`LogicalExpression` of the same precedence class it already belongs to* - that also depends on associativity (`**` is right-associative, so `(a ** b) ** c` needs parentheses around the left operand even though both sides have the same precedence) and, for `LogicalExpression`, on whether `??` and `&&`/`||` are being mixed (a `SyntaxError` regardless of precedence, see `isMixedLogicalAndCoalesceExpressions` in ESLint's own `ast-utils.js`).
54
+
55
+ @param {ESTree.Node} node - The AST node to check.
56
+ @returns {number} The precedence level. Node types this function doesn't recognize (for example `Identifier`, `Literal`, or `MemberExpression`) get the highest level, since they never need to be parenthesized based on precedence alone.
57
+ */
58
+ export default function getPrecedence(node) {
59
+ switch (node.type) {
60
+ case 'SequenceExpression': {
61
+ return 0;
62
+ }
63
+
64
+ case 'AssignmentExpression':
65
+ case 'ArrowFunctionExpression':
66
+ case 'YieldExpression': {
67
+ return 1;
68
+ }
69
+
70
+ case 'ConditionalExpression': {
71
+ return 3;
72
+ }
73
+
74
+ case 'LogicalExpression': {
75
+ return logicalOperatorPrecedence[node.operator];
76
+ }
77
+
78
+ case 'BinaryExpression': {
79
+ return binaryOperatorPrecedence[node.operator];
80
+ }
81
+
82
+ case 'TSAsExpression':
83
+ case 'TSSatisfiesExpression': {
84
+ return 10;
85
+ }
86
+
87
+ case 'UnaryExpression':
88
+ case 'AwaitExpression':
89
+ case 'TSTypeAssertion':
90
+ case 'TSNonNullExpression': {
91
+ return PRECEDENCE_UNARY;
92
+ }
93
+
94
+ case 'UpdateExpression': {
95
+ return node.prefix ? PRECEDENCE_UNARY : 17;
96
+ }
97
+
98
+ case 'CallExpression':
99
+ case 'ChainExpression':
100
+ case 'ImportExpression': {
101
+ return PRECEDENCE_CALL;
102
+ }
103
+
104
+ case 'NewExpression': {
105
+ return 19;
106
+ }
107
+
108
+ default: {
109
+ return 20;
110
+ }
111
+ }
112
+ }
@@ -6,7 +6,7 @@
6
6
  @param {import('estree').Node} node
7
7
  @returns {import('eslint').SourceCode}
8
8
  */
9
- function getTokenStore(context, node) {
9
+ export default function getTokenStore(context, node) {
10
10
  const {sourceCode} = context;
11
11
 
12
12
  if (
@@ -20,5 +20,3 @@ function getTokenStore(context, node) {
20
20
 
21
21
  return sourceCode;
22
22
  }
23
-
24
- export default getTokenStore;
@@ -25,6 +25,9 @@ const mergeTraceMap = (target, source) => {
25
25
  };
26
26
 
27
27
  export class GlobalReferenceTracker {
28
+ static READ = ReferenceTracker.READ;
29
+ static CALL = ReferenceTracker.CALL;
30
+ static CONSTRUCT = ReferenceTracker.CONSTRUCT;
28
31
  #traceMap = {};
29
32
  #context;
30
33
  #filter;
@@ -73,9 +76,3 @@ export class GlobalReferenceTracker {
73
76
  );
74
77
  }
75
78
  }
76
-
77
- Object.assign(GlobalReferenceTracker, {
78
- READ: ReferenceTracker.READ,
79
- CALL: ReferenceTracker.CALL,
80
- CONSTRUCT: ReferenceTracker.CONSTRUCT,
81
- });
@@ -23,6 +23,7 @@ export {
23
23
  } from './boolean.js';
24
24
 
25
25
  export {default as assertToken} from './assert-token.js';
26
+ export {default as canTokensBeAdjacent} from './can-tokens-be-adjacent.js';
26
27
  export {default as cartesianProductSamples} from './cartesian-product-samples.js';
27
28
  export {default as containsSuspensionPoint} from './contains-suspension-point.js';
28
29
  export {default as escapeString} from './escape-string.js';
@@ -32,6 +33,7 @@ export {default as getCallExpressionArgumentsText} from './get-call-expression-a
32
33
  export {getCallExpressionTokens, getNewExpressionTokens} from './get-call-or-new-expression-tokens.js';
33
34
  export {default as getDuplicateArrayElements, isComparableStaticValue} from './get-duplicate-array-elements.js';
34
35
  export {default as getIndentString} from './get-indent-string.js';
36
+ export {default as isIdentifierName} from './is-identifier-name.js';
35
37
  export {default as getComments} from './get-comments.js';
36
38
  export {
37
39
  getLastTrailingCommentOnSameLine,
@@ -94,6 +96,7 @@ export {default as isNodeValueNotFunction} from './is-node-value-not-function.js
94
96
  export {default as isNodeContainsLexicalThis} from './is-node-contains-lexical-this.js';
95
97
  export {default as isOnSameLine} from './is-on-same-line.js';
96
98
  export {default as isPromiseType} from './is-promise-type.js';
99
+ export {default as isReactHookName} from './is-react-hook-name.js';
97
100
  export {default as isSameIdentifier} from './is-same-identifier.js';
98
101
  export {default as isSameReference} from './is-same-reference.js';
99
102
  export {default as isUnresolvedVariable} from './is-unresolved-variable.js';
@@ -133,6 +136,7 @@ export {
133
136
  isBuiltinSet,
134
137
  } from './builtin-collection-type.js';
135
138
  export {checkVueTemplate} from './rule.js';
139
+ export {default as getPrecedence} from './get-precedence.js';
136
140
  export {default as shouldAddParenthesesToAwaitExpressionArgument} from './should-add-parentheses-to-await-expression-argument.js';
137
141
  export {default as shouldAddParenthesesToCallExpressionCallee} from './should-add-parentheses-to-call-expression-callee.js';
138
142
  export {default as shouldAddParenthesesToConditionalExpressionChild} from './should-add-parentheses-to-conditional-expression-child.js';