@zenstackhq/cli 3.0.0-alpha.0
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 +23 -0
- package/.turbo/turbo-lint.log +18 -0
- package/LICENSE +21 -0
- package/bin/cli +3 -0
- package/dist/index.cjs +543 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +517 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
- package/src/actions/action-utils.ts +47 -0
- package/src/actions/db.ts +46 -0
- package/src/actions/generate.ts +70 -0
- package/src/actions/index.ts +7 -0
- package/src/actions/info.ts +77 -0
- package/src/actions/init.ts +82 -0
- package/src/actions/migrate.ts +111 -0
- package/src/actions/templates.ts +52 -0
- package/src/cli-error.ts +4 -0
- package/src/index.ts +138 -0
- package/src/utils/exec-utils.ts +29 -0
- package/src/utils/version-utils.ts +13 -0
- package/test/ts-schema-gen.test.ts +185 -0
- package/tsconfig.json +7 -0
- package/tsup.config.ts +13 -0
- package/vitest.config.ts +4 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ZModelLanguageMetaData } from '@zenstackhq/language';
|
|
2
|
+
import colors from 'colors';
|
|
3
|
+
import { Command, Option } from 'commander';
|
|
4
|
+
import * as actions from './actions';
|
|
5
|
+
import { getVersion } from './utils/version-utils';
|
|
6
|
+
|
|
7
|
+
const generateAction = async (
|
|
8
|
+
options: Parameters<typeof actions.generate>[0]
|
|
9
|
+
): Promise<void> => {
|
|
10
|
+
await actions.generate(options);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const migrateAction = async (command: string, options: any): Promise<void> => {
|
|
14
|
+
await actions.migrate(command, options);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const dbAction = async (command: string, options: any): Promise<void> => {
|
|
18
|
+
await actions.db(command, options);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const infoAction = async (projectPath: string): Promise<void> => {
|
|
22
|
+
await actions.info(projectPath);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const initAction = async (projectPath: string): Promise<void> => {
|
|
26
|
+
await actions.init(projectPath);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function createProgram() {
|
|
30
|
+
const program = new Command('zenstack');
|
|
31
|
+
|
|
32
|
+
program.version(getVersion()!, '-v --version', 'display CLI version');
|
|
33
|
+
|
|
34
|
+
const schemaExtensions = ZModelLanguageMetaData.fileExtensions.join(', ');
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.description(
|
|
38
|
+
`${colors.bold.blue(
|
|
39
|
+
'ζ'
|
|
40
|
+
)} ZenStack is a Prisma power pack for building full-stack apps.\n\nDocumentation: https://zenstack.dev.`
|
|
41
|
+
)
|
|
42
|
+
.showHelpAfterError()
|
|
43
|
+
.showSuggestionAfterError();
|
|
44
|
+
|
|
45
|
+
const schemaOption = new Option(
|
|
46
|
+
'--schema <file>',
|
|
47
|
+
`schema file (with extension ${schemaExtensions}). Defaults to "schema.zmodel" unless specified in package.json.`
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
program
|
|
51
|
+
.command('generate')
|
|
52
|
+
.description('Run code generation.')
|
|
53
|
+
.addOption(schemaOption)
|
|
54
|
+
.addOption(
|
|
55
|
+
new Option(
|
|
56
|
+
'-o, --output <path>',
|
|
57
|
+
'default output directory for core plugins'
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
.action(generateAction);
|
|
61
|
+
|
|
62
|
+
const migrateCommand = program
|
|
63
|
+
.command('migrate')
|
|
64
|
+
.description('Update the database schema with migrations.');
|
|
65
|
+
|
|
66
|
+
migrateCommand
|
|
67
|
+
.command('dev')
|
|
68
|
+
.addOption(schemaOption)
|
|
69
|
+
.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
|
+
)
|
|
76
|
+
.action((options) => migrateAction('dev', options));
|
|
77
|
+
|
|
78
|
+
migrateCommand
|
|
79
|
+
.command('reset')
|
|
80
|
+
.addOption(schemaOption)
|
|
81
|
+
.addOption(new Option('--force', 'skip the confirmation prompt'))
|
|
82
|
+
.description(
|
|
83
|
+
'Reset your database and apply all migrations, all data will be lost.'
|
|
84
|
+
)
|
|
85
|
+
.action((options) => migrateAction('reset', options));
|
|
86
|
+
|
|
87
|
+
migrateCommand
|
|
88
|
+
.command('deploy')
|
|
89
|
+
.addOption(schemaOption)
|
|
90
|
+
.description(
|
|
91
|
+
'Deploy your pending migrations to your production/staging database.'
|
|
92
|
+
)
|
|
93
|
+
.action((options) => migrateAction('deploy', options));
|
|
94
|
+
|
|
95
|
+
migrateCommand
|
|
96
|
+
.command('status')
|
|
97
|
+
.addOption(schemaOption)
|
|
98
|
+
.description('check the status of your database migrations.')
|
|
99
|
+
.action((options) => migrateAction('status', options));
|
|
100
|
+
|
|
101
|
+
const dbCommand = program
|
|
102
|
+
.command('db')
|
|
103
|
+
.description('Manage your database schema during development.');
|
|
104
|
+
|
|
105
|
+
dbCommand
|
|
106
|
+
.command('push')
|
|
107
|
+
.description('Push the state from your schema to your database')
|
|
108
|
+
.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
|
+
)
|
|
118
|
+
.action((options) => dbAction('push', options));
|
|
119
|
+
|
|
120
|
+
program
|
|
121
|
+
.command('info')
|
|
122
|
+
.description(
|
|
123
|
+
'Get information of installed ZenStack and related packages.'
|
|
124
|
+
)
|
|
125
|
+
.argument('[path]', 'project path', '.')
|
|
126
|
+
.action(infoAction);
|
|
127
|
+
|
|
128
|
+
program
|
|
129
|
+
.command('init')
|
|
130
|
+
.description('Initialize an existing project for ZenStack.')
|
|
131
|
+
.argument('[path]', 'project path', '.')
|
|
132
|
+
.action(initAction);
|
|
133
|
+
|
|
134
|
+
return program;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const program = createProgram();
|
|
138
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { execSync as _exec, type ExecSyncOptions } from 'child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility for executing command synchronously and prints outputs on current console
|
|
5
|
+
*/
|
|
6
|
+
export function execSync(
|
|
7
|
+
cmd: string,
|
|
8
|
+
options?: Omit<ExecSyncOptions, 'env'> & { env?: Record<string, string> }
|
|
9
|
+
): void {
|
|
10
|
+
const { env, ...restOptions } = options ?? {};
|
|
11
|
+
const mergedEnv = env ? { ...process.env, ...env } : undefined;
|
|
12
|
+
_exec(cmd, {
|
|
13
|
+
encoding: 'utf-8',
|
|
14
|
+
stdio: options?.stdio ?? 'inherit',
|
|
15
|
+
env: mergedEnv,
|
|
16
|
+
...restOptions,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Utility for running package commands through npx/bunx
|
|
22
|
+
*/
|
|
23
|
+
export function execPackage(
|
|
24
|
+
cmd: string,
|
|
25
|
+
options?: Omit<ExecSyncOptions, 'env'> & { env?: Record<string, string> }
|
|
26
|
+
): void {
|
|
27
|
+
const packageManager = process?.versions?.['bun'] ? 'bunx' : 'npx';
|
|
28
|
+
execSync(`${packageManager} ${cmd}`, options);
|
|
29
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
export function getVersion(): string | undefined {
|
|
3
|
+
try {
|
|
4
|
+
return require('../package.json').version;
|
|
5
|
+
} catch {
|
|
6
|
+
try {
|
|
7
|
+
// dev environment
|
|
8
|
+
return require('../../package.json').version;
|
|
9
|
+
} catch {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { ExpressionUtils } from '@zenstackhq/runtime/schema';
|
|
2
|
+
import { generateTsSchema } from '@zenstackhq/testtools';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
describe('TypeScript schema generation tests', () => {
|
|
6
|
+
it('generates correct data models', async () => {
|
|
7
|
+
const { schema } = await generateTsSchema(`
|
|
8
|
+
model User {
|
|
9
|
+
id String @id @default(uuid())
|
|
10
|
+
name String
|
|
11
|
+
email String @unique
|
|
12
|
+
createdAt DateTime @default(now())
|
|
13
|
+
updatedAt DateTime @updatedAt
|
|
14
|
+
posts Post[]
|
|
15
|
+
|
|
16
|
+
@@map('users')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
model Post {
|
|
20
|
+
id String @id @default(cuid())
|
|
21
|
+
title String
|
|
22
|
+
published Boolean @default(false)
|
|
23
|
+
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
24
|
+
authorId String
|
|
25
|
+
}
|
|
26
|
+
`);
|
|
27
|
+
|
|
28
|
+
expect(schema.provider).toMatchObject({
|
|
29
|
+
type: 'sqlite',
|
|
30
|
+
dialectConfigProvider: expect.any(Function),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(schema.models).toMatchObject({
|
|
34
|
+
User: {
|
|
35
|
+
fields: {
|
|
36
|
+
id: {
|
|
37
|
+
type: 'String',
|
|
38
|
+
id: true,
|
|
39
|
+
default: ExpressionUtils.call('uuid'),
|
|
40
|
+
attributes: [
|
|
41
|
+
{ name: '@id' },
|
|
42
|
+
{
|
|
43
|
+
name: '@default',
|
|
44
|
+
args: [
|
|
45
|
+
{
|
|
46
|
+
value: {
|
|
47
|
+
kind: 'call',
|
|
48
|
+
function: 'uuid',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
name: { type: 'String' },
|
|
56
|
+
email: { type: 'String', unique: true },
|
|
57
|
+
createdAt: {
|
|
58
|
+
type: 'DateTime',
|
|
59
|
+
default: ExpressionUtils.call('now'),
|
|
60
|
+
attributes: [
|
|
61
|
+
{
|
|
62
|
+
name: '@default',
|
|
63
|
+
args: [
|
|
64
|
+
{
|
|
65
|
+
value: {
|
|
66
|
+
kind: 'call',
|
|
67
|
+
function: 'now',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
updatedAt: {
|
|
75
|
+
type: 'DateTime',
|
|
76
|
+
attributes: [
|
|
77
|
+
{
|
|
78
|
+
name: '@updatedAt',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
updatedAt: true,
|
|
82
|
+
},
|
|
83
|
+
posts: {
|
|
84
|
+
type: 'Post',
|
|
85
|
+
array: true,
|
|
86
|
+
relation: {
|
|
87
|
+
opposite: 'author',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
attributes: [
|
|
92
|
+
{
|
|
93
|
+
name: '@@map',
|
|
94
|
+
args: [{ name: 'name', value: { kind: 'literal' } }],
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
idFields: ['id'],
|
|
98
|
+
uniqueFields: {
|
|
99
|
+
id: { type: 'String' },
|
|
100
|
+
email: { type: 'String' },
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
Post: {
|
|
104
|
+
fields: {
|
|
105
|
+
id: {
|
|
106
|
+
type: 'String',
|
|
107
|
+
id: true,
|
|
108
|
+
default: ExpressionUtils.call('cuid'),
|
|
109
|
+
attributes: [
|
|
110
|
+
{ name: '@id' },
|
|
111
|
+
{
|
|
112
|
+
name: '@default',
|
|
113
|
+
args: [
|
|
114
|
+
{
|
|
115
|
+
value: {
|
|
116
|
+
kind: 'call',
|
|
117
|
+
function: 'cuid',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
title: { type: 'String' },
|
|
125
|
+
published: {
|
|
126
|
+
type: 'Boolean',
|
|
127
|
+
default: false,
|
|
128
|
+
},
|
|
129
|
+
authorId: { type: 'String' },
|
|
130
|
+
author: {
|
|
131
|
+
type: 'User',
|
|
132
|
+
relation: {
|
|
133
|
+
fields: ['authorId'],
|
|
134
|
+
references: ['id'],
|
|
135
|
+
onDelete: 'Cascade',
|
|
136
|
+
opposite: 'posts',
|
|
137
|
+
},
|
|
138
|
+
attributes: [
|
|
139
|
+
{
|
|
140
|
+
name: '@relation',
|
|
141
|
+
args: [
|
|
142
|
+
{
|
|
143
|
+
name: 'fields',
|
|
144
|
+
value: {
|
|
145
|
+
kind: 'array',
|
|
146
|
+
items: [
|
|
147
|
+
{
|
|
148
|
+
kind: 'field',
|
|
149
|
+
field: 'authorId',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'references',
|
|
156
|
+
value: {
|
|
157
|
+
kind: 'array',
|
|
158
|
+
items: [
|
|
159
|
+
{
|
|
160
|
+
kind: 'field',
|
|
161
|
+
field: 'id',
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'onDelete',
|
|
168
|
+
value: {
|
|
169
|
+
kind: 'literal',
|
|
170
|
+
value: 'Cascade',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
idFields: ['id'],
|
|
179
|
+
uniqueFields: {
|
|
180
|
+
id: { type: 'String' },
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
package/vitest.config.ts
ADDED