Skip to content

Commit 2d42606

Browse files
authored
fix: generated code fails to compile when prisma's output path overlaps with zenstack (#1765)
1 parent a2c78a1 commit 2d42606

File tree

8 files changed

+74
-10
lines changed

8 files changed

+74
-10
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getLiteral,
99
isDelegateModel,
1010
isDiscriminatorField,
11+
normalizedRelative,
1112
type PluginOptions,
1213
} from '@zenstackhq/sdk';
1314
import {
@@ -159,7 +160,7 @@ ${
159160
const zodAbsPath = path.isAbsolute(zodCustomOutput)
160161
? zodCustomOutput
161162
: path.resolve(schemaDir, zodCustomOutput);
162-
return path.relative(this.outDir, zodAbsPath) || '.';
163+
return normalizedRelative(this.outDir, zodAbsPath);
163164
}
164165

165166
private createSimplePrismaImports(prismaImport: string) {

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { PluginError, RUNTIME_PACKAGE, createProject, resolvePath, type PluginFunction } from '@zenstackhq/sdk';
1+
import {
2+
PluginError,
3+
RUNTIME_PACKAGE,
4+
createProject,
5+
normalizedRelative,
6+
resolvePath,
7+
type PluginFunction,
8+
} from '@zenstackhq/sdk';
29
import path from 'path';
310
import { getDefaultOutputFolder } from '../plugin-utils';
411
import { EnhancerGenerator } from './enhance';
@@ -31,7 +38,7 @@ const run: PluginFunction = async (model, options, _dmmf, globalOptions) => {
3138
const prismaClientPathAbs = path.resolve(outDir, 'models');
3239

3340
// resolve it relative to the schema path
34-
prismaClientPath = path.relative(path.dirname(options.schemaPath), prismaClientPathAbs);
41+
prismaClientPath = normalizedRelative(path.dirname(options.schemaPath), prismaClientPathAbs);
3542
} else {
3643
prismaClientPath = `${RUNTIME_PACKAGE}/models`;
3744
}

packages/schema/src/plugins/prisma/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { PluginError, type PluginFunction, type PluginOptions, getLiteral, resolvePath } from '@zenstackhq/sdk';
1+
import {
2+
PluginError,
3+
type PluginFunction,
4+
type PluginOptions,
5+
getLiteral,
6+
normalizedRelative,
7+
resolvePath,
8+
} from '@zenstackhq/sdk';
29
import { GeneratorDecl, isGeneratorDecl } from '@zenstackhq/sdk/ast';
310
import { getDMMF } from '@zenstackhq/sdk/prisma';
411
import colors from 'colors';
@@ -59,7 +66,7 @@ const run: PluginFunction = async (model, options, _dmmf, _globalOptions) => {
5966
const absPath = path.resolve(path.dirname(output), clientOutput);
6067

6168
// then make it relative to the zmodel schema location
62-
prismaClientPath = path.relative(path.dirname(options.schemaPath), absPath);
69+
prismaClientPath = normalizedRelative(path.dirname(options.schemaPath), absPath);
6370
}
6471
}
6572
} else {

packages/sdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './code-gen';
22
export * from './constants';
33
export { generate as generateModelMeta } from './model-meta-generator';
44
export * from './names';
5+
export * from './path';
56
export * from './policy';
67
export * from './types';
78
export * from './typescript-expression-transformer';

packages/sdk/src/path.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import path from 'path';
2+
3+
/**
4+
* Gets the relative path from `from` to `to` and normalizes it to start it with `./`
5+
*/
6+
export function normalizedRelative(from: string, to: string) {
7+
const result = path.relative(from, to);
8+
return result.startsWith('.') ? result : `./${result}`;
9+
}

packages/sdk/src/prisma.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Model } from './ast';
99
import { RUNTIME_PACKAGE } from './constants';
1010
import type { PluginOptions } from './types';
1111
import { getDataSourceProvider } from './utils';
12+
import { normalizedRelative } from './path';
1213

1314
/**
1415
* Given an import context directory and plugin options, compute the import spec for the Prisma Client.
@@ -34,12 +35,11 @@ export function getPrismaClientImportSpec(importingFromDir: string, options: Plu
3435
const resolvedPrismaClientOutput = path.resolve(path.dirname(options.schemaPath), options.prismaClientPath);
3536

3637
// translate to path relative to the importing context directory
37-
let result = path.relative(importingFromDir, resolvedPrismaClientOutput);
38+
let result = normalizedRelative(importingFromDir, resolvedPrismaClientOutput);
3839

3940
// remove leading `node_modules` (which may be provided by the user)
4041
result = result.replace(/^([./\\]*)?node_modules\//, '');
4142

42-
// compute prisma client absolute output dir relative to the importing file
4343
return normalizePath(result);
4444
}
4545

packages/testtools/src/schema.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ export type SchemaLoadOptions = {
134134
preserveTsFiles?: boolean;
135135
generatePermissionChecker?: boolean;
136136
previewFeatures?: string[];
137+
prismaLoadPath?: string;
137138
prismaClientOptions?: object;
138139
generateNoCompile?: boolean;
139140
};
@@ -263,7 +264,13 @@ export async function loadSchema(schema: string, options?: SchemaLoadOptions) {
263264
fs.cpSync(dep, path.join(projectDir, 'node_modules', pkgJson.name), { recursive: true, force: true });
264265
});
265266

266-
const PrismaClient = require(path.join(projectDir, 'node_modules/.prisma/client')).PrismaClient;
267+
const prismaLoadPath = options?.prismaLoadPath
268+
? path.isAbsolute(options.prismaLoadPath)
269+
? options.prismaLoadPath
270+
: path.join(projectDir, options.prismaLoadPath)
271+
: path.join(projectDir, 'node_modules/.prisma/client');
272+
const prismaModule = require(prismaLoadPath);
273+
const PrismaClient = prismaModule.PrismaClient;
267274

268275
let clientOptions: object = { log: ['info', 'warn', 'error'] };
269276
if (options?.prismaClientOptions) {
@@ -273,8 +280,6 @@ export async function loadSchema(schema: string, options?: SchemaLoadOptions) {
273280
// https://github.com/prisma/prisma/issues/18292
274281
prisma[Symbol.for('nodejs.util.inspect.custom')] = 'PrismaClient';
275282

276-
const prismaModule = loadModule('@prisma/client', projectDir).Prisma;
277-
278283
if (opt.pulseApiKey) {
279284
const withPulse = loadModule('@prisma/extension-pulse/node', projectDir).withPulse;
280285
prisma = prisma.$extends(withPulse({ apiKey: opt.pulseApiKey }));
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { loadSchema } from '@zenstackhq/testtools';
2+
describe('issue 1743', () => {
3+
it('regression', async () => {
4+
await loadSchema(
5+
`
6+
generator client {
7+
provider = "prisma-client-js"
8+
output = '../lib/zenstack/prisma'
9+
}
10+
11+
datasource db {
12+
provider = "sqlite"
13+
url = "file:./dev.db"
14+
}
15+
16+
plugin enhancer {
17+
provider = '@core/enhancer'
18+
output = './lib/zenstack'
19+
compile = false
20+
}
21+
22+
model User {
23+
id Int @id
24+
}
25+
`,
26+
{
27+
addPrelude: false,
28+
compile: true,
29+
output: './lib/zenstack',
30+
prismaLoadPath: './lib/zenstack/prisma',
31+
}
32+
);
33+
});
34+
});

0 commit comments

Comments
 (0)