diff --git a/index.js b/index.js index b895c1b..5f97eca 100644 --- a/index.js +++ b/index.js @@ -251,6 +251,13 @@ }; } + // map :: Functor f => (a -⁠> b) -⁠> f a -⁠> f b + // function map(f) { + // return function(xs) { + // return Z.map (f, xs); + // }; + // } + // init :: Array a -> Array a function init(xs) { return xs.slice (0, -1); } @@ -1508,9 +1515,64 @@ //. which refers to the entire value. function validate(t) { return function(x) { + // 1. build list of prop, validate function and value object for all keys + // 2. when value = null, use MissingValue object + // 3. run all remainder validate functions for nested type validation + // 4. remove all Rights from list + // 5. concatenate $$ (in returnValue) with all Lefts + var returnValue = []; var $$Result = t.validate ([]) (x); + // 1 and 2 + // props :: Array (Either Object Object) + var props = t.keys.map (function(p) { + return x == null + ? Left ({ + error: 'MissingValue', + type: t.name || t.type, + name: p, + value: x + }) + : Right ({ + name: p, + type: t.types[p], + value: x[p] + }); + }); + + var validateRights = Z.compose (function(p) { + if (p.result.isLeft) { + if (p.name in x) { + return Left ({ + error: 'WrongValue', + // TODO: figure out what propPath really is + type: p.result.value.propPath.length > 0 + ? p.type.types[p.result.value.propPath[0]].name + : p.type.name, + name: p.name, + value: p.value + }); + } else { + return Left ({ + error: 'MissingValue', + type: p.type.name, + name: p.name, + value: p.value + }); + } + } else { + return Right (p); + } + }, function(p) { + return { + name: p.name, + result: p.type.validate ([]) (p.value), + type: p.type, + value: p.value + }; + }); + returnValue.push ( $$Result.isLeft ? Left ({ @@ -1522,43 +1584,24 @@ : $$Result ); - if (x != null && t.keys.length > 0) { - var props = t.keys; - - for (var i = 0, len = props.length; i < len; i += 1) { - var propName = props[i]; - var propValue = x[propName]; - var type = t.types[propName]; - var result = type.validate ([]) (propValue); - - if (result.isLeft) { - if (propName in x) { - returnValue.push ( - Left ({ - error: 'WrongValue', - // TODO: figure what propPath really is - type: result.value.propPath.length > 0 - ? type.types[result.value.propPath[0]].name - : type.name, - name: propName, - value: propValue - }) - ); - } else { - returnValue.push ( - Left ({ - error: 'MissingValue', - type: type.name, - name: propName, - value: propValue - }) - ); - } - } - } - } - - return returnValue; + // 3 + var tmp0 = Z.map (function(prop) { + return Z.chain (validateRights, prop); + }, props); + + // 4 + var tmp1 = Z.filter (function(either) { + return either.isLeft; + }, tmp0); + + // 5 + return Z.concat (returnValue, tmp1); + // return Z.concat ( + // returnValue, + // Z.filter ( + // either => either.isLeft, + // Z.map (prop => Z.map (validateRights, prop), props)) + // ); }; } diff --git a/test/index.js b/test/index.js index 52aba7b..e936f05 100644 --- a/test/index.js +++ b/test/index.js @@ -3898,42 +3898,50 @@ suite ('validate', () => { // null is not a member of ‘FooBar’ eq ($.validate (FooBar) (null)) - ([Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': null})]); + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': null}), + Left ({'error': 'MissingValue', 'name': 'bar', 'type': 'FooBar', 'value': null}), + Left ({'error': 'MissingValue', 'name': 'foo', 'type': 'FooBar', 'value': null}), + ]); // undefined is not a member of ‘FooBar’ eq ($.validate (FooBar) (undefined)) - ([Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': undefined})]); + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': undefined}), + Left ({'error': 'MissingValue', 'name': 'bar', 'type': 'FooBar', 'value': undefined}), + Left ({'error': 'MissingValue', 'name': 'foo', 'type': 'FooBar', 'value': undefined}), + ]); // ''bar' field is missing', ''foo' field is missing' eq ($.validate (FooBar) ({})) - ([ - Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {}}), - Left ({'error': 'MissingValue', 'name': 'bar', 'type': 'Number', 'value': undefined}), - Left ({'error': 'MissingValue', 'name': 'foo', 'type': 'String', 'value': undefined}), - ]); + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {}}), + Left ({'error': 'MissingValue', 'name': 'bar', 'type': 'Number', 'value': undefined}), + Left ({'error': 'MissingValue', 'name': 'foo', 'type': 'String', 'value': undefined}), + ]); // 'bar' field is missing eq ($.validate (FooBar) ({foo: null})) - ([ - Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {'foo': null}}), - Left ({'error': 'MissingValue', 'name': 'bar', 'type': 'Number', 'value': undefined}), - Left ({'error': 'WrongValue', 'name': 'foo', 'type': 'String', 'value': null}), - ]); + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {'foo': null}}), + Left ({'error': 'MissingValue', 'name': 'bar', 'type': 'Number', 'value': undefined}), + Left ({'error': 'WrongValue', 'name': 'foo', 'type': 'String', 'value': null}), + ]); // Value of 'bar' field, null, is not a member of ‘Number’ eq ($.validate (FooBar) ({foo: null, bar: null})) - ([ - Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {'bar': null, 'foo': null}}), - Left ({'error': 'WrongValue', 'name': 'bar', 'type': 'Number', 'value': null}), - Left ({'error': 'WrongValue', 'name': 'foo', 'type': 'String', 'value': null}), - ]); + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {'bar': null, 'foo': null}}), + Left ({'error': 'WrongValue', 'name': 'bar', 'type': 'Number', 'value': null}), + Left ({'error': 'WrongValue', 'name': 'foo', 'type': 'String', 'value': null}), + ]); // Value of 'foo' field, null, is not a member of ‘String’ eq ($.validate (FooBar) ({foo: null, bar: 42})) - ([ - Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {'bar': 42, 'foo': null}}), - Left ({'error': 'WrongValue', 'name': 'foo', 'type': 'String', 'value': null}), - ]); + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'FooBar', 'value': {'bar': 42, 'foo': null}}), + Left ({'error': 'WrongValue', 'name': 'foo', 'type': 'String', 'value': null}), + ]); eq ($.validate (FooBar) ({foo: 'blue', bar: 42})) ([Right ({foo: 'blue', bar: 42})]); @@ -3968,6 +3976,13 @@ suite ('validate', () => { Left ({'error': 'WrongValue', 'name': 'date', 'type': 'DateIso', 'value': '2020-04-100'}), ]); + eq ($.validate (model2) (undefined)) + ([ + Left ({'error': 'WrongValue', 'name': '$$', 'type': 'RECORD', 'value': undefined}), + Left ({'error': 'MissingValue', 'name': 'date', 'type': 'RECORD', 'value': undefined}), + Left ({'error': 'MissingValue', 'name': 'bool', 'type': 'RECORD', 'value': undefined}), + ]); + eq ($.validate (model2) ({bool: 'foobar', date: '2020-04-100'})) ([ Left ({'error': 'WrongValue', 'name': '$$', 'type': 'RECORD', 'value': {'bool': 'foobar', 'date': '2020-04-100'}}),