ts-json-schema-generator icon indicating copy to clipboard operation
ts-json-schema-generator copied to clipboard

Incorrect output for intersection of records with the same property

Open GrantGryczan opened this issue 3 years ago • 12 comments

This

type Schema = {
    a: {
        b: any
    }
} & {
    a: {
        c: any
    }
};

yields this:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$ref": "#/definitions/Schema",
    "definitions": {
        "Schema": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "a": {
                    "type": "object",
                    "properties": {
                        "b": {}
                    },
                    "required": [
                        "b"
                    ],
                    "additionalProperties": false
                }
            },
            "required": [
                "a"
            ]
        }
    }
}

The c property is missing.

GrantGryczan avatar Nov 24 '21 01:11 GrantGryczan

Looks like we are not recursively merging key types here. Good catch. Do you want to take a stab at a pull request?

domoritz avatar Nov 24 '21 02:11 domoritz

Frankly, if I were to try to fix this myself, I don't know where I'd begin to look, nor what I'd do once I find what I'm looking for. I'm not in the slightest familiar with how this package works.

GrantGryczan avatar Nov 24 '21 03:11 GrantGryczan

Basically, the library consists of a parser stage and then a generator stage. One starting point could be the intersection node parser https://github.com/vega/ts-json-schema-generator/blob/next/src/NodeParser/IntersectionNodeParser.ts.

What I would do is create a failing test case, debug the test case, and step through the code. https://astexplorer.net/ is great for understanding what type of AST node you have and where to put a breakpoint.

Screen Shot 2021-11-23 at 22 31 38

domoritz avatar Nov 24 '21 03:11 domoritz

Thanks! I'll take a look when I can.

GrantGryczan avatar Nov 24 '21 03:11 GrantGryczan

I've definitely found the cause of the issue. It's in https://github.com/vega/ts-json-schema-generator/blob/next/src/Utils/deepMerge.ts. This screenshot alone should have all of the information necessary to see what's wrong.

image

Based on the values of the variables on the left sidebar, you can see the loop is just going to end and the entire function will return a shallow clone of b in this case, leaving the contents of a completely unused.

I don't really know where to go from here since I don't understand what the intention, scope, or usage of deepMerge is supposed to be. It clearly isn't meant to be just a function that deep-merges two arbitrary objects. Either that or there was a huge mistake in its implementation, because it doesn't do any deep merging at all--only shallow merging on line 18.

In fact, the function isn't even called recursively under any circumstance. Though I did find this old commit which removed functionality in which it was. And what do you know, I downloaded the repo from before that commit, and this issue doesn't occur in it (though the output is different in other ways, as you would expect from a much older version of the package). After that commit, it's broken again.

Irrelevant but still worth noting: this function's comment documents an intersectArrays parameter, but no such parameter exists on the function.

GrantGryczan avatar Nov 24 '21 08:11 GrantGryczan

That same breaking commit also removed a deepMerge test for it("merges objects", ...). Not sure why. That test should probably be added again; it seems to be relevant here. (Though perhaps completely differently from the way it was before.)

https://github.com/vega/ts-json-schema-generator/blob/2a8af9c1f290916aac76aa28cc96097c32ee5fa4/test/unit/deepMerge.test.ts#L39-L52

GrantGryczan avatar Nov 24 '21 09:11 GrantGryczan

Nice find. Of course I don't remember what I was thinking two years ago. I think I was fixing something around enums.

Let's try bringing the deep merge logic back.

domoritz avatar Nov 24 '21 14:11 domoritz

Alright! Let me know how that goes :)

GrantGryczan avatar Nov 24 '21 18:11 GrantGryczan

It's worth noting that the original version didn't merge arrays correctly, at least in this case. The required array would be empty rather than containing both "b" and "c".

GrantGryczan avatar Nov 24 '21 18:11 GrantGryczan

What's the status on this?

GrantGryczan avatar Jan 06 '22 02:01 GrantGryczan

Latest status is what's in this issue. I don't have the cycles to fix this unfortunately. Pull requests are very welcome.

domoritz avatar Jan 06 '22 02:01 domoritz

Oh okay, I asked because I was under the impression you were still trying to fix it yourself. Was wondering if you ran into complications or something.

GrantGryczan avatar Jan 06 '22 03:01 GrantGryczan