eslint 8.11.0 → 8.14.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.
@@ -5,6 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const { isConstant } = require("./utils/ast-utils");
9
+
8
10
  //------------------------------------------------------------------------------
9
11
  // Helpers
10
12
  //------------------------------------------------------------------------------
@@ -53,201 +55,6 @@ module.exports = {
53
55
  // Helpers
54
56
  //--------------------------------------------------------------------------
55
57
 
56
- /**
57
- * Returns literal's value converted to the Boolean type
58
- * @param {ASTNode} node any `Literal` node
59
- * @returns {boolean | null} `true` when node is truthy, `false` when node is falsy,
60
- * `null` when it cannot be determined.
61
- */
62
- function getBooleanValue(node) {
63
- if (node.value === null) {
64
-
65
- /*
66
- * it might be a null literal or bigint/regex literal in unsupported environments .
67
- * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es5.md#regexpliteral
68
- * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es2020.md#bigintliteral
69
- */
70
-
71
- if (node.raw === "null") {
72
- return false;
73
- }
74
-
75
- // regex is always truthy
76
- if (typeof node.regex === "object") {
77
- return true;
78
- }
79
-
80
- return null;
81
- }
82
-
83
- return !!node.value;
84
- }
85
-
86
- /**
87
- * Checks if a branch node of LogicalExpression short circuits the whole condition
88
- * @param {ASTNode} node The branch of main condition which needs to be checked
89
- * @param {string} operator The operator of the main LogicalExpression.
90
- * @returns {boolean} true when condition short circuits whole condition
91
- */
92
- function isLogicalIdentity(node, operator) {
93
- switch (node.type) {
94
- case "Literal":
95
- return (operator === "||" && getBooleanValue(node) === true) ||
96
- (operator === "&&" && getBooleanValue(node) === false);
97
-
98
- case "UnaryExpression":
99
- return (operator === "&&" && node.operator === "void");
100
-
101
- case "LogicalExpression":
102
-
103
- /*
104
- * handles `a && false || b`
105
- * `false` is an identity element of `&&` but not `||`
106
- */
107
- return operator === node.operator &&
108
- (
109
- isLogicalIdentity(node.left, operator) ||
110
- isLogicalIdentity(node.right, operator)
111
- );
112
-
113
- case "AssignmentExpression":
114
- return ["||=", "&&="].includes(node.operator) &&
115
- operator === node.operator.slice(0, -1) &&
116
- isLogicalIdentity(node.right, operator);
117
-
118
- // no default
119
- }
120
- return false;
121
- }
122
-
123
- /**
124
- * Checks if an identifier is a reference to a global variable.
125
- * @param {ASTNode} node An identifier node to check.
126
- * @returns {boolean} `true` if the identifier is a reference to a global variable.
127
- */
128
- function isReferenceToGlobalVariable(node) {
129
- const scope = context.getScope();
130
- const reference = scope.references.find(ref => ref.identifier === node);
131
-
132
- return Boolean(
133
- reference &&
134
- reference.resolved &&
135
- reference.resolved.scope.type === "global" &&
136
- reference.resolved.defs.length === 0
137
- );
138
- }
139
-
140
- /**
141
- * Checks if a node has a constant truthiness value.
142
- * @param {ASTNode} node The AST node to check.
143
- * @param {boolean} inBooleanPosition `true` if checking the test of a
144
- * condition. `false` in all other cases. When `false`, checks if -- for
145
- * both string and number -- if coerced to that type, the value will
146
- * be constant.
147
- * @returns {Bool} true when node's truthiness is constant
148
- * @private
149
- */
150
- function isConstant(node, inBooleanPosition) {
151
-
152
- // node.elements can return null values in the case of sparse arrays ex. [,]
153
- if (!node) {
154
- return true;
155
- }
156
- switch (node.type) {
157
- case "Literal":
158
- case "ArrowFunctionExpression":
159
- case "FunctionExpression":
160
- return true;
161
- case "ClassExpression":
162
- case "ObjectExpression":
163
-
164
- /**
165
- * In theory objects like:
166
- *
167
- * `{toString: () => a}`
168
- * `{valueOf: () => a}`
169
- *
170
- * Or a classes like:
171
- *
172
- * `class { static toString() { return a } }`
173
- * `class { static valueOf() { return a } }`
174
- *
175
- * Are not constant verifiably when `inBooleanPosition` is
176
- * false, but it's an edge case we've opted not to handle.
177
- */
178
- return true;
179
- case "TemplateLiteral":
180
- return (inBooleanPosition && node.quasis.some(quasi => quasi.value.cooked.length)) ||
181
- node.expressions.every(exp => isConstant(exp, false));
182
-
183
- case "ArrayExpression": {
184
- if (!inBooleanPosition) {
185
- return node.elements.every(element => isConstant(element, false));
186
- }
187
- return true;
188
- }
189
-
190
- case "UnaryExpression":
191
- if (
192
- node.operator === "void" ||
193
- node.operator === "typeof" && inBooleanPosition
194
- ) {
195
- return true;
196
- }
197
-
198
- if (node.operator === "!") {
199
- return isConstant(node.argument, true);
200
- }
201
-
202
- return isConstant(node.argument, false);
203
-
204
- case "BinaryExpression":
205
- return isConstant(node.left, false) &&
206
- isConstant(node.right, false) &&
207
- node.operator !== "in";
208
-
209
- case "LogicalExpression": {
210
- const isLeftConstant = isConstant(node.left, inBooleanPosition);
211
- const isRightConstant = isConstant(node.right, inBooleanPosition);
212
- const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator));
213
- const isRightShortCircuit = (inBooleanPosition && isRightConstant && isLogicalIdentity(node.right, node.operator));
214
-
215
- return (isLeftConstant && isRightConstant) ||
216
- isLeftShortCircuit ||
217
- isRightShortCircuit;
218
- }
219
- case "NewExpression":
220
- return inBooleanPosition;
221
- case "AssignmentExpression":
222
- if (node.operator === "=") {
223
- return isConstant(node.right, inBooleanPosition);
224
- }
225
-
226
- if (["||=", "&&="].includes(node.operator) && inBooleanPosition) {
227
- return isLogicalIdentity(node.right, node.operator.slice(0, -1));
228
- }
229
-
230
- return false;
231
-
232
- case "SequenceExpression":
233
- return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition);
234
- case "SpreadElement":
235
- return isConstant(node.argument, inBooleanPosition);
236
- case "CallExpression":
237
- if (node.callee.type === "Identifier" && node.callee.name === "Boolean") {
238
- if (node.arguments.length === 0 || isConstant(node.arguments[0], true)) {
239
- return isReferenceToGlobalVariable(node.callee);
240
- }
241
- }
242
- return false;
243
- case "Identifier":
244
- return node.name === "undefined" && isReferenceToGlobalVariable(node);
245
-
246
- // no default
247
- }
248
- return false;
249
- }
250
-
251
58
  /**
252
59
  * Tracks when the given node contains a constant condition.
253
60
  * @param {ASTNode} node The AST node to check.
@@ -255,7 +62,7 @@ module.exports = {
255
62
  * @private
256
63
  */
257
64
  function trackConstantConditionLoop(node) {
258
- if (node.test && isConstant(node.test, true)) {
65
+ if (node.test && isConstant(context.getScope(), node.test, true)) {
259
66
  loopsInCurrentScope.add(node);
260
67
  }
261
68
  }
@@ -280,7 +87,7 @@ module.exports = {
280
87
  * @private
281
88
  */
282
89
  function reportIfConstant(node) {
283
- if (node.test && isConstant(node.test, true)) {
90
+ if (node.test && isConstant(context.getScope(), node.test, true)) {
284
91
  context.report({ node: node.test, messageId: "unexpected" });
285
92
  }
286
93
  }
@@ -72,21 +72,25 @@ module.exports = {
72
72
  let funcInfo = null;
73
73
 
74
74
  /**
75
- * Pushs a variable scope (Program or Function) information to the stack.
75
+ * Pushs a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
76
+ * Top-level scopes are handled separately.
76
77
  *
77
78
  * This is used in order to check whether or not `this` binding is a
78
79
  * reference to the global object.
79
- * @param {ASTNode} node A node of the scope. This is one of Program,
80
- * FunctionDeclaration, FunctionExpression, and ArrowFunctionExpression.
80
+ * @param {ASTNode} node A node of the scope.
81
+ * For functions, this is one of FunctionDeclaration, FunctionExpression.
82
+ * For class static blocks, this is StaticBlock.
83
+ * For class field initializers, this can be any node that is PropertyDefinition#value.
81
84
  * @returns {void}
82
85
  */
83
- function enterVarScope(node) {
86
+ function enterThisScope(node) {
84
87
  const strict = context.getScope().isStrict;
85
88
 
86
89
  funcInfo = {
87
90
  upper: funcInfo,
88
91
  node,
89
92
  strict,
93
+ isTopLevelOfScript: false,
90
94
  defaultThis: false,
91
95
  initialized: strict
92
96
  };
@@ -96,7 +100,7 @@ module.exports = {
96
100
  * Pops a variable scope from the stack.
97
101
  * @returns {void}
98
102
  */
99
- function exitVarScope() {
103
+ function exitThisScope() {
100
104
  funcInfo = funcInfo.upper;
101
105
  }
102
106
 
@@ -222,12 +226,14 @@ module.exports = {
222
226
  strict =
223
227
  scope.isStrict ||
224
228
  node.sourceType === "module" ||
225
- (features.globalReturn && scope.childScopes[0].isStrict);
229
+ (features.globalReturn && scope.childScopes[0].isStrict),
230
+ isTopLevelOfScript = node.sourceType !== "module" && !features.globalReturn;
226
231
 
227
232
  funcInfo = {
228
233
  upper: null,
229
234
  node,
230
235
  strict,
236
+ isTopLevelOfScript,
231
237
  defaultThis: true,
232
238
  initialized: true
233
239
  };
@@ -236,21 +242,19 @@ module.exports = {
236
242
  "Program:exit"() {
237
243
  const globalScope = context.getScope();
238
244
 
239
- exitVarScope();
245
+ exitThisScope();
240
246
  reportAccessingEval(globalScope);
241
247
  reportAccessingEvalViaGlobalObject(globalScope);
242
248
  },
243
249
 
244
- FunctionDeclaration: enterVarScope,
245
- "FunctionDeclaration:exit": exitVarScope,
246
- FunctionExpression: enterVarScope,
247
- "FunctionExpression:exit": exitVarScope,
248
- ArrowFunctionExpression: enterVarScope,
249
- "ArrowFunctionExpression:exit": exitVarScope,
250
- "PropertyDefinition > *.value": enterVarScope,
251
- "PropertyDefinition > *.value:exit": exitVarScope,
252
- StaticBlock: enterVarScope,
253
- "StaticBlock:exit": exitVarScope,
250
+ FunctionDeclaration: enterThisScope,
251
+ "FunctionDeclaration:exit": exitThisScope,
252
+ FunctionExpression: enterThisScope,
253
+ "FunctionExpression:exit": exitThisScope,
254
+ "PropertyDefinition > *.value": enterThisScope,
255
+ "PropertyDefinition > *.value:exit": exitThisScope,
256
+ StaticBlock: enterThisScope,
257
+ "StaticBlock:exit": exitThisScope,
254
258
 
255
259
  ThisExpression(node) {
256
260
  if (!isMember(node.parent, "eval")) {
@@ -269,7 +273,8 @@ module.exports = {
269
273
  );
270
274
  }
271
275
 
272
- if (!funcInfo.strict && funcInfo.defaultThis) {
276
+ // `this` at the top level of scripts always refers to the global object
277
+ if (funcInfo.isTopLevelOfScript || (!funcInfo.strict && funcInfo.defaultThis)) {
273
278
 
274
279
  // `this.eval` is possible built-in `eval`.
275
280
  report(node.parent);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @fileoverview A rule to disallow `this` keywords outside of classes or class-like objects.
2
+ * @fileoverview A rule to disallow `this` keywords in contexts where the value of `this` is `undefined`.
3
3
  * @author Toru Nagashima
4
4
  */
5
5
 
@@ -36,7 +36,7 @@ module.exports = {
36
36
  type: "suggestion",
37
37
 
38
38
  docs: {
39
- description: "disallow `this` keywords outside of classes or class-like objects",
39
+ description: "disallow use of `this` in contexts where the value of `this` is `undefined`",
40
40
  recommended: false,
41
41
  url: "https://eslint.org/docs/rules/no-invalid-this"
42
42
  },
@@ -98,11 +98,11 @@ module.exports = {
98
98
  const scope = context.getScope();
99
99
  const features = context.parserOptions.ecmaFeatures || {};
100
100
 
101
+ // `this` at the top level of scripts always refers to the global object
101
102
  stack.push({
102
103
  init: true,
103
104
  node,
104
105
  valid: !(
105
- scope.isStrict ||
106
106
  node.sourceType === "module" ||
107
107
  (features.globalReturn && scope.childScopes[0].isStrict)
108
108
  )
@@ -76,8 +76,8 @@ module.exports = {
76
76
 
77
77
  fixable: "code",
78
78
  messages: {
79
- replaced: "Assignment (=) can be replaced with operator assignment ({{operator}}=).",
80
- unexpected: "Unexpected operator assignment ({{operator}}=) shorthand."
79
+ replaced: "Assignment (=) can be replaced with operator assignment ({{operator}}).",
80
+ unexpected: "Unexpected operator assignment ({{operator}}) shorthand."
81
81
  }
82
82
  },
83
83
 
@@ -109,11 +109,13 @@ module.exports = {
109
109
  const operator = expr.operator;
110
110
 
111
111
  if (isCommutativeOperatorWithShorthand(operator) || isNonCommutativeOperatorWithShorthand(operator)) {
112
+ const replacementOperator = `${operator}=`;
113
+
112
114
  if (astUtils.isSameReference(left, expr.left, true)) {
113
115
  context.report({
114
116
  node,
115
117
  messageId: "replaced",
116
- data: { operator },
118
+ data: { operator: replacementOperator },
117
119
  fix(fixer) {
118
120
  if (canBeFixed(left) && canBeFixed(expr.left)) {
119
121
  const equalsToken = getOperatorToken(node);
@@ -126,7 +128,7 @@ module.exports = {
126
128
  return null;
127
129
  }
128
130
 
129
- return fixer.replaceText(node, `${leftText}${expr.operator}=${rightText}`);
131
+ return fixer.replaceText(node, `${leftText}${replacementOperator}${rightText}`);
130
132
  }
131
133
  return null;
132
134
  }
@@ -141,7 +143,7 @@ module.exports = {
141
143
  context.report({
142
144
  node,
143
145
  messageId: "replaced",
144
- data: { operator }
146
+ data: { operator: replacementOperator }
145
147
  });
146
148
  }
147
149
  }
@@ -450,8 +450,7 @@ module.exports = {
450
450
  type: "array",
451
451
  items: { enum: Object.keys(StatementTypes) },
452
452
  minItems: 1,
453
- uniqueItems: true,
454
- additionalItems: false
453
+ uniqueItems: true
455
454
  }
456
455
  ]
457
456
  }
@@ -466,8 +465,7 @@ module.exports = {
466
465
  },
467
466
  additionalProperties: false,
468
467
  required: ["blankLine", "prev", "next"]
469
- },
470
- additionalItems: false
468
+ }
471
469
  },
472
470
 
473
471
  messages: {
@@ -32,6 +32,7 @@ const thisTagPattern = /^[\s*]*@this/mu;
32
32
 
33
33
 
34
34
  const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u;
35
+ const ESLINT_DIRECTIVE_PATTERN = /^(?:eslint[- ]|(?:globals?|exported) )/u;
35
36
  const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
36
37
 
37
38
  // A set of node types that can contain a list of statements
@@ -788,6 +789,203 @@ function getModuleExportName(node) {
788
789
  return node.value;
789
790
  }
790
791
 
792
+ /**
793
+ * Returns literal's value converted to the Boolean type
794
+ * @param {ASTNode} node any `Literal` node
795
+ * @returns {boolean | null} `true` when node is truthy, `false` when node is falsy,
796
+ * `null` when it cannot be determined.
797
+ */
798
+ function getBooleanValue(node) {
799
+ if (node.value === null) {
800
+
801
+ /*
802
+ * it might be a null literal or bigint/regex literal in unsupported environments .
803
+ * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es5.md#regexpliteral
804
+ * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es2020.md#bigintliteral
805
+ */
806
+
807
+ if (node.raw === "null") {
808
+ return false;
809
+ }
810
+
811
+ // regex is always truthy
812
+ if (typeof node.regex === "object") {
813
+ return true;
814
+ }
815
+
816
+ return null;
817
+ }
818
+
819
+ return !!node.value;
820
+ }
821
+
822
+ /**
823
+ * Checks if a branch node of LogicalExpression short circuits the whole condition
824
+ * @param {ASTNode} node The branch of main condition which needs to be checked
825
+ * @param {string} operator The operator of the main LogicalExpression.
826
+ * @returns {boolean} true when condition short circuits whole condition
827
+ */
828
+ function isLogicalIdentity(node, operator) {
829
+ switch (node.type) {
830
+ case "Literal":
831
+ return (operator === "||" && getBooleanValue(node) === true) ||
832
+ (operator === "&&" && getBooleanValue(node) === false);
833
+
834
+ case "UnaryExpression":
835
+ return (operator === "&&" && node.operator === "void");
836
+
837
+ case "LogicalExpression":
838
+
839
+ /*
840
+ * handles `a && false || b`
841
+ * `false` is an identity element of `&&` but not `||`
842
+ */
843
+ return operator === node.operator &&
844
+ (
845
+ isLogicalIdentity(node.left, operator) ||
846
+ isLogicalIdentity(node.right, operator)
847
+ );
848
+
849
+ case "AssignmentExpression":
850
+ return ["||=", "&&="].includes(node.operator) &&
851
+ operator === node.operator.slice(0, -1) &&
852
+ isLogicalIdentity(node.right, operator);
853
+
854
+ // no default
855
+ }
856
+ return false;
857
+ }
858
+
859
+ /**
860
+ * Checks if an identifier is a reference to a global variable.
861
+ * @param {Scope} scope The scope in which the identifier is referenced.
862
+ * @param {ASTNode} node An identifier node to check.
863
+ * @returns {boolean} `true` if the identifier is a reference to a global variable.
864
+ */
865
+ function isReferenceToGlobalVariable(scope, node) {
866
+ const reference = scope.references.find(ref => ref.identifier === node);
867
+
868
+ return Boolean(
869
+ reference &&
870
+ reference.resolved &&
871
+ reference.resolved.scope.type === "global" &&
872
+ reference.resolved.defs.length === 0
873
+ );
874
+ }
875
+
876
+
877
+ /**
878
+ * Checks if a node has a constant truthiness value.
879
+ * @param {Scope} scope Scope in which the node appears.
880
+ * @param {ASTNode} node The AST node to check.
881
+ * @param {boolean} inBooleanPosition `true` if checking the test of a
882
+ * condition. `false` in all other cases. When `false`, checks if -- for
883
+ * both string and number -- if coerced to that type, the value will
884
+ * be constant.
885
+ * @returns {boolean} true when node's truthiness is constant
886
+ * @private
887
+ */
888
+ function isConstant(scope, node, inBooleanPosition) {
889
+
890
+ // node.elements can return null values in the case of sparse arrays ex. [,]
891
+ if (!node) {
892
+ return true;
893
+ }
894
+ switch (node.type) {
895
+ case "Literal":
896
+ case "ArrowFunctionExpression":
897
+ case "FunctionExpression":
898
+ return true;
899
+ case "ClassExpression":
900
+ case "ObjectExpression":
901
+
902
+ /**
903
+ * In theory objects like:
904
+ *
905
+ * `{toString: () => a}`
906
+ * `{valueOf: () => a}`
907
+ *
908
+ * Or a classes like:
909
+ *
910
+ * `class { static toString() { return a } }`
911
+ * `class { static valueOf() { return a } }`
912
+ *
913
+ * Are not constant verifiably when `inBooleanPosition` is
914
+ * false, but it's an edge case we've opted not to handle.
915
+ */
916
+ return true;
917
+ case "TemplateLiteral":
918
+ return (inBooleanPosition && node.quasis.some(quasi => quasi.value.cooked.length)) ||
919
+ node.expressions.every(exp => isConstant(scope, exp, false));
920
+
921
+ case "ArrayExpression": {
922
+ if (!inBooleanPosition) {
923
+ return node.elements.every(element => isConstant(scope, element, false));
924
+ }
925
+ return true;
926
+ }
927
+
928
+ case "UnaryExpression":
929
+ if (
930
+ node.operator === "void" ||
931
+ node.operator === "typeof" && inBooleanPosition
932
+ ) {
933
+ return true;
934
+ }
935
+
936
+ if (node.operator === "!") {
937
+ return isConstant(scope, node.argument, true);
938
+ }
939
+
940
+ return isConstant(scope, node.argument, false);
941
+
942
+ case "BinaryExpression":
943
+ return isConstant(scope, node.left, false) &&
944
+ isConstant(scope, node.right, false) &&
945
+ node.operator !== "in";
946
+
947
+ case "LogicalExpression": {
948
+ const isLeftConstant = isConstant(scope, node.left, inBooleanPosition);
949
+ const isRightConstant = isConstant(scope, node.right, inBooleanPosition);
950
+ const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator));
951
+ const isRightShortCircuit = (inBooleanPosition && isRightConstant && isLogicalIdentity(node.right, node.operator));
952
+
953
+ return (isLeftConstant && isRightConstant) ||
954
+ isLeftShortCircuit ||
955
+ isRightShortCircuit;
956
+ }
957
+ case "NewExpression":
958
+ return inBooleanPosition;
959
+ case "AssignmentExpression":
960
+ if (node.operator === "=") {
961
+ return isConstant(scope, node.right, inBooleanPosition);
962
+ }
963
+
964
+ if (["||=", "&&="].includes(node.operator) && inBooleanPosition) {
965
+ return isLogicalIdentity(node.right, node.operator.slice(0, -1));
966
+ }
967
+
968
+ return false;
969
+
970
+ case "SequenceExpression":
971
+ return isConstant(scope, node.expressions[node.expressions.length - 1], inBooleanPosition);
972
+ case "SpreadElement":
973
+ return isConstant(scope, node.argument, inBooleanPosition);
974
+ case "CallExpression":
975
+ if (node.callee.type === "Identifier" && node.callee.name === "Boolean") {
976
+ if (node.arguments.length === 0 || isConstant(scope, node.arguments[0], true)) {
977
+ return isReferenceToGlobalVariable(scope, node.callee);
978
+ }
979
+ }
980
+ return false;
981
+ case "Identifier":
982
+ return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
983
+
984
+ // no default
985
+ }
986
+ return false;
987
+ }
988
+
791
989
  //------------------------------------------------------------------------------
792
990
  // Public Interface
793
991
  //------------------------------------------------------------------------------
@@ -908,12 +1106,8 @@ module.exports = {
908
1106
  const comment = node.value.trim();
909
1107
 
910
1108
  return (
911
- node.type === "Line" && comment.indexOf("eslint-") === 0 ||
912
- node.type === "Block" && (
913
- comment.indexOf("global ") === 0 ||
914
- comment.indexOf("eslint ") === 0 ||
915
- comment.indexOf("eslint-") === 0
916
- )
1109
+ node.type === "Line" && comment.startsWith("eslint-") ||
1110
+ node.type === "Block" && ESLINT_DIRECTIVE_PATTERN.test(comment)
917
1111
  );
918
1112
  },
919
1113
 
@@ -1905,6 +2099,7 @@ module.exports = {
1905
2099
  return OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN.test(rawString);
1906
2100
  },
1907
2101
 
2102
+ isReferenceToGlobalVariable,
1908
2103
  isLogicalExpression,
1909
2104
  isCoalesceExpression,
1910
2105
  isMixedLogicalAndCoalesceExpressions,
@@ -1918,5 +2113,6 @@ module.exports = {
1918
2113
  isSameReference,
1919
2114
  isLogicalAssignmentOperator,
1920
2115
  getSwitchCaseColonToken,
1921
- getModuleExportName
2116
+ getModuleExportName,
2117
+ isConstant
1922
2118
  };
@@ -173,3 +173,27 @@ module.exports = {};
173
173
  * @property {string} ruleId The rule ID.
174
174
  * @property {string[]} replacedBy The rule IDs that replace this deprecated rule.
175
175
  */
176
+
177
+ /**
178
+ * A linting result.
179
+ * @typedef {Object} LintResult
180
+ * @property {string} filePath The path to the file that was linted.
181
+ * @property {LintMessage[]} messages All of the messages for the result.
182
+ * @property {SuppressedLintMessage[]} suppressedMessages All of the suppressed messages for the result.
183
+ * @property {number} errorCount Number of errors for the result.
184
+ * @property {number} fatalErrorCount Number of fatal errors for the result.
185
+ * @property {number} warningCount Number of warnings for the result.
186
+ * @property {number} fixableErrorCount Number of fixable errors for the result.
187
+ * @property {number} fixableWarningCount Number of fixable warnings for the result.
188
+ * @property {string} [source] The source code of the file that was linted.
189
+ * @property {string} [output] The source code of the file that was linted, with as many fixes applied as possible.
190
+ * @property {DeprecatedRuleInfo[]} usedDeprecatedRules The list of used deprecated rules.
191
+ */
192
+
193
+ /**
194
+ * A formatter function.
195
+ * @callback FormatterFunction
196
+ * @param {LintResult[]} results The list of linting results.
197
+ * @param {{cwd: string, rulesMeta: Record<string, RuleMeta>}} [context] A context object.
198
+ * @returns {string | Promise<string>} Formatted text.
199
+ */