diff --git a/src/lib/error.ts b/src/lib/error.ts index ab5cad1..b6294a5 100644 --- a/src/lib/error.ts +++ b/src/lib/error.ts @@ -3,7 +3,8 @@ */ export interface GraphError { message: string; - path?: string[]; + /** GraphQL response path - field names and list indexes. */ + path?: ReadonlyArray; } /** RawError is an error that can be converted to a string by ErrorMessage */ @@ -15,14 +16,22 @@ export type RawError = ErrorMessage | Error | string | GraphError[]; * @returns true if the error is a RawError, false otherwise */ export const isRawError = (error: unknown): error is RawError => { + const isGraphError = (entry: unknown): entry is GraphError => { + if (!entry || typeof entry !== 'object') return false; + const candidate = entry as { message?: unknown; path?: unknown }; + if (typeof candidate.message !== 'string') return false; + if (candidate.path === undefined) return true; + return ( + Array.isArray(candidate.path) && + candidate.path.every((p) => typeof p === 'string' || typeof p === 'number') + ); + }; + return ( error instanceof ErrorMessage || error instanceof Error || typeof error === 'string' || - (Array.isArray(error) && - error.every( - (e) => typeof e.message === 'string' && (e.path === undefined || Array.isArray(e.path)) - )) + (Array.isArray(error) && error.every(isGraphError)) ); }; @@ -73,6 +82,21 @@ export const checkGraphResponse = ( export class ErrorMessage { private _lines: string[] = []; + /** formats a GraphQL path using dot notation for fields and brackets for indexes */ + private static formatGraphPath(path: ReadonlyArray): string { + let formatted = ''; + for (const segment of path) { + if (typeof segment === 'number') { + formatted += `[${segment}]`; + } else if (formatted.length === 0) { + formatted = segment; + } else { + formatted += `.${segment}`; + } + } + return formatted; + } + /** * Always creates a new ErrorMessage instance, even if there are no errors. * @param errors The raw errors to convert and store, or null/undefined for no error. @@ -136,7 +160,7 @@ export class ErrorMessage { errorLines = raw.map((e) => { const messageString = e.message || 'Unknown error'; if (e.path && e.path.length > 0) { - return `"${messageString}" at ${e.path.join('.')}`; + return `"${messageString}" at ${ErrorMessage.formatGraphPath(e.path)}`; } return messageString; });