📄 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.pushfunctionReturnsMap.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.reportreportcheckParameter
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.reportreportcheckParameter
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: MessageIdsunnamedMessageId: 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.includesisStaticMemberAccessOfValue (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)getReturnsInFunctiondoesImmediatelyReturnFunctionExpression (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.getScopescope.set.get[ DefinitionType.CatchClause, DefinitionType.ImplicitGlobalVariable, DefinitionType.ImportBinding, DefinitionType.Parameter, ].includescheckNode- 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.hasalreadyVisited.addgetReturnsInFunctioncheckFunctionExpressioncheckNodecheckFunctionfollowReferencecheckEmptyBodyFunctionExpression
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.reportcheckParameters
`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.hascheckedFunctions.addisAllowedNameisTypedFunctionExpression (from ../util/explicitReturnTypeUtils)ancestorHasReturnType (from ../util/explicitReturnTypeUtils)hasOverloadSignatures (from ../util)checkFunctionExpressionReturnType (from ../util/explicitReturnTypeUtils)context.reportcheckParameters
`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.hascheckedFunctions.addisAllowedNameancestorHasReturnType (from ../util/explicitReturnTypeUtils)hasOverloadSignatures (from ../util)checkFunctionReturnType (from ../util/explicitReturnTypeUtils)context.reportcheckParameters
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';