Skip to content

Commit

Permalink
Allow mapper function in map() calls to throw an error to reject the …
Browse files Browse the repository at this point in the history
…decoder
  • Loading branch information
nvie committed Aug 10, 2019
1 parent a2234c2 commit 165fa3a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
v1.16.0
-------

**New feature:**

- Allow `map()` calls to throw an exception in the mapper function to reject
the decoder. Previously, these mapper functions were not expected to ever
throw.


v1.15.0
-------

Expand Down
20 changes: 20 additions & 0 deletions src/__tests__/compose.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { annotate } from 'debrief';
import { Err, Ok } from 'lemons/Result';

import { guard } from '../guard';
import { number } from '../number';
import { string } from '../string';
import { compose, map } from '../utils';

Expand Down Expand Up @@ -44,4 +45,23 @@ describe('map', () => {
expect(upcase('123').unwrap()).toEqual('123');
expect(upcase('I am Hulk').unwrap()).toEqual('I AM HULK');
});

it('a failing mapper will fail the decoder', () => {
const odd = map(number, n => {
if (n % 2 !== 0) return n;
throw new Error('Must be odd');
});
expect(odd(13).unwrap()).toEqual(13);
expect(() => guard(odd)(4)).toThrow('^ Must be odd');
expect(odd(3).isErr()).toBe(false);
expect(odd(4).isErr()).toBe(true);

const weirdEven = map(number, n => {
if (n % 2 === 0) return n;
throw 'Must be even'; // Throwing a string, not an Error is non-conventional, but won't break anything
});
expect(weirdEven(3).isErr()).toBe(true);
expect(() => guard(weirdEven)(3)).toThrow('^ Must be even');
expect(weirdEven(4).unwrap()).toEqual(4);
});
});
8 changes: 7 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ export const isDate = (value: mixed): boolean %checks =>
export function map<T, V>(decoder: Decoder<T>, mapper: T => V): Decoder<V> {
return compose(
decoder,
x => Ok(mapper(x))
x => {
try {
return Ok(mapper(x));
} catch (e) {
return Err(annotate(x, e instanceof Error ? e.message : String(e)));
}
}
);
}

Expand Down

0 comments on commit 165fa3a

Please sign in to comment.