xref: /expo/packages/@expo/cli/src/utils/glob.ts (revision bb5069cd)
1import G, { Glob } from 'glob';
2
3/** Finds all matching files. */
4export function everyMatchAsync(pattern: string, options: G.IOptions) {
5  return new Promise<string[]>((resolve, reject) => {
6    const g = new Glob(pattern, options);
7    let called = false;
8    const callback = (er: Error | null, matched: string[]) => {
9      if (called) return;
10      called = true;
11      if (er) reject(er);
12      else resolve(matched);
13    };
14    g.on('error', callback);
15    g.on('end', (matches) => callback(null, matches));
16  });
17}
18
19/** Bails out early after finding the first matching file. */
20export function anyMatchAsync(pattern: string, options: G.IOptions) {
21  return new Promise<string[]>((resolve, reject) => {
22    const g = new Glob(pattern, options);
23    let called = false;
24    const callback = (er: Error | null, matched: string[]) => {
25      if (called) return;
26      called = true;
27      if (er) reject(er);
28      else resolve(matched);
29    };
30    g.on('error', callback);
31    g.on('match', (matched) => {
32      // We've disabled using abort as it breaks the entire glob package across all instances.
33      // https://github.com/isaacs/node-glob/issues/279 & https://github.com/isaacs/node-glob/issues/342
34      // For now, just collect every match.
35      // g.abort();
36      callback(null, [matched]);
37    });
38    g.on('end', (matches) => callback(null, matches));
39  });
40}
41
42/**
43 * Wait some time, then escape...
44 * Adding this because glob can sometimes freeze and fail to resolve if any other glob uses `.abort()`.
45 */
46export function wrapGlobWithTimeout(
47  query: () => Promise<string[]>,
48  duration: number
49): Promise<string[] | false> {
50  return new Promise(async (resolve, reject) => {
51    const timeout = setTimeout(() => {
52      resolve(false);
53    }, duration);
54
55    process.on('SIGINT', () => clearTimeout(timeout));
56
57    try {
58      resolve(await query());
59    } catch (error) {
60      reject(error);
61    } finally {
62      clearTimeout(timeout);
63    }
64  });
65}
66