spaceBeforeFunctionParenRule.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright 2016 Palantir Technologies, Inc.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. var tslib_1 = require("tslib");
  20. var tsutils_1 = require("tsutils");
  21. var ts = require("typescript");
  22. var Lint = require("../index");
  23. var ALWAYS_OR_NEVER = {
  24. enum: ["always", "never"],
  25. type: "string",
  26. };
  27. var Rule = /** @class */ (function (_super) {
  28. tslib_1.__extends(Rule, _super);
  29. function Rule() {
  30. return _super !== null && _super.apply(this, arguments) || this;
  31. }
  32. Rule.prototype.apply = function (sourceFile) {
  33. return this.applyWithFunction(sourceFile, walk, parseOptions(this.ruleArguments[0]));
  34. };
  35. Rule.metadata = {
  36. description: "Require or disallow a space before function parenthesis",
  37. hasFix: true,
  38. optionExamples: [
  39. true,
  40. [true, "always"],
  41. [true, "never"],
  42. [true, { anonymous: "always", named: "never", asyncArrow: "always" }],
  43. ],
  44. options: {
  45. properties: {
  46. anonymous: ALWAYS_OR_NEVER,
  47. asyncArrow: ALWAYS_OR_NEVER,
  48. constructor: ALWAYS_OR_NEVER,
  49. method: ALWAYS_OR_NEVER,
  50. named: ALWAYS_OR_NEVER,
  51. },
  52. type: "object",
  53. },
  54. optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n One argument which is an object which may contain the keys `anonymous`, `named`, and `asyncArrow`\n These should be set to either `\"always\"` or `\"never\"`.\n\n * `\"anonymous\"` checks before the opening paren in anonymous functions\n * `\"named\"` checks before the opening paren in named functions\n * `\"asyncArrow\"` checks before the opening paren in async arrow functions\n * `\"method\"` checks before the opening paren in class methods\n * `\"constructor\"` checks before the opening paren in class constructors\n "], ["\n One argument which is an object which may contain the keys \\`anonymous\\`, \\`named\\`, and \\`asyncArrow\\`\n These should be set to either \\`\"always\"\\` or \\`\"never\"\\`.\n\n * \\`\"anonymous\"\\` checks before the opening paren in anonymous functions\n * \\`\"named\"\\` checks before the opening paren in named functions\n * \\`\"asyncArrow\"\\` checks before the opening paren in async arrow functions\n * \\`\"method\"\\` checks before the opening paren in class methods\n * \\`\"constructor\"\\` checks before the opening paren in class constructors\n "]))),
  55. ruleName: "space-before-function-paren",
  56. type: "style",
  57. typescriptOnly: false,
  58. };
  59. Rule.INVALID_WHITESPACE_ERROR = "Spaces before function parens are disallowed";
  60. Rule.MISSING_WHITESPACE_ERROR = "Missing whitespace before function parens";
  61. return Rule;
  62. }(Lint.Rules.AbstractRule));
  63. exports.Rule = Rule;
  64. var optionNames = ["anonymous", "asyncArrow", "constructor", "method", "named"];
  65. function parseOptions(json) {
  66. // Need to specify constructor or it will be Object
  67. var options = { constructor: undefined };
  68. for (var _i = 0, optionNames_1 = optionNames; _i < optionNames_1.length; _i++) {
  69. var optionName = optionNames_1[_i];
  70. options[optionName] = typeof json === "object" ? json[optionName] : json === undefined ? "always" : json;
  71. }
  72. return options;
  73. }
  74. function walk(ctx) {
  75. var options = ctx.options, sourceFile = ctx.sourceFile;
  76. ts.forEachChild(sourceFile, function cb(node) {
  77. var option = getOption(node, options);
  78. if (option !== undefined) {
  79. check(node, option);
  80. }
  81. ts.forEachChild(node, cb);
  82. });
  83. function check(node, option) {
  84. var openParen = tsutils_1.getChildOfKind(node, ts.SyntaxKind.OpenParenToken, sourceFile);
  85. // openParen may be missing for an async arrow function `async x => ...`.
  86. if (openParen === undefined) {
  87. return;
  88. }
  89. var hasSpace = Lint.isWhiteSpace(sourceFile.text.charCodeAt(openParen.end - 2));
  90. if (hasSpace && option === "never") {
  91. var pos = openParen.getStart() - 1;
  92. ctx.addFailureAt(pos, 1, Rule.INVALID_WHITESPACE_ERROR, Lint.Replacement.deleteText(pos, 1));
  93. }
  94. else if (!hasSpace && option === "always") {
  95. var pos = openParen.getStart();
  96. ctx.addFailureAt(pos, 1, Rule.MISSING_WHITESPACE_ERROR, Lint.Replacement.appendText(pos, " "));
  97. }
  98. }
  99. }
  100. function getOption(node, options) {
  101. switch (node.kind) {
  102. case ts.SyntaxKind.ArrowFunction:
  103. return !hasTypeParameters(node) && tsutils_1.hasModifier(node.modifiers, ts.SyntaxKind.AsyncKeyword)
  104. ? options.asyncArrow : undefined;
  105. case ts.SyntaxKind.Constructor:
  106. return options.constructor;
  107. case ts.SyntaxKind.FunctionDeclaration:
  108. // name is optional for function declaration which is default export (TS will emit error in other cases).
  109. // Can be handled in the same way as function expression.
  110. case ts.SyntaxKind.FunctionExpression: {
  111. var functionName = node.name;
  112. var hasName = functionName !== undefined && functionName.text !== "";
  113. return hasName ? options.named : !hasTypeParameters(node) ? options.anonymous : undefined;
  114. }
  115. case ts.SyntaxKind.MethodDeclaration:
  116. case ts.SyntaxKind.MethodSignature:
  117. case ts.SyntaxKind.GetAccessor:
  118. case ts.SyntaxKind.SetAccessor:
  119. return options.method;
  120. default:
  121. return undefined;
  122. }
  123. }
  124. function hasTypeParameters(node) {
  125. return node.typeParameters !== undefined;
  126. }
  127. var templateObject_1;