From 95a2b7a74dd8f0221c9f83e4d0e7e32fd7efdbb4 Mon Sep 17 00:00:00 2001 From: ITOH <72305210+itohatweb@users.noreply.github.com> Date: Tue, 26 Jan 2021 08:44:25 +0000 Subject: [PATCH] feat(util): add camelToSnakeCase() & snakeToCamelCase() (#473) * Update utils.ts * add tests * Update utils.test.ts * void unnecessary * Apply suggestions from code review Co-authored-by: Ayyan * Update src/util/utils.ts Co-authored-by: Ayyan * Update utils.ts * remove object test * some name changes Co-authored-by: Ayyan --- src/util/utils.ts | 54 +++++++++++++++++++++++++++++ test/util/utils.test.ts | 75 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 test/util/utils.test.ts diff --git a/src/util/utils.ts b/src/util/utils.ts index a2febf9b3..1b2bb9b1f 100644 --- a/src/util/utils.ts +++ b/src/util/utils.ts @@ -60,3 +60,57 @@ export const formatImageURL = ( return `${url}.${format || (url.includes("/a_") ? "gif" : "jpg")}?size=${size}`; }; + +function camelToSnakeCase(text: string) { + return text.replace(/ID|[A-Z]/g, ($1) => { + if ($1 === "ID") return "_id"; + return `_${$1.toLowerCase()}`; + }); +} + +function snakeToCamelCase(text: string) { + return text.replace(/_id|([-_][a-z])/ig, ($1) => { + if ($1 === "_id") return "ID"; + return $1.toUpperCase().replace("_", ""); + }); +} + +function isObject(obj: unknown) { + return obj === Object(obj) && !Array.isArray(obj) && + typeof obj !== "function"; +} +// deno-lint-ignore no-explicit-any +export function camelKeysToSnakeCase(obj: Record) { + if (isObject(obj)) { + // deno-lint-ignore no-explicit-any + const convertedObject: Record = {}; + Object.keys(obj) + .forEach((key) => { + convertedObject[camelToSnakeCase(key)] = camelKeysToSnakeCase( + obj[key], + ); + }); + return convertedObject; + } else if (Array.isArray(obj)) { + obj = obj.map((element) => camelKeysToSnakeCase(element)); + } + return obj; +} + +// deno-lint-ignore no-explicit-any +export function snakeKeysToCamelCase(obj: Record) { + if (isObject(obj)) { + // deno-lint-ignore no-explicit-any + const convertedObject: Record = {}; + Object.keys(obj) + .forEach((key) => { + convertedObject[snakeToCamelCase(key)] = snakeKeysToCamelCase( + obj[key], + ); + }); + return convertedObject; + } else if (Array.isArray(obj)) { + obj = obj.map((element) => snakeKeysToCamelCase(element)); + } + return obj; +} diff --git a/test/util/utils.test.ts b/test/util/utils.test.ts new file mode 100644 index 000000000..5acfc6d5f --- /dev/null +++ b/test/util/utils.test.ts @@ -0,0 +1,75 @@ +import { + camelKeysToSnakeCase, + snakeKeysToCamelCase, +} from "../../src/util/utils.ts"; +import { assertEquals } from "../deps.ts"; + +const testSnakeObject = { + // deno-lint-ignore camelcase + hello_world: "hello_world", + // deno-lint-ignore camelcase + the_universe: { + blue_planet: { + water: "is_blue", + dirt: "isDirty", + }, + moon: { + earth_moon: { + is_round: true, + }, + other_moon: { + is_round: 0, + }, + }, + arrays: ["one_two", { moo_cow: { boo: true } }], + test_the_id: "123123123123", + }, +}; + +const testCamelObject = { + helloWorld: "hello_world", + theUniverse: { + bluePlanet: { + water: "is_blue", + dirt: "isDirty", + }, + moon: { + earthMoon: { + isRound: true, + }, + otherMoon: { + isRound: 0, + }, + }, + arrays: ["one_two", { mooCow: { boo: true } }], + testTheID: "123123123123", + }, +}; + +const someOther = { + helloWorld: 1, +}; + +const someElseOther = { + hello_world: 1, +}; + +Deno.test({ + name: "[utils] snakeKeysToCamelCase: assert convertion", + fn() { + const result = snakeKeysToCamelCase(testSnakeObject); + assertEquals(result, testCamelObject); + const resultTwo = snakeKeysToCamelCase(someOther); + assertEquals(resultTwo, someOther); + }, +}); + +Deno.test({ + name: "[utils] camelKeysToSnakeCase: assert convertion", + fn() { + const result = camelKeysToSnakeCase(testCamelObject); + assertEquals(result, testSnakeObject); + const resultTwo = camelKeysToSnakeCase(someElseOther); + assertEquals(resultTwo, someElseOther); + }, +});