@becollective/utils 1.10.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.semaphore/utils.yml +1 -1
- package/index.ts +7 -0
- package/lib/FeatureFlag.d.ts +12 -0
- package/lib/FeatureFlag.js +51 -0
- package/lib/constants/allowedHtmlTags.d.ts +7 -0
- package/lib/constants/allowedHtmlTags.js +8 -0
- package/lib/constants/avatarColours.d.ts +35 -0
- package/lib/constants/avatarColours.js +36 -0
- package/lib/constants/countries.d.ts +253 -0
- package/lib/constants/countries.js +254 -0
- package/lib/constants/currencies.d.ts +29 -0
- package/lib/constants/currencies.js +36 -0
- package/lib/constants/customFields.d.ts +11 -0
- package/lib/constants/customFields.js +12 -0
- package/lib/constants/distancesUnits.d.ts +11 -0
- package/lib/constants/distancesUnits.js +13 -0
- package/lib/constants/groups.d.ts +13 -0
- package/lib/constants/groups.js +85 -0
- package/lib/constants/insuranceStatuses.d.ts +15 -0
- package/lib/constants/insuranceStatuses.js +7 -0
- package/lib/constants/insuranceTypes.d.ts +35 -0
- package/lib/constants/insuranceTypes.js +36 -0
- package/lib/constants/languages.d.ts +2 -0
- package/lib/constants/languages.js +194 -0
- package/lib/constants/locales.d.ts +119 -0
- package/lib/constants/locales.js +191 -0
- package/lib/constants/notifications.d.ts +47 -0
- package/lib/constants/notifications.js +31 -0
- package/lib/constants/opportunities.d.ts +72 -0
- package/lib/constants/opportunities.js +82 -0
- package/lib/constants/qualificationTypes.d.ts +4 -0
- package/lib/constants/qualificationTypes.js +18 -0
- package/lib/constants/rules.d.ts +13 -0
- package/lib/constants/rules.js +21 -0
- package/lib/constants/subscriptions.d.ts +9 -0
- package/lib/constants/subscriptions.js +10 -0
- package/lib/constants/surveys.d.ts +16 -0
- package/lib/constants/surveys.js +17 -0
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +76 -0
- package/lib/date-time.d.ts +28 -0
- package/lib/date-time.js +79 -0
- package/lib/forms.d.ts +1 -0
- package/lib/forms.js +728 -0
- package/lib/locality.d.ts +5 -0
- package/lib/locality.js +15 -0
- package/lib/money.d.ts +7 -0
- package/lib/money.js +32 -0
- package/lib/opportunity.d.ts +1 -0
- package/lib/opportunity.js +11 -0
- package/lib/opportunityUser.d.ts +8 -0
- package/lib/opportunityUser.js +29 -0
- package/lib/password.d.ts +8 -0
- package/lib/password.js +43 -0
- package/lib/rrule/date.d.ts +4 -0
- package/lib/rrule/date.js +30 -0
- package/lib/rrule/index.d.ts +2 -0
- package/lib/rrule/index.js +18 -0
- package/lib/rrule/parsing.d.ts +6 -0
- package/lib/rrule/parsing.js +130 -0
- package/lib/rrule/parsing.test.d.ts +1 -0
- package/lib/rrule/parsing.test.js +11 -0
- package/lib/rrule.d.ts +49 -0
- package/lib/rrule.js +303 -0
- package/lib/src/FeatureFlag.d.ts +12 -0
- package/lib/src/FeatureFlag.js +51 -0
- package/lib/src/date-time.d.ts +28 -0
- package/lib/src/date-time.js +79 -0
- package/lib/src/forms.d.ts +1 -0
- package/lib/src/forms.js +728 -0
- package/lib/src/locality.d.ts +5 -0
- package/lib/src/locality.js +15 -0
- package/lib/src/money.d.ts +7 -0
- package/lib/src/money.js +32 -0
- package/lib/src/opportunity.d.ts +1 -0
- package/lib/src/opportunity.js +11 -0
- package/lib/src/opportunityUser.d.ts +8 -0
- package/lib/src/opportunityUser.js +29 -0
- package/lib/src/password.d.ts +8 -0
- package/lib/src/password.js +43 -0
- package/package.json +15 -29
- package/src/FeatureFlag.ts +26 -10
- package/src/constants/allowedHtmlTags.ts +6 -0
- package/src/constants/avatarColours.ts +34 -0
- package/src/constants/countries.ts +252 -0
- package/src/constants/currencies.ts +33 -0
- package/src/constants/customFields.ts +10 -0
- package/src/constants/distancesUnits.ts +11 -0
- package/src/constants/groups.ts +83 -0
- package/src/constants/insuranceStatuses.ts +5 -0
- package/src/constants/insuranceTypes.ts +34 -0
- package/src/constants/languages.ts +192 -0
- package/src/constants/locales.ts +189 -0
- package/src/constants/notifications.ts +30 -0
- package/src/constants/opportunities.ts +84 -0
- package/src/constants/qualificationTypes.ts +17 -0
- package/src/constants/rules.ts +22 -0
- package/src/constants/subscriptions.ts +8 -0
- package/src/constants/surveys.ts +15 -0
- package/src/constants.ts +40 -0
- package/src/{date-time.js → date-time.ts} +18 -11
- package/src/forms.ts +807 -0
- package/src/{opportunityUser.js → opportunityUser.ts} +5 -1
- package/src/{password.js → password.ts} +2 -0
- package/src/rrule/date.ts +25 -0
- package/src/rrule/index.ts +2 -0
- package/src/rrule/parsing.ts +136 -0
- package/src/rrule.ts +367 -0
- package/tests/{date-time.test.js → date-time.test.ts} +48 -46
- package/tests/featureFlag.test.ts +36 -39
- package/tests/forms.test-data.json +43 -0
- package/tests/forms.test-schema.json +144 -0
- package/tests/forms.test-uischema.json +117 -0
- package/tests/forms.test.ts +674 -0
- package/tests/{money.test.js → money.test.ts} +2 -3
- package/tests/{password.test.js → password.test.ts} +7 -6
- package/tests/rrule/parsing.test.ts +12 -0
- package/tests/rrule.test.ts +625 -0
- package/tsconfig.json +15 -12
- package/bundle.js +0 -270
- package/index.js +0 -25
- package/rollup.config.js +0 -25
- /package/src/{locality.js → locality.ts} +0 -0
- /package/src/{money.js → money.ts} +0 -0
- /package/src/{opportunity.js → opportunity.ts} +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { toRruleStr } from '../../lib/rrule/parsing';
|
|
2
|
+
|
|
3
|
+
it('removes null or undefined fields', () => {
|
|
4
|
+
expect(
|
|
5
|
+
toRruleStr({
|
|
6
|
+
DTSTART: '20120201T023000Z',
|
|
7
|
+
DURATION: '1h',
|
|
8
|
+
COUNT: null,
|
|
9
|
+
UNTIL: undefined,
|
|
10
|
+
})
|
|
11
|
+
).toEqual('DTSTART=20120201T023000Z;DURATION=1h');
|
|
12
|
+
});
|
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
/* eslint-disable jest/no-conditional-expect */
|
|
2
|
+
import { RRule } from 'rrule';
|
|
3
|
+
import { DateTime } from 'luxon';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
recurrencesBetween,
|
|
7
|
+
recurrencesBetweenV2,
|
|
8
|
+
recurrenceToText,
|
|
9
|
+
toRruleObj,
|
|
10
|
+
toRruleStr,
|
|
11
|
+
parse,
|
|
12
|
+
isValidRrule,
|
|
13
|
+
buildBcRruleString,
|
|
14
|
+
} from '../lib/rrule';
|
|
15
|
+
|
|
16
|
+
const RULE_CONFIG = {
|
|
17
|
+
'RRULE:FREQ': 'WEEKLY',
|
|
18
|
+
DTSTART: '20170703T125800Z',
|
|
19
|
+
UNTIL: '20170703T130200Z',
|
|
20
|
+
INTERVAL: '1',
|
|
21
|
+
BYDAY: 'WE,TU',
|
|
22
|
+
};
|
|
23
|
+
const RULE = 'RRULE:FREQ=WEEKLY;UNTIL=20170703T130200Z;INTERVAL=1;DTSTART=20170703T125800Z;BYDAY=WE,TU';
|
|
24
|
+
|
|
25
|
+
const date = (str) => DateTime.fromFormat(str, 'YYYY-MM-DD').toJSDate();
|
|
26
|
+
|
|
27
|
+
const validateDay = (timezone, { from, to }) => {
|
|
28
|
+
const VALID_DAYS = ['Tue', 'Wed'];
|
|
29
|
+
expect(VALID_DAYS.includes(DateTime.fromJSDate(from).setZone(timezone).toFormat('ddd'))).toBeTruthy();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const validateTime = (timezone, startTime, endTime, { from, to }) => {
|
|
33
|
+
const TIME_FORMAT = 'HH:mm';
|
|
34
|
+
const start = DateTime.fromJSDate(from).setZone(timezone).toFormat(TIME_FORMAT);
|
|
35
|
+
const end = DateTime.fromJSDate(to).setZone(timezone).toFormat(TIME_FORMAT);
|
|
36
|
+
|
|
37
|
+
expect(start).toEqual(startTime);
|
|
38
|
+
expect(end).toEqual(endTime);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe('Recurrences between', () => {
|
|
42
|
+
it('validates DTSTART is earlier or equal to than UNTIL', () => {
|
|
43
|
+
const rrule = 'RRULE:FREQ=MONTHLY;INTERVAL=1;DTSTART=20180110T050000Z;UNTIL=20180110T030000Z;BYDAY=1SA;BYMONTHDAY=';
|
|
44
|
+
const rruleObj = toRruleObj(rrule);
|
|
45
|
+
expect(isValidRrule(rruleObj)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('gets the start time correct consistently', () => {
|
|
49
|
+
const melbourne = 'Australia/Melbourne';
|
|
50
|
+
const start = new Date('2017-01-01');
|
|
51
|
+
const end = new Date('2017-12-31');
|
|
52
|
+
const DATE_FORMAT = 'YYYYMMDD';
|
|
53
|
+
let recurrences = recurrencesBetween(start, end, RULE, melbourne);
|
|
54
|
+
recurrences.forEach(validateDay.bind(null, melbourne));
|
|
55
|
+
recurrences.forEach(validateTime.bind(null, melbourne, '22:58', '23:02'));
|
|
56
|
+
|
|
57
|
+
const taipei = 'Asia/Taipei';
|
|
58
|
+
recurrences = recurrencesBetween(start, end, RULE, taipei);
|
|
59
|
+
recurrences.forEach(validateDay.bind(null, taipei));
|
|
60
|
+
recurrences.forEach(validateTime.bind(null, taipei, '20:58', '21:02'));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("doesn't enter an infinite loop when INTERVAL is empty", () => {
|
|
64
|
+
const recurrences = recurrencesBetween(
|
|
65
|
+
new Date('2018-01-11T07:25:47.871Z'),
|
|
66
|
+
new Date('2019-01-10T13:00:00.000Z'),
|
|
67
|
+
'RRULE:FREQ=MONTHLY;INTERVAL=;DTSTART=20180110T020000Z;UNTIL=20180110T050000Z;BYDAY=1SA;BYMONTHDAY=',
|
|
68
|
+
'Australia/Melbourne'
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('Recurrence to text', () => {
|
|
74
|
+
it('displays a consistent start time irrespective of daylight savings', () => {
|
|
75
|
+
// Test when there is no daylight savings
|
|
76
|
+
const rule = `${RULE};DURATION=4M`;
|
|
77
|
+
const melbourne = 'Australia/Melbourne';
|
|
78
|
+
let display = recurrenceToText(rule, melbourne);
|
|
79
|
+
expect(display.time).toEqual('10:58 PM to 11:02 PM');
|
|
80
|
+
|
|
81
|
+
// Test when daylight savings is active
|
|
82
|
+
display = recurrenceToText(rule, melbourne);
|
|
83
|
+
expect(display.time).toEqual('10:58 PM to 11:02 PM');
|
|
84
|
+
});
|
|
85
|
+
it('display text with two lines rrule', () => {
|
|
86
|
+
const rruleStr = buildBcRruleString(
|
|
87
|
+
new RRule({
|
|
88
|
+
dtstart: new Date(Date.UTC(2020, 10, 20, 14, 0)),
|
|
89
|
+
freq: RRule.WEEKLY,
|
|
90
|
+
bymonthday: [1, 2],
|
|
91
|
+
interval: 1,
|
|
92
|
+
until: new Date(Date.UTC(2020, 12, 31, 12, 59)),
|
|
93
|
+
}),
|
|
94
|
+
'2H'
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const melbourne = 'Australia/Melbourne';
|
|
98
|
+
const auckland = 'Pacific/Auckland';
|
|
99
|
+
|
|
100
|
+
const display = recurrenceToText(rruleStr, melbourne);
|
|
101
|
+
expect(display.time).toEqual('1:00 AM to 3:00 AM');
|
|
102
|
+
expect(display.text).toEqual('Every week on the 1st and 2nd until January 31, 2021');
|
|
103
|
+
const display2 = recurrenceToText(rruleStr, auckland);
|
|
104
|
+
expect(display2.time).toEqual('3:00 AM to 5:00 AM');
|
|
105
|
+
expect(display2.text).toEqual('Every week on the 1st and 2nd until February 1, 2021');
|
|
106
|
+
});
|
|
107
|
+
it('display text with flexible type opportunity', () => {
|
|
108
|
+
const rruleStr = buildBcRruleString(
|
|
109
|
+
new RRule({
|
|
110
|
+
dtstart: new Date(Date.UTC(2020, 10, 20, 14, 0)),
|
|
111
|
+
freq: RRule.WEEKLY,
|
|
112
|
+
interval: 1,
|
|
113
|
+
until: new Date(Date.UTC(2020, 12, 31, 12, 59)),
|
|
114
|
+
}),
|
|
115
|
+
'2H'
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const melbourne = 'Australia/Melbourne';
|
|
119
|
+
const auckland = 'Pacific/Auckland';
|
|
120
|
+
|
|
121
|
+
const display = recurrenceToText(rruleStr, melbourne, true);
|
|
122
|
+
expect(display.text).toEqual('2 hours every week until January 31, 2021');
|
|
123
|
+
const display2 = recurrenceToText(rruleStr, auckland, true);
|
|
124
|
+
expect(display2.text).toEqual('2 hours every week until February 1, 2021');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('display text with non-repeating opportunity', () => {
|
|
128
|
+
const rruleStr = buildBcRruleString(
|
|
129
|
+
new RRule({
|
|
130
|
+
dtstart: new Date(Date.UTC(2020, 10, 20, 14, 0)),
|
|
131
|
+
freq: RRule.YEARLY,
|
|
132
|
+
count: 1,
|
|
133
|
+
until: new Date(Date.UTC(2020, 12, 31, 12, 59)),
|
|
134
|
+
}),
|
|
135
|
+
'2H'
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const melbourne = 'Australia/Melbourne';
|
|
139
|
+
const auckland = 'Pacific/Auckland';
|
|
140
|
+
|
|
141
|
+
const display = recurrenceToText(rruleStr, melbourne, true);
|
|
142
|
+
expect(display.text).toEqual('2 hours in total by January 31, 2021');
|
|
143
|
+
const display2 = recurrenceToText(rruleStr, auckland, true);
|
|
144
|
+
expect(display2.text).toEqual('2 hours in total by February 1, 2021');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('Parsing', () => {
|
|
149
|
+
it('parses an empty string', () => {
|
|
150
|
+
const config = toRruleObj('');
|
|
151
|
+
expect(Object.keys(config)).toHaveLength(0);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('parses duration handle not exist', () => {
|
|
155
|
+
const { duration } = parse(RULE);
|
|
156
|
+
expect(duration).toEqual(0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('parses duration provided', () => {
|
|
160
|
+
const { duration } = parse(`${RULE};DURATION=1H`);
|
|
161
|
+
expect(duration).toEqual(3600000);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('parses fraction duration provided', () => {
|
|
165
|
+
const { duration } = parse(`${RULE};DURATION=1.5H`);
|
|
166
|
+
expect(duration).toEqual(5400000);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('do not bomb on dtend - backward no bomb test', () => {
|
|
170
|
+
const { duration, dtend } = parse(`${RULE};DTEND=20180110T050000Z`);
|
|
171
|
+
expect(duration).not.toEqual(0);
|
|
172
|
+
expect(dtend).toEqual('20180110T050000Z');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('converts rrule string to object', () => {
|
|
176
|
+
const config = toRruleObj(RULE);
|
|
177
|
+
expect(config).toEqual(RULE_CONFIG);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('converts to rrule string', () => {
|
|
181
|
+
const rrule = toRruleStr(RULE_CONFIG);
|
|
182
|
+
expect(rrule.indexOf('RRULE:FREQ=WEEKLY;')).toEqual(0);
|
|
183
|
+
expect(rrule.includes('UNTIL=20170703T130200Z')).toBeTruthy();
|
|
184
|
+
expect(rrule.includes('DTSTART=20170703T125800Z')).toBeTruthy();
|
|
185
|
+
expect(rrule.includes('INTERVAL=1')).toBeTruthy();
|
|
186
|
+
expect(rrule.includes('BYDAY=WE,TU')).toBeTruthy();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('buildBcRuleString', () => {
|
|
191
|
+
it('should work for weekly', () => {
|
|
192
|
+
const rruleStr = buildBcRruleString(
|
|
193
|
+
new RRule({
|
|
194
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
195
|
+
freq: RRule.WEEKLY,
|
|
196
|
+
interval: 1,
|
|
197
|
+
until: new Date(Date.UTC(2017, 7, 13, 13, 2)),
|
|
198
|
+
}),
|
|
199
|
+
'1H'
|
|
200
|
+
);
|
|
201
|
+
expect(rruleStr.indexOf('RRULE:FREQ=WEEKLY;')).toEqual(25);
|
|
202
|
+
expect(rruleStr.includes('UNTIL=20170813T130200Z')).toBeTruthy();
|
|
203
|
+
expect(rruleStr.includes('DTSTART:20170803T130200Z')).toBeTruthy();
|
|
204
|
+
expect(rruleStr.includes('INTERVAL=1')).toBeTruthy();
|
|
205
|
+
expect(rruleStr.includes('DURATION=1H')).toBeTruthy();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should work for yearly', () => {
|
|
209
|
+
const rruleStr = buildBcRruleString(
|
|
210
|
+
new RRule({
|
|
211
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
212
|
+
freq: RRule.YEARLY,
|
|
213
|
+
interval: 1,
|
|
214
|
+
until: new Date(Date.UTC(2017, 7, 13, 13, 2)),
|
|
215
|
+
}),
|
|
216
|
+
'1H'
|
|
217
|
+
);
|
|
218
|
+
expect(rruleStr.indexOf('RRULE:FREQ=YEARLY;')).toEqual(25);
|
|
219
|
+
expect(rruleStr.includes('UNTIL=20170813T130200Z')).toBeTruthy();
|
|
220
|
+
expect(rruleStr.includes('DTSTART:20170803T130200Z')).toBeTruthy();
|
|
221
|
+
expect(rruleStr.includes('INTERVAL=1')).toBeTruthy();
|
|
222
|
+
expect(rruleStr.includes('DURATION=1H')).toBeTruthy();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should fail for secondly', () => {
|
|
226
|
+
try {
|
|
227
|
+
const rruleStr = buildBcRruleString(
|
|
228
|
+
new RRule({
|
|
229
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
230
|
+
freq: RRule.SECONDLY,
|
|
231
|
+
interval: 1,
|
|
232
|
+
until: new Date(Date.UTC(2017, 7, 13, 13, 2)),
|
|
233
|
+
}),
|
|
234
|
+
'1H'
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
catch (err: any) {
|
|
238
|
+
expect(JSON.parse(err.message)[0]).toBe('Please enter a Frequency (Month/Weekly/Yearly)');
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should fail for weekly until', () => {
|
|
243
|
+
try {
|
|
244
|
+
const rruleStr = buildBcRruleString(
|
|
245
|
+
new RRule({
|
|
246
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
247
|
+
freq: RRule.WEEKLY,
|
|
248
|
+
interval: 1,
|
|
249
|
+
until: new Date(Date.UTC(2017, 7, 13, 13, 2)),
|
|
250
|
+
})
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
catch (err: any) {
|
|
254
|
+
expect(JSON.parse(err.message)[0]).toBe('Please enter a Duration');
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should fail for weekly', () => {
|
|
259
|
+
try {
|
|
260
|
+
const rruleStr = buildBcRruleString(
|
|
261
|
+
new RRule({
|
|
262
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
263
|
+
freq: RRule.WEEKLY,
|
|
264
|
+
interval: 1,
|
|
265
|
+
}),
|
|
266
|
+
'1H'
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
catch (err: any) {
|
|
270
|
+
expect(JSON.parse(err.message)[0]).toBe('Please enter a Until');
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe('recurrencesBetweenV2', () => {
|
|
276
|
+
it('should not bomb when 0 occurences', () => {
|
|
277
|
+
const rruleStr = buildBcRruleString(
|
|
278
|
+
new RRule({
|
|
279
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
280
|
+
freq: RRule.WEEKLY,
|
|
281
|
+
interval: 1,
|
|
282
|
+
until: new Date(Date.UTC(2017, 9, 13, 13, 2)),
|
|
283
|
+
count: 0,
|
|
284
|
+
}),
|
|
285
|
+
'1H'
|
|
286
|
+
);
|
|
287
|
+
const melbourne = 'Australia/Melbourne';
|
|
288
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne);
|
|
289
|
+
expect(result).toHaveLength(0);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should work entering into +11 from +10 in Australia/Melbourne timezone', () => {
|
|
293
|
+
const rruleStr = buildBcRruleString(
|
|
294
|
+
new RRule({
|
|
295
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
296
|
+
freq: RRule.WEEKLY,
|
|
297
|
+
interval: 1,
|
|
298
|
+
until: new Date(Date.UTC(2017, 9, 13, 13, 2)),
|
|
299
|
+
}),
|
|
300
|
+
'1H'
|
|
301
|
+
);
|
|
302
|
+
const melbourne = 'Australia/Melbourne';
|
|
303
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
304
|
+
expect(result.length).toBe(11);
|
|
305
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
306
|
+
'2017-08-03T13:02:00.000Z',
|
|
307
|
+
'2017-08-10T13:02:00.000Z',
|
|
308
|
+
'2017-08-17T13:02:00.000Z',
|
|
309
|
+
'2017-08-24T13:02:00.000Z',
|
|
310
|
+
'2017-08-31T13:02:00.000Z',
|
|
311
|
+
'2017-09-07T13:02:00.000Z',
|
|
312
|
+
'2017-09-14T13:02:00.000Z',
|
|
313
|
+
'2017-09-21T13:02:00.000Z',
|
|
314
|
+
'2017-09-28T13:02:00.000Z',
|
|
315
|
+
'2017-10-05T12:02:00.000Z',
|
|
316
|
+
'2017-10-12T12:02:00.000Z',
|
|
317
|
+
]);
|
|
318
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
319
|
+
'2017-08-03T14:02:00.000Z',
|
|
320
|
+
'2017-08-10T14:02:00.000Z',
|
|
321
|
+
'2017-08-17T14:02:00.000Z',
|
|
322
|
+
'2017-08-24T14:02:00.000Z',
|
|
323
|
+
'2017-08-31T14:02:00.000Z',
|
|
324
|
+
'2017-09-07T14:02:00.000Z',
|
|
325
|
+
'2017-09-14T14:02:00.000Z',
|
|
326
|
+
'2017-09-21T14:02:00.000Z',
|
|
327
|
+
'2017-09-28T14:02:00.000Z',
|
|
328
|
+
'2017-10-05T13:02:00.000Z',
|
|
329
|
+
'2017-10-12T13:02:00.000Z',
|
|
330
|
+
]);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('should work with a start date including only portion of date range', () => {
|
|
334
|
+
const rruleStr = buildBcRruleString(
|
|
335
|
+
new RRule({
|
|
336
|
+
dtstart: new Date(Date.UTC(2017, 7, 3, 13, 2)),
|
|
337
|
+
freq: RRule.WEEKLY,
|
|
338
|
+
interval: 1,
|
|
339
|
+
until: new Date(Date.UTC(2017, 9, 13, 13, 2)),
|
|
340
|
+
}),
|
|
341
|
+
'1H'
|
|
342
|
+
);
|
|
343
|
+
const melbourne = 'Australia/Melbourne';
|
|
344
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date(Date.UTC(2017, 7, 17, 13, 2)));
|
|
345
|
+
expect(result.length).toBe(9);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('should work entering into +10 from +11 in Australia/Melbourne timezone', () => {
|
|
349
|
+
const rruleStr = buildBcRruleString(
|
|
350
|
+
new RRule({
|
|
351
|
+
dtstart: new Date(Date.UTC(2017, 2, 3, 13, 2)),
|
|
352
|
+
freq: RRule.WEEKLY,
|
|
353
|
+
interval: 1,
|
|
354
|
+
until: new Date(Date.UTC(2017, 4, 13, 13, 2)),
|
|
355
|
+
}),
|
|
356
|
+
'1H'
|
|
357
|
+
);
|
|
358
|
+
const melbourne = 'Australia/Melbourne';
|
|
359
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
360
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
361
|
+
'2017-03-03T13:02:00.000Z',
|
|
362
|
+
'2017-03-10T13:02:00.000Z',
|
|
363
|
+
'2017-03-17T13:02:00.000Z',
|
|
364
|
+
'2017-03-24T13:02:00.000Z',
|
|
365
|
+
'2017-03-31T13:02:00.000Z',
|
|
366
|
+
'2017-04-07T14:02:00.000Z',
|
|
367
|
+
'2017-04-14T14:02:00.000Z',
|
|
368
|
+
'2017-04-21T14:02:00.000Z',
|
|
369
|
+
'2017-04-28T14:02:00.000Z',
|
|
370
|
+
'2017-05-05T14:02:00.000Z',
|
|
371
|
+
'2017-05-12T14:02:00.000Z',
|
|
372
|
+
]);
|
|
373
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
374
|
+
'2017-03-03T14:02:00.000Z',
|
|
375
|
+
'2017-03-10T14:02:00.000Z',
|
|
376
|
+
'2017-03-17T14:02:00.000Z',
|
|
377
|
+
'2017-03-24T14:02:00.000Z',
|
|
378
|
+
'2017-03-31T14:02:00.000Z',
|
|
379
|
+
'2017-04-07T15:02:00.000Z',
|
|
380
|
+
'2017-04-14T15:02:00.000Z',
|
|
381
|
+
'2017-04-21T15:02:00.000Z',
|
|
382
|
+
'2017-04-28T15:02:00.000Z',
|
|
383
|
+
'2017-05-05T15:02:00.000Z',
|
|
384
|
+
'2017-05-12T15:02:00.000Z',
|
|
385
|
+
]);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('should work entering into +12 from +13 in Pacific/Auckland', () => {
|
|
389
|
+
const rruleStr = buildBcRruleString(
|
|
390
|
+
new RRule({
|
|
391
|
+
dtstart: new Date(Date.UTC(2017, 8, 3, 13, 2)),
|
|
392
|
+
freq: RRule.WEEKLY,
|
|
393
|
+
interval: 1,
|
|
394
|
+
until: new Date(Date.UTC(2017, 9, 13, 13, 2)),
|
|
395
|
+
}),
|
|
396
|
+
'1H'
|
|
397
|
+
);
|
|
398
|
+
const auckland = 'Pacific/Auckland';
|
|
399
|
+
const result = recurrencesBetweenV2(rruleStr, auckland, new Date('2017-01-01'));
|
|
400
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
401
|
+
'2017-09-03T13:02:00.000Z',
|
|
402
|
+
'2017-09-10T13:02:00.000Z',
|
|
403
|
+
'2017-09-17T13:02:00.000Z',
|
|
404
|
+
'2017-09-24T12:02:00.000Z',
|
|
405
|
+
'2017-10-01T12:02:00.000Z',
|
|
406
|
+
'2017-10-08T12:02:00.000Z',
|
|
407
|
+
]);
|
|
408
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
409
|
+
'2017-09-03T14:02:00.000Z',
|
|
410
|
+
'2017-09-10T14:02:00.000Z',
|
|
411
|
+
'2017-09-17T14:02:00.000Z',
|
|
412
|
+
'2017-09-24T13:02:00.000Z',
|
|
413
|
+
'2017-10-01T13:02:00.000Z',
|
|
414
|
+
'2017-10-08T13:02:00.000Z',
|
|
415
|
+
]);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('should ignore shifts with to date over the until bound', () => {
|
|
419
|
+
const until = new Date(Date.UTC(2021, 3, 14, 3, 5, 8));
|
|
420
|
+
const rruleStr = buildBcRruleString(
|
|
421
|
+
new RRule({
|
|
422
|
+
dtstart: new Date(Date.UTC(2020, 8, 23, 3, 5, 8)),
|
|
423
|
+
freq: RRule.WEEKLY,
|
|
424
|
+
interval: 1,
|
|
425
|
+
until,
|
|
426
|
+
byweekday: RRule.WE,
|
|
427
|
+
}),
|
|
428
|
+
'10H'
|
|
429
|
+
);
|
|
430
|
+
const auckland = 'Australia/Melbourne';
|
|
431
|
+
const result = recurrencesBetweenV2(rruleStr, auckland);
|
|
432
|
+
const resultsInBound = result.filter(({ to }) => DateTime.fromISO(to) < DateTime.fromJSDate(until));
|
|
433
|
+
expect(resultsInBound.length).toBe(result.length);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should pick all the wednesdays 13hrs Melbourne time', () => {
|
|
437
|
+
const until = new Date(Date.UTC(2020, 9, 13, 3, 5, 8));
|
|
438
|
+
const rruleStr = buildBcRruleString(
|
|
439
|
+
new RRule({
|
|
440
|
+
dtstart: new Date(Date.UTC(2020, 8, 23, 3, 5, 8)),
|
|
441
|
+
freq: RRule.WEEKLY,
|
|
442
|
+
interval: 1,
|
|
443
|
+
until,
|
|
444
|
+
byweekday: RRule.WE,
|
|
445
|
+
}),
|
|
446
|
+
'10H'
|
|
447
|
+
);
|
|
448
|
+
const melbourne = 'Australia/Melbourne';
|
|
449
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
450
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
451
|
+
'2020-09-23T03:05:08.000Z',
|
|
452
|
+
'2020-09-30T03:05:08.000Z',
|
|
453
|
+
'2020-10-07T02:05:08.000Z',
|
|
454
|
+
]);
|
|
455
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
456
|
+
'2020-09-23T13:05:08.000Z',
|
|
457
|
+
'2020-09-30T13:05:08.000Z',
|
|
458
|
+
'2020-10-07T12:05:08.000Z',
|
|
459
|
+
]);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it('should pick all the wednesdays 9hrs Melbourne time', () => {
|
|
463
|
+
const until = new Date(Date.UTC(2020, 9, 12, 23, 5, 8));
|
|
464
|
+
const rruleStr = buildBcRruleString(
|
|
465
|
+
new RRule({
|
|
466
|
+
dtstart: new Date(Date.UTC(2020, 8, 22, 23, 5, 8)),
|
|
467
|
+
freq: RRule.WEEKLY,
|
|
468
|
+
interval: 1,
|
|
469
|
+
until,
|
|
470
|
+
byweekday: RRule.WE,
|
|
471
|
+
}),
|
|
472
|
+
'10H'
|
|
473
|
+
);
|
|
474
|
+
const melbourne = 'Australia/Melbourne';
|
|
475
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
476
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
477
|
+
'2020-09-22T23:05:08.000Z',
|
|
478
|
+
'2020-09-29T23:05:08.000Z',
|
|
479
|
+
'2020-10-06T22:05:08.000Z',
|
|
480
|
+
]);
|
|
481
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
482
|
+
'2020-09-23T09:05:08.000Z',
|
|
483
|
+
'2020-09-30T09:05:08.000Z',
|
|
484
|
+
'2020-10-07T08:05:08.000Z',
|
|
485
|
+
]);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it('should pick all first day of the month 9hrs Melbourne time', () => {
|
|
489
|
+
const until = new Date(Date.UTC(2020, 10, 1, 23, 5, 8));
|
|
490
|
+
const rruleStr = buildBcRruleString(
|
|
491
|
+
new RRule({
|
|
492
|
+
dtstart: new Date(Date.UTC(2020, 6, 30, 23, 5, 8)),
|
|
493
|
+
freq: RRule.MONTHLY,
|
|
494
|
+
interval: 1,
|
|
495
|
+
until,
|
|
496
|
+
bymonthday: 1,
|
|
497
|
+
byhour: 9,
|
|
498
|
+
}),
|
|
499
|
+
'10H'
|
|
500
|
+
);
|
|
501
|
+
const melbourne = 'Australia/Melbourne';
|
|
502
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
503
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
504
|
+
'2020-07-31T23:05:08.000Z',
|
|
505
|
+
'2020-08-31T23:05:08.000Z',
|
|
506
|
+
'2020-09-30T23:05:08.000Z',
|
|
507
|
+
'2020-10-31T22:05:08.000Z',
|
|
508
|
+
]);
|
|
509
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
510
|
+
'2020-08-01T09:05:08.000Z',
|
|
511
|
+
'2020-09-01T09:05:08.000Z',
|
|
512
|
+
'2020-10-01T09:05:08.000Z',
|
|
513
|
+
'2020-11-01T08:05:08.000Z',
|
|
514
|
+
]);
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
it('should pick last day of the month 9hrs Melbourne time', () => {
|
|
518
|
+
const until = new Date(Date.UTC(2020, 11, 1, 23, 0, 0));
|
|
519
|
+
const rruleStr = buildBcRruleString(
|
|
520
|
+
new RRule({
|
|
521
|
+
dtstart: new Date(Date.UTC(2020, 6, 31, 10, 23, 0, 0)),
|
|
522
|
+
freq: RRule.MONTHLY,
|
|
523
|
+
interval: 1,
|
|
524
|
+
until,
|
|
525
|
+
bymonthday: [30, 31],
|
|
526
|
+
bysetpos: -1,
|
|
527
|
+
byhour: 9,
|
|
528
|
+
}),
|
|
529
|
+
'10H'
|
|
530
|
+
);
|
|
531
|
+
const melbourne = 'Australia/Melbourne';
|
|
532
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
533
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
534
|
+
'2020-08-30T23:23:00.000Z',
|
|
535
|
+
'2020-09-29T23:23:00.000Z',
|
|
536
|
+
'2020-10-30T22:23:00.000Z',
|
|
537
|
+
'2020-11-29T22:23:00.000Z',
|
|
538
|
+
]);
|
|
539
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
540
|
+
'2020-08-31T09:23:00.000Z',
|
|
541
|
+
'2020-09-30T09:23:00.000Z',
|
|
542
|
+
'2020-10-31T08:23:00.000Z',
|
|
543
|
+
'2020-11-30T08:23:00.000Z',
|
|
544
|
+
]);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it('should pick last day of the month 9hrs Melbourne time without by hour', () => {
|
|
548
|
+
const until = new Date(Date.UTC(2020, 11, 1, 23, 0, 0));
|
|
549
|
+
const rruleStr = buildBcRruleString(
|
|
550
|
+
new RRule({
|
|
551
|
+
dtstart: new Date(Date.UTC(2020, 6, 30, 23, 23, 0, 0)),
|
|
552
|
+
freq: RRule.MONTHLY,
|
|
553
|
+
interval: 1,
|
|
554
|
+
until,
|
|
555
|
+
bymonthday: [30, 31],
|
|
556
|
+
bysetpos: -1,
|
|
557
|
+
}),
|
|
558
|
+
'10H'
|
|
559
|
+
);
|
|
560
|
+
const melbourne = 'Australia/Melbourne';
|
|
561
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
562
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
563
|
+
'2020-07-30T23:23:00.000Z',
|
|
564
|
+
'2020-08-30T23:23:00.000Z',
|
|
565
|
+
'2020-09-29T23:23:00.000Z',
|
|
566
|
+
'2020-10-30T22:23:00.000Z',
|
|
567
|
+
'2020-11-29T22:23:00.000Z',
|
|
568
|
+
]);
|
|
569
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
570
|
+
'2020-07-31T09:23:00.000Z',
|
|
571
|
+
'2020-08-31T09:23:00.000Z',
|
|
572
|
+
'2020-09-30T09:23:00.000Z',
|
|
573
|
+
'2020-10-31T08:23:00.000Z',
|
|
574
|
+
'2020-11-30T08:23:00.000Z',
|
|
575
|
+
]);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
it('should pick last day of the month 9hrs Melbourne time without by hour until next year', () => {
|
|
579
|
+
const until = new Date(Date.UTC(2021, 11, 1, 23, 0, 0));
|
|
580
|
+
const rruleStr = buildBcRruleString(
|
|
581
|
+
new RRule({
|
|
582
|
+
dtstart: new Date(Date.UTC(2020, 6, 30, 23, 23, 0, 0)),
|
|
583
|
+
freq: RRule.MONTHLY,
|
|
584
|
+
interval: 3,
|
|
585
|
+
until,
|
|
586
|
+
bymonthday: [],
|
|
587
|
+
byweekday: RRule.WE,
|
|
588
|
+
bysetpos: 1,
|
|
589
|
+
}),
|
|
590
|
+
'10H'
|
|
591
|
+
);
|
|
592
|
+
const melbourne = 'Australia/Melbourne';
|
|
593
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date('2017-01-01'));
|
|
594
|
+
expect(result.map((range) => range.from.toISOString())).toEqual([
|
|
595
|
+
'2020-10-06T22:23:00.000Z',
|
|
596
|
+
'2021-01-05T22:23:00.000Z',
|
|
597
|
+
'2021-04-06T23:23:00.000Z',
|
|
598
|
+
'2021-07-06T23:23:00.000Z',
|
|
599
|
+
'2021-10-05T22:23:00.000Z',
|
|
600
|
+
]);
|
|
601
|
+
expect(result.map((range) => range.to.toISOString())).toEqual([
|
|
602
|
+
'2020-10-07T08:23:00.000Z',
|
|
603
|
+
'2021-01-06T08:23:00.000Z',
|
|
604
|
+
'2021-04-07T09:23:00.000Z',
|
|
605
|
+
'2021-07-07T09:23:00.000Z',
|
|
606
|
+
'2021-10-06T08:23:00.000Z',
|
|
607
|
+
]);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('should return flexible recurrences use end date', () => {
|
|
611
|
+
const rruleStr = buildBcRruleString(
|
|
612
|
+
new RRule({
|
|
613
|
+
dtstart: new Date(Date.UTC(2021, 7, 21, 14)),
|
|
614
|
+
freq: RRule.WEEKLY,
|
|
615
|
+
interval: 1,
|
|
616
|
+
until: new Date(Date.UTC(2021, 9, 13, 13, 59, 59)),
|
|
617
|
+
}),
|
|
618
|
+
'1H'
|
|
619
|
+
);
|
|
620
|
+
const melbourne = 'Australia/Melbourne';
|
|
621
|
+
const result = recurrencesBetweenV2(rruleStr, melbourne, new Date(Date.UTC(2021, 7, 21, 14)), true);
|
|
622
|
+
expect(result).toHaveLength(8);
|
|
623
|
+
expect(result[0].to.toISOString()).toBe(DateTime.fromJSDate(result[1].from).minus({ seconds: 1 }).toUTC().toISO());
|
|
624
|
+
});
|
|
625
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"lib": ["
|
|
4
|
-
"
|
|
3
|
+
"lib": ["es2020"],
|
|
4
|
+
"target": "es2020",
|
|
5
|
+
"module": "commonjs",
|
|
5
6
|
"allowSyntheticDefaultImports": true,
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
7
|
+
"isolatedModules": true,
|
|
8
|
+
"module": "node20",
|
|
9
|
+
"moduleResolution": "node16",
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"outDir": "./lib",
|
|
12
|
+
"rootDir": "./src",
|
|
13
|
+
"strict": true,
|
|
14
|
+
"noImplicitAny": false,
|
|
15
|
+
"types": ["node","jest"],
|
|
16
|
+
"esModuleInterop": true
|
|
15
17
|
},
|
|
16
|
-
"
|
|
18
|
+
"include": ["src"],
|
|
19
|
+
"exclude": ["node_modules", "**/tests/*", "setup.ts"]
|
|
17
20
|
}
|