Skip to content

Commit 9ebfcf8

Browse files
committed
fix(zmodel): prefer to use triple-slash comments as ZModel documentation
fixes #1816
1 parent 77817f5 commit 9ebfcf8

File tree

5 files changed

+71
-17
lines changed

5 files changed

+71
-17
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { AstNode, JSDocDocumentationProvider } from 'langium';
2+
3+
/**
4+
* Documentation provider that first tries to use triple-slash comments and falls back to JSDoc comments.
5+
*/
6+
export class ZModelDocumentationProvider extends JSDocDocumentationProvider {
7+
getDocumentation(node: AstNode): string | undefined {
8+
// prefer to user triple-slash comments
9+
if ('comments' in node && Array.isArray(node.comments) && node.comments.length > 0) {
10+
return node.comments.map((c: string) => c.replace(/^[/]*\s*/, '')).join('\n');
11+
}
12+
13+
// fall back to JSDoc comments
14+
return super.getDocumentation(node);
15+
}
16+
}

packages/schema/src/language-server/zmodel-module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ import { ZModelValidationRegistry, ZModelValidator } from './validator/zmodel-va
2727
import { ZModelCodeActionProvider } from './zmodel-code-action';
2828
import { ZModelCompletionProvider } from './zmodel-completion-provider';
2929
import { ZModelDefinitionProvider } from './zmodel-definition';
30+
import { ZModelDocumentationProvider } from './zmodel-documentation-provider';
3031
import { ZModelFormatter } from './zmodel-formatter';
3132
import { ZModelHighlightProvider } from './zmodel-highlight';
3233
import { ZModelHoverProvider } from './zmodel-hover';
3334
import { ZModelLinker } from './zmodel-linker';
3435
import { ZModelScopeComputation, ZModelScopeProvider } from './zmodel-scope';
3536
import { ZModelSemanticTokenProvider } from './zmodel-semantic';
36-
import ZModelWorkspaceManager from './zmodel-workspace-manager';
37+
import { ZModelWorkspaceManager } from './zmodel-workspace-manager';
3738

3839
/**
3940
* Declaration of custom services - add your own service classes here.
@@ -77,6 +78,9 @@ export const ZModelModule: Module<ZModelServices, PartialLangiumServices & ZMode
7778
parser: {
7879
GrammarConfig: (services) => createGrammarConfig(services),
7980
},
81+
documentation: {
82+
DocumentationProvider: (services) => new ZModelDocumentationProvider(services),
83+
},
8084
};
8185

8286
// this duplicates createDefaultSharedModule except that a custom WorkspaceManager is used

packages/schema/src/language-server/zmodel-workspace-manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { PLUGIN_MODULE_NAME, STD_LIB_MODULE_NAME } from './constants';
99
/**
1010
* Custom Langium WorkspaceManager implementation which automatically loads stdlib.zmodel
1111
*/
12-
export default class ZModelWorkspaceManager extends DefaultWorkspaceManager {
12+
export class ZModelWorkspaceManager extends DefaultWorkspaceManager {
1313
public pluginModels = new Set<string>();
1414

1515
protected async loadAdditionalDocuments(

packages/schema/src/plugins/prisma/schema-generator.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,13 @@ export class PrismaSchemaGenerator {
282282
this.generateContainerAttribute(model, attr);
283283
}
284284

285-
decl.attributes
286-
.filter((attr) => attr.decl.ref && !this.isPrismaAttribute(attr))
287-
.forEach((attr) => model.addComment('/// ' + this.zModelGenerator.generate(attr)));
288-
289285
// user defined comments pass-through
290286
decl.comments.forEach((c) => model.addComment(c));
291287

288+
decl.attributes
289+
.filter((attr) => attr.decl.ref && !this.isPrismaAttribute(attr))
290+
.forEach((attr) => model.addComment('/// - _' + this.zModelGenerator.generate(attr) + '_'));
291+
292292
// generate relation fields on base models linking to concrete models
293293
this.generateDelegateRelationForBase(model, decl);
294294

@@ -765,9 +765,11 @@ export class PrismaSchemaGenerator {
765765

766766
const nonPrismaAttributes = field.attributes.filter((attr) => attr.decl.ref && !this.isPrismaAttribute(attr));
767767

768-
const documentations = nonPrismaAttributes.map((attr) => '/// ' + this.zModelGenerator.generate(attr));
768+
// user defined comments pass-through
769+
const docs: string[] = [...field.comments];
770+
docs.push(...nonPrismaAttributes.map((attr) => '/// - _' + this.zModelGenerator.generate(attr) + '_'));
769771

770-
const result = model.addField(field.name, type, attributes, documentations, addToFront);
772+
const result = model.addField(field.name, type, attributes, docs, addToFront);
771773

772774
if (this.mode === 'logical') {
773775
if (field.attributes.some((attr) => isDefaultWithAuth(attr))) {
@@ -777,8 +779,6 @@ export class PrismaSchemaGenerator {
777779
}
778780
}
779781

780-
// user defined comments pass-through
781-
field.comments.forEach((c) => result.addComment(c));
782782
return result;
783783
}
784784

@@ -898,12 +898,12 @@ export class PrismaSchemaGenerator {
898898
this.generateContainerAttribute(_enum, attr);
899899
}
900900

901-
decl.attributes
902-
.filter((attr) => attr.decl.ref && !this.isPrismaAttribute(attr))
903-
.forEach((attr) => _enum.addComment('/// ' + this.zModelGenerator.generate(attr)));
904-
905901
// user defined comments pass-through
906902
decl.comments.forEach((c) => _enum.addComment(c));
903+
904+
decl.attributes
905+
.filter((attr) => attr.decl.ref && !this.isPrismaAttribute(attr))
906+
.forEach((attr) => _enum.addComment('/// - _' + this.zModelGenerator.generate(attr) + '_'));
907907
}
908908

909909
private generateEnumField(_enum: PrismaEnum, field: EnumField) {
@@ -913,8 +913,9 @@ export class PrismaSchemaGenerator {
913913

914914
const nonPrismaAttributes = field.attributes.filter((attr) => attr.decl.ref && !this.isPrismaAttribute(attr));
915915

916-
const documentations = nonPrismaAttributes.map((attr) => '/// ' + this.zModelGenerator.generate(attr));
917-
_enum.addField(field.name, attributes, documentations.concat(field.comments));
916+
const docs = [...field.comments];
917+
docs.push(...nonPrismaAttributes.map((attr) => '/// - _' + this.zModelGenerator.generate(attr) + '_'));
918+
_enum.addField(field.name, attributes, docs);
918919
}
919920
}
920921

packages/schema/tests/generator/prisma-generator.test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,35 @@ describe('Prisma generator test', () => {
4747
provider = '@core/prisma'
4848
}
4949
50+
/// User roles
51+
enum Role {
52+
/// Admin role
53+
ADMIN
54+
/// Regular role
55+
USER
56+
57+
@@schema("auth")
58+
}
59+
60+
/// My user model
61+
/// defined here
5062
model User {
51-
id String @id
63+
/// the id field
64+
id String @id @allow('read', this == auth())
65+
role Role
5266
5367
@@schema("auth")
68+
@@allow('all', true)
69+
@@deny('update', this != auth())
70+
}
71+
72+
/**
73+
* My post model
74+
* defined here
75+
*/
76+
model Post {
77+
id String @id
78+
@@schema("public")
5479
}
5580
`);
5681

@@ -70,6 +95,14 @@ describe('Prisma generator test', () => {
7095
'extensions = [pg_trgm, postgis(version: "3.3.2"), uuid_ossp(map: "uuid-ossp", schema: "extensions")]'
7196
);
7297
expect(content).toContain('schemas = ["auth", "public"]');
98+
expect(content).toContain('/// My user model');
99+
expect(content).toContain(`/// - _@@allow('all', true)_`);
100+
expect(content).toContain(`/// the id field`);
101+
expect(content).toContain(`/// - _@allow('read', this == auth())_`);
102+
expect(content).not.toContain('/// My post model');
103+
expect(content).toContain('/// User roles');
104+
expect(content).toContain('/// Admin role');
105+
expect(content).toContain('/// Regular role');
73106
await getDMMF({ datamodel: content });
74107
});
75108

0 commit comments

Comments
 (0)