(body: unknown)
| 10 | | { ok: false; error: string }; |
| 11 | |
| 12 | export function parseAnalyzeBody(body: unknown): ParseResult { |
| 13 | const b = (body ?? {}) as Record<string, unknown>; |
| 14 | const ticker = |
| 15 | typeof b.ticker === "string" ? b.ticker.trim().slice(0, 32) : ""; |
| 16 | const tradeDate = typeof b.tradeDate === "string" ? b.tradeDate : ""; |
| 17 | if (!ticker) return { ok: false, error: "ticker is required" }; |
| 18 | if (!DATE_RE.test(tradeDate)) { |
| 19 | return { ok: false, error: "tradeDate must be YYYY-MM-DD" }; |
| 20 | } |
| 21 | const selectedAnalysts = Array.isArray(b.selectedAnalysts) |
| 22 | ? b.selectedAnalysts.filter( |
| 23 | (a): a is AnalystKey => |
| 24 | typeof a === "string" && |
| 25 | (VALID_ANALYSTS as readonly string[]).includes(a), |
| 26 | ) |
| 27 | : undefined; |
| 28 | const assetType = |
| 29 | b.assetType === "stock" || b.assetType === "crypto" ? b.assetType : undefined; |
| 30 | |
| 31 | const locale = typeof b.locale === "string" ? b.locale : ""; |
| 32 | const outputLanguage = isValidLocale(locale) ? localeToLangName(locale) : undefined; |
| 33 | |
| 34 | return { |
| 35 | ok: true, |
| 36 | input: { |
| 37 | ticker, |
| 38 | tradeDate, |
| 39 | selectedAnalysts, |
| 40 | assetType, |
| 41 | ...(outputLanguage ? { outputLanguage } : {}), |
| 42 | }, |
| 43 | }; |
| 44 | } |
no test coverage detected