@@ -15,6 +15,7 @@ import * as assert from 'assert';
1515import type * as tty from 'tty' ;
1616import type * as Module from 'module' ;
1717import { builtinModules } from 'module' ;
18+ import { tsSupportsMtsCtsExts } from './file-extensions' ;
1819
1920// Lazy-loaded.
2021let _processTopLevelAwait : ( src : string ) => string | null ;
@@ -43,7 +44,9 @@ export const STDIN_FILENAME = `[stdin].ts`;
4344/** @internal */
4445export const STDIN_NAME = `[stdin]` ;
4546/** @internal */
46- export const REPL_FILENAME = '<repl>.ts' ;
47+ export function REPL_FILENAME ( tsVersion : string ) {
48+ return tsSupportsMtsCtsExts ( tsVersion ) ? '<repl>.cts' : '<repl>.ts' ;
49+ }
4750/** @internal */
4851export const REPL_NAME = '<repl>' ;
4952
@@ -130,6 +133,11 @@ export interface CreateReplOptions {
130133 ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl ?: boolean ;
131134}
132135
136+ interface StartReplInternalOptions extends ReplOptions {
137+ code ?: string ;
138+ forceToBeModule ?: boolean ;
139+ }
140+
133141/**
134142 * Create a ts-node REPL instance.
135143 *
@@ -148,13 +156,21 @@ export interface CreateReplOptions {
148156 */
149157export function createRepl ( options : CreateReplOptions = { } ) {
150158 const { ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl = true } = options ;
151- let service = options . service ;
152159 let nodeReplServer : REPLServer ;
153160 // If `useGlobal` is not true, then REPL creates a context when started.
154161 // This stores a reference to it or to `global`, whichever is used, after REPL has started.
155162 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 ) ;
158174 const evalAwarePartialHost = createEvalAwarePartialHost (
159175 state ,
160176 options . composeWithEvalAwarePartialHost
@@ -167,6 +183,8 @@ export function createRepl(options: CreateReplOptions = {}) {
167183 ? console
168184 : new Console ( stdout , stderr ) ;
169185
186+ const declaredExports = new Set ( ) ;
187+
170188 const replService : ReplService = {
171189 state : options . state ?? new EvalState ( join ( process . cwd ( ) , EVAL_FILENAME ) ) ,
172190 setService,
@@ -186,6 +204,8 @@ export function createRepl(options: CreateReplOptions = {}) {
186204
187205 function setService ( _service : Service ) {
188206 service = _service ;
207+ if ( mustSetStatePath )
208+ state . path = join ( process . cwd ( ) , REPL_FILENAME ( service . ts . version ) ) ;
189209 if ( ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl ) {
190210 service . addDiagnosticFilter ( {
191211 appliesToAllFiles : false ,
@@ -200,7 +220,19 @@ export function createRepl(options: CreateReplOptions = {}) {
200220 }
201221 }
202222
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+
203234 function evalCode ( code : string ) {
235+ declareExports ( ) ;
204236 const result = appendCompileAndEvalInput ( {
205237 service : service ! ,
206238 state,
@@ -218,6 +250,7 @@ export function createRepl(options: CreateReplOptions = {}) {
218250 context : Context ;
219251 } ) {
220252 const { code, enableTopLevelAwait, context } = options ;
253+ declareExports ( ) ;
221254 return appendCompileAndEvalInput ( {
222255 service : service ! ,
223256 state,
@@ -321,9 +354,7 @@ export function createRepl(options: CreateReplOptions = {}) {
321354 }
322355
323356 // Note: `code` argument is deprecated
324- function startInternal (
325- options ?: ReplOptions & { code ?: string ; forceToBeModule ?: boolean }
326- ) {
357+ function startInternal ( options ?: StartReplInternalOptions ) {
327358 const { code, forceToBeModule = true , ...optionsOverride } = options ?? { } ;
328359 // TODO assert that `service` is set; remove all `service!` non-null assertions
329360
@@ -362,12 +393,11 @@ export function createRepl(options: CreateReplOptions = {}) {
362393
363394 // Bookmark the point where we should reset the REPL state.
364395 const resetEval = appendToEvalState ( state , '' ) ;
365-
366396 function reset ( ) {
367397 resetEval ( ) ;
368398
369- // Hard fix for TypeScript forcing `Object.defineProperty(exports, ...)`.
370- runInContext ( 'exports = module.exports' , state . path , context ) ;
399+ declareExports ( ) ;
400+
371401 if ( forceToBeModule ) {
372402 state . input += 'export {};void 0;\n' ;
373403 }
0 commit comments