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,6 +89,9 @@ 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' ) ) {
92
+ if ( getOptionValue ( '--experimental-strip-types' ) ) {
93
+ return evalTypeScriptModuleEntryPoint ( body , print ) ;
94
+ }
87
95
return evalModuleEntryPoint ( body , print ) ;
88
96
}
89
97
@@ -238,10 +246,120 @@ function readStdin(callback) {
238
246
} ) ;
239
247
}
240
248
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
+
241
356
module . exports = {
357
+ parseAndEvalCommonjsTypeScript,
358
+ parseAndEvalModuleTypeScript,
242
359
readStdin,
243
360
tryGetCwd,
244
361
evalModuleEntryPoint,
362
+ evalTypeScript,
245
363
evalScript,
246
364
onGlobalUncaughtException : createOnGlobalUncaughtException ( ) ,
247
365
setUncaughtExceptionCaptureCallback,
0 commit comments