@wheeparam/library 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/utils/index.ts
21
+ var utils_exports = {};
22
+ __export(utils_exports, {
23
+ EMAIL_REGEX: () => EMAIL_REGEX,
24
+ PASSWORD_REGEX: () => PASSWORD_REGEX,
25
+ PHONE_REGEX: () => PHONE_REGEX,
26
+ PHONE_WITH_HYPHEN_REGEX: () => PHONE_WITH_HYPHEN_REGEX,
27
+ containsHtml: () => containsHtml,
28
+ formatDateTime: () => formatDateTime,
29
+ formatPhoneWithHyphen: () => formatPhoneWithHyphen,
30
+ formatSize: () => formatSize,
31
+ getSummary: () => getSummary,
32
+ hexToRgb: () => hexToRgb,
33
+ ip2long: () => ip2long,
34
+ isValidEmail: () => isValidEmail,
35
+ isValidPassword: () => isValidPassword,
36
+ isValidPhone: () => isValidPhone,
37
+ josaConvert: () => josaConvert,
38
+ long2ip: () => long2ip,
39
+ maskEmail: () => maskEmail,
40
+ maskName: () => maskName,
41
+ normalizeEmail: () => normalizeEmail,
42
+ normalizePhone: () => normalizePhone,
43
+ toNumber: () => toNumber
44
+ });
45
+ module.exports = __toCommonJS(utils_exports);
46
+
47
+ // src/utils/ip.ts
48
+ var multipliers = [16777216, 65536, 256, 1];
49
+ function ip2long(ip) {
50
+ const parts = ip.split(".");
51
+ if (parts.length !== 4) return null;
52
+ let longValue = 0;
53
+ for (let i = 0; i < 4; i++) {
54
+ const n = Number(parts[i]);
55
+ if (!Number.isInteger(n) || n < 0 || n > 255) return null;
56
+ longValue += n * multipliers[i];
57
+ }
58
+ return longValue >>> 0;
59
+ }
60
+ function long2ip(longValue) {
61
+ if (!Number.isInteger(longValue) || longValue < 0 || longValue > 4294967295) {
62
+ return null;
63
+ }
64
+ return multipliers.map((m) => Math.floor(longValue % (m * 256) / m)).join(".");
65
+ }
66
+
67
+ // src/utils/josa.ts
68
+ var JOSA_MAP = {
69
+ \uC774\uAC00: ["\uC774", "\uAC00"],
70
+ \uC740\uB294: ["\uC740", "\uB294"],
71
+ \uC744\uB97C: ["\uC744", "\uB97C"],
72
+ \uACFC\uC640: ["\uACFC", "\uC640"],
73
+ \uC73C\uB85C: ["\uC73C\uB85C", "\uB85C"]
74
+ // 특수 처리
75
+ };
76
+ function getHangulJongseongInfo(ch) {
77
+ const code = ch.charCodeAt(0) - 44032;
78
+ if (code < 0 || code > 11171) return null;
79
+ const jong = code % 28;
80
+ return {
81
+ hasJong: jong !== 0,
82
+ jongCode: jong
83
+ // 8이면 'ㄹ'
84
+ };
85
+ }
86
+ function josaConvert(str) {
87
+ return str.replace(
88
+ /(.)\{(이가|은는|을를|과와|으로)\}/gu,
89
+ (_, lastChar, pattern) => {
90
+ const key = pattern;
91
+ const pair = JOSA_MAP[key];
92
+ if (!pair) return lastChar + `{${pattern}}`;
93
+ const info = getHangulJongseongInfo(lastChar);
94
+ if (!info) {
95
+ return lastChar + `{${pattern}}`;
96
+ }
97
+ const { hasJong, jongCode } = info;
98
+ if (key === "\uC73C\uB85C") {
99
+ return lastChar + (!hasJong || jongCode === 8 ? pair[1] : pair[0]);
100
+ }
101
+ return lastChar + (hasJong ? pair[0] : pair[1]);
102
+ }
103
+ );
104
+ }
105
+
106
+ // src/utils/format.ts
107
+ function formatSize(size, digits = 1) {
108
+ if (typeof size === "undefined") return "0 B";
109
+ const n = typeof size === "string" ? toNumber(size, NaN) : size;
110
+ if (!Number.isFinite(n) || n < 0) return "Invalid size";
111
+ const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
112
+ let unitIndex = 0;
113
+ let value = n;
114
+ while (value >= 1024 && unitIndex < units.length - 1) {
115
+ value /= 1024;
116
+ unitIndex++;
117
+ }
118
+ return `${value.toFixed(digits)} ${units[unitIndex]}`;
119
+ }
120
+ function formatDateTime(value, options) {
121
+ if (value === null || value === "") return "";
122
+ const now = options?.now ?? /* @__PURE__ */ new Date();
123
+ const date = toDate(value, { assumeUTCString: options?.assumeUTCString ?? false });
124
+ if (!date) return "";
125
+ const elapsedSeconds = Math.trunc((now.getTime() - date.getTime()) / 1e3);
126
+ if (elapsedSeconds < 10) return "\uBC29\uAE08 \uC804";
127
+ if (elapsedSeconds < 60) return `${elapsedSeconds}\uCD08 \uC804`;
128
+ if (elapsedSeconds < 60 * 60) return `${Math.trunc(elapsedSeconds / 60)}\uBD84 \uC804`;
129
+ if (elapsedSeconds < 60 * 60 * 24) return `${Math.trunc(elapsedSeconds / 3600)}\uC2DC\uAC04 \uC804`;
130
+ if (elapsedSeconds < 60 * 60 * 24 * 10) return `${Math.trunc(elapsedSeconds / 86400)}\uC77C \uC804`;
131
+ return formatYYMMDD(date);
132
+ }
133
+ function toDate(value, opts) {
134
+ if (value instanceof Date) {
135
+ return Number.isFinite(value.getTime()) ? value : null;
136
+ }
137
+ const s = String(value).trim();
138
+ if (!s) return null;
139
+ if (/[zZ]$/.test(s) || s.includes("T")) {
140
+ const d2 = new Date(s);
141
+ return Number.isFinite(d2.getTime()) ? d2 : null;
142
+ }
143
+ const m = s.match(
144
+ /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/
145
+ );
146
+ if (!m) {
147
+ const d2 = new Date(s);
148
+ return Number.isFinite(d2.getTime()) ? d2 : null;
149
+ }
150
+ const year = Number(m[1]);
151
+ const month = Number(m[2]) - 1;
152
+ const day = Number(m[3]);
153
+ const hour = Number(m[4] ?? "0");
154
+ const minute = Number(m[5] ?? "0");
155
+ const second = Number(m[6] ?? "0");
156
+ if (opts.assumeUTCString) {
157
+ const t = Date.UTC(year, month, day, hour, minute, second);
158
+ const d2 = new Date(t);
159
+ return Number.isFinite(d2.getTime()) ? d2 : null;
160
+ }
161
+ const d = new Date(year, month, day, hour, minute, second);
162
+ return Number.isFinite(d.getTime()) ? d : null;
163
+ }
164
+ function formatYYMMDD(date) {
165
+ const yy = String(date.getFullYear()).slice(-2);
166
+ const mm = String(date.getMonth() + 1).padStart(2, "0");
167
+ const dd = String(date.getDate()).padStart(2, "0");
168
+ return `${yy}.${mm}.${dd}`;
169
+ }
170
+ function toNumber(value, defaultValue = 0) {
171
+ if (typeof value === "number") {
172
+ return Number.isFinite(value) ? value : defaultValue;
173
+ }
174
+ if (typeof value === "string") {
175
+ const v = value.trim();
176
+ if (v === "") return defaultValue;
177
+ const n = Number(v);
178
+ return Number.isFinite(n) ? n : defaultValue;
179
+ }
180
+ return defaultValue;
181
+ }
182
+
183
+ // src/utils/validation.ts
184
+ var EMAIL_REGEX = /^[\w.-]+@([\w-]+\.)+[\w-]{2,}$/;
185
+ var PASSWORD_REGEX = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
186
+ var PHONE_REGEX = /^(01[016789]|02|0[3-9][0-9])([0-9]{3,4})([0-9]{4})$/;
187
+ var PHONE_WITH_HYPHEN_REGEX = /^(01[016789]|02|0[3-9][0-9])-?([0-9]{3,4})-?([0-9]{4})$/;
188
+ function isValidEmail(value) {
189
+ if (!value) return false;
190
+ return EMAIL_REGEX.test(value.trim());
191
+ }
192
+ function isValidPassword(value) {
193
+ if (!value) return false;
194
+ return PASSWORD_REGEX.test(value);
195
+ }
196
+ function isValidPhone(value, options) {
197
+ if (!value) return false;
198
+ const v = value.trim();
199
+ const allowHyphen = options?.allowHyphen ?? true;
200
+ return allowHyphen ? PHONE_WITH_HYPHEN_REGEX.test(v) : PHONE_REGEX.test(v);
201
+ }
202
+ function normalizePhone(value) {
203
+ if (!value) return null;
204
+ const trimmed = value.trim();
205
+ if (!trimmed) return null;
206
+ const digits = trimmed.replace(/[-\s]/g, "");
207
+ if (!/^\d+$/.test(digits)) return null;
208
+ if (!PHONE_REGEX.test(digits)) return null;
209
+ return digits;
210
+ }
211
+ function formatPhoneWithHyphen(value) {
212
+ const digits = normalizePhone(value);
213
+ if (!digits) return null;
214
+ const isSeoul = digits.startsWith("02");
215
+ if (isSeoul) {
216
+ const a2 = "02";
217
+ const rest2 = digits.slice(2);
218
+ if (rest2.length === 7) {
219
+ return `${a2}-${rest2.slice(0, 3)}-${rest2.slice(3)}`;
220
+ }
221
+ if (rest2.length === 8) {
222
+ return `${a2}-${rest2.slice(0, 4)}-${rest2.slice(4)}`;
223
+ }
224
+ return null;
225
+ }
226
+ const a = digits.slice(0, 3);
227
+ const rest = digits.slice(3);
228
+ if (rest.length === 7) {
229
+ return `${a}-${rest.slice(0, 3)}-${rest.slice(3)}`;
230
+ }
231
+ if (rest.length === 8) {
232
+ return `${a}-${rest.slice(0, 4)}-${rest.slice(4)}`;
233
+ }
234
+ return null;
235
+ }
236
+ function normalizeEmail(value) {
237
+ if (!value) return null;
238
+ const trimmed = value.trim();
239
+ if (!trimmed) return null;
240
+ const parts = trimmed.split("@");
241
+ if (parts.length !== 2) return null;
242
+ const [local, domain] = parts;
243
+ if (!local || !domain) return null;
244
+ const normalized = `${local}@${domain.toLowerCase()}`;
245
+ return isValidEmail(normalized) ? normalized : null;
246
+ }
247
+
248
+ // src/utils/color.ts
249
+ function hexToRgb(hex) {
250
+ if (!hex) return null;
251
+ let value = hex.trim().replace(/^#/, "");
252
+ if (value.length === 3) {
253
+ value = value.split("").map((c) => c + c).join("");
254
+ }
255
+ if (!/^[0-9a-fA-F]{6}$/.test(value)) return null;
256
+ const r = parseInt(value.slice(0, 2), 16);
257
+ const g = parseInt(value.slice(2, 4), 16);
258
+ const b = parseInt(value.slice(4, 6), 16);
259
+ return { r, g, b };
260
+ }
261
+
262
+ // src/utils/summary.ts
263
+ function containsHtml(str) {
264
+ if (!str) return false;
265
+ return /<\/?[a-z][\w:-]*\b[^>]*>/i.test(str);
266
+ }
267
+ function getSummary(content, length = 255) {
268
+ if (!content) return "";
269
+ const text = content.replace(/&nbsp;/gi, " ").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&amp;/gi, "&").replace(/&quot;/gi, '"').replace(/&#039;/gi, "'").replace(/<[^>]*>/g, "").replace(/\u00A0/g, " ").replace(/\s+/g, " ").trim();
270
+ if (length <= 0) return "";
271
+ if (text.length <= length) return text;
272
+ return text.substring(0, length);
273
+ }
274
+
275
+ // src/utils/privacy.ts
276
+ function maskEmail(email) {
277
+ if (!email) return "";
278
+ const parts = email.split("@");
279
+ if (parts.length !== 2) return email;
280
+ const [localPart, domainPart] = parts;
281
+ if (!localPart || !domainPart) return email;
282
+ const visibleLength = localPart.length <= 5 ? 1 : 5;
283
+ const visible = localPart.slice(0, visibleLength);
284
+ const masked = "*".repeat(Math.max(localPart.length - visibleLength, 0));
285
+ return `${visible}${masked}@${domainPart}`;
286
+ }
287
+ function maskName(name) {
288
+ const len = name.length;
289
+ if (len === 0) return "";
290
+ const hasKorean = /[가-힣]/.test(name);
291
+ if (hasKorean) {
292
+ if (len === 1) return "*";
293
+ if (len === 2) return name[0] + "*";
294
+ return name[0] + "*".repeat(len - 2) + name[len - 1];
295
+ }
296
+ const half = Math.ceil(len / 2);
297
+ return name.slice(0, half) + "*".repeat(len - half);
298
+ }
299
+ // Annotate the CommonJS export names for ESM import in node:
300
+ 0 && (module.exports = {
301
+ EMAIL_REGEX,
302
+ PASSWORD_REGEX,
303
+ PHONE_REGEX,
304
+ PHONE_WITH_HYPHEN_REGEX,
305
+ containsHtml,
306
+ formatDateTime,
307
+ formatPhoneWithHyphen,
308
+ formatSize,
309
+ getSummary,
310
+ hexToRgb,
311
+ ip2long,
312
+ isValidEmail,
313
+ isValidPassword,
314
+ isValidPhone,
315
+ josaConvert,
316
+ long2ip,
317
+ maskEmail,
318
+ maskName,
319
+ normalizeEmail,
320
+ normalizePhone,
321
+ toNumber
322
+ });
@@ -0,0 +1,344 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * IPv4 변환 유틸 (문자열 <-> 32bit number)
4
+ */
5
+ /**
6
+ * IPv4 문자열을 32bit 숫자로 변환한다.
7
+ *
8
+ * IPv6는 지원하지 않는다.
9
+ * 잘못된 형식일 경우 null을 반환한다.
10
+ *
11
+ * @param ip IPv4 문자열 (예: 192.168.0.1)
12
+ * @returns 변환된 숫자(uint32) 또는 null
13
+ *
14
+ * @example
15
+ * ip2long("192.168.0.1") // 3232235521
16
+ * ip2long("127.0.0.1") // 2130706433
17
+ * ip2long("abc") // null
18
+ */
19
+ declare function ip2long(ip: string): number | null;
20
+ /**
21
+ * 32bit 숫자를 IPv4 문자열로 변환한다.
22
+ *
23
+ * @param longValue 0 ~ 0xFFFFFFFF 범위의 정수
24
+ * @returns IPv4 문자열 또는 null
25
+ *
26
+ * @example
27
+ * long2ip(3232235521) // "192.168.0.1"
28
+ * long2ip(0) // "0.0.0.0"
29
+ * long2ip(-1) // null
30
+ */
31
+ declare function long2ip(longValue: number): string | null;
32
+
33
+ /**
34
+ * @packageDocumentation
35
+ * 한국어 조사 자동 치환 유틸
36
+ *
37
+ * 템플릿 문자열에서 "{이가}", "{은는}" 같은 패턴을 자동으로 올바른 조사로 치환한다.
38
+ */
39
+ /**
40
+ * 받침 유무에 따라 올바른 한국어 조사를 적용한다.
41
+ *
42
+ * 지원 패턴:
43
+ * - {이가} : 이/가
44
+ * - {은는} : 은/는
45
+ * - {을를} : 을/를
46
+ * - {과와} : 과/와
47
+ * - {으로} : 으로/로 (ㄹ 받침 특수 규칙 포함)
48
+ *
49
+ * ⚠️ 현재 구현은 "바로 앞 문자 1개"가 한글 음절일 때만 치환한다.
50
+ * (한글이 아니면 원문 패턴을 유지한다.)
51
+ *
52
+ * @param str 치환할 문자열
53
+ * @returns 치환된 문자열
54
+ *
55
+ * @example
56
+ * josaConvert("사과{이가} 맛있다") // "사과가 맛있다"
57
+ * josaConvert("집{으로} 간다") // "집으로 간다"
58
+ * josaConvert("달{으로} 간다") // "달로 간다" (ㄹ 받침 특수)
59
+ * josaConvert("A{이가}") // "A{이가}" (한글이 아니면 유지)
60
+ */
61
+ declare function josaConvert(str: string): string;
62
+
63
+ /**
64
+ * 바이트 단위 숫자를 사람이 읽기 쉬운 용량 문자열로 변환한다.
65
+ *
66
+ * @param size 바이트 크기 (number | string)
67
+ * @param digits 소수점 자리수 (기본 1)
68
+ * @returns 예: "0 B", "12.3 KB", "1.0 GB"
69
+ *
70
+ * @example
71
+ * formatSize(0) // "0 B"
72
+ * formatSize(1024) // "1.0 KB"
73
+ * formatSize("1048576") // "1.0 MB"
74
+ */
75
+ declare function formatSize(size: number | string | undefined, digits?: number): string;
76
+ /**
77
+ * 상대 시간 문자열을 반환한다. (moment 의존성 없음)
78
+ *
79
+ * 규칙:
80
+ * - 10초 미만: "방금 전"
81
+ * - 60초 미만: "N초 전"
82
+ * - 1시간 미만: "N분 전"
83
+ * - 24시간 미만: "N시간 전"
84
+ * - 10일 미만: "N일 전"
85
+ * - 그 외: "yy.MM.DD"
86
+ *
87
+ * @param value Date 또는 날짜 문자열
88
+ * @param options 옵션
89
+ * @param options.now 기준 시간(테스트/고정 출력용)
90
+ * @param options.assumeUTCString 문자열 입력이 "UTC" 기준이라고 가정할지 여부
91
+ * - true: "2026-02-20 10:00:00" 같은 문자열을 UTC로 해석
92
+ * - false: JS 기본 파싱(로컬/ISO 규칙)에 맡김
93
+ * @returns 상대 시간 문자열
94
+ *
95
+ * @example
96
+ * formatDateTime(new Date()) // "방금 전"
97
+ *
98
+ * @example
99
+ * formatDateTime("2026-02-01T00:00:00Z") // "yy.MM.DD" 또는 "N일 전"
100
+ *
101
+ * @example
102
+ * // DB에 "YYYY-MM-DD HH:mm:ss" 형태로 UTC 저장하는 경우
103
+ * formatDateTime("2026-02-20 01:00:00", { assumeUTCString: true })
104
+ */
105
+ declare function formatDateTime(value: string | Date, options?: {
106
+ now?: Date;
107
+ assumeUTCString?: boolean;
108
+ }): string;
109
+ /**
110
+ * 안전한 숫자 변환
111
+ *
112
+ * - 실패 시 defaultValue 반환
113
+ * - 문자열은 trim 후 Number 변환
114
+ * - NaN, Infinity 방지
115
+ *
116
+ * @param value 변환할 값
117
+ * @param defaultValue 변환 실패 시 반환할 기본값
118
+ * @returns 변환된 숫자 또는 defaultValue
119
+ *
120
+ * @example
121
+ * toNumber("123") // 123
122
+ * toNumber(" 1.5 ") // 1.5
123
+ * toNumber("abc", 7) // 7
124
+ * toNumber(Infinity, 0) // 0
125
+ */
126
+ declare function toNumber(value: unknown, defaultValue?: number): number;
127
+
128
+ /**
129
+ * @packageDocumentation
130
+ * Validation & Normalization Utilities
131
+ *
132
+ * - EMAIL/PASSWORD/PHONE 관련 "정책 기반" 검증 함수
133
+ * - 한국 전화번호 정규화(normalize) 함수 제공
134
+ *
135
+ * ⚠️ 이메일은 RFC 완전 검증이 아니라 일반적인 입력 필터 수준이다.
136
+ */
137
+ declare const EMAIL_REGEX: RegExp;
138
+ declare const PASSWORD_REGEX: RegExp;
139
+ declare const PHONE_REGEX: RegExp;
140
+ declare const PHONE_WITH_HYPHEN_REGEX: RegExp;
141
+ /**
142
+ * 이메일 형식(간단 정책)을 검사한다.
143
+ *
144
+ * @param value 이메일 문자열
145
+ * @returns 유효하면 true
146
+ *
147
+ * @example
148
+ * isValidEmail("user@test.com") // true
149
+ * isValidEmail("user@") // false
150
+ */
151
+ declare function isValidEmail(value: string | null | undefined): boolean;
152
+ /**
153
+ * 비밀번호 정책을 검사한다.
154
+ *
155
+ * 정책:
156
+ * - 최소 8자
157
+ * - 영문 1개 이상
158
+ * - 숫자 1개 이상
159
+ * - 특수문자 1개 이상 (@$!%*#?&)
160
+ *
161
+ * @param value 비밀번호 문자열
162
+ * @returns 정책을 만족하면 true
163
+ *
164
+ * @example
165
+ * isValidPassword("Abc123!!") // true
166
+ * isValidPassword("abcdefg") // false
167
+ */
168
+ declare function isValidPassword(value: string | null | undefined): boolean;
169
+ /**
170
+ * 한국 전화번호 형식을 검사한다.
171
+ *
172
+ * @param value 전화번호 문자열
173
+ * @param options 옵션
174
+ * @param options.allowHyphen 하이픈 허용 여부 (기본 true)
175
+ * @returns 유효하면 true
176
+ *
177
+ * @example
178
+ * isValidPhone("01012341234") // true
179
+ * isValidPhone("010-1234-1234") // true (기본 allowHyphen=true)
180
+ * isValidPhone("010-1234-1234", { allowHyphen: false }) // false
181
+ */
182
+ declare function isValidPhone(value: string | null | undefined, options?: {
183
+ allowHyphen?: boolean;
184
+ }): boolean;
185
+ /**
186
+ * 전화번호를 "숫자만" 형태로 정규화한다.
187
+ *
188
+ * - 공백 제거
189
+ * - 하이픈 제거
190
+ * - 숫자 외 문자가 포함되면 null 반환
191
+ * - 최종 결과가 유효한 한국 전화번호가 아니면 null 반환
192
+ *
193
+ * @param value 입력 전화번호
194
+ * @returns 정규화된 숫자 문자열 또는 null
195
+ *
196
+ * @example
197
+ * normalizePhone("010-1234-5678") // "01012345678"
198
+ * normalizePhone(" 02-123-4567 ") // "021234567"
199
+ * normalizePhone("abc") // null
200
+ */
201
+ declare function normalizePhone(value: string | null | undefined): string | null;
202
+ /**
203
+ * 전화번호를 하이픈 포함 형태로 포맷한다.
204
+ *
205
+ * - 입력은 숫자만 형태 또는 하이픈 포함 모두 가능
206
+ * - normalizePhone을 통과하지 못하면 null 반환
207
+ *
208
+ * 예:
209
+ * - 01012345678 -> 010-1234-5678
210
+ * - 021234567 -> 02-123-4567
211
+ * - 0311234567 -> 031-123-4567
212
+ *
213
+ * @param value 입력 전화번호
214
+ * @returns 하이픈 포함 포맷 또는 null
215
+ *
216
+ * @example
217
+ * formatPhoneWithHyphen("01012345678") // "010-1234-5678"
218
+ * formatPhoneWithHyphen("02-123-4567") // "02-123-4567"
219
+ */
220
+ declare function formatPhoneWithHyphen(value: string | null | undefined): string | null;
221
+ /**
222
+ * 이메일을 정규화한다.
223
+ *
224
+ * - 양끝 공백 제거
225
+ * - 도메인 부분은 소문자로 변환
226
+ * - 유효하지 않으면 null
227
+ *
228
+ * @param value 이메일 입력
229
+ * @returns 정규화된 이메일 또는 null
230
+ *
231
+ * @example
232
+ * normalizeEmail(" User@Test.COM ") // "User@test.com"
233
+ */
234
+ declare function normalizeEmail(value: string | null | undefined): string | null;
235
+
236
+ /**
237
+ * HEX 색상 코드를 RGB 객체로 변환한다.
238
+ *
239
+ * 지원 형식:
240
+ * - #RGB
241
+ * - #RRGGBB
242
+ * - RGB
243
+ * - RRGGBB
244
+ *
245
+ * 지원하지 않음:
246
+ * - #RGBA
247
+ * - #RRGGBBAA
248
+ *
249
+ * @param hex HEX 색상 문자열
250
+ * @returns RGB 객체 또는 null(잘못된 형식)
251
+ *
252
+ * @example
253
+ * hexToRgb("#fff") // { r:255, g:255, b:255 }
254
+ * hexToRgb("#000000") // { r:0, g:0, b:0 }
255
+ * hexToRgb("1a2b3c") // { r:26, g:43, b:60 }
256
+ * hexToRgb("#zzzzzz") // null
257
+ */
258
+ declare function hexToRgb(hex: string): {
259
+ r: number;
260
+ g: number;
261
+ b: number;
262
+ } | null;
263
+
264
+ /**
265
+ * 문자열에 HTML 태그가 포함되어 있는지 "간단히" 검사한다.
266
+ *
267
+ * ⚠️ 주의:
268
+ * - 완전한 HTML 파서는 아니다.
269
+ * - 단순한 태그 패턴(`<tag>`) 존재 여부만 빠르게 판단한다.
270
+ * - 사용자 입력 필터링/보안 검증 용도로 사용하면 안된다.
271
+ *
272
+ * @param str 검사할 문자열
273
+ * @returns HTML 태그로 보이는 패턴 존재 여부
274
+ *
275
+ * @example
276
+ * containsHtml("<b>Hello</b>") // true
277
+ *
278
+ * @example
279
+ * containsHtml("Hello world") // false
280
+ *
281
+ * @example
282
+ * containsHtml("< not html") // false
283
+ */
284
+ declare function containsHtml(str: string): boolean;
285
+ /**
286
+ * HTML 문자열에서 태그/엔티티/불필요 공백을 제거하고 요약 문자열을 만든다.
287
+ *
288
+ * - HTML 태그 제거
289
+ * - &nbsp; 등 일부 엔티티를 공백/문자 형태로 정리
290
+ * - 연속 공백 축약
291
+ * - length 기준으로 잘라 반환
292
+ *
293
+ * @param content HTML 또는 일반 문자열
294
+ * @param length 최대 길이 (기본 255)
295
+ * @returns 요약 문자열
296
+ *
297
+ * @example
298
+ * getSummary("<p>Hello&nbsp;<b>World</b></p>", 10) // "Hello Worl"
299
+ */
300
+ declare function getSummary(content: string, length?: number): string;
301
+
302
+ /**
303
+ * 이메일 주소의 로컬 파트를 마스킹한다.
304
+ *
305
+ * 규칙:
306
+ * - '@' 앞(localPart)의 앞 5글자만 노출
307
+ * - 나머지는 '*' 처리
308
+ * - 길이가 5 이하이면 1글자만 노출하고 나머지는 마스킹
309
+ *
310
+ * @param email 이메일 주소
311
+ * @returns 마스킹된 이메일
312
+ *
313
+ * @example
314
+ * maskEmail("abcdefghi@gmail.com")
315
+ * // "abcde****@gmail.com"
316
+ *
317
+ * @example
318
+ * maskEmail("ab@naver.com")
319
+ * // "a*@naver.com"
320
+ *
321
+ * @example
322
+ * maskEmail("invalid-email")
323
+ * // "invalid-email" (형식이 아니면 그대로 반환)
324
+ */
325
+ declare function maskEmail(email: string): string;
326
+ /**
327
+ * 이름을 마스킹 처리한다.
328
+ *
329
+ * 규칙:
330
+ * - 한글이 포함된 경우: 첫 글자/마지막 글자만 노출(2글자는 첫 글자만 노출)
331
+ * - 한글이 아닌 경우(영문 등): 앞 절반을 노출하고 나머지를 마스킹
332
+ *
333
+ * @param name 이름 문자열
334
+ * @returns 마스킹된 이름
335
+ *
336
+ * @example
337
+ * maskName("홍길동") // "홍*동"
338
+ * maskName("홍길") // "홍*"
339
+ * maskName("김") // "*"
340
+ * maskName("Michael") // "Mich***" (길이에 따라 달라짐)
341
+ */
342
+ declare function maskName(name: string): string;
343
+
344
+ export { EMAIL_REGEX, PASSWORD_REGEX, PHONE_REGEX, PHONE_WITH_HYPHEN_REGEX, containsHtml, formatDateTime, formatPhoneWithHyphen, formatSize, getSummary, hexToRgb, ip2long, isValidEmail, isValidPassword, isValidPhone, josaConvert, long2ip, maskEmail, maskName, normalizeEmail, normalizePhone, toNumber };