Skip to content

Commit bede6ed

Browse files
committed
Merge pull request #5366 from RyanCavanaugh/typeOperatorSpacingRule
Type operator spacing rule
2 parents ece96ac + d284a90 commit bede6ed

File tree

6 files changed

+47
-16
lines changed

6 files changed

+47
-16
lines changed

Jakefile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,8 @@ var tslintRuleDir = "scripts/tslint";
820820
var tslintRules = ([
821821
"nextLineRule",
822822
"noNullRule",
823-
"booleanTriviaRule"
823+
"booleanTriviaRule",
824+
"typeOperatorSpacingRule"
824825
]);
825826
var tslintRulesFiles = tslintRules.map(function(p) {
826827
return path.join(tslintRuleDir, p + ".ts");
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 = "The '|' and '&' operators must be surrounded by single spaces";
7+
8+
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
9+
return this.applyWithWalker(new TypeOperatorSpacingWalker(sourceFile, this.getOptions()));
10+
}
11+
}
12+
13+
class TypeOperatorSpacingWalker extends Lint.RuleWalker {
14+
public visitNode(node: ts.Node) {
15+
if (node.kind === ts.SyntaxKind.UnionType || node.kind === ts.SyntaxKind.IntersectionType) {
16+
let types = (<ts.UnionOrIntersectionTypeNode>node).types;
17+
let expectedStart = types[0].end + 2; // space, | or &
18+
for (let i = 1; i < types.length; i++) {
19+
let currentType = types[i];
20+
if (expectedStart !== currentType.pos || currentType.getLeadingTriviaWidth() !== 1) {
21+
const failure = this.createFailure(currentType.pos, currentType.getWidth(), Rule.FAILURE_STRING);
22+
this.addFailure(failure);
23+
}
24+
expectedStart = currentType.end + 2;
25+
}
26+
}
27+
super.visitNode(node);
28+
}
29+
}

src/compiler/checker.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7031,7 +7031,7 @@ namespace ts {
70317031
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
70327032
}
70337033

7034-
function getContextualTypeForJsxExpression(expr: JsxExpression|JsxSpreadAttribute): Type {
7034+
function getContextualTypeForJsxExpression(expr: JsxExpression | JsxSpreadAttribute): Type {
70357035
// Contextual type only applies to JSX expressions that are in attribute assignments (not in 'Children' positions)
70367036
if (expr.parent.kind === SyntaxKind.JsxAttribute) {
70377037
let attrib = <JsxAttribute>expr.parent;
@@ -7539,7 +7539,7 @@ namespace ts {
75397539
/**
75407540
* Returns true iff React would emit this tag name as a string rather than an identifier or qualified name
75417541
*/
7542-
function isJsxIntrinsicIdentifier(tagName: Identifier|QualifiedName) {
7542+
function isJsxIntrinsicIdentifier(tagName: Identifier | QualifiedName) {
75437543
if (tagName.kind === SyntaxKind.QualifiedName) {
75447544
return false;
75457545
}
@@ -7625,7 +7625,7 @@ namespace ts {
76257625
/// If this is a class-based tag (otherwise returns undefined), returns the symbol of the class
76267626
/// type or factory function.
76277627
/// Otherwise, returns unknownSymbol.
7628-
function getJsxElementTagSymbol(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
7628+
function getJsxElementTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
76297629
let flags: JsxFlags = JsxFlags.UnknownElement;
76307630
let links = getNodeLinks(node);
76317631
if (!links.resolvedSymbol) {
@@ -7638,7 +7638,7 @@ namespace ts {
76387638
}
76397639
return links.resolvedSymbol;
76407640

7641-
function lookupIntrinsicTag(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
7641+
function lookupIntrinsicTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
76427642
let intrinsicElementsType = getJsxIntrinsicElementsType();
76437643
if (intrinsicElementsType !== unknownType) {
76447644
// Property case
@@ -7666,7 +7666,7 @@ namespace ts {
76667666
}
76677667
}
76687668

7669-
function lookupClassTag(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
7669+
function lookupClassTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
76707670
let valueSymbol: Symbol = resolveJsxTagName(node);
76717671

76727672
// Look up the value in the current scope
@@ -7680,7 +7680,7 @@ namespace ts {
76807680
return valueSymbol || unknownSymbol;
76817681
}
76827682

7683-
function resolveJsxTagName(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
7683+
function resolveJsxTagName(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
76847684
if (node.tagName.kind === SyntaxKind.Identifier) {
76857685
let tag = <Identifier>node.tagName;
76867686
let sym = getResolvedSymbol(tag);
@@ -15547,7 +15547,7 @@ namespace ts {
1554715547
}
1554815548
}
1554915549

15550-
function checkGrammarJsxElement(node: JsxOpeningElement|JsxSelfClosingElement) {
15550+
function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
1555115551
const seen: Map<boolean> = {};
1555215552
for (let attr of node.attributes) {
1555315553
if (attr.kind === SyntaxKind.JsxSpreadAttribute) {

src/compiler/emitter.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,10 +1404,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
14041404
emit(span.literal);
14051405
}
14061406

1407-
function jsxEmitReact(node: JsxElement|JsxSelfClosingElement) {
1407+
function jsxEmitReact(node: JsxElement | JsxSelfClosingElement) {
14081408
/// Emit a tag name, which is either '"div"' for lower-cased names, or
14091409
/// 'Div' for upper-cased or dotted names
1410-
function emitTagName(name: Identifier|QualifiedName) {
1410+
function emitTagName(name: Identifier | QualifiedName) {
14111411
if (name.kind === SyntaxKind.Identifier && isIntrinsicJsxName((<Identifier>name).text)) {
14121412
write("\"");
14131413
emit(name);
@@ -1557,7 +1557,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
15571557
}
15581558
}
15591559

1560-
function jsxEmitPreserve(node: JsxElement|JsxSelfClosingElement) {
1560+
function jsxEmitPreserve(node: JsxElement | JsxSelfClosingElement) {
15611561
function emitJsxAttribute(node: JsxAttribute) {
15621562
emit(node.name);
15631563
if (node.initializer) {
@@ -1572,7 +1572,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
15721572
write("}");
15731573
}
15741574

1575-
function emitAttributes(attribs: NodeArray<JsxAttribute|JsxSpreadAttribute>) {
1575+
function emitAttributes(attribs: NodeArray<JsxAttribute | JsxSpreadAttribute>) {
15761576
for (let i = 0, n = attribs.length; i < n; i++) {
15771577
if (i > 0) {
15781578
write(" ");
@@ -1588,7 +1588,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
15881588
}
15891589
}
15901590

1591-
function emitJsxOpeningOrSelfClosingElement(node: JsxOpeningElement|JsxSelfClosingElement) {
1591+
function emitJsxOpeningOrSelfClosingElement(node: JsxOpeningElement | JsxSelfClosingElement) {
15921592
write("<");
15931593
emit(node.tagName);
15941594
if (node.attributes.length > 0 || (node.kind === SyntaxKind.JsxSelfClosingElement)) {
@@ -7246,7 +7246,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
72467246
return emitTemplateSpan(<TemplateSpan>node);
72477247
case SyntaxKind.JsxElement:
72487248
case SyntaxKind.JsxSelfClosingElement:
7249-
return emitJsxElement(<JsxElement|JsxSelfClosingElement>node);
7249+
return emitJsxElement(<JsxElement | JsxSelfClosingElement>node);
72507250
case SyntaxKind.JsxText:
72517251
return emitJsxText(<JsxText>node);
72527252
case SyntaxKind.JsxExpression:

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3532,7 +3532,7 @@ namespace ts {
35323532
return result;
35333533
}
35343534

3535-
function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement|JsxSelfClosingElement {
3535+
function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement {
35363536
let fullStart = scanner.getStartPos();
35373537

35383538
parseExpected(SyntaxKind.LessThanToken);

tslint.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"no-trailing-whitespace": true,
3939
"no-inferrable-types": true,
4040
"no-null": true,
41-
"boolean-trivia": true
41+
"boolean-trivia": true,
42+
"type-operator-spacing": true
4243
}
4344
}

0 commit comments

Comments
 (0)