Skip to content

Commit

Permalink
Merge pull request #16 from kitbagjs/wrap-map-exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
stackoverfloweth authored Mar 21, 2024
2 parents e9e3ca8 + 7b4d5dc commit e381195
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 1 deletion.
4 changes: 4 additions & 0 deletions docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Anytime `loadProfiles` is called with an import that includes anything that does
- Make sure your only exporting profiles from within map files
- Make sure each profile uses `as const satisfies Profile`

## ProfileMappingError

When the mapper is executing `map` function on a given profile, it wraps the call in a try catch. If that function throws an exception for any reason it is wrapped in a `ProfileMappingError`. This provides additional context to the end application where an error is taking place and inside of which specific profile to investigate.

## Missing types or source type never

If you hover `mapper.map` and see
Expand Down
7 changes: 6 additions & 1 deletion src/createMapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Mapper, Profile, ProfileKey, RegisteredProfile, RegisteredProfiles, ProfileNotFoundError } from '@/types'
import { ProfileMappingError } from '@/types/profileMappingError'
import { asArray } from '@/utilities'

export function createMapper(): Mapper<RegisteredProfiles> {
Expand Down Expand Up @@ -41,7 +42,11 @@ export function createMapper(): Mapper<RegisteredProfiles> {
const map: Mapper<RegisteredProfiles>['map'] = (sourceKey, source, destinationKey) => {
const profile = getProfile(sourceKey, destinationKey)

return profile.map(source)
try {
return profile.map(source)
} catch (exception) {
throw new ProfileMappingError(profile, { cause: exception })
}
}

const mapMany: Mapper<RegisteredProfiles>['mapMany'] = (sourceKey, sourceArray, destinationKey) => {
Expand Down
17 changes: 17 additions & 0 deletions src/createmapper.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect, test } from 'vitest'
import mapper from '@/index'
import { Profile } from '@/types'
import { ProfileMappingError } from '@/types/profileMappingError'

const stringToBoolean = {
sourceKey: 'string',
Expand Down Expand Up @@ -32,4 +33,20 @@ test('register works with single profile', () => {
mapper.register(singleProfile)

expect(mapper.has('foo', 'bar')).toBe(true)
})

test('when map function throws exception, wraps in ProfileMappingError', () => {
const singleProfile = {
sourceKey: 'foo',
destinationKey: 'bar',
map: () => {
throw 'not implemented'
},
} as const satisfies Profile

mapper.register(singleProfile)

const action: () => void = () => mapper.map('foo', null, 'bar')

expect(action).toThrow(ProfileMappingError)
})
7 changes: 7 additions & 0 deletions src/types/profileMappingError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Profile } from '@/types/profile'

export class ProfileMappingError extends Error {
public constructor(profile: Profile, options?: ErrorOptions) {
super(`Failed to Execute map for source "${profile.sourceKey}" and destination "${profile.destinationKey}"`, options)
}
}

0 comments on commit e381195

Please sign in to comment.