Skip to content

Commit 02d6ea2

Browse files
committed
✨ feat: enhance diagnostics with external info URL support
1 parent 2ac178e commit 02d6ea2

File tree

2 files changed

+116
-3
lines changed

2 files changed

+116
-3
lines changed

src/test/extension.test.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ suite('Extension Test Suite', () => {
190190
severity
191191
);
192192
diagnostic.source = 'phpmd';
193+
194+
// Add rule code and external info URL if available
195+
if (violation.externalInfoUrl) {
196+
diagnostic.code = {
197+
value: violation.rule,
198+
target: vscode.Uri.parse(violation.externalInfoUrl)
199+
};
200+
} else {
201+
diagnostic.code = violation.rule;
202+
}
203+
193204
diagnostics.push(diagnostic);
194205
}
195206
}
@@ -218,4 +229,102 @@ suite('Extension Test Suite', () => {
218229
assert.strictEqual(diagnostics[1].message.includes('ShortVariable'), true);
219230
assert.strictEqual(diagnostics[1].severity, vscode.DiagnosticSeverity.Error);
220231
});
232+
233+
// Test for external info URL in diagnostics
234+
test('Diagnostics include external info URL when available', async () => {
235+
// Define the same function as in the previous test
236+
const processPhpmdResults = (output: string): vscode.Diagnostic[] => {
237+
try {
238+
const results = JSON.parse(output);
239+
const diagnostics: vscode.Diagnostic[] = [];
240+
241+
if (results && results.files && results.files.length > 0) {
242+
for (const file of results.files) {
243+
for (const violation of file.violations) {
244+
const lineNum = violation.beginLine - 1; // Convert to 0-based
245+
const range = new vscode.Range(
246+
new vscode.Position(lineNum, 0),
247+
new vscode.Position(lineNum, Number.MAX_VALUE)
248+
);
249+
250+
// Map the priority to severity
251+
let severity: vscode.DiagnosticSeverity;
252+
switch (violation.priority) {
253+
case 1:
254+
severity = vscode.DiagnosticSeverity.Error;
255+
break;
256+
case 2:
257+
case 3:
258+
severity = vscode.DiagnosticSeverity.Warning;
259+
break;
260+
default:
261+
severity = vscode.DiagnosticSeverity.Information;
262+
}
263+
264+
const diagnostic = new vscode.Diagnostic(
265+
range,
266+
`${violation.description} (${violation.rule})`,
267+
severity
268+
);
269+
diagnostic.source = 'phpmd';
270+
271+
// Add rule code and external info URL if available
272+
if (violation.externalInfoUrl) {
273+
diagnostic.code = {
274+
value: violation.rule,
275+
target: vscode.Uri.parse(violation.externalInfoUrl)
276+
};
277+
} else {
278+
diagnostic.code = violation.rule;
279+
}
280+
281+
diagnostics.push(diagnostic);
282+
}
283+
}
284+
}
285+
286+
return diagnostics;
287+
} catch (error) {
288+
console.error('Error processing PHPMD output:', error);
289+
throw error;
290+
}
291+
};
292+
293+
// Process sample output
294+
const diagnostics = processPhpmdResults(SAMPLE_PHPMD_OUTPUT);
295+
296+
// Check that the first diagnostic has an external info URL
297+
assert.ok(diagnostics[0].code, 'Diagnostic should have a code property');
298+
299+
// When externalInfoUrl is provided, code should be an object with target
300+
if (typeof diagnostics[0].code === 'object') {
301+
assert.strictEqual(
302+
(diagnostics[0].code as any).value,
303+
'ExcessiveParameterList',
304+
'Code value should match the rule name'
305+
);
306+
assert.ok(
307+
(diagnostics[0].code as any).target instanceof vscode.Uri,
308+
'Code target should be a VS Code URI'
309+
);
310+
assert.strictEqual(
311+
(diagnostics[0].code as any).target.toString(),
312+
'https://phpmd.org/rules/codesize.html#excessiveparameterlist',
313+
'URI should match the external info URL'
314+
);
315+
} else {
316+
assert.fail('Code should be an object with target property when externalInfoUrl is available');
317+
}
318+
319+
// Ensure the second diagnostic also has the correct code
320+
if (typeof diagnostics[1].code === 'object') {
321+
assert.strictEqual((diagnostics[1].code as any).value, 'ShortVariable');
322+
assert.strictEqual(
323+
(diagnostics[1].code as any).target.toString(),
324+
'https://phpmd.org/rules/naming.html#shortvariable'
325+
);
326+
} else {
327+
assert.fail('Second diagnostic should also have code object with target');
328+
}
329+
});
221330
});

src/utils/diagnostic-utils.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,14 @@ export class DiagnosticUtils {
8888
diagnostic.source = 'phpmd';
8989

9090
// Add code and additional info if available
91-
diagnostic.code = violation.rule;
92-
// Store the external URL in the tags - VS Code will highlight it as a link
9391
if (violation.externalInfoUrl) {
94-
diagnostic.tags = [vscode.DiagnosticTag.Unnecessary];
92+
// Use DiagnosticRelatedInformation to include a link to documentation
93+
diagnostic.code = {
94+
value: violation.rule,
95+
target: vscode.Uri.parse(violation.externalInfoUrl)
96+
};
97+
} else {
98+
diagnostic.code = violation.rule;
9599
}
96100

97101
return diagnostic;

0 commit comments

Comments
 (0)