Add rule to check spaces around intersection/union type operators
This commit is contained in:
parent
28c2887d50
commit
69236c9be8
|
@ -820,7 +820,8 @@ var tslintRuleDir = "scripts/tslint";
|
||||||
var tslintRules = ([
|
var tslintRules = ([
|
||||||
"nextLineRule",
|
"nextLineRule",
|
||||||
"noNullRule",
|
"noNullRule",
|
||||||
"booleanTriviaRule"
|
"booleanTriviaRule",
|
||||||
|
"typeOperatorSpacingRule"
|
||||||
]);
|
]);
|
||||||
var tslintRulesFiles = tslintRules.map(function(p) {
|
var tslintRulesFiles = tslintRules.map(function(p) {
|
||||||
return path.join(tslintRuleDir, p + ".ts");
|
return path.join(tslintRuleDir, p + ".ts");
|
||||||
|
|
28
scripts/tslint/typeOperatorSpacingRule.ts
Normal file
28
scripts/tslint/typeOperatorSpacingRule.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/// <reference path="../../node_modules/tslint/typings/typescriptServices.d.ts" />
|
||||||
|
/// <reference path="../../node_modules/tslint/lib/tslint.d.ts" />
|
||||||
|
|
||||||
|
|
||||||
|
export class Rule extends Lint.Rules.AbstractRule {
|
||||||
|
public static FAILURE_STRING = "Place spaces around the '|' and '&' type operators";;
|
||||||
|
|
||||||
|
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||||
|
return this.applyWithWalker(new TypeOperatorSpacingWalker(sourceFile, this.getOptions()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeOperatorSpacingWalker extends Lint.RuleWalker {
|
||||||
|
public visitNode(node: ts.Node) {
|
||||||
|
if(node.kind === ts.SyntaxKind.UnionType || node.kind === ts.SyntaxKind.IntersectionType) {
|
||||||
|
let typeNode = <ts.UnionOrIntersectionTypeNode>node;
|
||||||
|
let expectedStart = typeNode.types[0].end + 2; // space, | or &
|
||||||
|
for (let i = 1; i < typeNode.types.length; i++) {
|
||||||
|
if(expectedStart !== typeNode.types[i].pos || typeNode.types[i].getLeadingTriviaWidth() !== 1) {
|
||||||
|
const failure = this.createFailure(typeNode.types[i].pos, typeNode.types[i].getWidth(), Rule.FAILURE_STRING);
|
||||||
|
this.addFailure(failure);
|
||||||
|
}
|
||||||
|
expectedStart = typeNode.types[i].end + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.visitNode(node);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7021,7 +7021,7 @@ namespace ts {
|
||||||
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContextualTypeForJsxExpression(expr: JsxExpression|JsxSpreadAttribute): Type {
|
function getContextualTypeForJsxExpression(expr: JsxExpression | JsxSpreadAttribute): Type {
|
||||||
// Contextual type only applies to JSX expressions that are in attribute assignments (not in 'Children' positions)
|
// Contextual type only applies to JSX expressions that are in attribute assignments (not in 'Children' positions)
|
||||||
if (expr.parent.kind === SyntaxKind.JsxAttribute) {
|
if (expr.parent.kind === SyntaxKind.JsxAttribute) {
|
||||||
let attrib = <JsxAttribute>expr.parent;
|
let attrib = <JsxAttribute>expr.parent;
|
||||||
|
@ -7532,7 +7532,7 @@ namespace ts {
|
||||||
/**
|
/**
|
||||||
* Returns true iff React would emit this tag name as a string rather than an identifier or qualified name
|
* Returns true iff React would emit this tag name as a string rather than an identifier or qualified name
|
||||||
*/
|
*/
|
||||||
function isJsxIntrinsicIdentifier(tagName: Identifier|QualifiedName) {
|
function isJsxIntrinsicIdentifier(tagName: Identifier | QualifiedName) {
|
||||||
if (tagName.kind === SyntaxKind.QualifiedName) {
|
if (tagName.kind === SyntaxKind.QualifiedName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -7618,7 +7618,7 @@ namespace ts {
|
||||||
/// If this is a class-based tag (otherwise returns undefined), returns the symbol of the class
|
/// If this is a class-based tag (otherwise returns undefined), returns the symbol of the class
|
||||||
/// type or factory function.
|
/// type or factory function.
|
||||||
/// Otherwise, returns unknownSymbol.
|
/// Otherwise, returns unknownSymbol.
|
||||||
function getJsxElementTagSymbol(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
|
function getJsxElementTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||||
let flags: JsxFlags = JsxFlags.UnknownElement;
|
let flags: JsxFlags = JsxFlags.UnknownElement;
|
||||||
let links = getNodeLinks(node);
|
let links = getNodeLinks(node);
|
||||||
if (!links.resolvedSymbol) {
|
if (!links.resolvedSymbol) {
|
||||||
|
@ -7631,7 +7631,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
return links.resolvedSymbol;
|
return links.resolvedSymbol;
|
||||||
|
|
||||||
function lookupIntrinsicTag(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
|
function lookupIntrinsicTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||||
let intrinsicElementsType = getJsxIntrinsicElementsType();
|
let intrinsicElementsType = getJsxIntrinsicElementsType();
|
||||||
if (intrinsicElementsType !== unknownType) {
|
if (intrinsicElementsType !== unknownType) {
|
||||||
// Property case
|
// Property case
|
||||||
|
@ -7659,7 +7659,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function lookupClassTag(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
|
function lookupClassTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||||
let valueSymbol: Symbol = resolveJsxTagName(node);
|
let valueSymbol: Symbol = resolveJsxTagName(node);
|
||||||
|
|
||||||
// Look up the value in the current scope
|
// Look up the value in the current scope
|
||||||
|
@ -7673,7 +7673,7 @@ namespace ts {
|
||||||
return valueSymbol || unknownSymbol;
|
return valueSymbol || unknownSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveJsxTagName(node: JsxOpeningLikeElement|JsxClosingElement): Symbol {
|
function resolveJsxTagName(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||||
if (node.tagName.kind === SyntaxKind.Identifier) {
|
if (node.tagName.kind === SyntaxKind.Identifier) {
|
||||||
let tag = <Identifier>node.tagName;
|
let tag = <Identifier>node.tagName;
|
||||||
let sym = getResolvedSymbol(tag);
|
let sym = getResolvedSymbol(tag);
|
||||||
|
@ -15540,7 +15540,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkGrammarJsxElement(node: JsxOpeningElement|JsxSelfClosingElement) {
|
function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
|
||||||
const seen: Map<boolean> = {};
|
const seen: Map<boolean> = {};
|
||||||
for (let attr of node.attributes) {
|
for (let attr of node.attributes) {
|
||||||
if (attr.kind === SyntaxKind.JsxSpreadAttribute) {
|
if (attr.kind === SyntaxKind.JsxSpreadAttribute) {
|
||||||
|
|
|
@ -1404,10 +1404,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||||
emit(span.literal);
|
emit(span.literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
function jsxEmitReact(node: JsxElement|JsxSelfClosingElement) {
|
function jsxEmitReact(node: JsxElement | JsxSelfClosingElement) {
|
||||||
/// Emit a tag name, which is either '"div"' for lower-cased names, or
|
/// Emit a tag name, which is either '"div"' for lower-cased names, or
|
||||||
/// 'Div' for upper-cased or dotted names
|
/// 'Div' for upper-cased or dotted names
|
||||||
function emitTagName(name: Identifier|QualifiedName) {
|
function emitTagName(name: Identifier | QualifiedName) {
|
||||||
if (name.kind === SyntaxKind.Identifier && isIntrinsicJsxName((<Identifier>name).text)) {
|
if (name.kind === SyntaxKind.Identifier && isIntrinsicJsxName((<Identifier>name).text)) {
|
||||||
write("\"");
|
write("\"");
|
||||||
emit(name);
|
emit(name);
|
||||||
|
@ -1557,7 +1557,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function jsxEmitPreserve(node: JsxElement|JsxSelfClosingElement) {
|
function jsxEmitPreserve(node: JsxElement | JsxSelfClosingElement) {
|
||||||
function emitJsxAttribute(node: JsxAttribute) {
|
function emitJsxAttribute(node: JsxAttribute) {
|
||||||
emit(node.name);
|
emit(node.name);
|
||||||
if (node.initializer) {
|
if (node.initializer) {
|
||||||
|
@ -1572,7 +1572,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||||
write("}");
|
write("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitAttributes(attribs: NodeArray<JsxAttribute|JsxSpreadAttribute>) {
|
function emitAttributes(attribs: NodeArray<JsxAttribute | JsxSpreadAttribute>) {
|
||||||
for (let i = 0, n = attribs.length; i < n; i++) {
|
for (let i = 0, n = attribs.length; i < n; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
write(" ");
|
write(" ");
|
||||||
|
@ -1588,7 +1588,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitJsxOpeningOrSelfClosingElement(node: JsxOpeningElement|JsxSelfClosingElement) {
|
function emitJsxOpeningOrSelfClosingElement(node: JsxOpeningElement | JsxSelfClosingElement) {
|
||||||
write("<");
|
write("<");
|
||||||
emit(node.tagName);
|
emit(node.tagName);
|
||||||
if (node.attributes.length > 0 || (node.kind === SyntaxKind.JsxSelfClosingElement)) {
|
if (node.attributes.length > 0 || (node.kind === SyntaxKind.JsxSelfClosingElement)) {
|
||||||
|
@ -7241,7 +7241,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||||
return emitTemplateSpan(<TemplateSpan>node);
|
return emitTemplateSpan(<TemplateSpan>node);
|
||||||
case SyntaxKind.JsxElement:
|
case SyntaxKind.JsxElement:
|
||||||
case SyntaxKind.JsxSelfClosingElement:
|
case SyntaxKind.JsxSelfClosingElement:
|
||||||
return emitJsxElement(<JsxElement|JsxSelfClosingElement>node);
|
return emitJsxElement(<JsxElement | JsxSelfClosingElement>node);
|
||||||
case SyntaxKind.JsxText:
|
case SyntaxKind.JsxText:
|
||||||
return emitJsxText(<JsxText>node);
|
return emitJsxText(<JsxText>node);
|
||||||
case SyntaxKind.JsxExpression:
|
case SyntaxKind.JsxExpression:
|
||||||
|
|
|
@ -3512,7 +3512,7 @@ namespace ts {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement|JsxSelfClosingElement {
|
function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement {
|
||||||
let fullStart = scanner.getStartPos();
|
let fullStart = scanner.getStartPos();
|
||||||
|
|
||||||
parseExpected(SyntaxKind.LessThanToken);
|
parseExpected(SyntaxKind.LessThanToken);
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"no-trailing-whitespace": true,
|
"no-trailing-whitespace": true,
|
||||||
"no-inferrable-types": true,
|
"no-inferrable-types": true,
|
||||||
"no-null": true,
|
"no-null": true,
|
||||||
"boolean-trivia": true
|
"boolean-trivia": true,
|
||||||
|
"type-operator-spacing": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue