mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 01:16:15 -08:00
fix(agents): validate srcdoc references and empty srcset
This commit is contained in:
1 parent
a7150d1e72
commit
3dbd522d70
4 files changed
+59
-3
No files matched your search
@@ -60,6 +60,8 @@ as Markdown links, including decoded attributes and fragment validation.
|
||||
URL attributes remove ASCII tabs/newlines throughout and discard surrounding
|
||||
ASCII control/space characters before resolution.
|
||||
Iframe/embed sources and object data attributes are document references and retain Markdown-target anchor checks.
|
||||
Inline iframe srcdoc documents are traversed too, with their own fragment anchors.
|
||||
Explicit srcset attributes must contain at least one parsed candidate.
|
||||
Image and media references require nonempty targets that resolve to files, not directories.
|
||||
Image references check file existence without interpreting image fragments as
|
||||
Markdown headings; document links keep anchor checks even when sharing a target.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>",
|
||||
}),
|
||||
[]
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user