Comprehensive internal utility library for Prisma's CLI operations, schema management, generator handling, and engine interactions
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The generator system domain provides comprehensive generator lifecycle management including initialization, execution, cleanup, and registry management for both JSON-RPC and in-process generators.
GeneratorAbstract base class for all generator implementations providing common interface and lifecycle management.
abstract class Generator {
abstract init(): Promise<void>
abstract generate(): Promise<void>
abstract setOptions(options: GeneratorOptions): void
abstract setBinaryPaths(binaryPaths: BinaryPaths): void
abstract getPrettyName(): string
abstract getProvider(): string
abstract stop(): void
}Methods:
init(): Promise<void> - Initialize the generatorgenerate(): Promise<void> - Execute generation processsetOptions(options: GeneratorOptions): void - Set generator optionssetBinaryPaths(binaryPaths: BinaryPaths): void - Set binary paths for enginesgetPrettyName(): string - Get display name for UIgetProvider(): string - Get provider name/identifierstop(): void - Stop and cleanup the generatorJsonRpcGeneratorGenerator implementation for JSON-RPC based external generators that communicate via process IPC.
class JsonRpcGenerator extends Generator {
constructor(
executablePath: string,
config: GeneratorConfig,
isNode?: boolean
)
}Constructor Parameters:
executablePath: string - Path to the generator executableconfig: GeneratorConfig - Generator configurationisNode?: boolean - Whether the generator is a Node.js processExample:
const generator = new JsonRpcGenerator(
'/path/to/prisma-client-generator',
{
name: 'client',
provider: 'prisma-client-js',
output: './node_modules/.prisma/client',
config: {},
binaryTargets: ['native']
},
true // is Node.js
)
await generator.init()
await generator.generate()
generator.stop()InProcessGeneratorGenerator implementation for in-process generators that run directly within the same Node.js process.
class InProcessGenerator extends Generator {
constructor(config: GeneratorConfig, generator: IGenerator)
}Constructor Parameters:
config: GeneratorConfig - Generator configurationgenerator: IGenerator - Generator implementation interfaceExample:
const inProcessGen = new InProcessGenerator(
config,
{
onManifest: () => Promise.resolve(manifest),
onGenerate: (options) => Promise.resolve()
}
)getGenerators(options)Factory function that creates and initializes all generators from schema configuration.
function getGenerators(options: GetGeneratorOptions): Promise<Generator[]>GetGeneratorOptions:
interface GetGeneratorOptions {
schemaPath?: string // Path to schema file
cwd?: string // Current working directory
schemaContent?: string // Schema content (alternative to schemaPath)
generators?: GeneratorConfig[] // Explicit generator configurations
generatorRegistry?: GeneratorRegistry // Registry of available generators
skipDownload?: boolean // Skip binary downloads
printDownloadProgress?: boolean // Show download progress
version?: string // Prisma version
engineVersion?: string // Engine version
}Returns: Promise<Generator[]> - Array of initialized generators
Example:
const generators = await getGenerators({
schemaPath: './prisma/schema.prisma',
cwd: process.cwd(),
printDownloadProgress: true,
skipDownload: false
})
console.log(`Initialized ${generators.length} generators`)
// Run all generators
for (const generator of generators) {
await generator.generate()
console.log(`✓ ${generator.getPrettyName()}`)
}
// Cleanup
generators.forEach(gen => gen.stop())getGenerator(options)Shortcut function for getting a single generator instance (useful for testing and single-generator scenarios).
function getGenerator(options: GetGeneratorOptions): Promise<Generator>Parameters: Same as getGenerators
Returns: Promise<Generator> - Single generator instance
Example:
const generator = await getGenerator({
schemaContent: `
generator client {
provider = "prisma-client-js"
output = "./generated/client"
}
`,
cwd: process.cwd()
})
await generator.generate()fixBinaryTargets(schemaBinaryTargets, runtimeBinaryTarget)Fixes binary targets by adding native or runtime target as needed to ensure generators can run properly.
function fixBinaryTargets(
schemaBinaryTargets: BinaryTargetsEnvValue[],
runtimeBinaryTarget: BinaryTarget | string
): BinaryTargetsEnvValue[]Parameters:
schemaBinaryTargets: BinaryTargetsEnvValue[] - Binary targets from schemaruntimeBinaryTarget: BinaryTarget | string - Runtime binary targetReturns: BinaryTargetsEnvValue[] - Fixed binary targets including necessary runtime targets
Example:
import { fixBinaryTargets, getBinaryTargetForCurrentPlatform } from '@prisma/internals'
const schemaBinaryTargets = [{ fromEnvVar: null, value: 'linux-musl' }]
const runtimeTarget = getBinaryTargetForCurrentPlatform()
const fixedTargets = fixBinaryTargets(schemaBinaryTargets, runtimeTarget)
console.log('Fixed binary targets:', fixedTargets)
// Ensures current platform is included if not already specifiedprintGeneratorConfig(config)Formats generator configuration as a readable string for debugging and logging.
function printGeneratorConfig(config: GeneratorConfig): stringParameters:
config: GeneratorConfig - Generator configuration to formatReturns: string - Formatted configuration string
Example:
const config: GeneratorConfig = {
name: 'client',
provider: 'prisma-client-js',
output: './generated/client',
config: { engineType: 'binary' },
binaryTargets: ['native', 'linux-musl']
}
console.log(printGeneratorConfig(config))
// Output:
// generator client {
// provider = "prisma-client-js"
// output = "./generated/client"
// engineType = "binary"
// binaryTargets = ["native", "linux-musl"]
// }GeneratorRegistryRegistry mapping generator providers to their implementations.
type GeneratorRegistry = Record<string, GeneratorRegistryEntry>GeneratorRegistryEntryUnion type for registry entries supporting both RPC and in-process generators.
type GeneratorRegistryEntry =
| {
type: 'rpc'
generatorPath: string
isNode?: boolean
}
| {
type: 'in-process'
generator: IGenerator
}RPC Registry Entry:
type: 'rpc' - Indicates JSON-RPC generatorgeneratorPath: string - Path to generator executableisNode?: boolean - Whether generator is Node.js basedIn-Process Registry Entry:
type: 'in-process' - Indicates in-process generatorgenerator: IGenerator - Generator implementationExample:
const registry: GeneratorRegistry = {
'prisma-client-js': {
type: 'rpc',
generatorPath: './node_modules/.prisma/client/generator-build/index.js',
isNode: true
},
'custom-generator': {
type: 'in-process',
generator: {
onManifest: () => Promise.resolve(customManifest),
onGenerate: (options) => customGenerate(options)
}
}
}IGeneratorInterface for in-process generator implementations.
interface IGenerator {
onManifest(config: GeneratorConfig): Promise<GeneratorManifest>
onGenerate(options: GeneratorOptions): Promise<void>
}Methods:
onManifest(config: GeneratorConfig): Promise<GeneratorManifest> - Return generator manifestonGenerate(options: GeneratorOptions): Promise<void> - Execute generationGeneratorManifestManifest describing generator capabilities and requirements.
interface GeneratorManifest {
prettyName?: string // Display name
defaultOutput?: string // Default output directory
denylist?: string[] // Unsupported features
requiresGenerators?: string[] // Required other generators
requiresEngines?: string[] // Required engine binaries
version: string // Generator version
}BinaryPathsPaths to engine binaries required by generators.
interface BinaryPaths {
queryEngine?: string // Query engine binary path
schemaEngine?: string // Schema engine binary path
libqueryEngine?: string // Query engine library path
migrationEngine?: string // Migration engine binary path (legacy)
}import {
getGenerators,
printGeneratorConfig,
fixBinaryTargets,
getBinaryTargetForCurrentPlatform
} from '@prisma/internals'
async function runGenerationPipeline() {
try {
// Get all generators from schema
const generators = await getGenerators({
schemaPath: './prisma/schema.prisma',
cwd: process.cwd(),
printDownloadProgress: true
})
console.log(`Found ${generators.length} generators`)
// Initialize all generators
for (const generator of generators) {
console.log(`Initializing ${generator.getPrettyName()}...`)
await generator.init()
}
// Set binary paths for all generators
const binaryPaths = {
queryEngine: '/path/to/query-engine',
schemaEngine: '/path/to/schema-engine'
}
generators.forEach(gen => {
gen.setBinaryPaths(binaryPaths)
})
// Generate with each generator
for (const generator of generators) {
const startTime = Date.now()
console.log(`Generating ${generator.getPrettyName()}...`)
await generator.generate()
const duration = Date.now() - startTime
console.log(`✓ Generated ${generator.getPrettyName()} (${duration}ms)`)
}
console.log('All generators completed successfully')
} catch (error) {
console.error('Generation failed:', error)
throw error
} finally {
// Always cleanup generators
if (generators) {
generators.forEach(gen => {
try {
gen.stop()
} catch (stopError) {
console.warn(`Failed to stop generator: ${stopError.message}`)
}
})
}
}
}import { InProcessGenerator, type IGenerator, type GeneratorManifest } from '@prisma/internals'
// Define custom generator
const customGenerator: IGenerator = {
async onManifest(config): Promise<GeneratorManifest> {
return {
prettyName: 'Custom TypeScript Generator',
defaultOutput: './generated/custom',
version: '1.0.0',
requiresEngines: ['queryEngine']
}
},
async onGenerate(options) {
console.log('Generating custom TypeScript files...')
// Access DMMF for model information
const models = options.dmmf.datamodel.models
for (const model of models) {
// Generate custom TypeScript interfaces
const interfaceCode = generateInterface(model)
// Write to output directory
const outputPath = path.join(options.generator.output!, `${model.name}.ts`)
await fs.writeFile(outputPath, interfaceCode)
}
console.log(`Generated files for ${models.length} models`)
}
}
// Create generator config
const config: GeneratorConfig = {
name: 'custom',
provider: 'custom-ts-generator',
output: './generated/custom',
config: {},
binaryTargets: ['native']
}
// Create and use generator
const generator = new InProcessGenerator(config, customGenerator)
await generator.init()
await generator.generate()
generator.stop()import {
getGenerators,
type GeneratorRegistry,
type GeneratorRegistryEntry
} from '@prisma/internals'
// Create custom registry
const customRegistry: GeneratorRegistry = {
// Built-in Prisma generators
'prisma-client-js': {
type: 'rpc',
generatorPath: require.resolve('@prisma/client/generator-build/index.js'),
isNode: true
},
// Custom external generator
'custom-external': {
type: 'rpc',
generatorPath: './custom-generators/external-gen',
isNode: false
},
// Custom in-process generator
'custom-internal': {
type: 'in-process',
generator: customGenerator
}
}
// Use generators with custom registry
async function runWithCustomRegistry() {
const generators = await getGenerators({
schemaContent: `
generator client {
provider = "prisma-client-js"
output = "./generated/client"
}
generator custom {
provider = "custom-internal"
output = "./generated/custom"
}
`,
generatorRegistry: customRegistry,
cwd: process.cwd()
})
// Process generators
for (const gen of generators) {
console.log(`Processing: ${gen.getProvider()}`)
await gen.init()
await gen.generate()
}
// Cleanup
generators.forEach(gen => gen.stop())
}import {
fixBinaryTargets,
getBinaryTargetForCurrentPlatform,
type BinaryTargetsEnvValue
} from '@prisma/internals'
function manageBinaryTargets(generatorConfig: GeneratorConfig) {
// Get current platform
const currentPlatform = getBinaryTargetForCurrentPlatform()
console.log('Current platform:', currentPlatform)
// Convert string array to BinaryTargetsEnvValue format
const schemaBinaryTargets: BinaryTargetsEnvValue[] =
generatorConfig.binaryTargets.map(target => ({
fromEnvVar: null,
value: target
}))
// Fix binary targets to ensure current platform is included
const fixedTargets = fixBinaryTargets(schemaBinaryTargets, currentPlatform)
// Update generator config
const updatedConfig: GeneratorConfig = {
...generatorConfig,
binaryTargets: fixedTargets.map(t => t.value)
}
console.log('Original targets:', generatorConfig.binaryTargets)
console.log('Fixed targets:', updatedConfig.binaryTargets)
return updatedConfig
}Install with Tessl CLI
npx tessl i tessl/npm-prisma--internals