Skip to content

Commit 789c439

Browse files
authored
feat(typescript-estree): switch to globby (#2418)
Fixes #2398 If the user has a particularly large node_modules folder and uses globs for `parserOption.project`, then the `glob` library can spend a decent chunk of time searching the `node_modules` folder. In some cases, this can be on the order of hundreds to thousands of milliseconds. This wouldn't be a problem, but for safety and correctness during a persistent parse, we have to do this check for every call to the parser (i.e. every file that's being linted). Over a whole project, this can easily add up to many, many seconds wasted. Previously, we: - applied the project globs, one by one - then manually excluded `tsconfig`s from the list. This meant that we are always slow. I remember I did this because I had issues getting `glob`'s `ignore` option to work at all. ## The solution `globby` is a better glob library: - it accepts an array of globs, which saves us doing manual looping - it supports exclusion globs (globs prefixed with `!`), which are evaluated as part of the glob process - it has caching built in by default This allows us to evaluate all of the `project` globs at once, as opposed to one at a time (so should be less duplicated work). This also allows us to evaluate the `projectFolderIgnoreList` at the same time as the `project` globs (so should be no useless work done). All of these together should cut the glob evaluation time down to ~50ms for the first parse, and ~2ms for each parse after that (due to caching). For comparison, previously, in bad cases we would spend ~3-500ms, per project, per parsed file. Example to illustrate how much faster this can potentially be: For a project that provides 2 globs and has 100 files. Before: 300ms * 2 * 100 = 60,000ms (60s) After: 50ms + 2 * 100 = 250ms This should also save a non-trival amount of time in other, more optimal setups. BREAKING CHANGE: - removes the ability to supply a `RegExp` to `projectFolderIgnoreList`, and changes the meaning of the string value from a regex to a glob.
1 parent c4f67a2 commit 789c439

File tree

7 files changed

+128
-68
lines changed

7 files changed

+128
-68
lines changed

Diff for: packages/parser/README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ interface ParserOptions {
5757
lib?: string[];
5858

5959
project?: string | string[];
60-
projectFolderIgnoreList?: (string | RegExp)[];
60+
projectFolderIgnoreList?: string[];
6161
tsconfigRootDir?: string;
6262
extraFileExtensions?: string[];
6363
warnOnUnsupportedTypeScriptVersion?: boolean;
@@ -156,12 +156,13 @@ This option allows you to provide the root directory for relative tsconfig paths
156156

157157
### `parserOptions.projectFolderIgnoreList`
158158

159-
Default `["/node_modules/"]`.
159+
Default `["**/node_modules/**"]`.
160160

161161
This option allows you to ignore folders from being included in your provided list of `project`s.
162-
Any resolved project path that matches one or more of the provided regular expressions will be removed from the list.
163162
This is useful if you have configured glob patterns, but want to make sure you ignore certain folders.
164163

164+
It accepts an array of globs to exclude from the `project` globs.
165+
165166
For example, by default it will ensure that a glob like `./**/tsconfig.json` will not match any `tsconfig`s within your `node_modules` folder (some npm packages do not exclude their source files from their published packages).
166167

167168
### `parserOptions.extraFileExtensions`

Diff for: packages/typescript-estree/README.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,13 @@ interface ParseAndGenerateServicesOptions extends ParseOptions {
183183
project?: string | string[];
184184

185185
/**
186-
* If you provide a glob (or globs) to the project option, you can use this option to blacklist
187-
* certain folders from being matched by the globs.
188-
* Any project path that matches one or more of the provided regular expressions will be removed from the list.
186+
* If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from
187+
* being matched by the globs.
188+
* This accepts an array of globs to ignore.
189189
*
190-
* Accepts an array of strings that are passed to new RegExp(), or an array of regular expressions.
191190
* By default, this is set to ["/node_modules/"]
192191
*/
193-
projectFolderIgnoreList?: (string | RegExp)[];
192+
projectFolderIgnoreList?: string[];
194193

195194
/**
196195
* The absolute path to the root directory for all provided `project`s.

Diff for: packages/typescript-estree/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"@typescript-eslint/types": "3.9.1",
4444
"@typescript-eslint/visitor-keys": "3.9.1",
4545
"debug": "^4.1.1",
46-
"glob": "^7.1.6",
46+
"globby": "^11.0.1",
4747
"is-glob": "^4.0.1",
4848
"lodash": "^4.17.15",
4949
"semver": "^7.3.2",

Diff for: packages/typescript-estree/src/parser-options.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,13 @@ interface ParseAndGenerateServicesOptions extends ParseOptions {
142142
project?: string | string[];
143143

144144
/**
145-
* If you provide a glob (or globs) to the project option, you can use this option to blacklist
146-
* certain folders from being matched by the globs.
147-
* Any project path that matches one or more of the provided regular expressions will be removed from the list.
145+
* If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from
146+
* being matched by the globs.
147+
* This accepts an array of globs to ignore.
148148
*
149-
* Accepts an array of strings that are passed to new RegExp(), or an array of regular expressions.
150-
* By default, this is set to ["/node_modules/"]
149+
* By default, this is set to ["**\/node_modules/**"]
151150
*/
152-
projectFolderIgnoreList?: (string | RegExp)[];
151+
projectFolderIgnoreList?: string[];
153152

154153
/**
155154
* The absolute path to the root directory for all provided `project`s.

Diff for: packages/typescript-estree/src/parser.ts

+25-42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import debug from 'debug';
2-
import { sync as globSync } from 'glob';
2+
import { sync as globSync } from 'globby';
33
import isGlob from 'is-glob';
44
import semver from 'semver';
55
import * as ts from 'typescript';
@@ -113,7 +113,7 @@ function resetExtra(): void {
113113
*/
114114
function prepareAndTransformProjects(
115115
projectsInput: string | string[] | undefined,
116-
ignoreListInput: (string | RegExp)[] | undefined,
116+
ignoreListInput: string[],
117117
): string[] {
118118
let projects: string[] = [];
119119

@@ -133,47 +133,21 @@ function prepareAndTransformProjects(
133133
}
134134

135135
// Transform glob patterns into paths
136-
projects = projects.reduce<string[]>(
137-
(projects, project) =>
138-
projects.concat(
139-
isGlob(project)
140-
? globSync(project, {
141-
cwd: extra.tsconfigRootDir,
142-
})
143-
: project,
144-
),
145-
[],
146-
);
147-
148-
// Normalize and sanitize the ignore regex list
149-
const ignoreRegexes: RegExp[] = [];
150-
if (Array.isArray(ignoreListInput)) {
151-
for (const ignore of ignoreListInput) {
152-
if (ignore instanceof RegExp) {
153-
ignoreRegexes.push(ignore);
154-
} else if (typeof ignore === 'string') {
155-
ignoreRegexes.push(new RegExp(ignore));
156-
}
157-
}
158-
} else {
159-
ignoreRegexes.push(/\/node_modules\//);
160-
}
161-
162-
// Remove any paths that match the ignore list
163-
const filtered = projects.filter(project => {
164-
for (const ignore of ignoreRegexes) {
165-
if (ignore.test(project)) {
166-
return false;
167-
}
168-
}
169-
170-
return true;
171-
});
136+
const globbedProjects = projects.filter(project => isGlob(project));
137+
projects = projects
138+
.filter(project => !isGlob(project))
139+
.concat(
140+
globSync([...globbedProjects, ...ignoreListInput], {
141+
cwd: extra.tsconfigRootDir,
142+
}),
143+
);
172144

173-
log('parserOptions.project matched projects: %s', projects);
174-
log('ignore list applied to parserOptions.project: %s', filtered);
145+
log(
146+
'parserOptions.project (excluding ignored) matched projects: %s',
147+
projects,
148+
);
175149

176-
return filtered;
150+
return projects;
177151
}
178152

179153
function applyParserOptionsToExtra(options: TSESTreeOptions): void {
@@ -278,9 +252,18 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void {
278252
extra.filePath = ensureAbsolutePath(extra.filePath, extra);
279253

280254
// NOTE - prepareAndTransformProjects relies upon having the correct tsconfigRootDir in extra
255+
const projectFolderIgnoreList = (options.projectFolderIgnoreList ?? [])
256+
.reduce<string[]>((acc, folder) => {
257+
if (typeof folder === 'string') {
258+
acc.push(folder);
259+
}
260+
return acc;
261+
}, [])
262+
// prefix with a ! for not match glob
263+
.map(folder => (folder.startsWith('!') ? folder : `!${folder}`));
281264
extra.projects = prepareAndTransformProjects(
282265
options.project,
283-
options.projectFolderIgnoreList,
266+
projectFolderIgnoreList,
284267
);
285268

286269
if (

Diff for: packages/typescript-estree/tests/lib/parse.test.ts

+3-9
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ describe('parse()', () => {
592592

593593
const testParse = (
594594
filePath: 'ignoreme' | 'includeme',
595-
projectFolderIgnoreList: TSESTreeOptions['projectFolderIgnoreList'] = [],
595+
projectFolderIgnoreList?: TSESTreeOptions['projectFolderIgnoreList'],
596596
) => (): void => {
597597
parser.parseAndGenerateServices(code, {
598598
...config,
@@ -606,14 +606,8 @@ describe('parse()', () => {
606606
expect(testParse('includeme')).not.toThrow();
607607
});
608608

609-
it('ignores a folder when given a string regexp', () => {
610-
const ignore = ['/ignoreme/'];
611-
expect(testParse('ignoreme', ignore)).toThrow();
612-
expect(testParse('includeme', ignore)).not.toThrow();
613-
});
614-
615-
it('ignores a folder when given a RegExp', () => {
616-
const ignore = [/\/ignoreme\//];
609+
it('ignores a folder when given a string glob', () => {
610+
const ignore = ['**/ignoreme/**'];
617611
expect(testParse('ignoreme', ignore)).toThrow();
618612
expect(testParse('includeme', ignore)).not.toThrow();
619613
});

Diff for: yarn.lock

+86-2
Original file line numberDiff line numberDiff line change
@@ -1405,11 +1405,32 @@
14051405
call-me-maybe "^1.0.1"
14061406
glob-to-regexp "^0.3.0"
14071407

1408+
"@nodelib/[email protected]":
1409+
version "2.1.3"
1410+
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
1411+
integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==
1412+
dependencies:
1413+
"@nodelib/fs.stat" "2.0.3"
1414+
run-parallel "^1.1.9"
1415+
1416+
"@nodelib/[email protected]", "@nodelib/fs.stat@^2.0.2":
1417+
version "2.0.3"
1418+
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3"
1419+
integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==
1420+
14081421
"@nodelib/fs.stat@^1.1.2":
14091422
version "1.1.3"
14101423
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
14111424
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
14121425

1426+
"@nodelib/fs.walk@^1.2.3":
1427+
version "1.2.4"
1428+
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976"
1429+
integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==
1430+
dependencies:
1431+
"@nodelib/fs.scandir" "2.1.3"
1432+
fastq "^1.6.0"
1433+
14131434
"@octokit/auth-token@^2.4.0":
14141435
version "2.4.0"
14151436
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f"
@@ -2042,6 +2063,11 @@ array-union@^1.0.2:
20422063
dependencies:
20432064
array-uniq "^1.0.1"
20442065

2066+
array-union@^2.1.0:
2067+
version "2.1.0"
2068+
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
2069+
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
2070+
20452071
array-uniq@^1.0.1:
20462072
version "1.0.3"
20472073
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
@@ -3433,6 +3459,13 @@ dir-glob@^2.2.2:
34333459
dependencies:
34343460
path-type "^3.0.0"
34353461

3462+
dir-glob@^3.0.1:
3463+
version "3.0.1"
3464+
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
3465+
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
3466+
dependencies:
3467+
path-type "^4.0.0"
3468+
34363469
34373470
version "1.5.0"
34383471
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
@@ -3977,6 +4010,18 @@ fast-glob@^2.2.6:
39774010
merge2 "^1.2.3"
39784011
micromatch "^3.1.10"
39794012

4013+
fast-glob@^3.1.1:
4014+
version "3.2.4"
4015+
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
4016+
integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==
4017+
dependencies:
4018+
"@nodelib/fs.stat" "^2.0.2"
4019+
"@nodelib/fs.walk" "^1.2.3"
4020+
glob-parent "^5.1.0"
4021+
merge2 "^1.3.0"
4022+
micromatch "^4.0.2"
4023+
picomatch "^2.2.1"
4024+
39804025
[email protected], fast-json-stable-stringify@^2.0.0:
39814026
version "2.1.0"
39824027
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
@@ -3987,6 +4032,13 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
39874032
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
39884033
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
39894034

4035+
fastq@^1.6.0:
4036+
version "1.8.0"
4037+
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481"
4038+
integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==
4039+
dependencies:
4040+
reusify "^1.0.4"
4041+
39904042
fb-watchman@^2.0.0:
39914043
version "2.0.1"
39924044
resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85"
@@ -4363,7 +4415,7 @@ glob-parent@^3.1.0:
43634415
is-glob "^3.1.0"
43644416
path-dirname "^1.0.0"
43654417

4366-
glob-parent@^5.0.0:
4418+
glob-parent@^5.0.0, glob-parent@^5.1.0:
43674419
version "5.1.1"
43684420
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
43694421
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
@@ -4438,6 +4490,18 @@ globals@^12.1.0:
44384490
dependencies:
44394491
type-fest "^0.8.1"
44404492

4493+
globby@^11.0.1:
4494+
version "11.0.1"
4495+
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357"
4496+
integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==
4497+
dependencies:
4498+
array-union "^2.1.0"
4499+
dir-glob "^3.0.1"
4500+
fast-glob "^3.1.1"
4501+
ignore "^5.1.4"
4502+
merge2 "^1.3.0"
4503+
slash "^3.0.0"
4504+
44414505
globby@^9.2.0:
44424506
version "9.2.0"
44434507
resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
@@ -4666,6 +4730,11 @@ ignore@^5.0.5, ignore@~5.1.4:
46664730
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
46674731
integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==
46684732

4733+
ignore@^5.1.4:
4734+
version "5.1.8"
4735+
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
4736+
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
4737+
46694738
import-fresh@^2.0.0:
46704739
version "2.0.0"
46714740
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
@@ -6199,6 +6268,11 @@ merge2@^1.2.3:
61996268
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
62006269
integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
62016270

6271+
merge2@^1.3.0:
6272+
version "1.4.1"
6273+
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
6274+
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
6275+
62026276
merge@^1.2.1:
62036277
version "1.2.1"
62046278
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145"
@@ -7036,7 +7110,7 @@ performance-now@^2.1.0:
70367110
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
70377111
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
70387112

7039-
picomatch@^2.0.4, picomatch@^2.0.5:
7113+
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
70407114
version "2.2.2"
70417115
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
70427116
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
@@ -7637,6 +7711,11 @@ retry@^0.10.0:
76377711
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
76387712
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
76397713

7714+
reusify@^1.0.4:
7715+
version "1.0.4"
7716+
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
7717+
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
7718+
76407719
rimraf@*, rimraf@^3.0.0, rimraf@^3.0.2:
76417720
version "3.0.2"
76427721
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@@ -7668,6 +7747,11 @@ run-async@^2.2.0, run-async@^2.4.0:
76687747
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
76697748
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
76707749

7750+
run-parallel@^1.1.9:
7751+
version "1.1.9"
7752+
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
7753+
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
7754+
76717755
run-queue@^1.0.0, run-queue@^1.0.3:
76727756
version "1.0.3"
76737757
resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"

0 commit comments

Comments
 (0)