{"record":{"id":"15fa60aff588bdb6","repo":"jackwener/OpenCLI","slug":"period-must-be-all-lastmonth-last3months-last6m","errorCode":null,"errorMessage":"period must be all, lastMonth, last3Months, last6Months, last12Months, a year like 2025, or YYYY-MM-DD:YYYY-MM-DD","messagePattern":"period must be all, lastMonth, last3Months, last6Months, last12Months, a year like 2025, or YYYY-MM-DD:YYYY-MM-DD","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/hltv/utils.js","lineNumber":223,"sourceCode":"  return copy;\n}\n\nexport function resolvePeriod(period) {\n  const raw = String(period ?? 'all').trim();\n  if (raw === 'all') return null;\n\n  const now = new Date();\n  if (raw === 'lastMonth') return { startDate: formatDate(addMonths(now, -1)), endDate: formatDate(now) };\n  if (raw === 'last3Months') return { startDate: formatDate(addMonths(now, -3)), endDate: formatDate(now) };\n  if (raw === 'last6Months') return { startDate: formatDate(addMonths(now, -6)), endDate: formatDate(now) };\n  if (raw === 'last12Months') return { startDate: formatDate(addMonths(now, -12)), endDate: formatDate(now) };\n  if (/^\\d{4}$/.test(raw)) return { startDate: `${raw}-01-01`, endDate: `${raw}-12-31` };\n  if (/^\\d{4}-\\d{2}-\\d{2}:\\d{4}-\\d{2}-\\d{2}$/.test(raw)) {\n    const [startDate, endDate] = raw.split(':');\n    return { startDate, endDate };\n  }\n\n  throw new ArgumentError('period must be all, lastMonth, last3Months, last6Months, last12Months, a year like 2025, or YYYY-MM-DD:YYYY-MM-DD');\n}\n\nexport function buildPlayerUrl(player) {\n  const { playerId, slug } = parsePlayerRef(player);\n  return new URL(`/player/${playerId}/${slug}`, BASE);\n}\n\nexport function buildPlayerMatchesUrl(args) {\n  const { playerId, slug } = parsePlayerRef(args.player);\n  const eventType = normalizeChoice(args.eventType, 'all', EVENT_TYPES, 'eventType');\n  const ranking = normalizeChoice(args.ranking, 'all', RANKING_FILTERS, 'ranking');\n  const map = normalizeChoice(args.map, 'all', MAPS, 'map');\n  const version = normalizeChoice(args.version, 'both', VERSIONS, 'version');\n  const offset = normalizeOffset(args.offset, 0);\n  const period = String(args.period ?? 'all');\n  const event = parseEventRef(args.event);\n\n  const url = new URL(`/stats/players/matches/${playerId}/${slug}`, BASE);","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/hltv/utils.js#L205-L241","documentation":"This ArgumentError is thrown by resolvePeriod when the period argument does not match any accepted value: the literals all, lastMonth, last3Months, last6Months, last12Months, a bare 4-digit year (e.g. 2025), or an explicit range YYYY-MM-DD:YYYY-MM-DD. resolvePeriod converts the period into { startDate, endDate } for HLTV stats queries; anything else cannot be mapped to a date window. Note the input is compared exactly (after trim), so case and formatting matter.","triggerScenarios":"resolvePeriod('Last 3 Months') (case/spelling mismatch), resolvePeriod('30d'), resolvePeriod('2025-01'), resolvePeriod('2025-01-01') (single date without :end), resolvePeriod('2025-01-01/2025-06-30') (wrong separator — must be ':'), or a range with dates not zero-padded.","commonSituations":"Building CLI flags from free-text user input; translating human period names ('last quarter') without mapping to the exact enum; generating ranges with '/' or '->' separators instead of ':'; passing Date objects instead of strings (String(date) never matches).","solutions":["Use one of the exact literals: 'all', 'lastMonth', 'last3Months', 'last6Months', 'last12Months', or a 4-digit year '2025'.","For custom windows, format as 'YYYY-MM-DD:YYYY-MM-DD' with zero-padded dates and a colon separator.","Preprocess user input: trim, lowercase, and map synonyms (e.g. 'last 3 months' -> 'last3Months') before calling.","Convert Date objects to 'YYYY-MM-DD' strings first and join with ':'."],"exampleFix":"// before\nresolvePeriod('2025-01-01/2025-06-30'); // ArgumentError\n// after\nresolvePeriod('2025-01-01:2025-06-30');\n// or a preset\nresolvePeriod('last6Months');","handlingStrategy":"validation","validationCode":"const PERIOD_RE = /^(all|lastMonth|last3Months|last6Months|last12Months|\\d{4}|\\d{4}-\\d{2}-\\d{2}:\\d{4}-\\d{2}-\\d{2})$/;\nfunction isValidPeriod(p) {\n  return PERIOD_RE.test(String(p ?? 'all').trim());\n}\nif (!isValidPeriod(input)) throw new TypeError(`invalid period: ${input}`);","typeGuard":"function isPeriod(v) {\n  return typeof v === 'string' && /^(all|lastMonth|last3Months|last6Months|last12Months|\\d{4}|\\d{4}-\\d{2}-\\d{2}:\\d{4}-\\d{2}-\\d{2})$/.test(v);\n}","tryCatchPattern":"try {\n  const period = resolvePeriod(input);\n} catch (err) {\n  if (err.name === 'ArgumentError' && err.message.startsWith('period must be')) {\n    console.error(`Bad --period \"${input}\"; use all|lastMonth|last3Months|last6Months|last12Months|YYYY|YYYY-MM-DD:YYYY-MM-DD`);\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Use a const enum/whitelist of period presets in your app and pass only those.","Format custom ranges with padded YYYY-MM-DD joined by ':' — never '/' or '->'.","Lowercase/alias-map user input ('last 3 months' -> 'last3Months') before calling.","Convert Date objects to 'YYYY-MM-DD' strings before composing a range."],"tags":["argument-error","validation","date-parsing","hltv"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}