zenstack 0.2.9 → 0.2.11

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": "ZenStack is a toolkit that simplifies full-stack development",
6
- "version": "0.2.9",
6
+ "version": "0.2.11",
7
7
  "author": {
8
8
  "name": "ZenStack Team"
9
9
  },
@@ -20,7 +20,7 @@
20
20
  "url": "https://github.com/zenstackhq/zenstack"
21
21
  },
22
22
  "engines": {
23
- "vscode": "^1.72.0"
23
+ "vscode": "^1.56.0"
24
24
  },
25
25
  "categories": [
26
26
  "Programming Languages"
@@ -64,7 +64,7 @@
64
64
  },
65
65
  "main": "./bundle/extension.js",
66
66
  "dependencies": {
67
- "@zenstackhq/internal": "0.2.9",
67
+ "@zenstackhq/internal": "0.2.11",
68
68
  "change-case": "^4.1.2",
69
69
  "chevrotain": "^9.1.0",
70
70
  "colors": "^1.4.0",
@@ -88,12 +88,12 @@
88
88
  "@types/pluralize": "^0.0.29",
89
89
  "@types/tmp": "^0.2.3",
90
90
  "@types/uuid": "^8.3.4",
91
- "@types/vscode": "^1.72.0",
92
- "@typescript-eslint/eslint-plugin": "^4.33.0",
93
- "@typescript-eslint/parser": "^4.33.0",
91
+ "@types/vscode": "^1.56.0",
92
+ "@typescript-eslint/eslint-plugin": "^5.42.0",
93
+ "@typescript-eslint/parser": "^5.42.0",
94
94
  "concurrently": "^7.4.0",
95
95
  "esbuild": "^0.15.12",
96
- "eslint": "^7.32.0",
96
+ "eslint": "^8.27.0",
97
97
  "jest": "^29.2.1",
98
98
  "langium-cli": "^0.5.0",
99
99
  "tmp": "^0.2.1",
@@ -1,10 +1,15 @@
1
1
  import { STD_LIB_MODULE_NAME } from '@lang/constants';
2
2
  import { Model } from '@lang/generated/ast';
3
+ import { createZModelServices } from '@lang/zmodel-module';
3
4
  import colors from 'colors';
4
5
  import fs from 'fs';
5
6
  import { LangiumServices } from 'langium';
7
+ import { NodeFileSystem } from 'langium/node';
6
8
  import path from 'path';
9
+ import { ZenStackGenerator } from '../generator';
7
10
  import { URI } from 'vscode-uri';
11
+ import { GENERATED_CODE_PATH } from '../generator/constants';
12
+ import { Context, GeneratorError } from '../generator/types';
8
13
 
9
14
  /**
10
15
  * Loads a zmodel document from a file.
@@ -69,3 +74,32 @@ export async function loadDocument(
69
74
 
70
75
  return document.parseResult.value as Model;
71
76
  }
77
+
78
+ export async function runGenerator(
79
+ options: { schema: string },
80
+ includedGenerators?: string[],
81
+ clearOutput = true
82
+ ) {
83
+ const services = createZModelServices(NodeFileSystem).ZModel;
84
+ const model = await loadDocument(options.schema, services);
85
+
86
+ const context: Context = {
87
+ schema: model,
88
+ outDir: path.dirname(options.schema),
89
+ // TODO: make this configurable
90
+ generatedCodeDir: GENERATED_CODE_PATH,
91
+ };
92
+
93
+ try {
94
+ await new ZenStackGenerator().generate(
95
+ context,
96
+ includedGenerators,
97
+ clearOutput
98
+ );
99
+ } catch (err) {
100
+ if (err instanceof GeneratorError) {
101
+ console.error(colors.red(err.message));
102
+ process.exit(1);
103
+ }
104
+ }
105
+ }
package/src/cli/index.ts CHANGED
@@ -1,38 +1,16 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { Command, Option } from 'commander';
3
- import { NodeFileSystem } from 'langium/node';
4
3
  import { ZModelLanguageMetaData } from '../language-server/generated/module';
5
- import { createZModelServices } from '../language-server/zmodel-module';
6
- import { Context, GeneratorError } from '../generator/types';
7
- import { ZenStackGenerator } from '../generator';
8
- import { GENERATED_CODE_PATH } from '../generator/constants';
9
4
  import colors from 'colors';
10
5
  import { execSync } from '../utils/exec-utils';
11
6
  import { paramCase } from 'change-case';
12
7
  import path from 'path';
13
- import { loadDocument } from './cli-util';
8
+ import { runGenerator } from './cli-util';
14
9
 
15
10
  export const generateAction = async (options: {
16
11
  schema: string;
17
12
  }): Promise<void> => {
18
- const services = createZModelServices(NodeFileSystem).ZModel;
19
- const model = await loadDocument(options.schema, services);
20
-
21
- const context: Context = {
22
- schema: model,
23
- outDir: path.dirname(options.schema),
24
- // TODO: make this configurable
25
- generatedCodeDir: GENERATED_CODE_PATH,
26
- };
27
-
28
- try {
29
- await new ZenStackGenerator().generate(context);
30
- } catch (err) {
31
- if (err instanceof GeneratorError) {
32
- console.error(colors.red(err.message));
33
- process.exit(1);
34
- }
35
- }
13
+ await runGenerator(options);
36
14
  };
37
15
 
38
16
  function prismaAction(prismaCmd: string): (...args: any[]) => Promise<void> {
@@ -50,6 +28,10 @@ function prismaAction(prismaCmd: string): (...args: any[]) => Promise<void> {
50
28
  );
51
29
  })
52
30
  .join(' ');
31
+
32
+ // regenerate prisma schema first
33
+ await runGenerator(options, ['prisma'], false);
34
+
53
35
  const prismaExec = `npx prisma ${prismaCmd} ${command.name()} ${optStr}`;
54
36
  console.log(prismaExec);
55
37
  try {
@@ -1,13 +1,12 @@
1
1
  /* eslint-disable @typescript-eslint/no-var-requires */
2
- import { Context, GeneratorError } from './types';
2
+ import { Context } from './types';
3
3
  import * as fs from 'fs';
4
4
  import colors from 'colors';
5
5
  import PrismaGenerator from './prisma';
6
6
  import ServiceGenerator from './service';
7
7
  import ReactHooksGenerator from './react-hooks';
8
8
  import NextAuthGenerator from './next-auth';
9
- import path from 'path';
10
- import { execSync } from '../utils/exec-utils';
9
+ import { TypescriptCompilation } from './tsc';
11
10
 
12
11
  /**
13
12
  * ZenStack code generator
@@ -16,20 +15,26 @@ export class ZenStackGenerator {
16
15
  /**
17
16
  * Runs a series of nested generators
18
17
  */
19
- async generate(context: Context): Promise<void> {
20
- // folder that stores generated prisma schema and migrations
18
+ async generate(
19
+ context: Context,
20
+ includeGenerators?: string[],
21
+ clearOutput = true
22
+ ): Promise<void> {
23
+ // ensure folder that stores generated prisma schema and migrations
21
24
  if (!fs.existsSync(context.outDir)) {
22
25
  fs.mkdirSync(context.outDir);
23
26
  }
24
27
 
25
- // folder that stores generated zenstack code
26
- if (fs.existsSync(context.generatedCodeDir)) {
27
- fs.rmSync(context.generatedCodeDir, {
28
- force: true,
29
- recursive: true,
30
- });
28
+ if (clearOutput) {
29
+ // recreate folder that stores generated zenstack code
30
+ if (fs.existsSync(context.generatedCodeDir)) {
31
+ fs.rmSync(context.generatedCodeDir, {
32
+ force: true,
33
+ recursive: true,
34
+ });
35
+ }
36
+ fs.mkdirSync(context.generatedCodeDir);
31
37
  }
32
- fs.mkdirSync(context.generatedCodeDir);
33
38
 
34
39
  const version = require('../../package.json').version;
35
40
  console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));
@@ -40,49 +45,19 @@ export class ZenStackGenerator {
40
45
  new ServiceGenerator(),
41
46
  new ReactHooksGenerator(),
42
47
  new NextAuthGenerator(),
48
+ new TypescriptCompilation(),
43
49
  ];
44
50
 
45
51
  for (const generator of generators) {
52
+ if (
53
+ includeGenerators &&
54
+ !includeGenerators.includes(generator.name)
55
+ ) {
56
+ continue;
57
+ }
46
58
  await generator.generate(context);
47
59
  }
48
60
 
49
- // generate package.json
50
- const packageJson = require(path.join(
51
- __dirname,
52
- '../res',
53
- 'package.template.json'
54
- ));
55
- fs.writeFileSync(
56
- path.join(context.generatedCodeDir, 'package.json'),
57
- JSON.stringify(packageJson, undefined, 4)
58
- );
59
-
60
- // compile ts sources
61
- const tsConfig = require(path.join(
62
- __dirname,
63
- '../res',
64
- 'tsconfig.template.json'
65
- ));
66
- fs.writeFileSync(
67
- path.join(context.generatedCodeDir, 'tsconfig.json'),
68
- JSON.stringify(tsConfig, undefined, 4)
69
- );
70
-
71
- try {
72
- execSync(
73
- `npx tsc -p "${path.join(
74
- context.generatedCodeDir,
75
- 'tsconfig.json'
76
- )}"`
77
- );
78
- } catch {
79
- throw new GeneratorError(
80
- 'Something went wrong, generated runtime code failed to compile...\nPlease check errors above.'
81
- );
82
- }
83
-
84
- console.log(colors.blue(' ✔️ Typescript source files transpiled'));
85
-
86
61
  console.log(
87
62
  colors.green(
88
63
  colors.bold('👻 All generators completed successfully!')
@@ -9,6 +9,10 @@ import { execSync } from 'child_process';
9
9
  * Generates NextAuth adaptor code
10
10
  */
11
11
  export default class NextAuthGenerator implements Generator {
12
+ get name() {
13
+ return 'next-auth';
14
+ }
15
+
12
16
  private findModel(schema: Model, name: string) {
13
17
  return schema.declarations.find(
14
18
  (d) => isDataModel(d) && d.name === name
@@ -8,6 +8,10 @@ import QueryGuardGenerator from './query-guard-generator';
8
8
  * Generates Prisma schema and db client
9
9
  */
10
10
  export default class PrismaGenerator implements Generator {
11
+ get name() {
12
+ return 'prisma';
13
+ }
14
+
11
15
  async generate(context: Context): Promise<void> {
12
16
  // generate prisma schema
13
17
  const schemaFile = await new PrismaSchemaGenerator(context).generate();
@@ -160,7 +160,8 @@ export default class QueryGuardGenerator {
160
160
  .addBody();
161
161
 
162
162
  func.addStatements(
163
- `const user = context.user ?? { id: '${UNKNOWN_USER_ID}' };`
163
+ // make suer user id is always available
164
+ `const user = context.user?.id ? context.user : { ...context.user, id: '${UNKNOWN_USER_ID}' };`
164
165
  );
165
166
 
166
167
  // r = <guard object>;
@@ -11,6 +11,10 @@ import { API_ROUTE_NAME, INTERNAL_PACKAGE } from '../constants';
11
11
  * Generate react data query hooks code
12
12
  */
13
13
  export default class ReactHooksGenerator implements Generator {
14
+ get name() {
15
+ return 'react-hooks';
16
+ }
17
+
14
18
  async generate(context: Context): Promise<void> {
15
19
  const project = new Project();
16
20
 
@@ -8,6 +8,10 @@ import { INTERNAL_PACKAGE } from '../constants';
8
8
  * Generates ZenStack service code
9
9
  */
10
10
  export default class ServiceGenerator implements Generator {
11
+ get name() {
12
+ return 'service';
13
+ }
14
+
11
15
  async generate(context: Context): Promise<void> {
12
16
  const project = new Project();
13
17
  const sf = project.createSourceFile(
@@ -0,0 +1,52 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
2
+ import colors from 'colors';
3
+ import * as fs from 'fs';
4
+ import path from 'path';
5
+ import { execSync } from '../../utils/exec-utils';
6
+ import { Context, Generator, GeneratorError } from '../types';
7
+
8
+ export class TypescriptCompilation implements Generator {
9
+ get name(): string {
10
+ return 'tsc';
11
+ }
12
+
13
+ async generate(context: Context) {
14
+ // generate package.json
15
+ const packageJson = require(path.join(
16
+ __dirname,
17
+ '../res',
18
+ 'package.template.json'
19
+ ));
20
+
21
+ fs.writeFileSync(
22
+ path.join(context.generatedCodeDir, 'package.json'),
23
+ JSON.stringify(packageJson, undefined, 4)
24
+ );
25
+
26
+ // compile ts sources
27
+ const tsConfig = require(path.join(
28
+ __dirname,
29
+ '../res',
30
+ 'tsconfig.template.json'
31
+ ));
32
+ fs.writeFileSync(
33
+ path.join(context.generatedCodeDir, 'tsconfig.json'),
34
+ JSON.stringify(tsConfig, undefined, 4)
35
+ );
36
+
37
+ try {
38
+ execSync(
39
+ `npx tsc -p "${path.join(
40
+ context.generatedCodeDir,
41
+ 'tsconfig.json'
42
+ )}"`
43
+ );
44
+ } catch {
45
+ throw new GeneratorError(
46
+ 'Something went wrong, generated runtime code failed to compile...\nPlease check errors above.'
47
+ );
48
+ }
49
+
50
+ console.log(colors.blue(' ✔️ Typescript source files transpiled'));
51
+ }
52
+ }
@@ -7,6 +7,7 @@ export interface Context {
7
7
  }
8
8
 
9
9
  export interface Generator {
10
+ get name(): string;
10
11
  generate(context: Context): Promise<void>;
11
12
  }
12
13