Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schema "AnyOf" generated as "anything" #17

Open
remigailard80 opened this issue Mar 22, 2022 · 10 comments
Open

Schema "AnyOf" generated as "anything" #17

remigailard80 opened this issue Mar 22, 2022 · 10 comments
Assignees
Labels
enhancement New feature or request

Comments

@remigailard80
Copy link

remigailard80 commented Mar 22, 2022

I generate a schema of this type,

export type ViewTypeReducerType =
  AdvertisementOverviewViewType.AsObject
  | ButtonTextViewType.AsObject 
  | FleaMarketOverviewViewType.AsObject
  | EventOverviewViewType.AsObject
  | GeneralBusinessOverviewViewType.AsObject
  | GeneralOverviewViewType.AsObject
  | GeneralProgressviewViewType.AsObject
  | GeneralWatchOverviewViewType.AsObject
  | ImageBannerViewType.AsObject
  | NoticeOverviewViewType.AsObject
  | PopupOverviewViewType.AsObject
  | QuestionViewType.AsObject
  | RegionCheckInViewType.AsObject

and generated stuff was

"ViewTypeReducerType": {
      "anyOf": [
        {
          "type": "object",
          "required": [
            "type"
          ],

.....

, the anyOf of objects.

and generated result on storybook was,

스크린샷 2022-03-22 오후 2 31 38

is there any method to resolve anyof schema correctly?

@remigailard80 remigailard80 changed the title Schema Bug when use "AnyOf" Schema "AnyOf" generated as "anything" Mar 22, 2022
@julrich
Copy link
Member

julrich commented Mar 22, 2022

Hey @remigailard80, will have a look at that, too! I don't think we have anyOf in the addon yet.
Do you use the Controls-addon, too? How do you handle the anyOf for that, out of curiosity? 🤔

@julrich julrich self-assigned this Mar 22, 2022
@julrich julrich added the enhancement New feature or request label Mar 22, 2022
@julrich
Copy link
Member

julrich commented Mar 22, 2022

After some first testing, anyOf should generally work, we have one case here:

grafik
https://www.kickstartds.com/storybook/?path=/story/base-section--inhaltsboxen

Could you post a slightly bigger excerpt of the anyOf you're using? The example above looks like this in our code:

    "content": {
      "type": "array",
      "items": {
        "anyOf": [
          {
            "$ref": "http://frontend.ruhmesmeile.com/content/organisms/quotes-slider.schema.json"
          },
          {
            "$ref": "http://frontend.ruhmesmeile.com/base/atoms/link-button.schema.json"
          },
          ...
        ]
      }
    },

And those $refs get inlined by json-schema-ref-parser before being put into the viewer.

@remigailard80
Copy link
Author

remigailard80 commented Mar 22, 2022

I think I found the problem,
In the anyOf elements,

{
  "$ref": "#/definitions/QuestionViewType.AsObject"
},

was the problem. If I delete that element from the anyOf array, it parsed correctly as

anyOf [object, object, object , ... ]

@remigailard80
Copy link
Author

Hey @remigailard80, will have a look at that, too! I don't think we have anyOf in the addon yet.
Do you use the Controls-addon, too? How do you handle the anyOf for that, out of curiosity? 🤔

using Controls-addon .

@julrich
Copy link
Member

julrich commented Mar 22, 2022

I think I found the problem, In the anyOf elements,

{
  "$ref": "#/definitions/QuestionViewType.AsObject"
},

was the problem. If I delete that element from the anyOf array, it parsed correctly as

anyOf [object, object, object , ... ]

That's really interesting. Because it hints at the problem, I think! Because I don't know how those inline $refs are handled actually. Have you tried just removing all $refs by running json-schema-ref-parser over it? 🤔 That should eliminate the problem entirely!

About controls-addon: How do you handle the anyOf there? I guess it's just a JSON field in the controls, right?

@remigailard80
Copy link
Author

I use json-schema-ref-parser and remove almost all of $ref but,

{
  "QuestionViewDataType": {
      "$ref": "#/definitions/QuestionViewType.Data.AsObject"
    },
    "QuestionViewType.Data.AsObject": {
      "type": "object",
      "properties": {
        "question": {
          "$ref": "#/definitions/QuestionViewType.Question.AsObject"
        }
      },
      "additionalProperties": false
    },
    "QuestionViewType.Question.AsObject": {
      "type": "object",
      "properties": {
        "id": {
          "type": "number"
        },
        "content": {
          "type": "string"
        },
        "kind": {
          "type": "number",
          "enum": [
            0,
            1,
            2,
            3
          ]
        },
        "negativeButtonText": {
          "type": "string"
        },
        "positiveButtonText": {
          "type": "string"
        },
        "androidTargetUri": {
          "type": "string"
        },
        "iosTargetUri": {
          "type": "string"
        },
        "questions": {
          "$ref": "#/definitions/QuestionViewType.Question.AsObject"
        }
      },
      "required": [
        "id",
        "content",
        "kind",
        "negativeButtonText",
        "positiveButtonText",
        "androidTargetUri",
        "iosTargetUri"
      ],
      "additionalProperties": false
    },
    "QuestionViewType.KindType": {
      "type": "number",
      "enum": [
        0,
        1,
        2,
        3
      ]
    }
  }
  }

because of this schema's circular ref, I added circular: "ignore" option.

this is my schema generator for json-schema-ref-parser

const $RefParser = require('@apidevtools/json-schema-ref-parser');
const schema = require('./schema.json');

// safely handles circular references
JSON.safeStringify = (obj, indent = 2) => {
    let cache = []; // circular references
    const retVal = JSON.stringify(
      obj,
        (key, value) => {
            return typeof value === "object" && value !== null
              ? cache.includes(value)
                ? value // Duplicate reference found, discard key
                : cache.push(value) && value // Store value in our collection
                    : value
        },
      indent
    );
    cache = null;
    return retVal;
};

$RefParser.dereference(schema, {
    continueOnError: true,
    resolve: {
        external: true
    },
    dereference: {
        circular: "ignore"
    }
}).then(res => console.log(JSON.safeStringify(res)))

that's the reason why there remains $ref, as i think.

About controls-addon: How do you handle the anyOf there? I guess it's just a JSON field in the controls, right?

right.

@julrich
Copy link
Member

julrich commented Mar 22, 2022

Could you keep those definitions in the file? (e.g. #/definitions/QuestionViewType.Data.AsObject)
Or did you just cut them manually, to make the snippet shorter? 🤔

Maybe it would just work, if you'd have those inline $refs only?

Alternatively you could replace those remaining $refs manually, in an additional processing pass. I know we're using https://github.com/epoberezkin/json-schema-traverse in some places to do similar stuff.
You could traverse the whole schema, before putting it into the addon, and just watch for the $ref and replace it manually!

Edit: I think if it really is recursive, and needs to be displayed as such, it could get challenging!

@remigailard80
Copy link
Author

Uploaded snippet is part of my schema(too long), so i cut them manually, which caused problem.

Maybe it would just work, if you'd have those inline $refs only?

is this meaning it is enough to work if there's inline $refs only ? Because I'm not good at English, so I may have misunderstood that phrase.

If I understood correctly, that cause some issue on storybook like,

스크린샷 2022-03-23 오후 2 15 07

the question field should [object] that linked to QuestionViewType.Question.AsObject, but appears anything.

As you suggested, I think �I should use json-schema-traverse to achieve my purpose.

@julrich
Copy link
Member

julrich commented Mar 23, 2022

You could give it a try, yeah! Let me know if it works!

And maybe the following snippet could help you:

const addExplicitAnyOfs = (schemaJson: JSONSchema7, schemaAnyOfs: JSONSchema7[]) => {
  traverse(schemaJson, {
    cb: (schema, pointer, rootSchema) => {
      if (schema.items && schema.items.anyOf) {
        const componentPath = rootSchema.$id.split('/');
        const componentType = path.basename(rootSchema.$id).split('.')[0];
        const componentName = uppercamelcase(componentType);

        schema.items.anyOf = schema.items.anyOf.map((anyOf: JSONSchema7) => {
          if (anyOf.$ref)
            return anyOf;

          const schemaName = `http://frontend.ruhmesmeile.com/${componentPath[3]}/${componentPath[4]}/${componentType}/${pointer.split('/').pop()}-${anyOf.title.replace(componentName, '').toLowerCase()}.interface.json`;
          schemaAnyOfs.push({
            $id: schemaName,
            $schema: "http://json-schema.org/draft-07/schema#",
            ...anyOf,
            definitions: schemaJson.definitions
          });
          return { $ref: schemaName };
        });
      }
    }
  });
}

It's not really doing what you need, but I think you could just modify it. This snippet takes all our anyOfs, and makes $refs out of them (e.g. { type: 'object', 'properties': { 'size': {...} } } gets turned into '$ref': 'sizeObject.schema.json'), I think you can use a similar approach to replace your recursive $ref`s.

About the inline $refs, forget that. I don't think that would really help or actually work!

@remigailard80
Copy link
Author

I'll try. thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants