Programmatic API
@kodalabs-io/eqo exposes a full programmatic API for use as a library in your own scripts, custom CI integrations, or tooling. All exports are ESM and fully typed.
import { analyze, loadConfig, writeReports } from "@kodalabs-io/eqo";Core functions
Section titled “Core functions”analyze(config, options?)
Section titled “analyze(config, options?)”Run the full RGAA v4.1.2 analysis (static + runtime, or either phase alone) and return the complete report.
function analyze( config: KodaRGAAConfig, options?: { staticOnly?: boolean; runtimeOnly?: boolean; projectRoot?: string; // defaults to process.cwd() signal?: AbortSignal; }): Promise<RGAAReport>Example:
import { analyze, loadConfig } from "@kodalabs-io/eqo";
const config = await loadConfig();const report = await analyze(config);
const pct = Math.round(report.summary.complianceRate * 100);console.log(`Compliance: ${pct}%`);console.log(`Issues: ${report.issues.length}`);Static-only (no browser):
const report = await analyze(config, { staticOnly: true });With abort signal (graceful cancellation):
const controller = new AbortController();setTimeout(() => controller.abort(), 30_000); // 30-second timeout
const report = await analyze(config, { signal: controller.signal });loadConfig(cwd?, configPath?)
Section titled “loadConfig(cwd?, configPath?)”Load and validate the Eqo configuration file. Searches cwd for rgaa.config.ts/js/mjs/json by default, or loads the file at configPath if provided.
function loadConfig( cwd?: string, // defaults to process.cwd() configPath?: string // explicit path to config file): Promise<KodaRGAAConfig>Throws ConfigError if the file is not found or fails schema validation.
Example:
import { loadConfig, ConfigError } from "@kodalabs-io/eqo";
try { const config = await loadConfig(process.cwd(), "./custom.config.ts"); console.log(`Project: ${config.projectName}`);} catch (err) { if (err instanceof ConfigError) { console.error("Config error:", err.message); } process.exit(1);}defineConfig(config)
Section titled “defineConfig(config)”A zero-overhead identity function that returns its argument unchanged. Its only purpose is to enable TypeScript inference on KodaRGAAConfig in config files.
function defineConfig(config: KodaRGAAConfig): KodaRGAAConfigimport { defineConfig } from "@kodalabs-io/eqo";
export default defineConfig({ baseUrl: "http://localhost:3000", // TypeScript will catch type errors and provide autocompletion here});writeReports(report, outputs)
Section titled “writeReports(report, outputs)”Write the analysis report in all configured output formats. Returns the list of file paths that were successfully written.
function writeReports( report: RGAAReport, outputs: OutputConfig[]): Promise<string[]>Example:
import { analyze, loadConfig, writeReports } from "@kodalabs-io/eqo";
const config = await loadConfig();const report = await analyze(config);
const written = await writeReports(report, config.output);for (const path of written) { console.log(`Written: ${path}`);}Individual format writers are also exported for granular control:
import { writeJsonReport, writeHtmlReport, writeSarifReport, writeMarkdownReport, writeJunitReport,} from "@kodalabs-io/eqo";
// Write only the JSON report to a custom pathawait writeJsonReport(report, "./custom-output/report.json", { minify: true });printReport(report)
Section titled “printReport(report)”Print the compliance summary to stdout in the same format as the CLI.
function printReport(report: RGAAReport): voidrunStaticAnalysis(config, options?)
Section titled “runStaticAnalysis(config, options?)”Run only the static (Babel AST) analysis phase and return its issues.
function runStaticAnalysis( config: KodaRGAAConfig, options?: { projectRoot?: string; signal?: AbortSignal }): Promise<RGAAIssue[]>runRuntimeAnalysis(config, options?)
Section titled “runRuntimeAnalysis(config, options?)”Run only the runtime (Playwright + axe-core) analysis phase and return its issues.
function runRuntimeAnalysis( config: KodaRGAAConfig, options?: { signal?: AbortSignal }): Promise<RGAAIssue[]>buildReport(config, issues, pages?)
Section titled “buildReport(config, issues, pages?)”Assemble a RGAAReport from a flat array of issues. Useful when you have collected issues through custom analysis logic and want to produce a report in any of Eqo’s output formats.
function buildReport( config: KodaRGAAConfig, issues: RGAAIssue[], pages?: PageResult[]): RGAAReportConfiguration utilities
Section titled “Configuration utilities”resolveConfigPath(cwd, configPath?)
Section titled “resolveConfigPath(cwd, configPath?)”Resolve the absolute path to the config file using Eqo’s default search order (ts → js → mjs → json).
function resolveConfigPath( cwd: string, configPath?: string): Promise<string | null>generateDefaultConfig(projectName?)
Section titled “generateDefaultConfig(projectName?)”Generate the default configuration string (the same content as eqo init).
function generateDefaultConfig(projectName?: string): stringCriteria utilities
Section titled “Criteria utilities”ALL_CRITERIA
Section titled “ALL_CRITERIA”The complete RGAA v4.1.2 criteria catalog — an array of 106 CriterionDefinition objects.
import { ALL_CRITERIA } from "@kodalabs-io/eqo";
console.log(`Total criteria: ${ALL_CRITERIA.length}`); // 106
const manualCriteria = ALL_CRITERIA.filter( (c) => c.automationLevel === "manual");console.log(`Manual criteria: ${manualCriteria.length}`);THEMES
Section titled “THEMES”Array of ThemeDefinition objects, one per RGAA theme (13 total).
CRITERIA_BY_ID
Section titled “CRITERIA_BY_ID”A Map<string, CriterionDefinition> for O(1) lookup by criterion ID.
import { CRITERIA_BY_ID } from "@kodalabs-io/eqo";
const criterion = CRITERIA_BY_ID.get("1.1");// → { id: "1.1", theme: 1, level: "A", wcag: ["1.1.1"], automationLevel: "full", ... }TOTAL_CRITERIA
Section titled “TOTAL_CRITERIA”const TOTAL_CRITERIA: number = 106i18n utilities
Section titled “i18n utilities”loadTranslations(locale)
Section titled “loadTranslations(locale)”Load and cache the translation catalog for a locale. Must be called before getTranslations.
function loadTranslations(locale: SupportedLocale): Promise<void>getTranslations(locale)
Section titled “getTranslations(locale)”Return the cached Translations object for a locale. Throws if loadTranslations has not been called first.
function getTranslations(locale: SupportedLocale): Translationsinterpolate(template, context)
Section titled “interpolate(template, context)”Interpolate named placeholders in a translation string.
function interpolate( template: string, context: Record<string, string>): stringgetSupportedLocales()
Section titled “getSupportedLocales()”function getSupportedLocales(): SupportedLocale[]// → ["en-US", "fr-FR"]axe-core mapping
Section titled “axe-core mapping”AXE_TO_RGAA
Section titled “AXE_TO_RGAA”A map from axe-core rule IDs to their corresponding RGAA criterion IDs.
import { AXE_TO_RGAA } from "@kodalabs-io/eqo";
const rgaaCriteria = AXE_TO_RGAA["color-contrast"];// → ["3.2", "3.3"]getRGAACriteria(axeRuleId)
Section titled “getRGAACriteria(axeRuleId)”Get the RGAA criterion IDs for a given axe-core rule ID.
function getRGAACriteria(axeRuleId: string): string[]getAxeRulesForCriterion(criterionId)
Section titled “getAxeRulesForCriterion(criterionId)”Get the axe-core rule IDs that map to a given RGAA criterion ID.
function getAxeRulesForCriterion(criterionId: string): string[]Error classes
Section titled “Error classes”ConfigError
Section titled “ConfigError”Thrown by loadConfig when the configuration file is missing, unparseable, or fails schema validation.
class ConfigError extends Error { name: "ConfigError"}AnalysisError
Section titled “AnalysisError”Thrown by analyze when a fatal error occurs during analysis (e.g., Playwright crash, worker pool failure).
class AnalysisError extends Error { name: "AnalysisError"}TimeoutError
Section titled “TimeoutError”Thrown when a page load or worker exceeds its configured timeout.
class TimeoutError extends Error { name: "TimeoutError"}Type reference
Section titled “Type reference”KodaRGAAConfig
Section titled “KodaRGAAConfig”The root configuration type. See Configuration for the full field reference.
interface KodaRGAAConfig { baseUrl: string; pages: PageConfig[]; output: OutputConfig[]; thresholds?: ThresholdConfig; exemptions?: ExemptionConfig[]; locale?: SupportedLocale; projectName?: string; static?: StaticConfig;}RGAAReport
Section titled “RGAAReport”The full analysis report returned by analyze().
interface RGAAReport { meta: { rgaaVersion: "4.1.2"; toolVersion: string; generatedAt: string; // ISO 8601 projectName?: string; analyzedPages: string[]; locale: SupportedLocale; }; summary: ReportSummary; themes: ThemeResult[]; pages: PageResult[]; issues: RGAAIssue[];}ReportSummary
Section titled “ReportSummary”interface ReportSummary { totalCriteria: number; // always 106 applicable: number; // criteria applicable to at least one page validated: number; // applicable criteria that passed invalidated: number; // applicable criteria that failed notApplicable: number; // not applicable or exempted needsReview: number; // require manual check (excluded from rate) complianceRate: number; // validated / applicable (0–1)}RGAAIssue
Section titled “RGAAIssue”A single accessibility issue found during analysis.
interface RGAAIssue { id: string; // unique issue ID criterionId: string; // e.g., "1.1" testId: string; // e.g., "1.1.1" phase: AnalysisPhase; // "static" | "runtime" severity: IssueSeverity; // "error" | "warning" | "notice" element?: string; // serialized HTML of the offending element file?: string; // source file path (static phase) line?: number; column?: number; page?: string; // page path (runtime phase) messageKey: string; // i18n message key remediationKey: string; // i18n remediation key messageContext?: Record<string, string>; wcag?: string; // WCAG success criterion (e.g., "1.1.1")}ThemeResult
Section titled “ThemeResult”interface ThemeResult { id: number; complianceRate: number; // 0–1 for this theme only criteriaResults: CriterionResult[];}CriterionResult
Section titled “CriterionResult”interface CriterionResult { id: string; // e.g., "1.1" status: CriterionStatus; // "validated" | "invalidated" | "not-applicable" | "needs-review" issueCount: number; testResults: TestResult[];}PageResult
Section titled “PageResult”interface PageResult { url: string; path: string; title?: string; issueCount: number; error?: string; // set if the page could not be analyzed}Enum types
Section titled “Enum types”type AutomationLevel = "full" | "partial" | "manual";type CriterionStatus = "validated" | "invalidated" | "not-applicable" | "needs-review";type IssueSeverity = "error" | "warning" | "notice";type AnalysisPhase = "static" | "runtime";type WCAGLevel = "A" | "AA";type OutputFormat = "json" | "html" | "sarif" | "markdown" | "junit";type SupportedLocale = "en-US" | "fr-FR";Full programmatic example
Section titled “Full programmatic example”This example runs a static-only analysis, filters for error-severity issues, and writes a custom Markdown summary — without using any CLI.
import { analyze, loadConfig, writeReports, ConfigError, AnalysisError,} from "@kodalabs-io/eqo";import { writeFile } from "node:fs/promises";
async function main() { // Load config let config; try { config = await loadConfig(); } catch (err) { if (err instanceof ConfigError) { console.error(`Configuration error: ${err.message}`); process.exit(1); } throw err; }
// Run static-only analysis let report; try { report = await analyze(config, { staticOnly: true }); } catch (err) { if (err instanceof AnalysisError) { console.error(`Analysis failed: ${err.message}`); process.exit(1); } throw err; }
const pct = Math.round(report.summary.complianceRate * 100); console.log(`Compliance: ${pct}%`);
// Filter for errors only const errors = report.issues.filter((i) => i.severity === "error"); console.log(`Errors: ${errors.length}`);
// Write all configured output formats await writeReports(report, config.output);
// Write a custom summary const summary = [ `# RGAA Audit Summary`, ``, `- **Compliance:** ${pct}%`, `- **Errors:** ${errors.length}`, `- **Total issues:** ${report.issues.length}`, ``, `## Errors`, ...errors.map( (i) => `- **${i.criterionId}** ${i.file ? `\`${i.file}:${i.line}\`` : i.page ?? ""}` ), ].join("\n");
await writeFile("./reports/summary.md", summary, "utf8");}
main();Adding a new locale
Section titled “Adding a new locale”To contribute a new language:
- Create
src/i18n/<locale>.tsimplementing theTranslationsinterface - Register it in
src/i18n/index.ts - Submit a pull request — see CONTRIBUTING.md
The Translations interface defines message keys for every issue type, remediation guidance, and console output. See src/i18n/en-US.ts for the complete reference implementation.