fix(agents): preserve block boundaries and validate embeds

This commit is contained in:
4gray committed 2026-09-21 02:21:11 +02:00
1 parent 6bc5688001
commit 3f8b5be06d
3 files changed
+76 -5

No files matched your search

+2 -2
View File
@@ -58,7 +58,7 @@ Explicit HTML anchors use `parse5`, excluding comments, scripts, styles and temp
Rendered HTML anchor and image-map area hrefs and image sources use the same local-reference checks
as Markdown links, including decoded attributes and fragment validation.
URL attributes discard surrounding ASCII control/space characters before resolution.
Iframe sources are document references and retain Markdown-target anchor checks.
Iframe/embed sources and object data attributes are document references and retain Markdown-target anchor checks.
Image and media references must 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.
@@ -85,7 +85,7 @@ separate package mentions from adjacent prose.
Markdown destinations decode HTML entities before URI parsing, matching rendered links.
Heading-anchor lookup is limited to Markdown targets. Source-file line fragments,
PDF page fragments and other non-Markdown fragments retain file-existence checks.
The import scan includes visible HTML text and literal backticks; it excludes parsed code nodes and non-rendered containers.
The import scan separates HTML block/table elements and includes visible text and literal backticks; it excludes parsed code nodes and non-rendered containers.
Navigation uses the parsed rendered tree too. Temporary in-memory markers retain
definition, unresolved-reference and literal-path metadata, so Markdown inside
inert templates is excluded consistently with raw HTML navigation.
+38 -3
View File
@@ -78,16 +78,20 @@ function htmlNavigation(html, inspect = () => {}) {
'source',
'track',
'iframe',
'embed',
].includes(node.tagName) &&
attribute.name === 'src') ||
(node.tagName === 'video' && attribute.name === 'poster')
(node.tagName === 'video' && attribute.name === 'poster') ||
(node.tagName === 'object' && attribute.name === 'data')
)
references.push({
target: attribute.value.replace(
/^[\u0000-\u0020]+|[\u0000-\u0020]+$/gu,
''
),
image: !['a', 'area', 'iframe'].includes(node.tagName),
image: !['a', 'area', 'iframe', 'object', 'embed'].includes(
node.tagName
),
});
if (
['img', 'source'].includes(node.tagName) &&
@@ -113,6 +117,37 @@ export function guidanceProse(markdown) {
if (node.nodeName === '#text') return node.value;
const content = (node.childNodes ?? []).map(text).join('');
return [
'address',
'article',
'aside',
'details',
'summary',
'dialog',
'dl',
'dt',
'dd',
'fieldset',
'legend',
'figure',
'figcaption',
'footer',
'form',
'header',
'hgroup',
'hr',
'main',
'nav',
'ol',
'ul',
'section',
'table',
'caption',
'thead',
'tbody',
'tfoot',
'tr',
'td',
'th',
'p',
'li',
'blockquote',
@@ -125,7 +160,7 @@ export function guidanceProse(markdown) {
'h5',
'h6',
].includes(node.tagName)
? content + '\n'
? '\n' + content + '\n'
: content;
}
return text(parseFragment(new Marked().parse(markdown)));
@@ -1334,3 +1334,39 @@ for (const reference of [
);
});
}
for (const html of [
'<details><summary>Use @angular/core</summary><p>for Angular</p></details>',
'<table><tr><td>Use @angular/core</td><td>for Angular</td></tr></table>',
'<section>Use @angular/core</section><aside>for Angular</aside>',
]) {
test(`HTML blocks separate package prose: ${html}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': html,
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
}),
[]
);
});
}
for (const tag of ['object', 'embed']) {
test(`embedded document targets are checked: ${tag}`, async (t) => {
const markup = (target) =>
`<${tag} ${tag === 'object' ? 'data' : 'src'}="${target}"></${tag}>`;
for (const target of ['docs/missing.pdf', 'docs/example.md#missing']) {
assert.ok(
(await diagnostics(t, { 'AGENTS.md': markup(target) })).length >
0
);
}
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': markup('docs/example.md#repeat'),
}),
[]
);
});
}