Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom node REPL with typescript and ts-node

I want to create a custom node REPL and make it work with typescript. As stated on ts-node documentations

nodeEval

nodeEval(code: string, context: any, _filename: string, callback: (err: null | > Error, result?: any) => any): void

Defined in src/repl.ts:91

eval implementation compatible with node's REPL API

Can be used in advanced scenarios if you want to manually create your own node > REPL instance and delegate eval to this ReplService.

Example:

import {start} from 'repl'; 
const replService: tsNode.ReplService = ...; // assuming you have already created a ts-node ReplService
const nodeRepl = start({eval: replService.eval});

Blockquote

Parameters

code: string

context: any

_filename: string

callback: (err: null | Error, result?: any) => any

(err: null | Error, result?: any): any

Parameters

err: null | Error

Optional result: any

Returns any

Returns void

nodeEval is a member of the ReplService class created with createRepl method. It seems to be compatible with the eval parameter that can be passed down to the start method.

So I wrote this:

import { start } from "repl";
import * as tsnode from "ts-node";

const tsNodeConfig = {
  compilerOptions: {
    target: "ES2017",
    module: "commonjs",
  },
};

tsnode.register({
  compilerOptions: {
    target: "ES2017",
    module: "CommonJS",
  },
});

const tsrepl: tsnode.ReplService = tsnode.createRepl({
  stdin: process.stdin,
  stdout: process.stdout,
});

const { nodeEval } = tsrepl;

tsnode.register(tsNodeConfig);

start({
  prompt: "$  ",
  ignoreUndefined: true,
  eval: nodeEval,
});

I then run the code in the terminal where I created this repl.ts file and run ts-node repl.ts the shell starts, but it gives me this error when I enter any value like let foo = "bar":

Uncaught TypeError: Cannot read properties of undefined (reading 'options')
    at REPLServer.Interface._ttyWrite (node:readline:1216:14)
    at REPLServer.Interface._line (node:readline:864:8)
    at REPLServer.Interface._onLine (node:readline:487:10)
    at REPLServer.emit (node:domain:475:12)
    at REPLServer.emit (node:events:527:28)
    at REPLServer.onLine (node:repl:893:10)
    at REPLServer.runBound [as eval] (node:domain:432:12)
    at bound (node:domain:421:15)
    at REPLServer.nodeEval (/Users/WAW/Documents/Projects/noiz-network-state/node_modules/ts-node/src/repl.ts:262:7)
    at handleError (/Users/WAW/Documents/Projects/noiz-network-state/node_modules/ts-node/src/repl.ts:271:18)
$  

If i pass down the object without the eval parameter, like this

start({
  prompt: "$  ",
  ignoreUndefined: true
});

the repl works as a node repl and it doesn't evaluate typescript code like type foo = string..

any idea??

like image 257
Giacomo Gagliano Avatar asked Jul 16 '26 05:07

Giacomo Gagliano


1 Answers

I found the solution, in fact there is need to configure the ts-node repl service properly in order for this to work.

First we need to import

  • repl from node packages
  • ts from typescript npm package
  • ts-node from package
import repl from "repl";
import ts from "typescript";
import * as tsnode from "ts-node";

then we need to create a ts-node repl service like this:

const replService: tsnode.ReplService = tsnode.createRepl();

now we can actually create a service thanks to the evalAwarePartialHost member that is's inside the replService that we just created:

const service = tsnode.create({ ...replService.evalAwarePartialHost });

we then set the ts member of the service to be ts that we imported:

service.ts = ts;

now we have to set the service in the ts-node repl:

replService.setService(service);

now it's time to create the actual repl server:

const replServer = repl.start({
  prompt: "$  ",
  ignoreUndefined: true,
  eval: replService.nodeEval,
});

the entire code looks like this:

import repl from "repl";
import ts from "typescript";
import * as tsnode from "ts-node";

// Create a ts-node replService
const replService: tsnode.ReplService = tsnode.createRepl();
const service = tsnode.create({ ...replService.evalAwarePartialHost });
service.ts = ts;
replService.setService(service);

// create a node-repl server
const replServer = repl.start({
  prompt: "$  ",
  ignoreUndefined: true,
  eval: replService.nodeEval,
});

// setup environment
replServer.setupHistory(".log", () => {});

hope this can be helpfull for someone else!!

=)

like image 110
Giacomo Gagliano Avatar answered Jul 17 '26 20:07

Giacomo Gagliano



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!