1
1
'use strict' ;
2
2
3
3
const {
4
+ ArrayPrototypeJoin,
5
+ ArrayPrototypeSplice,
4
6
RegExpPrototypeExec,
7
+ StringPrototypeSplit,
5
8
Symbol,
6
9
globalThis,
7
10
} = primordials ;
@@ -17,6 +20,7 @@ const {
17
20
} = require ( 'internal/errors' ) ;
18
21
const { pathToFileURL } = require ( 'internal/url' ) ;
19
22
const { exitCodes : { kGenericUserError } } = internalBinding ( 'errors' ) ;
23
+ const { stripTypeScriptModuleTypes } = require ( 'internal/modules/typescript' ) ;
20
24
21
25
const {
22
26
executionAsyncId,
@@ -84,7 +88,7 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) {
84
88
if ( getOptionValue ( '--experimental-detect-module' ) &&
85
89
getOptionValue ( '--input-type' ) === '' &&
86
90
containsModuleSyntax ( body , name , null , 'no CJS variables' ) ) {
87
- return evalModuleEntryPoint ( body , print ) ;
91
+ return evalTypeScriptModuleEntryPoint ( body , print ) ;
88
92
}
89
93
90
94
const runScript = ( ) => {
@@ -238,10 +242,114 @@ function readStdin(callback) {
238
242
} ) ;
239
243
}
240
244
245
+ /**
246
+ *
247
+ * Adds the TS message to the error stack
248
+ * At the 3rd line of the stack, the message is added
249
+ * @param {Error } originalStack the stack to decorate
250
+ * @param {string } newMessage the message to add to the error stack
251
+ * @returns {void }
252
+ */
253
+ function decorateCJSErrorWithTSMessage ( originalStack , newMessage ) {
254
+ const lines = StringPrototypeSplit ( originalStack , '\n' ) ;
255
+ ArrayPrototypeSplice ( lines , 3 , 0 , newMessage ) ;
256
+ return ArrayPrototypeJoin ( lines , '\n' ) ;
257
+ }
258
+
259
+ /**
260
+ *
261
+ * Wrapper of evalScript
262
+ *
263
+ * This function wraps the evaluation of the source code in a try-catch block.
264
+ * If the source code fails to be evaluated, it will retry evaluating the source code
265
+ * with the TypeScript parser.
266
+ *
267
+ * If the source code fails to be evaluated with the TypeScript parser,
268
+ * it will rethrow the original error, adding the TypeScript error message to the stack.
269
+ *
270
+ * This way we don't change the behavior of the code, but we provide a better error message
271
+ * in case of a typescript error.
272
+ */
273
+ function evalTypeScript ( name , source , breakFirstLine , print , shouldLoadESM = false ) {
274
+ try {
275
+ evalScript ( name , source , breakFirstLine , print , shouldLoadESM ) ;
276
+ } catch ( originalError ) {
277
+ try {
278
+ const strippedSource = stripTypeScriptModuleTypes ( source , name , false ) ;
279
+ evalScript ( name , strippedSource , breakFirstLine , print , shouldLoadESM ) ;
280
+ } catch ( tsError ) {
281
+ if ( tsError . code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ) {
282
+ originalError . stack = decorateCJSErrorWithTSMessage ( originalError . stack , tsError . message ) ;
283
+ }
284
+ throw originalError ;
285
+ }
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Wrapper of evalModuleEntryPoint
291
+ *
292
+ * This function wraps the evaluation of the source code in a try-catch block.
293
+ * If the source code fails to be evaluated, it will retry evaluating the source code
294
+ * with the TypeScript parser.
295
+ *
296
+ */
297
+ function evalTypeScriptModuleEntryPoint ( source , print ) {
298
+ if ( print ) {
299
+ throw new ERR_EVAL_ESM_CANNOT_PRINT ( ) ;
300
+ }
301
+
302
+ RegExpPrototypeExec ( / ^ / , '' ) ; // Necessary to reset RegExp statics before user code runs.
303
+
304
+ return require ( 'internal/modules/run_main' ) . runEntryPointWithESMLoader (
305
+ async ( loader ) => {
306
+ try {
307
+ // Await here to catch the error and rethrow it with the typescript error message
308
+ return await loader . eval ( source , getEvalModuleUrl ( ) , true ) ;
309
+ } catch ( originalError ) {
310
+ try {
311
+ const url = getEvalModuleUrl ( ) ;
312
+ const strippedSource = stripTypeScriptModuleTypes ( source , url , false ) ;
313
+ return loader . eval ( strippedSource , url , true ) ;
314
+ } catch ( tsError ) {
315
+ if ( tsError . code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ) {
316
+ originalError . stack = `${ tsError . message } \n\n${ originalError . stack } ` ;
317
+ }
318
+ throw originalError ;
319
+ }
320
+ }
321
+ } ,
322
+ ) ;
323
+ } ;
324
+
325
+ /**
326
+ *
327
+ * Function used to shortcut when `--input-type=module-typescript` is set
328
+ * @param {string } source
329
+ * @param {boolean } print
330
+ */
331
+ function parseAndEvalModuleTypeScript ( source , print ) {
332
+ const strippedSource = stripTypeScriptModuleTypes ( source , getEvalModuleUrl ( ) , false ) ;
333
+ evalModuleEntryPoint ( strippedSource , print ) ;
334
+ }
335
+
336
+ /**
337
+ * Function used to shortcut when `--input-type=commonjs-typescript` is set
338
+ * See evalScript signature
339
+ */
340
+ function parseAndEvalCommonjsTypeScript ( name , source , breakFirstLine , print , shouldLoadESM = false ) {
341
+ const strippedSource = stripTypeScriptModuleTypes ( source , getEvalModuleUrl ( ) , false ) ;
342
+ evalScript ( name , strippedSource , breakFirstLine , print , shouldLoadESM ) ;
343
+ }
344
+
241
345
module . exports = {
346
+ parseAndEvalCommonjsTypeScript,
347
+ parseAndEvalModuleTypeScript,
242
348
readStdin,
243
349
tryGetCwd,
350
+ evalTypeScriptModuleEntryPoint,
244
351
evalModuleEntryPoint,
352
+ evalTypeScript,
245
353
evalScript,
246
354
onGlobalUncaughtException : createOnGlobalUncaughtException ( ) ,
247
355
setUncaughtExceptionCaptureCallback,
0 commit comments