diff --git a/src/noDupActionsRule.ts b/src/noDupActionsRule.ts new file mode 100644 index 0000000..31f2f39 --- /dev/null +++ b/src/noDupActionsRule.ts @@ -0,0 +1,42 @@ +import * as Lint from "tslint"; +import * as ts from "typescript"; + +class NoDupActionsRule extends Lint.RuleWalker { + public actionNames: string[] = []; + + constructor( + sourceFile: ts.SourceFile, + options: Lint.IOptions + ) { + super(sourceFile, options); + } + + public visitCallExpression(node: ts.CallExpression): void { + super.visitCallExpression(node); + if (ts.isIdentifier(node.expression)) { + if (node.expression.escapedText === "createAsyncActions") { + for (const argument of node.arguments) { + if (this.actionNames.indexOf(argument.getText()) !== -1) { + this.addFailureAtNode(argument, "Duplicate redux action"); + return; + } + this.actionNames.push(argument.getText()); + } + } + if (node.expression.escapedText === "createAction") { + if (this.actionNames.indexOf(node.arguments[0].getText()) !== -1) { + this.addFailureAtNode(node.arguments[0], "Duplicate redux action"); + return; + } + this.actionNames.push(node.arguments[0].getText()); + } + } + } +} + +// tslint:disable-next-line:export-name max-classes-per-file +export class Rule extends Lint.Rules.TypedRule { + public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { + return this.applyWithWalker(new NoDupActionsRule(sourceFile, this.getOptions())); + } +} diff --git a/test/rules/no-dup-actions/create-action-dup/test.ts.lint b/test/rules/no-dup-actions/create-action-dup/test.ts.lint new file mode 100644 index 0000000..8868f1d --- /dev/null +++ b/test/rules/no-dup-actions/create-action-dup/test.ts.lint @@ -0,0 +1,22 @@ +export const addToCart = createAsyncActions( + "CART/ADD_TO_CART", + "CART/ADD_TO_CART_PENDING", + "CART/ADD_TO_CART_FULFILLED", + "CART/ADD_TO_CART_REJECTED" +)(); + +export const setFabricDataWithUrls = createAction( + "FABRIC/SET_DATA_WITH_URLS", + (resolve) => (data: IFabricData) => resolve(data) +); + +export const addImage = createAction( + "FABRIC/ADD_IMAGE_TO_EDITOR", + (resolve) => (url: string) => resolve(url) +); + +export const addShape = createAction( + "FABRIC/ADD_IMAGE_TO_EDITOR", + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Duplicate redux action] + (resolve) => (url: string) => resolve(url) +); diff --git a/test/rules/no-dup-actions/create-action-dup/tsconfig.json b/test/rules/no-dup-actions/create-action-dup/tsconfig.json new file mode 100644 index 0000000..9d7ea05 --- /dev/null +++ b/test/rules/no-dup-actions/create-action-dup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": ["es6"] + } +} diff --git a/test/rules/no-dup-actions/create-action-dup/tslint.json b/test/rules/no-dup-actions/create-action-dup/tslint.json new file mode 100644 index 0000000..1d21de6 --- /dev/null +++ b/test/rules/no-dup-actions/create-action-dup/tslint.json @@ -0,0 +1,8 @@ +{ + "rulesDirectory": [ + "../../../../lib" + ], + "rules": { + "no-dup-actions": true + } +} diff --git a/test/rules/no-dup-actions/create-async-actions-dup/test.ts.lint b/test/rules/no-dup-actions/create-async-actions-dup/test.ts.lint new file mode 100644 index 0000000..1261073 --- /dev/null +++ b/test/rules/no-dup-actions/create-async-actions-dup/test.ts.lint @@ -0,0 +1,14 @@ +export const addToCart = createAsyncActions( + "CART/ADD_TO_CART", + "CART/ADD_TO_CART_PENDING", + "CART/ADD_TO_CART_FULFILLED", + "CART/ADD_TO_CART_REJECTED" +)(); + +export const addToCart = createAsyncActions( + "CART/ADD_TO_CART", + ~~~~~~~~~~~~~~~~~~ [Duplicate redux action] + "CART/ADD_TO_CART_PENDING", + "CART/ADD_TO_CART_FULFILLED", + "CART/ADD_TO_CART_REJECTED" +)(); diff --git a/test/rules/no-dup-actions/create-async-actions-dup/tsconfig.json b/test/rules/no-dup-actions/create-async-actions-dup/tsconfig.json new file mode 100644 index 0000000..9d7ea05 --- /dev/null +++ b/test/rules/no-dup-actions/create-async-actions-dup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": ["es6"] + } +} diff --git a/test/rules/no-dup-actions/create-async-actions-dup/tslint.json b/test/rules/no-dup-actions/create-async-actions-dup/tslint.json new file mode 100644 index 0000000..1d21de6 --- /dev/null +++ b/test/rules/no-dup-actions/create-async-actions-dup/tslint.json @@ -0,0 +1,8 @@ +{ + "rulesDirectory": [ + "../../../../lib" + ], + "rules": { + "no-dup-actions": true + } +} diff --git a/test/rules/no-dup-actions/no-dup/test.ts.lint b/test/rules/no-dup-actions/no-dup/test.ts.lint new file mode 100644 index 0000000..46ce1ce --- /dev/null +++ b/test/rules/no-dup-actions/no-dup/test.ts.lint @@ -0,0 +1,21 @@ +export const addToCart = createAsyncActions( + "CART/ADD_TO_CART", + "CART/ADD_TO_CART_PENDING", + "CART/ADD_TO_CART_FULFILLED", + "CART/ADD_TO_CART_REJECTED" +)(); + +export const setFabricDataWithUrls = createAction( + "FABRIC/SET_DATA_WITH_URLS", + (resolve) => (data: IFabricData) => resolve(data) +); + +export const addImage = createAction( + "FABRIC/ADD_IMAGE_TO_EDITOR", + (resolve) => (url: string) => resolve(url) +); + +export const addShape = createAction( + "FABRIC/ADD_SHAPE_TO_EDITOR", + (resolve) => (url: string) => resolve(url) +); diff --git a/test/rules/no-dup-actions/no-dup/tsconfig.json b/test/rules/no-dup-actions/no-dup/tsconfig.json new file mode 100644 index 0000000..9d7ea05 --- /dev/null +++ b/test/rules/no-dup-actions/no-dup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": ["es6"] + } +} diff --git a/test/rules/no-dup-actions/no-dup/tslint.json b/test/rules/no-dup-actions/no-dup/tslint.json new file mode 100644 index 0000000..1d21de6 --- /dev/null +++ b/test/rules/no-dup-actions/no-dup/tslint.json @@ -0,0 +1,8 @@ +{ + "rulesDirectory": [ + "../../../../lib" + ], + "rules": { + "no-dup-actions": true + } +}