mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
Fix: stop flagging 1D dashed rules as grid backgrounds (#615)
codex-grid-background treated any 2D px background-size as a grid, so a single hairline tiled as a dash or rail false-positived. A finding now requires two hairline gradients plus a px tile. Prepared with AI assistance (Cursor agent), directed by @abdulwahabone. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1955,20 +1955,19 @@ function scanCssTextForGlow(content) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// Decorative grid or line-field backgrounds drawn with hairline
|
||||
// Decorative two-axis grid backgrounds drawn with hairline
|
||||
// linear-gradient layers tiled by a fixed pixel cell. Shared by the HTML
|
||||
// pattern pass and the regex source engine so standalone CSS, component
|
||||
// styles, and inline styles receive the same coverage. Both signals must
|
||||
// co-occur in one declaration block; unrelated rules must not add up across
|
||||
// the file. Returns [{ index, snippet }], capped at one finding per source to
|
||||
// match the page-level HTML check's existing behavior.
|
||||
// the file. A single hairline is a line, divider, or rail, not a grid, even
|
||||
// when tiled by a 2D px cell. Returns [{ index, snippet }], capped at one
|
||||
// finding per source to match the page-level HTML check's existing behavior.
|
||||
function scanCssTextForGridBackground(content) {
|
||||
const hairlineRe = /\b\d{1,3}px\s*,\s*transparent\s+\d{1,3}px/gi;
|
||||
const invertedHairlineRe = /transparent\s+calc\(100%\s*-\s*\d{1,3}px\)/gi;
|
||||
const sizeDeclPxRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\b/i;
|
||||
const sizeDeclPxPairRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\s+\d{1,3}px/i;
|
||||
const shorthandPxAnyRe = /\/\s*\d{1,3}px\b/;
|
||||
const shorthandPxPairRe = /\/\s*\d{1,3}px\s+\d{1,3}px/;
|
||||
const bgDeclRe = /\bbackground(?:-image)?\s*:\s*([^;{}"']*)/gi;
|
||||
const blockRe = /\{([^{}]*)\}|style\s*=\s*"([^"]*)"|style\s*=\s*'([^']*)'/gi;
|
||||
let blk;
|
||||
@@ -1985,13 +1984,10 @@ function scanCssTextForGridBackground(content) {
|
||||
}
|
||||
if (hairlineCount === 0) continue;
|
||||
const hasPxCell = sizeDeclPxRe.test(block) || shorthandPxAnyRe.test(bgJoined);
|
||||
const hasPxPairCell = sizeDeclPxPairRe.test(block) || shorthandPxPairRe.test(bgJoined);
|
||||
if ((hairlineCount >= 2 && hasPxCell) || hasPxPairCell) {
|
||||
if (hairlineCount >= 2 && hasPxCell) {
|
||||
return [{
|
||||
index: blk.index,
|
||||
snippet: hairlineCount >= 2
|
||||
? 'two-axis grid-line gradient background'
|
||||
: 'px-tiled hairline line-field background',
|
||||
snippet: 'two-axis grid-line gradient background',
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,20 +721,19 @@ function scanCssTextForGlow(content) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// Decorative grid or line-field backgrounds drawn with hairline
|
||||
// Decorative two-axis grid backgrounds drawn with hairline
|
||||
// linear-gradient layers tiled by a fixed pixel cell. Shared by the HTML
|
||||
// pattern pass and the regex source engine so standalone CSS, component
|
||||
// styles, and inline styles receive the same coverage. Both signals must
|
||||
// co-occur in one declaration block; unrelated rules must not add up across
|
||||
// the file. Returns [{ index, snippet }], capped at one finding per source to
|
||||
// match the page-level HTML check's existing behavior.
|
||||
// the file. A single hairline is a line, divider, or rail, not a grid, even
|
||||
// when tiled by a 2D px cell. Returns [{ index, snippet }], capped at one
|
||||
// finding per source to match the page-level HTML check's existing behavior.
|
||||
function scanCssTextForGridBackground(content) {
|
||||
const hairlineRe = /\b\d{1,3}px\s*,\s*transparent\s+\d{1,3}px/gi;
|
||||
const invertedHairlineRe = /transparent\s+calc\(100%\s*-\s*\d{1,3}px\)/gi;
|
||||
const sizeDeclPxRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\b/i;
|
||||
const sizeDeclPxPairRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\s+\d{1,3}px/i;
|
||||
const shorthandPxAnyRe = /\/\s*\d{1,3}px\b/;
|
||||
const shorthandPxPairRe = /\/\s*\d{1,3}px\s+\d{1,3}px/;
|
||||
const bgDeclRe = /\bbackground(?:-image)?\s*:\s*([^;{}"']*)/gi;
|
||||
const blockRe = /\{([^{}]*)\}|style\s*=\s*"([^"]*)"|style\s*=\s*'([^']*)'/gi;
|
||||
let blk;
|
||||
@@ -751,13 +750,10 @@ function scanCssTextForGridBackground(content) {
|
||||
}
|
||||
if (hairlineCount === 0) continue;
|
||||
const hasPxCell = sizeDeclPxRe.test(block) || shorthandPxAnyRe.test(bgJoined);
|
||||
const hasPxPairCell = sizeDeclPxPairRe.test(block) || shorthandPxPairRe.test(bgJoined);
|
||||
if ((hairlineCount >= 2 && hasPxCell) || hasPxPairCell) {
|
||||
if (hairlineCount >= 2 && hasPxCell) {
|
||||
return [{
|
||||
index: blk.index,
|
||||
snippet: hairlineCount >= 2
|
||||
? 'two-axis grid-line gradient background'
|
||||
: 'px-tiled hairline line-field background',
|
||||
snippet: 'two-axis grid-line gradient background',
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1806,11 +1806,9 @@ describe('codex-grid-background variants', () => {
|
||||
expect(grids(css)).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('flags single-axis hairline tiled by a px pair cell', () => {
|
||||
test('keeps single-axis hairline tiled by a px pair cell legal', () => {
|
||||
const css = `body { background: linear-gradient(90deg, rgba(23,25,24,.035) 1px, transparent 1px) 0 0 / 40px 40px, #f4f1ea; }`;
|
||||
const f = grids(css);
|
||||
expect(f).toHaveLength(1);
|
||||
expect(f[0].snippet).toContain('line-field');
|
||||
expect(grids(css)).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('keeps percent-tiled single hairlines (data-viz track rules) legal', () => {
|
||||
@@ -1818,6 +1816,36 @@ describe('codex-grid-background variants', () => {
|
||||
expect(grids(css)).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('keeps 1D dashed dot rules legal', () => {
|
||||
const css = `.dot-rule {
|
||||
height: 5px;
|
||||
background-image: linear-gradient(90deg, rgba(255,255,255,.75) 5px, transparent 5px);
|
||||
background-size: 10px 5px;
|
||||
background-repeat: repeat-x;
|
||||
}`;
|
||||
expect(grids(css)).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('keeps 1D progress rails with dash-period px pair tiles legal', () => {
|
||||
const css = `.progress-rail {
|
||||
background-image: linear-gradient(90deg, #eee 1px, transparent 1px);
|
||||
background-size: 8px 4px;
|
||||
background-repeat: repeat-x;
|
||||
}`;
|
||||
expect(grids(css)).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('regex source engine keeps 1D dot rules legal', () => {
|
||||
const css = `.dot-rule {
|
||||
height: 5px;
|
||||
background-image: linear-gradient(90deg, rgba(255,255,255,.75) 5px, transparent 5px);
|
||||
background-size: 10px 5px;
|
||||
background-repeat: repeat-x;
|
||||
}`;
|
||||
const findings = detectText(css, 'dot-rule.css');
|
||||
expect(findings.filter(f => f.antipattern === 'codex-grid-background')).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('classic two-axis background-size form still flags', () => {
|
||||
const css = `.hero { background-image:
|
||||
linear-gradient(#eee 1px, transparent 1px),
|
||||
|
||||
Reference in New Issue
Block a user