mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-19 09:36:59 +03:00
unreferencedPlates follows the artifact's linked stylesheets by name
Greptile's third P1 on the same seam: a stylesheet linked from the artifact but outside the bounded walk's root, depth, or file limit was still invisible. The hrefs the artifact itself declares are resolved against its directory and joined to the corpus, which closes every variant. AI-assisted (Claude Code).
This commit is contained in:
@@ -342,9 +342,24 @@ export function unreferencedPlates(spec, artifact = null) {
|
||||
const plates = (spec?.regions || []).filter((r) => r.medium === 'raster' && r.plate);
|
||||
if (!plates.length) return [];
|
||||
// The artifact narrows nothing: a plate may be referenced only from a
|
||||
// stylesheet the artifact links (assets/hero.css), so the source walk runs
|
||||
// either way and the artifact is simply guaranteed a seat in the corpus.
|
||||
const files = [...new Set([...(artifact && fs.existsSync(artifact) ? [artifact] : []), ...sourceFiles()])];
|
||||
// stylesheet the artifact links, so the source walk runs either way, the
|
||||
// artifact keeps a seat in the corpus, and the stylesheets it links are
|
||||
// added by name (resolved against the artifact's own directory), which
|
||||
// covers a stylesheet outside the walk's root, depth, or file limit.
|
||||
const linked = [];
|
||||
if (artifact && fs.existsSync(artifact)) {
|
||||
linked.push(artifact);
|
||||
try {
|
||||
const html = fs.readFileSync(artifact, 'utf8');
|
||||
for (const m of html.matchAll(/<link\b[^>]*href=["']([^"']+)["'][^>]*>/gi)) {
|
||||
const href = m[1];
|
||||
if (/^(https?:|data:|\/\/)/i.test(href)) continue;
|
||||
if (!/rel=["']?stylesheet/i.test(m[0]) && !/\.css(\?|$)/i.test(href)) continue;
|
||||
linked.push(path.resolve(path.dirname(artifact), href.split('?')[0]));
|
||||
}
|
||||
} catch { /* the artifact still counts */ }
|
||||
}
|
||||
const files = [...new Set([...linked, ...sourceFiles()])];
|
||||
let corpus = '';
|
||||
for (const f of files) { try { corpus += fs.readFileSync(f, 'utf8') + '\n'; } catch { /* skip */ } }
|
||||
const missing = [];
|
||||
|
||||
@@ -478,7 +478,14 @@ describe('unreferencedPlates', () => {
|
||||
// an explicit artifact does not bypass the stylesheet walk
|
||||
fs.writeFileSync(path.join(d, 'index.html'), '<link rel="stylesheet" href="assets/hero.css"><main class="hero"></main>');
|
||||
assert.deepEqual(unreferencedPlates(spec, path.join(d, 'index.html')), [], 'the linked stylesheet still counts with --artifact set');
|
||||
// a linked stylesheet beyond the walk's reach (deep path) still counts
|
||||
const deep = path.join(d, 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'styles');
|
||||
fs.mkdirSync(deep, { recursive: true });
|
||||
fs.writeFileSync(path.join(deep, 'deep.css'), ".hero { background-image: url('hero-plate.png'); }");
|
||||
fs.writeFileSync(path.join(d, 'index.html'), `<link rel="stylesheet" href="a/b/c/e/f/g/h/styles/deep.css"><main class="hero"></main>`);
|
||||
fs.writeFileSync(path.join(d, 'assets', 'hero.css'), '.hero { background: red; }');
|
||||
assert.deepEqual(unreferencedPlates(spec, path.join(d, 'index.html')), [], 'a stylesheet linked by the artifact counts wherever it lives');
|
||||
fs.writeFileSync(path.join(deep, 'deep.css'), '.hero { background: red; }');
|
||||
assert.equal(unreferencedPlates(spec, null).length, 1, 'an unreferenced plate is still named');
|
||||
assert.equal(unreferencedPlates(spec, path.join(d, 'index.html')).length, 1, 'and with the artifact set too');
|
||||
} finally { process.chdir(prev); fs.rmSync(d, { recursive: true, force: true }); }
|
||||
|
||||
Reference in New Issue
Block a user