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

Commit

Permalink
New rule option: 'check-rest-spread' for 'whitespace' rule (#3089)
Browse files Browse the repository at this point in the history
  • Loading branch information
ksvitkovsky authored and adidahiya committed Aug 10, 2017
1 parent 658cc8f commit 3b2d456
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 6 deletions.
43 changes: 37 additions & 6 deletions src/rules/whitespaceRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const OPTION_DECL = "check-decl";
const OPTION_OPERATOR = "check-operator";
const OPTION_MODULE = "check-module";
const OPTION_SEPARATOR = "check-separator";
const OPTION_REST_SPREAD = "check-rest-spread";
const OPTION_TYPE = "check-type";
const OPTION_TYPECAST = "check-typecast";
const OPTION_PREBLOCK = "check-preblock";
Expand All @@ -37,13 +38,14 @@ export class Rule extends Lint.Rules.AbstractRule {
description: "Enforces whitespace style conventions.",
rationale: "Helps maintain a readable, consistent style in your codebase.",
optionsDescription: Lint.Utils.dedent`
Eight arguments may be optionally provided:
Nine arguments may be optionally provided:
* \`"check-branch"\` checks branching statements (\`if\`/\`else\`/\`for\`/\`while\`) are followed by whitespace.
* \`"check-decl"\`checks that variable declarations have whitespace around the equals token.
* \`"check-operator"\` checks for whitespace around operator tokens.
* \`"check-module"\` checks for whitespace in import & export statements.
* \`"check-separator"\` checks for whitespace after separator tokens (\`,\`/\`;\`).
* \`"check-rest-spread"\` checks that there is no whitespace after rest/spread operator (\`...\`).
* \`"check-type"\` checks for whitespace before a variable type specification.
* \`"check-typecast"\` checks for whitespace between a typecast and its target.
* \`"check-preblock"\` checks for whitespace before the opening brace of a block`,
Expand All @@ -52,31 +54,33 @@ export class Rule extends Lint.Rules.AbstractRule {
items: {
type: "string",
enum: ["check-branch", "check-decl", "check-operator", "check-module",
"check-separator", "check-type", "check-typecast", "check-preblock"],
"check-separator", "check-rest-spread", "check-type", "check-typecast", "check-preblock"],
},
minLength: 0,
maxLength: 7,
maxLength: 9,
},
optionExamples: [[true, "check-branch", "check-operator", "check-typecast"]],
type: "style",
typescriptOnly: false,
};

public static FAILURE_STRING = "missing whitespace";
public static FAILURE_STRING_MISSING = "missing whitespace";
public static FAILURE_STRING_INVALID = "invalid whitespace";

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

type Options = Record<"branch" | "decl" | "operator" | "module" | "separator" | "type" | "typecast" | "preblock", boolean>;
type Options = Record<"branch" | "decl" | "operator" | "module" | "separator" | "restSpread" | "type" | "typecast" | "preblock", boolean>;
function parseOptions(ruleArguments: string[]): Options {
return {
branch: has(OPTION_BRANCH),
decl: has(OPTION_DECL),
operator: has(OPTION_OPERATOR),
module: has(OPTION_MODULE),
separator: has(OPTION_SEPARATOR),
restSpread: has(OPTION_REST_SPREAD),
type: has(OPTION_TYPE),
typecast: has(OPTION_TYPECAST),
preblock: has(OPTION_PREBLOCK),
Expand Down Expand Up @@ -192,6 +196,22 @@ function walk(ctx: Lint.WalkContext<Options>) {
if (options.decl && initializer !== undefined) {
checkForTrailingWhitespace((type !== undefined ? type : name).getEnd());
}
break;

case ts.SyntaxKind.BindingElement:
case ts.SyntaxKind.Parameter:
const { dotDotDotToken } = node as ts.BindingElement | ts.ParameterDeclaration;
if (options.restSpread && dotDotDotToken !== undefined) {
checkForExcessiveWhitespace(dotDotDotToken.end);
}
break;

case ts.SyntaxKind.SpreadAssignment:
case ts.SyntaxKind.SpreadElement:
if (options.restSpread) {
const position = (node as ts.SpreadAssignment).expression.getFullStart();
checkForExcessiveWhitespace(position);
}
}

ts.forEachChild(node, cb);
Expand Down Expand Up @@ -278,6 +298,17 @@ function walk(ctx: Lint.WalkContext<Options>) {
return;
}
const fix = Lint.Replacement.appendText(position, " ");
ctx.addFailureAt(position, 1, Rule.FAILURE_STRING, fix);
ctx.addFailureAt(position, 1, Rule.FAILURE_STRING_MISSING, fix);
}

function checkForExcessiveWhitespace(position: number): void {
if (position !== sourceFile.end && Lint.isWhiteSpace(sourceFile.text.charCodeAt(position))) {
addInvalidWhitespaceErrorAt(position);
}
}

function addInvalidWhitespaceErrorAt(position: number): void {
const fix = Lint.Replacement.deleteText(position, 1);
ctx.addFailureAt(position, 1, Rule.FAILURE_STRING_INVALID, fix);
}
}
8 changes: 8 additions & 0 deletions test/rules/whitespace/all/test.ts.fix
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,11 @@ else
const foo = 123;
// code that just wants to be encapsulated in a block scope
}

const foo = { ...bar };

const foo = [ ...bar ];

function foo (bar, ...baz) {}

const { foo, ...bar } = baz;
12 changes: 12 additions & 0 deletions test/rules/whitespace/all/test.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,15 @@ else
const foo = 123;
// code that just wants to be encapsulated in a block scope
}

const foo = { ... bar };
~ [invalid whitespace]

const foo = [ ... bar ];
~ [invalid whitespace]

function foo (bar, ... baz) {}
~ [invalid whitespace]

const { foo, ... bar } = baz;
~ [invalid whitespace]
1 change: 1 addition & 0 deletions test/rules/whitespace/all/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"check-module",
"check-preblock",
"check-separator",
"check-rest-spread",
"check-type",
"check-typecast"
]
Expand Down
8 changes: 8 additions & 0 deletions test/rules/whitespace/none/test.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,11 @@ else
const foo = 123;
// code that just wants to be encapsulated in a block scope
}

const foo = { ... bar };

const foo = [ ... bar ];

function foo (bar, ... baz) {}

const { foo, ... bar } = baz;

0 comments on commit 3b2d456

Please sign in to comment.