import assert from 'node:assert/strict';
import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join } from 'node:path';
import test from 'node:test';
import { validateAgentGuidance } from './validate-agent-guidance.mjs';
const map = 'docs/maintenance/agent-context-map.md';
const migration = 'docs/maintenance/agent-guidance-migration.md';
async function fixture(t, overrides = {}) {
const rootDir = await mkdtemp(join(tmpdir(), 'agent-guidance-'));
t.after(() => rm(rootDir, { recursive: true, force: true }));
for (const [path, body] of Object.entries({
'AGENTS.md': '# Guidance\n',
'tsconfig.base.json': JSON.stringify({
compilerOptions: { paths: { '@iptvnator/*': ['libs/*'] } },
}),
'CLAUDE.md': '@AGENTS.md\n',
[map]: '# Context\n',
[migration]: '# Migration\n',
'docs/example.md': '# Hello, `World`!\n\n## Repeat\n## Repeat\n',
...overrides,
})) {
await mkdir(dirname(join(rootDir, path)), { recursive: true });
await writeFile(join(rootDir, path), body);
}
return rootDir;
}
async function diagnostics(t, overrides) {
return (
await validateAgentGuidance({ rootDir: await fixture(t, overrides) })
).diagnostics;
}
test('valid guidance and remote links pass', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'[Doc](docs/example.md#hello-world) and `@iptvnator/services`\n',
[map]: '[Repeat](../example.md#repeat-1)\n',
[migration]:
'[Original](https://github.com/example/repo/blob/main/AGENTS.md#old)\n',
}),
[]
);
});
for (const [path, limit] of [
['AGENTS.md', 200],
['CLAUDE.md', 30],
]) {
for (const eol of ['\n', '\r\n']) {
test(`${path}: exact line limit accepts ${JSON.stringify(eol)}`, async (t) => {
const prefix = path === 'CLAUDE.md' ? '@AGENTS.md' : '# Guidance';
assert.deepEqual(
await diagnostics(t, {
[path]:
[prefix, ...Array(limit - 1).fill('x')].join(eol) + eol,
}),
[]
);
});
test(`${path}: one line over fails ${JSON.stringify(eol)}`, async (t) => {
const prefix = path === 'CLAUDE.md' ? '@AGENTS.md' : '# Guidance';
assert.match(
(
await diagnostics(t, {
[path]: [prefix, ...Array(limit).fill('x')].join(eol),
})
).join('\n'),
/lines/
);
});
}
}
for (const [path, limit] of [
['AGENTS.md', 16384],
['CLAUDE.md', 2048],
]) {
test(`${path}: UTF-8 byte budget is exact`, async (t) => {
const prefix = path === 'CLAUDE.md' ? '@AGENTS.md\n' : '';
const remaining = limit - Buffer.byteLength(prefix);
const body =
prefix +
'é'.repeat(Math.floor(remaining / 2)) +
'x'.repeat(remaining % 2);
assert.deepEqual(await diagnostics(t, { [path]: body }), []);
assert.match(
(await diagnostics(t, { [path]: body + 'é' })).join('\n'),
/bytes/
);
});
}
for (const body of [
'',
'See @AGENTS.md',
'@AGENTS.md\n@AGENTS.md',
'@AGENTS.md\n@docs/example.md',
'@AGENTS.md\nRead @docs/example.md for more.',
]) {
test(`rejects invalid CLAUDE imports: ${JSON.stringify(body)}`, async (t) => {
assert.match(
(await diagnostics(t, { 'CLAUDE.md': body })).join('\n'),
/import/
);
});
}
for (const source of ['AGENTS.md', 'CLAUDE.md']) {
for (const target of [
'package.json',
'libs/extra.txt',
'arbitrary.custom',
'tools/instructions',
'LICENSE',
'.nvmrc',
'./instructions',
]) {
test(`${source}: rejects inline file import @${target}`, async (t) => {
const prefix = source === 'CLAUDE.md' ? '@AGENTS.md\n' : '';
assert.match(
(
await diagnostics(t, {
[source]: `${prefix}Read @${target} for instructions.\n`,
})
).join('\n'),
/import/
);
});
}
}
test('AGENTS forbids imports while aliases in prose stay valid', async (t) => {
assert.match(
(await diagnostics(t, { 'AGENTS.md': '@docs/example.md\n' })).join(
'\n'
),
/import/
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'Use @iptvnator/services and `@iptvnator/ui/components`.\n',
}),
[]
);
});
for (const path of ['AGENTS.md', 'CLAUDE.md', map, migration]) {
test(`${path}: missing local links and anchors fail`, async (t) => {
const prefix = path === 'CLAUDE.md' ? '@AGENTS.md\n' : '';
const target = path.startsWith('docs/')
? '../example.md'
: 'docs/example.md';
const errors = await diagnostics(t, {
[path]:
prefix + `[Missing](missing.md) [Anchor](${target}#missing)`,
});
assert.match(errors.join('\n'), /missing.md/);
assert.match(errors.join('\n'), /anchor.*missing/);
});
}
test('literal root paths validate without interpreting commands or globs', async (t) => {
assert.deepEqual(
await diagnostics(t, {
[map]: '`docs/example.md` `pnpm nx test web` `apps/*` `libs/ Read @docs/example.md for Angular
',
]) {
test(`validates rendered HTML navigation: ${html}`, async (t) => {
assert.match(
(await diagnostics(t, { 'AGENTS.md': html })).join('\n'),
/does not exist/
);
});
}
test('HTML navigation supports valid anchors and decoded attributes', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'Guide
',
'docs/a&b.png': '',
}),
[]
);
assert.match(
(
await diagnostics(t, {
'AGENTS.md': 'Guide',
})
).join('\n'),
/missing anchor/
);
});
test('non-rendered HTML navigation is ignored', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'\n\n\nHidden',
}),
[]
);
});
test('GitHub heading slugs remove non-ASCII whitespace', async (t) => {
for (const heading of ['A B', 'A\u00a0B', 'A\u2003B']) {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '[Heading](docs/example.md#ab)',
'docs/example.md': '# ' + heading,
}),
[]
);
assert.match(
(
await diagnostics(t, {
'AGENTS.md': '[Heading](docs/example.md#a-b)',
'docs/example.md': '# ' + heading,
})
).join('\n'),
/missing anchor/
);
}
});
for (const body of [
'> @AGENTS.md',
'- @AGENTS.md',
'# @AGENTS.md',
'**@AGENTS.md**',
]) {
test(`structured Markdown cannot satisfy Claude import: ${body}`, async (t) => {
assert.match(
(await diagnostics(t, { 'CLAUDE.md': body })).join('\n'),
/standalone @AGENTS.md/
);
});
}
for (const tag of ['template', 'div']) {
test(`HTML container cannot supply Claude import: ${tag}`, async (t) => {
assert.match(
(
await diagnostics(t, {
'CLAUDE.md': `<${tag}>\n\n@AGENTS.md\n\n${tag}>`,
})
).join('\n'),
/standalone @AGENTS.md/
);
assert.deepEqual(
await diagnostics(t, {
'CLAUDE.md': `<${tag}>\n\nExample\n\n${tag}>\n\n@AGENTS.md`,
}),
[]
);
});
}
for (const punctuation of ['"', "'", '[', '{', ':']) {
test(`rejects inline imports after ${punctuation}`, async (t) => {
assert.match(
(
await diagnostics(t, {
'CLAUDE.md':
'@AGENTS.md\n\nRead ' +
punctuation +
'@docs/example.md',
})
).join('\n'),
/imports are not allowed/
);
});
}
for (const image of [
'',
'
',
'![Diagram][image]\n\n[image]: docs/diagram.png#gh-dark-mode-only',
]) {
test(`image fragments are not Markdown headings: ${image}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': image,
'docs/diagram.png': 'image fixture',
}),
[]
);
assert.match(
(await diagnostics(t, { 'AGENTS.md': image })).join('\n'),
/does not exist/
);
});
}
test('sharing an image reference does not suppress document anchor checks', async (t) => {
assert.match(
(
await diagnostics(t, {
'AGENTS.md':
'![Preview][target] [Read][target]\n\n[target]: docs/example.md#missing',
})
).join('\n'),
/missing anchor/
);
});
test('root literals cannot suppress source-relative definitions', async (t) => {
assert.match(
(
await diagnostics(t, {
[map]: '`README.md`\n\n[unused]: README.md',
'README.md': '# Root',
})
).join('\n'),
/does not exist: README.md/
);
});
test('visible HTML text cannot hide inline imports', async (t) => {
assert.match(
(
await diagnostics(t, {
'CLAUDE.md': '@AGENTS.md\n\n
',
]) {
test(`validates every srcset asset: ${html}`, async (t) => {
assert.match(
(
await diagnostics(t, {
'AGENTS.md': html,
'docs/light.png': '',
})
).join('\n'),
/does not exist: docs\/dark.png/
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': html,
'docs/light.png': '',
'docs/dark.png': '',
}),
[]
);
});
}
test('srcset data URLs do not become local filenames', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'',
'docs/image.png': '',
}),
[]
);
});
test('non-rendered HTML text and code do not introduce imports', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'CLAUDE.md':
'@AGENTS.md\n\n\n\n\n@docs/missing.md\n
@docs/missing.md',
}),
[]
);
});
test('declared scoped dependencies and aliases are not inline imports', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*', '@nx/devkit': '*' },
}),
'tsconfig.base.json': JSON.stringify({
compilerOptions: { paths: { '@custom/*': ['libs/*'] } },
}),
'AGENTS.md': 'Use @angular/core, @nx/* and @custom/services.',
}),
[]
);
});
test('TypeScript scope discovery supports JSONC', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'tsconfig.base.json':
'{ // comment\n "compilerOptions": { "paths": { "@custom/*": ["libs/*"], }, }, }',
'AGENTS.md': 'Use @custom/services.',
}),
[]
);
});
for (const target of [
'angular/../docs/example.md',
'angular/missing.md',
'angular/undeclared',
]) {
test(`declared scopes do not exempt undeclared imports: ${target}`, async (t) => {
assert.match(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md': '@AGENTS.md\n\nRead @' + target,
})
).join('\n'),
/imports are not allowed/
);
});
}
test('Markdown destination entities resolve rendered filenames', async (t) => {
for (const reference of [
'[Guide](docs/a&b.md)',
'[Guide][ref]\n\n[ref]: docs/a&b.md',
]) {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': reference,
'docs/a&b.md': '# Guide',
}),
[]
);
assert.match(
(
await diagnostics(t, {
'AGENTS.md': reference,
'docs/a&b.md': '# Wrong name',
})
).join('\n'),
/does not exist/
);
}
});
test('declared packages allow safe subpaths', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'AGENTS.md': 'Use @angular/core/testing.',
}),
[]
);
});
for (const filename of [
'Dockerfile',
'Makefile',
'LICENSE',
'NOTICE',
'Procfile',
]) {
test(`conventional extensionless filename is validated: ${filename}`, async (t) => {
assert.match(
(await diagnostics(t, { 'AGENTS.md': '`' + filename + '`' })).join(
'\n'
),
/does not exist/
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '`' + filename + '`',
[filename]: '',
}),
[]
);
});
}
for (const version of [
'22.1.6',
'^22.1.6',
'next',
'>=22.0.0',
'<=22.0.0',
'>22.0.0',
'<22.0.0',
]) {
test(`declared package can include version ${version}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'AGENTS.md': 'Use @angular/core@' + version,
}),
[]
);
});
}
for (const [path, fragment] of [
['apps/example.ts', 'L20'],
['docs/guide.pdf', 'page=3'],
]) {
test(`non-Markdown fragments are not headings: ${path}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': `[Target](${path}#${fragment})`,
[path]: 'fixture',
}),
[]
);
assert.match(
(
await diagnostics(t, {
'AGENTS.md': `[Target](${path}#${fragment})`,
})
).join('\n'),
/does not exist/
);
});
}
for (const mention of [
'@marked@17.0.0',
'@marked@^17.0.0',
'@angular/core?',
'@angular/core!',
]) {
test(`package mention accepts qualifier or punctuation: ${mention}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { marked: '*', '@angular/core': '*' },
}),
'AGENTS.md': 'Use ' + mention,
}),
[]
);
});
}
for (const content of [
'[example](docs/missing.md)',
'[example][ref]\n\n[ref]: docs/missing.md',
'[unused]: docs/missing.md',
'`docs/missing.md`',
'[example][undefined]',
]) {
test(`template Markdown is inert: ${content}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '\n\n' + content + '\n\n',
}),
[]
);
});
}
test('inert headings do not define or consume anchor slugs', async (t) => {
const body =
'\n\n# Hidden\n\n# Visible\n\n\n\n# Visible';
assert.match(
(
await diagnostics(t, {
'AGENTS.md': '[Hidden](docs/example.md#hidden)',
'docs/example.md': body,
})
).join('\n'),
/missing anchor/
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '[Visible](docs/example.md#visible)',
'docs/example.md': body,
}),
[]
);
});
test('explicit relative literal paths support spaces', async (t) => {
assert.match(
(
await diagnostics(t, {
'AGENTS.md': '`./docs/My Guide.md`',
})
).join('\n'),
/does not exist/
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '`./docs/My Guide.md`',
'docs/My Guide.md': '',
}),
[]
);
});
for (const filename of ['./docs/Design - Copy.md', './docs/Design -Copy.md']) {
test(`explicit spaced filename is checked: ${filename}`, async (t) => {
assert.match(
(await diagnostics(t, { 'AGENTS.md': '`' + filename + '`' })).join(
'\n'
),
/does not exist/
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '`' + filename + '`',
[filename]: '',
}),
[]
);
});
}
for (const html of [
'',
'',
'',
]) {
test(`rendered media source is checked: ${html}`, async (t) => {
assert.match(
(await diagnostics(t, { 'AGENTS.md': html })).join('\n'),
/does not exist/
);
assert.deepEqual(
await diagnostics(t, { 'AGENTS.md': html, 'docs/demo.mp4': '' }),
[]
);
});
}
for (const heading of ['A© B', 'A© B', 'A© B']) {
test(`semicolonless heading entities decode: ${heading}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '[Heading](docs/example.md#a-b)',
'docs/example.md': '# ' + heading,
}),
[]
);
});
}
test('semicolonless definition entities match rendered destinations', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '[ref]: docs/a©.md',
'docs/a©.md': '',
}),
[]
);
});
for (const html of [
'',
'',
]) {
test(`remaining media assets are checked: ${html}`, async (t) => {
assert.match(
(await diagnostics(t, { 'AGENTS.md': html })).join('\n'),
/does not exist/
);
assert.deepEqual(
await diagnostics(t, { 'AGENTS.md': html, 'docs/asset.png': '' }),
[]
);
});
}
for (const suffix of ["'s", '’s']) {
test(`declared package may be possessive: ${suffix}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'AGENTS.md': '@angular/core' + suffix + ' API',
}),
[]
);
});
}
for (const suffix of ['', '.']) {
test(`existing extensionless inline import is rejected: ${suffix}`, async (t) => {
const result = await diagnostics(t, {
'CLAUDE.md': '@AGENTS.md\n\nRead @INSTRUCTIONS' + suffix,
INSTRUCTIONS: 'Additional guidance',
});
assert.ok(
result.some((message) => message.includes('additional or inline'))
);
});
}
test('ordinary unknown handle is not a file import', async (t) => {
assert.deepEqual(
await diagnostics(t, { 'AGENTS.md': 'Ask @maintainer' }),
[]
);
});
for (const wrapper of ['\\`', '`']) {
test(`visible literal backticks preserve imports: ${wrapper}`, async (t) => {
const result = await diagnostics(t, {
'CLAUDE.md':
'@AGENTS.md\n\nRead ' + wrapper + '@docs/example.md' + wrapper,
});
assert.ok(
result.some((message) => message.includes('additional or inline'))
);
});
}
for (const filename of [
'Guide (old).md',
"Author's guide.md",
'Guide [draft].md',
]) {
test(`explicit path punctuation is validated: ${filename}`, async (t) => {
const guidance = '`./docs/' + filename + '`';
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': guidance,
['docs/' + filename]: '# Guide',
}),
[]
);
assert.ok((await diagnostics(t, { 'AGENTS.md': guidance })).length > 0);
});
}
for (const target of ['docs/missing.md', 'docs/example.md#missing']) {
test(`image-map navigation is validated: ${target}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'AGENTS.md': ``,
})
).length > 0
);
});
}
test('valid image-map navigation and inert areas pass', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'\n',
}),
[]
);
});
for (const ending of ['\n', '\r\n', '\r']) {
for (const [source, limit] of [
['AGENTS.md', 200],
['CLAUDE.md', 30],
]) {
test(`line budget handles ${JSON.stringify(ending)} in ${source}`, async (t) => {
const lines = [
source === 'CLAUDE.md' ? '@AGENTS.md' : '# Guidance',
...Array(limit - 1).fill('# Section'),
];
assert.deepEqual(
await diagnostics(t, { [source]: lines.join(ending) + ending }),
[]
);
const result = await diagnostics(t, {
[source]: [...lines, '# Extra'].join(ending) + ending,
});
assert.ok(
result.some((message) =>
message.includes(
`at most ${limit} lines allowed (received ${limit + 1})`
)
)
);
});
}
}
for (const punctuation of ['—its', '–its', '…', ',next', '。next', '”']) {
test(`package mention stops at Unicode punctuation: ${punctuation}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'AGENTS.md': 'Use @angular/core' + punctuation + ' APIs',
}),
[]
);
});
}
for (const suffix of ['—then', ',next', '”']) {
test(`extensionless imports stop at Unicode punctuation: ${suffix}`, async (t) => {
const result = await diagnostics(t, {
'CLAUDE.md':
'@AGENTS.md\n\nRead @INSTRUCTIONS' + suffix + ' continue',
INSTRUCTIONS: 'Additional guidance',
});
assert.ok(
result.some((message) => message.includes('additional or inline'))
);
});
}
for (const name of ['INSTRUCTIONS—v2', 'INSTRUCTIONS,extra']) {
test(`full punctuation filename remains an import: ${name}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'CLAUDE.md': '@AGENTS.md\n\nRead @' + name,
[name]: 'Guidance',
})
).some((message) => message.includes('additional or inline'))
);
});
}
for (const suffix of [',then', ';then', ':then', '!then', '?then']) {
test(`ASCII prose boundary handles imports and packages: ${suffix}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'CLAUDE.md': '@AGENTS.md\n\nRead @INSTRUCTIONS' + suffix,
INSTRUCTIONS: 'Guidance',
})
).some((message) => message.includes('additional or inline'))
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': 'Use @angular/core' + suffix + ' continue',
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
}),
[]
);
});
}
for (const target of ['docs/missing.html', 'docs/example.md#missing']) {
test(`iframe document target is validated: ${target}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'AGENTS.md': ``,
})
).length > 0
);
});
}
test('valid iframe and inert iframe targets pass', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
'\n',
}),
[]
);
});
for (const suffix of [
'.md#rules',
'.md?view=raw#rules',
'.txt#rules',
'.json#rules',
]) {
test(`package document imports retain suffix guards: ${suffix}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md':
'@AGENTS.md\n\nRead @angular/core/docs/extra' + suffix,
})
).some((message) => message.includes('additional or inline'))
);
});
}
for (const suffix of [
'.markdown',
'.mdown',
'.mkd',
'.md%23rules',
'.md%3Fraw',
'%2Emd',
'/%2e%2e/extra.md',
]) {
test(`document package exemptions reject alternate and encoded paths: ${suffix}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md':
'@AGENTS.md\n\nRead @angular/core/docs/extra' + suffix,
})
).some((message) => message.includes('additional or inline'))
);
});
}
for (const version of ['*', '22.*', '22.1.*']) {
test(`wildcard package version is prose: ${version}`, async (t) => {
assert.deepEqual(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'AGENTS.md': 'Use @angular/core@' + version,
}),
[]
);
});
}
for (const extension of ['rst', 'rest', 'adoc', 'asciidoc']) {
test(`non-Markdown document is not a package exemption: ${extension}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md':
'@AGENTS.md\n\nRead @angular/core/docs/guide.' +
extension,
})
).some((message) => message.includes('additional or inline'))
);
});
}
for (const extension of ['pdf', 'doc', 'docx', 'odt', 'rtf', 'org', 'tex']) {
test(`document format is not a package exemption: ${extension}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md':
'@AGENTS.md\n\nRead @angular/core/docs/guide.' +
extension,
})
).some((message) => message.includes('additional or inline'))
);
});
}
for (const html of [
'Guide',
'',
'',
]) {
test(`HTML URL edge whitespace is ignored: ${html}`, async (t) => {
assert.deepEqual(await diagnostics(t, { 'AGENTS.md': html }), []);
});
}
for (const name of [
'guide.ods',
'guide.odp',
'guide.docm',
'guide.dotx',
'guide.latex',
'AGENTS',
'CLAUDE',
'README',
'INSTRUCTIONS',
'LICENSE',
]) {
test(`package subpath cannot import guidance document ${name}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md':
'@AGENTS.md\n\nRead @angular/core/docs/' + name,
})
).some((message) => message.includes('additional or inline'))
);
});
}
for (const reference of [
'',
'
',
'',
'',
]) {
test(`media target must be a file: ${reference}`, async (t) => {
assert.ok(
(await diagnostics(t, { 'AGENTS.md': reference })).some((message) =>
message.includes('not a file')
)
);
});
}
for (const html of [
'
Use @angular/core
',
'Use @angular/core for Angular ', '']) {
test(`empty media references are rejected: ${markup}`, async (t) => {
assert.ok((await diagnostics(t, { 'AGENTS.md': markup })).length > 0);
});
}
for (const url of [
'https://example.com/@docs/guide',
'https://example.com/user?next=@docs/guide',
'//example.com/@docs/guide',
]) {
test(`external URL at-sign is not an import: ${url}`, async (t) => {
assert.deepEqual(
await diagnostics(t, { 'AGENTS.md': 'Visit ' + url }),
[]
);
});
}
for (const value of ['', ' ']) {
test(`empty srcset is rejected: ${JSON.stringify(value)}`, async (t) => {
assert.ok(
(await diagnostics(t, { 'AGENTS.md': `
` }))
.length > 0
);
});
}
for (const content of [
"Guide",
"
",
"Guide",
]) {
test(`srcdoc references are validated: ${content}`, async (t) => {
assert.ok(
(
await diagnostics(t, {
'AGENTS.md': ``,
})
).length > 0
);
});
}
test('srcdoc anchors are scoped and templates inert', async (t) => {
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md':
"
\">",
}),
[]
);
});
test('autolink does not hide adjacent import', async (t) => {
assert.ok(
(
await diagnostics(t, {
'CLAUDE.md':
'@AGENTS.md\n\n