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

Fix prefixItems / minItems / maxItems tuple generation #2053

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

duncanbeevers
Copy link
Contributor

@duncanbeevers duncanbeevers commented Dec 16, 2024

Changes

Closes #2048

  • Extract types generation for Array-type schemas to transformArraySchemaObject method
  • Throw error when OpenAPI items is array
  • Generate correct number of union members for minItems * maxItems unions
  • Generate readonly tuple members for minItems & maxItems unions
  • Generate readonly spread member for prefixItems tuple
  • Preserve prefixItems type members in minItems & maxItems tuples
  • Generate spread member for prefixItems tuple with no minItems / maxItems constraints
  • Add test case for error thrown when OpenAPI items is array
  • Add test case for heterogeneous item members: items: oneOf: [{ type: 'string' }, { type: 'number' }]
  • Add test cases for minItems + maxItems schema generating empty tuple, as outlined in --array-length with minItems: 1 generates empty array #2048
  • Add test cases for many combinations of arrayLength and immutable options, and prefixItems, minItems, maxItems schemas

The previous union+tuples generation implementation was a little hair-ball, and difficult for me to parse, so I replaced it with a stepped implementation, returning early with results whenever possible.

  • first returning the full min + max union-of-tuples if possible; each union member may be readonly, but not the union as a whole
  • next, returning the min tuple if possible; the tuple as a whole may be readonly, as well as its spread members.
  • finally, returning the simple array type, which may be readonly

Examples

Here's a simple schema, and the before+after generated types.

☕ minItems empty tuple

components:
  schemas:
    TwoNumbers:
      type: array
      items:
        type: number
      minItems: 1
      maxItems: 2
// Before
export interface components {
    schemas: {
        TwoNumbers: [
        ] | [
            number
        ];
    };
    

// After
export interface components {
    schemas: {
        TwoNumbers: [
            number
        ] | [
            number,
            number
        ];
    };
    

📖 readonly spread type

components:
  schemas:
    OneNumber:
      type: array
      items:
        type: number
      minItems: 1
// Before
export interface components {
    schemas: {
        readonly OneNumber: [
            number,
            ...number[]
        ];
    };
    

// After
export interface components {
    schemas: {
        readonly OneNumber: readonly [
            number,
            ...readonly number[]
        ];
    };
    

🙉 preserve prefixItems

components:
  schemas:
    WithPrefixItems:
      type: array
      items:
        type: string
      prefixItems:
        - type: string
          enum:
            - professor
        - type: string
          enum:
            - student
      minItems: 2
      maxItems: 4
// Before
export interface components {
    schemas: {
        WithPrefixItems: [
            "doctor",
            "intern"
        ];
    };
    

// After
export interface components {
    schemas: {
        WithPrefixItems: [
            "doctor",
            "intern",
            ...string[]
        ];
    };
    

The same schema with the arrayLength: true option set generates quite different types.

// Before
export interface components {
    schemas: {
        WithPrefixItems: [
        ] | [
            [
                "doctor",
                "intern"
            ]
        ] | [
            [
                "doctor",
                "intern"
            ],
            [
                "doctor",
                "intern"
            ]
        ];
    };
    

// After
export interface components {
    schemas: {
        WithPrefixItems: [
            "doctor",
            "intern"
        ] | [
            "doctor",
            "intern",
            string
        ] | [
            "doctor",
            "intern",
            string,
            string
        ];
    };
    

How to Review

  • Ensure generated schemas are all still acceptable
  • Ensure code-style is appropriate
  • Ensure newly-readonly spread member is acceptable (this may qualify as a breaking change)
  • Ensure new error behavior on OpenAPI items is array is acceptable
  • Ensure new spread behavior on prefixItems schemas is acceptable
  • Look closely at the new tests cases, and changes to old test cases, including options and schemas passed to the schema transformer
  • This PR undoes some of the work done in fix(openapi-typescript):transformSchemaObject support two-dimensional… #1489, updating its test case to use prefixItems and arrayLength in combination to generate the desired array-of-tuples

Checklist

  • Unit tests updated
  • docs/ updated (if necessary)
  • pnpm run update:examples run (only applicable for openapi-typescript)

@duncanbeevers duncanbeevers requested a review from a team as a code owner December 16, 2024 16:07
@duncanbeevers duncanbeevers requested a review from gzm0 December 16, 2024 16:07
Copy link

changeset-bot bot commented Dec 16, 2024

🦋 Changeset detected

Latest commit: 68d9191

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
openapi-typescript Major
swr-openapi Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@duncanbeevers duncanbeevers changed the title Simplify minItems / maxItems tuple generation Fix prefixItems / minItems / maxItems tuple generation Dec 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

--array-length with minItems: 1 generates empty array
1 participant