fork of hey-api/openapi-ts because I need some additional things
at main 4.0 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 = ( 106 args: ReadonlyArray<unknown>, 107 fields: FieldsConfig, 108) => { 109 const params: Params = { 110 body: {}, 111 headers: {}, 112 path: {}, 113 query: {}, 114 }; 115 116 const map = buildKeyMap(fields); 117 118 let config: FieldsConfig[number] | undefined; 119 120 for (const [index, arg] of args.entries()) { 121 if (fields[index]) { 122 config = fields[index]; 123 } 124 125 if (!config) { 126 continue; 127 } 128 129 if ('in' in config) { 130 if (config.key) { 131 const field = map.get(config.key)!; 132 const name = field.map || config.key; 133 if (field.in) { 134 (params[field.in] as Record<string, unknown>)[name] = arg; 135 } 136 } else { 137 params.body = arg; 138 } 139 } else { 140 for (const [key, value] of Object.entries(arg ?? {})) { 141 const field = map.get(key); 142 143 if (field) { 144 if (field.in) { 145 const name = field.map || key; 146 (params[field.in] as Record<string, unknown>)[name] = value; 147 } else { 148 params[field.map] = value; 149 } 150 } else { 151 const extra = extraPrefixes.find(([prefix]) => 152 key.startsWith(prefix), 153 ); 154 155 if (extra) { 156 const [prefix, slot] = extra; 157 (params[slot] as Record<string, unknown>)[ 158 key.slice(prefix.length) 159 ] = value; 160 } else if ('allowExtra' in config && config.allowExtra) { 161 for (const [slot, allowed] of Object.entries(config.allowExtra)) { 162 if (allowed) { 163 (params[slot as Slot] as Record<string, unknown>)[key] = value; 164 break; 165 } 166 } 167 } 168 } 169 } 170 } 171 } 172 173 stripEmptySlots(params); 174 175 return params; 176};