Skip to content

Commit

Permalink
Make diagnostic code link to linter rule doc in IDE (#4141)
Browse files Browse the repository at this point in the history
Saw that eslint extension was doing this. Part solution to
#3043 which could also
provide an explicit `Open documentation Url` command

<img width="568" alt="image"
src="https://github.com/user-attachments/assets/c3a322d2-17c7-45d9-962c-028c1e9cc93c">

For now all the API that gives that is limited to linter as other
diagnostic cannot define a url. Due to this limited usage I left the API
internal. The goal would be that any diagnostic can define a
documentation url and connect to this.
  • Loading branch information
timotheeguerin authored Aug 12, 2024
1 parent c8d242b commit 95ef4c3
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .chronus/changes/lsp-diag-url-2024-7-12-14-53-19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/compiler"
---

Diagnostic code in IDE now link to the linter rule documentation url if applicable
8 changes: 8 additions & 0 deletions packages/compiler/src/core/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import {
export interface Linter {
extendRuleSet(ruleSet: LinterRuleSet): Promise<readonly Diagnostic[]>;
lint(): readonly Diagnostic[];

/** @internal */
getRuleUrl(ruleId: string): string | undefined;
}

/**
Expand Down Expand Up @@ -64,8 +67,13 @@ export function createLinter(
return {
extendRuleSet,
lint,
getRuleUrl,
};

function getRuleUrl(ruleId: string): string | undefined {
return ruleMap.get(ruleId)?.url;
}

async function extendRuleSet(ruleSet: LinterRuleSet): Promise<readonly Diagnostic[]> {
tracer.trace("extend-rule-set.start", JSON.stringify(ruleSet, null, 2));
const diagnostics = createDiagnosticCollector();
Expand Down
8 changes: 8 additions & 0 deletions packages/compiler/src/core/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export interface Program {
* Project root. If a tsconfig was found/specified this is the directory for the tsconfig.json. Otherwise directory where the entrypoint is located.
*/
readonly projectRoot: string;

/** @internal */
getDiagnosticUrl(diagnostic: Diagnostic): string | undefined;
}

interface EmitterRef {
Expand Down Expand Up @@ -192,6 +195,7 @@ export async function compile(
resolveTypeReference,
getSourceFileLocationContext,
projectRoot: getDirectoryPath(options.config ?? resolvedMain ?? ""),
getDiagnosticUrl,
};

trace("compiler.options", JSON.stringify(options, null, 2));
Expand All @@ -206,6 +210,10 @@ export async function compile(
await loadStandardLibrary();
}

function getDiagnosticUrl(diagnostic: Diagnostic): string | undefined {
return linter.getRuleUrl(diagnostic.code);
}

// Load additional imports prior to compilation
if (resolvedMain && options.additionalImports) {
const importScript = options.additionalImports.map((i) => `import "${i}";`).join("\n");
Expand Down
7 changes: 7 additions & 0 deletions packages/compiler/src/server/serverlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,13 @@ export function createServer(host: ServerHost): Server {
const range = Range.create(start, end);
const severity = convertSeverity(each.severity);
const diagnostic = VSDiagnostic.create(range, each.message, severity, each.code, "TypeSpec");

const url = program.getDiagnosticUrl(each);
if (url) {
diagnostic.codeDescription = {
href: url,
};
}
if (each.code === "deprecated") {
diagnostic.tags = [DiagnosticTag.Deprecated];
}
Expand Down

0 comments on commit 95ef4c3

Please sign in to comment.