zenstack 0.1.47 → 0.1.50
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/LICENSE.md +9 -0
- package/bin/cli +1 -1
- package/bundle/asset/logo-dark-256.png +0 -0
- package/bundle/asset/logo-dark.png +0 -0
- package/bundle/asset/logo-light-256.png +0 -0
- package/bundle/asset/logo-light.png +0 -0
- package/bundle/cli/index.js +6849 -0
- package/bundle/cli/index.js.map +7 -0
- package/bundle/extension.js +39 -0
- package/bundle/extension.js.map +7 -0
- package/bundle/language-server/main.js +6105 -0
- package/bundle/language-server/main.js.map +7 -0
- package/{out/generator → bundle/res}/package.template.json +0 -0
- package/bundle/res/stdlib.zmodel +101 -0
- package/{out/generator → bundle/res}/tsconfig.template.json +0 -0
- package/package.json +38 -14
- package/src/cli/cli-util.ts +71 -0
- package/src/cli/index.ts +182 -0
- package/src/extension.ts +76 -0
- package/src/generator/constants.ts +5 -0
- package/src/generator/index.ts +102 -0
- package/{out/generator/next-auth/index.js → src/generator/next-auth/index.ts} +49 -58
- package/src/generator/prisma/expression-writer.ts +360 -0
- package/src/generator/prisma/index.ts +35 -0
- package/src/generator/prisma/prisma-builder.ts +370 -0
- package/src/generator/prisma/query-gard-generator.ts +213 -0
- package/src/generator/prisma/schema-generator.ts +305 -0
- package/src/generator/prisma/typescript-expression-transformer.ts +108 -0
- package/src/generator/react-hooks/index.ts +184 -0
- package/src/generator/service/index.ts +110 -0
- package/src/generator/types.ts +17 -0
- package/src/generator/utils.ts +18 -0
- package/src/language-server/constants.ts +28 -0
- package/src/language-server/generated/ast.ts +616 -0
- package/{out/language-server/generated/grammar.js → src/language-server/generated/grammar.ts} +5 -8
- package/src/language-server/generated/module.ts +24 -0
- package/src/language-server/langium-ext.d.ts +10 -0
- package/src/language-server/lsp/zmodel-definition-provider.ts +87 -0
- package/src/language-server/main.ts +13 -0
- package/src/language-server/types.ts +25 -0
- package/src/language-server/validator/attribute-validator.ts +11 -0
- package/src/language-server/validator/datamodel-validator.ts +311 -0
- package/src/language-server/validator/datasource-validator.ts +102 -0
- package/src/language-server/validator/enum-validator.ts +14 -0
- package/src/language-server/validator/schema-validator.ts +31 -0
- package/src/language-server/validator/utils.ts +158 -0
- package/src/language-server/validator/zmodel-validator.ts +84 -0
- package/src/language-server/zmodel-linker.ts +446 -0
- package/src/language-server/zmodel-module.ts +136 -0
- package/src/language-server/zmodel-scope.ts +45 -0
- package/src/language-server/zmodel-workspace-manager.ts +23 -0
- package/src/language-server/zmodel.langium +197 -0
- package/{out/cli → src/res}/package.template.json +2 -3
- package/src/res/stdlib.zmodel +101 -0
- package/{out/cli → src/res}/tsconfig.template.json +1 -1
- package/src/utils/exec-utils.ts +8 -0
- package/src/utils/indent-string.ts +9 -0
- package/LICENSE +0 -21
- package/out/cli/cli-util.js +0 -64
- package/out/cli/cli-util.js.map +0 -1
- package/out/cli/generator.js +0 -1
- package/out/cli/generator.js.map +0 -1
- package/out/cli/index.js +0 -124
- package/out/cli/index.js.map +0 -1
- package/out/extension.js +0 -81
- package/out/extension.js.map +0 -1
- package/out/generator/constants.js +0 -9
- package/out/generator/constants.js.map +0 -1
- package/out/generator/data-server/index.js +0 -1
- package/out/generator/data-server/index.js.map +0 -1
- package/out/generator/index.js +0 -98
- package/out/generator/index.js.map +0 -1
- package/out/generator/next-auth/index.js.map +0 -1
- package/out/generator/prisma/expression-writer.js +0 -287
- package/out/generator/prisma/expression-writer.js.map +0 -1
- package/out/generator/prisma/index.js +0 -44
- package/out/generator/prisma/index.js.map +0 -1
- package/out/generator/prisma/plain-expression-builder.js +0 -69
- package/out/generator/prisma/plain-expression-builder.js.map +0 -1
- package/out/generator/prisma/prisma-builder.js +0 -307
- package/out/generator/prisma/prisma-builder.js.map +0 -1
- package/out/generator/prisma/query-gard-generator.js +0 -159
- package/out/generator/prisma/query-gard-generator.js.map +0 -1
- package/out/generator/prisma/schema-generator.js +0 -193
- package/out/generator/prisma/schema-generator.js.map +0 -1
- package/out/generator/query-guard/index.js +0 -2
- package/out/generator/query-guard/index.js.map +0 -1
- package/out/generator/react-hooks/index.js +0 -179
- package/out/generator/react-hooks/index.js.map +0 -1
- package/out/generator/server/data/data-generator.js +0 -376
- package/out/generator/server/data/data-generator.js.map +0 -1
- package/out/generator/server/data/expression-writer.js +0 -287
- package/out/generator/server/data/expression-writer.js.map +0 -1
- package/out/generator/server/data/plain-expression-builder.js +0 -69
- package/out/generator/server/data/plain-expression-builder.js.map +0 -1
- package/out/generator/server/data-generator.js +0 -82
- package/out/generator/server/data-generator.js.map +0 -1
- package/out/generator/server/expression-writer.js +0 -1
- package/out/generator/server/expression-writer.js.map +0 -1
- package/out/generator/server/function/function-generator.js +0 -50
- package/out/generator/server/function/function-generator.js.map +0 -1
- package/out/generator/server/function-generator.js +0 -13
- package/out/generator/server/function-generator.js.map +0 -1
- package/out/generator/server/index.js +0 -88
- package/out/generator/server/index.js.map +0 -1
- package/out/generator/server/js-expression-builder.js +0 -1
- package/out/generator/server/js-expression-builder.js.map +0 -1
- package/out/generator/server/plain-expression-builder.js +0 -1
- package/out/generator/server/plain-expression-builder.js.map +0 -1
- package/out/generator/server/server-code-generator.js +0 -3
- package/out/generator/server/server-code-generator.js.map +0 -1
- package/out/generator/server/server-code-writer.js +0 -1
- package/out/generator/server/server-code-writer.js.map +0 -1
- package/out/generator/service/index.js +0 -133
- package/out/generator/service/index.js.map +0 -1
- package/out/generator/types.js +0 -10
- package/out/generator/types.js.map +0 -1
- package/out/generator/utils.js +0 -10
- package/out/generator/utils.js.map +0 -1
- package/out/langium-ext.js +0 -3
- package/out/langium-ext.js.map +0 -1
- package/out/language-server/constants.js +0 -20
- package/out/language-server/constants.js.map +0 -1
- package/out/language-server/generated/ast.js +0 -390
- package/out/language-server/generated/ast.js.map +0 -1
- package/out/language-server/generated/grammar.js.map +0 -1
- package/out/language-server/generated/module.js +0 -23
- package/out/language-server/generated/module.js.map +0 -1
- package/out/language-server/langium-ext.js +0 -3
- package/out/language-server/langium-ext.js.map +0 -1
- package/out/language-server/main.js +0 -13
- package/out/language-server/main.js.map +0 -1
- package/out/language-server/stdlib.zmodel +0 -23
- package/out/language-server/types.js +0 -3
- package/out/language-server/types.js.map +0 -1
- package/out/language-server/validator/attribute-validator copy.js +0 -12
- package/out/language-server/validator/attribute-validator copy.js.map +0 -1
- package/out/language-server/validator/attribute-validator.js +0 -7
- package/out/language-server/validator/attribute-validator.js.map +0 -1
- package/out/language-server/validator/datamodel-validator.js +0 -199
- package/out/language-server/validator/datamodel-validator.js.map +0 -1
- package/out/language-server/validator/datasource-validator copy.js +0 -77
- package/out/language-server/validator/datasource-validator copy.js.map +0 -1
- package/out/language-server/validator/datasource-validator.js +0 -77
- package/out/language-server/validator/datasource-validator.js.map +0 -1
- package/out/language-server/validator/enum-validator.js +0 -10
- package/out/language-server/validator/enum-validator.js.map +0 -1
- package/out/language-server/validator/model-validator.js +0 -21
- package/out/language-server/validator/model-validator.js.map +0 -1
- package/out/language-server/validator/schema-validator.js +0 -21
- package/out/language-server/validator/schema-validator.js.map +0 -1
- package/out/language-server/validator/utils.js +0 -106
- package/out/language-server/validator/utils.js.map +0 -1
- package/out/language-server/validator/zmodel-validator.js +0 -52
- package/out/language-server/validator/zmodel-validator.js.map +0 -1
- package/out/language-server/zmodel-index.js +0 -11
- package/out/language-server/zmodel-index.js.map +0 -1
- package/out/language-server/zmodel-linker.js +0 -249
- package/out/language-server/zmodel-linker.js.map +0 -1
- package/out/language-server/zmodel-module.js +0 -46
- package/out/language-server/zmodel-module.js.map +0 -1
- package/out/language-server/zmodel-scope.js +0 -41
- package/out/language-server/zmodel-scope.js.map +0 -1
- package/out/language-server/zmodel-validator.js +0 -35
- package/out/language-server/zmodel-validator.js.map +0 -1
- package/out/utils/exec-utils.js +0 -9
- package/out/utils/exec-utils.js.map +0 -1
- package/out/utils/indent-string.js +0 -9
- package/out/utils/indent-string.js.map +0 -1
|
File without changes
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Enum representing referential integrity related actions
|
|
3
|
+
*/
|
|
4
|
+
enum ReferentialAction {
|
|
5
|
+
/*
|
|
6
|
+
* Used with "onDelete": deleting a referenced record will trigger the deletion of referencing record.
|
|
7
|
+
* Used with "onUpdate": updates the relation scalar fields if the referenced scalar fields of the dependent record are updated.
|
|
8
|
+
*/
|
|
9
|
+
Cascade
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* Reads value from an environment variable
|
|
14
|
+
*/
|
|
15
|
+
function env(name: String): String {}
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* Gets thec current login user
|
|
19
|
+
*/
|
|
20
|
+
function auth(): Any {}
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Gets current date-time (as DateTime type)
|
|
24
|
+
*/
|
|
25
|
+
function now(): DateTime {}
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
* Generate a globally unique identifier based on the UUID spec
|
|
29
|
+
*/
|
|
30
|
+
function uuid(): String {}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Generate a globally unique identifier based on the CUID spec
|
|
34
|
+
*/
|
|
35
|
+
function cuid(): String {}
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
* Create a sequence of integers in the underlying database and assign the incremented
|
|
39
|
+
* values to the ID values of the created records based on the sequence
|
|
40
|
+
*/
|
|
41
|
+
function autoincrement(): Int {}
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* Represents default values that cannot be expressed in the Prisma schema (such as random()).
|
|
45
|
+
*/
|
|
46
|
+
function dbgenerated(expr: String): Any {}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* Defines an ID on the model
|
|
50
|
+
*/
|
|
51
|
+
attribute @id(map: String?)
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Defines a default value for a field
|
|
55
|
+
*/
|
|
56
|
+
attribute @default(_ value: ContextType)
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* Defines a unique constraint for this field
|
|
60
|
+
*/
|
|
61
|
+
attribute @unique(map: String?)
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* Defines a compound unique constraint for the specified fields
|
|
65
|
+
*/
|
|
66
|
+
attribute @@unique(_ fields: FieldReference[], name: String?, map: String?)
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* Defines an index in the database
|
|
70
|
+
*/
|
|
71
|
+
attribute @@index(_ fields: FieldReference[], map: String?)
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* Defines meta information about the relation
|
|
75
|
+
*/
|
|
76
|
+
attribute @relation(_ name: String?, fields: FieldReference[]?, references: FieldReference[]?, onDelete: ReferentialAction?, onUpdate: ReferentialAction?, map: String?)
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
* Maps a field name or enum value from the schema to a column with a different name in the database
|
|
80
|
+
*/
|
|
81
|
+
attribute @map(_ name: String)
|
|
82
|
+
|
|
83
|
+
/*
|
|
84
|
+
* Maps the schema model name to a table with a different name, or an enum name to a different underlying enum in the database
|
|
85
|
+
*/
|
|
86
|
+
attribute @@map(_ name: String)
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* Automatically stores the time when a record was last updated
|
|
90
|
+
*/
|
|
91
|
+
attribute @updatedAt()
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* Defines an access policy that allows a set of operations when the given condition is true
|
|
95
|
+
*/
|
|
96
|
+
attribute @@allow(_ operation: String, _ condition: Boolean)
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* Defines an access policy that denies a set of operations when the given condition is true
|
|
100
|
+
*/
|
|
101
|
+
attribute @@deny(_ operation: String, _ condition: Boolean)
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zenstack",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"publisher": "zenstack",
|
|
4
|
+
"displayName": "ZenStack Language Tools",
|
|
5
|
+
"description": "ZenStack is a toolkit that simplifies full-stack development",
|
|
6
|
+
"version": "0.1.50",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "ymc9"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"fullstack",
|
|
12
|
+
"react",
|
|
13
|
+
"typescript",
|
|
14
|
+
"data modeling"
|
|
15
|
+
],
|
|
16
|
+
"preview": true,
|
|
17
|
+
"icon": "asset/logo-light-256.png",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/zenstackhq/zenstack"
|
|
21
|
+
},
|
|
6
22
|
"engines": {
|
|
7
|
-
"vscode": "^1.
|
|
23
|
+
"vscode": "^1.72.0"
|
|
8
24
|
},
|
|
9
25
|
"categories": [
|
|
10
26
|
"Programming Languages"
|
|
@@ -22,8 +38,8 @@
|
|
|
22
38
|
],
|
|
23
39
|
"configuration": "./language-configuration.json",
|
|
24
40
|
"icon": {
|
|
25
|
-
"light": "./asset/logo-light.png",
|
|
26
|
-
"dark": "./asset/logo-dark.png"
|
|
41
|
+
"light": "./asset/logo-light-256.png",
|
|
42
|
+
"dark": "./asset/logo-dark-256.png"
|
|
27
43
|
}
|
|
28
44
|
}
|
|
29
45
|
],
|
|
@@ -40,14 +56,15 @@
|
|
|
40
56
|
],
|
|
41
57
|
"files": [
|
|
42
58
|
"bin",
|
|
43
|
-
"
|
|
59
|
+
"src",
|
|
60
|
+
"bundle"
|
|
44
61
|
],
|
|
45
62
|
"bin": {
|
|
46
63
|
"zenstack": "./bin/cli"
|
|
47
64
|
},
|
|
48
|
-
"main": "./
|
|
65
|
+
"main": "./bundle/extension.js",
|
|
49
66
|
"dependencies": {
|
|
50
|
-
"@zenstackhq/internal": "0.1.
|
|
67
|
+
"@zenstackhq/internal": "0.1.22",
|
|
51
68
|
"change-case": "^4.1.2",
|
|
52
69
|
"chevrotain": "^9.1.0",
|
|
53
70
|
"colors": "^1.4.0",
|
|
@@ -61,6 +78,7 @@
|
|
|
61
78
|
"vscode-jsonrpc": "^8.0.2",
|
|
62
79
|
"vscode-languageclient": "^8.0.2",
|
|
63
80
|
"vscode-languageserver": "^8.0.2",
|
|
81
|
+
"vscode-languageserver-textdocument": "^1.0.7",
|
|
64
82
|
"vscode-uri": "^3.0.6"
|
|
65
83
|
},
|
|
66
84
|
"devDependencies": {
|
|
@@ -74,6 +92,7 @@
|
|
|
74
92
|
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
75
93
|
"@typescript-eslint/parser": "^4.33.0",
|
|
76
94
|
"concurrently": "^7.4.0",
|
|
95
|
+
"esbuild": "^0.15.12",
|
|
77
96
|
"eslint": "^7.32.0",
|
|
78
97
|
"jest": "^29.2.1",
|
|
79
98
|
"langium-cli": "^0.5.0",
|
|
@@ -82,17 +101,22 @@
|
|
|
82
101
|
"ts-node": "^10.9.1",
|
|
83
102
|
"tsc-alias": "^1.7.0",
|
|
84
103
|
"tsconfig-paths-jest": "^0.0.1",
|
|
85
|
-
"typescript": "^4.8.4"
|
|
104
|
+
"typescript": "^4.8.4",
|
|
105
|
+
"vsce": "^2.13.0"
|
|
86
106
|
},
|
|
87
107
|
"scripts": {
|
|
88
|
-
"vscode:
|
|
89
|
-
"
|
|
90
|
-
"
|
|
108
|
+
"vscode:publish": "vsce publish --no-dependencies",
|
|
109
|
+
"vscode:prepublish": "pnpm lint && pnpm build && pnpm bundle",
|
|
110
|
+
"vscode:package": "vsce package --no-dependencies",
|
|
111
|
+
"build": "pnpm langium:generate && tsc --noEmit",
|
|
112
|
+
"bundle": "node build/bundle.js --minify",
|
|
113
|
+
"bundle-watch": "node build/bundle.js --watch",
|
|
114
|
+
"ts:watch": "tsc --watch --noEmit",
|
|
91
115
|
"tsc-alias:watch": "tsc-alias --watch",
|
|
92
116
|
"lint": "eslint src --ext ts",
|
|
93
117
|
"langium:generate": "langium generate",
|
|
94
118
|
"langium:watch": "langium generate --watch",
|
|
95
|
-
"watch": "concurrently --kill-others \"npm:langium:watch\" \"npm:
|
|
119
|
+
"watch": "concurrently --kill-others \"npm:langium:watch\" \"npm:bundle-watch\"",
|
|
96
120
|
"test": "jest"
|
|
97
121
|
}
|
|
98
122
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { STD_LIB_MODULE_NAME } from '@lang/constants';
|
|
2
|
+
import { Model } from '@lang/generated/ast';
|
|
3
|
+
import colors from 'colors';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { LangiumServices } from 'langium';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { URI } from 'vscode-uri';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Loads a zmodel document from a file.
|
|
11
|
+
* @param fileName File name
|
|
12
|
+
* @param services Language services
|
|
13
|
+
* @returns Parsed and validated AST
|
|
14
|
+
*/
|
|
15
|
+
export async function loadDocument(
|
|
16
|
+
fileName: string,
|
|
17
|
+
services: LangiumServices
|
|
18
|
+
): Promise<Model> {
|
|
19
|
+
const extensions = services.LanguageMetaData.fileExtensions;
|
|
20
|
+
if (!extensions.includes(path.extname(fileName))) {
|
|
21
|
+
console.error(
|
|
22
|
+
colors.yellow(`Please choose a file with extension: ${extensions}.`)
|
|
23
|
+
);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(fileName)) {
|
|
28
|
+
console.error(colors.red(`File ${fileName} does not exist.`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// load standard library
|
|
33
|
+
const stdLib =
|
|
34
|
+
services.shared.workspace.LangiumDocuments.getOrCreateDocument(
|
|
35
|
+
URI.file(
|
|
36
|
+
path.resolve(
|
|
37
|
+
path.join(__dirname, '../res', STD_LIB_MODULE_NAME)
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// load the document
|
|
43
|
+
const document =
|
|
44
|
+
services.shared.workspace.LangiumDocuments.getOrCreateDocument(
|
|
45
|
+
URI.file(path.resolve(fileName))
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// build the document together with standard library
|
|
49
|
+
await services.shared.workspace.DocumentBuilder.build([stdLib, document], {
|
|
50
|
+
validationChecks: 'all',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const validationErrors = (document.diagnostics ?? []).filter(
|
|
54
|
+
(e) => e.severity === 1
|
|
55
|
+
);
|
|
56
|
+
if (validationErrors.length > 0) {
|
|
57
|
+
console.error(colors.red('There are validation errors:'));
|
|
58
|
+
for (const validationError of validationErrors) {
|
|
59
|
+
console.error(
|
|
60
|
+
colors.red(
|
|
61
|
+
`line ${validationError.range.start.line + 1}: ${
|
|
62
|
+
validationError.message
|
|
63
|
+
} [${document.textDocument.getText(validationError.range)}]`
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return document.parseResult.value as Model;
|
|
71
|
+
}
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { Command, Option } from 'commander';
|
|
3
|
+
import { NodeFileSystem } from 'langium/node';
|
|
4
|
+
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
|
+
import colors from 'colors';
|
|
10
|
+
import { execSync } from '../utils/exec-utils';
|
|
11
|
+
import { paramCase } from 'change-case';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { loadDocument } from './cli-util';
|
|
14
|
+
|
|
15
|
+
export const generateAction = async (options: {
|
|
16
|
+
schema: string;
|
|
17
|
+
}): 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
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function prismaAction(prismaCmd: string): (...args: any[]) => Promise<void> {
|
|
39
|
+
return async (options: any, command: Command) => {
|
|
40
|
+
const optStr = Array.from(Object.entries<any>(options))
|
|
41
|
+
.map(([k, v]) => {
|
|
42
|
+
let optVal = v;
|
|
43
|
+
if (k === 'schema') {
|
|
44
|
+
optVal = path.join(path.dirname(v), 'schema.prisma');
|
|
45
|
+
}
|
|
46
|
+
return (
|
|
47
|
+
'--' +
|
|
48
|
+
paramCase(k) +
|
|
49
|
+
(typeof optVal === 'string' ? ` ${optVal}` : '')
|
|
50
|
+
);
|
|
51
|
+
})
|
|
52
|
+
.join(' ');
|
|
53
|
+
const prismaExec = `npx prisma ${prismaCmd} ${command.name()} ${optStr}`;
|
|
54
|
+
console.log(prismaExec);
|
|
55
|
+
try {
|
|
56
|
+
execSync(prismaExec);
|
|
57
|
+
} catch {
|
|
58
|
+
console.error(
|
|
59
|
+
colors.red(
|
|
60
|
+
'Prisma command failed to execute. See errors above.'
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default function (): void {
|
|
69
|
+
const program = new Command('zenstack');
|
|
70
|
+
|
|
71
|
+
program.version(
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
73
|
+
require('../../package.json').version,
|
|
74
|
+
'-v --version',
|
|
75
|
+
'display CLI version'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const schemaExtensions = ZModelLanguageMetaData.fileExtensions.join(', ');
|
|
79
|
+
|
|
80
|
+
program
|
|
81
|
+
.description(
|
|
82
|
+
`${colors.bold.blue(
|
|
83
|
+
'ζ'
|
|
84
|
+
)} ZenStack simplifies fullstack development by generating backend services and Typescript clients from a data model.\n\nDocumentation: https://zenstack.dev/doc.`
|
|
85
|
+
)
|
|
86
|
+
.showHelpAfterError()
|
|
87
|
+
.showSuggestionAfterError();
|
|
88
|
+
|
|
89
|
+
const schemaOption = new Option(
|
|
90
|
+
'--schema <file>',
|
|
91
|
+
`schema file (with extension ${schemaExtensions})`
|
|
92
|
+
).default('./zenstack/schema.zmodel');
|
|
93
|
+
|
|
94
|
+
//#region wraps Prisma commands
|
|
95
|
+
|
|
96
|
+
program
|
|
97
|
+
.command('generate')
|
|
98
|
+
.description(
|
|
99
|
+
'generates RESTful API and Typescript client for your data model'
|
|
100
|
+
)
|
|
101
|
+
.addOption(schemaOption)
|
|
102
|
+
.action(generateAction);
|
|
103
|
+
|
|
104
|
+
const migrate = program
|
|
105
|
+
.command('migrate')
|
|
106
|
+
.description(`wraps Prisma's ${colors.cyan('migrate')} command`);
|
|
107
|
+
|
|
108
|
+
migrate
|
|
109
|
+
.command('dev')
|
|
110
|
+
.description(
|
|
111
|
+
`alias for ${colors.cyan(
|
|
112
|
+
'prisma migrate dev'
|
|
113
|
+
)}\nCreate a migration, apply it to the database, generate db client.`
|
|
114
|
+
)
|
|
115
|
+
.addOption(schemaOption)
|
|
116
|
+
.option('--create-only', 'Create a migration without applying it')
|
|
117
|
+
.option('-n --name <name>', 'Name the migration')
|
|
118
|
+
.option('--skip-seed', 'Skip triggering seed')
|
|
119
|
+
.action(prismaAction('migrate'));
|
|
120
|
+
|
|
121
|
+
migrate
|
|
122
|
+
.command('reset')
|
|
123
|
+
.description(
|
|
124
|
+
`alias for ${colors.cyan(
|
|
125
|
+
'prisma migrate reset'
|
|
126
|
+
)}\nReset your database and apply all migrations.`
|
|
127
|
+
)
|
|
128
|
+
.addOption(schemaOption)
|
|
129
|
+
.option('--force', 'Skip the confirmation prompt')
|
|
130
|
+
.action(prismaAction('migrate'));
|
|
131
|
+
|
|
132
|
+
migrate
|
|
133
|
+
.command('deploy')
|
|
134
|
+
.description(
|
|
135
|
+
`alias for ${colors.cyan(
|
|
136
|
+
'prisma migrate deploy'
|
|
137
|
+
)}\nApply pending migrations to the database in production/staging.`
|
|
138
|
+
)
|
|
139
|
+
.addOption(schemaOption)
|
|
140
|
+
.action(prismaAction('migrate'));
|
|
141
|
+
|
|
142
|
+
migrate
|
|
143
|
+
.command('status')
|
|
144
|
+
.description(
|
|
145
|
+
`alias for ${colors.cyan(
|
|
146
|
+
'prisma migrate status'
|
|
147
|
+
)}\nCheck the status of migrations in the production/staging database.`
|
|
148
|
+
)
|
|
149
|
+
.addOption(schemaOption)
|
|
150
|
+
.action(prismaAction('migrate'));
|
|
151
|
+
|
|
152
|
+
const db = program
|
|
153
|
+
.command('db')
|
|
154
|
+
.description(`wraps Prisma's ${colors.cyan('db')} command`);
|
|
155
|
+
|
|
156
|
+
db.command('push')
|
|
157
|
+
.description(
|
|
158
|
+
`alias for ${colors.cyan(
|
|
159
|
+
'prisma db push'
|
|
160
|
+
)}\nPush the Prisma schema state to the database.`
|
|
161
|
+
)
|
|
162
|
+
.addOption(schemaOption)
|
|
163
|
+
.option('--accept-data-loss', 'Ignore data loss warnings')
|
|
164
|
+
.action(prismaAction('db'));
|
|
165
|
+
|
|
166
|
+
program
|
|
167
|
+
.command('studio')
|
|
168
|
+
.description(
|
|
169
|
+
`wraps Prisma's ${colors.cyan(
|
|
170
|
+
'studio'
|
|
171
|
+
)} command. Browse your data with Prisma Studio.`
|
|
172
|
+
)
|
|
173
|
+
.addOption(schemaOption)
|
|
174
|
+
.option('-p --port <port>', 'Port to start Studio in')
|
|
175
|
+
.option('-b --browser <browser>', 'Browser to open Studio in')
|
|
176
|
+
.option('-n --hostname', 'Hostname to bind the Express server to')
|
|
177
|
+
.action(prismaAction(''));
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
|
|
181
|
+
program.parse(process.argv);
|
|
182
|
+
}
|
package/src/extension.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import {
|
|
4
|
+
LanguageClient,
|
|
5
|
+
LanguageClientOptions,
|
|
6
|
+
ServerOptions,
|
|
7
|
+
TransportKind,
|
|
8
|
+
} from 'vscode-languageclient/node';
|
|
9
|
+
|
|
10
|
+
let client: LanguageClient;
|
|
11
|
+
|
|
12
|
+
// This function is called when the extension is activated.
|
|
13
|
+
export function activate(context: vscode.ExtensionContext): void {
|
|
14
|
+
client = startLanguageClient(context);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// This function is called when the extension is deactivated.
|
|
18
|
+
export function deactivate(): Thenable<void> | undefined {
|
|
19
|
+
if (client) {
|
|
20
|
+
return client.stop();
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function startLanguageClient(context: vscode.ExtensionContext): LanguageClient {
|
|
26
|
+
const serverModule = context.asAbsolutePath(
|
|
27
|
+
path.join('bundle', 'language-server', 'main')
|
|
28
|
+
);
|
|
29
|
+
// The debug options for the server
|
|
30
|
+
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging.
|
|
31
|
+
// By setting `process.env.DEBUG_BREAK` to a truthy value, the language server will wait until a debugger is attached.
|
|
32
|
+
const debugOptions = {
|
|
33
|
+
execArgv: [
|
|
34
|
+
'--nolazy',
|
|
35
|
+
`--inspect${process.env.DEBUG_BREAK ? '-brk' : ''}=${
|
|
36
|
+
process.env.DEBUG_SOCKET || '6009'
|
|
37
|
+
}`,
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// If the extension is launched in debug mode then the debug server options are used
|
|
42
|
+
// Otherwise the run options are used
|
|
43
|
+
const serverOptions: ServerOptions = {
|
|
44
|
+
run: { module: serverModule, transport: TransportKind.ipc },
|
|
45
|
+
debug: {
|
|
46
|
+
module: serverModule,
|
|
47
|
+
transport: TransportKind.ipc,
|
|
48
|
+
options: debugOptions,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const fileSystemWatcher =
|
|
53
|
+
vscode.workspace.createFileSystemWatcher('**/*.zmodel');
|
|
54
|
+
context.subscriptions.push(fileSystemWatcher);
|
|
55
|
+
|
|
56
|
+
// Options to control the language client
|
|
57
|
+
const clientOptions: LanguageClientOptions = {
|
|
58
|
+
documentSelector: [{ scheme: 'file', language: 'zmodel' }],
|
|
59
|
+
synchronize: {
|
|
60
|
+
// Notify the server about file changes to files contained in the workspace
|
|
61
|
+
fileEvents: fileSystemWatcher,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Create the language client and start the client.
|
|
66
|
+
const client = new LanguageClient(
|
|
67
|
+
'zmodel',
|
|
68
|
+
'ZenStack Model',
|
|
69
|
+
serverOptions,
|
|
70
|
+
clientOptions
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Start the client. This will also launch the server
|
|
74
|
+
client.start();
|
|
75
|
+
return client;
|
|
76
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const INTERNAL_PACKAGE = '@zenstackhq/internal';
|
|
2
|
+
export const GUARD_FIELD_NAME = 'zenstack_guard';
|
|
3
|
+
export const TRANSACTION_FIELD_NAME = 'zenstack_transaction';
|
|
4
|
+
export const API_ROUTE_NAME = 'zenstack';
|
|
5
|
+
export const GENERATED_CODE_PATH = 'node_modules/.zenstack';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
import { Context, GeneratorError } 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 NextAuthGenerator from './next-auth';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { execSync } from '../utils/exec-utils';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* ZenStack code generator
|
|
14
|
+
*/
|
|
15
|
+
export class ZenStackGenerator {
|
|
16
|
+
/**
|
|
17
|
+
* Runs a series of nested generators
|
|
18
|
+
*/
|
|
19
|
+
async generate(context: Context): Promise<void> {
|
|
20
|
+
// folder that stores generated prisma schema and migrations
|
|
21
|
+
if (!fs.existsSync(context.outDir)) {
|
|
22
|
+
fs.mkdirSync(context.outDir);
|
|
23
|
+
}
|
|
24
|
+
|
|
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
|
+
});
|
|
31
|
+
}
|
|
32
|
+
fs.mkdirSync(context.generatedCodeDir);
|
|
33
|
+
|
|
34
|
+
const version = require('../../package.json').version;
|
|
35
|
+
console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));
|
|
36
|
+
|
|
37
|
+
// TODO: plugin mechanism
|
|
38
|
+
const generators = [
|
|
39
|
+
new PrismaGenerator(),
|
|
40
|
+
new ServiceGenerator(),
|
|
41
|
+
new ReactHooksGenerator(),
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
require('next-auth');
|
|
46
|
+
generators.push(new NextAuthGenerator());
|
|
47
|
+
} catch {
|
|
48
|
+
console.warn(
|
|
49
|
+
colors.yellow(
|
|
50
|
+
'Next-auth module is not installed, skipping generating adapter.'
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const generator of generators) {
|
|
56
|
+
await generator.generate(context);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// generate package.json
|
|
60
|
+
const packageJson = require(path.join(
|
|
61
|
+
__dirname,
|
|
62
|
+
'../res',
|
|
63
|
+
'package.template.json'
|
|
64
|
+
));
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(context.generatedCodeDir, 'package.json'),
|
|
67
|
+
JSON.stringify(packageJson, undefined, 4)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// compile ts sources
|
|
71
|
+
const tsConfig = require(path.join(
|
|
72
|
+
__dirname,
|
|
73
|
+
'../res',
|
|
74
|
+
'tsconfig.template.json'
|
|
75
|
+
));
|
|
76
|
+
fs.writeFileSync(
|
|
77
|
+
path.join(context.generatedCodeDir, 'tsconfig.json'),
|
|
78
|
+
JSON.stringify(tsConfig, undefined, 4)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
execSync(
|
|
83
|
+
`npx tsc -p "${path.join(
|
|
84
|
+
context.generatedCodeDir,
|
|
85
|
+
'tsconfig.json'
|
|
86
|
+
)}"`
|
|
87
|
+
);
|
|
88
|
+
} catch {
|
|
89
|
+
throw new GeneratorError(
|
|
90
|
+
'Something went wrong, generated runtime code failed to compile...\nPlease check errors above.'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(colors.blue(' ✔️ Typescript source files transpiled'));
|
|
95
|
+
|
|
96
|
+
console.log(
|
|
97
|
+
colors.green(
|
|
98
|
+
colors.bold('👻 All generators completed successfully!')
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|