axios-case-converter
Version:
Axios transformer/interceptor that converts snake_case/camelCase
102 lines (90 loc) • 3.2 kB
text/typescript
import { camelCase as camelCaseString } from "camel-case";
import { snakeCase as snakeCaseString } from "snake-case";
import { headerCase as headerCaseString } from "header-case";
import { preserveArrayBrackets, preserveSpecificKeys } from "./decorators";
import { isFormData, isTransformable } from "./util";
import {
CreateTransform,
CreateTransformOf,
CreateTransforms,
Transformable,
Transformer,
TransformOptions,
TransformUsingCallback,
} from "./types";
const transformRecursive = (
data: unknown,
fn: Transformer,
overwrite: TransformOptions["overwrite"]
): unknown => {
if (!isTransformable(data)) {
return data;
}
/* eslint-disable no-console */
if (isFormData(data) && !data.entries) {
if (navigator.product === "ReactNative") {
console.warn(
"Be careful that FormData cannot be transformed on React Native. If you intentionally implemented, ignore this kind of warning: https://facebook.github.io/react-native/docs/debugging.html"
);
} else {
console.warn(
"You must use polyfill of FormData.prototype.entries() on Internet Explorer or Safari: https://github.com/jimmywarting/FormData"
);
}
return data;
}
/* eslint-enable no-console */
const prototype = Object.getPrototypeOf(data);
const store: Transformable = overwrite
? data
: !prototype
? Object.create(null)
: new prototype.constructor();
for (const [key, value] of prototype?.entries?.call(data) ||
Object.entries(data)) {
if (prototype?.append) {
prototype.append.call(
store,
typeof key === "string" ? fn(key) : key,
transformRecursive(value, fn, overwrite)
);
} else if (key !== "__proto__") {
store[fn(typeof key === "string" ? key : `${key}`)] = transformRecursive(
value,
fn,
overwrite
);
}
}
return store;
};
const transform: TransformUsingCallback = (data, fn, options) => {
// Backward compatibility
options = typeof options === "boolean" ? { overwrite: options } : options;
const composedFn = preserveSpecificKeys(
preserveArrayBrackets(fn),
options?.preservedKeys || []
);
return transformRecursive(data, composedFn, options?.overwrite || false);
};
export const createTransform: CreateTransform = (fn) => {
return (data, options): ReturnType<ReturnType<CreateTransform>> => {
return transform(data, fn, options);
};
};
export const snake = createTransform(snakeCaseString);
export const camel = createTransform(camelCaseString);
export const header = createTransform(headerCaseString);
export const createTransformOf: CreateTransformOf = (functionName, options) => {
const fn = options?.[functionName];
return fn ? createTransform(fn) : { snake, camel, header }[functionName];
};
export const createTransforms: CreateTransforms = (options) => {
const transforms: ReturnType<CreateTransforms> = { snake, camel, header };
const functionNames = Object.keys(transforms) as (keyof typeof transforms)[];
for (const functionName of functionNames) {
transforms[functionName] = createTransformOf(functionName, options);
}
return transforms;
};
export default transform;