sanctuary-js / sanctuary-def

Run-time type system for JavaScript
MIT License
294 stars 23 forks source link

validate 🎁🎅 #308

Open dotnetCarpenter opened 2 years ago

dotnetCarpenter commented 2 years ago

Signature

validate :: Type -> a -> Either (Array ValidationError) a

Example

// Right (undefined)
const valid   = $.validate ($.Undefined) (undefined);

// Left ([{"error": "WrongValue", "name": "$$", "type": "Undefined", "value": 1}])
const invalid = $.validate ($.Undefined) (1);

Task before merge

Description

Takes a type, and any value. Returns Right a if the value is a member of the type; Left (Array ValidationError) for each property that is invalid. The first index in a Left array is always named $$, which refers to the entire value.

Custom Type Example

//    $DateIso :: NullaryType
const $DateIso = (
  $.NullaryType ('DateIso')
                ('https://www.w3.org/QA/Tips/iso-date')
                ([$.String])
                (x => /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2]\d|3[0-1])$/.test (x))
);

const model = $.RecordType ({
  date: $.NonEmpty ($DateIso),
  bool: $.Boolean,
});

// Right ({"bool": false, "date": "2020-04-10"})
const valid   = $.validate (model) ({date: '2020-04-10', bool: false});

/* Left ([
  {"error": "WrongValue", "name": "$$", "type": "RECORD", "value": {"bool": "foobar", "date": "2020-04-100"}},
  {"error": "WrongValue", "name": "date", "type": "DateIso", "value": "2020-04-100"},
  {"error": "WrongValue", "name": "bool", "type": "Boolean", "value": "foobar"}
]) */
const invalid = $.validate (model) ({date: '2020-04-100', bool: 'foobar'});

/* Left ([
  {"error": "WrongValue", "name": "$$", "type": "RECORD", "value": {"bool": false}},
  {"error": "MissingValue", "name": "date", "type": "NonEmpty", "value": undefined}
]) */
const invalid = $.validate (model) ({bool: false});

Ref: https://github.com/sanctuary-js/sanctuary-def/issues/274

dotnetCarpenter commented 2 years ago

Since a value can have 3 distinct outcomes, I think that it would make the code more readable to encode that as a sum type.

  1. Right a A value is correct.
  2. Left MissingValue Property is missing on the value.
  3. Left WrongValue Value is wrong or property value on the value is wrong.

@davidchambers How do you feel about requiring daggy in sanctuary-def? I haven't done anything with daggy yet and won't try if you don't feel it should be a dependency of sanctuary-def.

dotnetCarpenter commented 2 years ago

There is plenty of room for optimization but before I do any of that, I want to create a simple form validation example using the new $.validate.

@davidchambers I really need you help to understand propPath. I might also need your help with sanctuary-benchmark. I looked at it before for https://github.com/dotnetCarpenter/express-mime-sniff but was not able to get anything working.