fork of hey-api/openapi-ts because I need some additional things
at main 169 lines 3.9 kB view raw
1// This file is auto-generated by @hey-api/openapi-ts 2 3type Slot = 'body' | 'headers' | 'path' | 'query' 4 5export type Field = 6 | { 7 in: Exclude<Slot, 'body'> 8 /** 9 * Field name. This is the name we want the user to see and use. 10 */ 11 key: string 12 /** 13 * Field mapped name. This is the name we want to use in the request. 14 * If omitted, we use the same value as `key`. 15 */ 16 map?: string 17 } 18 | { 19 in: Extract<Slot, 'body'> 20 /** 21 * Key isn't required for bodies. 22 */ 23 key?: string 24 map?: string 25 } 26 | { 27 /** 28 * Field name. This is the name we want the user to see and use. 29 */ 30 key: string 31 /** 32 * Field mapped name. This is the name we want to use in the request. 33 * If `in` is omitted, `map` aliases `key` to the transport layer. 34 */ 35 map: Slot 36 } 37 38export interface Fields { 39 allowExtra?: Partial<Record<Slot, boolean>> 40 args?: ReadonlyArray<Field> 41} 42 43export type FieldsConfig = ReadonlyArray<Field | Fields> 44 45const extraPrefixesMap: Record<string, Slot> = { 46 $body_: 'body', 47 $headers_: 'headers', 48 $path_: 'path', 49 $query_: 'query' 50} 51const extraPrefixes = Object.entries(extraPrefixesMap) 52 53type KeyMap = Map< 54 string, 55 | { 56 in: Slot 57 map?: string 58 } 59 | { 60 in?: never 61 map: Slot 62 } 63> 64 65const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { 66 if (!map) { 67 map = new Map() 68 } 69 70 for (const config of fields) { 71 if ('in' in config) { 72 if (config.key) { 73 map.set(config.key, { 74 in: config.in, 75 map: config.map 76 }) 77 } 78 } else if ('key' in config) { 79 map.set(config.key, { 80 map: config.map 81 }) 82 } else if (config.args) { 83 buildKeyMap(config.args, map) 84 } 85 } 86 87 return map 88} 89 90interface Params { 91 body: unknown 92 headers: Record<string, unknown> 93 path: Record<string, unknown> 94 query: Record<string, unknown> 95} 96 97const stripEmptySlots = (params: Params) => { 98 for (const [slot, value] of Object.entries(params)) { 99 if (value && typeof value === 'object' && !Object.keys(value).length) { 100 delete params[slot as Slot] 101 } 102 } 103} 104 105export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsConfig) => { 106 const params: Params = { 107 body: {}, 108 headers: {}, 109 path: {}, 110 query: {} 111 } 112 113 const map = buildKeyMap(fields) 114 115 let config: FieldsConfig[number] | undefined 116 117 for (const [index, arg] of args.entries()) { 118 if (fields[index]) { 119 config = fields[index] 120 } 121 122 if (!config) { 123 continue 124 } 125 126 if ('in' in config) { 127 if (config.key) { 128 const field = map.get(config.key)! 129 const name = field.map || config.key 130 if (field.in) { 131 ;(params[field.in] as Record<string, unknown>)[name] = arg 132 } 133 } else { 134 params.body = arg 135 } 136 } else { 137 for (const [key, value] of Object.entries(arg ?? {})) { 138 const field = map.get(key) 139 140 if (field) { 141 if (field.in) { 142 const name = field.map || key 143 ;(params[field.in] as Record<string, unknown>)[name] = value 144 } else { 145 params[field.map] = value 146 } 147 } else { 148 const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)) 149 150 if (extra) { 151 const [prefix, slot] = extra 152 ;(params[slot] as Record<string, unknown>)[key.slice(prefix.length)] = value 153 } else if ('allowExtra' in config && config.allowExtra) { 154 for (const [slot, allowed] of Object.entries(config.allowExtra)) { 155 if (allowed) { 156 ;(params[slot as Slot] as Record<string, unknown>)[key] = value 157 break 158 } 159 } 160 } 161 } 162 } 163 } 164 } 165 166 stripEmptySlots(params) 167 168 return params 169}