in src/common/IterationLookup.ts [55:155]
export function lookupIterations(iterations: string[]): IterationLookup {
const lookup: IterationLookup = {
byDate: {},
byVersionString: {},
orderedVersionStrings: [],
};
const iterationsByRange = new Map();
const rangesByIteration = new Map();
const STARTING_VERSION = 67;
// Remove duplicate date ranges (override in insertion order)
for (const value of iterations) {
const match = value.match(/(\d+)\.(\d+) - (.*)/);
if (match) {
const version = parseInt(match[1], 10);
// Ignore iterations before 67.1
if (version < STARTING_VERSION) continue;
const iterationString = `${match[1]}.${match[2]}`;
iterationsByRange.set(match[3], iterationString);
}
}
// Remove duplicate versions
for (const [range, iteration] of iterationsByRange) {
rangesByIteration.set(iteration, range);
}
// Add manual overrides
for (const { iteration, range } of ITERATION_OVERRIDES) {
if (range) {
rangesByIteration.set(iteration, range);
} else {
rangesByIteration.delete(iteration);
}
}
// In order to generate actual dates, we need to infer the year, since
// iterations aren't stored with years. We do this by using the starting
// version date as the epoch, and incrementing the year by one each time we
// see an iteration's start date has a month before the previous iteration's
// start date month.
let lastDate: DateTime;
let lastMonth = -1;
let year = 2019;
for (const [iteration, range] of rangesByIteration) {
// We can handle dates of the forms "July 3 - 14" and "Aug 28 - Sept 8"
// (where the end date falls in a different month than the start date).
const match = range.match(/(\w+) (\d+) ?- ?(?:(\w+) )?(\d+)/);
if (match) {
const startMonth = normalizeMonthString(match[1]);
const endMonth = match[3] ? normalizeMonthString(match[3]) : startMonth;
let startDate = DateTime.fromFormat(
`${startMonth} ${match[2]} ${year}`,
"LLL d y",
{ locale: "en-US" }
);
if (startDate.month < lastMonth) {
year += 1;
}
startDate = startDate.set({ year }).startOf("week");
lastMonth = startDate.month;
while (lastDate && startDate < lastDate) {
// This iteration starts before the previous iteration ended. That means
// we actually want it to start on the first Monday after the start.
startDate = startDate.plus({ weeks: 1 });
}
const startDateTime = startDate.startOf("day").toISO();
let endDate = DateTime.fromFormat(
`${endMonth} ${match[4]} ${year}`,
"LLL d y",
{ locale: "en-US" }
);
if (endDate.month < lastMonth) {
year += 1;
}
// If the end date is a Monday, set it to the previous Sunday.
if (endDate.weekday === 1) {
endDate = endDate.minus({ days: 1 });
}
// Otherwise, set it to the next Sunday.
endDate = endDate.set({ year }).endOf("week");
lastDate = endDate;
lastMonth = lastDate.month;
const endDateTime = endDate.startOf("day").toISO();
const weeks = Math.ceil(endDate.diff(startDate, "days").days / 7);
if (startDateTime && endDateTime && weeks) {
lookup.byVersionString[iteration] = {
startDate: startDateTime,
weeks,
endDate: endDateTime,
};
lookup.orderedVersionStrings.push(iteration);
const start = DateTime.fromISO(startDateTime);
for (let i = 0; i < weeks; i++) {
const monday = start.plus({ weeks: i });
lookup.byDate[monday.toFormat("yyyy-MM-dd")] = iteration;
}
}
}
}
return lookup;
}