fix(agents): validate srcdoc references and empty srcset

This commit is contained in:
4gray committed 2026-09-21 02:56:53 +02:00
1 parent a7150d1e72
commit 3dbd522d70
4 files changed
+59 -3

No files matched your search

+19 -2
View File
@@ -92,12 +92,29 @@ function htmlNavigation(html, inspect = () => {}) {
node.tagName
),
});
if (node.tagName === 'iframe' && attribute.name === 'srcdoc') {
const embedded = htmlNavigation(attribute.value);
for (const reference of embedded.references)
references.push(
reference.target.startsWith('#') &&
!reference.embeddedAnchors
? {
...reference,
embeddedAnchors: embedded.anchors,
}
: reference
);
}
if (
['img', 'source'].includes(node.tagName) &&
attribute.name === 'srcset'
)
for (const candidate of parseSrcset(attribute.value))
) {
const candidates = parseSrcset(attribute.value);
if (!candidates.length)
references.push({ target: '', image: true });
for (const candidate of candidates)
references.push({ target: candidate.url, image: true });
}
}
for (const child of node.childNodes ?? []) visit(child);
}
+5 -1
View File
@@ -36,7 +36,7 @@ function within(root, path) {
async function validateReference(
rootDir,
source,
{ target, literal, image, unresolvedReference }
{ target, literal, image, unresolvedReference, embeddedAnchors }
) {
if (unresolvedReference !== undefined)
return `${source}: unresolved Markdown reference "${unresolvedReference}"`;
@@ -53,6 +53,10 @@ async function validateReference(
} catch {
return `${source}: malformed local link: ${target}`;
}
if (embeddedAnchors && !path && !image)
return !anchor || embeddedAnchors.includes(anchor)
? undefined
: `${source}: missing anchor "${anchor}" in iframe srcdoc`;
const absolute = path
? resolve(literal ? rootDir : dirname(resolve(rootDir, source)), path)
: resolve(rootDir, source);
@@ -1399,3 +1399,36 @@ for (const url of [
);
});
}
for (const value of ['', ' ']) {
test(`empty srcset is rejected: ${JSON.stringify(value)}`, async (t) => {
assert.ok(
(await diagnostics(t, { 'AGENTS.md': `<img srcset="${value}">` }))
.length > 0
);
});
}
for (const content of [
"<a href='docs/missing.md'>Guide</a>",
"<img src='missing.png'>",
"<a href='#missing'>Guide</a>",
]) {
test(`srcdoc references are validated: ${content}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'AGENTS.md': `<iframe srcdoc="${content}"></iframe>`,
})
).length > 0
);
});
}
test('srcdoc anchors are scoped and templates inert', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
"<iframe srcdoc=\"<p id=local>Hi</p><a href='#local'>Go</a><template><img src='missing.png'></template>\"></iframe>",
}),
[]
);
});