@a11y-oracle/core-engine

中文文档
1.3.2发布于 2026/03/12MITTypeScriptES Module近 30 天下载 3093

通过 Chrome DevTools 协议实现框架不可知无障碍语音引擎和统一的 A11y Orchestrator

中文使用文档
文档目录16 节
  1. 安装
  2. 使用量
  3. 语音引擎( 只有语音)
  4. A11y Orchestrator(统一州)
  5. 配置选项
  6. API 参考
  7. SpeechEngine
  8. A11yOrchestrator
  9. 类型
  10. 角色绘图
  11. 互动作用
  12. 地标角色
  13. 结构作用
  14. 寂静的角色
  15. 国家测绘
  16. 出口

@a11y-oracle/ 核心引擎

A11y-Oracle 的框架不可知访问引擎. 提供两个主要的API:

  1. SpeechEngine ——通过CDP来读取浏览器的"无障碍树"并生成标准化的语音输出.
  2. A11yOrchestrator ——统一管弦乐器,将语音,键盘调度,焦点指标分析合并为一 pressKey() 电话.

这个软件包是Playwright和Cypress插件所建立的基础. 也可以直接与任何CDP兼容的客户端使用.

安装

npm install @a11y-oracle/core-engine

使用量

语音引擎( 只有语音)

语音引擎通过一个 CDPSessionLike 接口,任何 CDP 客户端都可以满足 :

import { SpeechEngine } from '@a11y-oracle/core-engine';

// Works with Playwright's CDPSession
const cdpSession = await page.context().newCDPSession(page);
const engine = new SpeechEngine(cdpSession);
await engine.enable();

// Get speech for the currently focused element
const result = await engine.getSpeech();
console.log(result?.speech); // "Products, button, collapsed"

// Get speech for every visible element
const all = await engine.getFullTreeSpeech();
const nav = all.find(r => r.speech.includes('navigation landmark'));

// Clean up
await engine.disable();

A11y Orchestrator(统一州)

管弦乐团协调语音引擎,键盘引擎,以及焦点分析器:

import { A11yOrchestrator } from '@a11y-oracle/core-engine';

const cdpSession = await page.context().newCDPSession(page);
const orchestrator = new A11yOrchestrator(cdpSession);
await orchestrator.enable();

// Press a key and get unified state
const state = await orchestrator.pressKey('Tab');
console.log(state.speech);                       // "Products, button, collapsed"
console.log(state.focusedElement?.tag);           // "BUTTON"
console.log(state.focusIndicator.meetsWCAG_AA);  // true

// Get state without pressing a key
const current = await orchestrator.getState();

// Tab order extraction
const report = await orchestrator.traverseTabOrder();
console.log(report.totalCount);  // 12

// Keyboard trap detection (WCAG 2.1.2)
const result = await orchestrator.traverseSubTree('#modal', 20);
console.log(result.isTrapped);  // false

await orchestrator.disable();

配置选项

const engine = new SpeechEngine(cdpSession, {
  // Include "landmark" suffix on landmark roles (default: true)
  // true:  "Main, navigation landmark"
  // false: "Main, navigation"
  includeLandmarks: true,

  // Include accessible descriptions in output (default: false)
  // true:  "Submit, button, Submits the form"
  // false: "Submit, button"
  includeDescription: false,
});

const orchestrator = new A11yOrchestrator(cdpSession, {
  // All SpeechEngine options, plus:

  // Milliseconds to wait after key press for focus/CSS to settle (default: 50)
  focusSettleMs: 50,
});

API 参考

SpeechEngine

语音引擎. 所有方法都是协同的,通过CDP会话运行.

constructor(cdp: CDPSessionLike, options?: SpeechEngineOptions)

创建新引擎实例 .

  • cdp - 任何执行 CDPSessionLike 接口.
  • options.includeLandmarks ——将"地标"附录为地标性角色. 默认 true。 。 。 .
  • options.includeDescription - 包含 aria-describedby 语句。 默认 false。 。 。 .

enable(): Promise<void>

启用 CDP 无障碍域 。 一定要在任何其他方法之前叫出来.

disable(): Promise<void>

禁用 CDP 无障碍域 。 完成后调用以释放浏览器资源 .

getSpeech(): Promise<SpeechResult | null>

获取当前焦点元素的语音输出 .

回返 null 如果没有元素有焦点或焦点元素被忽略(例如, role="presentation") (中文(简体) ).

const result = await engine.getSpeech();
if (result) {
  console.log(result.speech);  // "Products, button, collapsed"
  console.log(result.name);    // "Products"
  console.log(result.role);    // "button"
  console.log(result.states);  // ["collapsed"]
  console.log(result.rawNode); // Full CDP AXNode object
}

getFullTreeSpeech(): Promise<SpeechResult[]>

获得无障碍树上所有非受辱非寂静节点的演说. 用于坚持地标,标题,或结构元素没有焦点.

const all = await engine.getFullTreeSpeech();
const headings = all.filter(r => r.role.includes('heading'));
const landmarks = all.filter(r => r.role.includes('landmark'));

computeSpeech(node: AXNode): SpeechResult | null

计算单个 AX 节点的语音 。 回返 null 被忽略或沉默的节点.

findFocusedNode(nodes: AXNode[]): AXNode | null

查找平坦 AXTree 阵列中最具体的焦点节点. 当多个节点报告时 focused: true (例如, RootWebArea (单位:千美元) menuitem),最深的节点被还原.

A11yOrchestrator

协调三个分机的统一指挥员:

发动机责任
SpeechEngineAXTree 到语音字符串
KeyboardEngineCDP 密钥发送 + document.activeElement
FocusAnalyzerCSS 焦点指标 + 标签命令 + 陷阱检测

constructor(cdp: CDPSessionLike, options?: A11yOrchestratorOptions)

创建一个新的管弦乐团.

  • cdp 任何与协调委员会兼容的会议.
  • options.includeLandmarks ——将"地标"附录为地标性角色. 默认 true。 。 。 .
  • options.includeDescription - 包括说明案文。 默认 false。 。 。 .
  • options.focusSettleMs ——按键后延迟焦点/CSS结算. 默认 50。 。 。 .

enable(): Promise<void>

启用 CDP 无障碍域 。 必须先用其他方法.

disable(): Promise<void>

禁用 CDP 无障碍域 .

pressKey(key: string, modifiers?: ModifierKeys): Promise<A11yState>

调出一个关键媒体 并返回统一无障碍状态.

  1. 发送 keyDown + 键 keyUp 通过CDP Input.dispatchKeyEvent
  2. 等着 focusSettleMs 支助处过渡和重点活动
  3. 并行收集语音、重点要素和重点指标
const state = await orchestrator.pressKey('Tab');
// state.speech           → "Products, button, collapsed"
// state.focusedElement   → { tag: 'BUTTON', id: 'products-btn', ... }
// state.focusIndicator   → { isVisible: true, contrastRatio: 12.5, meetsWCAG_AA: true }

// With modifier keys
const prev = await orchestrator.pressKey('Tab', { shift: true });

getState(): Promise<A11yState>

获取当前统一状态而不按键 。 方案重点改变后有用.

await page.focus('#my-button');
const state = await orchestrator.getState();

traverseTabOrder(): Promise<TabOrderReport>

在 DOM 标签顺序中提取所有可制表元素 .

const report = await orchestrator.traverseTabOrder();
console.log(report.totalCount);     // 12
console.log(report.entries[0].tag); // "A"
console.log(report.entries[0].id);  // "home-link"

traverseSubTree(selector: string, maxTabs?: number): Promise<TraversalResult>

检测容器是否夹住键盘焦点(WCAG 2.1.2).

聚焦容器中的第一个可制表元素,按下标签至 maxTabs 时间(默认值50),并检查焦点是否逃脱.

const result = await orchestrator.traverseSubTree('#modal-container', 20);
if (result.isTrapped) {
  console.log('Keyboard trap detected!');
  console.log(`Focus visited ${result.visitedElements.length} elements`);
} else {
  console.log(`Focus escaped to: ${result.escapeElement?.tag}`);
}

类型

CDPSessionLike

引擎和测试框架之间的抽象边界:

interface CDPSessionLike {
  send(method: 'Accessibility.enable'): Promise<void>;
  send(method: 'Accessibility.disable'): Promise<void>;
  send(
    method: 'Accessibility.getFullAXTree',
    params?: { depth?: number; frameId?: string }
  ): Promise<{ nodes: AXNode[] }>;
  send(method: string, params?: Record<string, unknown>): Promise<unknown>;
}

两个剧作家的 CDPSession 财务报告和审定财务报表 chrome-remote-interface 客户端无需适配器即可满足此接口.

SpeechResult

归来 getSpeech() 财务报告和审定财务报表 getFullTreeSpeech()数字 :

interface SpeechResult {
  speech: string;              // "Products, button, collapsed"
  name: string;                // "Products"
  role: string;                // "button"
  states: string[];            // ["collapsed"]
  rawNode: Protocol.Accessibility.AXNode;
}

A11yState

归来 pressKey() 财务报告和审定财务报表 getState()数字 :

interface A11yState {
  speech: string;                          // "Products, button, collapsed"
  speechResult: SpeechResult | null;       // Full speech result with raw AXNode
  focusedElement: A11yFocusedElement | null; // DOM info
  focusIndicator: A11yFocusIndicator;      // CSS analysis
}

A11yFocusedElement

interface A11yFocusedElement {
  tag: string;        // "BUTTON"
  id: string;         // "submit-btn"
  className: string;  // "btn primary"
  textContent: string; // "Submit"
  role: string;       // "button"
  ariaLabel: string;  // "Submit form"
  tabIndex: number;   // 0
  rect: { x: number; y: number; width: number; height: number };
}

A11yFocusIndicator

interface A11yFocusIndicator {
  isVisible: boolean;           // true if outline or box-shadow detected
  contrastRatio: number | null; // null if colors unparseable
  meetsWCAG_AA: boolean;        // true if visible and contrast >= 3.0
}

ModifierKeys

interface ModifierKeys {
  shift?: boolean;
  ctrl?: boolean;
  alt?: boolean;
  meta?: boolean;
}

TabOrderReport

interface TabOrderReport {
  entries: TabOrderEntry[];
  totalCount: number;
}

TabOrderEntry

interface TabOrderEntry {
  index: number;     // Position in tab order (0-based)
  tag: string;       // "BUTTON"
  id: string;        // "submit-btn"
  textContent: string;
  tabIndex: number;
  role: string;
  rect: { x: number; y: number; width: number; height: number };
}

TraversalResult

interface TraversalResult {
  isTrapped: boolean;                  // true if focus never escaped
  tabCount: number;                    // Total Tab presses attempted
  visitedElements: TabOrderEntry[];    // Elements that received focus
  escapeElement: TabOrderEntry | null; // First element outside container
}

角色绘图

这个 ROLE_TO_SPEECH 记录50+ CDP 角色值到语音字符串。 作用分为四类:

互动作用

CDP 作用发言
buttonbutton
linklink
checkboxcheckbox
radioradio button
textboxedit text
comboboxcombo box
sliderslider
switchswitch
tabtab
menuitemmenu item
menuitemcheckboxmenu item checkbox
menuitemradiomenu item radio
optionoption
searchboxsearch text
spinbuttonspin button

地标角色

地标在 includeLandmarks 实值 true数字 :

CDP 作用发言
navigationnavigation landmark
mainmain landmark
bannerbanner landmark
contentinfocontent info landmark
complementarycomplementary landmark
searchsearch landmark
regionregion landmark
formform landmark

结构作用

CDP 作用发言
headingheading
listlist
listitemlist item
imgimage
tabletable
rowrow
cellcell
dialogdialog
alertalert
menumenu
menubarmenu bar
toolbartoolbar
treetree
treeitemtree item
tablisttab list
tabpaneltab panel
progressbarprogress bar
tooltiptooltip

寂静的角色

这些角色不会产生语音输出 :

generic, (中文(简体) ), none, (中文(简体) ), presentation, (中文(简体) ), StaticText, (中文(简体) ), InlineTextBox, (中文(简体) ), LineBreak, (中文(简体) ), RootWebArea, (中文(简体) ), WebArea, (中文(简体) ), paragraph, (中文(简体) ), DescriptionListDetail, (中文(简体) ), DescriptionListTerm, (中文(简体) ), DescriptionList

未知角色通过正即,以与新的ARIA角色进行前向相容.

国家测绘

这个 STATE_MAPPINGS 数组定义了布尔 ARIA 属性如何翻译为口语字符串 。 各国按下列顺序出现在产出中:

CDP 财产truefalse
expandedexpandedcollapsed
checkedcheckednot checked
selectedselected(安静地)
pressedpressednot pressed
disableddimmed(安静地)
requiredrequired(安静地)
invalidinvalid(安静地)
readonlyread only(安静地)
multiselectablemulti selectable(安静地)

标题级别是特殊情况: level 属性生成 level N (例如, level 2) (中文(简体) ).

当存在多个状态时,它们按上方的固定顺序合并:

"Submit, button, expanded, required"
"Email, edit text, invalid, required"

出口

// Main classes
export { SpeechEngine } from '@a11y-oracle/core-engine';
export { A11yOrchestrator } from '@a11y-oracle/core-engine';

// Core types
export type {
  CDPSessionLike,
  SpeechResult,
  SpeechEngineOptions,
  A11yState,
  A11yFocusedElement,
  A11yFocusIndicator,
  A11yOrchestratorOptions,
} from '@a11y-oracle/core-engine';

// Data (for advanced customization)
export { ROLE_TO_SPEECH, LANDMARK_ROLES } from '@a11y-oracle/core-engine';
export { STATE_MAPPINGS, extractStates } from '@a11y-oracle/core-engine';
export type { StateMapping, AXNodeProperty } from '@a11y-oracle/core-engine';

// Re-exports from sub-engines
export type { ModifierKeys, FocusedElementInfo, KeyDefinition } from '@a11y-oracle/core-engine';
export { KEY_DEFINITIONS } from '@a11y-oracle/core-engine';
export type { FocusIndicator, TabOrderEntry, TabOrderReport, TraversalResult } from '@a11y-oracle/core-engine';

版本与发布记录

@a11y-oracle/core-engine 共发布 10 个版本,首次发布于 2026/03/05;过去 12 个月发布了 10 个版本。

版本发布日期距今
1.3.2latest2026/03/127 个月前
1.3.12026/03/117 个月前
1.3.02026/03/068 个月前
1.2.02026/03/068 个月前
1.1.42026/03/068 个月前
1.1.32026/03/068 个月前

关于 @a11y-oracle/core-engine 的常见问题

@a11y-oracle/core-engine 是什么?

通过 Chrome DevTools 协议实现框架不可知无障碍语音引擎和统一的 A11y Orchestrator

如何安装 @a11y-oracle/core-engine?

在项目目录运行 npm install @a11y-oracle/core-engine,或使用 pnpm add / yarn add / bun add。

@a11y-oracle/core-engine 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@a11y-oracle/core-engine 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@a11y-oracle/core-engine 可以商用吗?

@a11y-oracle/core-engine 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@a11y-oracle/core-engine 的下载量有多少?

根据 npm 官方下载统计,@a11y-oracle/core-engine 在 2026/10/05 – 2026/11/03 这 30 天内被下载 3,093 次,日均约 103 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@a11y-oracle/core-engine 还在维护吗?

最新版本 1.3.2 发布于 2026/03/12(7 个月前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/03/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。