eslint 7.0.0-alpha.1 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/README.md +7 -7
  3. package/bin/eslint.js +115 -77
  4. package/conf/category-list.json +2 -3
  5. package/conf/environments.js +2 -1
  6. package/conf/eslint-recommended.js +3 -0
  7. package/lib/api.js +2 -0
  8. package/lib/cli-engine/cascading-config-array-factory.js +16 -2
  9. package/lib/cli-engine/cli-engine.js +53 -47
  10. package/lib/cli-engine/config-array/config-array.js +30 -1
  11. package/lib/cli-engine/config-array/ignore-pattern.js +7 -1
  12. package/lib/cli-engine/config-array-factory.js +244 -235
  13. package/lib/cli.js +181 -95
  14. package/lib/eslint/eslint.js +656 -0
  15. package/lib/eslint/index.js +7 -0
  16. package/lib/init/autoconfig.js +4 -4
  17. package/lib/init/config-file.js +2 -2
  18. package/lib/init/config-initializer.js +2 -4
  19. package/lib/init/source-code-utils.js +2 -2
  20. package/lib/linter/node-event-generator.js +2 -2
  21. package/lib/options.js +0 -1
  22. package/lib/rule-tester/rule-tester.js +178 -23
  23. package/lib/rules/accessor-pairs.js +2 -2
  24. package/lib/rules/array-callback-return.js +3 -18
  25. package/lib/rules/arrow-body-style.js +26 -15
  26. package/lib/rules/callback-return.js +4 -0
  27. package/lib/rules/camelcase.js +38 -1
  28. package/lib/rules/comma-style.js +3 -8
  29. package/lib/rules/computed-property-spacing.js +2 -2
  30. package/lib/rules/curly.js +124 -40
  31. package/lib/rules/func-call-spacing.js +4 -3
  32. package/lib/rules/func-names.js +31 -24
  33. package/lib/rules/getter-return.js +2 -12
  34. package/lib/rules/global-require.js +4 -0
  35. package/lib/rules/handle-callback-err.js +4 -0
  36. package/lib/rules/id-blacklist.js +140 -64
  37. package/lib/rules/id-length.js +14 -4
  38. package/lib/rules/indent-legacy.js +0 -16
  39. package/lib/rules/key-spacing.js +1 -1
  40. package/lib/rules/new-cap.js +1 -1
  41. package/lib/rules/newline-per-chained-call.js +6 -3
  42. package/lib/rules/no-alert.js +5 -3
  43. package/lib/rules/no-buffer-constructor.js +4 -0
  44. package/lib/rules/no-dupe-else-if.js +1 -1
  45. package/lib/rules/no-empty-function.js +4 -2
  46. package/lib/rules/no-eval.js +3 -2
  47. package/lib/rules/no-extra-bind.js +1 -1
  48. package/lib/rules/no-extra-boolean-cast.js +168 -38
  49. package/lib/rules/no-extra-parens.js +9 -5
  50. package/lib/rules/no-implied-eval.js +83 -101
  51. package/lib/rules/no-import-assign.js +1 -1
  52. package/lib/rules/no-inner-declarations.js +31 -39
  53. package/lib/rules/no-lone-blocks.js +1 -1
  54. package/lib/rules/no-magic-numbers.js +72 -37
  55. package/lib/rules/no-mixed-requires.js +4 -0
  56. package/lib/rules/no-new-object.js +15 -3
  57. package/lib/rules/no-new-require.js +4 -0
  58. package/lib/rules/no-new-wrappers.js +1 -1
  59. package/lib/rules/no-obj-calls.js +24 -5
  60. package/lib/rules/no-path-concat.js +4 -0
  61. package/lib/rules/no-plusplus.js +39 -3
  62. package/lib/rules/no-process-env.js +4 -0
  63. package/lib/rules/no-process-exit.js +4 -0
  64. package/lib/rules/no-prototype-builtins.js +1 -1
  65. package/lib/rules/no-restricted-modules.js +52 -18
  66. package/lib/rules/no-setter-return.js +1 -1
  67. package/lib/rules/no-sync.js +4 -0
  68. package/lib/rules/no-underscore-dangle.js +1 -1
  69. package/lib/rules/no-unexpected-multiline.js +22 -12
  70. package/lib/rules/no-useless-concat.js +1 -1
  71. package/lib/rules/operator-assignment.js +3 -3
  72. package/lib/rules/operator-linebreak.js +4 -16
  73. package/lib/rules/prefer-numeric-literals.js +3 -3
  74. package/lib/rules/prefer-object-spread.js +2 -2
  75. package/lib/rules/require-await.js +1 -1
  76. package/lib/rules/space-before-function-paren.js +5 -2
  77. package/lib/rules/template-curly-spacing.js +59 -42
  78. package/lib/rules/utils/ast-utils.js +65 -4
  79. package/lib/rules/wrap-iife.js +54 -17
  80. package/lib/rules/yoda.js +101 -51
  81. package/lib/shared/relative-module-resolver.js +1 -0
  82. package/lib/shared/types.js +9 -2
  83. package/messages/plugin-conflict.txt +7 -0
  84. package/package.json +27 -26
@@ -90,7 +90,24 @@ const configFilenames = [
90
90
  * @typedef {Object} ConfigArrayFactoryInternalSlots
91
91
  * @property {Map<string,Plugin>} additionalPluginPool The map for additional plugins.
92
92
  * @property {string} cwd The path to the current working directory.
93
- * @property {string} resolvePluginsRelativeTo An absolute path the the directory that plugins should be resolved from.
93
+ * @property {string | undefined} resolvePluginsRelativeTo An absolute path the the directory that plugins should be resolved from.
94
+ */
95
+
96
+ /**
97
+ * @typedef {Object} ConfigArrayFactoryLoadingContext
98
+ * @property {string} filePath The path to the current configuration.
99
+ * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
100
+ * @property {string} name The name of the current configuration.
101
+ * @property {string} pluginBasePath The base path to resolve plugins.
102
+ * @property {"config" | "ignore" | "implicit-processor"} type The type of the current configuration. This is `"config"` in normal. This is `"ignore"` if it came from `.eslintignore`. This is `"implicit-processor"` if it came from legacy file-extension processors.
103
+ */
104
+
105
+ /**
106
+ * @typedef {Object} ConfigArrayFactoryLoadingContext
107
+ * @property {string} filePath The path to the current configuration.
108
+ * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
109
+ * @property {string} name The name of the current configuration.
110
+ * @property {"config" | "ignore" | "implicit-processor"} type The type of the current configuration. This is `"config"` in normal. This is `"ignore"` if it came from `.eslintignore`. This is `"implicit-processor"` if it came from legacy file-extension processors.
94
111
  */
95
112
 
96
113
  /** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
@@ -328,21 +345,39 @@ function writeDebugLogForLoading(request, relativeTo, filePath) {
328
345
  }
329
346
 
330
347
  /**
331
- * Concatenate two config data.
332
- * @param {IterableIterator<ConfigArrayElement>|null} elements The config elements.
333
- * @param {ConfigArray|null} parentConfigArray The parent config array.
334
- * @returns {ConfigArray} The concatenated config array.
348
+ * Create a new context with default values.
349
+ * @param {ConfigArrayFactoryInternalSlots} slots The internal slots.
350
+ * @param {"config" | "ignore" | "implicit-processor" | undefined} providedType The type of the current configuration. Default is `"config"`.
351
+ * @param {string | undefined} providedName The name of the current configuration. Default is the relative path from `cwd` to `filePath`.
352
+ * @param {string | undefined} providedFilePath The path to the current configuration. Default is empty string.
353
+ * @param {string | undefined} providedMatchBasePath The type of the current configuration. Default is the directory of `filePath` or `cwd`.
354
+ * @returns {ConfigArrayFactoryLoadingContext} The created context.
335
355
  */
336
- function createConfigArray(elements, parentConfigArray) {
337
- if (!elements) {
338
- return parentConfigArray || new ConfigArray();
339
- }
340
- const configArray = new ConfigArray(...elements);
341
-
342
- if (parentConfigArray && !configArray.isRoot()) {
343
- configArray.unshift(...parentConfigArray);
344
- }
345
- return configArray;
356
+ function createContext(
357
+ { cwd, resolvePluginsRelativeTo },
358
+ providedType,
359
+ providedName,
360
+ providedFilePath,
361
+ providedMatchBasePath
362
+ ) {
363
+ const filePath = providedFilePath
364
+ ? path.resolve(cwd, providedFilePath)
365
+ : "";
366
+ const matchBasePath =
367
+ (providedMatchBasePath && path.resolve(cwd, providedMatchBasePath)) ||
368
+ (filePath && path.dirname(filePath)) ||
369
+ cwd;
370
+ const name =
371
+ providedName ||
372
+ (filePath && path.relative(cwd, filePath)) ||
373
+ "";
374
+ const pluginBasePath =
375
+ resolvePluginsRelativeTo ||
376
+ (filePath && path.dirname(filePath)) ||
377
+ cwd;
378
+ const type = providedType || "config";
379
+
380
+ return { filePath, matchBasePath, name, pluginBasePath, type };
346
381
  }
347
382
 
348
383
  /**
@@ -377,63 +412,95 @@ class ConfigArrayFactory {
377
412
  constructor({
378
413
  additionalPluginPool = new Map(),
379
414
  cwd = process.cwd(),
380
- resolvePluginsRelativeTo = cwd
415
+ resolvePluginsRelativeTo
381
416
  } = {}) {
382
- internalSlotsMap.set(this, { additionalPluginPool, cwd, resolvePluginsRelativeTo: path.resolve(cwd, resolvePluginsRelativeTo) });
417
+ internalSlotsMap.set(this, {
418
+ additionalPluginPool,
419
+ cwd,
420
+ resolvePluginsRelativeTo:
421
+ resolvePluginsRelativeTo &&
422
+ path.resolve(cwd, resolvePluginsRelativeTo)
423
+ });
383
424
  }
384
425
 
385
426
  /**
386
427
  * Create `ConfigArray` instance from a config data.
387
428
  * @param {ConfigData|null} configData The config data to create.
388
429
  * @param {Object} [options] The options.
430
+ * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
389
431
  * @param {string} [options.filePath] The path to this config data.
390
432
  * @param {string} [options.name] The config name.
391
- * @param {ConfigArray} [options.parent] The parent config array.
392
433
  * @returns {ConfigArray} Loaded config.
393
434
  */
394
- create(configData, { filePath, name, parent } = {}) {
395
- return createConfigArray(
396
- configData
397
- ? this._normalizeConfigData(configData, filePath, name)
398
- : null,
399
- parent
400
- );
435
+ create(configData, { basePath, filePath, name } = {}) {
436
+ if (!configData) {
437
+ return new ConfigArray();
438
+ }
439
+
440
+ const slots = internalSlotsMap.get(this);
441
+ const ctx = createContext(slots, "config", name, filePath, basePath);
442
+ const elements = this._normalizeConfigData(configData, ctx);
443
+
444
+ return new ConfigArray(...elements);
401
445
  }
402
446
 
403
447
  /**
404
448
  * Load a config file.
405
449
  * @param {string} filePath The path to a config file.
406
450
  * @param {Object} [options] The options.
451
+ * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
407
452
  * @param {string} [options.name] The config name.
408
- * @param {ConfigArray} [options.parent] The parent config array.
409
453
  * @returns {ConfigArray} Loaded config.
410
454
  */
411
- loadFile(filePath, { name, parent } = {}) {
412
- const { cwd } = internalSlotsMap.get(this);
413
- const absolutePath = path.resolve(cwd, filePath);
455
+ loadFile(filePath, { basePath, name } = {}) {
456
+ const slots = internalSlotsMap.get(this);
457
+ const ctx = createContext(slots, "config", name, filePath, basePath);
414
458
 
415
- return createConfigArray(
416
- this._loadConfigData(absolutePath, name),
417
- parent
418
- );
459
+ return new ConfigArray(...this._loadConfigData(ctx));
419
460
  }
420
461
 
421
462
  /**
422
463
  * Load the config file on a given directory if exists.
423
464
  * @param {string} directoryPath The path to a directory.
424
465
  * @param {Object} [options] The options.
466
+ * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
425
467
  * @param {string} [options.name] The config name.
426
- * @param {ConfigArray} [options.parent] The parent config array.
427
468
  * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
428
469
  */
429
- loadInDirectory(directoryPath, { name, parent } = {}) {
430
- const { cwd } = internalSlotsMap.get(this);
431
- const absolutePath = path.resolve(cwd, directoryPath);
470
+ loadInDirectory(directoryPath, { basePath, name } = {}) {
471
+ const slots = internalSlotsMap.get(this);
432
472
 
433
- return createConfigArray(
434
- this._loadConfigDataInDirectory(absolutePath, name),
435
- parent
436
- );
473
+ for (const filename of configFilenames) {
474
+ const ctx = createContext(
475
+ slots,
476
+ "config",
477
+ name,
478
+ path.join(directoryPath, filename),
479
+ basePath
480
+ );
481
+
482
+ if (fs.existsSync(ctx.filePath)) {
483
+ let configData;
484
+
485
+ try {
486
+ configData = loadConfigFile(ctx.filePath);
487
+ } catch (error) {
488
+ if (!error || error.code !== "ESLINT_CONFIG_FIELD_NOT_FOUND") {
489
+ throw error;
490
+ }
491
+ }
492
+
493
+ if (configData) {
494
+ debug(`Config file found: ${ctx.filePath}`);
495
+ return new ConfigArray(
496
+ ...this._normalizeConfigData(configData, ctx)
497
+ );
498
+ }
499
+ }
500
+ }
501
+
502
+ debug(`Config file not found on ${directoryPath}`);
503
+ return new ConfigArray();
437
504
  }
438
505
 
439
506
  /**
@@ -465,13 +532,18 @@ class ConfigArrayFactory {
465
532
  * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
466
533
  */
467
534
  loadESLintIgnore(filePath) {
468
- const { cwd } = internalSlotsMap.get(this);
469
- const absolutePath = path.resolve(cwd, filePath);
470
- const name = path.relative(cwd, absolutePath);
471
- const ignorePatterns = loadESLintIgnoreFile(absolutePath);
535
+ const slots = internalSlotsMap.get(this);
536
+ const ctx = createContext(
537
+ slots,
538
+ "ignore",
539
+ void 0,
540
+ filePath,
541
+ slots.cwd
542
+ );
543
+ const ignorePatterns = loadESLintIgnoreFile(ctx.filePath);
472
544
 
473
- return createConfigArray(
474
- this._normalizeESLintIgnoreData(ignorePatterns, absolutePath, name)
545
+ return new ConfigArray(
546
+ ...this._normalizeESLintIgnoreData(ignorePatterns, ctx)
475
547
  );
476
548
  }
477
549
 
@@ -480,9 +552,9 @@ class ConfigArrayFactory {
480
552
  * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
481
553
  */
482
554
  loadDefaultESLintIgnore() {
483
- const { cwd } = internalSlotsMap.get(this);
484
- const eslintIgnorePath = path.resolve(cwd, ".eslintignore");
485
- const packageJsonPath = path.resolve(cwd, "package.json");
555
+ const slots = internalSlotsMap.get(this);
556
+ const eslintIgnorePath = path.resolve(slots.cwd, ".eslintignore");
557
+ const packageJsonPath = path.resolve(slots.cwd, "package.json");
486
558
 
487
559
  if (fs.existsSync(eslintIgnorePath)) {
488
560
  return this.loadESLintIgnore(eslintIgnorePath);
@@ -494,12 +566,16 @@ class ConfigArrayFactory {
494
566
  if (!Array.isArray(data.eslintIgnore)) {
495
567
  throw new Error("Package.json eslintIgnore property requires an array of paths");
496
568
  }
497
- return createConfigArray(
498
- this._normalizeESLintIgnoreData(
499
- data.eslintIgnore,
500
- packageJsonPath,
501
- "eslintIgnore in package.json"
502
- )
569
+ const ctx = createContext(
570
+ slots,
571
+ "ignore",
572
+ "eslintIgnore in package.json",
573
+ packageJsonPath,
574
+ slots.cwd
575
+ );
576
+
577
+ return new ConfigArray(
578
+ ...this._normalizeESLintIgnoreData(data.eslintIgnore, ctx)
503
579
  );
504
580
  }
505
581
  }
@@ -509,65 +585,25 @@ class ConfigArrayFactory {
509
585
 
510
586
  /**
511
587
  * Load a given config file.
512
- * @param {string} filePath The path to a config file.
513
- * @param {string} name The config name.
588
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
514
589
  * @returns {IterableIterator<ConfigArrayElement>} Loaded config.
515
590
  * @private
516
591
  */
517
- _loadConfigData(filePath, name) {
518
- return this._normalizeConfigData(
519
- loadConfigFile(filePath),
520
- filePath,
521
- name
522
- );
523
- }
524
-
525
- /**
526
- * Load the config file in a given directory if exists.
527
- * @param {string} directoryPath The path to a directory.
528
- * @param {string} name The config name.
529
- * @returns {IterableIterator<ConfigArrayElement> | null} Loaded config. `null` if any config doesn't exist.
530
- * @private
531
- */
532
- _loadConfigDataInDirectory(directoryPath, name) {
533
- for (const filename of configFilenames) {
534
- const filePath = path.join(directoryPath, filename);
535
-
536
- if (fs.existsSync(filePath)) {
537
- let configData;
538
-
539
- try {
540
- configData = loadConfigFile(filePath);
541
- } catch (error) {
542
- if (!error || error.code !== "ESLINT_CONFIG_FIELD_NOT_FOUND") {
543
- throw error;
544
- }
545
- }
546
-
547
- if (configData) {
548
- debug(`Config file found: ${filePath}`);
549
- return this._normalizeConfigData(configData, filePath, name);
550
- }
551
- }
552
- }
553
-
554
- debug(`Config file not found on ${directoryPath}`);
555
- return null;
592
+ _loadConfigData(ctx) {
593
+ return this._normalizeConfigData(loadConfigFile(ctx.filePath), ctx);
556
594
  }
557
595
 
558
596
  /**
559
597
  * Normalize a given `.eslintignore` data to config array elements.
560
598
  * @param {string[]} ignorePatterns The patterns to ignore files.
561
- * @param {string|undefined} filePath The file path of this config.
562
- * @param {string|undefined} name The name of this config.
599
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
563
600
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
564
601
  * @private
565
602
  */
566
- *_normalizeESLintIgnoreData(ignorePatterns, filePath, name) {
603
+ *_normalizeESLintIgnoreData(ignorePatterns, ctx) {
567
604
  const elements = this._normalizeObjectConfigData(
568
- { type: "ignore", ignorePatterns },
569
- filePath,
570
- name
605
+ { ignorePatterns },
606
+ ctx
571
607
  );
572
608
 
573
609
  // Set `ignorePattern.loose` flag for backward compatibility.
@@ -582,53 +618,38 @@ class ConfigArrayFactory {
582
618
  /**
583
619
  * Normalize a given config to an array.
584
620
  * @param {ConfigData} configData The config data to normalize.
585
- * @param {string|undefined} providedFilePath The file path of this config.
586
- * @param {string|undefined} providedName The name of this config.
621
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
587
622
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
588
623
  * @private
589
624
  */
590
- _normalizeConfigData(configData, providedFilePath, providedName) {
591
- const { cwd } = internalSlotsMap.get(this);
592
- const filePath = providedFilePath
593
- ? path.resolve(cwd, providedFilePath)
594
- : "";
595
- const name = providedName || (filePath && path.relative(cwd, filePath));
596
-
597
- validateConfigSchema(configData, name || filePath);
598
-
599
- return this._normalizeObjectConfigData(configData, filePath, name);
625
+ _normalizeConfigData(configData, ctx) {
626
+ validateConfigSchema(configData, ctx.name || ctx.filePath);
627
+ return this._normalizeObjectConfigData(configData, ctx);
600
628
  }
601
629
 
602
630
  /**
603
631
  * Normalize a given config to an array.
604
632
  * @param {ConfigData|OverrideConfigData} configData The config data to normalize.
605
- * @param {string} filePath The file path of this config.
606
- * @param {string} name The name of this config.
633
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
607
634
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
608
635
  * @private
609
636
  */
610
- *_normalizeObjectConfigData(configData, filePath, name) {
611
- const { cwd } = internalSlotsMap.get(this);
637
+ *_normalizeObjectConfigData(configData, ctx) {
612
638
  const { files, excludedFiles, ...configBody } = configData;
613
- const basePath = filePath ? path.dirname(filePath) : cwd;
614
- const criteria = OverrideTester.create(files, excludedFiles, basePath);
615
- const elements =
616
- this._normalizeObjectConfigDataBody(configBody, filePath, name);
639
+ const criteria = OverrideTester.create(
640
+ files,
641
+ excludedFiles,
642
+ ctx.matchBasePath
643
+ );
644
+ const elements = this._normalizeObjectConfigDataBody(configBody, ctx);
617
645
 
618
646
  // Apply the criteria to every element.
619
647
  for (const element of elements) {
620
648
 
621
- // Adopt the base path of the entry file (the outermost base path).
622
- if (element.criteria) {
623
- element.criteria.basePath = basePath;
624
- }
625
- if (element.ignorePattern) {
626
- element.ignorePattern.basePath = basePath;
627
- }
628
-
629
649
  /*
630
- * Merge the criteria; this is for only file extension processors in
631
- * `overrides` section for now.
650
+ * Merge the criteria.
651
+ * This is for the `overrides` entries that came from the
652
+ * configurations of `overrides[].extends`.
632
653
  */
633
654
  element.criteria = OverrideTester.and(criteria, element.criteria);
634
655
 
@@ -647,8 +668,7 @@ class ConfigArrayFactory {
647
668
  /**
648
669
  * Normalize a given config to an array.
649
670
  * @param {ConfigData} configData The config data to normalize.
650
- * @param {string} filePath The file path of this config.
651
- * @param {string} name The name of this config.
671
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
652
672
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
653
673
  * @private
654
674
  */
@@ -667,41 +687,37 @@ class ConfigArrayFactory {
667
687
  root,
668
688
  rules,
669
689
  settings,
670
- type = "config",
671
690
  overrides: overrideList = []
672
691
  },
673
- filePath,
674
- name
692
+ ctx
675
693
  ) {
676
694
  const extendList = Array.isArray(extend) ? extend : [extend];
677
695
  const ignorePattern = ignorePatterns && new IgnorePattern(
678
696
  Array.isArray(ignorePatterns) ? ignorePatterns : [ignorePatterns],
679
- filePath ? path.dirname(filePath) : internalSlotsMap.get(this).cwd
697
+ ctx.matchBasePath
680
698
  );
681
699
 
682
700
  // Flatten `extends`.
683
701
  for (const extendName of extendList.filter(Boolean)) {
684
- yield* this._loadExtends(extendName, filePath, name);
702
+ yield* this._loadExtends(extendName, ctx);
685
703
  }
686
704
 
687
705
  // Load parser & plugins.
688
- const parser =
689
- parserName && this._loadParser(parserName, filePath, name);
690
- const plugins =
691
- pluginList && this._loadPlugins(pluginList, filePath, name);
706
+ const parser = parserName && this._loadParser(parserName, ctx);
707
+ const plugins = pluginList && this._loadPlugins(pluginList, ctx);
692
708
 
693
709
  // Yield pseudo config data for file extension processors.
694
710
  if (plugins) {
695
- yield* this._takeFileExtensionProcessors(plugins, filePath, name);
711
+ yield* this._takeFileExtensionProcessors(plugins, ctx);
696
712
  }
697
713
 
698
714
  // Yield the config data except `extends` and `overrides`.
699
715
  yield {
700
716
 
701
717
  // Debug information.
702
- type,
703
- name,
704
- filePath,
718
+ type: ctx.type,
719
+ name: ctx.name,
720
+ filePath: ctx.filePath,
705
721
 
706
722
  // Config data.
707
723
  criteria: null,
@@ -723,8 +739,7 @@ class ConfigArrayFactory {
723
739
  for (let i = 0; i < overrideList.length; ++i) {
724
740
  yield* this._normalizeObjectConfigData(
725
741
  overrideList[i],
726
- filePath,
727
- `${name}#overrides[${i}]`
742
+ { ...ctx, name: `${ctx.name}#overrides[${i}]` }
728
743
  );
729
744
  }
730
745
  }
@@ -732,34 +747,22 @@ class ConfigArrayFactory {
732
747
  /**
733
748
  * Load configs of an element in `extends`.
734
749
  * @param {string} extendName The name of a base config.
735
- * @param {string} importerPath The file path which has the `extends` property.
736
- * @param {string} importerName The name of the config which has the `extends` property.
750
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
737
751
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
738
752
  * @private
739
753
  */
740
- _loadExtends(extendName, importerPath, importerName) {
741
- debug("Loading {extends:%j} relative to %s", extendName, importerPath);
754
+ _loadExtends(extendName, ctx) {
755
+ debug("Loading {extends:%j} relative to %s", extendName, ctx.filePath);
742
756
  try {
743
757
  if (extendName.startsWith("eslint:")) {
744
- return this._loadExtendedBuiltInConfig(
745
- extendName,
746
- importerName
747
- );
758
+ return this._loadExtendedBuiltInConfig(extendName, ctx);
748
759
  }
749
760
  if (extendName.startsWith("plugin:")) {
750
- return this._loadExtendedPluginConfig(
751
- extendName,
752
- importerPath,
753
- importerName
754
- );
761
+ return this._loadExtendedPluginConfig(extendName, ctx);
755
762
  }
756
- return this._loadExtendedShareableConfig(
757
- extendName,
758
- importerPath,
759
- importerName
760
- );
763
+ return this._loadExtendedShareableConfig(extendName, ctx);
761
764
  } catch (error) {
762
- error.message += `\nReferenced from: ${importerPath || importerName}`;
765
+ error.message += `\nReferenced from: ${ctx.filePath || ctx.name}`;
763
766
  throw error;
764
767
  }
765
768
  }
@@ -767,32 +770,37 @@ class ConfigArrayFactory {
767
770
  /**
768
771
  * Load configs of an element in `extends`.
769
772
  * @param {string} extendName The name of a base config.
770
- * @param {string} importerName The name of the config which has the `extends` property.
773
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
771
774
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
772
775
  * @private
773
776
  */
774
- _loadExtendedBuiltInConfig(extendName, importerName) {
775
- const name = `${importerName} » ${extendName}`;
776
-
777
+ _loadExtendedBuiltInConfig(extendName, ctx) {
777
778
  if (extendName === "eslint:recommended") {
778
- return this._loadConfigData(eslintRecommendedPath, name);
779
+ return this._loadConfigData({
780
+ ...ctx,
781
+ filePath: eslintRecommendedPath,
782
+ name: `${ctx.name} » ${extendName}`
783
+ });
779
784
  }
780
785
  if (extendName === "eslint:all") {
781
- return this._loadConfigData(eslintAllPath, name);
786
+ return this._loadConfigData({
787
+ ...ctx,
788
+ filePath: eslintAllPath,
789
+ name: `${ctx.name} » ${extendName}`
790
+ });
782
791
  }
783
792
 
784
- throw configMissingError(extendName, importerName);
793
+ throw configMissingError(extendName, ctx.name);
785
794
  }
786
795
 
787
796
  /**
788
797
  * Load configs of an element in `extends`.
789
798
  * @param {string} extendName The name of a base config.
790
- * @param {string} importerPath The file path which has the `extends` property.
791
- * @param {string} importerName The name of the config which has the `extends` property.
799
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
792
800
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
793
801
  * @private
794
802
  */
795
- _loadExtendedPluginConfig(extendName, importerPath, importerName) {
803
+ _loadExtendedPluginConfig(extendName, ctx) {
796
804
  const slashIndex = extendName.lastIndexOf("/");
797
805
  const pluginName = extendName.slice("plugin:".length, slashIndex);
798
806
  const configName = extendName.slice(slashIndex + 1);
@@ -801,33 +809,32 @@ class ConfigArrayFactory {
801
809
  throw new Error("'extends' cannot use a file path for plugins.");
802
810
  }
803
811
 
804
- const plugin = this._loadPlugin(pluginName, importerPath, importerName);
812
+ const plugin = this._loadPlugin(pluginName, ctx);
805
813
  const configData =
806
814
  plugin.definition &&
807
815
  plugin.definition.configs[configName];
808
816
 
809
817
  if (configData) {
810
- return this._normalizeConfigData(
811
- configData,
812
- plugin.filePath,
813
- `${importerName} » plugin:${plugin.id}/${configName}`
814
- );
818
+ return this._normalizeConfigData(configData, {
819
+ ...ctx,
820
+ filePath: plugin.filePath || ctx.filePath,
821
+ name: `${ctx.name} » plugin:${plugin.id}/${configName}`
822
+ });
815
823
  }
816
824
 
817
- throw plugin.error || configMissingError(extendName, importerPath);
825
+ throw plugin.error || configMissingError(extendName, ctx.filePath);
818
826
  }
819
827
 
820
828
  /**
821
829
  * Load configs of an element in `extends`.
822
830
  * @param {string} extendName The name of a base config.
823
- * @param {string} importerPath The file path which has the `extends` property.
824
- * @param {string} importerName The name of the config which has the `extends` property.
831
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
825
832
  * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
826
833
  * @private
827
834
  */
828
- _loadExtendedShareableConfig(extendName, importerPath, importerName) {
835
+ _loadExtendedShareableConfig(extendName, ctx) {
829
836
  const { cwd } = internalSlotsMap.get(this);
830
- const relativeTo = importerPath || path.join(cwd, "__placeholder__.js");
837
+ const relativeTo = ctx.filePath || path.join(cwd, "__placeholder__.js");
831
838
  let request;
832
839
 
833
840
  if (isFilePath(extendName)) {
@@ -848,29 +855,32 @@ class ConfigArrayFactory {
848
855
  } catch (error) {
849
856
  /* istanbul ignore else */
850
857
  if (error && error.code === "MODULE_NOT_FOUND") {
851
- throw configMissingError(extendName, importerPath);
858
+ throw configMissingError(extendName, ctx.filePath);
852
859
  }
853
860
  throw error;
854
861
  }
855
862
 
856
863
  writeDebugLogForLoading(request, relativeTo, filePath);
857
- return this._loadConfigData(filePath, `${importerName} » ${request}`);
864
+ return this._loadConfigData({
865
+ ...ctx,
866
+ filePath,
867
+ name: `${ctx.name} » ${request}`
868
+ });
858
869
  }
859
870
 
860
871
  /**
861
872
  * Load given plugins.
862
873
  * @param {string[]} names The plugin names to load.
863
- * @param {string} importerPath The path to a config file that imports it. This is just a debug info.
864
- * @param {string} importerName The name of a config file that imports it. This is just a debug info.
874
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
865
875
  * @returns {Record<string,DependentPlugin>} The loaded parser.
866
876
  * @private
867
877
  */
868
- _loadPlugins(names, importerPath, importerName) {
878
+ _loadPlugins(names, ctx) {
869
879
  return names.reduce((map, name) => {
870
880
  if (isFilePath(name)) {
871
881
  throw new Error("Plugins array cannot includes file paths.");
872
882
  }
873
- const plugin = this._loadPlugin(name, importerPath, importerName);
883
+ const plugin = this._loadPlugin(name, ctx);
874
884
 
875
885
  map[plugin.id] = plugin;
876
886
 
@@ -881,15 +891,14 @@ class ConfigArrayFactory {
881
891
  /**
882
892
  * Load a given parser.
883
893
  * @param {string} nameOrPath The package name or the path to a parser file.
884
- * @param {string} importerPath The path to a config file that imports it.
885
- * @param {string} importerName The name of a config file that imports it. This is just a debug info.
894
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
886
895
  * @returns {DependentParser} The loaded parser.
887
896
  */
888
- _loadParser(nameOrPath, importerPath, importerName) {
889
- debug("Loading parser %j from %s", nameOrPath, importerPath);
897
+ _loadParser(nameOrPath, ctx) {
898
+ debug("Loading parser %j from %s", nameOrPath, ctx.filePath);
890
899
 
891
900
  const { cwd } = internalSlotsMap.get(this);
892
- const relativeTo = importerPath || path.join(cwd, "__placeholder__.js");
901
+ const relativeTo = ctx.filePath || path.join(cwd, "__placeholder__.js");
893
902
 
894
903
  try {
895
904
  const filePath = ModuleResolver.resolve(nameOrPath, relativeTo);
@@ -900,8 +909,8 @@ class ConfigArrayFactory {
900
909
  definition: require(filePath),
901
910
  filePath,
902
911
  id: nameOrPath,
903
- importerName,
904
- importerPath
912
+ importerName: ctx.name,
913
+ importerPath: ctx.filePath
905
914
  });
906
915
  } catch (error) {
907
916
 
@@ -912,19 +921,19 @@ class ConfigArrayFactory {
912
921
  definition: require("espree"),
913
922
  filePath: require.resolve("espree"),
914
923
  id: nameOrPath,
915
- importerName,
916
- importerPath
924
+ importerName: ctx.name,
925
+ importerPath: ctx.filePath
917
926
  });
918
927
  }
919
928
 
920
- debug("Failed to load parser '%s' declared in '%s'.", nameOrPath, importerName);
921
- error.message = `Failed to load parser '${nameOrPath}' declared in '${importerName}': ${error.message}`;
929
+ debug("Failed to load parser '%s' declared in '%s'.", nameOrPath, ctx.name);
930
+ error.message = `Failed to load parser '${nameOrPath}' declared in '${ctx.name}': ${error.message}`;
922
931
 
923
932
  return new ConfigDependency({
924
933
  error,
925
934
  id: nameOrPath,
926
- importerName,
927
- importerPath
935
+ importerName: ctx.name,
936
+ importerPath: ctx.filePath
928
937
  });
929
938
  }
930
939
  }
@@ -932,18 +941,17 @@ class ConfigArrayFactory {
932
941
  /**
933
942
  * Load a given plugin.
934
943
  * @param {string} name The plugin name to load.
935
- * @param {string} importerPath The path to a config file that imports it. This is just a debug info.
936
- * @param {string} importerName The name of a config file that imports it. This is just a debug info.
944
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
937
945
  * @returns {DependentPlugin} The loaded plugin.
938
946
  * @private
939
947
  */
940
- _loadPlugin(name, importerPath, importerName) {
941
- debug("Loading plugin %j from %s", name, importerPath);
948
+ _loadPlugin(name, ctx) {
949
+ debug("Loading plugin %j from %s", name, ctx.filePath);
942
950
 
943
- const { additionalPluginPool, resolvePluginsRelativeTo } = internalSlotsMap.get(this);
951
+ const { additionalPluginPool } = internalSlotsMap.get(this);
944
952
  const request = naming.normalizePackageName(name, "eslint-plugin");
945
953
  const id = naming.getShorthandName(request, "eslint-plugin");
946
- const relativeTo = path.join(resolvePluginsRelativeTo, "__placeholder__.js");
954
+ const relativeTo = path.join(ctx.pluginBasePath, "__placeholder__.js");
947
955
 
948
956
  if (name.match(/\s+/u)) {
949
957
  const error = Object.assign(
@@ -957,8 +965,8 @@ class ConfigArrayFactory {
957
965
  return new ConfigDependency({
958
966
  error,
959
967
  id,
960
- importerName,
961
- importerPath
968
+ importerName: ctx.name,
969
+ importerPath: ctx.filePath
962
970
  });
963
971
  }
964
972
 
@@ -970,10 +978,10 @@ class ConfigArrayFactory {
970
978
  if (plugin) {
971
979
  return new ConfigDependency({
972
980
  definition: normalizePlugin(plugin),
973
- filePath: importerPath,
981
+ filePath: "", // It's unknown where the plugin came from.
974
982
  id,
975
- importerName,
976
- importerPath
983
+ importerName: ctx.name,
984
+ importerPath: ctx.filePath
977
985
  });
978
986
  }
979
987
 
@@ -989,8 +997,8 @@ class ConfigArrayFactory {
989
997
  error.messageTemplate = "plugin-missing";
990
998
  error.messageData = {
991
999
  pluginName: request,
992
- resolvePluginsRelativeTo,
993
- importerName
1000
+ resolvePluginsRelativeTo: ctx.pluginBasePath,
1001
+ importerName: ctx.name
994
1002
  };
995
1003
  }
996
1004
  }
@@ -1008,33 +1016,32 @@ class ConfigArrayFactory {
1008
1016
  definition: normalizePlugin(pluginDefinition),
1009
1017
  filePath,
1010
1018
  id,
1011
- importerName,
1012
- importerPath
1019
+ importerName: ctx.name,
1020
+ importerPath: ctx.filePath
1013
1021
  });
1014
1022
  } catch (loadError) {
1015
1023
  error = loadError;
1016
1024
  }
1017
1025
  }
1018
1026
 
1019
- debug("Failed to load plugin '%s' declared in '%s'.", name, importerName);
1020
- error.message = `Failed to load plugin '${name}' declared in '${importerName}': ${error.message}`;
1027
+ debug("Failed to load plugin '%s' declared in '%s'.", name, ctx.name);
1028
+ error.message = `Failed to load plugin '${name}' declared in '${ctx.name}': ${error.message}`;
1021
1029
  return new ConfigDependency({
1022
1030
  error,
1023
1031
  id,
1024
- importerName,
1025
- importerPath
1032
+ importerName: ctx.name,
1033
+ importerPath: ctx.filePath
1026
1034
  });
1027
1035
  }
1028
1036
 
1029
1037
  /**
1030
1038
  * Take file expression processors as config array elements.
1031
1039
  * @param {Record<string,DependentPlugin>} plugins The plugin definitions.
1032
- * @param {string} filePath The file path of this config.
1033
- * @param {string} name The name of this config.
1040
+ * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
1034
1041
  * @returns {IterableIterator<ConfigArrayElement>} The config array elements of file expression processors.
1035
1042
  * @private
1036
1043
  */
1037
- *_takeFileExtensionProcessors(plugins, filePath, name) {
1044
+ *_takeFileExtensionProcessors(plugins, ctx) {
1038
1045
  for (const pluginId of Object.keys(plugins)) {
1039
1046
  const processors =
1040
1047
  plugins[pluginId] &&
@@ -1049,12 +1056,14 @@ class ConfigArrayFactory {
1049
1056
  if (processorId.startsWith(".")) {
1050
1057
  yield* this._normalizeObjectConfigData(
1051
1058
  {
1052
- type: "implicit-processor",
1053
1059
  files: [`*${processorId}`],
1054
1060
  processor: `${pluginId}/${processorId}`
1055
1061
  },
1056
- filePath,
1057
- `${name}#processors["${pluginId}/${processorId}"]`
1062
+ {
1063
+ ...ctx,
1064
+ type: "implicit-processor",
1065
+ name: `${ctx.name}#processors["${pluginId}/${processorId}"]`
1066
+ }
1058
1067
  );
1059
1068
  }
1060
1069
  }
@@ -1062,4 +1071,4 @@ class ConfigArrayFactory {
1062
1071
  }
1063
1072
  }
1064
1073
 
1065
- module.exports = { ConfigArrayFactory };
1074
+ module.exports = { ConfigArrayFactory, createContext };