From 6a0c17703ba7ab3167a7a2783f2e54bfcc3c19e0 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 13:57:30 -0600 Subject: [PATCH 1/7] fix(typescript-estree): Replace fast-glob with tinyglobby --- packages/typescript-estree/package.json | 2 +- .../src/parseSettings/resolveProjectList.ts | 5 +- .../typescript-estree/tests/lib/parse.test.ts | 46 +++++++++---------- yarn.lock | 2 +- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 40080b2878e5..77ee13f5188a 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -57,10 +57,10 @@ "@typescript-eslint/types": "8.18.1", "@typescript-eslint/visitor-keys": "8.18.1", "debug": "^4.3.4", - "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", + "tinyglobby": "^0.2.10", "ts-api-utils": "^1.3.0" }, "devDependencies": { diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index 8d9bd6bb6f9e..28c5252cb703 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -1,6 +1,6 @@ import debug from 'debug'; -import { sync as globSync } from 'fast-glob'; import isGlob from 'is-glob'; +import { globSync } from 'tinyglobby'; import type { CanonicalPath } from '../create-program/shared'; import type { TSESTreeOptions } from '../parser-options'; @@ -92,9 +92,6 @@ export function resolveProjectList( let globProjectPaths: string[] = []; if (globProjects.length > 0) { - // Although fast-glob supports multiple patterns, fast-glob returns arbitrary order of results - // to improve performance. To ensure the order is correct, we need to call fast-glob for each pattern - // separately and then concatenate the results in patterns' order. globProjectPaths = globProjects.flatMap(pattern => globSync(pattern, { cwd: options.tsconfigRootDir, diff --git a/packages/typescript-estree/tests/lib/parse.test.ts b/packages/typescript-estree/tests/lib/parse.test.ts index b701bf35d216..56813cd3ed5f 100644 --- a/packages/typescript-estree/tests/lib/parse.test.ts +++ b/packages/typescript-estree/tests/lib/parse.test.ts @@ -2,8 +2,8 @@ import type { CacheDurationSeconds } from '@typescript-eslint/types'; import type * as typescriptModule from 'typescript'; import debug from 'debug'; -import * as fastGlobModule from 'fast-glob'; import { join, resolve } from 'node:path'; +import * as tinyglobby from 'tinyglobby'; import type { TSESTreeOptions } from '../../src/parser-options'; @@ -40,11 +40,11 @@ jest.mock('typescript', () => { }; }); -jest.mock('fast-glob', () => { - const fastGlob = jest.requireActual('fast-glob'); +jest.mock('tinyglobby', () => { + const tg = jest.requireActual('tinyglobby'); return { - ...fastGlob, - sync: jest.fn(fastGlob.sync), + ...tg, + globSync: jest.fn(tinyglobby.globSync), }; }); @@ -53,7 +53,7 @@ const hrtimeSpy = jest.spyOn(process, 'hrtime'); const createDefaultCompilerOptionsFromExtra = jest.mocked( sharedParserUtilsModule.createDefaultCompilerOptionsFromExtra, ); -const fastGlobSyncMock = jest.mocked(fastGlobModule.sync); +const globSyncMock = jest.mocked(tinyglobby.globSync); /** * Aligns paths between environments, node for windows uses `\`, for linux and mac uses `/` @@ -815,11 +815,11 @@ describe('parseAndGenerateServices', () => { describe('cacheLifetime', () => { describe('glob', () => { const project = ['./**/tsconfig.json', './**/tsconfig.extra.json']; - // fast-glob returns arbitrary order of results to improve performance. - // `resolveProjectList()` calls fast-glob for each pattern to ensure the + // tinyglobby returns arbitrary order of results to improve performance. + // `resolveProjectList()` calls tinyglobby for each pattern to ensure the // order is correct. // Thus the expected call time of spy is the number of patterns. - const expectFastGlobCalls = project.length; + const expectTinyglobbyCalls = project.length; function doParse(lifetime: CacheDurationSeconds): void { parser.parseAndGenerateServices('const x = 1', { cacheLifetime: { @@ -834,50 +834,46 @@ describe('parseAndGenerateServices', () => { it('should cache globs if the lifetime is non-zero', () => { doParse(30); - expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls); + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls); doParse(30); - // shouldn't call fast-glob again due to the caching - expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls); + // shouldn't call tinyglobby again due to the caching + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls); }); it('should not cache globs if the lifetime is zero', () => { doParse(0); - expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls); + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls); doParse(0); - // should call fast-glob again because we specified immediate cache expiry - expect(fastGlobSyncMock).toHaveBeenCalledTimes( - expectFastGlobCalls * 2, - ); + // should call tinyglobby again because we specified immediate cache expiry + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls * 2); }); it('should evict the cache if the entry expires', () => { hrtimeSpy.mockReturnValueOnce([1, 0]); doParse(30); - expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls); + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls); // wow so much time has passed hrtimeSpy.mockReturnValueOnce([Number.MAX_VALUE, 0]); doParse(30); - // shouldn't call fast-glob again due to the caching - expect(fastGlobSyncMock).toHaveBeenCalledTimes( - expectFastGlobCalls * 2, - ); + // shouldn't call tinyglobby again due to the caching + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls * 2); }); it('should infinitely cache if passed Infinity', () => { hrtimeSpy.mockReturnValueOnce([1, 0]); doParse('Infinity'); - expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls); + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls); // wow so much time has passed hrtimeSpy.mockReturnValueOnce([Number.MAX_VALUE, 0]); doParse('Infinity'); - // shouldn't call fast-glob again due to the caching - expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls); + // shouldn't call tinyglobby again due to the caching + expect(globSyncMock).toHaveBeenCalledTimes(expectTinyglobbyCalls); }); }); }); diff --git a/yarn.lock b/yarn.lock index 773738e55cf3..761c1377d72b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5879,7 +5879,6 @@ __metadata: "@typescript-eslint/types": 8.18.1 "@typescript-eslint/visitor-keys": 8.18.1 debug: ^4.3.4 - fast-glob: ^3.3.2 glob: "*" is-glob: ^4.0.3 jest: 29.7.0 @@ -5887,6 +5886,7 @@ __metadata: prettier: ^3.2.5 rimraf: "*" semver: ^7.6.0 + tinyglobby: ^0.2.10 tmp: "*" ts-api-utils: ^1.3.0 typescript: "*" From 5c2cd026086530ebd4e3e78eebf03f851b116ee0 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 15:37:21 -0600 Subject: [PATCH 2/7] Fix reference to `globSync` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Josh Goldberg ✨ --- packages/typescript-estree/tests/lib/parse.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typescript-estree/tests/lib/parse.test.ts b/packages/typescript-estree/tests/lib/parse.test.ts index 56813cd3ed5f..feaf939c173b 100644 --- a/packages/typescript-estree/tests/lib/parse.test.ts +++ b/packages/typescript-estree/tests/lib/parse.test.ts @@ -44,7 +44,7 @@ jest.mock('tinyglobby', () => { const tg = jest.requireActual('tinyglobby'); return { ...tg, - globSync: jest.fn(tinyglobby.globSync), + globSync: jest.fn(tg.globSync), }; }); From 957d206d83568ab32c0e63cca021e63c3ca19e50 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 15:54:59 -0600 Subject: [PATCH 3/7] Fix `projectFolderIgnoreList` --- .../typescript-estree/src/parseSettings/resolveProjectList.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index 28c5252cb703..25c9dc093f71 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -59,8 +59,7 @@ export function resolveProjectList( options.projectFolderIgnoreList ?? ['**/node_modules/**'] ) .filter(folder => typeof folder === 'string') - // prefix with a ! for not match glob - .map(folder => (folder.startsWith('!') ? folder : `!${folder}`)); + .map(folder => (folder.startsWith('!') ? folder.slice(1) : folder)); const cacheKey = getHash({ project: sanitizedProjects, From c36be0b688244e1fd69c33770654147e36ca3741 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 16:04:28 -0600 Subject: [PATCH 4/7] Remove is-glob Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- .../typescript-estree/src/parseSettings/resolveProjectList.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index 25c9dc093f71..3b53fb3cc4bf 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -1,6 +1,5 @@ import debug from 'debug'; -import isGlob from 'is-glob'; -import { globSync } from 'tinyglobby'; +import { globSync, isDynamicPattern } from 'tinyglobby'; import type { CanonicalPath } from '../create-program/shared'; import type { TSESTreeOptions } from '../parser-options'; From 6ac5f5fbd561a5bf02468e03514dc9a43ead2411 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 16:04:38 -0600 Subject: [PATCH 5/7] Remove is-glob Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- packages/typescript-estree/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 77ee13f5188a..2261be8a74ac 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -57,7 +57,6 @@ "@typescript-eslint/types": "8.18.1", "@typescript-eslint/visitor-keys": "8.18.1", "debug": "^4.3.4", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.10", From db2ae6fa525fd093bc32c19b98ab51970b564935 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 16:05:50 -0600 Subject: [PATCH 6/7] Update `isGlob` references to `isDynamicPattern` --- .../src/parseSettings/resolveProjectList.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index 3b53fb3cc4bf..01149efd99fe 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -84,8 +84,12 @@ export function resolveProjectList( } // Transform glob patterns into paths - const nonGlobProjects = sanitizedProjects.filter(project => !isGlob(project)); - const globProjects = sanitizedProjects.filter(project => isGlob(project)); + const nonGlobProjects = sanitizedProjects.filter( + project => !isDynamicPattern(project), + ); + const globProjects = sanitizedProjects.filter(project => + isDynamicPattern(project), + ); let globProjectPaths: string[] = []; From 42eb0b26798ceaf22225d7e01f2f2a74af5e2e63 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Mon, 23 Dec 2024 16:16:52 -0600 Subject: [PATCH 7/7] Remove @types/is-glob --- package.json | 1 - yarn.lock | 9 --------- 2 files changed, 10 deletions(-) diff --git a/package.json b/package.json index 365518e8eb67..67f3c2b073ca 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "@types/babel__code-frame": "^7.0.6", "@types/babel__core": "^7.20.5", "@types/debug": "^4.1.12", - "@types/is-glob": "^4.0.4", "@types/jest": "29.5.13", "@types/jest-specific-snapshot": "^0.5.9", "@types/natural-compare": "^1.4.3", diff --git a/yarn.lock b/yarn.lock index 761c1377d72b..9a4fc12b1ad2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5213,13 +5213,6 @@ __metadata: languageName: node linkType: hard -"@types/is-glob@npm:^4.0.4": - version: 4.0.4 - resolution: "@types/is-glob@npm:4.0.4" - checksum: c790125e2d133d15c9783f6468995841cb06b5634b5c7b30aa32d23129f19d7dc271ec1a904bea4ca1e6a5ba19218a6602753d558f343b4fb8402fed25d17219 - languageName: node - linkType: hard - "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.4 resolution: "@types/istanbul-lib-coverage@npm:2.0.4" @@ -5816,7 +5809,6 @@ __metadata: "@types/babel__code-frame": ^7.0.6 "@types/babel__core": ^7.20.5 "@types/debug": ^4.1.12 - "@types/is-glob": ^4.0.4 "@types/jest": 29.5.13 "@types/jest-specific-snapshot": ^0.5.9 "@types/natural-compare": ^1.4.3 @@ -5880,7 +5872,6 @@ __metadata: "@typescript-eslint/visitor-keys": 8.18.1 debug: ^4.3.4 glob: "*" - is-glob: ^4.0.3 jest: 29.7.0 minimatch: ^9.0.4 prettier: ^3.2.5