Using the Interactive REPL

Interactive JavaScript evaluation with native module access

Sections

Terminology & Glossary
📖 Documentation
Navigation
22 sectionsv0.1
📄 Using the Interactive REPL — glaze help repl-usage
repl-usage

Using the Interactive REPL

Interactive JavaScript evaluation with native module access

Examplereplinteractivejavascriptconsolegoja-repl

The REPL (Read-Eval-Print Loop) provides an interactive JavaScript environment with immediate access to all registered native modules. This enables rapid experimentation, debugging, and prototyping without the overhead of creating separate script files.

Basic REPL Operations

The REPL accepts any valid JavaScript expression and immediately evaluates it within the full go-go-goja runtime environment.

Starting the REPL

# Canonical Bobatea-based JS REPL with completion/help widgets
go run ./cmd/goja-repl tui

# Add an extra plugin directory explicitly
go run ./cmd/goja-repl --plugin-dir /tmp/goja-plugins tui

# Restrict loading to specific plugin module names
go run ./cmd/goja-repl --allow-plugin-module plugin:examples:greeter tui

# With debug logging
go run ./cmd/goja-repl --log-level debug tui

When you do not pass --plugin-dir, goja-repl tui scans the default per-user plugin tree under ~/.go-go-goja/plugins/.... If you do pass one or more --plugin-dir flags, those explicit directories are used instead.

Basic JavaScript Evaluation

js> 2 + 3
5

js> const name = "World"
js> `Hello, ${name}!`
Hello, World!

js> Math.sqrt(16)
4

js> [1, 2, 3].map(x => x * 2)
[2, 4, 6]

Running Script Files

Use goja-repl run <file> when you want a one-shot runtime for a JavaScript file instead of a persistent REPL session:

go run ./cmd/goja-repl --enable-module yaml run ./examples/goja-repl/scripts/yaml.js

run creates a fresh runtime, applies the selected native-module flags, derives module roots from the script path, executes the file, and then closes the runtime. It does not require goja-repl create, a session-id, or a SQLite database.

Root-level plugin flags still apply:

go run ./cmd/goja-repl --plugin-dir ./plugins run ./scripts/with-plugins.js

Module Security Flags

By default, run (and all other goja-repl commands) load all registered native modules. You can restrict the module sandbox using persistent flags:

# Safe mode: load only data-only modules (crypto, events, path, time, timer)
go run ./cmd/goja-repl --safe-mode run ./script.js

# Whitelist: load only specific modules
go run ./cmd/goja-repl --enable-module fs,path run ./script.js

# Whitelist in the TUI; db is an alias for the database module
go run ./cmd/goja-repl tui --enable-module db

# Blacklist: load all except specific modules
go run ./cmd/goja-repl --disable-module fs,exec run ./script.js
FlagEffectExample
--safe-modeOnly data-safe modules (no filesystem, process, or DB access)--safe-mode
--enable-moduleWhitelist — only these modules are loaded--enable-module fs,path
--disable-moduleBlacklist — all modules except these are loaded--disable-module exec,os

These flags are persistent (available on all subcommands) and are applied when the engine runtime is built. They affect run, tui, eval, create, and all other commands that construct a runtime.

Module categories:

  • Safe (data-only): crypto, events, path, time, timer
  • Dangerous (host-access): fs, os, exec, database/db, yaml
  • Process exposure: process (requires WithProcess())

REPL Commands

The REPL recognizes special commands prefixed with ::

  • :help - Display available commands and usage information
  • :plugins - Display plugin discovery directories, discovered candidates, and loaded modules
  • :quit or :exit - Exit the REPL
  • :clear - Clear the current context (if implemented)

Module Usage Examples

All registered native modules are immediately available via require():

File System Operations

js> const fs = require("fs")
js> fs.writeFileSync("/tmp/demo.txt", "Hello from REPL!")
js> fs.readFileSync("/tmp/demo.txt")
Hello from REPL!

js> fs.existsSync("/tmp/demo.txt")
true

Plugin-backed Modules

Plugin-backed modules load through the same require() API as in-process native modules:

js> const echo = require("plugin:echo")
js> echo.ping("hello")
hello

js> echo.math.add(2, 3)
5

js> const kv = require("plugin:examples:kv")
js> kv.store.set("name", "Manuel")
{key: "name", value: "Manuel", size: 1}

js> kv.store.get("name")
Manuel

Use goja-repl help goja-plugin-user-guide for the full plugin reference and example catalog, and goja-repl help plugin-tutorial-build-install for the step-by-step build/install flow.

Unified Documentation Access

The runtime now also exposes a built-in docs module that lets JavaScript inspect embedded help pages, jsdoc stores when they are attached, and loaded plugin metadata:

js> const docs = require("docs")

js> docs.sources()
[
  { id: "default-help", kind: "glazed-help", ... },
  { id: "plugin-manifests", kind: "plugin", ... }
]

js> docs.bySlug("default-help", "repl-usage").title
REPL Usage

js> docs.byID("plugin-manifests", "plugin-method", "plugin:examples:kv/store.get").body
Get a key, returning null if it is absent

Use goja-repl help goja-docs-module-guide for the full API reference and examples.

HTTP Requests

js> const http = require("http")
js> const response = http.get("https://httpbin.org/json")
js> response.status
200

js> JSON.parse(response.body).slideshow.title
Sample Slide Show

Async Operations with Promises

js> const timer = require("timer")
js> timer.sleep(1000).then(() => console.log("Done!"))
Promise { <pending> }
js> // "Done!" appears after 1 second
Done!

js> async function demo() { await timer.sleep(500); return "Finished!"; }
js> demo().then(console.log)
Promise { <pending> }
js> // "Finished!" appears after 500ms
Finished!

YAML Parsing and Serialization

The yaml module provides native YAML support for configuration files, API payloads, and data interchange:

js> const yaml = require("yaml")

js> const config = yaml.parse("name: goja\nversion: 1.0")
js> config.name
goja

js> const out = yaml.stringify({ host: "localhost", port: 8080 })
js> console.log(out)
host: localhost
port: 8080

js> yaml.validate("[bad").valid
false

js> yaml.validate("hello: world").valid
true

Use goja-repl help yaml-module for the full API reference.

Multi-line Input

The REPL supports multi-line JavaScript constructs:

js> function fibonacci(n) {
...   if (n <= 1) return n;
...   return fibonacci(n-1) + fibonacci(n-2);
... }

js> fibonacci(10)
55

js> const users = [
...   { name: "Alice", age: 30 },
...   { name: "Bob", age: 25 }
... ]

js> users.filter(u => u.age > 27).map(u => u.name)
["Alice"]

Error Handling and Debugging

The REPL displays detailed error information for invalid JavaScript or module errors:

js> undefinedVariable
ReferenceError: undefinedVariable is not defined

js> const fs = require("fs")
js> fs.readFileSync("/nonexistent/file")
Error: open /nonexistent/file: no such file or directory

js> JSON.parse("invalid json")
SyntaxError: Unexpected token i in JSON at position 0

Debug Mode

Enable debug logging to see module registration and runtime details:

go run ./cmd/goja-repl --log-level debug tui
2024/01/15 10:30:45 engine initialised, modules: [fs, http, timer, uuid, yaml]
js> const fs = require("fs")
2024/01/15 10:30:47 module loaded: fs

Advanced REPL Techniques

The REPL maintains state across interactions, enabling sophisticated development workflows including variable persistence, API exploration, and iterative logic refinement.

Variable Persistence

Variables and functions persist across REPL sessions:

js> let counter = 0
js> function increment() { return ++counter; }
js> increment()
1
js> increment()
2
js> counter
2

Module Experimentation

Use the REPL to explore module APIs:

js> const uuid = require("uuid")
js> Object.getOwnPropertyNames(uuid)
["v4"]

js> typeof uuid.v4
function

js> uuid.v4()
123e4567-e89b-12d3-a456-426614174000

Testing Complex Logic

Prototype and test JavaScript logic interactively before moving it into a Go test, module implementation, or a higher-level automation flow:

js> function processData(items) {
...   return items
...     .filter(item => item.active)
...     .map(item => ({ ...item, processed: true }))
...     .sort((a, b) => a.priority - b.priority);
... }

js> const testData = [
...   { id: 1, active: true, priority: 2 },
...   { id: 2, active: false, priority: 1 },
...   { id: 3, active: true, priority: 1 }
... ]

js> processData(testData)
[
  { id: 3, active: true, priority: 1, processed: true },
  { id: 1, active: true, priority: 2, processed: true }
]

Console Integration

The global console object provides familiar debugging capabilities:

js> console.log("Simple message")
Simple message

js> console.log("Multiple", "arguments", 123)
Multiple arguments 123

js> const obj = { name: "test", value: 42 }
js> console.log("Object:", obj)
Object: [object Object]

js> console.error("This is an error message")
This is an error message

For structured output and advanced formatting, combine with native modules:

js> const data = { users: ["Alice", "Bob"], count: 2 }
js> console.log(JSON.stringify(data, null, 2))
{
  "users": [
    "Alice",
    "Bob"
  ],
  "count": 2
}