fork of hey-api/openapi-ts because I need some additional things
at main 3.1 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 = ( 75 args: ReadonlyArray<unknown>, 76 fields: FieldsConfig, 77) => { 78 const params: Params = { 79 body: {}, 80 headers: {}, 81 path: {}, 82 query: {}, 83 }; 84 85 const map = buildKeyMap(fields); 86 87 let config: FieldsConfig[number] | undefined; 88 89 for (const [index, arg] of args.entries()) { 90 if (fields[index]) { 91 config = fields[index]; 92 } 93 94 if (!config) { 95 continue; 96 } 97 98 if ('in' in config) { 99 if (config.key) { 100 const field = map.get(config.key)!; 101 const name = field.map || config.key; 102 (params[field.in] as Record<string, unknown>)[name] = arg; 103 } else { 104 params.body = arg; 105 } 106 } else { 107 for (const [key, value] of Object.entries(arg ?? {})) { 108 const field = map.get(key); 109 110 if (field) { 111 const name = field.map || key; 112 (params[field.in] as Record<string, unknown>)[name] = value; 113 } else { 114 const extra = extraPrefixes.find(([prefix]) => 115 key.startsWith(prefix), 116 ); 117 118 if (extra) { 119 const [prefix, slot] = extra; 120 (params[slot] as Record<string, unknown>)[ 121 key.slice(prefix.length) 122 ] = value; 123 } else { 124 for (const [slot, allowed] of Object.entries( 125 config.allowExtra ?? {}, 126 )) { 127 if (allowed) { 128 (params[slot as Slot] as Record<string, unknown>)[key] = value; 129 break; 130 } 131 } 132 } 133 } 134 } 135 } 136 } 137 138 stripEmptySlots(params); 139 140 return params; 141};