Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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" }
Expand Down Expand Up @@ -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<void>` - Pauses execution for a specified number of milliseconds
- `copyToClipboard(text: string): Promise<boolean>` - 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

Expand Down
37 changes: 37 additions & 0 deletions package/commonUtil/decodeBase64/index.test.ts
Original file line number Diff line number Diff line change
@@ -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("안녕하세요");
});
});
15 changes: 15 additions & 0 deletions package/commonUtil/decodeBase64/index.ts
Original file line number Diff line number Diff line change
@@ -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));
}
35 changes: 35 additions & 0 deletions package/commonUtil/encodeBase64/index.test.ts
Original file line number Diff line number Diff line change
@@ -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);
Comment thread
klmhyeonwoo marked this conversation as resolved.
});
test("한글이 들어오면 올바르게 인코딩해야 한다", () => {
const result = encodeBase64("안녕하세요");
expect(result).toBe(
"JUVDJTk1JTg4JUVCJTg1JTk1JUVEJTk1JTk4JUVDJTg0JUI4JUVDJTlBJTk0"
);
});
});
15 changes: 15 additions & 0 deletions package/commonUtil/encodeBase64/index.ts
Original file line number Diff line number Diff line change
@@ -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));
}
2 changes: 2 additions & 0 deletions package/commonUtil/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
13 changes: 13 additions & 0 deletions vitest-report.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="6" failures="0" errors="0" time="0.002156208">
<testsuite name="package/commonUtil/encodeBase64/indes.test.ts" timestamp="2025-09-25T14:42:58.765Z" hostname="klmhyeonwooui-MacBookPro.local" tests="6" failures="0" errors="0" skipped="0" time="0.002156208">
<testcase classname="package/commonUtil/encodeBase64/indes.test.ts" name="encodeBase64 유틸 함수 테스트 &gt; 정상적인 문자열을 Base64로 인코딩해야 한다" time="0.000807042">
</testcase>
<testcase classname="package/commonUtil/encodeBase64/indes.test.ts" name="encodeBase64 유틸 함수 테스트 &gt; 빈 문자열을 인코딩하면 빈 문자열을 반환해야 한다" time="0.000093625">
</testcase>
<testcase classname="package/commonUtil/encodeBase64/indes.test.ts" name="encodeBase64 유틸 함수 테스트 &gt; 특수 문자가 포함된 문자열을 올바르게 인코딩해야 한다" time="0.000173709">
</testcase>
<testcase classname="package/commonUtil/encodeBase64/indes.test.ts" name="encodeBase64 유틸 함수 테스트 &gt; 유니코드 문자가 포함된 문자열을 올바르게 인코딩해야 한다" time="0.000156042">
</testcase>
<testcase classname="package/commonUtil/encodeBase64/indes.test.ts" name="encodeBase64 유틸 함수 테스트 &gt; null 또는 undefined를 인코딩하면 그대로 반환해야 한다" time="0.000235916">
</testcase>
<testcase classname="package/commonUtil/encodeBase64/indes.test.ts" name="encodeBase64 유틸 함수 테스트 &gt; 한글이 들어오면 올바르게 인코딩해야 한다" time="0.000069459">
<testsuites name="vitest tests" tests="111" failures="0" errors="0" time="0.042221709">
<testsuite name="package/commonUtil/copyToClipboard/index.test.ts" timestamp="2025-09-21T02:31:20.170Z" hostname="192.168.nate.com" tests="5" failures="0" errors="0" skipped="0" time="0.003149416">
<testcase classname="package/commonUtil/copyToClipboard/index.test.ts" name="copyToClipboard &gt; 성공 케이스 &gt; 최신 Clipboard API를 사용하여 성공적으로 복사한다" time="0.001617584">
Expand Down