eslint 8.25.0 → 8.27.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.
@@ -161,6 +161,16 @@ function createRulesMeta(rules) {
161
161
  }, {});
162
162
  }
163
163
 
164
+ /**
165
+ * Return the absolute path of a file named `"__placeholder__.js"` in a given directory.
166
+ * This is used as a replacement for a missing file path.
167
+ * @param {string} cwd An absolute directory path.
168
+ * @returns {string} The absolute path of a file named `"__placeholder__.js"` in the given directory.
169
+ */
170
+ function getPlaceholderPath(cwd) {
171
+ return path.join(cwd, "__placeholder__.js");
172
+ }
173
+
164
174
  /** @type {WeakMap<ExtractedConfig, DeprecatedRuleInfo[]>} */
165
175
  const usedDeprecatedRulesCache = new WeakMap();
166
176
 
@@ -177,7 +187,7 @@ function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
177
187
  } = privateMembers.get(eslint);
178
188
  const filePath = path.isAbsolute(maybeFilePath)
179
189
  ? maybeFilePath
180
- : path.join(cwd, "__placeholder__.js");
190
+ : getPlaceholderPath(cwd);
181
191
  const config = configs.getConfig(filePath);
182
192
 
183
193
  // Most files use the same config, so cache it.
@@ -262,24 +272,16 @@ function findFlatConfigFile(cwd) {
262
272
  /**
263
273
  * Load the config array from the given filename.
264
274
  * @param {string} filePath The filename to load from.
265
- * @param {Object} options Options to help load the config file.
266
- * @param {string} options.basePath The base path for the config array.
267
- * @param {boolean} options.shouldIgnore Whether to honor ignore patterns.
268
- * @returns {Promise<FlatConfigArray>} The config array loaded from the config file.
275
+ * @returns {Promise<any>} The config loaded from the config file.
269
276
  */
270
- async function loadFlatConfigFile(filePath, { basePath, shouldIgnore }) {
277
+ async function loadFlatConfigFile(filePath) {
271
278
  debug(`Loading config from ${filePath}`);
272
279
 
273
280
  const fileURL = pathToFileURL(filePath);
274
281
 
275
282
  debug(`Config file URL is ${fileURL}`);
276
283
 
277
- const module = await import(fileURL);
278
-
279
- return new FlatConfigArray(module.default, {
280
- basePath,
281
- shouldIgnore
282
- });
284
+ return (await import(fileURL)).default;
283
285
  }
284
286
 
285
287
  /**
@@ -290,6 +292,7 @@ async function loadFlatConfigFile(filePath, { basePath, shouldIgnore }) {
290
292
  */
291
293
  async function calculateConfigArray(eslint, {
292
294
  cwd,
295
+ baseConfig,
293
296
  overrideConfig,
294
297
  configFile,
295
298
  ignore: shouldIgnore,
@@ -321,16 +324,18 @@ async function calculateConfigArray(eslint, {
321
324
  basePath = path.resolve(path.dirname(configFilePath));
322
325
  }
323
326
 
324
- // load config array
325
- let configs;
326
327
 
328
+ const configs = new FlatConfigArray(baseConfig || [], { basePath, shouldIgnore });
329
+
330
+ // load config file
327
331
  if (configFilePath) {
328
- configs = await loadFlatConfigFile(configFilePath, {
329
- basePath,
330
- shouldIgnore
331
- });
332
- } else {
333
- configs = new FlatConfigArray([], { basePath, shouldIgnore });
332
+ const fileConfig = await loadFlatConfigFile(configFilePath);
333
+
334
+ if (Array.isArray(fileConfig)) {
335
+ configs.push(...fileConfig);
336
+ } else {
337
+ configs.push(fileConfig);
338
+ }
334
339
  }
335
340
 
336
341
  // add in any configured defaults
@@ -362,17 +367,6 @@ async function calculateConfigArray(eslint, {
362
367
  const negated = pattern.startsWith("!");
363
368
  const basePattern = negated ? pattern.slice(1) : pattern;
364
369
 
365
- /*
366
- * Ignore patterns are considered relative to a directory
367
- * when the pattern contains a slash in a position other
368
- * than the last character. If that's the case, we need to
369
- * add the relative ignore path to the current pattern to
370
- * get the correct behavior. Otherwise, no change is needed.
371
- */
372
- if (!basePattern.includes("/") || basePattern.endsWith("/")) {
373
- return pattern;
374
- }
375
-
376
370
  return (negated ? "!" : "") +
377
371
  path.posix.join(relativeIgnorePath, basePattern);
378
372
  });
@@ -438,7 +432,7 @@ function verifyText({
438
432
  * `config.extractConfig(filePath)` requires an absolute path, but `linter`
439
433
  * doesn't know CWD, so it gives `linter` an absolute path always.
440
434
  */
441
- const filePathToVerify = filePath === "<text>" ? path.join(cwd, "__placeholder__.js") : filePath;
435
+ const filePathToVerify = filePath === "<text>" ? getPlaceholderPath(cwd) : filePath;
442
436
  const { fixed, messages, output } = linter.verifyAndFix(
443
437
  text,
444
438
  configs,
@@ -535,6 +529,14 @@ function *iterateRuleDeprecationWarnings(configs) {
535
529
  }
536
530
  }
537
531
 
532
+ /**
533
+ * Creates an error to be thrown when an array of results passed to `getRulesMetaForResults` was not created by the current engine.
534
+ * @returns {TypeError} An error object.
535
+ */
536
+ function createExtraneousResultsError() {
537
+ return new TypeError("Results object was not created from this ESLint instance.");
538
+ }
539
+
538
540
  //-----------------------------------------------------------------------------
539
541
  // Main API
540
542
  //-----------------------------------------------------------------------------
@@ -665,14 +667,16 @@ class FlatESLint {
665
667
  */
666
668
  getRulesMetaForResults(results) {
667
669
 
668
- const resultRules = new Map();
669
-
670
670
  // short-circuit simple case
671
671
  if (results.length === 0) {
672
- return resultRules;
672
+ return {};
673
673
  }
674
674
 
675
- const { configs } = privateMembers.get(this);
675
+ const resultRules = new Map();
676
+ const {
677
+ configs,
678
+ options: { cwd }
679
+ } = privateMembers.get(this);
676
680
 
677
681
  /*
678
682
  * We can only accurately return rules meta information for linting results if the
@@ -681,7 +685,7 @@ class FlatESLint {
681
685
  * to let the user know we can't do anything here.
682
686
  */
683
687
  if (!configs) {
684
- throw new TypeError("Results object was not created from this ESLint instance.");
688
+ throw createExtraneousResultsError();
685
689
  }
686
690
 
687
691
  for (const result of results) {
@@ -690,16 +694,23 @@ class FlatESLint {
690
694
  * Normalize filename for <text>.
691
695
  */
692
696
  const filePath = result.filePath === "<text>"
693
- ? "__placeholder__.js" : result.filePath;
694
-
695
- /*
696
- * All of the plugin and rule information is contained within the
697
- * calculated config for the given file.
698
- */
699
- const config = configs.getConfig(filePath);
697
+ ? getPlaceholderPath(cwd) : result.filePath;
700
698
  const allMessages = result.messages.concat(result.suppressedMessages);
701
699
 
702
700
  for (const { ruleId } of allMessages) {
701
+ if (!ruleId) {
702
+ continue;
703
+ }
704
+
705
+ /*
706
+ * All of the plugin and rule information is contained within the
707
+ * calculated config for the given file.
708
+ */
709
+ const config = configs.getConfig(filePath);
710
+
711
+ if (!config) {
712
+ throw createExtraneousResultsError();
713
+ }
703
714
  const rule = getRuleFromConfig(ruleId, config);
704
715
 
705
716
  // ensure the rule exists
@@ -1037,7 +1048,7 @@ class FlatESLint {
1037
1048
  const npmFormat = naming.normalizePackageName(normalizedFormatName, "eslint-formatter");
1038
1049
 
1039
1050
  // TODO: This is pretty dirty...would be nice to clean up at some point.
1040
- formatterPath = ModuleResolver.resolve(npmFormat, path.join(cwd, "__placeholder__.js"));
1051
+ formatterPath = ModuleResolver.resolve(npmFormat, getPlaceholderPath(cwd));
1041
1052
  } catch {
1042
1053
  formatterPath = path.resolve(__dirname, "../", "cli-engine", "formatters", `${normalizedFormatName}.js`);
1043
1054
  }
@@ -213,6 +213,7 @@ function addDeclaredGlobals(globalScope, configGlobals, { exportedVariables, ena
213
213
 
214
214
  if (variable) {
215
215
  variable.eslintUsed = true;
216
+ variable.eslintExported = true;
216
217
  }
217
218
  });
218
219
 
@@ -50,7 +50,7 @@ function normalizeOptions(optionValue, ecmaVersion) {
50
50
  objects: optionValue,
51
51
  imports: optionValue,
52
52
  exports: optionValue,
53
- functions: (!ecmaVersion || ecmaVersion < 8) ? "ignore" : optionValue
53
+ functions: ecmaVersion < 2017 ? "ignore" : optionValue
54
54
  };
55
55
  }
56
56
  if (typeof optionValue === "object" && optionValue !== null) {
@@ -134,7 +134,7 @@ module.exports = {
134
134
  },
135
135
 
136
136
  create(context) {
137
- const options = normalizeOptions(context.options[0], context.parserOptions.ecmaVersion);
137
+ const options = normalizeOptions(context.options[0], context.languageOptions.ecmaVersion);
138
138
 
139
139
  const sourceCode = context.getSourceCode();
140
140
 
@@ -44,7 +44,7 @@ function isModuleExports(pattern) {
44
44
  * @returns {boolean} True if the string is a valid identifier
45
45
  */
46
46
  function isIdentifier(name, ecmaVersion) {
47
- if (ecmaVersion >= 6) {
47
+ if (ecmaVersion >= 2015) {
48
48
  return esutils.keyword.isIdentifierES6(name);
49
49
  }
50
50
  return esutils.keyword.isIdentifierES5(name);
@@ -104,7 +104,7 @@ module.exports = {
104
104
  const nameMatches = typeof context.options[0] === "string" ? context.options[0] : "always";
105
105
  const considerPropertyDescriptor = options.considerPropertyDescriptor;
106
106
  const includeModuleExports = options.includeCommonJSModuleExports;
107
- const ecmaVersion = context.parserOptions && context.parserOptions.ecmaVersion ? context.parserOptions.ecmaVersion : 5;
107
+ const ecmaVersion = context.languageOptions.ecmaVersion;
108
108
 
109
109
  /**
110
110
  * Check whether node is a certain CallExpression.
@@ -112,18 +112,24 @@ module.exports = {
112
112
  }
113
113
  if (parent.type === "Property" && astUtils.getStaticPropertyName(parent) === "get" && parent.parent.type === "ObjectExpression") {
114
114
 
115
- // Object.defineProperty()
116
- if (parent.parent.parent.type === "CallExpression" &&
117
- astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") {
118
- return true;
115
+ // Object.defineProperty() or Reflect.defineProperty()
116
+ if (parent.parent.parent.type === "CallExpression") {
117
+ const callNode = parent.parent.parent.callee;
118
+
119
+ if (astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperty") ||
120
+ astUtils.isSpecificMemberAccess(callNode, "Reflect", "defineProperty")) {
121
+ return true;
122
+ }
119
123
  }
120
124
 
121
- // Object.defineProperties()
125
+ // Object.defineProperties() or Object.create()
122
126
  if (parent.parent.parent.type === "Property" &&
123
127
  parent.parent.parent.parent.type === "ObjectExpression" &&
124
- parent.parent.parent.parent.parent.type === "CallExpression" &&
125
- astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") {
126
- return true;
128
+ parent.parent.parent.parent.parent.type === "CallExpression") {
129
+ const callNode = parent.parent.parent.parent.parent.callee;
130
+
131
+ return astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperties") ||
132
+ astUtils.isSpecificMemberAccess(callNode, "Object", "create");
127
133
  }
128
134
  }
129
135
  }
@@ -123,6 +123,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
123
123
  "no-empty-character-class": () => require("./no-empty-character-class"),
124
124
  "no-empty-function": () => require("./no-empty-function"),
125
125
  "no-empty-pattern": () => require("./no-empty-pattern"),
126
+ "no-empty-static-block": () => require("./no-empty-static-block"),
126
127
  "no-eq-null": () => require("./no-eq-null"),
127
128
  "no-eval": () => require("./no-eval"),
128
129
  "no-ex-assign": () => require("./no-ex-assign"),
@@ -167,6 +168,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
167
168
  "no-nested-ternary": () => require("./no-nested-ternary"),
168
169
  "no-new": () => require("./no-new"),
169
170
  "no-new-func": () => require("./no-new-func"),
171
+ "no-new-native-nonconstructor": () => require("./no-new-native-nonconstructor"),
170
172
  "no-new-object": () => require("./no-new-object"),
171
173
  "no-new-require": () => require("./no-new-require"),
172
174
  "no-new-symbol": () => require("./no-new-symbol"),
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @fileoverview Rule to disallow empty static blocks.
3
+ * @author Sosuke Suzuki
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Rule Definition
9
+ //------------------------------------------------------------------------------
10
+
11
+ /** @type {import('../shared/types').Rule} */
12
+ module.exports = {
13
+ meta: {
14
+ type: "suggestion",
15
+
16
+ docs: {
17
+ description: "Disallow empty static blocks",
18
+ recommended: false,
19
+ url: "https://eslint.org/docs/rules/no-empty-static-block"
20
+ },
21
+
22
+ schema: [],
23
+
24
+ messages: {
25
+ unexpected: "Unexpected empty static block."
26
+ }
27
+ },
28
+
29
+ create(context) {
30
+ const sourceCode = context.getSourceCode();
31
+
32
+ return {
33
+ StaticBlock(node) {
34
+ if (node.body.length === 0) {
35
+ const closingBrace = sourceCode.getLastToken(node);
36
+
37
+ if (sourceCode.getCommentsBefore(closingBrace).length === 0) {
38
+ context.report({
39
+ node,
40
+ messageId: "unexpected"
41
+ });
42
+ }
43
+ }
44
+ }
45
+ };
46
+ }
47
+ };
@@ -17,6 +17,7 @@ const astUtils = require("./utils/ast-utils");
17
17
  /** @type {import('../shared/types').Rule} */
18
18
  module.exports = {
19
19
  meta: {
20
+ hasSuggestions: true,
20
21
  type: "suggestion",
21
22
 
22
23
  docs: {
@@ -39,7 +40,8 @@ module.exports = {
39
40
  ],
40
41
 
41
42
  messages: {
42
- unexpected: "Empty {{type}} statement."
43
+ unexpected: "Empty {{type}} statement.",
44
+ suggestComment: "Add comment inside empty {{type}} statement."
43
45
  }
44
46
  },
45
47
 
@@ -71,7 +73,22 @@ module.exports = {
71
73
  return;
72
74
  }
73
75
 
74
- context.report({ node, messageId: "unexpected", data: { type: "block" } });
76
+ context.report({
77
+ node,
78
+ messageId: "unexpected",
79
+ data: { type: "block" },
80
+ suggest: [
81
+ {
82
+ messageId: "suggestComment",
83
+ data: { type: "block" },
84
+ fix(fixer) {
85
+ const range = [node.range[0] + 1, node.range[1] - 1];
86
+
87
+ return fixer.replaceTextRange(range, " /* empty */ ");
88
+ }
89
+ }
90
+ ]
91
+ });
75
92
  },
76
93
 
77
94
  SwitchStatement(node) {
@@ -77,6 +77,11 @@ module.exports = {
77
77
  return;
78
78
  }
79
79
 
80
+ // Variables exported by "exported" block comments
81
+ if (variable.eslintExported) {
82
+ return;
83
+ }
84
+
80
85
  variable.defs.forEach(def => {
81
86
  const defNode = def.node;
82
87
 
@@ -193,15 +193,15 @@ module.exports = {
193
193
  * ecmaVersion doesn't support the `u` flag.
194
194
  */
195
195
  function isValidWithUnicodeFlag(pattern) {
196
- const { ecmaVersion } = context.parserOptions;
196
+ const { ecmaVersion } = context.languageOptions;
197
197
 
198
- // ecmaVersion is unknown or it doesn't support the 'u' flag
199
- if (typeof ecmaVersion !== "number" || ecmaVersion <= 5) {
198
+ // ecmaVersion <= 5 doesn't support the 'u' flag
199
+ if (ecmaVersion <= 5) {
200
200
  return false;
201
201
  }
202
202
 
203
203
  const validator = new RegExpValidator({
204
- ecmaVersion: Math.min(ecmaVersion + 2009, REGEXPP_LATEST_ECMA_VERSION)
204
+ ecmaVersion: Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION)
205
205
  });
206
206
 
207
207
  try {
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview Rule to disallow use of the new operator with global non-constructor functions
3
+ * @author Sosuke Suzuki
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Helpers
10
+ //------------------------------------------------------------------------------
11
+
12
+ const nonConstructorGlobalFunctionNames = ["Symbol", "BigInt"];
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Rule Definition
16
+ //------------------------------------------------------------------------------
17
+
18
+ /** @type {import('../shared/types').Rule} */
19
+ module.exports = {
20
+ meta: {
21
+ type: "problem",
22
+
23
+ docs: {
24
+ description: "Disallow `new` operators with global non-constructor functions",
25
+ recommended: false,
26
+ url: "https://eslint.org/docs/rules/no-new-native-nonconstructor"
27
+ },
28
+
29
+ schema: [],
30
+
31
+ messages: {
32
+ noNewNonconstructor: "`{{name}}` cannot be called as a constructor."
33
+ }
34
+ },
35
+
36
+ create(context) {
37
+
38
+ return {
39
+ "Program:exit"() {
40
+ const globalScope = context.getScope();
41
+
42
+ for (const nonConstructorName of nonConstructorGlobalFunctionNames) {
43
+ const variable = globalScope.set.get(nonConstructorName);
44
+
45
+ if (variable && variable.defs.length === 0) {
46
+ variable.references.forEach(ref => {
47
+ const node = ref.identifier;
48
+ const parent = node.parent;
49
+
50
+ if (parent && parent.type === "NewExpression" && parent.callee === node) {
51
+ context.report({
52
+ node,
53
+ messageId: "noNewNonconstructor",
54
+ data: { name: nonConstructorName }
55
+ });
56
+ }
57
+ });
58
+ }
59
+ }
60
+ }
61
+ };
62
+
63
+ }
64
+ };
@@ -248,14 +248,14 @@ module.exports = {
248
248
 
249
249
  /**
250
250
  * Returns a ecmaVersion compatible for regexpp.
251
- * @param {any} ecmaVersion The ecmaVersion to convert.
251
+ * @param {number} ecmaVersion The ecmaVersion to convert.
252
252
  * @returns {import("regexpp/ecma-versions").EcmaVersion} The resulting ecmaVersion compatible for regexpp.
253
253
  */
254
254
  function getRegexppEcmaVersion(ecmaVersion) {
255
- if (typeof ecmaVersion !== "number" || ecmaVersion <= 5) {
255
+ if (ecmaVersion <= 5) {
256
256
  return 5;
257
257
  }
258
- return Math.min(ecmaVersion + 2009, REGEXPP_LATEST_ECMA_VERSION);
258
+ return Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION);
259
259
  }
260
260
 
261
261
  /**
@@ -320,7 +320,7 @@ module.exports = {
320
320
  flags = getStringValue(node.arguments[1]);
321
321
  }
322
322
 
323
- const regexppEcmaVersion = getRegexppEcmaVersion(context.parserOptions.ecmaVersion);
323
+ const regexppEcmaVersion = getRegexppEcmaVersion(context.languageOptions.ecmaVersion);
324
324
  const RegExpValidatorInstance = new RegExpValidator({ ecmaVersion: regexppEcmaVersion });
325
325
 
326
326
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "8.25.0",
3
+ "version": "8.27.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -56,8 +56,9 @@
56
56
  "bugs": "https://github.com/eslint/eslint/issues/",
57
57
  "dependencies": {
58
58
  "@eslint/eslintrc": "^1.3.3",
59
- "@humanwhocodes/config-array": "^0.10.5",
59
+ "@humanwhocodes/config-array": "^0.11.6",
60
60
  "@humanwhocodes/module-importer": "^1.0.1",
61
+ "@nodelib/fs.walk": "^1.2.8",
61
62
  "ajv": "^6.10.0",
62
63
  "chalk": "^4.0.0",
63
64
  "cross-spawn": "^7.0.2",
@@ -73,14 +74,14 @@
73
74
  "fast-deep-equal": "^3.1.3",
74
75
  "file-entry-cache": "^6.0.1",
75
76
  "find-up": "^5.0.0",
76
- "glob-parent": "^6.0.1",
77
+ "glob-parent": "^6.0.2",
77
78
  "globals": "^13.15.0",
78
- "globby": "^11.1.0",
79
79
  "grapheme-splitter": "^1.0.4",
80
80
  "ignore": "^5.2.0",
81
81
  "import-fresh": "^3.0.0",
82
82
  "imurmurhash": "^0.1.4",
83
83
  "is-glob": "^4.0.0",
84
+ "is-path-inside": "^3.0.3",
84
85
  "js-sdsl": "^4.1.4",
85
86
  "js-yaml": "^4.1.0",
86
87
  "json-stable-stringify-without-jsonify": "^1.0.1",