UNPKG

7.72 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22const utils_1 = require("@typescript-eslint/utils");
23const ts = __importStar(require("typescript"));
24const util = __importStar(require("../util"));
25exports.default = util.createRule({
26 name: 'promise-function-async',
27 meta: {
28 type: 'suggestion',
29 fixable: 'code',
30 docs: {
31 description: 'Requires any function or method that returns a Promise to be marked async',
32 recommended: false,
33 requiresTypeChecking: true,
34 },
35 messages: {
36 missingAsync: 'Functions that return promises must be async.',
37 },
38 schema: [
39 {
40 type: 'object',
41 properties: {
42 allowAny: {
43 type: 'boolean',
44 },
45 allowedPromiseNames: {
46 type: 'array',
47 items: {
48 type: 'string',
49 },
50 },
51 checkArrowFunctions: {
52 type: 'boolean',
53 },
54 checkFunctionDeclarations: {
55 type: 'boolean',
56 },
57 checkFunctionExpressions: {
58 type: 'boolean',
59 },
60 checkMethodDeclarations: {
61 type: 'boolean',
62 },
63 },
64 additionalProperties: false,
65 },
66 ],
67 },
68 defaultOptions: [
69 {
70 allowAny: true,
71 allowedPromiseNames: [],
72 checkArrowFunctions: true,
73 checkFunctionDeclarations: true,
74 checkFunctionExpressions: true,
75 checkMethodDeclarations: true,
76 },
77 ],
78 create(context, [{ allowAny, allowedPromiseNames, checkArrowFunctions, checkFunctionDeclarations, checkFunctionExpressions, checkMethodDeclarations, },]) {
79 const allAllowedPromiseNames = new Set([
80 'Promise',
81 ...allowedPromiseNames,
82 ]);
83 const parserServices = util.getParserServices(context);
84 const checker = parserServices.program.getTypeChecker();
85 const sourceCode = context.getSourceCode();
86 function validateNode(node) {
87 var _a;
88 const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
89 const signatures = checker
90 .getTypeAtLocation(originalNode)
91 .getCallSignatures();
92 if (!signatures.length) {
93 return;
94 }
95 const returnType = checker.getReturnTypeOfSignature(signatures[0]);
96 if (!util.containsAllTypesByName(returnType, allowAny, allAllowedPromiseNames)) {
97 // Return type is not a promise
98 return;
99 }
100 if (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition) {
101 // Abstract method can't be async
102 return;
103 }
104 if (node.parent &&
105 (node.parent.type === utils_1.AST_NODE_TYPES.Property ||
106 node.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition) &&
107 (node.parent.kind === 'get' || node.parent.kind === 'set')) {
108 // Getters and setters can't be async
109 return;
110 }
111 if (util.isTypeFlagSet(returnType, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) {
112 // Report without auto fixer because the return type is unknown
113 return context.report({
114 messageId: 'missingAsync',
115 node,
116 loc: util.getFunctionHeadLoc(node, sourceCode),
117 });
118 }
119 context.report({
120 messageId: 'missingAsync',
121 node,
122 loc: util.getFunctionHeadLoc(node, sourceCode),
123 fix: fixer => {
124 if (node.parent &&
125 (node.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
126 (node.parent.type === utils_1.AST_NODE_TYPES.Property &&
127 node.parent.method))) {
128 // this function is a class method or object function property shorthand
129 const method = node.parent;
130 // the token to put `async` before
131 let keyToken = sourceCode.getFirstToken(method);
132 // if there are decorators then skip past them
133 if (method.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
134 method.decorators) {
135 const lastDecorator = method.decorators[method.decorators.length - 1];
136 keyToken = sourceCode.getTokenAfter(lastDecorator);
137 }
138 // if current token is a keyword like `static` or `public` then skip it
139 while (keyToken.type === utils_1.AST_TOKEN_TYPES.Keyword) {
140 keyToken = sourceCode.getTokenAfter(keyToken);
141 }
142 // check if there is a space between key and previous token
143 const insertSpace = !sourceCode.isSpaceBetween(sourceCode.getTokenBefore(keyToken), keyToken);
144 let code = 'async ';
145 if (insertSpace) {
146 code = ` ${code}`;
147 }
148 return fixer.insertTextBefore(keyToken, code);
149 }
150 return fixer.insertTextBefore(node, 'async ');
151 },
152 });
153 }
154 return Object.assign(Object.assign(Object.assign({}, (checkArrowFunctions && {
155 'ArrowFunctionExpression[async = false]'(node) {
156 validateNode(node);
157 },
158 })), (checkFunctionDeclarations && {
159 'FunctionDeclaration[async = false]'(node) {
160 validateNode(node);
161 },
162 })), { 'FunctionExpression[async = false]'(node) {
163 if (node.parent &&
164 node.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
165 node.parent.kind === 'method') {
166 if (checkMethodDeclarations) {
167 validateNode(node);
168 }
169 return;
170 }
171 if (checkFunctionExpressions) {
172 validateNode(node);
173 }
174 } });
175 },
176});
177//# sourceMappingURL=promise-function-async.js.map
\No newline at end of file