agentic-qe 3.3.4 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/v3/qe-queen-coordinator.md +332 -166
- package/.claude/helpers/statusline-v3.cjs +85 -42
- package/.claude/skills/qcsd-ideation-swarm/SKILL.md +7 -4
- package/README.md +71 -2
- package/package.json +1 -1
- package/scripts/cloud-db-config.json +10 -5
- package/scripts/merge-v3-to-root.sql +48 -0
- package/v3/CHANGELOG.md +156 -0
- package/v3/README.md +118 -1
- package/v3/assets/agents/v3/qe-queen-coordinator.md +332 -166
- package/v3/assets/skills/qcsd-ideation-swarm/SKILL.md +7 -4
- package/v3/dist/adapters/a2a/agent-cards/generator.d.ts +153 -0
- package/v3/dist/adapters/a2a/agent-cards/generator.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/agent-cards/generator.js +478 -0
- package/v3/dist/adapters/a2a/agent-cards/generator.js.map +1 -0
- package/v3/dist/adapters/a2a/agent-cards/schema.d.ts +274 -0
- package/v3/dist/adapters/a2a/agent-cards/schema.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/agent-cards/schema.js +135 -0
- package/v3/dist/adapters/a2a/agent-cards/schema.js.map +1 -0
- package/v3/dist/adapters/a2a/agent-cards/validator.d.ts +514 -0
- package/v3/dist/adapters/a2a/agent-cards/validator.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/agent-cards/validator.js +555 -0
- package/v3/dist/adapters/a2a/agent-cards/validator.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/index.d.ts +23 -0
- package/v3/dist/adapters/a2a/auth/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/index.js +85 -0
- package/v3/dist/adapters/a2a/auth/index.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/jwt-utils.d.ts +215 -0
- package/v3/dist/adapters/a2a/auth/jwt-utils.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/jwt-utils.js +314 -0
- package/v3/dist/adapters/a2a/auth/jwt-utils.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/middleware.d.ts +173 -0
- package/v3/dist/adapters/a2a/auth/middleware.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/middleware.js +300 -0
- package/v3/dist/adapters/a2a/auth/middleware.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/oauth-provider.d.ts +308 -0
- package/v3/dist/adapters/a2a/auth/oauth-provider.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/oauth-provider.js +573 -0
- package/v3/dist/adapters/a2a/auth/oauth-provider.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/routes.d.ts +244 -0
- package/v3/dist/adapters/a2a/auth/routes.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/routes.js +496 -0
- package/v3/dist/adapters/a2a/auth/routes.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/scopes.d.ts +219 -0
- package/v3/dist/adapters/a2a/auth/scopes.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/scopes.js +292 -0
- package/v3/dist/adapters/a2a/auth/scopes.js.map +1 -0
- package/v3/dist/adapters/a2a/auth/token-store.d.ts +278 -0
- package/v3/dist/adapters/a2a/auth/token-store.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/auth/token-store.js +453 -0
- package/v3/dist/adapters/a2a/auth/token-store.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/agent-health.d.ts +226 -0
- package/v3/dist/adapters/a2a/discovery/agent-health.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/agent-health.js +426 -0
- package/v3/dist/adapters/a2a/discovery/agent-health.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/discovery-service.d.ts +296 -0
- package/v3/dist/adapters/a2a/discovery/discovery-service.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/discovery-service.js +520 -0
- package/v3/dist/adapters/a2a/discovery/discovery-service.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/file-watcher.d.ts +166 -0
- package/v3/dist/adapters/a2a/discovery/file-watcher.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/file-watcher.js +385 -0
- package/v3/dist/adapters/a2a/discovery/file-watcher.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/hot-reload-service.d.ts +226 -0
- package/v3/dist/adapters/a2a/discovery/hot-reload-service.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/hot-reload-service.js +433 -0
- package/v3/dist/adapters/a2a/discovery/hot-reload-service.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/index.d.ts +18 -0
- package/v3/dist/adapters/a2a/discovery/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/index.js +54 -0
- package/v3/dist/adapters/a2a/discovery/index.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/metrics.d.ts +200 -0
- package/v3/dist/adapters/a2a/discovery/metrics.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/metrics.js +371 -0
- package/v3/dist/adapters/a2a/discovery/metrics.js.map +1 -0
- package/v3/dist/adapters/a2a/discovery/routes.d.ts +184 -0
- package/v3/dist/adapters/a2a/discovery/routes.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/discovery/routes.js +453 -0
- package/v3/dist/adapters/a2a/discovery/routes.js.map +1 -0
- package/v3/dist/adapters/a2a/index.d.ts +18 -0
- package/v3/dist/adapters/a2a/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/index.js +139 -0
- package/v3/dist/adapters/a2a/index.js.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/envelope.d.ts +312 -0
- package/v3/dist/adapters/a2a/jsonrpc/envelope.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/envelope.js +554 -0
- package/v3/dist/adapters/a2a/jsonrpc/envelope.js.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/errors.d.ts +244 -0
- package/v3/dist/adapters/a2a/jsonrpc/errors.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/errors.js +365 -0
- package/v3/dist/adapters/a2a/jsonrpc/errors.js.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/index.d.ts +14 -0
- package/v3/dist/adapters/a2a/jsonrpc/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/index.js +59 -0
- package/v3/dist/adapters/a2a/jsonrpc/index.js.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/methods.d.ts +400 -0
- package/v3/dist/adapters/a2a/jsonrpc/methods.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/jsonrpc/methods.js +249 -0
- package/v3/dist/adapters/a2a/jsonrpc/methods.js.map +1 -0
- package/v3/dist/adapters/a2a/notifications/index.d.ts +60 -0
- package/v3/dist/adapters/a2a/notifications/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/notifications/index.js +99 -0
- package/v3/dist/adapters/a2a/notifications/index.js.map +1 -0
- package/v3/dist/adapters/a2a/notifications/retry-queue.d.ts +225 -0
- package/v3/dist/adapters/a2a/notifications/retry-queue.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/notifications/retry-queue.js +449 -0
- package/v3/dist/adapters/a2a/notifications/retry-queue.js.map +1 -0
- package/v3/dist/adapters/a2a/notifications/signature.d.ts +133 -0
- package/v3/dist/adapters/a2a/notifications/signature.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/notifications/signature.js +244 -0
- package/v3/dist/adapters/a2a/notifications/signature.js.map +1 -0
- package/v3/dist/adapters/a2a/notifications/subscription-store.d.ts +243 -0
- package/v3/dist/adapters/a2a/notifications/subscription-store.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/notifications/subscription-store.js +486 -0
- package/v3/dist/adapters/a2a/notifications/subscription-store.js.map +1 -0
- package/v3/dist/adapters/a2a/notifications/webhook-service.d.ts +257 -0
- package/v3/dist/adapters/a2a/notifications/webhook-service.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/notifications/webhook-service.js +542 -0
- package/v3/dist/adapters/a2a/notifications/webhook-service.js.map +1 -0
- package/v3/dist/adapters/a2a/tasks/index.d.ts +16 -0
- package/v3/dist/adapters/a2a/tasks/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/tasks/index.js +33 -0
- package/v3/dist/adapters/a2a/tasks/index.js.map +1 -0
- package/v3/dist/adapters/a2a/tasks/task-manager.d.ts +306 -0
- package/v3/dist/adapters/a2a/tasks/task-manager.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/tasks/task-manager.js +562 -0
- package/v3/dist/adapters/a2a/tasks/task-manager.js.map +1 -0
- package/v3/dist/adapters/a2a/tasks/task-router.d.ts +270 -0
- package/v3/dist/adapters/a2a/tasks/task-router.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/tasks/task-router.js +574 -0
- package/v3/dist/adapters/a2a/tasks/task-router.js.map +1 -0
- package/v3/dist/adapters/a2a/tasks/task-store.d.ts +251 -0
- package/v3/dist/adapters/a2a/tasks/task-store.d.ts.map +1 -0
- package/v3/dist/adapters/a2a/tasks/task-store.js +468 -0
- package/v3/dist/adapters/a2a/tasks/task-store.js.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/aria-attributes.d.ts +294 -0
- package/v3/dist/adapters/a2ui/accessibility/aria-attributes.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/aria-attributes.js +447 -0
- package/v3/dist/adapters/a2ui/accessibility/aria-attributes.js.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/index.d.ts +83 -0
- package/v3/dist/adapters/a2ui/accessibility/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/index.js +155 -0
- package/v3/dist/adapters/a2ui/accessibility/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/keyboard-nav.d.ts +177 -0
- package/v3/dist/adapters/a2ui/accessibility/keyboard-nav.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/keyboard-nav.js +638 -0
- package/v3/dist/adapters/a2ui/accessibility/keyboard-nav.js.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/wcag-validator.d.ts +186 -0
- package/v3/dist/adapters/a2ui/accessibility/wcag-validator.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/accessibility/wcag-validator.js +816 -0
- package/v3/dist/adapters/a2ui/accessibility/wcag-validator.js.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/component-schemas.d.ts +227 -0
- package/v3/dist/adapters/a2ui/catalog/component-schemas.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/component-schemas.js +1090 -0
- package/v3/dist/adapters/a2ui/catalog/component-schemas.js.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/index.d.ts +55 -0
- package/v3/dist/adapters/a2ui/catalog/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/index.js +100 -0
- package/v3/dist/adapters/a2ui/catalog/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/qe-catalog.d.ts +456 -0
- package/v3/dist/adapters/a2ui/catalog/qe-catalog.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/qe-catalog.js +413 -0
- package/v3/dist/adapters/a2ui/catalog/qe-catalog.js.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/standard-catalog.d.ts +581 -0
- package/v3/dist/adapters/a2ui/catalog/standard-catalog.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/catalog/standard-catalog.js +409 -0
- package/v3/dist/adapters/a2ui/catalog/standard-catalog.js.map +1 -0
- package/v3/dist/adapters/a2ui/data/bound-value.d.ts +252 -0
- package/v3/dist/adapters/a2ui/data/bound-value.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/data/bound-value.js +403 -0
- package/v3/dist/adapters/a2ui/data/bound-value.js.map +1 -0
- package/v3/dist/adapters/a2ui/data/index.d.ts +14 -0
- package/v3/dist/adapters/a2ui/data/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/data/index.js +41 -0
- package/v3/dist/adapters/a2ui/data/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/data/json-pointer-resolver.d.ts +187 -0
- package/v3/dist/adapters/a2ui/data/json-pointer-resolver.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/data/json-pointer-resolver.js +425 -0
- package/v3/dist/adapters/a2ui/data/json-pointer-resolver.js.map +1 -0
- package/v3/dist/adapters/a2ui/data/reactive-store.d.ts +241 -0
- package/v3/dist/adapters/a2ui/data/reactive-store.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/data/reactive-store.js +461 -0
- package/v3/dist/adapters/a2ui/data/reactive-store.js.map +1 -0
- package/v3/dist/adapters/a2ui/index.d.ts +17 -0
- package/v3/dist/adapters/a2ui/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/index.js +119 -0
- package/v3/dist/adapters/a2ui/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/integration/agui-sync.d.ts +259 -0
- package/v3/dist/adapters/a2ui/integration/agui-sync.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/integration/agui-sync.js +559 -0
- package/v3/dist/adapters/a2ui/integration/agui-sync.js.map +1 -0
- package/v3/dist/adapters/a2ui/integration/index.d.ts +11 -0
- package/v3/dist/adapters/a2ui/integration/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/integration/index.js +23 -0
- package/v3/dist/adapters/a2ui/integration/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/integration/surface-state-bridge.d.ts +209 -0
- package/v3/dist/adapters/a2ui/integration/surface-state-bridge.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/integration/surface-state-bridge.js +545 -0
- package/v3/dist/adapters/a2ui/integration/surface-state-bridge.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/component-builder.d.ts +227 -0
- package/v3/dist/adapters/a2ui/renderer/component-builder.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/component-builder.js +488 -0
- package/v3/dist/adapters/a2ui/renderer/component-builder.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/index.d.ts +16 -0
- package/v3/dist/adapters/a2ui/renderer/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/index.js +50 -0
- package/v3/dist/adapters/a2ui/renderer/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/message-types.d.ts +299 -0
- package/v3/dist/adapters/a2ui/renderer/message-types.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/message-types.js +187 -0
- package/v3/dist/adapters/a2ui/renderer/message-types.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/surface-generator.d.ts +210 -0
- package/v3/dist/adapters/a2ui/renderer/surface-generator.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/surface-generator.js +586 -0
- package/v3/dist/adapters/a2ui/renderer/surface-generator.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/accessibility-surface.d.ts +149 -0
- package/v3/dist/adapters/a2ui/renderer/templates/accessibility-surface.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/accessibility-surface.js +414 -0
- package/v3/dist/adapters/a2ui/renderer/templates/accessibility-surface.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/coverage-surface.d.ts +95 -0
- package/v3/dist/adapters/a2ui/renderer/templates/coverage-surface.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/coverage-surface.js +231 -0
- package/v3/dist/adapters/a2ui/renderer/templates/coverage-surface.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/index.d.ts +12 -0
- package/v3/dist/adapters/a2ui/renderer/templates/index.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/index.js +16 -0
- package/v3/dist/adapters/a2ui/renderer/templates/index.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/security-surface.d.ts +121 -0
- package/v3/dist/adapters/a2ui/renderer/templates/security-surface.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/security-surface.js +367 -0
- package/v3/dist/adapters/a2ui/renderer/templates/security-surface.js.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/test-results-surface.d.ts +104 -0
- package/v3/dist/adapters/a2ui/renderer/templates/test-results-surface.d.ts.map +1 -0
- package/v3/dist/adapters/a2ui/renderer/templates/test-results-surface.js +294 -0
- package/v3/dist/adapters/a2ui/renderer/templates/test-results-surface.js.map +1 -0
- package/v3/dist/adapters/ag-ui/backpressure-handler.d.ts +201 -0
- package/v3/dist/adapters/ag-ui/backpressure-handler.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/backpressure-handler.js +399 -0
- package/v3/dist/adapters/ag-ui/backpressure-handler.js.map +1 -0
- package/v3/dist/adapters/ag-ui/event-adapter.d.ts +360 -0
- package/v3/dist/adapters/ag-ui/event-adapter.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/event-adapter.js +1083 -0
- package/v3/dist/adapters/ag-ui/event-adapter.js.map +1 -0
- package/v3/dist/adapters/ag-ui/event-batcher.d.ts +242 -0
- package/v3/dist/adapters/ag-ui/event-batcher.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/event-batcher.js +444 -0
- package/v3/dist/adapters/ag-ui/event-batcher.js.map +1 -0
- package/v3/dist/adapters/ag-ui/event-types.d.ts +450 -0
- package/v3/dist/adapters/ag-ui/event-types.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/event-types.js +173 -0
- package/v3/dist/adapters/ag-ui/event-types.js.map +1 -0
- package/v3/dist/adapters/ag-ui/index.d.ts +17 -0
- package/v3/dist/adapters/ag-ui/index.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/index.js +47 -0
- package/v3/dist/adapters/ag-ui/index.js.map +1 -0
- package/v3/dist/adapters/ag-ui/json-patch-utils.d.ts +136 -0
- package/v3/dist/adapters/ag-ui/json-patch-utils.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/json-patch-utils.js +574 -0
- package/v3/dist/adapters/ag-ui/json-patch-utils.js.map +1 -0
- package/v3/dist/adapters/ag-ui/json-patch.d.ts +241 -0
- package/v3/dist/adapters/ag-ui/json-patch.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/json-patch.js +726 -0
- package/v3/dist/adapters/ag-ui/json-patch.js.map +1 -0
- package/v3/dist/adapters/ag-ui/state-delta-cache.d.ts +218 -0
- package/v3/dist/adapters/ag-ui/state-delta-cache.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/state-delta-cache.js +422 -0
- package/v3/dist/adapters/ag-ui/state-delta-cache.js.map +1 -0
- package/v3/dist/adapters/ag-ui/state-manager.d.ts +249 -0
- package/v3/dist/adapters/ag-ui/state-manager.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/state-manager.js +511 -0
- package/v3/dist/adapters/ag-ui/state-manager.js.map +1 -0
- package/v3/dist/adapters/ag-ui/stream-controller.d.ts +195 -0
- package/v3/dist/adapters/ag-ui/stream-controller.d.ts.map +1 -0
- package/v3/dist/adapters/ag-ui/stream-controller.js +481 -0
- package/v3/dist/adapters/ag-ui/stream-controller.js.map +1 -0
- package/v3/dist/adapters/index.d.ts +4 -0
- package/v3/dist/adapters/index.d.ts.map +1 -1
- package/v3/dist/adapters/index.js +89 -0
- package/v3/dist/adapters/index.js.map +1 -1
- package/v3/dist/cli/bundle.js +1507 -425
- package/v3/dist/coordination/consensus/providers/claude-provider.js +1 -1
- package/v3/dist/coordination/consensus/providers/gemini-provider.js +1 -1
- package/v3/dist/coordination/consensus/providers/openai-provider.js +1 -1
- package/v3/dist/init/init-wizard.d.ts.map +1 -1
- package/v3/dist/init/init-wizard.js +19 -4
- package/v3/dist/init/init-wizard.js.map +1 -1
- package/v3/dist/init/migration/config-migrator.d.ts.map +1 -1
- package/v3/dist/init/migration/config-migrator.js +15 -1
- package/v3/dist/init/migration/config-migrator.js.map +1 -1
- package/v3/dist/init/phases/05-learning.js +1 -1
- package/v3/dist/init/phases/05-learning.js.map +1 -1
- package/v3/dist/init/self-configurator.d.ts +7 -0
- package/v3/dist/init/self-configurator.d.ts.map +1 -1
- package/v3/dist/init/self-configurator.js +23 -27
- package/v3/dist/init/self-configurator.js.map +1 -1
- package/v3/dist/integrations/ruvector/interfaces.js +1 -1
- package/v3/dist/integrations/ruvector/interfaces.js.map +1 -1
- package/v3/dist/kernel/index.d.ts +1 -1
- package/v3/dist/kernel/index.d.ts.map +1 -1
- package/v3/dist/kernel/index.js +3 -1
- package/v3/dist/kernel/index.js.map +1 -1
- package/v3/dist/kernel/plugin-loader.d.ts.map +1 -1
- package/v3/dist/kernel/plugin-loader.js +6 -1
- package/v3/dist/kernel/plugin-loader.js.map +1 -1
- package/v3/dist/kernel/unified-memory.d.ts +123 -0
- package/v3/dist/kernel/unified-memory.d.ts.map +1 -1
- package/v3/dist/kernel/unified-memory.js +258 -2
- package/v3/dist/kernel/unified-memory.js.map +1 -1
- package/v3/dist/learning/qe-unified-memory.js +1 -1
- package/v3/dist/learning/qe-unified-memory.js.map +1 -1
- package/v3/dist/learning/real-qe-reasoning-bank.js +2 -2
- package/v3/dist/learning/real-qe-reasoning-bank.js.map +1 -1
- package/v3/dist/learning/sqlite-persistence.d.ts +1 -1
- package/v3/dist/learning/sqlite-persistence.js +1 -1
- package/v3/dist/learning/sqlite-persistence.js.map +1 -1
- package/v3/dist/learning/v2-to-v3-migration.d.ts +2 -2
- package/v3/dist/learning/v2-to-v3-migration.d.ts.map +1 -1
- package/v3/dist/learning/v2-to-v3-migration.js +2 -2
- package/v3/dist/learning/v2-to-v3-migration.js.map +1 -1
- package/v3/dist/mcp/bundle.js +63075 -53304
- package/v3/dist/mcp/entry.d.ts +5 -0
- package/v3/dist/mcp/entry.d.ts.map +1 -1
- package/v3/dist/mcp/entry.js +36 -0
- package/v3/dist/mcp/entry.js.map +1 -1
- package/v3/dist/mcp/http-server.d.ts +95 -0
- package/v3/dist/mcp/http-server.d.ts.map +1 -0
- package/v3/dist/mcp/http-server.js +833 -0
- package/v3/dist/mcp/http-server.js.map +1 -0
- package/v3/dist/mcp/protocol-server.d.ts +6 -0
- package/v3/dist/mcp/protocol-server.d.ts.map +1 -1
- package/v3/dist/mcp/protocol-server.js +40 -0
- package/v3/dist/mcp/protocol-server.js.map +1 -1
- package/v3/dist/mcp/transport/index.d.ts +25 -3
- package/v3/dist/mcp/transport/index.d.ts.map +1 -1
- package/v3/dist/mcp/transport/index.js +22 -4
- package/v3/dist/mcp/transport/index.js.map +1 -1
- package/v3/dist/mcp/transport/sse/connection-manager.d.ts +84 -0
- package/v3/dist/mcp/transport/sse/connection-manager.d.ts.map +1 -0
- package/v3/dist/mcp/transport/sse/connection-manager.js +271 -0
- package/v3/dist/mcp/transport/sse/connection-manager.js.map +1 -0
- package/v3/dist/mcp/transport/sse/index.d.ts +10 -0
- package/v3/dist/mcp/transport/sse/index.d.ts.map +1 -0
- package/v3/dist/mcp/transport/sse/index.js +15 -0
- package/v3/dist/mcp/transport/sse/index.js.map +1 -0
- package/v3/dist/mcp/transport/sse/sse-transport.d.ts +56 -0
- package/v3/dist/mcp/transport/sse/sse-transport.d.ts.map +1 -0
- package/v3/dist/mcp/transport/sse/sse-transport.js +381 -0
- package/v3/dist/mcp/transport/sse/sse-transport.js.map +1 -0
- package/v3/dist/mcp/transport/sse/types.d.ts +237 -0
- package/v3/dist/mcp/transport/sse/types.d.ts.map +1 -0
- package/v3/dist/mcp/transport/sse/types.js +37 -0
- package/v3/dist/mcp/transport/sse/types.js.map +1 -0
- package/v3/dist/mcp/transport/websocket/connection-manager.d.ts +143 -0
- package/v3/dist/mcp/transport/websocket/connection-manager.d.ts.map +1 -0
- package/v3/dist/mcp/transport/websocket/connection-manager.js +522 -0
- package/v3/dist/mcp/transport/websocket/connection-manager.js.map +1 -0
- package/v3/dist/mcp/transport/websocket/index.d.ts +10 -0
- package/v3/dist/mcp/transport/websocket/index.d.ts.map +1 -0
- package/v3/dist/mcp/transport/websocket/index.js +19 -0
- package/v3/dist/mcp/transport/websocket/index.js.map +1 -0
- package/v3/dist/mcp/transport/websocket/types.d.ts +354 -0
- package/v3/dist/mcp/transport/websocket/types.d.ts.map +1 -0
- package/v3/dist/mcp/transport/websocket/types.js +49 -0
- package/v3/dist/mcp/transport/websocket/types.js.map +1 -0
- package/v3/dist/mcp/transport/websocket/websocket-transport.d.ts +77 -0
- package/v3/dist/mcp/transport/websocket/websocket-transport.d.ts.map +1 -0
- package/v3/dist/mcp/transport/websocket/websocket-transport.js +622 -0
- package/v3/dist/mcp/transport/websocket/websocket-transport.js.map +1 -0
- package/v3/dist/memory/crdt/convergence-tracker.d.ts +59 -0
- package/v3/dist/memory/crdt/convergence-tracker.d.ts.map +1 -0
- package/v3/dist/memory/crdt/convergence-tracker.js +325 -0
- package/v3/dist/memory/crdt/convergence-tracker.js.map +1 -0
- package/v3/dist/memory/crdt/crdt-store.d.ts +55 -0
- package/v3/dist/memory/crdt/crdt-store.d.ts.map +1 -0
- package/v3/dist/memory/crdt/crdt-store.js +582 -0
- package/v3/dist/memory/crdt/crdt-store.js.map +1 -0
- package/v3/dist/memory/crdt/g-counter.d.ts +47 -0
- package/v3/dist/memory/crdt/g-counter.d.ts.map +1 -0
- package/v3/dist/memory/crdt/g-counter.js +134 -0
- package/v3/dist/memory/crdt/g-counter.js.map +1 -0
- package/v3/dist/memory/crdt/index.d.ts +52 -0
- package/v3/dist/memory/crdt/index.d.ts.map +1 -0
- package/v3/dist/memory/crdt/index.js +66 -0
- package/v3/dist/memory/crdt/index.js.map +1 -0
- package/v3/dist/memory/crdt/lww-register.d.ts +40 -0
- package/v3/dist/memory/crdt/lww-register.d.ts.map +1 -0
- package/v3/dist/memory/crdt/lww-register.js +133 -0
- package/v3/dist/memory/crdt/lww-register.js.map +1 -0
- package/v3/dist/memory/crdt/or-set.d.ts +62 -0
- package/v3/dist/memory/crdt/or-set.d.ts.map +1 -0
- package/v3/dist/memory/crdt/or-set.js +336 -0
- package/v3/dist/memory/crdt/or-set.js.map +1 -0
- package/v3/dist/memory/crdt/pn-counter.d.ts +53 -0
- package/v3/dist/memory/crdt/pn-counter.d.ts.map +1 -0
- package/v3/dist/memory/crdt/pn-counter.js +147 -0
- package/v3/dist/memory/crdt/pn-counter.js.map +1 -0
- package/v3/dist/memory/crdt/types.d.ts +397 -0
- package/v3/dist/memory/crdt/types.d.ts.map +1 -0
- package/v3/dist/memory/crdt/types.js +12 -0
- package/v3/dist/memory/crdt/types.js.map +1 -0
- package/v3/dist/memory/index.d.ts +5 -2
- package/v3/dist/memory/index.d.ts.map +1 -1
- package/v3/dist/memory/index.js +5 -2
- package/v3/dist/memory/index.js.map +1 -1
- package/v3/dist/performance/benchmarks.d.ts +215 -0
- package/v3/dist/performance/benchmarks.d.ts.map +1 -0
- package/v3/dist/performance/benchmarks.js +516 -0
- package/v3/dist/performance/benchmarks.js.map +1 -0
- package/v3/dist/performance/ci-gates.d.ts +149 -0
- package/v3/dist/performance/ci-gates.d.ts.map +1 -0
- package/v3/dist/performance/ci-gates.js +425 -0
- package/v3/dist/performance/ci-gates.js.map +1 -0
- package/v3/dist/performance/index.d.ts +18 -0
- package/v3/dist/performance/index.d.ts.map +1 -0
- package/v3/dist/performance/index.js +26 -0
- package/v3/dist/performance/index.js.map +1 -0
- package/v3/dist/performance/optimizer.d.ts +323 -0
- package/v3/dist/performance/optimizer.d.ts.map +1 -0
- package/v3/dist/performance/optimizer.js +592 -0
- package/v3/dist/performance/optimizer.js.map +1 -0
- package/v3/dist/performance/profiler.d.ts +195 -0
- package/v3/dist/performance/profiler.d.ts.map +1 -0
- package/v3/dist/performance/profiler.js +369 -0
- package/v3/dist/performance/profiler.js.map +1 -0
- package/v3/dist/performance/run-gates.d.ts +23 -0
- package/v3/dist/performance/run-gates.d.ts.map +1 -0
- package/v3/dist/performance/run-gates.js +122 -0
- package/v3/dist/performance/run-gates.js.map +1 -0
- package/v3/dist/sync/claude-flow-bridge.d.ts +1 -1
- package/v3/dist/sync/claude-flow-bridge.js +1 -1
- package/v3/dist/sync/interfaces.d.ts +6 -0
- package/v3/dist/sync/interfaces.d.ts.map +1 -1
- package/v3/dist/sync/interfaces.js +34 -47
- package/v3/dist/sync/interfaces.js.map +1 -1
- package/v3/dist/sync/readers/sqlite-reader.d.ts +1 -1
- package/v3/dist/sync/readers/sqlite-reader.js +1 -1
- package/v3/dist/testing/index.d.ts +6 -0
- package/v3/dist/testing/index.d.ts.map +1 -0
- package/v3/dist/testing/index.js +7 -0
- package/v3/dist/testing/index.js.map +1 -0
- package/v3/dist/testing/load/agent-load-tester.d.ts +221 -0
- package/v3/dist/testing/load/agent-load-tester.d.ts.map +1 -0
- package/v3/dist/testing/load/agent-load-tester.js +566 -0
- package/v3/dist/testing/load/agent-load-tester.js.map +1 -0
- package/v3/dist/testing/load/bottleneck-analyzer.d.ts +150 -0
- package/v3/dist/testing/load/bottleneck-analyzer.d.ts.map +1 -0
- package/v3/dist/testing/load/bottleneck-analyzer.js +442 -0
- package/v3/dist/testing/load/bottleneck-analyzer.js.map +1 -0
- package/v3/dist/testing/load/index.d.ts +17 -0
- package/v3/dist/testing/load/index.d.ts.map +1 -0
- package/v3/dist/testing/load/index.js +23 -0
- package/v3/dist/testing/load/index.js.map +1 -0
- package/v3/dist/testing/load/metrics-collector.d.ts +275 -0
- package/v3/dist/testing/load/metrics-collector.d.ts.map +1 -0
- package/v3/dist/testing/load/metrics-collector.js +475 -0
- package/v3/dist/testing/load/metrics-collector.js.map +1 -0
- package/v3/package.json +5 -1
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2UI WCAG 2.2 Compliance Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates A2UI surfaces and components against WCAG 2.2 Level AA requirements.
|
|
5
|
+
* Provides detailed issue reporting with remediation guidance.
|
|
6
|
+
*
|
|
7
|
+
* Reference: https://www.w3.org/TR/WCAG22/
|
|
8
|
+
*
|
|
9
|
+
* @module adapters/a2ui/accessibility/wcag-validator
|
|
10
|
+
*/
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// WCAG 2.2 Criteria Reference
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* WCAG 2.2 Level A criteria
|
|
16
|
+
*/
|
|
17
|
+
export const WCAG_LEVEL_A_CRITERIA = {
|
|
18
|
+
'1.1.1': {
|
|
19
|
+
criterion: '1.1.1',
|
|
20
|
+
name: 'Non-text Content',
|
|
21
|
+
level: 'A',
|
|
22
|
+
principle: 'perceivable',
|
|
23
|
+
description: 'All non-text content has a text alternative',
|
|
24
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html',
|
|
25
|
+
},
|
|
26
|
+
'1.3.1': {
|
|
27
|
+
criterion: '1.3.1',
|
|
28
|
+
name: 'Info and Relationships',
|
|
29
|
+
level: 'A',
|
|
30
|
+
principle: 'perceivable',
|
|
31
|
+
description: 'Information, structure, and relationships conveyed through presentation can be programmatically determined',
|
|
32
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html',
|
|
33
|
+
},
|
|
34
|
+
'1.3.2': {
|
|
35
|
+
criterion: '1.3.2',
|
|
36
|
+
name: 'Meaningful Sequence',
|
|
37
|
+
level: 'A',
|
|
38
|
+
principle: 'perceivable',
|
|
39
|
+
description: 'When content presentation sequence affects meaning, correct reading sequence can be programmatically determined',
|
|
40
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/meaningful-sequence.html',
|
|
41
|
+
},
|
|
42
|
+
'2.1.1': {
|
|
43
|
+
criterion: '2.1.1',
|
|
44
|
+
name: 'Keyboard',
|
|
45
|
+
level: 'A',
|
|
46
|
+
principle: 'operable',
|
|
47
|
+
description: 'All functionality is operable through a keyboard interface',
|
|
48
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html',
|
|
49
|
+
},
|
|
50
|
+
'2.1.2': {
|
|
51
|
+
criterion: '2.1.2',
|
|
52
|
+
name: 'No Keyboard Trap',
|
|
53
|
+
level: 'A',
|
|
54
|
+
principle: 'operable',
|
|
55
|
+
description: 'Keyboard focus can be moved away from any component',
|
|
56
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/no-keyboard-trap.html',
|
|
57
|
+
},
|
|
58
|
+
'2.4.1': {
|
|
59
|
+
criterion: '2.4.1',
|
|
60
|
+
name: 'Bypass Blocks',
|
|
61
|
+
level: 'A',
|
|
62
|
+
principle: 'operable',
|
|
63
|
+
description: 'Mechanism to bypass blocks of content that are repeated',
|
|
64
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/bypass-blocks.html',
|
|
65
|
+
},
|
|
66
|
+
'2.4.2': {
|
|
67
|
+
criterion: '2.4.2',
|
|
68
|
+
name: 'Page Titled',
|
|
69
|
+
level: 'A',
|
|
70
|
+
principle: 'operable',
|
|
71
|
+
description: 'Web pages have titles that describe topic or purpose',
|
|
72
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/page-titled.html',
|
|
73
|
+
},
|
|
74
|
+
'3.2.1': {
|
|
75
|
+
criterion: '3.2.1',
|
|
76
|
+
name: 'On Focus',
|
|
77
|
+
level: 'A',
|
|
78
|
+
principle: 'understandable',
|
|
79
|
+
description: 'When a component receives focus, it does not initiate a change of context',
|
|
80
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/on-focus.html',
|
|
81
|
+
},
|
|
82
|
+
'3.2.2': {
|
|
83
|
+
criterion: '3.2.2',
|
|
84
|
+
name: 'On Input',
|
|
85
|
+
level: 'A',
|
|
86
|
+
principle: 'understandable',
|
|
87
|
+
description: 'Changing the setting of any UI component does not automatically cause a change of context',
|
|
88
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/on-input.html',
|
|
89
|
+
},
|
|
90
|
+
'3.3.1': {
|
|
91
|
+
criterion: '3.3.1',
|
|
92
|
+
name: 'Error Identification',
|
|
93
|
+
level: 'A',
|
|
94
|
+
principle: 'understandable',
|
|
95
|
+
description: 'If an input error is detected, the item is identified and described in text',
|
|
96
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/error-identification.html',
|
|
97
|
+
},
|
|
98
|
+
'3.3.2': {
|
|
99
|
+
criterion: '3.3.2',
|
|
100
|
+
name: 'Labels or Instructions',
|
|
101
|
+
level: 'A',
|
|
102
|
+
principle: 'understandable',
|
|
103
|
+
description: 'Labels or instructions are provided for user input',
|
|
104
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/labels-or-instructions.html',
|
|
105
|
+
},
|
|
106
|
+
'4.1.1': {
|
|
107
|
+
criterion: '4.1.1',
|
|
108
|
+
name: 'Parsing',
|
|
109
|
+
level: 'A',
|
|
110
|
+
principle: 'robust',
|
|
111
|
+
description: 'Content implemented using markup languages has complete start and end tags',
|
|
112
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/parsing.html',
|
|
113
|
+
},
|
|
114
|
+
'4.1.2': {
|
|
115
|
+
criterion: '4.1.2',
|
|
116
|
+
name: 'Name, Role, Value',
|
|
117
|
+
level: 'A',
|
|
118
|
+
principle: 'robust',
|
|
119
|
+
description: 'For all UI components, name and role can be programmatically determined',
|
|
120
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html',
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* WCAG 2.2 Level AA criteria (in addition to Level A)
|
|
125
|
+
*/
|
|
126
|
+
export const WCAG_LEVEL_AA_CRITERIA = {
|
|
127
|
+
'1.4.3': {
|
|
128
|
+
criterion: '1.4.3',
|
|
129
|
+
name: 'Contrast (Minimum)',
|
|
130
|
+
level: 'AA',
|
|
131
|
+
principle: 'perceivable',
|
|
132
|
+
description: 'Text has contrast ratio of at least 4.5:1 (3:1 for large text)',
|
|
133
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html',
|
|
134
|
+
},
|
|
135
|
+
'1.4.4': {
|
|
136
|
+
criterion: '1.4.4',
|
|
137
|
+
name: 'Resize Text',
|
|
138
|
+
level: 'AA',
|
|
139
|
+
principle: 'perceivable',
|
|
140
|
+
description: 'Text can be resized up to 200% without loss of content',
|
|
141
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/resize-text.html',
|
|
142
|
+
},
|
|
143
|
+
'1.4.5': {
|
|
144
|
+
criterion: '1.4.5',
|
|
145
|
+
name: 'Images of Text',
|
|
146
|
+
level: 'AA',
|
|
147
|
+
principle: 'perceivable',
|
|
148
|
+
description: 'Text is used to convey information rather than images of text',
|
|
149
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/images-of-text.html',
|
|
150
|
+
},
|
|
151
|
+
'1.4.10': {
|
|
152
|
+
criterion: '1.4.10',
|
|
153
|
+
name: 'Reflow',
|
|
154
|
+
level: 'AA',
|
|
155
|
+
principle: 'perceivable',
|
|
156
|
+
description: 'Content can reflow without two-dimensional scrolling at 320px width',
|
|
157
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/reflow.html',
|
|
158
|
+
},
|
|
159
|
+
'1.4.11': {
|
|
160
|
+
criterion: '1.4.11',
|
|
161
|
+
name: 'Non-text Contrast',
|
|
162
|
+
level: 'AA',
|
|
163
|
+
principle: 'perceivable',
|
|
164
|
+
description: 'UI components and graphical objects have 3:1 contrast ratio',
|
|
165
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html',
|
|
166
|
+
},
|
|
167
|
+
'1.4.12': {
|
|
168
|
+
criterion: '1.4.12',
|
|
169
|
+
name: 'Text Spacing',
|
|
170
|
+
level: 'AA',
|
|
171
|
+
principle: 'perceivable',
|
|
172
|
+
description: 'No loss of content when adjusting text spacing',
|
|
173
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/text-spacing.html',
|
|
174
|
+
},
|
|
175
|
+
'1.4.13': {
|
|
176
|
+
criterion: '1.4.13',
|
|
177
|
+
name: 'Content on Hover or Focus',
|
|
178
|
+
level: 'AA',
|
|
179
|
+
principle: 'perceivable',
|
|
180
|
+
description: 'Content triggered by hover or focus is dismissible, hoverable, and persistent',
|
|
181
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html',
|
|
182
|
+
},
|
|
183
|
+
'2.4.3': {
|
|
184
|
+
criterion: '2.4.3',
|
|
185
|
+
name: 'Focus Order',
|
|
186
|
+
level: 'AA',
|
|
187
|
+
principle: 'operable',
|
|
188
|
+
description: 'Focus order preserves meaning and operability',
|
|
189
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html',
|
|
190
|
+
},
|
|
191
|
+
'2.4.5': {
|
|
192
|
+
criterion: '2.4.5',
|
|
193
|
+
name: 'Multiple Ways',
|
|
194
|
+
level: 'AA',
|
|
195
|
+
principle: 'operable',
|
|
196
|
+
description: 'More than one way to locate a page within a set of pages',
|
|
197
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/multiple-ways.html',
|
|
198
|
+
},
|
|
199
|
+
'2.4.6': {
|
|
200
|
+
criterion: '2.4.6',
|
|
201
|
+
name: 'Headings and Labels',
|
|
202
|
+
level: 'AA',
|
|
203
|
+
principle: 'operable',
|
|
204
|
+
description: 'Headings and labels describe topic or purpose',
|
|
205
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/headings-and-labels.html',
|
|
206
|
+
},
|
|
207
|
+
'2.4.7': {
|
|
208
|
+
criterion: '2.4.7',
|
|
209
|
+
name: 'Focus Visible',
|
|
210
|
+
level: 'AA',
|
|
211
|
+
principle: 'operable',
|
|
212
|
+
description: 'Keyboard focus indicator is visible',
|
|
213
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html',
|
|
214
|
+
},
|
|
215
|
+
'2.4.11': {
|
|
216
|
+
criterion: '2.4.11',
|
|
217
|
+
name: 'Focus Not Obscured (Minimum)',
|
|
218
|
+
level: 'AA',
|
|
219
|
+
principle: 'operable',
|
|
220
|
+
description: 'When component receives focus, it is not entirely hidden',
|
|
221
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html',
|
|
222
|
+
},
|
|
223
|
+
'2.5.7': {
|
|
224
|
+
criterion: '2.5.7',
|
|
225
|
+
name: 'Dragging Movements',
|
|
226
|
+
level: 'AA',
|
|
227
|
+
principle: 'operable',
|
|
228
|
+
description: 'Functionality using dragging has single pointer alternative',
|
|
229
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements.html',
|
|
230
|
+
},
|
|
231
|
+
'2.5.8': {
|
|
232
|
+
criterion: '2.5.8',
|
|
233
|
+
name: 'Target Size (Minimum)',
|
|
234
|
+
level: 'AA',
|
|
235
|
+
principle: 'operable',
|
|
236
|
+
description: 'Target size is at least 24x24 CSS pixels',
|
|
237
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html',
|
|
238
|
+
},
|
|
239
|
+
'3.2.6': {
|
|
240
|
+
criterion: '3.2.6',
|
|
241
|
+
name: 'Consistent Help',
|
|
242
|
+
level: 'AA',
|
|
243
|
+
principle: 'understandable',
|
|
244
|
+
description: 'Help mechanisms appear in same relative order on each page',
|
|
245
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/consistent-help.html',
|
|
246
|
+
},
|
|
247
|
+
'3.3.7': {
|
|
248
|
+
criterion: '3.3.7',
|
|
249
|
+
name: 'Redundant Entry',
|
|
250
|
+
level: 'AA',
|
|
251
|
+
principle: 'understandable',
|
|
252
|
+
description: 'Previously entered information is auto-populated or available for selection',
|
|
253
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/redundant-entry.html',
|
|
254
|
+
},
|
|
255
|
+
'3.3.8': {
|
|
256
|
+
criterion: '3.3.8',
|
|
257
|
+
name: 'Accessible Authentication (Minimum)',
|
|
258
|
+
level: 'AA',
|
|
259
|
+
principle: 'understandable',
|
|
260
|
+
description: 'Cognitive function tests are not required for authentication',
|
|
261
|
+
url: 'https://www.w3.org/WAI/WCAG22/Understanding/accessible-authentication-minimum.html',
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Get all criteria for a conformance level
|
|
266
|
+
*/
|
|
267
|
+
export function getCriteriaForLevel(level) {
|
|
268
|
+
const criteria = [];
|
|
269
|
+
// Level A is always included
|
|
270
|
+
criteria.push(...Object.values(WCAG_LEVEL_A_CRITERIA));
|
|
271
|
+
// Level AA includes Level A
|
|
272
|
+
if (level === 'AA' || level === 'AAA') {
|
|
273
|
+
criteria.push(...Object.values(WCAG_LEVEL_AA_CRITERIA));
|
|
274
|
+
}
|
|
275
|
+
return criteria;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get criterion by ID
|
|
279
|
+
*/
|
|
280
|
+
export function getCriterion(criterionId) {
|
|
281
|
+
return WCAG_LEVEL_A_CRITERIA[criterionId] ?? WCAG_LEVEL_AA_CRITERIA[criterionId];
|
|
282
|
+
}
|
|
283
|
+
// ============================================================================
|
|
284
|
+
// Component Accessibility Requirements
|
|
285
|
+
// ============================================================================
|
|
286
|
+
/**
|
|
287
|
+
* Accessibility requirements by component type
|
|
288
|
+
*/
|
|
289
|
+
export const COMPONENT_REQUIREMENTS = {
|
|
290
|
+
// Standard components
|
|
291
|
+
button: {
|
|
292
|
+
componentType: 'button',
|
|
293
|
+
required: ['label'],
|
|
294
|
+
aria: ['role: button'],
|
|
295
|
+
keyboard: ['Enter', 'Space'],
|
|
296
|
+
criteria: ['4.1.2', '2.1.1', '2.4.7'],
|
|
297
|
+
notes: 'Must have accessible name via label or aria-label',
|
|
298
|
+
},
|
|
299
|
+
checkBox: {
|
|
300
|
+
componentType: 'checkBox',
|
|
301
|
+
required: ['label', 'checked'],
|
|
302
|
+
aria: ['role: checkbox', 'aria-checked'],
|
|
303
|
+
keyboard: ['Space'],
|
|
304
|
+
criteria: ['4.1.2', '2.1.1', '1.3.1'],
|
|
305
|
+
notes: 'Must indicate checked state',
|
|
306
|
+
},
|
|
307
|
+
slider: {
|
|
308
|
+
componentType: 'slider',
|
|
309
|
+
required: ['min', 'max', 'value'],
|
|
310
|
+
aria: ['role: slider', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow'],
|
|
311
|
+
keyboard: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'],
|
|
312
|
+
criteria: ['4.1.2', '2.1.1', '1.3.1'],
|
|
313
|
+
notes: 'Must have range information exposed',
|
|
314
|
+
},
|
|
315
|
+
textField: {
|
|
316
|
+
componentType: 'textField',
|
|
317
|
+
required: ['value'],
|
|
318
|
+
aria: ['role: textbox'],
|
|
319
|
+
keyboard: ['Tab', 'typing'],
|
|
320
|
+
criteria: ['4.1.2', '2.1.1', '3.3.2'],
|
|
321
|
+
notes: 'Should have visible label',
|
|
322
|
+
},
|
|
323
|
+
image: {
|
|
324
|
+
componentType: 'image',
|
|
325
|
+
required: ['alt'],
|
|
326
|
+
aria: ['role: img'],
|
|
327
|
+
keyboard: [],
|
|
328
|
+
criteria: ['1.1.1'],
|
|
329
|
+
notes: 'All images must have alt text; decorative images use alt=""',
|
|
330
|
+
},
|
|
331
|
+
modal: {
|
|
332
|
+
componentType: 'modal',
|
|
333
|
+
required: ['title'],
|
|
334
|
+
aria: ['role: dialog', 'aria-modal', 'aria-labelledby'],
|
|
335
|
+
keyboard: ['Escape', 'Tab (trapped)'],
|
|
336
|
+
criteria: ['2.1.2', '2.4.3', '4.1.2'],
|
|
337
|
+
notes: 'Focus must be trapped within modal',
|
|
338
|
+
},
|
|
339
|
+
tabs: {
|
|
340
|
+
componentType: 'tabs',
|
|
341
|
+
required: ['tabs'],
|
|
342
|
+
aria: ['role: tablist'],
|
|
343
|
+
keyboard: ['ArrowLeft', 'ArrowRight', 'Home', 'End'],
|
|
344
|
+
criteria: ['2.1.1', '4.1.2', '1.3.1'],
|
|
345
|
+
notes: 'Use roving tabindex pattern',
|
|
346
|
+
},
|
|
347
|
+
list: {
|
|
348
|
+
componentType: 'list',
|
|
349
|
+
required: ['children'],
|
|
350
|
+
aria: ['role: list'],
|
|
351
|
+
keyboard: ['ArrowUp', 'ArrowDown'],
|
|
352
|
+
criteria: ['1.3.1'],
|
|
353
|
+
},
|
|
354
|
+
card: {
|
|
355
|
+
componentType: 'card',
|
|
356
|
+
required: ['children'],
|
|
357
|
+
aria: ['role: article'],
|
|
358
|
+
keyboard: [],
|
|
359
|
+
criteria: ['1.3.1'],
|
|
360
|
+
},
|
|
361
|
+
// QE components
|
|
362
|
+
'qe:coverageGauge': {
|
|
363
|
+
componentType: 'qe:coverageGauge',
|
|
364
|
+
required: ['coverage'],
|
|
365
|
+
aria: ['role: meter', 'aria-valuenow', 'aria-valuemin', 'aria-valuemax'],
|
|
366
|
+
keyboard: [],
|
|
367
|
+
criteria: ['4.1.2', '1.3.1'],
|
|
368
|
+
notes: 'Coverage value must be exposed to assistive technology',
|
|
369
|
+
},
|
|
370
|
+
'qe:testStatusBadge': {
|
|
371
|
+
componentType: 'qe:testStatusBadge',
|
|
372
|
+
required: ['status'],
|
|
373
|
+
aria: ['role: status'],
|
|
374
|
+
keyboard: [],
|
|
375
|
+
criteria: ['4.1.2', '1.3.1'],
|
|
376
|
+
notes: 'Status changes should be announced',
|
|
377
|
+
},
|
|
378
|
+
'qe:vulnerabilityCard': {
|
|
379
|
+
componentType: 'qe:vulnerabilityCard',
|
|
380
|
+
required: ['severity', 'title'],
|
|
381
|
+
aria: ['role: article'],
|
|
382
|
+
keyboard: [],
|
|
383
|
+
criteria: ['1.3.1', '1.4.11'],
|
|
384
|
+
notes: 'Severity color must have sufficient contrast',
|
|
385
|
+
},
|
|
386
|
+
'qe:qualityGateIndicator': {
|
|
387
|
+
componentType: 'qe:qualityGateIndicator',
|
|
388
|
+
required: ['status', 'metrics'],
|
|
389
|
+
aria: ['role: status', 'aria-live: polite'],
|
|
390
|
+
keyboard: [],
|
|
391
|
+
criteria: ['4.1.2', '1.3.1'],
|
|
392
|
+
notes: 'Gate status should use live region for updates',
|
|
393
|
+
},
|
|
394
|
+
'qe:a11yFindingCard': {
|
|
395
|
+
componentType: 'qe:a11yFindingCard',
|
|
396
|
+
required: ['wcagLevel', 'rule', 'impact'],
|
|
397
|
+
aria: ['role: article'],
|
|
398
|
+
keyboard: [],
|
|
399
|
+
criteria: ['1.3.1'],
|
|
400
|
+
},
|
|
401
|
+
'qe:testTimeline': {
|
|
402
|
+
componentType: 'qe:testTimeline',
|
|
403
|
+
required: ['events'],
|
|
404
|
+
aria: ['role: list'],
|
|
405
|
+
keyboard: ['ArrowLeft', 'ArrowRight'],
|
|
406
|
+
criteria: ['1.3.1', '2.1.1'],
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
/**
|
|
410
|
+
* Get accessibility requirements for component type
|
|
411
|
+
*/
|
|
412
|
+
export function getAccessibilityRequirements(componentType) {
|
|
413
|
+
return COMPONENT_REQUIREMENTS[componentType];
|
|
414
|
+
}
|
|
415
|
+
// ============================================================================
|
|
416
|
+
// Validation Functions
|
|
417
|
+
// ============================================================================
|
|
418
|
+
/**
|
|
419
|
+
* Validate a single component for WCAG compliance
|
|
420
|
+
*/
|
|
421
|
+
export function validateComponent(component, level = 'AA') {
|
|
422
|
+
const issues = [];
|
|
423
|
+
const warnings = [];
|
|
424
|
+
const { id: componentId, type: componentType, properties } = component;
|
|
425
|
+
const accessibility = properties.accessibility;
|
|
426
|
+
// 4.1.2: Name, Role, Value - check for accessible name
|
|
427
|
+
validateNameRoleValue(componentId, componentType, properties, accessibility, issues);
|
|
428
|
+
// 1.1.1: Non-text Content - check images have alt text
|
|
429
|
+
if (componentType === 'image') {
|
|
430
|
+
validateImageAltText(componentId, properties, issues);
|
|
431
|
+
}
|
|
432
|
+
// 1.3.1: Info and Relationships - check semantic structure
|
|
433
|
+
validateInfoAndRelationships(componentId, componentType, properties, accessibility, issues, warnings);
|
|
434
|
+
// 3.3.2: Labels or Instructions - check form inputs
|
|
435
|
+
if (isFormInput(componentType)) {
|
|
436
|
+
validateLabels(componentId, componentType, properties, accessibility, issues, warnings);
|
|
437
|
+
}
|
|
438
|
+
// 2.1.1: Keyboard - check keyboard accessibility
|
|
439
|
+
if (isInteractive(componentType)) {
|
|
440
|
+
validateKeyboardAccess(componentId, componentType, properties, accessibility, issues, warnings);
|
|
441
|
+
}
|
|
442
|
+
// Check range components (slider, gauge, progress)
|
|
443
|
+
if (isRangeComponent(componentType)) {
|
|
444
|
+
validateRangeValues(componentId, componentType, properties, accessibility, issues);
|
|
445
|
+
}
|
|
446
|
+
// Level AA specific checks
|
|
447
|
+
if (level === 'AA' || level === 'AAA') {
|
|
448
|
+
// 2.4.6: Headings and Labels - check descriptive labels
|
|
449
|
+
validateHeadingsAndLabels(componentId, componentType, properties, accessibility, warnings);
|
|
450
|
+
// 1.4.11: Non-text Contrast - warn about dynamic content
|
|
451
|
+
if (componentType === 'qe:vulnerabilityCard' || componentType === 'qe:testStatusBadge') {
|
|
452
|
+
warnAboutColorContrast(componentId, componentType, warnings);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return { componentId, componentType, issues, warnings };
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Validate a surface for WCAG compliance
|
|
459
|
+
*/
|
|
460
|
+
export function validateSurface(surface, level = 'AA') {
|
|
461
|
+
const startTime = Date.now();
|
|
462
|
+
const allIssues = [];
|
|
463
|
+
const allWarnings = [];
|
|
464
|
+
const passedCriteria = new Map();
|
|
465
|
+
// Validate each component
|
|
466
|
+
for (const component of surface.components) {
|
|
467
|
+
const result = validateComponent(component, level);
|
|
468
|
+
allIssues.push(...result.issues);
|
|
469
|
+
allWarnings.push(...result.warnings);
|
|
470
|
+
}
|
|
471
|
+
// Track passed criteria
|
|
472
|
+
const allCriteria = getCriteriaForLevel(level);
|
|
473
|
+
const failedCriteria = new Set(allIssues.map((i) => i.criterion));
|
|
474
|
+
for (const criterion of allCriteria) {
|
|
475
|
+
if (!failedCriteria.has(criterion.criterion)) {
|
|
476
|
+
passedCriteria.set(criterion.criterion, (passedCriteria.get(criterion.criterion) ?? 0) + 1);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const passed = Array.from(passedCriteria.entries()).map(([criterion, count]) => {
|
|
480
|
+
const def = getCriterion(criterion);
|
|
481
|
+
return {
|
|
482
|
+
criterion,
|
|
483
|
+
name: def?.name ?? criterion,
|
|
484
|
+
componentCount: count,
|
|
485
|
+
};
|
|
486
|
+
});
|
|
487
|
+
// Determine if valid at requested level
|
|
488
|
+
const criticalIssues = allIssues.filter((i) => {
|
|
489
|
+
const criterion = getCriterion(i.criterion);
|
|
490
|
+
if (!criterion)
|
|
491
|
+
return false;
|
|
492
|
+
if (level === 'A')
|
|
493
|
+
return criterion.level === 'A';
|
|
494
|
+
if (level === 'AA')
|
|
495
|
+
return criterion.level === 'A' || criterion.level === 'AA';
|
|
496
|
+
return true;
|
|
497
|
+
});
|
|
498
|
+
const duration = Date.now() - startTime;
|
|
499
|
+
return {
|
|
500
|
+
valid: criticalIssues.length === 0,
|
|
501
|
+
level,
|
|
502
|
+
surfaceId: surface.surfaceId,
|
|
503
|
+
issues: allIssues,
|
|
504
|
+
warnings: allWarnings,
|
|
505
|
+
passed,
|
|
506
|
+
componentCount: surface.components.length,
|
|
507
|
+
timestamp: new Date().toISOString(),
|
|
508
|
+
duration,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get a summary of accessibility issues by criterion
|
|
513
|
+
*/
|
|
514
|
+
export function getIssueSummary(issues) {
|
|
515
|
+
const summary = {};
|
|
516
|
+
for (const issue of issues) {
|
|
517
|
+
if (!summary[issue.criterion]) {
|
|
518
|
+
summary[issue.criterion] = { count: 0, components: [] };
|
|
519
|
+
}
|
|
520
|
+
summary[issue.criterion].count++;
|
|
521
|
+
if (!summary[issue.criterion].components.includes(issue.componentId)) {
|
|
522
|
+
summary[issue.criterion].components.push(issue.componentId);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return summary;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Get accessibility score (0-100)
|
|
529
|
+
*/
|
|
530
|
+
export function getAccessibilityScore(result) {
|
|
531
|
+
const totalCriteria = getCriteriaForLevel(result.level).length;
|
|
532
|
+
const passedCount = result.passed.length;
|
|
533
|
+
const issueCount = new Set(result.issues.map((i) => i.criterion)).size;
|
|
534
|
+
const criteriaChecked = passedCount + issueCount;
|
|
535
|
+
if (criteriaChecked === 0)
|
|
536
|
+
return 100;
|
|
537
|
+
return Math.round((passedCount / totalCriteria) * 100);
|
|
538
|
+
}
|
|
539
|
+
// ============================================================================
|
|
540
|
+
// Validation Helpers
|
|
541
|
+
// ============================================================================
|
|
542
|
+
function validateNameRoleValue(componentId, componentType, properties, accessibility, issues) {
|
|
543
|
+
// Interactive components must have accessible name
|
|
544
|
+
if (isInteractive(componentType)) {
|
|
545
|
+
const hasLabel = Boolean(properties.label);
|
|
546
|
+
const hasAriaLabel = Boolean(accessibility?.label);
|
|
547
|
+
const hasLabelledBy = Boolean(accessibility?.labelledBy);
|
|
548
|
+
if (!hasLabel && !hasAriaLabel && !hasLabelledBy) {
|
|
549
|
+
issues.push({
|
|
550
|
+
criterion: '4.1.2',
|
|
551
|
+
level: 'A',
|
|
552
|
+
severity: 'error',
|
|
553
|
+
componentId,
|
|
554
|
+
componentType,
|
|
555
|
+
message: `${componentType} component must have an accessible name`,
|
|
556
|
+
remediation: 'Add a label property or aria-label/aria-labelledby via accessibility attributes',
|
|
557
|
+
property: 'label',
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// Check for required role
|
|
562
|
+
const requirements = COMPONENT_REQUIREMENTS[componentType];
|
|
563
|
+
if (requirements) {
|
|
564
|
+
const expectedRole = requirements.aria.find((a) => a.startsWith('role:'));
|
|
565
|
+
if (expectedRole && accessibility?.role) {
|
|
566
|
+
const expected = expectedRole.split(': ')[1];
|
|
567
|
+
if (accessibility.role !== expected) {
|
|
568
|
+
issues.push({
|
|
569
|
+
criterion: '4.1.2',
|
|
570
|
+
level: 'A',
|
|
571
|
+
severity: 'warning',
|
|
572
|
+
componentId,
|
|
573
|
+
componentType,
|
|
574
|
+
message: `${componentType} has unexpected role`,
|
|
575
|
+
remediation: `Use role="${expected}" for proper semantics`,
|
|
576
|
+
property: 'role',
|
|
577
|
+
expected,
|
|
578
|
+
actual: accessibility.role,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
function validateImageAltText(componentId, properties, issues) {
|
|
585
|
+
const alt = properties.alt;
|
|
586
|
+
if (alt === undefined || alt === null) {
|
|
587
|
+
issues.push({
|
|
588
|
+
criterion: '1.1.1',
|
|
589
|
+
level: 'A',
|
|
590
|
+
severity: 'error',
|
|
591
|
+
componentId,
|
|
592
|
+
componentType: 'image',
|
|
593
|
+
message: 'Image is missing alt text',
|
|
594
|
+
remediation: 'Add alt property with descriptive text, or empty string for decorative images',
|
|
595
|
+
property: 'alt',
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function validateInfoAndRelationships(componentId, componentType, properties, accessibility, issues, warnings) {
|
|
600
|
+
// Check headings have level
|
|
601
|
+
if (componentType === 'text') {
|
|
602
|
+
const usageHint = properties.usageHint;
|
|
603
|
+
if (usageHint && usageHint.match(/^h[1-6]$/)) {
|
|
604
|
+
if (!accessibility?.level) {
|
|
605
|
+
warnings.push({
|
|
606
|
+
criterion: '1.3.1',
|
|
607
|
+
componentId,
|
|
608
|
+
message: 'Heading element should have aria-level for programmatic access',
|
|
609
|
+
suggestion: 'Add level property to accessibility attributes',
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// Check lists have proper structure
|
|
615
|
+
if (componentType === 'list' || componentType === 'qe:testTimeline') {
|
|
616
|
+
if (!accessibility?.role || accessibility.role !== 'list') {
|
|
617
|
+
warnings.push({
|
|
618
|
+
criterion: '1.3.1',
|
|
619
|
+
componentId,
|
|
620
|
+
message: 'List component should have role="list" for proper semantics',
|
|
621
|
+
suggestion: 'Ensure list role is set in accessibility attributes',
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function validateLabels(componentId, componentType, properties, accessibility, issues, warnings) {
|
|
627
|
+
const hasLabel = Boolean(properties.label);
|
|
628
|
+
const hasAriaLabel = Boolean(accessibility?.label);
|
|
629
|
+
const hasLabelledBy = Boolean(accessibility?.labelledBy);
|
|
630
|
+
const hasPlaceholder = Boolean(properties.placeholder);
|
|
631
|
+
if (!hasLabel && !hasAriaLabel && !hasLabelledBy) {
|
|
632
|
+
if (hasPlaceholder) {
|
|
633
|
+
warnings.push({
|
|
634
|
+
criterion: '3.3.2',
|
|
635
|
+
componentId,
|
|
636
|
+
message: 'Using placeholder as only label is not accessible',
|
|
637
|
+
suggestion: 'Add a visible label or aria-label in addition to placeholder',
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
issues.push({
|
|
642
|
+
criterion: '3.3.2',
|
|
643
|
+
level: 'A',
|
|
644
|
+
severity: 'error',
|
|
645
|
+
componentId,
|
|
646
|
+
componentType,
|
|
647
|
+
message: 'Form input is missing label',
|
|
648
|
+
remediation: 'Add label property or aria-label/aria-labelledby',
|
|
649
|
+
property: 'label',
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// Check required fields are marked
|
|
654
|
+
if (properties.required === true && !accessibility?.required) {
|
|
655
|
+
warnings.push({
|
|
656
|
+
criterion: '3.3.2',
|
|
657
|
+
componentId,
|
|
658
|
+
message: 'Required field should have aria-required=true',
|
|
659
|
+
suggestion: 'Add required: true to accessibility attributes',
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function validateKeyboardAccess(componentId, componentType, properties, accessibility, issues, warnings) {
|
|
664
|
+
const tabIndex = accessibility?.tabIndex;
|
|
665
|
+
const disabled = Boolean(properties.disabled) || Boolean(accessibility?.disabled);
|
|
666
|
+
// Focusable elements should have tabIndex
|
|
667
|
+
if (!disabled && tabIndex === undefined) {
|
|
668
|
+
warnings.push({
|
|
669
|
+
criterion: '2.1.1',
|
|
670
|
+
componentId,
|
|
671
|
+
message: 'Interactive element should have explicit tabIndex',
|
|
672
|
+
suggestion: 'Add tabIndex: 0 for focusable elements, -1 for programmatically focusable only',
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
// Disabled elements should not be focusable
|
|
676
|
+
if (disabled && tabIndex !== undefined && tabIndex >= 0) {
|
|
677
|
+
issues.push({
|
|
678
|
+
criterion: '2.1.1',
|
|
679
|
+
level: 'A',
|
|
680
|
+
severity: 'warning',
|
|
681
|
+
componentId,
|
|
682
|
+
componentType,
|
|
683
|
+
message: 'Disabled element should not be in tab order',
|
|
684
|
+
remediation: 'Set tabIndex: -1 for disabled elements',
|
|
685
|
+
property: 'tabIndex',
|
|
686
|
+
expected: '-1',
|
|
687
|
+
actual: String(tabIndex),
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
// Modal should trap focus
|
|
691
|
+
if (componentType === 'modal') {
|
|
692
|
+
const trapsFocus = properties.trapFocus;
|
|
693
|
+
if (trapsFocus === false) {
|
|
694
|
+
issues.push({
|
|
695
|
+
criterion: '2.1.2',
|
|
696
|
+
level: 'A',
|
|
697
|
+
severity: 'error',
|
|
698
|
+
componentId,
|
|
699
|
+
componentType,
|
|
700
|
+
message: 'Modal must trap focus to prevent keyboard trap',
|
|
701
|
+
remediation: 'Enable focus trapping in modal or ensure proper focus management',
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
function validateRangeValues(componentId, componentType, properties, accessibility, issues) {
|
|
707
|
+
const value = properties.value ?? properties.coverage;
|
|
708
|
+
const min = properties.min ?? 0;
|
|
709
|
+
const max = properties.max ?? 100;
|
|
710
|
+
// Check required range attributes
|
|
711
|
+
if (accessibility) {
|
|
712
|
+
if (accessibility.valueNow === undefined && value !== undefined) {
|
|
713
|
+
issues.push({
|
|
714
|
+
criterion: '4.1.2',
|
|
715
|
+
level: 'A',
|
|
716
|
+
severity: 'warning',
|
|
717
|
+
componentId,
|
|
718
|
+
componentType,
|
|
719
|
+
message: 'Range component should expose current value via aria-valuenow',
|
|
720
|
+
remediation: 'Add valueNow to accessibility attributes',
|
|
721
|
+
property: 'valueNow',
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
if (accessibility.valueMin === undefined && min !== undefined) {
|
|
725
|
+
issues.push({
|
|
726
|
+
criterion: '4.1.2',
|
|
727
|
+
level: 'A',
|
|
728
|
+
severity: 'warning',
|
|
729
|
+
componentId,
|
|
730
|
+
componentType,
|
|
731
|
+
message: 'Range component should expose minimum value via aria-valuemin',
|
|
732
|
+
remediation: 'Add valueMin to accessibility attributes',
|
|
733
|
+
property: 'valueMin',
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
if (accessibility.valueMax === undefined && max !== undefined) {
|
|
737
|
+
issues.push({
|
|
738
|
+
criterion: '4.1.2',
|
|
739
|
+
level: 'A',
|
|
740
|
+
severity: 'warning',
|
|
741
|
+
componentId,
|
|
742
|
+
componentType,
|
|
743
|
+
message: 'Range component should expose maximum value via aria-valuemax',
|
|
744
|
+
remediation: 'Add valueMax to accessibility attributes',
|
|
745
|
+
property: 'valueMax',
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function validateHeadingsAndLabels(componentId, componentType, properties, accessibility, warnings) {
|
|
751
|
+
// Check labels are descriptive (basic heuristics)
|
|
752
|
+
const rawLabel = properties.label ?? accessibility?.label;
|
|
753
|
+
// Extract string from BoundValue if needed
|
|
754
|
+
const label = extractLabelString(rawLabel);
|
|
755
|
+
if (label) {
|
|
756
|
+
// Warn about generic labels
|
|
757
|
+
const genericLabels = ['click here', 'submit', 'ok', 'cancel', 'button', 'link'];
|
|
758
|
+
if (genericLabels.includes(label.toLowerCase())) {
|
|
759
|
+
warnings.push({
|
|
760
|
+
criterion: '2.4.6',
|
|
761
|
+
componentId,
|
|
762
|
+
message: `Label "${label}" is not descriptive enough`,
|
|
763
|
+
suggestion: 'Use a more descriptive label that explains the action or purpose',
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
// Warn about very short labels
|
|
767
|
+
if (label.length < 3 && componentType !== 'icon') {
|
|
768
|
+
warnings.push({
|
|
769
|
+
criterion: '2.4.6',
|
|
770
|
+
componentId,
|
|
771
|
+
message: 'Label may be too short to be descriptive',
|
|
772
|
+
suggestion: 'Consider using a more descriptive label',
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
function warnAboutColorContrast(componentId, componentType, warnings) {
|
|
778
|
+
warnings.push({
|
|
779
|
+
criterion: '1.4.11',
|
|
780
|
+
componentId,
|
|
781
|
+
message: `${componentType} uses color to convey status - ensure sufficient contrast`,
|
|
782
|
+
suggestion: 'Verify color contrast meets 3:1 ratio and consider adding icons or patterns for color-blind users',
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
function isInteractive(componentType) {
|
|
786
|
+
const interactiveTypes = [
|
|
787
|
+
'button', 'checkBox', 'slider', 'textField', 'dateTimeInput',
|
|
788
|
+
'tabs', 'modal',
|
|
789
|
+
];
|
|
790
|
+
return interactiveTypes.includes(componentType);
|
|
791
|
+
}
|
|
792
|
+
function isFormInput(componentType) {
|
|
793
|
+
const formTypes = ['textField', 'checkBox', 'slider', 'dateTimeInput'];
|
|
794
|
+
return formTypes.includes(componentType);
|
|
795
|
+
}
|
|
796
|
+
function isRangeComponent(componentType) {
|
|
797
|
+
const rangeTypes = ['slider', 'qe:coverageGauge'];
|
|
798
|
+
return rangeTypes.includes(componentType);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Extract string value from raw label (handles BoundValue objects)
|
|
802
|
+
*/
|
|
803
|
+
function extractLabelString(rawLabel) {
|
|
804
|
+
if (typeof rawLabel === 'string') {
|
|
805
|
+
return rawLabel;
|
|
806
|
+
}
|
|
807
|
+
if (typeof rawLabel === 'object' && rawLabel !== null) {
|
|
808
|
+
// Handle BoundValue - literalString takes precedence
|
|
809
|
+
const obj = rawLabel;
|
|
810
|
+
if ('literalString' in obj && typeof obj.literalString === 'string') {
|
|
811
|
+
return obj.literalString;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return undefined;
|
|
815
|
+
}
|
|
816
|
+
//# sourceMappingURL=wcag-validator.js.map
|