Help us shape the future of Go! Take the 2026 Go Developer Survey

quickjs

package module
v0.26.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: BSD-3-Clause Imports: 17 Imported by: 0

README

quickjs (liustack fork)

This repository is a fork of two modernc.org modules, merged into one Go module:

Upstream module Upstream repository Here
modernc.org/quickjs (the Go API) https://gitlab.com/cznic/quickjs repository root, package github.com/liustack/quickjs
modernc.org/libquickjs (QuickJS transpiled to Go by ccgo) https://gitlab.com/cznic/libquickjs lib/, package github.com/liustack/quickjs/lib

It starts from quickjs v0.25.0 and libquickjs v0.13.1 (QuickJS release 2026-06-04, commit 3d5e064), with these changes:

  • A VM that runs out of memory inside JSON.parse, or anything else that converts a string with non-ASCII characters to UTF-8, no longer leaks that string. JS_ToCStringLen2 kept a reference to its argument when allocating the UTF-8 copy failed, so the string outlived VM.Close. QuickJS, quickjs-ng and libquickjs still had this bug when the fork was made. Test: lib/tocstring_oom_test.go.

  • VM.Call and VM.CallValue report the exception thrown while evaluating the function expression (for example out of memory, or a name that is not defined) instead of cannot call a non-function.

  • Making an error no longer formats its stack. The engine records the frames (function name, bytecode and position) and formats the text the first time stack is read, with the same result as before. Code that makes many errors and reads few of their stacks, such as the development build of React (one error per JSX element), runs much faster. On darwin/arm64, a server render of a 100-item React component took 11.2 ms at the median with the development build, against 42.1 ms before. The production build of the same component, the production build of a four-route app and a JSON and array benchmark stayed within 1% of before. Top-level code that makes 500 errors per run took 1.8 ms instead of 3.2 ms. stack is an ordinary writable, configurable data property, so the error has the same shape as one whose stack was formatted at once. Once read, it is the string. What is different:

    • While the stack is pending, the value of stack is an internal object that holds the recorded frames. A pending error so carries three extra small allocations: that object, its property list and the frame record (about 150 bytes for a short stack). Assigning, defining or deleting stack frees them like any other value. The internal object belongs to a private class. The C patch makes it a built-in class of every runtime. In Go, its class ID is taken when the package loads, and a runtime registers the class the first time it records a lazy stack, a one-time cost of about a kilobyte.
    • No code sees the internal object. Everything that reads the value of stack formats it first: property reads in scripts and through the C API, Object.getOwnPropertyDescriptor(s) and JS_GetOwnProperty, and redefining a frozen stack with a value (the engine compares the old and the new value). What only looks at keys or attributes leaves it pending: Object.keys, Object.freeze, Object.seal, Object.isFrozen, Object.isSealed, propertyIsEnumerable, __lookupGetter__, __lookupSetter__, and the checks a proxy whose target is the error makes after a has, deleteProperty or ownKeys trap. stack is not enumerable, so spreading, Object.assign, Object.entries and JSON.stringify skip it.
    • Through a proxy, apart from those three checks, stack is formatted as before. A lookup of the attributes through a proxy (Object.keys, Object.freeze or propertyIsEnumerable on the proxy, for example) and the checks a proxy makes after a get, set, defineProperty or getOwnPropertyDescriptor trap read the error's full descriptor, which formats the stack. Results, trap calls and their order are the same as when the stack was formatted at once. The cost is memory: with almost none left, such an operation can fail with out of memory, where the upstream engine had already formatted the stack when the error was made.
    • Reading a property named stack whose value is an object takes the slow path of the interpreter, which is where the stack gets formatted. Other property reads do not change. In a loop of 160,000 reads, o.x took 1% less time than before, o.stack holding a number 5% more, o[k] 1% more, and an inherited o.x 9% less. A read takes about 19 ns there, so no change is more than 2 ns per read.
    • Until its stack is read or the error is freed, an error keeps the bytecode of every function on its stack alive, and with it the realm (global object) each function was compiled in. Most of these stay alive anyway. A function that runs once and makes an error that something keeps is the exception, together with every function it defines: one kept error from a function that defines 2,000 others kept 1.30 MB where 0.30 MB stayed before. An error made in one realm and kept by another keeps the first realm and everything its globals hold: with a 4 MiB ArrayBuffer in the first realm, the runtime used 4.31 MB where 67 KB stayed before, until the stack was read. Keeping only the file name and the line table would need either a copy of the line table for every frame of every error, which adds work and memory to every error made, the case this change is for, or a reference count of its own for the line table, which changes a struct of the engine and so needs a regeneration of lib/.
    • Reading a stack frees its three allocations, but the holes they leave between objects that are still alive are reused only by later allocations of the same sizes. After making 10,000 errors, keeping them and reading every stack, the allocator held 3.60 MB, against 2.06 MB when the stacks were formatted at once.
    • Errors made while top-level code (a script, an eval or a module body) is on the stack are still formatted at once, so that an error a library keeps from when it loaded does not keep that code alive. So are errors that cannot take new properties and errors that already have a stack.
    • If there is no memory left when stack is first read, the read throws an out of memory error and the stack stays pending, so a later read can give the text. Reading the property descriptor formats the stack the same way and so can throw too. When an error whose stack is still pending is printed (console.log, JS_PrintValue), formatting the stack never throws and never leaves a pending exception: out of memory there prints the error without its stack, and a later read can still give it. This covers the stack only. The rest of the print, such as the message, can run out of memory and leave an exception, as in the upstream engine. Printing an error whose stack is already a string works as it did before.
    • If the text cannot be formatted when a stack is built at once (any allocation of the formatting can fail: growing the text buffer, converting a function or file name to UTF-8, making the final string), stack becomes null and no exception is left, in Go and in the C patch alike. The upstream engine also gives null when the text buffer cannot grow. When converting a function name fails, it instead keeps a half-formatted stack with the name shown as <anonymous> and leaves an exception pending.

    Tests: errorstack_test.go, errorstack_unix_test.go, lib/backtrace_test.go, lib/backtrace_round2_test.go, lib/backtrace_round3_test.go, lib/backtrace_proxy_test.go, internal/fixlib/main_test.go.

  • A script's local time is UTC in every VM, whatever zone the process has. The engine used to take the zone from libc's localtime, which reads TZ. The process shares that libc and that variable with Go's time.Local, its logs and SQLite (through modernc.org/libc), so setting TZ=UTC to make server rendered pages the same on every machine changed all of those too. Now the engine's offset from UTC is always 0 and the process's zone is left alone. Intl, from package intl, defaults to UTC as well. What this changes for scripts:

    • getTimezoneOffset() is 0, and getHours, getDate, getDay and the other local getters give the same values as their getUTC* counterparts. The local setters (setHours, ...) set UTC fields.
    • new Date(2026, 0, 1), Date.parse of a date and time without an offset ('2026-01-01T13:05:00') and the other local forms read the fields as UTC.
    • toString, toDateString and toTimeString print UTC with GMT+0000. The engine's own toLocaleString, toLocaleDateString and toLocaleTimeString print UTC too. Package intl replaces those three, and its versions print UTC unless given a timeZone.

    A script that needs another zone names it to Intl, with package intl registered: d.toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai'}) or new Intl.DateTimeFormat('en-US', {timeZone: 'America/New_York', hour: 'numeric'}).formatToParts(d). Without intl the engine has no way to show another zone. Tests: dateutc_unix_test.go, internal/fixlib/main_test.go.

  • Package intl formats in every locale Chromium has, from CLDR 48.2 (cldr-json 48.2.3), where upstream formats en-US only. It covers Intl.DateTimeFormat, Intl.NumberFormat, Intl.PluralRules and the toLocale* methods, and its output is compared with Chromium 156 on about 60,000 expressions (intl/golden_test.go). Without a locale argument the locale is en-US, and without a timeZone option the zone is UTC: Intl and the toLocale* methods never read the host's settings, and neither does the engine's Date (see above). Register only puts stand-ins on the VM. The first use of Intl or a toLocale* method installs the rest, from bytecode compiled once per process. The package documentation lists what is not implemented and where the output differs from Chromium.

    What it costs, measured on darwin/arm64 against the en-US version: a program that uses intl is 1.7 MB larger (1.3 MB of it is the locale data). Register takes 0.09 ms and 9 KB of the VM's memory, against 0.85 ms and 46 KB before. The first use in a VM then takes 0.15 ms and 42 KB more. A language is decoded into the Go heap the first time it is used, once per process, in about 0.3 ms and 100 to 180 KB. The first use of any language also decodes about 1 MB of shared data. Formatting a date takes 3.3 µs in en-US (4.3 µs before) and 3.7 µs in zh-CN, a number 2.4 µs in en-US (2.4 µs before) and 2.7 µs in de.

The engine lives in the same module so that a fix to it ships together with the Go API, without waiting for an upstream release of either module.

go get github.com/liustack/quickjs

The license files of both projects are kept: LICENSE and LICENSE-LIBQUICKJS at the root, and lib/LICENSE, lib/LICENSE-LIBQUICKJS and lib/LICENSE_TEST262 for the engine. intl/LICENSE-DATA holds the notices of the locale data intl embeds, from Unicode CLDR and Chromium's ICU data: a program that imports intl distributes that data and has to include those notices in its documentation or with its copies. Maintenance notes are at the end of this file.

The rest of this section is the upstream README.


Go Reference LiberaPay receives patrons

logo_png

quickjs

Package quickjs is a pure Go embeddable Javascript engine. It supports the ECMA script 14 (ES2023) specification including modules, asynchronous generators, proxies and BigInt.

See also the original C QuickJS library.

The engine has no Intl: ECMA-402 is not implemented by the C library this package wraps. Package quickjs/intl adds Intl.DateTimeFormat, Intl.NumberFormat and Intl.PluralRules, in every locale Chromium has and over Go's time zone database, for a VM that opts in by calling its Register — once per VM, including one created to replace another, because Intl lives on that VM's global object.

Resolving IANA time zone names needs a zoneinfo database. Go reads the operating system's, or the copy time/tzdata embeds in the binary. That import belongs in a program's main package rather than in a library, so neither package makes it for you.

Maintaining the fork

Branches: main carries the fork. master and the other upstream branches mirror gitlab.com/cznic/quickjs and get no commits of their own.

Remotes, set up once in a fresh clone. The engine remotes must not fetch tags, because libquickjs tags (v0.13.1, ...) would clash with the tags of this repository:

git remote add upstream https://gitlab.com/cznic/quickjs.git
git remote add upstream-lib https://gitlab.com/cznic/libquickjs.git
git config remote.upstream-lib.tagOpt --no-tags
git fetch upstream
git fetch upstream-lib 'refs/tags/*:refs/tags/lib/*'   # engine tags as lib/v0.13.2, ...
Taking a new engine release

lib/ was added with git subtree, so an upstream libquickjs release merges in with its history:

git subtree pull --prefix lib upstream-lib <libquickjs tag, e.g. v0.13.2>

Conflicts to expect:

  • lib/ccgo_*.go: every upstream release regenerates these files, so the two lines added to XJS_ToCStringLen2, the calls into lib/backtrace.go (lazy error stacks) and the getTimezoneOffset that answers 0 (local time is UTC) conflict. Take the upstream version of every generated file, then put the changes back:

    git checkout --theirs -- 'lib/ccgo_*.go' 'lib/internal/run-test262/ccgo_*.go'
    go run ./internal/fixlib
    

    fixlib also rewrites modernc.org/libquickjs imports in hand-written files under lib/. go run ./internal/fixlib -check lists files that still need changes. If fixlib reports that XJS_ToCStringLen2 changed shape, read the new upstream code: QuickJS may have fixed the leak itself. If it reports that _getTimezoneOffset changed shape, or that the engine calls libc's local time functions (localtime, mktime, tzset, ...) somewhere else, upstream reads the local zone some new way: make that answer UTC too and teach fixTimezone about it. If it reports that _build_backtrace, _get_prop_string, JS_GetPropertyInternal, JS_GetOwnPropertyInternal, the interpreter's get_field, js_print_error, js_print_object or JS_ComputeMemoryUsage changed shape, compare the new upstream build_backtrace with lib/backtrace.go, which formats the same text from the recorded frames and must change with it. fixlib also audits how the engine uses property slots (the JSProperty that holds a value), because a pending stack must be formatted before anything hands the value on. It parses each generated function and follows slot pointers from where they are made (an object's property array, the slot find_own_property returns) through variables (=, := and var), stack cells, pointer arithmetic, call arguments and return values, whatever their names. A slot pointer that goes anywhere else (stored into a structure, in an assignment of several results, arithmetic on a stack cell other than a step to the next cell) is listed as a use there. For every function they reach it lists each use: reads and writes of the value or of another field, calls the pointer is passed to, stores, and which uses come before the function's first call into lib/backtrace.go. It also counts each function's descriptor lookups. internal/fixlib/slotsites.go holds the expected list with the reason each function is safe. When a release adds a function that uses slots, or changes how one does, fixlib stops and prints the difference: check whether the change can see a pending stack, wire it to lib/backtrace.go if so, and update the list (go run ./internal/fixlib -slots prints it). It also requires every property lookup in the interpreter loop (JS_CallInternal) to be a known guarded read or the put_field write. What the audit does not see: a slot pointer stored into a structure is listed as a use where it is stored, but not followed to where it is loaded again. Indirect calls are not followed. A function that no one passes a slot pointer to is not audited, so a new helper only shows up once something calls it with one. The allocator functions that resize or free the property array are listed as uses but not looked into. The order check only compares positions in the source with the first guard of the function. And slot addresses made some other way than from the property array, such as a raw offset into the object, are not recognized. So a change in these places needs a review by hand.

  • lib/internal/patch/quickjs.diff: holds the same changes in C, so that a regeneration keeps them. Keep the JS_ToCStringLen2 hunk unless upstream QuickJS has fixed the bug, the getTimezoneOffset hunk, and the lazy stack hunks (JSBacktrace, the built-in JS_CLASS_BACKTRACE class, js_backtrace_build and the js_backtrace_* calls in JS_GetPropertyInternal, JS_GetOwnPropertyInternal, JS_DefineProperty, the interpreter's GET_FIELD_INLINE, get_prop_string, js_print_error, js_print_object, JS_ComputeMemoryUsage, the callers that only need the attributes of a property (js_get_own_property_flags)). After a regeneration that includes them, lib/backtrace.go and its wiring in fixlib are no longer needed.

  • lib/go.mod, lib/go.sum: they do not exist here. When upstream changed them, delete them again (git rm lib/go.mod lib/go.sum) and bring any newer requirement into the root go.mod.

  • lib/internal/run-test262/go.mod is ours. Upstream has none there.

  • lib/internal/run-test262/ccgo_*.go: ccgo links a whole copy of the engine into the test262 runner, so as generated the runner tests that copy and not lib/. fixlib turns each engine API function of the runner into a call of the same function in lib/ (lib/test262_runner.go exports the one ccgo leaves unexported). Take the upstream files and run fixlib, as for lib/ccgo_*.go.

This fork does not regenerate lib/ccgo_*.go itself. lib/generator.go still assumes it is the root of its own module.

Taking a new release of the Go API
git merge <upstream tag>

Upstream commits import modernc.org/libquickjs and modernc.org/quickjs. After the merge, drop modernc.org/libquickjs from go.mod, run grep -rn 'modernc.org/quickjs\|modernc.org/libquickjs' --include='*.go' . and switch what it finds to github.com/liustack/quickjs. The only expected leftover is the Symbol key "modernc.org/quickjs/intl" in intl/stub.js, which is a runtime marker, not an import path.

intl/ has been rewritten here, so an upstream change to it conflicts. Keep this fork's version and bring over only what the upstream change fixes, checked with the golden test below.

Updating the intl locale data

intl/cldr.bin is generated from cldr-json and checked in, so neither a build nor go test needs the network or Node. To generate it again:

go run ./intl/internal/gen -fetch    # downloads what is missing into a cache directory
go test ./intl                       # includes the golden test against Chromium

To move to a new CLDR release, set cldrTag in intl/internal/gen/main.go to the cldr-json tag and run the two commands. The golden test then shows every expression whose output changed. Where the new CLDR changed a value Chromium does not have yet, add the value Chromium has to browserOverrides in intl/internal/gen/overrides.go, with where it comes from. The generator stops on an override CLDR has caught up with, so the list only ever holds live differences.

To compare with a newer Chromium, record its answers again. This needs Node and a Chromium that Playwright drives. Set it up once:

npm install -g playwright@1.64.0                # Chromium 156.0.8078.4, as recorded here
npx playwright@1.64.0 install chromium
export PLAYWRIGHT="$(npm root -g)/playwright"   # what record.cjs loads

Each Playwright release drives one Chromium build, so a newer Chromium needs a newer Playwright: its browsers.json names the build.

Then, from the repository root:

CLDR="$HOME/cldr-json"                                         # any directory for the downloads
go run ./intl/internal/gen -fetch -cldr "$CLDR"                # the list of CLDR locales
node intl/testdata/chromium/record.cjs availability "$CLDR"    # the locales Chromium has
go run ./intl/internal/gen -icudtl "$(node intl/testdata/chromium/record.cjs icudtl)"
go run ./intl/internal/gen -fetch -cldr "$CLDR"                # data for those locales
go test ./intl -run TestGolden -args -golden.corpus            # writes corpus.json
node intl/testdata/chromium/record.cjs golden                  # writes golden.json.gz
go test ./intl
rm -rf "$CLDR"

record.cjs icudtl prints where the browser keeps icudtl.dat, its ICU data file. The same file, byte for byte, is common/icudtl.dat in Chromium's copy of ICU, at the commit Chromium's DEPS pins for src/third_party/icu (5aa52620 for 156.0.8078.4), so summarizing it needs no browser:

curl -s 'https://chromium.googlesource.com/chromium/deps/icu/+/5aa526207171ecadf31597f0980a7b7ad8872f33/common/icudtl.dat?format=TEXT' |
	base64 -d > icudtl.dat
go run ./intl/internal/gen -icudtl icudtl.dat

The generator writes a summary of it to intl/testdata/chromium/icu.json.gz and makes every locale take each resource from where Chromium's ICU finds it, so a language whose data Chromium leaves out formats with root's or English data as it does in Chromium. To record another browser, set CHROMIUM to its executable for every record.cjs command.

Update the Chromium and ICU versions in the package documentation and here, and look at each new difference: fix the code when Chromium is right, or add the cause to goldenDifferences when the difference is in the data.

Checks
go test -short ./...                                     # all packages
go test -vet=off -run 'TestToCString' ./lib              # the leak reproduction
go test -run 'TestErrorStack' .                          # stack text and memory of lazy error stacks
go test -vet=off -run 'TestBacktrace' ./lib              # shapes, retries and writes of pending stacks
go run ./internal/fixlib -check                          # fork changes present in lib/
go test ./internal/fixlib                                # fixlib notices new reads of property values
for t in linux/amd64 linux/arm64 darwin/arm64 windows/amd64; do
	GOOS=${t%/*} GOARCH=${t#*/} go build ./...
done

lib/internal/run-test262 is a module of its own, so its 69 MiB of transpiled test runner stay out of the module zip. Test262 in lib/ builds it with go build -C. The runner runs the engine in lib/ (see fixlib), so it checks the changes made there.

Documentation

Overview

Package quickjs is a pure Go embeddable Javascript engine. It supports the ECMA script 14 (ES2023) specification including modules, asynchronous generators, proxies and BigInt.

See also the original C QuickJS library.

Internationalization

The engine has no Intl. ECMA-402 is not implemented by the C library this package wraps, so a page or bundle reaching for Intl.DateTimeFormat gets a ReferenceError, and the toLocale* methods it ships ignore both their locale and their timeZone argument. Package github.com/liustack/quickjs/intl provides Intl.DateTimeFormat and Intl.NumberFormat, en-US over Go's time zone database, for a VM that opts in by calling its Register.

Performance

Geomeans of time/op over a set of benchmarks, relative to CCGO, lower number is better. Detailed results available in the testdata/benchmarks directory.

 CCGO: github.com/liustack/quickjs/lib
 GOJA: github.com/dop251/goja@v0.0.0-20260723142020-b4aef50fa347
  QJS: github.com/fastschema/qjs@v0.0.6

	                        CCGO     GOJA     QJS
	-----------------------------------------------
	        darwin/amd64    1.000    1.575    1.300
	        darwin/arm64    1.000    1.069    1.080
	       freebsd/amd64    1.000    1.943    1.472    (qemu)
	       freebsd/arm64    1.000    1.803    1.030    (qemu)
	           linux/386    1.000    3.082   95.312    (qemu)
	         linux/amd64    1.000    1.419    1.213
	           linux/arm    1.000    3.859  139.339
	         linux/arm64    1.000    1.611    1.267
	       linux/loong64    1.000    1.555   85.539
	       linux/ppc64le    1.000    2.286   75.183
	       linux/riscv64    1.000    1.656   76.609
	         linux/s390x    1.000    2.016   68.871    (qemu)
	       windows/amd64    1.000    2.254    1.438
	       windows/arm64    1.000    2.002    1.610
	-----------------------------------------------
	                        CCGO     GOJA     QJS

Notes

Parts of the documentation were copied from the quickjs documentation, see LICENSE-QUICKJS for details.

Supported platforms and architectures

These combinations of GOOS and GOARCH are currently supported

OS      Arch
-------------
darwin  amd64
darwin  arm64
freebsd amd64
freebsd arm64
linux   386
linux   amd64
linux   arm
linux   arm64
linux   loong64
linux   ppc64le
linux   riscv64
linux   s390x
windows amd64
windows arm64

Builders

Builder results are available here.

Change Log

2026-07-27: Upgrade to QuickJS release 2026-06-04. The bytecode format changed, code produced by VM.Compile using an older release will no longer load.

2025-10-10: Upgrade to QuickJS release 2025-09-13.

Example (Ping)

Multiple concurrent Javascript virtual machines communicating via Go channels.

package main // import "github.com/liustack/quickjs"

import (
	"fmt"
)

// Multiple concurrent Javascript virtual machines communicating via Go channels.
func main() {
	tx := make(chan string, 1)
	rx := make(chan string, 1)
	client, _ := NewVM()
	defer client.Close()
	registerFuncs(client, tx, rx)
	go func() { // Start the server.
		server, _ := NewVM()
		defer server.Close()
		registerFuncs(server, rx, tx)
		server.Eval("send(receive()+' reply');", EvalGlobal)
	}()
	fmt.Println(client.Eval("send('ping'); receive();", EvalGlobal)) // Ping the server.
}

func registerFuncs(m *VM, tx, rx chan string) {
	m.RegisterFunc("send", func(s string) { tx <- s }, false)
	m.RegisterFunc("receive", func() string { return <-rx }, false)
}
Output:
ping reply <nil>

Index

Examples

Constants

View Source
const (
	EvalGlobal = lib.MJS_EVAL_TYPE_GLOBAL // global code
	EvalModule = lib.MJS_EVAL_TYPE_MODULE // module code
)

Eval flags.

Variables

View Source
var (

	// UndefinedValue is a Value representing Javascript value 'undefined'. It is
	// not associated with any particular VM.
	UndefinedValue = Value{/* contains filtered or unexported fields */}
)

Functions

func Version

func Version() string

Version returns the underlying QuickJS version.

Types

type Atom

type Atom = lib.TJSAtom

Atom is an unique identifier of, for example, a string value. Atom values are VM-specific.

type Error

type Error struct {
	Name         string // e.g. "ReferenceError", "TypeError"
	Message      string // the error message
	Stack        string // stack trace, one "    at ...\n" frame per line
	LineNumber   int    // line where the error occurred (parse errors only)
	ColumnNumber int    // column where the error occurred (parse errors only)
	FileName     string // file name where the error occurred (parse errors only)
	// contains filtered or unexported fields
}

Error holds structured information from a JavaScript exception. The error returned by VM.Eval, VM.Call and the other eval-family methods is an *Error; recover the fields with errors.As:

var e *quickjs.Error
if errors.As(err, &e) {
	fmt.Println(e.Stack)
}

Its Error method reports the same message string the engine has always returned, so existing code comparing the error text keeps working.

Only parse/syntax errors carry the FileName, LineNumber and ColumnNumber properties. For runtime errors those fields are zero and the source location is available only from Stack.

func ErrorFromValue

func ErrorFromValue(v Value) *Error

ErrorFromValue extracts structured error information from JavaScript error value 'v', typically an Error instance caught from a JS exception.

'v' is borrowed: ErrorFromValue does not free it and the caller remains responsible for its lifetime. Like all VM operations it must be called from the VM's own goroutine. See Error for which fields are populated.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface. It returns the same string the engine produces for the exception, unchanged from earlier releases.

type HostFunc

type HostFunc func(args []any) (any, error)

HostFunc is a Go function exposed to JavaScript by RegisterHostFunc. It receives the call arguments already converted to Go values and returns a single value to convert back to JS, or a non-nil error which is thrown as a JavaScript exception.

type ModuleLoaderFunc

type ModuleLoaderFunc func(vm *VM, moduleName string) (string, error)

ModuleLoaderFunc defines the signature for a custom module loader. It must return the module's source code (Javascript).

type ModuleNormalizeFunc

type ModuleNormalizeFunc func(vm *VM, moduleBaseName, moduleName string) (string, error)

ModuleNormalizeFunc defines the signature for a custom module normalizer. It receives the base name (the module making the import) and the requested name, and should return the normalized, absolute module name.

type Object

type Object struct {
	// contains filtered or unexported fields
}

Object represents the value of a Javascript object, but not the javascript object instance itself. Do not compare instances of Object.

func (*Object) Into

func (o *Object) Into(v any) error

Into helps you quickly deserialize an Object into a native Go type. This uses encoding/json.Unmarshal internally, so the target type must be compatible with that package.

Example

JSON unmarshalling into native Go struct.

m, _ := NewVM()
defer m.Close()
obj, _ := m.Eval("obj = {a: 42+314, b: 'foo'}; obj;", EvalGlobal)
var dst struct {
	A int    `json:"a"`
	B string `json:"b"`
}
obj.(*Object).Into(&dst)
fmt.Printf("%#v\n", dst)
Output:
struct { A int "json:\"a\""; B string "json:\"b\"" }{A:356, B:"foo"}

func (*Object) MarshalJSON

func (o *Object) MarshalJSON() (r []byte, err error)

MarshalJSON implements encoding/json.Marshaler.

Example

JSON marshalling.

m, _ := NewVM()
defer m.Close()
obj, _ := m.Eval("obj = {a: 42+314, b: 'foo'}; obj;", EvalGlobal)
s, _ := (obj.(*Object).MarshalJSON())
fmt.Printf("%s\n", s)
Output:
{"a":356,"b":"foo"}

func (*Object) String

func (o *Object) String() string

String implements fmt.Stringer.

Example

JSON marshalling.

m, _ := NewVM()
defer m.Close()
obj, _ := m.Eval("obj = {a: 42+314, b: 'foo'}; obj;", EvalGlobal)
fmt.Printf("%s\n", obj)
Output:
{"a":356,"b":"foo"}

type PromiseCapability

type PromiseCapability struct {
	Promise Value
	Resolve Value
	Reject  Value
}

PromiseCapability holds a Promise along with its resolve and reject functions, obtained without evaluating JS source.

func (*PromiseCapability) Dup

Dup duplicates the capability — its promise and both resolving functions — returning a new PromiseCapability that must itself be released via Free.

func (*PromiseCapability) Free

func (pc *PromiseCapability) Free()

Free releases all values held by the capability.

type Undefined

type Undefined struct{}

Undefined represents the Javascript value "undefined".

func (Undefined) String

func (u Undefined) String() string

String implements fmt.Stringer.

type Unsupported

type Unsupported struct{}

Unsupported represents an unsupported Javascript value.

func (Unsupported) String

func (u Unsupported) String() string

String implements fmt.Stringer.

type VM

type VM struct {
	// contains filtered or unexported fields
}

VM represents a Javascript context (or Realm). Each VM has its own global objects and system objects.

Note: VM is not safe for concurrent use by multiple goroutines.

func NewVM

func NewVM() (*VM, error)

NewVM returns a newly created VM.

func (*VM) Call

func (m *VM) Call(function string, args ...any) (r any, err error)

Call evaluates 'function(args...)' and returns the resulting (value, error).

Argument types must be one of:

Go argument type                        Javascript argument type
----------------------------------------------------------------
nil                                     null
Undefined                               undefined
string                                  string
int*/uint* (value in int32 range)       int
int*/uint* (value out of int32 range)   float
bool                                    bool
float64                                 float64
*math/big.Int                           BigInt
*Object                                 object
Value                                   native Javascript Value
any other type                          object from JSON produced by encoding.json/Marshall(arg)
Example (Function)

Call a Javascript function.

m, _ := NewVM()
defer m.Close()
fmt.Println(m.Call("parseInt", "1234"))
Output:
1234 <nil>
Example (Method)

Call a Javascript method.

m, _ := NewVM()
defer m.Close()
fmt.Println(m.Call("Math.abs", -1234))
Output:
1234 <nil>

func (*VM) CallValue

func (m *VM) CallValue(function string, args ...any) (r Value, err error)

CallValue is like Call but returns (Value, error) like EvalValue

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) Close

func (m *VM) Close() error

Close releases the resources held by 'm'. That includes the module loader and normalizer set by VM.SetModuleLoader: Close removes them, so a closed VM keeps nothing they close over reachable.

func (*VM) Compile

func (m *VM) Compile(javascript string, flags int) ([]byte, error)

Compile compiles the bytecode representation of the passed script.

The returned bytecode can be later executed using EvalBytecode or EvalBytecodeValue.

Note: The bytecode format is linked to a given QuickJS version.

func (*VM) Eval

func (m *VM) Eval(javascript string, flags int) (r any, err error)

Eval evaluates a script or module source in 'javascript'.

Javascript result type  Go result type                          Go result error
-------------------------------------------------------------------------------
exception               nil                                     non-nil
null                    nil                                     nil
undefined               Undefined                               nil
string                  string                                  nil
int                     int                                     nil
bool                    bool                                    nil
float64                 float64                                 nil
BigInt                  *math/big.Int                           nil
object                  *Object                                 nil
any other type          Unsupported                             nil
Example (Exception)

Getting exception.

m, _ := NewVM()
defer m.Close()
fmt.Println(m.Eval("throw new Error('failed');", EvalGlobal))
Output:
<nil> Error: failed
Example (Expression)

Evaluate a simple Javascript expression.

m, _ := NewVM()
defer m.Close()
fmt.Println(m.Eval("1+2", EvalGlobal))
Output:
3 <nil>
Example (Object)

Object example.

m, _ := NewVM()
defer m.Close()
fmt.Println(m.Eval("obj = {a: 42+314, b: 'foo'}; obj;", EvalGlobal))
Output:
{"a":356,"b":"foo"} <nil>

func (*VM) EvalBytecode

func (m *VM) EvalBytecode(bytecode []byte) (r any, err error)

EvalBytecode is like Eval but uses QuickJS bytecode.

Note: The bytecode format is linked to a given QuickJS version. Moreover, no security check is done before its execution. Hence the bytecode should not be loaded from untrusted sources.

Note: Javascript 'this' is always set to the global context.

func (*VM) EvalBytecodeValue

func (m *VM) EvalBytecodeValue(bytecode []byte) (r Value, err error)

EvalBytecodeValue is like EvalValue but operates on QuickJS bytecode.

Exceptions thrown during evaluation of the script are returned as Go errors.

If no error is returned, the caller must properly handle the returned Value using Dup/Free.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) EvalThis

func (m *VM) EvalThis(obj Value, javascript string, flags int) (r any, err error)

EvalThis is like eval but sets javascript 'this' to 'obj'.

func (*VM) EvalThisValue

func (m *VM) EvalThisValue(obj Value, javascript string, flags int) (r Value, err error)

EvalThisValue is like EvalValue but sets javascript 'this' to obj.

func (*VM) EvalValue

func (m *VM) EvalValue(javascript string, flags int) (r Value, err error)

EvalValue evaluates a script or module source in 'javascript' and returns the resulting Value, or an error, if any.

Exceptions thrown during evaluation of the script are returned as Go errors.

If no error is returned, the caller must properly handle the returned Value using Dup/Free.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) ExecutePendingJobs

func (m *VM) ExecutePendingJobs() (n int, err error)

ExecutePendingJobs runs queued Javascript jobs — Promise reactions (the .then/.catch/.finally callbacks) and async/await continuations — until the queue is empty, returning the number of jobs executed. The runtime does not run these itself: an embedding event loop calls ExecutePendingJobs at the end of each turn to drain the microtask queue (so a resolved Promise's .then runs, a pending await resumes, etc.). An exception thrown by a job is returned as an error — the first one — while the remaining jobs still run; a self-feeding job queue is bounded so it cannot hang the host.

func (*VM) GetProperty

func (m *VM) GetProperty(this Value, prop Atom) (r any, err error)

GetProperty returns this.prop.

func (*VM) GetPropertyValue

func (m *VM) GetPropertyValue(this Value, prop Atom) (r Value, err error)

GetPropertyValue returns this.prop.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) GlobalObject

func (m *VM) GlobalObject() (r Value)

GlobalObject returns m's global object.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) Interrupt

func (m *VM) Interrupt()

Interrupt requests 'm' to interrupt Javascript evaluation. Interrupt can be called asynchronously at any time m is evaluating a script. The request stays pending until the outermost call into javascript returns, so javascript a host function evaluates on m meanwhile does not clear it.

Example
const timeout = time.Second
m, _ := NewVM()
defer m.Close()

go func() {
	time.Sleep(timeout)
	m.Interrupt()
}()

t0 := time.Now()
r, err := m.Eval(`
function f() {
	var sink;
	for (var i = 0; i < 10000; i++) {
		sink += 42;
		sink -= 42;
	}
}

(function() {
	for (var i = 0; i < 10000; i++) {
		f();
	}
	return 42;
})();
`, EvalGlobal)
d := time.Since(t0)
step := timeout / 5
d = d / step * step
fmt.Println(r, err, d)
Output:
<nil> InternalError: interrupted 1s

func (*VM) NewAtom

func (m *VM) NewAtom(s string) (r Atom, err error)

NewAtom returns an unique indentifier of 's' or an error, if any.

func (*VM) NewFloat64

func (m *VM) NewFloat64(n float64) Value

NewFloat64 returns a new Value from 'n'.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) NewInt

func (m *VM) NewInt(n int) Value

NewInt returns a new Value from 'n'.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) NewObjectValue

func (m *VM) NewObjectValue() (r Value, err error)

NewObjectValue returns a new Value representing '{}'.

func (*VM) NewPromiseCapability

func (m *VM) NewPromiseCapability() (*PromiseCapability, error)

NewPromiseCapability creates a new JavaScript Promise along with its resolve and reject functions.

The returned PromiseCapability must be freed via Free when no longer needed.

To expose a promise to JS from a Go function registered with RegisterFunc, return pc.Promise from the Go function. The resolve/reject values captured by the closure need no Dup because the C API already holds a reference for each:

m.RegisterFunc("delayed", func(delay int) Value {
    pc, err := m.NewPromiseCapability()
    if err != nil { panic(err) }
    youreventloop.Schedule(func() {
        time.Sleep(time.Duration(delay) * time.Millisecond)
        pc.Resolve.Call(UndefinedValue, "done")
        pc.Resolve.Free()
        pc.Reject.Free()
        // pc.Promise.Free() // <- only if returned pc.Promise.Dup()!
    })
    return pc.Promise
}, false)

func (*VM) NewString

func (m *VM) NewString(s string) (r Value, err error)

NewString returns a new Value from 's'.

Note: See the Value documentation for details about manual memory management of Value objects.

func (*VM) RegisterFunc

func (m *VM) RegisterFunc(name string, f any, wantThis bool) error

RegisterFunc registers a Go function 'f' and makes it callable from Javascript.

The 'f' argument can be a regular Go function, a closure, a method expression or a method value. All of them are called 'Go function' below.

The Go function can have zero or more parameters. If 'wantThis' is true then the first parameter of the Go function will get the Javascript value of 'this'. Depending on context, 'this' can be Javascript null or undefined.

Go functions with multiple results return them as an Javascript array.

Go nil errors are converted to Javascript null.

Go non-nil errors are converted to Javascript strings using the Error() method.

Any Go <-> Javascript failing type conversion between arguments/return values throws a Javascript type error exception.

There is a limit on the total number of currently registered Go functions.

Note: The 'name' argument should be a valid Javascript identifier. It is not currently enforced but this may change later.

For binding host objects (a DOM, console, fetch, …) prefer RegisterHostFunc, which gives the more convenient single-return / error-throws-exception shape.

Example (Error)

Call error returning Go function from Javascript.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(a int) error {
	if a < 0 {
		return fmt.Errorf("negative")
	}
	return nil
}, false)
fmt.Println(m.Eval("gofunc(-1)", EvalGlobal))
fmt.Println(m.Eval("gofunc(1)", EvalGlobal))
Output:
negative <nil>
<nil> <nil>
Example (MultipleReturn)

Call multiple return Go function from Javascript.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(a, b int) (int, int) { return 10 * a, 100 * b }, false)
fmt.Println(m.Eval("gofunc(2, 3)", EvalGlobal))
Output:
[20,300] <nil>
Example (SingleReturn)

Call single return Go function from Javascript.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(a, b, c int) int { return a + b*c }, false)
fmt.Println(m.Eval("gofunc(2, 3, 5)", EvalGlobal))
Output:
17 <nil>
Example (ThisNonNull)

Passing Javascript 'this' to a Go function.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(this any) any { return this }, true)
fmt.Println(m.Eval("var obj = { foo: 314, method: gofunc }; obj.method()", EvalGlobal))
Output:
{"foo":314} <nil>
Example (ThisNonNull2)

Passing Javascript 'this' to a Go function.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(this any, n int) (any, int) { return this, 10 * n }, true)
fmt.Println(m.Eval("var obj = { foo: 314, method: gofunc }; obj.method(42)", EvalGlobal))
Output:
[{"foo":314},420] <nil>
Example (ThisNull)

Passing undefined Javascript 'this' to a Go function.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(this any) any { return this }, true)
fmt.Println(m.Eval("gofunc()", EvalGlobal))
Output:
undefined <nil>
Example (ThisNull2)

Passing undefined Javascript 'this' to a Go function.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(this any, n int) (any, int) { return this, 10 * n }, true)
fmt.Println(m.Eval("gofunc(42)", EvalGlobal))
Output:
[null,420] <nil>
Example (Void)

Call void Go function from Javascript.

m, _ := NewVM()
defer m.Close()
m.RegisterFunc("gofunc", func(a, b, c int) { fmt.Println(a + b*c) }, false)
fmt.Println(m.Eval("gofunc(2, 3, 5)", EvalGlobal))
Output:
17
undefined <nil>

func (*VM) RegisterHostFunc

func (m *VM) RegisterHostFunc(name string, fn HostFunc) error

RegisterHostFunc exposes fn to JavaScript as a global function named name, using the calling convention an embedding host wants: every JS call argument arrives in the single []any slice (already converted to Go values), fn returns exactly one value to convert back to JS, and a non-nil error is thrown as a JavaScript exception.

This differs from RegisterFunc, whose reflection mapping turns a Go multiple-return into a JS array and converts a returned error like any other value (so a (value, error) pair becomes the array [value, error] rather than a value-or-throw). RegisterHostFunc is the better fit for binding host objects; RegisterFunc remains for direct, typed Go calls.

func (*VM) SetCanBlock

func (m *VM) SetCanBlock(value bool)

SetCanBlock configures m's blocking mode.

func (*VM) SetDefaultModuleLoader

func (m *VM) SetDefaultModuleLoader()

SetDefaultModuleLoader will enable loading module using the default module loader.

Example

Enabling the module loader.

m, _ := NewVM()
defer m.Close()
m.SetDefaultModuleLoader()
// testdata/power.js:
//  export const name = "Power";
//
//  export function square(x) {
//  	return x*x;
//  }
//
//  export function cube(x) {
//  	return x*x*x;
//  }
m.Eval("import * as Power from './testdata/power.js'; globalThis.Power = Power;", EvalModule)
fmt.Println(m.Eval("[Power.square(2), Power.cube(2)];", EvalGlobal))
Output:
[4,8] <nil>

func (*VM) SetEvalTimeout

func (m *VM) SetEvalTimeout(d time.Duration) error

SetEvalTimeout sets the timeout for the various eval functions. Passing zero 'd' disables timeouts. The timeout starts with the outermost call into javascript: a host function that evaluates more javascript on m runs inside the time left to the call that got it there.

Example
m, _ := NewVM()
defer m.Close()

for _, timeout := range []time.Duration{100 * time.Millisecond, time.Second, 3 * time.Second} {
	m.SetEvalTimeout(timeout)
	t0 := time.Now()
	r, err := m.Eval(`
function f() {
	var sink;
	for (var i = 0; i < 10000; i++) {
		sink += 42;
		sink -= 42;
	}
}

(function() {
	for (var i = 0; i < 10000; i++) {
		f();
	}
	return 42;
})();
`, EvalGlobal)
	d := time.Since(t0)
	min := timeout / 2
	max := timeout * 3 / 2
	fmt.Println(r, err, timeout, d >= min && d <= max)
}
Output:
<nil> InternalError: interrupted 100ms true
<nil> InternalError: interrupted 1s true
<nil> InternalError: interrupted 3s true

func (*VM) SetGCThreshold

func (m *VM) SetGCThreshold(threshold uintptr)

SetGCThreshold sets the memory threshold at which a GC will be performed, in bytes.

func (*VM) SetMaxStackSize

func (m *VM) SetMaxStackSize(threshold uintptr)

SetMaxStackSize limits the JS call depth, in libc.TLS stack slots (~one per JS call frame in the CGo-free port). Deep recursion then throws a catchable RangeError instead of overflowing the Go goroutine stack. 0 restores the MaxStackSlots default.

func (*VM) SetMemoryLimit

func (m *VM) SetMemoryLimit(limit uintptr)

SetMemoryLimit limits m's maxmimum memory usage, in bytes. Small values of 'limit' are not honored because the VM needs to allocate memory also for the exception object itself. The particular value of "small" is unspecified and subject to change without notice.

func (*VM) SetModuleLoader

func (m *VM) SetModuleLoader(loader ModuleLoaderFunc, normalize ModuleNormalizeFunc)

SetModuleLoader configures custom Go functions to load and normalize Javascript modules. Passing nil for 'loader' removes the custom loader, and so does Close; until then the engine keeps 'loader' and 'normalize', and whatever they close over, reachable. If 'normalize' is nil, the engine falls back to the default QuickJS module normalizer.

func (*VM) SetProperty

func (m *VM) SetProperty(this Value, prop Atom, val any) (err error)

SetProperty sets this.prop = val.

func (*VM) SetPropertyValue

func (m *VM) SetPropertyValue(this Value, prop Atom, val Value) (err error)

SetPropertyValue sets this.prop = val.

func (*VM) StdAddHelpers

func (m *VM) StdAddHelpers() error

StdAddHelpers adds the 'print' and 'console' global objects to 'm'.

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value represents a native Javascript value. Values are reference counted and their lifetime is managed by an independent Javascript garbage collector. To avoid memory corruption/leaks caused by tripping the Javascript GC, a Value must not

  • be copied. Use the Dup method instead.
  • become unreachable without calling its Free method.
  • be used after its Free() method was called.
  • outlive its VM.

It is recommended to use native Go values instead of Value where possible.

When passing a Value down the call stack use Dup. For example in main

v, _ := EvalValue(someScript)
defer v.Free()
foo(v.Dup()) // Instead of foo(v)

In 'foo' Free must be used. For example

func foo(v Value) {
        defer v.Free()
        ...
}

This ensures the/only topmost Free marks 'v' eligible for garbage collection.

Beware that the correct setup/handling becomes more complicated when using closures, Values are sent through a channel etc. In particular, if a goroutine 1 passes a Dup of 'v' to goroutine 2 and goroutine 1 completes and thus frees 'v' before goroutine 2 completes, the reference counting mechanism will fail. In other words, every Free must be strictly paired with the Dup that preceded obtaining the Value and the Dup/Free calls must respect the original nesting. This is correct.

Dup             // in main
        Dup     // in foo
        Free    // in foo
Free            // in main

This will fail, for example in the above discussed goroutines scenario.

Dup            // in g1
        Dup    // in g2
Free           // in g1
        Free   // in g2

The fix might be in this case to arrange goroutine 1 to wait for goroutine 2 to complete before executing Free in goroutine 1.

See TestMemgrind for an example of how to detect memory leaks caused not only by improper Value use.

func (Value) Any

func (v Value) Any() (r any, err error)

Any attemtps to convert 'v' to any using the same rules as there are for the return value of VM.Eval.

func (Value) Call

func (v Value) Call(this Value, args ...any) (r any, err error)

Call evaluates 'v(args...)' with 'this' as the receiver and returns the resulting (value, error). 'v' must be a Javascript function. Pass UndefinedValue as 'this' when the function does not use it.

resolve.Call(quickjs.UndefinedValue, "done")
reject.Call(quickjs.UndefinedValue, err.Error())

Argument types are converted using the same rules as in VM.Call and the result is unpacked using the same rules as there are for the return value of VM.Eval. Note that a Go error is not one of the recognized types, so it is marshaled to JSON like any other value — and because the standard error types have no exported fields that yields '{}'. Pass err.Error() instead.

Note: A Value passed to a Go function registered by VM.RegisterFunc is valid only for the duration of that call. To call it later, for example to settle a promise after the Go function has returned, retain it using Value.Dup and release it using Value.Free when done.

Note: See the Value documentation for details about manual memory management of Value objects.

func (Value) CallValue

func (v Value) CallValue(this Value, args ...any) (r Value, err error)

CallValue is like Value.Call but returns (Value, error) like VM.EvalValue.

Note: See the Value documentation for details about manual memory management of Value objects.

func (Value) Dup

func (v Value) Dup() Value

Dup returns a copy of 'v' while updating its reference count.

func (*Value) Free

func (v *Value) Free()

Free marks 'v' as no longer used and updates its reference count. 'v' must not be used afterwards.

func (Value) GetProperty deprecated

func (v Value) GetProperty(this Value, prop Atom) (r any, err error)

GetProperty returns v.prop. The 'this' argument is ignored.

Deprecated: The 'this' argument is vestigial, the property is always looked up on 'v'. Use Value.Property instead.

func (Value) GetPropertyValue

func (v Value) GetPropertyValue(prop Atom) (r Value, err error)

GetPropertyValue returns v.prop.

func (Value) IsUndefined

func (v Value) IsUndefined() bool

IsUndefined reports whether 'v' represents the Javascript value 'undefined'.

func (Value) MarshalJSON

func (v Value) MarshalJSON() (r []byte, err error)

MarshalJSON implements encoding/json.Marshaler.

func (Value) Property

func (v Value) Property(prop Atom) (r any, err error)

Property returns v.prop. It is Value.GetProperty without the vestigial 'this' argument.

func (Value) SetProperty

func (v Value) SetProperty(prop Atom, val any) (err error)

SetProperty sets v.prop = val.

func (Value) SetPropertyValue

func (v Value) SetPropertyValue(prop Atom, val Value) (err error)

SetPropertyValue sets v.prop = val.

func (Value) Then

func (v Value) Then(onFulfilled, onRejected func(Value)) (_ Value, err error)

Then attaches fulfillment and rejection handlers to the Promise v, returning the new promise for chaining. Either onFulfilled or onRejected may be nil.

func (*Value) VM

func (v *Value) VM() *VM

VM returns the VM associated with 'v'.

Directories

Path Synopsis
Package fmt exposes some functionality of the Go stdlib fmt package to a quickjs.VM.
Package fmt exposes some functionality of the Go stdlib fmt package to a quickjs.VM.
internal
fixlib command
Command fixlib reapplies this fork's changes to the engine under lib/ after its files were taken from upstream libquickjs, as happens when a git subtree pull hits a conflict in a generated ccgo_*.go file and the upstream version is checked out.
Command fixlib reapplies this fork's changes to the engine under lib/ after its files were taken from upstream libquickjs, as happens when a git subtree pull hits a conflict in a generated ccgo_*.go file and the upstream version is checked out.
Package intl implements ECMA-402, the ECMAScript Internationalization API, for a quickjs.VM.
Package intl implements ECMA-402, the ECMAScript Internationalization API, for a quickjs.VM.
internal/gen command
Command gen builds intl/cldr.bin, the locale data package intl formats with, from the JSON distribution of CLDR (github.com/unicode-org/cldr-json).
Command gen builds intl/cldr.bin, the locale data package intl formats with, from the JSON distribution of CLDR (github.com/unicode-org/cldr-json).
Package libquickjs is a pure Go embeddable Javascript engine.
Package libquickjs is a pure Go embeddable Javascript engine.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL