{"record":{"id":"1b69411a65647025","repo":"jackwener/OpenCLI","slug":"name-must-be-yyyy-mm-dd-got-json-stringify","errorCode":null,"errorMessage":"--${name} must be YYYY-MM-DD, got ${JSON.stringify(raw)}","messagePattern":"--(.+?) must be YYYY-MM-DD, got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/utils.js","lineNumber":215,"sourceCode":"    };\n}\n\n/* --------- Helpers shared by hotel-search / flight (browser-context) ---------- */\n\nconst ISO_DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Validate YYYY-MM-DD and return the canonical string. Rejects out-of-range\n * month/day, malformed input, and silent NaN. Does NOT coerce or shift timezones.\n */\nexport function parseIsoDate(name, raw) {\n    if (raw === undefined || raw === null || raw === '' || String(raw).trim() === '') {\n        throw new ArgumentError(`--${name} is required (YYYY-MM-DD)`);\n    }\n    const value = String(raw);\n    const m = ISO_DATE_RE.exec(value);\n    if (!m) {\n        throw new ArgumentError(`--${name} must be YYYY-MM-DD, got ${JSON.stringify(raw)}`);\n    }\n    const year = Number(m[1]);\n    const month = Number(m[2]);\n    const day = Number(m[3]);\n    if (month < 1 || month > 12 || day < 1 || day > 31) {\n        throw new ArgumentError(`--${name} has invalid month/day: ${value}`);\n    }\n    // Cross-check via UTC date math so 2026-02-30 doesn't pass.\n    const parsed = new Date(Date.UTC(year, month - 1, day));\n    if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) {\n        throw new ArgumentError(`--${name} is not a real calendar date: ${value}`);\n    }\n    return value;\n}\n\n/**\n * Validate a 3-letter IATA airport / metro code, return uppercase.\n * Ctrip URL accepts both single-airport (PEK / PVG) and metro-group (BJS / SHA) codes.","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/utils.js#L197-L233","documentation":"parseIsoDate throws this ArgumentError when the provided value does not match the strict YYYY-MM-DD pattern /^\\d{4}-\\d{2}-\\d{2}$/. The raw input is JSON-stringified into the message. No coercion (e.g. 2026/09/01 or 20260901) is attempted, keeping behavior deterministic.","triggerScenarios":"Calling parseIsoDate(name, raw) with values like '2026/09/01', '09-01-2026', '2026-9-1', 'tomorrow', or a Date object stringified — anything not exactly four digits, dash, two digits, dash, two digits.","commonSituations":"US-style date format habit (MM/DD/YYYY); user types a human phrase like 'next Friday'; locale-formatted date pasted from a calendar app; missing zero-padding.","solutions":["Rewrite the date as YYYY-MM-DD with zero-padded month/day, e.g. 2026-09-01","Use `date -d 'tomorrow' +%F` (GNU) to generate a compliant string","Do not rely on the library to coerce formats — validate before calling","Check for stray whitespace or quotes around the value"],"exampleFix":"// before\n--depart 9/1/2026\n// after\n--depart 2026-09-01","handlingStrategy":"validation","validationCode":"const ISO_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\nif (!ISO_RE.test(dateInput)) throw new Error(`date must be YYYY-MM-DD, got ${dateInput}`);","typeGuard":"function isIsoDateString(v) {\n  return typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(v);\n}","tryCatchPattern":"try {\n  const date = parseIsoDate('depart', raw);\n} catch (err) {\n  if (err instanceof ArgumentError && /must be YYYY-MM-DD/.test(err.message)) {\n    // show usage example: 2026-09-01\n  }\n  throw err;\n}","preventionTips":["Always format dates as zero-padded YYYY-MM-DD","Use `date +%F` or toISOString().slice(0,10) to generate dates","Never pass human phrases like 'tomorrow' directly","Normalize slashes/dots to dashes before invoking"],"tags":["argument-validation","date-format","cli"],"backgroundTag":"invalid-date-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}