Skip to content

fix: correctly handled mapped union types#2490

Open
AmadeusK525 wants to merge 4 commits into
vega:nextfrom
profusion:fix/mapped-distributed-unions
Open

fix: correctly handled mapped union types#2490
AmadeusK525 wants to merge 4 commits into
vega:nextfrom
profusion:fix/mapped-distributed-unions

Conversation

@AmadeusK525

Copy link
Copy Markdown

Mapped types may take Unions as "parameters", and, in that case, they
must distribute over each Union individually. This was wrong before, it
was creating an intersection.

This implementation handles discriminated unions as well and preserves
the potential @discriminator annotation. Non-OpenAPI discriminator
were not tested (they generate if/then schemas).

Closes #2106

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@domoritz is this change correct here? I don't have vega-lite context

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have vega-lite context either, but I took a look at the source code that was used to generate the types and the new schema is correct. It's correctly accounting for unions using anyOf instead of merging them into an object schema. Any validations that were previously passing should still pass with the new schema

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's confirm. Please clone https://github.com/vega/vega-lite, link to this version of the schema generator, generate the schema, and run npm run test. If everything still passes, we are good. Could you do that to confirm that we don't have a regression in Vega-Lite?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We previously simplified the type instead of keeping the anyOf format. Should we mark this as a breaking change?

@AmadeusK525 AmadeusK525 Mar 10, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it may be considered a breaking change, but I really don't see the gain in simplifying these Unions. I agree that allOf can be simplified into a parent merged schema, but anyOf and oneOf are good ways of representing unions (and, in my case, working with discriminated unions and validating via ajv, they're absolutely necessary).

I don't think this is a breaking change, though. It is in the sense that it changes the generated schemas by fixing them (they were wrong before), but the schemas are more correct now and if anything was previously validating but stops validating due to this change, the validation BEFORE this fix was wrong.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's a fix. Let's still make it a minor version bump, not just a patch? We might need to mark this pull request as feat: to get that behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really like to keep the simplifications where possible. Makes schemas much more readable.

@AmadeusK525 AmadeusK525 force-pushed the fix/mapped-distributed-unions branch 4 times, most recently from b887cca to fd1881e Compare March 10, 2026 16:37
The annotations from referenced types were not always preserved. Mainly,
in `preserveAnnotation`, `isAssignableTo` and `inferMap` function flows
were wrongly stripping them.
Mapped types may take Unions as "parameters", and, in that case, they
must distribute over each Union individually. This was wrong before, it
was creating an intersection.

This implementation handles discriminated unions as well and preserves
the potential `@discriminator` annotation. Non-OpenAPI `discriminator`
were not tested (they generate `if`/`then` schemas).

Closes vega#2106
This formatter was mutating the original type by deleting the
`discriminator` annotation. If the type was shared/referenced in
multiple places, this would result in the annotation being lost.
This allows for projects requiring the package from GitHub to build them
directly.
@AmadeusK525 AmadeusK525 force-pushed the fix/mapped-distributed-unions branch from fd1881e to 5a6affd Compare March 16, 2026 13:49

@domoritz domoritz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few comments. Looks good overall.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's confirm. Please clone https://github.com/vega/vega-lite, link to this version of the schema generator, generate the schema, and run npm run test. If everything still passes, we are good. Could you do that to confirm that we don't have a regression in Vega-Lite?

const annotations = type.getAnnotations();
// Copy annotations to avoid mutating the original object, which may be shared
// with other AnnotatedType instances (e.g., via preserveAnnotation).
let restAnnotations = annotations;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't actually make a copy. You could also still use annotations. The comment about not mutating is for like 66 now, I guess?

insideTypes: Set<BaseType> = new Set(),
): boolean {
// Keep original source for infer map so annotations (e.g. @discriminator) are preserved
const originalSource = source;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this is not a copy.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's a fix. Let's still make it a minor version bump, not just a patch? We might need to mark this pull request as feat: to get that behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really like to keep the simplifications where possible. Makes schemas much more readable.

@arthurfiorette arthurfiorette added the feedback Waiting for feedback resolution label Jun 18, 2026
@arthurfiorette

Copy link
Copy Markdown
Collaborator

@AmadeusK525 do you still need the fixes on this PR?

@AmadeusK525

Copy link
Copy Markdown
Author

@arthurfiorette Hey, yes I do. Sorry, a lot of stuff came up in life and I couldn't get back to this. I'll ask someone else (who is using the fork because of this feature) to try and handle this for me. Thanks for reminding me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feedback Waiting for feedback resolution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MappedTypeNodeParser doesn't take Unions into account

3 participants