kristianmandrup/schema-to-yup

Use custom methods from yup global context

Closed this issue · 7 comments

Hello,
first of all, let me thank you for a great tool.
I have not found an issue (yet) rather a missing feature.

What I am trying to do:
I have existing yup config with localization and custom methods added to various types. Now I am trying to use schema-to-yup on my json configuration coming from the backend.
While the localization set on global yup instance works fine, added methods are not recognized by the schema builder.
What I have discovered is that I can "enable" custom rules by adding "extends" or "enabled" to the config of the builder. However the implementation also needs to be provided by me and I am a bit lost on how to do it. Instead I would like to reuse existing and working methods added to the yup global instance. Is it possible currently?

I will appreciate feedback and help.
Thanks in advance,
Dominik

Should be possible. Look up shapeConfig in Readme and propToShape (or similar name) method on the YupBuilder class, which should both return. The actual Yup shape object instance which you can then extend.

See

Not that const shapeConfig = this.propsToShape({ properties, name, config }); could use a cleanup of args passed as only name is used

To override the default yup instance and provide your own instance, simply override YupBuilder getter by extending YupBuilder with your own class

  get validator() {
    return yup;
  }

https://github.com/kristianmandrup/schema-to-yup/blob/master/src/yup-builder.js#L77

I've now slightly modified it in latest commit so the yup instance can be supplied in the config. Pls let me know if that works for you.

  get validator() {
    return this.config.validator || yup;
  }

Also see

Thanks a lot for quick reply and adjustments in the code. I have tested ur change without a luck. I am sure I am missing someting. in fact I do not get the concept of a validator at all right now, what is it actually?

here are some more details of my case, I add a custom validation like these:

  import * as Yup from 'yup'
  
  Yup.addMethod(Yup.array, 'customMethod', function (args) {
    return this.test('customMethodTest', message, function (value) {
      const { path, createError } = this
      return true
    })
  })

then I can use it with yup:

Yup.object({
  // @ts-ignore
  foo: Yup.array().customMethod(),
}).validate({foo: []}) // it works

however specifying:

foo: {
  customMethod: true
  }

in my validation schema does not work. customMethod is not triggered at all.

I have naivly tried to provide whole imported Yup as validator

buildYup(schema, {
   validator: Yup,
 })

but i guess that's not how it should be done :)

could you please enlighten me a bit? I am strugling to graps key concepts used by schema-to-yup classes

Sorry, been very busy lately - work and private life. Unfortunately this functionality has not been tested so I'm not sure the validator will be passed through currently. The import * as Yup from 'yup' should give you a singleton object with the yup methods. Not sure what happens if you do two imports with different names and add methods to one of them.

import * as Yup from 'yup'
import * as Yup2 from 'yup'
Yup.addMethod(...)
// call the added method on Yup2 - is it available there? I think not
// therefore I would think they are each an independent object with a set of Yup API methods that you can extend as needed.

I have never seen this form before

however specifying:

foo: {
  customMethod: true
  }

In my validation schema does not work. customMethod is not triggered at all.

There is no built-in functionality for that currently. To support this would require you to extend the typehandler functionality using the customization options described under custom-constraint-handler-functions.

It could perhaps look something like this

const mixed = {
  yupMethodNames: ['customMethod'],
  extends: [
    "custom-yup-methods"
  },
  convert: {
    "custom-yup-methods": (th) =>
        let args = []
        for (let methName of this.config.yupMethodNames) {
           const yupCustomMeth = th.validator[methName]
           const result = yupCustomMeth(...args)
           // do something with custom Yup method result?
        }
    }
  }
}

const yupSchema = buildYup(jsonSchema, { mixed }

@kristianmandrup Hey, thanks for the answer and sorry for late reply from my side as well.
Thanks for confirming that the add method functionality is not there and thanks for the code sample. I will experiment with it.

We are using ur package in a mvp version of our product. I hope we will be able to stick to it for longer. If not then we will have to get rid of yup in order to keep our validation schema jsons. The thing which is most problematic for me right now is lack of typescript typing of schema objects. It forces me to look into docs over and over again :)

One more question If I may, is the trim supported? I have tried it in simple example but it has no effect:

{
  trim: true,
  type: 'string',
  required: true,
}

I have tried to dig into YupObject methods, like convert, but was not able to figure out if this specific detail is there without more elaborate debugging session. Could you clarify that?

The current schema model is based mostly on the JSON schema model and what you can set there and is an attempt to convert those to equivalent Yup schema. There is no direct support for specifying Yup specific attributes, methods etc. Those currently need to be added via the customization options.

I believe this is the case for trim and null able. Check mixed.js for the core schema properties supported.