@simplysm/core-common 13.0.0-beta.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.
Files changed (202) hide show
  1. package/.cache/typecheck-browser.tsbuildinfo +1 -0
  2. package/.cache/typecheck-node.tsbuildinfo +1 -0
  3. package/.cache/typecheck-tests-browser.tsbuildinfo +1 -0
  4. package/.cache/typecheck-tests-node.tsbuildinfo +1 -0
  5. package/README.md +887 -0
  6. package/dist/common.types.d.ts +74 -0
  7. package/dist/common.types.d.ts.map +1 -0
  8. package/dist/common.types.js +5 -0
  9. package/dist/common.types.js.map +7 -0
  10. package/dist/env.d.ts +6 -0
  11. package/dist/env.d.ts.map +1 -0
  12. package/dist/env.js +9 -0
  13. package/dist/env.js.map +7 -0
  14. package/dist/errors/argument-error.d.ts +25 -0
  15. package/dist/errors/argument-error.d.ts.map +1 -0
  16. package/dist/errors/argument-error.js +18 -0
  17. package/dist/errors/argument-error.js.map +7 -0
  18. package/dist/errors/not-implemented-error.d.ts +29 -0
  19. package/dist/errors/not-implemented-error.d.ts.map +1 -0
  20. package/dist/errors/not-implemented-error.js +14 -0
  21. package/dist/errors/not-implemented-error.js.map +7 -0
  22. package/dist/errors/sd-error.d.ts +27 -0
  23. package/dist/errors/sd-error.d.ts.map +1 -0
  24. package/dist/errors/sd-error.js +23 -0
  25. package/dist/errors/sd-error.js.map +7 -0
  26. package/dist/errors/timeout-error.d.ts +31 -0
  27. package/dist/errors/timeout-error.d.ts.map +1 -0
  28. package/dist/errors/timeout-error.js +17 -0
  29. package/dist/errors/timeout-error.js.map +7 -0
  30. package/dist/extensions/arr-ext.d.ts +15 -0
  31. package/dist/extensions/arr-ext.d.ts.map +1 -0
  32. package/dist/extensions/arr-ext.helpers.d.ts +19 -0
  33. package/dist/extensions/arr-ext.helpers.d.ts.map +1 -0
  34. package/dist/extensions/arr-ext.helpers.js +35 -0
  35. package/dist/extensions/arr-ext.helpers.js.map +7 -0
  36. package/dist/extensions/arr-ext.js +546 -0
  37. package/dist/extensions/arr-ext.js.map +7 -0
  38. package/dist/extensions/arr-ext.types.d.ts +215 -0
  39. package/dist/extensions/arr-ext.types.d.ts.map +1 -0
  40. package/dist/extensions/arr-ext.types.js +1 -0
  41. package/dist/extensions/arr-ext.types.js.map +7 -0
  42. package/dist/extensions/map-ext.d.ts +57 -0
  43. package/dist/extensions/map-ext.d.ts.map +1 -0
  44. package/dist/extensions/map-ext.js +26 -0
  45. package/dist/extensions/map-ext.js.map +7 -0
  46. package/dist/extensions/set-ext.d.ts +36 -0
  47. package/dist/extensions/set-ext.d.ts.map +1 -0
  48. package/dist/extensions/set-ext.js +29 -0
  49. package/dist/extensions/set-ext.js.map +7 -0
  50. package/dist/features/debounce-queue.d.ts +53 -0
  51. package/dist/features/debounce-queue.d.ts.map +1 -0
  52. package/dist/features/debounce-queue.js +80 -0
  53. package/dist/features/debounce-queue.js.map +7 -0
  54. package/dist/features/event-emitter.d.ts +66 -0
  55. package/dist/features/event-emitter.d.ts.map +1 -0
  56. package/dist/features/event-emitter.js +82 -0
  57. package/dist/features/event-emitter.js.map +7 -0
  58. package/dist/features/serial-queue.d.ts +47 -0
  59. package/dist/features/serial-queue.d.ts.map +1 -0
  60. package/dist/features/serial-queue.js +66 -0
  61. package/dist/features/serial-queue.js.map +7 -0
  62. package/dist/globals.d.ts +12 -0
  63. package/dist/globals.d.ts.map +1 -0
  64. package/dist/globals.js +1 -0
  65. package/dist/globals.js.map +7 -0
  66. package/dist/index.d.ts +32 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +31 -0
  69. package/dist/index.js.map +7 -0
  70. package/dist/types/date-only.d.ts +152 -0
  71. package/dist/types/date-only.d.ts.map +1 -0
  72. package/dist/types/date-only.js +251 -0
  73. package/dist/types/date-only.js.map +7 -0
  74. package/dist/types/date-time.d.ts +96 -0
  75. package/dist/types/date-time.d.ts.map +1 -0
  76. package/dist/types/date-time.js +220 -0
  77. package/dist/types/date-time.js.map +7 -0
  78. package/dist/types/lazy-gc-map.d.ts +80 -0
  79. package/dist/types/lazy-gc-map.d.ts.map +1 -0
  80. package/dist/types/lazy-gc-map.js +179 -0
  81. package/dist/types/lazy-gc-map.js.map +7 -0
  82. package/dist/types/time.d.ts +68 -0
  83. package/dist/types/time.d.ts.map +1 -0
  84. package/dist/types/time.js +151 -0
  85. package/dist/types/time.js.map +7 -0
  86. package/dist/types/uuid.d.ts +35 -0
  87. package/dist/types/uuid.d.ts.map +1 -0
  88. package/dist/types/uuid.js +71 -0
  89. package/dist/types/uuid.js.map +7 -0
  90. package/dist/utils/bytes.d.ts +51 -0
  91. package/dist/utils/bytes.d.ts.map +1 -0
  92. package/dist/utils/bytes.js +89 -0
  93. package/dist/utils/bytes.js.map +7 -0
  94. package/dist/utils/date-format.d.ts +90 -0
  95. package/dist/utils/date-format.d.ts.map +1 -0
  96. package/dist/utils/date-format.js +106 -0
  97. package/dist/utils/date-format.js.map +7 -0
  98. package/dist/utils/json.d.ts +34 -0
  99. package/dist/utils/json.d.ts.map +1 -0
  100. package/dist/utils/json.js +152 -0
  101. package/dist/utils/json.js.map +7 -0
  102. package/dist/utils/num.d.ts +60 -0
  103. package/dist/utils/num.d.ts.map +1 -0
  104. package/dist/utils/num.js +39 -0
  105. package/dist/utils/num.js.map +7 -0
  106. package/dist/utils/obj.d.ts +258 -0
  107. package/dist/utils/obj.d.ts.map +1 -0
  108. package/dist/utils/obj.js +538 -0
  109. package/dist/utils/obj.js.map +7 -0
  110. package/dist/utils/path.d.ts +23 -0
  111. package/dist/utils/path.d.ts.map +1 -0
  112. package/dist/utils/path.js +21 -0
  113. package/dist/utils/path.js.map +7 -0
  114. package/dist/utils/primitive.d.ts +18 -0
  115. package/dist/utils/primitive.d.ts.map +1 -0
  116. package/dist/utils/primitive.js +20 -0
  117. package/dist/utils/primitive.js.map +7 -0
  118. package/dist/utils/str.d.ts +103 -0
  119. package/dist/utils/str.d.ts.map +1 -0
  120. package/dist/utils/str.js +128 -0
  121. package/dist/utils/str.js.map +7 -0
  122. package/dist/utils/template-strings.d.ts +84 -0
  123. package/dist/utils/template-strings.d.ts.map +1 -0
  124. package/dist/utils/template-strings.js +49 -0
  125. package/dist/utils/template-strings.js.map +7 -0
  126. package/dist/utils/transferable.d.ts +47 -0
  127. package/dist/utils/transferable.d.ts.map +1 -0
  128. package/dist/utils/transferable.js +153 -0
  129. package/dist/utils/transferable.js.map +7 -0
  130. package/dist/utils/wait.d.ts +19 -0
  131. package/dist/utils/wait.d.ts.map +1 -0
  132. package/dist/utils/wait.js +19 -0
  133. package/dist/utils/wait.js.map +7 -0
  134. package/dist/utils/xml.d.ts +36 -0
  135. package/dist/utils/xml.d.ts.map +1 -0
  136. package/dist/utils/xml.js +51 -0
  137. package/dist/utils/xml.js.map +7 -0
  138. package/dist/zip/sd-zip.d.ts +80 -0
  139. package/dist/zip/sd-zip.d.ts.map +1 -0
  140. package/dist/zip/sd-zip.js +153 -0
  141. package/dist/zip/sd-zip.js.map +7 -0
  142. package/package.json +31 -0
  143. package/src/common.types.ts +91 -0
  144. package/src/env.ts +11 -0
  145. package/src/errors/argument-error.ts +40 -0
  146. package/src/errors/not-implemented-error.ts +32 -0
  147. package/src/errors/sd-error.ts +53 -0
  148. package/src/errors/timeout-error.ts +36 -0
  149. package/src/extensions/arr-ext.helpers.ts +53 -0
  150. package/src/extensions/arr-ext.ts +777 -0
  151. package/src/extensions/arr-ext.types.ts +258 -0
  152. package/src/extensions/map-ext.ts +86 -0
  153. package/src/extensions/set-ext.ts +68 -0
  154. package/src/features/debounce-queue.ts +116 -0
  155. package/src/features/event-emitter.ts +112 -0
  156. package/src/features/serial-queue.ts +94 -0
  157. package/src/globals.ts +12 -0
  158. package/src/index.ts +55 -0
  159. package/src/types/date-only.ts +329 -0
  160. package/src/types/date-time.ts +294 -0
  161. package/src/types/lazy-gc-map.ts +244 -0
  162. package/src/types/time.ts +210 -0
  163. package/src/types/uuid.ts +113 -0
  164. package/src/utils/bytes.ts +160 -0
  165. package/src/utils/date-format.ts +239 -0
  166. package/src/utils/json.ts +230 -0
  167. package/src/utils/num.ts +97 -0
  168. package/src/utils/obj.ts +956 -0
  169. package/src/utils/path.ts +40 -0
  170. package/src/utils/primitive.ts +33 -0
  171. package/src/utils/str.ts +252 -0
  172. package/src/utils/template-strings.ts +132 -0
  173. package/src/utils/transferable.ts +269 -0
  174. package/src/utils/wait.ts +40 -0
  175. package/src/utils/xml.ts +105 -0
  176. package/src/zip/sd-zip.ts +218 -0
  177. package/tests/errors/errors.spec.ts +196 -0
  178. package/tests/extensions/array-extension.spec.ts +790 -0
  179. package/tests/extensions/map-extension.spec.ts +147 -0
  180. package/tests/extensions/set-extension.spec.ts +74 -0
  181. package/tests/types/date-only.spec.ts +636 -0
  182. package/tests/types/date-time.spec.ts +391 -0
  183. package/tests/types/lazy-gc-map.spec.ts +692 -0
  184. package/tests/types/time.spec.ts +559 -0
  185. package/tests/types/types.spec.ts +55 -0
  186. package/tests/types/uuid.spec.ts +91 -0
  187. package/tests/utils/bytes-utils.spec.ts +230 -0
  188. package/tests/utils/date-format.spec.ts +371 -0
  189. package/tests/utils/debounce-queue.spec.ts +272 -0
  190. package/tests/utils/json.spec.ts +475 -0
  191. package/tests/utils/number.spec.ts +184 -0
  192. package/tests/utils/object.spec.ts +827 -0
  193. package/tests/utils/path.spec.ts +78 -0
  194. package/tests/utils/primitive.spec.ts +55 -0
  195. package/tests/utils/sd-event-emitter.spec.ts +216 -0
  196. package/tests/utils/serial-queue.spec.ts +365 -0
  197. package/tests/utils/string.spec.ts +294 -0
  198. package/tests/utils/template-strings.spec.ts +96 -0
  199. package/tests/utils/transferable.spec.ts +698 -0
  200. package/tests/utils/wait.spec.ts +145 -0
  201. package/tests/utils/xml.spec.ts +146 -0
  202. package/tests/zip/sd-zip.spec.ts +234 -0
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 경로 유틸리티 함수
3
+ * Node.js path 모듈 대체용 (브라우저 환경 지원)
4
+ *
5
+ * @note 이 유틸리티는 POSIX 스타일 경로(슬래시 `/`)만 지원합니다.
6
+ * Windows 백슬래시(`\`) 경로는 지원하지 않습니다.
7
+ * 브라우저 환경 및 Capacitor 플러그인용으로 설계되었습니다.
8
+ */
9
+
10
+ /**
11
+ * 경로 조합 (path.join 대체)
12
+ * @note POSIX 스타일 경로만 지원 (슬래시 `/`)
13
+ */
14
+ export function pathJoin(...segments: string[]): string {
15
+ return segments
16
+ .map((s, i) => (i === 0 ? s.replace(/\/+$/, "") : s.replace(/^\/+|\/+$/g, "")))
17
+ .filter(Boolean)
18
+ .join("/");
19
+ }
20
+
21
+ /**
22
+ * 파일명 추출 (path.basename 대체)
23
+ */
24
+ export function pathBasename(filePath: string, ext?: string): string {
25
+ const name = filePath.split("/").pop() ?? "";
26
+ if (ext != null && ext !== "" && name.endsWith(ext)) {
27
+ return name.slice(0, -ext.length);
28
+ }
29
+ return name;
30
+ }
31
+
32
+ /**
33
+ * 확장자 추출 (path.extname 대체)
34
+ * @note 숨김 파일(예: `.gitignore`)은 빈 문자열을 반환합니다 (Node.js path.extname과 동일)
35
+ */
36
+ export function pathExtname(filePath: string): string {
37
+ const name = filePath.split("/").pop() ?? "";
38
+ const dotIndex = name.lastIndexOf(".");
39
+ return dotIndex > 0 ? name.slice(dotIndex) : "";
40
+ }
@@ -0,0 +1,33 @@
1
+ import { DateTime } from "../types/date-time";
2
+ import { DateOnly } from "../types/date-only";
3
+ import { Time } from "../types/time";
4
+ import { Uuid } from "../types/uuid";
5
+ import { ArgumentError } from "../errors/argument-error";
6
+ import type { PrimitiveTypeMap, PrimitiveTypeStr } from "../common.types";
7
+
8
+ /**
9
+ * 값에서 PrimitiveTypeStr 추론
10
+ *
11
+ * 런타임에서 값의 타입을 검사하여 해당하는 PrimitiveTypeStr을 반환합니다.
12
+ *
13
+ * @param value 타입을 추론할 값
14
+ * @returns 값에 해당하는 PrimitiveTypeStr
15
+ * @throws ArgumentError 지원하지 않는 타입인 경우
16
+ *
17
+ * @example
18
+ * getPrimitiveTypeStr("hello") // "string"
19
+ * getPrimitiveTypeStr(123) // "number"
20
+ * getPrimitiveTypeStr(new DateTime()) // "DateTime"
21
+ * getPrimitiveTypeStr(new Uint8Array()) // "Bytes"
22
+ */
23
+ export function getPrimitiveTypeStr(value: PrimitiveTypeMap[PrimitiveTypeStr]): PrimitiveTypeStr {
24
+ if (typeof value === "string") return "string";
25
+ if (typeof value === "number") return "number";
26
+ if (typeof value === "boolean") return "boolean";
27
+ if (value instanceof DateTime) return "DateTime";
28
+ if (value instanceof DateOnly) return "DateOnly";
29
+ if (value instanceof Time) return "Time";
30
+ if (value instanceof Uuid) return "Uuid";
31
+ if (value instanceof Uint8Array) return "Bytes";
32
+ throw new ArgumentError("알 수 없는 값 타입입니다.", { type: typeof value });
33
+ }
@@ -0,0 +1,252 @@
1
+ /**
2
+ * 문자열 유틸리티 함수
3
+ */
4
+
5
+ //#region 한글 조사 처리
6
+
7
+ // 한글 조사 매핑 테이블 (모듈 로드 시 1회만 생성)
8
+ const suffixTable = {
9
+ 을: { t: "을", f: "를" },
10
+ 은: { t: "은", f: "는" },
11
+ 이: { t: "이", f: "가" },
12
+ 와: { t: "과", f: "와" },
13
+ 랑: { t: "이랑", f: "랑" },
14
+ 로: { t: "으로", f: "로" },
15
+ 라: { t: "이라", f: "라" },
16
+ };
17
+
18
+ /**
19
+ * 한글 조사를 받침에 따라 적절히 반환
20
+ * @param text 텍스트
21
+ * @param type 조사 타입
22
+ * - `"을"`: 을/를
23
+ * - `"은"`: 은/는
24
+ * - `"이"`: 이/가
25
+ * - `"와"`: 과/와
26
+ * - `"랑"`: 이랑/랑
27
+ * - `"로"`: 으로/로
28
+ * - `"라"`: 이라/라
29
+ *
30
+ * @example
31
+ * getSuffix("사과", "을") // "를"
32
+ * getSuffix("책", "이") // "이"
33
+ */
34
+ export function strGetSuffix(text: string, type: "을" | "은" | "이" | "와" | "랑" | "로" | "라"): string {
35
+ const table = suffixTable;
36
+
37
+ // 빈 문자열 또는 마지막 글자가 한글이 아닌 경우 받침 없음으로 처리
38
+ if (text.length === 0) {
39
+ return table[type].f;
40
+ }
41
+
42
+ const lastCharCode = text.charCodeAt(text.length - 1);
43
+
44
+ // 한글 범위 체크 (0xAC00 ~ 0xD7A3)
45
+ if (lastCharCode < 0xac00 || lastCharCode > 0xd7a3) {
46
+ return table[type].f;
47
+ }
48
+
49
+ // 받침 존재 여부 및 종성 인덱스 계산
50
+ const jongseongIndex = (lastCharCode - 0xac00) % 28;
51
+ const hasLast = jongseongIndex !== 0;
52
+
53
+ // "로" 조사는 받침 ㄹ(종성 인덱스 8)일 때 "로"로 처리
54
+ if (type === "로" && jongseongIndex === 8) {
55
+ return table[type].f;
56
+ }
57
+
58
+ return hasLast ? table[type].t : table[type].f;
59
+ }
60
+
61
+ //#endregion
62
+
63
+ //#region 전각→반각 변환
64
+
65
+ // 전각 → 반각 매핑 테이블 (모듈 로드 시 1회만 생성)
66
+ const specialCharMap: Record<string, string> = {
67
+ "A": "A",
68
+ "B": "B",
69
+ "C": "C",
70
+ "D": "D",
71
+ "E": "E",
72
+ "F": "F",
73
+ "G": "G",
74
+ "H": "H",
75
+ "I": "I",
76
+ "J": "J",
77
+ "K": "K",
78
+ "L": "L",
79
+ "M": "M",
80
+ "N": "N",
81
+ "O": "O",
82
+ "P": "P",
83
+ "Q": "Q",
84
+ "R": "R",
85
+ "S": "S",
86
+ "T": "T",
87
+ "U": "U",
88
+ "V": "V",
89
+ "W": "W",
90
+ "X": "X",
91
+ "Y": "Y",
92
+ "Z": "Z",
93
+ "a": "a",
94
+ "b": "b",
95
+ "c": "c",
96
+ "d": "d",
97
+ "e": "e",
98
+ "f": "f",
99
+ "g": "g",
100
+ "h": "h",
101
+ "i": "i",
102
+ "j": "j",
103
+ "k": "k",
104
+ "l": "l",
105
+ "m": "m",
106
+ "n": "n",
107
+ "o": "o",
108
+ "p": "p",
109
+ "q": "q",
110
+ "r": "r",
111
+ "s": "s",
112
+ "t": "t",
113
+ "u": "u",
114
+ "v": "v",
115
+ "w": "w",
116
+ "x": "x",
117
+ "y": "y",
118
+ "z": "z",
119
+ "0": "0",
120
+ "1": "1",
121
+ "2": "2",
122
+ "3": "3",
123
+ "4": "4",
124
+ "5": "5",
125
+ "6": "6",
126
+ "7": "7",
127
+ "8": "8",
128
+ "9": "9",
129
+ " ": " ",
130
+ ")": ")",
131
+ "(": "(",
132
+ };
133
+
134
+ // 정규식도 1회만 생성
135
+ const specialCharRegex = new RegExp(`[${Object.keys(specialCharMap).join("")}]`, "g");
136
+
137
+ /**
138
+ * 전각(Full-width) 문자를 반각(Half-width) 문자로 변환
139
+ *
140
+ * 변환 대상:
141
+ * - 전각 영문 대문자 (A-Z → A-Z)
142
+ * - 전각 영문 소문자 (a-z → a-z)
143
+ * - 전각 숫자 (0-9 → 0-9)
144
+ * - 전각 공백 (  → 일반 공백)
145
+ * - 전각 괄호 (() → ())
146
+ *
147
+ * @example
148
+ * replaceSpecialDefaultChar("A123") // "A123"
149
+ * replaceSpecialDefaultChar("(株)") // "(株)"
150
+ */
151
+ export function strReplaceFullWidth(str: string): string {
152
+ return str.replace(specialCharRegex, (char) => specialCharMap[char] ?? char);
153
+ }
154
+
155
+ //#endregion
156
+
157
+ //#region 케이스 변환
158
+
159
+ /**
160
+ * PascalCase로 변환
161
+ * @example "hello-world" → "HelloWorld"
162
+ * @example "hello_world" → "HelloWorld"
163
+ * @example "hello.world" → "HelloWorld"
164
+ */
165
+ export function strToPascalCase(str: string): string {
166
+ return str.replace(/[-._][a-z]/g, (m) => m[1].toUpperCase()).replace(/^[a-z]/, (m) => m.toUpperCase());
167
+ }
168
+
169
+ /**
170
+ * camelCase로 변환
171
+ * @example "hello-world" → "helloWorld"
172
+ * @example "hello_world" → "helloWorld"
173
+ * @example "HelloWorld" → "helloWorld"
174
+ */
175
+ export function strToCamelCase(str: string): string {
176
+ return str.replace(/[-._][a-z]/g, (m) => m[1].toUpperCase()).replace(/^[A-Z]/, (m) => m.toLowerCase());
177
+ }
178
+
179
+ /**
180
+ * kebab-case로 변환
181
+ *
182
+ * @example "HelloWorld" → "hello-world"
183
+ * @example "helloWorld" → "hello-world"
184
+ * @example "hello_world" → "hello_world" (소문자만 있으면 변환 안됨)
185
+ * @example "Hello_World" → "hello-_world" (기존 분리자는 유지됨)
186
+ * @example "Hello-World" → "hello--world" (기존 분리자는 유지됨)
187
+ * @example "XMLParser" → "x-m-l-parser" (연속된 대문자는 각각 분리됨)
188
+ */
189
+ export function strToKebabCase(str: string): string {
190
+ return toCaseWithSeparator(str, "-");
191
+ }
192
+
193
+ /**
194
+ * snake_case로 변환
195
+ *
196
+ * @example "HelloWorld" → "hello_world"
197
+ * @example "helloWorld" → "hello_world"
198
+ * @example "hello-world" → "hello-world" (소문자만 있으면 변환 안됨)
199
+ * @example "Hello-World" → "hello_-world" (기존 분리자는 유지됨)
200
+ * @example "Hello_World" → "hello__world" (기존 분리자는 유지됨)
201
+ * @example "XMLParser" → "x_m_l_parser" (연속된 대문자는 각각 분리됨)
202
+ */
203
+ export function strToSnakeCase(str: string): string {
204
+ return toCaseWithSeparator(str, "_");
205
+ }
206
+
207
+ function toCaseWithSeparator(str: string, separator: string): string {
208
+ return str.replace(/^[A-Z]/, (m) => m.toLowerCase()).replace(/[-_]?[A-Z]/g, (m) => separator + m.toLowerCase());
209
+ }
210
+
211
+ //#endregion
212
+
213
+ //#region 기타
214
+
215
+ /**
216
+ * undefined 또는 빈 문자열 여부 체크 (타입 가드)
217
+ *
218
+ * @param str 체크할 문자열
219
+ * @returns undefined, null, 빈 문자열이면 true
220
+ *
221
+ * @example
222
+ * const name: string | undefined = getValue();
223
+ * if (strIsNullOrEmpty(name)) {
224
+ * // name: "" | undefined
225
+ * console.log("이름이 비어있습니다");
226
+ * } else {
227
+ * // name: string (비어있지 않은 문자열)
228
+ * console.log(`이름: ${name}`);
229
+ * }
230
+ */
231
+ export function strIsNullOrEmpty(str: string | undefined): str is "" | undefined {
232
+ return str == null || str === "";
233
+ }
234
+
235
+ /**
236
+ * 문자열 특정 위치에 삽입
237
+ *
238
+ * @param str 원본 문자열
239
+ * @param index 삽입할 위치 (0부터 시작)
240
+ * @param insertString 삽입할 문자열
241
+ * @returns 삽입된 새 문자열
242
+ *
243
+ * @example
244
+ * strInsert("Hello World", 5, ","); // "Hello, World"
245
+ * strInsert("abc", 0, "X"); // "Xabc"
246
+ * strInsert("abc", 3, "X"); // "abcX"
247
+ */
248
+ export function strInsert(str: string, index: number, insertString: string): string {
249
+ return str.substring(0, index) + insertString + str.substring(index);
250
+ }
251
+
252
+ //#endregion
@@ -0,0 +1,132 @@
1
+ /**
2
+ * 템플릿 문자열 태그 함수들
3
+ * IDE 코드 하이라이팅 지원용 (실제 동작은 문자열 조합 + 들여쓰기 정리)
4
+ */
5
+
6
+ /**
7
+ * JavaScript 코드 하이라이팅용 템플릿 태그
8
+ * @param strings 템플릿 문자열 배열
9
+ * @param values 보간된 값들
10
+ * @returns 들여쓰기가 정리된 문자열
11
+ * @example
12
+ * const code = js`
13
+ * function hello() {
14
+ * return "world";
15
+ * }
16
+ * `;
17
+ */
18
+ export function js(strings: TemplateStringsArray, ...values: unknown[]): string {
19
+ return _combine(strings, values);
20
+ }
21
+
22
+ /**
23
+ * TypeScript 코드 하이라이팅용 템플릿 태그
24
+ * @param strings 템플릿 문자열 배열
25
+ * @param values 보간된 값들
26
+ * @returns 들여쓰기가 정리된 문자열
27
+ * @example
28
+ * const code = ts`
29
+ * interface User {
30
+ * name: string;
31
+ * age: number;
32
+ * }
33
+ * `;
34
+ */
35
+ export function ts(strings: TemplateStringsArray, ...values: unknown[]): string {
36
+ return _combine(strings, values);
37
+ }
38
+
39
+ /**
40
+ * HTML 마크업 하이라이팅용 템플릿 태그
41
+ * @param strings 템플릿 문자열 배열
42
+ * @param values 보간된 값들
43
+ * @returns 들여쓰기가 정리된 문자열
44
+ * @example
45
+ * const markup = html`
46
+ * <div class="container">
47
+ * <span>${name}</span>
48
+ * </div>
49
+ * `;
50
+ */
51
+ export function html(strings: TemplateStringsArray, ...values: unknown[]): string {
52
+ return _combine(strings, values);
53
+ }
54
+
55
+ /**
56
+ * MSSQL T-SQL 하이라이팅용 템플릿 태그
57
+ * @param strings 템플릿 문자열 배열
58
+ * @param values 보간된 값들
59
+ * @returns 들여쓰기가 정리된 문자열
60
+ * @example
61
+ * const query = tsql`
62
+ * SELECT TOP 10 *
63
+ * FROM Users
64
+ * WHERE Name LIKE '%${keyword}%'
65
+ * `;
66
+ */
67
+ export function tsql(strings: TemplateStringsArray, ...values: unknown[]): string {
68
+ return _combine(strings, values);
69
+ }
70
+
71
+ /**
72
+ * MySQL SQL 하이라이팅용 템플릿 태그
73
+ * @param strings 템플릿 문자열 배열
74
+ * @param values 보간된 값들
75
+ * @returns 들여쓰기가 정리된 문자열
76
+ * @example
77
+ * const query = mysql`
78
+ * SELECT *
79
+ * FROM users
80
+ * LIMIT 10
81
+ * `;
82
+ */
83
+ export function mysql(strings: TemplateStringsArray, ...values: unknown[]): string {
84
+ return _combine(strings, values);
85
+ }
86
+
87
+ /**
88
+ * PostgreSQL SQL 하이라이팅용 템플릿 태그
89
+ * @param strings 템플릿 문자열 배열
90
+ * @param values 보간된 값들
91
+ * @returns 들여쓰기가 정리된 문자열
92
+ * @example
93
+ * const query = pgsql`
94
+ * SELECT *
95
+ * FROM users
96
+ * OFFSET 0 LIMIT 10
97
+ * `;
98
+ */
99
+ export function pgsql(strings: TemplateStringsArray, ...values: unknown[]): string {
100
+ return _combine(strings, values);
101
+ }
102
+
103
+ function _combine(strings: TemplateStringsArray, values: unknown[]): string {
104
+ const raw = strings.reduce((result, str, i) => {
105
+ const value = values[i] !== undefined ? String(values[i]) : "";
106
+ return result + str + value;
107
+ }, "");
108
+ return _trimIndent(raw);
109
+ }
110
+
111
+ function _trimIndent(text: string): string {
112
+ const lines = text.split("\n");
113
+
114
+ // 첫/마지막 빈 줄 제거 (연속된 빈 줄 모두 제거)
115
+ while (lines.length > 0 && lines[0].trim() === "") {
116
+ lines.shift();
117
+ }
118
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
119
+ lines.pop();
120
+ }
121
+
122
+ // 최소 들여쓰기 계산
123
+ const minIndent = lines
124
+ .filter((line) => line.trim() !== "")
125
+ .reduce((min, line) => {
126
+ const indent = line.match(/^ */)?.[0].length ?? 0;
127
+ return Math.min(min, indent);
128
+ }, Infinity);
129
+
130
+ // 들여쓰기 제거
131
+ return lines.map((line) => (line.trim() === "" ? "" : line.slice(minIndent))).join("\n");
132
+ }