Skip to content

Commit

Permalink
feat(typescript-estree): add flag EXPERIMENTAL_useSourceOfProjectRefe…
Browse files Browse the repository at this point in the history
…renceRedirect (#2669)
  • Loading branch information
bradzacher committed Oct 15, 2020
1 parent 2c4b838 commit 90a5878
Show file tree
Hide file tree
Showing 16 changed files with 121 additions and 33 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -26,6 +26,7 @@ module.exports = {
],
tsconfigRootDir: __dirname,
warnOnUnsupportedTypeScriptVersion: false,
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
},
rules: {
//
Expand Down
3 changes: 2 additions & 1 deletion packages/eslint-plugin-internal/tsconfig.json
Expand Up @@ -4,5 +4,6 @@
"composite": false,
"rootDir": "."
},
"include": ["src", "typings", "tests"]
"include": ["src", "typings", "tests"],
"references": [{ "path": "../experimental-utils/tsconfig.build.json" }]
}
6 changes: 1 addition & 5 deletions packages/eslint-plugin-tslint/tsconfig.build.json
Expand Up @@ -6,9 +6,5 @@
"resolveJsonModule": true
},
"include": ["src"],
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../parser/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
]
"references": [{ "path": "../experimental-utils/tsconfig.build.json" }]
}
3 changes: 2 additions & 1 deletion packages/eslint-plugin-tslint/tsconfig.json
Expand Up @@ -5,5 +5,6 @@
"rootDir": "."
},
"include": ["src", "tests"],
"exclude": ["tests/test-project", "tests/test-tslint-rules-directory"]
"exclude": ["tests/test-project", "tests/test-tslint-rules-directory"],
"references": [{ "path": "../experimental-utils/tsconfig.build.json" }]
}
3 changes: 1 addition & 2 deletions packages/eslint-plugin/tsconfig.build.json
Expand Up @@ -12,7 +12,6 @@
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../parser/tsconfig.build.json" },
{ "path": "../scope-manager/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
{ "path": "../scope-manager/tsconfig.build.json" }
]
}
7 changes: 6 additions & 1 deletion packages/eslint-plugin/tsconfig.json
Expand Up @@ -4,5 +4,10 @@
"composite": false,
"rootDir": "."
},
"include": ["src", "typings", "tests", "tools"]
"include": ["src", "typings", "tests", "tools"],
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../parser/tsconfig.build.json" },
{ "path": "../scope-manager/tsconfig.build.json" }
]
}
7 changes: 6 additions & 1 deletion packages/experimental-utils/tsconfig.json
Expand Up @@ -4,5 +4,10 @@
"composite": false,
"rootDir": "."
},
"include": ["src", "typings", "tests", "tools"]
"include": ["src", "typings", "tests", "tools"],
"references": [
{ "path": "../scope-manager/tsconfig.build.json" },
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
]
}
6 changes: 3 additions & 3 deletions packages/parser/tsconfig.build.json
Expand Up @@ -9,9 +9,9 @@
"include": ["src"],
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" },
{ "path": "../scope-manager/tsconfig.build.json" },
{ "path": "../shared-fixtures/tsconfig.build.json" }
{ "path": "../shared-fixtures/tsconfig.build.json" },
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
]
}
9 changes: 8 additions & 1 deletion packages/parser/tsconfig.json
Expand Up @@ -5,5 +5,12 @@
"rootDir": "."
},
"include": ["src", "tests", "tools"],
"exclude": ["tests/fixtures"]
"exclude": ["tests/fixtures"],
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../scope-manager/tsconfig.build.json" },
{ "path": "../shared-fixtures/tsconfig.build.json" },
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
]
}
7 changes: 6 additions & 1 deletion packages/scope-manager/tsconfig.json
Expand Up @@ -4,5 +4,10 @@
"composite": false,
"rootDir": "."
},
"include": ["src", "typings", "tests", "tools"]
"include": ["src", "typings", "tests", "tools"],
"references": [
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" },
{ "path": "../visitor-keys/tsconfig.build.json" }
]
}
1 change: 1 addition & 0 deletions packages/types/src/parser-options.ts
Expand Up @@ -37,6 +37,7 @@ interface ParserOptions {
debugLevel?: DebugLevel;
errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;
errorOnUnknownASTType?: boolean;
EXPERIMENTAL_useSourceOfProjectReferenceRedirect?: boolean; // purposely undocumented for now
extraFileExtensions?: string[];
filePath?: string;
loc?: boolean;
Expand Down
12 changes: 12 additions & 0 deletions packages/typescript-estree/README.md
Expand Up @@ -152,6 +152,18 @@ interface ParseAndGenerateServicesOptions extends ParseOptions {
*/
errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;

/**
* ***EXPERIMENTAL FLAG*** - Use this at your own risk.
*
* Causes TS to use the source files for referenced projects instead of the compiled .d.ts files.
* This feature is not yet optimized, and is likely to cause OOMs for medium to large projects.
*
* This flag REQUIRES at least TS v3.9, otherwise it does nothing.
*
* See: https://github.com/typescript-eslint/typescript-eslint/issues/2094
*/
EXPERIMENTAL_useSourceOfProjectReferenceRedirect?: boolean;

/**
* When `project` is provided, this controls the non-standard file extensions which will be parsed.
* It accepts an array of file extensions, each preceded by a `.`.
Expand Down
62 changes: 47 additions & 15 deletions packages/typescript-estree/src/create-program/createWatchProgram.ts
Expand Up @@ -117,6 +117,20 @@ function createHash(content: string): string {
return content;
}

function updateCachedFileList(
tsconfigPath: CanonicalPath,
program: ts.Program,
extra: Extra,
): Set<CanonicalPath> {
const fileList = extra.EXPERIMENTAL_useSourceOfProjectReferenceRedirect
? new Set(
program.getSourceFiles().map(sf => getCanonicalFileName(sf.fileName)),
)
: new Set(program.getRootFileNames().map(f => getCanonicalFileName(f)));
programFileListCache.set(tsconfigPath, fileList);
return fileList;
}

/**
* Calculate project environments using options provided by consumer and paths from config
* @param code The code being linted
Expand Down Expand Up @@ -154,21 +168,12 @@ function getProgramsForProjects(
* before we go into the process of attempting to find and update every program
* see if we know of a program that contains this file
*/
for (const rawTsconfigPath of extra.projects) {
const tsconfigPath = getTsconfigPath(rawTsconfigPath, extra);
const existingWatch = knownWatchProgramMap.get(tsconfigPath);
if (!existingWatch) {
continue;
}

for (const [tsconfigPath, existingWatch] of knownWatchProgramMap.entries()) {
let fileList = programFileListCache.get(tsconfigPath);
let updatedProgram: ts.Program | null = null;
if (!fileList) {
updatedProgram = existingWatch.getProgram().getProgram();
fileList = new Set(
updatedProgram.getRootFileNames().map(f => getCanonicalFileName(f)),
);
programFileListCache.set(tsconfigPath, fileList);
fileList = updateCachedFileList(tsconfigPath, updatedProgram, extra);
}

if (fileList.has(filePath)) {
Expand Down Expand Up @@ -209,18 +214,38 @@ function getProgramsForProjects(

// sets parent pointers in source files
updatedProgram.getTypeChecker();
results.push(updatedProgram);

// cache and check the file list
const fileList = updateCachedFileList(
tsconfigPath,
updatedProgram,
extra,
);
if (fileList.has(filePath)) {
log('Found updated program for file. %s', filePath);
// we can return early because we know this program contains the file
return [updatedProgram];
}

results.push(updatedProgram);
continue;
}

const programWatch = createWatchProgram(tsconfigPath, extra);
const program = programWatch.getProgram().getProgram();

// cache watch program and return current program
knownWatchProgramMap.set(tsconfigPath, programWatch);

const program = programWatch.getProgram().getProgram();
// sets parent pointers in source files
program.getTypeChecker();

// cache and check the file list
const fileList = updateCachedFileList(tsconfigPath, program, extra);
if (fileList.has(filePath)) {
log('Found program for file. %s', filePath);
// we can return early because we know this program contains the file
return [program];
}

results.push(program);
}

Expand Down Expand Up @@ -324,6 +349,13 @@ function createWatchProgram(
);
watchCompilerHost.trace = log;

/**
* TODO: this needs refinement and development, but we're allowing users to opt-in to this for now for testing and feedback.
* See https://github.com/typescript-eslint/typescript-eslint/issues/2094
*/
watchCompilerHost.useSourceOfProjectReferenceRedirect = (): boolean =>
extra.EXPERIMENTAL_useSourceOfProjectReferenceRedirect;

// Since we don't want to asynchronously update program we want to disable timeout methods
// So any changes in the program will be delayed and updated when getProgram is called on watch
let callback: (() => void) | undefined;
Expand Down
13 changes: 13 additions & 0 deletions packages/typescript-estree/src/parser-options.ts
Expand Up @@ -12,6 +12,7 @@ export interface Extra {
debugLevel: Set<DebugModule>;
errorOnTypeScriptSyntacticAndSemanticIssues: boolean;
errorOnUnknownASTType: boolean;
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: boolean;
extraFileExtensions: string[];
filePath: string;
jsx: boolean;
Expand Down Expand Up @@ -111,6 +112,18 @@ interface ParseAndGenerateServicesOptions extends ParseOptions {
*/
errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;

/**
* ***EXPERIMENTAL FLAG*** - Use this at your own risk.
*
* Causes TS to use the source files for referenced projects instead of the compiled .d.ts files.
* This feature is not yet optimized, and is likely to cause OOMs for medium to large projects.
*
* This flag REQUIRES at least TS v3.9, otherwise it does nothing.
*
* See: https://github.com/typescript-eslint/typescript-eslint/issues/2094
*/
EXPERIMENTAL_useSourceOfProjectReferenceRedirect?: boolean;

/**
* When `project` is provided, this controls the non-standard file extensions which will be parsed.
* It accepts an array of file extensions, each preceded by a `.`.
Expand Down
7 changes: 6 additions & 1 deletion packages/typescript-estree/src/parser.ts
Expand Up @@ -93,6 +93,7 @@ function resetExtra(): void {
debugLevel: new Set(),
errorOnTypeScriptSyntacticAndSemanticIssues: false,
errorOnUnknownASTType: false,
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: false,
extraFileExtensions: [],
filePath: getFileName(),
jsx: false,
Expand Down Expand Up @@ -168,7 +169,7 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void {
if (
extra.debugLevel.has('eslint') ||
// make sure we don't turn off the eslint debug if it was enabled via --debug
debug.enabled('eslint:*')
debug.enabled('eslint:*,-eslint:code-path')
) {
// https://github.com/eslint/eslint/blob/9dfc8501fb1956c90dc11e6377b4cb38a6bea65d/bin/eslint.js#L25
namespaces.push('eslint:*,-eslint:code-path');
Expand Down Expand Up @@ -284,6 +285,10 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void {
extra.createDefaultProgram =
typeof options.createDefaultProgram === 'boolean' &&
options.createDefaultProgram;

extra.EXPERIMENTAL_useSourceOfProjectReferenceRedirect =
typeof options.EXPERIMENTAL_useSourceOfProjectReferenceRedirect ===
'boolean' && options.EXPERIMENTAL_useSourceOfProjectReferenceRedirect;
}

function warnAboutTSVersion(): void {
Expand Down
7 changes: 6 additions & 1 deletion packages/typescript-estree/tsconfig.build.json
Expand Up @@ -6,5 +6,10 @@
"rootDir": "./src",
"resolveJsonModule": true
},
"include": ["src", "typings"]
"include": ["src", "typings"],
"references": [
{ "path": "../shared-fixtures/tsconfig.build.json" },
{ "path": "../types/tsconfig.build.json" },
{ "path": "../visitor-keys/tsconfig.build.json" }
]
}

0 comments on commit 90a5878

Please sign in to comment.