function readdir(dir, ignores) {
  if (Array.isArray(ignores)) {
    ignores = {
      str: ignores.filter(isString),
      fn: ignores.filter(isFunction)
    }
  }

  if (isString(dir)) {
    dir = {
      current: dir,
      root: dir
    }
  }
  const result = fsPromises
    .readdir(dir.current)
    .then((children) => {
      const filtered = []

      children.forEach((child) => {
        const res = resolve(dir.current, child)
        const rel = relative(dir.root, res)

        if (!match(rel, ignores.str).length) {
          filtered.push(
            stat(res).then((stat) => {
              // it would be better to put this check together with the previous if,
              // but that would break backwards-compatibility with Metalsmith 2.3.0
              // as the stat object needs to be passed to ignore fns
              if (ignores.fn.some((fn) => fn(rel, stat))) {
                return null
              }
              if (stat.isDirectory()) {
                return readdir({ current: res, root: dir.root }, ignores)
              }
              return res
            })
          )
        }
      })
      return Promise.all(filtered)
    })
    .then((files) => {
      const result = files
        // @TODO: this is a catch-all & can probably be finetuned with some more tests
        .filter((file) => !(file instanceof Error) && file !== null)
        .reduce((all, file) => all.concat(file), [])
        .sort()
      return result
    })
    .catch((err) => {
      throw err
    })

  return result
}
Recursive readdir with support for ignores
@private
@param {String} dir
@param {Array<String|Function>} ignores