kristianmandrup / schema-to-yup

Schema to Yup validation
Other
283 stars 50 forks source link

shapeConfig is always undefined #124

Closed xrutayisire closed 1 year ago

xrutayisire commented 1 year ago

Hi, first thanks for this lib :)

I'm trying to get the shapeConfig as documented here, but it's not working.

The shapeConfig is always undefined.

Moreover, I have a TypeScript error telling me that shapeConfig don't even exist in the returned object.

const shapeConfig: any
Property 'shapeConfig' does not exist on type 'ObjectSchema<{ [x: string]: AnySchema<any, any, any> | Reference<unknown> | Lazy<any, any>; }, AnyObject, TypeOfShape<{ [x: string]: AnySchema<any, any, any> | Reference<...> | Lazy<...>; }>, AssertsShape<...>>'.ts(2339)

Demo: You can check the result in the code sandbox console.

https://codesandbox.io/s/shcema-to-yup-error-1-8div5j?file=/demo.tsx

Also, less important but I had to give undefined as the third param for the buildYup method but it should not be required since you don't always pass it in your doc:

(alias) buildYup(schema: any, config: {}, parentNode: any): ObjectSchema<{
    [x: string]: AnySchema<any, any, any> | Reference<unknown> | Lazy<any, any>;
}, AnyObject, TypeOfShape<...>, AssertsShape<...>>
import buildYup
Expected 3 arguments, but got 2.ts(2554)
yup-builder.d.ts(1, 51): An argument for 'parentNode' was not provided.
kristianmandrup commented 1 year ago

I'm fixing the typescript error by setting parentNode to undefined as default value. Unfortunately typescript support was added later on.

export function buildYup(schema, config = {}, parentNode = undefined) {
  return new YupBuilder(schema, { ...config }, parentNode).yupSchema;
}

export class YupBuilder extends Base {
  constructor(schema, config = {}, parentNode = undefined) {
    super(config);
    this.init(schema, config, parentNode);
  }

  init(schema, config, parentNode = undefined) {
     // ...
  }

Regarding shapeConfig

In the yupBuilder.js the init method sets shapeConfig via propsToShape

    const name = this.getName(schema);
    const buildProperties = (
      config.buildProperties || this.buildProperties
    ).bind(this);
    const properties = buildProperties(schema, this);

    const shapeConfig = this.propsToShape({ properties, name, config });
    this.shapeConfig = shapeConfig;

propsToShape returns the shape

  propsToShape(opts = {}) {
    const shape = this.objPropsToShape(opts);
    this.objPropsShape = shape;
    this.addPropsShape = this.additionalPropsToShape(opts, shape);
    return shape;
  }

which calls objPropsToShape

  objPropsToShape({ name }) {
    const properties = {
      ...this.properties,
    };
    const keys = Object.keys(properties);
    return keys.reduce((acc, key) => {
      const value = properties[key];
      const argsObj = {
        name,
        key,
        value,
      };
      const yupSchemaEntry = this.propToYupSchemaEntry(argsObj);
      this.logInfo("propsToShape", { ...argsObj, yupSchemaEntry });
      if (yupSchemaEntry) {
        acc[key] = yupSchemaEntry;
      }
      return acc;
    }, {});
  }

Try calling these methods directly and see if you get a shape object returned. Then I will investigate why it is not set as an instance var on the builder.

kristianmandrup commented 1 year ago

The next types (generated) will not require the parent node

export function buildYup(schema: any, config?: {}, parentNode?: any): yup.ObjectSchema<{
    [x: string]: yup.AnySchema<any, any, any> | import("yup/lib/Reference").default<unknown> | import("yup/lib/Lazy").default<any, any>;
}, import("yup/lib/object").AnyObject, import("yup/lib/object").TypeOfShape<{
    [x: string]: yup.AnySchema<any, any, any> | import("yup/lib/Reference").default<unknown> | import("yup/lib/Lazy").default<any, any>;
}>, import("yup/lib/object").AssertsShape<{
    [x: string]: yup.AnySchema<any, any, any> | import("yup/lib/Reference").default<unknown> | import("yup/lib/Lazy").default<any, any>;
}>>;
export class YupBuilder extends Base {
    constructor(schema: any, config?: {}, parentNode?: any);
    init(schema: any, config: any, parentNode?: any): void;
    // ...
}
kristianmandrup commented 1 year ago

Try the latest commit from master - should fix type issues. Let me know what you find regarding shape. We should add a test case for that as well ;)

xrutayisire commented 1 year ago

Thanks!

  const shapeConfig = new YupBuilder(schema, config, undefined).propsToShape();

Demo: https://codesandbox.io/s/shcema-to-yup-error-1-fix-694bih?file=/demo.tsx

It seems that it's working! I will test this in my project :)

For the types issues it seems good! Thanks

kristianmandrup commented 1 year ago

Awesome 👍

kristianmandrup commented 1 year ago

I released 1.12.2 which now includes a reducePropToShape(acc, key, prop) method on the builder for more fine grained control and debugging etc.

xrutayisire commented 1 year ago

Thank you!

I don't see the new version in NPM yet, is that normal?

cf: https://www.npmjs.com/package/schema-to-yup

kristianmandrup commented 1 year ago

Forgot I had to do 2FA after running publish command. Should be there now.

kristianmandrup commented 1 year ago

Also updated docs to clarify this alternative approach

kristianmandrup commented 1 year ago

Btw, I've now added better class/type support for the config object as well (see Readme under typescript)