#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = void 0;
const path_1 = require("path");
const util_1 = require("util");
const Module = require("module");
const arg = require("arg");
const repl_1 = require("./repl");
const index_1 = require("./index");
/**
 * Main `bin` functionality.
 */
function main(argv = process.argv.slice(2), entrypointArgs = {}) {
    const args = Object.assign(Object.assign({}, entrypointArgs), arg({
        // Node.js-like options.
        '--eval': String,
        '--interactive': Boolean,
        '--print': Boolean,
        '--require': [String],
        // CLI options.
        '--help': Boolean,
        '--script-mode': Boolean,
        '--version': arg.COUNT,
        // Project options.
        '--dir': String,
        '--files': Boolean,
        '--compiler': String,
        '--compiler-options': index_1.parse,
        '--project': String,
        '--ignore-diagnostics': [String],
        '--ignore': [String],
        '--transpile-only': Boolean,
        '--type-check': Boolean,
        '--compiler-host': Boolean,
        '--pretty': Boolean,
        '--skip-project': Boolean,
        '--skip-ignore': Boolean,
        '--prefer-ts-exts': Boolean,
        '--log-error': Boolean,
        '--emit': Boolean,
        // Aliases.
        '-e': '--eval',
        '-i': '--interactive',
        '-p': '--print',
        '-r': '--require',
        '-h': '--help',
        '-s': '--script-mode',
        '-v': '--version',
        '-T': '--transpile-only',
        '-H': '--compiler-host',
        '-I': '--ignore',
        '-P': '--project',
        '-C': '--compiler',
        '-D': '--ignore-diagnostics',
        '-O': '--compiler-options'
    }, {
        argv,
        stopAtPositional: true
    }));
    // Only setting defaults for CLI-specific flags
    // Anything passed to `register()` can be `undefined`; `create()` will apply
    // defaults.
    const { '--dir': dir, '--help': help = false, '--script-mode': scriptMode = false, '--version': version = 0, '--require': argsRequire = [], '--eval': code = undefined, '--print': print = false, '--interactive': interactive = false, '--files': files, '--compiler': compiler, '--compiler-options': compilerOptions, '--project': project, '--ignore-diagnostics': ignoreDiagnostics, '--ignore': ignore, '--transpile-only': transpileOnly, '--type-check': typeCheck, '--compiler-host': compilerHost, '--pretty': pretty, '--skip-project': skipProject, '--skip-ignore': skipIgnore, '--prefer-ts-exts': preferTsExts, '--log-error': logError, '--emit': emit } = args;
    if (help) {
        console.log(`
  Usage: ts-node [options] [ -e script | script.ts ] [arguments]

  Options:

    -e, --eval [code]              Evaluate code
    -p, --print                    Print result of \`--eval\`
    -r, --require [path]           Require a node module before execution
    -i, --interactive              Opens the REPL even if stdin does not appear to be a terminal

    -h, --help                     Print CLI usage
    -v, --version                  Print module version information
    -s, --script-mode              Use cwd from <script.ts> instead of current directory

    -T, --transpile-only           Use TypeScript's faster \`transpileModule\`
    -H, --compiler-host            Use TypeScript's compiler host API
    -I, --ignore [pattern]         Override the path patterns to skip compilation
    -P, --project [path]           Path to TypeScript JSON project file
    -C, --compiler [name]          Specify a custom TypeScript compiler
    -D, --ignore-diagnostics [code] Ignore TypeScript warnings by diagnostic code
    -O, --compiler-options [opts]   JSON object to merge with compiler options

    --dir                          Specify working directory for config resolution
    --scope                        Scope compiler to files within \`cwd\` only
    --files                        Load \`files\`, \`include\` and \`exclude\` from \`tsconfig.json\` on startup
    --pretty                       Use pretty diagnostic formatter (usually enabled by default)
    --skip-project                 Skip reading \`tsconfig.json\`
    --skip-ignore                  Skip \`--ignore\` checks
    --prefer-ts-exts               Prefer importing TypeScript files over JavaScript files
    --log-error                    Logs TypeScript errors to stderr instead of throwing exceptions
  `);
        process.exit(0);
    }
    // Output project information.
    if (version === 1) {
        console.log(`v${index_1.VERSION}`);
        process.exit(0);
    }
    const cwd = dir || process.cwd();
    /** Unresolved.  May point to a symlink, not realpath.  May be missing file extension */
    const scriptPath = args._.length ? path_1.resolve(cwd, args._[0]) : undefined;
    const state = new repl_1.EvalState(scriptPath || path_1.join(cwd, repl_1.EVAL_FILENAME));
    const replService = repl_1.createRepl({ state });
    const { evalAwarePartialHost } = replService;
    // Register the TypeScript compiler instance.
    const service = index_1.register({
        dir: getCwd(dir, scriptMode, scriptPath),
        emit,
        files,
        pretty,
        transpileOnly,
        typeCheck,
        compilerHost,
        ignore,
        preferTsExts,
        logError,
        project,
        skipProject,
        skipIgnore,
        compiler,
        ignoreDiagnostics,
        compilerOptions,
        require: argsRequire,
        readFile: code !== undefined ? evalAwarePartialHost.readFile : undefined,
        fileExists: code !== undefined ? evalAwarePartialHost.fileExists : undefined
    });
    // Bind REPL service to ts-node compiler service (chicken-and-egg problem)
    replService.setService(service);
    // Output project information.
    if (version >= 2) {
        console.log(`ts-node v${index_1.VERSION}`);
        console.log(`node ${process.version}`);
        console.log(`compiler v${service.ts.version}`);
        process.exit(0);
    }
    // Create a local module instance based on `cwd`.
    const module = new Module(state.path);
    module.filename = state.path;
    module.paths = Module._nodeModulePaths(cwd);
    // Prepend `ts-node` arguments to CLI for child processes.
    process.execArgv.unshift(__filename, ...process.argv.slice(2, process.argv.length - args._.length));
    process.argv = [process.argv[1]].concat(scriptPath || []).concat(args._.slice(1));
    // Execute the main contents (either eval, script or piped).
    if (code !== undefined && !interactive) {
        evalAndExit(replService, module, code, print);
    }
    else {
        if (args._.length) {
            Module.runMain();
        }
        else {
            // Piping of execution _only_ occurs when no other script is specified.
            // --interactive flag forces REPL
            if (interactive || process.stdin.isTTY) {
                replService.start(code);
            }
            else {
                let buffer = code || '';
                process.stdin.on('data', (chunk) => buffer += chunk);
                process.stdin.on('end', () => evalAndExit(replService, module, buffer, print));
            }
        }
    }
}
exports.main = main;
/**
 * Get project path from args.
 */
function getCwd(dir, scriptMode, scriptPath) {
    // Validate `--script-mode` usage is correct.
    if (scriptMode) {
        if (!scriptPath) {
            throw new TypeError('Script mode must be used with a script name, e.g. `ts-node -s <script.ts>`');
        }
        if (dir) {
            throw new TypeError('Script mode cannot be combined with `--dir`');
        }
        // Use node's own resolution behavior to ensure we follow symlinks.
        // scriptPath may omit file extension or point to a directory with or without package.json.
        // This happens before we are registered, so we tell node's resolver to consider ts, tsx, and jsx files.
        // In extremely rare cases, is is technically possible to resolve the wrong directory,
        // because we do not yet know preferTsExts, jsx, nor allowJs.
        // See also, justification why this will not happen in real-world situations:
        // https://github.com/TypeStrong/ts-node/pull/1009#issuecomment-613017081
        const exts = ['.js', '.jsx', '.ts', '.tsx'];
        const extsTemporarilyInstalled = [];
        for (const ext of exts) {
            if (!hasOwnProperty(require.extensions, ext)) { // tslint:disable-line
                extsTemporarilyInstalled.push(ext);
                require.extensions[ext] = function () { }; // tslint:disable-line
            }
        }
        try {
            return path_1.dirname(require.resolve(scriptPath));
        }
        finally {
            for (const ext of extsTemporarilyInstalled) {
                delete require.extensions[ext]; // tslint:disable-line
            }
        }
    }
    return dir;
}
/**
 * Evaluate a script.
 */
function evalAndExit(replService, module, code, isPrinted) {
    let result;
    global.__filename = module.filename;
    global.__dirname = path_1.dirname(module.filename);
    global.exports = module.exports;
    global.module = module;
    global.require = module.require.bind(module);
    try {
        result = replService.evalCode(code);
    }
    catch (error) {
        if (error instanceof index_1.TSError) {
            console.error(error);
            process.exit(1);
        }
        throw error;
    }
    if (isPrinted) {
        console.log(typeof result === 'string' ? result : util_1.inspect(result));
    }
}
/** Safe `hasOwnProperty` */
function hasOwnProperty(object, property) {
    return Object.prototype.hasOwnProperty.call(object, property);
}
if (require.main === module) {
    main();
}
//# sourceMappingURL=bin.js.map