eslint-plugin-complete 1.0.9 → 1.0.11

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.
package/dist/comments.js CHANGED
@@ -18,27 +18,27 @@ export function isEnumBlockLabel(text) {
18
18
  text = text.trim();
19
19
  return (
20
20
  // e.g. CollectibleType.SAD_ONION
21
- /^\w+\.\w+$/.test(text) ||
21
+ /^\w+\.\w+$/.test(text)
22
22
  // e.g. CollectibleType.SAD_ONION (1)
23
- /^\w+\.\w+ \(\d+\)$/.test(text) ||
23
+ || /^\w+\.\w+ \(\d+\)$/.test(text)
24
24
  // e.g. CacheFlag.FIRE_DELAY (1 << 1)
25
- /^\w+\.\w+ \(\d+ << \d+\)$/.test(text) ||
25
+ || /^\w+\.\w+ \(\d+ << \d+\)$/.test(text)
26
26
  // e.g. 1
27
- /^\d+$/.test(text) ||
27
+ || /^\d+$/.test(text)
28
28
  // e.g. 1.0
29
- /^\d+\.\d+$/.test(text) ||
29
+ || /^\d+\.\d+$/.test(text)
30
30
  // e.g. 1 << 1
31
- /^\d+ << \d+$/.test(text) ||
31
+ || /^\d+ << \d+$/.test(text)
32
32
  // e.g. 1, 2, 3, 4, 5
33
- /^\d+, \d+$/.test(text) ||
34
- /^\d+, \d+, \d+$/.test(text) ||
35
- /^(?:\d+, ){3}\d+$/.test(text) ||
36
- /^(?:\d+, ){4}\d+$/.test(text) ||
33
+ || /^\d+, \d+$/.test(text)
34
+ || /^\d+, \d+, \d+$/.test(text)
35
+ || /^(?:\d+, ){3}\d+$/.test(text)
36
+ || /^(?:\d+, ){4}\d+$/.test(text)
37
37
  // e.g. 1.0, 2.0, 3.0, 4.0, 5.0
38
- /^\d+\.\d+, \d+\.\d+$/.test(text) ||
39
- /^(?:\d+\.\d+, ){2}\d+\.\d+$/.test(text) ||
40
- /^(?:\d+\.\d+, ){3}\d+\.\d+$/.test(text) ||
41
- /^(?:\d+\.\d+, ){4}\d+\.\d+$/.test(text));
38
+ || /^\d+\.\d+, \d+\.\d+$/.test(text)
39
+ || /^(?:\d+\.\d+, ){2}\d+\.\d+$/.test(text)
40
+ || /^(?:\d+\.\d+, ){3}\d+\.\d+$/.test(text)
41
+ || /^(?:\d+\.\d+, ){4}\d+\.\d+$/.test(text));
42
42
  }
43
43
  /**
44
44
  * A "separator" line is a line with all hyphens like the following:
@@ -54,14 +54,14 @@ export function isSeparatorLine(text) {
54
54
  }
55
55
  export function isSpecialComment(text) {
56
56
  text = text.trim();
57
- return (text.startsWith("eslint-") ||
58
- text.startsWith("prettier-") ||
59
- text.startsWith("cspell:") ||
60
- text.startsWith("ts-prune-") || // e.g. ts-prune-ignore-next
61
- text.startsWith("@ts-") ||
62
- text.startsWith("@template-") || // e.g. @template-customization-start (complete-cli directives)
63
- text.startsWith("TODO:") ||
64
- text.startsWith("FIXME:") ||
65
- text === "TODO" ||
66
- text === "FIXME");
57
+ return (text.startsWith("eslint-")
58
+ || text.startsWith("prettier-")
59
+ || text.startsWith("cspell:")
60
+ || text.startsWith("ts-prune-") // e.g. ts-prune-ignore-next
61
+ || text.startsWith("@ts-")
62
+ || text.startsWith("@template-") // e.g. @template-customization-start (complete-cli directives)
63
+ || text.startsWith("TODO:")
64
+ || text.startsWith("FIXME:")
65
+ || text === "TODO"
66
+ || text === "FIXME");
67
67
  }
@@ -40,9 +40,9 @@ export function isFirstLetterCapitalized(string) {
40
40
  * `!Array.isArray(variable)`.
41
41
  */
42
42
  export function isObject(variable) {
43
- return (typeof variable === "object" &&
44
- variable !== null &&
45
- !Array.isArray(variable));
43
+ return (typeof variable === "object"
44
+ && variable !== null
45
+ && !Array.isArray(variable));
46
46
  }
47
47
  /**
48
48
  * Helper function to trim a prefix from a string, if it exists. Returns the trimmed string.
@@ -160,28 +160,28 @@ function getIncompleteSentenceKind(sentence, isLoneSentence) {
160
160
  // Ignore / whitelist some specific things.
161
161
  if (
162
162
  // Blank text.
163
- text === "" ||
163
+ text === ""
164
164
  // Sentences that do not contain any letters.
165
- !/[A-Za-z]/.test(text) ||
165
+ || !/[A-Za-z]/.test(text)
166
166
  // Sentences with an arrow, like: "Alice --> Bob"
167
- text.includes("-->") ||
167
+ || text.includes("-->")
168
168
  // Placeholder text.
169
- text === "n/a" ||
169
+ || text === "n/a"
170
170
  // Special comments.
171
- isSpecialComment(text) ||
171
+ || isSpecialComment(text)
172
172
  // Dates.
173
- isDate(text) ||
173
+ || isDate(text)
174
174
  // URLS.
175
- hasURL(text) ||
175
+ || hasURL(text)
176
176
  // Single JSDoc tags.
177
- /^@\w+$/.test(text) ||
177
+ || /^@\w+$/.test(text)
178
178
  // Lists.
179
- text.startsWith(LIST_ELEMENT_IDENTIFIER) ||
179
+ || text.startsWith(LIST_ELEMENT_IDENTIFIER)
180
180
  // Code blocks.
181
- text.includes("```") ||
181
+ || text.includes("```")
182
182
  // Sentences that end with a number in parenthesis (which indicates some kind of expression).
183
183
  // This must check the original text.
184
- / \(\d+\)$/.test(sentence.trimEnd())) {
184
+ || / \(\d+\)$/.test(sentence.trimEnd())) {
185
185
  return undefined;
186
186
  }
187
187
  // First, check for a double period.
@@ -191,9 +191,11 @@ function getIncompleteSentenceKind(sentence, isLoneSentence) {
191
191
  return "doublePeriod";
192
192
  }
193
193
  }
194
- if (isLoneSentence &&
194
+ if (isLoneSentence
195
195
  // Single words, double words, and triple words.
196
- (/^\S+$/.test(text) || /^\S+ \S+$/.test(text) || /^\S+ \S+ \S+$/.test(text))) {
196
+ && (/^\S+$/.test(text)
197
+ || /^\S+ \S+$/.test(text)
198
+ || /^\S+ \S+ \S+$/.test(text))) {
197
199
  return undefined;
198
200
  }
199
201
  if (/^[a-z]/.test(text) && !isCapitalizedWordException(text)) {
@@ -201,23 +203,23 @@ function getIncompleteSentenceKind(sentence, isLoneSentence) {
201
203
  }
202
204
  if (
203
205
  // Allow normal end-of-line punctuation.
204
- !text.endsWith(".") &&
205
- !text.endsWith("!") &&
206
- !text.endsWith("?") &&
206
+ !text.endsWith(".")
207
+ && !text.endsWith("!")
208
+ && !text.endsWith("?")
207
209
  // Allow ending with a period inside of a single quote or double quote, since it is implied that
208
210
  // this is a fully quoted sentence.
209
- !text.endsWith('."') &&
210
- !text.endsWith('!"') &&
211
- !text.endsWith('?"') &&
212
- !text.endsWith(".'") &&
213
- !text.endsWith("!'") &&
214
- !text.endsWith("?'") &&
211
+ && !text.endsWith('."')
212
+ && !text.endsWith('!"')
213
+ && !text.endsWith('?"')
214
+ && !text.endsWith(".'")
215
+ && !text.endsWith("!'")
216
+ && !text.endsWith("?'")
215
217
  // Allow ending with a colon, since it is implied that there is an example of something on the
216
218
  // subsequent block.
217
- !text.endsWith(":") &&
219
+ && !text.endsWith(":")
218
220
  // Allow ending with anything if there is a colon in the middle of the sentence, since it is
219
221
  // implied that this is an example of something.
220
- !text.includes(": ")) {
222
+ && !text.includes(": ")) {
221
223
  return "missingPeriod";
222
224
  }
223
225
  return undefined;
@@ -246,20 +248,20 @@ function isDate(text) {
246
248
  const match1 = text.match(/^(?<month>\w+) \d+(?<ordinal>\w+)$/);
247
249
  if (match1 !== null && match1.groups !== undefined) {
248
250
  const { month, ordinal } = match1.groups;
249
- if (month !== undefined &&
250
- MONTHS_SET.has(month) &&
251
- ordinal !== undefined &&
252
- ORDINALS_SET.has(ordinal)) {
251
+ if (month !== undefined
252
+ && MONTHS_SET.has(month)
253
+ && ordinal !== undefined
254
+ && ORDINALS_SET.has(ordinal)) {
253
255
  return true;
254
256
  }
255
257
  }
256
258
  const match2 = text.match(/^(?<month>\w+) \d+(?<ordinal>\w+), \d+$/);
257
259
  if (match2 !== null && match2.groups !== undefined) {
258
260
  const { month, ordinal } = match2.groups;
259
- if (month !== undefined &&
260
- MONTHS_SET.has(month) &&
261
- ordinal !== undefined &&
262
- ORDINALS_SET.has(ordinal)) {
261
+ if (month !== undefined
262
+ && MONTHS_SET.has(month)
263
+ && ordinal !== undefined
264
+ && ORDINALS_SET.has(ordinal)) {
263
265
  return true;
264
266
  }
265
267
  }
package/dist/format.js CHANGED
@@ -66,26 +66,26 @@ export function formatText(text, maxLength, shouldParseJSDocTags = true) {
66
66
  // Append the blank line, but ignore multiple blank lines in a row (unless we are inside of a
67
67
  // code block).
68
68
  const lastCharacter = formattedText.at(-1);
69
- if ((lastCharacter !== undefined && lastCharacter !== "\n") ||
70
- insideCodeBlock) {
69
+ if ((lastCharacter !== undefined && lastCharacter !== "\n")
70
+ || insideCodeBlock) {
71
71
  formattedText += "\n";
72
72
  }
73
73
  insideList = undefined;
74
74
  continue;
75
75
  }
76
76
  // Handle code blocks. This case is simple because we need to exactly preserve the text.
77
- if (hasCodeBlock ||
78
- previousLineHasCodeBlock ||
79
- insideCodeBlock ||
80
- insideExampleTagBlock) {
77
+ if (hasCodeBlock
78
+ || previousLineHasCodeBlock
79
+ || insideCodeBlock
80
+ || insideExampleTagBlock) {
81
81
  // Append the partial line that we were building, if any.
82
82
  [formattedLine, formattedText] = appendLineToText(formattedLine, formattedText);
83
83
  // Enforce newlines before the beginning of code blocks. (But not inside of an example code
84
84
  // block, because there should not be newlines between tags.)
85
- if (hasCodeBlock &&
86
- !previousLineInsideCodeBlock &&
87
- !previousLineWasBlank &&
88
- !insideExampleTagBlock) {
85
+ if (hasCodeBlock
86
+ && !previousLineInsideCodeBlock
87
+ && !previousLineWasBlank
88
+ && !insideExampleTagBlock) {
89
89
  formattedText += "\n";
90
90
  }
91
91
  // Copy the line exactly.
@@ -94,10 +94,10 @@ export function formatText(text, maxLength, shouldParseJSDocTags = true) {
94
94
  // because there should not be newlines between tags.)
95
95
  const nextLine = lines[i + 1];
96
96
  const nextLineIsBlank = nextLine === undefined || nextLine.trim() === "";
97
- if (hasCodeBlock &&
98
- previousLineInsideCodeBlock &&
99
- !nextLineIsBlank &&
100
- !insideExampleTagBlock) {
97
+ if (hasCodeBlock
98
+ && previousLineInsideCodeBlock
99
+ && !nextLineIsBlank
100
+ && !insideExampleTagBlock) {
101
101
  // Append the partial line that we were building, if any.
102
102
  [formattedLine, formattedText] = appendLineToText(formattedLine, formattedText);
103
103
  formattedText += "\n";
@@ -131,30 +131,30 @@ export function formatText(text, maxLength, shouldParseJSDocTags = true) {
131
131
  }
132
132
  // Lists and some other specific text elements indicate that we should always insert a new line,
133
133
  // even if the text has no wrapped to the end of the ruler yet.
134
- if (list !== undefined ||
135
- lineHasURL ||
136
- previousLineHadURL ||
137
- hasExample ||
138
- separatorLine ||
139
- previousLineWasSeparatorLine ||
140
- enumBlockLabel ||
141
- previousLineWasEnumBlockLabel) {
134
+ if (list !== undefined
135
+ || lineHasURL
136
+ || previousLineHadURL
137
+ || hasExample
138
+ || separatorLine
139
+ || previousLineWasSeparatorLine
140
+ || enumBlockLabel
141
+ || previousLineWasEnumBlockLabel) {
142
142
  // Append the partial line that we were building, if any.
143
143
  [formattedLine, formattedText] = appendLineToText(formattedLine, formattedText);
144
144
  }
145
145
  // Keep track of when we first encounter JSDoc tags. (JSDoc comments can be thought of as having
146
146
  // an "description" or "introductory" section at the top, and then a list of JSDoc tags at the
147
147
  // bottom.)
148
- if (shouldParseJSDocTags &&
149
- !encounteredJSDocTags &&
150
- list !== undefined &&
151
- list.kind === ListKind.JSDocTag) {
148
+ if (shouldParseJSDocTags
149
+ && !encounteredJSDocTags
150
+ && list !== undefined
151
+ && list.kind === ListKind.JSDocTag) {
152
152
  encounteredJSDocTags = true;
153
153
  // Enforce a newline between a JSDoc description (i.e. introductory text) and the first JSDoc
154
154
  // tag.
155
- if (!stringContainsOnlyWhitespace(formattedText) &&
156
- !previousLineWasBlank &&
157
- !previousLineInsideExampleTagBlock) {
155
+ if (!stringContainsOnlyWhitespace(formattedText)
156
+ && !previousLineWasBlank
157
+ && !previousLineInsideExampleTagBlock) {
158
158
  // Append the partial line that we were building, if any.
159
159
  [formattedLine, formattedText] = appendLineToText(formattedLine, formattedText);
160
160
  formattedText += "\n";
@@ -226,10 +226,10 @@ function appendLineToText(formattedLine, formattedText) {
226
226
  }
227
227
  function startsWithExample(text) {
228
228
  const trimmedText = text.trimStart();
229
- return (trimmedText.startsWith("e.g. ") ||
230
- trimmedText.startsWith("(e.g. ") ||
231
- trimmedText.startsWith("i.e. ") ||
232
- trimmedText.startsWith("(i.e. "));
229
+ return (trimmedText.startsWith("e.g. ")
230
+ || trimmedText.startsWith("(e.g. ")
231
+ || trimmedText.startsWith("i.e. ")
232
+ || trimmedText.startsWith("(i.e. "));
233
233
  }
234
234
  function stringContainsOnlyWhitespace(string) {
235
235
  return string.trim() === "";
package/dist/jsdoc.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { TSESTree } from "@typescript-eslint/utils";
2
2
  export function getJSDocComments(comments) {
3
- return comments.filter((comment) => comment.type === TSESTree.AST_TOKEN_TYPES.Block && // i.e. a "/*" comment
4
- comment.value.startsWith("*"));
3
+ return comments.filter((comment) => comment.type === TSESTree.AST_TOKEN_TYPES.Block // i.e. a "/*" comment
4
+ && comment.value.startsWith("*"));
5
5
  }
6
6
  export function getTextFromJSDocComment(comment) {
7
7
  comment = comment.trim();
@@ -1,10 +1,10 @@
1
1
  import { TSESTree } from "@typescript-eslint/utils";
2
2
  import { isCommentOnOwnLine, isSeparatorLine } from "./comments.js";
3
3
  export function getLeadingLineComments(sourceCode, comments) {
4
- return comments.filter((comment) => comment.type === TSESTree.AST_TOKEN_TYPES.Line && // i.e. a "//" comment
5
- comment.value.trim() !== "" &&
6
- !comment.value.startsWith("/") && // Filter out triple slash directives
7
- isCommentOnOwnLine(sourceCode, comment));
4
+ return comments.filter((comment) => comment.type === TSESTree.AST_TOKEN_TYPES.Line // i.e. a "//" comment
5
+ && comment.value.trim() !== ""
6
+ && !comment.value.startsWith("/") // Filter out triple slash directives
7
+ && isCommentOnOwnLine(sourceCode, comment));
8
8
  }
9
9
  /**
10
10
  * Returns an array of grouped comments. For example, the following code would return an array of
package/dist/list.js CHANGED
@@ -60,9 +60,9 @@ function getList(line) {
60
60
  }
61
61
  /** e.g. "1. A bullet point can start with a number and a period." */
62
62
  const numberPeriodMatch = line.match(/^(\d+)\. /);
63
- if (numberPeriodMatch !== null &&
64
- numberPeriodMatch[1] !== undefined &&
65
- numberPeriodMatch[1] !== "0") {
63
+ if (numberPeriodMatch !== null
64
+ && numberPeriodMatch[1] !== undefined
65
+ && numberPeriodMatch[1] !== "0") {
66
66
  return {
67
67
  kind: ListKind.NumberPeriod,
68
68
  numLeadingSpaces,
@@ -71,9 +71,9 @@ function getList(line) {
71
71
  }
72
72
  /** e.g. "1) A bullet point can start with a number and a parenthesis." */
73
73
  const numberParenthesisMatch = line.match(/^(\d+)\) /);
74
- if (numberParenthesisMatch !== null &&
75
- numberParenthesisMatch[1] !== undefined &&
76
- numberParenthesisMatch[1] !== "0") {
74
+ if (numberParenthesisMatch !== null
75
+ && numberParenthesisMatch[1] !== undefined
76
+ && numberParenthesisMatch[1] !== "0") {
77
77
  return {
78
78
  kind: ListKind.NumberParenthesis,
79
79
  numLeadingSpaces,
@@ -133,8 +133,8 @@ export function reachedNewList(insideList, list) {
133
133
  if (list === undefined) {
134
134
  return false;
135
135
  }
136
- return (insideList === undefined || // Going from a non-list to list
137
- insideList.numLeadingSpaces !== list.numLeadingSpaces || // Going from a list to a sub-list
138
- insideList.jsDocTagName !== list.jsDocTagName // Going from a JSDoc to a different JSDoc tag
136
+ return (insideList === undefined // Going from a non-list to list
137
+ || insideList.numLeadingSpaces !== list.numLeadingSpaces // Going from a list to a sub-list
138
+ || insideList.jsDocTagName !== list.jsDocTagName // Going from a JSDoc to a different JSDoc tag
139
139
  );
140
140
  }
@@ -39,13 +39,13 @@ export const completeSentencesLineComments = createRule({
39
39
  }
40
40
  // Comments in-between "separator lines" are whitelisted.
41
41
  const previousCommentBlock = commentBlocks[i - 1];
42
- if (previousCommentBlock !== undefined &&
43
- isSeparatorLine(previousCommentBlock.mergedText)) {
42
+ if (previousCommentBlock !== undefined
43
+ && isSeparatorLine(previousCommentBlock.mergedText)) {
44
44
  continue;
45
45
  }
46
46
  const nextCommentBlock = commentBlocks[i + 1];
47
- if (nextCommentBlock !== undefined &&
48
- isSeparatorLine(nextCommentBlock.mergedText)) {
47
+ if (nextCommentBlock !== undefined
48
+ && isSeparatorLine(nextCommentBlock.mergedText)) {
49
49
  continue;
50
50
  }
51
51
  // Unlike JSDoc comments, we want to whitelist comment blocks that begin with JavaScript
@@ -98,9 +98,9 @@ export const formatJSDocComments = createRule({
98
98
  */
99
99
  function canFitOnSingleJSDocLine(text, effectiveMaxLength) {
100
100
  const textLines = text.split("\n");
101
- return (textLines.length === 1 &&
102
- text.length + EXTRA_NUM_CHARACTERS_TO_FIT_ON_JSDOC_SINGLE_LINE <=
103
- effectiveMaxLength);
101
+ return (textLines.length === 1
102
+ && text.length + EXTRA_NUM_CHARACTERS_TO_FIT_ON_JSDOC_SINGLE_LINE
103
+ <= effectiveMaxLength);
104
104
  }
105
105
  function getJSDocCommentSingleLine(text, leftWhitespace) {
106
106
  return `${leftWhitespace}/** ${text} */`;
@@ -23,8 +23,8 @@ export const noEmptyLineComments = createRule({
23
23
  */
24
24
  create(context) {
25
25
  const comments = context.sourceCode.getAllComments();
26
- const emptyLeadingLineComments = comments.filter((comment) => comment.type === TSESTree.AST_TOKEN_TYPES.Line && // i.e. a "//" comment
27
- comment.value.trim() === "");
26
+ const emptyLeadingLineComments = comments.filter((comment) => comment.type === TSESTree.AST_TOKEN_TYPES.Line // i.e. a "//" comment
27
+ && comment.value.trim() === "");
28
28
  for (const comment of emptyLeadingLineComments) {
29
29
  context.report({
30
30
  loc: {
@@ -53,9 +53,9 @@ function getErrorMessageId(type) {
53
53
  return undefined;
54
54
  }
55
55
  // Handle unwrapping promises.
56
- if (typeName === "Promise" &&
57
- isTypeReferenceType(type) &&
58
- type.typeArguments !== undefined) {
56
+ if (typeName === "Promise"
57
+ && isTypeReferenceType(type)
58
+ && type.typeArguments !== undefined) {
59
59
  const typeArgument = type.typeArguments[0];
60
60
  if (typeArgument !== undefined) {
61
61
  return getErrorMessageId(typeArgument);
@@ -46,14 +46,14 @@ export const noObjectMethodsWithMapSet = createRule({
46
46
  }
47
47
  // Second, check if the object is `Object`.
48
48
  const { object } = callee;
49
- if (object.type !== AST_NODE_TYPES.Identifier ||
50
- object.name !== "Object") {
49
+ if (object.type !== AST_NODE_TYPES.Identifier
50
+ || object.name !== "Object") {
51
51
  return;
52
52
  }
53
53
  // Third, check if this is one of the problem methods.
54
54
  const { property } = callee;
55
- if (property.type !== AST_NODE_TYPES.Identifier ||
56
- !PROBLEM_METHODS.has(property.name)) {
55
+ if (property.type !== AST_NODE_TYPES.Identifier
56
+ || !PROBLEM_METHODS.has(property.name)) {
57
57
  return;
58
58
  }
59
59
  const methodName = property.name;
@@ -24,8 +24,8 @@ export const noStringLength0 = createRule({
24
24
  if (node.type !== AST_NODE_TYPES.MemberExpression) {
25
25
  return false;
26
26
  }
27
- if (node.property.type !== AST_NODE_TYPES.Identifier ||
28
- node.property.name !== "length") {
27
+ if (node.property.type !== AST_NODE_TYPES.Identifier
28
+ || node.property.name !== "length") {
29
29
  return false;
30
30
  }
31
31
  const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node.object);
@@ -36,8 +36,8 @@ export const noStringLength0 = createRule({
36
36
  }
37
37
  return {
38
38
  BinaryExpression(node) {
39
- if ((is0(node.left) && isStringLength(node.right)) ||
40
- (is0(node.right) && isStringLength(node.left))) {
39
+ if ((is0(node.left) && isStringLength(node.right))
40
+ || (is0(node.right) && isStringLength(node.left))) {
41
41
  context.report({
42
42
  node,
43
43
  messageId: "noStringLength0",
@@ -23,8 +23,8 @@ export const noTemplateCurlyInStringFix = createRule({
23
23
  create(context) {
24
24
  return {
25
25
  Literal(node) {
26
- if (typeof node.value === "string" &&
27
- ERRONEOUS_TEMPLATE_STRING_REGEX.test(node.value)) {
26
+ if (typeof node.value === "string"
27
+ && ERRONEOUS_TEMPLATE_STRING_REGEX.test(node.value)) {
28
28
  context.report({
29
29
  node,
30
30
  messageId: "unexpectedTemplateExpression",
@@ -97,8 +97,8 @@ export const noUnnecessaryAssignment = createRule({
97
97
  const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
98
98
  const type = checker.getTypeAtLocation(tsNode);
99
99
  const types = unionTypeParts(type);
100
- return (types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Null)) &&
101
- !types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Undefined)));
100
+ return (types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Null))
101
+ && !types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Undefined)));
102
102
  }
103
103
  function hasUndefinedAndNotNull(node) {
104
104
  if (isUndefined(node)) {
@@ -107,8 +107,8 @@ export const noUnnecessaryAssignment = createRule({
107
107
  const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
108
108
  const type = checker.getTypeAtLocation(tsNode);
109
109
  const types = unionTypeParts(type);
110
- return (types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Undefined)) &&
111
- !types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Null)));
110
+ return (types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Undefined))
111
+ && !types.some((t) => isFlagSet(t.flags, ts.TypeFlags.Null)));
112
112
  }
113
113
  function checkEqualSign(node) {
114
114
  const leftTSNode = parserServices.esTreeNodeToTSNodeMap.get(node.left);
@@ -129,9 +129,9 @@ export const noUnnecessaryAssignment = createRule({
129
129
  if (node.operator === "=") {
130
130
  checkEqualSign(node);
131
131
  }
132
- else if (USELESS_ASSIGNMENT_OPERATORS_WITH_ZERO.has(node.operator) &&
133
- isNumber(node.left) &&
134
- isLiteralZero(node.right)) {
132
+ else if (USELESS_ASSIGNMENT_OPERATORS_WITH_ZERO.has(node.operator)
133
+ && isNumber(node.left)
134
+ && isLiteralZero(node.right)) {
135
135
  context.report({
136
136
  loc: node.loc,
137
137
  messageId: "unnecessaryZero",
@@ -140,9 +140,9 @@ export const noUnnecessaryAssignment = createRule({
140
140
  },
141
141
  });
142
142
  }
143
- else if (node.operator === "+=" &&
144
- isString(node.left) &&
145
- isLiteralEmptyString(node.right)) {
143
+ else if (node.operator === "+="
144
+ && isString(node.left)
145
+ && isLiteralEmptyString(node.right)) {
146
146
  context.report({
147
147
  loc: node.loc,
148
148
  messageId: "unnecessaryEmptyString",
@@ -150,9 +150,9 @@ export const noUnnecessaryAssignment = createRule({
150
150
  }
151
151
  },
152
152
  BinaryExpression(node) {
153
- if (USELESS_OPERATORS_WITH_ZERO.has(node.operator) &&
154
- ((isNumber(node.left) && isLiteralZero(node.right)) ||
155
- (isNumber(node.right) && isLiteralZero(node.left)))) {
153
+ if (USELESS_OPERATORS_WITH_ZERO.has(node.operator)
154
+ && ((isNumber(node.left) && isLiteralZero(node.right))
155
+ || (isNumber(node.right) && isLiteralZero(node.left)))) {
156
156
  context.report({
157
157
  loc: node.loc,
158
158
  messageId: "unnecessaryZero",
@@ -162,9 +162,9 @@ export const noUnnecessaryAssignment = createRule({
162
162
  });
163
163
  }
164
164
  // Plus is the only operator valid for strings.
165
- if (node.operator === "+" &&
166
- ((isString(node.left) && isLiteralEmptyString(node.right)) ||
167
- (isString(node.right) && isLiteralEmptyString(node.left)))) {
165
+ if (node.operator === "+"
166
+ && ((isString(node.left) && isLiteralEmptyString(node.right))
167
+ || (isString(node.right) && isLiteralEmptyString(node.left)))) {
168
168
  context.report({
169
169
  loc: node.loc,
170
170
  messageId: "unnecessaryEmptyString",
@@ -173,13 +173,13 @@ export const noUnnecessaryAssignment = createRule({
173
173
  },
174
174
  LogicalExpression(node) {
175
175
  const { parent } = node;
176
- if (parent.type !== AST_NODE_TYPES.AssignmentExpression &&
177
- parent.type !== AST_NODE_TYPES.VariableDeclarator) {
176
+ if (parent.type !== AST_NODE_TYPES.AssignmentExpression
177
+ && parent.type !== AST_NODE_TYPES.VariableDeclarator) {
178
178
  return;
179
179
  }
180
- if (node.operator === "||" &&
181
- isBoolean(node.left) &&
182
- isFalse(node.right)) {
180
+ if (node.operator === "||"
181
+ && isBoolean(node.left)
182
+ && isFalse(node.right)) {
183
183
  context.report({
184
184
  loc: node.loc,
185
185
  messageId: "unnecessaryShortCircuit",
@@ -188,9 +188,9 @@ export const noUnnecessaryAssignment = createRule({
188
188
  },
189
189
  });
190
190
  }
191
- if (node.operator === "&&" &&
192
- isBoolean(node.left) &&
193
- isTrue(node.right)) {
191
+ if (node.operator === "&&"
192
+ && isBoolean(node.left)
193
+ && isTrue(node.right)) {
194
194
  context.report({
195
195
  loc: node.loc,
196
196
  messageId: "unnecessaryShortCircuit",
@@ -199,9 +199,9 @@ export const noUnnecessaryAssignment = createRule({
199
199
  },
200
200
  });
201
201
  }
202
- if (node.operator === "||" &&
203
- isNumber(node.left) &&
204
- isZero(node.right)) {
202
+ if (node.operator === "||"
203
+ && isNumber(node.left)
204
+ && isZero(node.right)) {
205
205
  context.report({
206
206
  loc: node.loc,
207
207
  messageId: "unnecessaryShortCircuit",
@@ -210,9 +210,9 @@ export const noUnnecessaryAssignment = createRule({
210
210
  },
211
211
  });
212
212
  }
213
- if (node.operator === "||" &&
214
- isString(node.left) &&
215
- isEmptyString(node.right)) {
213
+ if (node.operator === "||"
214
+ && isString(node.left)
215
+ && isEmptyString(node.right)) {
216
216
  context.report({
217
217
  loc: node.loc,
218
218
  messageId: "unnecessaryShortCircuit",
@@ -221,9 +221,9 @@ export const noUnnecessaryAssignment = createRule({
221
221
  },
222
222
  });
223
223
  }
224
- if (node.operator === "??" &&
225
- hasNullAndNotUndefined(node.left) &&
226
- isNull(node.right)) {
224
+ if (node.operator === "??"
225
+ && hasNullAndNotUndefined(node.left)
226
+ && isNull(node.right)) {
227
227
  context.report({
228
228
  loc: node.loc,
229
229
  messageId: "unnecessaryShortCircuit",
@@ -232,9 +232,9 @@ export const noUnnecessaryAssignment = createRule({
232
232
  },
233
233
  });
234
234
  }
235
- if (node.operator === "??" &&
236
- hasUndefinedAndNotNull(node.left) &&
237
- isUndefined(node.right)) {
235
+ if (node.operator === "??"
236
+ && hasUndefinedAndNotNull(node.left)
237
+ && isUndefined(node.right)) {
238
238
  context.report({
239
239
  loc: node.loc,
240
240
  messageId: "unnecessaryShortCircuit",
@@ -23,9 +23,9 @@ export const noVoidReturnType = createRule({
23
23
  const { parent } = node;
24
24
  if (
25
25
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
26
- parent !== undefined &&
27
- (parent.type === AST_NODE_TYPES.ExportNamedDeclaration ||
28
- parent.type === AST_NODE_TYPES.ExportDefaultDeclaration)) {
26
+ parent !== undefined
27
+ && (parent.type === AST_NODE_TYPES.ExportNamedDeclaration
28
+ || parent.type === AST_NODE_TYPES.ExportDefaultDeclaration)) {
29
29
  return;
30
30
  }
31
31
  const { returnType } = node;
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-readonly-parameter-types.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-readonly-parameter-types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAY1E,KAAK,OAAO,GAAG;IACb;QACE,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAC;QAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,wBAAwB,CAAC,EAAE,OAAO,CAAC;KACpC;CACF,CAAC;AAGF,eAAO,MAAM,4BAA4B,6MA4LvC,CAAC"}
1
+ {"version":3,"file":"prefer-readonly-parameter-types.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-readonly-parameter-types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAY1E,KAAK,OAAO,GAAG;IACb;QACE,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAC;QAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,wBAAwB,CAAC,EAAE,OAAO,CAAC;KACpC;CACF,CAAC;AAGF,eAAO,MAAM,4BAA4B,6MA6MvC,CAAC"}
@@ -71,16 +71,28 @@ export const preferReadonlyParameterTypes = createRule({
71
71
  AST_NODE_TYPES.TSFunctionType,
72
72
  AST_NODE_TYPES.TSMethodSignature,
73
73
  ].join(", ")](node) {
74
+ // Early return in the special case of a map method. (This would result in an unfixable lint
75
+ // error.)
76
+ if (node.type === AST_NODE_TYPES.ArrowFunctionExpression
77
+ || node.type === AST_NODE_TYPES.FunctionExpression) {
78
+ const { parent } = node;
79
+ if (parent.type === AST_NODE_TYPES.CallExpression
80
+ && parent.callee.type === AST_NODE_TYPES.MemberExpression
81
+ && parent.callee.property.type === AST_NODE_TYPES.Identifier
82
+ && parent.callee.property.name === "map") {
83
+ return;
84
+ }
85
+ }
74
86
  for (const param of node.params) {
75
- if (checkParameterProperties === false &&
76
- param.type === AST_NODE_TYPES.TSParameterProperty) {
87
+ if (checkParameterProperties === false
88
+ && param.type === AST_NODE_TYPES.TSParameterProperty) {
77
89
  continue;
78
90
  }
79
91
  const actualParam = param.type === AST_NODE_TYPES.TSParameterProperty
80
92
  ? param.parameter
81
93
  : param;
82
- if (ignoreInferredTypes === true &&
83
- actualParam.typeAnnotation === undefined) {
94
+ if (ignoreInferredTypes === true
95
+ && actualParam.typeAnnotation === undefined) {
84
96
  continue;
85
97
  }
86
98
  const type = services.getTypeAtLocation(actualParam);
@@ -89,10 +101,10 @@ export const preferReadonlyParameterTypes = createRule({
89
101
  const parts = unionTypeParts(type);
90
102
  const hasAllBasicDataStructures = parts.every((t) => {
91
103
  const typeName = getTypeName(t);
92
- return (typeName === "Array" ||
93
- typeName === "Map" ||
94
- typeName === "Set" ||
95
- typeName === "Record");
104
+ return (typeName === "Array"
105
+ || typeName === "Map"
106
+ || typeName === "Set"
107
+ || typeName === "Record");
96
108
  });
97
109
  if (!hasAllBasicDataStructures) {
98
110
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"require-variadic-function-argument.d.ts","sourceRoot":"","sources":["../../src/rules/require-variadic-function-argument.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAIvE,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,YAAY,CAAC;AAItC,eAAO,MAAM,+BAA+B,0HA8D1C,CAAC"}
1
+ {"version":3,"file":"require-variadic-function-argument.d.ts","sourceRoot":"","sources":["../../src/rules/require-variadic-function-argument.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAIvE,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,YAAY,CAAC;AAatC,eAAO,MAAM,+BAA+B,0HA8D1C,CAAC"}
@@ -2,6 +2,14 @@ import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
2
  import ts from "typescript";
3
3
  import { createRule } from "../utils.js";
4
4
  const JSDOC_EXCEPTION_TAG = "allowEmptyVariadic";
5
+ const LOGGER_METHOD_NAMES = new Set([
6
+ "trace",
7
+ "debug",
8
+ "info",
9
+ "warn",
10
+ "error",
11
+ "fatal",
12
+ ]);
5
13
  export const requireVariadicFunctionArgument = createRule({
6
14
  name: "require-variadic-function-argument",
7
15
  meta: {
@@ -34,8 +42,8 @@ export const requireVariadicFunctionArgument = createRule({
34
42
  if (declaration === undefined) {
35
43
  return;
36
44
  }
37
- if (isHardCodedException(node) ||
38
- hasJSDocExceptionTag(checker, declaration)) {
45
+ if (isHardCodedException(node)
46
+ || hasJSDocExceptionTag(checker, declaration)) {
39
47
  return;
40
48
  }
41
49
  for (let i = 0; i < declaration.parameters.length; i++) {
@@ -43,8 +51,8 @@ export const requireVariadicFunctionArgument = createRule({
43
51
  if (parameter === undefined) {
44
52
  continue;
45
53
  }
46
- if (ts.isRestParameter(parameter) &&
47
- node.arguments[i] === undefined) {
54
+ if (ts.isRestParameter(parameter)
55
+ && node.arguments[i] === undefined) {
48
56
  context.report({
49
57
  loc: node.loc,
50
58
  messageId: "noArgument",
@@ -57,7 +65,20 @@ export const requireVariadicFunctionArgument = createRule({
57
65
  });
58
66
  function isHardCodedException(node) {
59
67
  const { callee } = node;
60
- return isConsoleOrWindowOrLoggerFunction(callee) || isTimeoutFunction(callee);
68
+ const methodName = getMethodName(callee) ?? "unknown";
69
+ return (isConsoleOrWindowOrLoggerFunction(callee)
70
+ || isTimeoutFunction(callee)
71
+ || LOGGER_METHOD_NAMES.has(methodName));
72
+ }
73
+ function getMethodName(node) {
74
+ if (node.type !== AST_NODE_TYPES.MemberExpression) {
75
+ return undefined;
76
+ }
77
+ const { property } = node;
78
+ if (property.type !== AST_NODE_TYPES.Identifier) {
79
+ return undefined;
80
+ }
81
+ return property.name;
61
82
  }
62
83
  /**
63
84
  * This rule has a false positive with any logger function. (Both `console.log` and logger functions
@@ -73,9 +94,9 @@ function isConsoleOrWindowOrLoggerFunction(callee) {
73
94
  if (object.type !== AST_NODE_TYPES.Identifier) {
74
95
  return false;
75
96
  }
76
- return (object.name === "console" ||
77
- object.name === "window" ||
78
- object.name === "logger");
97
+ return (object.name === "console"
98
+ || object.name === "window"
99
+ || object.name === "logger");
79
100
  }
80
101
  function isTimeoutFunction(callee) {
81
102
  if (callee.type !== AST_NODE_TYPES.Identifier) {
@@ -60,9 +60,9 @@ export const strictArrayMethods = createRule({
60
60
  for (const callSignature of callSignatures) {
61
61
  const returnType = callSignature.getReturnType();
62
62
  const returnTypeName = getTypeName(returnType);
63
- if (returnTypeName !== "boolean" &&
64
- returnTypeName !== "true" &&
65
- returnTypeName !== "false") {
63
+ if (returnTypeName !== "boolean"
64
+ && returnTypeName !== "true"
65
+ && returnTypeName !== "false") {
66
66
  return false;
67
67
  }
68
68
  }
@@ -70,8 +70,8 @@ export const strictArrayMethods = createRule({
70
70
  }
71
71
  return {
72
72
  CallExpression(node) {
73
- if (isArrayMethodInvocationWithBooleanFunction(node) &&
74
- !firstArgumentHasBooleanReturnType(node)) {
73
+ if (isArrayMethodInvocationWithBooleanFunction(node)
74
+ && !firstArgumentHasBooleanReturnType(node)) {
75
75
  context.report({
76
76
  loc: node.loc,
77
77
  messageId: "conditionError",
@@ -3,10 +3,10 @@ import { ESLintUtils } from "@typescript-eslint/utils";
3
3
  import ts from "typescript";
4
4
  import { isSymbolFlagSet, isTypeFlagSet, unionTypeParts, } from "../typeUtils.js";
5
5
  import { createRule } from "../utils.js";
6
- const ALLOWED_TYPES_FOR_ANY_ENUM_ARGUMENT = ts.TypeFlags.Any |
7
- ts.TypeFlags.Unknown |
8
- ts.TypeFlags.Number |
9
- ts.TypeFlags.String;
6
+ const ALLOWED_TYPES_FOR_ANY_ENUM_ARGUMENT = ts.TypeFlags.Any
7
+ | ts.TypeFlags.Unknown
8
+ | ts.TypeFlags.Number
9
+ | ts.TypeFlags.String;
10
10
  export const strictEnums = createRule({
11
11
  name: "strict-enums",
12
12
  meta: {
@@ -187,8 +187,8 @@ export const strictEnums = createRule({
187
187
  for (let i = 0; i < leftTypeArguments.length; i++) {
188
188
  const leftTypeArgument = leftTypeArguments[i];
189
189
  const rightTypeArgument = rightTypeArguments[i];
190
- if (leftTypeArgument === undefined ||
191
- rightTypeArgument === undefined) {
190
+ if (leftTypeArgument === undefined
191
+ || rightTypeArgument === undefined) {
192
192
  continue;
193
193
  }
194
194
  if (isAssigningNonEnumValueToEnumVariable(leftTypeArgument, rightTypeArgument)) {
@@ -235,8 +235,8 @@ export const strictEnums = createRule({
235
235
  for (let i = 0; i < argumentTypeArguments.length; i++) {
236
236
  const argumentTypeArgument = argumentTypeArguments[i];
237
237
  const parameterTypeArgument = parameterTypeArguments[i];
238
- if (argumentTypeArgument === undefined ||
239
- parameterTypeArgument === undefined) {
238
+ if (argumentTypeArgument === undefined
239
+ || parameterTypeArgument === undefined) {
240
240
  continue;
241
241
  }
242
242
  if (isMismatchedEnumFunctionArgument(argumentTypeArgument, parameterTypeArgument)) {
@@ -286,10 +286,10 @@ export const strictEnums = createRule({
286
286
  */
287
287
  const argumentSubTypes = unionTypeParts(argumentType);
288
288
  for (const argumentSubType of argumentSubTypes) {
289
- if (argumentSubType.isLiteral() &&
290
- !isEnum(argumentSubType) &&
289
+ if (argumentSubType.isLiteral()
290
+ && !isEnum(argumentSubType)
291
291
  // Allow passing number literals if there are number literals in the actual function type.
292
- !parameterSubTypes.includes(argumentSubType)) {
292
+ && !parameterSubTypes.includes(argumentSubType)) {
293
293
  return true;
294
294
  }
295
295
  }
@@ -429,11 +429,11 @@ function isEnum(type) {
429
429
  return isTypeFlagSet(type, ts.TypeFlags.EnumLiteral);
430
430
  }
431
431
  function isNullOrUndefinedOrAnyOrUnknownOrNever(...types) {
432
- return types.some((type) => isTypeFlagSet(type, ts.TypeFlags.Null |
433
- ts.TypeFlags.Undefined |
434
- ts.TypeFlags.Any |
435
- ts.TypeFlags.Unknown |
436
- ts.TypeFlags.Never));
432
+ return types.some((type) => isTypeFlagSet(type, ts.TypeFlags.Null
433
+ | ts.TypeFlags.Undefined
434
+ | ts.TypeFlags.Any
435
+ | ts.TypeFlags.Unknown
436
+ | ts.TypeFlags.Never));
437
437
  }
438
438
  function setHasAnyElementFromSet(set1, set2) {
439
439
  for (const value of set2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-complete",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "An ESLint plugin that contains useful rules.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -44,9 +44,9 @@
44
44
  "test": "jest"
45
45
  },
46
46
  "dependencies": {
47
- "@typescript-eslint/type-utils": "8.24.1",
48
- "@typescript-eslint/utils": "8.24.1",
49
- "typescript-eslint": "8.24.1"
47
+ "@typescript-eslint/type-utils": "8.25.0",
48
+ "@typescript-eslint/utils": "8.25.0",
49
+ "typescript-eslint": "8.25.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@babel/core": "7.26.9",
@@ -54,10 +54,10 @@
54
54
  "@babel/preset-typescript": "7.26.0",
55
55
  "@types/jest": "29.5.14",
56
56
  "@types/node": "22.13.5",
57
- "@typescript-eslint/rule-tester": "8.24.1",
58
- "@typescript-eslint/types": "8.24.1",
59
- "complete-common": "^1.1.1",
60
- "complete-node": "^3.0.1",
57
+ "@typescript-eslint/rule-tester": "8.25.0",
58
+ "@typescript-eslint/types": "8.25.0",
59
+ "complete-common": "1.3.0",
60
+ "complete-node": "3.1.8",
61
61
  "jest": "29.7.0",
62
62
  "prettier": "3.5.2",
63
63
  "typescript": "5.7.3"