test: improve language service tests performance (#30585)
With this change we reduce the amount of IO operations. This is especially a huge factor in windows since IO ops are slower. With this change mainly we cache `existsSync` and `readFileSync` calls Here's the results Before ``` //packages/language-service/test:test INFO: Elapsed time: 258.755s, Critical Path: 253.91s ``` After ``` //packages/language-service/test:test INFO: Elapsed time: 66.403s, Critical Path: 63.13s ``` PR Close #30585
This commit is contained in:
parent
661c6e6f10
commit
41cf066906
|
@ -18,9 +18,14 @@ describe('reflector_host_spec', () => {
|
||||||
// Regression #21811
|
// Regression #21811
|
||||||
it('should be able to find angular under windows', () => {
|
it('should be able to find angular under windows', () => {
|
||||||
const originalJoin = path.join;
|
const originalJoin = path.join;
|
||||||
let mockHost = new MockTypescriptHost(
|
const originalPosixJoin = path.posix.join;
|
||||||
['/app/main.ts', '/app/parsing-cases.ts'], toh, 'app/node_modules',
|
let mockHost =
|
||||||
{...path, join: (...args: string[]) => originalJoin.apply(path, args)});
|
new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], toh, 'app/node_modules', {
|
||||||
|
...path,
|
||||||
|
join: (...args: string[]) => originalJoin.apply(path, args),
|
||||||
|
posix:
|
||||||
|
{...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)}
|
||||||
|
});
|
||||||
const reflectorHost = new ReflectorHost(() => undefined as any, mockHost, {basePath: '\\app'});
|
const reflectorHost = new ReflectorHost(() => undefined as any, mockHost, {basePath: '\\app'});
|
||||||
|
|
||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
|
|
|
@ -72,13 +72,15 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||||
private projectVersion = 0;
|
private projectVersion = 0;
|
||||||
private options: ts.CompilerOptions;
|
private options: ts.CompilerOptions;
|
||||||
private overrideDirectory = new Set<string>();
|
private overrideDirectory = new Set<string>();
|
||||||
|
private existsCache = new Map<string, boolean>();
|
||||||
|
private fileCache = new Map<string, string|undefined>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private scriptNames: string[], private data: MockData,
|
private scriptNames: string[], private data: MockData,
|
||||||
private node_modules: string = 'node_modules', private myPath: typeof path = path) {
|
private node_modules: string = 'node_modules', private myPath: typeof path = path) {
|
||||||
const support = setup();
|
const support = setup();
|
||||||
this.nodeModulesPath = path.join(support.basePath, 'node_modules');
|
this.nodeModulesPath = path.posix.join(support.basePath, 'node_modules');
|
||||||
this.angularPath = path.join(this.nodeModulesPath, '@angular');
|
this.angularPath = path.posix.join(this.nodeModulesPath, '@angular');
|
||||||
this.options = {
|
this.options = {
|
||||||
target: ts.ScriptTarget.ES5,
|
target: ts.ScriptTarget.ES5,
|
||||||
module: ts.ModuleKind.CommonJS,
|
module: ts.ModuleKind.CommonJS,
|
||||||
|
@ -146,7 +148,7 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||||
} else if (effectiveName == '/' + this.node_modules) {
|
} else if (effectiveName == '/' + this.node_modules) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return fs.existsSync(effectiveName);
|
return this.pathExists(effectiveName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,14 +188,19 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||||
cacheUsed.add(fileName);
|
cacheUsed.add(fileName);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let effectiveName = this.getEffectiveName(fileName);
|
|
||||||
if (effectiveName === fileName)
|
const effectiveName = this.getEffectiveName(fileName);
|
||||||
|
if (effectiveName === fileName) {
|
||||||
return open(fileName, this.data);
|
return open(fileName, this.data);
|
||||||
else if (
|
} else if (
|
||||||
!fileName.match(angularts) && !fileName.match(rxjsts) && !fileName.match(rxjsmetadata) &&
|
!fileName.match(angularts) && !fileName.match(rxjsts) && !fileName.match(rxjsmetadata) &&
|
||||||
!fileName.match(tsxfile)) {
|
!fileName.match(tsxfile)) {
|
||||||
if (fs.existsSync(effectiveName)) {
|
if (this.fileCache.has(effectiveName)) {
|
||||||
return fs.readFileSync(effectiveName, 'utf8');
|
return this.fileCache.get(effectiveName);
|
||||||
|
} else if (this.pathExists(effectiveName)) {
|
||||||
|
const content = fs.readFileSync(effectiveName, 'utf8');
|
||||||
|
this.fileCache.set(effectiveName, content);
|
||||||
|
return content;
|
||||||
} else {
|
} else {
|
||||||
missingCache.set(fileName, true);
|
missingCache.set(fileName, true);
|
||||||
reportedMissing.add(fileName);
|
reportedMissing.add(fileName);
|
||||||
|
@ -203,19 +210,29 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private pathExists(path: string): boolean {
|
||||||
|
if (this.existsCache.has(path)) {
|
||||||
|
return this.existsCache.get(path) !;
|
||||||
|
}
|
||||||
|
|
||||||
|
const exists = fs.existsSync(path);
|
||||||
|
this.existsCache.set(path, exists);
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
private getEffectiveName(name: string): string {
|
private getEffectiveName(name: string): string {
|
||||||
const node_modules = this.node_modules;
|
const node_modules = this.node_modules;
|
||||||
const at_angular = '/@angular';
|
const at_angular = '/@angular';
|
||||||
if (name.startsWith('/' + node_modules)) {
|
if (name.startsWith('/' + node_modules)) {
|
||||||
if (this.nodeModulesPath && !name.startsWith('/' + node_modules + at_angular)) {
|
if (this.nodeModulesPath && !name.startsWith('/' + node_modules + at_angular)) {
|
||||||
let result = this.myPath.join(this.nodeModulesPath, name.substr(node_modules.length + 1));
|
const result =
|
||||||
if (!name.match(rxjsts))
|
this.myPath.posix.join(this.nodeModulesPath, name.substr(node_modules.length + 1));
|
||||||
if (fs.existsSync(result)) {
|
if (!name.match(rxjsts) && this.pathExists(result)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.angularPath && name.startsWith('/' + node_modules + at_angular)) {
|
if (this.angularPath && name.startsWith('/' + node_modules + at_angular)) {
|
||||||
return this.myPath.join(
|
return this.myPath.posix.join(
|
||||||
this.angularPath, name.substr(node_modules.length + at_angular.length + 1));
|
this.angularPath, name.substr(node_modules.length + at_angular.length + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,8 +296,6 @@ function getLocationMarkers(value: string): {[name: string]: number} {
|
||||||
}
|
}
|
||||||
|
|
||||||
const referenceMarker = /«(((\w|\-)+)|([^ᐱ]*ᐱ(\w+)ᐱ.[^»]*))»/g;
|
const referenceMarker = /«(((\w|\-)+)|([^ᐱ]*ᐱ(\w+)ᐱ.[^»]*))»/g;
|
||||||
const definitionMarkerGroup = 1;
|
|
||||||
const nameMarkerGroup = 2;
|
|
||||||
|
|
||||||
export type ReferenceMarkers = {
|
export type ReferenceMarkers = {
|
||||||
[name: string]: Span[]
|
[name: string]: Span[]
|
||||||
|
|
Loading…
Reference in New Issue