preferInlineDecoratorRule.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. "use strict";
  2. var __extends = (this && this.__extends) || (function () {
  3. var extendStatics = function (d, b) {
  4. extendStatics = Object.setPrototypeOf ||
  5. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  6. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  7. return extendStatics(d, b);
  8. };
  9. return function (d, b) {
  10. extendStatics(d, b);
  11. function __() { this.constructor = d; }
  12. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  13. };
  14. })();
  15. var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
  16. if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
  17. return cooked;
  18. };
  19. var __assign = (this && this.__assign) || function () {
  20. __assign = Object.assign || function(t) {
  21. for (var s, i = 1, n = arguments.length; i < n; i++) {
  22. s = arguments[i];
  23. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  24. t[p] = s[p];
  25. }
  26. return t;
  27. };
  28. return __assign.apply(this, arguments);
  29. };
  30. var _a, _b, _c, _d, _e, _f;
  31. Object.defineProperty(exports, "__esModule", { value: true });
  32. var rules_1 = require("tslint/lib/rules");
  33. var utils_1 = require("tslint/lib/utils");
  34. var typescript_1 = require("typescript");
  35. var isNotNullOrUndefined_1 = require("./util/isNotNullOrUndefined");
  36. var objectKeys_1 = require("./util/objectKeys");
  37. var utils_2 = require("./util/utils");
  38. var OPTION_GETTERS = 'getters';
  39. var OPTION_METHODS = 'methods';
  40. var OPTION_PARAMETER_PROPERTIES = 'parameter-properties';
  41. var OPTION_PARAMETERS = 'parameters';
  42. var OPTION_PROPERTIES = 'properties';
  43. var OPTION_SETTERS = 'setters';
  44. var OPTION_SAFELIST = 'safelist';
  45. var OPTION_SCHEMA_VALUE = {
  46. oneOf: [
  47. {
  48. type: 'boolean'
  49. },
  50. {
  51. properties: {
  52. items: {
  53. type: 'string'
  54. },
  55. type: 'array',
  56. uniqueItems: true
  57. },
  58. type: 'object'
  59. }
  60. ]
  61. };
  62. var DEFAULT_OPTIONS = (_a = {},
  63. _a[OPTION_GETTERS] = true,
  64. _a[OPTION_METHODS] = true,
  65. _a[OPTION_PARAMETER_PROPERTIES] = true,
  66. _a[OPTION_PARAMETERS] = true,
  67. _a[OPTION_PROPERTIES] = true,
  68. _a[OPTION_SETTERS] = true,
  69. _a);
  70. var STYLE_GUIDE_LINK = 'https://angular.io/guide/styleguide#style-05-12';
  71. var Rule = (function (_super) {
  72. __extends(Rule, _super);
  73. function Rule() {
  74. return _super !== null && _super.apply(this, arguments) || this;
  75. }
  76. Rule.prototype.apply = function (sourceFile) {
  77. var options = __assign(__assign({}, DEFAULT_OPTIONS), this.ruleArguments[0]);
  78. return this.applyWithFunction(sourceFile, walk, options);
  79. };
  80. Rule.prototype.isEnabled = function () {
  81. return _super.prototype.isEnabled.call(this) && this.areOptionsValid();
  82. };
  83. Rule.prototype.areOptionsValid = function () {
  84. var ruleArgumentsLength = this.ruleArguments.length;
  85. if (ruleArgumentsLength === 0)
  86. return true;
  87. if (ruleArgumentsLength > 1)
  88. return false;
  89. var ruleOptions = Rule.metadata.options;
  90. var ruleArgument = this.ruleArguments[0];
  91. var ruleArgumentsKeys = objectKeys_1.objectKeys(ruleArgument);
  92. var propertiesKeys = objectKeys_1.objectKeys(ruleOptions.properties);
  93. return (ruleArgumentsKeys.every(function (argumentKey) { return propertiesKeys.indexOf(argumentKey) !== -1; }) &&
  94. ruleArgumentsKeys
  95. .map(function (argumentKey) { return ruleArgument[argumentKey]; })
  96. .every(function (argumentValue) {
  97. if (typeof argumentValue === 'boolean')
  98. return true;
  99. if (!argumentValue || typeof argumentValue !== 'object')
  100. return false;
  101. var argumentValueKeys = objectKeys_1.objectKeys(argumentValue);
  102. if (argumentValueKeys.length !== 1)
  103. return false;
  104. var safelist = argumentValue[argumentValueKeys[0]];
  105. return Array.isArray(safelist) && safelist.length > 0;
  106. }));
  107. };
  108. Rule.metadata = {
  109. description: 'Ensures that declarations are on the same line as its decorator(s).',
  110. descriptionDetails: "See more at " + STYLE_GUIDE_LINK + ".",
  111. optionExamples: [
  112. true,
  113. [true, (_b = {}, _b[OPTION_METHODS] = false, _b)],
  114. [
  115. true,
  116. (_c = {},
  117. _c[OPTION_GETTERS] = (_d = {},
  118. _d[OPTION_SAFELIST] = [utils_2.AngularInnerClassDecorators.Input],
  119. _d),
  120. _c[OPTION_METHODS] = true,
  121. _c[OPTION_PARAMETER_PROPERTIES] = false,
  122. _c[OPTION_PARAMETERS] = false,
  123. _c[OPTION_PROPERTIES] = (_e = {},
  124. _e[OPTION_SAFELIST] = [utils_2.AngularInnerClassDecorators.Output, 'MyCustomDecorator'],
  125. _e),
  126. _c[OPTION_SETTERS] = true,
  127. _c)
  128. ]
  129. ],
  130. options: {
  131. additionalProperties: false,
  132. properties: (_f = {},
  133. _f[OPTION_GETTERS] = OPTION_SCHEMA_VALUE,
  134. _f[OPTION_METHODS] = OPTION_SCHEMA_VALUE,
  135. _f[OPTION_PARAMETER_PROPERTIES] = OPTION_SCHEMA_VALUE,
  136. _f[OPTION_PARAMETERS] = OPTION_SCHEMA_VALUE,
  137. _f[OPTION_PROPERTIES] = OPTION_SCHEMA_VALUE,
  138. _f[OPTION_SETTERS] = OPTION_SCHEMA_VALUE,
  139. _f),
  140. type: 'object'
  141. },
  142. optionsDescription: utils_1.dedent(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n An optional object with optional `", "`, `", "`, `", "`, `", "`, `", "` and `", "` properties.\n\n The properties can be specifed as booleans or as objects with the property `", "` containing the names of the decorators that should be ignored. Note that if a declaration is decorated with multiple decorators and at least one of them is present in `", "`, this declaration is ignored.\n\n * `", "` - requires that ", " are on the same line as its decorator(s). Defaults to `true`.\n * `", "` - requires that ", " are on the same line as its decorator(s). Defaults to `true`.\n * `", "` - requires that parameter properties are on the same line as its decorator(s). Defaults to `true`.\n * `", "` - requires that ", " are on the same line as its decorator(s). Defaults to `true`.\n * `", "` - requires that ", " are on the same line as its decorator(s). Defaults to `true`.\n * `", "` - requires that ", " are on the same line as its decorator(s). Defaults to `true`.\n "], ["\n An optional object with optional \\`", "\\`, \\`", "\\`, \\`", "\\`, \\`", "\\`, \\`", "\\` and \\`", "\\` properties.\n\n The properties can be specifed as booleans or as objects with the property \\`", "\\` containing the names of the decorators that should be ignored. Note that if a declaration is decorated with multiple decorators and at least one of them is present in \\`", "\\`, this declaration is ignored.\n\n * \\`", "\\` - requires that ", " are on the same line as its decorator(s). Defaults to \\`true\\`.\n * \\`", "\\` - requires that ", " are on the same line as its decorator(s). Defaults to \\`true\\`.\n * \\`", "\\` - requires that parameter properties are on the same line as its decorator(s). Defaults to \\`true\\`.\n * \\`", "\\` - requires that ", " are on the same line as its decorator(s). Defaults to \\`true\\`.\n * \\`", "\\` - requires that ", " are on the same line as its decorator(s). Defaults to \\`true\\`.\n * \\`", "\\` - requires that ", " are on the same line as its decorator(s). Defaults to \\`true\\`.\n "])), OPTION_GETTERS, OPTION_METHODS, OPTION_PARAMETER_PROPERTIES, OPTION_PARAMETERS, OPTION_PROPERTIES, OPTION_SETTERS, OPTION_SAFELIST, OPTION_SAFELIST, OPTION_GETTERS, OPTION_GETTERS, OPTION_METHODS, OPTION_METHODS, OPTION_PARAMETER_PROPERTIES, OPTION_PARAMETERS, OPTION_PARAMETERS, OPTION_PROPERTIES, OPTION_PROPERTIES, OPTION_SETTERS, OPTION_SETTERS),
  143. rationale: 'Placing the decorator on the same line usually makes for shorter code and still easily identifies the declarations.',
  144. ruleName: 'prefer-inline-decorator',
  145. type: 'style',
  146. typescriptOnly: true
  147. };
  148. Rule.FAILURE_STRING = "Place declarations on the same line as its decorator(s) (" + STYLE_GUIDE_LINK + ")";
  149. return Rule;
  150. }(rules_1.AbstractRule));
  151. exports.Rule = Rule;
  152. var callbackHandler = function (walkContext, node) {
  153. var _a = walkContext.options, getters = _a.getters, methods = _a.methods, _b = OPTION_PARAMETER_PROPERTIES, parameterProperties = _a[_b], parameters = _a.parameters, properties = _a.properties, setters = _a.setters;
  154. if (getters && typescript_1.isGetAccessorDeclaration(node)) {
  155. validateGetAccessorDeclaration(walkContext, node);
  156. }
  157. else if (methods && typescript_1.isMethodDeclaration(node)) {
  158. validateMethodDeclaration(walkContext, node);
  159. }
  160. else if (parameters && typescript_1.isParameter(node) && !typescript_1.isParameterPropertyDeclaration(node, node.parent)) {
  161. validateParameterDeclaration(walkContext, node);
  162. }
  163. else if (parameterProperties && typescript_1.isParameterPropertyDeclaration(node, node.parent)) {
  164. validateParameterPropertyDeclaration(walkContext, node);
  165. }
  166. else if (properties && typescript_1.isPropertyDeclaration(node)) {
  167. validatePropertyDeclaration(walkContext, node);
  168. }
  169. else if (setters && typescript_1.isSetAccessorDeclaration(node)) {
  170. validateSetAccessorDeclaration(walkContext, node);
  171. }
  172. };
  173. var canIgnoreDecorator = function (walkContext, decoratorName, optionKey) {
  174. var _a = optionKey, optionValue = walkContext.options[_a];
  175. return optionValue && typeof optionValue === 'object' && optionValue.safelist.indexOf(decoratorName) !== -1;
  176. };
  177. var hasAnyIgnoredDecorator = function (walkContext, decorators, optionKey) {
  178. var nonIgnoredDecoratorNames = decorators
  179. .map(utils_2.getDecoratorName)
  180. .filter(isNotNullOrUndefined_1.isNotNullOrUndefined)
  181. .filter(function (decoratorName) { return !canIgnoreDecorator(walkContext, decoratorName, optionKey); });
  182. return decorators.length !== nonIgnoredDecoratorNames.length;
  183. };
  184. var validateDecorators = function (walkContext, decorators, declaration, optionKey) {
  185. if (decorators.length === 0 || hasAnyIgnoredDecorator(walkContext, decorators, optionKey))
  186. return;
  187. var firstDecorator = decorators[0];
  188. var firstDecoratorStartPos = firstDecorator.getStart();
  189. var declarationStartPos = declaration.name.getStart();
  190. if (utils_2.isSameLine(walkContext.sourceFile, firstDecoratorStartPos, declarationStartPos))
  191. return;
  192. walkContext.addFailureAt(firstDecoratorStartPos, declaration.getWidth(), Rule.FAILURE_STRING);
  193. };
  194. var validateDeclaration = function (walkContext, declaration, optionKey) {
  195. validateDecorators(walkContext, typescript_1.createNodeArray(declaration.decorators), declaration, optionKey);
  196. };
  197. var validateGetAccessorDeclaration = function (walkContext, node) {
  198. validateDeclaration(walkContext, node, OPTION_GETTERS);
  199. };
  200. var validateMethodDeclaration = function (walkContext, node) {
  201. validateDeclaration(walkContext, node, OPTION_METHODS);
  202. };
  203. var validateParameterDeclaration = function (walkContext, node) {
  204. validateDeclaration(walkContext, node, OPTION_PARAMETERS);
  205. };
  206. var validateParameterPropertyDeclaration = function (walkContext, node) {
  207. validateDeclaration(walkContext, node, OPTION_PARAMETER_PROPERTIES);
  208. };
  209. var validatePropertyDeclaration = function (walkContext, node) {
  210. validateDeclaration(walkContext, node, OPTION_PROPERTIES);
  211. };
  212. var validateSetAccessorDeclaration = function (walkContext, node) {
  213. validateDeclaration(walkContext, node, OPTION_SETTERS);
  214. };
  215. var walk = function (walkContext) {
  216. var sourceFile = walkContext.sourceFile;
  217. var callback = function (node) {
  218. callbackHandler(walkContext, node);
  219. typescript_1.forEachChild(node, callback);
  220. };
  221. typescript_1.forEachChild(sourceFile, callback);
  222. };
  223. var templateObject_1;