File size: 3,237 Bytes
cf86710
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { type DateLib, defaultDateLib } from "../classes/DateLib.js";
import type { Matcher } from "../types/index.js";

import { dateMatchModifiers } from "./dateMatchModifiers.js";
import { rangeContainsDayOfWeek } from "./rangeContainsDayOfWeek.js";
import { rangeIncludesDate } from "./rangeIncludesDate.js";
import { rangeOverlaps } from "./rangeOverlaps.js";
import {
  isDateAfterType,
  isDateBeforeType,
  isDateInterval,
  isDateRange,
  isDatesArray,
  isDayOfWeekType,
} from "./typeguards.js";

/**
 * Checks if a date range contains dates that match the given modifiers.
 *
 * @since 9.2.2
 * @param range - The date range to check.
 * @param modifiers - The modifiers to match against.
 * @param dateLib - The date utility library instance.
 * @returns `true` if the range contains matching dates, otherwise `false`.
 * @group Utilities
 */
export function rangeContainsModifiers(
  range: { from: Date; to: Date },
  modifiers: Matcher | Matcher[],
  dateLib: DateLib = defaultDateLib,
): boolean {
  const matchers = Array.isArray(modifiers) ? modifiers : [modifiers];

  // Defer function matchers evaluation as they are the least performant.
  const nonFunctionMatchers = matchers.filter(
    (matcher) => typeof matcher !== "function",
  );

  const nonFunctionMatchersResult = nonFunctionMatchers.some((matcher) => {
    if (typeof matcher === "boolean") return matcher;

    if (dateLib.isDate(matcher)) {
      return rangeIncludesDate(range, matcher, false, dateLib);
    }

    if (isDatesArray(matcher, dateLib)) {
      return matcher.some((date) =>
        rangeIncludesDate(range, date, false, dateLib),
      );
    }

    if (isDateRange(matcher)) {
      if (matcher.from && matcher.to) {
        return rangeOverlaps(
          range,
          { from: matcher.from, to: matcher.to },
          dateLib,
        );
      }
      return false;
    }

    if (isDayOfWeekType(matcher)) {
      return rangeContainsDayOfWeek(range, matcher.dayOfWeek, dateLib);
    }

    if (isDateInterval(matcher)) {
      const isClosedInterval = dateLib.isAfter(matcher.before, matcher.after);
      if (isClosedInterval) {
        return rangeOverlaps(
          range,
          {
            from: dateLib.addDays(matcher.after, 1),
            to: dateLib.addDays(matcher.before, -1),
          },
          dateLib,
        );
      }
      return (
        dateMatchModifiers(range.from, matcher, dateLib) ||
        dateMatchModifiers(range.to, matcher, dateLib)
      );
    }

    if (isDateAfterType(matcher) || isDateBeforeType(matcher)) {
      return (
        dateMatchModifiers(range.from, matcher, dateLib) ||
        dateMatchModifiers(range.to, matcher, dateLib)
      );
    }

    return false;
  });

  if (nonFunctionMatchersResult) {
    return true;
  }

  const functionMatchers = matchers.filter(
    (matcher) => typeof matcher === "function",
  );

  if (functionMatchers.length) {
    let date = range.from;
    const totalDays = dateLib.differenceInCalendarDays(range.to, range.from);

    for (let i = 0; i <= totalDays; i++) {
      if (functionMatchers.some((matcher) => matcher(date))) {
        return true;
      }
      date = dateLib.addDays(date, 1);
    }
  }

  return false;
}