docs: function processStackItem(out, stack, rootPath, userFilter, readMode) {
    // Initialize a new file object.
    const initFile = (dirPath) => {
      return (fileName, callback) => {
        const filePath = path.join(dirPath, fileName);
        fs.stat(filePath, (error, stats) => {
          async.nextTick(callback, error, {
            path: path.relative(rootPath, filePath),
            stats,
          });
        });
      };
    };
  
    // Filter supported files.
    const filterSupported = () => {
      return (file, callback) => {
        const keep = file.stats.isFile() || file.stats.isDirectory();
        async.nextTick(callback, null, keep);
      };
    };
  
    // Filter output files.
    const filterOutput = () => {
      return (file, callback) => {
        const keep = file.stats.isFile() && userFilter(file);
        async.nextTick(callback, null, keep);
      };
    };
  
    // Read a file's data.
    const readData = () => {
      return (file, callback) => {
        const filePath = path.join(rootPath, file.path);
        read(filePath, readMode, (error, data) => {
          async.nextTick(callback, error, Object.assign({}, file, { data }));
        });
      };
    };
  
    return (callback) => {
      const dirPath = stack.shift();
      async.waterfall([
        cb => fs.readdir(dirPath, cb),
        (fileNames, cb) => async.map(fileNames, initFile(dirPath), cb),
        (files, cb) => async.filter(files, filterSupported(), cb),
        (files, cb) => populateStack(stack, rootPath, files, cb),
        (files, cb) => async.filter(files, filterOutput(), cb),
        (files, cb) => async.map(files, readData(), cb),
      ], (error, result) => {
        if (error) {
          async.nextTick(callback, error);
          return;
        }
  
        out.push(...result);
        async.nextTick(callback, null);
      });
    };
  }