📄 explicit-module-boundary-types.ts
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 13 |
📦 Imports | 15 |
📊 Variables & Constants | 8 |
📑 Type Aliases | 2 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts
📦 Imports¶
Name | Source |
---|---|
TSESTree |
@typescript-eslint/utils |
DefinitionType |
@typescript-eslint/scope-manager |
AST_NODE_TYPES |
@typescript-eslint/utils |
FunctionExpression |
../util/explicitReturnTypeUtils |
FunctionInfo |
../util/explicitReturnTypeUtils |
FunctionNode |
../util/explicitReturnTypeUtils |
createRule |
../util |
hasOverloadSignatures |
../util |
isFunction |
../util |
isStaticMemberAccessOfValue |
../util |
ancestorHasReturnType |
../util/explicitReturnTypeUtils |
checkFunctionExpressionReturnType |
../util/explicitReturnTypeUtils |
checkFunctionReturnType |
../util/explicitReturnTypeUtils |
doesImmediatelyReturnFunctionExpression |
../util/explicitReturnTypeUtils |
isTypedFunctionExpression |
../util/explicitReturnTypeUtils |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
checkedFunctions |
Set<any> |
const | new Set<FunctionNode>() |
✗ |
functionStack |
FunctionNode[] |
const | [] |
✗ |
functionReturnsMap |
Map<any, TSESTree.ReturnStatement[]> |
const | `new Map< | |
FunctionNode, | ||||
TSESTree.ReturnStatement[] | ||||
>()` | ✗ | |||
alreadyVisited |
Set<TSESTree.Node> |
const | new Set<TSESTree.Node>() |
✗ |
current |
any |
const | functionStack[functionStack.length - 1] |
✗ |
current |
TSESTree.Node | undefined |
let/var | node.parent |
✗ |
isConstructor |
boolean |
const | `node.parent.type === AST_NODE_TYPES.MethodDefinition && | |
node.parent.kind === 'constructor'` | ✗ | |||
isSetAccessor |
boolean |
const | `(node.parent.type === AST_NODE_TYPES.TSAbstractMethodDefinition | |
node.parent.type === AST_NODE_TYPES.MethodDefinition) && | ||||
node.parent.kind === 'set'` | ✗ |
Functions¶
getReturnsInFunction(node: FunctionNode): TSESTree.ReturnStatement[]
¶
Code
- Parameters:
node: FunctionNode
- Return Type:
TSESTree.ReturnStatement[]
- Calls:
functionReturnsMap.get
enterFunction(node: FunctionNode): void
¶
Code
- Parameters:
node: FunctionNode
- Return Type:
void
- Calls:
functionStack.push
functionReturnsMap.set
exitFunction(): void
¶
- Return Type:
void
- Calls:
functionStack.pop
checkParameters(node: FunctionNode | TSESTree.TSEmptyBodyFunctionExpression): void
¶
Code
function checkParameters(
node: FunctionNode | TSESTree.TSEmptyBodyFunctionExpression,
): void {
function checkParameter(param: TSESTree.Parameter): void {
function report(
namedMessageId: MessageIds,
unnamedMessageId: MessageIds,
): void {
if (param.type === AST_NODE_TYPES.Identifier) {
context.report({
node: param,
messageId: namedMessageId,
data: { name: param.name },
});
} else if (param.type === AST_NODE_TYPES.ArrayPattern) {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Array pattern' },
});
} else if (param.type === AST_NODE_TYPES.ObjectPattern) {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Object pattern' },
});
} else if (param.type === AST_NODE_TYPES.RestElement) {
if (param.argument.type === AST_NODE_TYPES.Identifier) {
context.report({
node: param,
messageId: namedMessageId,
data: { name: param.argument.name },
});
} else {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Rest' },
});
}
}
}
switch (param.type) {
case AST_NODE_TYPES.ArrayPattern:
case AST_NODE_TYPES.Identifier:
case AST_NODE_TYPES.ObjectPattern:
case AST_NODE_TYPES.RestElement:
if (!param.typeAnnotation) {
report('missingArgType', 'missingArgTypeUnnamed');
} else if (
options.allowArgumentsExplicitlyTypedAsAny !== true &&
param.typeAnnotation.typeAnnotation.type ===
AST_NODE_TYPES.TSAnyKeyword
) {
report('anyTypedArg', 'anyTypedArgUnnamed');
}
return;
case AST_NODE_TYPES.TSParameterProperty:
return checkParameter(param.parameter);
case AST_NODE_TYPES.AssignmentPattern: // ignored as it has a type via its assignment
return;
}
}
for (const arg of node.params) {
checkParameter(arg);
}
}
- Parameters:
node: FunctionNode | TSESTree.TSEmptyBodyFunctionExpression
- Return Type:
void
- Calls:
context.report
report
checkParameter
checkParameter(param: TSESTree.Parameter): void
¶
Code
function checkParameter(param: TSESTree.Parameter): void {
function report(
namedMessageId: MessageIds,
unnamedMessageId: MessageIds,
): void {
if (param.type === AST_NODE_TYPES.Identifier) {
context.report({
node: param,
messageId: namedMessageId,
data: { name: param.name },
});
} else if (param.type === AST_NODE_TYPES.ArrayPattern) {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Array pattern' },
});
} else if (param.type === AST_NODE_TYPES.ObjectPattern) {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Object pattern' },
});
} else if (param.type === AST_NODE_TYPES.RestElement) {
if (param.argument.type === AST_NODE_TYPES.Identifier) {
context.report({
node: param,
messageId: namedMessageId,
data: { name: param.argument.name },
});
} else {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Rest' },
});
}
}
}
switch (param.type) {
case AST_NODE_TYPES.ArrayPattern:
case AST_NODE_TYPES.Identifier:
case AST_NODE_TYPES.ObjectPattern:
case AST_NODE_TYPES.RestElement:
if (!param.typeAnnotation) {
report('missingArgType', 'missingArgTypeUnnamed');
} else if (
options.allowArgumentsExplicitlyTypedAsAny !== true &&
param.typeAnnotation.typeAnnotation.type ===
AST_NODE_TYPES.TSAnyKeyword
) {
report('anyTypedArg', 'anyTypedArgUnnamed');
}
return;
case AST_NODE_TYPES.TSParameterProperty:
return checkParameter(param.parameter);
case AST_NODE_TYPES.AssignmentPattern: // ignored as it has a type via its assignment
return;
}
}
- Parameters:
param: TSESTree.Parameter
- Return Type:
void
- Calls:
context.report
report
checkParameter
report(namedMessageId: MessageIds, unnamedMessageId: MessageIds): void
¶
Code
function report(
namedMessageId: MessageIds,
unnamedMessageId: MessageIds,
): void {
if (param.type === AST_NODE_TYPES.Identifier) {
context.report({
node: param,
messageId: namedMessageId,
data: { name: param.name },
});
} else if (param.type === AST_NODE_TYPES.ArrayPattern) {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Array pattern' },
});
} else if (param.type === AST_NODE_TYPES.ObjectPattern) {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Object pattern' },
});
} else if (param.type === AST_NODE_TYPES.RestElement) {
if (param.argument.type === AST_NODE_TYPES.Identifier) {
context.report({
node: param,
messageId: namedMessageId,
data: { name: param.argument.name },
});
} else {
context.report({
node: param,
messageId: unnamedMessageId,
data: { type: 'Rest' },
});
}
}
}
- Parameters:
namedMessageId: MessageIds
unnamedMessageId: MessageIds
- Return Type:
void
- Calls:
context.report
isAllowedName(node: TSESTree.Node | undefined): boolean
¶
Code
function isAllowedName(node: TSESTree.Node | undefined): boolean {
if (!node || !options.allowedNames || options.allowedNames.length === 0) {
return false;
}
if (
node.type === AST_NODE_TYPES.VariableDeclarator ||
node.type === AST_NODE_TYPES.FunctionDeclaration
) {
return (
node.id?.type === AST_NODE_TYPES.Identifier &&
options.allowedNames.includes(node.id.name)
);
}
if (
node.type === AST_NODE_TYPES.MethodDefinition ||
node.type === AST_NODE_TYPES.TSAbstractMethodDefinition ||
(node.type === AST_NODE_TYPES.Property && node.method) ||
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
return isStaticMemberAccessOfValue(
node,
context,
...options.allowedNames,
);
}
return false;
}
-
JSDoc:
-
Parameters:
node: TSESTree.Node | undefined
- Return Type:
boolean
- Calls:
options.allowedNames.includes
isStaticMemberAccessOfValue (from ../util)
`isExportedHigherOrderFunction({¶
node,
}: FunctionInfo<FunctionNode>): boolean`
Code
function isExportedHigherOrderFunction({
node,
}: FunctionInfo<FunctionNode>): boolean {
let current: TSESTree.Node | undefined = node.parent;
while (current) {
if (current.type === AST_NODE_TYPES.ReturnStatement) {
// the parent of a return will always be a block statement, so we can skip over it
current = current.parent.parent;
continue;
}
if (!isFunction(current)) {
return false;
}
const returns = getReturnsInFunction(current);
if (
!doesImmediatelyReturnFunctionExpression({ node: current, returns })
) {
return false;
}
if (checkedFunctions.has(current)) {
return true;
}
current = current.parent;
}
return false;
}
- Parameters:
{ node, }: FunctionInfo<FunctionNode>
- Return Type:
boolean
- Calls:
isFunction (from ../util)
getReturnsInFunction
doesImmediatelyReturnFunctionExpression (from ../util/explicitReturnTypeUtils)
checkedFunctions.has
- Internal Comments:
followReference(node: TSESTree.Identifier): void
¶
Code
function followReference(node: TSESTree.Identifier): void {
const scope = context.sourceCode.getScope(node);
const variable = scope.set.get(node.name);
/* istanbul ignore if */ if (!variable) {
return;
}
// check all of the definitions
for (const definition of variable.defs) {
// cases we don't care about in this rule
if (
[
DefinitionType.CatchClause,
DefinitionType.ImplicitGlobalVariable,
DefinitionType.ImportBinding,
DefinitionType.Parameter,
].includes(definition.type)
) {
continue;
}
checkNode(definition.node);
}
// follow references to find writes to the variable
for (const reference of variable.references) {
if (
// we don't want to check the initialization ref, as this is handled by the declaration check
!reference.init &&
reference.writeExpr
) {
checkNode(reference.writeExpr);
}
}
}
- Parameters:
node: TSESTree.Identifier
- Return Type:
void
- Calls:
context.sourceCode.getScope
scope.set.get
[ DefinitionType.CatchClause, DefinitionType.ImplicitGlobalVariable, DefinitionType.ImportBinding, DefinitionType.Parameter, ].includes
checkNode
- Internal Comments:
checkNode(node: TSESTree.Node | null): void
¶
Code
function checkNode(node: TSESTree.Node | null): void {
if (node == null || alreadyVisited.has(node)) {
return;
}
alreadyVisited.add(node);
switch (node.type) {
case AST_NODE_TYPES.ArrowFunctionExpression:
case AST_NODE_TYPES.FunctionExpression: {
const returns = getReturnsInFunction(node);
return checkFunctionExpression({ node, returns });
}
case AST_NODE_TYPES.ArrayExpression:
for (const element of node.elements) {
checkNode(element);
}
return;
case AST_NODE_TYPES.PropertyDefinition:
case AST_NODE_TYPES.AccessorProperty:
case AST_NODE_TYPES.MethodDefinition:
case AST_NODE_TYPES.TSAbstractMethodDefinition:
if (
node.accessibility === 'private' ||
node.key.type === AST_NODE_TYPES.PrivateIdentifier
) {
return;
}
return checkNode(node.value);
case AST_NODE_TYPES.ClassDeclaration:
case AST_NODE_TYPES.ClassExpression:
for (const element of node.body.body) {
checkNode(element);
}
return;
case AST_NODE_TYPES.FunctionDeclaration: {
const returns = getReturnsInFunction(node);
return checkFunction({ node, returns });
}
case AST_NODE_TYPES.Identifier:
return followReference(node);
case AST_NODE_TYPES.ObjectExpression:
for (const property of node.properties) {
checkNode(property);
}
return;
case AST_NODE_TYPES.Property:
return checkNode(node.value);
case AST_NODE_TYPES.TSEmptyBodyFunctionExpression:
return checkEmptyBodyFunctionExpression(node);
case AST_NODE_TYPES.VariableDeclaration:
for (const declaration of node.declarations) {
checkNode(declaration);
}
return;
case AST_NODE_TYPES.VariableDeclarator:
return checkNode(node.init);
}
}
- Parameters:
node: TSESTree.Node | null
- Return Type:
void
- Calls:
alreadyVisited.has
alreadyVisited.add
getReturnsInFunction
checkFunctionExpression
checkNode
checkFunction
followReference
checkEmptyBodyFunctionExpression
checkEmptyBodyFunctionExpression(node: TSESTree.TSEmptyBodyFunctionExpression): void
¶
Code
function checkEmptyBodyFunctionExpression(
node: TSESTree.TSEmptyBodyFunctionExpression,
): void {
const isConstructor =
node.parent.type === AST_NODE_TYPES.MethodDefinition &&
node.parent.kind === 'constructor';
const isSetAccessor =
(node.parent.type === AST_NODE_TYPES.TSAbstractMethodDefinition ||
node.parent.type === AST_NODE_TYPES.MethodDefinition) &&
node.parent.kind === 'set';
if (!isConstructor && !isSetAccessor && !node.returnType) {
context.report({
node,
messageId: 'missingReturnType',
});
}
checkParameters(node);
}
- Parameters:
node: TSESTree.TSEmptyBodyFunctionExpression
- Return Type:
void
- Calls:
context.report
checkParameters
`checkFunctionExpression({¶
node,
returns,
}: FunctionInfo<FunctionExpression>): void`
Code
function checkFunctionExpression({
node,
returns,
}: FunctionInfo<FunctionExpression>): void {
if (checkedFunctions.has(node)) {
return;
}
checkedFunctions.add(node);
if (
isAllowedName(node.parent) ||
isTypedFunctionExpression(node, options) ||
ancestorHasReturnType(node)
) {
return;
}
if (
options.allowOverloadFunctions &&
node.parent.type === AST_NODE_TYPES.MethodDefinition &&
hasOverloadSignatures(node.parent, context)
) {
return;
}
checkFunctionExpressionReturnType(
{ node, returns },
options,
context.sourceCode,
loc => {
context.report({
loc,
node,
messageId: 'missingReturnType',
});
},
);
checkParameters(node);
}
- Parameters:
{ node, returns, }: FunctionInfo<FunctionExpression>
- Return Type:
void
- Calls:
checkedFunctions.has
checkedFunctions.add
isAllowedName
isTypedFunctionExpression (from ../util/explicitReturnTypeUtils)
ancestorHasReturnType (from ../util/explicitReturnTypeUtils)
hasOverloadSignatures (from ../util)
checkFunctionExpressionReturnType (from ../util/explicitReturnTypeUtils)
context.report
checkParameters
`checkFunction({¶
node,
returns,
}: FunctionInfo<TSESTree.FunctionDeclaration>): void`
Code
function checkFunction({
node,
returns,
}: FunctionInfo<TSESTree.FunctionDeclaration>): void {
if (checkedFunctions.has(node)) {
return;
}
checkedFunctions.add(node);
if (isAllowedName(node) || ancestorHasReturnType(node)) {
return;
}
if (
options.allowOverloadFunctions &&
hasOverloadSignatures(node, context)
) {
return;
}
checkFunctionReturnType(
{ node, returns },
options,
context.sourceCode,
loc => {
context.report({
loc,
node,
messageId: 'missingReturnType',
});
},
);
checkParameters(node);
}
- Parameters:
{ node, returns, }: FunctionInfo<TSESTree.FunctionDeclaration>
- Return Type:
void
- Calls:
checkedFunctions.has
checkedFunctions.add
isAllowedName
ancestorHasReturnType (from ../util/explicitReturnTypeUtils)
hasOverloadSignatures (from ../util)
checkFunctionReturnType (from ../util/explicitReturnTypeUtils)
context.report
checkParameters
Type Aliases¶
Options
¶
type Options = [
{
allowArgumentsExplicitlyTypedAsAny?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
allowedNames?: string[];
allowHigherOrderFunctions?: boolean;
allowTypedFunctionExpressions?: boolean;
allowOverloadFunctions?: boolean;
},
];
MessageIds
¶
type MessageIds = | 'anyTypedArg'
| 'anyTypedArgUnnamed'
| 'missingArgType'
| 'missingArgTypeUnnamed'
| 'missingReturnType';