@zenstackhq/cli 3.0.0-alpha.3 → 3.0.0-alpha.30
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/.turbo/turbo-build.log +22 -23
- package/bin/cli +1 -1
- package/dist/index.cjs +385 -193
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +387 -199
- package/dist/index.js.map +1 -1
- package/eslint.config.js +4 -0
- package/package.json +16 -17
- package/src/actions/action-utils.ts +81 -10
- package/src/actions/check.ts +22 -0
- package/src/actions/db.ts +30 -29
- package/src/actions/generate.ts +101 -38
- package/src/actions/index.ts +2 -1
- package/src/actions/info.ts +9 -18
- package/src/actions/init.ts +6 -27
- package/src/actions/migrate.ts +90 -63
- package/src/actions/templates.ts +4 -3
- package/src/index.ts +57 -47
- package/src/plugins/index.ts +2 -0
- package/src/plugins/prisma.ts +21 -0
- package/src/plugins/typescript.ts +21 -0
- package/src/utils/exec-utils.ts +2 -5
- package/src/utils/version-utils.ts +9 -9
- package/test/check.test.ts +101 -0
- package/test/db.test.ts +18 -0
- package/test/generate.test.ts +47 -0
- package/test/init.test.ts +13 -0
- package/test/migrate.test.ts +72 -0
- package/test/plugins/custom-plugin.test.ts +50 -0
- package/test/plugins/prisma-plugin.test.ts +60 -0
- package/test/ts-schema-gen.test.ts +180 -1
- package/test/utils.ts +23 -0
- package/tsconfig.json +1 -4
- package/vitest.config.ts +1 -1
- package/.turbo/turbo-lint.log +0 -18
package/dist/index.js
CHANGED
|
@@ -1,86 +1,17 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
-
});
|
|
10
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
11
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
6
|
};
|
|
13
7
|
|
|
14
|
-
// package.json
|
|
15
|
-
var require_package = __commonJS({
|
|
16
|
-
"package.json"(exports, module) {
|
|
17
|
-
module.exports = {
|
|
18
|
-
name: "@zenstackhq/cli",
|
|
19
|
-
publisher: "zenstack",
|
|
20
|
-
displayName: "ZenStack CLI",
|
|
21
|
-
description: "FullStack database toolkit with built-in access control and automatic API generation.",
|
|
22
|
-
version: "3.0.0-alpha.3",
|
|
23
|
-
type: "module",
|
|
24
|
-
author: {
|
|
25
|
-
name: "ZenStack Team"
|
|
26
|
-
},
|
|
27
|
-
homepage: "https://zenstack.dev",
|
|
28
|
-
license: "MIT",
|
|
29
|
-
keywords: [
|
|
30
|
-
"orm",
|
|
31
|
-
"fullstack",
|
|
32
|
-
"react",
|
|
33
|
-
"typescript",
|
|
34
|
-
"data modeling"
|
|
35
|
-
],
|
|
36
|
-
bin: {
|
|
37
|
-
zenstack: "bin/cli"
|
|
38
|
-
},
|
|
39
|
-
scripts: {
|
|
40
|
-
build: "tsup-node",
|
|
41
|
-
watch: "tsup-node --watch",
|
|
42
|
-
lint: "eslint src --ext ts",
|
|
43
|
-
test: "vitest",
|
|
44
|
-
pack: "pnpm pack"
|
|
45
|
-
},
|
|
46
|
-
dependencies: {
|
|
47
|
-
"@types/node": "^20.0.0",
|
|
48
|
-
"@zenstackhq/language": "workspace:*",
|
|
49
|
-
"@zenstackhq/sdk": "workspace:*",
|
|
50
|
-
"async-exit-hook": "^2.0.1",
|
|
51
|
-
colors: "1.4.0",
|
|
52
|
-
commander: "^8.3.0",
|
|
53
|
-
langium: "~3.3.0",
|
|
54
|
-
ora: "^5.4.1",
|
|
55
|
-
"package-manager-detector": "^1.3.0",
|
|
56
|
-
"tiny-invariant": "^1.3.3",
|
|
57
|
-
"ts-pattern": "^4.3.0"
|
|
58
|
-
},
|
|
59
|
-
peerDependencies: {
|
|
60
|
-
prisma: "^6.0.0",
|
|
61
|
-
typescript: "^5.0.0"
|
|
62
|
-
},
|
|
63
|
-
devDependencies: {
|
|
64
|
-
"@types/async-exit-hook": "^2.0.0",
|
|
65
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
66
|
-
"@types/semver": "^7.3.13",
|
|
67
|
-
"@types/tmp": "^0.2.6",
|
|
68
|
-
"@zenstackhq/runtime": "workspace:*",
|
|
69
|
-
"@zenstackhq/testtools": "workspace:*",
|
|
70
|
-
"better-sqlite3": "^11.8.1",
|
|
71
|
-
tmp: "^0.2.3"
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
8
|
// src/index.ts
|
|
78
9
|
import { ZModelLanguageMetaData } from "@zenstackhq/language";
|
|
79
|
-
import
|
|
80
|
-
import { Command, Option } from "commander";
|
|
10
|
+
import colors6 from "colors";
|
|
11
|
+
import { Command, CommanderError, Option } from "commander";
|
|
81
12
|
|
|
82
13
|
// src/actions/db.ts
|
|
83
|
-
import
|
|
14
|
+
import fs2 from "fs";
|
|
84
15
|
|
|
85
16
|
// src/utils/exec-utils.ts
|
|
86
17
|
import { execSync as _exec } from "child_process";
|
|
@@ -105,7 +36,12 @@ function execPackage(cmd, options) {
|
|
|
105
36
|
__name(execPackage, "execPackage");
|
|
106
37
|
|
|
107
38
|
// src/actions/action-utils.ts
|
|
108
|
-
import
|
|
39
|
+
import { loadDocument } from "@zenstackhq/language";
|
|
40
|
+
import { isDataSource } from "@zenstackhq/language/ast";
|
|
41
|
+
import { PrismaSchemaGenerator } from "@zenstackhq/sdk";
|
|
42
|
+
import colors from "colors";
|
|
43
|
+
import fs from "fs";
|
|
44
|
+
import path from "path";
|
|
109
45
|
|
|
110
46
|
// src/cli-error.ts
|
|
111
47
|
var CliError = class extends Error {
|
|
@@ -115,8 +51,6 @@ var CliError = class extends Error {
|
|
|
115
51
|
};
|
|
116
52
|
|
|
117
53
|
// src/actions/action-utils.ts
|
|
118
|
-
import { loadDocument } from "@zenstackhq/language";
|
|
119
|
-
import colors from "colors";
|
|
120
54
|
function getSchemaFile(file) {
|
|
121
55
|
if (file) {
|
|
122
56
|
if (!fs.existsSync(file)) {
|
|
@@ -124,6 +58,13 @@ function getSchemaFile(file) {
|
|
|
124
58
|
}
|
|
125
59
|
return file;
|
|
126
60
|
}
|
|
61
|
+
const pkgJsonConfig = getPkgJsonConfig(process.cwd());
|
|
62
|
+
if (pkgJsonConfig.schema) {
|
|
63
|
+
if (!fs.existsSync(pkgJsonConfig.schema)) {
|
|
64
|
+
throw new CliError(`Schema file not found: ${pkgJsonConfig.schema}`);
|
|
65
|
+
}
|
|
66
|
+
return pkgJsonConfig.schema;
|
|
67
|
+
}
|
|
127
68
|
if (fs.existsSync("./zenstack/schema.zmodel")) {
|
|
128
69
|
return "./zenstack/schema.zmodel";
|
|
129
70
|
} else if (fs.existsSync("./schema.zmodel")) {
|
|
@@ -136,12 +77,14 @@ __name(getSchemaFile, "getSchemaFile");
|
|
|
136
77
|
async function loadSchemaDocument(schemaFile) {
|
|
137
78
|
const loadResult = await loadDocument(schemaFile);
|
|
138
79
|
if (!loadResult.success) {
|
|
139
|
-
console.error(colors.red("Error loading schema:"));
|
|
140
80
|
loadResult.errors.forEach((err) => {
|
|
141
81
|
console.error(colors.red(err));
|
|
142
82
|
});
|
|
143
|
-
throw new CliError("
|
|
83
|
+
throw new CliError("Schema contains errors. See above for details.");
|
|
144
84
|
}
|
|
85
|
+
loadResult.warnings.forEach((warn) => {
|
|
86
|
+
console.warn(colors.yellow(warn));
|
|
87
|
+
});
|
|
145
88
|
return loadResult.model;
|
|
146
89
|
}
|
|
147
90
|
__name(loadSchemaDocument, "loadSchemaDocument");
|
|
@@ -153,90 +96,272 @@ function handleSubProcessError(err) {
|
|
|
153
96
|
}
|
|
154
97
|
}
|
|
155
98
|
__name(handleSubProcessError, "handleSubProcessError");
|
|
99
|
+
async function generateTempPrismaSchema(zmodelPath, folder) {
|
|
100
|
+
const model = await loadSchemaDocument(zmodelPath);
|
|
101
|
+
if (!model.declarations.some(isDataSource)) {
|
|
102
|
+
throw new CliError("Schema must define a datasource");
|
|
103
|
+
}
|
|
104
|
+
const prismaSchema = await new PrismaSchemaGenerator(model).generate();
|
|
105
|
+
if (!folder) {
|
|
106
|
+
folder = path.dirname(zmodelPath);
|
|
107
|
+
}
|
|
108
|
+
const prismaSchemaFile = path.resolve(folder, "~schema.prisma");
|
|
109
|
+
fs.writeFileSync(prismaSchemaFile, prismaSchema);
|
|
110
|
+
return prismaSchemaFile;
|
|
111
|
+
}
|
|
112
|
+
__name(generateTempPrismaSchema, "generateTempPrismaSchema");
|
|
113
|
+
function getPkgJsonConfig(startPath) {
|
|
114
|
+
const result = {
|
|
115
|
+
schema: void 0,
|
|
116
|
+
output: void 0
|
|
117
|
+
};
|
|
118
|
+
const pkgJsonFile = findUp([
|
|
119
|
+
"package.json"
|
|
120
|
+
], startPath, false);
|
|
121
|
+
if (!pkgJsonFile) {
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
let pkgJson = void 0;
|
|
125
|
+
try {
|
|
126
|
+
pkgJson = JSON.parse(fs.readFileSync(pkgJsonFile, "utf8"));
|
|
127
|
+
} catch {
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
if (pkgJson.zenstack && typeof pkgJson.zenstack === "object") {
|
|
131
|
+
result.schema = pkgJson.zenstack.schema && path.resolve(path.dirname(pkgJsonFile), pkgJson.zenstack.schema);
|
|
132
|
+
result.output = pkgJson.zenstack.output && path.resolve(path.dirname(pkgJsonFile), pkgJson.zenstack.output);
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
__name(getPkgJsonConfig, "getPkgJsonConfig");
|
|
137
|
+
function findUp(names, cwd = process.cwd(), multiple = false, result = []) {
|
|
138
|
+
if (!names.some((name) => !!name)) {
|
|
139
|
+
return void 0;
|
|
140
|
+
}
|
|
141
|
+
const target = names.find((name) => fs.existsSync(path.join(cwd, name)));
|
|
142
|
+
if (multiple === false && target) {
|
|
143
|
+
return path.join(cwd, target);
|
|
144
|
+
}
|
|
145
|
+
if (target) {
|
|
146
|
+
result.push(path.join(cwd, target));
|
|
147
|
+
}
|
|
148
|
+
const up = path.resolve(cwd, "..");
|
|
149
|
+
if (up === cwd) {
|
|
150
|
+
return multiple && result.length > 0 ? result : void 0;
|
|
151
|
+
}
|
|
152
|
+
return findUp(names, up, multiple, result);
|
|
153
|
+
}
|
|
154
|
+
__name(findUp, "findUp");
|
|
155
|
+
|
|
156
|
+
// src/actions/db.ts
|
|
157
|
+
async function run(command, options) {
|
|
158
|
+
switch (command) {
|
|
159
|
+
case "push":
|
|
160
|
+
await runPush(options);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
__name(run, "run");
|
|
165
|
+
async function runPush(options) {
|
|
166
|
+
const schemaFile = getSchemaFile(options.schema);
|
|
167
|
+
const prismaSchemaFile = await generateTempPrismaSchema(schemaFile);
|
|
168
|
+
try {
|
|
169
|
+
const cmd = [
|
|
170
|
+
"prisma db push",
|
|
171
|
+
` --schema "${prismaSchemaFile}"`,
|
|
172
|
+
options.acceptDataLoss ? " --accept-data-loss" : "",
|
|
173
|
+
options.forceReset ? " --force-reset" : "",
|
|
174
|
+
" --skip-generate"
|
|
175
|
+
].join("");
|
|
176
|
+
try {
|
|
177
|
+
await execPackage(cmd);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
handleSubProcessError(err);
|
|
180
|
+
}
|
|
181
|
+
} finally {
|
|
182
|
+
if (fs2.existsSync(prismaSchemaFile)) {
|
|
183
|
+
fs2.unlinkSync(prismaSchemaFile);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
__name(runPush, "runPush");
|
|
156
188
|
|
|
157
189
|
// src/actions/generate.ts
|
|
190
|
+
import { invariant } from "@zenstackhq/common-helpers";
|
|
158
191
|
import { isPlugin } from "@zenstackhq/language/ast";
|
|
159
|
-
import {
|
|
192
|
+
import { getLiteral, getLiteralArray } from "@zenstackhq/language/utils";
|
|
160
193
|
import colors2 from "colors";
|
|
161
|
-
import
|
|
162
|
-
import
|
|
163
|
-
|
|
164
|
-
|
|
194
|
+
import path4 from "path";
|
|
195
|
+
import ora from "ora";
|
|
196
|
+
|
|
197
|
+
// src/plugins/index.ts
|
|
198
|
+
var plugins_exports = {};
|
|
199
|
+
__export(plugins_exports, {
|
|
200
|
+
prisma: () => prisma_default,
|
|
201
|
+
typescript: () => typescript_default
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// src/plugins/prisma.ts
|
|
205
|
+
import { PrismaSchemaGenerator as PrismaSchemaGenerator2 } from "@zenstackhq/sdk";
|
|
206
|
+
import fs3 from "fs";
|
|
207
|
+
import path2 from "path";
|
|
208
|
+
var plugin = {
|
|
209
|
+
name: "Prisma Schema Generator",
|
|
210
|
+
statusText: "Generating Prisma schema",
|
|
211
|
+
async generate({ model, schemaFile, defaultOutputPath, pluginOptions }) {
|
|
212
|
+
let outFile = path2.join(defaultOutputPath, "schema.prisma");
|
|
213
|
+
if (typeof pluginOptions["output"] === "string") {
|
|
214
|
+
outFile = path2.resolve(path2.dirname(schemaFile), pluginOptions["output"]);
|
|
215
|
+
if (!fs3.existsSync(path2.dirname(outFile))) {
|
|
216
|
+
fs3.mkdirSync(path2.dirname(outFile), {
|
|
217
|
+
recursive: true
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const prismaSchema = await new PrismaSchemaGenerator2(model).generate();
|
|
222
|
+
fs3.writeFileSync(outFile, prismaSchema);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
var prisma_default = plugin;
|
|
226
|
+
|
|
227
|
+
// src/plugins/typescript.ts
|
|
228
|
+
import { TsSchemaGenerator } from "@zenstackhq/sdk";
|
|
229
|
+
import fs4 from "fs";
|
|
230
|
+
import path3 from "path";
|
|
231
|
+
var plugin2 = {
|
|
232
|
+
name: "TypeScript Schema Generator",
|
|
233
|
+
statusText: "Generating TypeScript schema",
|
|
234
|
+
async generate({ model, defaultOutputPath, pluginOptions }) {
|
|
235
|
+
let outDir = defaultOutputPath;
|
|
236
|
+
if (typeof pluginOptions["output"] === "string") {
|
|
237
|
+
outDir = path3.resolve(defaultOutputPath, pluginOptions["output"]);
|
|
238
|
+
if (!fs4.existsSync(outDir)) {
|
|
239
|
+
fs4.mkdirSync(outDir, {
|
|
240
|
+
recursive: true
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
await new TsSchemaGenerator().generate(model, outDir);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
var typescript_default = plugin2;
|
|
248
|
+
|
|
249
|
+
// src/actions/generate.ts
|
|
250
|
+
async function run2(options) {
|
|
251
|
+
const start = Date.now();
|
|
165
252
|
const schemaFile = getSchemaFile(options.schema);
|
|
166
253
|
const model = await loadSchemaDocument(schemaFile);
|
|
167
|
-
const outputPath = options
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
fs2.writeFileSync(path.join(outputPath, "schema.prisma"), prismaSchema);
|
|
173
|
-
if (!options.silent) {
|
|
174
|
-
console.log(colors2.green("Generation completed successfully."));
|
|
175
|
-
console.log(`You can now create a ZenStack client with it.
|
|
254
|
+
const outputPath = getOutputPath(options, schemaFile);
|
|
255
|
+
await runPlugins(schemaFile, model, outputPath);
|
|
256
|
+
console.log(colors2.green(`Generation completed successfully in ${Date.now() - start}ms.
|
|
257
|
+
`));
|
|
258
|
+
console.log(`You can now create a ZenStack client with it.
|
|
176
259
|
|
|
177
260
|
\`\`\`ts
|
|
178
261
|
import { ZenStackClient } from '@zenstackhq/runtime';
|
|
179
262
|
import { schema } from '${outputPath}/schema';
|
|
180
263
|
|
|
181
264
|
const client = new ZenStackClient(schema, {
|
|
182
|
-
|
|
265
|
+
dialect: { ... }
|
|
183
266
|
});
|
|
184
|
-
|
|
185
|
-
|
|
267
|
+
\`\`\``);
|
|
268
|
+
}
|
|
269
|
+
__name(run2, "run");
|
|
270
|
+
function getOutputPath(options, schemaFile) {
|
|
271
|
+
if (options.output) {
|
|
272
|
+
return options.output;
|
|
273
|
+
}
|
|
274
|
+
const pkgJsonConfig = getPkgJsonConfig(process.cwd());
|
|
275
|
+
if (pkgJsonConfig.output) {
|
|
276
|
+
return pkgJsonConfig.output;
|
|
277
|
+
} else {
|
|
278
|
+
return path4.dirname(schemaFile);
|
|
186
279
|
}
|
|
187
280
|
}
|
|
188
|
-
__name(
|
|
189
|
-
async function runPlugins(model, outputPath
|
|
281
|
+
__name(getOutputPath, "getOutputPath");
|
|
282
|
+
async function runPlugins(schemaFile, model, outputPath) {
|
|
190
283
|
const plugins = model.declarations.filter(isPlugin);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
284
|
+
const processedPlugins = [];
|
|
285
|
+
for (const plugin3 of plugins) {
|
|
286
|
+
const provider = getPluginProvider(plugin3);
|
|
287
|
+
let cliPlugin;
|
|
288
|
+
if (provider.startsWith("@core/")) {
|
|
289
|
+
cliPlugin = plugins_exports[provider.slice("@core/".length)];
|
|
290
|
+
if (!cliPlugin) {
|
|
291
|
+
throw new CliError(`Unknown core plugin: ${provider}`);
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
let moduleSpec = provider;
|
|
295
|
+
if (moduleSpec.startsWith(".")) {
|
|
296
|
+
moduleSpec = path4.resolve(path4.dirname(schemaFile), moduleSpec);
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
cliPlugin = (await import(moduleSpec)).default;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
throw new CliError(`Failed to load plugin ${provider}: ${error}`);
|
|
302
|
+
}
|
|
198
303
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
model,
|
|
203
|
-
outputPath,
|
|
204
|
-
tsSchemaFile
|
|
304
|
+
processedPlugins.push({
|
|
305
|
+
cliPlugin,
|
|
306
|
+
pluginOptions: getPluginOptions(plugin3)
|
|
205
307
|
});
|
|
206
308
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
309
|
+
const defaultPlugins = [
|
|
310
|
+
typescript_default
|
|
311
|
+
].reverse();
|
|
312
|
+
defaultPlugins.forEach((d) => {
|
|
313
|
+
if (!processedPlugins.some((p) => p.cliPlugin === d)) {
|
|
314
|
+
processedPlugins.push({
|
|
315
|
+
cliPlugin: d,
|
|
316
|
+
pluginOptions: {}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
216
319
|
});
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
320
|
+
for (const { cliPlugin, pluginOptions } of processedPlugins) {
|
|
321
|
+
invariant(typeof cliPlugin.generate === "function", `Plugin ${cliPlugin.name} does not have a generate function`);
|
|
322
|
+
const spinner = ora(cliPlugin.statusText ?? `Running plugin ${cliPlugin.name}`).start();
|
|
323
|
+
try {
|
|
324
|
+
await cliPlugin.generate({
|
|
325
|
+
schemaFile,
|
|
326
|
+
model,
|
|
327
|
+
defaultOutputPath: outputPath,
|
|
328
|
+
pluginOptions
|
|
329
|
+
});
|
|
330
|
+
spinner.succeed();
|
|
331
|
+
} catch (err) {
|
|
332
|
+
spinner.fail();
|
|
333
|
+
console.error(err);
|
|
334
|
+
}
|
|
222
335
|
}
|
|
223
336
|
}
|
|
224
|
-
__name(
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
337
|
+
__name(runPlugins, "runPlugins");
|
|
338
|
+
function getPluginProvider(plugin3) {
|
|
339
|
+
const providerField = plugin3.fields.find((f) => f.name === "provider");
|
|
340
|
+
invariant(providerField, `Plugin ${plugin3.name} does not have a provider field`);
|
|
341
|
+
const provider = providerField.value.value;
|
|
342
|
+
return provider;
|
|
343
|
+
}
|
|
344
|
+
__name(getPluginProvider, "getPluginProvider");
|
|
345
|
+
function getPluginOptions(plugin3) {
|
|
346
|
+
const result = {};
|
|
347
|
+
for (const field of plugin3.fields) {
|
|
348
|
+
if (field.name === "provider") {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const value = getLiteral(field.value) ?? getLiteralArray(field.value);
|
|
352
|
+
if (value === void 0) {
|
|
353
|
+
console.warn(`Plugin "${plugin3.name}" option "${field.name}" has unsupported value, skipping`);
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
result[field.name] = value;
|
|
233
357
|
}
|
|
358
|
+
return result;
|
|
234
359
|
}
|
|
235
|
-
__name(
|
|
360
|
+
__name(getPluginOptions, "getPluginOptions");
|
|
236
361
|
|
|
237
362
|
// src/actions/info.ts
|
|
238
363
|
import colors3 from "colors";
|
|
239
|
-
import
|
|
364
|
+
import path5 from "path";
|
|
240
365
|
async function run3(projectPath) {
|
|
241
366
|
const packages = await getZenStackPackages(projectPath);
|
|
242
367
|
if (!packages) {
|
|
@@ -258,14 +383,14 @@ async function run3(projectPath) {
|
|
|
258
383
|
__name(run3, "run");
|
|
259
384
|
async function getZenStackPackages(projectPath) {
|
|
260
385
|
let pkgJson;
|
|
261
|
-
const resolvedPath =
|
|
386
|
+
const resolvedPath = path5.resolve(projectPath);
|
|
262
387
|
try {
|
|
263
|
-
pkgJson = (await import(
|
|
388
|
+
pkgJson = (await import(path5.join(resolvedPath, "package.json"), {
|
|
264
389
|
with: {
|
|
265
390
|
type: "json"
|
|
266
391
|
}
|
|
267
392
|
})).default;
|
|
268
|
-
} catch
|
|
393
|
+
} catch {
|
|
269
394
|
return [];
|
|
270
395
|
}
|
|
271
396
|
const packages = Array.from(new Set([
|
|
@@ -296,9 +421,9 @@ __name(getZenStackPackages, "getZenStackPackages");
|
|
|
296
421
|
|
|
297
422
|
// src/actions/init.ts
|
|
298
423
|
import colors4 from "colors";
|
|
299
|
-
import
|
|
300
|
-
import
|
|
301
|
-
import
|
|
424
|
+
import fs5 from "fs";
|
|
425
|
+
import path6 from "path";
|
|
426
|
+
import ora2 from "ora";
|
|
302
427
|
import { detect, resolveCommand } from "package-manager-detector";
|
|
303
428
|
|
|
304
429
|
// src/actions/templates.ts
|
|
@@ -360,7 +485,7 @@ async function run4(projectPath) {
|
|
|
360
485
|
if (!resolved) {
|
|
361
486
|
throw new CliError(`Unable to determine how to install package "${pkg.name}". Please install it manually.`);
|
|
362
487
|
}
|
|
363
|
-
const spinner =
|
|
488
|
+
const spinner = ora2(`Installing "${pkg.name}"`).start();
|
|
364
489
|
try {
|
|
365
490
|
execSync(`${resolved.command} ${resolved.args.join(" ")}`, {
|
|
366
491
|
cwd: projectPath
|
|
@@ -372,11 +497,11 @@ async function run4(projectPath) {
|
|
|
372
497
|
}
|
|
373
498
|
}
|
|
374
499
|
const generationFolder = "zenstack";
|
|
375
|
-
if (!
|
|
376
|
-
|
|
500
|
+
if (!fs5.existsSync(path6.join(projectPath, generationFolder))) {
|
|
501
|
+
fs5.mkdirSync(path6.join(projectPath, generationFolder));
|
|
377
502
|
}
|
|
378
|
-
if (!
|
|
379
|
-
|
|
503
|
+
if (!fs5.existsSync(path6.join(projectPath, generationFolder, "schema.zmodel"))) {
|
|
504
|
+
fs5.writeFileSync(path6.join(projectPath, generationFolder, "schema.zmodel"), STARTER_ZMODEL);
|
|
380
505
|
} else {
|
|
381
506
|
console.log(colors4.yellow("Schema file already exists. Skipping generation of sample."));
|
|
382
507
|
}
|
|
@@ -387,35 +512,47 @@ async function run4(projectPath) {
|
|
|
387
512
|
__name(run4, "run");
|
|
388
513
|
|
|
389
514
|
// src/actions/migrate.ts
|
|
390
|
-
import
|
|
515
|
+
import fs6 from "fs";
|
|
516
|
+
import path7 from "path";
|
|
391
517
|
async function run5(command, options) {
|
|
392
518
|
const schemaFile = getSchemaFile(options.schema);
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
519
|
+
const prismaSchemaDir = options.migrations ? path7.dirname(options.migrations) : void 0;
|
|
520
|
+
const prismaSchemaFile = await generateTempPrismaSchema(schemaFile, prismaSchemaDir);
|
|
521
|
+
try {
|
|
522
|
+
switch (command) {
|
|
523
|
+
case "dev":
|
|
524
|
+
await runDev(prismaSchemaFile, options);
|
|
525
|
+
break;
|
|
526
|
+
case "reset":
|
|
527
|
+
await runReset(prismaSchemaFile, options);
|
|
528
|
+
break;
|
|
529
|
+
case "deploy":
|
|
530
|
+
await runDeploy(prismaSchemaFile, options);
|
|
531
|
+
break;
|
|
532
|
+
case "status":
|
|
533
|
+
await runStatus(prismaSchemaFile, options);
|
|
534
|
+
break;
|
|
535
|
+
case "resolve":
|
|
536
|
+
await runResolve(prismaSchemaFile, options);
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
} finally {
|
|
540
|
+
if (fs6.existsSync(prismaSchemaFile)) {
|
|
541
|
+
fs6.unlinkSync(prismaSchemaFile);
|
|
542
|
+
}
|
|
411
543
|
}
|
|
412
544
|
}
|
|
413
545
|
__name(run5, "run");
|
|
414
|
-
async function runDev(prismaSchemaFile,
|
|
546
|
+
async function runDev(prismaSchemaFile, options) {
|
|
415
547
|
try {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
548
|
+
const cmd = [
|
|
549
|
+
"prisma migrate dev",
|
|
550
|
+
` --schema "${prismaSchemaFile}"`,
|
|
551
|
+
" --skip-generate",
|
|
552
|
+
options.name ? ` --name ${options.name}` : "",
|
|
553
|
+
options.createOnly ? " --create-only" : ""
|
|
554
|
+
].join("");
|
|
555
|
+
await execPackage(cmd);
|
|
419
556
|
} catch (err) {
|
|
420
557
|
handleSubProcessError2(err);
|
|
421
558
|
}
|
|
@@ -423,9 +560,12 @@ async function runDev(prismaSchemaFile, _options) {
|
|
|
423
560
|
__name(runDev, "runDev");
|
|
424
561
|
async function runReset(prismaSchemaFile, options) {
|
|
425
562
|
try {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
563
|
+
const cmd = [
|
|
564
|
+
"prisma migrate reset",
|
|
565
|
+
` --schema "${prismaSchemaFile}"`,
|
|
566
|
+
options.force ? " --force" : ""
|
|
567
|
+
].join("");
|
|
568
|
+
await execPackage(cmd);
|
|
429
569
|
} catch (err) {
|
|
430
570
|
handleSubProcessError2(err);
|
|
431
571
|
}
|
|
@@ -433,9 +573,11 @@ async function runReset(prismaSchemaFile, options) {
|
|
|
433
573
|
__name(runReset, "runReset");
|
|
434
574
|
async function runDeploy(prismaSchemaFile, _options) {
|
|
435
575
|
try {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
576
|
+
const cmd = [
|
|
577
|
+
"prisma migrate deploy",
|
|
578
|
+
` --schema "${prismaSchemaFile}"`
|
|
579
|
+
].join("");
|
|
580
|
+
await execPackage(cmd);
|
|
439
581
|
} catch (err) {
|
|
440
582
|
handleSubProcessError2(err);
|
|
441
583
|
}
|
|
@@ -443,14 +585,29 @@ async function runDeploy(prismaSchemaFile, _options) {
|
|
|
443
585
|
__name(runDeploy, "runDeploy");
|
|
444
586
|
async function runStatus(prismaSchemaFile, _options) {
|
|
445
587
|
try {
|
|
446
|
-
await execPackage(`prisma migrate status --schema "${prismaSchemaFile}"
|
|
447
|
-
stdio: "inherit"
|
|
448
|
-
});
|
|
588
|
+
await execPackage(`prisma migrate status --schema "${prismaSchemaFile}"`);
|
|
449
589
|
} catch (err) {
|
|
450
590
|
handleSubProcessError2(err);
|
|
451
591
|
}
|
|
452
592
|
}
|
|
453
593
|
__name(runStatus, "runStatus");
|
|
594
|
+
async function runResolve(prismaSchemaFile, options) {
|
|
595
|
+
if (!options.applied && !options.rolledBack) {
|
|
596
|
+
throw new CliError("Either --applied or --rolled-back option must be provided");
|
|
597
|
+
}
|
|
598
|
+
try {
|
|
599
|
+
const cmd = [
|
|
600
|
+
"prisma migrate resolve",
|
|
601
|
+
` --schema "${prismaSchemaFile}"`,
|
|
602
|
+
options.applied ? ` --applied ${options.applied}` : "",
|
|
603
|
+
options.rolledBack ? ` --rolled-back ${options.rolledBack}` : ""
|
|
604
|
+
].join("");
|
|
605
|
+
await execPackage(cmd);
|
|
606
|
+
} catch (err) {
|
|
607
|
+
handleSubProcessError2(err);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
__name(runResolve, "runResolve");
|
|
454
611
|
function handleSubProcessError2(err) {
|
|
455
612
|
if (err instanceof Error && "status" in err && typeof err.status === "number") {
|
|
456
613
|
process.exit(err.status);
|
|
@@ -460,29 +617,43 @@ function handleSubProcessError2(err) {
|
|
|
460
617
|
}
|
|
461
618
|
__name(handleSubProcessError2, "handleSubProcessError");
|
|
462
619
|
|
|
620
|
+
// src/actions/check.ts
|
|
621
|
+
import colors5 from "colors";
|
|
622
|
+
async function run6(options) {
|
|
623
|
+
const schemaFile = getSchemaFile(options.schema);
|
|
624
|
+
try {
|
|
625
|
+
await loadSchemaDocument(schemaFile);
|
|
626
|
+
console.log(colors5.green("\u2713 Schema validation completed successfully."));
|
|
627
|
+
} catch (error) {
|
|
628
|
+
console.error(colors5.red("\u2717 Schema validation failed."));
|
|
629
|
+
throw error;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
__name(run6, "run");
|
|
633
|
+
|
|
463
634
|
// src/utils/version-utils.ts
|
|
635
|
+
import fs7 from "fs";
|
|
636
|
+
import path8 from "path";
|
|
637
|
+
import { fileURLToPath } from "url";
|
|
464
638
|
function getVersion() {
|
|
465
639
|
try {
|
|
466
|
-
|
|
640
|
+
const _dirname = typeof __dirname !== "undefined" ? __dirname : path8.dirname(fileURLToPath(import.meta.url));
|
|
641
|
+
return JSON.parse(fs7.readFileSync(path8.join(_dirname, "../package.json"), "utf8")).version;
|
|
467
642
|
} catch {
|
|
468
|
-
|
|
469
|
-
return require_package().version;
|
|
470
|
-
} catch {
|
|
471
|
-
return void 0;
|
|
472
|
-
}
|
|
643
|
+
return void 0;
|
|
473
644
|
}
|
|
474
645
|
}
|
|
475
646
|
__name(getVersion, "getVersion");
|
|
476
647
|
|
|
477
648
|
// src/index.ts
|
|
478
649
|
var generateAction = /* @__PURE__ */ __name(async (options) => {
|
|
479
|
-
await
|
|
650
|
+
await run2(options);
|
|
480
651
|
}, "generateAction");
|
|
481
652
|
var migrateAction = /* @__PURE__ */ __name(async (command, options) => {
|
|
482
653
|
await run5(command, options);
|
|
483
654
|
}, "migrateAction");
|
|
484
655
|
var dbAction = /* @__PURE__ */ __name(async (command, options) => {
|
|
485
|
-
await
|
|
656
|
+
await run(command, options);
|
|
486
657
|
}, "dbAction");
|
|
487
658
|
var infoAction = /* @__PURE__ */ __name(async (projectPath) => {
|
|
488
659
|
await run3(projectPath);
|
|
@@ -490,29 +661,46 @@ var infoAction = /* @__PURE__ */ __name(async (projectPath) => {
|
|
|
490
661
|
var initAction = /* @__PURE__ */ __name(async (projectPath) => {
|
|
491
662
|
await run4(projectPath);
|
|
492
663
|
}, "initAction");
|
|
664
|
+
var checkAction = /* @__PURE__ */ __name(async (options) => {
|
|
665
|
+
await run6(options);
|
|
666
|
+
}, "checkAction");
|
|
493
667
|
function createProgram() {
|
|
494
668
|
const program2 = new Command("zenstack");
|
|
495
669
|
program2.version(getVersion(), "-v --version", "display CLI version");
|
|
496
670
|
const schemaExtensions = ZModelLanguageMetaData.fileExtensions.join(", ");
|
|
497
|
-
program2.description(`${
|
|
671
|
+
program2.description(`${colors6.bold.blue("\u03B6")} ZenStack is the data layer for modern TypeScript apps.
|
|
498
672
|
|
|
499
673
|
Documentation: https://zenstack.dev.`).showHelpAfterError().showSuggestionAfterError();
|
|
500
|
-
const schemaOption = new Option("--schema <file>", `schema file (with extension ${schemaExtensions}). Defaults to "schema.zmodel" unless specified in package.json.`);
|
|
501
|
-
program2.command("generate").description("Run code generation.").addOption(schemaOption).addOption(new Option("-o, --output <path>", "default output directory for
|
|
502
|
-
const migrateCommand = program2.command("migrate").description("
|
|
503
|
-
|
|
504
|
-
migrateCommand.command("
|
|
505
|
-
migrateCommand.command("
|
|
506
|
-
migrateCommand.command("
|
|
674
|
+
const schemaOption = new Option("--schema <file>", `schema file (with extension ${schemaExtensions}). Defaults to "zenstack/schema.zmodel" unless specified in package.json.`);
|
|
675
|
+
program2.command("generate").description("Run code generation plugins.").addOption(schemaOption).addOption(new Option("-o, --output <path>", "default output directory for code generation")).action(generateAction);
|
|
676
|
+
const migrateCommand = program2.command("migrate").description("Run database schema migration related tasks.");
|
|
677
|
+
const migrationsOption = new Option("--migrations <path>", 'path that contains the "migrations" directory');
|
|
678
|
+
migrateCommand.command("dev").addOption(schemaOption).addOption(new Option("-n, --name <name>", "migration name")).addOption(new Option("--create-only", "only create migration, do not apply")).addOption(migrationsOption).description("Create a migration from changes in schema and apply it to the database.").action((options) => migrateAction("dev", options));
|
|
679
|
+
migrateCommand.command("reset").addOption(schemaOption).addOption(new Option("--force", "skip the confirmation prompt")).addOption(migrationsOption).description("Reset your database and apply all migrations, all data will be lost.").action((options) => migrateAction("reset", options));
|
|
680
|
+
migrateCommand.command("deploy").addOption(schemaOption).addOption(migrationsOption).description("Deploy your pending migrations to your production/staging database.").action((options) => migrateAction("deploy", options));
|
|
681
|
+
migrateCommand.command("status").addOption(schemaOption).addOption(migrationsOption).description("Check the status of your database migrations.").action((options) => migrateAction("status", options));
|
|
682
|
+
migrateCommand.command("resolve").addOption(schemaOption).addOption(migrationsOption).addOption(new Option("--applied <migration>", "record a specific migration as applied")).addOption(new Option("--rolled-back <migration>", "record a specific migration as rolled back")).description("Resolve issues with database migrations in deployment databases.").action((options) => migrateAction("resolve", options));
|
|
507
683
|
const dbCommand = program2.command("db").description("Manage your database schema during development.");
|
|
508
|
-
dbCommand.command("push").description("Push the state from your schema to your database").addOption(schemaOption).addOption(new Option("--accept-data-loss", "ignore data loss warnings")).addOption(new Option("--force-reset", "force a reset of the database before push")).action((options) => dbAction("push", options));
|
|
509
|
-
program2.command("info").description("Get information of installed ZenStack
|
|
684
|
+
dbCommand.command("push").description("Push the state from your schema to your database.").addOption(schemaOption).addOption(new Option("--accept-data-loss", "ignore data loss warnings")).addOption(new Option("--force-reset", "force a reset of the database before push")).action((options) => dbAction("push", options));
|
|
685
|
+
program2.command("info").description("Get information of installed ZenStack packages.").argument("[path]", "project path", ".").action(infoAction);
|
|
510
686
|
program2.command("init").description("Initialize an existing project for ZenStack.").argument("[path]", "project path", ".").action(initAction);
|
|
687
|
+
program2.command("check").description("Check a ZModel schema for syntax or semantic errors.").addOption(schemaOption).action(checkAction);
|
|
511
688
|
return program2;
|
|
512
689
|
}
|
|
513
690
|
__name(createProgram, "createProgram");
|
|
514
691
|
var program = createProgram();
|
|
515
|
-
program.
|
|
692
|
+
program.parseAsync().catch((err) => {
|
|
693
|
+
if (err instanceof CliError) {
|
|
694
|
+
console.error(colors6.red(err.message));
|
|
695
|
+
process.exit(1);
|
|
696
|
+
} else if (err instanceof CommanderError) {
|
|
697
|
+
process.exit(err.exitCode);
|
|
698
|
+
} else {
|
|
699
|
+
console.error(colors6.red("An unexpected error occurred:"));
|
|
700
|
+
console.error(err);
|
|
701
|
+
process.exit(1);
|
|
702
|
+
}
|
|
703
|
+
});
|
|
516
704
|
export {
|
|
517
705
|
createProgram
|
|
518
706
|
};
|