eslint 5.12.0 → 5.14.1

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 (146) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +76 -143
  3. package/conf/eslint-all.js +3 -5
  4. package/conf/eslint-recommended.js +4 -268
  5. package/lib/built-in-rules-index.js +277 -0
  6. package/lib/cli-engine.js +6 -2
  7. package/lib/config/config-file.js +25 -2
  8. package/lib/config/config-initializer.js +150 -143
  9. package/lib/config/config-ops.js +30 -0
  10. package/lib/config/config-rule.js +2 -4
  11. package/lib/config/plugins.js +12 -4
  12. package/lib/config.js +1 -1
  13. package/lib/formatters/table.js +13 -4
  14. package/lib/formatters/tap.js +7 -4
  15. package/lib/linter.js +31 -31
  16. package/lib/load-rules.js +2 -5
  17. package/lib/rules/accessor-pairs.js +4 -2
  18. package/lib/rules/array-bracket-newline.js +4 -2
  19. package/lib/rules/array-callback-return.js +2 -1
  20. package/lib/rules/array-element-newline.js +4 -2
  21. package/lib/rules/arrow-body-style.js +1 -1
  22. package/lib/rules/arrow-parens.js +2 -1
  23. package/lib/rules/arrow-spacing.js +7 -6
  24. package/lib/rules/brace-style.js +2 -1
  25. package/lib/rules/camelcase.js +3 -2
  26. package/lib/rules/capitalized-comments.js +15 -14
  27. package/lib/rules/class-methods-use-this.js +1 -1
  28. package/lib/rules/comma-spacing.js +10 -4
  29. package/lib/rules/complexity.js +7 -9
  30. package/lib/rules/consistent-return.js +2 -1
  31. package/lib/rules/dot-notation.js +5 -3
  32. package/lib/rules/eqeqeq.js +2 -1
  33. package/lib/rules/for-direction.js +30 -17
  34. package/lib/rules/func-call-spacing.js +2 -1
  35. package/lib/rules/func-style.js +3 -2
  36. package/lib/rules/getter-return.js +2 -1
  37. package/lib/rules/global-require.js +5 -2
  38. package/lib/rules/guard-for-in.js +5 -2
  39. package/lib/rules/handle-callback-err.js +5 -2
  40. package/lib/rules/id-blacklist.js +4 -1
  41. package/lib/rules/id-length.js +9 -6
  42. package/lib/rules/id-match.js +11 -5
  43. package/lib/rules/implicit-arrow-linebreak.js +7 -3
  44. package/lib/rules/indent-legacy.js +11 -5
  45. package/lib/rules/indent.js +18 -9
  46. package/lib/rules/init-declarations.js +13 -13
  47. package/lib/rules/jsx-quotes.js +5 -2
  48. package/lib/rules/key-spacing.js +70 -35
  49. package/lib/rules/keyword-spacing.js +18 -12
  50. package/lib/rules/line-comment-position.js +15 -8
  51. package/lib/rules/linebreak-style.js +6 -6
  52. package/lib/rules/lines-around-comment.js +20 -16
  53. package/lib/rules/lines-around-directive.js +5 -2
  54. package/lib/rules/lines-between-class-members.js +8 -6
  55. package/lib/rules/max-depth.js +11 -9
  56. package/lib/rules/max-len.js +24 -13
  57. package/lib/rules/max-lines-per-function.js +17 -18
  58. package/lib/rules/max-lines.js +14 -10
  59. package/lib/rules/max-nested-callbacks.js +12 -11
  60. package/lib/rules/max-params.js +11 -9
  61. package/lib/rules/max-statements-per-line.js +8 -5
  62. package/lib/rules/max-statements.js +12 -11
  63. package/lib/rules/multiline-comment-style.js +18 -17
  64. package/lib/rules/multiline-ternary.js +8 -6
  65. package/lib/rules/new-cap.js +18 -11
  66. package/lib/rules/new-parens.js +5 -2
  67. package/lib/rules/newline-after-var.js +6 -8
  68. package/lib/rules/newline-before-return.js +5 -1
  69. package/lib/rules/newline-per-chained-call.js +7 -3
  70. package/lib/rules/no-async-promise-executor.js +5 -2
  71. package/lib/rules/no-bitwise.js +2 -1
  72. package/lib/rules/no-confusing-arrow.js +1 -1
  73. package/lib/rules/no-constant-condition.js +24 -2
  74. package/lib/rules/no-duplicate-imports.js +17 -11
  75. package/lib/rules/no-else-return.js +2 -1
  76. package/lib/rules/no-empty.js +2 -1
  77. package/lib/rules/no-eval.js +1 -1
  78. package/lib/rules/no-extra-parens.js +4 -4
  79. package/lib/rules/no-fallthrough.js +8 -4
  80. package/lib/rules/no-floating-decimal.js +7 -3
  81. package/lib/rules/no-implicit-coercion.js +9 -6
  82. package/lib/rules/no-irregular-whitespace.js +8 -4
  83. package/lib/rules/no-labels.js +6 -4
  84. package/lib/rules/no-magic-numbers.js +6 -3
  85. package/lib/rules/no-mixed-operators.js +5 -4
  86. package/lib/rules/no-mixed-requires.js +4 -2
  87. package/lib/rules/no-multi-spaces.js +2 -1
  88. package/lib/rules/no-param-reassign.js +1 -1
  89. package/lib/rules/no-plusplus.js +2 -1
  90. package/lib/rules/no-redeclare.js +2 -2
  91. package/lib/rules/no-self-assign.js +2 -1
  92. package/lib/rules/no-shadow-restricted-names.js +16 -2
  93. package/lib/rules/no-shadow.js +3 -3
  94. package/lib/rules/no-sync.js +2 -1
  95. package/lib/rules/no-tabs.js +2 -1
  96. package/lib/rules/no-trailing-spaces.js +5 -3
  97. package/lib/rules/no-undef.js +7 -3
  98. package/lib/rules/no-underscore-dangle.js +6 -3
  99. package/lib/rules/no-unexpected-multiline.js +14 -13
  100. package/lib/rules/no-unneeded-ternary.js +2 -1
  101. package/lib/rules/no-unsafe-negation.js +6 -3
  102. package/lib/rules/no-unused-expressions.js +6 -3
  103. package/lib/rules/no-unused-labels.js +7 -2
  104. package/lib/rules/no-unused-vars.js +8 -4
  105. package/lib/rules/no-use-before-define.js +3 -3
  106. package/lib/rules/no-useless-rename.js +3 -3
  107. package/lib/rules/object-curly-newline.js +6 -4
  108. package/lib/rules/object-property-newline.js +5 -3
  109. package/lib/rules/object-shorthand.js +9 -5
  110. package/lib/rules/one-var.js +24 -38
  111. package/lib/rules/operator-assignment.js +8 -4
  112. package/lib/rules/padded-blocks.js +32 -9
  113. package/lib/rules/prefer-arrow-callback.js +4 -2
  114. package/lib/rules/prefer-const.js +7 -4
  115. package/lib/rules/prefer-destructuring.js +70 -12
  116. package/lib/rules/prefer-promise-reject-errors.js +1 -1
  117. package/lib/rules/prefer-spread.js +2 -13
  118. package/lib/rules/quote-props.js +10 -5
  119. package/lib/rules/quotes.js +4 -2
  120. package/lib/rules/require-jsdoc.js +13 -7
  121. package/lib/rules/semi-spacing.js +6 -8
  122. package/lib/rules/semi.js +5 -4
  123. package/lib/rules/sort-imports.js +6 -3
  124. package/lib/rules/sort-keys.js +13 -5
  125. package/lib/rules/sort-vars.js +2 -1
  126. package/lib/rules/space-before-function-paren.js +6 -3
  127. package/lib/rules/space-infix-ops.js +2 -1
  128. package/lib/rules/space-unary-ops.js +20 -10
  129. package/lib/rules/spaced-comment.js +2 -1
  130. package/lib/rules/strict.js +34 -35
  131. package/lib/rules/switch-colon-spacing.js +11 -8
  132. package/lib/rules/symbol-description.js +6 -3
  133. package/lib/rules/template-curly-spacing.js +10 -10
  134. package/lib/rules/template-tag-spacing.js +7 -3
  135. package/lib/rules/unicode-bom.js +7 -3
  136. package/lib/rules/use-isnan.js +5 -2
  137. package/lib/rules/valid-jsdoc.js +40 -19
  138. package/lib/rules/valid-typeof.js +9 -4
  139. package/lib/rules/vars-on-top.js +6 -4
  140. package/lib/rules/wrap-iife.js +12 -6
  141. package/lib/rules/yield-star-spacing.js +17 -10
  142. package/lib/rules/yoda.js +9 -4
  143. package/lib/rules.js +4 -34
  144. package/lib/util/ajv.js +1 -0
  145. package/lib/util/config-comment-parser.js +7 -10
  146. package/package.json +20 -20
@@ -3,6 +3,7 @@
3
3
  * @author Ilya Volodin
4
4
  */
5
5
 
6
+
6
7
  "use strict";
7
8
 
8
9
  //------------------------------------------------------------------------------
@@ -28,6 +29,8 @@ const debug = require("debug")("eslint:config-initializer");
28
29
  // Private
29
30
  //------------------------------------------------------------------------------
30
31
 
32
+ const DEFAULT_ECMA_VERSION = 2018;
33
+
31
34
  /* istanbul ignore next: hard to test fs function */
32
35
  /**
33
36
  * Create .eslintrc file in the current working directory
@@ -239,43 +242,65 @@ function configureRules(answers, config) {
239
242
  * @returns {Object} config object
240
243
  */
241
244
  function processAnswers(answers) {
242
- let config = { rules: {}, env: {}, parserOptions: {} };
245
+ let config = {
246
+ rules: {},
247
+ env: {},
248
+ parserOptions: {},
249
+ extends: []
250
+ };
243
251
 
244
- config.parserOptions.ecmaVersion = answers.ecmaVersion;
245
- if (answers.ecmaVersion >= 2015) {
246
- if (answers.modules) {
247
- config.parserOptions.sourceType = "module";
248
- }
249
- config.env.es6 = true;
250
- }
252
+ // set the latest ECMAScript version
253
+ config.parserOptions.ecmaVersion = DEFAULT_ECMA_VERSION;
254
+ config.env.es6 = true;
255
+ config.globals = {
256
+ Atomics: "readonly",
257
+ SharedArrayBuffer: "readonly"
258
+ };
251
259
 
252
- if (answers.commonjs) {
260
+ // set the module type
261
+ if (answers.moduleType === "esm") {
262
+ config.parserOptions.sourceType = "module";
263
+ } else if (answers.moduleType === "commonjs") {
253
264
  config.env.commonjs = true;
254
265
  }
266
+
267
+ // add in browser and node environments if necessary
255
268
  answers.env.forEach(env => {
256
269
  config.env[env] = true;
257
270
  });
258
- if (answers.jsx) {
259
- config.parserOptions = config.parserOptions || {};
260
- config.parserOptions.ecmaFeatures = config.parserOptions.ecmaFeatures || {};
261
- config.parserOptions.ecmaFeatures.jsx = true;
262
- if (answers.react) {
263
- config.plugins = ["react"];
264
- config.parserOptions.ecmaVersion = 2018;
265
- }
271
+
272
+ // add in library information
273
+ if (answers.framework === "react") {
274
+ config.parserOptions.ecmaFeatures = {
275
+ jsx: true
276
+ };
277
+ config.plugins = ["react"];
278
+ } else if (answers.framework === "vue") {
279
+ config.plugins = ["vue"];
280
+ config.extends.push("plugin:vue/essential");
266
281
  }
267
282
 
268
- if (answers.source === "prompt") {
269
- config.extends = "eslint:recommended";
270
- config.rules.indent = ["error", answers.indent];
271
- config.rules.quotes = ["error", answers.quotes];
272
- config.rules["linebreak-style"] = ["error", answers.linebreak];
273
- config.rules.semi = ["error", answers.semi ? "always" : "never"];
283
+ // setup rules based on problems/style enforcement preferences
284
+ if (answers.purpose === "problems") {
285
+ config.extends.unshift("eslint:recommended");
286
+ } else if (answers.purpose === "style") {
287
+ if (answers.source === "prompt") {
288
+ config.extends.unshift("eslint:recommended");
289
+ config.rules.indent = ["error", answers.indent];
290
+ config.rules.quotes = ["error", answers.quotes];
291
+ config.rules["linebreak-style"] = ["error", answers.linebreak];
292
+ config.rules.semi = ["error", answers.semi ? "always" : "never"];
293
+ } else if (answers.source === "auto") {
294
+ config = configureRules(answers, config);
295
+ config = autoconfig.extendFromRecommended(config);
296
+ }
274
297
  }
275
298
 
276
- if (answers.source === "auto") {
277
- config = configureRules(answers, config);
278
- config = autoconfig.extendFromRecommended(config);
299
+ // normalize extends
300
+ if (config.extends.length === 0) {
301
+ delete config.extends;
302
+ } else if (config.extends.length === 1) {
303
+ config.extends = config.extends[0];
279
304
  }
280
305
 
281
306
  ConfigOps.normalizeToStrings(config);
@@ -324,7 +349,7 @@ function getLocalESLintVersion() {
324
349
  * @returns {string} The shareable config name.
325
350
  */
326
351
  function getStyleGuideName(answers) {
327
- if (answers.styleguide === "airbnb" && !answers.airbnbReact) {
352
+ if (answers.styleguide === "airbnb" && answers.framework !== "react") {
328
353
  return "airbnb-base";
329
354
  }
330
355
  return answers.styleguide;
@@ -417,16 +442,62 @@ function askInstallModules(modules, packageJsonExists) {
417
442
  function promptUser() {
418
443
 
419
444
  return inquirer.prompt([
445
+ {
446
+ type: "list",
447
+ name: "purpose",
448
+ message: "How would you like to use ESLint?",
449
+ default: "problems",
450
+ choices: [
451
+ { name: "To check syntax only", value: "syntax" },
452
+ { name: "To check syntax and find problems", value: "problems" },
453
+ { name: "To check syntax, find problems, and enforce code style", value: "style" }
454
+ ]
455
+ },
456
+ {
457
+ type: "list",
458
+ name: "moduleType",
459
+ message: "What type of modules does your project use?",
460
+ default: "esm",
461
+ choices: [
462
+ { name: "JavaScript modules (import/export)", value: "esm" },
463
+ { name: "CommonJS (require/exports)", value: "commonjs" },
464
+ { name: "None of these", value: "none" }
465
+ ]
466
+ },
467
+ {
468
+ type: "list",
469
+ name: "framework",
470
+ message: "Which framework does your project use?",
471
+ default: "react",
472
+ choices: [
473
+ { name: "React", value: "react" },
474
+ { name: "Vue.js", value: "vue" },
475
+ { name: "None of these", value: "none" }
476
+ ]
477
+ },
478
+ {
479
+ type: "checkbox",
480
+ name: "env",
481
+ message: "Where does your code run?",
482
+ default: ["browser"],
483
+ choices: [
484
+ { name: "Browser", value: "browser" },
485
+ { name: "Node", value: "node" }
486
+ ]
487
+ },
420
488
  {
421
489
  type: "list",
422
490
  name: "source",
423
- message: "How would you like to configure ESLint?",
424
- default: "prompt",
491
+ message: "How would you like to define a style for your project?",
492
+ default: "guide",
425
493
  choices: [
426
494
  { name: "Use a popular style guide", value: "guide" },
427
495
  { name: "Answer questions about your style", value: "prompt" },
428
496
  { name: "Inspect your JavaScript file(s)", value: "auto" }
429
- ]
497
+ ],
498
+ when(answers) {
499
+ return answers.purpose === "style";
500
+ }
430
501
  },
431
502
  {
432
503
  type: "list",
@@ -442,15 +513,6 @@ function promptUser() {
442
513
  return answers.source === "guide" && answers.packageJsonExists;
443
514
  }
444
515
  },
445
- {
446
- type: "confirm",
447
- name: "airbnbReact",
448
- message: "Do you use React?",
449
- default: false,
450
- when(answers) {
451
- return answers.styleguide === "airbnb";
452
- }
453
- },
454
516
  {
455
517
  type: "input",
456
518
  name: "patterns",
@@ -470,10 +532,7 @@ function promptUser() {
470
532
  name: "format",
471
533
  message: "What format do you want your config file to be in?",
472
534
  default: "JavaScript",
473
- choices: ["JavaScript", "YAML", "JSON"],
474
- when(answers) {
475
- return ((answers.source === "guide" && answers.packageJsonExists) || answers.source === "auto");
476
- }
535
+ choices: ["JavaScript", "YAML", "JSON"]
477
536
  },
478
537
  {
479
538
  type: "confirm",
@@ -492,6 +551,15 @@ function promptUser() {
492
551
  }
493
552
  ]).then(earlyAnswers => {
494
553
 
554
+ // early exit if no style guide is necessary
555
+ if (earlyAnswers.purpose !== "style") {
556
+ const config = processAnswers(earlyAnswers);
557
+ const modules = getModulesList(config);
558
+
559
+ return askInstallModules(modules, earlyAnswers.packageJsonExists)
560
+ .then(() => writeFile(config, earlyAnswers.format));
561
+ }
562
+
495
563
  // early exit if you are using a style guide
496
564
  if (earlyAnswers.source === "guide") {
497
565
  if (!earlyAnswers.packageJsonExists) {
@@ -501,130 +569,69 @@ function promptUser() {
501
569
  if (earlyAnswers.installESLint === false && !semver.satisfies(earlyAnswers.localESLintVersion, earlyAnswers.requiredESLintVersionRange)) {
502
570
  log.info(`Note: it might not work since ESLint's version is mismatched with the ${earlyAnswers.styleguide} config.`);
503
571
  }
504
- if (earlyAnswers.styleguide === "airbnb" && !earlyAnswers.airbnbReact) {
572
+ if (earlyAnswers.styleguide === "airbnb" && earlyAnswers.framework !== "react") {
505
573
  earlyAnswers.styleguide = "airbnb-base";
506
574
  }
507
575
 
508
- const config = getConfigForStyleGuide(earlyAnswers.styleguide);
576
+ const config = ConfigOps.merge(processAnswers(earlyAnswers), getConfigForStyleGuide(earlyAnswers.styleguide));
509
577
  const modules = getModulesList(config);
510
578
 
511
579
  return askInstallModules(modules, earlyAnswers.packageJsonExists)
512
580
  .then(() => writeFile(config, earlyAnswers.format));
581
+
513
582
  }
514
583
 
515
- // continue with the questions otherwise...
584
+ if (earlyAnswers.source === "auto") {
585
+ const combinedAnswers = Object.assign({}, earlyAnswers);
586
+ const config = processAnswers(combinedAnswers);
587
+ const modules = getModulesList(config);
588
+
589
+ return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
590
+ }
591
+
592
+ // continue with the style questions otherwise...
516
593
  return inquirer.prompt([
517
594
  {
518
595
  type: "list",
519
- name: "ecmaVersion",
520
- message: "Which version of ECMAScript do you use?",
521
- choices: [
522
- { name: "ES3", value: 3 },
523
- { name: "ES5", value: 5 },
524
- { name: "ES2015", value: 2015 },
525
- { name: "ES2016", value: 2016 },
526
- { name: "ES2017", value: 2017 },
527
- { name: "ES2018", value: 2018 }
528
- ],
529
- default: 1 // This is the index in the choices list
596
+ name: "indent",
597
+ message: "What style of indentation do you use?",
598
+ default: "tab",
599
+ choices: [{ name: "Tabs", value: "tab" }, { name: "Spaces", value: 4 }]
530
600
  },
531
601
  {
532
- type: "confirm",
533
- name: "modules",
534
- message: "Are you using ES6 modules?",
535
- default: false,
536
- when(answers) {
537
- return answers.ecmaVersion >= 2015;
538
- }
539
- },
540
- {
541
- type: "checkbox",
542
- name: "env",
543
- message: "Where will your code run?",
544
- default: ["browser"],
545
- choices: [{ name: "Browser", value: "browser" }, { name: "Node", value: "node" }]
602
+ type: "list",
603
+ name: "quotes",
604
+ message: "What quotes do you use for strings?",
605
+ default: "double",
606
+ choices: [{ name: "Double", value: "double" }, { name: "Single", value: "single" }]
546
607
  },
547
608
  {
548
- type: "confirm",
549
- name: "commonjs",
550
- message: "Do you use CommonJS?",
551
- default: false,
552
- when(answers) {
553
- return answers.env.some(env => env === "browser");
554
- }
609
+ type: "list",
610
+ name: "linebreak",
611
+ message: "What line endings do you use?",
612
+ default: "unix",
613
+ choices: [{ name: "Unix", value: "unix" }, { name: "Windows", value: "windows" }]
555
614
  },
556
615
  {
557
616
  type: "confirm",
558
- name: "jsx",
559
- message: "Do you use JSX?",
560
- default: false
617
+ name: "semi",
618
+ message: "Do you require semicolons?",
619
+ default: true
561
620
  },
562
621
  {
563
- type: "confirm",
564
- name: "react",
565
- message: "Do you use React?",
566
- default: false,
567
- when(answers) {
568
- return answers.jsx;
569
- }
570
- }
571
- ]).then(secondAnswers => {
572
-
573
- // early exit if you are using automatic style generation
574
- if (earlyAnswers.source === "auto") {
575
- const combinedAnswers = Object.assign({}, earlyAnswers, secondAnswers);
576
-
577
- const config = processAnswers(combinedAnswers);
578
-
579
- const modules = getModulesList(config);
580
-
581
- return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
622
+ type: "list",
623
+ name: "format",
624
+ message: "What format do you want your config file to be in?",
625
+ default: "JavaScript",
626
+ choices: ["JavaScript", "YAML", "JSON"]
582
627
  }
628
+ ]).then(answers => {
629
+ const totalAnswers = Object.assign({}, earlyAnswers, answers);
583
630
 
584
- // continue with the style questions otherwise...
585
- return inquirer.prompt([
586
- {
587
- type: "list",
588
- name: "indent",
589
- message: "What style of indentation do you use?",
590
- default: "tab",
591
- choices: [{ name: "Tabs", value: "tab" }, { name: "Spaces", value: 4 }]
592
- },
593
- {
594
- type: "list",
595
- name: "quotes",
596
- message: "What quotes do you use for strings?",
597
- default: "double",
598
- choices: [{ name: "Double", value: "double" }, { name: "Single", value: "single" }]
599
- },
600
- {
601
- type: "list",
602
- name: "linebreak",
603
- message: "What line endings do you use?",
604
- default: "unix",
605
- choices: [{ name: "Unix", value: "unix" }, { name: "Windows", value: "windows" }]
606
- },
607
- {
608
- type: "confirm",
609
- name: "semi",
610
- message: "Do you require semicolons?",
611
- default: true
612
- },
613
- {
614
- type: "list",
615
- name: "format",
616
- message: "What format do you want your config file to be in?",
617
- default: "JavaScript",
618
- choices: ["JavaScript", "YAML", "JSON"]
619
- }
620
- ]).then(answers => {
621
- const totalAnswers = Object.assign({}, earlyAnswers, secondAnswers, answers);
622
-
623
- const config = processAnswers(totalAnswers);
624
- const modules = getModulesList(config);
631
+ const config = processAnswers(totalAnswers);
632
+ const modules = getModulesList(config);
625
633
 
626
- return askInstallModules(modules).then(() => writeFile(config, answers.format));
627
- });
634
+ return askInstallModules(modules).then(() => writeFile(config, answers.format));
628
635
  });
629
636
  });
630
637
  }
@@ -370,5 +370,35 @@ module.exports = {
370
370
 
371
371
  return patternList.some(pattern => minimatch(filePath, pattern, opts)) &&
372
372
  !excludedPatternList.some(excludedPattern => minimatch(filePath, excludedPattern, opts));
373
+ },
374
+
375
+ /**
376
+ * Normalizes a value for a global in a config
377
+ * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
378
+ * a global directive comment
379
+ * @returns {("readable"|"writeable"|"off")} The value normalized as a string
380
+ */
381
+ normalizeConfigGlobal(configuredValue) {
382
+ switch (configuredValue) {
383
+ case "off":
384
+ return "off";
385
+
386
+ case true:
387
+ case "true":
388
+ case "writeable":
389
+ case "writable":
390
+ return "writeable";
391
+
392
+ case null:
393
+ case false:
394
+ case "false":
395
+ case "readable":
396
+ case "readonly":
397
+ return "readable";
398
+
399
+ // Fallback to minimize compatibility impact
400
+ default:
401
+ return "writeable";
402
+ }
373
403
  }
374
404
  };
@@ -10,7 +10,7 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const Rules = require("../rules"),
13
- loadRules = require("../load-rules");
13
+ builtInRules = require("../built-in-rules-index");
14
14
 
15
15
  const rules = new Rules();
16
16
 
@@ -299,9 +299,7 @@ function generateConfigsFromSchema(schema) {
299
299
  * @returns {rulesConfig} Hash of rule names and arrays of possible configurations
300
300
  */
301
301
  function createCoreRuleConfigs() {
302
- const ruleList = loadRules();
303
-
304
- return Object.keys(ruleList).reduce((accumulator, id) => {
302
+ return Object.keys(builtInRules).reduce((accumulator, id) => {
305
303
  const rule = rules.get(id);
306
304
  const schema = (typeof rule === "function") ? rule.schema : rule.meta.schema;
307
305
 
@@ -24,12 +24,12 @@ class Plugins {
24
24
  /**
25
25
  * Creates the plugins context
26
26
  * @param {Environments} envContext - env context
27
- * @param {Rules} rulesContext - rules context
27
+ * @param {function(string, Rule): void} defineRule - Callback for when a plugin is defined which introduces rules
28
28
  */
29
- constructor(envContext, rulesContext) {
29
+ constructor(envContext, defineRule) {
30
30
  this._plugins = Object.create(null);
31
31
  this._environments = envContext;
32
- this._rules = rulesContext;
32
+ this._defineRule = defineRule;
33
33
  }
34
34
 
35
35
  /**
@@ -45,7 +45,15 @@ class Plugins {
45
45
  // load up environments and rules
46
46
  this._plugins[shortName] = plugin;
47
47
  this._environments.importPlugin(plugin, shortName);
48
- this._rules.importPlugin(plugin, shortName);
48
+
49
+ if (plugin.rules) {
50
+ Object.keys(plugin.rules).forEach(ruleId => {
51
+ const qualifiedRuleId = `${shortName}/${ruleId}`,
52
+ rule = plugin.rules[ruleId];
53
+
54
+ this._defineRule(qualifiedRuleId, rule);
55
+ });
56
+ }
49
57
  }
50
58
 
51
59
  /**
package/lib/config.js CHANGED
@@ -71,7 +71,7 @@ class Config {
71
71
  const options = providedOptions || {};
72
72
 
73
73
  this.linterContext = linterContext;
74
- this.plugins = new Plugins(linterContext.environments, linterContext.rules);
74
+ this.plugins = new Plugins(linterContext.environments, linterContext.defineRule.bind(linterContext));
75
75
 
76
76
  this.options = options;
77
77
  this.ignore = options.ignore;
@@ -9,13 +9,22 @@
9
9
  //------------------------------------------------------------------------------
10
10
 
11
11
  const chalk = require("chalk"),
12
- table = require("table").table,
13
- pluralize = require("pluralize");
12
+ table = require("table").table;
14
13
 
15
14
  //------------------------------------------------------------------------------
16
15
  // Helpers
17
16
  //------------------------------------------------------------------------------
18
17
 
18
+ /**
19
+ * Given a word and a count, append an "s" if count is not one.
20
+ * @param {string} word A word.
21
+ * @param {number} count Quantity.
22
+ * @returns {string} The original word with an s on the end if count is not one.
23
+ */
24
+ function pluralize(word, count) {
25
+ return (count === 1 ? word : `${word}s`);
26
+ }
27
+
19
28
  /**
20
29
  * Draws text table.
21
30
  * @param {Array<Object>} messages Error messages relating to a specific file.
@@ -129,10 +138,10 @@ module.exports = function(report) {
129
138
 
130
139
  result += `\n${table([
131
140
  [
132
- chalk.red(pluralize("Error", errorCount, true))
141
+ chalk.red(pluralize(`${errorCount} Error`, errorCount))
133
142
  ],
134
143
  [
135
- chalk.yellow(pluralize("Warning", warningCount, true))
144
+ chalk.yellow(pluralize(`${warningCount} Warning`, warningCount))
136
145
  ]
137
146
  ], {
138
147
  columns: {
@@ -20,7 +20,6 @@ function getMessageType(message) {
20
20
  return "error";
21
21
  }
22
22
  return "warning";
23
-
24
23
  }
25
24
 
26
25
  /**
@@ -50,12 +49,11 @@ module.exports = function(results) {
50
49
  let diagnostics = {};
51
50
 
52
51
  if (messages.length > 0) {
53
- testResult = "not ok";
54
-
55
52
  messages.forEach(message => {
53
+ const severity = getMessageType(message);
56
54
  const diagnostic = {
57
55
  message: message.message,
58
- severity: getMessageType(message),
56
+ severity,
59
57
  data: {
60
58
  line: message.line || 0,
61
59
  column: message.column || 0,
@@ -63,6 +61,11 @@ module.exports = function(results) {
63
61
  }
64
62
  };
65
63
 
64
+ // This ensures a warning message is not flagged as error
65
+ if (severity === "error") {
66
+ testResult = "not ok";
67
+ }
68
+
66
69
  /*
67
70
  * If we have multiple messages place them under a messages key
68
71
  * The first error will be logged as message key