fork of hey-api/openapi-ts because I need some additional things
at feat/skip-token 169 lines 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 = (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};