zenstack 0.4.1 → 0.4.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.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publisher": "zenstack",
4
4
  "displayName": "ZenStack Language Tools",
5
5
  "description": "A toolkit for building secure CRUD apps with Next.js + Typescript",
6
- "version": "0.4.1",
6
+ "version": "0.4.2",
7
7
  "author": {
8
8
  "name": "ZenStack Team"
9
9
  },
@@ -75,6 +75,7 @@
75
75
  "langium": "^0.5.0",
76
76
  "mixpanel": "^0.17.0",
77
77
  "node-machine-id": "^1.1.12",
78
+ "ora": "^6.1.2",
78
79
  "pluralize": "^8.0.0",
79
80
  "prisma": "~4.7.0",
80
81
  "promisify": "^0.0.3",
@@ -86,7 +87,7 @@
86
87
  "vscode-languageserver": "^8.0.2",
87
88
  "vscode-languageserver-textdocument": "^1.0.7",
88
89
  "vscode-uri": "^3.0.6",
89
- "@zenstackhq/runtime": "0.4.1"
90
+ "@zenstackhq/runtime": "0.4.2"
90
91
  },
91
92
  "devDependencies": {
92
93
  "@prisma/internals": "~4.7.0",
@@ -1,7 +1,3 @@
1
- import { Context, Generator } from '../types';
2
- import { Project, SourceFile } from 'ts-morph';
3
- import * as path from 'path';
4
- import colors from 'colors';
5
1
  import {
6
2
  DataModel,
7
3
  DataModelField,
@@ -10,6 +6,9 @@ import {
10
6
  isLiteralExpr,
11
7
  LiteralExpr,
12
8
  } from '@lang/generated/ast';
9
+ import * as path from 'path';
10
+ import { Project, SourceFile } from 'ts-morph';
11
+ import { Context, Generator } from '../types';
13
12
 
14
13
  /**
15
14
  * Generates field constraint validators (run on both client and server side)
@@ -19,7 +18,15 @@ export default class FieldConstraintGenerator implements Generator {
19
18
  return 'field-constraint';
20
19
  }
21
20
 
22
- async generate(context: Context): Promise<void> {
21
+ get startMessage() {
22
+ return 'Generating field constraints...';
23
+ }
24
+
25
+ get successMessage() {
26
+ return 'Successfully generated field constraints';
27
+ }
28
+
29
+ async generate(context: Context) {
23
30
  const project = new Project();
24
31
  const sf = project.createSourceFile(
25
32
  path.join(
@@ -41,7 +48,7 @@ export default class FieldConstraintGenerator implements Generator {
41
48
  sf.formatText();
42
49
  await project.save();
43
50
 
44
- console.log(colors.blue(` ✔️ Field constraint validators generated`));
51
+ return [];
45
52
  }
46
53
 
47
54
  private generateConstraints(sf: SourceFile, model: DataModel) {
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-var-requires */
2
- import { Context } from './types';
2
+ import { Context, Generator } from './types';
3
3
  import * as fs from 'fs';
4
4
  import colors from 'colors';
5
5
  import PrismaGenerator from './prisma';
@@ -8,6 +8,7 @@ import ReactHooksGenerator from './react-hooks';
8
8
  import { TypescriptCompilation } from './tsc';
9
9
  import FieldConstraintGenerator from './field-constraint';
10
10
  import telemetry from '../telemetry';
11
+ import ora from 'ora';
11
12
 
12
13
  /**
13
14
  * ZenStack code generator
@@ -37,11 +38,8 @@ export class ZenStackGenerator {
37
38
  fs.mkdirSync(context.generatedCodeDir);
38
39
  }
39
40
 
40
- const version = require('../../package.json').version;
41
- console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));
42
-
43
41
  // TODO: plugin mechanism
44
- const generators = [
42
+ const generators: Generator[] = [
45
43
  new PrismaGenerator(),
46
44
  new ServiceGenerator(),
47
45
  new ReactHooksGenerator(),
@@ -49,6 +47,10 @@ export class ZenStackGenerator {
49
47
  new TypescriptCompilation(),
50
48
  ];
51
49
 
50
+ const version = require('../../package.json').version;
51
+ console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));
52
+
53
+ const warnings: string[] = [];
52
54
  for (const generator of generators) {
53
55
  if (
54
56
  includeGenerators &&
@@ -57,6 +59,7 @@ export class ZenStackGenerator {
57
59
  continue;
58
60
  }
59
61
 
62
+ const spinner = ora(generator.startMessage).start();
60
63
  await telemetry.trackSpan(
61
64
  'cli:generator:start',
62
65
  'cli:generator:complete',
@@ -64,8 +67,12 @@ export class ZenStackGenerator {
64
67
  {
65
68
  generator: generator.name,
66
69
  },
67
- () => generator.generate(context)
70
+ async () => {
71
+ const genWarnings = await generator.generate(context);
72
+ warnings.push(...genWarnings);
73
+ }
68
74
  );
75
+ spinner.succeed(`${colors.cyan(generator.successMessage)}`);
69
76
  }
70
77
 
71
78
  console.log(
@@ -73,5 +80,7 @@ export class ZenStackGenerator {
73
80
  colors.bold('👻 All generators completed successfully!')
74
81
  )
75
82
  );
83
+
84
+ warnings.forEach((w) => console.warn(colors.yellow(w)));
76
85
  }
77
86
  }
@@ -1,8 +1,7 @@
1
- import colors from 'colors';
2
- import { Context, Generator, GeneratorError } from '../types';
3
1
  import { execSync } from '../../utils/exec-utils';
4
- import PrismaSchemaGenerator from './schema-generator';
2
+ import { Context, Generator, GeneratorError } from '../types';
5
3
  import QueryGuardGenerator from './query-guard-generator';
4
+ import PrismaSchemaGenerator from './schema-generator';
6
5
 
7
6
  /**
8
7
  * Generates Prisma schema and db client
@@ -12,7 +11,15 @@ export default class PrismaGenerator implements Generator {
12
11
  return 'prisma';
13
12
  }
14
13
 
15
- async generate(context: Context): Promise<void> {
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) {
16
23
  // generate prisma schema
17
24
  const schemaFile = await new PrismaSchemaGenerator(context).generate();
18
25
 
@@ -22,9 +29,7 @@ export default class PrismaGenerator implements Generator {
22
29
  // generate prisma query guard
23
30
  await new QueryGuardGenerator(context).generate();
24
31
 
25
- console.log(
26
- colors.blue(` ✔️ Prisma schema and query guard generated`)
27
- );
32
+ return [];
28
33
  }
29
34
 
30
35
  private async generatePrismaClient(schemaFile: string) {
@@ -1,10 +1,9 @@
1
- import { Context, Generator } from '../types';
2
- import { Project } from 'ts-morph';
3
- import * as path from 'path';
4
- import { paramCase } from 'change-case';
5
1
  import { DataModel, isDataModel } from '@lang/generated/ast';
6
- import colors from 'colors';
2
+ import { paramCase } from 'change-case';
3
+ import * as path from 'path';
4
+ import { Project } from 'ts-morph';
7
5
  import { API_ROUTE_NAME, RUNTIME_PACKAGE } from '../constants';
6
+ import { Context, Generator } from '../types';
8
7
 
9
8
  /**
10
9
  * Generate react data query hooks code
@@ -14,9 +13,18 @@ export default class ReactHooksGenerator implements Generator {
14
13
  return 'react-hooks';
15
14
  }
16
15
 
17
- async generate(context: Context): Promise<void> {
16
+ get startMessage() {
17
+ return 'Generating React hooks...';
18
+ }
19
+
20
+ get successMessage(): string {
21
+ return 'Successfully generated React hooks';
22
+ }
23
+
24
+ async generate(context: Context) {
18
25
  const project = new Project();
19
26
  const models: DataModel[] = [];
27
+ const warnings: string[] = [];
20
28
 
21
29
  for (const model of context.schema.declarations.filter(
22
30
  (d): d is DataModel => isDataModel(d)
@@ -25,10 +33,8 @@ export default class ReactHooksGenerator implements Generator {
25
33
  (attr) => attr.decl.ref?.name === '@@allow'
26
34
  );
27
35
  if (!hasAllowRule) {
28
- console.warn(
29
- colors.yellow(
30
- `Not generating hooks for "${model.name}" because it doesn't have any @@allow rule`
31
- )
36
+ warnings.push(
37
+ `Not generating hooks for "${model.name}" because it doesn't have any @@allow rule`
32
38
  );
33
39
  } else {
34
40
  models.push(model);
@@ -40,8 +46,7 @@ export default class ReactHooksGenerator implements Generator {
40
46
  models.forEach((d) => this.generateModelHooks(project, context, d));
41
47
 
42
48
  await project.save();
43
-
44
- console.log(colors.blue(' ✔️ React hooks generated'));
49
+ return warnings;
45
50
  }
46
51
 
47
52
  private getValidator(model: DataModel, mode: 'create' | 'update') {
@@ -1,6 +1,5 @@
1
1
  import { DataModel, isDataModel } from '@lang/generated/ast';
2
2
  import { camelCase } from 'change-case';
3
- import colors from 'colors';
4
3
  import * as path from 'path';
5
4
  import { Project } from 'ts-morph';
6
5
  import { RUNTIME_PACKAGE } from '../constants';
@@ -14,7 +13,15 @@ export default class ServiceGenerator implements Generator {
14
13
  return 'service';
15
14
  }
16
15
 
17
- async generate(context: Context): Promise<void> {
16
+ get startMessage() {
17
+ return 'Generating ZenStack service...';
18
+ }
19
+
20
+ get successMessage() {
21
+ return 'Successfully generated ZenStack service';
22
+ }
23
+
24
+ async generate(context: Context) {
18
25
  const project = new Project();
19
26
  const sf = project.createSourceFile(
20
27
  path.join(context.generatedCodeDir, 'src/index.ts'),
@@ -101,6 +108,6 @@ export default class ServiceGenerator implements Generator {
101
108
  sf.formatText();
102
109
  await project.save();
103
110
 
104
- console.log(colors.blue(` ✔️ ZenStack service generated`));
111
+ return [];
105
112
  }
106
113
  }
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable @typescript-eslint/no-var-requires */
2
- import colors from 'colors';
3
2
  import * as fs from 'fs';
4
3
  import path from 'path';
5
4
  import { execSync } from '../../utils/exec-utils';
@@ -10,6 +9,14 @@ export class TypescriptCompilation implements Generator {
10
9
  return 'tsc';
11
10
  }
12
11
 
12
+ get startMessage() {
13
+ return 'Transpiling generated code...';
14
+ }
15
+
16
+ get successMessage() {
17
+ return 'Successfully transpiled all generated code';
18
+ }
19
+
13
20
  async generate(context: Context) {
14
21
  // generate package.json
15
22
  const packageJson = require(path.join(
@@ -47,6 +54,6 @@ export class TypescriptCompilation implements Generator {
47
54
  );
48
55
  }
49
56
 
50
- console.log(colors.blue(' ✔️ Typescript source files transpiled'));
57
+ return [];
51
58
  }
52
59
  }
@@ -8,7 +8,9 @@ export interface Context {
8
8
 
9
9
  export interface Generator {
10
10
  get name(): string;
11
- generate(context: Context): Promise<void>;
11
+ get startMessage(): string;
12
+ get successMessage(): string;
13
+ generate(context: Context): Promise<string[]>;
12
14
  }
13
15
 
14
16
  export class GeneratorError extends Error {