From aa548ff3bd606d36ec5dc77e90cb6cd1d85bc741 Mon Sep 17 00:00:00 2001 From: Max Sysoev Date: Sun, 3 Feb 2019 12:16:32 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=E2=AD=90=20feat(rules/number-literal-forma?= =?UTF-8?q?t):=20add=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/numberLiteralFormatRule.ts | 67 ++++++++++++++----- test/rules/number-literal-format/test.ts.fix | 26 +++++++ test/rules/number-literal-format/test.ts.lint | 51 +++++++------- 3 files changed, 103 insertions(+), 41 deletions(-) create mode 100644 test/rules/number-literal-format/test.ts.fix diff --git a/src/rules/numberLiteralFormatRule.ts b/src/rules/numberLiteralFormatRule.ts index 5e48e394923..497fe8cfbe4 100644 --- a/src/rules/numberLiteralFormatRule.ts +++ b/src/rules/numberLiteralFormatRule.ts @@ -25,6 +25,7 @@ export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "number-literal-format", + hasFix: true, description: "Checks that decimal literals should begin with '0.' instead of just '.', and should not end with a trailing '0'.", optionsDescription: "Not configurable.", @@ -63,6 +64,7 @@ function walk(ctx: Lint.WalkContext): void { function check(node: ts.NumericLiteral): void { // Apparently the number literal '0.0' has a '.text' of '0', so use '.getText()' instead. const text = node.getText(sourceFile); + const start = node.getStart(); if (text.length <= 1) { return; @@ -72,8 +74,14 @@ function walk(ctx: Lint.WalkContext): void { // Hex/octal/binary number can't have decimal point or exponent, so no other errors possible. switch (text[1]) { case "x": - if (!isUpperCase(text.slice(2))) { - ctx.addFailureAtNode(node, Rule.FAILURE_STRING_NOT_UPPERCASE); + // strip "0x" + const hexNumber = text.slice(2); + if (!isUpperCase(hexNumber)) { + ctx.addFailureAtNode( + node, + Rule.FAILURE_STRING_NOT_UPPERCASE, + Lint.Replacement.replaceNode(node, `0x${hexNumber.toUpperCase()}`), + ); } return; case "o": @@ -82,35 +90,60 @@ function walk(ctx: Lint.WalkContext): void { case ".": break; default: - ctx.addFailureAtNode(node, Rule.FAILURE_STRING_LEADING_0); + ctx.addFailureAtNode( + node, + Rule.FAILURE_STRING_LEADING_0, + Lint.Replacement.deleteFromTo(start, start + /^0+/.exec(text)![0].length), + ); return; } } - const [num, exp] = text.split(/e/i); + const [num, exp = ""] = text.split(/e/i); + const [integer, float = ""] = num.split("."); + const match = /(\.)([1-9]*)(0+)/.exec(num); + const [dot = "", numbers = "", zeroes = ""] = Array.isArray(match) ? match.slice(1) : []; + if (exp !== undefined && (exp.startsWith("-0") || exp.startsWith("0"))) { - ctx.addFailureAt(node.getEnd() - exp.length, exp.length, Rule.FAILURE_STRING_LEADING_0); + const expStart = start + num.length + 1; // position of exp part + const expNumberStart = /\D/.test(exp.charAt(0)) ? expStart + 1 : expStart; // do not remove "-" or "+" + ctx.addFailureAt( + node.getEnd() - exp.length, + exp.length, + Rule.FAILURE_STRING_LEADING_0, + Lint.Replacement.deleteFromTo( + expNumberStart, + expNumberStart + /0+/.exec(exp)![0].length, + ), + ); } if (!num.includes(".")) { return; - } - - if (num.startsWith(".")) { - fail(Rule.FAILURE_STRING_LEADING_DECIMAL); - } - - if (num.endsWith(".")) { - fail(Rule.FAILURE_STRING_TRAILING_DECIMAL); + } else if (num.startsWith(".")) { + // .1 -> 0.1 + fail(Rule.FAILURE_STRING_LEADING_DECIMAL, Lint.Replacement.appendText(start, "0")); + } else if (num.endsWith(".")) { + // 1. -> 1 + fail( + Rule.FAILURE_STRING_TRAILING_DECIMAL, + Lint.Replacement.deleteText(start + num.length - 1, 1), + ); } // Allow '10', but not '1.0' - if (num.endsWith("0")) { - fail(Rule.FAILURE_STRING_TRAILING_0); + if (float.endsWith("0")) { + // 1.0 -> 1 + const offset = numbers.length > 0 ? dot.length + numbers.length : 0; + const length = (numbers.length > 0 ? 0 : dot.length) + zeroes.length; + fail( + Rule.FAILURE_STRING_TRAILING_0, + Lint.Replacement.deleteText(start + integer.length + offset, length), + ); } - function fail(message: string): void { - ctx.addFailureAt(node.getStart(sourceFile), num.length, message); + function fail(message: string, fix?: Lint.Replacement | Lint.Replacement[]): void { + ctx.addFailureAt(node.getStart(sourceFile), num.length, message, fix); } } } diff --git a/test/rules/number-literal-format/test.ts.fix b/test/rules/number-literal-format/test.ts.fix new file mode 100644 index 00000000000..3049049e8d0 --- /dev/null +++ b/test/rules/number-literal-format/test.ts.fix @@ -0,0 +1,26 @@ +0; +0.5; +10; +1.1e10; + +-6000; + +-777; + +-0; + +-0.9; + +-0.2; + +-0.5; + +-123e3; + +-145E4; + +-1467e-8; + +-189e10; + +-0xDEADBEEF; \ No newline at end of file diff --git a/test/rules/number-literal-format/test.ts.lint b/test/rules/number-literal-format/test.ts.lint index 0b6b363e78d..08403e89824 100644 --- a/test/rules/number-literal-format/test.ts.lint +++ b/test/rules/number-literal-format/test.ts.lint @@ -3,38 +3,41 @@ 10; 1.1e10; -01; -~~ [leading-0] +-0000006000; + ~~~~~~~~~~ [leading-0] -1. -~~ [trailing-decimal] +-777.; + ~~~~ [trailing-decimal] -0.0; -~~~ [trailing-0] -0.50; -~~~~ [trailing-0] +-0.000; + ~~~~~ [trailing-0] -.5; -~~ [leading-decimal] +-0.90000; + ~~~~~~~ [trailing-0] -.50; -~~~ [trailing-0] -~~~ [leading-decimal] +-.2; + ~~ [leading-decimal] -1e01; - ~~ [leading-0] -1E01; - ~~ [leading-0] -1e-01; - ~~~ [leading-0] -1.0e10; -~~~ [trailing-0] +-.50000; + ~~~~~~ [trailing-0] + ~~~~~~ [leading-decimal] -0xDEAdBEEF; -~~~~~~~~~~ [uppercase] +-123e0003; + ~~~~ [leading-0] +-145E0004; + ~~~~ [leading-0] + +-1467e-0008; + ~~~~~ [leading-0] + +-189.000e10; + ~~~~~~~ [trailing-0] + +-0xDEAdBEEF; + ~~~~~~~~~~ [uppercase] [leading-0]: Number literal should not have a leading '0'. [trailing-0]: Number literal should not have a trailing '0'. [trailing-decimal]: Number literal should not end in '.'. [leading-decimal]: Number literal should begin with '0.' and not just '.'. -[uppercase]: Hexadecimal number literal should be uppercase. +[uppercase]: Hexadecimal number literal should be uppercase. \ No newline at end of file From dea7ef67d2f2d1324f10c08c0111678dddc71d82 Mon Sep 17 00:00:00 2001 From: Max Sysoev Date: Mon, 4 Feb 2019 10:17:20 +0300 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=94=8D=20test(number-literal-format):?= =?UTF-8?q?=20return=20back=20testcases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/rules/number-literal-format/test.ts.fix | 21 +++++++++++- test/rules/number-literal-format/test.ts.lint | 33 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/test/rules/number-literal-format/test.ts.fix b/test/rules/number-literal-format/test.ts.fix index 3049049e8d0..5eb2601034c 100644 --- a/test/rules/number-literal-format/test.ts.fix +++ b/test/rules/number-literal-format/test.ts.fix @@ -23,4 +23,23 @@ -189e10; --0xDEADBEEF; \ No newline at end of file +-0xDEADBEEF; + +1; + +1 + +0; +0.5; + +0.5; + +0.5; + +1e1; +1E1; +1e-1; +1e10; + +0xDEADBEEF; + diff --git a/test/rules/number-literal-format/test.ts.lint b/test/rules/number-literal-format/test.ts.lint index 08403e89824..36b285dd244 100644 --- a/test/rules/number-literal-format/test.ts.lint +++ b/test/rules/number-literal-format/test.ts.lint @@ -36,8 +36,39 @@ -0xDEAdBEEF; ~~~~~~~~~~ [uppercase] + +01; +~~ [leading-0] + +1. +~~ [trailing-decimal] + +0.0; +~~~ [trailing-0] +0.50; +~~~~ [trailing-0] + +.5; +~~ [leading-decimal] + +.50; +~~~ [trailing-0] +~~~ [leading-decimal] + +1e01; + ~~ [leading-0] +1E01; + ~~ [leading-0] +1e-01; + ~~~ [leading-0] +1.0e10; +~~~ [trailing-0] + +0xDEAdBEEF; +~~~~~~~~~~ [uppercase] + [leading-0]: Number literal should not have a leading '0'. [trailing-0]: Number literal should not have a trailing '0'. [trailing-decimal]: Number literal should not end in '.'. [leading-decimal]: Number literal should begin with '0.' and not just '.'. -[uppercase]: Hexadecimal number literal should be uppercase. \ No newline at end of file +[uppercase]: Hexadecimal number literal should be uppercase. From e9205087d7976e43a4e5f48e93108628ba450e69 Mon Sep 17 00:00:00 2001 From: Max Sysoev Date: Tue, 5 Feb 2019 10:01:58 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=98=92=20chore(rules/number-literal-f?= =?UTF-8?q?ormat):=20rename=20matches,=20correct=20conditions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/numberLiteralFormatRule.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/rules/numberLiteralFormatRule.ts b/src/rules/numberLiteralFormatRule.ts index 497fe8cfbe4..b06d557f1fb 100644 --- a/src/rules/numberLiteralFormatRule.ts +++ b/src/rules/numberLiteralFormatRule.ts @@ -101,10 +101,10 @@ function walk(ctx: Lint.WalkContext): void { const [num, exp = ""] = text.split(/e/i); const [integer, float = ""] = num.split("."); - const match = /(\.)([1-9]*)(0+)/.exec(num); - const [dot = "", numbers = "", zeroes = ""] = Array.isArray(match) ? match.slice(1) : []; + const matchedNumeric = /(\.)([1-9]*)(0+)/.exec(num); + const [dot = "", numbers = "", zeroes = ""] = Array.isArray(matchedNumeric) ? matchedNumeric.slice(1) : []; - if (exp !== undefined && (exp.startsWith("-0") || exp.startsWith("0"))) { + if (exp.startsWith("-0") || exp.startsWith("0")) { const expStart = start + num.length + 1; // position of exp part const expNumberStart = /\D/.test(exp.charAt(0)) ? expStart + 1 : expStart; // do not remove "-" or "+" ctx.addFailureAt( @@ -120,7 +120,9 @@ function walk(ctx: Lint.WalkContext): void { if (!num.includes(".")) { return; - } else if (num.startsWith(".")) { + } + + if (num.startsWith(".")) { // .1 -> 0.1 fail(Rule.FAILURE_STRING_LEADING_DECIMAL, Lint.Replacement.appendText(start, "0")); } else if (num.endsWith(".")) { From 2f2904ec5025bcf76a3602036a040a108e6a7939 Mon Sep 17 00:00:00 2001 From: Max Sysoev Date: Tue, 5 Feb 2019 10:14:38 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=92=84=20style(rules/number-literal-f?= =?UTF-8?q?ormat):=20multiline=20ternary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/numberLiteralFormatRule.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rules/numberLiteralFormatRule.ts b/src/rules/numberLiteralFormatRule.ts index b06d557f1fb..052a4c2a231 100644 --- a/src/rules/numberLiteralFormatRule.ts +++ b/src/rules/numberLiteralFormatRule.ts @@ -102,7 +102,9 @@ function walk(ctx: Lint.WalkContext): void { const [num, exp = ""] = text.split(/e/i); const [integer, float = ""] = num.split("."); const matchedNumeric = /(\.)([1-9]*)(0+)/.exec(num); - const [dot = "", numbers = "", zeroes = ""] = Array.isArray(matchedNumeric) ? matchedNumeric.slice(1) : []; + const [dot = "", numbers = "", zeroes = ""] = Array.isArray(matchedNumeric) + ? matchedNumeric.slice(1) + : []; if (exp.startsWith("-0") || exp.startsWith("0")) { const expStart = start + num.length + 1; // position of exp part