const ANNUAL_WEEK_START_MONTH_INDEX = 5; const ANNUAL_WEEK_START_DAY = 1; const CURRENT_PERIOD_TOKENS = new Set([ "current", "current-week", "this-week", "week-current", "semana-atual", "week atual", ]); const CURRENT_MONTH_TOKENS = new Set([ "current", "current-month", "this-month", "month-current", "mes-atual", "mês-atual", "mes atual", "mês atual", ]); const CURRENT_QUARTER_TOKENS = new Set([ "current", "current-quarter", "this-quarter", "quarter-current", "quarter atual", "trimestre-atual", "trimestre atual", ]); const CURRENT_FISCAL_YEAR_TOKENS = new Set([ "current", "current-fy", "this-fy", "fy-current", "fy atual", "ano-fiscal-atual", "ano fiscal atual", ]); function quoteLiteral(value) { return `'${String(value).replace(/'/g, "''")}'`; } function lastDayOfMonth(year, monthIndex) { return new Date(year, monthIndex + 1, 0); } function formatIsoDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; } function addDays(date, days) { const next = new Date(date.getTime()); next.setDate(next.getDate() + days); return next; } function isLeapYear(year) { return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); } function isValidIsoCalendarDate(raw) { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw); if (!match) return false; const [, yearText, monthText, dayText] = match; const year = Number(yearText); const month = Number(monthText); const day = Number(dayText); if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) { return false; } if (month < 1 || month > 12) return false; const daysInMonth = [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; return day >= 1 && day <= daysInMonth[month - 1]; } function resolveDateInput(value, fallback) { const raw = String(value || fallback || "").trim(); if (!raw) { throw new Error("Date input is required."); } if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) { if (!isValidIsoCalendarDate(raw)) { throw new Error(`Invalid calendar date "${raw}". Use a real date in YYYY-MM-DD format.`); } return { input: raw, isoDate: raw }; } if (raw.toLowerCase() === "today") { return { input: raw, isoDate: formatIsoDate(new Date()) }; } const relativeMatch = /^(?:today)?([+-]\d+)d$/i.exec(raw); if (relativeMatch) { const days = Number(relativeMatch[1]); return { input: raw, isoDate: formatIsoDate(addDays(new Date(), days)) }; } throw new Error( `Unsupported date token "${raw}". Use YYYY-MM-DD, today, +7d, -3d, or today+7d.` ); } function resolveMonthInput(value) { const raw = String(value || "").trim(); if (CURRENT_MONTH_TOKENS.has(raw.toLowerCase())) { const today = new Date(); const first = new Date(today.getFullYear(), today.getMonth(), 1); const last = lastDayOfMonth(today.getFullYear(), today.getMonth()); return { input: raw, fromDate: formatIsoDate(first), toDate: formatIsoDate(last), }; } if (!/^\d{4}-\d{2}$/.test(raw)) { throw new Error(`Unsupported month token "${raw}". Use YYYY-MM, for example 2026-04.`); } const [yearText, monthText] = raw.split("-"); const year = Number(yearText); const month = Number(monthText); if (!Number.isInteger(year) || !Number.isInteger(month) || month < 1 || month > 12) { throw new Error(`Unsupported month token "${raw}". Use YYYY-MM, for example 2026-04.`); } const first = new Date(year, month - 1, 1); const last = lastDayOfMonth(year, month - 1); return { input: raw, fromDate: formatIsoDate(first), toDate: formatIsoDate(last), }; } function fiscalQuarterToDateWindow(fiscalYear, quarter) { const normalizedFiscalYear = String(fiscalYear || "").trim().toUpperCase(); const normalizedQuarter = String(quarter || "").trim().toUpperCase(); const fiscalMatch = /^FY(\d{2,4})$/.exec(normalizedFiscalYear); const quarterMatch = /^Q([1-4])$/.exec(normalizedQuarter); if (!fiscalMatch || !quarterMatch) { throw new Error(`Unsupported fiscal quarter token "${fiscalYear} ${quarter}". Use FY26-Q4 or Q4 FY26.`); } const endYear = fiscalMatch[1].length === 2 ? 2000 + Number(fiscalMatch[1]) : Number(fiscalMatch[1]); const quarterNumber = Number(quarterMatch[1]); const startYear = endYear - 1; const quarterWindows = { 1: { from: new Date(startYear, 5, 1), to: lastDayOfMonth(startYear, 7) }, 2: { from: new Date(startYear, 8, 1), to: lastDayOfMonth(startYear, 10) }, 3: { from: new Date(startYear, 11, 1), to: lastDayOfMonth(endYear, 1) }, 4: { from: new Date(endYear, 2, 1), to: lastDayOfMonth(endYear, 4) }, }; return { fiscalYear: normalizedFiscalYear, quarter: `Q${quarterNumber}`, fromDate: formatIsoDate(quarterWindows[quarterNumber].from), toDate: formatIsoDate(quarterWindows[quarterNumber].to), }; } export function resolveQuarterInput(value) { const raw = String(value || "").trim(); const normalized = raw.toLowerCase(); if (CURRENT_QUARTER_TOKENS.has(normalized)) { const today = new Date(); const cycleYear = resolveWeekYearInput(""); const monthIndex = today.getMonth(); let quarter = "Q1"; if (monthIndex >= 5 && monthIndex <= 7) { quarter = "Q1"; } else if (monthIndex >= 8 && monthIndex <= 10) { quarter = "Q2"; } else if (monthIndex === 11 || monthIndex <= 1) { quarter = "Q3"; } else { quarter = "Q4"; } const fiscalYear = `FY${String(cycleYear + 1).padStart(2, "0").slice(-2)}`; return { input: raw, ...fiscalQuarterToDateWindow(fiscalYear, quarter), }; } const compactMatch = /^(FY\d{2,4})[-\s]Q([1-4])$/i.exec(raw); if (compactMatch) { return { input: raw, ...fiscalQuarterToDateWindow(compactMatch[1], `Q${compactMatch[2]}`), }; } const reversedMatch = /^Q([1-4])[-\s]?(FY\d{2,4})$/i.exec(raw); if (reversedMatch) { return { input: raw, ...fiscalQuarterToDateWindow(reversedMatch[2], `Q${reversedMatch[1]}`), }; } throw new Error(`Unsupported quarter token "${raw}". Use FY26-Q4, Q4 FY26, or current-quarter.`); } export function resolveWeekYearInput(value) { const raw = String(value || "").trim(); if (!raw || CURRENT_FISCAL_YEAR_TOKENS.has(raw.toLowerCase())) { const today = new Date(); const cycleStart = new Date(today.getFullYear(), ANNUAL_WEEK_START_MONTH_INDEX, ANNUAL_WEEK_START_DAY); return today >= cycleStart ? today.getFullYear() : today.getFullYear() - 1; } if (!/^\d{4}$/.test(raw)) { throw new Error(`Unsupported week year token "${raw}". Use the cycle start year YYYY, for example 2025.`); } return Number(raw); } export function resolveAnnualWeekInput(value, weekYear) { const raw = String(value || "").trim().toLowerCase(); if (CURRENT_PERIOD_TOKENS.has(raw)) { const year = resolveWeekYearInput(weekYear); const cycleStart = new Date(year, ANNUAL_WEEK_START_MONTH_INDEX, ANNUAL_WEEK_START_DAY); const cycleEnd = new Date(year + 1, ANNUAL_WEEK_START_MONTH_INDEX, 0); const today = new Date(); const boundedToday = today < cycleStart ? cycleStart : today > cycleEnd ? cycleEnd : today; const week = Math.floor((boundedToday - cycleStart) / (7 * 24 * 60 * 60 * 1000)) + 1; return resolveAnnualWeekInput(`w${week}`, year); } const match = raw.match(/^(?:w|week\s*)?([1-9]|[1-4]\d|5[0-3])$/); if (!match) { throw new Error(`Unsupported week token "${value}". Use 1..53, w1..w53, or week 1..week 53.`); } const week = Number(match[1]); const year = resolveWeekYearInput(weekYear); const cycleStart = new Date(year, ANNUAL_WEEK_START_MONTH_INDEX, ANNUAL_WEEK_START_DAY); const cycleEnd = new Date(year + 1, ANNUAL_WEEK_START_MONTH_INDEX, 0); const weekStart = addDays(cycleStart, (week - 1) * 7); if (weekStart > cycleEnd) { throw new Error(`Week ${week} is outside the ${year}-${year + 1} cycle. Use 1..53.`); } const provisionalWeekEnd = addDays(weekStart, 6); const weekEnd = provisionalWeekEnd > cycleEnd ? cycleEnd : provisionalWeekEnd; return { input: String(value || "").trim(), week, weekLabel: `W${week}`, year, fromDate: formatIsoDate(weekStart), toDate: formatIsoDate(weekEnd), }; } export function resolveDateWindow(args, defaults = { from: "today", to: "+7d" }) { const hasSingleDate = Boolean(args.date); const hasMonth = Boolean(args.month); const hasWeek = Boolean(args.week); const hasQuarter = Boolean(args.quarter); const hasExplicitWindow = Boolean(args["from-date"] || args["to-date"]); if ( [hasSingleDate, hasMonth, hasWeek, hasQuarter].filter(Boolean).length > 1 || ((hasSingleDate || hasMonth || hasWeek || hasQuarter) && hasExplicitWindow) ) { throw new Error( "Use either --date, --month, --quarter, --week, or the pair --from-date/--to-date for date-window queries." ); } if (hasSingleDate) { const exact = resolveDateInput(args.date); return { fromDateInput: exact.input, toDateInput: exact.input, fromDate: exact.isoDate, toDate: exact.isoDate, fromDateSql: `DATE ${quoteLiteral(exact.isoDate)}`, toDateSql: `DATE ${quoteLiteral(exact.isoDate)}`, preset: "single-date", }; } if (hasMonth) { const month = resolveMonthInput(args.month); return { fromDateInput: month.input, toDateInput: month.input, fromDate: month.fromDate, toDate: month.toDate, fromDateSql: `DATE ${quoteLiteral(month.fromDate)}`, toDateSql: `DATE ${quoteLiteral(month.toDate)}`, preset: "calendar-month", }; } if (hasQuarter) { const quarter = resolveQuarterInput(args.quarter); return { fromDateInput: quarter.input, toDateInput: quarter.input, fromDate: quarter.fromDate, toDate: quarter.toDate, fromDateSql: `DATE ${quoteLiteral(quarter.fromDate)}`, toDateSql: `DATE ${quoteLiteral(quarter.toDate)}`, preset: "fiscal-quarter", fiscalYear: quarter.fiscalYear, fiscalQuarter: quarter.quarter, }; } if (hasWeek) { const week = resolveAnnualWeekInput(args.week, args["week-year"]); return { fromDateInput: week.input, toDateInput: week.input, fromDate: week.fromDate, toDate: week.toDate, fromDateSql: `DATE ${quoteLiteral(week.fromDate)}`, toDateSql: `DATE ${quoteLiteral(week.toDate)}`, preset: "annual-week", week: week.week, weekLabel: week.weekLabel, weekYear: week.year, }; } const from = resolveDateInput(args["from-date"], defaults.from); const to = resolveDateInput(args["to-date"], defaults.to); if (from.isoDate > to.isoDate) { throw new Error(`Invalid date window: from-date ${from.isoDate} is after to-date ${to.isoDate}.`); } return { fromDateInput: from.input, toDateInput: to.input, fromDate: from.isoDate, toDate: to.isoDate, fromDateSql: `DATE ${quoteLiteral(from.isoDate)}`, toDateSql: `DATE ${quoteLiteral(to.isoDate)}`, preset: "date-window", }; } export function hasAnyDateWindowArgs(args) { return Boolean( args.date || args.month || args.quarter || args.week || args["from-date"] || args["to-date"] ); }