spected icon indicating copy to clipboard operation
spected copied to clipboard

Validation on the root element

Open benneq opened this issue 5 years ago • 2 comments

I want to validate a single (non-object) value, like this:

spected(
    [[ isNotEmpty, "must not be empty" ]],
    "foo"
);

I get the following error:

Uncaught TypeError: Invalid attempt to destructure non-iterable instance

Another use case would be something like this:

const obj = null; (or undefined, or anything else)
spected(
    [[ val => typeof val === 'object', "must be an object" ]],
    obj
)

Or maybe: Is object or array? (both are valid). And then apply validation either to the object, or to all elements of the array.

benneq avatar Jan 07 '19 20:01 benneq

Thanks for the feedback, will try to see how we can approach this as soon as I have some time. Should find some time this week!

busypeoples avatar Jan 08 '19 12:01 busypeoples

Thank you! :)

I guess root validation would basically just the code "within" the reduce of the validate method.

Something like this might work (pseudo code):

const validate = curry((successFn: Function, failFn: Function, spec: Object, input: Object): Object => {
  const inputFn = typeof input === 'function' ? input : (key?: string) => key ? input : input
  const input = inputFn();

  if(typeof input === 'object') {
    const keys = Object.keys(inputFn())
    return reduce((result, key) => {
      // ... just like it was before
    }
  } else {
    // here comes the code from within the `reduce` function
    // i just removed all the "key" and "...result" stuff
    // i've not tested this at all 
    const inputObj = input;
    const value = inputObj
    const predicates = spec
    if (Array.isArray(predicates)) {
      return transform(() => successFn(value), failFn, map(f => runPredicate(f, value, inputObj, key), predicates)
    } else if (typeof predicates === 'object') {
      return validate(successFn, failFn, predicates, value)
    } else if (typeof predicates === 'function') {
      const rules = predicates(value)
      return validate(successFn, failFn, rules, value)
    } else {
      return successFn([])
    }
  }
})

Btw. could you make the const inputFn line a bit better formatted? I still don't understand what it does 😆 Here's how I read it:

const inputFn = typeof input === 'function' // if input === 'function'
    ? input // then return input
    : (key?: string) => key // else if ???
    ? input // then return input
    : input // else return input

The "else if" part doesn't make sense to me. Or maybe (more likely) I'm just reading it wrong

Using this formatting, ternary operators (even nested) are really easy to read:

const res = a === null                  // if a === null
    ? 'null'                            // then return 'null'
    : typeof a === 'string'             // else if a is a string
    ? a === 'foo'                       // then check if a === 'foo'
        ? 'it is foo'                   // if that's true, return 'it is foo'
        : 'it's not foo, but a string'  // if that's not true, return this
    : 'not a string, and not null';     // else return this

// equivalent:
if(a === null) {
  return 'null'
} else if(typeof a === 'string') {
  if(a === 'foo') {
    return 'it is foo'
  } else {
    return 'it's not foo, but a string'
  }
} else {
  return 'not a string, and not null'
}

benneq avatar Jan 08 '19 12:01 benneq