bin.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #!/usr/bin/env node
  2. "use strict";
  3. Object.defineProperty(exports, "__esModule", { value: true });
  4. var path_1 = require("path");
  5. var repl_1 = require("repl");
  6. var util_1 = require("util");
  7. var arrify = require("arrify");
  8. var Module = require("module");
  9. var minimist = require("minimist");
  10. var diff_1 = require("diff");
  11. var vm_1 = require("vm");
  12. var fs_1 = require("fs");
  13. var index_1 = require("./index");
  14. var argv = minimist(process.argv.slice(2), {
  15. stopEarly: true,
  16. string: ['eval', 'print', 'compiler', 'project', 'ignoreDiagnostics', 'require', 'cacheDirectory', 'ignore'],
  17. boolean: ['help', 'transpileOnly', 'typeCheck', 'version', 'files', 'cache', 'pretty', 'skipProject', 'skipIgnore'],
  18. alias: {
  19. eval: ['e'],
  20. print: ['p'],
  21. require: ['r'],
  22. help: ['h'],
  23. version: ['v'],
  24. typeCheck: ['type-check'],
  25. transpileOnly: ['T', 'transpile-only'],
  26. cacheDirectory: ['cache-directory'],
  27. ignore: ['I'],
  28. project: ['P'],
  29. skipIgnore: ['skip-ignore'],
  30. skipProject: ['skip-project'],
  31. compiler: ['C'],
  32. ignoreDiagnostics: ['D', 'ignore-diagnostics'],
  33. compilerOptions: ['O', 'compiler-options']
  34. },
  35. default: {
  36. cache: index_1.DEFAULTS.cache,
  37. files: index_1.DEFAULTS.files,
  38. pretty: index_1.DEFAULTS.pretty,
  39. typeCheck: index_1.DEFAULTS.typeCheck,
  40. transpileOnly: index_1.DEFAULTS.transpileOnly,
  41. cacheDirectory: index_1.DEFAULTS.cacheDirectory,
  42. ignore: index_1.DEFAULTS.ignore,
  43. project: index_1.DEFAULTS.project,
  44. skipIgnore: index_1.DEFAULTS.skipIgnore,
  45. skipProject: index_1.DEFAULTS.skipProject,
  46. compiler: index_1.DEFAULTS.compiler,
  47. ignoreDiagnostics: index_1.DEFAULTS.ignoreDiagnostics
  48. }
  49. });
  50. if (argv.help) {
  51. console.log("\nUsage: ts-node [options] [ -e script | script.ts ] [arguments]\n\nOptions:\n\n -e, --eval [code] Evaluate code\n -p, --print [code] Evaluate code and print result\n -r, --require [path] Require a node module before execution\n\n -h, --help Print CLI usage\n -v, --version Print module version information\n\n -T, --transpile-only Use TypeScript's faster `transpileModule`\n --cache-directory Configure the output file cache directory\n -I, --ignore [pattern] Override the path patterns to skip compilation\n -P, --project [path] Path to TypeScript JSON project file\n -C, --compiler [name] Specify a custom TypeScript compiler\n -D, --ignoreDiagnostics [code] Ignore TypeScript warnings by diagnostic code\n -O, --compilerOptions [opts] JSON object to merge with compiler options\n\n --files Load files from `tsconfig.json` on startup\n --pretty Use pretty diagnostic formatter\n --no-cache Disable the local TypeScript Node cache\n --skip-project Skip reading `tsconfig.json`\n --skip-ignore Skip `--ignore` checks\n");
  52. process.exit(0);
  53. }
  54. var cwd = process.cwd();
  55. var code = argv.eval === undefined ? argv.print : argv.eval;
  56. var isEval = typeof argv.eval === 'string' || !!argv.print; // Minimist struggles with empty strings.
  57. var isPrinted = argv.print !== undefined;
  58. // Register the TypeScript compiler instance.
  59. var service = index_1.register({
  60. files: argv.files,
  61. pretty: argv.pretty,
  62. typeCheck: argv.typeCheck,
  63. transpileOnly: argv.transpileOnly,
  64. cache: argv.cache,
  65. cacheDirectory: argv.cacheDirectory,
  66. ignore: argv.ignore,
  67. project: argv.project,
  68. skipIgnore: argv.skipIgnore,
  69. skipProject: argv.skipProject,
  70. compiler: argv.compiler,
  71. ignoreDiagnostics: argv.ignoreDiagnostics,
  72. compilerOptions: index_1.parse(argv.compilerOptions) || index_1.DEFAULTS.compilerOptions,
  73. readFile: isEval ? readFileEval : undefined,
  74. fileExists: isEval ? fileExistsEval : undefined
  75. });
  76. // Output project information.
  77. if (argv.version) {
  78. console.log("ts-node v" + index_1.VERSION);
  79. console.log("node " + process.version);
  80. console.log("typescript v" + service.ts.version);
  81. console.log("cache " + JSON.stringify(service.cachedir));
  82. process.exit(0);
  83. }
  84. // Require specified modules before start-up.
  85. Module._preloadModules(arrify(argv.require));
  86. /**
  87. * Eval helpers.
  88. */
  89. var EVAL_FILENAME = "[eval].ts";
  90. var EVAL_PATH = path_1.join(cwd, EVAL_FILENAME);
  91. var EVAL_INSTANCE = { input: '', output: '', version: 0, lines: 0 };
  92. // Execute the main contents (either eval, script or piped).
  93. if (isEval) {
  94. evalAndExit(code, isPrinted);
  95. }
  96. else {
  97. if (argv._.length) {
  98. process.argv = ['node'].concat(path_1.resolve(cwd, argv._[0])).concat(argv._.slice(1));
  99. process.execArgv.unshift(__filename);
  100. Module.runMain();
  101. }
  102. else {
  103. // Piping of execution _only_ occurs when no other script is specified.
  104. if (process.stdin.isTTY) {
  105. startRepl();
  106. }
  107. else {
  108. var code_1 = '';
  109. process.stdin.on('data', function (chunk) { return code_1 += chunk; });
  110. process.stdin.on('end', function () { return evalAndExit(code_1, isPrinted); });
  111. }
  112. }
  113. }
  114. /**
  115. * Evaluate a script.
  116. */
  117. function evalAndExit(code, isPrinted) {
  118. var module = new Module(EVAL_FILENAME);
  119. module.filename = EVAL_FILENAME;
  120. module.paths = Module._nodeModulePaths(cwd);
  121. global.__filename = EVAL_FILENAME;
  122. global.__dirname = cwd;
  123. global.exports = module.exports;
  124. global.module = module;
  125. global.require = module.require.bind(module);
  126. var result;
  127. try {
  128. result = _eval(code);
  129. }
  130. catch (error) {
  131. if (error instanceof index_1.TSError) {
  132. console.error(error.diagnosticText);
  133. process.exit(1);
  134. }
  135. throw error;
  136. }
  137. if (isPrinted) {
  138. console.log(typeof result === 'string' ? result : util_1.inspect(result));
  139. }
  140. }
  141. /**
  142. * Evaluate the code snippet.
  143. */
  144. function _eval(input) {
  145. var lines = EVAL_INSTANCE.lines;
  146. var isCompletion = !/\n$/.test(input);
  147. var undo = appendEval(input);
  148. var output;
  149. try {
  150. output = service.compile(EVAL_INSTANCE.input, EVAL_PATH, -lines);
  151. }
  152. catch (err) {
  153. undo();
  154. throw err;
  155. }
  156. // Use `diff` to check for new JavaScript to execute.
  157. var changes = diff_1.diffLines(EVAL_INSTANCE.output, output);
  158. if (isCompletion) {
  159. undo();
  160. }
  161. else {
  162. EVAL_INSTANCE.output = output;
  163. }
  164. return changes.reduce(function (result, change) {
  165. return change.added ? exec(change.value, EVAL_FILENAME) : result;
  166. }, undefined);
  167. }
  168. /**
  169. * Execute some code.
  170. */
  171. function exec(code, filename) {
  172. var script = new vm_1.Script(code, { filename: filename });
  173. return script.runInThisContext();
  174. }
  175. /**
  176. * Start a CLI REPL.
  177. */
  178. function startRepl() {
  179. var repl = repl_1.start({
  180. prompt: '> ',
  181. input: process.stdin,
  182. output: process.stdout,
  183. terminal: process.stdout.isTTY,
  184. eval: replEval,
  185. useGlobal: true
  186. });
  187. // Bookmark the point where we should reset the REPL state.
  188. var resetEval = appendEval('');
  189. function reset() {
  190. resetEval();
  191. // Hard fix for TypeScript forcing `Object.defineProperty(exports, ...)`.
  192. exec('exports = module.exports', EVAL_FILENAME);
  193. }
  194. reset();
  195. repl.on('reset', reset);
  196. repl.defineCommand('type', {
  197. help: 'Check the type of a TypeScript identifier',
  198. action: function (identifier) {
  199. if (!identifier) {
  200. repl.displayPrompt();
  201. return;
  202. }
  203. var undo = appendEval(identifier);
  204. var _a = service.getTypeInfo(EVAL_INSTANCE.input, EVAL_PATH, EVAL_INSTANCE.input.length), name = _a.name, comment = _a.comment;
  205. undo();
  206. repl.outputStream.write(name + "\n" + (comment ? comment + "\n" : ''));
  207. repl.displayPrompt();
  208. }
  209. });
  210. }
  211. /**
  212. * Eval code from the REPL.
  213. */
  214. function replEval(code, _context, _filename, callback) {
  215. var err;
  216. var result;
  217. // TODO: Figure out how to handle completion here.
  218. if (code === '.scope') {
  219. callback();
  220. return;
  221. }
  222. try {
  223. result = _eval(code);
  224. }
  225. catch (error) {
  226. if (error instanceof index_1.TSError) {
  227. // Support recoverable compilations using >= node 6.
  228. if (repl_1.Recoverable && isRecoverable(error)) {
  229. err = new repl_1.Recoverable(error);
  230. }
  231. else {
  232. console.error(error.diagnosticText);
  233. err = undefined;
  234. }
  235. }
  236. else {
  237. err = error;
  238. }
  239. }
  240. callback(err, result);
  241. }
  242. /**
  243. * Append to the eval instance and return an undo function.
  244. */
  245. function appendEval(input) {
  246. var undoInput = EVAL_INSTANCE.input;
  247. var undoVersion = EVAL_INSTANCE.version;
  248. var undoOutput = EVAL_INSTANCE.output;
  249. var undoLines = EVAL_INSTANCE.lines;
  250. // Handle ASI issues with TypeScript re-evaluation.
  251. if (undoInput.charAt(undoInput.length - 1) === '\n' && /^\s*[\[\(\`]/.test(input) && !/;\s*$/.test(undoInput)) {
  252. EVAL_INSTANCE.input = EVAL_INSTANCE.input.slice(0, -1) + ";\n";
  253. }
  254. EVAL_INSTANCE.input += input;
  255. EVAL_INSTANCE.lines += lineCount(input);
  256. EVAL_INSTANCE.version++;
  257. return function () {
  258. EVAL_INSTANCE.input = undoInput;
  259. EVAL_INSTANCE.output = undoOutput;
  260. EVAL_INSTANCE.version = undoVersion;
  261. EVAL_INSTANCE.lines = undoLines;
  262. };
  263. }
  264. /**
  265. * Count the number of lines.
  266. */
  267. function lineCount(value) {
  268. var count = 0;
  269. for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
  270. var char = value_1[_i];
  271. if (char === '\n') {
  272. count++;
  273. }
  274. }
  275. return count;
  276. }
  277. /**
  278. * Get the file text, checking for eval first.
  279. */
  280. function readFileEval(path) {
  281. if (path === EVAL_PATH)
  282. return EVAL_INSTANCE.input;
  283. try {
  284. return fs_1.readFileSync(path, 'utf8');
  285. }
  286. catch (err) { /* Ignore. */ }
  287. }
  288. /**
  289. * Get whether the file exists.
  290. */
  291. function fileExistsEval(path) {
  292. if (path === EVAL_PATH)
  293. return true;
  294. try {
  295. var stats = fs_1.statSync(path);
  296. return stats.isFile() || stats.isFIFO();
  297. }
  298. catch (err) {
  299. return false;
  300. }
  301. }
  302. var RECOVERY_CODES = new Set([
  303. 1003,
  304. 1005,
  305. 1109,
  306. 1126,
  307. 1160,
  308. 1161,
  309. 2355 // "A function whose declared type is neither 'void' nor 'any' must return a value."
  310. ]);
  311. /**
  312. * Check if a function can recover gracefully.
  313. */
  314. function isRecoverable(error) {
  315. return error.diagnosticCodes.every(function (code) { return RECOVERY_CODES.has(code); });
  316. }
  317. //# sourceMappingURL=bin.js.map