Skip to content

fix: regenerate Prisma schema on related cli commands #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-monorepo",
"version": "0.2.10",
"version": "0.2.11",
"description": "",
"scripts": {
"build": "pnpm -r build",
Expand Down
3 changes: 2 additions & 1 deletion packages/internal/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/internal",
"version": "0.2.10",
"version": "0.2.11",
"displayName": "ZenStack Internal Library",
"description": "ZenStack internal runtime library. This package is for supporting runtime functionality of ZenStack and not supposed to be used directly.",
"repository": {
Expand Down Expand Up @@ -42,6 +42,7 @@
"@types/jest": "^29.0.3",
"@types/node": "^14.18.29",
"@types/uuid": "^8.3.4",
"eslint": "^8.27.0",
"jest": "^29.0.3",
"ts-jest": "^29.0.1",
"ts-node": "^10.9.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/runtime",
"displayName": "ZenStack Runtime Library",
"version": "0.2.10",
"version": "0.2.11",
"description": "This package contains runtime library for consuming client and server side code generated by ZenStack.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "zenstack",
"displayName": "ZenStack Language Tools",
"description": "ZenStack is a toolkit that simplifies full-stack development",
"version": "0.2.10",
"version": "0.2.11",
"author": {
"name": "ZenStack Team"
},
Expand Down
34 changes: 34 additions & 0 deletions packages/schema/src/cli/cli-util.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { STD_LIB_MODULE_NAME } from '@lang/constants';
import { Model } from '@lang/generated/ast';
import { createZModelServices } from '@lang/zmodel-module';
import colors from 'colors';
import fs from 'fs';
import { LangiumServices } from 'langium';
import { NodeFileSystem } from 'langium/node';
import path from 'path';
import { ZenStackGenerator } from '../generator';
import { URI } from 'vscode-uri';
import { GENERATED_CODE_PATH } from '../generator/constants';
import { Context, GeneratorError } from '../generator/types';

/**
* Loads a zmodel document from a file.
Expand Down Expand Up @@ -69,3 +74,32 @@ export async function loadDocument(

return document.parseResult.value as Model;
}

export async function runGenerator(
options: { schema: string },
includedGenerators?: string[],
clearOutput = true
) {
const services = createZModelServices(NodeFileSystem).ZModel;
const model = await loadDocument(options.schema, services);

const context: Context = {
schema: model,
outDir: path.dirname(options.schema),
// TODO: make this configurable
generatedCodeDir: GENERATED_CODE_PATH,
};

try {
await new ZenStackGenerator().generate(
context,
includedGenerators,
clearOutput
);
} catch (err) {
if (err instanceof GeneratorError) {
console.error(colors.red(err.message));
process.exit(1);
}
}
}
30 changes: 6 additions & 24 deletions packages/schema/src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Command, Option } from 'commander';
import { NodeFileSystem } from 'langium/node';
import { ZModelLanguageMetaData } from '../language-server/generated/module';
import { createZModelServices } from '../language-server/zmodel-module';
import { Context, GeneratorError } from '../generator/types';
import { ZenStackGenerator } from '../generator';
import { GENERATED_CODE_PATH } from '../generator/constants';
import colors from 'colors';
import { execSync } from '../utils/exec-utils';
import { paramCase } from 'change-case';
import path from 'path';
import { loadDocument } from './cli-util';
import { runGenerator } from './cli-util';

export const generateAction = async (options: {
schema: string;
}): Promise<void> => {
const services = createZModelServices(NodeFileSystem).ZModel;
const model = await loadDocument(options.schema, services);

const context: Context = {
schema: model,
outDir: path.dirname(options.schema),
// TODO: make this configurable
generatedCodeDir: GENERATED_CODE_PATH,
};

try {
await new ZenStackGenerator().generate(context);
} catch (err) {
if (err instanceof GeneratorError) {
console.error(colors.red(err.message));
process.exit(1);
}
}
await runGenerator(options);
};

function prismaAction(prismaCmd: string): (...args: any[]) => Promise<void> {
Expand All @@ -50,6 +28,10 @@ function prismaAction(prismaCmd: string): (...args: any[]) => Promise<void> {
);
})
.join(' ');

// regenerate prisma schema first
await runGenerator(options, ['prisma'], false);

const prismaExec = `npx prisma ${prismaCmd} ${command.name()} ${optStr}`;
console.log(prismaExec);
try {
Expand Down
73 changes: 24 additions & 49 deletions packages/schema/src/generator/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { Context, GeneratorError } from './types';
import { Context } from './types';
import * as fs from 'fs';
import colors from 'colors';
import PrismaGenerator from './prisma';
import ServiceGenerator from './service';
import ReactHooksGenerator from './react-hooks';
import NextAuthGenerator from './next-auth';
import path from 'path';
import { execSync } from '../utils/exec-utils';
import { TypescriptCompilation } from './tsc';

/**
* ZenStack code generator
Expand All @@ -16,20 +15,26 @@ export class ZenStackGenerator {
/**
* Runs a series of nested generators
*/
async generate(context: Context): Promise<void> {
// folder that stores generated prisma schema and migrations
async generate(
context: Context,
includeGenerators?: string[],
clearOutput = true
): Promise<void> {
// ensure folder that stores generated prisma schema and migrations
if (!fs.existsSync(context.outDir)) {
fs.mkdirSync(context.outDir);
}

// folder that stores generated zenstack code
if (fs.existsSync(context.generatedCodeDir)) {
fs.rmSync(context.generatedCodeDir, {
force: true,
recursive: true,
});
if (clearOutput) {
// recreate folder that stores generated zenstack code
if (fs.existsSync(context.generatedCodeDir)) {
fs.rmSync(context.generatedCodeDir, {
force: true,
recursive: true,
});
}
fs.mkdirSync(context.generatedCodeDir);
}
fs.mkdirSync(context.generatedCodeDir);

const version = require('../../package.json').version;
console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));
Expand All @@ -40,49 +45,19 @@ export class ZenStackGenerator {
new ServiceGenerator(),
new ReactHooksGenerator(),
new NextAuthGenerator(),
new TypescriptCompilation(),
];

for (const generator of generators) {
if (
includeGenerators &&
!includeGenerators.includes(generator.name)
) {
continue;
}
await generator.generate(context);
}

// generate package.json
const packageJson = require(path.join(
__dirname,
'../res',
'package.template.json'
));
fs.writeFileSync(
path.join(context.generatedCodeDir, 'package.json'),
JSON.stringify(packageJson, undefined, 4)
);

// compile ts sources
const tsConfig = require(path.join(
__dirname,
'../res',
'tsconfig.template.json'
));
fs.writeFileSync(
path.join(context.generatedCodeDir, 'tsconfig.json'),
JSON.stringify(tsConfig, undefined, 4)
);

try {
execSync(
`npx tsc -p "${path.join(
context.generatedCodeDir,
'tsconfig.json'
)}"`
);
} catch {
throw new GeneratorError(
'Something went wrong, generated runtime code failed to compile...\nPlease check errors above.'
);
}

console.log(colors.blue(' ✔️ Typescript source files transpiled'));

console.log(
colors.green(
colors.bold('👻 All generators completed successfully!')
Expand Down
4 changes: 4 additions & 0 deletions packages/schema/src/generator/next-auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { execSync } from 'child_process';
* Generates NextAuth adaptor code
*/
export default class NextAuthGenerator implements Generator {
get name() {
return 'next-auth';
}

private findModel(schema: Model, name: string) {
return schema.declarations.find(
(d) => isDataModel(d) && d.name === name
Expand Down
4 changes: 4 additions & 0 deletions packages/schema/src/generator/prisma/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import QueryGuardGenerator from './query-guard-generator';
* Generates Prisma schema and db client
*/
export default class PrismaGenerator implements Generator {
get name() {
return 'prisma';
}

async generate(context: Context): Promise<void> {
// generate prisma schema
const schemaFile = await new PrismaSchemaGenerator(context).generate();
Expand Down
4 changes: 4 additions & 0 deletions packages/schema/src/generator/react-hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { API_ROUTE_NAME, INTERNAL_PACKAGE } from '../constants';
* Generate react data query hooks code
*/
export default class ReactHooksGenerator implements Generator {
get name() {
return 'react-hooks';
}

async generate(context: Context): Promise<void> {
const project = new Project();

Expand Down
4 changes: 4 additions & 0 deletions packages/schema/src/generator/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { INTERNAL_PACKAGE } from '../constants';
* Generates ZenStack service code
*/
export default class ServiceGenerator implements Generator {
get name() {
return 'service';
}

async generate(context: Context): Promise<void> {
const project = new Project();
const sf = project.createSourceFile(
Expand Down
52 changes: 52 additions & 0 deletions packages/schema/src/generator/tsc/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import colors from 'colors';
import * as fs from 'fs';
import path from 'path';
import { execSync } from '../../utils/exec-utils';
import { Context, Generator, GeneratorError } from '../types';

export class TypescriptCompilation implements Generator {
get name(): string {
return 'tsc';
}

async generate(context: Context) {
// generate package.json
const packageJson = require(path.join(
__dirname,
'../res',
'package.template.json'
));

fs.writeFileSync(
path.join(context.generatedCodeDir, 'package.json'),
JSON.stringify(packageJson, undefined, 4)
);

// compile ts sources
const tsConfig = require(path.join(
__dirname,
'../res',
'tsconfig.template.json'
));
fs.writeFileSync(
path.join(context.generatedCodeDir, 'tsconfig.json'),
JSON.stringify(tsConfig, undefined, 4)
);

try {
execSync(
`npx tsc -p "${path.join(
context.generatedCodeDir,
'tsconfig.json'
)}"`
);
} catch {
throw new GeneratorError(
'Something went wrong, generated runtime code failed to compile...\nPlease check errors above.'
);
}

console.log(colors.blue(' ✔️ Typescript source files transpiled'));
}
}
1 change: 1 addition & 0 deletions packages/schema/src/generator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Context {
}

export interface Generator {
get name(): string;
generate(context: Context): Promise<void>;
}

Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading