"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.action = action;
exports.default = void 0;

function _axios() {
  const data = _interopRequireDefault(require("axios"));

  _axios = function () {
    return data;
  };

  return data;
}

function _crypto() {
  const data = _interopRequireDefault(require("crypto"));

  _crypto = function () {
    return data;
  };

  return data;
}

function _fsExtra() {
  const data = _interopRequireDefault(require("fs-extra"));

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _validator() {
  const data = _interopRequireDefault(require("validator"));

  _validator = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _targz() {
  const data = _interopRequireDefault(require("targz"));

  _targz = function () {
    return data;
  };

  return data;
}

function _xdl() {
  const data = require("@expo/xdl");

  _xdl = function () {
    return data;
  };

  return data;
}

function _log() {
  const data = _interopRequireDefault(require("../log"));

  _log = function () {
    return data;
  };

  return data;
}

function _exit() {
  const data = require("../exit");

  _exit = function () {
    return data;
  };

  return data;
}

function _CommandError() {
  const data = _interopRequireDefault(require("../CommandError"));

  _CommandError = function () {
    return data;
  };

  return data;
}

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

async function action(projectDir, options = {}) {
  const outputPath = _path().default.resolve(projectDir, options.outputDir);

  if (_fsExtra().default.existsSync(outputPath)) {
    throw new (_CommandError().default)('OUTPUT_DIR_EXISTS', `Output directory ${outputPath} already exists. Aborting export.`);
  }

  if (!options.publicUrl) {
    throw new (_CommandError().default)('MISSING_PUBLIC_URL', 'Missing required option: --public-url');
  } // If we are not in dev mode, ensure that url is https


  if (!options.dev && !_xdl().UrlUtils.isHttps(options.publicUrl)) {
    throw new (_CommandError().default)('INVALID_PUBLIC_URL', '--public-url must be a valid HTTPS URL.');
  } else if (!_validator().default.isURL(options.publicUrl, {
    protocols: ['http', 'https']
  })) {
    console.warn(`Dev Mode: publicUrl ${options.publicUrl} does not conform to HTTP format.`);
  }

  const status = await _xdl().Project.currentStatus(projectDir);
  let startedOurOwn = false;

  if (status !== 'running') {
    (0, _log().default)('Unable to find an existing Expo CLI instance for this directory, starting a new one...');
    (0, _exit().installExitHooks)(projectDir);
    const startOpts = {
      reset: options.clear,
      nonPersistent: true
    };

    if (options.maxWorkers) {
      startOpts.maxWorkers = options.maxWorkers;
    }

    (0, _log().default)('Exporting your app...');
    await _xdl().Project.startAsync(projectDir, startOpts, !options.quiet);
    startedOurOwn = true;
  } // Make outputDir an absolute path if it isnt already


  const exportOptions = {
    dumpAssetmap: options.dumpAssetmap,
    dumpSourcemap: options.dumpSourcemap,
    isDev: options.dev
  };

  const absoluteOutputDir = _path().default.resolve(process.cwd(), options.outputDir);

  await _xdl().Project.exportForAppHosting(projectDir, options.publicUrl, options.assetUrl, absoluteOutputDir, exportOptions);

  if (startedOurOwn) {
    (0, _log().default)('Terminating server processes.');
    await _xdl().Project.stopAsync(projectDir);
  } // Merge src dirs/urls into a multimanifest if specified


  const mergeSrcDirs = []; // src urls were specified to merge in, so download and decompress them

  if (options.mergeSrcUrl.length > 0) {
    // delete .tmp if it exists and recreate it anew
    const tmpFolder = _path().default.resolve(projectDir, _path().default.join('.tmp'));

    await _fsExtra().default.remove(tmpFolder);
    await _fsExtra().default.ensureDir(tmpFolder); // Download the urls into a tmp dir

    const downloadDecompressPromises = options.mergeSrcUrl.map(async url => {
      // Add the absolute paths to srcDir
      const uniqFilename = `${_path().default.basename(url, '.tar.gz')}_${_crypto().default.randomBytes(16).toString('hex')}`;

      const tmpFileCompressed = _path().default.resolve(tmpFolder, uniqFilename + '_compressed');

      const tmpFolderUncompressed = _path().default.resolve(tmpFolder, uniqFilename);

      await download(url, tmpFileCompressed);
      await decompress(tmpFileCompressed, tmpFolderUncompressed); // add the decompressed folder to be merged

      mergeSrcDirs.push(tmpFolderUncompressed);
    });
    await Promise.all(downloadDecompressPromises);
  } // add any local src dirs to be merged


  mergeSrcDirs.push(...options.mergeSrcDir);

  if (mergeSrcDirs.length > 0) {
    const srcDirs = options.mergeSrcDir.concat(options.mergeSrcUrl).join(' ');
    (0, _log().default)(`Starting project merge of ${srcDirs} into ${options.outputDir}`); // Merge app distributions

    await _xdl().Project.mergeAppDistributions(projectDir, [...mergeSrcDirs, options.outputDir], // merge stuff in srcDirs and outputDir together
    options.outputDir);
    (0, _log().default)(`Project merge was successful. Your merged files can be found in ${options.outputDir}`);
  }

  (0, _log().default)(`Export was successful. Your exported files can be found in ${options.outputDir}`);
}

const download = async (uri, filename) => {
  return new Promise((resolve, reject) => {
    (0, _axios().default)(uri).pipe(_fsExtra().default.createWriteStream(filename)).on('close', () => resolve(null)).on('error', err => {
      reject(err);
    });
  });
};

const decompress = async (src, dest) => {
  return new Promise((resolve, reject) => {
    _targz().default.decompress({
      src,
      dest
    }, error => {
      if (error) {
        reject(error);
      } else {
        resolve(null);
      }
    });
  });
};

function collect(val, memo) {
  memo.push(val);
  return memo;
}

var _default = program => {
  program.command('export [project-dir]').description('Exports the static files of the app for hosting it on a web server.').option('-p, --public-url <url>', 'The public url that will host the static files. (Required)').option('--output-dir <dir>', 'The directory to export the static files to. Default directory is `dist`', 'dist').option('-a, --asset-url <url>', "The absolute or relative url that will host the asset files. Default is './assets', which will be resolved against the public-url.", './assets').option('-d, --dump-assetmap', 'Dump the asset map for further processing.').option('--dev', 'Configures static files for developing locally using a non-https server').option('-s, --dump-sourcemap', 'Dump the source map for debugging the JS bundle.').option('-q, --quiet', 'Suppress verbose output from the React Native packager.').option('--merge-src-dir [dir]', 'A repeatable source dir to merge in.', collect, []).option('--merge-src-url [url]', 'A repeatable source tar.gz file URL to merge in.', collect, []).option('--max-workers [num]', 'Maximum number of tasks to allow Metro to spawn.').asyncActionProjectDir(action, false, true);
};

exports.default = _default;
//# sourceMappingURL=../__sourcemaps__/commands/export.js.map