-
-
Notifications
You must be signed in to change notification settings - Fork 247
Add incremental compilation. #198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
b17381c
extracted interface from IncrementalChecker.
0xorial 67f737c
got something working with TypeScript incremental compilation API.
0xorial b8eb249
added some linting.
0xorial c5d7216
got new checker passing old integration tests.
0xorial 654afab
more reliable way of finding if compilation started.
0xorial e5774ed
keep errors from previous run.
0xorial 53d690b
added some tests to incremental typescript compiler.
0xorial 591f55a
added some vue support.
0xorial 666d3d6
output compilation time.
0xorial 6db2175
add option to disable time measurement and use logger for output.
0xorial 9df72d0
added some docs.
0xorial e94b062
added some comments.
0xorial 6af7dfb
fix 'should find the same errors on multi-process mode' test
johnnyreilly 0b8b09b
improve WorkSet typing - bye bye any
johnnyreilly 553e789
update changelog / version
johnnyreilly d54b2c1
name incremental api testpack
johnnyreilly 03230ba
fixed useCaseSensitiveFileNames.
0xorial cbdd847
added tests comments.
0xorial b6ee86c
vue tests for incremental API are actually testing inremental API now.
0xorial 1b1dec7
added tslintAutofix test.
0xorial e847ddd
reorganise tests
johnnyreilly 07a4bd2
split out tests
johnnyreilly 8a48402
run common tests with useTypescriptIncrementalApi both true and false
johnnyreilly 7bb0fb2
removed typescript-collections.
0xorial 2b0b680
added should find semantic errors test
johnnyreilly 0030218
upgrade deps
johnnyreilly File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import * as ts from 'typescript'; | ||
import * as minimatch from 'minimatch'; | ||
import * as path from 'path'; | ||
import { IncrementalCheckerInterface } from './IncrementalCheckerInterface'; | ||
import { CancellationToken } from './CancellationToken'; | ||
import { NormalizedMessage } from './NormalizedMessage'; | ||
import { Configuration, Linter, LintResult } from 'tslint'; | ||
import { CompilerHost } from './CompilerHost'; | ||
import { FsHelper } from './FsHelper'; | ||
|
||
// Need some augmentation here - linterOptions.exclude is not (yet) part of the official | ||
// types for tslint. | ||
interface ConfigurationFile extends Configuration.IConfigurationFile { | ||
linterOptions?: { | ||
typeCheck?: boolean; | ||
exclude?: string[]; | ||
}; | ||
} | ||
|
||
export class ApiIncrementalChecker implements IncrementalCheckerInterface { | ||
private linterConfig?: ConfigurationFile; | ||
|
||
private readonly tsIncrementalCompiler: CompilerHost; | ||
private linterExclusions: minimatch.IMinimatch[] = []; | ||
|
||
private currentLintErrors = new Map<string, LintResult>(); | ||
private lastUpdatedFiles: string[] = []; | ||
private lastRemovedFiles: string[] = []; | ||
|
||
constructor( | ||
programConfigFile: string, | ||
compilerOptions: ts.CompilerOptions, | ||
private linterConfigFile: string | false, | ||
private linterAutoFix: boolean, | ||
checkSyntacticErrors: boolean | ||
) { | ||
this.initLinterConfig(); | ||
|
||
this.tsIncrementalCompiler = new CompilerHost( | ||
programConfigFile, | ||
compilerOptions, | ||
checkSyntacticErrors | ||
); | ||
} | ||
|
||
private initLinterConfig() { | ||
if (!this.linterConfig && this.linterConfigFile) { | ||
this.linterConfig = ApiIncrementalChecker.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)) | ||
); | ||
} | ||
} | ||
} | ||
|
||
private static loadLinterConfig(configFile: string): ConfigurationFile { | ||
const tslint = require('tslint'); | ||
|
||
return tslint.Configuration.loadConfigurationFromPath( | ||
configFile | ||
) as ConfigurationFile; | ||
} | ||
|
||
private createLinter(program: ts.Program): Linter { | ||
const tslint = require('tslint'); | ||
|
||
return new tslint.Linter({ fix: this.linterAutoFix }, program); | ||
} | ||
|
||
public hasLinter(): boolean { | ||
return !!this.linterConfig; | ||
} | ||
|
||
public isFileExcluded(filePath: string): boolean { | ||
return ( | ||
filePath.endsWith('.d.ts') || | ||
this.linterExclusions.some(matcher => matcher.match(filePath)) | ||
); | ||
} | ||
|
||
public nextIteration() { | ||
// do nothing | ||
} | ||
|
||
public async getDiagnostics(_cancellationToken: CancellationToken) { | ||
const diagnostics = await this.tsIncrementalCompiler.processChanges(); | ||
this.lastUpdatedFiles = diagnostics.updatedFiles; | ||
this.lastRemovedFiles = diagnostics.removedFiles; | ||
|
||
return NormalizedMessage.deduplicate( | ||
diagnostics.results.map(NormalizedMessage.createFromDiagnostic) | ||
); | ||
} | ||
|
||
public getLints(_cancellationToken: CancellationToken) { | ||
if (!this.linterConfig) { | ||
return []; | ||
} | ||
|
||
for (const updatedFile of this.lastUpdatedFiles) { | ||
if (this.isFileExcluded(updatedFile)) { | ||
continue; | ||
} | ||
|
||
try { | ||
const linter = this.createLinter( | ||
this.tsIncrementalCompiler.getProgram() | ||
); | ||
// const source = fs.readFileSync(updatedFile, 'utf-8'); | ||
linter.lint(updatedFile, undefined!, this.linterConfig); | ||
const lints = linter.getResult(); | ||
this.currentLintErrors.set(updatedFile, lints); | ||
} catch (e) { | ||
if ( | ||
FsHelper.existsSync(updatedFile) && | ||
// 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; | ||
} | ||
} | ||
|
||
for (const removedFile of this.lastRemovedFiles) { | ||
this.currentLintErrors.delete(removedFile); | ||
} | ||
} | ||
|
||
const allLints = []; | ||
for (const [, value] of this.currentLintErrors) { | ||
allLints.push(...value.failures); | ||
} | ||
|
||
return NormalizedMessage.deduplicate( | ||
allLints.map(NormalizedMessage.createFromLint) | ||
); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This dependency doesn't seems to be used, was it maybe included for the linked list at one point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right. removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your awesome work, I am looking forward to trying this feature out when it is merged :)