From 89c83291320732c3993225a568ccce2f8d390b06 Mon Sep 17 00:00:00 2001 From: paibamboo Date: Wed, 23 Oct 2019 15:17:16 +0700 Subject: [PATCH] feat: enum sort keys rule --- README.md | 3 ++ src/enumSortKeysRule.ts | 42 +++++++++++++++++++ .../rules/enum-sort-keys/default/test.ts.lint | 25 +++++++++++ test/rules/enum-sort-keys/default/tslint.json | 8 ++++ tslint-rules.json | 1 + 5 files changed, 79 insertions(+) create mode 100644 src/enumSortKeysRule.ts create mode 100644 test/rules/enum-sort-keys/default/test.ts.lint create mode 100644 test/rules/enum-sort-keys/default/tslint.json diff --git a/README.md b/README.md index d36766c..8442d79 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ Initially you should: called. Still, as you see, we need to provide string literal as arugments due to typescript limitation, if we provide any string variable, the type will be deduced to just `string`. This rule enforces 2nd, 3rd, and 4th argument to be the concatenation of the first argument string and `_PENDING`, `_FULFILLED`, and `_REJECTED` respectively. +### `enum-sort-keys` + - Same as [object-literal-sort-keys](https://palantir.github.io/tslint/rules/object-literal-sort-keys/) but applied to + enum keys ### `import-react` - Specify how you should import `react`. Either `import *` or `import React`. - Rule options: diff --git a/src/enumSortKeysRule.ts b/src/enumSortKeysRule.ts new file mode 100644 index 0000000..8063ed6 --- /dev/null +++ b/src/enumSortKeysRule.ts @@ -0,0 +1,42 @@ +import * as Lint from "tslint"; +import * as ts from "typescript"; + +class EnumSortKeysRule extends Lint.AbstractWalker { + public walk(sourceFile: ts.SourceFile): void { + const cb = (node: ts.Node): void => { + if (ts.isEnumDeclaration(node)) { + const properties = node.members.map((member) => member.getText()); + const unsortedIndex = this.getUnsortedIndex(properties); + if (unsortedIndex !== -1) { + const member = node.members[unsortedIndex]; + this.addFailureAtNode(member.name, `The key "${member.name.getText()}" is not sorted alphabetically`); + } + } + return ts.forEachChild(node, cb); + }; + return ts.forEachChild(sourceFile, cb); + } + + private getUnsortedIndex(strs: string[], startIndex: number = 0): number { + if (strs.length < 2 || strs.length === startIndex + 1) { + return -1; + } + if (strs[startIndex] > strs[startIndex + 1]) { + return startIndex; + } + return this.getUnsortedIndex(strs, startIndex + 1); + } +} + +// tslint:disable-next-line:export-name max-classes-per-file +export class Rule extends Lint.Rules.AbstractRule { + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker( + new EnumSortKeysRule( + sourceFile, + "enum-sort-keys", + undefined + ) + ); + } +} diff --git a/test/rules/enum-sort-keys/default/test.ts.lint b/test/rules/enum-sort-keys/default/test.ts.lint new file mode 100644 index 0000000..411a160 --- /dev/null +++ b/test/rules/enum-sort-keys/default/test.ts.lint @@ -0,0 +1,25 @@ +enum Character { + AAA = "aaa", + BBB = "bbb", + CCC = "ccc" +} + +enum Character { + AAA = "aaa", + CCC = "ccc", + ~~~ [The key "CCC" is not sorted alphabetically] + BBB = "bbb" +} + +enum Number { + ONE, + THREE, + TWO +} + +enum Number { + ONE, + TWO, + ~~~ [The key "TWO" is not sorted alphabetically] + THREE +} diff --git a/test/rules/enum-sort-keys/default/tslint.json b/test/rules/enum-sort-keys/default/tslint.json new file mode 100644 index 0000000..f97bd32 --- /dev/null +++ b/test/rules/enum-sort-keys/default/tslint.json @@ -0,0 +1,8 @@ +{ + "rulesDirectory": [ + "../../../../lib" + ], + "rules": { + "enum-sort-keys": true + } +} diff --git a/tslint-rules.json b/tslint-rules.json index 0881159..913649c 100644 --- a/tslint-rules.json +++ b/tslint-rules.json @@ -1,6 +1,7 @@ { "rulesDirectory": "./lib", "rules": { + "enum-sort-keys": true, "import-react": [true, {"type": "star"}], "hex-format": true, "interface-sort-keys": true