Issues and pull requests are welcome. The library is small and the tests are fast, so the loop below runs in seconds on a development machine — no Nerves toolchain and no device needed for anything except the extension itself.
Running the tests
There are three layers, and CI runs all of them:
make check # C unit tests — libc only, no GLib, no WebKit
make -C test/c syntax # compile the WebKit-facing C (needs GLib)
mix test # the Elixir side
mix format --check-formatted
The parsing, matching and configuration layers (c_src/manifest.c,
match_pattern.c, config.c, json.c) are deliberately libc-only so they can be
tested anywhere with a compiler. That covers the whole precedence between
manifest, device configuration and meta tag, including the property the design
rests on: a page that is not a trusted origin cannot switch a script off.
injector.c and extension.c need WebKit, so they are not in the unit tests.
make -C test/c syntax compiles them against declared signatures in test/c/stubs
so a typo does not have to wait for a device build. It checks our use of the API,
not the API — a WebKit change is still something only a device build finds.
Trying a change without a device
mix myelin.harness
open http://127.0.0.1:8899/test/harness.html
The harness wraps each script the way the extension does — same prelude, same
ctx argument — so what runs in the browser is what runs on a device. Settings
come from test/config.json and from query parameters that become meta tags.
?trusted=0 puts it in the foreign-page state. See Development in the README
for the details.
Use real clicks rather than element.click() when testing anything
keyboard-related: a scripted click moves no focus.
Building the extension
Only a cross-compile produces the .so:
MIX_TARGET=<target> mix compile
Three invariants in the Makefile are easy to break by accident — pkg-config pointing
at the toolchain rather than the sysroot, --cflags without --libs, and undefined
symbols being intended. They are written up in the Makefile's own header, next to
the code they constrain. Read that before changing it.
Style
mix formatfor Elixir. The C is hand-formatted; match the file you are in.- Scripts are ES5-compatible plain JS, no build step, no dependencies. They are meant to be read and reworked by whoever copies them, so clarity beats brevity.
- User-facing strings are English, and configurable where that is reasonable.
Adding a script
A script is a plain .js file whose body is the script — the loader wraps it in a
function, so there is no IIFE to write and no "use strict" to declare. Settings come
from ctx.config(name, default), events from ctx.on and ctx.emit, and everything
else from the DOM. Read priv/scripts/tap-to-top for the shortest whole example, and
Writing a script in the README for the rest.