semicolonRule.js
7.22 KB
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var ts = require("typescript");
var Lint = require("../lint");
var OPTION_ALWAYS = "always";
var OPTION_NEVER = "never";
var OPTION_IGNORE_INTERFACES = "ignore-interfaces";
var Rule = (function (_super) {
__extends(Rule, _super);
function Rule() {
_super.apply(this, arguments);
}
Rule.prototype.apply = function (sourceFile) {
return this.applyWithWalker(new SemicolonWalker(sourceFile, this.getOptions()));
};
Rule.metadata = {
ruleName: "semicolon",
description: "Enforces consistent semicolon usage at the end of every statement.",
optionsDescription: (_a = ["\n One of the following arguments must be provided:\n\n * `\"", "\"` enforces semicolons at the end of every statement.\n * `\"", "\"` disallows semicolons at the end of every statement except for when they are necessary.\n\n The following arguments may be optionaly provided:\n * `\"", "\"` skips checking semicolons at the end of interface members."], _a.raw = ["\n One of the following arguments must be provided:\n\n * \\`\"", "\"\\` enforces semicolons at the end of every statement.\n * \\`\"", "\"\\` disallows semicolons at the end of every statement except for when they are necessary.\n\n The following arguments may be optionaly provided:\n * \\`\"", "\"\\` skips checking semicolons at the end of interface members."], Lint.Utils.dedent(_a, OPTION_ALWAYS, OPTION_NEVER, OPTION_IGNORE_INTERFACES)),
options: {
type: "array",
items: [{
type: "string",
enum: [OPTION_ALWAYS, OPTION_NEVER],
}, {
type: "string",
enum: [OPTION_IGNORE_INTERFACES],
}],
additionalItems: false,
},
optionExamples: [
("[true, \"" + OPTION_ALWAYS + "\"]"),
("[true, \"" + OPTION_NEVER + "\"]"),
("[true, \"" + OPTION_ALWAYS + "\", \"" + OPTION_IGNORE_INTERFACES + "\"]"),
],
type: "style",
};
Rule.FAILURE_STRING_MISSING = "Missing semicolon";
Rule.FAILURE_STRING_UNNECESSARY = "Unnecessary semicolon";
return Rule;
var _a;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
var SemicolonWalker = (function (_super) {
__extends(SemicolonWalker, _super);
function SemicolonWalker() {
_super.apply(this, arguments);
}
SemicolonWalker.prototype.visitVariableStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitVariableStatement.call(this, node);
};
SemicolonWalker.prototype.visitExpressionStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitExpressionStatement.call(this, node);
};
SemicolonWalker.prototype.visitReturnStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitReturnStatement.call(this, node);
};
SemicolonWalker.prototype.visitBreakStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitBreakStatement.call(this, node);
};
SemicolonWalker.prototype.visitContinueStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitContinueStatement.call(this, node);
};
SemicolonWalker.prototype.visitThrowStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitThrowStatement.call(this, node);
};
SemicolonWalker.prototype.visitImportDeclaration = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitImportDeclaration.call(this, node);
};
SemicolonWalker.prototype.visitImportEqualsDeclaration = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitImportEqualsDeclaration.call(this, node);
};
SemicolonWalker.prototype.visitDoStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitDoStatement.call(this, node);
};
SemicolonWalker.prototype.visitDebuggerStatement = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitDebuggerStatement.call(this, node);
};
SemicolonWalker.prototype.visitPropertyDeclaration = function (node) {
var initializer = node.initializer;
if (this.hasOption(OPTION_NEVER) || !(initializer && initializer.kind === ts.SyntaxKind.ArrowFunction)) {
this.checkSemicolonAt(node);
}
_super.prototype.visitPropertyDeclaration.call(this, node);
};
SemicolonWalker.prototype.visitInterfaceDeclaration = function (node) {
if (this.hasOption(OPTION_IGNORE_INTERFACES)) {
return;
}
for (var _i = 0, _a = node.members; _i < _a.length; _i++) {
var member = _a[_i];
this.checkSemicolonAt(member);
}
_super.prototype.visitInterfaceDeclaration.call(this, node);
};
SemicolonWalker.prototype.visitExportAssignment = function (node) {
this.checkSemicolonAt(node);
_super.prototype.visitExportAssignment.call(this, node);
};
SemicolonWalker.prototype.checkSemicolonAt = function (node) {
var sourceFile = this.getSourceFile();
var children = node.getChildren(sourceFile);
var hasSemicolon = children.some(function (child) { return child.kind === ts.SyntaxKind.SemicolonToken; });
var position = node.getStart(sourceFile) + node.getWidth(sourceFile);
var always = this.hasOption(OPTION_ALWAYS) || (this.getOptions() && this.getOptions().length === 0);
if (always && !hasSemicolon) {
var failureStart = Math.min(position, this.getLimit());
var fix = new Lint.Fix(Rule.metadata.ruleName, [
this.appendText(failureStart, ";"),
]);
this.addFailure(this.createFailure(failureStart, 0, Rule.FAILURE_STRING_MISSING, fix));
}
else if (this.hasOption(OPTION_NEVER) && hasSemicolon) {
var scanner = ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, sourceFile.text);
scanner.setTextPos(position);
var tokenKind = scanner.scan();
while (tokenKind === ts.SyntaxKind.WhitespaceTrivia || tokenKind === ts.SyntaxKind.NewLineTrivia) {
tokenKind = scanner.scan();
}
if (tokenKind !== ts.SyntaxKind.OpenParenToken && tokenKind !== ts.SyntaxKind.OpenBracketToken
&& tokenKind !== ts.SyntaxKind.PlusToken && tokenKind !== ts.SyntaxKind.MinusToken) {
var failureStart = Math.min(position - 1, this.getLimit());
var fix = new Lint.Fix(Rule.metadata.ruleName, [
this.deleteText(failureStart, 1),
]);
this.addFailure(this.createFailure(failureStart, 1, Rule.FAILURE_STRING_UNNECESSARY, fix));
}
}
};
return SemicolonWalker;
}(Lint.RuleWalker));