Skip to content

Commit 2187f83

Browse files
authored
Add declared types formatter (#1185)
1 parent 5b02bfc commit 2187f83

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed

packages/langium/src/generator/template-string.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function expandToString(staticParts: TemplateStringsArray, ...substitutio
5757
}
5858

5959
export const SNLE = Object.freeze('__«SKIP^NEW^LINE^IF^EMPTY»__');
60-
export const NEWLINE_REGEXP = /\r?\n/g;
60+
export const NEWLINE_REGEXP = /\r?\n/gm;
6161
const nonWhitespace = /\S|$/;
6262

6363
// add the alignment of the previous static part to all lines of the following substitution

packages/langium/src/grammar/lsp/grammar-formatter.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import type { AstNode } from '../../syntax-tree.js';
88
import { AbstractFormatter, Formatting } from '../../lsp/formatter.js';
99
import * as ast from '../generated/ast.js';
1010

11+
const indentOrSpace = Formatting.fit(Formatting.oneSpace(), Formatting.indent());
12+
1113
export class LangiumGrammarFormatter extends AbstractFormatter {
1214

1315
protected format(node: AstNode): void {
@@ -57,6 +59,26 @@ export class LangiumGrammarFormatter extends AbstractFormatter {
5759
formatter.keyword('<').surround(Formatting.noSpace());
5860
formatter.keyword(',').append(Formatting.oneSpace());
5961
formatter.properties('arguments').append(Formatting.noSpace());
62+
} else if (ast.isInterface(node)) {
63+
const formatter = this.getNodeFormatter(node);
64+
formatter.keyword('interface').append(Formatting.oneSpace());
65+
formatter.keyword('extends').prepend(Formatting.oneSpace()).append(indentOrSpace);
66+
formatter.keywords(',').prepend(Formatting.noSpace()).append(indentOrSpace);
67+
const bracesOpen = formatter.keyword('{');
68+
bracesOpen.prepend(Formatting.fit(Formatting.oneSpace(), Formatting.newLine()));
69+
const bracesClose = formatter.keyword('}');
70+
bracesClose.prepend(Formatting.newLine());
71+
formatter.interior(bracesOpen, bracesClose).prepend(Formatting.indent());
72+
} else if (ast.isType(node)) {
73+
const formatter = this.getNodeFormatter(node);
74+
formatter.keyword('type').append(Formatting.oneSpace());
75+
formatter.keyword('=').prepend(Formatting.oneSpace()).append(indentOrSpace);
76+
formatter.keyword(';').prepend(Formatting.noSpace()).append(Formatting.newLine());
77+
} else if (ast.isGrammar(node)) {
78+
const formatter = this.getNodeFormatter(node);
79+
const nodes = formatter.nodes(...node.rules, ...node.interfaces, ...node.types, ...node.imports);
80+
nodes.prepend(Formatting.noIndent());
81+
formatter.keyword('grammar').prepend(Formatting.noSpace()).append(Formatting.oneSpace());
6082
}
6183

6284
if (ast.isAbstractElement(node)) {

packages/langium/src/test/langium-test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import * as assert from 'node:assert';
1919
import { stream } from '../utils/stream.js';
2020
import type { AsyncDisposable } from '../utils/disposable.js';
2121
import { Disposable } from '../utils/disposable.js';
22+
import { normalizeEOL } from '../generator/template-string.js';
2223

2324
export interface ParseHelperOptions extends BuildOptions {
2425
/**
@@ -479,7 +480,7 @@ export function expectFormatting(services: LangiumServices): (expectedFormatting
479480
formatter.formatDocument(document, { options, textDocument: identifier }));
480481

481482
const editedDocument = TextDocument.applyEdits(document.textDocument, edits);
482-
expectedFunction(editedDocument, expectedFormatting.after);
483+
expectedFunction(normalizeEOL(editedDocument), normalizeEOL(expectedFormatting.after));
483484

484485
const disposable = Disposable.create(() => clearDocuments(services, [document]));
485486
if (expectedFormatting.disposeAfterCheck) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/******************************************************************************
2+
* Copyright 2023 TypeFox GmbH
3+
* This program and the accompanying materials are made available under the
4+
* terms of the MIT License, which is available in the project root.
5+
******************************************************************************/
6+
7+
import { describe, test } from 'vitest';
8+
import { EmptyFileSystem, createLangiumGrammarServices, expandToString } from 'langium';
9+
import { expectFormatting } from 'langium/test';
10+
11+
const services = createLangiumGrammarServices(EmptyFileSystem);
12+
const formatting = expectFormatting(services.grammar);
13+
14+
describe('Grammar Formatter', () => {
15+
16+
test('Indents interface properties', async () => {
17+
await formatting({
18+
before: expandToString`
19+
interface Test {
20+
// This is a comment
21+
a: string
22+
b: number
23+
// This is another comment
24+
c: boolean
25+
}
26+
`,
27+
after: expandToString`
28+
interface Test {
29+
// This is a comment
30+
a: string
31+
b: number
32+
// This is another comment
33+
c: boolean
34+
}
35+
`
36+
});
37+
});
38+
39+
test('Formats interface extends references', async () => {
40+
await formatting({
41+
before: expandToString`
42+
interface A extends B,C, D,E{}
43+
`,
44+
after: expandToString`
45+
interface A extends B, C, D, E {
46+
}
47+
`
48+
});
49+
});
50+
51+
test('Formats union type definitions', async () => {
52+
await formatting({
53+
before: expandToString`
54+
type A= B | C | D
55+
;
56+
`,
57+
after: expandToString`
58+
type A = B | C | D;
59+
`
60+
});
61+
});
62+
63+
});

packages/langium/test/grammar/lsp/langium-grammar-semantic-token-provider.test.ts renamed to packages/langium/test/grammar/lsp/grammar-semantic-token-provider.test.ts

File renamed without changes.

0 commit comments

Comments
 (0)