UNPKG

7.38 kBJavaScriptView Raw
1var __extends = (this && this.__extends) || function (d, b) {
2 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
3 function __() { this.constructor = d; }
4 __.prototype = b.prototype;
5 d.prototype = new __();
6};
7var SyntaxKind = require('./utils/SyntaxKind');
8var ErrorTolerantWalker = require('./utils/ErrorTolerantWalker');
9var AstUtils = require('./utils/AstUtils');
10var Utils = require('./utils/Utils');
11var Rule = (function (_super) {
12 __extends(Rule, _super);
13 function Rule() {
14 _super.apply(this, arguments);
15 }
16 Rule.prototype.apply = function (sourceFile) {
17 return this.applyWithWalker(new PromiseAnalyzer(sourceFile, this.getOptions()));
18 };
19 Rule.FAILURE_STRING = 'A Promise was found that appears to not have resolve or reject invoked on all code paths';
20 return Rule;
21})(Lint.Rules.AbstractRule);
22exports.Rule = Rule;
23var PromiseAnalyzer = (function (_super) {
24 __extends(PromiseAnalyzer, _super);
25 function PromiseAnalyzer() {
26 _super.apply(this, arguments);
27 }
28 PromiseAnalyzer.prototype.isPromiseDeclaration = function (node) {
29 if (node.expression.kind === SyntaxKind.current().Identifier
30 && node.expression.getText() === 'Promise'
31 && node.arguments != null && node.arguments.length > 0) {
32 var firstArg = node.arguments[0];
33 if (firstArg.kind === SyntaxKind.current().ArrowFunction || firstArg.kind === SyntaxKind.current().FunctionExpression) {
34 return true;
35 }
36 }
37 return false;
38 };
39 PromiseAnalyzer.prototype.getCompletionIdentifiers = function (declaration) {
40 var result = [];
41 if (declaration.parameters == null || declaration.parameters.length === 0) {
42 return result;
43 }
44 var arg1 = declaration.parameters[0];
45 var arg2 = declaration.parameters[1];
46 if (arg1 != null && arg1.name.kind === SyntaxKind.current().Identifier) {
47 result.push(declaration.parameters[0].name);
48 }
49 if (arg2 != null && arg2.name.kind === SyntaxKind.current().Identifier) {
50 result.push(declaration.parameters[1].name);
51 }
52 return result;
53 };
54 PromiseAnalyzer.prototype.visitNewExpression = function (node) {
55 if (this.isPromiseDeclaration(node)) {
56 var functionArgument = node.arguments[0];
57 var functionBody = functionArgument.body;
58 var competionIdentifiers = this.getCompletionIdentifiers(functionArgument);
59 this.validatePromiseUsage(node, functionBody, competionIdentifiers);
60 }
61 _super.prototype.visitNewExpression.call(this, node);
62 };
63 PromiseAnalyzer.prototype.validatePromiseUsage = function (promiseInstantiation, block, completionIdentifiers) {
64 var blockAnalyzer = new PromiseCompletionWalker(this.getSourceFile(), this.getOptions(), completionIdentifiers);
65 blockAnalyzer.visitNode(block);
66 if (!blockAnalyzer.isAlwaysCompleted()) {
67 var failure = this.createFailure(promiseInstantiation.getStart(), promiseInstantiation.getWidth(), Rule.FAILURE_STRING);
68 this.addFailure(failure);
69 }
70 };
71 return PromiseAnalyzer;
72})(ErrorTolerantWalker);
73var PromiseCompletionWalker = (function (_super) {
74 __extends(PromiseCompletionWalker, _super);
75 function PromiseCompletionWalker(sourceFile, options, completionIdentifiers) {
76 _super.call(this, sourceFile, options);
77 this.wasCompleted = false;
78 this.allBranchesCompleted = true;
79 this.hasBranches = false;
80 this.walkerOptions = options;
81 this.completionIdentifiers = completionIdentifiers;
82 }
83 PromiseCompletionWalker.prototype.visitNode = function (node) {
84 _super.prototype.visitNode.call(this, node);
85 };
86 PromiseCompletionWalker.prototype.isAlwaysCompleted = function () {
87 if (this.wasCompleted) {
88 return true;
89 }
90 if (!this.hasBranches) {
91 return false;
92 }
93 return this.allBranchesCompleted;
94 };
95 PromiseCompletionWalker.prototype.visitIfStatement = function (node) {
96 this.hasBranches = true;
97 var ifAnalyzer = new PromiseCompletionWalker(this.getSourceFile(), this.walkerOptions, this.completionIdentifiers);
98 var elseAnalyzer = new PromiseCompletionWalker(this.getSourceFile(), this.walkerOptions, this.completionIdentifiers);
99 ifAnalyzer.visitNode(node.thenStatement);
100 if (!ifAnalyzer.isAlwaysCompleted()) {
101 this.allBranchesCompleted = false;
102 }
103 else if (node.elseStatement != null) {
104 elseAnalyzer.visitNode(node.elseStatement);
105 if (!elseAnalyzer.isAlwaysCompleted()) {
106 this.allBranchesCompleted = false;
107 }
108 }
109 };
110 PromiseCompletionWalker.prototype.visitCallExpression = function (node) {
111 var _this = this;
112 if (node.expression.kind === SyntaxKind.current().Identifier) {
113 if (this.isCompletionIdentifier(node.expression)) {
114 this.wasCompleted = true;
115 return;
116 }
117 }
118 var referenceEscaped = Utils.exists(node.arguments, function (argument) {
119 return _this.isCompletionIdentifier(argument);
120 });
121 if (referenceEscaped) {
122 this.wasCompleted = true;
123 return;
124 }
125 _super.prototype.visitCallExpression.call(this, node);
126 };
127 PromiseCompletionWalker.prototype.visitArrowFunction = function (node) {
128 var nonShadowedIdentifiers = this.getNonShadowedCompletionIdentifiers(node);
129 var analyzer = new PromiseCompletionWalker(this.getSourceFile(), this.walkerOptions, nonShadowedIdentifiers);
130 analyzer.visitNode(node.body);
131 if (analyzer.isAlwaysCompleted()) {
132 this.wasCompleted = true;
133 }
134 };
135 PromiseCompletionWalker.prototype.visitFunctionExpression = function (node) {
136 var nonShadowedIdentifiers = this.getNonShadowedCompletionIdentifiers(node);
137 var analyzer = new PromiseCompletionWalker(this.getSourceFile(), this.walkerOptions, nonShadowedIdentifiers);
138 analyzer.visitNode(node.body);
139 if (analyzer.isAlwaysCompleted()) {
140 this.wasCompleted = true;
141 }
142 };
143 PromiseCompletionWalker.prototype.getNonShadowedCompletionIdentifiers = function (declaration) {
144 var result = [];
145 this.completionIdentifiers.forEach(function (identifier) {
146 var isShadowed = Utils.exists(declaration.parameters, function (parameter) {
147 return AstUtils.isSameIdentifer(identifier, parameter.name);
148 });
149 if (!isShadowed) {
150 result.push(identifier);
151 }
152 });
153 return result;
154 };
155 PromiseCompletionWalker.prototype.isCompletionIdentifier = function (sourceIdentifier) {
156 return Utils.exists(this.completionIdentifiers, function (identifier) {
157 return AstUtils.isSameIdentifer(sourceIdentifier, identifier);
158 });
159 };
160 return PromiseCompletionWalker;
161})(ErrorTolerantWalker);
162//# sourceMappingURL=promiseMustCompleteRule.js.map
\No newline at end of file