Skip to content

Commit cadf543

Browse files
committed
Merge branch 'master' into out-module-concat
2 parents 1baea88 + 4cba1b2 commit cadf543

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+4446
-3480
lines changed

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
built
22
doc
3+
lib/README.md
34
scripts
45
src
56
tests

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
language: node_js
22

33
node_js:
4+
- 'stable'
45
- '4'
56
- '0.10'
67

CONTRIBUTING.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ Your pull request should:
3232
* Follow the code conventions descriped in [Coding guidelines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines)
3333
* To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration
3434

35+
## Contributing `lib.d.ts` fixes
36+
37+
The library sources are in: [src/lib](https://github.com/Microsoft/TypeScript/tree/master/src/lib)
38+
39+
To build the library files, run
40+
```Shell
41+
jake lib
42+
```
43+
44+
#### `src/lib/dom.generated.d.ts` and `src/lib/webworker.generated.d.ts`
45+
46+
These two files represent the DOM typings and are auto-generated. To make any modifications to them, please submit a PR to https://github.com/Microsoft/TSJS-lib-generator
47+
3548
## Running the Tests
3649

3750
To run all tests, invoke the `runtests` target using jake:

Jakefile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ var tslintRuleDir = "scripts/tslint";
862862
var tslintRules = ([
863863
"nextLineRule",
864864
"noNullRule",
865+
"preferConstRule",
865866
"booleanTriviaRule",
866867
"typeOperatorSpacingRule"
867868
]);

lib/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Read this!
2+
3+
These files are not meant to be edited by hand.
4+
If you need to make modifications, the respective files should be changed within the repository's top-level `src` directory.

scripts/tslint/preferConstRule.ts

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/// <reference path="../../node_modules/tslint/typings/typescriptServices.d.ts" />
2+
/// <reference path="../../node_modules/tslint/lib/tslint.d.ts" />
3+
4+
5+
export class Rule extends Lint.Rules.AbstractRule {
6+
public static FAILURE_STRING_FACTORY = (identifier: string) => `Identifier '${identifier}' never appears on the LHS of an assignment - use const instead of let for its declaration.`;
7+
8+
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
9+
return this.applyWithWalker(new PreferConstWalker(sourceFile, this.getOptions()));
10+
}
11+
}
12+
13+
function isBindingPattern(node: ts.Node): node is ts.BindingPattern {
14+
return !!node && (node.kind === ts.SyntaxKind.ArrayBindingPattern || node.kind === ts.SyntaxKind.ObjectBindingPattern);
15+
}
16+
17+
function walkUpBindingElementsAndPatterns(node: ts.Node): ts.Node {
18+
while (node && (node.kind === ts.SyntaxKind.BindingElement || isBindingPattern(node))) {
19+
node = node.parent;
20+
}
21+
22+
return node;
23+
}
24+
25+
function getCombinedNodeFlags(node: ts.Node): ts.NodeFlags {
26+
node = walkUpBindingElementsAndPatterns(node);
27+
28+
let flags = node.flags;
29+
if (node.kind === ts.SyntaxKind.VariableDeclaration) {
30+
node = node.parent;
31+
}
32+
33+
if (node && node.kind === ts.SyntaxKind.VariableDeclarationList) {
34+
flags |= node.flags;
35+
node = node.parent;
36+
}
37+
38+
if (node && node.kind === ts.SyntaxKind.VariableStatement) {
39+
flags |= node.flags;
40+
}
41+
42+
return flags;
43+
}
44+
45+
function isLet(node: ts.Node) {
46+
return !!(getCombinedNodeFlags(node) & ts.NodeFlags.Let);
47+
}
48+
49+
function isExported(node: ts.Node) {
50+
return !!(getCombinedNodeFlags(node) & ts.NodeFlags.Export);
51+
}
52+
53+
function isAssignmentOperator(token: ts.SyntaxKind): boolean {
54+
return token >= ts.SyntaxKind.FirstAssignment && token <= ts.SyntaxKind.LastAssignment;
55+
}
56+
57+
function isBindingLiteralExpression(node: ts.Node): node is (ts.ArrayLiteralExpression | ts.ObjectLiteralExpression) {
58+
return (!!node) && (node.kind === ts.SyntaxKind.ObjectLiteralExpression || node.kind === ts.SyntaxKind.ArrayLiteralExpression);
59+
}
60+
61+
interface DeclarationUsages {
62+
declaration: ts.VariableDeclaration;
63+
usages: number;
64+
}
65+
66+
class PreferConstWalker extends Lint.RuleWalker {
67+
private inScopeLetDeclarations: ts.Map<DeclarationUsages>[] = [];
68+
private errors: Lint.RuleFailure[] = [];
69+
private markAssignment(identifier: ts.Identifier) {
70+
const name = identifier.text;
71+
for (let i = this.inScopeLetDeclarations.length - 1; i >= 0; i--) {
72+
const declarations = this.inScopeLetDeclarations[i];
73+
if (declarations[name]) {
74+
declarations[name].usages++;
75+
break;
76+
}
77+
}
78+
}
79+
80+
visitSourceFile(node: ts.SourceFile) {
81+
super.visitSourceFile(node);
82+
// Sort errors by position because tslint doesn't
83+
this.errors.sort((a, b) => a.getStartPosition().getPosition() - b.getStartPosition().getPosition()).forEach(e => this.addFailure(e));
84+
}
85+
86+
visitBinaryExpression(node: ts.BinaryExpression) {
87+
if (isAssignmentOperator(node.operatorToken.kind)) {
88+
this.visitLHSExpressions(node.left);
89+
}
90+
super.visitBinaryExpression(node);
91+
}
92+
93+
private visitLHSExpressions(node: ts.Expression) {
94+
while (node.kind === ts.SyntaxKind.ParenthesizedExpression) {
95+
node = (node as ts.ParenthesizedExpression).expression;
96+
}
97+
if (node.kind === ts.SyntaxKind.Identifier) {
98+
this.markAssignment(node as ts.Identifier);
99+
}
100+
else if (isBindingLiteralExpression(node)) {
101+
this.visitBindingLiteralExpression(node as (ts.ArrayLiteralExpression | ts.ObjectLiteralExpression));
102+
}
103+
}
104+
105+
private visitBindingLiteralExpression(node: ts.ArrayLiteralExpression | ts.ObjectLiteralExpression) {
106+
if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) {
107+
const pattern = node as ts.ObjectLiteralExpression;
108+
for (const element of pattern.properties) {
109+
if (element.name.kind === ts.SyntaxKind.Identifier) {
110+
this.markAssignment(element.name as ts.Identifier)
111+
}
112+
else if (isBindingPattern(element.name)) {
113+
this.visitBindingPatternIdentifiers(element.name as ts.BindingPattern);
114+
}
115+
}
116+
}
117+
else if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) {
118+
const pattern = node as ts.ArrayLiteralExpression;
119+
for (const element of pattern.elements) {
120+
this.visitLHSExpressions(element);
121+
}
122+
}
123+
}
124+
125+
private visitBindingPatternIdentifiers(pattern: ts.BindingPattern) {
126+
for (const element of pattern.elements) {
127+
if (element.name.kind === ts.SyntaxKind.Identifier) {
128+
this.markAssignment(element.name as ts.Identifier);
129+
}
130+
else {
131+
this.visitBindingPatternIdentifiers(element.name as ts.BindingPattern);
132+
}
133+
}
134+
}
135+
136+
visitPrefixUnaryExpression(node: ts.PrefixUnaryExpression) {
137+
this.visitAnyUnaryExpression(node);
138+
super.visitPrefixUnaryExpression(node);
139+
}
140+
141+
visitPostfixUnaryExpression(node: ts.PostfixUnaryExpression) {
142+
this.visitAnyUnaryExpression(node);
143+
super.visitPostfixUnaryExpression(node);
144+
}
145+
146+
private visitAnyUnaryExpression(node: ts.PrefixUnaryExpression | ts.PostfixUnaryExpression) {
147+
if (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) {
148+
this.visitLHSExpressions(node.operand);
149+
}
150+
}
151+
152+
visitModuleDeclaration(node: ts.ModuleDeclaration) {
153+
if (node.body.kind === ts.SyntaxKind.ModuleBlock) {
154+
// For some reason module blocks are left out of the visit block traversal
155+
this.visitBlock(node.body as ts.ModuleBlock);
156+
}
157+
super.visitModuleDeclaration(node);
158+
}
159+
160+
visitForOfStatement(node: ts.ForOfStatement) {
161+
this.visitAnyForStatement(node);
162+
super.visitForOfStatement(node);
163+
this.popDeclarations();
164+
}
165+
166+
visitForInStatement(node: ts.ForInStatement) {
167+
this.visitAnyForStatement(node);
168+
super.visitForInStatement(node);
169+
this.popDeclarations();
170+
}
171+
172+
private visitAnyForStatement(node: ts.ForOfStatement | ts.ForInStatement) {
173+
const names: ts.Map<DeclarationUsages> = {};
174+
if (isLet(node.initializer)) {
175+
if (node.initializer.kind === ts.SyntaxKind.VariableDeclarationList) {
176+
this.collectLetIdentifiers(node.initializer as ts.VariableDeclarationList, names);
177+
}
178+
}
179+
this.inScopeLetDeclarations.push(names);
180+
}
181+
182+
private popDeclarations() {
183+
const completed = this.inScopeLetDeclarations.pop();
184+
for (const name in completed) {
185+
if (Object.hasOwnProperty.call(completed, name)) {
186+
const element = completed[name];
187+
if (element.usages === 0) {
188+
this.errors.push(this.createFailure(element.declaration.getStart(this.getSourceFile()), element.declaration.getWidth(this.getSourceFile()), Rule.FAILURE_STRING_FACTORY(name)));
189+
}
190+
}
191+
}
192+
}
193+
194+
visitBlock(node: ts.Block) {
195+
const names: ts.Map<DeclarationUsages> = {};
196+
for (const statement of node.statements) {
197+
if (statement.kind === ts.SyntaxKind.VariableStatement) {
198+
this.collectLetIdentifiers((statement as ts.VariableStatement).declarationList, names);
199+
}
200+
}
201+
this.inScopeLetDeclarations.push(names);
202+
super.visitBlock(node);
203+
this.popDeclarations();
204+
}
205+
206+
private collectLetIdentifiers(list: ts.VariableDeclarationList, ret: ts.Map<DeclarationUsages>) {
207+
for (const node of list.declarations) {
208+
if (isLet(node) && !isExported(node)) {
209+
this.collectNameIdentifiers(node, node.name, ret);
210+
}
211+
}
212+
}
213+
214+
private collectNameIdentifiers(value: ts.VariableDeclaration, node: ts.Identifier | ts.BindingPattern, table: ts.Map<DeclarationUsages>) {
215+
if (node.kind === ts.SyntaxKind.Identifier) {
216+
table[(node as ts.Identifier).text] = {declaration: value, usages: 0};
217+
}
218+
else {
219+
this.collectBindingPatternIdentifiers(value, node as ts.BindingPattern, table);
220+
}
221+
}
222+
223+
private collectBindingPatternIdentifiers(value: ts.VariableDeclaration, pattern: ts.BindingPattern, table: ts.Map<DeclarationUsages>) {
224+
for (const element of pattern.elements) {
225+
this.collectNameIdentifiers(value, element.name, table);
226+
}
227+
}
228+
}

0 commit comments

Comments
 (0)