From 6bf44a6b0951e44f4c6181d975435d46ff67d3c3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:10:41 +0100 Subject: [PATCH 01/12] Setup failure test file --- package-lock.json | 108 +++++++++++++++++++++++++++++++++++++++++ package.json | 4 ++ test-files/failure.tsx | 49 +++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 test-files/failure.tsx diff --git a/package-lock.json b/package-lock.json index 0e99d76..177569d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,35 @@ "integrity": "sha512-D1xlXHZpDonVX+VJ28XtcD5xlu8ex6Fc4cQNnrm2wJvlQnbec9RedhCrhQr6kRAE9XWHSec+JPuTmqJ9jC0qsA==", "dev": true }, + "@types/prop-types": { + "version": "15.5.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz", + "integrity": "sha512-mOrlCEdwX3seT3n0AXNt4KNPAZZxcsABUHwBgFXOt+nvFUXkxCAO6UBJHPrDxWEa2KDMil86355fjo8jbZ+K0Q==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react": { + "version": "16.4.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.14.tgz", + "integrity": "sha512-Gh8irag2dbZ2K6vPn+S8+LNrULuG3zlCgJjVUrvuiUK7waw9d9CFk2A/tZFyGhcMDUyO7tznbx1ZasqlAGjHxA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-redux": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-6.0.9.tgz", + "integrity": "sha512-LatgnnZ7bG63SmzEqGMjAIP1bN36iaXpb4G7UW3SqpHyo+OQ97MnMXm9BoNi720r61+PvseyIUJN4el4GVhAAg==", + "dev": true, + "requires": { + "@types/react": "*", + "redux": "^4.0.0" + } + }, "abab": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", @@ -1117,6 +1146,12 @@ "cssom": "0.3.x" } }, + "csstype": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.5.7.tgz", + "integrity": "sha512-Nt5VDyOTIIV4/nRFswoCKps1R5CD1hkiyjBE9/thNaNZILLEviVw9yWQw15+O+CpNjQKB/uvdcxFFOrSflY3Yw==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -2370,6 +2405,12 @@ } } }, + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==", + "dev": true + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -3399,6 +3440,12 @@ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, + "lodash-es": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.11.tgz", + "integrity": "sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q==", + "dev": true + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -4051,6 +4098,16 @@ "sisteransi": "^0.1.1" } }, + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "dev": true, + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -4100,6 +4157,32 @@ } } }, + "react": { + "version": "16.5.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.5.2.tgz", + "integrity": "sha512-FDCSVd3DjVTmbEAjUNX6FgfAmQ+ypJfHUsqUJOYNCBUp1h8lqmtC+0mXJ+JjsWx4KAVTkk1vKd1hLQPvEviSuw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "schedule": "^0.5.0" + } + }, + "react-redux": { + "version": "5.0.7", + "resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", + "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", + "dev": true, + "requires": { + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.0.0", + "lodash": "^4.17.5", + "lodash-es": "^4.17.5", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.0" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -4166,6 +4249,16 @@ "util.promisify": "^1.0.0" } }, + "redux": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.0.tgz", + "integrity": "sha512-NnnHF0h0WVE/hXyrB6OlX67LYRuaf/rJcbWvnHHEPCF/Xa/AZpwhs/20WyqzQae5x4SD2F9nPObgBh2rxAgLiA==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "symbol-observable": "^1.2.0" + } + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -4652,6 +4745,15 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "schedule": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/schedule/-/schedule-0.5.0.tgz", + "integrity": "sha512-HUcJicG5Ou8xfR//c2rPT0lPIRR09vVvN81T9fqfVgBmhERUbDEQoYKjpBxbueJnCPpSu2ujXzOnRQt6x9o/jw==", + "dev": true, + "requires": { + "object-assign": "^4.1.1" + } + }, "semver": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", @@ -5035,6 +5137,12 @@ "has-flag": "^3.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", diff --git a/package.json b/package.json index 4065d9e..afa54e9 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,12 @@ }, "devDependencies": { "@types/jest": "^23.3.2", + "@types/react": "^16.4.14", + "@types/react-redux": "^6.0.9", "jest": "^23.6.0", "prettier": "^1.14.2", + "react": "^16.5.2", + "react-redux": "^5.0.7", "ts-jest": "^23.10.1", "tslint": "^5.11.0", "tslint-config-dabapps": "github:dabapps/tslint-config-dabapps#v0.5.1" diff --git a/test-files/failure.tsx b/test-files/failure.tsx new file mode 100644 index 0000000..9fab8da --- /dev/null +++ b/test-files/failure.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; + +const { PureComponent } = React; + +interface Props { + foo: 'bar'; +} + +interface DispatchProps { + baz: () => null; +} + +export class MyComponent extends React.Component { + public render () { + return ( +

+ Hello, World! +

+ ); + } +} + +export class MyOtherComponent extends PureComponent<{} | Props> { + public render () { + return
; + } +} + +export class YetAnotherComponent extends PureComponent { + public render () { + return
; + } +} + + +export const mapStateToProps = () => { + return { + foo: 'not-bar' + }; +} + +function mapDispatchToProps () { + return { + baz: () => 'this-is-wrong' + }; +} + +export default connect<{}>(mapStateToProps, mapDispatchToProps)(MyComponent); From df7f3705d052a921700d4fe6579485b33cc23726 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:10:53 +0100 Subject: [PATCH 02/12] Add prepublishOnly dist script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index afa54e9..c92800d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "prettier-check": "diffs=$(prettier --list-different '{src,tests,types,examples,docs}/**/*.ts?(x)'); if [ ! -z $diffs ]; then echo \"Run 'npm run prettier'\nThe following files need formatting:\n$diffs\" && exit 1; fi;", "tests": "jest", "test": "npm run lint && npm run tests -- --runInBand --coverage", - "prettier": "prettier --write '{src,tests,types,examples,docs}/**/*.ts?(x)'" + "prettier": "prettier --write '{src,tests,types,examples,docs}/**/*.ts?(x)'", + "prepublishOnly": "npm run dist" }, "repository": { "type": "git", From 8597114eed68fd1047587ea47b1540cdea2a3b1b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:11:18 +0100 Subject: [PATCH 03/12] Allow multiple classes per file --- tslint.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tslint.json b/tslint.json index 3676fac..7c01a24 100644 --- a/tslint.json +++ b/tslint.json @@ -3,6 +3,7 @@ "tslint-config-dabapps" ], "rules": { - "no-unused-variable": false + "no-unused-variable": false, + "max-classes-per-file": false } } From 354327fb18cee0320b12fd6fea885819b301e0e5 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:11:29 +0100 Subject: [PATCH 04/12] Include test-files in tsconfig --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 17bcbda..a5cc75e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ "./src/", "./examples/", "./tests/", - "./types/" + "./types/", + "./test-files" ] } From 8a003294c4fe108d67ec37c6192c93372783bee0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:11:46 +0100 Subject: [PATCH 05/12] Add new tslint config for test files --- test-files/tslint.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test-files/tslint.json diff --git a/test-files/tslint.json b/test-files/tslint.json new file mode 100644 index 0000000..5f2ac0d --- /dev/null +++ b/test-files/tslint.json @@ -0,0 +1,9 @@ +{ + "extends": [ + "../dist/" + ], + "rules": { + "no-prop-intersection": true, + "no-prop-union": true + } +} From 57a112c4eb9114f9b3132c8c9461203241daf017 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:11:57 +0100 Subject: [PATCH 06/12] Add script for testing rules --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c92800d..99fefe3 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "tests": "jest", "test": "npm run lint && npm run tests -- --runInBand --coverage", "prettier": "prettier --write '{src,tests,types,examples,docs}/**/*.ts?(x)'", + "test-files": "npm run dist && tslint --project tsconfig.json 'test-files/**/*.@(ts|tsx)'", "prepublishOnly": "npm run dist" }, "repository": { From 67bd79de712ee9d90e7c930605d814b4cd5e335a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:12:18 +0100 Subject: [PATCH 07/12] Setup no-prop-intersection and no-prop-union rules --- src/index.ts | 4 +-- src/noPropIntersectionRule.ts | 55 +++++++++++++++++++++++++++++++++++ src/noPropUnionRule.ts | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/noPropIntersectionRule.ts create mode 100644 src/noPropUnionRule.ts diff --git a/src/index.ts b/src/index.ts index 4bd8367..09f5280 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1 @@ -export const message = 'Hello, World!'; - -export default message; +export = { rulesDirectory: '.' }; diff --git a/src/noPropIntersectionRule.ts b/src/noPropIntersectionRule.ts new file mode 100644 index 0000000..e521f48 --- /dev/null +++ b/src/noPropIntersectionRule.ts @@ -0,0 +1,55 @@ +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +export class Rule extends Lint.Rules.AbstractRule { + public static FAILURE_STRING = 'Props must not be an intersection in Component or PureComponent params'; + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new NoPropIntersectionWalker(sourceFile, this.getOptions())); + } +} + +// The walker takes care of all the work. +class NoPropIntersectionWalker extends Lint.RuleWalker { + public visitClassDeclaration (node: ts.ClassDeclaration) { + if (node.heritageClauses && node.heritageClauses.length) { + node.heritageClauses.forEach((heritage) => { + heritage.forEachChild((child) => { + if (child.kind === ts.SyntaxKind.ExpressionWithTypeArguments) { + this.checkExpression(child as ts.ExpressionWithTypeArguments); + } + }); + }); + } + + // call the base version of this visitor to actually parse this node + super.visitClassDeclaration(node); + } + + private getExpressionName (node: ts.ExpressionWithTypeArguments) { + if (ts.isIdentifier(node.expression)) { + return (node.expression as ts.Identifier).escapedText; + } else if (node.expression.kind === ts.SyntaxKind.PropertyAccessExpression) { + return (node.expression as ts.PropertyAccessExpression).name.escapedText; + } + + return ''; + } + + private checkExpression (node: ts.ExpressionWithTypeArguments) { + const name = this.getExpressionName(node); + + if (name === 'PureComponent' || name === 'Component') { + const { typeArguments } = node; + + if (typeArguments) { + typeArguments.forEach((typeArgument) => { + if (typeArgument.kind === ts.SyntaxKind.IntersectionType) { + // create a failure at the current position + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); + } + }); + } + } + } +} diff --git a/src/noPropUnionRule.ts b/src/noPropUnionRule.ts new file mode 100644 index 0000000..e202520 --- /dev/null +++ b/src/noPropUnionRule.ts @@ -0,0 +1,55 @@ +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +export class Rule extends Lint.Rules.AbstractRule { + public static FAILURE_STRING = 'Props must not be an union in Component or PureComponent params'; + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new NoPropUnionWalker(sourceFile, this.getOptions())); + } +} + +// The walker takes care of all the work. +class NoPropUnionWalker extends Lint.RuleWalker { + public visitClassDeclaration (node: ts.ClassDeclaration) { + if (node.heritageClauses && node.heritageClauses.length) { + node.heritageClauses.forEach((heritage) => { + heritage.forEachChild((child) => { + if (child.kind === ts.SyntaxKind.ExpressionWithTypeArguments) { + this.checkExpression(child as ts.ExpressionWithTypeArguments); + } + }); + }); + } + + // call the base version of this visitor to actually parse this node + super.visitClassDeclaration(node); + } + + private getExpressionName (node: ts.ExpressionWithTypeArguments) { + if (ts.isIdentifier(node.expression)) { + return (node.expression as ts.Identifier).escapedText; + } else if (node.expression.kind === ts.SyntaxKind.PropertyAccessExpression) { + return (node.expression as ts.PropertyAccessExpression).name.escapedText; + } + + return ''; + } + + private checkExpression (node: ts.ExpressionWithTypeArguments) { + const name = this.getExpressionName(node); + + if (name === 'PureComponent' || name === 'Component') { + const { typeArguments } = node; + + if (typeArguments) { + typeArguments.forEach((typeArgument) => { + if (typeArgument.kind === ts.SyntaxKind.UnionType) { + // create a failure at the current position + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); + } + }); + } + } + } +} From 5e9960f3808eb6ae16a29a12f801fa5bb271100b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:15:19 +0100 Subject: [PATCH 08/12] Add reference rule --- src/__reference-rule__.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/__reference-rule__.ts diff --git a/src/__reference-rule__.ts b/src/__reference-rule__.ts new file mode 100644 index 0000000..f5c2b39 --- /dev/null +++ b/src/__reference-rule__.ts @@ -0,0 +1,21 @@ +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +export class Rule extends Lint.Rules.AbstractRule { + public static FAILURE_STRING = 'Props must not be an union in Component or PureComponent params'; + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new NoImportsWalker(sourceFile, this.getOptions())); + } +} + +// The walker takes care of all the work. +class NoImportsWalker extends Lint.RuleWalker { + public visitImportDeclaration (node: ts.ImportDeclaration) { + // create a failure at the current position + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); + + // call the base version of this visitor to actually parse this node + super.visitImportDeclaration(node); + } +} From 5421522e2ddeb52e66a906e584fc2e29478051d3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:25:18 +0100 Subject: [PATCH 09/12] Install node types --- package-lock.json | 6 ++++++ package.json | 1 + 2 files changed, 7 insertions(+) diff --git a/package-lock.json b/package-lock.json index 177569d..823a714 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,12 @@ "integrity": "sha512-D1xlXHZpDonVX+VJ28XtcD5xlu8ex6Fc4cQNnrm2wJvlQnbec9RedhCrhQr6kRAE9XWHSec+JPuTmqJ9jC0qsA==", "dev": true }, + "@types/node": { + "version": "10.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.10.3.tgz", + "integrity": "sha512-dWk7F3b0m6uDLHero7tsnpAi9r2RGPQHGbb0/VCv7DPJRMFtk3RonY1/29vfJKnheRMBa7+uF+vunlg/mBGlxg==", + "dev": true + }, "@types/prop-types": { "version": "15.5.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz", diff --git a/package.json b/package.json index 99fefe3..b868e8f 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "devDependencies": { "@types/jest": "^23.3.2", + "@types/node": "^10.10.3", "@types/react": "^16.4.14", "@types/react-redux": "^6.0.9", "jest": "^23.6.0", From 0d236a1def830b4ec0634581952e13fa0a915d0c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:25:34 +0100 Subject: [PATCH 10/12] Fix tests --- src/__reference-rule__.ts | 16 ++++++++-------- src/noPropIntersectionRule.ts | 16 ++++++++-------- src/noPropUnionRule.ts | 16 ++++++++-------- tests/index.ts | 7 ++++--- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/__reference-rule__.ts b/src/__reference-rule__.ts index f5c2b39..b9c5ffc 100644 --- a/src/__reference-rule__.ts +++ b/src/__reference-rule__.ts @@ -1,21 +1,21 @@ import * as Lint from 'tslint'; import * as ts from 'typescript'; -export class Rule extends Lint.Rules.AbstractRule { - public static FAILURE_STRING = 'Props must not be an union in Component or PureComponent params'; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoImportsWalker(sourceFile, this.getOptions())); - } -} +const FAILURE_STRING = 'Import statements are disallowed'; // The walker takes care of all the work. class NoImportsWalker extends Lint.RuleWalker { public visitImportDeclaration (node: ts.ImportDeclaration) { // create a failure at the current position - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), FAILURE_STRING)); // call the base version of this visitor to actually parse this node super.visitImportDeclaration(node); } } + +export class Rule extends Lint.Rules.AbstractRule { + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new NoImportsWalker(sourceFile, this.getOptions())); + } +} diff --git a/src/noPropIntersectionRule.ts b/src/noPropIntersectionRule.ts index e521f48..e2aba8a 100644 --- a/src/noPropIntersectionRule.ts +++ b/src/noPropIntersectionRule.ts @@ -1,13 +1,7 @@ import * as Lint from 'tslint'; import * as ts from 'typescript'; -export class Rule extends Lint.Rules.AbstractRule { - public static FAILURE_STRING = 'Props must not be an intersection in Component or PureComponent params'; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoPropIntersectionWalker(sourceFile, this.getOptions())); - } -} +const FAILURE_STRING = 'Props must not be an intersection in Component or PureComponent params'; // The walker takes care of all the work. class NoPropIntersectionWalker extends Lint.RuleWalker { @@ -46,10 +40,16 @@ class NoPropIntersectionWalker extends Lint.RuleWalker { typeArguments.forEach((typeArgument) => { if (typeArgument.kind === ts.SyntaxKind.IntersectionType) { // create a failure at the current position - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), FAILURE_STRING)); } }); } } } } + +export class Rule extends Lint.Rules.AbstractRule { + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new NoPropIntersectionWalker(sourceFile, this.getOptions())); + } +} diff --git a/src/noPropUnionRule.ts b/src/noPropUnionRule.ts index e202520..a0a1bdd 100644 --- a/src/noPropUnionRule.ts +++ b/src/noPropUnionRule.ts @@ -1,13 +1,7 @@ import * as Lint from 'tslint'; import * as ts from 'typescript'; -export class Rule extends Lint.Rules.AbstractRule { - public static FAILURE_STRING = 'Props must not be an union in Component or PureComponent params'; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoPropUnionWalker(sourceFile, this.getOptions())); - } -} +const FAILURE_STRING = 'Props must not be an union in Component or PureComponent params'; // The walker takes care of all the work. class NoPropUnionWalker extends Lint.RuleWalker { @@ -46,10 +40,16 @@ class NoPropUnionWalker extends Lint.RuleWalker { typeArguments.forEach((typeArgument) => { if (typeArgument.kind === ts.SyntaxKind.UnionType) { // create a failure at the current position - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), FAILURE_STRING)); } }); } } } } + +export class Rule extends Lint.Rules.AbstractRule { + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new NoPropUnionWalker(sourceFile, this.getOptions())); + } +} diff --git a/tests/index.ts b/tests/index.ts index 4d83912..bca2ad4 100644 --- a/tests/index.ts +++ b/tests/index.ts @@ -1,7 +1,8 @@ -import message from '../src'; +// tslint:disable-next-line:no-var-requires +const index = require('../src'); describe('index.ts', () => { - it('should export hello world', () => { - expect(message).toBe('Hello, World!'); + it('should export a reference to its directory', () => { + expect(index).toEqual({ rulesDirectory: '.' }); }); }); From 6c5ec2b0919cc5d5234c8bd51cf287caa2297eec Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:28:07 +0100 Subject: [PATCH 11/12] Add rule to test tslint config --- test-files/tslint.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-files/tslint.json b/test-files/tslint.json index 5f2ac0d..23d551e 100644 --- a/test-files/tslint.json +++ b/test-files/tslint.json @@ -4,6 +4,7 @@ ], "rules": { "no-prop-intersection": true, - "no-prop-union": true + "no-prop-union": true, + "require-prop-alias": true } } From 4f017286455d9a3b480cccd5f516323284280266 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Sep 2018 20:28:43 +0100 Subject: [PATCH 12/12] Create placeholder rule --- src/requirePropAliasRule.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/requirePropAliasRule.ts diff --git a/src/requirePropAliasRule.ts b/src/requirePropAliasRule.ts new file mode 100644 index 0000000..1d43913 --- /dev/null +++ b/src/requirePropAliasRule.ts @@ -0,0 +1,21 @@ +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +const FAILURE_STRING = 'Props must alias individual prop types (State, Dispatch, Own, etc)'; + +// The walker takes care of all the work. +class RequirePropAliasWalker extends Lint.RuleWalker { + public visitImportDeclaration (node: ts.ImportDeclaration) { + // create a failure at the current position + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), FAILURE_STRING)); + + // call the base version of this visitor to actually parse this node + super.visitImportDeclaration(node); + } +} + +export class Rule extends Lint.Rules.AbstractRule { + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new RequirePropAliasWalker(sourceFile, this.getOptions())); + } +}