Skip to content

Commit

Permalink
[tslint] lint typescript code
Browse files Browse the repository at this point in the history
  • Loading branch information
spalger committed May 16, 2018
1 parent 45bf3c2 commit 6ec4110
Show file tree
Hide file tree
Showing 25 changed files with 453 additions and 54 deletions.
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
"debug": "node --nolazy --inspect --debug-brk scripts/kibana --dev",
"precommit": "node scripts/precommit_hook",
"karma": "karma start",
"lint": "echo 'use `node scripts/eslint`' && false",
"lintroller": "echo 'use `node scripts/eslint --fix`' && false",
"lint": "echo 'use `node scripts/eslint` and/or `node scripts/tslint`' && false",
"lintroller": "echo 'use `node scripts/eslint --fix` and/or `node scripts/tslint --fix`' && false",
"makelogs": "echo 'use `node scripts/makelogs`' && false",
"mocha": "echo 'use `node scripts/mocha`' && false",
"sterilize": "grunt sterilize",
Expand All @@ -85,6 +85,8 @@
"@kbn/pm": "link:packages/kbn-pm",
"@kbn/test-subj-selector": "link:packages/kbn-test-subj-selector",
"@kbn/ui-framework": "link:packages/kbn-ui-framework",
"@types/eslint": "^4.16.2",
"@types/execa": "^0.9.0",
"JSONStream": "1.1.1",
"accept-language-parser": "1.2.0",
"angular": "1.6.9",
Expand Down Expand Up @@ -225,6 +227,8 @@
"@kbn/eslint-plugin-license-header": "link:packages/kbn-eslint-plugin-license-header",
"@kbn/plugin-generator": "link:packages/kbn-plugin-generator",
"@kbn/test": "link:packages/kbn-test",
"@types/getopts": "^2.0.0",
"@types/minimatch": "^2.0.29",
"angular-mocks": "1.4.7",
"babel-eslint": "8.1.2",
"babel-jest": "^22.4.3",
Expand Down Expand Up @@ -302,6 +306,9 @@
"ts-jest": "^22.4.3",
"ts-loader": "^3.5.0",
"ts-node": "^6.0.3",
"tslint": "^5.10.0",
"tslint-config-prettier": "^1.12.0",
"tslint-plugin-prettier": "^1.3.0",
"typescript": "^2.8.3",
"vinyl-fs": "^3.0.2",
"xml2js": "^0.4.19",
Expand Down
18 changes: 18 additions & 0 deletions packages/kbn-dev-utils/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Readable } from 'stream';

type LogLevel = 'silent' | 'error' | 'warning' | 'info' | 'debug' | 'verbose';

export interface IToolingLog extends Readable {
verbose(...args: any[]): void;
debug(...args: any[]): void;
info(...args: any[]): void;
success(...args: any[]): void;
warning(...args: any[]): void;
error(errOrMsg: string | Error): void;
write(...args: any[]): void;
indent(spaces: number): void;
getLevel(): LogLevel;
setLevel(level: LogLevel): void;
}

export function createToolingLog(level?: LogLevel): IToolingLog;
6 changes: 6 additions & 0 deletions packages/kbn-dev-utils/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "../../tsconfig.json",
"include": [
"index.d.ts"
],
}
18 changes: 18 additions & 0 deletions packages/kbn-pm/tslint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
extends: ../../tslint.yaml

rules:
max-classes-per-file: false
interface-name: false
variable-name: false
no-empty: false
object-literal-sort-keys: false
member-ordering: false
no-console: false
only-arrow-functions: false
no-shadowed-variable: false
no-empty-interface: false
ordered-imports: false
interface-over-type-literal: false
prettier: false
prefer-const: false
member-access: false
14 changes: 14 additions & 0 deletions packages/kbn-system-loader/tslint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
extends: ../../tslint.yaml

rules:
max-classes-per-file: false
interface-name: false
variable-name: false
no-empty: false
object-literal-sort-keys: false
member-ordering: false
member-access: false
ordered-imports: false
interface-over-type-literal: false
array-type: false
prefer-const: false
2 changes: 2 additions & 0 deletions scripts/tslint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require('../src/babel-register');
require('../src/dev/tslint').runTslintCli();
File renamed without changes.
4 changes: 2 additions & 2 deletions src/dev/eslint/lint_files.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ export function lintFiles(log, files) {
if (report.warningCount > 0) failTypes.push('warning');

if (!failTypes.length) {
log.success('%d files linted successfully', files.length);
log.success('[eslint] %d files linted successfully', files.length);
return;
}

log.error(cli.getFormatter()(report.results));
throw createFailError(`eslint ${failTypes.join(' & ')}`, 1);
throw createFailError(`[eslint] ${failTypes.join(' & ')}`, 1);
}
4 changes: 2 additions & 2 deletions src/dev/eslint/pick_files_to_lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export function pickFilesToLint(log, files) {
const path = file.getRelativePath();

if (cli.isPathIgnored(path)) {
log.warning(`%j ignored by .eslintignore`, file);
log.warning(`[eslint] %j ignored by .eslintignore`, file);
return false;
}

log.debug('linting %j', file);
log.debug('[eslint] linting %j', file);
return true;
});
}
46 changes: 0 additions & 46 deletions src/dev/file.js

This file was deleted.

58 changes: 58 additions & 0 deletions src/dev/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { dirname, extname, join, relative, resolve } from 'path';

import { REPO_ROOT } from './constants';

export class File {
private path: string;
private relativePath: string;
private ext: string;

constructor(path: string) {
this.path = resolve(path);
this.relativePath = relative(REPO_ROOT, this.path);
this.ext = extname(this.path);
}

public getAbsolutePath() {
return this.path;
}

public getRelativePath() {
return this.relativePath;
}

public isJs() {
return this.ext === '.js';
}

public isTypescript() {
return this.ext === '.ts' || this.ext === '.tsx';
}

public getRelativeParentDirs() {
const parents: string[] = [];

while (true) {
// NOTE: resolve() produces absolute paths, so we have to use join()
const parent = parents.length
? join(parents[parents.length - 1], '..')
: dirname(this.relativePath);

if (parent === '..' || parent === '.') {
break;
} else {
parents.push(parent);
}
}

return parents;
}

public toString() {
return this.relativePath;
}

public toJSON() {
return this.relativePath;
}
}
1 change: 1 addition & 0 deletions src/dev/precommit_hook/casing_check_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const IGNORE_FILE_GLOBS = [
'**/.*',
'**/{webpackShims,__mocks__}/**/*',
'x-pack/docs/**/*',
'src/dev/tslint/rules/*',
];


Expand Down
1 change: 1 addition & 0 deletions src/dev/run/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function createFailError(msg: string, exitCode: number): Error;
11 changes: 9 additions & 2 deletions src/dev/run_precommit_hook.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { run } from './run';

import { lintFiles, pickFilesToLint } from './eslint';
import * as Eslint from './eslint';
import * as Tslint from './tslint';
import { getFilesForCommit, checkFileCasing } from './precommit_hook';

run(async ({ log }) => {
const files = await getFilesForCommit();
await checkFileCasing(log, files);
await lintFiles(log, pickFilesToLint(log, files));

for (const Linter of [Eslint, Tslint]) {
const filesToLint = Linter.pickFilesToLint(log, files);
if (filesToLint.length > 0) {
await Linter.lintFiles(log, filesToLint);
}
}
});
3 changes: 3 additions & 0 deletions src/dev/tslint/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { runTslintCli } from './run_tslint_cli';
export { lintFiles } from './lint_files';
export { pickFilesToLint } from './pick_files_to_lint';
72 changes: 72 additions & 0 deletions src/dev/tslint/lint_files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { CLIEngine } from 'eslint';
import { run } from 'tslint/lib/runner';

import { IToolingLog } from '@kbn/dev-utils';
import { REPO_ROOT } from '../constants';
import { File } from '../file';
import { createFailError } from '../run';
import { getTsProjects, Project } from './projects';

function groupFilesByProject(files: File[]) {
const projects = getTsProjects();
const filesByProject: Map<Project, File[]> = new Map();

files.forEach(file => {
const project = projects.find(p => p.isFileSelected(file));

if (!project) {
throw createFailError(
`[tslint] ${file.getRelativePath()} is not a part of any project`,
1
);
}

if (filesByProject.has(project)) {
filesByProject.get(project)!.push(file);
} else {
filesByProject.set(project, [file]);
}
});

return filesByProject;
}

/**
* Lints a list of files with eslint. eslint reports are written to the log
* and a FailError is thrown when linting errors occur.
*
* @param {ToolingLog} log
* @param {Array<File>} files
* @return {undefined}
*/
export async function lintFiles(log: IToolingLog, files: File[]) {
for (const [project, filesInProject] of groupFilesByProject(files)) {
const exitCode = await run(
{
exclude: [],
files: filesInProject.map(f => f.getAbsolutePath()),
fix: false,
format: 'stylish',
project: project.getTsConfigPath(),
},
{
log(m: string) {
log.write(m);
},
error(m: string) {
log.error(m);
},
}
);

if (exitCode > 0) {
throw createFailError(`[tslint] failure`, 1);
} else {
log.success(
'[tslint/%s] %d files linted successfully',
project.getName(),
files.length
);
}
}
}
38 changes: 38 additions & 0 deletions src/dev/tslint/pick_files_to_lint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { IToolingLog } from '@kbn/dev-utils';

import { Minimatch } from 'minimatch';
import { File } from '../file';
import { createFailError } from '../run';
import { getTsProjects } from './projects';

export function pickFilesToLint(log: IToolingLog, files: File[]) {
const projects = getTsProjects();

const filesNotInProjects: File[] = [];
const filesToLint = files.filter(file => {
if (!file.isTypescript()) {
return false;
}

const project = projects.find(p => p.isFileSelected(file));

if (!project) {
filesNotInProjects.push(file);
log.error(
`[tslint] ${file.getRelativePath()} is not a part of any TypeScript project.`
);
return false;
}

return true;
});

if (filesNotInProjects.length) {
throw createFailError(
`[tslint] Ensure that all files are selected by a tsconfig.json file, and that all tsconfig.json files are litsted in "src/dev/tslint/projects.ts"`,
1
);
}

return filesToLint;
}
Loading

0 comments on commit 6ec4110

Please sign in to comment.