zenstack 0.5.0 → 0.6.0-pre.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/{LICENSE.md → LICENSE} +0 -0
  2. package/bin/cli +1 -1
  3. package/package.json +17 -13
  4. package/bin/post-install.js +0 -0
  5. package/bundle/asset/logo-256-bg.png +0 -0
  6. package/bundle/asset/logo-dark-256.png +0 -0
  7. package/bundle/asset/logo-light-256.png +0 -0
  8. package/bundle/cli/index.js +0 -6952
  9. package/bundle/extension.js +0 -39
  10. package/bundle/language-server/main.js +0 -6208
  11. package/bundle/res/package.template.json +0 -9
  12. package/bundle/res/prism-zmodel.js +0 -22
  13. package/bundle/res/stdlib.zmodel +0 -218
  14. package/bundle/res/tsconfig.template.json +0 -17
  15. package/src/cli/cli-error.ts +0 -4
  16. package/src/cli/cli-util.ts +0 -214
  17. package/src/cli/index.ts +0 -246
  18. package/src/extension.ts +0 -76
  19. package/src/generator/ast-utils.ts +0 -18
  20. package/src/generator/constants.ts +0 -6
  21. package/src/generator/field-constraint/index.ts +0 -304
  22. package/src/generator/index.ts +0 -86
  23. package/src/generator/prisma/expression-writer.ts +0 -360
  24. package/src/generator/prisma/index.ts +0 -44
  25. package/src/generator/prisma/prisma-builder.ts +0 -370
  26. package/src/generator/prisma/query-guard-generator.ts +0 -249
  27. package/src/generator/prisma/schema-generator.ts +0 -313
  28. package/src/generator/prisma/typescript-expression-transformer.ts +0 -108
  29. package/src/generator/react-hooks/index.ts +0 -273
  30. package/src/generator/service/index.ts +0 -113
  31. package/src/generator/tsc/index.ts +0 -59
  32. package/src/generator/types.ts +0 -20
  33. package/src/global.d.ts +0 -3
  34. package/src/language-server/constants.ts +0 -29
  35. package/src/language-server/generated/ast.ts +0 -643
  36. package/src/language-server/generated/grammar.ts +0 -2492
  37. package/src/language-server/generated/module.ts +0 -24
  38. package/src/language-server/langium-ext.d.ts +0 -22
  39. package/src/language-server/main.ts +0 -13
  40. package/src/language-server/types.ts +0 -25
  41. package/src/language-server/utils.ts +0 -21
  42. package/src/language-server/validator/attribute-validator.ts +0 -11
  43. package/src/language-server/validator/datamodel-validator.ts +0 -426
  44. package/src/language-server/validator/datasource-validator.ts +0 -102
  45. package/src/language-server/validator/enum-validator.ts +0 -14
  46. package/src/language-server/validator/expression-validator.ts +0 -48
  47. package/src/language-server/validator/schema-validator.ts +0 -31
  48. package/src/language-server/validator/utils.ts +0 -158
  49. package/src/language-server/validator/zmodel-validator.ts +0 -91
  50. package/src/language-server/zmodel-linker.ts +0 -453
  51. package/src/language-server/zmodel-module.ts +0 -131
  52. package/src/language-server/zmodel-scope.ts +0 -45
  53. package/src/language-server/zmodel-workspace-manager.ts +0 -23
  54. package/src/language-server/zmodel.langium +0 -207
  55. package/src/res/package.template.json +0 -9
  56. package/src/res/prism-zmodel.js +0 -22
  57. package/src/res/stdlib.zmodel +0 -218
  58. package/src/res/tsconfig.template.json +0 -17
  59. package/src/telemetry.ts +0 -119
  60. package/src/utils/exec-utils.ts +0 -8
  61. package/src/utils/indent-string.ts +0 -9
  62. package/src/utils/pkg-utils.ts +0 -63
@@ -1,86 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-var-requires */
2
- import { Context, Generator } from './types';
3
- import * as fs from 'fs';
4
- import colors from 'colors';
5
- import PrismaGenerator from './prisma';
6
- import ServiceGenerator from './service';
7
- import ReactHooksGenerator from './react-hooks';
8
- import { TypescriptCompilation } from './tsc';
9
- import FieldConstraintGenerator from './field-constraint';
10
- import telemetry from '../telemetry';
11
- import ora from 'ora';
12
-
13
- /**
14
- * ZenStack code generator
15
- */
16
- export class ZenStackGenerator {
17
- /**
18
- * Runs a series of nested generators
19
- */
20
- async generate(
21
- context: Context,
22
- includeGenerators?: string[],
23
- clearOutput = true
24
- ): Promise<void> {
25
- // ensure folder that stores generated prisma schema and migrations
26
- if (!fs.existsSync(context.outDir)) {
27
- fs.mkdirSync(context.outDir);
28
- }
29
-
30
- if (clearOutput) {
31
- // recreate folder that stores generated zenstack code
32
- if (fs.existsSync(context.generatedCodeDir)) {
33
- fs.rmSync(context.generatedCodeDir, {
34
- force: true,
35
- recursive: true,
36
- });
37
- }
38
- fs.mkdirSync(context.generatedCodeDir);
39
- }
40
-
41
- // TODO: plugin mechanism
42
- const generators: Generator[] = [
43
- new PrismaGenerator(),
44
- new ServiceGenerator(),
45
- new ReactHooksGenerator(),
46
- new FieldConstraintGenerator(),
47
- new TypescriptCompilation(),
48
- ];
49
-
50
- const version = require('../../package.json').version;
51
- console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));
52
-
53
- const warnings: string[] = [];
54
- for (const generator of generators) {
55
- if (
56
- includeGenerators &&
57
- !includeGenerators.includes(generator.name)
58
- ) {
59
- continue;
60
- }
61
-
62
- const spinner = ora(generator.startMessage).start();
63
- await telemetry.trackSpan(
64
- 'cli:generator:start',
65
- 'cli:generator:complete',
66
- 'cli:generator:error',
67
- {
68
- generator: generator.name,
69
- },
70
- async () => {
71
- const genWarnings = await generator.generate(context);
72
- warnings.push(...genWarnings);
73
- }
74
- );
75
- spinner.succeed(`${colors.cyan(generator.successMessage)}`);
76
- }
77
-
78
- console.log(
79
- colors.green(
80
- colors.bold('👻 All generators completed successfully!')
81
- )
82
- );
83
-
84
- warnings.forEach((w) => console.warn(colors.yellow(w)));
85
- }
86
- }
@@ -1,360 +0,0 @@
1
- import {
2
- BinaryExpr,
3
- Expression,
4
- isDataModel,
5
- isDataModelField,
6
- isEnumField,
7
- isMemberAccessExpr,
8
- isReferenceExpr,
9
- isThisExpr,
10
- LiteralExpr,
11
- MemberAccessExpr,
12
- ReferenceExpr,
13
- UnaryExpr,
14
- } from '@lang/generated/ast';
15
- import { CodeBlockWriter } from 'ts-morph';
16
- import { GUARD_FIELD_NAME } from '../constants';
17
- import { GeneratorError } from '../types';
18
- import TypeScriptExpressionTransformer from './typescript-expression-transformer';
19
-
20
- type ComparisonOperator = '==' | '!=' | '>' | '>=' | '<' | '<=';
21
-
22
- /**
23
- * Utility for writing ZModel expression as Prisma query argument objects into a ts-morph writer
24
- */
25
- export default class ExpressionWriter {
26
- private readonly plainExprBuilder = new TypeScriptExpressionTransformer();
27
-
28
- constructor(private readonly writer: CodeBlockWriter) {}
29
-
30
- /**
31
- * Writes the given ZModel expression.
32
- */
33
- write(expr: Expression): void {
34
- const _write = () => {
35
- switch (expr.$type) {
36
- case LiteralExpr:
37
- this.writeLiteral(expr as LiteralExpr);
38
- break;
39
-
40
- case UnaryExpr:
41
- this.writeUnary(expr as UnaryExpr);
42
- break;
43
-
44
- case BinaryExpr:
45
- this.writeBinary(expr as BinaryExpr);
46
- break;
47
-
48
- case ReferenceExpr:
49
- this.writeReference(expr as ReferenceExpr);
50
- break;
51
-
52
- case MemberAccessExpr:
53
- this.writeMemberAccess(expr as MemberAccessExpr);
54
- break;
55
-
56
- default:
57
- throw new Error(`Not implemented: ${expr.$type}`);
58
- }
59
- };
60
-
61
- this.block(_write);
62
- }
63
-
64
- private writeReference(expr: ReferenceExpr) {
65
- if (isEnumField(expr.target.ref)) {
66
- throw new Error('We should never get here');
67
- } else {
68
- this.writer.write(`${expr.target.ref?.name}: true`);
69
- }
70
- }
71
-
72
- private writeMemberAccess(expr: MemberAccessExpr) {
73
- this.writeFieldCondition(
74
- expr.operand,
75
- () => {
76
- this.block(() => {
77
- this.writer.write(`${expr.member.ref?.name}: true`);
78
- });
79
- },
80
- 'is'
81
- );
82
- }
83
-
84
- private writeExprList(exprs: Expression[]) {
85
- this.writer.writeLine('[');
86
- for (let i = 0; i < exprs.length; i++) {
87
- this.write(exprs[i]);
88
- if (i !== exprs.length - 1) {
89
- this.writer.writeLine(',');
90
- }
91
- }
92
- this.writer.writeLine(']');
93
- }
94
-
95
- private writeBinary(expr: BinaryExpr) {
96
- switch (expr.operator) {
97
- case '&&':
98
- case '||':
99
- this.writeLogical(expr, expr.operator);
100
- break;
101
-
102
- case '==':
103
- case '!=':
104
- case '>':
105
- case '>=':
106
- case '<':
107
- case '<=':
108
- this.writeComparison(expr, expr.operator);
109
- break;
110
-
111
- case '?':
112
- case '!':
113
- case '^':
114
- this.writeCollectionPredicate(expr, expr.operator);
115
- break;
116
- }
117
- }
118
-
119
- private writeCollectionPredicate(expr: BinaryExpr, operator: string) {
120
- this.writeFieldCondition(
121
- expr.left,
122
- () => {
123
- this.write(expr.right);
124
- },
125
- operator === '?' ? 'some' : operator === '!' ? 'every' : 'none'
126
- );
127
- }
128
-
129
- private isFieldAccess(expr: Expression): boolean {
130
- if (isThisExpr(expr)) {
131
- return true;
132
- }
133
- if (isMemberAccessExpr(expr)) {
134
- return this.isFieldAccess(expr.operand);
135
- }
136
- if (isReferenceExpr(expr) && isDataModelField(expr.target.ref)) {
137
- return true;
138
- }
139
- return false;
140
- }
141
-
142
- private guard(write: () => void) {
143
- this.writer.write(`${GUARD_FIELD_NAME}: `);
144
- write();
145
- }
146
-
147
- private plain(expr: Expression) {
148
- this.writer.write(this.plainExprBuilder.transform(expr));
149
- }
150
-
151
- private writeComparison(expr: BinaryExpr, operator: ComparisonOperator) {
152
- const leftIsFieldAccess = this.isFieldAccess(expr.left);
153
- const rightIsFieldAccess = this.isFieldAccess(expr.right);
154
-
155
- if (leftIsFieldAccess && rightIsFieldAccess) {
156
- throw new GeneratorError(
157
- `Comparison between fields are not supported yet`
158
- );
159
- }
160
-
161
- if (!leftIsFieldAccess && !rightIsFieldAccess) {
162
- // compile down to a plain expression
163
- this.guard(() => {
164
- this.plain(expr.left);
165
- this.writer.write(' ' + operator + ' ');
166
- this.plain(expr.right);
167
- });
168
-
169
- return;
170
- }
171
-
172
- let fieldAccess: Expression;
173
- let operand: Expression;
174
- if (leftIsFieldAccess) {
175
- fieldAccess = expr.left;
176
- operand = expr.right;
177
- } else {
178
- fieldAccess = expr.right;
179
- operand = expr.left;
180
- operator = this.negateOperator(operator);
181
- }
182
-
183
- this.writeFieldCondition(
184
- fieldAccess,
185
- () => {
186
- this.block(
187
- () => {
188
- if (this.isModelTyped(fieldAccess)) {
189
- // comparing with an object, conver to "id" comparison instead
190
- this.writer.write('id: ');
191
- this.block(() => {
192
- this.writeOperator(operator, () => {
193
- this.plain(operand);
194
- this.writer.write('?.id');
195
- });
196
- });
197
- } else {
198
- this.writeOperator(operator, () => {
199
- this.plain(operand);
200
- });
201
- }
202
- },
203
- // "this" expression is compiled away (to .id access), so we should
204
- // avoid generating a new layer
205
- !isThisExpr(fieldAccess)
206
- );
207
- },
208
- 'is'
209
- );
210
- }
211
-
212
- private writeOperator(
213
- operator: ComparisonOperator,
214
- writeOperand: () => void
215
- ) {
216
- if (operator === '!=') {
217
- // wrap a 'not'
218
- this.writer.write('not: ');
219
- this.block(() => {
220
- this.writeOperator('==', writeOperand);
221
- });
222
- } else {
223
- this.writer.write(`${this.mapOperator(operator)}: `);
224
- writeOperand();
225
- }
226
- }
227
-
228
- private writeFieldCondition(
229
- fieldAccess: Expression,
230
- writeCondition: () => void,
231
- relationOp: 'is' | 'some' | 'every' | 'none'
232
- ) {
233
- let selector: string | undefined;
234
- let operand: Expression | undefined;
235
-
236
- if (isThisExpr(fieldAccess)) {
237
- // pass on
238
- writeCondition();
239
- return;
240
- } else if (isReferenceExpr(fieldAccess)) {
241
- selector = fieldAccess.target.ref?.name;
242
- } else if (isMemberAccessExpr(fieldAccess)) {
243
- selector = fieldAccess.member.ref?.name;
244
- operand = fieldAccess.operand;
245
- } else {
246
- throw new GeneratorError(
247
- `Unsupported expression type: ${fieldAccess.$type}`
248
- );
249
- }
250
-
251
- if (!selector) {
252
- throw new GeneratorError(`Failed to write FieldAccess expression`);
253
- }
254
-
255
- if (operand) {
256
- // member access expression
257
- this.writeFieldCondition(
258
- operand,
259
- () => {
260
- this.block(
261
- () => {
262
- this.writer.write(selector + ': ');
263
- if (this.isModelTyped(fieldAccess)) {
264
- // expression is resolved to a model, generate relation query
265
- this.block(() => {
266
- this.writer.write(`${relationOp}: `);
267
- writeCondition();
268
- });
269
- } else {
270
- // generate plain query
271
- writeCondition();
272
- }
273
- },
274
- // if operand is "this", it doesn't really generate a new layer of query,
275
- // so we should avoid generating a new block
276
- !isThisExpr(operand)
277
- );
278
- },
279
- 'is'
280
- );
281
- } else if (this.isModelTyped(fieldAccess)) {
282
- // reference resolved to a model, generate relation query
283
- this.writer.write(selector + ': ');
284
- this.block(() => {
285
- this.writer.write(`${relationOp}: `);
286
- writeCondition();
287
- });
288
- } else {
289
- // generate a plain query
290
- this.writer.write(selector + ': ');
291
- writeCondition();
292
- }
293
- }
294
-
295
- private block(write: () => void, condition = true) {
296
- if (condition) {
297
- this.writer.block(write);
298
- } else {
299
- write();
300
- }
301
- }
302
-
303
- private isModelTyped(expr: Expression) {
304
- return isDataModel(expr.$resolvedType?.decl);
305
- }
306
-
307
- private mapOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') {
308
- switch (operator) {
309
- case '==':
310
- return 'equals';
311
- case '!=':
312
- throw new Error('Operation != should have been compiled away');
313
- case '>':
314
- return 'gt';
315
- case '>=':
316
- return 'ge';
317
- case '<':
318
- return 'lt';
319
- case '<=':
320
- return 'le';
321
- }
322
- }
323
-
324
- private negateOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') {
325
- switch (operator) {
326
- case '>':
327
- return '<=';
328
- case '<':
329
- return '>=';
330
- case '>=':
331
- return '<';
332
- case '<=':
333
- return '>';
334
- default:
335
- return operator;
336
- }
337
- }
338
-
339
- private writeLogical(expr: BinaryExpr, operator: '&&' | '||') {
340
- this.writer.writeLine(`${operator === '&&' ? 'AND' : 'OR'}: `);
341
- this.writeExprList([expr.left, expr.right]);
342
- }
343
-
344
- private writeUnary(expr: UnaryExpr) {
345
- if (expr.operator !== '!') {
346
- throw new GeneratorError(
347
- `Unary operator "${expr.operator}" is not supported`
348
- );
349
- }
350
-
351
- this.writer.writeLine('NOT: ');
352
- this.write(expr.operand);
353
- }
354
-
355
- private writeLiteral(expr: LiteralExpr) {
356
- this.guard(() => {
357
- this.plain(expr);
358
- });
359
- }
360
- }
@@ -1,44 +0,0 @@
1
- import { execSync } from '../../utils/exec-utils';
2
- import { Context, Generator, GeneratorError } from '../types';
3
- import QueryGuardGenerator from './query-guard-generator';
4
- import PrismaSchemaGenerator from './schema-generator';
5
-
6
- /**
7
- * Generates Prisma schema and db client
8
- */
9
- export default class PrismaGenerator implements Generator {
10
- get name() {
11
- return 'prisma';
12
- }
13
-
14
- get startMessage() {
15
- return 'Generating Prisma client...';
16
- }
17
-
18
- get successMessage() {
19
- return 'Successfully generated Prisma client';
20
- }
21
-
22
- async generate(context: Context) {
23
- // generate prisma schema
24
- const schemaFile = await new PrismaSchemaGenerator(context).generate();
25
-
26
- // run prisma generate and install @prisma/client
27
- await this.generatePrismaClient(schemaFile);
28
-
29
- // generate prisma query guard
30
- await new QueryGuardGenerator(context).generate();
31
-
32
- return [];
33
- }
34
-
35
- private async generatePrismaClient(schemaFile: string) {
36
- try {
37
- execSync(`npx prisma generate --schema "${schemaFile}"`);
38
- } catch {
39
- throw new GeneratorError(
40
- `Failed to generate client code with Prisma. Check errors above for clues.\nThis normally shouldn't happen. Please file an issue at: http://go.zenstack.dev/bug.`
41
- );
42
- }
43
- }
44
- }