Skip to content

Commit 556267c

Browse files
authored
Add anyOf support (#201)
1 parent 24229e9 commit 556267c

File tree

5 files changed

+686
-421
lines changed

5 files changed

+686
-421
lines changed

src/utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,17 @@ export function isObjNode(node: any): boolean {
5151
}
5252

5353
/**
54-
* Return ture if oneOf type
54+
* Return true if anyOf type
55+
*/
56+
export function isAnyOfNode(node: any): boolean {
57+
if (!isSchemaObj(node)) {
58+
return false;
59+
}
60+
return Array.isArray(node.anyOf);
61+
}
62+
63+
/**
64+
* Return true if oneOf type
5565
*/
5666
export function isOneOfNode(node: any): boolean {
5767
if (!isSchemaObj(node)) {

src/v2.ts

Lines changed: 73 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -42,102 +42,96 @@ export default function generateTypesV2(
4242
);
4343
}
4444

45-
// 1st pass: expand $refs first to reduce lookups & prevent circular refs
46-
const expandedRefs = JSON.parse(
47-
JSON.stringify(schema.definitions),
48-
(_, node) =>
49-
node && node["$ref"]
50-
? escape(
51-
`definitions['${node.$ref
52-
.replace("#/definitions/", "")
53-
.replace(/\//g, "']['")}']`
54-
) // important: use single-quotes here for JSON (you can always change w/ Prettier at the end)
55-
: node // return by default
56-
);
57-
58-
// 2nd pass: propertyMapper
45+
// propertyMapper
5946
const propertyMapped = options
60-
? propertyMapper(expandedRefs, options.propertyMapper)
61-
: expandedRefs;
47+
? propertyMapper(schema.definitions, options.propertyMapper)
48+
: schema.definitions;
6249

63-
// 3rd pass: primitives
64-
const primitives = JSON.parse(
50+
// type conversions
51+
const objectsAndArrays = JSON.parse(
6552
JSON.stringify(propertyMapped),
66-
(_, node: OpenAPI2SchemaObject) => {
53+
(_, node) => {
54+
// $ref
55+
if (node["$ref"]) {
56+
return escape(
57+
`definitions['${node.$ref
58+
.replace("#/definitions/", "")
59+
.replace(/\//g, "']['")}']`
60+
); // important: use single-quotes her
61+
}
62+
63+
// primitives
6764
if (node.type && PRIMITIVES[node.type]) {
68-
// prepend comment to each item
6965
return escape(
7066
node.enum
71-
? tsUnionOf(node.enum.map((item) => `'${item}'`))
67+
? tsUnionOf((node.enum as string[]).map((item) => `'${item}'`))
7268
: PRIMITIVES[node.type]
7369
);
7470
}
75-
return node; // return by default
76-
}
77-
);
7871

79-
// 4th pass: objects & arrays
80-
const objectsAndArrays = JSON.parse(JSON.stringify(primitives), (_, node) => {
81-
// object
82-
if (isObjNode(node)) {
83-
// handle no properties
84-
if (
85-
(!node.properties || !Object.keys(node.properties).length) &&
86-
(!node.allOf || !node.allOf.length) &&
87-
!node.additionalProperties
88-
) {
89-
return escape(`{[key: string]: any}`);
90-
}
72+
// object
73+
if (isObjNode(node)) {
74+
// handle no properties
75+
if (
76+
(!node.properties || !Object.keys(node.properties).length) &&
77+
(!node.allOf || !node.allOf.length) &&
78+
!node.additionalProperties
79+
) {
80+
return escape(`{[key: string]: any}`);
81+
}
9182

92-
// unescape properties if some have been transformed already for nested objects
93-
const properties = makeOptional(
94-
fromEntries(
95-
Object.entries(
96-
(node.properties as OpenAPI2SchemaObject["properties"]) || {}
97-
).map(([key, val]) => {
98-
if (typeof val === "string") {
99-
// try and parse as JSON to remove bad string escapes; otherwise, escape normally
100-
try {
101-
return [key, JSON.parse(val)];
102-
} catch (err) {
103-
return [key, escape(unescape(val))];
83+
// unescape properties if some have been transformed already for nested objects
84+
const properties = makeOptional(
85+
fromEntries(
86+
Object.entries(
87+
(node.properties as OpenAPI2SchemaObject["properties"]) || {}
88+
).map(([key, val]) => {
89+
if (typeof val === "string") {
90+
// try and parse as JSON to remove bad string escapes; otherwise, escape normally
91+
try {
92+
return [key, JSON.parse(val)];
93+
} catch (err) {
94+
return [key, escape(unescape(val))];
95+
}
10496
}
105-
}
106-
return [key, val];
107-
})
108-
),
109-
node.required
110-
);
97+
return [key, val];
98+
})
99+
),
100+
node.required
101+
);
111102

112-
// if additional properties, add to end of properties
113-
if (node.additionalProperties) {
114-
const addlType =
115-
typeof node.additionalProperties === "string" &&
116-
PRIMITIVES[unescape(node.additionalProperties)];
117-
properties[escape("[key: string]")] = escape(addlType || "any");
103+
// if additional properties, add to end of properties
104+
if (node.additionalProperties) {
105+
const addlType =
106+
typeof node.additionalProperties === "string" &&
107+
PRIMITIVES[unescape(node.additionalProperties)];
108+
properties[escape("[key: string]")] = escape(addlType || "any");
109+
}
110+
111+
return tsIntersectionOf([
112+
// append allOf first
113+
...(node.allOf
114+
? node.allOf.map((item: any) =>
115+
isSchemaObj(item)
116+
? JSON.stringify(makeOptional(item, node.required))
117+
: item
118+
)
119+
: []),
120+
// then properties + additionalProperties
121+
...(Object.keys(properties).length
122+
? [JSON.stringify(properties)]
123+
: []),
124+
]);
118125
}
119126

120-
return tsIntersectionOf([
121-
// append allOf first
122-
...(node.allOf
123-
? node.allOf.map((item: any) =>
124-
isSchemaObj(item)
125-
? JSON.stringify(makeOptional(item, node.required))
126-
: item
127-
)
128-
: []),
129-
// then properties + additionalProperties
130-
...(Object.keys(properties).length ? [JSON.stringify(properties)] : []),
131-
]);
132-
}
127+
// arrays
128+
if (isArrayNode(node) && typeof node.items === "string") {
129+
return escape(tsArrayOf(node.items));
130+
}
133131

134-
// arrays
135-
if (isArrayNode(node) && typeof node.items === "string") {
136-
return escape(tsArrayOf(node.items));
132+
return node; // return by default
137133
}
138-
139-
return node; // return by default
140-
});
134+
);
141135

142136
return `export interface definitions {
143137
${unescape(

0 commit comments

Comments
 (0)