β¬ οΈ Back to Table of Contents
π method-signature-style¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 8 |
| π¦ Imports | 10 |
| π Type Aliases | 2 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/method-signature-style.ts
π€ Default Export¶
| Property | Value |
|---|---|
name |
'method-signature-style' |
meta.type |
'suggestion' |
meta.docs.description |
'Enforce using a particular method signature syntax' |
meta.fixable |
'code' |
meta.hasSuggestions |
true |
meta.messages.convertToMethodSignature |
'Convert to a method signature. This removes the readonly modifier, allowing the member to be reassigned.' |
meta.messages.errorMethod |
'Shorthand method signature is forbidden. Use a function property instead.' |
meta.messages.errorProperty |
'Function property signature is forbidden. Use a method shorthand instead.' |
meta.schema |
[ { type: 'string', description: 'The method signature style to enforce using.', enum: ['property', 'method'], }, ] |
defaultOptions |
['property'] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESTree |
@typescript-eslint/utils |
ReportFixFunction |
@typescript-eslint/utils/ts-eslint |
AST_NODE_TYPES |
@typescript-eslint/utils |
createRule |
../util |
forEachChildESTree |
../util |
isClosingParenToken |
../util |
isCommaToken |
../util |
isOpeningParenToken |
../util |
isSemicolonToken |
../util |
nullThrows |
../util |
Functions¶
create(context: any, [mode]: any): { TSPropertySignature(propertyNode: any): void; TSMethodSig⦶
Parameters:
contextany[mode]any
Returns: { TSPropertySignature(propertyNode: any): void; TSMethodSignature(methodNode: any): void; }
Calls:
context.sourceCode.getTextnullThrows (from ../util)context.sourceCode.getTokenBeforecontext.sourceCode.getTokenAftercontext.sourceCode.text.substringcontext.sourceCode.getLastTokenisSemicolonToken (from ../util)isCommaToken (from ../util)isNodeParentModuleDeclarationreturnTypeReferencesThisTypemembers.filtergetMethodKeycontext.report[ methodNode, ...duplicatedKeyMethodNodes, ].sortmethodNodes .map(node => { const params = getMethodParams(node); const returnType = getMethodReturnType(node); return(${params} => ${returnType}); }) .joingetDelimiterfixer.replaceTextfixer.removefixer.replaceTextRangegetMethodParamsgetMethodReturnType
Internal Comments:
// we just make it explicit here so we can do the fix
// There is no syntax for a `readonly` method signature, so converting
// a `readonly` function-typed property drops the `readonly` modifier.
// That is a behavioral change (a method may be reassigned, a
// `readonly` property may not), so it is offered as a suggestion
// rather than applied as an autofix.
Code
create(context, [mode]) {
function getMethodKey(
node: TSESTree.TSMethodSignature | TSESTree.TSPropertySignature,
): string {
let key = context.sourceCode.getText(node.key);
if (node.computed) {
key = `[${key}]`;
}
if (node.optional) {
key = `${key}?`;
}
return key;
}
function getMethodParams(
node: TSESTree.TSFunctionType | TSESTree.TSMethodSignature,
): string {
let params = '()';
if (node.params.length > 0) {
const openingParen = nullThrows(
context.sourceCode.getTokenBefore(
node.params[0],
isOpeningParenToken,
),
'Missing opening paren before first parameter',
);
const closingParen = nullThrows(
context.sourceCode.getTokenAfter(
node.params[node.params.length - 1],
isClosingParenToken,
),
'Missing closing paren after last parameter',
);
params = context.sourceCode.text.substring(
openingParen.range[0],
closingParen.range[1],
);
}
if (node.typeParameters != null) {
const typeParams = context.sourceCode.getText(node.typeParameters);
params = `${typeParams}${params}`;
}
return params;
}
function getMethodReturnType(
node: TSESTree.TSFunctionType | TSESTree.TSMethodSignature,
): string {
return node.returnType == null
? // if the method has no return type, it implicitly has an `any` return type
// we just make it explicit here so we can do the fix
'any'
: context.sourceCode.getText(node.returnType.typeAnnotation);
}
function getDelimiter(node: TSESTree.Node): string {
const lastToken = context.sourceCode.getLastToken(node);
if (
lastToken &&
(isSemicolonToken(lastToken) || isCommaToken(lastToken))
) {
return lastToken.value;
}
return '';
}
function isNodeParentModuleDeclaration(node: TSESTree.Node): boolean {
if (!node.parent) {
return false;
}
if (node.parent.type === AST_NODE_TYPES.TSModuleDeclaration) {
return true;
}
if (node.parent.type === AST_NODE_TYPES.Program) {
return false;
}
return isNodeParentModuleDeclaration(node.parent);
}
return {
...(mode === 'property' && {
TSMethodSignature(methodNode): void {
if (methodNode.kind !== 'method') {
return;
}
const skipFix = returnTypeReferencesThisType(methodNode.returnType);
const parent = methodNode.parent;
const members =
parent.type === AST_NODE_TYPES.TSInterfaceBody
? parent.body
: parent.members;
const duplicatedKeyMethodNodes: TSESTree.TSMethodSignature[] =
members.filter(
(element): element is TSESTree.TSMethodSignature =>
element.type === AST_NODE_TYPES.TSMethodSignature &&
element !== methodNode &&
getMethodKey(element) === getMethodKey(methodNode),
);
const isParentModule = isNodeParentModuleDeclaration(methodNode);
if (duplicatedKeyMethodNodes.length > 0) {
if (isParentModule) {
context.report({
node: methodNode,
messageId: 'errorMethod',
});
} else {
context.report({
node: methodNode,
messageId: 'errorMethod',
fix: skipFix
? undefined
: function* fix(fixer) {
const methodNodes = [
methodNode,
...duplicatedKeyMethodNodes,
].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1));
const typeString = methodNodes
.map(node => {
const params = getMethodParams(node);
const returnType = getMethodReturnType(node);
return `(${params} => ${returnType})`;
})
.join(' & ');
const key = getMethodKey(methodNode);
const delimiter = getDelimiter(methodNode);
yield fixer.replaceText(
methodNode,
`${key}: ${typeString}${delimiter}`,
);
for (const node of duplicatedKeyMethodNodes) {
const lastToken = context.sourceCode.getLastToken(node);
if (lastToken) {
const nextToken =
context.sourceCode.getTokenAfter(lastToken);
if (nextToken) {
yield fixer.remove(node);
yield fixer.replaceTextRange(
[lastToken.range[1], nextToken.range[0]],
'',
);
}
}
}
},
});
}
return;
}
if (isParentModule) {
context.report({
node: methodNode,
messageId: 'errorMethod',
});
} else {
context.report({
node: methodNode,
messageId: 'errorMethod',
fix: skipFix
? undefined
: fixer => {
const key = getMethodKey(methodNode);
const params = getMethodParams(methodNode);
const returnType = getMethodReturnType(methodNode);
const delimiter = getDelimiter(methodNode);
return fixer.replaceText(
methodNode,
`${key}: ${params} => ${returnType}${delimiter}`,
);
},
});
}
},
}),
...(mode === 'method' && {
TSPropertySignature(propertyNode): void {
const typeNode = propertyNode.typeAnnotation?.typeAnnotation;
if (typeNode?.type !== AST_NODE_TYPES.TSFunctionType) {
return;
}
const fix: ReportFixFunction = fixer => {
const key = getMethodKey(propertyNode);
const params = getMethodParams(typeNode);
const returnType = getMethodReturnType(typeNode);
const delimiter = getDelimiter(propertyNode);
return fixer.replaceText(
propertyNode,
`${key}${params}: ${returnType}${delimiter}`,
);
};
// There is no syntax for a `readonly` method signature, so converting
// a `readonly` function-typed property drops the `readonly` modifier.
// That is a behavioral change (a method may be reassigned, a
// `readonly` property may not), so it is offered as a suggestion
// rather than applied as an autofix.
if (propertyNode.readonly) {
context.report({
node: propertyNode,
messageId: 'errorProperty',
suggest: [{ messageId: 'convertToMethodSignature', fix }],
});
return;
}
context.report({
node: propertyNode,
messageId: 'errorProperty',
fix,
});
},
}),
};
}
returnTypeReferencesThisType(node: TSESTree.TSTypeAnnotation | undefined): boolean¶
Parameters:
nodeTSESTree.TSTypeAnnotation | undefined
Returns: boolean
Calls:
forEachChildESTree (from ../util)
Code
Internal helpers¶
Declared inside another function in this file.
getMethodKey(node: TSESTree.TSMethodSignature | TSESTree.Tβ¦): string¶
Parameters:
nodeTSESTree.TSMethodSignature | TSESTree.TSPropertySignature
Returns: string
Calls:
context.sourceCode.getText
Code
getMethodParams(node: TSESTree.TSFunctionType | TSESTree.TSMeβ¦): string¶
Parameters:
nodeTSESTree.TSFunctionType | TSESTree.TSMethodSignature
Returns: string
Calls:
nullThrows (from ../util)context.sourceCode.getTokenBeforecontext.sourceCode.getTokenAftercontext.sourceCode.text.substringcontext.sourceCode.getText
Code
function getMethodParams(
node: TSESTree.TSFunctionType | TSESTree.TSMethodSignature,
): string {
let params = '()';
if (node.params.length > 0) {
const openingParen = nullThrows(
context.sourceCode.getTokenBefore(
node.params[0],
isOpeningParenToken,
),
'Missing opening paren before first parameter',
);
const closingParen = nullThrows(
context.sourceCode.getTokenAfter(
node.params[node.params.length - 1],
isClosingParenToken,
),
'Missing closing paren after last parameter',
);
params = context.sourceCode.text.substring(
openingParen.range[0],
closingParen.range[1],
);
}
if (node.typeParameters != null) {
const typeParams = context.sourceCode.getText(node.typeParameters);
params = `${typeParams}${params}`;
}
return params;
}
getMethodReturnType(node: TSESTree.TSFunctionType | TSESTree.TSMeβ¦): string¶
Parameters:
nodeTSESTree.TSFunctionType | TSESTree.TSMethodSignature
Returns: string
Calls:
context.sourceCode.getText
Internal Comments:
Code
function getMethodReturnType(
node: TSESTree.TSFunctionType | TSESTree.TSMethodSignature,
): string {
return node.returnType == null
? // if the method has no return type, it implicitly has an `any` return type
// we just make it explicit here so we can do the fix
'any'
: context.sourceCode.getText(node.returnType.typeAnnotation);
}
getDelimiter(node: TSESTree.Node): string¶
Parameters:
nodeTSESTree.Node
Returns: string
Calls:
context.sourceCode.getLastTokenisSemicolonToken (from ../util)isCommaToken (from ../util)
Code
isNodeParentModuleDeclaration(node: TSESTree.Node): boolean¶
Parameters:
nodeTSESTree.Node
Returns: boolean
Calls:
isNodeParentModuleDeclaration
Code
function isNodeParentModuleDeclaration(node: TSESTree.Node): boolean {
if (!node.parent) {
return false;
}
if (node.parent.type === AST_NODE_TYPES.TSModuleDeclaration) {
return true;
}
if (node.parent.type === AST_NODE_TYPES.Program) {
return false;
}
return isNodeParentModuleDeclaration(node.parent);
}
fix(fixer: any): any¶
Parameters:
fixerany
Returns: any
Calls:
getMethodKeygetMethodParamsgetMethodReturnTypegetDelimiterfixer.replaceText
Code
Type Aliases¶
Options¶
MessageIds¶
Generated by Syntax Scribe