forked from desktop/desktop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreactReadonlyPropsAndStateRule.ts
73 lines (60 loc) · 2.03 KB
/
reactReadonlyPropsAndStateRule.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* react-readonly-props-and-state
*
* This custom tslint rule is highly specific to GitHub Desktop and attempts
* to prevent props and state interfaces from being declared with mutable
* members.
*
* While it's technically possible to modify this.props there's never a good
* reason to do so and marking our interfaces as read only ensures that we
* get compiler support for that fact.
*/
import * as ts from 'typescript'
import * as Lint from 'tslint'
// The walker takes care of all the work.
class ReactReadonlyPropsAndStateWalker extends Lint.RuleWalker {
protected visitInterfaceDeclaration(node: ts.InterfaceDeclaration): void {
if (node.name.text.endsWith('Props')) {
this.ensureReadOnly(node.members)
}
if (node.name.text.endsWith('State')) {
this.ensureReadOnly(node.members)
}
super.visitInterfaceDeclaration(node)
}
private ensureReadOnly(members: ts.NodeArray<ts.TypeElement>) {
members.forEach(member => {
if (member.kind !== ts.SyntaxKind.PropertySignature) {
return
}
const propertySignature = member as ts.PropertySignature
if (!this.isReadOnly(propertySignature)) {
const start = propertySignature.getStart()
const width = propertySignature.getWidth()
const error = `Property and state signatures should be read-only`
this.addFailure(this.createFailure(start, width, error))
}
})
}
private isReadOnly(propertySignature: ts.PropertySignature): boolean {
const modifiers = propertySignature.modifiers
if (!modifiers) {
return false
}
if (modifiers.find(m => m.kind === ts.SyntaxKind.ReadonlyKeyword)) {
return true
}
return false
}
}
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
if (sourceFile.languageVariant === ts.LanguageVariant.JSX) {
return this.applyWithWalker(
new ReactReadonlyPropsAndStateWalker(sourceFile, this.getOptions())
)
} else {
return []
}
}
}