fork of hey-api/openapi-ts because I need some additional things
at feat/skip-token 132 lines 3.0 kB view raw
1type Slot = 'body' | 'headers' | 'path' | 'query'; 2 3export type Field = 4 | { 5 in: Exclude<Slot, 'body'>; 6 key: string; 7 map?: string; 8 } 9 | { 10 in: Extract<Slot, 'body'>; 11 key?: string; 12 map?: string; 13 }; 14 15export interface Fields { 16 allowExtra?: Partial<Record<Slot, boolean>>; 17 args?: ReadonlyArray<Field>; 18} 19 20export type FieldsConfig = ReadonlyArray<Field | Fields>; 21 22const extraPrefixesMap: Record<string, Slot> = { 23 $body_: 'body', 24 $headers_: 'headers', 25 $path_: 'path', 26 $query_: 'query', 27}; 28const extraPrefixes = Object.entries(extraPrefixesMap); 29 30type KeyMap = Map< 31 string, 32 { 33 in: Slot; 34 map?: string | undefined; 35 } 36>; 37 38const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { 39 if (!map) { 40 map = new Map(); 41 } 42 43 for (const config of fields) { 44 if ('in' in config) { 45 if (config.key) { 46 map.set(config.key, { 47 in: config.in, 48 map: config.map, 49 }); 50 } 51 } else if (config.args) { 52 buildKeyMap(config.args, map); 53 } 54 } 55 56 return map; 57}; 58 59interface Params { 60 body: unknown; 61 headers: Record<string, unknown>; 62 path: Record<string, unknown>; 63 query: Record<string, unknown>; 64} 65 66const stripEmptySlots = (params: Params) => { 67 for (const [slot, value] of Object.entries(params)) { 68 if (value && typeof value === 'object' && !Object.keys(value).length) { 69 delete params[slot as Slot]; 70 } 71 } 72}; 73 74export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsConfig) => { 75 const params: Params = { 76 body: {}, 77 headers: {}, 78 path: {}, 79 query: {}, 80 }; 81 82 const map = buildKeyMap(fields); 83 84 let config: FieldsConfig[number] | undefined; 85 86 for (const [index, arg] of args.entries()) { 87 if (fields[index]) { 88 config = fields[index]; 89 } 90 91 if (!config) { 92 continue; 93 } 94 95 if ('in' in config) { 96 if (config.key) { 97 const field = map.get(config.key)!; 98 const name = field.map || config.key; 99 (params[field.in] as Record<string, unknown>)[name] = arg; 100 } else { 101 params.body = arg; 102 } 103 } else { 104 for (const [key, value] of Object.entries(arg ?? {})) { 105 const field = map.get(key); 106 107 if (field) { 108 const name = field.map || key; 109 (params[field.in] as Record<string, unknown>)[name] = value; 110 } else { 111 const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); 112 113 if (extra) { 114 const [prefix, slot] = extra; 115 (params[slot] as Record<string, unknown>)[key.slice(prefix.length)] = value; 116 } else { 117 for (const [slot, allowed] of Object.entries(config.allowExtra ?? {})) { 118 if (allowed) { 119 (params[slot as Slot] as Record<string, unknown>)[key] = value; 120 break; 121 } 122 } 123 } 124 } 125 } 126 } 127 } 128 129 stripEmptySlots(params); 130 131 return params; 132};