Skip to content

Commit 9adad39

Browse files
committed
refactor: address PR comments
1 parent 9936278 commit 9adad39

File tree

6 files changed

+80
-60
lines changed

6 files changed

+80
-60
lines changed

src/model/collection/schema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Interval, IntervalMaybeValid } from "luxon";
22

33
export abstract class Collection {
44
public abstract includes(filePath: string): boolean;
5+
// TODO: Would this make more sense in its own interface?
56
public getIntervalOf(filePath: string): IntervalMaybeValid {
67
return Interval.invalid(`interval not implemented`, `"${filePath}" was ignored`);
78
}

src/model/index/schema.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface VaultIndex {
2020
/** @returns the list of collections registered with this index. */
2121
getCollections(): Collection[];
2222

23-
/** @returns a list of collections that claim to include the given file path. */
23+
/** @returns the list of collections that claim to include the given file path. */
2424
getCollectionsWithFile(filePath: string): Collection[];
2525
}
2626

Original file line numberDiff line numberDiff line change
@@ -1,56 +1,84 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "group of equal intervals" 1`] = `
3+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "group of equal intervals" 1`] = `
44
[Error: user-provided message
5-
- indexes between [0, 5) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-07T00:00:00.000Z)]
5+
- indexes between [0, 5) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-07T00:00:00.000Z)]
66
`;
77

8-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "group of one interval after an overlapping group" 1`] = `
8+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "group of one interval after an overlapping group" 1`] = `
99
[Error: user-provided message
10-
- indexes between [0, 3) all overlap with [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]
10+
- indexes between [0, 3) all overlap between [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]
1111
`;
1212

13-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "group of one interval before an overlapping group" 1`] = `
13+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "group of one interval before an overlapping group" 1`] = `
1414
[Error: user-provided message
15-
- indexes between [1, 4) all overlap with [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]
15+
- indexes between [1, 4) all overlap between [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]
1616
`;
1717

18-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "group of overlapping intervals with non-overlapping intervals in between" 1`] = `
18+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "group of overlapping intervals with non-overlapping intervals in between" 1`] = `
1919
[Error: user-provided message
20-
- indexes between [0, 2) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)
21-
- indexes between [3, 5) all overlap with [2025-03-21T00:00:00.000Z – 2025-03-25T00:00:00.000Z)
22-
- indexes between [6, 8) all overlap with [2025-04-13T00:00:00.000Z – 2025-04-17T00:00:00.000Z)]
20+
- indexes between [0, 2) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)
21+
- indexes between [3, 5) all overlap between [2025-03-21T00:00:00.000Z – 2025-03-25T00:00:00.000Z)
22+
- indexes between [6, 8) all overlap between [2025-04-13T00:00:00.000Z – 2025-04-17T00:00:00.000Z)]
2323
`;
2424

25-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "group of overlapping intervals with the same end time" 1`] = `
25+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "group of overlapping intervals with the same end time" 1`] = `
2626
[Error: user-provided message
27-
- indexes between [0, 3) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]
27+
- indexes between [0, 3) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]
2828
`;
2929

30-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "group of overlapping intervals with the same start time" 1`] = `
30+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "group of overlapping intervals with the same start time" 1`] = `
3131
[Error: user-provided message
32-
- indexes between [0, 3) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]
32+
- indexes between [0, 3) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]
3333
`;
3434

35-
exports[`assertNoOverlaps > with message "user-provided message" > should reject "pair of overlapping intervals" 1`] = `
35+
exports[`assertNoOverlaps > with message="user-provided message" > should reject "pair of overlapping intervals" 1`] = `
3636
[Error: user-provided message
37-
- indexes between [0, 2) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)]
37+
- indexes between [0, 2) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)]
3838
`;
3939

40-
exports[`assertNoOverlaps > with message undefined > should reject "group of equal intervals" 1`] = `[Error: - indexes between [0, 5) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-07T00:00:00.000Z)]`;
40+
exports[`assertNoOverlaps > with message=undefined > should reject "group of equal intervals" 1`] = `[Error: - indexes between [0, 5) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-07T00:00:00.000Z)]`;
4141

42-
exports[`assertNoOverlaps > with message undefined > should reject "group of one interval after an overlapping group" 1`] = `[Error: - indexes between [0, 3) all overlap with [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]`;
42+
exports[`assertNoOverlaps > with message=undefined > should reject "group of one interval after an overlapping group" 1`] = `[Error: - indexes between [0, 3) all overlap between [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]`;
4343

44-
exports[`assertNoOverlaps > with message undefined > should reject "group of one interval before an overlapping group" 1`] = `[Error: - indexes between [1, 4) all overlap with [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]`;
44+
exports[`assertNoOverlaps > with message=undefined > should reject "group of one interval before an overlapping group" 1`] = `[Error: - indexes between [1, 4) all overlap between [2025-03-05T00:00:00.000Z – 2025-03-10T00:00:00.000Z)]`;
4545

46-
exports[`assertNoOverlaps > with message undefined > should reject "group of overlapping intervals with non-overlapping intervals in between" 1`] = `
47-
[Error: - indexes between [0, 2) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)
48-
- indexes between [3, 5) all overlap with [2025-03-21T00:00:00.000Z – 2025-03-25T00:00:00.000Z)
49-
- indexes between [6, 8) all overlap with [2025-04-13T00:00:00.000Z – 2025-04-17T00:00:00.000Z)]
46+
exports[`assertNoOverlaps > with message=undefined > should reject "group of overlapping intervals with non-overlapping intervals in between" 1`] = `
47+
[Error: - indexes between [0, 2) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)
48+
- indexes between [3, 5) all overlap between [2025-03-21T00:00:00.000Z – 2025-03-25T00:00:00.000Z)
49+
- indexes between [6, 8) all overlap between [2025-04-13T00:00:00.000Z – 2025-04-17T00:00:00.000Z)]
5050
`;
5151

52-
exports[`assertNoOverlaps > with message undefined > should reject "group of overlapping intervals with the same end time" 1`] = `[Error: - indexes between [0, 3) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]`;
52+
exports[`assertNoOverlaps > with message=undefined > should reject "group of overlapping intervals with the same end time" 1`] = `[Error: - indexes between [0, 3) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]`;
5353

54-
exports[`assertNoOverlaps > with message undefined > should reject "group of overlapping intervals with the same start time" 1`] = `[Error: - indexes between [0, 3) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]`;
54+
exports[`assertNoOverlaps > with message=undefined > should reject "group of overlapping intervals with the same start time" 1`] = `[Error: - indexes between [0, 3) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-06T00:00:00.000Z)]`;
5555

56-
exports[`assertNoOverlaps > with message undefined > should reject "pair of overlapping intervals" 1`] = `[Error: - indexes between [0, 2) all overlap with [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)]`;
56+
exports[`assertNoOverlaps > with message=undefined > should reject "pair of overlapping intervals" 1`] = `[Error: - indexes between [0, 2) all overlap between [2025-03-01T00:00:00.000Z – 2025-03-05T00:00:00.000Z)]`;
57+
58+
exports[`newInvalidError > with message="user-provided message" > should accept 'DateTime' 1`] = `
59+
[Error: user-provided message
60+
InvalidDateTime: user-provided reason. user-provided explanation]
61+
`;
62+
63+
exports[`newInvalidError > with message="user-provided message" > should accept 'Duration' 1`] = `
64+
[Error: user-provided message
65+
InvalidDuration: user-provided reason. user-provided explanation]
66+
`;
67+
68+
exports[`newInvalidError > with message="user-provided message" > should accept 'Interval' 1`] = `
69+
[Error: user-provided message
70+
InvalidInterval: user-provided reason. user-provided explanation]
71+
`;
72+
73+
exports[`newInvalidError > with message="user-provided message" > should accept undefined 1`] = `
74+
[Error: user-provided message
75+
unspecified error]
76+
`;
77+
78+
exports[`newInvalidError > with message=undefined > should accept 'DateTime' 1`] = `[Error: InvalidDateTime: user-provided reason. user-provided explanation]`;
79+
80+
exports[`newInvalidError > with message=undefined > should accept 'Duration' 1`] = `[Error: InvalidDuration: user-provided reason. user-provided explanation]`;
81+
82+
exports[`newInvalidError > with message=undefined > should accept 'Interval' 1`] = `[Error: InvalidInterval: user-provided reason. user-provided explanation]`;
83+
84+
exports[`newInvalidError > with message=undefined > should accept undefined 1`] = `[Error: unspecified error]`;

src/util/__tests__/luxon-utils.const.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Interval } from "luxon";
22

3+
export type NamedIntervalSequences = { [description: string]: readonly Interval<true>[] };
4+
35
export const WITH_OVERLAPPING_INTERVALS = {
46
"pair of overlapping intervals": [
57
Interval.fromISO("2025-03-01/2025-03-04", { zone: "utc" }),
@@ -50,10 +52,11 @@ export const WITH_OVERLAPPING_INTERVALS = {
5052
Interval.fromISO("2025-03-07/2025-03-10", { zone: "utc" }),
5153
Interval.fromISO("2025-03-11/2025-03-13", { zone: "utc" }),
5254
],
53-
} as Record<string, Interval<true>[]>;
55+
} as NamedIntervalSequences;
5456

5557
export const WITHOUT_OVERLAPPING_INTERVALS = {
5658
"empty group of intervals": [],
59+
5760
"group of one interval": [Interval.fromISO("2025-03-01/2025-03-04", { zone: "utc" })],
5861

5962
"pair of non-overlapping intervals": [
@@ -75,4 +78,4 @@ export const WITHOUT_OVERLAPPING_INTERVALS = {
7578
Interval.fromISO("2025-03-09/2025-03-11", { zone: "utc" }),
7679
Interval.fromISO("2025-03-13/2025-03-15", { zone: "utc" }),
7780
],
78-
} as Record<string, Interval<true>[]>;
81+
} as NamedIntervalSequences;

src/util/__tests__/luxon-utils.ts

+16-15
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,30 @@ import { assertNoOverlaps, newInvalidError } from "../luxon-utils";
66
import { WITH_OVERLAPPING_INTERVALS, WITHOUT_OVERLAPPING_INTERVALS } from "./luxon-utils.const";
77

88
describe(newInvalidError.name, () => {
9-
const reason = "reason";
10-
const explanation = "explanation";
9+
const reason = "user-provided reason";
10+
const explanation = "user-provided explanation";
1111

12-
describe.each(["user-provided message", undefined])("with message %j", (message) => {
13-
it.each([DateTime, Duration, Interval].map((ctor) => ctor.invalid(reason, explanation)))(
14-
"should accept invalid $constructor.name",
15-
(invalidObj) => {
16-
const errorMessage = newInvalidError(invalidObj, message).message;
17-
expect(errorMessage).toMatch(message ?? "");
18-
expect(errorMessage).toMatch(reason);
19-
expect(errorMessage).toMatch(explanation);
20-
},
21-
);
12+
const _throw = (e: Error) => {
13+
throw e;
14+
};
15+
16+
describe.each(["user-provided message", undefined])("with message=%j", (message) => {
17+
it.each([
18+
DateTime.invalid(reason, explanation),
19+
Duration.invalid(reason, explanation),
20+
Interval.invalid(reason, explanation),
21+
])("should accept $constructor.name", (invalidResult) => {
22+
expect(() => _throw(newInvalidError(invalidResult, message))).toThrowErrorMatchingSnapshot();
23+
});
2224

2325
it("should accept undefined", () => {
24-
const errorMessage = newInvalidError().message;
25-
expect(errorMessage).toMatch("unspecified error");
26+
expect(() => _throw(newInvalidError(undefined, message))).toThrowErrorMatchingSnapshot();
2627
});
2728
});
2829
});
2930

3031
describe(assertNoOverlaps.name, () => {
31-
describe.each(["user-provided message", undefined])("with message %j", (message) => {
32+
describe.each(["user-provided message", undefined])("with message=%j", (message) => {
3233
it.each(entriesIn(WITHOUT_OVERLAPPING_INTERVALS))("should accept %j", (_, intervals) => {
3334
expect(() => assertNoOverlaps(intervals, message)).not.toThrow();
3435
});

src/util/luxon-utils.ts

+3-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import assert from "assert";
21
import { isString, sortBy } from "lodash";
32
import { DateTime, Duration, Interval } from "luxon";
43

@@ -28,9 +27,8 @@ export function getIndexCollisions(sorted: Interval<true>[]): [number, number][]
2827

2928
let startIncl = 0;
3029
for (let stopExcl = 2; stopExcl <= sorted.length; ++stopExcl) {
31-
const last = sorted[stopExcl - 1];
3230
const formerStartIncl = startIncl;
33-
while (startIncl < stopExcl && !intersects(sorted[startIncl], last)) {
31+
while (startIncl < stopExcl && !sorted[startIncl].intersection(sorted[stopExcl - 1])) {
3432
startIncl += 1;
3533
}
3634
if (startIncl - formerStartIncl > 1) {
@@ -44,25 +42,14 @@ export function getIndexCollisions(sorted: Interval<true>[]): [number, number][]
4442
return collidingRanges;
4543
}
4644

47-
/**
48-
* @param a - the first interval. Must be _earlier than_ the second interval.
49-
* @param b - the second interval. Must be _later than_ the first interval.
50-
*
51-
* @returns true if the two intervals have a non-empty intersection.
52-
*/
53-
export function intersects(a: Interval<true>, b: Interval<true>): boolean {
54-
assert(a.start <= b.start && a.end <= b.end);
55-
return b.overlaps(a) && !b.abutsStart(a);
56-
}
57-
5845
/**
5946
* Asserts that the given array of intervals have no intersections.
6047
*
6148
* @param unsorted - the array of intervals to check.
6249
* @param message - optional message to include with the error.
6350
* @throws an {@link Error} if the array has overlapping intervals.
6451
*/
65-
export function assertNoOverlaps(unsorted: ReadonlyArray<Interval<true>>, message?: string): void {
52+
export function assertNoOverlaps(unsorted: readonly Interval<true>[], message?: string): void {
6653
const sorted = sortBy(unsorted, "start", "end");
6754
const indexCollisions = getIndexCollisions(sorted);
6855

@@ -71,7 +58,7 @@ export function assertNoOverlaps(unsorted: ReadonlyArray<Interval<true>>, messag
7158
lines.push(
7259
...indexCollisions.map(([start, end]) => {
7360
const overlap = Interval.fromDateTimes(sorted[start].start, sorted[end - 1].end);
74-
return `\t-\tindexes between [${start}, ${end}) all overlap with ${overlap}`;
61+
return `\t-\tindexes between [${start}, ${end}) all overlap between ${overlap}`;
7562
}),
7663
);
7764
throw new Error(lines.join("\n"));

0 commit comments

Comments
 (0)