Skip to content

Commit 83bdd6d

Browse files
authored
fix(cli): enhancer code fails to compile when generated into a custom folder (#1678)
1 parent 2275102 commit 83bdd6d

File tree

5 files changed

+130
-9
lines changed

5 files changed

+130
-9
lines changed

packages/schema/src/plugins/enhancer/enhance/index.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
import { upperCaseFirst } from 'upper-case-first';
3939
import { name } from '..';
4040
import { execPackage } from '../../../utils/exec-utils';
41+
import { CorePlugins, getPluginCustomOutputFolder } from '../../plugin-utils';
4142
import { trackPrismaSchemaError } from '../../prisma';
4243
import { PrismaSchemaGenerator } from '../../prisma/schema-generator';
4344
import { isDefaultWithAuth } from '../enhancer-utils';
@@ -100,7 +101,11 @@ import { type EnhancementContext, type EnhancementOptions, type ZodSchemas, type
100101
import { createEnhancement } from '@zenstackhq/runtime/enhancements';
101102
import modelMeta from './model-meta';
102103
import policy from './policy';
103-
${this.options.withZodSchemas ? "import * as zodSchemas from './zod';" : 'const zodSchemas = undefined;'}
104+
${
105+
this.options.withZodSchemas
106+
? `import * as zodSchemas from '${this.getZodImport()}';`
107+
: 'const zodSchemas = undefined;'
108+
}
104109
105110
${
106111
logicalPrismaClientDir
@@ -126,6 +131,27 @@ ${
126131
return { dmmf };
127132
}
128133

134+
private getZodImport() {
135+
const zodCustomOutput = getPluginCustomOutputFolder(this.model, CorePlugins.Zod);
136+
137+
if (!this.options.output && !zodCustomOutput) {
138+
// neither zod or me (enhancer) have custom output, use the default
139+
return './zod';
140+
}
141+
142+
if (!zodCustomOutput) {
143+
// I have a custom output, but zod doesn't, import from runtime
144+
return '@zenstackhq/runtime/zod';
145+
}
146+
147+
// both zod and me have custom output, resolve to relative path and import
148+
const schemaDir = path.dirname(this.options.schemaPath);
149+
const zodAbsPath = path.isAbsolute(zodCustomOutput)
150+
? zodCustomOutput
151+
: path.resolve(schemaDir, zodCustomOutput);
152+
return path.relative(this.outDir, zodAbsPath);
153+
}
154+
129155
private createSimplePrismaImports(prismaImport: string) {
130156
return `import { Prisma, type PrismaClient } from '${prismaImport}';
131157
import type * as _P from '${prismaImport}';

packages/schema/src/plugins/plugin-utils.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { DEFAULT_RUNTIME_LOAD_PATH, type PolicyOperationKind } from '@zenstackhq/runtime';
2-
import { PluginGlobalOptions, ensureEmptyDir } from '@zenstackhq/sdk';
2+
import { PluginGlobalOptions, ensureEmptyDir, getLiteral } from '@zenstackhq/sdk';
33
import fs from 'fs';
44
import path from 'path';
55
import { PluginRunnerOptions } from '../cli/plugin-runner';
6+
import { isPlugin, Model, Plugin } from '@zenstackhq/sdk/ast';
67

78
export const ALL_OPERATION_KINDS: PolicyOperationKind[] = ['create', 'update', 'postUpdate', 'read', 'delete'];
89

@@ -114,3 +115,18 @@ export enum CorePlugins {
114115
Zod = '@core/zod',
115116
Enhancer = '@core/enhancer',
116117
}
118+
119+
/**
120+
* Gets the custom output folder for a plugin.
121+
*/
122+
export function getPluginCustomOutputFolder(zmodel: Model, provider: string) {
123+
const plugin = zmodel.declarations.find(
124+
(d): d is Plugin =>
125+
isPlugin(d) && d.fields.some((f) => f.name === 'provider' && getLiteral<string>(f.value) === provider)
126+
);
127+
if (!plugin) {
128+
return undefined;
129+
}
130+
const output = plugin.fields.find((f) => f.name === 'output');
131+
return output && getLiteral<string>(output.value);
132+
}

packages/testtools/src/schema.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export type SchemaLoadOptions = {
135135
generatePermissionChecker?: boolean;
136136
previewFeatures?: string[];
137137
prismaClientOptions?: object;
138+
generateNoCompile?: boolean;
138139
};
139140

140141
const defaultOptions: SchemaLoadOptions = {
@@ -146,6 +147,7 @@ const defaultOptions: SchemaLoadOptions = {
146147
logPrismaQuery: false,
147148
provider: 'sqlite',
148149
preserveTsFiles: false,
150+
generateNoCompile: false,
149151
};
150152

151153
export async function loadSchemaFromFile(schemaFile: string, options?: SchemaLoadOptions) {
@@ -225,13 +227,20 @@ export async function loadSchema(schema: string, options?: SchemaLoadOptions) {
225227
}
226228

227229
const outputArg = opt.output ? ` --output ${opt.output}` : '';
230+
let otherArgs = '';
231+
if (opt.generateNoCompile) {
232+
otherArgs = ' --no-compile';
233+
}
228234

229235
if (opt.customSchemaFilePath) {
230-
run(`npx zenstack generate --no-version-check --schema ${zmodelPath} --no-dependency-check${outputArg}`, {
231-
NODE_PATH: './node_modules',
232-
});
236+
run(
237+
`npx zenstack generate --no-version-check --schema ${zmodelPath} --no-dependency-check${outputArg}${otherArgs}`,
238+
{
239+
NODE_PATH: './node_modules',
240+
}
241+
);
233242
} else {
234-
run(`npx zenstack generate --no-version-check --no-dependency-check${outputArg}`, {
243+
run(`npx zenstack generate --no-version-check --no-dependency-check${outputArg}${otherArgs}`, {
235244
NODE_PATH: './node_modules',
236245
});
237246
}

tests/integration/tests/plugins/zod.test.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ describe('Zod plugin tests', () => {
497497
expect(schema.safeParse({ arr: [4] }).error.issues[1].path).toEqual(['arr', 'every']);
498498
expect(schema.safeParse({ arr: [4] }).error.issues[2].path).toEqual(['arr', 'some']);
499499
expect(schema.safeParse({ arr: [1, 2, 3] }).success).toBeTruthy();
500-
})
500+
});
501501

502502
it('full-text search', async () => {
503503
const model = `
@@ -788,6 +788,11 @@ describe('Zod plugin tests', () => {
788788
provider = 'prisma-client-js'
789789
}
790790
791+
plugin enhancer {
792+
provider = '@core/enhancer'
793+
output = "$projectRoot/enhance"
794+
}
795+
791796
plugin zod {
792797
provider = "@core/zod"
793798
output = "$projectRoot/zod"
@@ -801,7 +806,7 @@ describe('Zod plugin tests', () => {
801806
password String @omit
802807
}
803808
`,
804-
{ addPrelude: false, pushDb: false, projectDir }
809+
{ addPrelude: false, pushDb: false, projectDir, getPrismaOnly: true, generateNoCompile: true }
805810
);
806811

807812
expect(fs.existsSync(path.join(projectDir, 'zod', 'test.txt'))).toBeFalsy();
@@ -822,6 +827,11 @@ describe('Zod plugin tests', () => {
822827
generator js {
823828
provider = 'prisma-client-js'
824829
}
830+
831+
plugin enhancer {
832+
provider = '@core/enhancer'
833+
output = "$projectRoot/enhance"
834+
}
825835
826836
plugin zod {
827837
provider = "@core/zod"
@@ -836,7 +846,7 @@ describe('Zod plugin tests', () => {
836846
password String @omit
837847
}
838848
`,
839-
{ addPrelude: false, pushDb: false, projectDir }
849+
{ addPrelude: false, pushDb: false, projectDir, generateNoCompile: true }
840850
)
841851
).rejects.toThrow('already exists and is not a directory');
842852
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { loadSchema } from '@zenstackhq/testtools';
2+
3+
describe('issue 1667', () => {
4+
it('custom enhance standard zod output', async () => {
5+
await loadSchema(
6+
`
7+
generator client {
8+
provider = "prisma-client-js"
9+
}
10+
11+
datasource db {
12+
provider = "sqlite"
13+
url = "file:./dev.db"
14+
}
15+
16+
plugin enhancer {
17+
provider = '@core/enhancer'
18+
output = './zen'
19+
}
20+
21+
model User {
22+
id Int @id
23+
email String @unique @email
24+
}
25+
`,
26+
{ addPrelude: false, getPrismaOnly: true, preserveTsFiles: true }
27+
);
28+
});
29+
30+
it('custom enhance custom zod output', async () => {
31+
await loadSchema(
32+
`
33+
generator client {
34+
provider = "prisma-client-js"
35+
}
36+
37+
datasource db {
38+
provider = "sqlite"
39+
url = "file:./dev.db"
40+
}
41+
42+
plugin enhancer {
43+
provider = '@core/enhancer'
44+
output = './zen'
45+
}
46+
47+
plugin zod {
48+
provider = '@core/zod'
49+
output = './myzod'
50+
}
51+
52+
model User {
53+
id Int @id
54+
email String @unique @email
55+
}
56+
`,
57+
{ addPrelude: false, getPrismaOnly: true, generateNoCompile: true, compile: true }
58+
);
59+
});
60+
});

0 commit comments

Comments
 (0)