diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..5c619fa1 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +./test/integration/project/lintingError.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 587aa9a5..6565fb34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.4.15 + +* [Add `tslintAutoFix` option to be passed on to tslint to auto format typescript files](https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/174) (#174) + ## v0.4.14 * [Add support for `reportFiles` option](https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/179) (#179) diff --git a/README.md b/README.md index 445b71bf..368edabd 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,9 @@ Allows overriding TypeScript options. Should be specified in the same format as * **tslint** `string | true`: Path to *tslint.json* file or `true`. If `true`, uses `path.resolve(compiler.options.context, './tslint.json')`. Default: `undefined`. +* **tslintAutoFix** `boolean `: +Passes on `--fix` flag while running `tslint` to auto fix linting errors. Default: false. + * **watch** `string | string[]`: Directories or files to watch by service. Not necessary but improves performance (reduces number of `fs.stat` calls). diff --git a/fork-ts-checker-webpack-plugin-v0.4.11.tgz b/fork-ts-checker-webpack-plugin-v0.4.11.tgz new file mode 100644 index 00000000..fd990d7b Binary files /dev/null and b/fork-ts-checker-webpack-plugin-v0.4.11.tgz differ diff --git a/package.json b/package.json index 992faf3b..83479b49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fork-ts-checker-webpack-plugin", - "version": "0.4.14", + "version": "0.4.15", "description": "Runs typescript type checker and linter on separate process.", "main": "lib/index.js", "types": "lib/types/index.d.ts", diff --git a/src/IncrementalChecker.ts b/src/IncrementalChecker.ts index cc549547..d3c0a88b 100644 --- a/src/IncrementalChecker.ts +++ b/src/IncrementalChecker.ts @@ -24,6 +24,7 @@ export class IncrementalChecker { programConfigFile: string; compilerOptions: object; linterConfigFile: string | false; + linterAutoFix: boolean; watchPaths: string[]; workNumber: number; workDivision: number; @@ -44,6 +45,7 @@ export class IncrementalChecker { programConfigFile: string, compilerOptions: object, linterConfigFile: string | false, + linterAutoFix: boolean, watchPaths: string[], workNumber: number, workDivision: number, @@ -53,6 +55,7 @@ export class IncrementalChecker { this.programConfigFile = programConfigFile; this.compilerOptions = compilerOptions; this.linterConfigFile = linterConfigFile; + this.linterAutoFix = linterAutoFix; this.watchPaths = watchPaths; this.workNumber = workNumber || 0; this.workDivision = workDivision || 1; @@ -137,10 +140,10 @@ export class IncrementalChecker { ); } - static createLinter(program: ts.Program) { + createLinter(program: ts.Program) { const tslint = require('tslint'); - return new tslint.Linter({ fix: false }, program); + return new tslint.Linter({ fix: this.linterAutoFix }, program); } static isFileExcluded( @@ -192,7 +195,7 @@ export class IncrementalChecker { this.program = this.vue ? this.loadVueProgram() : this.loadDefaultProgram(); if (this.linterConfig) { - this.linter = IncrementalChecker.createLinter(this.program); + this.linter = this.createLinter(this.program); } } diff --git a/src/index.ts b/src/index.ts index aac5abd2..3561c5f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ interface Options { tsconfig: string; compilerOptions: object; tslint: string | true; + tslintAutoFix: boolean; watch: string | string[]; async: boolean; ignoreDiagnostics: number[]; @@ -76,6 +77,7 @@ class ForkTsCheckerWebpackPlugin { tsconfig: string; compilerOptions: object; tslint: string | true; + tslintAutoFix: boolean; watch: string[]; ignoreDiagnostics: number[]; ignoreLints: string[]; @@ -128,6 +130,7 @@ class ForkTsCheckerWebpackPlugin { ? './tslint.json' : options.tslint : undefined; + this.tslintAutoFix = options.tslintAutoFix || false; this.watch = isString(options.watch) ? [options.watch] : options.watch || []; @@ -566,6 +569,7 @@ class ForkTsCheckerWebpackPlugin { TSCONFIG: this.tsconfigPath, COMPILER_OPTIONS: JSON.stringify(this.compilerOptions), TSLINT: this.tslintPath || '', + TSLINTAUTOFIX: this.tslintAutoFix, WATCH: this.isWatching ? this.watchPaths.join('|') : '', WORK_DIVISION: Math.max(1, this.workersNumber), MEMORY_LIMIT: this.memoryLimit, diff --git a/src/service.ts b/src/service.ts index 01307205..226a7fa8 100644 --- a/src/service.ts +++ b/src/service.ts @@ -8,6 +8,7 @@ const checker = new IncrementalChecker( process.env.TSCONFIG, JSON.parse(process.env.COMPILER_OPTIONS), process.env.TSLINT === '' ? false : process.env.TSLINT, + process.env.TSLINTAUTOFIX === 'true', process.env.WATCH === '' ? [] : process.env.WATCH.split('|'), parseInt(process.env.WORK_NUMBER, 10), parseInt(process.env.WORK_DIVISION, 10), diff --git a/test/integration/index.spec.js b/test/integration/index.spec.js index 3592e6d9..a872abb8 100644 --- a/test/integration/index.spec.js +++ b/test/integration/index.spec.js @@ -1,3 +1,4 @@ +var fs = require('fs'); var describe = require('mocha').describe; var it = require('mocha').it; var chai = require('chai'); @@ -9,12 +10,31 @@ chai.config.truncateThreshold = 0; var expect = chai.expect; var webpackMajorVersion = require('./webpackVersion')(); +const writeContentsToLintingErrorFile = (fileName, data) => { + const promise = new Promise((resolve, reject) => { + try { + fs.writeFileSync( + path.resolve(__dirname, `./project/src/${fileName}.ts`), + data, + { flag: 'w' } + ); + } catch (e) { + return reject(e); + } + return resolve(); + }); + return promise; +}; describe('[INTEGRATION] index', function() { this.timeout(60000); var plugin; - function createCompiler(options, happyPackMode) { + function createCompiler( + options, + happyPackMode, + entryPoint = './src/index.ts' + ) { plugin = new ForkTsCheckerWebpackPlugin( Object.assign({}, options, { silent: true }) ); @@ -26,7 +46,7 @@ describe('[INTEGRATION] index', function() { return webpack({ ...(webpackMajorVersion >= 4 ? { mode: 'development' } : {}), context: path.resolve(__dirname, './project'), - entry: './src/index.ts', + entry: entryPoint, output: { path: path.resolve(__dirname, '../../tmp') }, @@ -92,6 +112,95 @@ describe('[INTEGRATION] index', function() { }); }); + it('should fix linting errors with tslintAutofix flag set to true', function(callback) { + const lintErrorFileContents = `function someFunctionName(param1,param2){return param1+param2}; +`; + const formattedFileContents = `function someFunctionName(param1, param2) {return param1 + param2; } +`; + const fileName = 'lintingError1'; + writeContentsToLintingErrorFile(fileName, lintErrorFileContents).then( + () => { + var compiler = createCompiler( + { + tslintAutoFix: true, + tslint: path.resolve(__dirname, './project/tslint.autofix.json'), + tsconfig: false + }, + false, + `./src/${fileName}.ts` + ); + const deleteFile = () => + fs.unlinkSync( + path.resolve(__dirname, `./project/src/${fileName}.ts`) + ); + compiler.run(function(err, stats) { + expect(stats.compilation.warnings.length).to.be.eq(0); + let fileContents; + try { + fileContents = fs.readFileSync( + path.resolve(__dirname, `./project/src/${fileName}.ts`), + { + encoding: 'utf-8' + } + ); + } catch (e) { + throw e; + } + /* + Helpful to wrap this in a try catch. + If the assertion fails we still need to cleanup + the temporary file created as part of the test + */ + try { + expect(fileContents).to.be.eq(formattedFileContents); + } catch (e) { + deleteFile(); + throw e; + } + deleteFile(); + callback(); + }); + }, + err => { + throw err; + } + ); + }); + it('should not fix linting by default', function(callback) { + const lintErrorFileContents = `function someFunctionName(param1,param2){return param1+param2}; +`; + const fileName = 'lintingError2'; + const deleteFile = () => + fs.unlinkSync(path.resolve(__dirname, `./project/src/${fileName}.ts`)); + writeContentsToLintingErrorFile(fileName, lintErrorFileContents).then( + () => { + var compiler = createCompiler( + { tslint: true }, + false, + `./src/${fileName}.ts` + ); + compiler.run(function(err, stats) { + /* + Helpful to wrap this in a try catch. + If the assertion fails we still need to cleanup + the temporary file created as part of the test + */ + try { + expect(stats.compilation.warnings.length).to.be.eq(7); + } catch (e) { + deleteFile(); + throw e; + } + deleteFile(); + callback(); + }); + }, + err => { + throw err; + } + ); + }); + it('should block emit on build mode', function(callback) { var compiler = createCompiler(); diff --git a/test/integration/project/tslint.autofix.json b/test/integration/project/tslint.autofix.json new file mode 100644 index 00000000..8ff4101b --- /dev/null +++ b/test/integration/project/tslint.autofix.json @@ -0,0 +1,14 @@ +{ + "defaultSeverity": "warning", + "extends": [ + "tslint:recommended" + ], + "linterOptions": { + "exclude": [ + "src/index.ts" + ] + }, + "jsRules": {}, + "rules": {}, + "rulesDirectory": [] +} diff --git a/test/integration/vue.spec.js b/test/integration/vue.spec.js index bc622c51..d2ed0091 100644 --- a/test/integration/vue.spec.js +++ b/test/integration/vue.spec.js @@ -78,6 +78,7 @@ describe('[INTEGRATION] vue', function() { plugin.tsconfigPath, {}, plugin.tslintPath || false, + plugin.tslintAutoFix || false, [compiler.context], ForkTsCheckerWebpackPlugin.ONE_CPU, 1,