eslint 8.19.0 → 8.20.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.
package/README.md CHANGED
@@ -45,21 +45,15 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
45
45
 
46
46
  Prerequisites: [Node.js](https://nodejs.org/) (`^12.22.0`, `^14.17.0`, or `>=16.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
47
47
 
48
- You can install ESLint using npm:
48
+ You can install and configure ESLint using this command:
49
49
 
50
- ```sh
51
- npm install eslint --save-dev
52
- ```
53
-
54
- You should then set up a configuration file:
55
-
56
- ```sh
50
+ ```shell
57
51
  npm init @eslint/config
58
52
  ```
59
53
 
60
54
  After that, you can run ESLint on any file or directory like this:
61
55
 
62
- ```sh
56
+ ```shell
63
57
  ./node_modules/.bin/eslint yourfile.js
64
58
  ```
65
59
 
@@ -1510,7 +1510,31 @@ class Linter {
1510
1510
  options.filterCodeBlock ||
1511
1511
  (blockFilename => blockFilename.endsWith(".js"));
1512
1512
  const originalExtname = path.extname(filename);
1513
- const messageLists = preprocess(text, filenameToExpose).map((block, i) => {
1513
+
1514
+ let blocks;
1515
+
1516
+ try {
1517
+ blocks = preprocess(text, filenameToExpose);
1518
+ } catch (ex) {
1519
+
1520
+ // If the message includes a leading line number, strip it:
1521
+ const message = `Preprocessing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
1522
+
1523
+ debug("%s\n%s", message, ex.stack);
1524
+
1525
+ return [
1526
+ {
1527
+ ruleId: null,
1528
+ fatal: true,
1529
+ severity: 2,
1530
+ message,
1531
+ line: ex.lineNumber,
1532
+ column: ex.column
1533
+ }
1534
+ ];
1535
+ }
1536
+
1537
+ const messageLists = blocks.map((block, i) => {
1514
1538
  debug("A code block was found: %o", block.filename || "(unnamed)");
1515
1539
 
1516
1540
  // Keep the legacy behavior.
@@ -1788,13 +1812,36 @@ class Linter {
1788
1812
  const physicalFilename = options.physicalFilename || filenameToExpose;
1789
1813
  const text = ensureText(textOrSourceCode);
1790
1814
  const preprocess = options.preprocess || (rawText => [rawText]);
1791
-
1792
1815
  const postprocess = options.postprocess || (messagesList => messagesList.flat());
1793
1816
  const filterCodeBlock =
1794
1817
  options.filterCodeBlock ||
1795
1818
  (blockFilename => blockFilename.endsWith(".js"));
1796
1819
  const originalExtname = path.extname(filename);
1797
- const messageLists = preprocess(text, filenameToExpose).map((block, i) => {
1820
+
1821
+ let blocks;
1822
+
1823
+ try {
1824
+ blocks = preprocess(text, filenameToExpose);
1825
+ } catch (ex) {
1826
+
1827
+ // If the message includes a leading line number, strip it:
1828
+ const message = `Preprocessing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
1829
+
1830
+ debug("%s\n%s", message, ex.stack);
1831
+
1832
+ return [
1833
+ {
1834
+ ruleId: null,
1835
+ fatal: true,
1836
+ severity: 2,
1837
+ message,
1838
+ line: ex.lineNumber,
1839
+ column: ex.column
1840
+ }
1841
+ ];
1842
+ }
1843
+
1844
+ const messageLists = blocks.map((block, i) => {
1798
1845
  debug("A code block was found: %o", block.filename || "(unnamed)");
1799
1846
 
1800
1847
  // Keep the legacy behavior.
@@ -103,38 +103,6 @@ module.exports = {
103
103
  });
104
104
  }
105
105
 
106
- /**
107
- * Validates the spacing around a comma token.
108
- * @param {Object} tokens The tokens to be validated.
109
- * @param {Token} tokens.comma The token representing the comma.
110
- * @param {Token} [tokens.left] The last token before the comma.
111
- * @param {Token} [tokens.right] The first token after the comma.
112
- * @param {Token|ASTNode} reportItem The item to use when reporting an error.
113
- * @returns {void}
114
- * @private
115
- */
116
- function validateCommaItemSpacing(tokens, reportItem) {
117
- if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
118
- (options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
119
- ) {
120
- report(reportItem, "before", tokens.left);
121
- }
122
-
123
- if (tokens.right && astUtils.isClosingParenToken(tokens.right)) {
124
- return;
125
- }
126
-
127
- if (tokens.right && !options.after && tokens.right.type === "Line") {
128
- return;
129
- }
130
-
131
- if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
132
- (options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
133
- ) {
134
- report(reportItem, "after", tokens.right);
135
- }
136
- }
137
-
138
106
  /**
139
107
  * Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list.
140
108
  * @param {ASTNode} node An ArrayExpression or ArrayPattern node.
@@ -172,18 +140,44 @@ module.exports = {
172
140
  return;
173
141
  }
174
142
 
175
- if (token && token.type === "JSXText") {
176
- return;
177
- }
178
-
179
143
  const previousToken = tokensAndComments[i - 1];
180
144
  const nextToken = tokensAndComments[i + 1];
181
145
 
182
- validateCommaItemSpacing({
183
- comma: token,
184
- left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.includes(token) ? null : previousToken,
185
- right: astUtils.isCommaToken(nextToken) ? null : nextToken
186
- }, token);
146
+ if (
147
+ previousToken &&
148
+ !astUtils.isCommaToken(previousToken) && // ignore spacing between two commas
149
+
150
+ /*
151
+ * `commaTokensToIgnore` are ending commas of `null` elements (array holes/elisions).
152
+ * In addition to spacing between two commas, this can also ignore:
153
+ *
154
+ * - Spacing after `[` (controlled by array-bracket-spacing)
155
+ * Example: [ , ]
156
+ * ^
157
+ * - Spacing after a comment (for backwards compatibility, this was possibly unintentional)
158
+ * Example: [a, /* * / ,]
159
+ * ^
160
+ */
161
+ !commaTokensToIgnore.includes(token) &&
162
+
163
+ astUtils.isTokenOnSameLine(previousToken, token) &&
164
+ options.before !== sourceCode.isSpaceBetweenTokens(previousToken, token)
165
+ ) {
166
+ report(token, "before", previousToken);
167
+ }
168
+
169
+ if (
170
+ nextToken &&
171
+ !astUtils.isCommaToken(nextToken) && // ignore spacing between two commas
172
+ !astUtils.isClosingParenToken(nextToken) && // controlled by space-in-parens
173
+ !astUtils.isClosingBracketToken(nextToken) && // controlled by array-bracket-spacing
174
+ !astUtils.isClosingBraceToken(nextToken) && // controlled by object-curly-spacing
175
+ !(!options.after && nextToken.type === "Line") && // special case, allow space before line comment
176
+ astUtils.isTokenOnSameLine(token, nextToken) &&
177
+ options.after !== sourceCode.isSpaceBetweenTokens(token, nextToken)
178
+ ) {
179
+ report(token, "after", nextToken);
180
+ }
187
181
  });
188
182
  },
189
183
  ArrayExpression: addNullElementsToIgnoreList,
@@ -64,59 +64,45 @@ module.exports = {
64
64
  */
65
65
  function convertToRegExp(term) {
66
66
  const escaped = escapeRegExp(term);
67
- const wordBoundary = "\\b";
68
- const eitherOrWordBoundary = `|${wordBoundary}`;
69
- let prefix;
70
67
 
71
68
  /*
72
- * If the term ends in a word character (a-z0-9_), ensure a word
73
- * boundary at the end, so that substrings do not get falsely
74
- * matched. eg "todo" in a string such as "mastodon".
75
- * If the term ends in a non-word character, then \b won't match on
76
- * the boundary to the next non-word character, which would likely
77
- * be a space. For example `/\bFIX!\b/.test('FIX! blah') === false`.
78
- * In these cases, use no bounding match. Same applies for the
79
- * prefix, handled below.
69
+ * When matching at the start, ignore leading whitespace, and
70
+ * there's no need to worry about word boundaries.
71
+ *
72
+ * These expressions for the prefix and suffix are designed as follows:
73
+ * ^ handles any terms at the beginning of a comment.
74
+ * e.g. terms ["TODO"] matches `//TODO something`
75
+ * $ handles any terms at the end of a comment
76
+ * e.g. terms ["TODO"] matches `// something TODO`
77
+ * \s* handles optional leading spaces (for "start" location only)
78
+ * e.g. terms ["TODO"] matches `// TODO something`
79
+ * \b handles terms preceded/followed by word boundary
80
+ * e.g. terms: ["!FIX", "FIX!"] matches `// FIX!something` or `// something!FIX`
81
+ * terms: ["FIX"] matches `// FIX!` or `// !FIX`, but not `// fixed or affix`
80
82
  */
81
- const suffix = /\w$/u.test(term) ? "\\b" : "";
83
+ const wordBoundary = "\\b";
82
84
 
83
- if (location === "start") {
85
+ let prefix = "";
84
86
 
85
- /*
86
- * When matching at the start, ignore leading whitespace, and
87
- * there's no need to worry about word boundaries.
88
- */
87
+ if (location === "start") {
89
88
  prefix = "^\\s*";
90
89
  } else if (/^\w/u.test(term)) {
91
90
  prefix = wordBoundary;
92
- } else {
93
- prefix = "";
94
91
  }
95
92
 
96
- if (location === "start") {
97
-
98
- /*
99
- * For location "start" the regex should be
100
- * ^\s*TERM\b. This checks the word boundary
101
- * at the beginning of the comment.
102
- */
103
- return new RegExp(prefix + escaped + suffix, "iu");
104
- }
93
+ const suffix = /\w$/u.test(term) ? wordBoundary : "";
94
+ const flags = "iu"; // Case-insensitive with Unicode case folding.
105
95
 
106
96
  /*
107
- * For location "anywhere" the regex should be
108
- * \bTERM\b|\bTERM\b, this checks the entire comment
109
- * for the term.
97
+ * For location "start", the typical regex is:
98
+ * /^\s*ESCAPED_TERM\b/iu.
99
+ *
100
+ * For location "anywhere" the typical regex is
101
+ * /\bESCAPED_TERM\b/iu
102
+ *
103
+ * If it starts or ends with non-word character, the prefix and suffix empty, respectively.
110
104
  */
111
- return new RegExp(
112
- prefix +
113
- escaped +
114
- suffix +
115
- eitherOrWordBoundary +
116
- term +
117
- wordBoundary,
118
- "iu"
119
- );
105
+ return new RegExp(`${prefix}${escaped}${suffix}`, flags);
120
106
  }
121
107
 
122
108
  const warningRegExps = warningTerms.map(convertToRegExp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "8.19.0",
3
+ "version": "8.20.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -102,9 +102,9 @@
102
102
  "eslint": "file:.",
103
103
  "eslint-config-eslint": "file:packages/eslint-config-eslint",
104
104
  "eslint-plugin-eslint-comments": "^3.2.0",
105
- "eslint-plugin-eslint-plugin": "^4.2.0",
105
+ "eslint-plugin-eslint-plugin": "^4.4.0",
106
106
  "eslint-plugin-internal-rules": "file:tools/internal-rules",
107
- "eslint-plugin-jsdoc": "^37.0.0",
107
+ "eslint-plugin-jsdoc": "^38.1.6",
108
108
  "eslint-plugin-node": "^11.1.0",
109
109
  "eslint-plugin-unicorn": "^42.0.0",
110
110
  "eslint-release": "^3.2.0",
@@ -123,8 +123,8 @@
123
123
  "karma-webpack": "^5.0.0",
124
124
  "lint-staged": "^11.0.0",
125
125
  "load-perf": "^0.2.0",
126
- "markdownlint": "^0.24.0",
127
- "markdownlint-cli": "^0.30.0",
126
+ "markdownlint": "^0.25.1",
127
+ "markdownlint-cli": "^0.31.1",
128
128
  "marked": "^4.0.8",
129
129
  "memfs": "^3.0.1",
130
130
  "metascraper": "^5.25.7",