@shexjs/extension-wasi-test
v1.0.0-alpha.33
Published
Shape Expressions Test semantic action module implemented in WebAssembly, printing via WASI fd_write.
Readme
@shexjs/extension-wasi-test
The ShEx Test semantic-action extension
reimplemented in hand-written WebAssembly.
A drop-in alternative to
@shexjs/extension-test: same extension URL
(http://shex.io/extensions/Test/), same grammar, same results collection and
SemActFailure protocol — but the parsing and argument assembly run inside a
1.3 KB Wasm module (lib/extension-wasi-test.wat),
and each assembled line is genuinely printed through
WASI — the WebAssembly System Interface
(wasi_snapshot_preview1), the standardized "libc analog" syscall layer for
Wasm runtimes. fd_write, the one import this module uses, is the
writev(2)-shaped call that wasi-libc's
printf bottoms out in.
npm install @shexjs/extension-wasi-testBeing WASI-portable is the point: the same .wasm binary could execute a
schema's Test semantic actions under any conforming host — another ShEx
implementation, wasmtime, a browser WASI polyfill — not just this JavaScript
one.
usage
Anywhere @shexjs/extension-test works. With the
CLI's --extension:
npx shex-validate \
-x doc.shex -d doc.ttl -n tag:node123 \
--extension @shexjs/extension-wasi-testor via the API:
const WasiTest = require("@shexjs/extension-wasi-test");
const results = WasiTest.register(validator, {ShExTerm});
// ... validator.validateShapeMap(...) ...
WasiTest.done(validator);Semantic actions look like:
PREFIX ex: <http://ex.example/#>
ex:S { ex:p1 . %<http://shex.io/extensions/Test/>{ print(s, ' ', o) %} }Each print(...)/fail(...) invocation concatenates its arguments — quoted
strings with the outer quotes stripped and the two sanctioned escapes decoded
(\\ and \<quote> each yield their second character, per the extension
definition) and s/p/o as the matched triple's term
.values — collects the line in
validator.semActHandler.results["http://shex.io/extensions/Test/"], and
writes the line plus "\n" to WASI fd 1 as a single gathered fd_write
(one ciovec for the line, one for the newline). print succeeds; fail
reports a SemActFailure.
configuration
configure(overrides) derives a module bound to different host options:
const quiet = WasiTest.configure({
stdout: someFd, // host file descriptor receiving WASI fd 1 (default 1)
impl: "shim", // "wasi" | "shim" | "auto" (default)
});wasihosts the module with Node's built-innode:wasi(constructing it prints anExperimentalWarning; silence with--no-warningsif it offends).shimhosts it with a ~20-linefd_writeimplemented in this package — for Nodes wherenode:wasiis absent or flag-gated, or when you want no warning. The Wasm module can't tell the difference; its one import is standard WASI either way.auto(default) triesnode:wasi, falls back to the shim.
the Wasm ABI
The module is a pure WASI reactor (exports _initialize, no _start). The
host packs the semantic-action code and the in-scope term values as UTF-8 into
linear memory at inputBase and calls:
dispatch(codePtr, codeLen, sPtr, sLen, pPtr, pLen, oPtr, oLen) -> statuspassing length -1 for any term not in scope (e.g. startActs). Statuses:
| status | meaning |
|-------:|---------|
| 1 PASS | code matched print; line assembled and printed |
| 0 FAIL | code matched fail; line assembled and printed |
| -1 NO_MATCH | code didn't match the grammar (host throws an invocation error) |
| -2 NO_TRIPLE | a position was referenced with no triple in scope; errCode holds the letter |
| -3 WRITE_ERROR | fd_write errored (errCode holds the WASI errno) or stalled |
| -4 OOM | memory.grow refused to enlarge the line buffer |
After PASS/FAIL the assembled line sits at exported globals
linePtr/lineLen for the host to collect into
semActHandler.results. The module grows its own memory for arbitrarily
large lines and retries partial writes; the full grammar, memory map and host
protocol are documented at the top of
lib/extension-wasi-test.wat.
building
lib/extension-wasi-test.wasm is committed. To rebuild it from the .wat
source (using the wabt toolchain's
wat2wasm, a devDependency):
npm install && npm run builddeviations from @shexjs/extension-test
print/faillines are actually printed (WASI fd 1); the reference implementation only collects them.- Error texts differ (e.g. referencing a position with no triple in scope
throws a descriptive invocation error rather than a
TypeError), but every code that throws there throws here and vice versa — see the parity suite intest/extension-wasi-test-test.js.
@shexjs/extension-wasi-test is one of the shex.js packages; installing shex pulls in the whole suite, and its README maps them.
