Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/typescript-estree/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,12 @@
"@typescript-eslint/types": "8.46.4",
"@typescript-eslint/visitor-keys": "8.46.4",
"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.15",
"ts-api-utils": "^2.1.0"
},
"devDependencies": {
"@types/is-glob": "^4.0.4",
"@vitest/coverage-v8": "^3.1.3",
"eslint": "*",
"glob": "*",
Expand Down
20 changes: 10 additions & 10 deletions packages/typescript-estree/src/parseSettings/resolveProjectList.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import debug from 'debug';
import { sync as globSync } from 'fast-glob';
import isGlob from 'is-glob';
import { globSync, isDynamicPattern } from 'tinyglobby';

import type { CanonicalPath } from '../create-program/shared';
import type { TSESTreeOptions } from '../parser-options';
Expand Down Expand Up @@ -57,10 +56,7 @@ export function resolveProjectList(

const projectFolderIgnoreList = (
options.projectFolderIgnoreList ?? ['**/node_modules/**']
)
.filter(folder => typeof folder === 'string')
// prefix with a ! for not match glob
.map(folder => (folder.startsWith('!') ? folder : `!${folder}`));
).filter(folder => typeof folder === 'string');

const cacheKey = getHash({
project: sanitizedProjects,
Expand All @@ -86,18 +82,22 @@ 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[] = [];

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
// To ensure the order is correct, we need to glob for each pattern
// separately and then concatenate the results in patterns' order.
globProjectPaths = globProjects.flatMap(pattern =>
globSync(pattern, {
cwd: options.tsconfigRootDir,
expandDirectories: false,
ignore: projectFolderIgnoreList,
}),
);
Expand Down
49 changes: 23 additions & 26 deletions packages/typescript-estree/tests/lib/parse.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { CacheDurationSeconds } from '@typescript-eslint/types';

import debug from 'debug';
import * as fastGlobModule from 'fast-glob';
import { join, resolve } from 'node:path';
import * as tinyGlobbyModule from 'tinyglobby';

import type { TSESTreeOptions } from '../../src/parser-options';

Expand Down Expand Up @@ -39,20 +39,21 @@ vi.mock(import('typescript'), async importOriginal => {
};
});

vi.mock('fast-glob', async importOriginal => {
const fastGlob = await importOriginal<typeof fastGlobModule>();
vi.mock('tinyglobby', async importOriginal => {
const tinyglobby = await importOriginal<typeof tinyGlobbyModule>();

return {
...fastGlob,
default: fastGlob.default,
sync: vi.fn(fastGlob.sync),
...tinyglobby,
// eslint-disable-next-line @typescript-eslint/no-deprecated -- see #10215
globSync: vi.fn(tinyglobby.globSync),
};
});

const createDefaultCompilerOptionsFromExtra = vi.mocked(
sharedParserUtilsModule.createDefaultCompilerOptionsFromExtra,
);
const fastGlobSyncMock = vi.mocked(fastGlobModule.sync);
// eslint-disable-next-line @typescript-eslint/no-deprecated -- seems like a bug in the rule
const globSyncMock = vi.mocked(tinyGlobbyModule.globSync);

/**
* Aligns paths between environments, node for windows uses `\`, for linux and mac uses `/`
Expand Down Expand Up @@ -831,11 +832,11 @@ describe(parser.parseAndGenerateServices, () => {
() => {
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()` runs a glob 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 expectedGlobCount = project.length;
function doParse(lifetime: CacheDurationSeconds): void {
parser.parseAndGenerateServices('const x = 1', {
cacheLifetime: {
Expand All @@ -850,50 +851,46 @@ describe(parser.parseAndGenerateServices, () => {

it('should cache globs if the lifetime is non-zero', () => {
doParse(30);
expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls);
expect(globSyncMock).toHaveBeenCalledTimes(expectedGlobCount);
doParse(30);
// shouldn't call fast-glob again due to the caching
expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls);
// shouldn't glob again due to the caching
expect(globSyncMock).toHaveBeenCalledTimes(expectedGlobCount);
});

it('should not cache globs if the lifetime is zero', () => {
doParse(0);
expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls);
expect(globSyncMock).toHaveBeenCalledTimes(expectedGlobCount);
doParse(0);
// should call fast-glob again because we specified immediate cache expiry
expect(fastGlobSyncMock).toHaveBeenCalledTimes(
expectFastGlobCalls * 2,
);
// should glob again because we specified immediate cache expiry
expect(globSyncMock).toHaveBeenCalledTimes(2 * expectedGlobCount);
});

it('should evict the cache if the entry expires', () => {
hrtimeSpy.mockReturnValueOnce([1, 0]);

doParse(30);
expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls);
expect(globSyncMock).toHaveBeenCalledTimes(expectedGlobCount);

// 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 glob again due to the caching
expect(globSyncMock).toHaveBeenCalledTimes(2 * expectedGlobCount);
});

it('should infinitely cache if passed Infinity', () => {
hrtimeSpy.mockReturnValueOnce([1, 0]);

doParse('Infinity');
expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls);
expect(globSyncMock).toHaveBeenCalledTimes(expectedGlobCount);

// 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 glob again due to the caching
expect(globSyncMock).toHaveBeenCalledTimes(expectedGlobCount);
});
});
},
Expand Down
13 changes: 2 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5551,13 +5551,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":
version: 2.0.4
resolution: "@types/istanbul-lib-coverage@npm:2.0.4"
Expand Down Expand Up @@ -6186,20 +6179,18 @@ __metadata:
version: 0.0.0-use.local
resolution: "@typescript-eslint/typescript-estree@workspace:packages/typescript-estree"
dependencies:
"@types/is-glob": ^4.0.4
"@typescript-eslint/project-service": 8.46.4
"@typescript-eslint/tsconfig-utils": 8.46.4
"@typescript-eslint/types": 8.46.4
"@typescript-eslint/visitor-keys": 8.46.4
"@vitest/coverage-v8": ^3.1.3
debug: ^4.3.4
eslint: "*"
fast-glob: ^3.3.2
glob: "*"
is-glob: ^4.0.3
minimatch: ^9.0.4
rimraf: "*"
semver: ^7.6.0
tinyglobby: ^0.2.15
ts-api-utils: ^2.1.0
typescript: "*"
vitest: ^3.1.3
Expand Down Expand Up @@ -10594,7 +10585,7 @@ __metadata:
languageName: node
linkType: hard

"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3":
"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.3":
version: 3.3.3
resolution: "fast-glob@npm:3.3.3"
dependencies:
Expand Down