Open jamesopti opened 4 years ago
๐ Thanks for opening this issue! ๐ท I have applied any labels matching special text in your issue.
The team will review the labels and make any necessary changes.
@eriktim any thought on whats going wrong here?
@jamesopti @fantapop the oneOf construct is far from mature here. The following changes are needed (even though the specification file is not incorrect):
oneOf
cannot be nested, so Todos
should not be an object with a field but just the oneOf
;urlValue
and urlList
must be objects with in this case only one field.Thank you for the hints here. Looking closer at the open api spec, I see that the generated typescript is more like anyOf
. It looks like oneOf
is intended to be an exclusive Or. anyOf
, however, seems to fail in the same way.
@fantapop You are right. Though anyOf
would also allow a mixture of types (e.g. two fields from type A and one field from type B). I personally favor the use case of defining union/sum types.
To fully support the exclusivity, I guess the generator should apply strict de-serialisation first.
I recently had a similar conversation with one of the maintainers of the https://github.com/lukeautry/tsoa project which generates an open api spec from typescript definitions. They are now using anyOf
as their implementation of union which I think makes sense. It's very important to me that the generated typescript types from the open api spec are compatible with the input types that generate them in the tsoa project. Some of the nuances of these types are a little over my head. @eriktim Do you agree that anyOf
would translate best to a straight typescript union? I was thinking oneOf
could be something like what's arrived at here: https://timhwang21.gitbook.io/index/programming/typescript/xor-type . Although, I'm not really seeing how TSOA would translate something like a oneOf
from their end unless some more prescriptive type or syntax was released by the typescript project or if unless there was a documented type name that could be used for that specific purpose. Regardless, it feels like getting the union definition working is a very important step in bringing this template along. I wonder if the true nature of this bug is really, how should unions work vs how should oneOf
be translated.
I've been tinkering around with this for a couple of evenings now. I was able to get something working for top level anyOf/oneOf types but there is not enough data provided by the core to build out the proper support for inline types. That happens to be most of the use case for our current spec. It looks like this outstanding PR get's most of the way if not all of the way there. https://github.com/OpenAPITools/openapi-generator/pull/3162
Hey ๐๐ป
Any new about this one? Atm open-api-generator is producing invalid Typescript for toJSON
& fromJSON
functions when oneOf
is used with enums ๐
Example code:
...
components:
schemas:
TopLvlEnum:
oneOf:
- $ref: "#/components/schemas/EnumA"
- $ref: "#/components/schemas/EnumB"
- $ref: "#/components/schemas/EnumC"
EnumA:
type: string
enum:
- optionA1
- optionA2
EnumB:
type: string
enum:
- optionB1
- optionB2
EnumC:
type: string
enum:
- optionC1
- optionC2
...
@AntunVukicevic It's not great but I utilize the post processing feature of open api generator cli to programmatically fix errors. Here is a copy of the node script I use for this purpose.
#!/usr/local/bin/node
const fs = require('fs').promises;
const path = require('path');
function escapeRegex(string) {
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
}
// prettier-ignore
const replacementsByFile = {
'models/MediaCollection.ts': [
{
source: "MediaSizeName | MediaNameFromJSON(json['media-key'])",
replacement: "json['media-key'] as MediaSizeName | MediaName",
},
{
source: "MediaSizeName | MediaNameToJSON(value.media_key)",
replacement: 'value.media_key',
},
],
'models/JobTemplateAttributes.ts': [
{
source: ".map(number | stringFromJSON)",
replacement: " as Array<number | string>",
},
{
source: ".map(number | stringToJSON)",
replacement: "",
},
]
};
async function main() {
const [, , filePath] = process.argv;
const relativePath = path.relative(
path.resolve(`${__dirname}/../src/generated/client/src/`),
filePath,
);
const fileReplacements = replacementsByFile[relativePath] || [];
if (fileReplacements.length) {
let data = await fs.readFile(filePath);
for (const { source, replacement } of fileReplacements) {
const sourceRegex = new RegExp(escapeRegex(source), 'g');
data = data.toString().replace(sourceRegex, replacement);
}
await fs.writeFile(filePath, data);
}
}
main().then(() => process.exit(0)).catch(console.error);
It's triggered by using the TS_POST_PROCESS_FILE
environment variable. Here is the package.json script entry I'm using.
"client:gen": "rm -rf ./src/generated/client && TS_POST_PROCESS_FILE='bin/postProcess.js' yarn openapi-generator-cli generate && cd ./src/generated/client/ && yarn",
@fantapop is there any progress on this? I am having similar issues.
I opened a PR trying to unblock this, it at least gives us a workaround... @eriktim @jamesopti @fantapop maybe you can take a look at #10017?
Bug Report Checklist
Description
For a property defined using
oneOf
, invalid methods are generated for<Model>FromJSONTyped
and for<Model>ToJSON
:See the
nextUrl
field below:Expected
For both of those fields, I would expect a
typeof
check to decide what to do:openapi-generator version
4.2.3
viaOpenAPI declaration file content or url
Command line used for generation
./node_modules/@openapitools/openapi-generator-cli/bin/openapi-generator generate -g typescript-fetch -i ./openapi.yaml -o .
CONFIG: -
"generateAliasAsModel": true
If
generateAliasAsModel
isfalse
(default) then the generatedTodos
model is also incorrect: