Skip to content

Commit 4fc5d76

Browse files
authored
Fix ranges and validation setting for MD own path + header links (microsoft#152270)
* Fix ranges and validation setting for MD own path + header links Previously for a `file.md`, links to headers in that file that use paths, such as `[link](./file.md#some-header)` were validated using `markdown.experimental.validate.fragmentLinks.enabled` This is confusing as that setting was only meant to be used for links such as`[link](#some-header`). It also resulted in the diagnostic having the incorrect range This change instead makes these links be validated by `markdown.experimental.validate.fileLinks.markdownFragmentLinks` * Fix compile
1 parent 16c2a3a commit 4fc5d76

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

extensions/markdown-language-features/src/languageFeatures/diagnostics.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export class DiagnosticComputer {
394394
return {
395395
links,
396396
diagnostics: (await Promise.all([
397-
this.validateFileLinks(doc, options, links, token),
397+
this.validateFileLinks(options, links, token),
398398
Array.from(this.validateReferenceLinks(options, links)),
399399
this.validateFragmentLinks(doc, options, links, token),
400400
])).flat()
@@ -415,6 +415,7 @@ export class DiagnosticComputer {
415415
const diagnostics: vscode.Diagnostic[] = [];
416416
for (const link of links) {
417417
if (link.href.kind === 'internal'
418+
&& link.source.text.startsWith('#')
418419
&& link.href.path.toString() === doc.uri.toString()
419420
&& link.href.fragment
420421
&& !toc.lookup(link.href.fragment)
@@ -449,14 +450,15 @@ export class DiagnosticComputer {
449450
}
450451
}
451452

452-
private async validateFileLinks(doc: SkinnyTextDocument, options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise<vscode.Diagnostic[]> {
453+
private async validateFileLinks(options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise<vscode.Diagnostic[]> {
453454
const pathErrorSeverity = toSeverity(options.validateFileLinks);
454455
if (typeof pathErrorSeverity === 'undefined') {
455456
return [];
456457
}
457458
const fragmentErrorSeverity = toSeverity(typeof options.validateMarkdownFileLinkFragments === 'undefined' ? options.validateFragmentLinks : options.validateMarkdownFileLinkFragments);
458459

459-
const linkSet = new FileLinkMap(links);
460+
// We've already validated our own fragment links in `validateOwnHeaderLinks`
461+
const linkSet = new FileLinkMap(links.filter(link => !link.source.text.startsWith('#')));
460462
if (linkSet.size === 0) {
461463
return [];
462464
}
@@ -472,11 +474,6 @@ export class DiagnosticComputer {
472474
}
473475

474476
const hrefDoc = await tryFindMdDocumentForLink({ kind: 'internal', path: path, fragment: '' }, this.workspaceContents);
475-
if (hrefDoc && hrefDoc.uri.toString() === doc.uri.toString()) {
476-
// We've already validated our own links in `validateOwnHeaderLinks`
477-
return;
478-
}
479-
480477
if (!hrefDoc && !await this.workspaceContents.pathExists(path)) {
481478
const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath);
482479
for (const link of links) {

extensions/markdown-language-features/src/test/diagnostic.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,4 +347,48 @@ suite('markdown: Diagnostics', () => {
347347
new vscode.Range(5, 7, 5, 17),
348348
]);
349349
});
350+
351+
test('Should generate diagnostics for non-existent header using file link to own file', async () => {
352+
const doc = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines(
353+
`[bad](doc.md#no-such)`,
354+
`[bad](doc#no-such)`,
355+
`[bad](/sub/doc.md#no-such)`,
356+
`[bad](/sub/doc#no-such)`,
357+
));
358+
359+
const diagnostics = await getComputedDiagnostics(doc, new InMemoryWorkspaceMarkdownDocuments([doc]));
360+
assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [
361+
new vscode.Range(0, 12, 0, 20),
362+
new vscode.Range(1, 9, 1, 17),
363+
new vscode.Range(2, 17, 2, 25),
364+
new vscode.Range(3, 14, 3, 22),
365+
]);
366+
});
367+
368+
test('Own header link using file path link should be controlled by "validateMarkdownFileLinkFragments" instead of "validateFragmentLinks"', async () => {
369+
const doc = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines(
370+
`[bad](doc.md#no-such)`,
371+
`[bad](doc#no-such)`,
372+
`[bad](/sub/doc.md#no-such)`,
373+
`[bad](/sub/doc#no-such)`,
374+
));
375+
376+
const contents = new InMemoryWorkspaceMarkdownDocuments([doc]);
377+
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({
378+
validateFragmentLinks: DiagnosticLevel.ignore,
379+
validateMarkdownFileLinkFragments: DiagnosticLevel.warning,
380+
}));
381+
const { diagnostics } = await manager.recomputeDiagnosticState(doc, noopToken);
382+
383+
assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [
384+
new vscode.Range(0, 12, 0, 20),
385+
new vscode.Range(1, 9, 1, 17),
386+
new vscode.Range(2, 17, 2, 25),
387+
new vscode.Range(3, 14, 3, 22),
388+
]);
389+
});
350390
});
391+
392+
function orderDiagnosticsByRange(diagnostics: Iterable<vscode.Diagnostic>): readonly vscode.Diagnostic[] {
393+
return Array.from(diagnostics).sort((a, b) => a.range.start.compareTo(b.range.start));
394+
}

0 commit comments

Comments
 (0)