parseWithAwait.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import { z } from '@hono/zod-openapi';
  2. export async function parseWithAwait<T>(schema: z.ZodSchema<T>, data: unknown): Promise<T> {
  3. // 先尝试同步解析,捕获 Promise 错误
  4. const syncResult = schema.safeParse(data);
  5. if (!syncResult.success) {
  6. // 提取 Promise 错误的路径信息
  7. const promiseErrors = syncResult.error.issues.filter(issue =>
  8. issue.code === 'invalid_type' &&
  9. issue.message.includes('received Promise')
  10. );
  11. if (promiseErrors.length > 0) {
  12. // 根据路径直接 await Promise
  13. const processedData = await resolvePromisesByPath(data, promiseErrors);
  14. // 重新解析处理后的数据
  15. return schema.parse(processedData) as T;
  16. }
  17. throw syncResult.error;
  18. }
  19. return syncResult.data as T;
  20. }
  21. async function resolvePromisesByPath(data: any, promiseErrors: any[]): Promise<any> {
  22. const clonedData = JSON.parse(JSON.stringify(data, (_, value) => {
  23. // 保留 Promise 对象,不进行序列化
  24. return typeof value?.then === 'function' ? value : value;
  25. }));
  26. // 根据错误路径逐个处理 Promise
  27. for (const error of promiseErrors) {
  28. const path = error.path;
  29. const promiseValue = getValueByPath(data, path);
  30. if (promiseValue && typeof promiseValue.then === 'function') {
  31. const resolvedValue = await promiseValue;
  32. setValueByPath(clonedData, path, resolvedValue);
  33. }
  34. }
  35. return clonedData;
  36. }
  37. function getValueByPath(obj: any, path: (string | number)[]): any {
  38. return path.reduce((current, key) => current?.[key], obj);
  39. }
  40. function setValueByPath(obj: any, path: (string | number)[], value: any): void {
  41. const lastKey = path[path.length - 1];
  42. const parentPath = path.slice(0, -1);
  43. const parent = getValueByPath(obj, parentPath);
  44. if (parent) {
  45. parent[lastKey] = value;
  46. }
  47. }