Skip to content

Commit 5951ede

Browse files
committed
Address comments
1 parent 725470a commit 5951ede

4 files changed

Lines changed: 107 additions & 84 deletions

File tree

src/adapter/market-status.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { TransportGenerics } from '../transports'
22
import { AdapterEndpoint } from './endpoint'
33
import { AdapterEndpointParams } from './types'
4-
import { validateWeekend } from '../validation/market-status'
4+
import { parseWeekendString } from '../validation/market-status'
5+
import { AdapterInputError } from '../validation/error'
56

67
/**
78
* Base input parameter config that any [[MarketStatusEndpoint]] must extend
@@ -70,7 +71,13 @@ export class MarketStatusEndpoint<
7071
params.customInputValidation = (req, _adapterSettings) => {
7172
const data = req.requestContext.data as Record<string, string>
7273
if (data['type'] === '24/5') {
73-
validateWeekend(data['weekend'])
74+
parseWeekendString(data['weekend'])
75+
}
76+
if (data['type'] === 'regular' && data['weekend']) {
77+
throw new AdapterInputError({
78+
statusCode: 400,
79+
message: '[Param: weekend] must be empty when [Param: weekend] is regular',
80+
})
7481
}
7582
return undefined
7683
}

src/validation/market-status.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AdapterInputError } from '../validation/error'
22
import { TZDate } from '@date-fns/tz'
33

4-
export const validateWeekend = (weekend?: string) => {
4+
export const parseWeekendString = (weekend?: string) => {
55
const dayHour = /[0-6](0\d|1\d|2[0-3])/
66
const timezonePattern = /[^\s]+/
77
const regex = new RegExp(`^(${dayHour.source})-(${dayHour.source}):(${timezonePattern.source})$`)
@@ -14,31 +14,35 @@ export const validateWeekend = (weekend?: string) => {
1414
})
1515
}
1616

17+
const result = {
18+
start: match[1],
19+
end: match[3],
20+
tz: match[5],
21+
}
22+
1723
try {
1824
// eslint-disable-next-line new-cap
19-
Intl.DateTimeFormat(undefined, { timeZone: weekend?.split(':')[1] })
25+
Intl.DateTimeFormat(undefined, { timeZone: result.tz })
2026
} catch (error) {
2127
throw new AdapterInputError({
2228
statusCode: 400,
23-
message: `[Param: weekend] is not valid: ${error}`,
29+
message: `timezone ${result.tz} in [Param: weekend] is not valid: ${error}`,
2430
})
2531
}
26-
}
2732

28-
export const isWeekend = (weekend?: string) => {
29-
validateWeekend(weekend)
33+
return result
34+
}
3035

31-
// Weekend looks like 520-020:America/New_York
32-
const [range, tz] = (weekend || '').split(':')
33-
const [start, end] = range.split('-')
36+
export const isWeekendNow = (weekend?: string) => {
37+
const parsed = parseWeekendString(weekend)
3438

35-
const startDay = Number(start[0])
36-
const startHour = Number(start.slice(1))
37-
const endDay = Number(end[0])
38-
const endHour = Number(end.slice(1))
39+
const startDay = Number(parsed.start[0])
40+
const startHour = Number(parsed.start.slice(1))
41+
const endDay = Number(parsed.end[0])
42+
const endHour = Number(parsed.end.slice(1))
3943

40-
const nowDay = TZDate.tz(tz).getDay()
41-
const nowHour = TZDate.tz(tz).getHours()
44+
const nowDay = TZDate.tz(parsed.tz).getDay()
45+
const nowHour = TZDate.tz(parsed.tz).getHours()
4246

4347
// Case 1: weekend does NOT wrap around the week
4448
if (startDay < endDay || (startDay === endDay && startHour < endHour)) {

test/adapter/market-status.test.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Adapter } from '../../src/adapter/basic'
1212
import { Transport } from '../../src/transports'
1313
import { ResponseCache } from '../../src/cache/response'
1414

15-
test('MarketStatusEndpoint - validates weekend when type is 24/5', async (t) => {
15+
test('MarketStatusEndpoint - validates weekend', async (t) => {
1616
class MarketStatusTestTransport implements Transport<MarketStatusEndpointGenerics> {
1717
name!: string
1818
responseCache!: ResponseCache<MarketStatusEndpointGenerics>
@@ -57,30 +57,39 @@ test('MarketStatusEndpoint - validates weekend when type is 24/5', async (t) =>
5757
const response1 = await testAdapter.request({
5858
market: 'BTC',
5959
type: 'regular',
60-
weekend: '520-020',
6160
endpoint: 'test',
6261
})
63-
t.is(response1.statusCode, 200, 'Should succeed with invalid weekend when type is regular')
62+
t.is(response1.statusCode, 200, 'Should succeed with empty weekend when type is regular')
6463

6564
const response2 = await testAdapter.request({
6665
market: 'BTC',
67-
type: '24/5',
66+
type: 'regular',
6867
weekend: '520-020',
6968
endpoint: 'test',
7069
})
71-
t.is(response2.statusCode, 400, 'Should fail with invalid weekend format')
70+
t.is(response2.statusCode, 400, 'Should fail with weekend when type is regular')
7271
t.true(
73-
response2.json().error.message.includes('[Param: weekend] does not match format'),
74-
'Error message should mention weekend format',
72+
response2
73+
.json()
74+
.error.message.includes('[Param: weekend] must be empty when [Param: weekend] is regular'),
7575
)
7676

7777
const response3 = await testAdapter.request({
78+
market: 'BTC',
79+
type: '24/5',
80+
weekend: '520-020',
81+
endpoint: 'test',
82+
})
83+
t.is(response3.statusCode, 400, 'Should fail with invalid weekend format when type is 24/5')
84+
t.true(response3.json().error.message.includes('[Param: weekend] does not match format'))
85+
86+
const response4 = await testAdapter.request({
7887
market: 'BTC',
7988
type: '24/5',
8089
weekend: '520-020:America/New_York',
8190
endpoint: 'test',
8291
})
83-
t.is(response3.statusCode, 200, 'Should succeed with valid weekend')
92+
t.is(response4.statusCode, 200, 'Should succeed with valid weekend when type is 24/5')
8493

8594
await testAdapter.api.close()
8695
})
Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,62 @@
11
import test from 'ava'
22
import FakeTimers from '@sinonjs/fake-timers'
3-
import { validateWeekend, isWeekend } from '../../src/validation/market-status'
3+
import { parseWeekendString, isWeekendNow } from '../../src/validation/market-status'
44

5-
test('validateWeekend - success', (t) => {
5+
test('parseWeekendString - success', (t) => {
66
t.notThrows(() => {
7-
validateWeekend('520-020:America/New_York')
8-
validateWeekend('000-123:UTC')
9-
validateWeekend('123-423:Europe/London')
10-
validateWeekend('600-023:Asia/Tokyo')
7+
parseWeekendString('520-020:America/New_York')
8+
parseWeekendString('000-123:UTC')
9+
parseWeekendString('123-423:Europe/London')
10+
parseWeekendString('600-023:Asia/Tokyo')
1111
})
1212
})
1313

14-
test('validateWeekend - bad format', (t) => {
14+
test('parseWeekendString - bad format', (t) => {
1515
t.throws(() => {
16-
validateWeekend('520020:America/New_York')
16+
parseWeekendString('520020:America/New_York')
1717
})
1818
t.throws(() => {
19-
validateWeekend('520-020America/New_York')
19+
parseWeekendString('520-020America/New_York')
2020
})
2121
t.throws(() => {
22-
validateWeekend('520-020:')
22+
parseWeekendString('520-020:')
2323
})
2424
t.throws(() => {
25-
validateWeekend('55-020:UTC')
25+
parseWeekendString('55-020:UTC')
2626
})
2727
t.throws(() => {
28-
validateWeekend('55-20:UTC')
28+
parseWeekendString('55-20:UTC')
2929
})
3030
t.throws(() => {
31-
validateWeekend('')
31+
parseWeekendString('')
3232
})
3333
t.throws(() => {
34-
validateWeekend()
34+
parseWeekendString()
3535
})
3636
t.throws(() => {
37-
validateWeekend('520:020-America/New_York')
37+
parseWeekendString('520:020-America/New_York')
3838
})
3939
t.throws(() => {
40-
validateWeekend('520-020: ')
40+
parseWeekendString('520-020: ')
4141
})
4242
})
4343

44-
test('validateWeekend - bad number', (t) => {
44+
test('parseWeekendString - bad number', (t) => {
4545
t.throws(() => {
46-
validateWeekend('720-020:UTC')
46+
parseWeekendString('720-020:UTC')
4747
})
4848
t.throws(() => {
49-
validateWeekend('524-020:UTC')
49+
parseWeekendString('524-020:UTC')
5050
})
5151
t.throws(() => {
52-
validateWeekend('525-020:UTC')
52+
parseWeekendString('525-020:UTC')
5353
})
5454
})
5555

56-
test('validateWeekend - invalid timezone', (t) => {
56+
test('parseWeekendString - invalid timezone', (t) => {
5757
t.throws(() => {
58-
validateWeekend('520-020:Invalid/Timezone')
59-
validateWeekend('520-020:AmericaNew_York')
58+
parseWeekendString('520-020:Invalid/Timezone')
59+
parseWeekendString('520-020:AmericaNew_York')
6060
})
6161
})
6262

@@ -66,78 +66,81 @@ test.after(() => {
6666
clock.uninstall()
6767
})
6868

69-
test('isWeekend - UTC', (t) => {
69+
test('isWeekendNow - UTC', (t) => {
7070
// Saturday 12:00 -> 612
7171
clock.setSystemTime(new Date('2024-01-06T12:00:00Z').getTime())
7272

73-
t.false(isWeekend('000-123:UTC'), 'Before start day')
74-
t.false(isWeekend('400-500:UTC'), 'After end day')
75-
t.false(isWeekend('613-620:UTC'), 'Before start hour')
76-
t.false(isWeekend('610-612:UTC'), 'After end hour')
73+
t.false(isWeekendNow('000-123:UTC'), 'Before start day')
74+
t.false(isWeekendNow('400-500:UTC'), 'After end day')
75+
t.false(isWeekendNow('613-620:UTC'), 'Before start hour')
76+
t.false(isWeekendNow('610-612:UTC'), 'After end hour')
7777

78-
t.true(isWeekend('610-620:UTC'), 'Non-wrapping: middle of weekend should return true')
79-
t.true(isWeekend('600-023:UTC'), 'Non-wrapping: spanning multiple days should return true')
80-
t.true(isWeekend('612-615:UTC'), 'Non-wrapping: same day, at start hour should return true')
78+
t.true(isWeekendNow('610-620:UTC'), 'Non-wrapping: middle of weekend should return true')
79+
t.true(isWeekendNow('600-023:UTC'), 'Non-wrapping: spanning multiple days should return true')
80+
t.true(isWeekendNow('612-615:UTC'), 'Non-wrapping: same day, at start hour should return true')
8181

82-
t.true(isWeekend('520-020:UTC'), 'Wrapping: nowDay > startDay should return true')
83-
t.true(isWeekend('400-200:UTC'), 'Wrapping: nowDay > startDay should return true')
82+
t.true(isWeekendNow('520-020:UTC'), 'Wrapping: nowDay > startDay should return true')
83+
t.true(isWeekendNow('400-200:UTC'), 'Wrapping: nowDay > startDay should return true')
8484

85-
t.true(isWeekend('612-020:UTC'), 'After start hour')
86-
t.true(isWeekend('520-613:UTC'), 'Before end hour')
85+
t.true(isWeekendNow('612-020:UTC'), 'After start hour')
86+
t.true(isWeekendNow('520-613:UTC'), 'Before end hour')
8787

88-
t.false(isWeekend('620-610:UTC'), 'Wrapping same day: between end and start should return false')
88+
t.false(
89+
isWeekendNow('620-610:UTC'),
90+
'Wrapping same day: between end and start should return false',
91+
)
8992
})
9093

91-
test('isWeekend - ET', (t) => {
94+
test('isWeekendNow - ET', (t) => {
9295
// Saturday 12:00 UTC = Saturday 07:00 EST -> 607
9396
clock.setSystemTime(new Date('2024-01-06T12:00:00Z').getTime())
9497

95-
t.false(isWeekend('000-123:America/New_York'), 'Before start day')
96-
t.false(isWeekend('400-500:America/New_York'), 'After end day')
97-
t.false(isWeekend('608-620:America/New_York'), 'Before start hour')
98-
t.false(isWeekend('605-607:America/New_York'), 'After end hour')
98+
t.false(isWeekendNow('000-123:America/New_York'), 'Before start day')
99+
t.false(isWeekendNow('400-500:America/New_York'), 'After end day')
100+
t.false(isWeekendNow('608-620:America/New_York'), 'Before start hour')
101+
t.false(isWeekendNow('605-607:America/New_York'), 'After end hour')
99102

100-
t.true(isWeekend('605-620:America/New_York'), 'Non-wrapping: middle of weekend')
101-
t.true(isWeekend('600-023:America/New_York'), 'Non-wrapping: spanning multiple days')
102-
t.true(isWeekend('607-610:America/New_York'), 'Non-wrapping: same day, at start hour ')
103+
t.true(isWeekendNow('605-620:America/New_York'), 'Non-wrapping: middle of weekend')
104+
t.true(isWeekendNow('600-023:America/New_York'), 'Non-wrapping: spanning multiple days')
105+
t.true(isWeekendNow('607-610:America/New_York'), 'Non-wrapping: same day, at start hour ')
103106

104-
t.true(isWeekend('520-020:America/New_York'), 'Wrapping: nowDay > startDay should return true')
105-
t.true(isWeekend('400-200:America/New_York'), 'Wrapping: nowDay > startDay should return true')
107+
t.true(isWeekendNow('520-020:America/New_York'), 'Wrapping: nowDay > startDay should return true')
108+
t.true(isWeekendNow('400-200:America/New_York'), 'Wrapping: nowDay > startDay should return true')
106109

107-
t.true(isWeekend('607-020:America/New_York'), 'After start hour')
108-
t.true(isWeekend('520-608:America/New_York'), 'Before end hour')
110+
t.true(isWeekendNow('607-020:America/New_York'), 'After start hour')
111+
t.true(isWeekendNow('520-608:America/New_York'), 'Before end hour')
109112

110-
t.false(isWeekend('620-607:America/New_York'), 'Wrapping same day: at end hour should')
113+
t.false(isWeekendNow('620-607:America/New_York'), 'Wrapping same day: at end hour should')
111114
})
112115

113-
test('isWeekend - ET - Fri to Sun 8 to 8', (t) => {
116+
test('isWeekendNow - ET - Fri to Sun 8 to 8', (t) => {
114117
// Weekend: Fri 20:00 to Sun 20:00 ET (520-020:America/New_York)
115118
const range = '520-020:America/New_York'
116119
// Thu 21:00 ET
117120
clock.setSystemTime(new Date('2024-01-05T02:00:00Z').getTime())
118-
t.false(isWeekend(range), 'Before start day')
121+
t.false(isWeekendNow(range), 'Before start day')
119122
// Fri 19:00 ET
120123
clock.setSystemTime(new Date('2024-01-06T00:00:00Z').getTime())
121-
t.false(isWeekend(range), 'On start day, before start hour')
124+
t.false(isWeekendNow(range), 'On start day, before start hour')
122125
// Fri 20:00 ET
123126
clock.setSystemTime(new Date('2024-01-06T01:00:00Z').getTime())
124-
t.true(isWeekend(range), 'On start day, at start hour')
127+
t.true(isWeekendNow(range), 'On start day, at start hour')
125128
// Fri 23:00 ET
126129
clock.setSystemTime(new Date('2024-01-06T04:00:00Z').getTime())
127-
t.true(isWeekend(range), 'On start day, after start hour')
130+
t.true(isWeekendNow(range), 'On start day, after start hour')
128131
// Sat 12:00 ET
129132
clock.setSystemTime(new Date('2024-01-06T17:00:00Z').getTime())
130-
t.true(isWeekend(range), 'Middle day (Saturday)')
133+
t.true(isWeekendNow(range), 'Middle day (Saturday)')
131134
// Sun 19:00 ET
132135
clock.setSystemTime(new Date('2024-01-08T00:00:00Z').getTime())
133-
t.true(isWeekend(range), 'On end day, before end hour')
136+
t.true(isWeekendNow(range), 'On end day, before end hour')
134137
// Sun 20:00 ET
135138
clock.setSystemTime(new Date('2024-01-08T01:00:00Z').getTime())
136-
t.false(isWeekend(range), 'On end day, at end hour')
139+
t.false(isWeekendNow(range), 'On end day, at end hour')
137140
// Sun 21:00 ET
138141
clock.setSystemTime(new Date('2024-01-08T02:00:00Z').getTime())
139-
t.false(isWeekend(range), 'On end day, after end hour')
142+
t.false(isWeekendNow(range), 'On end day, after end hour')
140143
// Mon 10:00 ET
141144
clock.setSystemTime(new Date('2024-01-08T15:00:00Z').getTime())
142-
t.false(isWeekend(range), 'After end day')
145+
t.false(isWeekendNow(range), 'After end day')
143146
})

0 commit comments

Comments
 (0)