Skip to content

Commit

Permalink
Support config option to enforce delimiter even in one liners (palant…
Browse files Browse the repository at this point in the history
  • Loading branch information
pablobirukov authored and johnwiseheart committed Jul 25, 2018
1 parent 9280754 commit f77812c
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 15 deletions.
52 changes: 37 additions & 15 deletions src/rules/typeLiteralDelimiterRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,29 @@ import * as ts from "typescript";

import * as Lint from "../index";

const singeLineConfigOptionName = "singleLine";
interface Options {
[singeLineConfigOptionName]?: "never" | "always";
}

export class Rule extends Lint.Rules.AbstractRule {
/* tslint:disable:object-literal-sort-keys */
public static metadata: Lint.IRuleMetadata = {
ruleName: "type-literal-delimiter",
description: Lint.Utils.dedent`
Checks that type literal members are separated by semicolons.
Enforces a trailing semicolon for multiline type literals.`,
optionsDescription: "Not configurable.",
options: null,
optionsDescription: `\`{${singeLineConfigOptionName}: "always"}\` enforces semicolon for one liners`,
options: {
type: "object",
properties: {
[singeLineConfigOptionName]: {
type: "string",
enum: ["always", "never"] as Array<Options["singleLine"]>,
},
},
},
hasFix: true,
optionExamples: [true],
type: "style",
typescriptOnly: true,
Expand All @@ -43,43 +57,51 @@ export class Rule extends Lint.Rules.AbstractRule {
"Did not expect single-line type literal to have a trailing ';'.";

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
return this.applyWithFunction(
sourceFile,
walk,
this.getRuleOptions());
}

private getRuleOptions(): Options {
if (this.ruleArguments[0] === undefined) {
return {};
} else {
return this.ruleArguments[0] as Options;
}
}
}

function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
function walk(ctx: Lint.WalkContext<Options>): void {
const { sourceFile, options } = ctx;
ts.forEachChild(sourceFile, function cb(node: ts.Node): void {
if (isTypeLiteralNode(node)) {
check(node);
}
ts.forEachChild(node, cb);
});

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());
// Check if delimiter should be ommitted for a single-line type literal.
const shouldOmit = options.singleLine === "always"
? false
: idx === node.members.length - 1 && isSameLine(sourceFile, node.getStart(sourceFile), node.getEnd());
const delimiter = sourceFile.text[end];
switch (delimiter) {
case ";":
if (shouldOmit) {
fail(Rule.FAILURE_STRING_TRAILING);
ctx.addFailureAt(end, 1, Rule.FAILURE_STRING_TRAILING, Lint.Replacement.replaceFromTo(end, end + 1, ""));
}
break;
case ",":
fail(Rule.FAILURE_STRING_COMMA);
ctx.addFailureAt(end, 1, Rule.FAILURE_STRING_COMMA, Lint.Replacement.replaceFromTo(end, end + 1, ";"));
break;
default:
if (!shouldOmit) {
fail(Rule.FAILURE_STRING_MISSING);
ctx.addFailureAt(end, 1, Rule.FAILURE_STRING_MISSING, Lint.Replacement.replaceFromTo(end + 1, end + 1, ";"));
}
}

function fail(failure: string): void {
ctx.addFailureAt(end, 1, failure);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type T = {
x: number;
y: string;
};

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

type T = {
x: number;
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 };

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type T = {
x: number;
y: string;
};

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

type T = {
x: number;
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 ; };

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
type T = {
x: number,
~ [COMMA]
y: string
~ [MISSING]
};

type T = {
x: number
~ [MISSING]
y: string,
~ [COMMA]
};

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

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

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

[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 ';'.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"rules": {
"type-literal-delimiter": [
true,
{
"singleLine": "always"
}
]
}
}

0 comments on commit f77812c

Please sign in to comment.