export function lookupIterations()

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;
}