bin.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. #!/usr/bin/env node
  2. "use strict";
  3. Object.defineProperty(exports, "__esModule", { value: true });
  4. exports.bootstrap = exports.main = void 0;
  5. const path_1 = require("path");
  6. const util_1 = require("util");
  7. const Module = require("module");
  8. let arg;
  9. const util_2 = require("./util");
  10. const repl_1 = require("./repl");
  11. const index_1 = require("./index");
  12. const node_internal_modules_cjs_helpers_1 = require("../dist-raw/node-internal-modules-cjs-helpers");
  13. const spawn_child_1 = require("./child/spawn-child");
  14. const configuration_1 = require("./configuration");
  15. /**
  16. * Main `bin` functionality.
  17. *
  18. * This file is split into a chain of functions (phases), each one adding to a shared state object.
  19. * This is done so that the next function can either be invoked in-process or, if necessary, invoked in a child process.
  20. *
  21. * The functions are intentionally given uncreative names and left in the same order as the original code, to make a
  22. * smaller git diff.
  23. */
  24. function main(argv = process.argv.slice(2), entrypointArgs = {}) {
  25. const args = parseArgv(argv, entrypointArgs);
  26. const state = {
  27. shouldUseChildProcess: false,
  28. isInChildProcess: false,
  29. isCli: true,
  30. tsNodeScript: __filename,
  31. parseArgvResult: args,
  32. };
  33. return bootstrap(state);
  34. }
  35. exports.main = main;
  36. /** @internal */
  37. function bootstrap(state) {
  38. if (!state.phase2Result) {
  39. state.phase2Result = phase2(state);
  40. if (state.shouldUseChildProcess && !state.isInChildProcess) {
  41. // Note: When transitioning into the child-process after `phase2`,
  42. // the updated working directory needs to be preserved.
  43. return (0, spawn_child_1.callInChild)(state);
  44. }
  45. }
  46. if (!state.phase3Result) {
  47. state.phase3Result = phase3(state);
  48. if (state.shouldUseChildProcess && !state.isInChildProcess) {
  49. // Note: When transitioning into the child-process after `phase2`,
  50. // the updated working directory needs to be preserved.
  51. return (0, spawn_child_1.callInChild)(state);
  52. }
  53. }
  54. return phase4(state);
  55. }
  56. exports.bootstrap = bootstrap;
  57. function parseArgv(argv, entrypointArgs) {
  58. arg !== null && arg !== void 0 ? arg : (arg = require('arg'));
  59. // HACK: technically, this function is not marked @internal so it's possible
  60. // that libraries in the wild are doing `require('ts-node/dist/bin').main({'--transpile-only': true})`
  61. // We can mark this function @internal in next major release.
  62. // For now, rewrite args to avoid a breaking change.
  63. entrypointArgs = { ...entrypointArgs };
  64. for (const key of Object.keys(entrypointArgs)) {
  65. entrypointArgs[key.replace(/([a-z])-([a-z])/g, (_$0, $1, $2) => `${$1}${$2.toUpperCase()}`)] = entrypointArgs[key];
  66. }
  67. const args = {
  68. ...entrypointArgs,
  69. ...arg({
  70. // Node.js-like options.
  71. '--eval': String,
  72. '--interactive': Boolean,
  73. '--print': Boolean,
  74. '--require': [String],
  75. // CLI options.
  76. '--help': Boolean,
  77. '--cwdMode': Boolean,
  78. '--scriptMode': Boolean,
  79. '--version': arg.COUNT,
  80. '--showConfig': Boolean,
  81. '--esm': Boolean,
  82. // Project options.
  83. '--cwd': String,
  84. '--files': Boolean,
  85. '--compiler': String,
  86. '--compilerOptions': util_2.parse,
  87. '--project': String,
  88. '--ignoreDiagnostics': [String],
  89. '--ignore': [String],
  90. '--transpileOnly': Boolean,
  91. '--transpiler': String,
  92. '--swc': Boolean,
  93. '--typeCheck': Boolean,
  94. '--compilerHost': Boolean,
  95. '--pretty': Boolean,
  96. '--skipProject': Boolean,
  97. '--skipIgnore': Boolean,
  98. '--preferTsExts': Boolean,
  99. '--logError': Boolean,
  100. '--emit': Boolean,
  101. '--scope': Boolean,
  102. '--scopeDir': String,
  103. '--noExperimentalReplAwait': Boolean,
  104. '--experimentalSpecifierResolution': String,
  105. // Aliases.
  106. '-e': '--eval',
  107. '-i': '--interactive',
  108. '-p': '--print',
  109. '-r': '--require',
  110. '-h': '--help',
  111. '-s': '--script-mode',
  112. '-v': '--version',
  113. '-T': '--transpileOnly',
  114. '-H': '--compilerHost',
  115. '-I': '--ignore',
  116. '-P': '--project',
  117. '-C': '--compiler',
  118. '-D': '--ignoreDiagnostics',
  119. '-O': '--compilerOptions',
  120. '--dir': '--cwd',
  121. // Support both tsc-style camelCase and node-style hypen-case for *all* flags
  122. '--cwd-mode': '--cwdMode',
  123. '--script-mode': '--scriptMode',
  124. '--show-config': '--showConfig',
  125. '--compiler-options': '--compilerOptions',
  126. '--ignore-diagnostics': '--ignoreDiagnostics',
  127. '--transpile-only': '--transpileOnly',
  128. '--type-check': '--typeCheck',
  129. '--compiler-host': '--compilerHost',
  130. '--skip-project': '--skipProject',
  131. '--skip-ignore': '--skipIgnore',
  132. '--prefer-ts-exts': '--preferTsExts',
  133. '--log-error': '--logError',
  134. '--scope-dir': '--scopeDir',
  135. '--no-experimental-repl-await': '--noExperimentalReplAwait',
  136. '--experimental-specifier-resolution': '--experimentalSpecifierResolution',
  137. }, {
  138. argv,
  139. stopAtPositional: true,
  140. }),
  141. };
  142. // Only setting defaults for CLI-specific flags
  143. // Anything passed to `register()` can be `undefined`; `create()` will apply
  144. // defaults.
  145. const { '--cwd': cwdArg, '--help': help = false, '--scriptMode': scriptMode, '--cwdMode': cwdMode, '--version': version = 0, '--showConfig': showConfig, '--require': argsRequire = [], '--eval': code = undefined, '--print': print = false, '--interactive': interactive = false, '--files': files, '--compiler': compiler, '--compilerOptions': compilerOptions, '--project': project, '--ignoreDiagnostics': ignoreDiagnostics, '--ignore': ignore, '--transpileOnly': transpileOnly, '--typeCheck': typeCheck, '--transpiler': transpiler, '--swc': swc, '--compilerHost': compilerHost, '--pretty': pretty, '--skipProject': skipProject, '--skipIgnore': skipIgnore, '--preferTsExts': preferTsExts, '--logError': logError, '--emit': emit, '--scope': scope = undefined, '--scopeDir': scopeDir = undefined, '--noExperimentalReplAwait': noExperimentalReplAwait, '--experimentalSpecifierResolution': experimentalSpecifierResolution, '--esm': esm, _: restArgs, } = args;
  146. return {
  147. // Note: argv and restArgs may be overwritten by child process
  148. argv: process.argv,
  149. restArgs,
  150. cwdArg,
  151. help,
  152. scriptMode,
  153. cwdMode,
  154. version,
  155. showConfig,
  156. argsRequire,
  157. code,
  158. print,
  159. interactive,
  160. files,
  161. compiler,
  162. compilerOptions,
  163. project,
  164. ignoreDiagnostics,
  165. ignore,
  166. transpileOnly,
  167. typeCheck,
  168. transpiler,
  169. swc,
  170. compilerHost,
  171. pretty,
  172. skipProject,
  173. skipIgnore,
  174. preferTsExts,
  175. logError,
  176. emit,
  177. scope,
  178. scopeDir,
  179. noExperimentalReplAwait,
  180. experimentalSpecifierResolution,
  181. esm,
  182. };
  183. }
  184. function phase2(payload) {
  185. const { help, version, cwdArg, esm } = payload.parseArgvResult;
  186. if (help) {
  187. console.log(`
  188. Usage: ts-node [options] [ -e script | script.ts ] [arguments]
  189. Options:
  190. -e, --eval [code] Evaluate code
  191. -p, --print Print result of \`--eval\`
  192. -r, --require [path] Require a node module before execution
  193. -i, --interactive Opens the REPL even if stdin does not appear to be a terminal
  194. --esm Bootstrap with the ESM loader, enabling full ESM support
  195. --swc Use the faster swc transpiler
  196. -h, --help Print CLI usage
  197. -v, --version Print module version information. -vvv to print additional information
  198. --showConfig Print resolved configuration and exit
  199. -T, --transpileOnly Use TypeScript's faster \`transpileModule\` or a third-party transpiler
  200. -H, --compilerHost Use TypeScript's compiler host API
  201. -I, --ignore [pattern] Override the path patterns to skip compilation
  202. -P, --project [path] Path to TypeScript JSON project file
  203. -C, --compiler [name] Specify a custom TypeScript compiler
  204. --transpiler [name] Specify a third-party, non-typechecking transpiler
  205. -D, --ignoreDiagnostics [code] Ignore TypeScript warnings by diagnostic code
  206. -O, --compilerOptions [opts] JSON object to merge with compiler options
  207. --cwd Behave as if invoked within this working directory.
  208. --files Load \`files\`, \`include\` and \`exclude\` from \`tsconfig.json\` on startup
  209. --pretty Use pretty diagnostic formatter (usually enabled by default)
  210. --cwdMode Use current directory instead of <script.ts> for config resolution
  211. --skipProject Skip reading \`tsconfig.json\`
  212. --skipIgnore Skip \`--ignore\` checks
  213. --emit Emit output files into \`.ts-node\` directory
  214. --scope Scope compiler to files within \`scopeDir\`. Anything outside this directory is ignored.
  215. --scopeDir Directory for \`--scope\`
  216. --preferTsExts Prefer importing TypeScript files over JavaScript files
  217. --logError Logs TypeScript errors to stderr instead of throwing exceptions
  218. --noExperimentalReplAwait Disable top-level await in REPL. Equivalent to node's --no-experimental-repl-await
  219. --experimentalSpecifierResolution [node|explicit]
  220. Equivalent to node's --experimental-specifier-resolution
  221. `);
  222. process.exit(0);
  223. }
  224. // Output project information.
  225. if (version === 1) {
  226. console.log(`v${index_1.VERSION}`);
  227. process.exit(0);
  228. }
  229. const cwd = cwdArg ? (0, path_1.resolve)(cwdArg) : process.cwd();
  230. // If ESM is explicitly enabled through the flag, stage3 should be run in a child process
  231. // with the ESM loaders configured.
  232. if (esm)
  233. payload.shouldUseChildProcess = true;
  234. return {
  235. cwd,
  236. };
  237. }
  238. function phase3(payload) {
  239. const { emit, files, pretty, transpileOnly, transpiler, noExperimentalReplAwait, typeCheck, swc, compilerHost, ignore, preferTsExts, logError, scriptMode, cwdMode, project, skipProject, skipIgnore, compiler, ignoreDiagnostics, compilerOptions, argsRequire, scope, scopeDir, esm, experimentalSpecifierResolution, } = payload.parseArgvResult;
  240. const { cwd } = payload.phase2Result;
  241. // NOTE: When we transition to a child process for ESM, the entry-point script determined
  242. // here might not be the one used later in `phase4`. This can happen when we execute the
  243. // original entry-point but then the process forks itself using e.g. `child_process.fork`.
  244. // We will always use the original TS project in forked processes anyway, so it is
  245. // expected and acceptable to retrieve the entry-point information here in `phase2`.
  246. // See: https://github.com/TypeStrong/ts-node/issues/1812.
  247. const { entryPointPath } = getEntryPointInfo(payload);
  248. const preloadedConfig = (0, configuration_1.findAndReadConfig)({
  249. cwd,
  250. emit,
  251. files,
  252. pretty,
  253. transpileOnly: (transpileOnly !== null && transpileOnly !== void 0 ? transpileOnly : transpiler != null) ? true : undefined,
  254. experimentalReplAwait: noExperimentalReplAwait ? false : undefined,
  255. typeCheck,
  256. transpiler,
  257. swc,
  258. compilerHost,
  259. ignore,
  260. logError,
  261. projectSearchDir: getProjectSearchDir(cwd, scriptMode, cwdMode, entryPointPath),
  262. project,
  263. skipProject,
  264. skipIgnore,
  265. compiler,
  266. ignoreDiagnostics,
  267. compilerOptions,
  268. require: argsRequire,
  269. scope,
  270. scopeDir,
  271. preferTsExts,
  272. esm,
  273. experimentalSpecifierResolution: experimentalSpecifierResolution,
  274. });
  275. // If ESM is enabled through the parsed tsconfig, stage4 should be run in a child
  276. // process with the ESM loaders configured.
  277. if (preloadedConfig.options.esm)
  278. payload.shouldUseChildProcess = true;
  279. return { preloadedConfig };
  280. }
  281. /**
  282. * Determines the entry-point information from the argv and phase2 result. This
  283. * method will be invoked in two places:
  284. *
  285. * 1. In phase 3 to be able to find a project from the potential entry-point script.
  286. * 2. In phase 4 to determine the actual entry-point script.
  287. *
  288. * Note that we need to explicitly re-resolve the entry-point information in the final
  289. * stage because the previous stage information could be modified when the bootstrap
  290. * invocation transitioned into a child process for ESM.
  291. *
  292. * Stages before (phase 4) can and will be cached by the child process through the Brotli
  293. * configuration and entry-point information is only reliable in the final phase. More
  294. * details can be found in here: https://github.com/TypeStrong/ts-node/issues/1812.
  295. */
  296. function getEntryPointInfo(state) {
  297. const { code, interactive, restArgs } = state.parseArgvResult;
  298. const { cwd } = state.phase2Result;
  299. const { isCli } = state;
  300. // Figure out which we are executing: piped stdin, --eval, REPL, and/or entrypoint
  301. // This is complicated because node's behavior is complicated
  302. // `node -e code -i ./script.js` ignores -e
  303. const executeEval = code != null && !(interactive && restArgs.length);
  304. const executeEntrypoint = !executeEval && restArgs.length > 0;
  305. const executeRepl = !executeEntrypoint &&
  306. (interactive || (process.stdin.isTTY && !executeEval));
  307. const executeStdin = !executeEval && !executeRepl && !executeEntrypoint;
  308. /**
  309. * Unresolved. May point to a symlink, not realpath. May be missing file extension
  310. * NOTE: resolution relative to cwd option (not `process.cwd()`) is legacy backwards-compat; should be changed in next major: https://github.com/TypeStrong/ts-node/issues/1834
  311. */
  312. const entryPointPath = executeEntrypoint
  313. ? isCli
  314. ? (0, path_1.resolve)(cwd, restArgs[0])
  315. : (0, path_1.resolve)(restArgs[0])
  316. : undefined;
  317. return {
  318. executeEval,
  319. executeEntrypoint,
  320. executeRepl,
  321. executeStdin,
  322. entryPointPath,
  323. };
  324. }
  325. function phase4(payload) {
  326. var _a, _b, _c, _d, _e, _f, _g;
  327. const { isInChildProcess, tsNodeScript } = payload;
  328. const { version, showConfig, restArgs, code, print, argv } = payload.parseArgvResult;
  329. const { cwd } = payload.phase2Result;
  330. const { preloadedConfig } = payload.phase3Result;
  331. const { entryPointPath, executeEntrypoint, executeEval, executeRepl, executeStdin, } = getEntryPointInfo(payload);
  332. let evalStuff;
  333. let replStuff;
  334. let stdinStuff;
  335. let evalAwarePartialHost = undefined;
  336. if (executeEval) {
  337. const state = new repl_1.EvalState((0, path_1.join)(cwd, repl_1.EVAL_FILENAME));
  338. evalStuff = {
  339. state,
  340. repl: (0, repl_1.createRepl)({
  341. state,
  342. composeWithEvalAwarePartialHost: evalAwarePartialHost,
  343. ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl: false,
  344. }),
  345. };
  346. ({ evalAwarePartialHost } = evalStuff.repl);
  347. // Create a local module instance based on `cwd`.
  348. const module = (evalStuff.module = new Module(repl_1.EVAL_NAME));
  349. module.filename = evalStuff.state.path;
  350. module.paths = Module._nodeModulePaths(cwd);
  351. }
  352. if (executeStdin) {
  353. const state = new repl_1.EvalState((0, path_1.join)(cwd, repl_1.STDIN_FILENAME));
  354. stdinStuff = {
  355. state,
  356. repl: (0, repl_1.createRepl)({
  357. state,
  358. composeWithEvalAwarePartialHost: evalAwarePartialHost,
  359. ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl: false,
  360. }),
  361. };
  362. ({ evalAwarePartialHost } = stdinStuff.repl);
  363. // Create a local module instance based on `cwd`.
  364. const module = (stdinStuff.module = new Module(repl_1.STDIN_NAME));
  365. module.filename = stdinStuff.state.path;
  366. module.paths = Module._nodeModulePaths(cwd);
  367. }
  368. if (executeRepl) {
  369. const state = new repl_1.EvalState((0, path_1.join)(cwd, repl_1.REPL_FILENAME));
  370. replStuff = {
  371. state,
  372. repl: (0, repl_1.createRepl)({
  373. state,
  374. composeWithEvalAwarePartialHost: evalAwarePartialHost,
  375. }),
  376. };
  377. ({ evalAwarePartialHost } = replStuff.repl);
  378. }
  379. // Register the TypeScript compiler instance.
  380. const service = (0, index_1.createFromPreloadedConfig)({
  381. // Since this struct may have been marshalled across thread or process boundaries, we must restore
  382. // un-marshall-able values.
  383. ...preloadedConfig,
  384. options: {
  385. ...preloadedConfig.options,
  386. readFile: (_a = evalAwarePartialHost === null || evalAwarePartialHost === void 0 ? void 0 : evalAwarePartialHost.readFile) !== null && _a !== void 0 ? _a : undefined,
  387. fileExists: (_b = evalAwarePartialHost === null || evalAwarePartialHost === void 0 ? void 0 : evalAwarePartialHost.fileExists) !== null && _b !== void 0 ? _b : undefined,
  388. tsTrace: index_1.DEFAULTS.tsTrace,
  389. },
  390. });
  391. (0, index_1.register)(service);
  392. if (isInChildProcess)
  393. require('./child/child-loader').lateBindHooks((0, index_1.createEsmHooks)(service));
  394. // Bind REPL service to ts-node compiler service (chicken-and-egg problem)
  395. replStuff === null || replStuff === void 0 ? void 0 : replStuff.repl.setService(service);
  396. evalStuff === null || evalStuff === void 0 ? void 0 : evalStuff.repl.setService(service);
  397. stdinStuff === null || stdinStuff === void 0 ? void 0 : stdinStuff.repl.setService(service);
  398. // Output project information.
  399. if (version === 2) {
  400. console.log(`ts-node v${index_1.VERSION}`);
  401. console.log(`node ${process.version}`);
  402. console.log(`compiler v${service.ts.version}`);
  403. process.exit(0);
  404. }
  405. if (version >= 3) {
  406. console.log(`ts-node v${index_1.VERSION} ${(0, path_1.dirname)(__dirname)}`);
  407. console.log(`node ${process.version}`);
  408. console.log(`compiler v${service.ts.version} ${(_c = service.compilerPath) !== null && _c !== void 0 ? _c : ''}`);
  409. process.exit(0);
  410. }
  411. if (showConfig) {
  412. const ts = service.ts;
  413. if (typeof ts.convertToTSConfig !== 'function') {
  414. console.error('Error: --showConfig requires a typescript versions >=3.2 that support --showConfig');
  415. process.exit(1);
  416. }
  417. let moduleTypes = undefined;
  418. if (service.options.moduleTypes) {
  419. // Assumption: this codepath requires CLI invocation, so moduleTypes must have come from a tsconfig, not API.
  420. const showRelativeTo = (0, path_1.dirname)(service.configFilePath);
  421. moduleTypes = {};
  422. for (const [key, value] of Object.entries(service.options.moduleTypes)) {
  423. moduleTypes[(0, path_1.relative)(showRelativeTo, (0, path_1.resolve)((_d = service.options.optionBasePaths) === null || _d === void 0 ? void 0 : _d.moduleTypes, key))] = value;
  424. }
  425. }
  426. const json = {
  427. ['ts-node']: {
  428. ...service.options,
  429. require: ((_e = service.options.require) === null || _e === void 0 ? void 0 : _e.length)
  430. ? service.options.require
  431. : undefined,
  432. moduleTypes,
  433. optionBasePaths: undefined,
  434. compilerOptions: undefined,
  435. project: (_f = service.configFilePath) !== null && _f !== void 0 ? _f : service.options.project,
  436. },
  437. ...ts.convertToTSConfig(service.config, (_g = service.configFilePath) !== null && _g !== void 0 ? _g : (0, path_1.join)(cwd, 'ts-node-implicit-tsconfig.json'), service.ts.sys),
  438. };
  439. console.log(
  440. // Assumes that all configuration options which can possibly be specified via the CLI are JSON-compatible.
  441. // If, in the future, we must log functions, for example readFile and fileExists, then we can implement a JSON
  442. // replacer function.
  443. JSON.stringify(json, null, 2));
  444. process.exit(0);
  445. }
  446. // Prepend `ts-node` arguments to CLI for child processes.
  447. process.execArgv.push(tsNodeScript, ...argv.slice(2, argv.length - restArgs.length));
  448. // TODO this comes from BootstrapState
  449. process.argv = [process.argv[1]]
  450. .concat(executeEntrypoint ? [entryPointPath] : [])
  451. .concat(restArgs.slice(executeEntrypoint ? 1 : 0));
  452. // Execute the main contents (either eval, script or piped).
  453. if (executeEntrypoint) {
  454. if (payload.isInChildProcess &&
  455. (0, util_2.versionGteLt)(process.versions.node, '18.6.0')) {
  456. // HACK workaround node regression
  457. require('../dist-raw/runmain-hack.js').run(entryPointPath);
  458. }
  459. else {
  460. Module.runMain();
  461. }
  462. }
  463. else {
  464. // Note: eval and repl may both run, but never with stdin.
  465. // If stdin runs, eval and repl will not.
  466. if (executeEval) {
  467. (0, node_internal_modules_cjs_helpers_1.addBuiltinLibsToObject)(global);
  468. evalAndExitOnTsError(evalStuff.repl, evalStuff.module, code, print, 'eval');
  469. }
  470. if (executeRepl) {
  471. replStuff.repl.start();
  472. }
  473. if (executeStdin) {
  474. let buffer = code || '';
  475. process.stdin.on('data', (chunk) => (buffer += chunk));
  476. process.stdin.on('end', () => {
  477. evalAndExitOnTsError(stdinStuff.repl, stdinStuff.module, buffer,
  478. // `echo 123 | node -p` still prints 123
  479. print, 'stdin');
  480. });
  481. }
  482. }
  483. }
  484. /**
  485. * Get project search path from args.
  486. */
  487. function getProjectSearchDir(cwd, scriptMode, cwdMode, scriptPath) {
  488. // Validate `--script-mode` / `--cwd-mode` / `--cwd` usage is correct.
  489. if (scriptMode && cwdMode) {
  490. throw new TypeError('--cwd-mode cannot be combined with --script-mode');
  491. }
  492. if (scriptMode && !scriptPath) {
  493. throw new TypeError('--script-mode must be used with a script name, e.g. `ts-node --script-mode <script.ts>`');
  494. }
  495. const doScriptMode = scriptMode === true ? true : cwdMode === true ? false : !!scriptPath;
  496. if (doScriptMode) {
  497. // Use node's own resolution behavior to ensure we follow symlinks.
  498. // scriptPath may omit file extension or point to a directory with or without package.json.
  499. // This happens before we are registered, so we tell node's resolver to consider ts, tsx, and jsx files.
  500. // In extremely rare cases, is is technically possible to resolve the wrong directory,
  501. // because we do not yet know preferTsExts, jsx, nor allowJs.
  502. // See also, justification why this will not happen in real-world situations:
  503. // https://github.com/TypeStrong/ts-node/pull/1009#issuecomment-613017081
  504. const exts = ['.js', '.jsx', '.ts', '.tsx'];
  505. const extsTemporarilyInstalled = [];
  506. for (const ext of exts) {
  507. if (!(0, util_2.hasOwnProperty)(require.extensions, ext)) {
  508. extsTemporarilyInstalled.push(ext);
  509. require.extensions[ext] = function () { };
  510. }
  511. }
  512. try {
  513. return (0, path_1.dirname)(requireResolveNonCached(scriptPath));
  514. }
  515. finally {
  516. for (const ext of extsTemporarilyInstalled) {
  517. delete require.extensions[ext];
  518. }
  519. }
  520. }
  521. return cwd;
  522. }
  523. const guaranteedNonexistentDirectoryPrefix = (0, path_1.resolve)(__dirname, 'doesnotexist');
  524. let guaranteedNonexistentDirectorySuffix = 0;
  525. /**
  526. * require.resolve an absolute path, tricking node into *not* caching the results.
  527. * Necessary so that we do not pollute require.resolve cache prior to installing require.extensions
  528. *
  529. * Is a terrible hack, because node does not expose the necessary cache invalidation APIs
  530. * https://stackoverflow.com/questions/59865584/how-to-invalidate-cached-require-resolve-results
  531. */
  532. function requireResolveNonCached(absoluteModuleSpecifier) {
  533. // node <= 12.1.x fallback: The trick below triggers a node bug on old versions.
  534. // On these old versions, pollute the require cache instead. This is a deliberate
  535. // ts-node limitation that will *rarely* manifest, and will not matter once node 12
  536. // is end-of-life'd on 2022-04-30
  537. const isSupportedNodeVersion = (0, util_2.versionGteLt)(process.versions.node, '12.2.0');
  538. if (!isSupportedNodeVersion)
  539. return require.resolve(absoluteModuleSpecifier);
  540. const { dir, base } = (0, path_1.parse)(absoluteModuleSpecifier);
  541. const relativeModuleSpecifier = `./${base}`;
  542. const req = (0, util_2.createRequire)((0, path_1.join)(dir, 'imaginaryUncacheableRequireResolveScript'));
  543. return req.resolve(relativeModuleSpecifier, {
  544. paths: [
  545. `${guaranteedNonexistentDirectoryPrefix}${guaranteedNonexistentDirectorySuffix++}`,
  546. ...(req.resolve.paths(relativeModuleSpecifier) || []),
  547. ],
  548. });
  549. }
  550. /**
  551. * Evaluate an [eval] or [stdin] script
  552. */
  553. function evalAndExitOnTsError(replService, module, code, isPrinted, filenameAndDirname) {
  554. let result;
  555. (0, repl_1.setupContext)(global, module, filenameAndDirname);
  556. try {
  557. result = replService.evalCode(code);
  558. }
  559. catch (error) {
  560. if (error instanceof index_1.TSError) {
  561. console.error(error);
  562. process.exit(1);
  563. }
  564. throw error;
  565. }
  566. if (isPrinted) {
  567. console.log(typeof result === 'string'
  568. ? result
  569. : (0, util_1.inspect)(result, { colors: process.stdout.isTTY }));
  570. }
  571. }
  572. if (require.main === module) {
  573. main();
  574. }
  575. //# sourceMappingURL=bin.js.map