Skip to content

Commit

Permalink
feat: customize rendering of @param, @result, and @typeParam tags
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-reimann committed Nov 12, 2023
1 parent 9b1522f commit 599843d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 19 deletions.
10 changes: 10 additions & 0 deletions packages/safe-ds-lang/src/helpers/stringUtils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* Normalizes line breaks to `\n`.
*
* @param text The text to normalize.
* @return The normalized text.
*/
export const normalizeLineBreaks = (text: string | undefined): string => {
return text?.replace(/\r\n?/gu, '\n') ?? '';
};

/**
* Based on the given count, returns the singular or plural form of the given word.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
JSDocComment,
JSDocDocumentationProvider,
JSDocRenderOptions,
type JSDocTag,
parseJSDoc,
} from 'langium';
import {
Expand All @@ -17,6 +18,10 @@ import {
SdsTypeParameter,
} from '../generated/ast.js';

const PARAM_TAG = 'param';
const RESULT_TAG = 'result';
const TYPE_PARAM_TAG = 'typeParam';

export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
override getDocumentation(node: AstNode): string | undefined {
if (isSdsParameter(node) || isSdsResult(node) || isSdsTypeParameter(node)) {
Expand All @@ -39,6 +44,16 @@ export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
}
}

protected override documentationTagRenderer(node: AstNode, tag: JSDocTag): string | undefined {
if (tag.name === PARAM_TAG || tag.name === RESULT_TAG || tag.name === TYPE_PARAM_TAG) {
const contentMd = tag.content.toMarkdown();
const [paramName, description] = contentMd.split(/\s(.*)/su);
return `**@${tag.name}** *${paramName}* — ${(description ?? '').trim()}`;
} else {
return super.documentationTagRenderer(node, tag);
}
}

private getJSDocComment(node: AstNode): JSDocComment | undefined {
const comment = this.commentProvider.getComment(node);
if (comment && isJSDoc(comment)) {
Expand Down Expand Up @@ -70,11 +85,11 @@ export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {

private getTagName(node: SdsParameter | SdsResult | SdsTypeParameter): string {
if (isSdsParameter(node)) {
return 'param';
return PARAM_TAG;
} else if (isSdsResult(node)) {
return 'result';
return RESULT_TAG;
} else {
return 'typeParam';
return TYPE_PARAM_TAG;
}
}

Expand All @@ -83,6 +98,10 @@ export class SafeDsDocumentationProvider extends JSDocDocumentationProvider {
renderLink: (link, display) => {
return this.documentationLinkRenderer(node, link, display);
},
tag: 'bold',
renderTag: (tag: JSDocTag) => {
return this.documentationTagRenderer(node, tag);
},
};
}
}
29 changes: 28 additions & 1 deletion packages/safe-ds-lang/tests/helpers/stringUtils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
import { describe, expect, it } from 'vitest';
import { pluralize } from '../../src/helpers/stringUtils.js';
import { normalizeLineBreaks, pluralize } from '../../src/helpers/stringUtils.js';

describe('normalizeLineBreaks', () => {
it.each([
{
text: undefined,
expected: '',
},
{
text: '',
expected: '',
},
{
text: 'foo\nbar',
expected: 'foo\nbar',
},
{
text: 'foo\rbar',
expected: 'foo\nbar',
},
{
text: 'foo\r\nbar',
expected: 'foo\nbar',
},
])(`should normalize line breaks (%#)`, ({ text, expected }) => {
expect(normalizeLineBreaks(text)).toBe(expected);
});
});

describe('pluralize', () => {
it.each([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { afterEach, describe, expect, it } from 'vitest';
import { createSafeDsServices } from '../../../src/language/safe-ds-module.js';
import { AstNode, EmptyFileSystem } from 'langium';
import { AstNode, EmptyFileSystem, expandToString } from 'langium';
import { clearDocuments } from 'langium/test';
import { getNodeOfType } from '../../helpers/nodeFinder.js';
import { afterEach, describe, expect, it } from 'vitest';
import { normalizeLineBreaks } from '../../../src/helpers/stringUtils.js';
import {
isSdsAnnotation,
isSdsFunction,
isSdsParameter,
isSdsResult,
isSdsTypeParameter,
} from '../../../src/language/generated/ast.js';
import { createSafeDsServices } from '../../../src/language/index.js';
import { getNodeOfType } from '../../helpers/nodeFinder.js';

const services = createSafeDsServices(EmptyFileSystem).SafeDs;
const documentationProvider = services.documentation.DocumentationProvider;
Expand Down Expand Up @@ -166,11 +167,39 @@ describe('SafeDsDocumentationProvider', () => {
predicate: isSdsTypeParameter,
expectedDocumentation: undefined,
},
{
testName: 'custom tag rendering',
code: `
/**
* ${testDocumentation}
*
* @param param ${testDocumentation}
* @result result ${testDocumentation}
* @typeParam T ${testDocumentation}
* @since 1.0.0
*/
fun myFunction<T>(param: String) -> result: String
`,
predicate: isSdsFunction,
expectedDocumentation: expandToString`
Lorem ipsum.
**@param** *param* — Lorem ipsum.
**@result** *result* — Lorem ipsum.
**@typeParam** *T* — Lorem ipsum.
**@since** — 1.0.0
`,
},
];

it.each(testCases)('$testName', async ({ code, predicate, expectedDocumentation }) => {
const node = await getNodeOfType(services, code, predicate);
expect(documentationProvider.getDocumentation(node)).toStrictEqual(expectedDocumentation);
const normalizedActual = normalizeLineBreaks(documentationProvider.getDocumentation(node));
const normalizedExpected = normalizeLineBreaks(expectedDocumentation);
expect(normalizedActual).toStrictEqual(normalizedExpected);
});

it('should resolve links', async () => {
Expand Down
11 changes: 1 addition & 10 deletions packages/safe-ds-lang/tests/language/lsp/formatting/creator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';
import { EmptyFileSystem, URI } from 'langium';
import { Diagnostic } from 'vscode-languageserver';
import { normalizeLineBreaks } from '../../../../src/helpers/stringUtils.js';
import { createSafeDsServices } from '../../../../src/language/index.js';
import { getSyntaxErrors } from '../../../helpers/diagnostics.js';
import { TestDescription, TestDescriptionError } from '../../../helpers/testDescription.js';
Expand Down Expand Up @@ -64,16 +65,6 @@ const invalidTest = (error: TestDescriptionError): FormattingTest => {
};
};

/**
* Normalizes line breaks to `\n`.
*
* @param code The code to normalize.
* @return The normalized code.
*/
const normalizeLineBreaks = (code: string): string => {
return code.replace(/\r\n?/gu, '\n');
};

/**
* A description of a formatting test.
*/
Expand Down

0 comments on commit 599843d

Please sign in to comment.