mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
Fix: blank preprocessor line comments inside component style blocks
Standalone SCSS/Sass/Less files already ignored // comments, but <style lang="scss"> in Astro/Vue/Svelte still scanned them as live CSS. Prepared with AI assistance. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -261,17 +261,34 @@ function blankHtmlComments(text) {
|
|||||||
return text.replace(/<!--[\s\S]*?-->/g, comment => comment.replace(/[^\n]/g, ' '));
|
return text.replace(/<!--[\s\S]*?-->/g, comment => comment.replace(/[^\n]/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function blankCssLineCommentsInStyleBlocks(text) {
|
||||||
|
const re = /<style\b[^>]*>([\s\S]*?)<\/style>/gi;
|
||||||
|
let output = '';
|
||||||
|
let lastIndex = 0;
|
||||||
|
let match;
|
||||||
|
while ((match = re.exec(text)) !== null) {
|
||||||
|
const inner = match[1];
|
||||||
|
const openLength = match[0].length - inner.length - '</style>'.length;
|
||||||
|
output += text.slice(lastIndex, match.index);
|
||||||
|
output += match[0].slice(0, openLength);
|
||||||
|
output += blankCssLineComments(inner);
|
||||||
|
output += match[0].slice(openLength + inner.length);
|
||||||
|
lastIndex = re.lastIndex;
|
||||||
|
}
|
||||||
|
return output + text.slice(lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
function blankHtmlAndCssCommentsOutsideScripts(text) {
|
function blankHtmlAndCssCommentsOutsideScripts(text) {
|
||||||
const re = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
|
const re = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
|
||||||
let output = '';
|
let output = '';
|
||||||
let lastIndex = 0;
|
let lastIndex = 0;
|
||||||
let match;
|
let match;
|
||||||
while ((match = re.exec(text)) !== null) {
|
while ((match = re.exec(text)) !== null) {
|
||||||
output += stripCssComments(blankHtmlComments(text.slice(lastIndex, match.index)));
|
output += blankCssLineCommentsInStyleBlocks(stripCssComments(blankHtmlComments(text.slice(lastIndex, match.index))));
|
||||||
output += match[0];
|
output += match[0];
|
||||||
lastIndex = re.lastIndex;
|
lastIndex = re.lastIndex;
|
||||||
}
|
}
|
||||||
return output + stripCssComments(blankHtmlComments(text.slice(lastIndex)));
|
return output + blankCssLineCommentsInStyleBlocks(stripCssComments(blankHtmlComments(text.slice(lastIndex))));
|
||||||
}
|
}
|
||||||
|
|
||||||
function blankCssLineComments(text) {
|
function blankCssLineComments(text) {
|
||||||
@@ -1194,7 +1211,7 @@ function detectText(content, filePath, options = {}) {
|
|||||||
}, () => extractStyleBlocks(content, ext))
|
}, () => extractStyleBlocks(content, ext))
|
||||||
: extractStyleBlocks(content, ext);
|
: extractStyleBlocks(content, ext);
|
||||||
for (const block of styleBlocks) {
|
for (const block of styleBlocks) {
|
||||||
const blockContent = stripCssComments(block.content);
|
const blockContent = blankCssLineComments(stripCssComments(block.content));
|
||||||
const blockLines = blockContent.split('\n');
|
const blockLines = blockContent.split('\n');
|
||||||
findings.push(...runRegexMatchers(blockLines, filePath, block.startLine - 1, true, {
|
findings.push(...runRegexMatchers(blockLines, filePath, block.startLine - 1, true, {
|
||||||
profile,
|
profile,
|
||||||
|
|||||||
@@ -551,6 +551,32 @@ describe('detectText — broken images in source comments', () => {
|
|||||||
|
|
||||||
expect(detectText(source, 'hero.astro').filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
|
expect(detectText(source, 'hero.astro').filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('ignores preprocessor line comments in component style blocks', () => {
|
||||||
|
const source = [
|
||||||
|
'<style lang="scss">',
|
||||||
|
'// font-family: Inter',
|
||||||
|
'.hero { color: red; }',
|
||||||
|
'</style>',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
for (const filePath of ['hero.astro', 'hero.vue', 'hero.svelte']) {
|
||||||
|
expect(detectText(source, filePath).filter(r => r.antipattern === 'overused-font')).toHaveLength(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('still detects live font-family after a style-block line comment', () => {
|
||||||
|
const source = [
|
||||||
|
'<style lang="scss">',
|
||||||
|
'// skip this',
|
||||||
|
'.hero { font-family: Inter; }',
|
||||||
|
'</style>',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const findings = detectText(source, 'hero.vue').filter(r => r.antipattern === 'overused-font');
|
||||||
|
expect(findings).toHaveLength(1);
|
||||||
|
expect(findings[0].line).toBe(3);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('detectText — CSS borders', () => {
|
describe('detectText — CSS borders', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user