Clarify markdown validate settings (#151997)

Clairify markdown validate settings

Fixes #150949

- Rename headerLinks -> fragmentLinks
- Add new `fileLink.markdownFragmentsLinks` to validate the headers on fragment links (inherits the default setting value from `fragmentLinks`)
This commit is contained in:
Matt Bierner
2022-06-13 17:06:28 -07:00
committed by GitHub
parent af754ef399
commit 1a07fd15d7
4 changed files with 101 additions and 49 deletions

View File

@@ -23,15 +23,16 @@ async function getComputedDiagnostics(doc: InMemoryDocument, workspaceContents:
return (
await computer.getDiagnostics(doc, {
enabled: true,
validateFilePaths: DiagnosticLevel.warning,
validateOwnHeaders: DiagnosticLevel.warning,
validateFileLinks: DiagnosticLevel.warning,
validateFragmentLinks: DiagnosticLevel.warning,
validateMarkdownFileLinkFragments: DiagnosticLevel.warning,
validateReferences: DiagnosticLevel.warning,
ignoreLinks: [],
}, noopToken)
).diagnostics;
}
function createDiagnosticsManager(workspaceContents: MdWorkspaceContents, configuration = new MemoryDiagnosticConfiguration()) {
function createDiagnosticsManager(workspaceContents: MdWorkspaceContents, configuration = new MemoryDiagnosticConfiguration({})) {
const engine = createNewMarkdownEngine();
const linkProvider = new MdLinkProvider(engine);
return new DiagnosticManager(new DiagnosticComputer(engine, workspaceContents, linkProvider), configuration);
@@ -45,32 +46,28 @@ function assertDiagnosticsEqual(actual: readonly vscode.Diagnostic[], expectedRa
}
}
const defaultDiagnosticsOptions = Object.freeze<DiagnosticOptions>({
enabled: true,
validateFileLinks: DiagnosticLevel.warning,
validateMarkdownFileLinkFragments: undefined,
validateFragmentLinks: DiagnosticLevel.warning,
validateReferences: DiagnosticLevel.warning,
ignoreLinks: [],
});
class MemoryDiagnosticConfiguration implements DiagnosticConfiguration {
private readonly _onDidChange = new vscode.EventEmitter<void>();
public readonly onDidChange = this._onDidChange.event;
constructor(
private readonly enabled: boolean = true,
private readonly ignoreLinks: string[] = [],
private readonly _options: Partial<DiagnosticOptions>,
) { }
getOptions(_resource: vscode.Uri): DiagnosticOptions {
if (!this.enabled) {
return {
enabled: false,
validateFilePaths: DiagnosticLevel.ignore,
validateOwnHeaders: DiagnosticLevel.ignore,
validateReferences: DiagnosticLevel.ignore,
ignoreLinks: this.ignoreLinks,
};
}
return {
enabled: true,
validateFilePaths: DiagnosticLevel.warning,
validateOwnHeaders: DiagnosticLevel.warning,
validateReferences: DiagnosticLevel.warning,
ignoreLinks: this.ignoreLinks,
...defaultDiagnosticsOptions,
...this._options,
};
}
}
@@ -172,7 +169,7 @@ suite('markdown: Diagnostics', () => {
`[text][no-such-ref]`,
));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(false));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration({ enabled: false }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
@@ -203,17 +200,52 @@ suite('markdown: Diagnostics', () => {
`[text]: /no-such-file`,
));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/no-such-file']));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration({ ignoreLinks: ['/no-such-file'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
test('Should be able to disable fragment validation for external files', async () => {
const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines(
`![i](/doc2.md#no-such)`,
));
const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines(''));
const contents = new InMemoryWorkspaceMarkdownDocuments([doc1, doc2]);
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ validateMarkdownFileLinkFragments: DiagnosticLevel.ignore }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
test('Disabling own fragment validation should also disable path fragment validation by default', async () => {
const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines(
`[b](#no-head)`,
`![i](/doc2.md#no-such)`,
));
const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines(''));
const contents = new InMemoryWorkspaceMarkdownDocuments([doc1, doc2]);
{
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ validateFragmentLinks: DiagnosticLevel.ignore }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
}
{
// But we should be able to override the default
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ validateFragmentLinks: DiagnosticLevel.ignore, validateMarkdownFileLinkFragments: DiagnosticLevel.warning }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 1);
}
});
test('ignoreLinks should allow skipping link to non-existent file', async () => {
const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines(
`[text](/no-such-file#header)`,
));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/no-such-file']));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration({ ignoreLinks: ['/no-such-file'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
@@ -223,7 +255,7 @@ suite('markdown: Diagnostics', () => {
`[text](/no-such-file#header)`,
));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/no-such-file']));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration({ ignoreLinks: ['/no-such-file'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
@@ -235,7 +267,7 @@ suite('markdown: Diagnostics', () => {
`![i](/images/sub/sub2/ccc.png)`,
));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/images/**/*.png']));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration({ ignoreLinks: ['/images/**/*.png'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
@@ -245,7 +277,7 @@ suite('markdown: Diagnostics', () => {
`![i](#no-such)`,
));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['#no-such']));
const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration({ ignoreLinks: ['#no-such'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
@@ -258,12 +290,12 @@ suite('markdown: Diagnostics', () => {
const contents = new InMemoryWorkspaceMarkdownDocuments([doc1, doc2]);
{
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration(true, ['/doc2.md#no-such']));
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ ignoreLinks: ['/doc2.md#no-such'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
}
{
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration(true, ['/doc2.md#*']));
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ ignoreLinks: ['/doc2.md#*'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
}
@@ -276,7 +308,7 @@ suite('markdown: Diagnostics', () => {
const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines(''));
const contents = new InMemoryWorkspaceMarkdownDocuments([doc1, doc2]);
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration(true, ['/doc2.md']));
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ ignoreLinks: ['/doc2.md'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});
@@ -289,7 +321,7 @@ suite('markdown: Diagnostics', () => {
));
const contents = new InMemoryWorkspaceMarkdownDocuments([doc1]);
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration(true, ['/doc2.md']));
const manager = createDiagnosticsManager(contents, new MemoryDiagnosticConfiguration({ ignoreLinks: ['/doc2.md'] }));
const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken);
assert.deepStrictEqual(diagnostics.length, 0);
});