All files / src/utils chapters.ts

100% Statements 119/119
94.73% Branches 18/19
100% Functions 6/6
100% Lines 119/119

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 1201x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 36x 36x 36x 36x 36x 36x 36x 36x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 32x 16x 16x 16x 32x 32x 32x 32x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 32x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
import { isMatch, formatISO, parseISO } from "date-fns";
 
import type { Chapter, ValuesPerDay, CalendarYearsData } from "~/types";
import { convertToCalendarYearData } from "./calendar";
 
/**
 * Checks if a chapter should be included based on the given conditions.
 *
 * @param {Chapter} chapter - The chapter to check.
 * @returns {boolean} - `true` if the chapter should be included, `false`
 * otherwise.
 */
export const shouldIncludeChapter = (chapter: Chapter): boolean => {
  const shouldShow = chapter.meta.show === true;
  const hasValidWebNovelRef = (chapter.partOf.webNovel?.ref ?? 0) > 0;
  const hasValidPublishedDate = isMatch(
    chapter.partOf.webNovel?.published ?? "",
    "yyyy-MM-dd'T'HH:mm:ssXXX"
  );
 
  return shouldShow && hasValidWebNovelRef && hasValidPublishedDate;
};
 
/** The return data from the `convertChaptersToMapping` function. */
export interface ConvertChaptersToMappingOutput {
  /** This maps a date string to the number of words written on that day. */
  mapping: ValuesPerDay;
  /** The minimum year in the dataset. */
  minYear: number;
  /** The maximum year in the dataset. */
  maxYear: number;
  /** The minimum value in the dataset. */
  minValue: number;
  /** The maximum value in the dataset. */
  maxValue: number;
}
 
/**
 * Converts an array of `Chapter` objects to a `ConvertChaptersToMappingOutput`.
 *
 * @param {Chapter[]} chapters - The array of `Chapter` objects.
 * @returns {ConvertChaptersToMappingOutput} - The output of the conversion.
 */
export const convertChaptersToMapping = (
  chapters: Chapter[]
): ConvertChaptersToMappingOutput => {
  const mapping: ValuesPerDay = new Map();
 
  let minYear = Number.POSITIVE_INFINITY;
  let maxYear = Number.NEGATIVE_INFINITY;
  let minValue = Number.POSITIVE_INFINITY;
  let maxValue = Number.NEGATIVE_INFINITY;
 
  for (const chapter of chapters) {
    if (!shouldIncludeChapter(chapter)) {
      continue;
    }
 
    const publishedDate = chapter.partOf.webNovel?.published ?? "";
    const totalWords = chapter.partOf.webNovel?.totalWords ?? 0;
 
    if (publishedDate) {
      const date = parseISO(publishedDate);
      const dateKey = formatISO(date, {
        representation: "date",
      });
 
      const existingWordCount = mapping.get(dateKey) ?? 0;
      const newWordCount = existingWordCount + totalWords;
      mapping.set(dateKey, newWordCount);
 
      const year = date.getFullYear();
      minYear = Math.min(minYear, year);
      maxYear = Math.max(maxYear, year);
      minValue = Math.min(minValue, newWordCount);
      maxValue = Math.max(maxValue, newWordCount);
    }
  }
 
  return { mapping, minYear, maxYear, minValue, maxValue };
};
 
/** The return data from the `convertChaptersToCalendarYearData` function. */
export interface ConvertChaptersToCalendarYearDataOutput {
  /** The list of word counts per calendar year. */
  data: CalendarYearsData;
  /** The minimum year in the dataset. */
  minYear: number;
  /** The maximum year in the dataset. */
  maxYear: number;
  /** The minimum value in the dataset. */
  minValue: number;
  /** The maximum value in the dataset. */
  maxValue: number;
}
 
/**
 * Converts an array of `Chapter` objects to a
 * `ConvertChaptersToCalendarYearDataOutput` object.
 *
 * @param {Chapter[]} chapters - The array of `Chapter` objects.
 * @returns {ConvertChaptersToCalendarYearDataOutput} - The output of the
 * conversion.
 */
export const convertChaptersToCalendarYearData = (
  chapters: Chapter[]
): ConvertChaptersToCalendarYearDataOutput => {
  const { mapping, minYear, maxYear, minValue, maxValue } =
    convertChaptersToMapping(chapters);
  const calendarYearsData = convertToCalendarYearData(mapping);
 
  return {
    data: calendarYearsData,
    minYear,
    maxYear,
    minValue,
    maxValue,
  };
};