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,
@@ -32,6 +36,7 @@ const { getOptionValue } = require('internal/options');
32
36
const {
33
37
makeContextifyScript, runScriptInThisContext,
34
38
} = require ( 'internal/vm' ) ;
39
+ const { emitExperimentalWarning } = require ( 'internal/util' ) ;
35
40
// shouldAbortOnUncaughtToggle is a typed array for faster
36
41
// communication with JS.
37
42
const { shouldAbortOnUncaughtToggle } = internalBinding ( 'util' ) ;
@@ -84,7 +89,7 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) {
84
89
if ( getOptionValue ( '--experimental-detect-module' ) &&
85
90
getOptionValue ( '--input-type' ) === '' &&
86
91
containsModuleSyntax ( body , name , null , 'no CJS variables' ) ) {
87
- return evalModuleEntryPoint ( body , print ) ;
92
+ return evalTypeScriptModuleEntryPoint ( body , print ) ;
88
93
}
89
94
90
95
const runScript = ( ) => {
@@ -238,10 +243,121 @@ function readStdin(callback) {
238
243
} ) ;
239
244
}
240
245
246
+ /**
247
+ *
248
+ * Adds the TS message to the error stack
249
+ * At the 3rd line of the stack, the message is added
250
+ * @param {Error } originalStack the stack to decorate
251
+ * @param {string } newMessage the message to add to the error stack
252
+ * @returns {void }
253
+ */
254
+ function decorateCJSErrorWithTSMessage ( originalStack , newMessage ) {
255
+ const lines = StringPrototypeSplit ( originalStack , '\n' ) ;
256
+ ArrayPrototypeSplice ( lines , 3 , 0 , newMessage ) ;
257
+ return ArrayPrototypeJoin ( lines , '\n' ) ;
258
+ }
259
+
260
+ /**
261
+ *
262
+ * Wrapper of evalScript
263
+ *
264
+ * This function wraps the evaluation of the source code in a try-catch block.
265
+ * If the source code fails to be evaluated, it will retry evaluating the source code
266
+ * with the TypeScript parser.
267
+ *
268
+ * If the source code fails to be evaluated with the TypeScript parser,
269
+ * it will rethrow the original error, adding the TypeScript error message to the stack.
270
+ *
271
+ * This way we don't change the behavior of the code, but we provide a better error message
272
+ * in case of a typescript error.
273
+ */
274
+ function evalTypeScript ( name , source , breakFirstLine , print , shouldLoadESM = false ) {
275
+ try {
276
+ evalScript ( name , source , breakFirstLine , print , shouldLoadESM ) ;
277
+ } catch ( originalError ) {
278
+ try {
279
+ const strippedSource = stripTypeScriptModuleTypes ( source , name , false ) ;
280
+ evalScript ( name , strippedSource , breakFirstLine , print , shouldLoadESM ) ;
281
+ // Throw the expiramental warning after the code was successfully evaluated.
282
+ emitExperimentalWarning ( 'Type Stripping' ) ;
283
+ } catch ( tsError ) {
284
+ if ( tsError . code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ) {
285
+ originalError . stack = decorateCJSErrorWithTSMessage ( originalError . stack , tsError . message ) ;
286
+ }
287
+ throw originalError ;
288
+ }
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Wrapper of evalModuleEntryPoint
294
+ *
295
+ * This function wraps the evaluation of the source code in a try-catch block.
296
+ * If the source code fails to be evaluated, it will retry evaluating the source code
297
+ * with the TypeScript parser.
298
+ *
299
+ */
300
+ function evalTypeScriptModuleEntryPoint ( source , print ) {
301
+ if ( print ) {
302
+ throw new ERR_EVAL_ESM_CANNOT_PRINT ( ) ;
303
+ }
304
+
305
+ RegExpPrototypeExec ( / ^ / , '' ) ; // Necessary to reset RegExp statics before user code runs.
306
+
307
+ return require ( 'internal/modules/run_main' ) . runEntryPointWithESMLoader (
308
+ async ( loader ) => {
309
+ try {
310
+ // Await here to catch the error and rethrow it with the typescript error message.
311
+ return await loader . eval ( source , getEvalModuleUrl ( ) , true ) ;
312
+ } catch ( originalError ) {
313
+ try {
314
+ const url = getEvalModuleUrl ( ) ;
315
+ const strippedSource = stripTypeScriptModuleTypes ( source , url , false ) ;
316
+ const result = await loader . eval ( strippedSource , url , true ) ;
317
+ // Throw the expiramental warning after the code was successfully evaluated.
318
+ emitExperimentalWarning ( 'Type Stripping' ) ;
319
+ return result ;
320
+ } catch ( tsError ) {
321
+ if ( tsError . code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ) {
322
+ originalError . stack = `${ tsError . message } \n\n${ originalError . stack } ` ;
323
+ }
324
+ throw originalError ;
325
+ }
326
+ }
327
+ } ,
328
+ ) ;
329
+ } ;
330
+
331
+ /**
332
+ *
333
+ * Function used to shortcut when `--input-type=module-typescript` is set.
334
+ * @param {string } source
335
+ * @param {boolean } print
336
+ */
337
+ function parseAndEvalModuleTypeScript ( source , print ) {
338
+ // We know its a TypeScript module, we can safely emit the experimental warning.
339
+ const strippedSource = stripTypeScriptModuleTypes ( source , getEvalModuleUrl ( ) ) ;
340
+ evalModuleEntryPoint ( strippedSource , print ) ;
341
+ }
342
+
343
+ /**
344
+ * Function used to shortcut when `--input-type=commonjs-typescript` is set
345
+ * See evalScript signature
346
+ */
347
+ function parseAndEvalCommonjsTypeScript ( name , source , breakFirstLine , print , shouldLoadESM = false ) {
348
+ // We know its a TypeScript module, we can safely emit the experimental warning.
349
+ const strippedSource = stripTypeScriptModuleTypes ( source , getEvalModuleUrl ( ) ) ;
350
+ evalScript ( name , strippedSource , breakFirstLine , print , shouldLoadESM ) ;
351
+ }
352
+
241
353
module . exports = {
354
+ parseAndEvalCommonjsTypeScript,
355
+ parseAndEvalModuleTypeScript,
242
356
readStdin,
243
357
tryGetCwd,
358
+ evalTypeScriptModuleEntryPoint,
244
359
evalModuleEntryPoint,
360
+ evalTypeScript,
245
361
evalScript,
246
362
onGlobalUncaughtException : createOnGlobalUncaughtException ( ) ,
247
363
setUncaughtExceptionCaptureCallback,
0 commit comments