Skip to content

Commit

Permalink
Fix empty error branches in complex either expressions
Browse files Browse the repository at this point in the history
Fixes #83
  • Loading branch information
nvie committed Jun 11, 2018
1 parent b8cd56f commit af267b1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 7 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
v1.8.2
------
**Improved error reporting:**

- Fix bug where empty error branches could be shown in complex either
expressions (fixes #83)


v1.8.1
------
- Fix: revert accidentally emitting $ReadOnlyArray types in array decoders
Expand Down
39 changes: 33 additions & 6 deletions src/__tests__/either.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,56 @@ import { constant, undefined_ } from '../constants';
import { either, either4, either9 } from '../either';
import { guard } from '../guard';
import { number } from '../number';
import { string } from '../string';
import { object } from '../object';
import { regex, string } from '../string';
import { INPUTS } from './fixtures';

describe('either', () => {
const decoder = guard(either(string, boolean));
const stringOrBooleanDecoder = guard(either(string, boolean));
const [okay, not_okay] = partition(INPUTS, x => typeof x === 'string' || typeof x === 'boolean');

it('valid', () => {
expect(okay.length).not.toBe(0);
for (const value of okay) {
expect(decoder(value)).toBe(value);
expect(stringOrBooleanDecoder(value)).toBe(value);
}
});

it('invalid', () => {
expect(not_okay.length).not.toBe(0);
for (const value of not_okay) {
expect(() => decoder(value)).toThrow();
expect(() => stringOrBooleanDecoder(value)).toThrow();
}
});

it('errors nicely', () => {
expect(() => decoder(42)).toThrow('Either:');
it('errors nicely in trivial eithers', () => {
expect(() => stringOrBooleanDecoder(42)).toThrow('Either:');
});

it('errors nicely in common, simple eithers (ie optional)', () => {
// Either undefined or string
const g1 = guard(either(undefined_, string));
expect(() => g1(42)).toThrow('Either:');
expect(() => g1({})).toThrow('Either:');

// Either undefined or object
const g2 = guard(either(undefined_, object({ name: string })));
expect(() => g2(42)).toThrow('Either:');
expect(() => g2({ name: 42 })).toThrow('Either');

const g3 = guard(either(regex(/1/, 'Must contain 1'), regex(/2/, 'Must contain 2')));
expect(() => g3(42)).toThrow('Either');
expect(() => g3('foobar')).toThrow('Either');
});

it.skip('errors nicely in complex eithers (with two wildly different branches)', () => {
const g = guard(either(object({ foo: string }), object({ bar: number })));
expect(() =>
g({
foo: 123,
bar: 'not a number',
})
).toThrow('XXX FIXME - this Either: error looks horrendous');
});
});

Expand Down
12 changes: 11 additions & 1 deletion src/either.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow strict

import { annotate, indent } from 'debrief';
import { summarize } from 'debrief';
import { Err, Ok } from 'lemons';

import type { Decoder, anything } from './types';
Expand All @@ -21,7 +22,16 @@ export function either<T1, T2>(d1: Decoder<T1>, d2: Decoder<T2>): Decoder<T1 | T
d2(blob).dispatch(
value2 => Ok(value2),
err2 =>
Err(annotate(blob, ['Either:', itemize(err1.annotation), itemize(err2.annotation)].join('\n')))
Err(
annotate(
blob,
[
'Either:',
itemize(summarize(err1).join('\n')),
itemize(summarize(err2).join('\n')),
].join('\n')
)
)
)
);
}
Expand Down

0 comments on commit af267b1

Please sign in to comment.