or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

child-process.mdcrypto.mddns.mdfs.mdindex.mdreadline.mdzlib.md

readline.mddocs/

0

# Interactive Readline

1

2

Create interactive command-line interfaces with promise-based question handling and completer support. Provides modern async/await compatibility for Node.js readline operations.

3

4

## Capabilities

5

6

### Interface Creation

7

8

Create readline interfaces for interactive command-line input.

9

10

```javascript { .api }

11

/**

12

* Create a readline interface

13

* @param input - Readable stream for input

14

* @param output - Writable stream for output

15

* @param completer - Auto-completion function

16

* @param terminal - Whether to treat streams as TTY

17

* @returns Enhanced Interface instance

18

*/

19

function createInterface(input, output, completer, terminal): Interface;

20

21

/**

22

* Create a readline interface with options object

23

* @param options - Interface configuration options

24

* @returns Enhanced Interface instance

25

*/

26

function createInterface(options): Interface;

27

```

28

29

### Enhanced Interface Class

30

31

Promise-enabled Interface class with auto-completion support.

32

33

```javascript { .api }

34

/**

35

* Enhanced readline Interface with promise support

36

*/

37

class Interface {

38

/**

39

* Ask a question and wait for response

40

* @param query - Question string to display

41

* @param callback - Optional callback for traditional usage

42

* @returns Promise resolving to user's answer

43

*/

44

question(query, callback): Promise<string>;

45

46

// All other Interface methods from native readline are available

47

}

48

```

49

50

### Auto-completion Support

51

52

Enhanced completer function handling for sync, async, and promise-based completers.

53

54

```javascript { .api }

55

/**

56

* Completer function types supported:

57

* - Synchronous: (line) => [completions, line]

58

* - Asynchronous: (line, callback) => void

59

* - Promise-based: (line) => Promise<[completions, line]>

60

*/

61

type CompleterFunction =

62

| ((line: string) => [string[], string])

63

| ((line: string, callback: (err: Error, result: [string[], string]) => void) => void)

64

| ((line: string) => Promise<[string[], string]>);

65

```

66

67

**Usage Examples:**

68

69

```javascript

70

const readline = require('mz/readline');

71

const { stdin: input, stdout: output } = process;

72

73

// Basic question and answer

74

async function askQuestions() {

75

const rl = readline.createInterface({ input, output });

76

77

try {

78

const name = await rl.question('What is your name? ');

79

console.log(`Hello, ${name}!`);

80

81

const age = await rl.question('How old are you? ');

82

console.log(`You are ${age} years old.`);

83

84

} finally {

85

rl.close();

86

}

87

}

88

89

// Interactive command-line application

90

async function commandLineApp() {

91

const rl = readline.createInterface({ input, output });

92

93

console.log('Enter commands (type "quit" to exit):');

94

95

try {

96

while (true) {

97

const command = await rl.question('> ');

98

99

if (command.toLowerCase() === 'quit') {

100

break;

101

}

102

103

// Process command

104

console.log(`You entered: ${command}`);

105

}

106

} finally {

107

rl.close();

108

console.log('Goodbye!');

109

}

110

}

111

112

// With auto-completion (synchronous)

113

async function withSyncCompleter() {

114

function completer(line) {

115

const completions = ['help', 'quit', 'save', 'load', 'status'];

116

const hits = completions.filter(c => c.startsWith(line));

117

return [hits.length ? hits : completions, line];

118

}

119

120

const rl = readline.createInterface({

121

input,

122

output,

123

completer,

124

terminal: true

125

});

126

127

try {

128

const command = await rl.question('Enter command (tab for completion): ');

129

console.log(`Command: ${command}`);

130

} finally {

131

rl.close();

132

}

133

}

134

135

// With auto-completion (promise-based)

136

async function withPromiseCompleter() {

137

async function completer(line) {

138

// Simulate async completion (e.g., from database or API)

139

await new Promise(resolve => setTimeout(resolve, 10));

140

141

const completions = ['apple', 'banana', 'cherry', 'date'];

142

const hits = completions.filter(c => c.startsWith(line));

143

return [hits.length ? hits : completions, line];

144

}

145

146

const rl = readline.createInterface({

147

input,

148

output,

149

completer,

150

terminal: true

151

});

152

153

try {

154

const fruit = await rl.question('Choose a fruit (tab for completion): ');

155

console.log(`You chose: ${fruit}`);

156

} finally {

157

rl.close();

158

}

159

}

160

161

// Callback support is still available

162

const rl = readline.createInterface({ input, output });

163

rl.question('What is your favorite color? ', (answer) => {

164

console.log(`Your favorite color is ${answer}`);

165

rl.close();

166

});

167

168

// Password input (hide characters)

169

async function passwordInput() {

170

const rl = readline.createInterface({

171

input,

172

output: process.stderr, // Use stderr to avoid logging

173

terminal: true

174

});

175

176

try {

177

// Note: This doesn't actually hide input in basic implementation

178

// For true password input, you'd need additional libraries

179

const password = await rl.question('Password: ');

180

console.log('Password entered (hidden from logs)');

181

} finally {

182

rl.close();

183

}

184

}

185

186

// Multi-step form

187

async function multiStepForm() {

188

const rl = readline.createInterface({ input, output });

189

190

const user = {};

191

192

try {

193

user.name = await rl.question('Name: ');

194

user.email = await rl.question('Email: ');

195

user.age = parseInt(await rl.question('Age: '));

196

197

console.log('\nUser information:');

198

console.log(JSON.stringify(user, null, 2));

199

200

} finally {

201

rl.close();

202

}

203

}

204

```

205

206

## Interface Options

207

208

The `createInterface()` function accepts an options object:

209

210

```javascript { .api }

211

interface InterfaceOptions {

212

/** Readable stream for input */

213

input: NodeJS.ReadableStream;

214

/** Writable stream for output */

215

output?: NodeJS.WritableStream;

216

/** Auto-completion function */

217

completer?: CompleterFunction;

218

/** Whether to treat as TTY terminal */

219

terminal?: boolean;

220

/** History size limit */

221

historySize?: number;

222

/** String to use for prompt */

223

prompt?: string;

224

/** String to use for continuation prompt */

225

crlfDelay?: number;

226

/** Whether to remove ANSI escape codes */

227

removeHistoryDuplicates?: boolean;

228

/** Escape code timeout */

229

escapeCodeTimeout?: number;

230

/** Tab size for completion */

231

tabSize?: number;

232

}

233

```

234

235

## Auto-completion Function Types

236

237

The library automatically wraps completer functions to handle different patterns:

238

239

```javascript

240

// Synchronous completer

241

function syncCompleter(line) {

242

const completions = ['help', 'quit'];

243

const hits = completions.filter(c => c.startsWith(line));

244

return [hits, line];

245

}

246

247

// Asynchronous completer with callback

248

function asyncCompleter(line, callback) {

249

setTimeout(() => {

250

const completions = ['help', 'quit'];

251

const hits = completions.filter(c => c.startsWith(line));

252

callback(null, [hits, line]);

253

}, 10);

254

}

255

256

// Promise-based completer

257

async function promiseCompleter(line) {

258

const completions = ['help', 'quit'];

259

const hits = completions.filter(c => c.startsWith(line));

260

return [hits, line];

261

}

262

```

263

264

## Error Handling

265

266

Readline operations can fail for various reasons:

267

268

```javascript

269

const readline = require('mz/readline');

270

271

async function handleReadlineErrors() {

272

const rl = readline.createInterface({

273

input: process.stdin,

274

output: process.stdout

275

});

276

277

try {

278

const answer = await rl.question('Enter something: ');

279

console.log('You entered:', answer);

280

} catch (error) {

281

console.error('Readline error:', error);

282

} finally {

283

rl.close();

284

}

285

}

286

```

287

288

## Practical Patterns

289

290

### Question Validation

291

292

```javascript

293

async function askWithValidation(rl, question, validator) {

294

while (true) {

295

const answer = await rl.question(question);

296

if (validator(answer)) {

297

return answer;

298

}

299

console.log('Invalid input, please try again.');

300

}

301

}

302

303

// Usage

304

const rl = readline.createInterface({ input, output });

305

const email = await askWithValidation(

306

rl,

307

'Email: ',

308

(input) => input.includes('@')

309

);

310

```

311

312

### Menu Selection

313

314

```javascript

315

async function showMenu(rl, options) {

316

console.log('\nSelect an option:');

317

options.forEach((option, index) => {

318

console.log(`${index + 1}. ${option}`);

319

});

320

321

while (true) {

322

const choice = await rl.question('Choice (1-' + options.length + '): ');

323

const index = parseInt(choice) - 1;

324

if (index >= 0 && index < options.length) {

325

return index;

326

}

327

console.log('Invalid choice, please try again.');

328

}

329

}

330

```

331

332

## Implementation Notes

333

334

- Creates custom `InterfaceAsPromised` class that extends native `Interface`

335

- Automatically wraps completer functions to handle sync/async/promise patterns

336

- Uses `object-assign` to merge with native readline exports

337

- Maintains complete compatibility with native readline behavior

338

- Supports both promise and callback interfaces

339

- All native readline methods and properties are available on the Interface