Skip to content

Commit

Permalink
Merge pull request #169 from liangchunn/chore/lint
Browse files Browse the repository at this point in the history
Support linting + formatting with pre-commit hook
  • Loading branch information
johnnyreilly committed Oct 17, 2018
2 parents 237b1fd + 9f90748 commit aa4a97e
Show file tree
Hide file tree
Showing 34 changed files with 1,892 additions and 1,003 deletions.
30 changes: 12 additions & 18 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
{
"env": {
"node": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
"parserOptions": {
"ecmaVersion": 6,
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
},
"env": {
"node": true,
"mocha": true,
"es6": true
},
"extends": "eslint:recommended"
}
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"singleQuote": true,
"semi": true,
"tabWidth": 2,
"useTabs": false,
"printWidth": 80
}
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ install:
- yarn install
- yarn build
- yarn add $WEBPACK $TSLOADER $VUELOADER -D
- yarn lint
env:
- WEBPACK=webpack@^4.0.0 TSLOADER=ts-loader@^4.3.0 VUELOADER=vue-loader@^15.2.4
- WEBPACK=webpack@^3.10.0 TSLOADER=ts-loader@^3.4.0 VUELOADER=vue-loader@^13.5.0
Expand Down
32 changes: 28 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"test": "npm run build && npm run test:unit && npm run test:integration",
"test:watch": "mocha -R spec --watch ./test/unit",
"test:coverage": "rimraf coverage && istanbul cover -root lib --include-all-sources mocha -- -R spec ./test/unit ./test/integration",
"lint": "eslint ./lib ./test",
"lint:fix": "eslint ./lib ./test --fix"
"lint": "tslint --project src/tsconfig.json && eslint ./test",
"lint:fix": "tslint --project src/tsconfig.json --fix && eslint ./test --fix"
},
"repository": {
"url": "https://github.com/Realytics/fork-ts-checker-webpack-plugin.git",
Expand Down Expand Up @@ -61,15 +61,19 @@
"@types/webpack": "^4.4.9",
"chai": "^3.5.0",
"css-loader": "^0.28.7",
"eslint": "^3.19.0",
"eslint": "^5.7.0",
"husky": "^1.1.2",
"istanbul": "^0.4.5",
"lint-staged": "^7.3.0",
"mocha": "^3.4.1",
"mock-fs": "^4.3.0",
"mock-require": "^2.0.2",
"prettier": "^1.14.3",
"rimraf": "^2.5.4",
"sinon": "^2.3.1",
"ts-loader": "4.3.0",
"tslint": "^5.0.0",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"typescript": "^3.0.1",
"vue": "^2.5.16",
"vue-class-component": "^6.1.1",
Expand All @@ -93,5 +97,25 @@
"minimatch": "^3.0.4",
"resolve": "^1.5.0",
"tapable": "^1.0.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"concurrent": false,
"linters": {
"*.js": [
"eslint --fix"
],
"*.ts": [
"tslint --fix"
],
"*.{js,ts}": [
"prettier --write",
"git add"
]
}
}
}
8 changes: 3 additions & 5 deletions src/CancellationToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ export class CancellationToken {
lastCancellationCheckTime: number;
constructor(cancellationFileName: string, isCancelled: boolean) {
this.isCancelled = !!isCancelled;
this.cancellationFileName = cancellationFileName || crypto.randomBytes(64).toString('hex');
this.cancellationFileName =
cancellationFileName || crypto.randomBytes(64).toString('hex');
this.lastCancellationCheckTime = 0;
}

static createFromJSON(json: CancellationTokenData) {
return new CancellationToken(
json.cancellationFileName,
json.isCancelled
);
return new CancellationToken(json.cancellationFileName, json.isCancelled);
}

toJSON() {
Expand Down
3 changes: 1 addition & 2 deletions src/FilesRegister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface DataShape {
}

export class FilesRegister {
files: { [filePath: string]: { mtime: number; data: DataShape; }};
files: { [filePath: string]: { mtime: number; data: DataShape } };
dataFactory: (_data?: any) => DataShape; // It doesn't seem that the _data parameter is ever used?

constructor(dataFactory: (_data?: any) => DataShape) {
Expand Down Expand Up @@ -74,4 +74,3 @@ export class FilesRegister {
}
}
}

10 changes: 5 additions & 5 deletions src/FilesWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@ export class FilesWatcher {
}

this.watchers = this.watchPaths.map((watchPath: string) => {
return chokidar.watch(
watchPath,
{ persistent: true, alwaysStat: true }
)
return chokidar
.watch(watchPath, { persistent: true, alwaysStat: true })
.on('change', (filePath: string, stats: any) => {
if (this.isFileSupported(filePath)) {
(this.listeners['change'] || []).forEach(changeListener => {
Expand Down Expand Up @@ -67,7 +65,9 @@ export class FilesWatcher {

off(event: string, listener: Function) {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter(oldListener => oldListener !== listener);
this.listeners[event] = this.listeners[event].filter(
oldListener => oldListener !== listener
);
}
}
}
118 changes: 85 additions & 33 deletions src/IncrementalChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,19 @@ export class IncrementalChecker {

// it's shared between compilations
this.files = new FilesRegister(() => ({
// data shape
source: undefined,
linted: false,
lints: []
// data shape
source: undefined,
linted: false,
lints: []
}));
}

static loadProgramConfig(configFile: string) {
return ts.parseJsonConfigFileContent(
// Regardless of the setting in the tsconfig.json we want isolatedModules to be false
Object.assign(ts.readConfigFile(configFile, ts.sys.readFile).config, { isolatedModules: false }),
Object.assign(ts.readConfigFile(configFile, ts.sys.readFile).config, {
isolatedModules: false
}),
ts.sys,
path.dirname(configFile)
);
Expand All @@ -80,7 +82,9 @@ export class IncrementalChecker {
static loadLinterConfig(configFile: string): ConfigurationFile {
const tslint = require('tslint');

return tslint.Configuration.loadConfigurationFromPath(configFile) as ConfigurationFile;
return tslint.Configuration.loadConfigurationFromPath(
configFile
) as ConfigurationFile;
}

static createProgram(
Expand All @@ -107,7 +111,7 @@ export class IncrementalChecker {

// get source file only if there is no source in files register
if (!files.has(filePath) || !files.getData(filePath).source) {
files.mutateData(filePath, (data) => {
files.mutateData(filePath, data => {
data.source = realGetSourceFile(filePath, languageVersion, onError);
});
}
Expand All @@ -129,13 +133,21 @@ export class IncrementalChecker {
return new tslint.Linter({ fix: false }, program);
}

static isFileExcluded(filePath: string, linterExclusions: minimatch.IMinimatch[]): boolean {
return endsWith(filePath, '.d.ts') || linterExclusions.some(matcher => matcher.match(filePath));
static isFileExcluded(
filePath: string,
linterExclusions: minimatch.IMinimatch[]
): boolean {
return (
endsWith(filePath, '.d.ts') ||
linterExclusions.some(matcher => matcher.match(filePath))
);
}

nextIteration() {
if (!this.watcher) {
const watchExtensions = this.vue ? ['.ts', '.tsx', '.vue'] : ['.ts', '.tsx'];
const watchExtensions = this.vue
? ['.ts', '.tsx', '.vue']
: ['.ts', '.tsx'];
this.watcher = new FilesWatcher(this.watchPaths, watchExtensions);

// connect watcher with register
Expand All @@ -150,13 +162,20 @@ export class IncrementalChecker {
}

if (!this.linterConfig && this.linterConfigFile) {
this.linterConfig = IncrementalChecker.loadLinterConfig(this.linterConfigFile);

if (this.linterConfig.linterOptions && this.linterConfig.linterOptions.exclude) {
this.linterConfig = IncrementalChecker.loadLinterConfig(
this.linterConfigFile
);

if (
this.linterConfig.linterOptions &&
this.linterConfig.linterOptions.exclude
) {
// Pre-build minimatch patterns to avoid additional overhead later on.
// Note: Resolving the path is required to properly match against the full file paths,
// and also deals with potential cross-platform problems regarding path separators.
this.linterExclusions = this.linterConfig.linterOptions.exclude.map(pattern => new minimatch.Minimatch(path.resolve(pattern)));
this.linterExclusions = this.linterConfig.linterOptions.exclude.map(
pattern => new minimatch.Minimatch(path.resolve(pattern))
);
}
}

Expand All @@ -168,7 +187,9 @@ export class IncrementalChecker {
}

loadVueProgram() {
this.programConfig = this.programConfig || VueProgram.loadProgramConfig(this.programConfigFile);
this.programConfig =
this.programConfig ||
VueProgram.loadProgramConfig(this.programConfigFile);

return VueProgram.createProgram(
this.programConfig,
Expand All @@ -180,9 +201,16 @@ export class IncrementalChecker {
}

loadDefaultProgram() {
this.programConfig = this.programConfig || IncrementalChecker.loadProgramConfig(this.programConfigFile);
this.programConfig =
this.programConfig ||
IncrementalChecker.loadProgramConfig(this.programConfigFile);

return IncrementalChecker.createProgram(this.programConfig, this.files, this.watcher, this.program);
return IncrementalChecker.createProgram(
this.programConfig,
this.files,
this.watcher,
this.program
);
}

hasLinter() {
Expand All @@ -195,18 +223,30 @@ export class IncrementalChecker {
const filesToCheck = this.program.getSourceFiles();

// calculate subset of work to do
const workSet = new WorkSet(filesToCheck, this.workNumber, this.workDivision);
const workSet = new WorkSet(
filesToCheck,
this.workNumber,
this.workDivision
);

// check given work set
workSet.forEach(sourceFile => {
if (cancellationToken) {
cancellationToken.throwIfCancellationRequested();
}

const diagnosticsToRegister: ReadonlyArray<ts.Diagnostic> = this.checkSyntacticErrors
const diagnosticsToRegister: ReadonlyArray<ts.Diagnostic> = this
.checkSyntacticErrors
? []
.concat(this.program.getSemanticDiagnostics(sourceFile, cancellationToken))
.concat(this.program.getSyntacticDiagnostics(sourceFile, cancellationToken))
.concat(
this.program.getSemanticDiagnostics(sourceFile, cancellationToken)
)
.concat(
this.program.getSyntacticDiagnostics(
sourceFile,
cancellationToken
)
)
: this.program.getSemanticDiagnostics(sourceFile, cancellationToken);

diagnostics.push.apply(diagnostics, diagnosticsToRegister);
Expand All @@ -224,12 +264,20 @@ export class IncrementalChecker {
}

// select files to lint
const filesToLint = this.files.keys().filter(filePath =>
!this.files.getData(filePath).linted && !IncrementalChecker.isFileExcluded(filePath, this.linterExclusions)
);
const filesToLint = this.files
.keys()
.filter(
filePath =>
!this.files.getData(filePath).linted &&
!IncrementalChecker.isFileExcluded(filePath, this.linterExclusions)
);

// calculate subset of work to do
const workSet = new WorkSet(filesToLint, this.workNumber, this.workDivision);
const workSet = new WorkSet(
filesToLint,
this.workNumber,
this.workDivision
);

// lint given work set
workSet.forEach(fileName => {
Expand All @@ -239,11 +287,11 @@ export class IncrementalChecker {
this.linter.lint(fileName, undefined, this.linterConfig);
} catch (e) {
if (
fs.existsSync(fileName) &&
// check the error type due to file system lag
!(e instanceof Error) &&
!(e.constructor.name === 'FatalError') &&
!(e.message && e.message.trim().startsWith("Invalid source file"))
fs.existsSync(fileName) &&
// check the error type due to file system lag
!(e instanceof Error) &&
!(e.constructor.name === 'FatalError') &&
!(e.message && e.message.trim().startsWith('Invalid source file'))
) {
// it's not because file doesn't exist - throw error
throw e;
Expand All @@ -269,9 +317,13 @@ export class IncrementalChecker {
});

// get all lints
const lints = this.files.keys().reduce((innerLints, filePath) =>
innerLints.concat(this.files.getData(filePath).lints),
[]);
const lints = this.files
.keys()
.reduce(
(innerLints, filePath) =>
innerLints.concat(this.files.getData(filePath).lints),
[]
);

// normalize and deduplicate lints
return NormalizedMessage.deduplicate(
Expand Down
4 changes: 2 additions & 2 deletions src/Message.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NormalizedMessage } from './NormalizedMessage';

export interface Message {
diagnostics: NormalizedMessage[];
lints: NormalizedMessage[];
diagnostics: NormalizedMessage[];
lints: NormalizedMessage[];
}
Loading

0 comments on commit aa4a97e

Please sign in to comment.