Primeiro Commit v0.beta1

This commit is contained in:
2026-04-29 00:27:50 -03:00
parent 93d4906fb5
commit 8662a153fe
27 changed files with 16303 additions and 0 deletions

View File

@@ -0,0 +1,340 @@
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"]
);
}