Skip to content

Commit

Permalink
fix(openapi): support additionalProperties
Browse files Browse the repository at this point in the history
  • Loading branch information
solufa committed Apr 30, 2020
1 parent 51dbba1 commit 11c14ee
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 41 deletions.
59 changes: 30 additions & 29 deletions packages/openapi2aspida/samples/swagger/$api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { Methods as Methods0 } from './pet/index'
import { Methods as Methods1 } from './pet/_petId/index'
import { Methods as Methods2 } from './pet/_petId/uploadImage'
import { Methods as Methods3 } from './pet/findByStatus'
import { Methods as Methods4 } from './store/order/index'
import { Methods as Methods5 } from './store/order/_orderId'
import { Methods as Methods6 } from './user/index'
import { Methods as Methods7 } from './user/_username'
import { Methods as Methods8 } from './user/createWithArray'
import { Methods as Methods9 } from './user/createWithList'
import { Methods as Methods10 } from './user/login'
import { Methods as Methods4 } from './store/inventory'
import { Methods as Methods5 } from './store/order/index'
import { Methods as Methods6 } from './store/order/_orderId'
import { Methods as Methods7 } from './user/index'
import { Methods as Methods8 } from './user/_username'
import { Methods as Methods9 } from './user/createWithArray'
import { Methods as Methods10 } from './user/createWithList'
import { Methods as Methods11 } from './user/login'

const api = <T>(client: AspidaClient<T>) => {
const prefix = (client.baseURL === undefined ? 'https://petstore.swagger.io/v2' : client.baseURL).replace(/\/$/, '')
Expand Down Expand Up @@ -55,69 +56,69 @@ const api = <T>(client: AspidaClient<T>) => {
store: {
inventory: {
get: (option?: { config?: T }) =>
client.fetch<void>(prefix, '/store/inventory', 'GET', option).send(),
client.fetch<Methods4['get']['resBody']>(prefix, '/store/inventory', 'GET', option).json(),
$get: async (option?: { config?: T }) =>
(await client.fetch<void>(prefix, '/store/inventory', 'GET', option).send()).data
(await client.fetch<Methods4['get']['resBody']>(prefix, '/store/inventory', 'GET', option).json()).data
},
order: {
_orderId: (val1: number | string) => ({
get: (option?: { config?: T }) =>
client.fetch<Methods5['get']['resBody']>(prefix, `/store/order/${val1}`, 'GET', option).json(),
client.fetch<Methods6['get']['resBody']>(prefix, `/store/order/${val1}`, 'GET', option).json(),
$get: async (option?: { config?: T }) =>
(await client.fetch<Methods5['get']['resBody']>(prefix, `/store/order/${val1}`, 'GET', option).json()).data,
(await client.fetch<Methods6['get']['resBody']>(prefix, `/store/order/${val1}`, 'GET', option).json()).data,
delete: (option?: { config?: T }) =>
client.fetch<void>(prefix, `/store/order/${val1}`, 'DELETE', option).send(),
$delete: async (option?: { config?: T }) =>
(await client.fetch<void>(prefix, `/store/order/${val1}`, 'DELETE', option).send()).data
}),
post: (option: { data: Methods4['post']['reqBody'], config?: T }) =>
client.fetch<Methods4['post']['resBody']>(prefix, '/store/order', 'POST', option).json(),
$post: async (option: { data: Methods4['post']['reqBody'], config?: T }) =>
(await client.fetch<Methods4['post']['resBody']>(prefix, '/store/order', 'POST', option).json()).data
post: (option: { data: Methods5['post']['reqBody'], config?: T }) =>
client.fetch<Methods5['post']['resBody']>(prefix, '/store/order', 'POST', option).json(),
$post: async (option: { data: Methods5['post']['reqBody'], config?: T }) =>
(await client.fetch<Methods5['post']['resBody']>(prefix, '/store/order', 'POST', option).json()).data
}
},
user: {
_username: (val2: number | string) => ({
get: (option?: { config?: T }) =>
client.fetch<Methods7['get']['resBody']>(prefix, `/user/${val2}`, 'GET', option).json(),
client.fetch<Methods8['get']['resBody']>(prefix, `/user/${val2}`, 'GET', option).json(),
$get: async (option?: { config?: T }) =>
(await client.fetch<Methods7['get']['resBody']>(prefix, `/user/${val2}`, 'GET', option).json()).data,
put: (option: { data: Methods7['put']['reqBody'], config?: T }) =>
(await client.fetch<Methods8['get']['resBody']>(prefix, `/user/${val2}`, 'GET', option).json()).data,
put: (option: { data: Methods8['put']['reqBody'], config?: T }) =>
client.fetch<void>(prefix, `/user/${val2}`, 'PUT', option).send(),
$put: async (option: { data: Methods7['put']['reqBody'], config?: T }) =>
$put: async (option: { data: Methods8['put']['reqBody'], config?: T }) =>
(await client.fetch<void>(prefix, `/user/${val2}`, 'PUT', option).send()).data,
delete: (option?: { config?: T }) =>
client.fetch<void>(prefix, `/user/${val2}`, 'DELETE', option).send(),
$delete: async (option?: { config?: T }) =>
(await client.fetch<void>(prefix, `/user/${val2}`, 'DELETE', option).send()).data
}),
createWithArray: {
post: (option: { data: Methods8['post']['reqBody'], config?: T }) =>
post: (option: { data: Methods9['post']['reqBody'], config?: T }) =>
client.fetch<void>(prefix, '/user/createWithArray', 'POST', option).send(),
$post: async (option: { data: Methods8['post']['reqBody'], config?: T }) =>
$post: async (option: { data: Methods9['post']['reqBody'], config?: T }) =>
(await client.fetch<void>(prefix, '/user/createWithArray', 'POST', option).send()).data
},
createWithList: {
post: (option: { data: Methods9['post']['reqBody'], config?: T }) =>
post: (option: { data: Methods10['post']['reqBody'], config?: T }) =>
client.fetch<void>(prefix, '/user/createWithList', 'POST', option).send(),
$post: async (option: { data: Methods9['post']['reqBody'], config?: T }) =>
$post: async (option: { data: Methods10['post']['reqBody'], config?: T }) =>
(await client.fetch<void>(prefix, '/user/createWithList', 'POST', option).send()).data
},
login: {
get: (option: { query: Methods10['get']['query'], config?: T }) =>
client.fetch<Methods10['get']['resBody'], Methods10['get']['resHeaders']>(prefix, '/user/login', 'GET', option).text(),
$get: async (option: { query: Methods10['get']['query'], config?: T }) =>
(await client.fetch<Methods10['get']['resBody'], Methods10['get']['resHeaders']>(prefix, '/user/login', 'GET', option).text()).data
get: (option: { query: Methods11['get']['query'], config?: T }) =>
client.fetch<Methods11['get']['resBody'], Methods11['get']['resHeaders']>(prefix, '/user/login', 'GET', option).text(),
$get: async (option: { query: Methods11['get']['query'], config?: T }) =>
(await client.fetch<Methods11['get']['resBody'], Methods11['get']['resHeaders']>(prefix, '/user/login', 'GET', option).text()).data
},
logout: {
get: (option?: { config?: T }) =>
client.fetch<void>(prefix, '/user/logout', 'GET', option).send(),
$get: async (option?: { config?: T }) =>
(await client.fetch<void>(prefix, '/user/logout', 'GET', option).send()).data
},
post: (option: { data: Methods6['post']['reqBody'], config?: T }) =>
post: (option: { data: Methods7['post']['reqBody'], config?: T }) =>
client.fetch<void>(prefix, '/user', 'POST', option).send(),
$post: async (option: { data: Methods6['post']['reqBody'], config?: T }) =>
$post: async (option: { data: Methods7['post']['reqBody'], config?: T }) =>
(await client.fetch<void>(prefix, '/user', 'POST', option).send()).data
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/openapi2aspida/samples/swagger/store/inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
import { mockMethods } from 'aspida-mock'
export type Methods = {
get: {
resBody: {
[key: string]: number
}
}
}

export default mockMethods<Methods>({
get: () => ({ status: 200 })
get: () => ({ status: 200, resBody: { foo: 1 } })
})
41 changes: 31 additions & 10 deletions packages/openapi2aspida/src/builderUtils/converters.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-use-before-define */
import { OpenAPIV3 } from 'openapi-types'
import { Prop, PropValue } from './props2String'

Expand Down Expand Up @@ -40,23 +40,23 @@ export const getPropertyName = (name: string) =>

const of2Values = (obj: OpenAPIV3.SchemaObject): PropValue[] | null => {
const values = (obj.oneOf || obj.allOf || [])
// eslint-disable-next-line @typescript-eslint/no-use-before-define
.map(p => schema2value(p))
.filter(v => v) as PropValue[]
return values.length ? values : null
}

const object2value = (obj: OpenAPIV3.NonArraySchemaObject): Prop[] | null => {
if (!obj.properties) return null
export const ADDITIONAL_NAME = '[key: string]'

const value = Object.keys(obj.properties)
const object2value = (obj: OpenAPIV3.NonArraySchemaObject): Prop[] => {
const properties = obj.properties ?? {}

const value = Object.keys(properties)
.filter(name => {
const target = obj.properties![name]
const target = properties[name]
return isRefObject(target) || !target.deprecated
})
.map<Prop | null>(name => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const val = schema2value(obj.properties![name])
const val = schema2value(properties[name])
if (!val) return null

return {
Expand All @@ -68,7 +68,28 @@ const object2value = (obj: OpenAPIV3.NonArraySchemaObject): Prop[] | null => {
})
.filter(v => v) as Prop[]

return value.length ? value : null
const additionalProps = obj.additionalProperties
if (additionalProps) {
const val =
additionalProps === true
? {
isArray: false,
isEnum: false,
isOneOf: false,
value: 'any'
}
: schema2value(additionalProps)

if (val)
value.push({
name: ADDITIONAL_NAME,
required: true,
isOneOf: false,
values: [val]
})
}

return value
}

export const schema2value = (
Expand All @@ -92,7 +113,7 @@ export const schema2value = (
} else if (isArraySchema(schema)) {
isArray = true
value = schema2value(schema.items)
} else if (schema.properties) {
} else if (schema.properties || schema.additionalProperties) {
value = object2value(schema)
} else if (schema.format === 'binary') {
value = 'ArrayBuffer'
Expand Down
13 changes: 12 additions & 1 deletion packages/openapi2aspida/src/builderUtils/methods2MockString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
import { Prop, PropValue } from './props2String'
import { Parameter } from './parameters2Props'
import { Schema } from './schemas2Props'
import { ADDITIONAL_NAME } from './converters'

const primitive2String = (p: string) =>
(({
any: "'bar'",
ArrayBuffer: 'new ArrayBuffer(32)',
number: '1',
string: "'a'",
Expand Down Expand Up @@ -33,7 +35,16 @@ const resolveTypes = (t: string, params: Parameter[], schemas: Schema[]): string
}
}
const props2String = (ps: Prop[], params: Parameter[], schemas: Schema[]) =>
`{ ${ps.map(p => `${p.name}: ${value2String(p.values[0], params, schemas)}`).join(', ')} }`
`{ ${ps
.map(
p =>
`${p.name === ADDITIONAL_NAME ? 'foo' : p.name}: ${value2String(
p.values[0],
params,
schemas
)}`
)
.join(', ')} }`
const allOf2String = (vs: PropValue[], params: Parameter[], schemas: Schema[]) =>
`{ ${vs
.map(
Expand Down

0 comments on commit 11c14ee

Please sign in to comment.