Skip to content
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
1 change: 1 addition & 0 deletions packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"langium": "^0.5.0",
"mixpanel": "^0.17.0",
"node-machine-id": "^1.1.12",
"ora": "^6.1.2",
"pluralize": "^8.0.0",
"prisma": "~4.7.0",
"promisify": "^0.0.3",
Expand Down
19 changes: 13 additions & 6 deletions packages/schema/src/generator/field-constraint/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { Context, Generator } from '../types';
import { Project, SourceFile } from 'ts-morph';
import * as path from 'path';
import colors from 'colors';
import {
DataModel,
DataModelField,
Expand All @@ -10,6 +6,9 @@ import {
isLiteralExpr,
LiteralExpr,
} from '@lang/generated/ast';
import * as path from 'path';
import { Project, SourceFile } from 'ts-morph';
import { Context, Generator } from '../types';

/**
* Generates field constraint validators (run on both client and server side)
Expand All @@ -19,7 +18,15 @@ export default class FieldConstraintGenerator implements Generator {
return 'field-constraint';
}

async generate(context: Context): Promise<void> {
get startMessage() {
return 'Generating field constraints...';
}

get successMessage() {
return 'Successfully generated field constraints';
}

async generate(context: Context) {
const project = new Project();
const sf = project.createSourceFile(
path.join(
Expand All @@ -41,7 +48,7 @@ export default class FieldConstraintGenerator implements Generator {
sf.formatText();
await project.save();

console.log(colors.blue(` ✔️ Field constraint validators generated`));
return [];
}

private generateConstraints(sf: SourceFile, model: DataModel) {
Expand Down
21 changes: 15 additions & 6 deletions packages/schema/src/generator/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { Context } from './types';
import { Context, Generator } from './types';
import * as fs from 'fs';
import colors from 'colors';
import PrismaGenerator from './prisma';
Expand All @@ -8,6 +8,7 @@ import ReactHooksGenerator from './react-hooks';
import { TypescriptCompilation } from './tsc';
import FieldConstraintGenerator from './field-constraint';
import telemetry from '../telemetry';
import ora from 'ora';

/**
* ZenStack code generator
Expand Down Expand Up @@ -37,18 +38,19 @@ export class ZenStackGenerator {
fs.mkdirSync(context.generatedCodeDir);
}

const version = require('../../package.json').version;
console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));

// TODO: plugin mechanism
const generators = [
const generators: Generator[] = [
new PrismaGenerator(),
new ServiceGenerator(),
new ReactHooksGenerator(),
new FieldConstraintGenerator(),
new TypescriptCompilation(),
];

const version = require('../../package.json').version;
console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`));

const warnings: string[] = [];
for (const generator of generators) {
if (
includeGenerators &&
Expand All @@ -57,21 +59,28 @@ export class ZenStackGenerator {
continue;
}

const spinner = ora(generator.startMessage).start();
await telemetry.trackSpan(
'cli:generator:start',
'cli:generator:complete',
'cli:generator:error',
{
generator: generator.name,
},
() => generator.generate(context)
async () => {
const genWarnings = await generator.generate(context);
warnings.push(...genWarnings);
}
);
spinner.succeed(`${colors.cyan(generator.successMessage)}`);
}

console.log(
colors.green(
colors.bold('👻 All generators completed successfully!')
)
);

warnings.forEach((w) => console.warn(colors.yellow(w)));
}
}
19 changes: 12 additions & 7 deletions packages/schema/src/generator/prisma/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import colors from 'colors';
import { Context, Generator, GeneratorError } from '../types';
import { execSync } from '../../utils/exec-utils';
import PrismaSchemaGenerator from './schema-generator';
import { Context, Generator, GeneratorError } from '../types';
import QueryGuardGenerator from './query-guard-generator';
import PrismaSchemaGenerator from './schema-generator';

/**
* Generates Prisma schema and db client
Expand All @@ -12,7 +11,15 @@ export default class PrismaGenerator implements Generator {
return 'prisma';
}

async generate(context: Context): Promise<void> {
get startMessage() {
return 'Generating Prisma client...';
}

get successMessage() {
return 'Successfully generated Prisma client';
}

async generate(context: Context) {
// generate prisma schema
const schemaFile = await new PrismaSchemaGenerator(context).generate();

Expand All @@ -22,9 +29,7 @@ export default class PrismaGenerator implements Generator {
// generate prisma query guard
await new QueryGuardGenerator(context).generate();

console.log(
colors.blue(` ✔️ Prisma schema and query guard generated`)
);
return [];
}

private async generatePrismaClient(schemaFile: string) {
Expand Down
29 changes: 17 additions & 12 deletions packages/schema/src/generator/react-hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Context, Generator } from '../types';
import { Project } from 'ts-morph';
import * as path from 'path';
import { paramCase } from 'change-case';
import { DataModel, isDataModel } from '@lang/generated/ast';
import colors from 'colors';
import { paramCase } from 'change-case';
import * as path from 'path';
import { Project } from 'ts-morph';
import { API_ROUTE_NAME, RUNTIME_PACKAGE } from '../constants';
import { Context, Generator } from '../types';

/**
* Generate react data query hooks code
Expand All @@ -14,9 +13,18 @@ export default class ReactHooksGenerator implements Generator {
return 'react-hooks';
}

async generate(context: Context): Promise<void> {
get startMessage() {
return 'Generating React hooks...';
}

get successMessage(): string {
return 'Successfully generated React hooks';
}

async generate(context: Context) {
const project = new Project();
const models: DataModel[] = [];
const warnings: string[] = [];

for (const model of context.schema.declarations.filter(
(d): d is DataModel => isDataModel(d)
Expand All @@ -25,10 +33,8 @@ export default class ReactHooksGenerator implements Generator {
(attr) => attr.decl.ref?.name === '@@allow'
);
if (!hasAllowRule) {
console.warn(
colors.yellow(
`Not generating hooks for "${model.name}" because it doesn't have any @@allow rule`
)
warnings.push(
`Not generating hooks for "${model.name}" because it doesn't have any @@allow rule`
);
} else {
models.push(model);
Expand All @@ -40,8 +46,7 @@ export default class ReactHooksGenerator implements Generator {
models.forEach((d) => this.generateModelHooks(project, context, d));

await project.save();

console.log(colors.blue(' ✔️ React hooks generated'));
return warnings;
}

private getValidator(model: DataModel, mode: 'create' | 'update') {
Expand Down
13 changes: 10 additions & 3 deletions packages/schema/src/generator/service/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DataModel, isDataModel } from '@lang/generated/ast';
import { camelCase } from 'change-case';
import colors from 'colors';
import * as path from 'path';
import { Project } from 'ts-morph';
import { RUNTIME_PACKAGE } from '../constants';
Expand All @@ -14,7 +13,15 @@ export default class ServiceGenerator implements Generator {
return 'service';
}

async generate(context: Context): Promise<void> {
get startMessage() {
return 'Generating ZenStack service...';
}

get successMessage() {
return 'Successfully generated ZenStack service';
}

async generate(context: Context) {
const project = new Project();
const sf = project.createSourceFile(
path.join(context.generatedCodeDir, 'src/index.ts'),
Expand Down Expand Up @@ -101,6 +108,6 @@ export default class ServiceGenerator implements Generator {
sf.formatText();
await project.save();

console.log(colors.blue(` ✔️ ZenStack service generated`));
return [];
}
}
11 changes: 9 additions & 2 deletions packages/schema/src/generator/tsc/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* 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';
Expand All @@ -10,6 +9,14 @@ export class TypescriptCompilation implements Generator {
return 'tsc';
}

get startMessage() {
return 'Transpiling generated code...';
}

get successMessage() {
return 'Successfully transpiled all generated code';
}

async generate(context: Context) {
// generate package.json
const packageJson = require(path.join(
Expand Down Expand Up @@ -47,6 +54,6 @@ export class TypescriptCompilation implements Generator {
);
}

console.log(colors.blue(' ✔️ Typescript source files transpiled'));
return [];
}
}
4 changes: 3 additions & 1 deletion packages/schema/src/generator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export interface Context {

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

export class GeneratorError extends Error {
Expand Down
Loading