V8.Extended is a small package to add useful common utilities to a ClearScript.V8 JavaScript Engine. This include things like console
, setTimeout
, path
, fs
, etc.
All host objects imitate nodejs / browsers standard behavior as closely as possible, but not 100% of APIs are implemented.
In addition to the JavaScript-side API, V8.Extended provides a host-side (C#) API to fine-tune and control some of the APIs behavior. For example, you can lock the fs
module to a specific folder, or modify console
colors.
With V8.Extended enabled, the following code would work:
console.log("Will write file after one second..");
setTimeout(function() {
fs.writeFileSync(path.join('subdir', 'hello.txt'), 'hello world!');
console.log("File saved!");
}, 1000);
To see more code examples check out V8.Extended.Demo
, or look at the tests code at V8.Extended.Tests
.
Package NuGet can be found here: https://www.nuget.org/packages/V8.Extended.
V8.Extended comes with a set of modules you can attach to a running V8 engine to extend its functionality. Each module can be added separately, so you can control which modules to add.
Implements the basic logging methods of the console
object, including trace
, debug
, info
, log
, warn
, error
and assert
.
By default, will output logs to System.Console
with different colors per log level.
To add the console
module:
// v8 is a V8ScriptEngine instance.
V8Extended.Console _console = new();
_console.Extend(v8);
v8.Execute("console.debug('hello', 'world!');");
You can enable / disable console colors:
// enable colors (default to true)
_console.UseColors = true;
And set which color to use per log level:
// set error level logs to red
_console.LogLevelColor[V8Extended.ConsoleLevel.Error] = ConsoleColor.Red;
You can add custom handlers to handle console
log calls:
// add a custom handler to copy all console output to an object called `myLogger`.
// return true to continue to next handler, or false to break the chain (will also skip the default `System.Console` part).
_console.AddHandler((string msg, V8Extended.ConsoleLevel level) =>
{
myLogger.Write(msg);
return true;
});
Implements setTimeout
, setInterval
, clearTimeout
and clearInterval
, as standard browsers have.
To add the intervals
module:
// v8 is a V8ScriptEngine instance.
V8Extended.Intervals _intervals = new();
_intervals.Extend(v8);
In addition to attaching the JavaScript module to the V8 engine, you also need to update the timers from C# side. You can do it automatically in a background thread:
// start timers in background. call _intervals.StopEventsLoop(); to stop
_intervals.StartEventsLoopBackground();
Or in the same thread:
// start timers in current thread. call _intervals.StopEventsLoop(); to stop
_intervals.StartEventsLoop();
Or call it manually however you like (recommended to call this every 1 ms, so that timers will not suffer from delays):
_intervals.DoEvents();
v8.Execute("setTimeout(function() { console.debug('1000 ms passed!'); }, 1000);");
Temporarily pause the events loop.
Clear all timeouts and intervals.
Optional errors handler you can attach to handle exceptions from inside the timers execution.
If true (default) and exception occurs from inside a timeout / interval callback, it will automatically use the console
object to write error to console before propagating the error.
If console
is not set, will skip it.
Implements the nodejs path
module.
The following methods / members are implemented:
- sep
- delimiter
- join()
- normalize()
- parse()
- basename()
- dirname()
- extname()
- format()
- isAbsolute()
- resolve()
To learn more about these methods, please see nodejs docs on Path
module.
To add the path
module:
// v8 is a V8ScriptEngine instance.
V8Extended.Path _path = new();
_path.Extend(v8);
v8.Execute("var filePath = path.join('hello', 'world!');");
Implements the nodejs fs
module.
The following methods / members are implemented:
- readFile()
- writeFile()
- appendFile()
- readdir()
- exists()
- unlink()
- rename()
- renameFile()
- renameDir()
- mkdir()
- rmdir()
- stat()
Plus the following non-standard methods:
- getType() -> returns 'file', 'dir' or 'none'.
- isdir()
- isfile()
Note that every fs
method have three versions to it:
- The regular method (eg
fs.readFile
), which accepts a callback with (err, returnVal) to be called when operation is complete. - The
Sync
version (egfs.readFileSync
), which blocks until completion and return the value directly (will throw exception on errors). - The
Promise
version (located underfsPromises
, egfsPromises.readFile
), which returns a promise.
To learn more about these methods, please see nodejs docs on the fs
module.
To add the fs
module:
// v8 is a V8ScriptEngine instance.
V8Extended.Filesystem _fs = new();
_fs.Extend(v8);
v8.Execute($"fs.writeFileSync('test.txt', 'hello world!');");
Set the root folder all filesystem-related operation will be relative to.
If called, will permanently lock all operation to be inside the RootFolder
folder (ie preventing the script from leaving that folder) and will also block the ability to change the root folder. For example, if the JavaScript part tries to write file at "../filename.txt" an exception will be thrown.
This action is irreversible, unless you create and attach a new filesystem module to the v8 engine.
Note: I tested most basic cases but there's a chance I've missed something, so please use carefully and at your own risk.
Implements the TextEncoder
and TextDecoder
classes, which are currently missing from V8.
The following methods / members are implemented:
- encode()
- decode()
- encoding
Note: does not support the TextDecodeOptions
optional argument.
To add the encoding classes:
// v8 is a V8ScriptEngine instance.
V8Extended.TextEncoder _enc = new();
_enc.Extend(v8);
This will add both TextEncoder
and TextDecoder
classes.
v8.Execute($"let textBytes = (new TextEncoder()).encode('hello world!');");
Additional method in TextDecoder
that accept additional params, start
and end
, to decode just a part of the buffer.
- Added
TextEncoder
andTextDecoder
classes.
- Fixed filesystem async methods to not throw exception when no callback is provided.
- Fixed filesystem async and promises to be actually async.
- Extended the demo project.
- Updated ClearCode and V8 versions to latest (don't affect package, just for compatibility testing).
- Fixed bug with timeouts execution.
- Improved intervals and timeouts code.
- Fixed running intervals / timers in background thread / loop to work properly + updated tests.
V8.Extended is distributed under the permissive MIT license.