function* findAllImports(finder, filename) {
  // it doesn't matter if finder is sync or async!
  let specifiers = yield finder(filename);

  // pretend there's some de-duping, caching,
  // scrubbing, etc. happening here

  for (const specifier of specifiers) {
    // it's okay to be recursive
    specifiers = [...specifiers, ...(yield* findAllImports(finder, specifier))];
  }
  return specifiers;
}
Recursively crawls a dependency tree to find all dependencies

@template {string[] | Promise<string[]>} TResult Type of result (list of imports)
@param {(filepath: string) => TResult} finder Function which reads a file and returns its imports
@param {string} filename File to start from; entry point
@returns {Generator<TResult, string[], string[]>} Generator yielding list of imports