This repository has been archived by the owner on Jun 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
serializeRule.ts
86 lines (75 loc) · 2.55 KB
/
serializeRule.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
74
75
76
77
78
79
80
81
82
83
84
85
86
import * as ts from "typescript"
import * as Lint from "tslint"
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "cannot use a captured variable in a serialized function"
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new NoCaptureUseInSerializedFunction(sourceFile, this.getOptions()))
}
}
// The walker takes care of all the work.
class NoCaptureUseInSerializedFunction extends Lint.RuleWalker {
private getSiblings(node: ts.Node): ts.Node[] {
const siblings: ts.Node[] = []
if (node.parent) {
ts.forEachChild(node.parent, (sibling: ts.Node) => {
if (sibling !== node) {
siblings.push(sibling)
}
})
}
return siblings
}
private forEachParent(node: ts.Node, iterator: (node: ts.Node) => boolean) {
if (node.parent) {
if (!iterator(node.parent)) {
this.forEachParent(node.parent, iterator)
}
}
}
private isDeclaration(node: ts.Identifier): boolean {
const kinds = [
ts.SyntaxKind.VariableDeclaration,
ts.SyntaxKind.VariableDeclarationList,
ts.SyntaxKind.FunctionDeclaration,
ts.SyntaxKind.ClassDeclaration,
ts.SyntaxKind.InterfaceDeclaration,
ts.SyntaxKind.TypeAliasDeclaration,
ts.SyntaxKind.EnumDeclaration,
ts.SyntaxKind.ModuleDeclaration,
ts.SyntaxKind.ImportEqualsDeclaration,
ts.SyntaxKind.ImportDeclaration,
ts.SyntaxKind.ExportDeclaration,
]
return (kinds.includes(node.parent.kind))
}
public visitIdentifier(node: ts.Identifier) {
if (!this.isDeclaration(node) && node.parent.kind !== ts.SyntaxKind.PropertyAccessExpression) {
let block: ts.Block | null = null
this.forEachParent(node, (parent) => {
this.getSiblings(parent).forEach((sibling) => {
if (sibling.kind === ts.SyntaxKind.ExpressionStatement) {
const { expression } = sibling as ts.ExpressionStatement
if (expression.kind === ts.SyntaxKind.StringLiteral) {
const lit: ts.StringLiteral = expression as ts.StringLiteral
if (lit.text === "serialized") {
this.forEachParent(sibling, (directiveParent) => {
if (directiveParent.kind === ts.SyntaxKind.Block) {
block = directiveParent as ts.Block
return true
} else {
return false
}
})
}
}
}
})
return block !== null
})
// 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.visitIdentifier(node)
}
}