From 4724e4a2d6a6660fc150733d55f529275148923f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 3 May 2024 13:08:05 -0700 Subject: [PATCH 1/2] Dont pass tsconfig canonical file name to typescript API to get program details for config file Without this it generates root files with incorrect casing and results in errors with casing with forceConsistentCasingInFileNames which is true by default in newer typescript versions --- .../create-program/createDefaultProgram.ts | 4 ++-- .../create-program/createProjectProgram.ts | 6 +++-- .../getWatchProgramsForProjects.ts | 18 +++++++++------ .../src/parseSettings/createParseSettings.ts | 4 ++-- .../src/parseSettings/index.ts | 2 +- .../src/parseSettings/resolveProjectList.ts | 22 ++++++++++--------- packages/typescript-estree/src/parser.ts | 10 ++++----- 7 files changed, 37 insertions(+), 29 deletions(-) diff --git a/packages/typescript-estree/src/create-program/createDefaultProgram.ts b/packages/typescript-estree/src/create-program/createDefaultProgram.ts index b42ec76c678b..f169f2da4389 100644 --- a/packages/typescript-estree/src/create-program/createDefaultProgram.ts +++ b/packages/typescript-estree/src/create-program/createDefaultProgram.ts @@ -23,11 +23,11 @@ function createDefaultProgram( parseSettings.filePath || 'unnamed file', ); - if (parseSettings.projects.length !== 1) { + if (parseSettings.projects.size !== 1) { return undefined; } - const tsconfigPath = parseSettings.projects[0]; + const tsconfigPath = Array.from(parseSettings.projects.values())[0]; const commandLine = ts.getParsedCommandLineOfConfigFile( tsconfigPath, diff --git a/packages/typescript-estree/src/create-program/createProjectProgram.ts b/packages/typescript-estree/src/create-program/createProjectProgram.ts index a58097e3cd73..3e8432d0b46f 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgram.ts +++ b/packages/typescript-estree/src/create-program/createProjectProgram.ts @@ -48,7 +48,9 @@ function createProjectProgram( parseSettings.filePath, parseSettings.tsconfigRootDir, ); - const relativeProjects = parseSettings.projects.map(describeProjectFilePath); + const relativeProjects = Array.from(parseSettings.projects.values()).map( + describeProjectFilePath, + ); const describedPrograms = relativeProjects.length === 1 ? relativeProjects[0] @@ -93,7 +95,7 @@ function createProjectProgram( if (!hasMatchedAnError) { const [describedInclusions, describedSpecifiers] = - parseSettings.projects.length === 1 + parseSettings.projects.size === 1 ? ['that TSConfig does not', 'that TSConfig'] : ['none of those TSConfigs', 'one of those TSConfigs']; errorLines.push( diff --git a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts index 1ad82ec29b3d..01ef2a2532b9 100644 --- a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts +++ b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts @@ -151,7 +151,7 @@ function getWatchProgramsForProjects( ); } - const currentProjectsFromSettings = new Set(parseSettings.projects); + const currentProjectsFromSettings = new Map(parseSettings.projects); /* * before we go into the process of attempting to find and update every program @@ -198,13 +198,13 @@ function getWatchProgramsForProjects( * - the file is new/renamed, and the program hasn't been updated. */ for (const tsconfigPath of parseSettings.projects) { - const existingWatch = knownWatchProgramMap.get(tsconfigPath); + const existingWatch = knownWatchProgramMap.get(tsconfigPath[0]); if (existingWatch) { const updatedProgram = maybeInvalidateProgram( existingWatch, filePath, - tsconfigPath, + tsconfigPath[0], ); if (!updatedProgram) { continue; @@ -215,7 +215,7 @@ function getWatchProgramsForProjects( // cache and check the file list const fileList = updateCachedFileList( - tsconfigPath, + tsconfigPath[0], updatedProgram, parseSettings, ); @@ -229,15 +229,19 @@ function getWatchProgramsForProjects( continue; } - const programWatch = createWatchProgram(tsconfigPath, parseSettings); - knownWatchProgramMap.set(tsconfigPath, programWatch); + const programWatch = createWatchProgram(tsconfigPath[1], parseSettings); + knownWatchProgramMap.set(tsconfigPath[0], 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, parseSettings); + const fileList = updateCachedFileList( + tsconfigPath[0], + program, + parseSettings, + ); if (fileList.has(filePath)) { log('Found program for file. %s', filePath); // we can return early because we know this program contains the file diff --git a/packages/typescript-estree/src/parseSettings/createParseSettings.ts b/packages/typescript-estree/src/parseSettings/createParseSettings.ts index 49d048391d8f..b5d52ce569b8 100644 --- a/packages/typescript-estree/src/parseSettings/createParseSettings.ts +++ b/packages/typescript-estree/src/parseSettings/createParseSettings.ts @@ -113,7 +113,7 @@ export function createParseSettings( : console.log, // eslint-disable-line no-console preserveNodeMaps: options.preserveNodeMaps !== false, programs: Array.isArray(options.programs) ? options.programs : null, - projects: [], + projects: new Map(), range: options.range === true, singleRun, suppressDeprecatedPropertyWarnings: @@ -172,7 +172,7 @@ export function createParseSettings( // So in this specific case we default to 'none' if no value was provided if ( options.jsDocParsingMode == null && - parseSettings.projects.length === 0 && + parseSettings.projects.size === 0 && parseSettings.programs == null && parseSettings.EXPERIMENTAL_projectService == null ) { diff --git a/packages/typescript-estree/src/parseSettings/index.ts b/packages/typescript-estree/src/parseSettings/index.ts index 1df275901066..3511e3be718d 100644 --- a/packages/typescript-estree/src/parseSettings/index.ts +++ b/packages/typescript-estree/src/parseSettings/index.ts @@ -128,7 +128,7 @@ export interface MutableParseSettings { /** * Normalized paths to provided project paths. */ - projects: readonly CanonicalPath[]; + projects: ReadonlyMap; /** * Whether to add the `range` property to AST nodes. diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index 9c3b8480499a..4b24608b6ff8 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -18,8 +18,10 @@ const log = debug( 'typescript-eslint:typescript-estree:parser:parseSettings:resolveProjectList', ); -let RESOLUTION_CACHE: ExpiringCache | null = - null; +let RESOLUTION_CACHE: ExpiringCache< + string, + ReadonlyMap +> | null = null; export function clearGlobCache(): void { RESOLUTION_CACHE?.clear(); @@ -36,7 +38,7 @@ export function resolveProjectList( singleRun: boolean; tsconfigRootDir: string; }>, -): readonly CanonicalPath[] { +): ReadonlyMap { const sanitizedProjects: string[] = []; // Normalize and sanitize the project paths @@ -49,7 +51,7 @@ export function resolveProjectList( } if (sanitizedProjects.length === 0) { - return []; + return new Map(); } const projectFolderIgnoreList = ( @@ -91,7 +93,7 @@ export function resolveProjectList( const nonGlobProjects = sanitizedProjects.filter(project => !isGlob(project)); const globProjects = sanitizedProjects.filter(project => isGlob(project)); - const uniqueCanonicalProjectPaths = new Set( + const uniqueCanonicalProjectPaths = new Map( nonGlobProjects .concat( globProjects.length === 0 @@ -100,11 +102,12 @@ export function resolveProjectList( cwd: options.tsconfigRootDir, }), ) - .map(project => + .map(project => [ getCanonicalFileName( ensureAbsolutePath(project, options.tsconfigRootDir), ), - ), + ensureAbsolutePath(project, options.tsconfigRootDir), + ]), ); log( @@ -112,9 +115,8 @@ export function resolveProjectList( uniqueCanonicalProjectPaths, ); - const returnValue = Array.from(uniqueCanonicalProjectPaths); - RESOLUTION_CACHE.set(cacheKey, returnValue); - return returnValue; + RESOLUTION_CACHE.set(cacheKey, uniqueCanonicalProjectPaths); + return uniqueCanonicalProjectPaths; } function getHash({ diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index b4931a6da36e..d724d81e379d 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -188,12 +188,12 @@ function parseAndGenerateServices( if ( parseSettings.singleRun && !parseSettings.programs && - parseSettings.projects.length > 0 + parseSettings.projects.size > 0 ) { parseSettings.programs = { *[Symbol.iterator](): Iterator { for (const configFile of parseSettings.projects) { - const existingProgram = existingPrograms.get(configFile); + const existingProgram = existingPrograms.get(configFile[0]); if (existingProgram) { yield existingProgram; } else { @@ -201,8 +201,8 @@ function parseAndGenerateServices( 'Detected single-run/CLI usage, creating Program once ahead of time for project: %s', configFile, ); - const newProgram = createProgramFromConfigFile(configFile); - existingPrograms.set(configFile, newProgram); + const newProgram = createProgramFromConfigFile(configFile[1]); + existingPrograms.set(configFile[0], newProgram); yield newProgram; } } @@ -214,7 +214,7 @@ function parseAndGenerateServices( * Generate a full ts.Program or offer provided instances in order to be able to provide parser services, such as type-checking */ const hasFullTypeInformation = - parseSettings.programs != null || parseSettings.projects.length > 0; + parseSettings.programs != null || parseSettings.projects.size > 0; if ( typeof options.errorOnTypeScriptSyntacticAndSemanticIssues === 'boolean' && From b685720ec13ba992e3cfb9515dd990dbeee37fe7 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 3 May 2024 15:36:51 -0700 Subject: [PATCH 2/2] Fixes --- .../typescript-estree/tests/lib/semanticInfo-singleRun.test.ts | 3 +-- packages/website/src/components/linter/config.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts b/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts index 1051b8d2f171..f041d403f4fb 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts @@ -1,7 +1,6 @@ import glob = require('glob'); import * as path from 'path'; -import { getCanonicalFileName } from '../../src/create-program/shared'; import { createProgramFromConfigFile as createProgramFromConfigFileOriginal } from '../../src/create-program/useProvidedPrograms'; import { clearParseAndGenerateServicesCalls, @@ -94,7 +93,7 @@ const options = { } as const; const resolvedProject = (p: string): string => - getCanonicalFileName(path.resolve(path.join(process.cwd(), FIXTURES_DIR), p)); + path.resolve(path.join(process.cwd(), FIXTURES_DIR), p); describe('semanticInfo - singleRun', () => { beforeEach(() => { diff --git a/packages/website/src/components/linter/config.ts b/packages/website/src/components/linter/config.ts index 8262487369c1..c0e22f4e1637 100644 --- a/packages/website/src/components/linter/config.ts +++ b/packages/website/src/components/linter/config.ts @@ -25,7 +25,7 @@ export const defaultParseSettings: ParseSettings = { log: console.log, preserveNodeMaps: true, programs: null, - projects: [], + projects: new Map(), range: true, singleRun: false, suppressDeprecatedPropertyWarnings: false,