Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
type-literal-delimiter: Prefer ';' instead of ',', and lint for trail…
Browse files Browse the repository at this point in the history
…ing delimiter (#2787)
  • Loading branch information
andy-hanson authored and nchen63 committed May 20, 2017
1 parent f02ba21 commit ce4dbfe
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 48 deletions.
6 changes: 3 additions & 3 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface IConfigurationFile {
* Other linter options, currently for testing. Not publicly supported.
*/
linterOptions?: {
typeCheck?: boolean,
typeCheck?: boolean;
};

/**
Expand Down Expand Up @@ -447,8 +447,8 @@ export interface RawRulesConfig {
[key: string]: RawRuleConfig;
}
export type RawRuleConfig = null | undefined | boolean | any[] | {
severity?: RuleSeverity | "warn" | "none" | "default",
options?: any,
severity?: RuleSeverity | "warn" | "none" | "default";
options?: any;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/enableDisableRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function getSwitchRange(modifier: Modifier, range: ts.TextRange, sourceFile: ts.
}

type Modifier = "line" | "next-line" | undefined;
function parseComment(commentText: string): { rulesList: string[] | "all", isEnabled: boolean, modifier: Modifier } | undefined {
function parseComment(commentText: string): { rulesList: string[] | "all"; isEnabled: boolean; modifier: Modifier } | undefined {
// regex is: start of string followed by any amount of whitespace
// followed by tslint and colon
// followed by either "enable" or "disable"
Expand Down
2 changes: 1 addition & 1 deletion src/rules/adjacentOverloadSignaturesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function getOverloadKey(node: ts.SignatureDeclaration): string | undefine
return (computed ? "0" : "1") + (isStatic ? "0" : "1") + name;
}

function getOverloadInfo(node: ts.SignatureDeclaration): string | { name: string, computed?: boolean } | undefined {
function getOverloadInfo(node: ts.SignatureDeclaration): string | { name: string; computed?: boolean } | undefined {
switch (node.kind) {
case ts.SyntaxKind.ConstructSignature:
case ts.SyntaxKind.Constructor:
Expand Down
6 changes: 3 additions & 3 deletions src/rules/memberOrderingRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ function getMemberKind(member: Member): MemberKind | undefined {
}
}

type MemberCategoryJson = { name: string, kinds: string[] } | string;
type MemberCategoryJson = { name: string; kinds: string[] } | string;
class MemberCategory {
constructor(readonly name: string, private readonly kinds: Set<MemberKind>) {}
public has(kind: MemberKind) { return this.kinds.has(kind); }
Expand All @@ -376,12 +376,12 @@ function parseOptions(options: any[]): Options {
: new MemberCategory(cat.name, new Set(flatMap(cat.kinds, memberKindFromName))));
return { order, alphabetize };
}
function getOptionsJson(allOptions: any[]): { order: MemberCategoryJson[], alphabetize: boolean } {
function getOptionsJson(allOptions: any[]): { order: MemberCategoryJson[]; alphabetize: boolean } {
if (allOptions == null || allOptions.length === 0 || allOptions[0] == null) {
throw new Error("Got empty options");
}

const firstOption = allOptions[0] as { order: MemberCategoryJson[] | string, alphabetize?: boolean } | string;
const firstOption = allOptions[0] as { order: MemberCategoryJson[] | string; alphabetize?: boolean } | string;
if (typeof firstOption !== "object") {
// Undocumented direct string option. Deprecate eventually.
return { order: convertFromOldStyleOptions(allOptions), alphabetize: false }; // presume allOptions to be string[]
Expand Down
2 changes: 1 addition & 1 deletion src/rules/preferForOfRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function nodeEquals(a: ts.Node, b: ts.Node, sourceFile: ts.SourceFile): boolean
}

// returns the iterator and array of a `for` loop if the `for` loop is basic.
function getForLoopHeaderInfo(forLoop: ts.ForStatement): { indexVariable: ts.Identifier, arrayExpr: ts.Expression } | undefined {
function getForLoopHeaderInfo(forLoop: ts.ForStatement): { indexVariable: ts.Identifier; arrayExpr: ts.Expression } | undefined {
const { initializer, condition, incrementor } = forLoop;
if (initializer === undefined || condition === undefined || incrementor === undefined) {
return undefined;
Expand Down
38 changes: 24 additions & 14 deletions src/rules/typeLiteralDelimiterRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

import { isTypeLiteralNode } from "tsutils";
import { isSameLine, isTypeLiteralNode } from "tsutils";
import * as ts from "typescript";

import * as Lint from "../index";
Expand All @@ -25,8 +25,8 @@ export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: "type-literal-delimiter",
description: Lint.Utils.dedent`
Checks that type literal members are separated by commas.
Does not check the last member, as that is done by 'trailing-comma'.`,
Checks that type literal members are separated by semicolons.
Enforces a trailing semicolon for multiline type literals.`,
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],
Expand All @@ -36,9 +36,11 @@ export class Rule extends Lint.Rules.AbstractRule {
/* tslint:enable:object-literal-sort-keys */

public static FAILURE_STRING_MISSING =
"Expected type literal to use ',' to separate members.";
public static FAILURE_STRING_SEMICOLON =
"Expected type literal to use ',' instead of ';'.";
"Expected type literal to use ';' to separate members.";
public static FAILURE_STRING_COMMA =
"Expected type literal to use ';' instead of ','.";
public static FAILURE_STRING_TRAILING =
"Did not expect single-line type literal to have a trailing ';'.";

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
Expand All @@ -54,23 +56,31 @@ function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(node, cb);
});

function check({ members }: ts.TypeLiteralNode): void {
members.forEach((member, idx) => {
function check(node: ts.TypeLiteralNode): void {
node.members.forEach((member, idx) => {
const end = member.end - 1;
// Trailing delimiter should be ommitted for a single-line type literal.
const shouldOmit = idx === node.members.length - 1 && isSameLine(sourceFile, node.getStart(sourceFile), node.getEnd());
const delimiter = sourceFile.text[end];
switch (delimiter) {
case ",":
break;
case ";":
ctx.addFailureAt(end, 1, Rule.FAILURE_STRING_SEMICOLON);
if (shouldOmit) {
fail(Rule.FAILURE_STRING_TRAILING);
}
break;
case ",":
fail(Rule.FAILURE_STRING_COMMA);
break;
default:
// Allow missing trailing ','
if (idx !== members.length - 1) {
ctx.addFailureAt(end, 1, Rule.FAILURE_STRING_MISSING);
if (!shouldOmit) {
fail(Rule.FAILURE_STRING_MISSING);
}
break;
}

function fail(failure: string): void {
ctx.addFailureAt(end, 1, failure);
}
});
}
}
6 changes: 3 additions & 3 deletions src/rules/unifiedSignaturesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ interface Failure {
only2: boolean;
}
type Unify =
| { kind: "single-parameter-difference", p0: ts.ParameterDeclaration, p1: ts.ParameterDeclaration }
| { kind: "extra-parameter", extraParameter: ts.ParameterDeclaration, otherSignature: ts.NodeArray<ts.ParameterDeclaration> };
| { kind: "single-parameter-difference"; p0: ts.ParameterDeclaration; p1: ts.ParameterDeclaration }
| { kind: "extra-parameter"; extraParameter: ts.ParameterDeclaration; otherSignature: ts.NodeArray<ts.ParameterDeclaration> };

function checkOverloads<T>(
signatures: T[],
Expand Down Expand Up @@ -247,7 +247,7 @@ function signaturesDifferByOptionalOrRestParameter(sig1: ts.NodeArray<ts.Paramet
* Given a node, if it could potentially be an overload, return its signature and key.
* All signatures which are overloads should have equal keys.
*/
type GetOverload<T> = (node: T) => { signature: ts.SignatureDeclaration, key: string } | undefined;
type GetOverload<T> = (node: T) => { signature: ts.SignatureDeclaration; key: string } | undefined;

/**
* Returns true if typeName is the name of an *outer* type parameter.
Expand Down
2 changes: 1 addition & 1 deletion src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export interface SkippedTest {
export interface TestResult {
directory: string;
results: {
[fileName: string]: TestOutput | SkippedTest,
[fileName: string]: TestOutput | SkippedTest;
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function parseErrorsFromMarkup(text: string): LintError[] {
const errorLinesForCodeLines = createCodeLineNoToErrorsMap(lines);

const lintErrors: LintError[] = [];
function addError(errorLine: EndErrorLine, errorStartPos: { line: number, col: number }, lineNo: number) {
function addError(errorLine: EndErrorLine, errorStartPos: { line: number; col: number }, lineNo: number) {
lintErrors.push({
startPos: errorStartPos,
endPos: { line: lineNo, col: errorLine.endCol },
Expand Down
38 changes: 18 additions & 20 deletions test/rules/type-literal-delimiter/test.ts.lint
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
type T = {
x: number
~ [MISSING]
y: string
}

type T = {
x: number,
// Doesn't care about missing final comma; trailing-comma will handle.
~ [COMMA]
y: string
}
~ [MISSING]
};

// Does care about semicolon.
type T = {
x: number,
y: string;
~ [SEMI]
}
x: number
~ [MISSING]
y: string,
~ [COMMA]
};

type T = {
x: number;
~ [SEMI]
y: string
}
y: string;
};

type T = { x: number; y: string };

// Works even when there's extra whitespace
type T = { x: number , y: number };
type T = { x: number ; y: number };
~ [SEMI]
type T = { x: number , y: number ; };
~ [COMMA]
~ [EXTRA]

[MISSING]: Expected type literal to use ',' to separate members.
[SEMI]: Expected type literal to use ',' instead of ';'.
[MISSING]: Expected type literal to use ';' to separate members.
[COMMA]: Expected type literal to use ';' instead of ','.
[EXTRA]: Did not expect single-line type literal to have a trailing ';'.

0 comments on commit ce4dbfe

Please sign in to comment.