mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 15:46:30 +03:00
Fix: harden live overlay detector waivers (#639 follow-up)
Read waiver config from every live root (appRoot, contextRoot, repoRoot), so monorepo projects whose config lives at the repo root reach the overlay; serialize served roots and page identities repo-relative there. Resolve each page URL to its actual serving file via the inject config's resolved page list before applying file-scoped waivers; ambiguous URLs keep the conservative common-ancestor fallback (PR #645 review discussion r3840011436). Honour detector.ignoreFiles: a wholly waived page now scans to zero findings in the overlay, matching the CLI and the edit hook. Guard the resolver call so a throwing resolver degrades to an unfiltered scan instead of breaking the detect toggle. Match design-system-color waivers by color value across hex and rgb() spellings, and stop extracting font values for bounce-easing findings, mirroring extractFindingIgnoreValue. Regenerate the browser bundle. AI-assisted change: reviewed, planned, and implemented with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Abdul Wahab
co-authored by
Claude Fable 5
parent
09506a9bb5
commit
152d6940b0
@@ -22,7 +22,6 @@ import net from 'node:net';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { parseDesignMd } from './lib/design-parser.mjs';
|
||||
import { loadContext } from './context.mjs';
|
||||
import { readConfig as readHookConfig } from './hook-lib.mjs';
|
||||
import {
|
||||
assembleLiveBrowserScript,
|
||||
assertLiveBrowserScriptParts,
|
||||
@@ -46,10 +45,10 @@ import {
|
||||
readLiveServerInfo,
|
||||
removeLiveServerInfo,
|
||||
resolveDesignSidecarPath,
|
||||
resolveLiveConfigPath,
|
||||
writeLiveServerInfo,
|
||||
} from './lib/impeccable-paths.mjs';
|
||||
import { countByPage as countPendingByPage } from './live/manual-edits-buffer.mjs';
|
||||
import { collectProjectDetectorIgnores } from './live/project-ignores.mjs';
|
||||
import {
|
||||
createManualApplyController,
|
||||
summarizeManualApplyFailures,
|
||||
@@ -696,51 +695,6 @@ function isLoopbackOrigin(origin) {
|
||||
// HTTP request handler
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Project detector waivers for the browser overlay (issue #639). The CLI and
|
||||
// the edit hook filter findings through .impeccable/config.json; the overlay
|
||||
// scans in the browser, so the same config rides along in the /live.js
|
||||
// prelude and live-browser-ignores.js applies it per page at scan time.
|
||||
function readProjectDetectorIgnores() {
|
||||
// readConfig merges config.json with the gitignored config.local.json and
|
||||
// type-checks both, exactly as the edit hook reads the same pair.
|
||||
const config = readHookConfig(process.cwd());
|
||||
return {
|
||||
ignoreRules: Array.isArray(config.ignoreRules) ? config.ignoreRules : [],
|
||||
// Serve only what the browser matches on; createdAt/reason stay local.
|
||||
ignoreValues: (Array.isArray(config.ignoreValues) ? config.ignoreValues : []).map((entry) => ({
|
||||
rule: entry.rule,
|
||||
value: entry.value,
|
||||
...(Array.isArray(entry.files) && entry.files.length > 0 ? { files: entry.files } : {}),
|
||||
})),
|
||||
roots: readLiveServedRoots(),
|
||||
};
|
||||
}
|
||||
|
||||
// Where the served pages live inside the project. Ignore globs are
|
||||
// project-relative and the browser only knows its URL path, so it needs the
|
||||
// prefix; the inject config's own `files` globs are the authority on it.
|
||||
// Deriving it from the ignore globs instead fails silently: one entry scoped
|
||||
// to prototype/library/** would lend prototype/library/ as a candidate prefix
|
||||
// to every page, and that rule would suppress site-wide.
|
||||
function readLiveServedRoots() {
|
||||
try {
|
||||
const configPath = resolveLiveConfigPath({ cwd: process.cwd(), scriptsDir: __dirname });
|
||||
const live = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
const files = Array.isArray(live?.files) ? live.files : [];
|
||||
return [...new Set(files
|
||||
.filter((glob) => typeof glob === 'string' && glob)
|
||||
.map((glob) => {
|
||||
const wildcardAt = glob.search(/[*?{]/);
|
||||
const head = wildcardAt === -1 ? glob : glob.slice(0, wildcardAt);
|
||||
const cut = head.lastIndexOf('/');
|
||||
return cut > -1 ? head.slice(0, cut + 1) : '';
|
||||
}))];
|
||||
} catch {
|
||||
// No readable inject config: the browser matches URL paths as-is.
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function createRequestHandler({ detectScript, liveScriptParts }) {
|
||||
return (req, res) => {
|
||||
const url = new URL(req.url, `http://localhost:${state.port}`);
|
||||
@@ -802,8 +756,16 @@ function createRequestHandler({ detectScript, liveScriptParts }) {
|
||||
appRoot: process.cwd(),
|
||||
parts,
|
||||
// Read per request rather than cached, so editing the config and
|
||||
// reloading the tab is enough to pick up a new waiver.
|
||||
projectIgnores: readProjectDetectorIgnores(),
|
||||
// reloading the tab is enough to pick up a new waiver. Config comes
|
||||
// from every root the session spans (appRoot, contextRoot, repoRoot):
|
||||
// in a monorepo the hook and the CLI key it at the repo root, which
|
||||
// is not the appRoot this process chdir'd onto.
|
||||
projectIgnores: collectProjectDetectorIgnores({
|
||||
appRoot: process.cwd(),
|
||||
contextRoot: LIVE_ROOTS?.contextRoot,
|
||||
repoRoot: LIVE_ROOTS?.repoRoot,
|
||||
scriptsDir: __dirname,
|
||||
}),
|
||||
});
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/javascript',
|
||||
|
||||
Reference in New Issue
Block a user