Skip to content

Commit

Permalink
feat(ts-sdk): Parse dates using DateFromUnknown utility type (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
ships committed Apr 25, 2023
1 parent 43075d0 commit 1f0b08e
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
48 changes: 44 additions & 4 deletions packages/ts-sdk/src/test/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import test from 'ava'
import { UrlFromString } from '../util'
import { DateFromUnknown, UrlFromString } from '../util'
import { isRight, Either } from 'fp-ts/lib/Either'

function rightAnd<T>(e: Either<unknown, T>, validation: (res: T) => void) {
Expand Down Expand Up @@ -41,11 +41,51 @@ test('UrlFromString success cases', (t) => {

test('UrlFromString failure cases', (t) => {
const url1 = UrlFromString.decode('NOT_A_URL')
t.false(isRight(UrlFromString.decode(url1)))
t.false(isRight(url1))

const url2 = UrlFromString.decode(409)
t.false(isRight(UrlFromString.decode(url2)))
t.false(isRight(url2))

const url3 = UrlFromString.decode({})
t.false(isRight(UrlFromString.decode(url3)))
t.false(isRight(url3))
})

test('DateFromUnknown success cases', (t) => {
const d1 = DateFromUnknown.decode(new Date(0))
t.true(
rightAnd(d1, (d) => {
t.is(d.valueOf(), 0)
t.is(d.getUTCFullYear(), 1970)
t.is(DateFromUnknown.encode(d), '1970-01-01T00:00:00.000Z')
}),
)

const d2 = DateFromUnknown.decode(0)
t.true(
rightAnd(d2, (d) => {
t.is(d.valueOf(), 0)
t.is(d.getUTCFullYear(), 1970)
t.is(DateFromUnknown.encode(d), '1970-01-01T00:00:00.000Z')
}),
)

const d4 = DateFromUnknown.decode('1970-01-01T00:00:00.000Z')
t.true(
rightAnd(d4, (d) => {
t.is(d.valueOf(), 0)
t.is(d.getUTCFullYear(), 1970)
t.is(DateFromUnknown.encode(d), '1970-01-01T00:00:00.000Z')
}),
)
})

test('DateFromUnknown failure cases', (t) => {
const d1 = DateFromUnknown.decode('NOT_A_DATE')
t.false(isRight(d1))

const d2 = DateFromUnknown.decode(undefined)
t.false(isRight(d2))

const d4 = DateFromUnknown.decode({ some: 'thing' })
t.false(isRight(d4))
})
9 changes: 4 additions & 5 deletions packages/ts-sdk/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as t from 'io-ts'
import { DateFromISOString } from 'io-ts-types'
import { UrlFromString } from './util'
import { UrlFromString, DateFromUnknown } from './util'

function arrayOrOneOf(literalStrings: string[]) {
const [one, two, ...r] = literalStrings
Expand Down Expand Up @@ -87,7 +86,7 @@ export const DocmapThing = t.intersection([
t.partial({
// TODO use DateFromString for better parsing:
// https://github.com/gcanti/io-ts/blob/dedb64e05328417ecd3d87e00008d9e72130374a/index.md#custom-types
published: DateFromISOString,
published: DateFromUnknown,
id: t.string,
doi: t.string,
type: t.union([t.array(t.string), t.string]), // TODO this Type can be more specific ('web-page', 'preprint', etc)
Expand Down Expand Up @@ -137,12 +136,12 @@ export const Docmap = t.intersection([
]),
publisher: DocmapPublisher,
// TODO: required contents of these date strings,
created: DateFromISOString,
created: DateFromUnknown,
}),
t.partial({
steps: t.record(t.string, DocmapStep),
'first-step': t.string,
updated: DateFromISOString,
updated: DateFromUnknown,
}),
])

Expand Down
23 changes: 23 additions & 0 deletions packages/ts-sdk/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,26 @@ export const UrlFromString: UrlFromStringC = new t.Type<URL, string, unknown>(
),
String,
)

/** Date from Anything
*
* based on example there:
* https://github.com/gcanti/io-ts/blob/master/index.md#custom-types
*/

export type DateFromUnknownC = t.Type<Date, string, unknown>

export const DateFromUnknown: DateFromUnknownC = new t.Type<Date, string, unknown>(
'DateFromUnknown',
(input: unknown): input is Date => input instanceof Date,
(input, context) => {
if (typeof input === 'string' || typeof input === 'number' || input instanceof Date) {
const date = new Date(input)
if (!isNaN(date.getTime())) {
return t.success(date)
}
}
return t.failure(input, context, 'Invalid date-like input')
},
(date: Date) => date.toISOString(),
)

0 comments on commit 1f0b08e

Please sign in to comment.