Source: storage/list.js

import { hasTrailingSlash, title } from 'cpb-common';
import { StorageInstance as storage } from './shared.js';

/**
 * @typedef  {object} DirectoryListing
 * @property {string} bucket - gce storage bucket
 * @property {object[]} files - files in the bucket
 * @property {object[]} dirs - directories within the bucket
 */

/**
 * @internal
 * @description
 * ### Recursively get top-level directory listing for the given storage bucket.
 * Due to the Google nodejs api limitations there is no native way to get this data.
 * We have to manually iterate the apiResponse object and fill the prefixes.
 * @param {string} bucket - gce storage bucket name
 * @param {?string} delimiter - The delimiter argument can be used to restrict the results to only the
 * "files" in the given "folder". Without the delimiter, the entire tree under the prefix is returned.
 * @param {?string} prefix - directory prefix. This can be used to list all blobs in a "folder", e.g.
 *   "public/".
 * @param {?boolean} [versions=false] - include previous file versions
 * @returns {Promise<DirectoryListing>}
 * @example
 * For example, given these blobs:
 *   /a/1.txt
 *   /a/b/2.txt
 * If you just specify prefix = 'a/', you'll get back:
 *   /a/1.txt
 *   /a/b/2.txt
 * However, if you specify prefix='a/' and delimiter='/', you'll get back:
 *   /a/1.txt
 */
async function list({ bucket = process.env.BUCKET || 'custom-product-builder', delimiter, prefix, versions = false }) {
  title('[cpb-storage/list]', { bucket, prefix, delimiter, versions });
  //  if (!bucket) {
  //    throw new TypeError('!bucket');
  //  }

  /**
   * @type {DirectoryListing}
   */
  const result = {
    files: [],
    dirs: [],
    bucket,
  };

  return await new Promise((resolve, reject) => {
    async function callback(err, files, nextQuery, apiResponse) {
      if (err) {
        console.error(err);
        reject(err);
      }

      (files || []).forEach(file => {
        if (hasTrailingSlash(file.name)) {
          result.dirs.push({
            id: file.metadata.id,
            name: file.name,
            bucket,
          });
        } else {
          result.files.push({
            id: file.metadata.id,
            name: file.name,
            bucket,
            currentFileSize: file.metadata.size,
            generation: file.metadata.generation,
            metadata: file.metadata,
          });
        }
      });

      ((apiResponse || {}).prefixes || []).forEach(name => {
        result.dirs.push({
          name,
          bucket,
        });
      });

      if (nextQuery) await storage.bucket(bucket).getFiles(nextQuery, callback);
      else return resolve(result);
    }

    storage.bucket(bucket).getFiles({ autoPaginate: false, prefix, delimiter, versions }, callback);
  });
}

/**
 * @method module:cpb-storage.LSD
 * @description
 * ### Get bucket directory/files listing
 * @async
 * @param {string} bucket - GCS Storage Bucket Name
 * @param {?string} [delimiter]
 * @param {?string} [prefix] - directory prefix
 * @param {?boolean} [versions] - include previous file versions
 * @returns {Promise<DirectoryListing>}
 */
export default async function LSD({ bucket, delimiter, prefix, versions }) {
  return await list({ bucket, delimiter, prefix, versions });
}