From 275b3554a9ae827e2885f1cb95d827f8b2ed3691 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 26 Sep 2025 09:34:46 -0400 Subject: [PATCH 1/6] feat(typescript-estree): mention file specifics in project service allowDefaultProject error --- .../src/useProgramFromProjectService.ts | 20 ++++++++++- .../lib/useProgramFromProjectService.test.ts | 36 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/typescript-estree/src/useProgramFromProjectService.ts index 9a365029de02..f6877e11121a 100644 --- a/packages/typescript-estree/src/useProgramFromProjectService.ts +++ b/packages/typescript-estree/src/useProgramFromProjectService.ts @@ -96,8 +96,26 @@ function openClientFileFromProjectService( } if (!isDefaultProjectAllowed) { + const baseMessage = `${wasNotFound}. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`; + const allowDefaultProject = + parseSettings.projectService?.allowDefaultProject; + + if (!allowDefaultProject) { + throw new Error(baseMessage); + } + + const relativeFilePath = path.relative( + parseSettings.tsconfigRootDir, + filePathAbsolute, + ); + throw new Error( - `${wasNotFound}. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`, + [ + baseMessage, + `allowDefaultProject is set to ${JSON.stringify(allowDefaultProject)}, which does not match '${relativeFilePath}'.`, + ] + .filter(Boolean) + .join('\n'), ); } } diff --git a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts index 48e62e1c39b6..89f9d4e65dea 100644 --- a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts +++ b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts @@ -167,7 +167,7 @@ describe(useProgramFromProjectService, () => { expect(service.reloadProjects).not.toHaveBeenCalled(); }); - it('throws an error after reloading projects when hasFullTypeInformation is enabled, the file is neither in the project service nor allowDefaultProject, and the last reload was recent', () => { + it('throws a non-file-specific error after reloading projects when hasFullTypeInformation is enabled, the file is neither in the project service nor an empty allowDefaultProject, and the last reload was recent', () => { const { service } = createMockProjectService(); service.openClientFile.mockReturnValueOnce({}).mockReturnValueOnce({}); @@ -189,6 +189,40 @@ describe(useProgramFromProjectService, () => { expect(service.reloadProjects).toHaveBeenCalledOnce(); }); + it('throws a file-specific error after reloading projects when hasFullTypeInformation is enabled, the file is neither in the project service nor a populated allowDefaultProject, and the last reload was recent', () => { + const { service } = createMockProjectService(); + const allowDefaultProject = ['a.js', 'b.js']; + + service.openClientFile.mockReturnValueOnce({}).mockReturnValueOnce({}); + + expect(() => + useProgramFromProjectService( + createProjectServiceSettings({ + allowDefaultProject, + lastReloadTimestamp: 0, + service, + }), + { + ...mockParseSettings, + projectService: { + allowDefaultProject, + lastReloadTimestamp: 0, + maximumDefaultProjectFileMatchCount: 8, + service, + }, + }, + true, + new Set(), + ), + ).toThrow( + [ + `${mockParseSettings.filePath} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`, + `allowDefaultProject is set to ["a.js","b.js"], which does not match 'path/PascalCaseDirectory/camelCaseFile.ts'.`, + ].join('\n'), + ); + expect(service.reloadProjects).toHaveBeenCalledOnce(); + }); + it('returns a created program after reloading projects when hasFullTypeInformation is enabled, the file is only in the project service after reload, and the last reload was recent', () => { const { service } = createMockProjectService(); const program = { getSourceFile: vi.fn() }; From 56bdc0799458e8ea46a44f61cf00280dd5d5438c Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 26 Sep 2025 09:46:45 -0400 Subject: [PATCH 2/6] test: normalize paths --- docs/packages/Parser.mdx | 2 +- docs/packages/TypeScript_ESTree.mdx | 2 +- .../tests/lib/useProgramFromProjectService.test.ts | 2 +- packages/website/src/vendor/sandbox.d.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/packages/Parser.mdx b/docs/packages/Parser.mdx index 52a294e67e41..8b6e3b09487e 100644 --- a/docs/packages/Parser.mdx +++ b/docs/packages/Parser.mdx @@ -53,7 +53,7 @@ interface ParserOptions { jsxPragma?: string | null; lib?: string[]; programs?: import('typescript').Program[]; - project?: string | string[] | boolean | null; + project?: string | string[] | boolean | ts.Project | ts.Project[] | null; projectFolderIgnoreList?: string[]; projectService?: boolean | ProjectServiceOptions; tsconfigRootDir?: string; diff --git a/docs/packages/TypeScript_ESTree.mdx b/docs/packages/TypeScript_ESTree.mdx index c00bd325b6ad..2ce745bf82f1 100644 --- a/docs/packages/TypeScript_ESTree.mdx +++ b/docs/packages/TypeScript_ESTree.mdx @@ -241,7 +241,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * * Note that {@link projectService} is now preferred. */ - project?: string[] | string | boolean | null; + project?: string[] | string | boolean | ts.Project | ts.Project[] | null; /** * If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from diff --git a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts index 89f9d4e65dea..3e0a30a52940 100644 --- a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts +++ b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts @@ -217,7 +217,7 @@ describe(useProgramFromProjectService, () => { ).toThrow( [ `${mockParseSettings.filePath} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`, - `allowDefaultProject is set to ["a.js","b.js"], which does not match 'path/PascalCaseDirectory/camelCaseFile.ts'.`, + `allowDefaultProject is set to ["a.js","b.js"], which does not match '${path.normalize('path/PascalCaseDirectory/camelCaseFile.ts')}'.`, ].join('\n'), ); expect(service.reloadProjects).toHaveBeenCalledOnce(); diff --git a/packages/website/src/vendor/sandbox.d.ts b/packages/website/src/vendor/sandbox.d.ts index b69804b12550..294f20bb5eeb 100644 --- a/packages/website/src/vendor/sandbox.d.ts +++ b/packages/website/src/vendor/sandbox.d.ts @@ -277,7 +277,7 @@ export declare const createTypeScriptSandbox: ( paths?: MonacoEditor.languages.typescript.MapLike; preserveConstEnums?: boolean; preserveSymlinks?: boolean; - project?: string; + project?: string | ts.Project; reactNamespace?: string; jsxFactory?: string; composite?: boolean; From 4a71c1c0afc266cf1f63421b1a26718c5f917143 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 30 Sep 2025 11:18:43 -0400 Subject: [PATCH 3/6] Reset to main --- packages/website/src/vendor/sandbox.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/website/src/vendor/sandbox.d.ts b/packages/website/src/vendor/sandbox.d.ts index 294f20bb5eeb..b69804b12550 100644 --- a/packages/website/src/vendor/sandbox.d.ts +++ b/packages/website/src/vendor/sandbox.d.ts @@ -277,7 +277,7 @@ export declare const createTypeScriptSandbox: ( paths?: MonacoEditor.languages.typescript.MapLike; preserveConstEnums?: boolean; preserveSymlinks?: boolean; - project?: string | ts.Project; + project?: string; reactNamespace?: string; jsxFactory?: string; composite?: boolean; From f55db6c9fcc1f6a295c1b9e39469357455453a39 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 30 Sep 2025 11:18:59 -0400 Subject: [PATCH 4/6] Reset to main --- docs/packages/Parser.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packages/Parser.mdx b/docs/packages/Parser.mdx index 8b6e3b09487e..52a294e67e41 100644 --- a/docs/packages/Parser.mdx +++ b/docs/packages/Parser.mdx @@ -53,7 +53,7 @@ interface ParserOptions { jsxPragma?: string | null; lib?: string[]; programs?: import('typescript').Program[]; - project?: string | string[] | boolean | ts.Project | ts.Project[] | null; + project?: string | string[] | boolean | null; projectFolderIgnoreList?: string[]; projectService?: boolean | ProjectServiceOptions; tsconfigRootDir?: string; From d8a79b20d6a735116db3dc6775bb8f3a849b219d Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 30 Sep 2025 11:19:06 -0400 Subject: [PATCH 5/6] Reset to main --- docs/packages/TypeScript_ESTree.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packages/TypeScript_ESTree.mdx b/docs/packages/TypeScript_ESTree.mdx index 2ce745bf82f1..c00bd325b6ad 100644 --- a/docs/packages/TypeScript_ESTree.mdx +++ b/docs/packages/TypeScript_ESTree.mdx @@ -241,7 +241,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * * Note that {@link projectService} is now preferred. */ - project?: string[] | string | boolean | ts.Project | ts.Project[] | null; + project?: string[] | string | boolean | null; /** * If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from From 46020d033aa90a973cb218650fcbb3132f69d33e Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Thu, 2 Oct 2025 10:22:28 -0400 Subject: [PATCH 6/6] Unnecessary .filter(Boolean) --- .../typescript-estree/src/useProgramFromProjectService.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/typescript-estree/src/useProgramFromProjectService.ts index f6877e11121a..fec277ce4ea6 100644 --- a/packages/typescript-estree/src/useProgramFromProjectService.ts +++ b/packages/typescript-estree/src/useProgramFromProjectService.ts @@ -113,9 +113,7 @@ function openClientFileFromProjectService( [ baseMessage, `allowDefaultProject is set to ${JSON.stringify(allowDefaultProject)}, which does not match '${relativeFilePath}'.`, - ] - .filter(Boolean) - .join('\n'), + ].join('\n'), ); } }