diff --git a/apps/lsp-playground/package.json b/apps/lsp-playground/package.json index 963ddc4f2e2b..01fff299d01f 100644 --- a/apps/lsp-playground/package.json +++ b/apps/lsp-playground/package.json @@ -35,7 +35,7 @@ "ws": "^8.21.2" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", "@types/ws": "^8.5.13", diff --git a/apps/telemetry-backend/package.json b/apps/telemetry-backend/package.json index 797c82ef9ba8..4af618f40eba 100644 --- a/apps/telemetry-backend/package.json +++ b/apps/telemetry-backend/package.json @@ -27,7 +27,7 @@ "evlog": "^2.24.0" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/compute-sdk": "^0.39.0", "@prisma/management-api-sdk": "^1.56.0", "@repo/test-utils": "workspace:8.0.0-rc.11", diff --git a/examples/bundle-size/package.json b/examples/bundle-size/package.json index a73bbb6299f4..579dbea3a00f 100644 --- a/examples/bundle-size/package.json +++ b/examples/bundle-size/package.json @@ -28,7 +28,7 @@ "pg": "catalog:" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/dev": "catalog:", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", diff --git a/examples/mongo-blog-leaderboard/package.json b/examples/mongo-blog-leaderboard/package.json index a19039cd8a46..bd94bfa5f239 100644 --- a/examples/mongo-blog-leaderboard/package.json +++ b/examples/mongo-blog-leaderboard/package.json @@ -19,7 +19,7 @@ "mongodb": "catalog:" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", "mongodb-memory-server": "catalog:", diff --git a/examples/mongo-demo/package.json b/examples/mongo-demo/package.json index f6a785f94547..146baa2754b2 100644 --- a/examples/mongo-demo/package.json +++ b/examples/mongo-demo/package.json @@ -24,7 +24,7 @@ "react-dom": "^19.2.8" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", diff --git a/examples/multi-extension-monorepo/package.json b/examples/multi-extension-monorepo/package.json index 6b3e6f559d40..f45d2555d651 100644 --- a/examples/multi-extension-monorepo/package.json +++ b/examples/multi-extension-monorepo/package.json @@ -18,7 +18,7 @@ "@prisma/orm-postgres": "workspace:8.0.0-rc.11" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", diff --git a/examples/paradedb-demo/package.json b/examples/paradedb-demo/package.json index 0d581aac964b..cb2821fd3f52 100644 --- a/examples/paradedb-demo/package.json +++ b/examples/paradedb-demo/package.json @@ -25,7 +25,7 @@ "pg": "catalog:" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", diff --git a/examples/prisma-8-cloudflare-worker/package.json b/examples/prisma-8-cloudflare-worker/package.json index f34cad4983a2..843391fc064d 100644 --- a/examples/prisma-8-cloudflare-worker/package.json +++ b/examples/prisma-8-cloudflare-worker/package.json @@ -29,7 +29,7 @@ "devDependencies": { "@cloudflare/vitest-pool-workers": "0.20.3", "@cloudflare/workers-types": "5.20260804.1", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", "@types/pg": "catalog:", diff --git a/examples/prisma-8-demo-sqlite/package.json b/examples/prisma-8-demo-sqlite/package.json index ee9ef635fd85..1af1fff29a4c 100644 --- a/examples/prisma-8-demo-sqlite/package.json +++ b/examples/prisma-8-demo-sqlite/package.json @@ -20,7 +20,7 @@ "dotenv": "^17.4.2" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", "tsx": "catalog:", diff --git a/examples/prisma-8-demo/package.json b/examples/prisma-8-demo/package.json index cf212b51d1c0..3439027500c1 100644 --- a/examples/prisma-8-demo/package.json +++ b/examples/prisma-8-demo/package.json @@ -32,7 +32,7 @@ "react-dom": "^19.2.8" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/dev": "catalog:", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", diff --git a/examples/prisma-8-postgis-demo/package.json b/examples/prisma-8-postgis-demo/package.json index 4917e8fc37cb..80157a7c0712 100644 --- a/examples/prisma-8-postgis-demo/package.json +++ b/examples/prisma-8-postgis-demo/package.json @@ -33,7 +33,7 @@ "react-leaflet": "^5.0.0" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/leaflet": "^1.9.22", diff --git a/examples/prisma7-adoption/package.json b/examples/prisma7-adoption/package.json index d35d34162baa..fa72fdbb0e22 100644 --- a/examples/prisma7-adoption/package.json +++ b/examples/prisma7-adoption/package.json @@ -29,7 +29,7 @@ "temporal-polyfill": "^1.0.4" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/dev": "catalog:", "@prisma/prisma7": "7.10.0", "@repo/test-utils": "workspace:8.0.0-rc.11", diff --git a/examples/react-router-demo/package.json b/examples/react-router-demo/package.json index ba91e60e42b9..955b7228a520 100644 --- a/examples/react-router-demo/package.json +++ b/examples/react-router-demo/package.json @@ -30,7 +30,7 @@ "react-router": "^8.1.0" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/dev": "catalog:", "@react-router/dev": "^8.1.0", "@repo/test-utils": "workspace:8.0.0-rc.11", diff --git a/examples/retail-store/package.json b/examples/retail-store/package.json index 308a234be8d8..ff284a91e396 100644 --- a/examples/retail-store/package.json +++ b/examples/retail-store/package.json @@ -39,7 +39,7 @@ "tailwindcss": "^4.3.3" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", diff --git a/examples/supabase/package.json b/examples/supabase/package.json index 5e9a7961a96b..8e5cc17c7be3 100644 --- a/examples/supabase/package.json +++ b/examples/supabase/package.json @@ -18,7 +18,7 @@ "pg": "catalog:" }, "devDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@types/node": "catalog:", diff --git a/packages/1-framework/3-tooling/cli/package.json b/packages/1-framework/3-tooling/cli/package.json index 4d017599d0c5..7fcd6d8f6e24 100644 --- a/packages/1-framework/3-tooling/cli/package.json +++ b/packages/1-framework/3-tooling/cli/package.json @@ -52,7 +52,7 @@ "@internal/sql-contract-ts": "workspace:8.0.0-rc.11", "@internal/sql-operations": "workspace:8.0.0-rc.11", "@internal/sql-runtime": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@repo/tsdown": "workspace:8.0.0-rc.11", @@ -62,7 +62,7 @@ "vitest": "catalog:" }, "peerDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "typescript": ">=5.9" }, "peerDependenciesMeta": { diff --git a/packages/1-framework/3-tooling/cli/src/orm/config-section.ts b/packages/1-framework/3-tooling/cli/src/orm/config-section.ts index cb0d885eba06..01e7e9af85a2 100644 --- a/packages/1-framework/3-tooling/cli/src/orm/config-section.ts +++ b/packages/1-framework/3-tooling/cli/src/orm/config-section.ts @@ -1,12 +1,13 @@ import type { PrismaNextConfig } from '@internal/config/config-types'; import type { ConfigValidationIssue } from '@internal/config/config-validation'; import { collectConfigIssues } from '@internal/config/config-validation'; +import { finalizeContractConfig, finalizeMigrationsConfig } from '@internal/config-loader'; import { getEmittedArtifactPaths } from '@internal/emitter'; import { blindCast } from '@internal/utils/casts'; -import type { SectionValidation } from '@prisma/cli-engine'; +import type { SectionProvenance, SectionValidation } from '@prisma/cli-engine'; import { defineConfigSection } from '@prisma/cli-engine'; import type { Diagnostic, NextAction } from '@prisma/cli-engine/protocol'; -import { normalize } from 'pathe'; +import { dirname, normalize } from 'pathe'; /** * The single config section the `orm` command family owns. The whole Prisma @@ -128,7 +129,40 @@ function collectArtifactCollisionIssues( ]; } -function validate(raw: unknown): SectionValidation { +function declaringDir(provenance: SectionProvenance, key: string): string | undefined { + const file = provenance.keys[key] ?? provenance.files[0]; + return file === undefined ? undefined : dirname(file); +} + +/** + * Resolves the section's path-valued keys against the config file that + * declared each key — never against the invocation directory. Config files + * chain from cwd to the repo root and merge per key, so `contract` and + * `migrations` can come from different files; each resolves against its own. + * Absent `migrations` defaults to `migrations/` beside the nearest declaring + * file. Absolute paths pass through unchanged. + */ +function resolveAgainstDeclaringFiles( + config: PrismaNextConfig, + provenance: SectionProvenance, +): PrismaNextConfig { + const contractDir = declaringDir(provenance, 'contract'); + const migrationsDir = declaringDir(provenance, 'migrations'); + return { + ...config, + ...(config.contract !== undefined && contractDir !== undefined + ? { contract: finalizeContractConfig(config.contract, contractDir) } + : undefined), + ...(migrationsDir !== undefined + ? { migrations: finalizeMigrationsConfig(config.migrations, migrationsDir) } + : undefined), + }; +} + +function validate( + raw: unknown, + provenance: SectionProvenance, +): SectionValidation { if (raw === undefined) { return { ok: false as const, diagnostics: [sectionAbsentDiagnostic()] }; } @@ -147,14 +181,20 @@ function validate(raw: unknown): SectionValidation { return { ok: false as const, diagnostics: issues.map(issueDiagnostic) }; } - return { - ok: true as const, - value: blindCast< - PrismaNextConfig, - 'collectConfigIssues found no structural problem, so every required section is present and well-typed' - >(raw), - diagnostics: [], - }; + const config = blindCast< + PrismaNextConfig, + 'collectConfigIssues found no structural problem, so every required section is present and well-typed' + >(raw); + try { + return { + ok: true as const, + value: resolveAgainstDeclaringFiles(config, provenance), + diagnostics: [], + }; + } catch (error) { + // Resolution spreads the config, so a throwing getter surfaces here. + return { ok: false as const, diagnostics: [unreadableDiagnostic(error)] }; + } } export const ormConfigSection = defineConfigSection({ diff --git a/packages/1-framework/3-tooling/cli/src/orm/define-command.ts b/packages/1-framework/3-tooling/cli/src/orm/define-command.ts index 391292999705..6f6f1c15f91d 100644 --- a/packages/1-framework/3-tooling/cli/src/orm/define-command.ts +++ b/packages/1-framework/3-tooling/cli/src/orm/define-command.ts @@ -1,6 +1,3 @@ -import type { PrismaNextConfig } from '@internal/config/config-types'; -import { finalizeConfig } from '@internal/config-loader'; -import { blindCast } from '@internal/utils/casts'; import { isInternalError } from '@internal/utils/internal-error'; import type { ArgsSpec, @@ -30,39 +27,6 @@ import { normalizeError } from './normalize-error'; * Prisma ORM rather than something the user did. Re-throwing lets the engine settle it as a bug * at exit 1, where converting it would report the same number as a bad connection string. */ -function isRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} - -/** - * Hands the handler a config whose paths are absolute. The engine's own - * loader evaluates `prisma.config.ts` without touching the paths inside it, so - * a command mounted in the unified host receives `contract.output` and - * `migrations.dir` exactly as authored — usually relative — while this repo's - * bin finalizes them in its loader. Anchoring here, on the section every ORM - * command reads, makes both hosts hand handlers the same absolute paths. - * - * The anchor is the working directory: the engine discovers the config in the - * working directory only, so that is the file's own directory. (A `--config` - * pointing into another directory is not visible from a command context; a - * relative path inside such a file resolves against the invocation directory, - * which is also what the file's author sees the command run from.) - * Finalization is idempotent — an already-absolute path resolves to itself — - * so a config that arrived finalized passes through unchanged. - */ -function finalizedConfigContext( - ctx: TCtx, -): TCtx { - if (!isRecord(ctx.config)) { - return ctx; - } - const config = blindCast< - PrismaNextConfig, - 'every ORM command that declares needs.config reads the orm section, whose validated value is PrismaNextConfig' - >(ctx.config); - return { ...ctx, config: finalizeConfig(config, ctx.cwd) }; -} - export function defineOrmCommand< TFlags extends Record> = Record>, TPositionals extends Record> = Record< @@ -86,7 +50,7 @@ export function defineOrmCommand< ...def, handler: async (args, ctx) => { try { - return await def.handler(args, finalizedConfigContext(ctx)); + return await def.handler(args, ctx); } catch (error) { if (isInternalError(error)) { throw error; diff --git a/packages/1-framework/3-tooling/cli/src/orm/load-config.ts b/packages/1-framework/3-tooling/cli/src/orm/load-config.ts index c49c0a200845..d378c244d998 100644 --- a/packages/1-framework/3-tooling/cli/src/orm/load-config.ts +++ b/packages/1-framework/3-tooling/cli/src/orm/load-config.ts @@ -23,6 +23,10 @@ export interface LoadOrmConfigOptions { * does — definePrismaConfig from `@prisma/cli-engine` with the whole Prisma ORM * configuration nested as the single `orm` section. * + * The engine's config is a chain of files; this loader reads one file, so the + * chain it hands back is that one file, and the section's provenance names it + * as the declaring file for every key. + * * Only failures that prevent evaluation entirely are diagnostics here, and * they carry `section: null` so they fail exactly the commands that read * config. Structural verdicts belong to the section validator. @@ -32,14 +36,12 @@ export async function loadOrmConfig(options: LoadOrmConfigOptions): Promise { asked.push(configPath ?? '(none)'); return Promise.resolve({ - path: configPath ?? 'prisma.config.ts', - sections: {}, + files: [{ path: configPath ?? 'prisma.config.ts', sections: {} }], diagnostics: [], }); }, diff --git a/packages/1-framework/3-tooling/cli/test/orm/config-section.test.ts b/packages/1-framework/3-tooling/cli/test/orm/config-section.test.ts index 37d40fe70b12..6e3368f35978 100644 --- a/packages/1-framework/3-tooling/cli/test/orm/config-section.test.ts +++ b/packages/1-framework/3-tooling/cli/test/orm/config-section.test.ts @@ -1,5 +1,23 @@ +import type { SectionProvenance } from '@prisma/cli-engine'; +import { ok } from '@prisma/cli-engine/protocol'; +import { createTestCli } from '@prisma/cli-engine/testing'; import { describe, expect, it } from 'vitest'; import { ormConfigSection } from '../../src/orm/config-section'; +import { defineOrmCommand } from '../../src/orm/define-command'; + +const CONFIG_FILE = '/repo/packages/db/prisma.config.ts'; + +function provenanceFor( + raw: Record, + file: string = CONFIG_FILE, +): SectionProvenance { + return { + files: [file], + keys: Object.fromEntries(Object.keys(raw).map((key) => [key, file])), + }; +} + +const HOSTILE_PROVENANCE: SectionProvenance = { files: [CONFIG_FILE], keys: {} }; function validFamily() { return { @@ -37,11 +55,15 @@ describe('ormConfigSection', () => { }); describe('a structurally valid section', () => { - it('validates and hands the value through untouched', () => { + it('validates and defaults migrations.dir beside the declaring file', () => { const raw = validConfig(); - const result = ormConfigSection.validate(raw); + const result = ormConfigSection.validate(raw, provenanceFor(raw)); - expect(result).toEqual({ ok: true, value: raw, diagnostics: [] }); + expect(result).toEqual({ + ok: true, + value: { ...raw, migrations: { dir: '/repo/packages/db/migrations' } }, + diagnostics: [], + }); }); it('accepts the optional subsections', () => { @@ -52,13 +74,13 @@ describe('ormConfigSection', () => { db: { connection: 'postgres://localhost/app' }, }; - expect(ormConfigSection.validate(raw).ok).toBe(true); + expect(ormConfigSection.validate(raw, provenanceFor(raw)).ok).toBe(true); }); }); describe('absence', () => { it('reports the missing config file rather than throwing', () => { - const result = ormConfigSection.validate(undefined); + const result = ormConfigSection.validate(undefined, { files: [], keys: {} }); expect(result).toEqual({ ok: false, @@ -84,7 +106,7 @@ describe('ormConfigSection', () => { describe('whole-section blocking', () => { it('fails the whole section when one subsection is malformed', () => { const raw = { ...validConfig(), migrations: { dir: 42 } }; - const result = ormConfigSection.validate(raw); + const result = ormConfigSection.validate(raw, provenanceFor(raw)); expect(result.ok).toBe(false); expect(result.diagnostics).toEqual([ @@ -105,7 +127,7 @@ describe('ormConfigSection', () => { }); it('reports every issue it found, not just the first', () => { - const result = ormConfigSection.validate({ migrations: { dir: 42 } }); + const result = ormConfigSection.validate({ migrations: { dir: 42 } }, HOSTILE_PROVENANCE); expect(result.ok).toBe(false); expect(result.diagnostics.map((diagnostic) => diagnostic.meta?.['field'])).toEqual([ @@ -117,13 +139,14 @@ describe('ormConfigSection', () => { }); it('reports an emitted artifact listed as a contract input', () => { - const result = ormConfigSection.validate({ + const raw = { ...validConfig(), contract: { source: { format: 'psl', inputs: ['/app/contract.json'], load: () => ({}) }, output: '/app/contract.json', }, - }); + }; + const result = ormConfigSection.validate(raw, provenanceFor(raw)); expect(result.ok).toBe(false); expect(result.diagnostics.map((diagnostic) => diagnostic.meta?.['field'])).toEqual([ @@ -132,13 +155,14 @@ describe('ormConfigSection', () => { }); it('reports the collision when the input spells the same file differently', () => { - const result = ormConfigSection.validate({ + const raw = { ...validConfig(), contract: { source: { format: 'psl', inputs: ['./out/./contract.json'], load: () => ({}) }, output: 'out/contract.json', }, - }); + }; + const result = ormConfigSection.validate(raw, provenanceFor(raw)); expect(result.ok).toBe(false); expect(result.diagnostics.map((diagnostic) => diagnostic.meta?.['field'])).toEqual([ @@ -147,13 +171,14 @@ describe('ormConfigSection', () => { }); it('does not report a collision for a genuinely different file', () => { - const result = ormConfigSection.validate({ + const raw = { ...validConfig(), contract: { source: { format: 'psl', inputs: ['./src/contract.prisma'], load: () => ({}) }, output: 'out/contract.json', }, - }); + }; + const result = ormConfigSection.validate(raw, provenanceFor(raw)); expect(result.ok).toBe(true); }); @@ -168,7 +193,7 @@ describe('ormConfigSection', () => { ['an array', []], ['a function', () => undefined], ])('rejects %s without throwing', (_label, raw) => { - const result = ormConfigSection.validate(raw); + const result = ormConfigSection.validate(raw, HOSTILE_PROVENANCE); expect(result.ok).toBe(false); expect(result.diagnostics).toEqual([ @@ -201,7 +226,7 @@ describe('ormConfigSection', () => { ], ['deeply nested garbage', { family: { kind: { kind: { kind: {} } } } }], ])('never throws on %s', (_label, raw) => { - expect(() => ormConfigSection.validate(raw)).not.toThrow(); + expect(() => ormConfigSection.validate(raw, HOSTILE_PROVENANCE)).not.toThrow(); }); it('never throws when a descriptor getter explodes', () => { @@ -212,8 +237,142 @@ describe('ormConfigSection', () => { }, }; - expect(() => ormConfigSection.validate(raw)).not.toThrow(); - expect(ormConfigSection.validate(raw).ok).toBe(false); + expect(() => ormConfigSection.validate(raw, HOSTILE_PROVENANCE)).not.toThrow(); + expect(ormConfigSection.validate(raw, HOSTILE_PROVENANCE).ok).toBe(false); + }); + }); + + describe('declaring-file path resolution', () => { + function contractSection(inputs: readonly string[], output: string) { + return { source: { format: 'psl', inputs: [...inputs], load: () => ({}) }, output }; + } + + function validatedValue(raw: Record, provenance: SectionProvenance) { + const result = ormConfigSection.validate(raw, provenance); + if (!result.ok) { + throw new Error(`expected ok, got ${JSON.stringify(result.diagnostics)}`); + } + return result.value; + } + + it('resolves contract paths against the file that declared the contract key', () => { + const raw = { + ...validConfig(), + contract: contractSection(['./src/schema.psl'], './out/contract.json'), + }; + + const value = validatedValue(raw, provenanceFor(raw)); + + expect(value.contract?.source.inputs).toEqual(['/repo/packages/db/src/schema.psl']); + expect(value.contract?.output).toBe('/repo/packages/db/out/contract.json'); + }); + + it('resolves migrations.dir against the file that declared the migrations key', () => { + const raw = { ...validConfig(), migrations: { dir: './db/migrations' } }; + + const value = validatedValue(raw, provenanceFor(raw)); + + expect(value.migrations?.dir).toBe('/repo/packages/db/db/migrations'); + }); + + it('resolves each key against its own declaring file when files differ', () => { + const raw = { + ...validConfig(), + contract: contractSection(['./schema.psl'], './contract.json'), + migrations: { dir: './migrations' }, + }; + const provenance: SectionProvenance = { + files: ['/repo/packages/db/prisma.config.ts', '/repo/prisma.config.ts'], + keys: { + ...provenanceFor(raw, '/repo/packages/db/prisma.config.ts').keys, + migrations: '/repo/prisma.config.ts', + }, + }; + + const value = validatedValue(raw, provenance); + + expect(value.contract?.output).toBe('/repo/packages/db/contract.json'); + expect(value.migrations?.dir).toBe('/repo/migrations'); + }); + + it('defaults migrations.dir beside the nearest declaring file when no file sets it', () => { + const raw = validConfig(); + const provenance = provenanceFor(raw, '/repo/packages/db/prisma.config.ts'); + + expect(validatedValue(raw, provenance).migrations?.dir).toBe('/repo/packages/db/migrations'); + }); + + it('defaults contract.output beside the file that declared the contract key', () => { + const raw = { ...validConfig(), contract: { source: contractSection([], 'x').source } }; + + expect(validatedValue(raw, provenanceFor(raw)).contract?.output).toBe( + '/repo/packages/db/src/prisma/contract.json', + ); + }); + + it('passes absolute paths through unchanged', () => { + const raw = { + ...validConfig(), + contract: contractSection(['/abs/schema.psl'], '/abs/out/contract.json'), + migrations: { dir: '/abs/migrations' }, + }; + + const value = validatedValue(raw, provenanceFor(raw)); + + expect(value.contract?.source.inputs).toEqual(['/abs/schema.psl']); + expect(value.contract?.output).toBe('/abs/out/contract.json'); + expect(value.migrations?.dir).toBe('/abs/migrations'); + }); + }); +}); + +describe('the config an ORM command handler receives', () => { + it('carries paths under the declaring config file, whatever directory the command ran in', async () => { + const configDir = '/repo/packages/db'; + let seen: { output?: string | undefined; dir?: string | undefined } = {}; + const cli = createTestCli({ + commands: { + probe: defineOrmCommand({ + help: { summary: 'Records the config paths the handler receives' }, + needs: { config: ormConfigSection }, + handler: async (_args, ctx) => { + seen = { output: ctx.config.contract?.output, dir: ctx.config.migrations?.dir }; + return ok( + ctx.present( + { data: seen, exitCode: 0 }, + { stdout: () => [], next: () => [], human: () => [], json: () => seen }, + ), + ); + }, + }), + }, + loadConfig: () => + Promise.resolve({ + files: [ + { + path: `${configDir}/prisma.config.ts`, + sections: { + orm: { + ...validConfig(), + contract: { + source: { format: 'psl', inputs: ['./schema.psl'], load: () => ({}) }, + output: './out/contract.json', + }, + migrations: { dir: './migrations' }, + }, + }, + }, + ], + diagnostics: [], + }), + }); + + const run = await cli.run(['probe', '--json'], { cwd: process.cwd() }); + + expect(run.exitCode).toBe(0); + expect(seen).toEqual({ + output: `${configDir}/out/contract.json`, + dir: `${configDir}/migrations`, }); }); }); diff --git a/packages/1-framework/3-tooling/cli/test/orm/contract-emit.test.ts b/packages/1-framework/3-tooling/cli/test/orm/contract-emit.test.ts index f227754bd181..1fc7e0782bf5 100644 --- a/packages/1-framework/3-tooling/cli/test/orm/contract-emit.test.ts +++ b/packages/1-framework/3-tooling/cli/test/orm/contract-emit.test.ts @@ -101,8 +101,7 @@ function countingLoader(config: Record = ormConfig()): { loadConfig: (configPath) => { calls.push(configPath ?? '(none)'); return Promise.resolve({ - path: join(PROJECT_DIR, 'prisma.config.ts'), - sections: { orm: config }, + files: [{ path: join(PROJECT_DIR, 'prisma.config.ts'), sections: { orm: config } }], diagnostics: [], }); }, diff --git a/packages/1-framework/3-tooling/cli/test/orm/define-command.test.ts b/packages/1-framework/3-tooling/cli/test/orm/define-command.test.ts index 7b09f6771f2b..dcd06c9a8af3 100644 --- a/packages/1-framework/3-tooling/cli/test/orm/define-command.test.ts +++ b/packages/1-framework/3-tooling/cli/test/orm/define-command.test.ts @@ -144,57 +144,3 @@ describe('defineOrmCommand', () => { }); }); }); - -describe('config finalization at the command boundary', () => { - it('hands the handler absolute contract and migration paths whatever the loader left relative', async () => { - let seen: { output?: string | undefined; dir?: string | undefined } = {}; - const cli = createTestCli({ - commands: { - probe: defineOrmCommand({ - help: { summary: 'Records the config paths the handler receives' }, - needs: { - config: { - name: 'orm', - validate: (raw) => ({ - ok: true as const, - value: raw as Record, - diagnostics: [], - }), - }, - }, - handler: async (_args, ctx) => { - const config = ctx.config as { - contract?: { output?: string }; - migrations?: { dir?: string }; - }; - seen = { output: config.contract?.output, dir: config.migrations?.dir }; - return ok( - ctx.present( - { data: seen, exitCode: 0 }, - { stdout: () => [], next: () => [], human: () => [], json: () => seen }, - ), - ); - }, - }), - }, - config: { - orm: { - contract: { - source: { load: async () => ({ ok: true, value: {} }) }, - output: './src/prisma/contract.json', - }, - migrations: { dir: './migrations' }, - }, - }, - }); - - const cwd = process.cwd(); - const run = await cli.run(['probe', '--json'], { cwd }); - - expect(run.exitCode).toBe(0); - expect(seen).toEqual({ - output: `${cwd}/src/prisma/contract.json`, - dir: `${cwd}/migrations`, - }); - }); -}); diff --git a/packages/1-framework/3-tooling/cli/test/orm/load-config.test.ts b/packages/1-framework/3-tooling/cli/test/orm/load-config.test.ts index a26fea13e443..d86fe03de26d 100644 --- a/packages/1-framework/3-tooling/cli/test/orm/load-config.test.ts +++ b/packages/1-framework/3-tooling/cli/test/orm/load-config.test.ts @@ -1,4 +1,5 @@ import { realpathSync, rmSync, writeFileSync } from 'node:fs'; +import type { LoadedConfig } from '@prisma/cli-engine'; import { timeouts } from '@repo/test-utils'; import { join } from 'pathe'; import { afterEach, describe, expect, it } from 'vitest'; @@ -13,6 +14,10 @@ function projectDir(): string { return dir; } +function ormSection(loaded: LoadedConfig): unknown { + return loaded.files[0]?.sections['orm']; +} + /** * Written without importing the workspace, so what the loader reads is exactly * what these tests write and nothing resolves out of the fixture package. The @@ -54,7 +59,7 @@ describe('loadOrmConfig', () => { const loaded = await loadOrmConfig({ cwd: dir }); expect(loaded.diagnostics).toEqual([]); - expect(Object.keys(loaded.sections)).toEqual(['orm']); + expect(loaded.files.map((file) => Object.keys(file.sections))).toEqual([['orm']]); }, // The first load pays jiti's cold transform for the config module. timeouts.coldTransformImport, @@ -65,7 +70,7 @@ describe('loadOrmConfig', () => { writeConfig(dir, VALID_BODY); const loaded = await loadOrmConfig({ cwd: dir }); - const orm = loaded.sections['orm'] as { + const orm = ormSection(loaded) as { contract?: { output?: string; source?: { inputs?: readonly string[] } }; }; @@ -78,7 +83,7 @@ describe('loadOrmConfig', () => { writeConfig(dir, VALID_BODY); expect(dir).not.toBe(process.cwd()); - expect((await loadOrmConfig({ cwd: dir })).sections['orm']).toBeDefined(); + expect(ormSection(await loadOrmConfig({ cwd: dir }))).toBeDefined(); }); it('reads an explicit config path relative to the cwd', async () => { @@ -88,14 +93,14 @@ describe('loadOrmConfig', () => { const loaded = await loadOrmConfig({ cwd: dir, configPath: 'custom.config.ts' }); expect(loaded.diagnostics).toEqual([]); - expect(loaded.sections['orm']).toBeDefined(); + expect(ormSection(loaded)).toBeDefined(); }); describe('a config that cannot be evaluated', () => { - it('reports a file-level diagnostic and no sections', async () => { + it('reports a file-level diagnostic and an empty chain', async () => { const loaded = await loadOrmConfig({ cwd: projectDir() }); - expect(loaded.sections).toEqual({}); + expect(loaded.files).toEqual([]); expect(loaded.diagnostics).toHaveLength(1); expect(loaded.diagnostics[0]?.section).toBeNull(); expect(loaded.diagnostics[0]?.diagnostic).toMatchObject({ @@ -122,7 +127,7 @@ describe('loadOrmConfig', () => { const loaded = await loadOrmConfig({ cwd: dir }); - expect(loaded.sections).toEqual({}); + expect(loaded.files).toEqual([]); expect(loaded.diagnostics).toHaveLength(1); expect(loaded.diagnostics[0]).toMatchObject({ section: null }); expect(loaded.diagnostics[0]?.diagnostic.code).toMatch(/^[A-Z][A-Z0-9]*\.[A-Z][A-Z0-9_]*$/); @@ -134,7 +139,7 @@ describe('loadOrmConfig', () => { const loaded = await loadOrmConfig({ cwd: dir }); - expect(loaded.sections).toEqual({}); + expect(loaded.files).toEqual([]); expect(loaded.diagnostics[0]).toMatchObject({ section: null, diagnostic: { code: 'CONFIG.VERSION_MARKER_MISSING' }, @@ -150,7 +155,7 @@ describe('loadOrmConfig', () => { const loaded = await loadOrmConfig({ cwd: dir }); expect(loaded.diagnostics).toEqual([]); - expect(loaded.sections['orm']).toMatchObject({ migrations: { dir: 42 } }); + expect(ormSection(loaded)).toMatchObject({ migrations: { dir: 42 } }); }); }); }); diff --git a/packages/1-framework/3-tooling/config-loader/src/exports/index.ts b/packages/1-framework/3-tooling/config-loader/src/exports/index.ts index e13af5fc6e29..a233ff8c208a 100644 --- a/packages/1-framework/3-tooling/config-loader/src/exports/index.ts +++ b/packages/1-framework/3-tooling/config-loader/src/exports/index.ts @@ -1,5 +1,9 @@ export type { PrismaNextConfig } from '@internal/config/config-types'; -export { finalizeConfig } from '../finalize-config'; +export { + finalizeConfig, + finalizeContractConfig, + finalizeMigrationsConfig, +} from '../finalize-config'; export type { ConfigSection, LoadedConfig } from '../load'; export { findNearestConfigPathForFile, diff --git a/packages/3-extensions/paradedb/package.json b/packages/3-extensions/paradedb/package.json index bbf99b61622e..9ace90b0b3cf 100644 --- a/packages/3-extensions/paradedb/package.json +++ b/packages/3-extensions/paradedb/package.json @@ -34,7 +34,7 @@ "@internal/operations": "workspace:8.0.0-rc.11", "@internal/sql-contract-ts": "workspace:8.0.0-rc.11", "@internal/target-postgres": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@repo/tsdown": "workspace:8.0.0-rc.11", diff --git a/packages/3-extensions/pgvector/package.json b/packages/3-extensions/pgvector/package.json index 6eefa451526a..7db9155aa324 100644 --- a/packages/3-extensions/pgvector/package.json +++ b/packages/3-extensions/pgvector/package.json @@ -39,7 +39,7 @@ "@internal/postgres": "workspace:8.0.0-rc.11", "@internal/postgres-codec-testkit": "workspace:8.0.0-rc.11", "@internal/sql-contract-ts": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@repo/tsdown": "workspace:8.0.0-rc.11", diff --git a/packages/3-extensions/postgis/package.json b/packages/3-extensions/postgis/package.json index 737e25e3a844..d0b0c17c8a91 100644 --- a/packages/3-extensions/postgis/package.json +++ b/packages/3-extensions/postgis/package.json @@ -37,7 +37,7 @@ "@internal/operations": "workspace:8.0.0-rc.11", "@internal/postgres": "workspace:8.0.0-rc.11", "@internal/sql-contract-ts": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@repo/tsdown": "workspace:8.0.0-rc.11", diff --git a/packages/3-extensions/supabase/package.json b/packages/3-extensions/supabase/package.json index 446373923539..bf1daca4a11e 100644 --- a/packages/3-extensions/supabase/package.json +++ b/packages/3-extensions/supabase/package.json @@ -48,7 +48,7 @@ "@internal/operations": "workspace:8.0.0-rc.11", "@internal/psl-printer": "workspace:8.0.0-rc.11", "@internal/sql-contract-psl": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", "@repo/tsdown": "workspace:8.0.0-rc.11", diff --git a/packages/9-public/@prisma/orm-toolchain/package.json b/packages/9-public/@prisma/orm-toolchain/package.json index cd96195253f1..7d48324577ea 100644 --- a/packages/9-public/@prisma/orm-toolchain/package.json +++ b/packages/9-public/@prisma/orm-toolchain/package.json @@ -48,7 +48,7 @@ "typescript": "catalog:" }, "peerDependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "typescript": ">=5.9", "vite": "^7.0.0 || ^8.0.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4314ccb0214..8f7774d4224b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,8 +192,8 @@ importers: version: 8.21.3 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/tsconfig': specifier: workspace:8.0.0-rc.11 version: link:../../packages/0-config/tsconfig @@ -229,8 +229,8 @@ importers: version: 2.24.0(express@5.2.1)(hono@4.11.4)(next@16.3.0(@types/node@26.1.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-router@8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(vite@8.1.4(@types/node@26.1.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/compute-sdk': specifier: ^0.39.0 version: 0.39.0(@prisma/management-api-sdk@1.61.0)(encoding@0.1.13)(rollup@4.59.0) @@ -284,8 +284,8 @@ importers: version: 8.22.0 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/dev': specifier: 'catalog:' version: 0.25.1(typescript@5.9.3)(vite@8.1.4(@types/node@26.1.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) @@ -336,8 +336,8 @@ importers: version: 7.5.0(socks@2.8.9) devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/tsconfig': specifier: workspace:8.0.0-rc.11 version: link:../../packages/0-config/tsconfig @@ -379,8 +379,8 @@ importers: version: 19.2.8(react@19.2.8) devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../test/utils @@ -425,8 +425,8 @@ importers: version: link:../../packages/9-public/@prisma/orm-postgres devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../test/utils @@ -462,8 +462,8 @@ importers: version: 8.22.0 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../test/utils @@ -508,8 +508,8 @@ importers: specifier: 5.20260804.1 version: 5.20260804.1 '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/tsconfig': specifier: workspace:8.0.0-rc.11 version: link:../../packages/0-config/tsconfig @@ -560,8 +560,8 @@ importers: version: 19.2.8(react@19.2.8) devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/dev': specifier: 'catalog:' version: 0.25.1(typescript@5.9.3)(vite@8.1.4(@types/node@26.1.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) @@ -624,8 +624,8 @@ importers: version: 17.4.2 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/tsconfig': specifier: workspace:8.0.0-rc.11 version: link:../../packages/0-config/tsconfig @@ -673,8 +673,8 @@ importers: version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../test/utils @@ -728,8 +728,8 @@ importers: version: 1.0.4 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/dev': specifier: 'catalog:' version: 0.25.1(typescript@5.9.3)(vite@8.1.4(@types/node@26.1.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) @@ -792,8 +792,8 @@ importers: version: 8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/dev': specifier: 'catalog:' version: 0.25.1(typescript@5.9.3)(vite@8.1.4(@types/node@26.1.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) @@ -898,8 +898,8 @@ importers: version: 4.3.3 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../test/utils @@ -947,8 +947,8 @@ importers: version: 8.22.0 devDependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../test/utils @@ -1419,8 +1419,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../../2-sql/5-runtime '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../../../test/utils @@ -3152,8 +3152,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../3-targets/3-targets/postgres '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../../test/utils @@ -3240,8 +3240,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../2-sql/2-authoring/contract-ts '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../../test/utils @@ -3322,8 +3322,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../2-sql/2-authoring/contract-ts '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../../test/utils @@ -3680,8 +3680,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../2-sql/2-authoring/contract-psl '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../../../test/utils @@ -5188,8 +5188,8 @@ importers: packages/9-public/@prisma/orm-toolchain: dependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/orm-framework': specifier: workspace:8.0.0-rc.11 version: link:../orm-framework @@ -5331,8 +5331,8 @@ importers: test/e2e/framework/test/fixtures: dependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/orm-extension-arktype-json': specifier: workspace:8.0.0-rc.11 version: link:../../../../../packages/9-public/@prisma/orm-extension-arktype-json @@ -5349,8 +5349,8 @@ importers: test/e2e/framework/test/sqlite/fixtures: dependencies: '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/orm-sqlite': specifier: workspace:8.0.0-rc.11 version: link:../../../../../../packages/9-public/@prisma/orm-sqlite @@ -5524,8 +5524,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../packages/0-shared/publish-surface '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@repo/test-utils': specifier: workspace:8.0.0-rc.11 version: link:../utils @@ -5638,8 +5638,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../../../../../packages/1-framework/0-foundation/utils '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/orm-extension-pgvector': specifier: workspace:8.0.0-rc.11 version: link:../../../../../../packages/9-public/@prisma/orm-extension-pgvector @@ -5713,8 +5713,8 @@ importers: specifier: workspace:8.0.0-rc.11 version: link:../../../../../../packages/1-framework/0-foundation/utils '@prisma/cli-engine': - specifier: 0.4.0 - version: 0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) + specifier: 0.5.0 + version: 0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4) '@prisma/orm-extension-pgvector': specifier: workspace:8.0.0-rc.11 version: link:../../../../../../packages/9-public/@prisma/orm-extension-pgvector @@ -7495,8 +7495,8 @@ packages: '@prisma/adapter-pg@7.10.0': resolution: {integrity: sha512-N7nwSor0HO1Kz6xBv0TPAjAPysKK0fac6p4fVN3ensLOuzc/83Fgmln5k92eK/cvzqdkSR/2kkAqlbcdwVrwpw==} - '@prisma/cli-engine@0.4.0': - resolution: {integrity: sha512-8mrARMPTQDKgAQ4M8NnDZuWqtWisnVaI1WI8+pAs+cBmurKxSjGxgNPsQgFwP7/Y3OhpbOtY4nJE/JqUbjVWLw==} + '@prisma/cli-engine@0.5.0': + resolution: {integrity: sha512-Bnou3nHmPESo2kAxp5ueDS9fCsox5jLR0BXmBdIoG69ljtnBXpd8Jzd2w8X4fWghS6Dj9WW2If9my7kwjpflLg==} engines: {node: '>=22.12.0'} peerDependencies: '@prisma/management-api-sdk': ^1.55.0 @@ -13340,7 +13340,7 @@ snapshots: transitivePeerDependencies: - pg-native - '@prisma/cli-engine@0.4.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4)': + '@prisma/cli-engine@0.5.0(@prisma/management-api-sdk@1.61.0)(magicast@0.5.4)': dependencies: '@clack/prompts': 1.5.0 '@prisma/management-api-sdk': 1.61.0 diff --git a/test/e2e/framework/test/fixtures/package.json b/test/e2e/framework/test/fixtures/package.json index d9a36b6ad58a..1e2e568b26d4 100644 --- a/test/e2e/framework/test/fixtures/package.json +++ b/test/e2e/framework/test/fixtures/package.json @@ -5,7 +5,7 @@ "version": "8.0.0-rc.11", "description": "The Postgres fixture of the e2e suite. Its own manifest because emission reads the nearest one to decide which package names generated files import, and this suite exercises two databases whose halves must not name each other's facade.", "dependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/orm-extension-arktype-json": "workspace:8.0.0-rc.11", "@prisma/orm-extension-pgvector": "workspace:8.0.0-rc.11", "@prisma/orm-postgres": "workspace:8.0.0-rc.11", diff --git a/test/e2e/framework/test/sqlite/fixtures/package.json b/test/e2e/framework/test/sqlite/fixtures/package.json index 69c19ad38284..86849383ccf4 100644 --- a/test/e2e/framework/test/sqlite/fixtures/package.json +++ b/test/e2e/framework/test/sqlite/fixtures/package.json @@ -5,7 +5,7 @@ "version": "8.0.0-rc.11", "description": "The SQLite fixture of the e2e suite. Its own manifest because emission reads the nearest one to decide which package names generated files import, and this suite exercises two databases whose halves must not name each other's facade.", "dependencies": { - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/orm-sqlite": "workspace:8.0.0-rc.11" } } diff --git a/test/integration/package.json b/test/integration/package.json index c452bc1ffaa3..4492d063e665 100644 --- a/test/integration/package.json +++ b/test/integration/package.json @@ -78,7 +78,7 @@ "@internal/middleware-cache": "workspace:8.0.0-rc.11", "@internal/mongo-lowering": "workspace:8.0.0-rc.11", "@internal/publish-surface": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@repo/test-utils": "workspace:8.0.0-rc.11", "@repo/tsdown": "workspace:8.0.0-rc.11", "@repo/tsconfig": "workspace:8.0.0-rc.11", diff --git a/test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/prisma.config.prisma7.ts b/test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/prisma.config.prisma7.ts index d53fbfe6fd37..7e989d14eb37 100644 --- a/test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/prisma.config.prisma7.ts +++ b/test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/prisma.config.prisma7.ts @@ -2,9 +2,9 @@ // app stays on one import root (ADR 242), and the published shell re-exports // exactly these two functions. import { defineConfig as postgres, prisma7Schema } from '@internal/postgres/config'; -import { defineConfig } from '@prisma/cli-engine'; +import { definePrismaConfig } from '@prisma/cli-engine'; -export default defineConfig({ +export default definePrismaConfig({ orm: postgres({ contract: prisma7Schema('./schema.prisma'), db: { diff --git a/test/integration/test/fixtures/cli/cli-e2e-test-app/package.json b/test/integration/test/fixtures/cli/cli-e2e-test-app/package.json index f4a11479230f..b378000d3e8a 100644 --- a/test/integration/test/fixtures/cli/cli-e2e-test-app/package.json +++ b/test/integration/test/fixtures/cli/cli-e2e-test-app/package.json @@ -19,7 +19,7 @@ "@internal/target-mongo": "workspace:8.0.0-rc.11", "@internal/target-postgres": "workspace:8.0.0-rc.11", "@internal/utils": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/orm-extension-pgvector": "workspace:8.0.0-rc.11", "@prisma/orm-mongo": "workspace:8.0.0-rc.11", "@prisma/orm-postgres": "workspace:8.0.0-rc.11", diff --git a/test/integration/test/fixtures/cli/cli-integration-test-app/package.json b/test/integration/test/fixtures/cli/cli-integration-test-app/package.json index 4fb2d473d6d4..2089b49aa23b 100644 --- a/test/integration/test/fixtures/cli/cli-integration-test-app/package.json +++ b/test/integration/test/fixtures/cli/cli-integration-test-app/package.json @@ -20,7 +20,7 @@ "@internal/target-mongo": "workspace:8.0.0-rc.11", "@internal/target-postgres": "workspace:8.0.0-rc.11", "@internal/utils": "workspace:8.0.0-rc.11", - "@prisma/cli-engine": "0.4.0", + "@prisma/cli-engine": "0.5.0", "@prisma/orm-extension-pgvector": "workspace:8.0.0-rc.11", "@prisma/orm-mongo": "workspace:8.0.0-rc.11", "@prisma/orm-postgres": "workspace:8.0.0-rc.11", diff --git a/test/integration/test/ports/engines/writes/top_level_mutations/create_many/_fixture/prisma.config.ts b/test/integration/test/ports/engines/writes/top_level_mutations/create_many/_fixture/prisma.config.ts index f197173e5b84..c19c293e813c 100644 --- a/test/integration/test/ports/engines/writes/top_level_mutations/create_many/_fixture/prisma.config.ts +++ b/test/integration/test/ports/engines/writes/top_level_mutations/create_many/_fixture/prisma.config.ts @@ -1,7 +1,7 @@ import { defineConfig as ormConfig } from '@internal/postgres/config'; -import { defineConfig } from '@prisma/cli-engine'; +import { definePrismaConfig } from '@prisma/cli-engine'; -export default defineConfig({ +export default definePrismaConfig({ orm: ormConfig({ contract: './contract.prisma', output: 'generated', diff --git a/upgrade-instructions/pending/config-declaring-file-paths/app/instructions.md b/upgrade-instructions/pending/config-declaring-file-paths/app/instructions.md new file mode 100644 index 000000000000..e447fc814c7b --- /dev/null +++ b/upgrade-instructions/pending/config-declaring-file-paths/app/instructions.md @@ -0,0 +1,36 @@ +--- +changes: + - id: engine-pin-moves-to-0-5-0 + summary: | + The toolchain now peers `@prisma/cli-engine@0.5.0`. A project that pins + `@prisma/cli-engine` itself must move the pin to `0.5.0`. + detection: + glob: "**/package.json" + contains: + - '"@prisma/cli-engine": "0.4.0"' + - id: orm-config-paths-resolve-against-declaring-file + summary: | + Relative paths in the `orm` section of `prisma.config.ts` (contract inputs and + output, `migrations.dir`) now resolve against the config file that declares them, + not against the directory the command runs in. Engine 0.5.0 discovers config + files from the current directory up to the repository root and merges them, so a + root config's `orm` section reaches commands run in any subdirectory; a path + written next to the root config keeps meaning the root's directory from anywhere. + A project that ran commands only from the config's own directory sees no change. + A project that relied on cwd-relative resolution from another directory must + rewrite those paths relative to the config file. + detection: + glob: "**/prisma.config.ts" + contains: + - "orm" +--- + +# `orm` config paths anchor at the declaring file + +## `engine-pin-moves-to-0-5-0` + +For every `package.json` matched by `detection`, change the `@prisma/cli-engine` version to `0.5.0` and reinstall. Projects assembled by the unified `prisma` CLI resolve the engine automatically and need no change. + +## `orm-config-paths-resolve-against-declaring-file` + +Relative paths in the `orm` section now mean "relative to this config file", from whatever directory a command runs in. Check each relative path in the section (contract `input`/`output`, `migrations.dir`): if it was written relative to the config file's own directory — the overwhelmingly common case — nothing changes. If it relied on being resolved against a different working directory, rewrite it relative to the config file. diff --git a/upgrade-instructions/pending/config-declaring-file-paths/extension/instructions.md b/upgrade-instructions/pending/config-declaring-file-paths/extension/instructions.md new file mode 100644 index 000000000000..e447fc814c7b --- /dev/null +++ b/upgrade-instructions/pending/config-declaring-file-paths/extension/instructions.md @@ -0,0 +1,36 @@ +--- +changes: + - id: engine-pin-moves-to-0-5-0 + summary: | + The toolchain now peers `@prisma/cli-engine@0.5.0`. A project that pins + `@prisma/cli-engine` itself must move the pin to `0.5.0`. + detection: + glob: "**/package.json" + contains: + - '"@prisma/cli-engine": "0.4.0"' + - id: orm-config-paths-resolve-against-declaring-file + summary: | + Relative paths in the `orm` section of `prisma.config.ts` (contract inputs and + output, `migrations.dir`) now resolve against the config file that declares them, + not against the directory the command runs in. Engine 0.5.0 discovers config + files from the current directory up to the repository root and merges them, so a + root config's `orm` section reaches commands run in any subdirectory; a path + written next to the root config keeps meaning the root's directory from anywhere. + A project that ran commands only from the config's own directory sees no change. + A project that relied on cwd-relative resolution from another directory must + rewrite those paths relative to the config file. + detection: + glob: "**/prisma.config.ts" + contains: + - "orm" +--- + +# `orm` config paths anchor at the declaring file + +## `engine-pin-moves-to-0-5-0` + +For every `package.json` matched by `detection`, change the `@prisma/cli-engine` version to `0.5.0` and reinstall. Projects assembled by the unified `prisma` CLI resolve the engine automatically and need no change. + +## `orm-config-paths-resolve-against-declaring-file` + +Relative paths in the `orm` section now mean "relative to this config file", from whatever directory a command runs in. Check each relative path in the section (contract `input`/`output`, `migrations.dir`): if it was written relative to the config file's own directory — the overwhelmingly common case — nothing changes. If it relied on being resolved against a different working directory, rewrite it relative to the config file.