new-parens.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /**
  2. * @fileoverview Rule to flag when using constructor without parentheses
  3. * @author Ilya Volodin
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("./utils/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. //------------------------------------------------------------------------------
  14. // Rule Definition
  15. //------------------------------------------------------------------------------
  16. module.exports = {
  17. meta: {
  18. type: "layout",
  19. docs: {
  20. description: "enforce or disallow parentheses when invoking a constructor with no arguments",
  21. category: "Stylistic Issues",
  22. recommended: false,
  23. url: "https://eslint.org/docs/rules/new-parens"
  24. },
  25. fixable: "code",
  26. schema: {
  27. anyOf: [
  28. {
  29. type: "array",
  30. items: [
  31. {
  32. enum: ["always", "never"]
  33. }
  34. ],
  35. minItems: 0,
  36. maxItems: 1
  37. }
  38. ]
  39. },
  40. messages: {
  41. missing: "Missing '()' invoking a constructor.",
  42. unnecessary: "Unnecessary '()' invoking a constructor with no arguments."
  43. }
  44. },
  45. create(context) {
  46. const options = context.options;
  47. const always = options[0] !== "never"; // Default is always
  48. const sourceCode = context.getSourceCode();
  49. return {
  50. NewExpression(node) {
  51. if (node.arguments.length !== 0) {
  52. return; // if there are arguments, there have to be parens
  53. }
  54. const lastToken = sourceCode.getLastToken(node);
  55. const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
  56. // `hasParens` is true only if the new expression ends with its own parens, e.g., new new foo() does not end with its own parens
  57. const hasParens = hasLastParen &&
  58. astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken)) &&
  59. node.callee.range[1] < node.range[1];
  60. if (always) {
  61. if (!hasParens) {
  62. context.report({
  63. node,
  64. messageId: "missing",
  65. fix: fixer => fixer.insertTextAfter(node, "()")
  66. });
  67. }
  68. } else {
  69. if (hasParens) {
  70. context.report({
  71. node,
  72. messageId: "unnecessary",
  73. fix: fixer => [
  74. fixer.remove(sourceCode.getTokenBefore(lastToken)),
  75. fixer.remove(lastToken),
  76. fixer.insertTextBefore(node, "("),
  77. fixer.insertTextAfter(node, ")")
  78. ]
  79. });
  80. }
  81. }
  82. }
  83. };
  84. }
  85. };