3.1 KB104 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8module.exports = {
9 meta: {
10 type: 'problem',
11 docs: {
12 description:
13 'Require explicit type annotations for callback parameters in Internal API promise chains (.then and .catch)',
14 },
15 fixable: null, // Not automatically fixable
16 messages: {
17 missingTypeAnnotation:
18 'Parameters in callbacks for Internal API promise chains must have explicit type annotations to avoid "any" type errors when mirrored to open source.',
19 },
20 schema: [], // no options
21 },
22 create(context) {
23 // Helper function to check if a node is part of an Internal API call chain
24 function isInternalApiCall(node) {
25 // Start from the object of the .then() call and traverse up
26 let current = node;
27
28 while (current) {
29 // Check for direct Internal.something pattern
30 if (
31 current.type === 'MemberExpression' &&
32 current.object &&
33 current.object.type === 'Identifier' &&
34 current.object.name === 'Internal'
35 ) {
36 return true;
37 }
38
39 // Check for property access on Internal
40 if (current.type === 'MemberExpression' && current.object) {
41 current = current.object;
42 continue;
43 }
44
45 // Check for call expressions
46 if (current.type === 'CallExpression' && current.callee) {
47 current = current.callee;
48 continue;
49 }
50
51 // Check for optional chaining
52 if (current.type === 'ChainExpression' && current.expression) {
53 current = current.expression;
54 continue;
55 }
56
57 // If we can't traverse further up, break the loop
58 break;
59 }
60
61 return false;
62 }
63
64 return {
65 // Look for .then() and .catch() calls
66 'CallExpression[callee.property.name="then"], CallExpression[callee.property.name="catch"]'(
67 node,
68 ) {
69 const methodName = node.callee.property.name;
70
71 // Check if the object of the .then() or .catch() call is part of an Internal API call chain
72 if (!isInternalApiCall(node.callee.object)) {
73 return;
74 }
75
76 // Check if there are arguments to the call
77 if (!node.arguments || node.arguments.length === 0) {
78 return;
79 }
80
81 // Get the callback function (first argument to .then() or .catch())
82 const callback = node.arguments[0];
83
84 // Check if it's an arrow function or function expression
85 if (callback.type !== 'ArrowFunctionExpression' && callback.type !== 'FunctionExpression') {
86 return;
87 }
88
89 // Check each parameter for type annotations
90 const params = callback.params || [];
91 for (const param of params) {
92 // If the parameter doesn't have a type annotation, report an error
93 if (!param.typeAnnotation) {
94 context.report({
95 node: param,
96 messageId: 'missingTypeAnnotation',
97 });
98 }
99 }
100 },
101 };
102 },
103};
104