feat(api): enhance KeyMap and FieldsConfig handling for improved flexibility

- Added support for unmapped fields in `KeyMap` definitions and parsing.
- Updated `buildKeyMap` to allow aliasing keys without transport layer mappings.
- Improved parameter assignment logic to handle optional `in` mappings.
- Enhanced handling of `allowExtra` fields for more concise and robust configurations.
This commit is contained in:
2026-03-01 18:01:34 +01:00
parent ff7a67cb58
commit 846fc31190
3 changed files with 37 additions and 14 deletions

View File

@@ -152,7 +152,7 @@ type BuildUrlFn = <
url: string; url: string;
}, },
>( >(
options: Pick<TData, 'url'> & Options<TData>, options: TData & Options<TData>,
) => string; ) => string;
export type Client = CoreClient< export type Client = CoreClient<
@@ -195,7 +195,7 @@ export type Options<
RequestOptions<TResponse, ThrowOnError>, RequestOptions<TResponse, ThrowOnError>,
'body' | 'path' | 'query' | 'url' 'body' | 'path' | 'query' | 'url'
> & > &
Omit<TData, 'url'>; ([TData] extends [never] ? unknown : Omit<TData, 'url'>);
export type OptionsLegacyParser< export type OptionsLegacyParser<
TData = unknown, TData = unknown,

View File

@@ -23,6 +23,17 @@ export type Field =
*/ */
key?: string; key?: string;
map?: string; map?: string;
}
| {
/**
* Field name. This is the name we want the user to see and use.
*/
key: string;
/**
* Field mapped name. This is the name we want to use in the request.
* If `in` is omitted, `map` aliases `key` to the transport layer.
*/
map: Slot;
}; };
export interface Fields { export interface Fields {
@@ -42,10 +53,14 @@ const extraPrefixes = Object.entries(extraPrefixesMap);
type KeyMap = Map< type KeyMap = Map<
string, string,
{ | {
in: Slot; in: Slot;
map?: string; map?: string;
} }
| {
in?: never;
map: Slot;
}
>; >;
const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
@@ -61,6 +76,10 @@ const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
map: config.map, map: config.map,
}); });
} }
} else if ('key' in config) {
map.set(config.key, {
map: config.map,
});
} else if (config.args) { } else if (config.args) {
buildKeyMap(config.args, map); buildKeyMap(config.args, map);
} }
@@ -112,7 +131,9 @@ export const buildClientParams = (
if (config.key) { if (config.key) {
const field = map.get(config.key)!; const field = map.get(config.key)!;
const name = field.map || config.key; const name = field.map || config.key;
(params[field.in] as Record<string, unknown>)[name] = arg; if (field.in) {
(params[field.in] as Record<string, unknown>)[name] = arg;
}
} else { } else {
params.body = arg; params.body = arg;
} }
@@ -121,8 +142,12 @@ export const buildClientParams = (
const field = map.get(key); const field = map.get(key);
if (field) { if (field) {
const name = field.map || key; if (field.in) {
(params[field.in] as Record<string, unknown>)[name] = value; const name = field.map || key;
(params[field.in] as Record<string, unknown>)[name] = value;
} else {
params[field.map] = value;
}
} else { } else {
const extra = extraPrefixes.find(([prefix]) => const extra = extraPrefixes.find(([prefix]) =>
key.startsWith(prefix), key.startsWith(prefix),
@@ -133,10 +158,8 @@ export const buildClientParams = (
(params[slot] as Record<string, unknown>)[ (params[slot] as Record<string, unknown>)[
key.slice(prefix.length) key.slice(prefix.length)
] = value; ] = value;
} else { } else if ('allowExtra' in config && config.allowExtra) {
for (const [slot, allowed] of Object.entries( for (const [slot, allowed] of Object.entries(config.allowExtra)) {
config.allowExtra ?? {},
)) {
if (allowed) { if (allowed) {
(params[slot as Slot] as Record<string, unknown>)[key] = value; (params[slot as Slot] as Record<string, unknown>)[key] = value;
break; break;

View File

@@ -8,7 +8,7 @@
* *
* For custom handler behavior, use src/mocks/handlers/overrides.ts * For custom handler behavior, use src/mocks/handlers/overrides.ts
* *
* Generated: 2025-11-26T12:21:51.098Z * Generated: 2026-03-01T17:00:19.178Z
*/ */
import { http, HttpResponse, delay } from 'msw'; import { http, HttpResponse, delay } from 'msw';