Skip to content

Commit

Permalink
fix: canonicalize plugin's output folder detection; don't generate au…
Browse files Browse the repository at this point in the history
…x field unnecessarily (#423)
  • Loading branch information
ymc9 authored May 20, 2023
1 parent a5848ea commit 9eaf235
Show file tree
Hide file tree
Showing 27 changed files with 365 additions and 187 deletions.
7 changes: 5 additions & 2 deletions packages/plugins/openapi/src/generator-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { DMMF } from '@prisma/generator-helper';
import { PluginError, PluginOptions, getDataModels, hasAttribute } from '@zenstackhq/sdk';
import { Model } from '@zenstackhq/sdk/ast';
import type { OpenAPIV3_1 as OAPI } from 'openapi-types';
import { SecuritySchemesSchema } from './schema';
import { fromZodError } from 'zod-validation-error';
import { SecuritySchemesSchema } from './schema';

export abstract class OpenAPIGeneratorBase {
constructor(protected model: Model, protected options: PluginOptions, protected dmmf: DMMF.Document) {}
Expand Down Expand Up @@ -51,7 +51,10 @@ export abstract class OpenAPIGeneratorBase {
if (securitySchemes) {
const parsed = SecuritySchemesSchema.safeParse(securitySchemes);
if (!parsed.success) {
throw new PluginError(`"securitySchemes" option is invalid: ${fromZodError(parsed.error)}`);
throw new PluginError(
this.options.name,
`"securitySchemes" option is invalid: ${fromZodError(parsed.error)}`
);
}
return parsed.data;
}
Expand Down
9 changes: 4 additions & 5 deletions packages/plugins/openapi/src/rest-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import { DMMF } from '@prisma/generator-helper';
import {
AUXILIARY_FIELDS,
PluginError,
analyzePolicies,
getDataModels,
isForeignKeyField,
isIdField,
isRelationshipField,
requireOption,
resolvePath,
} from '@zenstackhq/sdk';
import { DataModel, DataModelField, DataModelFieldType, Enum, isDataModel, isEnum } from '@zenstackhq/sdk/ast';
import * as fs from 'fs';
Expand All @@ -30,10 +31,8 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase {
private warnings: string[] = [];

generate() {
const output = this.getOption('output', '');
if (!output) {
throw new PluginError('"output" option is required');
}
let output = requireOption<string>(this.options, 'output');
output = resolvePath(output, this.options);

const components = this.generateComponents();
const paths = this.generatePaths();
Expand Down
10 changes: 4 additions & 6 deletions packages/plugins/openapi/src/rpc-generator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator

import { DMMF } from '@prisma/generator-helper';
import { analyzePolicies, AUXILIARY_FIELDS, PluginError } from '@zenstackhq/sdk';
import { analyzePolicies, AUXILIARY_FIELDS, PluginError, requireOption, resolvePath } from '@zenstackhq/sdk';
import { DataModel, isDataModel } from '@zenstackhq/sdk/ast';
import {
addMissingInputObjectTypesForAggregate,
Expand Down Expand Up @@ -31,10 +31,8 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
private warnings: string[] = [];

generate() {
const output = this.getOption('output', '');
if (!output) {
throw new PluginError('"output" option is required');
}
let output = requireOption<string>(this.options, 'output');
output = resolvePath(output, this.options);

// input types
this.inputObjectTypes.push(...this.dmmf.schema.inputObjectTypes.prisma);
Expand Down Expand Up @@ -663,7 +661,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
return this.wrapArray(this.ref(def.type, false), def.isList);

default:
throw new PluginError(`Unsupported field kind: ${def.kind}`);
throw new PluginError(this.options.name, `Unsupported field kind: ${def.kind}`);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/react/src/generator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.
case 'react-query':
return reactQueryGenerate(model, options, dmmf);
default:
throw new PluginError(`Unknown "fetcher" option: ${fetcher}, use "swr" or "react-query"`);
throw new PluginError(options.name, `Unknown "fetcher" option: ${fetcher}, use "swr" or "react-query"`);
}
}
14 changes: 4 additions & 10 deletions packages/plugins/react/src/generator/react-query.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import { DMMF } from '@prisma/generator-helper';
import { PluginError, PluginOptions, createProject, getDataModels, saveProject } from '@zenstackhq/sdk';
import { PluginOptions, createProject, getDataModels, saveProject } from '@zenstackhq/sdk';
import { DataModel, Model } from '@zenstackhq/sdk/ast';
import { requireOption, resolvePath } from '@zenstackhq/sdk/utils';
import { paramCase } from 'change-case';
import { lowerCaseFirst } from 'lower-case-first';
import * as path from 'path';
import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph';
import { upperCaseFirst } from 'upper-case-first';

export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) {
let outDir = options.output as string;
if (!outDir) {
throw new PluginError('"output" option is required');
}

if (!path.isAbsolute(outDir)) {
// output dir is resolved relative to the schema file path
outDir = path.join(path.dirname(options.schemaPath), outDir);
}
let outDir = requireOption<string>(options, 'output');
outDir = resolvePath(outDir, options);

const project = createProject();
const warnings: string[] = [];
Expand Down
14 changes: 4 additions & 10 deletions packages/plugins/react/src/generator/swr.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { DMMF } from '@prisma/generator-helper';
import {
CrudFailureReason,
PluginError,
PluginOptions,
createProject,
getDataModels,
requireOption,
resolvePath,
saveProject,
} from '@zenstackhq/sdk';
import { DataModel, Model } from '@zenstackhq/sdk/ast';
Expand All @@ -14,15 +15,8 @@ import * as path from 'path';
import { Project } from 'ts-morph';

export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) {
let outDir = options.output as string;
if (!outDir) {
throw new PluginError('"output" option is required');
}

if (!path.isAbsolute(outDir)) {
// output dir is resolved relative to the schema file path
outDir = path.join(path.dirname(options.schemaPath), outDir);
}
let outDir = requireOption<string>(options, 'output');
outDir = resolvePath(outDir, options);

const project = createProject();
const warnings: string[] = [];
Expand Down
14 changes: 4 additions & 10 deletions packages/plugins/swr/src/generator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { DMMF } from '@prisma/generator-helper';
import {
CrudFailureReason,
PluginError,
PluginOptions,
createProject,
getDataModels,
requireOption,
resolvePath,
saveProject,
} from '@zenstackhq/sdk';
import { DataModel, Model } from '@zenstackhq/sdk/ast';
Expand All @@ -15,15 +16,8 @@ import path from 'path';
import { Project } from 'ts-morph';

export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) {
let outDir = options.output as string;
if (!outDir) {
throw new PluginError('"output" option is required');
}

if (!path.isAbsolute(outDir)) {
// output dir is resolved relative to the schema file path
outDir = path.join(path.dirname(options.schemaPath), outDir);
}
let outDir = requireOption<string>(options, 'output');
outDir = resolvePath(outDir, options);

const project = createProject();
const warnings: string[] = [];
Expand Down
44 changes: 23 additions & 21 deletions packages/plugins/tanstack-query/src/generator.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
import { DMMF } from '@prisma/generator-helper';
import { PluginError, PluginOptions, createProject, getDataModels, saveProject } from '@zenstackhq/sdk';
import {
PluginError,
PluginOptions,
createProject,
getDataModels,
requireOption,
resolvePath,
saveProject,
} from '@zenstackhq/sdk';
import { DataModel, Model } from '@zenstackhq/sdk/ast';
import { paramCase } from 'change-case';
import fs from 'fs';
import { lowerCaseFirst } from 'lower-case-first';
import path from 'path';
import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph';
import { upperCaseFirst } from 'upper-case-first';
import { name } from '.';

const supportedTargets = ['react', 'svelte'];
type TargetFramework = (typeof supportedTargets)[number];

export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) {
let outDir = options.output as string;
if (!outDir) {
throw new PluginError('"output" option is required');
}

if (!path.isAbsolute(outDir)) {
// output dir is resolved relative to the schema file path
outDir = path.join(path.dirname(options.schemaPath), outDir);
}
let outDir = requireOption<string>(options, 'output');
outDir = resolvePath(outDir, options);

const project = createProject();
const warnings: string[] = [];
const models = getDataModels(model);

const target = options.target as string;
if (!target) {
throw new PluginError(`"target" option is required, supported values: ${supportedTargets.join(', ')}`);
}
const target = requireOption<string>(options, 'target');
if (!supportedTargets.includes(target)) {
throw new PluginError(`Unsupported target "${target}", supported values: ${supportedTargets.join(', ')}`);
throw new PluginError(
options.name,
`Unsupported target "${target}", supported values: ${supportedTargets.join(', ')}`
);
}

generateIndex(project, outDir, models);
Expand Down Expand Up @@ -198,7 +200,7 @@ function generateMutationHook(
break;

default:
throw new PluginError(`Unsupported target "${target}"`);
throw new PluginError(name, `Unsupported target "${target}"`);
}

func.addStatements('return mutation;');
Expand Down Expand Up @@ -395,7 +397,7 @@ function generateHelper(target: TargetFramework, project: Project, outDir: strin
srcFile = path.join(__dirname, './res/svelte/helper.ts');
break;
default:
throw new PluginError(`Unsupported target: ${target}`);
throw new PluginError(name, `Unsupported target: ${target}`);
}

// merge content of `shared.ts`, `helper.ts` and `marshal-?.ts`
Expand All @@ -418,7 +420,7 @@ function makeGetContext(target: TargetFramework) {
case 'svelte':
return `const { endpoint } = getContext<RequestHandlerContext>(SvelteQueryContextKey);`;
default:
throw new PluginError(`Unsupported target "${target}"`);
throw new PluginError(name, `Unsupported target "${target}"`);
}
}

Expand All @@ -441,7 +443,7 @@ function makeBaseImports(target: TargetFramework) {
...shared,
];
default:
throw new PluginError(`Unsupported target: ${target}`);
throw new PluginError(name, `Unsupported target: ${target}`);
}
}

Expand All @@ -452,7 +454,7 @@ function makeQueryOptions(target: string, returnType: string) {
case 'svelte':
return `QueryOptions<${returnType}>`;
default:
throw new PluginError(`Unsupported target: ${target}`);
throw new PluginError(name, `Unsupported target: ${target}`);
}
}

Expand All @@ -463,6 +465,6 @@ function makeMutationOptions(target: string, returnType: string, argsType: strin
case 'svelte':
return `MutationOptions<${returnType}, unknown, ${argsType}>`;
default:
throw new PluginError(`Unsupported target: ${target}`);
throw new PluginError(name, `Unsupported target: ${target}`);
}
}
22 changes: 11 additions & 11 deletions packages/plugins/trpc/src/generator.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { DMMF } from '@prisma/generator-helper';
import { CrudFailureReason, PluginError, PluginOptions, RUNTIME_PACKAGE, saveProject } from '@zenstackhq/sdk';
import {
CrudFailureReason,
PluginOptions,
RUNTIME_PACKAGE,
requireOption,
resolvePath,
saveProject,
} from '@zenstackhq/sdk';
import { Model } from '@zenstackhq/sdk/ast';
import { lowerCaseFirst } from 'lower-case-first';
import { promises as fs } from 'fs';
import { lowerCaseFirst } from 'lower-case-first';
import path from 'path';
import { Project } from 'ts-morph';
import {
Expand All @@ -17,15 +24,8 @@ import removeDir from './utils/removeDir';
import { generate as PrismaZodGenerator } from './zod/generator';

export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) {
let outDir = options.output as string;
if (!outDir) {
throw new PluginError('"output" option is required');
}

if (!path.isAbsolute(outDir)) {
// output dir is resolved relative to the schema file path
outDir = path.join(path.dirname(options.schemaPath), outDir);
}
let outDir = requireOption<string>(options, 'output');
outDir = resolvePath(outDir, options);

await fs.mkdir(outDir, { recursive: true });
await removeDir(outDir, true);
Expand Down
6 changes: 4 additions & 2 deletions packages/plugins/trpc/src/zod/generator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ConnectorType, DMMF } from '@prisma/generator-helper';
import { Dictionary } from '@prisma/internals';
import { PluginOptions, getLiteral } from '@zenstackhq/sdk';
import { PluginOptions, getLiteral, resolvePath } from '@zenstackhq/sdk';
import { DataSource, Model, isDataSource } from '@zenstackhq/sdk/ast';
import {
AggregateOperationSupport,
Expand All @@ -14,7 +14,9 @@ import removeDir from './utils/removeDir';
import { writeFileSafely } from './utils/writeFileSafely';

export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) {
const output = (options.output as string) ?? './generated';
let output = (options.output as string) ?? './generated';
output = resolvePath(output, options);

await handleGeneratorOutputValue(output);

const prismaClientDmmf = dmmf;
Expand Down
Loading

0 comments on commit 9eaf235

Please sign in to comment.