mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-22 19:29:17 +00:00
Fix ranges and validation setting for MD own path + header links (#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
This commit is contained in:
@@ -394,7 +394,7 @@ export class DiagnosticComputer {
|
|||||||
return {
|
return {
|
||||||
links,
|
links,
|
||||||
diagnostics: (await Promise.all([
|
diagnostics: (await Promise.all([
|
||||||
this.validateFileLinks(doc, options, links, token),
|
this.validateFileLinks(options, links, token),
|
||||||
Array.from(this.validateReferenceLinks(options, links)),
|
Array.from(this.validateReferenceLinks(options, links)),
|
||||||
this.validateFragmentLinks(doc, options, links, token),
|
this.validateFragmentLinks(doc, options, links, token),
|
||||||
])).flat()
|
])).flat()
|
||||||
@@ -415,6 +415,7 @@ export class DiagnosticComputer {
|
|||||||
const diagnostics: vscode.Diagnostic[] = [];
|
const diagnostics: vscode.Diagnostic[] = [];
|
||||||
for (const link of links) {
|
for (const link of links) {
|
||||||
if (link.href.kind === 'internal'
|
if (link.href.kind === 'internal'
|
||||||
|
&& link.source.text.startsWith('#')
|
||||||
&& link.href.path.toString() === doc.uri.toString()
|
&& link.href.path.toString() === doc.uri.toString()
|
||||||
&& link.href.fragment
|
&& link.href.fragment
|
||||||
&& !toc.lookup(link.href.fragment)
|
&& !toc.lookup(link.href.fragment)
|
||||||
@@ -449,14 +450,15 @@ export class DiagnosticComputer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateFileLinks(doc: SkinnyTextDocument, options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise<vscode.Diagnostic[]> {
|
private async validateFileLinks(options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise<vscode.Diagnostic[]> {
|
||||||
const pathErrorSeverity = toSeverity(options.validateFileLinks);
|
const pathErrorSeverity = toSeverity(options.validateFileLinks);
|
||||||
if (typeof pathErrorSeverity === 'undefined') {
|
if (typeof pathErrorSeverity === 'undefined') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const fragmentErrorSeverity = toSeverity(typeof options.validateMarkdownFileLinkFragments === 'undefined' ? options.validateFragmentLinks : options.validateMarkdownFileLinkFragments);
|
const fragmentErrorSeverity = toSeverity(typeof options.validateMarkdownFileLinkFragments === 'undefined' ? options.validateFragmentLinks : options.validateMarkdownFileLinkFragments);
|
||||||
|
|
||||||
const linkSet = new FileLinkMap(links);
|
// We've already validated our own fragment links in `validateOwnHeaderLinks`
|
||||||
|
const linkSet = new FileLinkMap(links.filter(link => !link.source.text.startsWith('#')));
|
||||||
if (linkSet.size === 0) {
|
if (linkSet.size === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -472,11 +474,6 @@ export class DiagnosticComputer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hrefDoc = await tryFindMdDocumentForLink({ kind: 'internal', path: path, fragment: '' }, this.workspaceContents);
|
const hrefDoc = await tryFindMdDocumentForLink({ kind: 'internal', path: path, fragment: '' }, this.workspaceContents);
|
||||||
if (hrefDoc && hrefDoc.uri.toString() === doc.uri.toString()) {
|
|
||||||
// We've already validated our own links in `validateOwnHeaderLinks`
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hrefDoc && !await this.workspaceContents.pathExists(path)) {
|
if (!hrefDoc && !await this.workspaceContents.pathExists(path)) {
|
||||||
const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath);
|
const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath);
|
||||||
for (const link of links) {
|
for (const link of links) {
|
||||||
|
|||||||
@@ -347,4 +347,48 @@ suite('markdown: Diagnostics', () => {
|
|||||||
new vscode.Range(5, 7, 5, 17),
|
new vscode.Range(5, 7, 5, 17),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should generate diagnostics for non-existent header using file link to own file', async () => {
|
||||||
|
const doc = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines(
|
||||||
|
`[bad](doc.md#no-such)`,
|
||||||
|
`[bad](doc#no-such)`,
|
||||||
|
`[bad](/sub/doc.md#no-such)`,
|
||||||
|
`[bad](/sub/doc#no-such)`,
|
||||||
|
));
|
||||||
|
|
||||||
|
const diagnostics = await getComputedDiagnostics(doc, new InMemoryWorkspaceMarkdownDocuments([doc]));
|
||||||
|
assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [
|
||||||
|
new vscode.Range(0, 12, 0, 20),
|
||||||
|
new vscode.Range(1, 9, 1, 17),
|
||||||
|
new vscode.Range(2, 17, 2, 25),
|
||||||
|
new vscode.Range(3, 14, 3, 22),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Own header link using file path link should be controlled by "validateMarkdownFileLinkFragments" instead of "validateFragmentLinks"', async () => {
|
||||||
|
const doc = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines(
|
||||||
|
`[bad](doc.md#no-such)`,
|
||||||
|
`[bad](doc#no-such)`,
|
||||||
|
`[bad](/sub/doc.md#no-such)`,
|
||||||
|
`[bad](/sub/doc#no-such)`,
|
||||||
|
));
|
||||||
|
|
||||||
|
const contents = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||||
|
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({
|
||||||
|
validateFragmentLinks: DiagnosticLevel.ignore,
|
||||||
|
validateMarkdownFileLinkFragments: DiagnosticLevel.warning,
|
||||||
|
}));
|
||||||
|
const { diagnostics } = await manager.recomputeDiagnosticState(doc, noopToken);
|
||||||
|
|
||||||
|
assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [
|
||||||
|
new vscode.Range(0, 12, 0, 20),
|
||||||
|
new vscode.Range(1, 9, 1, 17),
|
||||||
|
new vscode.Range(2, 17, 2, 25),
|
||||||
|
new vscode.Range(3, 14, 3, 22),
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function orderDiagnosticsByRange(diagnostics: Iterable<vscode.Diagnostic>): readonly vscode.Diagnostic[] {
|
||||||
|
return Array.from(diagnostics).sort((a, b) => a.range.start.compareTo(b.range.start));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user