Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(eslint-plugin): sort members alphabetically
- Loading branch information
Showing
3 changed files
with
383 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
212 changes: 212 additions & 0 deletions
212
packages/eslint-plugin/src/rules/sort-interface-members.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
/** | ||
* @fileoverview Forbids unsorted interface members | ||
*/ | ||
|
||
import * as util from '../util'; | ||
import { | ||
Identifier, | ||
TSCallSignatureDeclaration, | ||
TSConstructSignatureDeclaration, | ||
TSIndexSignature, | ||
TSMethodSignature, | ||
TSPropertySignature, | ||
TSTypeAnnotation, | ||
TSTypeReference, | ||
TypeElement, | ||
} from '@typescript-eslint/typescript-estree/dist/ts-estree/ts-estree'; | ||
|
||
type Options = []; | ||
type MessageIds = 'notSorted'; | ||
|
||
function isPropertySignature( | ||
member: TypeElement, | ||
): member is TSPropertySignature { | ||
return (<TSPropertySignature>member).type === 'TSPropertySignature'; | ||
} | ||
|
||
function isMethodSignature(member: TypeElement): member is TSMethodSignature { | ||
return (<TSMethodSignature>member).type === 'TSMethodSignature'; | ||
} | ||
|
||
function isIndexSignature(member: TypeElement): member is TSIndexSignature { | ||
return (<TSIndexSignature>member).type === 'TSIndexSignature'; | ||
} | ||
|
||
function isConstructSignatureDeclaration( | ||
member: TypeElement, | ||
): member is TSConstructSignatureDeclaration { | ||
return ( | ||
(<TSConstructSignatureDeclaration>member).type === | ||
'TSConstructSignatureDeclaration' | ||
); | ||
} | ||
|
||
function isCallSignatureDeclaration( | ||
member: TypeElement, | ||
): member is TSCallSignatureDeclaration { | ||
return ( | ||
(<TSCallSignatureDeclaration>member).type === 'TSCallSignatureDeclaration' | ||
); | ||
} | ||
|
||
export default util.createRule<Options, MessageIds>({ | ||
name: 'sort-interface-members', | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'Forbids unsorted interface members', | ||
category: 'Stylistic Issues', | ||
recommended: false, | ||
}, | ||
schema: [], | ||
messages: { | ||
notSorted: 'The interface members are not sorted alphabetically.', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
return { | ||
TSInterfaceBody(node) { | ||
const members = node.body; | ||
const propertySignatures: TSPropertySignature[] = []; | ||
const methodSignatures: TSMethodSignature[] = []; | ||
const indexSignatures: TSIndexSignature[] = []; | ||
const constructSignatureDeclarations: TSConstructSignatureDeclaration[] = []; | ||
const callSignatureDeclarations: TSCallSignatureDeclaration[] = []; | ||
|
||
// TODO This algorithm assumes an order of TSPropertySignature > TSMethodSignature > TSIndexSignature > TSConstructSignatureDeclaration > TSCallSignatureDeclaration - it is only used to evaluate if it works alongside the member-ordering rule | ||
for (let i = 0; i < members.length; i++) { | ||
if (isPropertySignature(members[i])) { | ||
if ( | ||
methodSignatures.length > 0 || | ||
indexSignatures.length > 0 || | ||
constructSignatureDeclarations.length > 0 || | ||
callSignatureDeclarations.length > 0 | ||
) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: members[i], | ||
}); | ||
} | ||
|
||
propertySignatures.push(members[i] as TSPropertySignature); | ||
} else if (isMethodSignature(members[i])) { | ||
if ( | ||
indexSignatures.length > 0 || | ||
constructSignatureDeclarations.length > 0 || | ||
callSignatureDeclarations.length > 0 | ||
) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: members[i], | ||
}); | ||
} | ||
|
||
methodSignatures.push(members[i] as TSMethodSignature); | ||
} else if (isIndexSignature(members[i])) { | ||
if ( | ||
constructSignatureDeclarations.length > 0 || | ||
callSignatureDeclarations.length > 0 | ||
) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: members[i], | ||
}); | ||
} | ||
|
||
indexSignatures.push(members[i] as TSIndexSignature); | ||
} else if (isConstructSignatureDeclaration(members[i])) { | ||
if (callSignatureDeclarations.length > 0) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: members[i], | ||
}); | ||
} | ||
|
||
constructSignatureDeclarations.push(members[ | ||
i | ||
] as TSConstructSignatureDeclaration); | ||
} else if (isCallSignatureDeclaration(members[i])) { | ||
callSignatureDeclarations.push(members[ | ||
i | ||
] as TSCallSignatureDeclaration); | ||
} | ||
} | ||
|
||
for (let i = 0; i < propertySignatures.length - 1; i++) { | ||
const currentItem = <Identifier>propertySignatures[i].key; | ||
const nextItem = <Identifier>propertySignatures[i + 1].key; | ||
|
||
if (currentItem.name > nextItem.name) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: currentItem, | ||
}); | ||
} | ||
} | ||
|
||
for (let i = 0; i < methodSignatures.length - 1; i++) { | ||
const currentItem = <Identifier>methodSignatures[i].key; | ||
const nextItem = <Identifier>methodSignatures[i + 1].key; | ||
|
||
if (currentItem.name > nextItem.name) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: currentItem, | ||
}); | ||
} | ||
} | ||
|
||
for (let i = 0; i < indexSignatures.length - 1; i++) { | ||
const currentItem = <Identifier>indexSignatures[i].parameters[0]; | ||
const nextItem = <Identifier>indexSignatures[i + 1].parameters[0]; | ||
|
||
if (currentItem.name > nextItem.name) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: currentItem, | ||
}); | ||
} | ||
} | ||
|
||
for (let i = 0; i < constructSignatureDeclarations.length - 1; i++) { | ||
const currentItem = (<TSTypeReference>( | ||
(<TSTypeAnnotation>constructSignatureDeclarations[i].returnType) | ||
.typeAnnotation | ||
)).typeName; | ||
const nextItem = (<TSTypeReference>( | ||
(<TSTypeAnnotation>constructSignatureDeclarations[i + 1].returnType) | ||
.typeAnnotation | ||
)).typeName; | ||
|
||
if (currentItem > nextItem) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: currentItem, | ||
}); | ||
} | ||
} | ||
|
||
for (let i = 0; i < callSignatureDeclarations.length - 1; i++) { | ||
const currentItem = (<TSTypeReference>( | ||
(<TSTypeAnnotation>callSignatureDeclarations[i].returnType) | ||
.typeAnnotation | ||
)).typeName; | ||
const nextItem = (<TSTypeReference>( | ||
(<TSTypeAnnotation>callSignatureDeclarations[i + 1].returnType) | ||
.typeAnnotation | ||
)).typeName; | ||
|
||
if (currentItem > nextItem) { | ||
return context.report({ | ||
messageId: 'notSorted', | ||
node: currentItem, | ||
}); | ||
} | ||
} | ||
|
||
return; // No rule violation found | ||
}, | ||
}; | ||
}, | ||
}); |
Oops, something went wrong.