Skip to content

Commit 4d7699f

Browse files
authored
feat: more flexible formating for zmodel and generated prisma file (#388)
- Formatter should preserve blank between fields - Support format generated Prisma file using prisma format
1 parent 5616c05 commit 4d7699f

File tree

5 files changed

+78
-3
lines changed

5 files changed

+78
-3
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export class ZModelFormatter extends AbstractFormatter {
2525
} else if (ast.isAbstractDeclaration(node)) {
2626
const bracesOpen = formatter.keyword('{');
2727
const bracesClose = formatter.keyword('}');
28-
// this line decide the indent count return by this.getIndent()
29-
formatter.interior(bracesOpen, bracesClose).prepend(Formatting.indent());
28+
// allow extra blank lines between declarations
29+
formatter.interior(bracesOpen, bracesClose).prepend(Formatting.indent({ allowMore: true }));
3030
bracesOpen.prepend(Formatting.oneSpace());
3131
bracesClose.prepend(Formatting.newLine());
3232
} else if (ast.isModel(node)) {

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AUXILIARY_FIELDS } from '@zenstackhq/sdk';
12
import indentString from './indent-string';
23

34
/**
@@ -145,10 +146,23 @@ export class Model extends ContainerDeclaration {
145146
}
146147

147148
toString(): string {
149+
const auxiliaryFields = this.fields.filter((f) => AUXILIARY_FIELDS.includes(f.name));
150+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
151+
const result: any[] = this.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name));
152+
153+
if (auxiliaryFields.length > 0) {
154+
// Add a blank line before the auxiliary fields
155+
result.push('', ...auxiliaryFields);
156+
if (this.attributes.length > 0) {
157+
// Add a blank line before the attributes
158+
result.push('');
159+
}
160+
}
161+
result.push(...this.attributes);
148162
return (
149163
super.toString() +
150164
`model ${this.name} {\n` +
151-
indentString([...this.fields, ...this.attributes].map((d) => d.toString()).join('\n')) +
165+
indentString(result.map((d) => d.toString()).join('\n')) +
152166
`\n}`
153167
);
154168
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ export default class PrismaSchemaGenerator {
100100
}
101101
await writeFile(outFile, this.PRELUDE + prisma.toString());
102102

103+
if (options.format === true) {
104+
// run 'prisma format'
105+
await execSync(`npx prisma format --schema ${outFile}`);
106+
}
107+
103108
const generateClient = options.generateClient !== false;
104109

105110
if (generateClient) {

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ describe('Prisma generator test', () => {
300300
await getDMMF({ datamodel: content });
301301
expect(content).toContain('@map("myGuardField")');
302302
expect(content).toContain('@map("myTransactionField")');
303+
expect(content).toContain('value Int\n\n zenstack_guard');
304+
expect(content).toContain(
305+
'zenstack_transaction String? @map("myTransactionField")\n\n @@index([zenstack_transaction])'
306+
);
303307
});
304308

305309
it('abstract multi files', async () => {
@@ -328,4 +332,34 @@ describe('Prisma generator test', () => {
328332
const todo = dmmf.datamodel.models.find((m) => m.name === 'Todo');
329333
expect(todo?.documentation?.replace(/\s/g, '')).toBe(`@@allow('read', owner == auth())`.replace(/\s/g, ''));
330334
});
335+
336+
it('format prisma', async () => {
337+
const model = await loadModel(`
338+
datasource db {
339+
provider = 'postgresql'
340+
url = env('URL')
341+
}
342+
343+
model Post {
344+
id Int @id() @default(autoincrement())
345+
title String
346+
content String?
347+
published Boolean @default(false)
348+
@@allow('read', published)
349+
}
350+
`);
351+
352+
const { name } = tmp.fileSync({ postfix: '.prisma' });
353+
await new PrismaSchemaGenerator().generate(model, {
354+
provider: '@core/prisma',
355+
schemaPath: 'schema.zmodel',
356+
output: name,
357+
format: true,
358+
});
359+
360+
const content = fs.readFileSync(name, 'utf-8');
361+
const expected = fs.readFileSync(path.join(__dirname, './prisma/format.prisma'), 'utf-8');
362+
363+
expect(content).toBe(expected);
364+
});
331365
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//////////////////////////////////////////////////////////////////////////////////////////////
2+
// DO NOT MODIFY THIS FILE //
3+
// This file is automatically generated by ZenStack CLI and should not be manually updated. //
4+
//////////////////////////////////////////////////////////////////////////////////////////////
5+
6+
datasource db {
7+
provider = "postgresql"
8+
url = env("URL")
9+
}
10+
11+
/// @@allow('read', published)
12+
model Post {
13+
id Int @id() @default(autoincrement())
14+
title String
15+
content String?
16+
published Boolean @default(false)
17+
18+
zenstack_guard Boolean @default(true)
19+
zenstack_transaction String?
20+
21+
@@index([zenstack_transaction])
22+
}

0 commit comments

Comments
 (0)