@zenstackhq/cli 3.0.0-alpha.4 → 3.0.0-alpha.7

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.
@@ -1,7 +1,9 @@
1
- import fs from 'node:fs';
2
- import { CliError } from '../cli-error';
3
1
  import { loadDocument } from '@zenstackhq/language';
2
+ import { PrismaSchemaGenerator } from '@zenstackhq/sdk';
4
3
  import colors from 'colors';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { CliError } from '../cli-error';
5
7
 
6
8
  export function getSchemaFile(file?: string) {
7
9
  if (file) {
@@ -17,7 +19,7 @@ export function getSchemaFile(file?: string) {
17
19
  return './schema.zmodel';
18
20
  } else {
19
21
  throw new CliError(
20
- 'Schema file not found in default locations ("./zenstack/schema.zmodel" or "./schema.zmodel").'
22
+ 'Schema file not found in default locations ("./zenstack/schema.zmodel" or "./schema.zmodel").',
21
23
  );
22
24
  }
23
25
  }
@@ -35,13 +37,17 @@ export async function loadSchemaDocument(schemaFile: string) {
35
37
  }
36
38
 
37
39
  export function handleSubProcessError(err: unknown) {
38
- if (
39
- err instanceof Error &&
40
- 'status' in err &&
41
- typeof err.status === 'number'
42
- ) {
40
+ if (err instanceof Error && 'status' in err && typeof err.status === 'number') {
43
41
  process.exit(err.status);
44
42
  } else {
45
43
  process.exit(1);
46
44
  }
47
45
  }
46
+
47
+ export async function generateTempPrismaSchema(zmodelPath: string) {
48
+ const model = await loadSchemaDocument(zmodelPath);
49
+ const prismaSchema = await new PrismaSchemaGenerator(model).generate();
50
+ const prismaSchemaFile = path.resolve(path.dirname(zmodelPath), '~schema.prisma');
51
+ fs.writeFileSync(prismaSchemaFile, prismaSchema);
52
+ return prismaSchemaFile;
53
+ }
package/src/actions/db.ts CHANGED
@@ -1,46 +1,44 @@
1
- import path from 'node:path';
1
+ import fs from 'node:fs';
2
2
  import { execPackage } from '../utils/exec-utils';
3
- import { getSchemaFile, handleSubProcessError } from './action-utils';
4
- import { run as runGenerate } from './generate';
3
+ import { generateTempPrismaSchema, getSchemaFile, handleSubProcessError } from './action-utils';
5
4
 
6
- type CommonOptions = {
5
+ type Options = {
7
6
  schema?: string;
8
- name?: string;
7
+ acceptDataLoss?: boolean;
8
+ forceReset?: boolean;
9
9
  };
10
10
 
11
11
  /**
12
12
  * CLI action for db related commands
13
13
  */
14
- export async function run(command: string, options: CommonOptions) {
15
- const schemaFile = getSchemaFile(options.schema);
16
-
17
- // run generate first
18
- await runGenerate({
19
- schema: schemaFile,
20
- silent: true,
21
- });
22
-
23
- const prismaSchemaFile = path.join(
24
- path.dirname(schemaFile),
25
- 'schema.prisma'
26
- );
27
-
14
+ export async function run(command: string, options: Options) {
28
15
  switch (command) {
29
16
  case 'push':
30
- await runPush(prismaSchemaFile, options);
17
+ await runPush(options);
31
18
  break;
32
19
  }
33
20
  }
34
21
 
35
- async function runPush(prismaSchemaFile: string, options: any) {
36
- const cmd = `prisma db push --schema "${prismaSchemaFile}"${
37
- options.acceptDataLoss ? ' --accept-data-loss' : ''
38
- }${options.forceReset ? ' --force-reset' : ''} --skip-generate`;
22
+ async function runPush(options: Options) {
23
+ // generate a temp prisma schema file
24
+ const schemaFile = getSchemaFile(options.schema);
25
+ const prismaSchemaFile = await generateTempPrismaSchema(schemaFile);
26
+
39
27
  try {
40
- await execPackage(cmd, {
41
- stdio: 'inherit',
42
- });
43
- } catch (err) {
44
- handleSubProcessError(err);
28
+ // run prisma db push
29
+ const cmd = `prisma db push --schema "${prismaSchemaFile}"${
30
+ options.acceptDataLoss ? ' --accept-data-loss' : ''
31
+ }${options.forceReset ? ' --force-reset' : ''} --skip-generate`;
32
+ try {
33
+ await execPackage(cmd, {
34
+ stdio: 'inherit',
35
+ });
36
+ } catch (err) {
37
+ handleSubProcessError(err);
38
+ }
39
+ } finally {
40
+ if (fs.existsSync(prismaSchemaFile)) {
41
+ fs.unlinkSync(prismaSchemaFile);
42
+ }
45
43
  }
46
44
  }
@@ -1,16 +1,16 @@
1
+ import { invariant } from '@zenstackhq/common-helpers';
1
2
  import { isPlugin, LiteralExpr, type Model } from '@zenstackhq/language/ast';
2
- import type { CliGenerator } from '@zenstackhq/runtime/client';
3
- import { PrismaSchemaGenerator, TsSchemaGenerator } from '@zenstackhq/sdk';
3
+ import { PrismaSchemaGenerator, TsSchemaGenerator, type CliGenerator } from '@zenstackhq/sdk';
4
4
  import colors from 'colors';
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
- import invariant from 'tiny-invariant';
8
7
  import { getSchemaFile, loadSchemaDocument } from './action-utils';
9
8
 
10
9
  type Options = {
11
10
  schema?: string;
12
11
  output?: string;
13
12
  silent?: boolean;
13
+ savePrismaSchema?: string | boolean;
14
14
  };
15
15
 
16
16
  /**
@@ -29,8 +29,15 @@ export async function run(options: Options) {
29
29
  await runPlugins(model, outputPath, tsSchemaFile);
30
30
 
31
31
  // generate Prisma schema
32
- const prismaSchema = await new PrismaSchemaGenerator(model).generate();
33
- fs.writeFileSync(path.join(outputPath, 'schema.prisma'), prismaSchema);
32
+ if (options.savePrismaSchema) {
33
+ const prismaSchema = await new PrismaSchemaGenerator(model).generate();
34
+ let prismaSchemaFile = path.join(outputPath, 'schema.prisma');
35
+ if (typeof options.savePrismaSchema === 'string') {
36
+ prismaSchemaFile = path.resolve(outputPath, options.savePrismaSchema);
37
+ fs.mkdirSync(path.dirname(prismaSchemaFile), { recursive: true });
38
+ }
39
+ fs.writeFileSync(prismaSchemaFile, prismaSchema);
40
+ }
34
41
 
35
42
  if (!options.silent) {
36
43
  console.log(colors.green('Generation completed successfully.'));
@@ -41,25 +48,18 @@ import { ZenStackClient } from '@zenstackhq/runtime';
41
48
  import { schema } from '${outputPath}/schema';
42
49
 
43
50
  const client = new ZenStackClient(schema, {
44
- dialectConfig: { ... }
51
+ dialectConfig: { ... }
45
52
  });
46
53
  \`\`\`
47
54
  `);
48
55
  }
49
56
  }
50
57
 
51
- async function runPlugins(
52
- model: Model,
53
- outputPath: string,
54
- tsSchemaFile: string
55
- ) {
58
+ async function runPlugins(model: Model, outputPath: string, tsSchemaFile: string) {
56
59
  const plugins = model.declarations.filter(isPlugin);
57
60
  for (const plugin of plugins) {
58
61
  const providerField = plugin.fields.find((f) => f.name === 'provider');
59
- invariant(
60
- providerField,
61
- `Plugin ${plugin.name} does not have a provider field`
62
- );
62
+ invariant(providerField, `Plugin ${plugin.name} does not have a provider field`);
63
63
  const provider = (providerField.value as LiteralExpr).value as string;
64
64
  let useProvider = provider;
65
65
  if (useProvider.startsWith('@core/')) {
@@ -7,9 +7,7 @@ import path from 'node:path';
7
7
  export async function run(projectPath: string) {
8
8
  const packages = await getZenStackPackages(projectPath);
9
9
  if (!packages) {
10
- console.error(
11
- 'Unable to locate package.json. Are you in a valid project directory?'
12
- );
10
+ console.error('Unable to locate package.json. Are you in a valid project directory?');
13
11
  return;
14
12
  }
15
13
 
@@ -23,17 +21,11 @@ export async function run(projectPath: string) {
23
21
  }
24
22
 
25
23
  if (versions.size > 1) {
26
- console.warn(
27
- colors.yellow(
28
- 'WARNING: Multiple versions of Zenstack packages detected. This may cause issues.'
29
- )
30
- );
24
+ console.warn(colors.yellow('WARNING: Multiple versions of Zenstack packages detected. This may cause issues.'));
31
25
  }
32
26
  }
33
27
 
34
- async function getZenStackPackages(
35
- projectPath: string
36
- ): Promise<Array<{ pkg: string; version: string | undefined }>> {
28
+ async function getZenStackPackages(projectPath: string): Promise<Array<{ pkg: string; version: string | undefined }>> {
37
29
  let pkgJson: {
38
30
  dependencies: Record<string, unknown>;
39
31
  devDependencies: Record<string, unknown>;
@@ -45,17 +37,16 @@ async function getZenStackPackages(
45
37
  with: { type: 'json' },
46
38
  })
47
39
  ).default;
48
- } catch (err) {
40
+ } catch {
49
41
  return [];
50
42
  }
51
43
 
52
44
  const packages = Array.from(
53
45
  new Set(
54
- [
55
- ...Object.keys(pkgJson.dependencies ?? {}),
56
- ...Object.keys(pkgJson.devDependencies ?? {}),
57
- ].filter((p) => p.startsWith('@zenstackhq/') || p === 'zenstack')
58
- )
46
+ [...Object.keys(pkgJson.dependencies ?? {}), ...Object.keys(pkgJson.devDependencies ?? {})].filter(
47
+ (p) => p.startsWith('@zenstackhq/') || p === 'zenstack',
48
+ ),
49
+ ),
59
50
  ).sort();
60
51
 
61
52
  const result = await Promise.all(
@@ -70,7 +61,7 @@ async function getZenStackPackages(
70
61
  } catch {
71
62
  return { pkg, version: undefined };
72
63
  }
73
- })
64
+ }),
74
65
  );
75
66
 
76
67
  return result;
@@ -28,9 +28,7 @@ export async function run(projectPath: string) {
28
28
  ...(pkg.dev ? [pm.agent === 'yarn' ? '--dev' : '--save-dev'] : []),
29
29
  ]);
30
30
  if (!resolved) {
31
- throw new CliError(
32
- `Unable to determine how to install package "${pkg.name}". Please install it manually.`
33
- );
31
+ throw new CliError(`Unable to determine how to install package "${pkg.name}". Please install it manually.`);
34
32
  }
35
33
 
36
34
  const spinner = ora(`Installing "${pkg.name}"`).start();
@@ -51,32 +49,13 @@ export async function run(projectPath: string) {
51
49
  fs.mkdirSync(path.join(projectPath, generationFolder));
52
50
  }
53
51
 
54
- if (
55
- !fs.existsSync(
56
- path.join(projectPath, generationFolder, 'schema.zmodel')
57
- )
58
- ) {
59
- fs.writeFileSync(
60
- path.join(projectPath, generationFolder, 'schema.zmodel'),
61
- STARTER_ZMODEL
62
- );
52
+ if (!fs.existsSync(path.join(projectPath, generationFolder, 'schema.zmodel'))) {
53
+ fs.writeFileSync(path.join(projectPath, generationFolder, 'schema.zmodel'), STARTER_ZMODEL);
63
54
  } else {
64
- console.log(
65
- colors.yellow(
66
- 'Schema file already exists. Skipping generation of sample.'
67
- )
68
- );
55
+ console.log(colors.yellow('Schema file already exists. Skipping generation of sample.'));
69
56
  }
70
57
 
71
58
  console.log(colors.green('ZenStack project initialized successfully!'));
72
- console.log(
73
- colors.gray(
74
- `See "${generationFolder}/schema.zmodel" for your database schema.`
75
- )
76
- );
77
- console.log(
78
- colors.gray(
79
- 'Run `zenstack generate` to compile the the schema into a TypeScript file.'
80
- )
81
- );
59
+ console.log(colors.gray(`See "${generationFolder}/schema.zmodel" for your database schema.`));
60
+ console.log(colors.gray('Run `zenstack generate` to compile the the schema into a TypeScript file.'));
82
61
  }
@@ -1,109 +1,101 @@
1
- import path from 'node:path';
1
+ import fs from 'node:fs';
2
2
  import { execPackage } from '../utils/exec-utils';
3
- import { getSchemaFile } from './action-utils';
4
- import { run as runGenerate } from './generate';
3
+ import { generateTempPrismaSchema, getSchemaFile } from './action-utils';
5
4
 
6
5
  type CommonOptions = {
7
6
  schema?: string;
7
+ };
8
+
9
+ type DevOptions = CommonOptions & {
8
10
  name?: string;
11
+ createOnly?: boolean;
12
+ };
13
+
14
+ type ResetOptions = CommonOptions & {
15
+ force?: boolean;
9
16
  };
10
17
 
18
+ type DeployOptions = CommonOptions;
19
+
20
+ type StatusOptions = CommonOptions;
21
+
11
22
  /**
12
23
  * CLI action for migration-related commands
13
24
  */
14
25
  export async function run(command: string, options: CommonOptions) {
15
26
  const schemaFile = getSchemaFile(options.schema);
27
+ const prismaSchemaFile = await generateTempPrismaSchema(schemaFile);
16
28
 
17
- // run generate first
18
- await runGenerate({
19
- schema: schemaFile,
20
- silent: true,
21
- });
22
-
23
- const prismaSchemaFile = path.join(
24
- path.dirname(schemaFile),
25
- 'schema.prisma'
26
- );
27
-
28
- switch (command) {
29
- case 'dev':
30
- await runDev(prismaSchemaFile, options);
31
- break;
29
+ try {
30
+ switch (command) {
31
+ case 'dev':
32
+ await runDev(prismaSchemaFile, options as DevOptions);
33
+ break;
32
34
 
33
- case 'reset':
34
- await runReset(prismaSchemaFile, options as any);
35
- break;
35
+ case 'reset':
36
+ await runReset(prismaSchemaFile, options as ResetOptions);
37
+ break;
36
38
 
37
- case 'deploy':
38
- await runDeploy(prismaSchemaFile, options);
39
- break;
39
+ case 'deploy':
40
+ await runDeploy(prismaSchemaFile, options as DeployOptions);
41
+ break;
40
42
 
41
- case 'status':
42
- await runStatus(prismaSchemaFile, options);
43
- break;
43
+ case 'status':
44
+ await runStatus(prismaSchemaFile, options as StatusOptions);
45
+ break;
46
+ }
47
+ } finally {
48
+ if (fs.existsSync(prismaSchemaFile)) {
49
+ fs.unlinkSync(prismaSchemaFile);
50
+ }
44
51
  }
45
52
  }
46
53
 
47
- async function runDev(prismaSchemaFile: string, _options: unknown) {
54
+ async function runDev(prismaSchemaFile: string, options: DevOptions) {
48
55
  try {
49
56
  await execPackage(
50
- `prisma migrate dev --schema "${prismaSchemaFile}" --skip-generate`,
57
+ `prisma migrate dev --schema "${prismaSchemaFile}" --skip-generate${options.name ? ` --name ${options.name}` : ''}${options.createOnly ? ' --create-only' : ''}`,
51
58
  {
52
59
  stdio: 'inherit',
53
- }
60
+ },
54
61
  );
55
62
  } catch (err) {
56
63
  handleSubProcessError(err);
57
64
  }
58
65
  }
59
66
 
60
- async function runReset(prismaSchemaFile: string, options: { force: boolean }) {
67
+ async function runReset(prismaSchemaFile: string, options: ResetOptions) {
61
68
  try {
62
- await execPackage(
63
- `prisma migrate reset --schema "${prismaSchemaFile}"${
64
- options.force ? ' --force' : ''
65
- }`,
66
- {
67
- stdio: 'inherit',
68
- }
69
- );
69
+ await execPackage(`prisma migrate reset --schema "${prismaSchemaFile}"${options.force ? ' --force' : ''}`, {
70
+ stdio: 'inherit',
71
+ });
70
72
  } catch (err) {
71
73
  handleSubProcessError(err);
72
74
  }
73
75
  }
74
76
 
75
- async function runDeploy(prismaSchemaFile: string, _options: unknown) {
77
+ async function runDeploy(prismaSchemaFile: string, _options: DeployOptions) {
76
78
  try {
77
- await execPackage(
78
- `prisma migrate deploy --schema "${prismaSchemaFile}"`,
79
- {
80
- stdio: 'inherit',
81
- }
82
- );
79
+ await execPackage(`prisma migrate deploy --schema "${prismaSchemaFile}"`, {
80
+ stdio: 'inherit',
81
+ });
83
82
  } catch (err) {
84
83
  handleSubProcessError(err);
85
84
  }
86
85
  }
87
86
 
88
- async function runStatus(prismaSchemaFile: string, _options: unknown) {
87
+ async function runStatus(prismaSchemaFile: string, _options: StatusOptions) {
89
88
  try {
90
- await execPackage(
91
- `prisma migrate status --schema "${prismaSchemaFile}"`,
92
- {
93
- stdio: 'inherit',
94
- }
95
- );
89
+ await execPackage(`prisma migrate status --schema "${prismaSchemaFile}"`, {
90
+ stdio: 'inherit',
91
+ });
96
92
  } catch (err) {
97
93
  handleSubProcessError(err);
98
94
  }
99
95
  }
100
96
 
101
97
  function handleSubProcessError(err: unknown) {
102
- if (
103
- err instanceof Error &&
104
- 'status' in err &&
105
- typeof err.status === 'number'
106
- ) {
98
+ if (err instanceof Error && 'status' in err && typeof err.status === 'number') {
107
99
  process.exit(err.status);
108
100
  } else {
109
101
  process.exit(1);
package/src/index.ts CHANGED
@@ -4,9 +4,7 @@ import { Command, Option } from 'commander';
4
4
  import * as actions from './actions';
5
5
  import { getVersion } from './utils/version-utils';
6
6
 
7
- const generateAction = async (
8
- options: Parameters<typeof actions.generate>[0]
9
- ): Promise<void> => {
7
+ const generateAction = async (options: Parameters<typeof actions.generate>[0]): Promise<void> => {
10
8
  await actions.generate(options);
11
9
  };
12
10
 
@@ -36,60 +34,52 @@ export function createProgram() {
36
34
  program
37
35
  .description(
38
36
  `${colors.bold.blue(
39
- 'ζ'
40
- )} ZenStack is a Prisma power pack for building full-stack apps.\n\nDocumentation: https://zenstack.dev.`
37
+ 'ζ',
38
+ )} ZenStack is a Prisma power pack for building full-stack apps.\n\nDocumentation: https://zenstack.dev.`,
41
39
  )
42
40
  .showHelpAfterError()
43
41
  .showSuggestionAfterError();
44
42
 
45
43
  const schemaOption = new Option(
46
44
  '--schema <file>',
47
- `schema file (with extension ${schemaExtensions}). Defaults to "schema.zmodel" unless specified in package.json.`
45
+ `schema file (with extension ${schemaExtensions}). Defaults to "schema.zmodel" unless specified in package.json.`,
48
46
  );
49
47
 
50
48
  program
51
49
  .command('generate')
52
50
  .description('Run code generation.')
53
51
  .addOption(schemaOption)
52
+ .addOption(new Option('--silent', 'do not print any output'))
54
53
  .addOption(
55
54
  new Option(
56
- '-o, --output <path>',
57
- 'default output directory for core plugins'
58
- )
55
+ '--save-prisma-schema [path]',
56
+ 'save a Prisma schema file, by default into the output directory',
57
+ ),
59
58
  )
59
+ .addOption(new Option('-o, --output <path>', 'default output directory for core plugins'))
60
60
  .action(generateAction);
61
61
 
62
- const migrateCommand = program
63
- .command('migrate')
64
- .description('Update the database schema with migrations.');
62
+ const migrateCommand = program.command('migrate').description('Update the database schema with migrations.');
65
63
 
66
64
  migrateCommand
67
65
  .command('dev')
68
66
  .addOption(schemaOption)
69
67
  .addOption(new Option('-n, --name <name>', 'migration name'))
70
- .addOption(
71
- new Option('--create-only', 'only create migration, do not apply')
72
- )
73
- .description(
74
- 'Create a migration from changes in schema and apply it to the database.'
75
- )
68
+ .addOption(new Option('--create-only', 'only create migration, do not apply'))
69
+ .description('Create a migration from changes in schema and apply it to the database.')
76
70
  .action((options) => migrateAction('dev', options));
77
71
 
78
72
  migrateCommand
79
73
  .command('reset')
80
74
  .addOption(schemaOption)
81
75
  .addOption(new Option('--force', 'skip the confirmation prompt'))
82
- .description(
83
- 'Reset your database and apply all migrations, all data will be lost.'
84
- )
76
+ .description('Reset your database and apply all migrations, all data will be lost.')
85
77
  .action((options) => migrateAction('reset', options));
86
78
 
87
79
  migrateCommand
88
80
  .command('deploy')
89
81
  .addOption(schemaOption)
90
- .description(
91
- 'Deploy your pending migrations to your production/staging database.'
92
- )
82
+ .description('Deploy your pending migrations to your production/staging database.')
93
83
  .action((options) => migrateAction('deploy', options));
94
84
 
95
85
  migrateCommand
@@ -98,30 +88,19 @@ export function createProgram() {
98
88
  .description('check the status of your database migrations.')
99
89
  .action((options) => migrateAction('status', options));
100
90
 
101
- const dbCommand = program
102
- .command('db')
103
- .description('Manage your database schema during development.');
91
+ const dbCommand = program.command('db').description('Manage your database schema during development.');
104
92
 
105
93
  dbCommand
106
94
  .command('push')
107
95
  .description('Push the state from your schema to your database')
108
96
  .addOption(schemaOption)
109
- .addOption(
110
- new Option('--accept-data-loss', 'ignore data loss warnings')
111
- )
112
- .addOption(
113
- new Option(
114
- '--force-reset',
115
- 'force a reset of the database before push'
116
- )
117
- )
97
+ .addOption(new Option('--accept-data-loss', 'ignore data loss warnings'))
98
+ .addOption(new Option('--force-reset', 'force a reset of the database before push'))
118
99
  .action((options) => dbAction('push', options));
119
100
 
120
101
  program
121
102
  .command('info')
122
- .description(
123
- 'Get information of installed ZenStack and related packages.'
124
- )
103
+ .description('Get information of installed ZenStack and related packages.')
125
104
  .argument('[path]', 'project path', '.')
126
105
  .action(infoAction);
127
106
 
@@ -3,10 +3,7 @@ import { execSync as _exec, type ExecSyncOptions } from 'child_process';
3
3
  /**
4
4
  * Utility for executing command synchronously and prints outputs on current console
5
5
  */
6
- export function execSync(
7
- cmd: string,
8
- options?: Omit<ExecSyncOptions, 'env'> & { env?: Record<string, string> }
9
- ): void {
6
+ export function execSync(cmd: string, options?: Omit<ExecSyncOptions, 'env'> & { env?: Record<string, string> }): void {
10
7
  const { env, ...restOptions } = options ?? {};
11
8
  const mergedEnv = env ? { ...process.env, ...env } : undefined;
12
9
  _exec(cmd, {
@@ -22,7 +19,7 @@ export function execSync(
22
19
  */
23
20
  export function execPackage(
24
21
  cmd: string,
25
- options?: Omit<ExecSyncOptions, 'env'> & { env?: Record<string, string> }
22
+ options?: Omit<ExecSyncOptions, 'env'> & { env?: Record<string, string> },
26
23
  ): void {
27
24
  const packageManager = process?.versions?.['bun'] ? 'bunx' : 'npx';
28
25
  execSync(`${packageManager} ${cmd}`, options);
@@ -1,13 +1,13 @@
1
- /* eslint-disable @typescript-eslint/no-var-requires */
2
- export function getVersion(): string | undefined {
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ export function getVersion() {
3
6
  try {
4
- return require('../package.json').version;
7
+ // isomorphic __dirname
8
+ const _dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
9
+ return JSON.parse(fs.readFileSync(path.join(_dirname, '../package.json'), 'utf8')).version;
5
10
  } catch {
6
- try {
7
- // dev environment
8
- return require('../../package.json').version;
9
- } catch {
10
- return undefined;
11
- }
11
+ return undefined;
12
12
  }
13
13
  }
@@ -0,0 +1,18 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { createProject, runCli } from './utils';
5
+
6
+ const model = `
7
+ model User {
8
+ id String @id @default(cuid())
9
+ }
10
+ `;
11
+
12
+ describe('CLI db commands test', () => {
13
+ it('should generate a database with db push', () => {
14
+ const workDir = createProject(model);
15
+ runCli('db push', workDir);
16
+ expect(fs.existsSync(path.join(workDir, 'zenstack/dev.db'))).toBe(true);
17
+ });
18
+ });