mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-11 17:41:26 -06:00
simple-indent
This commit is contained in:
parent
d1ae830def
commit
afafd3fcb3
72
scripts/eslint/rules/simple-indent.ts
Normal file
72
scripts/eslint/rules/simple-indent.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { TSESTree } from "@typescript-eslint/typescript-estree";
|
||||
import { createRule } from "./utils";
|
||||
|
||||
type MessageId = "simpleIndentError";
|
||||
type Options = any;
|
||||
|
||||
export = createRule<Options, MessageId>({
|
||||
name: "simple-indent",
|
||||
meta: {
|
||||
docs: {
|
||||
description: "Enforce consistent indentation",
|
||||
category: "Stylistic Issues",
|
||||
recommended: "error",
|
||||
},
|
||||
messages: {
|
||||
simpleIndentError: "4 space indentation expected",
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [],
|
||||
type: "layout",
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
const TAB_SIZE = 4;
|
||||
const TAB_REGEX = /\t/g;
|
||||
const sourceCode = context.getSourceCode();
|
||||
const linebreaks = sourceCode.getText().match(/\r\n|[\r\n\u2028\u2029]/gu);
|
||||
|
||||
const checkIndent = (node: TSESTree.Program) => {
|
||||
const lines = sourceCode.getLines();
|
||||
const linesLen = lines.length;
|
||||
let totalLen = 0;
|
||||
|
||||
for (let i = 0; i < linesLen; i++) {
|
||||
const lineNumber = i + 1;
|
||||
const line = lines[i];
|
||||
const linebreaksLen = linebreaks && linebreaks[i] ? linebreaks[i].length : 1;
|
||||
const lineLen = line.length + linebreaksLen;
|
||||
const matches = /\S/.exec(line);
|
||||
|
||||
if (matches && matches.index) {
|
||||
const indentEnd = matches.index;
|
||||
const whitespace = line.slice(0, indentEnd);
|
||||
|
||||
if (!TAB_REGEX.test(whitespace)) {
|
||||
totalLen += lineLen;
|
||||
continue;
|
||||
}
|
||||
|
||||
context.report({
|
||||
messageId: 'simpleIndentError',
|
||||
node,
|
||||
loc: { column: indentEnd, line: lineNumber },
|
||||
fix(fixer) {
|
||||
const rangeStart = totalLen;
|
||||
const rangeEnd = rangeStart + indentEnd;
|
||||
|
||||
return fixer
|
||||
.replaceTextRange([rangeStart, rangeEnd], whitespace.replace(TAB_REGEX, " ".repeat(TAB_SIZE)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
totalLen += lineLen;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
Program: checkIndent,
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -1,8 +1,6 @@
|
||||
import { RuleTester, ROOT_DIR } from "./support/RuleTester";
|
||||
import { RuleTester, ROOT_DIR, FILENAME } from "./support/RuleTester";
|
||||
import rule = require("../rules/boolean-trivia");
|
||||
|
||||
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parserOptions: {
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
@ -17,21 +15,25 @@ const ruleTester = new RuleTester({
|
||||
|
||||
ruleTester.run("boolean-trivia", rule, {
|
||||
valid: [{
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: boolean) => {};
|
||||
fn(/* boolean prop */ true);
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: null) => {};
|
||||
fn(/* null prop */ null);
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: null) => {};
|
||||
fn(/*null prop*/ null);
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: boolean) => {};
|
||||
fn(/* comment */
|
||||
@ -39,6 +41,7 @@ fn(/* comment */
|
||||
);
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: boolean) => {};
|
||||
fn.apply(null, true);
|
||||
@ -46,24 +49,28 @@ fn.apply(null, true);
|
||||
}],
|
||||
|
||||
invalid: [{
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: null) => {};
|
||||
fn(null);
|
||||
`,
|
||||
errors: [{ messageId: "booleanTriviaArgumentError" }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: boolean) => {};
|
||||
fn(false);
|
||||
`,
|
||||
errors: [{ messageId: "booleanTriviaArgumentError" }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: boolean) => {};
|
||||
fn(/* boolean arg */false);
|
||||
`,
|
||||
errors: [{ messageId: "booleanTriviaArgumentSpaceError" }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const fn = (prop: boolean) => {};
|
||||
fn(/* first comment */ /* second comment */ false);
|
||||
|
||||
0
scripts/eslint/tests/fixtures/file.ts
vendored
Normal file
0
scripts/eslint/tests/fixtures/file.ts
vendored
Normal file
@ -1,9 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"lib": ["es2015", "es2017", "esnext"]
|
||||
}
|
||||
}
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"lib": ["es2015", "es2017", "esnext"],
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { RuleTester, ROOT_DIR } from "./support/RuleTester";
|
||||
import { RuleTester, ROOT_DIR, FILENAME } from "./support/RuleTester";
|
||||
import rule = require("../rules/no-double-space");
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
@ -15,51 +15,69 @@ const ruleTester = new RuleTester({
|
||||
|
||||
ruleTester.run("no-double-space", rule, {
|
||||
valid: [{
|
||||
filename: FILENAME,
|
||||
code: `const a = {};`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `function fn() {}`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `const a = " ";`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `// ^ ^`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `class Cl {}`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `// comment `,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `/* comment */`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `" string ";`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `/ regexp /g;`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `const rgx = / regexp /g;`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: "const str = ` string template`;",
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: ` // comment`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: ` /* comment */`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `// `,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const a =
|
||||
1;
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
/**
|
||||
* comment
|
||||
*/
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
// comment
|
||||
// - comment
|
||||
// - comment
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
interface Props {
|
||||
prop: string[]; // comment prop
|
||||
@ -67,6 +85,7 @@ interface Props {
|
||||
}
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
/**
|
||||
* Returns a JSON-encoded value of the type: string[]
|
||||
@ -76,6 +95,7 @@ interface Props {
|
||||
*/
|
||||
`,
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const obj = {
|
||||
content: "function f() { 1; }",
|
||||
@ -84,27 +104,35 @@ const obj = {
|
||||
}],
|
||||
|
||||
invalid: [{
|
||||
filename: FILENAME,
|
||||
code: `const a = {};`,
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 6 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `function fn() {}`,
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 9 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `class Cl {}`,
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 6 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: "const str = ` string template`;",
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 12 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `/** comment */`,
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 12 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `/** comment with many spaces */`,
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 12 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `// comment with many spaces`,
|
||||
errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 11 }],
|
||||
}, {
|
||||
filename: FILENAME,
|
||||
code: `
|
||||
const a = 1;
|
||||
const b = 2;
|
||||
|
||||
333
scripts/eslint/tests/simple-indent.test.ts
Normal file
333
scripts/eslint/tests/simple-indent.test.ts
Normal file
@ -0,0 +1,333 @@
|
||||
import { RuleTester } from "./support/RuleTester";
|
||||
import rule = require("../rules/simple-indent");
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parserOptions: {
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
},
|
||||
parser: require.resolve("@typescript-eslint/parser"),
|
||||
});
|
||||
|
||||
ruleTester.run("simple-indent", rule, {
|
||||
valid: [
|
||||
{
|
||||
code: `
|
||||
/**
|
||||
* Comment
|
||||
*/
|
||||
`
|
||||
},
|
||||
{
|
||||
code: `
|
||||
module TestModule {
|
||||
var func = () => {
|
||||
console.warn("hi");
|
||||
};
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
class TestClass {
|
||||
private variable;
|
||||
|
||||
testFunction() {
|
||||
this.variable = 3;
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
var obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
export enum TestEnum {
|
||||
VALUE1,
|
||||
VALUE2
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
switch (integerValue) {
|
||||
case 1:
|
||||
console.warn("1");
|
||||
break;
|
||||
default:
|
||||
console.warn("default");
|
||||
break;
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
function loops() {
|
||||
for (var i = 0; i < 1; ++i) {
|
||||
console.warn(i);
|
||||
}
|
||||
|
||||
while (i < 1) {
|
||||
console.warn(i);
|
||||
}
|
||||
|
||||
do {
|
||||
console.warn(i);
|
||||
} while (i < 1);
|
||||
|
||||
if (i < 1) {
|
||||
console.warn(i);
|
||||
} else {
|
||||
console.warn(i + 1);
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
module TestModule {
|
||||
\tvar testVariable = 123;
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
module TestModule {
|
||||
var testVariable = 123;
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
function a() {
|
||||
\t\tvar test = 123;
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
function a() {
|
||||
var test = 123;
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
class TestClass {
|
||||
\tprivate variable;
|
||||
|
||||
\ttestFunction() {
|
||||
\t\tthis.variable = 3;
|
||||
\t}
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
class TestClass {
|
||||
private variable;
|
||||
|
||||
testFunction() {
|
||||
this.variable = 3;
|
||||
}
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
{ messageId: 'simpleIndentError', line: 5, column: 2 },
|
||||
{ messageId: 'simpleIndentError', line: 6, column: 3 },
|
||||
{ messageId: 'simpleIndentError', line: 7, column: 2 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
var obj = {
|
||||
\ta: 1,
|
||||
\tb: 2,
|
||||
\tc: 3
|
||||
};
|
||||
`,
|
||||
output: `
|
||||
var obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
{ messageId: 'simpleIndentError', line: 4, column: 2 },
|
||||
{ messageId: 'simpleIndentError', line: 5, column: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
enum TestEnum {
|
||||
\tVALUE1,
|
||||
VALUE2
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
enum TestEnum {
|
||||
VALUE1,
|
||||
VALUE2
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
switch (integerValue) {
|
||||
\tcase 0:
|
||||
\t\tconsole.warn("1");
|
||||
\t\tbreak;
|
||||
case 1:
|
||||
console.warn("1");
|
||||
break;
|
||||
\tdefault:
|
||||
\t\tconsole.log("2");
|
||||
\t\tbreak;
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
switch (integerValue) {
|
||||
case 0:
|
||||
console.warn("1");
|
||||
break;
|
||||
case 1:
|
||||
console.warn("1");
|
||||
break;
|
||||
default:
|
||||
console.log("2");
|
||||
break;
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
{ messageId: 'simpleIndentError', line: 4, column: 3 },
|
||||
{ messageId: 'simpleIndentError', line: 5, column: 3 },
|
||||
{ messageId: 'simpleIndentError', line: 9, column: 2 },
|
||||
{ messageId: 'simpleIndentError', line: 10, column: 3 },
|
||||
{ messageId: 'simpleIndentError', line: 11, column: 3 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
for (var i = 0; i < 1; ++i) {
|
||||
\tconsole.warn("123");
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
for (var i = 0; i < 1; ++i) {
|
||||
console.warn("123");
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
while (i < 1) {
|
||||
\tconsole.warn("123");
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
while (i < 1) {
|
||||
console.warn("123");
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
do {
|
||||
\tconsole.warn("123");
|
||||
} while (i < 1);
|
||||
`,
|
||||
output: `
|
||||
do {
|
||||
console.warn("123");
|
||||
} while (i < 1);
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
if (i < 1) {
|
||||
\tconsole.warn("123");
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
if (i < 1) {
|
||||
console.warn("123");
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
var arr = [
|
||||
\t1,
|
||||
2
|
||||
];
|
||||
`,
|
||||
output: `
|
||||
var arr = [
|
||||
1,
|
||||
2
|
||||
];
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 3, column: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
var arr2 = [
|
||||
{
|
||||
\t\ta: 1,
|
||||
b: 2
|
||||
},
|
||||
{
|
||||
a: 3,
|
||||
\t\tb: 4
|
||||
}
|
||||
];
|
||||
`,
|
||||
output: `
|
||||
var arr2 = [
|
||||
{
|
||||
a: 1,
|
||||
b: 2
|
||||
},
|
||||
{
|
||||
a: 3,
|
||||
b: 4
|
||||
}
|
||||
];
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'simpleIndentError', line: 4, column: 3 },
|
||||
{ messageId: 'simpleIndentError', line: 9, column: 3 },
|
||||
]
|
||||
}
|
||||
],
|
||||
});
|
||||
@ -1,5 +1,6 @@
|
||||
import * as path from "path";
|
||||
import { TSESLint } from "@typescript-eslint/experimental-utils";
|
||||
|
||||
export const ROOT_DIR = path.resolve(__dirname);
|
||||
export const ROOT_DIR = path.join(process.cwd(), 'scripts', 'eslint', 'tests', 'fixtures');
|
||||
export const FILENAME = path.join(ROOT_DIR, 'file.ts');
|
||||
export const RuleTester = TSESLint.RuleTester;
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"noResolve": false,
|
||||
"strict": true,
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"outDir": "../../built/eslint",
|
||||
"lib": ["es2015", "es2016"]
|
||||
},
|
||||
@ -24,5 +24,9 @@
|
||||
"rules",
|
||||
"tests",
|
||||
"tests/support/*.json"
|
||||
],
|
||||
|
||||
"exclude": [
|
||||
"tests/fixtures"
|
||||
]
|
||||
}
|
||||
|
||||
@ -5916,7 +5916,8 @@ namespace ts {
|
||||
|
||||
// If fileName is provided, gets all the diagnostics associated with that file name.
|
||||
// Otherwise, returns all the diagnostics (global and file associated) in this collection.
|
||||
getDiagnostics(fileName?: string): DiagnosticWithLocation[];
|
||||
getDiagnostics(): Diagnostic[];
|
||||
getDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
||||
reattachFileDiagnostics(newFile: SourceFile): void;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user