diff --git a/README.md b/README.md index 7723bac..465a5d8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A comprehensive collection of TypeScript utility functions for modern web develo ## Features -- ๐Ÿ› ๏ธ **Comprehensive**: String, object, cookie, number, validation, format, search query, device, and common utilities +- ๐Ÿ› ๏ธ **Comprehensive**: String, object, cookie, number, validation, format, search query, device, type and common utilities - ๐Ÿ“ฆ **Tree-shakable**: Import only what you need - ๐Ÿ”’ **Type-safe**: Full TypeScript support with type definitions - โšก **Lightweight**: Minimal dependencies and optimized for performance @@ -70,6 +70,8 @@ const nullCheck = commonUtil.isNull(null); // true const notNull = commonUtil.isNull("hello"); // false await commonUtil.sleep(1000); // Pauses execution for 1 second const copied = await commonUtil.copyToClipboard("Hello, World!"); // true if successful +const encoded = commonUtil.encodeBase64("Hello ํ•œ๊ธ€!"); // Base64 encoded string +const decoded = commonUtil.decodeBase64(encoded); // "Hello ํ•œ๊ธ€!" // Search Query utilities const queryParams = searchQueryUtil.getAllQuery(); // { key: ["value1", "value2"], id: "123" } @@ -125,6 +127,8 @@ const formattedPhone = formatUtil.formatPhoneNumber("01012345678"); // "010-1234 - `isNull(value: unknown): value is null` - Type guard that checks if a value is null and narrows the type - `sleep(ms: number): Promise` - Pauses execution for a specified number of milliseconds - `copyToClipboard(text: string): Promise` - Copies text to the user's clipboard. Uses modern Clipboard API with fallback to legacy execCommand method. Returns true if successful, false if failed. +- `encodeBase64(str: string, options?: { convertSpecialChars?: boolean }): string` - Encodes a string to Base64 format with optional special character handling +- `decodeBase64(str: string, options?: { convertSpecialChars?: boolean }): string` - Decodes a Base64 string back to original text with optional special character handling ### SearchQueryUtil diff --git a/package/commonUtil/decodeBase64/index.test.ts b/package/commonUtil/decodeBase64/index.test.ts new file mode 100644 index 0000000..e0cf155 --- /dev/null +++ b/package/commonUtil/decodeBase64/index.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, test } from "vitest"; +import decodeBase64 from "."; + +describe("decodeBase64 ์œ ํ‹ธ ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ", () => { + test("์ •์ƒ์ ์ธ Base64 ๋ฌธ์ž์—ด์„ ๋””์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = decodeBase64("SGVsbG8sJTIwV29ybGQh"); + expect(result).toBe("Hello, World!"); + }); + test("๋นˆ ๋ฌธ์ž์—ด์„ ๋””์ฝ”๋”ฉํ•˜๋ฉด ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = decodeBase64(""); + expect(result).toBe(""); + }); + test("ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ Base64 ๋ฌธ์ž์—ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋””์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = decodeBase64( + "ISU0MCUyMyUyNCUyNSU1RSUyNiooKV8lMkIlMkYlM0IlMkMlM0YlM0ElNDAlMjY=" + ); + expect(result).toBe("!@#$%^&*()_+/;,?:@&"); + }); + test("์œ ๋‹ˆ์ฝ”๋“œ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ Base64 ๋ฌธ์ž์—ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋””์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = decodeBase64( + "JUUzJTgxJTkzJUUzJTgyJTkzJUUzJTgxJUFCJUUzJTgxJUExJUUzJTgxJUFG" + ); + expect(result).toBe("ใ“ใ‚“ใซใกใฏ"); + }); + test("null ๋˜๋Š” undefined๋ฅผ ๋””์ฝ”๋”ฉํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค", () => { + // @ts-ignore + expect(decodeBase64(null)).toBe(null); + // @ts-ignore + expect(decodeBase64(undefined)).toBe(undefined); + }); + test("ํ•œ๊ธ€์ด ๋“ค์–ด์˜ค๋ฉด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋””์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = decodeBase64( + "JUVDJTk1JTg4JUVCJTg1JTk1JUVEJTk1JTk4JUVDJTg0JUI4JUVDJTlBJTk0" + ); + expect(result).toBe("์•ˆ๋…•ํ•˜์„ธ์š”"); + }); +}); diff --git a/package/commonUtil/decodeBase64/index.ts b/package/commonUtil/decodeBase64/index.ts new file mode 100644 index 0000000..1b46e20 --- /dev/null +++ b/package/commonUtil/decodeBase64/index.ts @@ -0,0 +1,15 @@ +interface decodeBase64Options { + convertSpecialChars?: boolean; +} + +export default function decodeBase64( + str: string, + { convertSpecialChars = true }: decodeBase64Options = {} +): string { + if (str == null) return str; + + if (convertSpecialChars) { + return decodeURIComponent(atob(str)); + } + return decodeURI(atob(str)); +} diff --git a/package/commonUtil/encodeBase64/index.test.ts b/package/commonUtil/encodeBase64/index.test.ts new file mode 100644 index 0000000..81c1087 --- /dev/null +++ b/package/commonUtil/encodeBase64/index.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, test } from "vitest"; +import encodeBase64 from "."; + +describe("encodeBase64 ์œ ํ‹ธ ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ", () => { + test("์ •์ƒ์ ์ธ ๋ฌธ์ž์—ด์„ Base64๋กœ ์ธ์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = encodeBase64("Hello, World!"); + expect(result).toBe("SGVsbG8lMkMlMjBXb3JsZCE="); + }); + test("๋นˆ ๋ฌธ์ž์—ด์„ ์ธ์ฝ”๋”ฉํ•˜๋ฉด ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = encodeBase64(""); + expect(result).toBe(""); + }); + test("ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ ๋ฌธ์ž์—ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ธ์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = encodeBase64("!@#$%^&*()_+"); + expect(result).toBe("ISU0MCUyMyUyNCUyNSU1RSUyNiooKV8lMkI="); + }); + test("์œ ๋‹ˆ์ฝ”๋“œ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ ๋ฌธ์ž์—ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ธ์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = encodeBase64("ใ“ใ‚“ใซใกใฏ"); + expect(result).toBe( + "JUUzJTgxJTkzJUUzJTgyJTkzJUUzJTgxJUFCJUUzJTgxJUExJUUzJTgxJUFG" + ); + }); + test("null ๋˜๋Š” undefined๋ฅผ ์ธ์ฝ”๋”ฉํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค", () => { + // @ts-ignore + expect(encodeBase64(null)).toBe(null); + // @ts-ignore + expect(encodeBase64(undefined)).toBe(undefined); + }); + test("ํ•œ๊ธ€์ด ๋“ค์–ด์˜ค๋ฉด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ธ์ฝ”๋”ฉํ•ด์•ผ ํ•œ๋‹ค", () => { + const result = encodeBase64("์•ˆ๋…•ํ•˜์„ธ์š”"); + expect(result).toBe( + "JUVDJTk1JTg4JUVCJTg1JTk1JUVEJTk1JTk4JUVDJTg0JUI4JUVDJTlBJTk0" + ); + }); +}); diff --git a/package/commonUtil/encodeBase64/index.ts b/package/commonUtil/encodeBase64/index.ts new file mode 100644 index 0000000..5d4a088 --- /dev/null +++ b/package/commonUtil/encodeBase64/index.ts @@ -0,0 +1,15 @@ +interface encodeBase64Options { + convertSpecialChars?: boolean; +} + +export default function encodeBase64( + str: string, + { convertSpecialChars = true }: encodeBase64Options = {} +): string { + if (str == null) return str; + + if (convertSpecialChars) { + return btoa(encodeURIComponent(str)); + } + return btoa(encodeURI(str)); +} diff --git a/package/commonUtil/index.ts b/package/commonUtil/index.ts index c92eab9..a2d3a45 100644 --- a/package/commonUtil/index.ts +++ b/package/commonUtil/index.ts @@ -2,3 +2,5 @@ export { default as isEmpty } from "./isEmpty"; export { default as isNull } from "./isNull"; export { default as sleep } from "./sleep"; export { default as copyToClipboard } from "./copyToClipboard"; +export { default as encodeBase64 } from "./encodeBase64"; +export { default as decodeBase64 } from "./decodeBase64"; diff --git a/vitest-report.xml b/vitest-report.xml index 9c0abde..b839a5b 100644 --- a/vitest-report.xml +++ b/vitest-report.xml @@ -1,4 +1,17 @@ + + + + + + + + + + + + +