├── .gitignore
├── .npmignore
├── .travis.yml
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── helpers
├── getClassMethods.ts
├── getJsxAttributes.ts
├── getLeadingWhitespace.ts
└── nodeIsKind.ts
├── package.json
├── prettier.config.js
├── rules
├── camelCaseLocalFunctionsRule.ts
├── classMethodNewlinesRule.ts
├── declareClassMethodsAfterUseRule.ts
├── index.json
├── jsxAttributeSpacingRule.ts
├── jsxExpressionSpacingRule.ts
├── jsxNoBracesForStringAttributesRule.ts
├── jsxNoClosingBracketNewlineRule.ts
├── noBracesForSingleLineArrowFunctionsRule.ts
├── noPropertyInitializersRule.ts
├── noUnnecessaryParensForArrowFunctionArgumentsRule.ts
├── preferEs6ImportsRule.ts
├── preferOrOperatorOverTernaryRule.ts
├── reactLifecycleOrderRule.ts
└── sortImportsRule.ts
├── test
├── camelCaseLocalFunctionsRule
│ ├── camelCaseLocalFunctionsRule.tsx.lint
│ └── tslint.json
├── classMethodNewlinesRule
│ ├── classMethodNewlinesRule.ts.fix
│ ├── classMethodNewlinesRule.ts.lint
│ └── tslint.json
├── declareClassMethodsAfterUseRule
│ ├── declareClassMethodsAfterUseRule.ts.lint
│ └── tslint.json
├── jsxAttributeSpacingRule
│ ├── jsxAttributeSpacingRule.tsx.fix
│ ├── jsxAttributeSpacingRule.tsx.lint
│ └── tslint.json
├── jsxExpressionSpacingRule
│ ├── jsxExpressionSpacingRule.tsx.fix
│ ├── jsxExpressionSpacingRule.tsx.lint
│ └── tslint.json
├── jsxNoBracesForStringAttributesRule
│ ├── jsxNoBracesForStringAttributesRule.tsx.fix
│ ├── jsxNoBracesForStringAttributesRule.tsx.lint
│ └── tslint.json
├── jsxNoClosingBracketNewlineRule
│ ├── jsxNoClosingBracketNewlineRule.tsx.fix
│ ├── jsxNoClosingBracketNewlineRule.tsx.lint
│ └── tslint.json
├── noBracesForSingleLineArrowFunctionsRule
│ ├── noBracesForSingleLineArrowFunctionsRule.tsx.fix
│ ├── noBracesForSingleLineArrowFunctionsRule.tsx.lint
│ └── tslint.json
├── noPropertyInitializersRule
│ ├── noPropertyInitializersRule.ts.lint
│ └── tslint.json
├── noUnnecessaryParensForArrowFunctionArgumentsRule
│ ├── noUnnecessaryParensForArrowFunctionArgumentsRule.ts.lint
│ └── tslint.json
├── preferEs6ImportsRule
│ ├── preferEs6ImportsRule.ts.lint
│ └── tslint.json
├── preferOrOperatorOverTernaryRule
│ ├── preferOrOperatorOverTernaryRule.ts.fix
│ ├── preferOrOperatorOverTernaryRule.ts.lint
│ └── tslint.json
├── reactLifecycleOrderRule
│ ├── reactLifecycleOrderRule.tsx.lint
│ └── tslint.json
├── runner.js
├── sortImportsRule
│ ├── sortImportsRule.ts.fix
│ ├── sortImportsRule.ts.lint
│ └── tslint.json
├── sortImportsRuleWhitespaceInsensitive
│ ├── sortImportsRule.ts.fix
│ ├── sortImportsRule.ts.lint
│ └── tslint.json
└── watch.js
├── tsconfig.json
├── tslint.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | *.js
2 | *.js.map
3 | *.log
4 | node_modules
5 | typings
6 | !test/runner.js
7 | !test/watch.js
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .travis.yml
2 | .vscode
3 | typings
4 | test
5 | *.ts
6 | *.log
7 | ts*.json
8 | yarn.lock
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - 10
5 | - 8
6 | - 6
7 |
8 | env:
9 | - TYPESCRIPT_VERSION="3.1"
10 | - TYPESCRIPT_VERSION="3.0"
11 | - TYPESCRIPT_VERSION="2.9"
12 | - TYPESCRIPT_VERSION="2.8"
13 | - TYPESCRIPT_VERSION="2.7"
14 | - TYPESCRIPT_VERSION="2.6"
15 | - TYPESCRIPT_VERSION="2.5"
16 | - TYPESCRIPT_VERSION="2.4"
17 | - TYPESCRIPT_VERSION="2.3"
18 | - TYPESCRIPT_VERSION="2.2"
19 | - TYPESCRIPT_VERSION="2.1"
20 |
21 | script:
22 | - yarn lint
23 | - yarn add typescript@${TYPESCRIPT_VERSION}
24 | - yarn ci
25 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch",
6 | "type": "node",
7 | "protocol": "inspector",
8 | "request": "launch",
9 | "program": "${workspaceRoot}/node_modules/tslint/lib/tslint-cli.js",
10 | "stopOnEntry": false,
11 | "args": [
12 | "--test",
13 | "test/ruleNameGoesHere"
14 | ],
15 | "cwd": "${workspaceRoot}",
16 | "preLaunchTask": "build",
17 | "runtimeExecutable": null,
18 | "runtimeArgs": [
19 | "--nolazy"
20 | ],
21 | "env": {
22 | "NODE_ENV": "development"
23 | },
24 | "sourceMaps": true
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | "**/*.js": {
4 | "when": "$(basename).ts"
5 | }
6 | },
7 | "typescript.tsdk": "./node_modules/typescript/lib",
8 | "tslint.autoFixOnSave": true,
9 | "editor.formatOnSave": true,
10 | "files.insertFinalNewline": true
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.1.0",
3 | "command": "npm",
4 | "isShellCommand": true,
5 | "showOutput": "always",
6 | "suppressTaskName": true,
7 | "tasks": [
8 | {
9 | "taskName": "build",
10 | "args": ["run", "build"]
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Justin Bay
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/jwbay/tslint-misc-rules)
2 | [](https://www.npmjs.com/package/tslint-misc-rules)
3 | [](https://github.com/jwbay/tslint-misc-rules/pulls)
4 | [](https://github.com/prettier/prettier)
5 | # misc-tslint-rules
6 |
7 | Collection of miscellaneous TSLint rules
8 |
9 | 1. `$ npm install tslint-misc-rules --save-dev`
10 | 2. Add the path to it to your tslint.json and add some rules:
11 |
12 | ```json
13 | {
14 | "rules": {
15 | "sort-imports": true
16 | },
17 | "rulesDirectory": [
18 | "tslint-misc-rules"
19 | ]
20 | }
21 | ```
22 |
23 | # Rules
24 |
25 | 1. [sort-imports](#1) [has autofix]
26 | 1. [prefer-es6-imports](#2)
27 | 1. [class-method-newlines](#3) [has autofix]
28 | 1. [jsx-attribute-spacing](#4) [has autofix]
29 | 1. [jsx-expression-spacing](#5) [has autofix]
30 | 1. [jsx-no-closing-bracket-newline](#6) [has autofix]
31 | 1. [jsx-no-braces-for-string-attributes](#7) [has autofix]
32 | 1. [react-lifecycle-order](#8)
33 | 1. [prefer-or-operator-over-ternary](#9) [has autofix]
34 | 1. [no-property-initializers](#10)
35 | 1. [camel-case-local-function](#11)
36 | 1. [declare-class-methods-after-use](#12)
37 | 1. [no-braces-for-single-line-arrow-functions](#13) [has autofix]
38 | 1. [no-unnecessary-parens-for-arrow-function-arguments](#14)
39 |
40 | ## "sort-imports" [↑](#TOC)
41 | Fails:
42 | ```ts
43 | import b from "b";
44 | import a from "a";
45 | ```
46 | Passes:
47 | ```ts
48 | import a from "a";
49 | import b from "b";
50 | ```
51 | Blocks are grouped, so this also passes:
52 | ```ts
53 | import a from "a";
54 | import z from "z";
55 | testSetup();
56 | import c from "c";
57 | import d from "d";
58 | ```
59 | Precedence is essentially `*`, `{`, then alpha, so:
60 | ```ts
61 | import * as a from "a";
62 | import { b, c } from "bc";
63 | import d from "d";
64 | ```
65 | This rule has one option, `whitespace-insensitive`, that collapses all whitespace spans (including line breaks) down to one space when sorting. This provides compatibility with formatters like Prettier, which may decide to turn a single-line import into a multi-line import when it grows too long. This could otherwise introduce a lint failure. Ex:
66 |
67 | ```json
68 | "sort-imports": [ true, "whitespace-insensitive" ]
69 | ```
70 | Fails:
71 | ```ts
72 | import {
73 | x,
74 | y,
75 | } from "xy";
76 | import { a } from "a";
77 | ```
78 | Passes:
79 | ```ts
80 | import { a } from "a";
81 | import {
82 | x,
83 | y,
84 | } from "xy";
85 | ```
86 |
87 | ## "prefer-es6-imports" [↑](#TOC)
88 | With configuration (required):
89 | ```json
90 | {
91 | "prefer-es6-imports": [
92 | true,
93 | "module-name"
94 | ]
95 | }
96 | ```
97 | Fails:
98 | ```ts
99 | import mod = require("module-name");
100 | import mod = require("path/to/module-name");
101 | import mod = require("../module-name");
102 | ```
103 |
104 | ## "class-method-newlines" [↑](#TOC)
105 | Ensure each method in class is preceded by a newline.
106 |
107 | Fails:
108 | ```ts
109 | class foo {
110 | propertyOne: any;
111 | propertyTwo: any;
112 | one() {
113 | }
114 | two() {
115 | }
116 | }
117 | ```
118 |
119 | Passes:
120 | ```ts
121 | class foo {
122 | propertyOne: any;
123 | propertyTwo: any;
124 |
125 | one() {
126 | }
127 |
128 | two() {
129 | }
130 | }
131 | ```
132 |
133 | The first method is exempt, so this also passes:
134 | ```ts
135 | class foo {
136 | one() {
137 | }
138 |
139 | two() {
140 | }
141 | }
142 | ```
143 |
144 |
145 | ## "jsx-attribute-spacing" [↑](#TOC)
146 | Fails:
147 | ```jsx
148 |
149 |
150 |
151 | ```
152 | Passes:
153 | ```jsx
154 |
155 | ```
156 |
157 | ## "jsx-expression-spacing" [↑](#TOC)
158 | Fails:
159 | ```jsx
160 |
161 |
162 |
163 |
164 | {value}
165 | { value}
166 | {value }
167 |
168 | ```
169 | Passes:
170 | ```jsx
171 |
172 |
173 | { value }
174 |
175 | ```
176 |
177 | ##
"jsx-no-closing-bracket-newline" [↑](#TOC)
178 | Fails:
179 | ```jsx
180 |
183 |
184 |
188 | text
189 |
190 | ```
191 |
192 | Passes:
193 | ```jsx
194 |
196 |
197 |
200 | text
201 |
202 | ```
203 |
204 | ##
"jsx-no-braces-for-string-attributes" [↑](#TOC)
205 | Fails:
206 | ```jsx
207 |
208 | ```
209 | Passes:
210 | ```jsx
211 |
212 | ```
213 |
214 | ##
"react-lifecycle-order" [↑](#TOC)
215 | With configuration (optional):
216 | ```json
217 | {
218 | "react-lifecycle-order": [
219 | true,
220 | "componentWillMount",
221 | "render",
222 | "componentWillUnmount"
223 | ]
224 | }
225 | ```
226 | Fails:
227 | ```ts
228 | class extends React.Component {
229 | componentWillMount() {
230 | }
231 |
232 | componentWillUnmount() {
233 | }
234 |
235 | render() {
236 | }
237 | }
238 | ```
239 |
240 | Passes:
241 | ```ts
242 | class extends React.Component {
243 | componentWillMount() {
244 | }
245 |
246 | render() {
247 | }
248 |
249 | componentWillUnmount() {
250 | }
251 | }
252 | ```
253 |
254 | If configuration is not specified, React's [invocation order](https://facebook.github.io/react/docs/component-specs.html#lifecycle-methods) is used.
255 |
256 | ##
"prefer-or-operator-over-ternary" [↑](#TOC)
257 | Fails:
258 | ```ts
259 | const maybeFoo = foo ? foo : bar;
260 | ```
261 |
262 | Passes:
263 | ```ts
264 | const maybeFoo = foo || bar;
265 | ```
266 |
267 | ##
"no-property-initializers" [↑](#TOC)
268 | Fails:
269 | ```ts
270 | class foo {
271 | bar = 42;
272 | }
273 | ```
274 |
275 | Passes:
276 | ```ts
277 | class foo {
278 | bar: number;
279 | }
280 | ```
281 |
282 | ##
"camel-case-local-functions" [↑](#TOC)
283 | Due to React's Stateless Functional Components, this rule checks callsites rather than declarations.
284 | Fails:
285 | ```ts
286 | import FooImport from 'foo';
287 |
288 | function FooDeclaration() { }
289 |
290 | FooImport();
291 | FooDeclaration();
292 | ```
293 |
294 | Passes:
295 | ```jsx
296 | import fooImport from 'foo';
297 |
298 | function fooDeclaration() { }
299 | function SomeSFC(props) { return null; }
300 |
301 | fooImport();
302 | fooDeclaration();
303 | const el = ;
304 | ```
305 |
306 | ##
"declare-class-methods-after-use" [↑](#TOC)
307 | Fails:
308 | ```ts
309 | class foo {
310 | bar() {
311 | }
312 |
313 | foo() {
314 | this.bar();
315 | }
316 | }
317 | ```
318 |
319 | Passes:
320 | ```ts
321 | class foo {
322 | foo() {
323 | this.bar();
324 | }
325 |
326 | bar() {
327 | }
328 | }
329 | ```
330 |
331 | ##
"no-braces-for-single-line-arrow-functions" [↑](#TOC)
332 |
333 | Fails:
334 | ```ts
335 | const add = (x, y) => { return x + y };
336 | const btn =