| 1962 | * @throws Error if parsing fails after attempting type conversions |
| 1963 | */ |
| 1964 | export async function parseWithTypeConversion<T extends z.ZodTypeAny>(schema: T, arg: unknown, maxDepth: number = 10): Promise<z.infer<T>> { |
| 1965 | // Safety check: prevent infinite recursion |
| 1966 | if (maxDepth <= 0) { |
| 1967 | throw new Error('Maximum recursion depth reached in parseWithTypeConversion') |
| 1968 | } |
| 1969 | |
| 1970 | try { |
| 1971 | return await schema.parseAsync(arg) |
| 1972 | } catch (e) { |
| 1973 | // Check if it's a ZodError and try to fix type mismatches |
| 1974 | if (z.ZodError && e instanceof z.ZodError) { |
| 1975 | const zodError = e as z.ZodError |
| 1976 | // Deep clone the arg to avoid mutating the original |
| 1977 | const modifiedArg = typeof arg === 'object' && arg !== null ? cloneDeep(arg) : arg |
| 1978 | let hasModification = false |
| 1979 | |
| 1980 | // Helper function to set a value at a nested path |
| 1981 | const setValueAtPath = (obj: any, path: (string | number)[], value: any): void => { |
| 1982 | let current = obj |
| 1983 | for (let i = 0; i < path.length - 1; i++) { |
| 1984 | const key = path[i] |
| 1985 | if (current && typeof current === 'object' && key in current) { |
| 1986 | current = current[key] |
| 1987 | } else { |
| 1988 | return // Path doesn't exist |
| 1989 | } |
| 1990 | } |
| 1991 | if (current !== undefined && current !== null) { |
| 1992 | const finalKey = path[path.length - 1] |
| 1993 | current[finalKey] = value |
| 1994 | } |
| 1995 | } |
| 1996 | |
| 1997 | // Helper function to get a value at a nested path |
| 1998 | const getValueAtPath = (obj: any, path: (string | number)[]): any => { |
| 1999 | let current = obj |
| 2000 | for (const key of path) { |
| 2001 | if (current && typeof current === 'object' && key in current) { |
| 2002 | current = current[key] |
| 2003 | } else { |
| 2004 | return undefined |
| 2005 | } |
| 2006 | } |
| 2007 | return current |
| 2008 | } |
| 2009 | |
| 2010 | // Helper function to convert value to expected type |
| 2011 | const convertValue = (value: any, expected: string, received: string): any => { |
| 2012 | // Expected string |
| 2013 | if (expected === 'string') { |
| 2014 | if (received === 'object' || received === 'array') { |
| 2015 | return JSON.stringify(value) |
| 2016 | } |
| 2017 | if (received === 'number' || received === 'boolean') { |
| 2018 | return String(value) |
| 2019 | } |
| 2020 | } |
| 2021 | // Expected number |