From 6bf166924b142609ca8e0d1b95611584b2b3081d Mon Sep 17 00:00:00 2001 From: Marco Ippolito Date: Wed, 25 Dec 2024 09:56:16 +0100 Subject: [PATCH] lib: add typescript support to STDIN eval --- doc/api/typescript.md | 4 +- lib/internal/main/eval_stdin.js | 32 +++- test/fixtures/eval/stdin_typescript.js | 38 ++++ test/fixtures/eval/stdin_typescript.snapshot | 191 +++++++++++++++++++ test/parallel/test-node-output-eval.mjs | 1 + 5 files changed, 258 insertions(+), 8 deletions(-) create mode 100644 test/fixtures/eval/stdin_typescript.js create mode 100644 test/fixtures/eval/stdin_typescript.snapshot diff --git a/doc/api/typescript.md b/doc/api/typescript.md index d2680670a5f316..4d90f5c285f525 100644 --- a/doc/api/typescript.md +++ b/doc/api/typescript.md @@ -153,10 +153,10 @@ import { fn, FnParams } from './fn.ts'; ### Non-file forms of input -Type stripping can be enabled for `--eval`. The module system +Type stripping can be enabled for `--eval` and STDIN. The module system will be determined by `--input-type`, as it is for JavaScript. -TypeScript syntax is unsupported in the REPL, STDIN input, `--print`, `--check`, and +TypeScript syntax is unsupported in the REPL, `--check`, and `inspect`. ### Source maps diff --git a/lib/internal/main/eval_stdin.js b/lib/internal/main/eval_stdin.js index 2fd685dd6afcfa..b06bfa8c2a7640 100644 --- a/lib/internal/main/eval_stdin.js +++ b/lib/internal/main/eval_stdin.js @@ -11,6 +11,9 @@ const { getOptionValue } = require('internal/options'); const { evalModuleEntryPoint, + evalTypeScript, + parseAndEvalCommonjsTypeScript, + parseAndEvalModuleTypeScript, evalScript, readStdin, } = require('internal/process/execution'); @@ -25,13 +28,30 @@ readStdin((code) => { const print = getOptionValue('--print'); const shouldLoadESM = getOptionValue('--import').length > 0; - if (getOptionValue('--input-type') === 'module') { + const inputType = getOptionValue('--input-type'); + const tsEnabled = getOptionValue('--experimental-strip-types'); + if (inputType === 'module') { evalModuleEntryPoint(code, print); + } else if (inputType === 'module-typescript' && tsEnabled) { + parseAndEvalModuleTypeScript(code, print); } else { - evalScript('[stdin]', - code, - getOptionValue('--inspect-brk'), - print, - shouldLoadESM); + + let evalFunction; + if (inputType === 'commonjs') { + evalFunction = evalScript; + } else if (inputType === 'commonjs-typescript' && tsEnabled) { + evalFunction = parseAndEvalCommonjsTypeScript; + } else if (tsEnabled) { + evalFunction = evalTypeScript; + } else { + // Default to commonjs. + evalFunction = evalScript; + } + + evalFunction('[stdin]', + code, + getOptionValue('--inspect-brk'), + print, + shouldLoadESM); } }); diff --git a/test/fixtures/eval/stdin_typescript.js b/test/fixtures/eval/stdin_typescript.js new file mode 100644 index 00000000000000..360f28f2c6353d --- /dev/null +++ b/test/fixtures/eval/stdin_typescript.js @@ -0,0 +1,38 @@ +'use strict'; + +require('../../common'); + +const spawn = require('child_process').spawn; + +function run(cmd, strict, cb) { + const args = ['--experimental-strip-types', '--disable-warning=ExperimentalWarning']; + if (strict) args.push('--use_strict'); + args.push('-p'); + const child = spawn(process.execPath, args); + child.stdout.pipe(process.stdout); + child.stderr.pipe(process.stdout); + child.stdin.end(cmd); + child.on('close', cb); +} + +const queue = + [ + 'enum Foo{};', + 'throw new SyntaxError("hello")', + 'const foo;', + 'let x: number = 100;x;', + 'const foo: string = 10;', + 'function foo(){};foo(1);', + 'interface Foo{};const foo;', + 'function foo(){ await Promise.resolve(1)};', + ]; + +function go() { + const c = queue.shift(); + if (!c) return console.log('done'); + run(c, false, function () { + run(c, true, go); + }); +} + +go(); diff --git a/test/fixtures/eval/stdin_typescript.snapshot b/test/fixtures/eval/stdin_typescript.snapshot new file mode 100644 index 00000000000000..a7c98ac932e8b0 --- /dev/null +++ b/test/fixtures/eval/stdin_typescript.snapshot @@ -0,0 +1,191 @@ +[stdin]:1 +enum Foo{}; +^^^^ + x TypeScript enum is not supported in strip-only mode + ,---- + 1 | enum Foo{}; + : ^^^^^^^^^^ + `---- + + +SyntaxError: Unexpected reserved word + + + + + + + + + +Node.js * +[stdin]:1 +enum Foo{}; +^^^^ + x TypeScript enum is not supported in strip-only mode + ,---- + 1 | enum Foo{}; + : ^^^^^^^^^^ + `---- + + +SyntaxError: Unexpected reserved word + + + + + + + + + +Node.js * +[stdin]:1 +throw new SyntaxError("hello") +^ + +SyntaxError: hello + + + + + + + + + + + +Node.js * +[stdin]:1 +throw new SyntaxError("hello") +^ + +SyntaxError: hello + + + + + + + + + + + +Node.js * +[stdin]:1 +const foo; + ^^^ + +SyntaxError: Missing initializer in const declaration + + + + + + + + + +Node.js * +[stdin]:1 +const foo; + ^^^ + +SyntaxError: Missing initializer in const declaration + + + + + + + + + +Node.js * +100 +100 +undefined +undefined +false +false +[stdin]:1 + ;const foo; + ^^^ + +SyntaxError: Missing initializer in const declaration + + + + + + + + + +Node.js * +[stdin]:1 + ;const foo; + ^^^ + +SyntaxError: Missing initializer in const declaration + + + + + + + + + +Node.js * +[stdin]:1 +function foo(){ await Promise.resolve(1)}; + ^^^^^ + x await isn't allowed in non-async function + ,---- + 1 | function foo(){ await Promise.resolve(1)}; + : ^^^^^^^ + `---- + + +Caused by: + failed to parse + +SyntaxError: await is only valid in async functions and the top level bodies of modules + + + + + + + + + +Node.js * +[stdin]:1 +function foo(){ await Promise.resolve(1)}; + ^^^^^ + x await isn't allowed in non-async function + ,---- + 1 | function foo(){ await Promise.resolve(1)}; + : ^^^^^^^ + `---- + + +Caused by: + failed to parse + +SyntaxError: await is only valid in async functions and the top level bodies of modules + + + + + + + + + +Node.js * +done diff --git a/test/parallel/test-node-output-eval.mjs b/test/parallel/test-node-output-eval.mjs index 2fa60206e1ea1c..a8bfd730e92cf4 100644 --- a/test/parallel/test-node-output-eval.mjs +++ b/test/parallel/test-node-output-eval.mjs @@ -24,6 +24,7 @@ describe('eval output', { concurrency: true }, () => { const tests = [ { name: 'eval/eval_messages.js' }, { name: 'eval/stdin_messages.js' }, + { name: 'eval/stdin_typescript.js' }, ]; for (const { name } of tests) {