Paradise

Paradise reads a web page in source — HTML, JavaScript, and CSS together — and reasons about how it will behave, before it renders. Underneath sits a particular stance: source code is a projection of an executable model of behaviour, and accessibility is a property you verify against that model — not a checklist you apply to the code. Most tooling asks is this attribute present? Paradise is built to ask what can a user do here, and where does that break down?

What ships today is the first and simplest application of that idea: a multi-model analyser. It parses HTML, JavaScript, and CSS into one integrated model and runs fourteen analysers over it — catching issues single-file linters miss and ones rendered-DOM scanners can’t tell from intentional behaviour, with a measured 88% fewer false positives than axe and eslint-jsx-a11y on the test corpus.

In this application ActionLanguage acts as a kind of intermediate representation — a structured form of the program that is easier to reason about than raw source, the familiar role an IR plays. But it is not an IR Paradise builds on the fly. Its action semantics, relationships, and state models are explicit and complete: it is a model in its own right — an architecture domain in the Shlaer-Mellor sense — that Paradise populates.

It descends from doctoral work on adaptive user interfaces — published in the W4A 2008 CISNA Model paper, parked when I left academia for CNIB, and finished, fifteen years later, when source-level reasoning about JavaScript turned out to be exactly the missing piece for honest accessibility analysis.

Paradise is a platform I continue to develop, not a finished commercial tool. Fourteen working analysers, twenty-one ARIA widget patterns validated, ninety-five passing tests, over ninety percent coverage. Available as a VS Code extension: the extension is in active development, and is available in source at bobdodd/paradise. A browser plugin version is planned. A working in-browser Playground demonstrates what the analysers detect and serves as a template for anyone wanting to build their own analysis surface. GPL-3.0. Source on GitHub.

What Paradise is

Most accessibility tooling sees one slice of a web page. Linters like eslint-plugin-jsx-a11y read a JavaScript file in isolation and flag patterns that might be problems — they never see the HTML the handler actually attaches to. Browser-based scanners like axe, WAVE, and Lighthouse read the rendered DOM after JavaScript has run — they see the result, but they cannot tell whether a missing handler was an oversight in the source or an artefact of a code path the scanner did not trigger.

Paradise reads the source. It parses HTML into a DOMModel, JavaScript into an ActionLanguage tree, and CSS into a CSSModel; it merges the three into a unified DocumentModel using CSS selectors as the joining key; and it runs its analysers over the integrated structure. A button defined in index.html, given a click handler in handlers.js, hidden by a CSS class in styles.css, is one element to Paradise. Its analysers reason about that single element across all three files at once.

The current set covers cross-file event-handler validation, ARIA relationship validation, focus-management validation, all twenty-one WAI-ARIA widget patterns, and framework-specific patterns for React, Vue, Svelte, and Angular. Most ship as multi-model analysers that require all three sources together. A few work on JavaScript alone — useful as a fallback when the corresponding HTML isn’t available.

What’s different about it

Three families of accessibility analysis tools, in the order they appear in most projects:

AST-pattern lintersRendered-DOM scannersParadise
Exampleseslint-plugin-jsx-a11yaxe, WAVE, LighthouseParadise
What it readsone file’s ASTthe rendered DOMsource HTML + JS + CSS
Sees source intentyesnoyes
Sees runtime effectsnoyesyes (via the IR)
Cross-file reasoningnon/a (one DOM only)yes
Framework-awarepartiallynoyes

The cost of seeing only one slice is false positives. An AST linter flags a <div onclick> even when the handler in another file is keyboard-accessible. A rendered-DOM scanner flags a missing aria-labelledbytarget because the JavaScript that injects it runs on a code path the scanner didn’t trigger. Both tools are noisy enough that practitioners learn to ignore their output — which means real issues hide in the noise.

Paradise’s measured false-positive reduction against axe and ESLint-jsx-a11y on the test corpus is 88%. The methodology and the case studies live on the evidence page (in progress).

The ActionLanguage intermediate representation

The technical contribution. Most JavaScript analysis works on the abstract syntax tree — what was written. Paradise’s ActionLanguage works on a tree of actions — what the program does. A loop over an array becomes an iteration node; a closure over a variable becomes a binding node; an addEventListener becomes a registration node tied to the selector it targets.

The form of the tree comes directly from my PhD-era work on adaptive user interfaces, where it described the executable semantics of small algorithm fragments that could be substituted at runtime to suit a particular user. The same shape — actions in a tree, sequenced, with attributes — turned out to be exactly what was needed to reason about runtime accessibility behaviour from source. The IR is annotated enough to recover original line numbers for diagnostics, but abstract enough that two semantically-equivalent JavaScript fragments collapse to the same tree.

The bigger idea: accessibility as behavioural verification

The analyser is the visible part. The architecture underneath is model-driven engineering — specifically Shlaer-Mellor, the original executable-modelling method, where a system is a set of formal domains joined by explicit counterpart mappings and behaviour is modelled as precisely as data. In that frame ActionLanguage is the behavioural architecture domain that the CISNA accessibility domains map into — many-to-many, across the Shlaer-Mellor bridges; remediation becomes a transformation of the model, not a patch to the text; and a model that executes can be simulated.

Simulation is what would make this different in kind, not degree. Today’s tools work at three levels — static rules, runtime inspection (axe, the accessibility tree), and human testing. A simulable model adds a fourth: run a capability model — a keyboard-only user, a switch user, a screen-reader user — against the behavioural model and ask whether they can ever reach a state where focus is trapped, an announcement never fires, or a control becomes unreachable. That is behavioural verification — the posture safety-critical engineering takes — and it is how the older idea of intrinsic accessibility becomes something you can actually check.

It also meets current AI research from an unusual direction. Most AI code-remediation treats source text as primary and infers behaviour, or skips the model and rewrites the text — producing diffs no one can verify. This architecture inverts that: the model is primary, the code is a projection, and the counterpart-mapping chain gives remediation what AI rewriting lacks — traceability, and verification by re-simulation. In the clean theory the model is populated by counterpart mapping across the bridges; in the implementation the harder, more opaque step is the lift — recovering a faithful behavioural model from real-world JavaScript, and verifying that it is faithful. That is the open problem, and where the research edge sits.

Most of this section describes the architecture’s reach and trajectory, not shipped features. What ships today is the analyser and its suggested fixes; simulation and model-level adaptation are where the platform is going.

Status, scope, and what it does not do

  • Working analysers for the families listed above. Detail page in progress.
  • Confidence-weighted findings. Every issue carries a HIGH / MEDIUM / LOW level and a short reason, exposed as a percentage in the surfaces. Confidence is engine certainty given the source it has, not severity. See Architecture for how the level resolves and why.
  • Suggested fixes.For many findings the engine emits a corrective code suggestion alongside the diagnostic. Surfaces apply best-effort: the Playground’s Fix dialog, the VS Code plugin’s Quick Fixes (Code Actions), and CI consumers iterating issue.fix programmatically.
  • VS Code plugin in active development. Distributed as a .vsix from the source repo.
  • Browser plugin planned, not yet built.
  • CI use via the analyser engine consumed as a Node library.
  • Honest limitations.Paradise does not see things that only exist at runtime — third-party widgets injected into iframes, dynamically loaded modules whose source isn’t present, content fetched at interaction time. For those, runtime tools win. autoA11y is the runtime complement; its history (academic origins, multiple lineages including a commercial CNIB version) belongs on the research page.
  • Not a replacement for human review. Like every other tool in this space, Paradise reports what it can detect, not everything that matters.

Source, licence, citation

Paradise is open source at bobdodd/paradise. History extracted with git filter-repo from its original home as the Action Language/ subdirectory of the doctoral repo, so every commit that ever touched the code is preserved in the new repo.

Licence: GPL-3.0-or-later for the analyser engine and the VS Code plugin, matching the rest of the Bob-owned tooling. The companion documentation pages (this page and the /paradise/*sub-pages) are CC BY-SA 4.0 alongside the rest of a11ybob.com.

The W4A 2008 paper underlying the ActionLanguage tree shape: Dodd, Green & Pearson — The CISNA Model of Accessible Adaptive Hypermedia.

More

  • Lineage — the PhD-era work, the W4A 2008 CISNA Model paper, where ActionLanguage came from, and the relationship with autoA11y.
  • Architecture — the multi-model approach in detail, with a worked example of cross-file analysis.
  • ActionLanguage IR — the form of the tree, the model entities, and a worked JS-to-IR translation.
  • Analysers — the fourteen accessibility analysers that ship with Paradise, grouped by family, each with its own page.
  • Widget patterns — the twenty-one canonical WAI-ARIA widget patterns, with expected roles, states, and keyboard interactions for each.
  • Evidence — the 88% number, the corpus and methodology behind it, and where Paradise still misses.
  • VS Code plugin — install, configure, use; current release status and the planned browser plugin.
  • Cite — suggested citation, BibTeX entries for Paradise and the W4A 2008 paper.
  • Playground— the in-browser surface running Paradise’s analysers.