templateUseTrackByFunctionRule.js 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. Object.defineProperty(exports, "__esModule", { value: true });
  16. var rules_1 = require("tslint/lib/rules");
  17. var ngWalker_1 = require("./angular/ngWalker");
  18. var basicTemplateAstVisitor_1 = require("./angular/templates/basicTemplateAstVisitor");
  19. var PATTERN = /trackBy\s*:|\[ngForTrackBy\]\s*=\s*['"].*['"]/;
  20. var currentOffset = 0;
  21. var Rule = (function (_super) {
  22. __extends(Rule, _super);
  23. function Rule() {
  24. return _super !== null && _super.apply(this, arguments) || this;
  25. }
  26. Rule.prototype.apply = function (sourceFile) {
  27. currentOffset = 0;
  28. var walkerConfig = { templateVisitorCtrl: TemplateVisitorCtrl };
  29. var walker = new ngWalker_1.NgWalker(sourceFile, this.getOptions(), walkerConfig);
  30. return this.applyWithWalker(walker);
  31. };
  32. Rule.metadata = {
  33. description: 'Ensures trackBy function is used.',
  34. options: null,
  35. optionsDescription: 'Not configurable.',
  36. rationale: "The use of 'trackBy' is considered a good practice.",
  37. ruleName: 'template-use-track-by-function',
  38. type: 'maintainability',
  39. typescriptOnly: true
  40. };
  41. Rule.FAILURE_STRING = 'Missing trackBy function in ngFor directive';
  42. return Rule;
  43. }(rules_1.AbstractRule));
  44. exports.Rule = Rule;
  45. var TemplateUseTrackByFunctionVisitor = (function (_super) {
  46. __extends(TemplateUseTrackByFunctionVisitor, _super);
  47. function TemplateUseTrackByFunctionVisitor() {
  48. return _super !== null && _super.apply(this, arguments) || this;
  49. }
  50. TemplateUseTrackByFunctionVisitor.prototype.visitDirectiveProperty = function (prop, context) {
  51. this.validateDirective(prop, context);
  52. _super.prototype.visitDirectiveProperty.call(this, prop, context);
  53. };
  54. TemplateUseTrackByFunctionVisitor.prototype.validateDirective = function (prop, context) {
  55. var templateName = prop.templateName;
  56. if (templateName !== 'ngForOf')
  57. return;
  58. var _a = prop.sourceSpan, endOffset = _a.end.offset, startOffset = _a.start.offset;
  59. if (PATTERN.test((context.codeWithMap.source || '').substr(currentOffset))) {
  60. currentOffset = endOffset;
  61. return;
  62. }
  63. context.addFailureFromStartToEnd(startOffset, endOffset, Rule.FAILURE_STRING);
  64. };
  65. return TemplateUseTrackByFunctionVisitor;
  66. }(basicTemplateAstVisitor_1.BasicTemplateAstVisitor));
  67. var TemplateVisitorCtrl = (function (_super) {
  68. __extends(TemplateVisitorCtrl, _super);
  69. function TemplateVisitorCtrl() {
  70. var _this = _super !== null && _super.apply(this, arguments) || this;
  71. _this.visitors = new Set([
  72. new TemplateUseTrackByFunctionVisitor(_this.getSourceFile(), _this.getOptions(), _this.context, _this.templateStart)
  73. ]);
  74. return _this;
  75. }
  76. TemplateVisitorCtrl.prototype.visitDirectiveProperty = function (prop, context) {
  77. var _this = this;
  78. this.visitors.forEach(function (visitor) { return visitor.visitDirectiveProperty(prop, _this); });
  79. _super.prototype.visitDirectiveProperty.call(this, prop, context);
  80. };
  81. return TemplateVisitorCtrl;
  82. }(basicTemplateAstVisitor_1.BasicTemplateAstVisitor));