1
- import assert from "assert" ;
2
- import { attempt , isError } from "lodash" ;
1
+ import { notStrictEqual as assertNotStrictEqual } from "assert" ;
2
+ import { attempt , clone , isError } from "lodash" ;
3
3
import { DateTime , DateTimeOptions , Duration , DurationLike , Interval , IntervalMaybeValid } from "luxon" ;
4
4
import { parse } from "path" ;
5
+ import { DeepReadonly } from "utility-types" ;
5
6
6
7
import { assertLuxonFormat , assertValid } from "@/util/luxon-utils" ;
7
8
8
9
import { DateBasedCollection } from "./schema" ;
9
- import { sanitizeFolder } from "./util" ;
10
-
11
- /**
12
- * Configuration options for {@link PeriodicNotes}.
13
- * @param IsValidConfiguration - whether the configuration is valid.
14
- */
15
- export type PeriodicNotesConfig < IsValidConfiguration extends boolean > =
16
- IsValidConfiguration extends true ?
17
- {
18
- /** {@inheritDoc PeriodicNotes.folder } */
19
- folder : string ;
20
- /** {@inheritDoc PeriodicNotes.dateFormat } */
21
- dateFormat : string ;
22
- /** {@inheritDoc PeriodicNotes.dateOptions } */
23
- dateOptions : DateTimeOptions ;
24
- /** {@inheritDoc PeriodicNotes.intervalDuration } */
25
- intervalDuration : Duration < true > ;
26
- /** {@inheritDoc PeriodicNotes.intervalOffset } */
27
- intervalOffset : Duration < true > ;
28
- }
29
- : {
30
- /** {@inheritDoc PeriodicNotes.folder } */
31
- folder : string ;
32
- /** {@inheritDoc PeriodicNotes.dateFormat } */
33
- dateFormat : string ;
34
- /** {@inheritDoc PeriodicNotes.dateOptions } */
35
- dateOptions ?: DateTimeOptions ;
36
- /** {@inheritDoc PeriodicNotes.intervalDuration } */
37
- intervalDuration : DurationLike ;
38
- /** {@inheritDoc PeriodicNotes.intervalOffset } */
39
- intervalOffset ?: DurationLike ;
40
- } ;
10
+ import { stripTrailingSlash } from "./util" ;
41
11
42
12
/**
43
13
* Intended to handle the popular "Periodic Notes" community plugin.
@@ -55,7 +25,7 @@ export class PeriodicNotes extends DateBasedCollection implements PeriodicNotesC
55
25
public readonly dateFormat : string ;
56
26
57
27
/** Luxon options used when parsing {@link DateTime}s from file names. */
58
- public readonly dateOptions : DateTimeOptions ;
28
+ public readonly dateOptions : DeepReadonly < DateTimeOptions > ;
59
29
60
30
/**
61
31
* The {@link Duration} of each file's corresponding {@link Interval}.
@@ -101,23 +71,64 @@ export class PeriodicNotes extends DateBasedCollection implements PeriodicNotesC
101
71
}
102
72
103
73
/**
104
- * @param config - the config to validate.
105
- * @throws if any of the config's properties are invalid.
106
- * @returns a valid config.
74
+ * Configuration options for {@link PeriodicNotes}.
75
+ * @typeParam IsValidConfiguration - whether the configuration is valid.
76
+ */
77
+ export type PeriodicNotesConfig < IsValidConfiguration extends boolean > =
78
+ IsValidConfiguration extends true ?
79
+ {
80
+ /** {@inheritDoc PeriodicNotes.folder } */
81
+ folder : string ;
82
+ /** {@inheritDoc PeriodicNotes.dateFormat } */
83
+ dateFormat : string ;
84
+ /** {@inheritDoc PeriodicNotes.dateOptions } */
85
+ dateOptions : DateTimeOptions ;
86
+ /** {@inheritDoc PeriodicNotes.intervalDuration } */
87
+ intervalDuration : Duration < true > ;
88
+ /** {@inheritDoc PeriodicNotes.intervalOffset } */
89
+ intervalOffset : Duration < true > ;
90
+ }
91
+ : {
92
+ /** {@inheritDoc PeriodicNotes.folder } */
93
+ folder : string ;
94
+ /** {@inheritDoc PeriodicNotes.dateFormat } */
95
+ dateFormat : string ;
96
+ /** {@inheritDoc PeriodicNotes.dateOptions } */
97
+ dateOptions ?: DateTimeOptions ;
98
+ /** {@inheritDoc PeriodicNotes.intervalDuration } */
99
+ intervalDuration : DurationLike ;
100
+ /** {@inheritDoc PeriodicNotes.intervalOffset } */
101
+ intervalOffset ?: DurationLike ;
102
+ } ;
103
+
104
+ /**
105
+ * Validates and normalizes a PeriodicNotes configuration object.
106
+ *
107
+ * This function checks that:
108
+ * - the folder path (after stripping any trailing slash) is non-empty,
109
+ * - the date format is valid with the given date options,
110
+ * - the interval duration is a valid, non-zero duration, and
111
+ * - the interval offset is a valid duration.
112
+ *
113
+ * If any of these validations fail, an {@link AggregateError} is thrown containing details
114
+ * about each issue. On success, a new configuration object with strictly defined properties is returned.
115
+ * @param config - The configuration object to validate.
116
+ * @returns A validated configuration object with normalized properties.
117
+ * @throws If one or more configuration properties are invalid.
107
118
*/
108
119
function validated ( config : PeriodicNotesConfig < false > ) : PeriodicNotesConfig < true > {
109
- const folder = sanitizeFolder ( config . folder ) ;
120
+ const folder = stripTrailingSlash ( config . folder ) ;
110
121
const dateFormat = config . dateFormat ;
111
- const dateOptions = config . dateOptions ?? { } ;
122
+ const dateOptions = clone ( config . dateOptions ?? { } ) ;
112
123
const intervalDuration = Duration . fromDurationLike ( config . intervalDuration ) ;
113
124
const intervalOffset = Duration . fromDurationLike ( config . intervalOffset ?? 0 ) ;
114
125
115
126
const errors = [
116
- attempt ( ( ) => assert ( folder . length > 0 , "folder must be non-empty" ) ) ,
127
+ attempt ( ( ) => assertNotStrictEqual ( folder . length , 0 , "folder must be non-empty" ) ) ,
117
128
attempt ( ( ) => assertLuxonFormat ( dateFormat , dateOptions ) ) ,
118
- attempt ( ( ) => assertValid ( intervalOffset , "interval offset is invalid" ) ) ,
119
129
attempt ( ( ) => assertValid ( intervalDuration , "interval duration is invalid" ) ) ,
120
- attempt ( ( ) => assert ( intervalDuration . valueOf ( ) !== 0 , "interval duration must not be zero" ) ) ,
130
+ attempt ( ( ) => assertNotStrictEqual ( intervalDuration . valueOf ( ) , 0 , "interval duration must not be zero" ) ) ,
131
+ attempt ( ( ) => assertValid ( intervalOffset , "interval offset is invalid" ) ) ,
121
132
] . filter ( isError ) ;
122
133
123
134
if ( errors . length > 0 ) {
0 commit comments