@@ -15,6 +15,7 @@ import * as assert from 'assert';
15
15
import type * as tty from 'tty' ;
16
16
import type * as Module from 'module' ;
17
17
import { builtinModules } from 'module' ;
18
+ import { tsSupportsMtsCtsExts } from './file-extensions' ;
18
19
19
20
// Lazy-loaded.
20
21
let _processTopLevelAwait : ( src : string ) => string | null ;
@@ -43,7 +44,9 @@ export const STDIN_FILENAME = `[stdin].ts`;
43
44
/** @internal */
44
45
export const STDIN_NAME = `[stdin]` ;
45
46
/** @internal */
46
- export const REPL_FILENAME = '<repl>.ts' ;
47
+ export function REPL_FILENAME ( tsVersion : string ) {
48
+ return tsSupportsMtsCtsExts ( tsVersion ) ? '<repl>.cts' : '<repl>.ts' ;
49
+ }
47
50
/** @internal */
48
51
export const REPL_NAME = '<repl>' ;
49
52
@@ -130,6 +133,11 @@ export interface CreateReplOptions {
130
133
ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl ?: boolean ;
131
134
}
132
135
136
+ interface StartReplInternalOptions extends ReplOptions {
137
+ code ?: string ;
138
+ forceToBeModule ?: boolean ;
139
+ }
140
+
133
141
/**
134
142
* Create a ts-node REPL instance.
135
143
*
@@ -148,13 +156,21 @@ export interface CreateReplOptions {
148
156
*/
149
157
export function createRepl ( options : CreateReplOptions = { } ) {
150
158
const { ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl = true } = options ;
151
- let service = options . service ;
152
159
let nodeReplServer : REPLServer ;
153
160
// If `useGlobal` is not true, then REPL creates a context when started.
154
161
// This stores a reference to it or to `global`, whichever is used, after REPL has started.
155
162
let context : Context | undefined ;
156
- const state =
157
- options . state ?? new EvalState ( join ( process . cwd ( ) , REPL_FILENAME ) ) ;
163
+ let state : EvalState ;
164
+ let mustSetStatePath = false ;
165
+ if ( options . state ) {
166
+ state = options . state ;
167
+ } else {
168
+ // Correct path set later
169
+ state = new EvalState ( '' ) ;
170
+ mustSetStatePath = true ;
171
+ }
172
+ let service : Service ;
173
+ if ( options . service ) setService ( options . service ) ;
158
174
const evalAwarePartialHost = createEvalAwarePartialHost (
159
175
state ,
160
176
options . composeWithEvalAwarePartialHost
@@ -167,6 +183,8 @@ export function createRepl(options: CreateReplOptions = {}) {
167
183
? console
168
184
: new Console ( stdout , stderr ) ;
169
185
186
+ const declaredExports = new Set ( ) ;
187
+
170
188
const replService : ReplService = {
171
189
state : options . state ?? new EvalState ( join ( process . cwd ( ) , EVAL_FILENAME ) ) ,
172
190
setService,
@@ -186,6 +204,8 @@ export function createRepl(options: CreateReplOptions = {}) {
186
204
187
205
function setService ( _service : Service ) {
188
206
service = _service ;
207
+ if ( mustSetStatePath )
208
+ state . path = join ( process . cwd ( ) , REPL_FILENAME ( service . ts . version ) ) ;
189
209
if ( ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl ) {
190
210
service . addDiagnosticFilter ( {
191
211
appliesToAllFiles : false ,
@@ -200,7 +220,19 @@ export function createRepl(options: CreateReplOptions = {}) {
200
220
}
201
221
}
202
222
223
+ // Hard fix for TypeScript forcing `Object.defineProperty(exports, ...)`.
224
+ function declareExports ( ) {
225
+ if ( declaredExports . has ( context ) ) return ;
226
+ runInContext (
227
+ 'exports = typeof module === "undefined" ? {} : module.exports;' ,
228
+ state . path ,
229
+ context
230
+ ) ;
231
+ declaredExports . add ( context ) ;
232
+ }
233
+
203
234
function evalCode ( code : string ) {
235
+ declareExports ( ) ;
204
236
const result = appendCompileAndEvalInput ( {
205
237
service : service ! ,
206
238
state,
@@ -218,6 +250,7 @@ export function createRepl(options: CreateReplOptions = {}) {
218
250
context : Context ;
219
251
} ) {
220
252
const { code, enableTopLevelAwait, context } = options ;
253
+ declareExports ( ) ;
221
254
return appendCompileAndEvalInput ( {
222
255
service : service ! ,
223
256
state,
@@ -321,9 +354,7 @@ export function createRepl(options: CreateReplOptions = {}) {
321
354
}
322
355
323
356
// Note: `code` argument is deprecated
324
- function startInternal (
325
- options ?: ReplOptions & { code ?: string ; forceToBeModule ?: boolean }
326
- ) {
357
+ function startInternal ( options ?: StartReplInternalOptions ) {
327
358
const { code, forceToBeModule = true , ...optionsOverride } = options ?? { } ;
328
359
// TODO assert that `service` is set; remove all `service!` non-null assertions
329
360
@@ -362,12 +393,11 @@ export function createRepl(options: CreateReplOptions = {}) {
362
393
363
394
// Bookmark the point where we should reset the REPL state.
364
395
const resetEval = appendToEvalState ( state , '' ) ;
365
-
366
396
function reset ( ) {
367
397
resetEval ( ) ;
368
398
369
- // Hard fix for TypeScript forcing `Object.defineProperty(exports, ...)`.
370
- runInContext ( 'exports = module.exports' , state . path , context ) ;
399
+ declareExports ( ) ;
400
+
371
401
if ( forceToBeModule ) {
372
402
state . input += 'export {};void 0;\n' ;
373
403
}
0 commit comments