Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,213
  • Linux
  • Apple
createErrorMessageWithContext.ts6.98 kB
import * as DMMF from '@prisma/dmmf' import indentString from 'indent-string' import { bold, dim, gray, red, underline } from 'kleur/colors' import { CallSite, LocationInFile } from './CallSite' import { SourceFileSlice } from './SourceFileSlice' declare global { /** * a global variable that is injected by us via jest to make our snapshots * work in clients that cannot read from disk (e.g. wasm or edge clients) */ let $getTemplateParameters: typeof getTemplateParameters | undefined } export interface ErrorArgs { callsite?: CallSite originalMethod: string message: string isPanic?: boolean showColors?: boolean callArguments?: string } type Colors = { red: (str: string) => string gray: (str: string) => string dim: (str: string) => string bold: (str: string) => string underline: (str: string) => string highlightSource: (source: SourceFileSlice) => SourceFileSlice } const colorsEnabled: Colors = { red, gray, dim, bold, underline, highlightSource: (source) => source.highlight(), } const colorsDisabled: Colors = { red: (str) => str, gray: (str) => str, dim: (str) => str, bold: (str) => str, underline: (str) => str, highlightSource: (source) => source, } type ErrorContextTemplateParameters = { functionName: string message: string location?: LocationInFile contextLines?: SourceFileSlice callArguments?: string isPanic: boolean } function getRawTemplateParameters({ message, originalMethod, isPanic, callArguments, }: ErrorArgs): ErrorContextTemplateParameters { return { functionName: `prisma.${originalMethod}()`, message, isPanic: isPanic ?? false, callArguments, } } export function getTemplateParameters( { callsite, message, originalMethod, isPanic, callArguments }: ErrorArgs, colors: Colors, ): ErrorContextTemplateParameters { const templateParameters = getRawTemplateParameters({ message, originalMethod, isPanic, callArguments }) // @ts-ignore if (!callsite || typeof window !== 'undefined') { return templateParameters } if (process.env.NODE_ENV === 'production') { return templateParameters } const callLocation = callsite.getLocation() if (!callLocation || !callLocation.lineNumber || !callLocation.columnNumber) { return templateParameters } const contextFirstLine = Math.max(1, callLocation.lineNumber - 3) let source = SourceFileSlice.read(callLocation.fileName)?.slice(contextFirstLine, callLocation.lineNumber) const invocationLine = source?.lineAt(callLocation.lineNumber) if (source && invocationLine) { const invocationLineIndent = getIndent(invocationLine) const invocationCallCode = findPrismaActionCall(invocationLine) if (!invocationCallCode) { return templateParameters } templateParameters.functionName = `${invocationCallCode.code})` templateParameters.location = callLocation if (!isPanic) { source = source.mapLineAt(callLocation.lineNumber, (line) => line.slice(0, invocationCallCode.openingBraceIndex)) } source = colors.highlightSource(source) const numberColumnWidth = String(source.lastLineNumber).length templateParameters.contextLines = source .mapLines((line, lineNumber) => colors.gray(String(lineNumber).padStart(numberColumnWidth)) + ' ' + line) .mapLines((line) => colors.dim(line)) .prependSymbolAt(callLocation.lineNumber, colors.bold(colors.red('→'))) if (callArguments) { let indentValue = invocationLineIndent + numberColumnWidth + 1 /* space between number and code */ indentValue += 2 // arrow + space between arrow and number // indent all lines but first, because first line of the arguments will be printed // on the same line as the function call templateParameters.callArguments = indentString(callArguments, indentValue).slice(indentValue) } } return templateParameters } function findPrismaActionCall(str: string): { code: string; openingBraceIndex: number } | null { const allActions = Object.keys(DMMF.ModelAction).join('|') const regexp = new RegExp(String.raw`\.(${allActions})\(`) const match = regexp.exec(str) if (match) { const openingBraceIndex = match.index + match[0].length // to get the code we are slicing the string up to a found brace. We start // with first non-space character if space is found in the line before that or // 0 if it is not. const statementStart = str.lastIndexOf(' ', match.index) + 1 return { code: str.slice(statementStart, openingBraceIndex), openingBraceIndex, } } return null } function getIndent(line: string): number { let spaceCount = 0 for (let i = 0; i < line.length; i++) { if (line.charAt(i) !== ' ') { return spaceCount } spaceCount++ } return spaceCount } function stringifyErrorMessage( { functionName, location, message, isPanic, contextLines, callArguments }: ErrorContextTemplateParameters, colors: Colors, ) { const lines: string[] = [''] const introSuffix = location ? ' in' : ':' if (isPanic) { lines.push(colors.red(`Oops, an unknown error occurred! This is ${colors.bold('on us')}, you did nothing wrong.`)) lines.push(colors.red(`It occurred in the ${colors.bold(`\`${functionName}\``)} invocation${introSuffix}`)) } else { lines.push(colors.red(`Invalid ${colors.bold(`\`${functionName}\``)} invocation${introSuffix}`)) } if (location) { lines.push(colors.underline(stringifyLocationInFile(location))) } if (contextLines) { lines.push('') const contextLineParts = [contextLines.toString()] if (callArguments) { contextLineParts.push(callArguments) contextLineParts.push(colors.dim(')')) } lines.push(contextLineParts.join('')) if (callArguments) { lines.push('') } } else { lines.push('') if (callArguments) { lines.push(callArguments) } lines.push('') } lines.push(message) return lines.join('\n') } function stringifyLocationInFile(location: LocationInFile): string { const parts = [location.fileName] if (location.lineNumber) { parts.push(String(location.lineNumber)) } if (location.columnNumber) { parts.push(String(location.columnNumber)) } return parts.join(':') } export function createErrorMessageWithContext(args: ErrorArgs): string { const colors = args.showColors ? colorsEnabled : colorsDisabled let templateParameters: ErrorContextTemplateParameters if ( TARGET_BUILD_TYPE === 'wasm-engine-edge' || TARGET_BUILD_TYPE === 'wasm-compiler-edge' || TARGET_BUILD_TYPE === 'edge' ) { if (typeof $getTemplateParameters !== 'undefined') { templateParameters = $getTemplateParameters(args, colors) } else { templateParameters = getRawTemplateParameters(args) } } else { templateParameters = getTemplateParameters(args, colors) } return stringifyErrorMessage(templateParameters, colors) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/prisma/prisma'

If you have feedback or need assistance with the MCP directory API, please join our Discord server