@zenstackhq/cli 3.0.0-beta.2 → 3.0.0-beta.20

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.
@@ -13,7 +13,7 @@ import { STARTER_ZMODEL } from './templates';
13
13
  export async function run(projectPath: string) {
14
14
  const packages = [
15
15
  { name: '@zenstackhq/cli@next', dev: true },
16
- { name: '@zenstackhq/runtime@next', dev: false },
16
+ { name: '@zenstackhq/orm@next', dev: false },
17
17
  ];
18
18
  let pm = await detect();
19
19
  if (!pm) {
@@ -82,9 +82,12 @@ async function runDev(prismaSchemaFile: string, options: DevOptions) {
82
82
 
83
83
  async function runReset(prismaSchemaFile: string, options: ResetOptions) {
84
84
  try {
85
- const cmd = ['prisma migrate reset', ` --schema "${prismaSchemaFile}"`, options.force ? ' --force' : ''].join(
86
- '',
87
- );
85
+ const cmd = [
86
+ 'prisma migrate reset',
87
+ ` --schema "${prismaSchemaFile}"`,
88
+ ' --skip-generate',
89
+ options.force ? ' --force' : '',
90
+ ].join('');
88
91
 
89
92
  await execPackage(cmd);
90
93
  } catch (err) {
@@ -26,7 +26,7 @@ model Post {
26
26
  }
27
27
  `;
28
28
 
29
- export const STARTER_MAIN_TS = `import { ZenStackClient } from '@zenstackhq/runtime';
29
+ export const STARTER_MAIN_TS = `import { ZenStackClient } from '@zenstackhq/orm';
30
30
  import SQLite from 'better-sqlite3';
31
31
  import { SqliteDialect } from 'kysely';
32
32
  import { schema } from './zenstack/schema';
package/src/constants.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  // replaced at build time
2
2
  export const TELEMETRY_TRACKING_TOKEN = '<TELEMETRY_TRACKING_TOKEN>';
3
+
4
+ // plugin-contributed model file name
5
+ export const PLUGIN_MODULE_NAME = 'plugin.zmodel';
package/src/index.ts CHANGED
@@ -59,6 +59,8 @@ function createProgram() {
59
59
  .addOption(schemaOption)
60
60
  .addOption(noVersionCheckOption)
61
61
  .addOption(new Option('-o, --output <path>', 'default output directory for code generation'))
62
+ .addOption(new Option('--lite', 'also generate a lite version of schema without attributes').default(false))
63
+ .addOption(new Option('--lite-only', 'only generate lite version of schema without attributes').default(false))
62
64
  .addOption(new Option('--silent', 'suppress all output except errors').default(false))
63
65
  .action(generateAction);
64
66
 
@@ -5,10 +5,10 @@ import path from 'node:path';
5
5
  const plugin: CliPlugin = {
6
6
  name: 'Prisma Schema Generator',
7
7
  statusText: 'Generating Prisma schema',
8
- async generate({ model, schemaFile, defaultOutputPath, pluginOptions }) {
8
+ async generate({ model, defaultOutputPath, pluginOptions }) {
9
9
  let outFile = path.join(defaultOutputPath, 'schema.prisma');
10
10
  if (typeof pluginOptions['output'] === 'string') {
11
- outFile = path.resolve(path.dirname(schemaFile), pluginOptions['output']);
11
+ outFile = path.resolve(defaultOutputPath, pluginOptions['output']);
12
12
  if (!fs.existsSync(path.dirname(outFile))) {
13
13
  fs.mkdirSync(path.dirname(outFile), { recursive: true });
14
14
  }
@@ -7,6 +7,7 @@ const plugin: CliPlugin = {
7
7
  name: 'TypeScript Schema Generator',
8
8
  statusText: 'Generating TypeScript schema',
9
9
  async generate({ model, defaultOutputPath, pluginOptions }) {
10
+ // output path
10
11
  let outDir = defaultOutputPath;
11
12
  if (typeof pluginOptions['output'] === 'string') {
12
13
  outDir = path.resolve(defaultOutputPath, pluginOptions['output']);
@@ -14,7 +15,14 @@ const plugin: CliPlugin = {
14
15
  fs.mkdirSync(outDir, { recursive: true });
15
16
  }
16
17
  }
17
- await new TsSchemaGenerator().generate(model, outDir);
18
+
19
+ // lite mode
20
+ const lite = pluginOptions['lite'] === true;
21
+
22
+ // liteOnly mode
23
+ const liteOnly = pluginOptions['liteOnly'] === true;
24
+
25
+ await new TsSchemaGenerator().generate(model, { outDir, lite, liteOnly });
18
26
  },
19
27
  };
20
28
 
@@ -44,4 +44,18 @@ describe('CLI generate command test', () => {
44
44
  runCli('generate', workDir);
45
45
  expect(fs.existsSync(path.join(workDir, 'bar/schema.ts'))).toBe(true);
46
46
  });
47
+
48
+ it('should respect lite option', () => {
49
+ const workDir = createProject(model);
50
+ runCli('generate --lite', workDir);
51
+ expect(fs.existsSync(path.join(workDir, 'zenstack/schema.ts'))).toBe(true);
52
+ expect(fs.existsSync(path.join(workDir, 'zenstack/schema-lite.ts'))).toBe(true);
53
+ });
54
+
55
+ it('should respect liteOnly option', () => {
56
+ const workDir = createProject(model);
57
+ runCli('generate --lite-only', workDir);
58
+ expect(fs.existsSync(path.join(workDir, 'zenstack/schema.ts'))).toBe(false);
59
+ expect(fs.existsSync(path.join(workDir, 'zenstack/schema-lite.ts'))).toBe(true);
60
+ });
47
61
  });
@@ -57,4 +57,25 @@ model User {
57
57
  runCli('generate', workDir);
58
58
  expect(fs.existsSync(path.join(workDir, 'prisma/schema.prisma'))).toBe(true);
59
59
  });
60
+
61
+ it('can generate a Prisma schema with custom output relative to zenstack.output', () => {
62
+ const workDir = createProject(`
63
+ plugin prisma {
64
+ provider = '@core/prisma'
65
+ output = './schema.prisma'
66
+ }
67
+
68
+ model User {
69
+ id String @id @default(cuid())
70
+ }
71
+ `);
72
+
73
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(workDir, 'package.json'), 'utf8'));
74
+ pkgJson.zenstack = {
75
+ output: './relative',
76
+ };
77
+ fs.writeFileSync(path.join(workDir, 'package.json'), JSON.stringify(pkgJson, null, 2));
78
+ runCli('generate', workDir);
79
+ expect(fs.existsSync(path.join(workDir, 'relative/schema.prisma'))).toBe(true);
80
+ });
60
81
  });
@@ -1,4 +1,4 @@
1
- import { ExpressionUtils } from '@zenstackhq/runtime/schema';
1
+ import { ExpressionUtils } from '@zenstackhq/orm/schema';
2
2
  import { createTestProject, generateTsSchema, generateTsSchemaInPlace } from '@zenstackhq/testtools';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
@@ -360,4 +360,86 @@ model User extends Base {
360
360
  expect(schema.enums).toMatchObject({ Role: expect.any(Object) });
361
361
  expect(schema.models).toMatchObject({ User: expect.any(Object) });
362
362
  });
363
+
364
+ it('generates correct default literal function arguments', async () => {
365
+ const { schema } = await generateTsSchema(`
366
+ model User {
367
+ id String @id @default(uuid(7))
368
+ }
369
+ `);
370
+
371
+ expect(schema.models).toMatchObject({
372
+ User: {
373
+ name: 'User',
374
+ fields: {
375
+ id: {
376
+ name: 'id',
377
+ type: 'String',
378
+ id: true,
379
+ attributes: [
380
+ {
381
+ name: '@id',
382
+ },
383
+ {
384
+ name: '@default',
385
+ args: [
386
+ {
387
+ name: 'value',
388
+ value: {
389
+ kind: 'call',
390
+ function: 'uuid',
391
+ args: [
392
+ {
393
+ kind: 'literal',
394
+ value: 7,
395
+ },
396
+ ],
397
+ },
398
+ },
399
+ ],
400
+ },
401
+ ],
402
+ default: {
403
+ kind: 'call',
404
+ function: 'uuid',
405
+ args: [
406
+ {
407
+ kind: 'literal',
408
+ value: 7,
409
+ },
410
+ ],
411
+ },
412
+ },
413
+ },
414
+ idFields: ['id'],
415
+ uniqueFields: {
416
+ id: {
417
+ type: 'String',
418
+ },
419
+ },
420
+ },
421
+ });
422
+ });
423
+
424
+ it('supports lite schema generation', async () => {
425
+ const { schemaLite } = await generateTsSchema(
426
+ `
427
+ model User {
428
+ id String @id @default(uuid())
429
+ name String
430
+ email String @unique
431
+
432
+ @@map('users')
433
+ }
434
+ `,
435
+ undefined,
436
+ undefined,
437
+ undefined,
438
+ true,
439
+ );
440
+
441
+ expect(schemaLite!.models.User.attributes).toBeUndefined();
442
+ expect(schemaLite!.models.User.fields.id.attributes).toBeUndefined();
443
+ expect(schemaLite!.models.User.fields.email.attributes).toBeUndefined();
444
+ });
363
445
  });
package/tsup.config.ts CHANGED
@@ -1,5 +1,3 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
1
  import { defineConfig } from 'tsup';
4
2
 
5
3
  export default defineConfig({
@@ -12,19 +10,4 @@ export default defineConfig({
12
10
  clean: true,
13
11
  dts: true,
14
12
  format: ['esm', 'cjs'],
15
- onSuccess: async () => {
16
- if (!process.env['TELEMETRY_TRACKING_TOKEN']) {
17
- return;
18
- }
19
- const filesToProcess = ['dist/index.js', 'dist/index.cjs'];
20
- for (const file of filesToProcess) {
21
- console.log(`Processing ${file} for telemetry token...`);
22
- const content = fs.readFileSync(path.join(__dirname, file), 'utf-8');
23
- const updatedContent = content.replace(
24
- '<TELEMETRY_TRACKING_TOKEN>',
25
- process.env['TELEMETRY_TRACKING_TOKEN'],
26
- );
27
- fs.writeFileSync(file, updatedContent, 'utf-8');
28
- }
29
- },
30
13
  });