new-parens.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * @fileoverview Rule to flag when using constructor without parentheses
  3. * @author Ilya Volodin
  4. * @deprecated in ESLint v8.53.0
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Requirements
  9. //------------------------------------------------------------------------------
  10. const astUtils = require("./utils/ast-utils");
  11. //------------------------------------------------------------------------------
  12. // Helpers
  13. //------------------------------------------------------------------------------
  14. //------------------------------------------------------------------------------
  15. // Rule Definition
  16. //------------------------------------------------------------------------------
  17. /** @type {import('../types').Rule.RuleModule} */
  18. module.exports = {
  19. meta: {
  20. deprecated: {
  21. message: "Formatting rules are being moved out of ESLint core.",
  22. url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
  23. deprecatedSince: "8.53.0",
  24. availableUntil: "11.0.0",
  25. replacedBy: [
  26. {
  27. message:
  28. "ESLint Stylistic now maintains deprecated stylistic core rules.",
  29. url: "https://eslint.style/guide/migration",
  30. plugin: {
  31. name: "@stylistic/eslint-plugin",
  32. url: "https://eslint.style",
  33. },
  34. rule: {
  35. name: "new-parens",
  36. url: "https://eslint.style/rules/new-parens",
  37. },
  38. },
  39. ],
  40. },
  41. type: "layout",
  42. docs: {
  43. description:
  44. "Enforce or disallow parentheses when invoking a constructor with no arguments",
  45. recommended: false,
  46. url: "https://eslint.org/docs/latest/rules/new-parens",
  47. },
  48. fixable: "code",
  49. schema: [
  50. {
  51. enum: ["always", "never"],
  52. },
  53. ],
  54. messages: {
  55. missing: "Missing '()' invoking a constructor.",
  56. unnecessary:
  57. "Unnecessary '()' invoking a constructor with no arguments.",
  58. },
  59. },
  60. create(context) {
  61. const options = context.options;
  62. const always = options[0] !== "never"; // Default is always
  63. const sourceCode = context.sourceCode;
  64. return {
  65. NewExpression(node) {
  66. if (node.arguments.length !== 0) {
  67. return; // if there are arguments, there have to be parens
  68. }
  69. const lastToken = sourceCode.getLastToken(node);
  70. const hasLastParen =
  71. lastToken && astUtils.isClosingParenToken(lastToken);
  72. // `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
  73. const hasParens =
  74. hasLastParen &&
  75. astUtils.isOpeningParenToken(
  76. sourceCode.getTokenBefore(lastToken),
  77. ) &&
  78. node.callee.range[1] < node.range[1];
  79. if (always) {
  80. if (!hasParens) {
  81. context.report({
  82. node,
  83. messageId: "missing",
  84. fix: fixer => fixer.insertTextAfter(node, "()"),
  85. });
  86. }
  87. } else {
  88. if (hasParens) {
  89. context.report({
  90. node,
  91. messageId: "unnecessary",
  92. fix: fixer => [
  93. fixer.remove(
  94. sourceCode.getTokenBefore(lastToken),
  95. ),
  96. fixer.remove(lastToken),
  97. fixer.insertTextBefore(node, "("),
  98. fixer.insertTextAfter(node, ")"),
  99. ],
  100. });
  101. }
  102. }
  103. },
  104. };
  105. },
  106. };