mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 15:46:30 +03:00
AI-assisted implementation by Codex at maintainer pbakaus request. Merge current main without dropping upstream oracle updates. Resolve component waivers while the actual visual candidate is in hand; carry stamps through sampling and screenshot fallback. Forward project selectors through the live prelude and per-page scan config, and keep waived findings out of direct/snapshot/offscreen UI groups. Add Rust and Node regressions. Rust workspace, rebuilt bundle/engine, full Bun/Node/oracle/plugin suite and real Chrome direct/snapshot checks passed. Deterministic full live E2E sweep is still running. Generated provider harness output intentionally omitted.
75 lines
3.0 KiB
JavaScript
75 lines
3.0 KiB
JavaScript
// --- browser-bundle/30-scan-common.js ---
|
|
// Scan-config plumbing shared by the in-page bundle (50-scan.js) and the
|
|
// extension's offscreen document (60-offscreen.js): which visual-contrast
|
|
// mode a scan runs in, the options it resolves to, which analyses the lazy
|
|
// (scroll-into-view) pass re-tries, and the scanId echo. `config` is the
|
|
// page's `window.__IMPECCABLE_CONFIG__` in the page and the extension's scan
|
|
// config offscreen.
|
|
|
|
// Visual contrast has three modes. Explicit true runs the full sampled
|
|
// pass; explicit false disables it entirely (the deterministic-only mode
|
|
// the test suites use). Unset — the default overlay run — samples ONLY
|
|
// image-backed text: the one class the analytic walk deliberately skips,
|
|
// because a url() layer's pixels are unknowable without looking. In-page
|
|
// sampling draws the source image alone to a canvas (glyph ink never
|
|
// pollutes it), and a cross-origin image without CORS reports unresolved
|
|
// instead of guessing.
|
|
function __visualContrastMode(options = {}, config = {}) {
|
|
const explicit = typeof options.visualContrast === 'boolean'
|
|
? options.visualContrast
|
|
: typeof config?.visualContrast === 'boolean'
|
|
? config.visualContrast
|
|
: null;
|
|
if (explicit === true) return 'full';
|
|
if (explicit === false) return false;
|
|
return 'image-only';
|
|
}
|
|
|
|
function __visualContrastOptions(options = {}, config = {}) {
|
|
config = config || {};
|
|
const scrollOffscreen = typeof options.scrollOffscreen === 'boolean'
|
|
? options.scrollOffscreen
|
|
: typeof options.visualContrastScrollOffscreen === 'boolean'
|
|
? options.visualContrastScrollOffscreen
|
|
: typeof config.visualContrastScrollOffscreen === 'boolean'
|
|
? config.visualContrastScrollOffscreen
|
|
: false;
|
|
return {
|
|
...options,
|
|
...(Array.isArray(config.ignoreSelectors) ? { ignoreSelectors: config.ignoreSelectors } : {}),
|
|
maxCandidates: Number.isFinite(options.visualContrastMaxCandidates)
|
|
? options.visualContrastMaxCandidates
|
|
: Number.isFinite(options.maxCandidates)
|
|
? options.maxCandidates
|
|
: Number.isFinite(config.visualContrastMaxCandidates)
|
|
? config.visualContrastMaxCandidates
|
|
: undefined,
|
|
scrollOffscreen,
|
|
};
|
|
}
|
|
|
|
// Engines keep waiver stamps for callers that report suppression counts.
|
|
// UI consumers render only reportable findings, including after visual passes.
|
|
function __reportableGroups(groups) {
|
|
return groups.map(group => ({
|
|
...group,
|
|
findings: group.findings.filter(finding => !finding.ignoredBy),
|
|
})).filter(group => group.findings.length > 0);
|
|
}
|
|
|
|
// The analyses the lazy pass watches: unresolved only because the text was
|
|
// outside the viewport, and addressable.
|
|
function __lazyVisualContrastCandidates(analyses) {
|
|
return (analyses || []).filter(result =>
|
|
result?.status === 'unresolved' &&
|
|
result.reason === 'text outside viewport' &&
|
|
result.selector
|
|
);
|
|
}
|
|
|
|
function __scanResultMeta(options = {}) {
|
|
const scanId = options.scanId;
|
|
if (typeof scanId !== 'string' && typeof scanId !== 'number') return {};
|
|
return { scanId: String(scanId) };
|
|
}
|