Skip to content

Commit e049148

Browse files
authored
feat: customize rendering of @param, @result, and @typeParam tags (#764)
Closes partially #669 ### Summary of Changes Write tag in bold and the declaration name in italics for rendered `@param`, `@result` and `@typeParam` tags.
1 parent 9b1522f commit e049148

File tree

5 files changed

+95
-19
lines changed

5 files changed

+95
-19
lines changed

packages/safe-ds-lang/src/helpers/stringUtils.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* Normalizes line breaks to `\n`.
3+
*
4+
* @param text The text to normalize.
5+
* @return The normalized text.
6+
*/
7+
export const normalizeLineBreaks = (text: string | undefined): string => {
8+
return text?.replace(/\r\n?/gu, '\n') ?? '';
9+
};
10+
111
/**
212
* Based on the given count, returns the singular or plural form of the given word.
313
*/

packages/safe-ds-lang/src/language/documentation/safe-ds-documentation-provider.ts

+22-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
JSDocComment,
66
JSDocDocumentationProvider,
77
JSDocRenderOptions,
8+
type JSDocTag,
89
parseJSDoc,
910
} from 'langium';
1011
import {
@@ -17,6 +18,10 @@ import {
1718
SdsTypeParameter,
1819
} from '../generated/ast.js';
1920

21+
const PARAM_TAG = 'param';
22+
const RESULT_TAG = 'result';
23+
const TYPE_PARAM_TAG = 'typeParam';
24+
2025
export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
2126
override getDocumentation(node: AstNode): string | undefined {
2227
if (isSdsParameter(node) || isSdsResult(node) || isSdsTypeParameter(node)) {
@@ -39,6 +44,16 @@ export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
3944
}
4045
}
4146

47+
protected override documentationTagRenderer(node: AstNode, tag: JSDocTag): string | undefined {
48+
if (tag.name === PARAM_TAG || tag.name === RESULT_TAG || tag.name === TYPE_PARAM_TAG) {
49+
const contentMd = tag.content.toMarkdown();
50+
const [paramName, description] = contentMd.split(/\s(.*)/su);
51+
return `**@${tag.name}** *${paramName}* — ${(description ?? '').trim()}`;
52+
} else {
53+
return super.documentationTagRenderer(node, tag);
54+
}
55+
}
56+
4257
private getJSDocComment(node: AstNode): JSDocComment | undefined {
4358
const comment = this.commentProvider.getComment(node);
4459
if (comment && isJSDoc(comment)) {
@@ -70,11 +85,11 @@ export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
7085

7186
private getTagName(node: SdsParameter | SdsResult | SdsTypeParameter): string {
7287
if (isSdsParameter(node)) {
73-
return 'param';
88+
return PARAM_TAG;
7489
} else if (isSdsResult(node)) {
75-
return 'result';
90+
return RESULT_TAG;
7691
} else {
77-
return 'typeParam';
92+
return TYPE_PARAM_TAG;
7893
}
7994
}
8095

@@ -83,6 +98,10 @@ export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
8398
renderLink: (link, display) => {
8499
return this.documentationLinkRenderer(node, link, display);
85100
},
101+
tag: 'bold',
102+
renderTag: (tag: JSDocTag) => {
103+
return this.documentationTagRenderer(node, tag);
104+
},
86105
};
87106
}
88107
}

packages/safe-ds-lang/tests/helpers/stringUtils.test.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
import { describe, expect, it } from 'vitest';
2-
import { pluralize } from '../../src/helpers/stringUtils.js';
2+
import { normalizeLineBreaks, pluralize } from '../../src/helpers/stringUtils.js';
3+
4+
describe('normalizeLineBreaks', () => {
5+
it.each([
6+
{
7+
text: undefined,
8+
expected: '',
9+
},
10+
{
11+
text: '',
12+
expected: '',
13+
},
14+
{
15+
text: 'foo\nbar',
16+
expected: 'foo\nbar',
17+
},
18+
{
19+
text: 'foo\rbar',
20+
expected: 'foo\nbar',
21+
},
22+
{
23+
text: 'foo\r\nbar',
24+
expected: 'foo\nbar',
25+
},
26+
])(`should normalize line breaks (%#)`, ({ text, expected }) => {
27+
expect(normalizeLineBreaks(text)).toBe(expected);
28+
});
29+
});
330

431
describe('pluralize', () => {
532
it.each([

packages/safe-ds-lang/tests/language/documentation/safe-ds-documentation-provider.test.ts

+34-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import { afterEach, describe, expect, it } from 'vitest';
2-
import { createSafeDsServices } from '../../../src/language/safe-ds-module.js';
3-
import { AstNode, EmptyFileSystem } from 'langium';
1+
import { AstNode, EmptyFileSystem, expandToString } from 'langium';
42
import { clearDocuments } from 'langium/test';
5-
import { getNodeOfType } from '../../helpers/nodeFinder.js';
3+
import { afterEach, describe, expect, it } from 'vitest';
4+
import { normalizeLineBreaks } from '../../../src/helpers/stringUtils.js';
65
import {
76
isSdsAnnotation,
87
isSdsFunction,
98
isSdsParameter,
109
isSdsResult,
1110
isSdsTypeParameter,
1211
} from '../../../src/language/generated/ast.js';
12+
import { createSafeDsServices } from '../../../src/language/index.js';
13+
import { getNodeOfType } from '../../helpers/nodeFinder.js';
1314

1415
const services = createSafeDsServices(EmptyFileSystem).SafeDs;
1516
const documentationProvider = services.documentation.DocumentationProvider;
@@ -166,11 +167,39 @@ describe('SafeDsDocumentationProvider', () => {
166167
predicate: isSdsTypeParameter,
167168
expectedDocumentation: undefined,
168169
},
170+
{
171+
testName: 'custom tag rendering',
172+
code: `
173+
/**
174+
* ${testDocumentation}
175+
*
176+
* @param param ${testDocumentation}
177+
* @result result ${testDocumentation}
178+
* @typeParam T ${testDocumentation}
179+
* @since 1.0.0
180+
*/
181+
fun myFunction<T>(param: String) -> result: String
182+
`,
183+
predicate: isSdsFunction,
184+
expectedDocumentation: expandToString`
185+
Lorem ipsum.
186+
187+
**@param** *param* — Lorem ipsum.
188+
189+
**@result** *result* — Lorem ipsum.
190+
191+
**@typeParam** *T* — Lorem ipsum.
192+
193+
**@since** — 1.0.0
194+
`,
195+
},
169196
];
170197

171198
it.each(testCases)('$testName', async ({ code, predicate, expectedDocumentation }) => {
172199
const node = await getNodeOfType(services, code, predicate);
173-
expect(documentationProvider.getDocumentation(node)).toStrictEqual(expectedDocumentation);
200+
const normalizedActual = normalizeLineBreaks(documentationProvider.getDocumentation(node));
201+
const normalizedExpected = normalizeLineBreaks(expectedDocumentation);
202+
expect(normalizedActual).toStrictEqual(normalizedExpected);
174203
});
175204

176205
it('should resolve links', async () => {

packages/safe-ds-lang/tests/language/lsp/formatting/creator.ts

+1-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'fs';
22
import { EmptyFileSystem, URI } from 'langium';
33
import { Diagnostic } from 'vscode-languageserver';
4+
import { normalizeLineBreaks } from '../../../../src/helpers/stringUtils.js';
45
import { createSafeDsServices } from '../../../../src/language/index.js';
56
import { getSyntaxErrors } from '../../../helpers/diagnostics.js';
67
import { TestDescription, TestDescriptionError } from '../../../helpers/testDescription.js';
@@ -64,16 +65,6 @@ const invalidTest = (error: TestDescriptionError): FormattingTest => {
6465
};
6566
};
6667

67-
/**
68-
* Normalizes line breaks to `\n`.
69-
*
70-
* @param code The code to normalize.
71-
* @return The normalized code.
72-
*/
73-
const normalizeLineBreaks = (code: string): string => {
74-
return code.replace(/\r\n?/gu, '\n');
75-
};
76-
7768
/**
7869
* A description of a formatting test.
7970
*/

0 commit comments

Comments
 (0)