You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This fixes a bug when doing nested length-constrained array generation, specifically the situation added in options > arrayLength: true > minItems: 1, maxItems: 1; minItems: 1, maxItems: 1. Without the change, the code would generate the following (note the extra layer of nesting):
[
[
string
][]
]
What went wrong in the old code? I think the main issue is that itemType could either be the actual item type, or the type of the entire array (in the case of a tuple). In the problematic nesting situation, in the outer nesting, we run the code itemType = ts.factory.createArrayTypeNode(transformSchemaObject(schemaObject.items, options));. The call to transformSchemaObject returns [string], and then createArrayTypeNode turns it into [string][]. Finally, we go through the logic of arrayLength, which wraps that double nested array again as a singleton array, to become a triply-nested array.
This also likely fixes a situation where length-constrained arrays were not being declared as readonly when the immutable flag was set - notice the old code early-returns when computing length-constrained arrays.
The obvious first change is to stop doing itemType = ts.factory.createArrayTypeNode(transformSchemaObject(schemaObject.items, options)); completely and always just do itemType = transformSchemaObject(schemaObject.items, options);, but this runs into a problem with basic nested arrays. In the basic nested array case, in the inner run itemType is string[], which makes sense, and then we would like to in the outer run turn that it into string[][]. However, this does not happen - when computing finalType, we will skip the array-wrapping in this case, as itemType is indeed an array (it is an array because the type of the item is a nested array, but we do not know that).
Fundamentally, I think the problem is that sometimes itemType is the type of a single item in the array, and sometimes it is the entire array, and we cannot simply check whether itemType is an array/tuple or not to detect that, so in the length-unconstrained array case we added a hack that then caused problems with the nested length-constrained array case.
Hence, this diff changes things so that itemType is truly the type of the item, and hence is applicable only with arrays. Instead, we have arrayType, which is the type of the array/tuple before potentially applying immutability. In this flow of logic, for tuple types, we simply create the tuple and stop there in the arrayType computation. It is only for arrays that we compute the itemType, which is truly the type of a single item in the array. Then, for length-constrained arrays we use that itemType to generate the array, whiule for length-unconstrained arrays we simply make an array of itemType.
How to Review
The main thing is - are there additional missing tests, which would catch issues overlooked in this change? Also, the change in logic should hopefully be clearer in addition to fixing this specific problem.
(The main code is also easier to review when hiding whitespace)
Checklist
Unit tests updated
[N/A] docs/ updated (if necessary)
pnpm run update:examples run (only applicable for openapi-typescript)
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
I think#2148 should address this, but I haven't rebased it for a while.
I'll see if I can squeeze in some time this weekend to compare this PR to the older one and shepherd a solution.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
openapi-tsRelevant to the openapi-typescript library
4 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
This fixes a bug when doing nested length-constrained array generation, specifically the situation added in
options > arrayLength: true > minItems: 1, maxItems: 1; minItems: 1, maxItems: 1. Without the change, the code would generate the following (note the extra layer of nesting):What went wrong in the old code? I think the main issue is that
itemTypecould either be the actual item type, or the type of the entire array (in the case of a tuple). In the problematic nesting situation, in the outer nesting, we run the codeitemType = ts.factory.createArrayTypeNode(transformSchemaObject(schemaObject.items, options));. The call totransformSchemaObjectreturns[string], and thencreateArrayTypeNodeturns it into[string][]. Finally, we go through the logic ofarrayLength, which wraps that double nested array again as a singleton array, to become a triply-nested array.This also likely fixes a situation where length-constrained arrays were not being declared as
readonlywhen the immutable flag was set - notice the old code early-returns when computing length-constrained arrays.The obvious first change is to stop doing
itemType = ts.factory.createArrayTypeNode(transformSchemaObject(schemaObject.items, options));completely and always just doitemType = transformSchemaObject(schemaObject.items, options);, but this runs into a problem with basic nested arrays. In the basic nested array case, in the inner runitemTypeisstring[], which makes sense, and then we would like to in the outer run turn that it intostring[][]. However, this does not happen - when computingfinalType, we will skip the array-wrapping in this case, as itemType is indeed an array (it is an array because the type of the item is a nested array, but we do not know that).Fundamentally, I think the problem is that sometimes
itemTypeis the type of a single item in the array, and sometimes it is the entire array, and we cannot simply check whetheritemTypeis an array/tuple or not to detect that, so in the length-unconstrained array case we added a hack that then caused problems with the nested length-constrained array case.Hence, this diff changes things so that
itemTypeis truly the type of the item, and hence is applicable only with arrays. Instead, we havearrayType, which is the type of the array/tuple before potentially applying immutability. In this flow of logic, for tuple types, we simply create the tuple and stop there in thearrayTypecomputation. It is only for arrays that we compute theitemType, which is truly the type of a single item in the array. Then, for length-constrained arrays we use thatitemTypeto generate the array, whiule for length-unconstrained arrays we simply make an array ofitemType.How to Review
The main thing is - are there additional missing tests, which would catch issues overlooked in this change? Also, the change in logic should hopefully be clearer in addition to fixing this specific problem.
(The main code is also easier to review when hiding whitespace)
Checklist
docs/updated (if necessary)pnpm run update:examplesrun (only applicable for openapi-typescript)