"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.help = exports.normalizeOptions = exports.argv = exports.resolveEntry = exports.version = void 0;
const parseArgv = require("minimist");
const compiler_1 = require("./compiler");
const util_1 = require("./util");
const path_1 = require("path");
const target_1 = require("./target");
const os_1 = require("os");
const chalk_1 = require("chalk");
const resolve_dependencies_1 = require("resolve-dependencies");
const caw = require('caw');
const c = process.platform === 'win32' ? chalk_1.default.constructor({ enabled: false }) : chalk_1.default;
exports.version = "4.0.0-rc.4";
const defaults = {
    flags: [],
    cwd: process.cwd(),
    fs: true,
    configure: [],
    mangle: true,
    make: [],
    targets: [],
    vcBuild: util_1.isWindows ? ['nosign', 'release'] : [],
    enableNodeCli: false,
    build: false,
    bundle: true,
    patches: [],
    plugins: [],
    remote: 'https://github.com/nexe/nexe/releases/download/v3.3.3/',
};
const alias = {
    i: 'input',
    o: 'output',
    v: 'version',
    a: 'asset',
    t: 'target',
    b: 'build',
    n: 'name',
    r: 'resource',
    p: 'python',
    f: 'flag',
    c: 'configure',
    m: 'make',
    h: 'help',
    l: 'loglevel',
    'fake-argv': 'fakeArgv',
    'gh-token': 'ghToken',
};
const argv = parseArgv(process.argv, { alias, default: Object.assign({}, defaults) });
exports.argv = argv;
let help = `
${c.bold('nexe <entry-file> [options]')}

   ${c.underline.bold('Options:')}

  -i   --input                      -- application entry point
  -o   --output                     -- path to output file
  -t   --target                     -- node version description
  -n   --name                       -- main app module name
  -r   --resource                   -- *embed files (glob) within the binary
       --remote                     -- alternate location (URL) to download pre-built base (nexe) binaries from
       --plugin                     -- extend nexe runtime behavior

   ${c.underline.bold('Building from source:')}

  -b   --build                      -- build from source
  -p   --python                     -- python3 (as python) executable path
  -f   --flag                       -- *v8 flags to include during compilation
  -c   --configure                  -- *arguments to the configure step
  -m   --make                       -- *arguments to the make/build step
       --patch                      -- module with middleware default export for adding a build patch
       --no-mangle                  -- used when generating base binaries, or when patching _third_party_main manually
       --snapshot                   -- path to a warmup snapshot
       --ico                        -- file name for alternate icon file (windows)
       --rc-*                       -- populate rc file options (windows)
       --sourceUrl                  -- pass an alternate source (node.tar.gz) url
       --enableNodeCli              -- enable node cli enforcement (blocks app cli)

   ${c.underline.bold('Other options:')}

       --bundle                     -- custom bundling module with 'createBundle' export
       --temp                       -- temp file storage default '~/.nexe'
       --cwd                        -- set the current working directory for the command
       --fake-argv                  -- fake argv[1] with entry file
       --clean                      -- force download of sources
       --silent                     -- disable logging
       --verbose                    -- set logging to verbose

       -* variable key name         * option can be used more than once`.trim();
exports.help = help;
exports.help = help = os_1.EOL + help + os_1.EOL;
function flatten(...args) {
    return [].concat(...args).filter((x) => x);
}
/**
 * Extract keys such as { "rc-CompanyName": "Node.js" } to
 * { CompanyName: "Node.js" }
 * @param {*} match
 * @param {*} options
 */
function extractCliMap(match, options) {
    return Object.keys(options)
        .filter((x) => match.test(x))
        .reduce((map, option) => {
        const key = option.split('-')[1];
        map[key] = options[option];
        delete options[option];
        return map;
    }, {});
}
function extractLogLevel(options) {
    if (options.loglevel)
        return options.loglevel;
    if (options.silent)
        return 'silent';
    if (options.verbose)
        return 'verbose';
    return 'info';
}
function isName(name) {
    return name && name !== 'index' && name !== util_1.STDIN_FLAG;
}
function extractName(options) {
    let name = options.name;
    //try and use the input filename as the output filename if its not index
    if (!isName(name) && typeof options.input === 'string') {
        name = (0, path_1.basename)(options.input).replace((0, path_1.extname)(options.input), '');
    }
    //try and use the directory as the filename
    if (!isName(name) && (0, path_1.basename)(options.cwd)) {
        name = (0, path_1.basename)(options.cwd);
    }
    return name.replace(/\.exe$/, '');
}
function padRelative(input) {
    let prefix = '';
    if (!input.startsWith('.')) {
        prefix = './';
    }
    return prefix + input;
}
function isEntryFile(filename) {
    return Boolean(filename && !(0, path_1.isAbsolute)(filename));
}
function resolveEntry(input, cwd, maybeEntry, bundle) {
    let result = null;
    if (input === '-' || maybeEntry === '-') {
        return util_1.STDIN_FLAG;
    }
    if (input && (0, path_1.isAbsolute)(input)) {
        return input;
    }
    if (input) {
        const inputPath = padRelative(input);
        result = (0, resolve_dependencies_1.resolveSync)(cwd, inputPath);
    }
    if (isEntryFile(maybeEntry) && (!result || !result.absPath)) {
        const inputPath = padRelative(maybeEntry);
        result = (0, resolve_dependencies_1.resolveSync)(cwd, inputPath);
    }
    if (!process.stdin.isTTY && (!result || !result.absPath) && bundle === defaults.bundle) {
        return util_1.STDIN_FLAG;
    }
    if (!result || !result.absPath) {
        result = (0, resolve_dependencies_1.resolveSync)(cwd, '.');
    }
    if (!result.absPath) {
        throw new compiler_1.NexeError(`Entry file "${input || ''}" not found!`);
    }
    return result.absPath;
}
exports.resolveEntry = resolveEntry;
function isCli(options) {
    return argv === options;
}
function normalizeOptions(input) {
    const options = Object.assign({}, defaults, input);
    const opts = options;
    const cwd = (options.cwd = (0, path_1.resolve)(options.cwd));
    options.temp = options.temp
        ? (0, path_1.resolve)(cwd, options.temp)
        : process.env.NEXE_TEMP || (0, path_1.join)((0, os_1.homedir)(), '.nexe');
    const maybeEntry = isCli(input) ? argv._[argv._.length - 1] : undefined;
    options.input = resolveEntry(options.input, cwd, maybeEntry, options.bundle);
    options.enableStdIn = isCli(input) && options.input === util_1.STDIN_FLAG;
    options.name = extractName(options);
    options.loglevel = extractLogLevel(options);
    options.flags = flatten(opts.flag, options.flags);
    options.targets = flatten(opts.target, options.targets).map(target_1.getTarget);
    if (!options.targets.length) {
        options.targets.push((0, target_1.getTarget)());
    }
    options.ghToken = options.ghToken || process.env.GITHUB_TOKEN || '';
    options.make = flatten(util_1.isWindows ? options.vcBuild : options.make);
    options.configure = flatten(options.configure);
    options.resources = flatten(opts.resource, options.resources);
    if (!options.remote.endsWith('/')) {
        options.remote += '/';
    }
    options.downloadOptions = options.downloadOptions || {};
    options.downloadOptions.headers = options.downloadOptions.headers || {};
    options.downloadOptions.headers['User-Agent'] = 'nexe (https://www.npmjs.com/package/nexe)';
    options.downloadOptions.agent = process.env.HTTPS_PROXY
        ? caw(process.env.HTTPS_PROXY, { protocol: 'https' })
        : options.downloadOptions.agent || require('https').globalAgent;
    options.downloadOptions.rejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED
        ? false
        : true;
    options.rc = options.rc || extractCliMap(/^rc-.*/, options);
    options.output =
        options.targets[0].platform === 'windows'
            ? `${(options.output || options.name).replace(/\.exe$/, '')}.exe`
            : `${options.output || options.name}`;
    options.output = (0, path_1.resolve)(cwd, options.output);
    const requireDefault = (x) => {
        if (typeof x === 'string') {
            return require(x).default;
        }
        return x;
    };
    options.mangle = 'mangle' in opts ? opts.mangle : true;
    options.plugins = flatten(opts.plugin, options.plugins).map(requireDefault);
    options.patches = flatten(opts.patch, options.patches).map(requireDefault);
    if ((!options.mangle && !options.bundle) || options.patches.length) {
        options.build = true;
    }
    if (options.build) {
        const { arch } = options.targets[0];
        if (util_1.isWindows) {
            options.make = Array.from(new Set(options.make.concat(arch)));
        }
        else {
            options.configure = Array.from(new Set(options.configure.concat([`--dest-cpu=${arch}`])));
        }
    }
    Object.keys(alias)
        .filter((k) => k !== 'rc')
        .forEach((x) => delete opts[x]);
    return options;
}
exports.normalizeOptions = normalizeOptions;
