11'use strict' ;
22
33const {
4+ ArrayPrototypeJoin,
5+ ArrayPrototypeSplice,
46 RegExpPrototypeExec,
7+ StringPrototypeSplit,
58 Symbol,
69 globalThis,
710} = primordials ;
@@ -17,6 +20,7 @@ const {
1720} = require ( 'internal/errors' ) ;
1821const { pathToFileURL } = require ( 'internal/url' ) ;
1922const { exitCodes : { kGenericUserError } } = internalBinding ( 'errors' ) ;
23+ const { stripTypeScriptModuleTypes } = require ( 'internal/modules/typescript' ) ;
2024
2125const {
2226 executionAsyncId,
@@ -32,6 +36,7 @@ const { getOptionValue } = require('internal/options');
3236const {
3337 makeContextifyScript, runScriptInThisContext,
3438} = require ( 'internal/vm' ) ;
39+ const { emitExperimentalWarning } = require ( 'internal/util' ) ;
3540// shouldAbortOnUncaughtToggle is a typed array for faster
3641// communication with JS.
3742const { shouldAbortOnUncaughtToggle } = internalBinding ( 'util' ) ;
@@ -84,7 +89,10 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) {
8489 if ( getOptionValue ( '--experimental-detect-module' ) &&
8590 getOptionValue ( '--input-type' ) === '' &&
8691 containsModuleSyntax ( body , name , null , 'no CJS variables' ) ) {
87- return evalModuleEntryPoint ( body , print ) ;
92+ if ( getOptionValue ( '--experimental-strip-types' ) ) {
93+ return evalTypeScriptModuleEntryPoint ( body , print ) ;
94+ }
95+ return evalModuleEntryPoint ( body , print ) ;
8896 }
8997
9098 const runScript = ( ) => {
@@ -238,10 +246,121 @@ function readStdin(callback) {
238246 } ) ;
239247}
240248
249+ /**
250+ *
251+ * Adds the TS message to the error stack
252+ * At the 3rd line of the stack, the message is added
253+ * @param {Error } originalStack the stack to decorate
254+ * @param {string } newMessage the message to add to the error stack
255+ * @returns {void }
256+ */
257+ function decorateCJSErrorWithTSMessage ( originalStack , newMessage ) {
258+ const lines = StringPrototypeSplit ( originalStack , '\n' ) ;
259+ ArrayPrototypeSplice ( lines , 3 , 0 , newMessage ) ;
260+ return ArrayPrototypeJoin ( lines , '\n' ) ;
261+ }
262+
263+ /**
264+ *
265+ * Wrapper of evalScript
266+ *
267+ * This function wraps the evaluation of the source code in a try-catch block.
268+ * If the source code fails to be evaluated, it will retry evaluating the source code
269+ * with the TypeScript parser.
270+ *
271+ * If the source code fails to be evaluated with the TypeScript parser,
272+ * it will rethrow the original error, adding the TypeScript error message to the stack.
273+ *
274+ * This way we don't change the behavior of the code, but we provide a better error message
275+ * in case of a typescript error.
276+ */
277+ function evalTypeScript ( name , source , breakFirstLine , print , shouldLoadESM = false ) {
278+ try {
279+ evalScript ( name , source , breakFirstLine , print , shouldLoadESM ) ;
280+ } catch ( originalError ) {
281+ try {
282+ const strippedSource = stripTypeScriptModuleTypes ( source , name , false ) ;
283+ evalScript ( name , strippedSource , breakFirstLine , print , shouldLoadESM ) ;
284+ // Emit the experimental warning after the code was successfully evaluated.
285+ emitExperimentalWarning ( 'Type Stripping' ) ;
286+ } catch ( tsError ) {
287+ if ( tsError . code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ) {
288+ originalError . stack = decorateCJSErrorWithTSMessage ( originalError . stack , tsError . message ) ;
289+ }
290+ throw originalError ;
291+ }
292+ }
293+ }
294+
295+ /**
296+ * Wrapper of evalModuleEntryPoint
297+ *
298+ * This function wraps the evaluation of the source code in a try-catch block.
299+ * If the source code fails to be evaluated, it will retry evaluating the source code
300+ * with the TypeScript parser.
301+ *
302+ */
303+ function evalTypeScriptModuleEntryPoint ( source , print ) {
304+ if ( print ) {
305+ throw new ERR_EVAL_ESM_CANNOT_PRINT ( ) ;
306+ }
307+
308+ RegExpPrototypeExec ( / ^ / , '' ) ; // Necessary to reset RegExp statics before user code runs.
309+
310+ return require ( 'internal/modules/run_main' ) . runEntryPointWithESMLoader (
311+ async ( loader ) => {
312+ try {
313+ // Await here to catch the error and rethrow it with the typescript error message.
314+ return await loader . eval ( source , getEvalModuleUrl ( ) , true ) ;
315+ } catch ( originalError ) {
316+ try {
317+ const url = getEvalModuleUrl ( ) ;
318+ const strippedSource = stripTypeScriptModuleTypes ( source , url , false ) ;
319+ const result = await loader . eval ( strippedSource , url , true ) ;
320+ // Emit the experimental warning after the code was successfully evaluated.
321+ emitExperimentalWarning ( 'Type Stripping' ) ;
322+ return result ;
323+ } catch ( tsError ) {
324+ if ( tsError . code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ) {
325+ originalError . stack = `${ tsError . message } \n\n${ originalError . stack } ` ;
326+ }
327+ throw originalError ;
328+ }
329+ }
330+ } ,
331+ ) ;
332+ } ;
333+
334+ /**
335+ *
336+ * Function used to shortcut when `--input-type=module-typescript` is set.
337+ * @param {string } source
338+ * @param {boolean } print
339+ */
340+ function parseAndEvalModuleTypeScript ( source , print ) {
341+ // We know its a TypeScript module, we can safely emit the experimental warning.
342+ const strippedSource = stripTypeScriptModuleTypes ( source , getEvalModuleUrl ( ) ) ;
343+ evalModuleEntryPoint ( strippedSource , print ) ;
344+ }
345+
346+ /**
347+ * Function used to shortcut when `--input-type=commonjs-typescript` is set
348+ * See evalScript signature
349+ */
350+ function parseAndEvalCommonjsTypeScript ( name , source , breakFirstLine , print , shouldLoadESM = false ) {
351+ // We know its a TypeScript module, we can safely emit the experimental warning.
352+ const strippedSource = stripTypeScriptModuleTypes ( source , getEvalModuleUrl ( ) ) ;
353+ evalScript ( name , strippedSource , breakFirstLine , print , shouldLoadESM ) ;
354+ }
355+
241356module . exports = {
357+ parseAndEvalCommonjsTypeScript,
358+ parseAndEvalModuleTypeScript,
242359 readStdin,
243360 tryGetCwd,
361+ evalTypeScriptModuleEntryPoint,
244362 evalModuleEntryPoint,
363+ evalTypeScript,
245364 evalScript,
246365 onGlobalUncaughtException : createOnGlobalUncaughtException ( ) ,
247366 setUncaughtExceptionCaptureCallback,
0 commit comments