noUnnecessaryClassRule.js 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright 2017 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 ts = require("typescript");
  21. var Lint = require("../index");
  22. var tsutils_1 = require("tsutils");
  23. var OPTION__ALLOW_CONSTRUCTOR_ONLY = "allow-constructor-only";
  24. var OPTION__ALLOW_EMPTY_CLASS = "allow-empty-class";
  25. var OPTION__ALLOW_STATIC_ONLY = "allow-static-only";
  26. function parseOptions(options) {
  27. return {
  28. allowConstructorOnly: options.indexOf(OPTION__ALLOW_CONSTRUCTOR_ONLY) !== -1,
  29. allowEmptyClass: options.indexOf(OPTION__ALLOW_EMPTY_CLASS) !== -1,
  30. allowStaticOnly: options.indexOf(OPTION__ALLOW_STATIC_ONLY) !== -1,
  31. };
  32. }
  33. var Rule = /** @class */ (function (_super) {
  34. tslib_1.__extends(Rule, _super);
  35. function Rule() {
  36. return _super !== null && _super.apply(this, arguments) || this;
  37. }
  38. Rule.prototype.apply = function (sourceFile) {
  39. return this.applyWithWalker(new NoUnnecessaryClassWalker(sourceFile, this.ruleName, parseOptions(this.ruleArguments)));
  40. };
  41. /* tslint:disable:object-literal-sort-keys */
  42. Rule.metadata = {
  43. ruleName: "no-unnecessary-class",
  44. description: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Disallows classes that are not strictly necessary."], ["\n Disallows classes that are not strictly necessary."]))),
  45. rationale: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n Users who come from a Java-style OO language may wrap\n their utility functions in an extra class, instead of\n putting them at the top level."], ["\n Users who come from a Java-style OO language may wrap\n their utility functions in an extra class, instead of\n putting them at the top level."]))),
  46. optionsDescription: Lint.Utils.dedent(templateObject_3 || (templateObject_3 = tslib_1.__makeTemplateObject(["\n Three arguments may be optionally provided:\n\n * `\"allow-constructor-only\"` ignores classes whose members are constructors.\n * `\"allow-empty-class\"` ignores `class DemoClass {}`.\n * `\"allow-static-only\"` ignores classes whose members are static."], ["\n Three arguments may be optionally provided:\n\n * \\`\"allow-constructor-only\"\\` ignores classes whose members are constructors.\n * \\`\"allow-empty-class\"\\` ignores \\`class DemoClass {}\\`.\n * \\`\"allow-static-only\"\\` ignores classes whose members are static."]))),
  47. options: {
  48. type: "array",
  49. items: {
  50. type: "string",
  51. },
  52. minLength: 0,
  53. maxLength: 3,
  54. },
  55. optionExamples: [true, ["allow-empty-class", "allow-constructor-only"]],
  56. type: "functionality",
  57. typescriptOnly: false,
  58. };
  59. /* tslint:enable:object-literal-sort-keys */
  60. Rule.FAILURE_CONSTRUCTOR_ONLY = "Every member of this class is a constructor. Use functions instead.";
  61. Rule.FAILURE_STATIC_ONLY = "Every member of this class is static. Use namespaces or plain objects instead.";
  62. Rule.FAILURE_EMPTY_CLASS = "This class has no members.";
  63. return Rule;
  64. }(Lint.Rules.AbstractRule));
  65. exports.Rule = Rule;
  66. var NoUnnecessaryClassWalker = /** @class */ (function (_super) {
  67. tslib_1.__extends(NoUnnecessaryClassWalker, _super);
  68. function NoUnnecessaryClassWalker() {
  69. return _super !== null && _super.apply(this, arguments) || this;
  70. }
  71. NoUnnecessaryClassWalker.prototype.walk = function (sourceFile) {
  72. var _this = this;
  73. var checkIfUnnecessaryClass = function (node) {
  74. if (tsutils_1.isClassDeclaration(node) && !hasExtendsClause(node)) {
  75. _this.checkMembers(node);
  76. }
  77. return ts.forEachChild(node, checkIfUnnecessaryClass);
  78. };
  79. ts.forEachChild(sourceFile, checkIfUnnecessaryClass);
  80. };
  81. NoUnnecessaryClassWalker.prototype.checkMembers = function (node) {
  82. if (node.members.length === 0) {
  83. if (!this.options.allowEmptyClass) {
  84. this.addFailureAtNode(tsutils_1.getChildOfKind(node, ts.SyntaxKind.ClassKeyword), Rule.FAILURE_EMPTY_CLASS);
  85. }
  86. return;
  87. }
  88. var allMembersAreConstructors = node.members.every(tsutils_1.isConstructorDeclaration);
  89. if (allMembersAreConstructors &&
  90. !this.options.allowConstructorOnly &&
  91. !node.members.some(isConstructorWithShorthandProps)) {
  92. this.addFailureAtNode(tsutils_1.getChildOfKind(node, ts.SyntaxKind.ClassKeyword, this.sourceFile), Rule.FAILURE_CONSTRUCTOR_ONLY);
  93. }
  94. if (!allMembersAreConstructors &&
  95. !this.options.allowStaticOnly &&
  96. !node.members.some(isNonStaticMember)) {
  97. this.addFailureAtNode(tsutils_1.getChildOfKind(node, ts.SyntaxKind.ClassKeyword, this.sourceFile), Rule.FAILURE_STATIC_ONLY);
  98. }
  99. };
  100. return NoUnnecessaryClassWalker;
  101. }(Lint.AbstractWalker));
  102. function isNonStaticMember(member) {
  103. return (isConstructorWithShorthandProps(member) ||
  104. (!tsutils_1.isConstructorDeclaration(member) && !tsutils_1.hasModifier(member.modifiers, ts.SyntaxKind.StaticKeyword)));
  105. }
  106. function hasExtendsClause(declaration) {
  107. return (declaration.heritageClauses !== undefined &&
  108. declaration.heritageClauses[0].token === ts.SyntaxKind.ExtendsKeyword);
  109. }
  110. function isConstructorWithShorthandProps(member) {
  111. return tsutils_1.isConstructorDeclaration(member) && member.parameters.some(tsutils_1.isParameterProperty);
  112. }
  113. var templateObject_1, templateObject_2, templateObject_3;