Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/accessibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
node-version: 22

# In your own repository this becomes:
# uses: likeBloodMoon/eaa-kit@v0.9.1
# uses: likeBloodMoon/eaa-kit@v0.10.0
#
# An exact release tag. There is deliberately no moving v0 tag to follow:
# this is a 0.x package, the flags and the JSON contract can still move
Expand Down
122 changes: 122 additions & 0 deletions .github/workflows/soak.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Soak

# Real projects, built from scratch, every night.
#
# The stack fixtures in tests/fixtures/stacks are file layouts, checked on every
# pull request, and they are only as true as the day they were copied. A
# framework's next release can move its output directory or change a manifest
# format without touching any of them. This scaffolds each framework with its
# own official starter, installs it, builds it the way `npx eaa-kit` would, and
# audits it, so a change on the framework's side shows up here within a day,
# and before somebody's first run meets it.
#
# Too slow and too dependent on registries to gate a pull request. A red run
# here is triaged into a fix or an issue, not left standing.

on:
schedule:
- cron: '17 3 * * *'
workflow_dispatch:

permissions:
contents: read

jobs:
stack:
name: ${{ matrix.stack }} on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
stack: [next, astro, sveltekit, nuxt, docusaurus, vite]
include:
# The one most people meet first, on the other two platforms too.
- os: windows-latest
stack: next
scaffold: npx --yes create-next-app@16 site --yes --use-npm --skip-install
- os: macos-latest
stack: next
scaffold: npx --yes create-next-app@16 site --yes --use-npm --skip-install
- stack: next
scaffold: npx --yes create-next-app@16 site --yes --use-npm --skip-install
- stack: astro
scaffold: npm create --yes astro@4 site -- --template minimal --no-install --no-git --yes
- stack: sveltekit
scaffold: npx --yes sv@0 create site --template minimal --types ts --no-add-ons --no-install
- stack: nuxt
scaffold: npx --yes nuxi@3 init site --template minimal --packageManager npm --gitInit false --no-install
- stack: docusaurus
scaffold: npx --yes create-docusaurus@3 site classic --javascript --package-manager npm --skip-install
- stack: vite
scaffold: npm create --yes vite@7 site -- --template react-ts --no-interactive
# A Vite app is an empty shell until its script runs.
browser: true

runs-on: ${{ matrix.os }}
timeout-minutes: 30

steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm

- run: pnpm install --frozen-lockfile

- run: pnpm build

- name: Scaffold ${{ matrix.stack }}
working-directory: ${{ runner.temp }}
shell: bash
# No terminal, as in CI: every starter here was checked to run
# without asking anything.
run: ${{ matrix.scaffold }} < /dev/null

- name: Install its dependencies
working-directory: ${{ runner.temp }}/site
shell: bash
run: |
npm install --no-audit --no-fund
if [ "${{ matrix.browser }}" = "true" ]; then
npm install --no-audit --no-fund -D playwright
npx playwright install ${{ runner.os == 'Linux' && '--with-deps' || '' }} chromium
fi

- name: What detect makes of it
working-directory: ${{ runner.temp }}/site
shell: bash
run: node "$GITHUB_WORKSPACE/dist/cli/index.js" detect --json | tee detect.json

# Exit 1 means barriers were found, which is a working run. Exit 2 means
# it could not audit the project at all, which is what this job exists
# to catch.
- name: Audit it with no directory, so detection decides
working-directory: ${{ runner.temp }}/site
shell: bash
run: |
set +e
node "$GITHUB_WORKSPACE/dist/cli/index.js" audit ${{ matrix.browser && '--browser' || '' }} \
--format json --output report.json
code=$?
set -e
echo "exit code $code"
test "$code" -le 1
node -e '
const r = require("./report.json")
const pages = r.pages.length
console.log(`${pages} pages, discovery ${r.completeness.discovery}`)
if (pages === 0) process.exit(1)
'

- uses: actions/upload-artifact@v4
if: always()
with:
name: soak-${{ matrix.stack }}-${{ matrix.os }}
path: |
${{ runner.temp }}/site/detect.json
${{ runner.temp }}/site/report.json
if-no-files-found: ignore
74 changes: 74 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,80 @@ move: the JSON report's `schemaVersion` and the baseline file's. Both are bumped
a field is removed, renamed, or changes meaning — new fields may appear without one, so
consumers must ignore what they do not recognise.

## 0.10.0 — 2026-09-26

It finds your site, whatever it is built with.

### Added

- **Next.js, in depth.** With no directory, a Next.js app that renders on a server is
built, started with `next start` on a free port, and crawled from the list of pages its
own build manifests give, so a page nothing links to is still audited. `basePath`, the
default locale's unprefixed paths and `trailingSlash` are respected; API routes, error
pages and metadata files are left out. A dynamic route with no prerendered pages is named
as not audited, with the reason. A standalone build is served by its `server.js` when its
static files are in place. `next dev` is never used.
- **Twenty more stacks**:
- apps: Qwik, SolidStart, TanStack Start, Analog, Vue CLI, Parcel, Rsbuild, Rspack and
Ember;
- documentation and static generators: Hexo, MkDocs, Sphinx, mdBook, Zola, Quarto and
Pelican, each with its output directory read out of its config;
- never started, and pointed at `--url`: Drupal, Statamic, and Ghost and Shopify themes.

Hugo is also found through `config/_default/`. Zola is told from Hugo by what
`config.toml` says, and Hexo from Jekyll by its dependency.
- **Monorepos.** Run from the root of a pnpm, yarn or npm workspace, or a Turborepo, Nx or
Lerna repository, `eaa-kit` finds the packages that are sites. One site is audited as
though the command ran inside it. Several are listed with the command for each. `init`
asks which site to set up and writes the config there.
- **Package managers.** Corepack's `packageManager` field is read first, then the lockfile:
Bun's text `bun.lock`, `deno.lock` and `package-lock.json` as well as pnpm's, yarn's and
Bun's binary one. The lockfile is looked for up to the repository root. Deno runs scripts
as tasks, and `init` writes a Deno or Bun setup step into the workflow.
- **`eaa-kit detect [dir]`** says what an audit here would do, and the evidence for each
part: the framework and what identified it, the package manager and why, the build
output or what would be built or started. It builds, starts and writes nothing.
`--json` prints the same as data.
- **`eaa-kit doctor [dir]`** checks, on one screen, everything the tool needs in a
project. Each problem is followed by the command that fixes it:
- the Node.js version;
- the package manager;
- the site;
- the config;
- a GitHub, GitLab or Bitbucket pipeline;
- the baseline and any expired entries;
- Playwright and Chromium.

It exits 2 only for what stops an audit from running.
- **A recorded answer for every stack.** `tests/fixtures/stacks` holds one project layout
per kind of stack, with the answer `detect` must give for it, and the suite checks each
one. A nightly job scaffolds Next.js, Astro, SvelteKit, Nuxt, Docusaurus and a Vite app
from their official starters, installs them and audits them with no directory.

### Changed

- **A single-page app's empty shell is no longer audited as a clean page.** A page with
nothing a visitor could perceive before a script runs, such as a Vite build's
`<div id="root"></div>`, is set aside and listed in `completeness.unreachable`. A build
that holds only a shell stops with exit 2 and the command to audit it with `--browser`,
which runs the script as before.
- **`storybook-static/` is never audited** as part of the site.
- **Servers are started on a free port,** offered through `PORT`. The address a server
prints is read through colour codes and `0.0.0.0`. The Angular, Gatsby, Hugo and Jekyll
default ports are also tried.

### Fixed

- **On Windows, a server the audit started is stopped with everything it started.**
Stopping only the `cmd.exe` that ran the script left the real server running after
the report was written, holding its port and its directory.

### Report format

- `completeness.discovery` can now be `"manifest"`: the pages came from the project's own
build, a Next.js build's manifests. `schemaVersion` stays 2, since no field was removed
or renamed. A consumer that switches on `discovery` should expect the new value.

## 0.9.1 — 2026-09-26

### Fixed
Expand Down
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ the statute and supervisory body of **fifteen countries**: Austria, Belgium, Cze
Denmark, Finland, France, Germany, Ireland, Italy, the Netherlands, Poland, Portugal,
Spain, Sweden and Switzerland, each in its own language as well as English.

0.10.0 finds your site, whatever it is built with. A Next.js app that renders on a server
is built, started and audited page by page from its own build manifests, including pages
nothing links to. Forty-one stacks are recognised, from Qwik and TanStack Start to
MkDocs, Sphinx and Zola, and a monorepo's sites are found from its root. The package
manager comes from the project itself, Bun and Deno included. A single-page app's empty
shell is named as not audited instead of passing. `eaa-kit detect` says what the tool
makes of a project and why, and `eaa-kit doctor` checks everything it needs on one screen.

0.9.0 needs no setup. `npx eaa-kit` on its own finds the site, audits it, writes an HTML
report and says which command comes next. `init` fills itself in from what the built site
states, and also writes a baseline and a GitHub Actions workflow tailored to the project.
Expand Down Expand Up @@ -42,6 +50,8 @@ npx eaa-kit init # the config, a baseline and a CI workflow
npx eaa-kit statement # accessibility statement, in one of fifteen countries
npx eaa-kit countries # which ones, in which languages, under which law
npx eaa-kit checklist # the manual review no engine can do for you
npx eaa-kit detect # what it makes of this project, and why
npx eaa-kit doctor # everything it needs here, checked on one screen
```

> **Not legal advice.** eaa-kit reports what an automated engine can and cannot determine
Expand Down Expand Up @@ -71,8 +81,10 @@ answer.
eaa-kit audit ./dist --fail-on serious
```

Sites that render on a server and never write HTML to disk — Next.js without a static
export, Nuxt, SvelteKit, anything behind a CMS — are audited running instead:
Sites that render on a server and never write HTML to disk, such as Next.js without a
static export, Nuxt or SvelteKit, are built and started by `eaa-kit audit` with no
directory, and crawled while they run. Anything behind a CMS is never started uninvited;
start it yourself and audit it running:

```bash
eaa-kit audit --url http://localhost:3000
Expand Down
4 changes: 3 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ having to learn the tool first. These releases get there:
the wrong version.
- **0.10.0 — it finds your site.** Stack detection for what people actually build with
(Next.js properly first), monorepos and package managers, and `eaa-kit detect` and
`eaa-kit doctor` to explain what it found.
`eaa-kit doctor` to explain what it found. *Done:* forty-one stacks, Next.js served and
crawled from its build manifests, single-page-app shells named instead of passed, a
recorded `detect` answer per stack fixture, and a nightly soak over six real starters.
- **0.11.0 — it fits your workflow.** GitLab and Bitbucket CI from `init`, a Markdown
summary for job summaries and PR comments, and an HTML report that prints, speaks the
site's language and shows what changed since last time.
Expand Down
Loading
Loading