UNPKG

4.45 kBJavaScriptView Raw
1"use strict";
2var __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})();
15Object.defineProperty(exports, "__esModule", { value: true });
16var ts = require("typescript");
17var Lint = require("tslint");
18var tsutils = require("tsutils");
19var Utils_1 = require("./utils/Utils");
20var MochaUtils_1 = require("./utils/MochaUtils");
21var FAILURE_STRING = 'Unneeded Mocha Done. Parameter can be safely removed: ';
22var Rule = (function (_super) {
23 __extends(Rule, _super);
24 function Rule() {
25 return _super !== null && _super.apply(this, arguments) || this;
26 }
27 Rule.prototype.apply = function (sourceFile) {
28 return this.applyWithFunction(sourceFile, walk);
29 };
30 Rule.metadata = {
31 ruleName: 'mocha-unneeded-done',
32 type: 'maintainability',
33 description: 'A function declares a MochaDone parameter but only resolves it synchronously in the main function.',
34 options: null,
35 optionsDescription: '',
36 typescriptOnly: true,
37 issueClass: 'Ignored',
38 issueType: 'Warning',
39 severity: 'Low',
40 level: 'Opportunity for Excellence',
41 group: 'Clarity'
42 };
43 return Rule;
44}(Lint.Rules.AbstractRule));
45exports.Rule = Rule;
46function walk(ctx) {
47 function validateMochaDoneUsage(node) {
48 var doneIdentifier = maybeGetMochaDoneParameter(node);
49 if (doneIdentifier === undefined) {
50 return;
51 }
52 if (!isIdentifierInvokedDirectlyInBody(doneIdentifier, node)) {
53 return;
54 }
55 var count = getReferenceCount(doneIdentifier, node.body);
56 if (count === 1) {
57 ctx.addFailureAt(doneIdentifier.getStart(), doneIdentifier.getWidth(), FAILURE_STRING + doneIdentifier.getText());
58 }
59 }
60 function isIdentifierInvokedDirectlyInBody(doneIdentifier, node) {
61 if (node.body === undefined || node.body.kind !== ts.SyntaxKind.Block) {
62 return false;
63 }
64 var block = node.body;
65 return Utils_1.Utils.exists(block.statements, function (statement) {
66 if (statement.kind === ts.SyntaxKind.ExpressionStatement) {
67 var expression = statement.expression;
68 if (expression.kind === ts.SyntaxKind.CallExpression) {
69 var leftHandSideExpression = expression.expression;
70 return leftHandSideExpression.getText() === doneIdentifier.getText();
71 }
72 }
73 return false;
74 });
75 }
76 function maybeGetMochaDoneParameter(node) {
77 if (node.parameters.length === 0) {
78 return undefined;
79 }
80 var allDones = node.parameters.filter(function (parameter) {
81 if (parameter.type !== undefined && parameter.type.getText() === 'MochaDone') {
82 return true;
83 }
84 return parameter.name.getText() === 'done';
85 });
86 if (allDones.length === 0 || allDones[0].name.kind !== ts.SyntaxKind.Identifier) {
87 return undefined;
88 }
89 return allDones[0].name;
90 }
91 function cb(node) {
92 if (tsutils.isArrowFunction(node) || tsutils.isFunctionExpression(node)) {
93 validateMochaDoneUsage(node);
94 }
95 return ts.forEachChild(node, cb);
96 }
97 if (MochaUtils_1.MochaUtils.isMochaTest(ctx.sourceFile)) {
98 ts.forEachChild(ctx.sourceFile, cb);
99 }
100}
101function getReferenceCount(identifier, body) {
102 var count = 0;
103 var identifierText = identifier.getText();
104 function cb(node) {
105 if (tsutils.isIdentifier(node)) {
106 if (node.getText() === identifierText) {
107 count += 1;
108 }
109 }
110 ts.forEachChild(node, cb);
111 }
112 body.statements.forEach(cb);
113 return count;
114}
115//# sourceMappingURL=mochaUnneededDoneRule.js.map
\No newline at end of file