Skip to content
bizzehdee edited this page Jun 23, 2026 · 15 revisions

Standard Library (DScript.Extras)

The DScript.Extras package provides a JavaScript-compatible standard library. Register it with:

new EngineFunctionLoader().RegisterFunctions(engine);
// or with permission restrictions:
new EngineFunctionLoader().RegisterFunctions(engine, EnginePermissions.FileSystem | EnginePermissions.Network);

See Permissions for the full list of flags.


Global functions

Function Description
eval(str) Parse and execute a string as DScript code
exec(str) Execute a statement string (alias of eval for statements)
trace(val) Print a debug representation of any value
parseInt(str, radix?) Parse an integer; radix defaults to 10
parseFloat(str) Parse a floating-point number
isNaN(val) True if val is NaN
isFinite(val) True if val is a finite number
encodeURIComponent(str) Percent-encode a URI component
decodeURIComponent(str) Decode a percent-encoded URI component
encodeURI(str) Encode a full URI (preserves : / ? # …)
decodeURI(str) Decode a full URI
btoa(str) Base-64 encode a string
atob(str) Base-64 decode a string
charToInt(ch) Return the Unicode code point of the first character
structuredClone(val) Deep-clone any value
queueMicrotask(fn) Queue fn on the microtask queue

console

console.log("hello");
console.error("oops");
console.warn("careful");
console.info("fyi");
console.clear();

console.time("label");
// ... work ...
console.timeEnd("label");   // prints elapsed ms
console.timeLog("label");   // prints elapsed ms without stopping

Redirecting output from C# — set static delegates before registering:

ConsoleFunctionProvider.SetOutput(
    stdout: msg => myLog.Info(msg),
    stderr: msg => myLog.Error(msg)
);

Math

Math.abs(-5)      // 5
Math.ceil(1.2)    // 2
Math.floor(1.9)   // 1
Math.round(1.5)   // 2
Math.trunc(1.9)   // 1
Math.sign(-3)     // -1

Math.min(1, 2, 3) // 1
Math.max(1, 2, 3) // 3
Math.pow(2, 10)   // 1024
Math.sqrt(16)     // 4
Math.cbrt(27)     // 3
Math.hypot(3, 4)  // 5

Math.random()     // float in [0,1)
Math.log(Math.E)  // 1
Math.log2(8)      // 3
Math.log10(1000)  // 3

Math.sin(x)   Math.cos(x)   Math.tan(x)
Math.asin(x)  Math.acos(x)  Math.atan(x)  Math.atan2(y, x)
Math.sinh(x)  Math.cosh(x)  Math.tanh(x)
Math.exp(x)

Math.clz32(x)   // count leading zeros in 32-bit int
Math.fround(x)  // nearest 32-bit float
Math.imul(a,b)  // 32-bit integer multiply

Constants: Math.PI, Math.E, Math.SQRT2, Math.SQRT1_2, Math.LN2, Math.LN10, Math.LOG2E, Math.LOG10E


String

Instance methods are available on all string values.

var s = "Hello, World!";

s.length                    // 13
s.charAt(0)                 // "H"
s.charCodeAt(0)             // 72
s.codePointAt(0)            // 72
s.indexOf("o")              // 4
s.lastIndexOf("o")          // 8
s.includes("World")         // true
s.startsWith("Hello")       // true
s.endsWith("!")             // true
s.slice(7, 12)              // "World"
s.substring(7, 12)          // "World"
s.toUpperCase()             // "HELLO, WORLD!"
s.toLowerCase()             // "hello, world!"
s.trim()                    // strips whitespace
s.trimStart()               // strips leading whitespace
s.trimEnd()                 // strips trailing whitespace
s.split(", ")               // ["Hello", "World!"]
s.replace("World", "DScript") // "Hello, DScript!"
s.replaceAll("l", "L")      // "HeLLo, WorLd!"
s.repeat(2)                 // "Hello, World!Hello, World!"
s.padStart(15, "*")         // "**Hello, World!"
s.padEnd(15, "-")           // "Hello, World!--"
s.concat(" ", "More")       // "Hello, World! More"
s.match(/\w+/g)             // ["Hello", "World"]
s.matchAll(/(\w+)/g)        // iterator of match arrays
s.normalize("NFC")          // Unicode normalization
s.at(-1)                    // "!"

String.fromCharCode(72, 101, 108) // "Hel"
String.fromCodePoint(128512)      // emoji 😀

Array

Instance methods are available on all array values.

var a = [3, 1, 4, 1, 5];

// Mutating
a.push(9)              // append; returns new length
a.pop()                // remove last; returns element
a.shift()              // remove first; returns element
a.unshift(0)           // prepend; returns new length
a.splice(1, 2)         // remove 2 at index 1; returns removed
a.splice(1, 0, 99)     // insert 99 at index 1
a.reverse()            // in-place reverse
a.sort()               // in-place sort (lexicographic by default)
a.sort((a,b) => a - b) // with comparator
a.fill(0, 2, 4)        // fill indices 2..3 with 0
a.copyWithin(0, 2)     // copy from index 2 to start

// Non-mutating
a.slice(1, 3)          // copy of indices 1..2
a.concat([6, 7])       // new array
a.join(", ")           // "3, 1, 4, 1, 5"
a.indexOf(1)           // 1
a.lastIndexOf(1)       // 3
a.includes(4)          // true
a.find(x => x > 3)     // 4
a.findIndex(x => x > 3) // 2
a.every(x => x > 0)    // true
a.some(x => x > 4)     // true
a.flat()               // flatten one level
a.flat(Infinity)       // flatten all levels
a.at(-1)               // last element

// Higher-order
a.map(x => x * 2)
a.filter(x => x > 2)
a.forEach(x => console.log(x))
a.reduce((acc, x) => acc + x, 0)
a.reduceRight((acc, x) => acc + x, 0)
a.flatMap(x => [x, x * 2])

// Immutable copies (ES2023)
a.toSorted()           // sorted copy
a.toReversed()         // reversed copy
a.toSpliced(1, 1)      // splice copy
a.with(2, 99)          // copy with index 2 replaced

// Iteration
a.keys()               // index iterator
a.values()             // value iterator
a.entries()            // [index, value] iterator

// Static
Array.isArray(a)       // true
Array.from("abc")      // ["a","b","c"]
Array.of(1, 2, 3)      // [1,2,3]

Object

var obj = { a: 1, b: 2, c: 3 };

Object.keys(obj)              // ["a","b","c"]
Object.values(obj)            // [1,2,3]
Object.entries(obj)           // [["a",1],["b",2],["c",3]]
Object.fromEntries([["a",1]]) // { a: 1 }
Object.assign({}, obj, { d: 4 })  // shallow merge
Object.create(proto)          // new object with prototype
Object.freeze(obj)            // prevent all modification
Object.isFrozen(obj)          // true/false
Object.seal(obj)              // prevent add/delete but allow modification
Object.isSealed(obj)          // true/false
Object.hasOwn(obj, "a")       // true (ES2022)
Object.is(NaN, NaN)           // true (handles NaN and -0 correctly)
Object.groupBy(arr, fn)       // group array items into an object by key
obj.hasOwnProperty("a")       // true

Number

Number.isInteger(42)       // true
Number.isFinite(1/0)       // false
Number.isNaN(NaN)          // true
Number.isSafeInteger(2**53) // false
Number.parseInt("42px")    // 42
Number.parseFloat("3.14x") // 3.14

(3.14159).toFixed(2)       // "3.14"
(3.14159).toPrecision(4)   // "3.142"
(255).toString(16)         // "ff"
(1234).toExponential(2)    // "1.23e+3"

Constants: Number.MAX_VALUE, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NaN, Number.EPSILON


JSON

var obj  = JSON.parse('{"a":1,"b":[2,3]}');
var json = JSON.stringify(obj);           // '{"a":1,"b":[2,3]}'
var pretty = JSON.stringify(obj, null, 2);  // indented

Map

var m = new Map();
m.set("key", 42);
m.get("key");           // 42
m.has("key");           // true
m.delete("key");
m.size;                 // 0
m.clear();

m.forEach((v, k) => console.log(k, v));
m.keys();   m.values();   m.entries();

// ES2024 groupBy
var grouped = Map.groupBy([1,2,3,4], x => x % 2 === 0 ? "even" : "odd");

Set

var s = new Set([1, 2, 3, 2, 1]);
s.size;            // 3
s.has(2);          // true
s.add(4);
s.delete(1);
s.clear();

s.forEach(v => console.log(v));
s.keys();   s.values();   s.entries();

Date

var now  = new Date();
var d    = new Date(2024, 0, 15);  // Jan 15 2024

d.getFullYear()      // 2024
d.getMonth()         // 0 (January)
d.getDate()          // 15
d.getDay()           // day of week (0=Sun)
d.getHours()         d.getMinutes()   d.getSeconds()
d.getMilliseconds()  d.getTime()      // ms since epoch

d.toISOString()          // "2024-01-15T00:00:00.000Z"
d.toLocaleDateString()
d.toString()

Date.now()           // current timestamp in ms

RegExp

var re = new RegExp("(\\d+)", "g");
re.test("abc123");        // true
re.exec("abc123");        // ["123","123"]

re.source     // "(\\d+)"
re.flags      // "g"
re.global     // true
re.ignoreCase // false
re.multiline  // false

Buffer

Binary data backed by a byte[].

// Creating
var b1 = Buffer.from("hello", "utf8");
var b2 = Buffer.from([72, 101, 108, 108, 111]);
var b3 = Buffer.alloc(10);          // zeroed
var b4 = Buffer.allocUnsafe(10);    // uninitialized

// Checking
Buffer.isBuffer(b1);    // true

// Reading
b1.length;              // 5
b1.toString("utf8");    // "hello"
b1.toString("hex");     // "68656c6c6f"
b1.toString("base64");  // "aGVsbG8="
b1.readUInt8(0);        // 72

// Modifying
b3.writeUInt8(255, 0);

// Operations
Buffer.concat([b1, b2]);
b1.slice(1, 3);
b1.copy(b3, 0);         // copy b1 into b3 starting at offset 0
b1.equals(b2);          // false

EventEmitter

var emitter = new EventEmitter();

emitter.on("data", function(chunk) {
    console.log("received:", chunk);
});

emitter.once("end", function() {
    console.log("stream ended");
});

emitter.emit("data", "hello");
emitter.emit("end");

emitter.listeners("data");          // array of listeners
emitter.listenerCount("data");      // 0 (once fired and removed)
emitter.removeAllListeners("data");
emitter.off("data", myHandler);

EventEmitter.defaultMaxListeners (default 10) — a warning is printed when exceeded.


Timers

var id = setTimeout(function() {
    console.log("fired after 100ms");
}, 100);

clearTimeout(id);

var interval = setInterval(function() {
    console.log("tick");
}, 1000);

clearInterval(interval);

Timers do not fire automatically — the host must call engine.DrainTimers() periodically:

engine.Run(program);
while (engine.HasPendingTimers)
{
    Thread.Sleep(10);
    engine.DrainTimers();
}

process

process.platform      // "win32", "linux", "darwin", …
process.version       // engine version string
process.argv          // array of command-line arguments
process.env           // object of environment variables
process.getenv("PATH") // read one environment variable
process.cwd()         // current working directory
process.exit(0)       // exit with code

// Lifecycle hooks
process.on("exit", function(code) {
    console.log("exiting with", code);
});

process.on("uncaughtException", function(err) {
    console.error("unhandled error:", err.message);
});

process.on("unhandledRejection", function(reason) {
    console.error("unhandled rejection:", reason);
});

Reading process.env and calling process.exit require the appropriate EnginePermissions flags.


assert

assert(value, "message");          // alias of assert.ok
assert.ok(value, "msg");           // throws if falsy
assert.equal(a, b, "msg");         // == comparison
assert.strictEqual(a, b, "msg");   // === comparison
assert.notEqual(a, b);
assert.notStrictEqual(a, b);
assert.deepEqual(a, b);            // recursive value equality
assert.throws(fn, errorMatcher?);  // asserts fn throws
assert.doesNotThrow(fn);
assert.fail("forced failure");

util

util.format("%s is %d years old", "Alice", 30);
// "Alice is 30 years old"
// Placeholders: %s (string), %d/%i (int), %f (float), %o (inspect), %j (JSON)

util.inspect({ a: 1, b: [2, 3] });
// "{ a: 1, b: [ 2, 3 ] }"

var readFileAsync = util.promisify(fs.readFile);
readFileAsync("data.txt").then(contents => console.log(contents));

var oldFn = util.deprecate(function() {}, "use newFn instead");
oldFn(); // prints deprecation warning on first call

path

path.join("a", "b", "c.txt")     // "a/b/c.txt" (or "a\b\c.txt" on Windows)
path.resolve(".", "src", "app")   // absolute path
path.dirname("/foo/bar/baz.txt")  // "/foo/bar"
path.basename("/foo/bar/baz.txt") // "baz.txt"
path.basename("/foo/bar/baz.txt", ".txt")  // "baz"
path.extname("baz.txt")           // ".txt"
path.isAbsolute("/foo")           // true
path.normalize("/foo//bar/../baz") // "/foo/baz"
path.sep                          // "/" or "\\"

os

os.hostname()    // "mypc"
os.platform()    // "linux" / "win32" / "darwin"
os.arch()        // "x64" / "arm64"
os.homedir()     // "/home/user"
os.tmpdir()      // "/tmp"
os.totalmem()    // total RAM in bytes
os.freemem()     // free RAM in bytes
os.cpus()        // number of logical CPUs
os.EOL           // "\n" or "\r\n"

fs

All methods are synchronous. Requires EnginePermissions.FileSystem.

fs.readFileSync("file.txt")           // string (UTF-8)
fs.readFileSync("file.bin", "binary") // binary string
fs.writeFileSync("out.txt", "hello")
fs.appendFileSync("log.txt", "line\n")
fs.existsSync("file.txt")             // true/false
fs.mkdirSync("new/dir", { recursive: true })
fs.rmdirSync("old/dir")
fs.unlinkSync("file.txt")
fs.readdirSync(".")                   // array of entry names
fs.renameSync("old.txt", "new.txt")
fs.copyFileSync("src.txt", "dst.txt")

var stat = fs.statSync("file.txt");
stat.size           // bytes
stat.isFile()       // true/false
stat.isDirectory()  // true/false
stat.mtime          // last-modified timestamp

crypto

crypto.randomUUID()          // "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
crypto.randomBytes(16)       // Buffer of 16 random bytes
crypto.getRandomValues(arr)  // fills a script array with random ints

var hash = crypto.createHash("sha256");
hash.update("hello");
hash.digest("hex");    // "2cf24dba…"
hash.digest("base64"); // base64-encoded
hash.digest();         // Buffer

var hmac = crypto.createHmac("sha256", "secret");
hmac.update("message");
hmac.digest("hex");

Supported algorithms: sha256, sha512, sha1, md5.


fetch

Synchronous HTTP client. Requires EnginePermissions.Network.

var res = fetch("https://api.example.com/data");
// or
var res = fetch("https://api.example.com/data", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ key: "value" })
});

res.ok;           // true if status 200–299
res.status;       // 200
res.statusText;   // "OK"
res.headers;      // object of response headers
res.text();       // response body as string
res.json();       // parsed JSON object
res.arrayBuffer(); // Buffer

http

HTTP server. Requires EnginePermissions.Network.

var server = http.createServer(function(req, res) {
    console.log(req.method, req.url);

    req.on("data", function(chunk) { /* request body */ });
    req.on("end", function() {
        res.writeHead(200, { "Content-Type": "text/plain" });
        res.end("Hello, World!");
    });

    server.close(); // stop after one request
});

server.listen(8080, "localhost", function() {
    console.log("listening on port 8080");
});

server.listen blocks until server.close() is called.


child_process

Requires EnginePermissions.ProcessSpawn.

// Synchronous — blocks until done
var out = child_process.execSync("echo hello");  // stdout string
// throws ScriptException on non-zero exit

var result = child_process.spawnSync("node", ["-e", "console.log(1)"]);
result.stdout   // string
result.stderr   // string
result.status   // exit code (int)
result.signal   // null or "SIGTERM"

// Async (callback style)
child_process.exec("echo hello", function(err, stdout, stderr) {
    if (err) { console.error(err); return; }
    console.log(stdout);
});

// Spawn — returns process object
var proc = child_process.spawn("node", ["-e", "console.log('hi')"]);
proc.on("exit", function(code) { console.log("exited:", code); });
proc.on("data", function(chunk) { console.log("stdout:", chunk); });
proc.pid;  // process ID

readline

var rl = readline.createInterface({
    input: process.stdin,   // or any Readable with a TextReader via SetData
    output: process.stdout
});

rl.question("What is your name? ", function(answer) {
    console.log("Hello,", answer);
    rl.close();
});

rl.on("line", function(line) { console.log("got:", line); });
rl.on("close", function() { console.log("closed"); });

net

TCP networking. Requires EnginePermissions.Network.

// TCP server
var server = net.createServer(function(socket) {
    var data = socket.read();
    socket.write("echo: " + data);
    socket.end();
    server.close();
});
server.listen(9000, "127.0.0.1", function() {
    console.log("listening");
});
server.on("connection", function(socket) { /* alternative handler */ });

// TCP client
var sock = net.createConnection(9000, "127.0.0.1", function() {
    console.log("connected");
});
sock.write("hello");
sock.read();              // returns available data (non-blocking)
sock.end();
sock.on("data",    function(chunk) { });
sock.on("close",   function()      { });
sock.on("connect", function()      { });
sock.remoteAddress;  // "127.0.0.1"
sock.remotePort;     // 9000

stream

// Readable
var r = new stream.Readable();
r.on("data", function(chunk) { console.log("chunk:", chunk); });
r.on("end",  function()      { console.log("done"); });
r.push("hello ");
r.push("world");
r.push(null);   // signals end of stream
r.read();       // returns and clears the internal buffer

// Writable
var w = new stream.Writable();
w.on("finish", function() { console.log("finished"); });
w.write("foo");
w.end("bar");
w.getBuffer();   // "foobar" — returns accumulated content (non-Node API)

// Pipe
r.pipe(w);       // writes all buffered Readable data into Writable then calls end()

// Transform (combined Readable + Writable)
var t = new stream.Transform();
t.on("data", function(chunk) { /* receive transformed output */ });
t.write("input");
t.end();

zlib

var compressed   = zlib.gzipSync("hello world");   // Buffer
var decompressed = zlib.gunzipSync(compressed);     // Buffer
decompressed.toString("utf8");                       // "hello world"

var deflated  = zlib.deflateSync("hello");
var inflated  = zlib.inflateSync(deflated);
inflated.toString("utf8");  // "hello"

Input can be a Buffer or a plain string (treated as UTF-8). All methods are synchronous.


URL / URLSearchParams

var u = new URL("https://user:pass@example.com:8080/path?a=1&b=2#frag");

u.href       // full URL string
u.protocol   // "https:"
u.host       // "example.com:8080"
u.hostname   // "example.com"
u.port       // "8080"
u.pathname   // "/path"
u.search     // "?a=1&b=2"
u.hash       // "#frag"
u.origin     // "https://example.com:8080"
u.username   // "user"
u.password   // "pass"
u.toString() // same as href

u.searchParams.get("a")       // "1"
u.searchParams.getAll("a")    // ["1"]
u.searchParams.has("b")       // true
u.searchParams.set("a", "99")
u.searchParams.append("c", "3")
u.searchParams.delete("b")
u.searchParams.toString()     // "a=99&c=3"

// Relative URL
var rel = new URL("/other", "https://example.com");
rel.href;   // "https://example.com/other"

// Standalone URLSearchParams
var sp = new URLSearchParams("x=1&y=2");
sp.set("x", "hello");
sp.toString();  // "x=hello&y=2"

TextEncoder / TextDecoder

var enc = new TextEncoder();
enc.encoding;              // "utf-8"
var buf = enc.encode("hello 😀");  // Buffer

var dec = new TextDecoder();        // defaults to "utf-8"
dec.decode(buf);           // "hello 😀"

var decLatin = new TextDecoder("latin1");
decLatin.encoding;         // "latin1"
decLatin.decode(buf);      // (Latin-1 decoded string)

Supported encodings: utf-8 (default), ascii, latin1 / iso-8859-1 / binary.

Clone this wiki locally