Skip to content

Commit 14ecd8f

Browse files
Audit repl externs for Node 24 + Haxe 4 (#261)
* Audit repl externs for Node 24 and Haxe 4. Add Recoverable, deprecated builtinModules, and default writer; extend REPLServer from readline.Interface with Node 24.2 setupHistory options; refresh comments and copyright years. Co-authored-by: Cursor <cursoragent@cursor.com> * Polish repl writer options typing and doc links. Expose util.inspect-compatible options on Repl.writer and tighten Node 24 API documentation references on Repl/REPLServer. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent fcd9550 commit 14ecd8f

3 files changed

Lines changed: 203 additions & 25 deletions

File tree

src/js/node/Repl.hx

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C)2014-2020 Haxe Foundation
2+
* Copyright (C)2014-2026 Haxe Foundation
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a
55
* copy of this software and associated documentation files (the "Software"),
@@ -25,24 +25,50 @@ package js.node;
2525
import haxe.DynamicAccess;
2626
import js.lib.Error;
2727
import js.lib.Symbol;
28+
import js.node.Util.InspectOptions;
2829
import js.node.repl.REPLServer;
2930
import js.node.stream.Readable.IReadable;
3031
import js.node.stream.Writable.IWritable;
3132

3233
/**
33-
The `repl` module provides a Read-Eval-Print-Loop (REPL) implementation that is available both as a standalone
34+
The `node:repl` module provides a Read-Eval-Print-Loop (REPL) implementation that is available both as a standalone
3435
program or includible in other applications.
3536
37+
Related types: `js.node.repl.REPLServer`, `js.node.repl.Recoverable`.
38+
3639
@see https://nodejs.org/docs/latest-v24.x/api/repl.html
3740
**/
3841
@:jsRequire("repl")
3942
extern class Repl {
4043
/**
4144
The `repl.start()` method creates and starts a `repl.REPLServer` instance.
45+
46+
If `options` is a string, then it specifies the input prompt.
47+
48+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#replstartoptions
4249
**/
4350
@:overload(function(prompt:String):REPLServer {})
4451
static function start(?options:ReplOptions):REPLServer;
4552

53+
/**
54+
Default function used to format each command's output before writing to `output`.
55+
A wrapper for `util.inspect()`; may be overridden by a custom `writer` option.
56+
Inspect defaults are available via `writer.options`.
57+
58+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#customizing-repl-output
59+
**/
60+
static final writer:ReplWriter;
61+
62+
/**
63+
A list of the names of some Node.js modules, e.g. `'http'`.
64+
65+
Deprecated since: v24.0.0. Use `js.node.Module.builtinModules` instead.
66+
67+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#replbuiltinmodules
68+
**/
69+
@:deprecated("Use js.node.Module.builtinModules instead")
70+
static var builtinModules(default, null):Array<String>;
71+
4672
/**
4773
Evaluates expressions in sloppy mode.
4874
**/
@@ -56,7 +82,7 @@ extern class Repl {
5682
}
5783

5884
/**
59-
Options object used by `Repl.start`.
85+
Options object used by `Repl.start` / `new REPLServer`.
6086
6187
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#replstartoptions
6288
**/
@@ -78,40 +104,46 @@ typedef ReplOptions = {
78104

79105
/**
80106
If `true`, specifies that the `output` should be treated as a TTY terminal.
107+
Default: checking the value of the `isTTY` property on the `output` stream upon instantiation.
81108
**/
82109
@:optional var terminal:Bool;
83110

84111
/**
85112
The function to be used when evaluating each given line of input.
86113
Default: an async wrapper for the JavaScript `eval()` function.
87114
115+
An `eval` function can error with `repl.Recoverable` to indicate the input was incomplete
116+
and prompt for additional lines.
117+
88118
// TODO(section-5): replace DynamicAccess<Dynamic>/Dynamic result with a typed REPL context model
89119
**/
90120
@:optional var eval:(code:String, context:DynamicAccess<Dynamic>, file:String, cb:(error:Null<Error>, ?result:Dynamic) -> Void) -> Void;
91121

92122
/**
93123
If `true`, specifies that the default `writer` function should include ANSI color styling to REPL output.
124+
If a custom `writer` is provided then this has no effect.
125+
Default: checking color support on the `output` stream if the REPL instance's `terminal` value is `true`.
94126
**/
95127
@:optional var useColors:Bool;
96128

97129
/**
98-
If `true`, specifies that the default evaluation function will use the JavaScript `global` as the context.
130+
If `true`, specifies that the default evaluation function will use the JavaScript `global` as the context
131+
as opposed to creating a new separate context for the REPL instance.
132+
The node CLI REPL sets this value to `true`. Default: `false`.
99133
**/
100134
@:optional var useGlobal:Bool;
101135

102136
/**
103137
If `true`, specifies that the default writer will not output the return value of a command if it evaluates to
104-
`undefined`.
138+
`undefined`. Default: `false`.
105139
**/
106140
@:optional var ignoreUndefined:Bool;
107141

108142
/**
109143
The function to invoke to format the output of each command before writing to `output`.
110-
Default: `util.inspect()`.
111-
112-
// TODO(section-5): type writer as (value:Dynamic) -> String
144+
Default: `util.inspect()` / `repl.writer`.
113145
**/
114-
@:optional var writer:Dynamic->Dynamic;
146+
@:optional var writer:(obj:Dynamic) -> String;
115147

116148
/**
117149
An optional function used for custom Tab auto completion.
@@ -127,12 +159,33 @@ typedef ReplOptions = {
127159

128160
/**
129161
Stop evaluating the current piece of code when `SIGINT` is received, i.e. `Ctrl+C` is pressed.
130-
This cannot be used together with a custom `eval` function.
162+
This cannot be used together with a custom `eval` function. Default: `false`.
131163
**/
132164
@:optional var breakEvalOnSigint:Bool;
133165

134166
/**
135-
If `true`, show preview of the results when inputting. Default depends on Node version / terminal.
167+
Defines if the REPL prints autocomplete and output previews.
168+
Default: `true` with the default eval function and `false` when a custom eval function is used.
169+
If `terminal` is falsy, there are no previews and this value has no effect.
136170
**/
137171
@:optional var preview:Bool;
138172
}
173+
174+
/**
175+
Default REPL writer: callable formatter with `util.inspect`-compatible `options`.
176+
**/
177+
@:callable
178+
abstract ReplWriter((obj:Dynamic) -> String) from((obj:Dynamic) -> String) to((obj:Dynamic) -> String) {
179+
/**
180+
Inspection options used by the default writer.
181+
**/
182+
public var options(get, set):InspectOptions;
183+
184+
inline function get_options():InspectOptions
185+
return Reflect.field(this, "options");
186+
187+
inline function set_options(value:InspectOptions):InspectOptions {
188+
Reflect.setField(this, "options", value);
189+
return value;
190+
}
191+
}

src/js/node/repl/REPLServer.hx

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C)2014-2020 Haxe Foundation
2+
* Copyright (C)2014-2026 Haxe Foundation
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a
55
* copy of this software and associated documentation files (the "Software"),
@@ -23,51 +23,97 @@
2323
package js.node.repl;
2424

2525
import haxe.DynamicAccess;
26+
import haxe.extern.EitherType;
2627
import js.lib.Error;
27-
import js.node.events.EventEmitter;
28+
import js.node.Repl.ReplOptions;
29+
import js.node.events.EventEmitter.Event;
30+
import js.node.readline.Interface;
31+
import js.node.stream.Readable.IReadable;
32+
import js.node.stream.Writable.IWritable;
2833

2934
/**
30-
Enumeration of events emitted by the `REPLServer` objects.
35+
Enumeration of events emitted by `REPLServer` objects.
3136
**/
3237
enum abstract REPLServerEvent<T:haxe.Constraints.Function>(Event<T>) to Event<T> {
3338
/**
3439
The `'exit'` event is emitted when the REPL is exited either by receiving the `.exit` command as input,
35-
the user pressing `<ctrl>-C` twice to signal `SIGINT`, or by pressing `<ctrl>-D` to signal 'end' on the input stream.
40+
the user pressing Ctrl+C twice to signal `SIGINT`, or by pressing Ctrl+D to signal `'end'` on the input stream.
41+
42+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#event-exit
3643
**/
37-
var Exit:REPLServerEvent<Void->Void> = "exit";
44+
var Exit:REPLServerEvent<() -> Void> = "exit";
3845

3946
/**
4047
The `'reset'` event is emitted when the REPL's context is reset.
48+
This occurs whenever the `.clear` command is received as input unless the REPL is using the default evaluator
49+
and the `REPLServer` instance was created with the `useGlobal` option set to `true`.
4150
4251
// TODO(section-5): type context beyond DynamicAccess<Dynamic>
52+
53+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#event-reset
4354
**/
4455
var Reset:REPLServerEvent<(context:DynamicAccess<Dynamic>) -> Void> = "reset";
4556
}
4657

4758
/**
48-
Instances of `repl.REPLServer` are created using the `repl.start()` method and should not be created directly using
49-
the JavaScript `new` keyword.
59+
Instances of `repl.REPLServer` are created using `repl.start()` or directly with `new REPLServer(options)`.
60+
61+
Extends `readline.Interface`.
5062
5163
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#class-replserver
5264
**/
5365
@:jsRequire("repl", "REPLServer")
54-
extern class REPLServer extends EventEmitter<REPLServer> {
66+
extern class REPLServer extends Interface {
67+
/**
68+
Creates a new `REPLServer` instance. Prefer `Repl.start()` in most cases.
69+
**/
70+
function new(?options:ReplOptions);
71+
5572
/**
56-
It is possible to expose a variable to the REPL explicitly by assigning it to the `context` object associated
57-
with each `REPLServer`.
73+
The `vm` / REPL context object provided to the `eval` function.
5874
5975
// TODO(section-5): type context beyond DynamicAccess<Dynamic>
6076
**/
6177
var context(default, null):DynamicAccess<Dynamic>;
6278

79+
/**
80+
The `Readable` stream from which REPL input will be read.
81+
**/
82+
var input(default, null):IReadable;
83+
84+
/**
85+
The `Writable` stream to which REPL output will be written.
86+
**/
87+
var output(default, null):IWritable;
88+
89+
/**
90+
Deprecated alias for `input`. Deprecated since: v14.3.0.
91+
**/
92+
@:deprecated("Use input instead")
93+
var inputStream(default, null):IReadable;
94+
95+
/**
96+
Deprecated alias for `output`. Deprecated since: v14.3.0.
97+
**/
98+
@:deprecated("Use output instead")
99+
var outputStream(default, null):IWritable;
100+
101+
/**
102+
Commands registered via `defineCommand()`.
103+
**/
104+
var commands(default, null):DynamicAccess<EitherType<REPLCommand, (rest:String) -> Void>>;
105+
63106
/**
64107
The `replServer.defineCommand()` method is used to add new `.`-prefixed commands to the REPL instance.
65108
**/
66109
@:overload(function(keyword:String, cmd:(rest:String) -> Void):Void {})
67-
function defineCommand(keyword:String, cmd:REPLServerOptions):Void;
110+
function defineCommand(keyword:String, cmd:REPLCommand):Void;
68111

69112
/**
70-
The `replServer.displayPrompt()` method readies the REPL instance for input from the user.
113+
The `replServer.displayPrompt()` method readies the REPL instance for input from the user,
114+
printing the configured `prompt` to a new line in `output` and resuming `input`.
115+
116+
When multi-line input is being entered, a pipe `'|'` is printed rather than the prompt.
71117
**/
72118
function displayPrompt(?preserveCursor:Bool):Void;
73119

@@ -78,21 +124,57 @@ extern class REPLServer extends EventEmitter<REPLServer> {
78124

79125
/**
80126
Initializes a history log file for the REPL instance.
127+
128+
When `historyConfig` is a string, it is the path to the history file.
129+
Since Node.js v24.2.0, an options object may be passed instead.
81130
**/
131+
@:overload(function(historyConfig:REPLServerHistoryOptions, ?callback:(err:Null<Error>, repl:Null<REPLServer>) -> Void):Void {})
82132
function setupHistory(historyPath:String, callback:(err:Null<Error>, repl:Null<REPLServer>) -> Void):Void;
83133
}
84134

135+
/**
136+
Object form of `replServer.setupHistory` (Node.js v24.2.0+).
137+
138+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#replserversetuphistoryhistoryconfig-callback
139+
**/
140+
typedef REPLServerHistoryOptions = {
141+
/**
142+
The path to the history file.
143+
**/
144+
@:optional var filePath:String;
145+
146+
/**
147+
Maximum number of history lines retained. Set to `0` to disable history.
148+
Only applies when `terminal` is `true`. Default: `30`.
149+
**/
150+
@:optional var size:Int;
151+
152+
/**
153+
If `true`, when a new input line duplicates an older one, the older line is removed. Default: `false`.
154+
**/
155+
@:optional var removeHistoryDuplicates:Bool;
156+
157+
/**
158+
Called when history writes are ready or upon error.
159+
May be used instead of the `callback` argument to `setupHistory`.
160+
**/
161+
@:optional var onHistoryFileLoaded:(err:Null<Error>, repl:Null<REPLServer>) -> Void;
162+
}
163+
85164
/**
86165
Options object used by `REPLServer.defineCommand`.
87166
**/
88-
typedef REPLServerOptions = {
167+
typedef REPLCommand = {
89168
/**
90169
Help text to be displayed when `.help` is entered.
91170
**/
92171
@:optional var help:String;
93172

94173
/**
95-
The function to execute.
174+
The function to execute, optionally accepting a single string argument.
96175
**/
97176
var action:(rest:String) -> Void;
98177
}
178+
179+
/** @deprecated Use `REPLCommand` instead. **/
180+
typedef REPLServerOptions = REPLCommand;

src/js/node/repl/Recoverable.hx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C)2014-2026 Haxe Foundation
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a
5+
* copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the
9+
* Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
* DEALINGS IN THE SOFTWARE.
21+
*/
22+
23+
package js.node.repl;
24+
25+
import js.lib.Error;
26+
27+
/**
28+
Indicates a recoverable error that a `REPLServer` can use to support multi-line input.
29+
30+
Pass an instance to the custom `eval` callback to request additional lines when input is incomplete
31+
(e.g. unclosed braces).
32+
33+
@see https://nodejs.org/docs/latest-v24.x/api/repl.html#recoverable-errors
34+
**/
35+
@:jsRequire("repl", "Recoverable")
36+
extern class Recoverable extends Error {
37+
/**
38+
The underlying error that triggered the recoverable state.
39+
**/
40+
var err:Error;
41+
42+
function new(err:Error);
43+
}

0 commit comments

Comments
 (0)