@simplysm/sd-cli 13.0.69 → 13.0.71

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 (201) hide show
  1. package/README.md +10 -957
  2. package/dist/builders/BaseBuilder.d.ts +23 -23
  3. package/dist/builders/BaseBuilder.d.ts.map +1 -1
  4. package/dist/builders/BaseBuilder.js +15 -15
  5. package/dist/builders/DtsBuilder.d.ts +4 -4
  6. package/dist/builders/DtsBuilder.js +1 -1
  7. package/dist/builders/LibraryBuilder.d.ts +3 -3
  8. package/dist/builders/types.d.ts +10 -10
  9. package/dist/capacitor/capacitor.d.ts +36 -36
  10. package/dist/capacitor/capacitor.js +63 -63
  11. package/dist/capacitor/capacitor.js.map +1 -1
  12. package/dist/commands/add-client.d.ts +8 -8
  13. package/dist/commands/add-client.js +15 -15
  14. package/dist/commands/add-client.js.map +1 -1
  15. package/dist/commands/add-server.d.ts +9 -9
  16. package/dist/commands/add-server.js +13 -13
  17. package/dist/commands/add-server.js.map +1 -1
  18. package/dist/commands/build.d.ts +9 -9
  19. package/dist/commands/check.js +3 -3
  20. package/dist/commands/check.js.map +1 -1
  21. package/dist/commands/dev.d.ts +9 -9
  22. package/dist/commands/device.d.ts +9 -9
  23. package/dist/commands/device.d.ts.map +1 -1
  24. package/dist/commands/device.js +17 -17
  25. package/dist/commands/device.js.map +1 -1
  26. package/dist/commands/init.d.ts +6 -6
  27. package/dist/commands/init.js +12 -12
  28. package/dist/commands/init.js.map +1 -1
  29. package/dist/commands/lint.d.ts +23 -23
  30. package/dist/commands/lint.d.ts.map +1 -1
  31. package/dist/commands/lint.js +25 -25
  32. package/dist/commands/lint.js.map +1 -1
  33. package/dist/commands/publish.d.ts +13 -13
  34. package/dist/commands/publish.d.ts.map +1 -1
  35. package/dist/commands/publish.js +61 -61
  36. package/dist/commands/publish.js.map +1 -1
  37. package/dist/commands/replace-deps.d.ts +3 -3
  38. package/dist/commands/replace-deps.d.ts.map +1 -1
  39. package/dist/commands/replace-deps.js +1 -1
  40. package/dist/commands/replace-deps.js.map +1 -1
  41. package/dist/commands/typecheck.d.ts +20 -20
  42. package/dist/commands/typecheck.d.ts.map +1 -1
  43. package/dist/commands/typecheck.js +20 -20
  44. package/dist/commands/typecheck.js.map +1 -1
  45. package/dist/commands/watch.d.ts +7 -7
  46. package/dist/electron/electron.d.ts +27 -27
  47. package/dist/electron/electron.js +32 -32
  48. package/dist/electron/electron.js.map +1 -1
  49. package/dist/infra/ResultCollector.d.ts +9 -9
  50. package/dist/infra/ResultCollector.js +5 -5
  51. package/dist/infra/SignalHandler.d.ts +7 -7
  52. package/dist/infra/SignalHandler.js +4 -4
  53. package/dist/infra/WorkerManager.d.ts +14 -14
  54. package/dist/infra/WorkerManager.js +11 -11
  55. package/dist/orchestrators/BuildOrchestrator.d.ts +19 -19
  56. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  57. package/dist/orchestrators/BuildOrchestrator.js +26 -26
  58. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  59. package/dist/orchestrators/DevOrchestrator.d.ts +25 -25
  60. package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
  61. package/dist/orchestrators/DevOrchestrator.js +30 -30
  62. package/dist/orchestrators/DevOrchestrator.js.map +1 -1
  63. package/dist/orchestrators/WatchOrchestrator.d.ts +13 -13
  64. package/dist/orchestrators/WatchOrchestrator.js +17 -17
  65. package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
  66. package/dist/sd-cli-entry.d.ts +2 -2
  67. package/dist/sd-cli-entry.js +38 -38
  68. package/dist/sd-cli-entry.js.map +1 -1
  69. package/dist/sd-cli.d.ts +2 -2
  70. package/dist/sd-cli.js +1 -1
  71. package/dist/sd-cli.js.map +1 -1
  72. package/dist/sd-config.types.d.ts +84 -84
  73. package/dist/sd-config.types.d.ts.map +1 -1
  74. package/dist/utils/build-env.d.ts +1 -1
  75. package/dist/utils/config-editor.d.ts +5 -5
  76. package/dist/utils/config-editor.js +2 -2
  77. package/dist/utils/config-editor.js.map +1 -1
  78. package/dist/utils/copy-public.d.ts +9 -9
  79. package/dist/utils/copy-src.d.ts +9 -9
  80. package/dist/utils/esbuild-config.d.ts +30 -30
  81. package/dist/utils/esbuild-config.d.ts.map +1 -1
  82. package/dist/utils/output-utils.d.ts +6 -6
  83. package/dist/utils/package-utils.d.ts +6 -6
  84. package/dist/utils/package-utils.js +1 -1
  85. package/dist/utils/package-utils.js.map +1 -1
  86. package/dist/utils/rebuild-manager.js +3 -3
  87. package/dist/utils/rebuild-manager.js.map +1 -1
  88. package/dist/utils/replace-deps.d.ts +25 -25
  89. package/dist/utils/replace-deps.js +3 -3
  90. package/dist/utils/replace-deps.js.map +1 -1
  91. package/dist/utils/sd-config.d.ts +3 -3
  92. package/dist/utils/sd-config.js +3 -3
  93. package/dist/utils/sd-config.js.map +1 -1
  94. package/dist/utils/tailwind-config-deps.d.ts +3 -3
  95. package/dist/utils/template.d.ts +8 -8
  96. package/dist/utils/tsconfig.d.ts +16 -16
  97. package/dist/utils/tsconfig.js +2 -2
  98. package/dist/utils/tsconfig.js.map +1 -1
  99. package/dist/utils/typecheck-serialization.d.ts +8 -8
  100. package/dist/utils/vite-config.d.ts +8 -8
  101. package/dist/utils/vite-config.d.ts.map +1 -1
  102. package/dist/utils/vite-config.js +3 -3
  103. package/dist/utils/worker-events.d.ts +12 -12
  104. package/dist/utils/worker-events.d.ts.map +1 -1
  105. package/dist/utils/worker-utils.d.ts +3 -3
  106. package/dist/utils/worker-utils.js +2 -2
  107. package/dist/utils/worker-utils.js.map +1 -1
  108. package/dist/workers/client.worker.d.ts +14 -14
  109. package/dist/workers/client.worker.d.ts.map +1 -1
  110. package/dist/workers/client.worker.js +1 -1
  111. package/dist/workers/client.worker.js.map +1 -1
  112. package/dist/workers/dts.worker.d.ts +13 -13
  113. package/dist/workers/dts.worker.d.ts.map +1 -1
  114. package/dist/workers/dts.worker.js +3 -3
  115. package/dist/workers/dts.worker.js.map +1 -1
  116. package/dist/workers/library.worker.d.ts +12 -12
  117. package/dist/workers/library.worker.js +1 -1
  118. package/dist/workers/library.worker.js.map +1 -1
  119. package/dist/workers/lint.worker.d.ts +1 -1
  120. package/dist/workers/server-runtime.worker.d.ts +6 -6
  121. package/dist/workers/server-runtime.worker.js +6 -6
  122. package/dist/workers/server-runtime.worker.js.map +1 -1
  123. package/dist/workers/server.worker.d.ts +20 -20
  124. package/dist/workers/server.worker.d.ts.map +1 -1
  125. package/dist/workers/server.worker.js +6 -6
  126. package/dist/workers/server.worker.js.map +1 -1
  127. package/package.json +8 -7
  128. package/src/builders/BaseBuilder.ts +33 -33
  129. package/src/builders/DtsBuilder.ts +5 -5
  130. package/src/builders/LibraryBuilder.ts +9 -9
  131. package/src/builders/types.ts +10 -10
  132. package/src/capacitor/capacitor.ts +119 -119
  133. package/src/commands/add-client.ts +31 -31
  134. package/src/commands/add-server.ts +34 -34
  135. package/src/commands/build.ts +9 -9
  136. package/src/commands/check.ts +5 -5
  137. package/src/commands/dev.ts +9 -9
  138. package/src/commands/device.ts +30 -30
  139. package/src/commands/init.ts +25 -25
  140. package/src/commands/lint.ts +64 -64
  141. package/src/commands/publish.ts +139 -139
  142. package/src/commands/replace-deps.ts +4 -4
  143. package/src/commands/typecheck.ts +74 -74
  144. package/src/commands/watch.ts +7 -7
  145. package/src/electron/electron.ts +51 -51
  146. package/src/infra/ResultCollector.ts +9 -9
  147. package/src/infra/SignalHandler.ts +7 -7
  148. package/src/infra/WorkerManager.ts +14 -14
  149. package/src/orchestrators/BuildOrchestrator.ts +76 -76
  150. package/src/orchestrators/DevOrchestrator.ts +88 -88
  151. package/src/orchestrators/WatchOrchestrator.ts +39 -39
  152. package/src/sd-cli-entry.ts +43 -43
  153. package/src/sd-cli.ts +15 -15
  154. package/src/sd-config.types.ts +85 -85
  155. package/src/utils/build-env.ts +1 -1
  156. package/src/utils/config-editor.ts +19 -19
  157. package/src/utils/copy-public.ts +17 -17
  158. package/src/utils/copy-src.ts +11 -11
  159. package/src/utils/esbuild-config.ts +33 -33
  160. package/src/utils/output-utils.ts +11 -11
  161. package/src/utils/package-utils.ts +12 -12
  162. package/src/utils/rebuild-manager.ts +3 -3
  163. package/src/utils/replace-deps.ts +361 -361
  164. package/src/utils/sd-config.ts +44 -44
  165. package/src/utils/tailwind-config-deps.ts +98 -98
  166. package/src/utils/template.ts +56 -56
  167. package/src/utils/tsconfig.ts +127 -127
  168. package/src/utils/typecheck-serialization.ts +86 -86
  169. package/src/utils/vite-config.ts +341 -341
  170. package/src/utils/worker-events.ts +16 -16
  171. package/src/utils/worker-utils.ts +45 -45
  172. package/src/workers/client.worker.ts +34 -34
  173. package/src/workers/dts.worker.ts +467 -467
  174. package/src/workers/library.worker.ts +314 -314
  175. package/src/workers/lint.worker.ts +16 -16
  176. package/src/workers/server-runtime.worker.ts +157 -157
  177. package/src/workers/server.worker.ts +572 -572
  178. package/templates/add-client/__CLIENT__/package.json.hbs +1 -1
  179. package/templates/add-server/__SERVER__/package.json.hbs +2 -2
  180. package/templates/init/package.json.hbs +3 -3
  181. package/tests/config-editor.spec.ts +160 -0
  182. package/tests/copy-src.spec.ts +50 -0
  183. package/tests/get-compiler-options-for-package.spec.ts +139 -0
  184. package/tests/get-package-source-files.spec.ts +181 -0
  185. package/tests/get-types-from-package-json.spec.ts +107 -0
  186. package/tests/infra/ResultCollector.spec.ts +39 -0
  187. package/tests/infra/SignalHandler.spec.ts +38 -0
  188. package/tests/infra/WorkerManager.spec.ts +97 -0
  189. package/tests/load-ignore-patterns.spec.ts +188 -0
  190. package/tests/load-sd-config.spec.ts +137 -0
  191. package/tests/package-utils.spec.ts +188 -0
  192. package/tests/parse-root-tsconfig.spec.ts +89 -0
  193. package/tests/replace-deps.spec.ts +308 -0
  194. package/tests/run-lint.spec.ts +415 -0
  195. package/tests/run-typecheck.spec.ts +653 -0
  196. package/tests/run-watch.spec.ts +75 -0
  197. package/tests/sd-cli.spec.ts +330 -0
  198. package/tests/tailwind-config-deps.spec.ts +30 -0
  199. package/tests/template.spec.ts +70 -0
  200. package/tests/utils/rebuild-manager.spec.ts +43 -0
  201. package/tests/write-changed-output-files.spec.ts +97 -0
@@ -17,7 +17,7 @@ import type { SdCapacitorConfig } from "../sd-config.types";
17
17
  import { execa } from "execa";
18
18
 
19
19
  /**
20
- * package.json 타입
20
+ * package.json type
21
21
  */
22
22
  interface NpmConfig {
23
23
  name: string;
@@ -29,7 +29,7 @@ interface NpmConfig {
29
29
  }
30
30
 
31
31
  /**
32
- * 설정 검증 에러
32
+ * Configuration validation error
33
33
  */
34
34
  class CapacitorConfigError extends Error {
35
35
  constructor(message: string) {
@@ -39,11 +39,11 @@ class CapacitorConfigError extends Error {
39
39
  }
40
40
 
41
41
  /**
42
- * Capacitor 프로젝트 관리 클래스
42
+ * Capacitor project management class
43
43
  *
44
- * - Capacitor 프로젝트 초기화
45
- * - Android APK/AAB 빌드
46
- * - 디바이스에서 실행
44
+ * - Initialize Capacitor project
45
+ * - Build Android APK/AAB
46
+ * - Run app on device
47
47
  */
48
48
  export class Capacitor {
49
49
  private static readonly _ANDROID_KEYSTORE_FILE_NAME = "android.keystore";
@@ -65,10 +65,10 @@ export class Capacitor {
65
65
  }
66
66
 
67
67
  /**
68
- * Capacitor 인스턴스 생성 (설정 검증 포함)
68
+ * Create Capacitor instance (with configuration validation)
69
69
  */
70
70
  static async create(pkgPath: string, config: SdCapacitorConfig): Promise<Capacitor> {
71
- // F5: 런타임 설정 검증
71
+ // F5: validate runtime configuration
72
72
  Capacitor._validateConfig(config);
73
73
 
74
74
  const npmConfig = await fsReadJson<NpmConfig>(path.resolve(pkgPath, "package.json"));
@@ -76,48 +76,48 @@ export class Capacitor {
76
76
  }
77
77
 
78
78
  /**
79
- * F5: 설정 검증
79
+ * F5: Validate configuration
80
80
  */
81
81
  private static _validateConfig(config: SdCapacitorConfig): void {
82
82
  if (typeof config.appId !== "string" || config.appId.trim() === "") {
83
- throw new CapacitorConfigError("capacitor.appId 필수입니다.");
83
+ throw new CapacitorConfigError("capacitor.appId is required.");
84
84
  }
85
85
  if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/i.test(config.appId)) {
86
- throw new CapacitorConfigError(`capacitor.appId 형식이 올바르지 않습니다: ${config.appId}`);
86
+ throw new CapacitorConfigError(`capacitor.appId format is invalid: ${config.appId}`);
87
87
  }
88
88
  if (typeof config.appName !== "string" || config.appName.trim() === "") {
89
- throw new CapacitorConfigError("capacitor.appName 필수입니다.");
89
+ throw new CapacitorConfigError("capacitor.appName is required.");
90
90
  }
91
91
  if (config.platform != null) {
92
92
  const platforms = Object.keys(config.platform);
93
93
  for (const p of platforms) {
94
94
  if (p !== "android") {
95
- throw new CapacitorConfigError(`지원하지 않는 플랫폼: ${p} (현재 android 지원)`);
95
+ throw new CapacitorConfigError(`unsupported platform: ${p} (currently only android is supported)`);
96
96
  }
97
97
  }
98
98
  }
99
99
  }
100
100
 
101
101
  /**
102
- * 명령어 실행 (로깅 포함)
102
+ * Execute command (with logging)
103
103
  */
104
104
  private async _exec(cmd: string, args: string[], cwd: string): Promise<string> {
105
- Capacitor._logger.debug(`실행 명령: ${cmd} ${args.join(" ")}`);
105
+ Capacitor._logger.debug(`executed command: ${cmd} ${args.join(" ")}`);
106
106
  const { stdout: result } = await execa(cmd, args, { cwd });
107
- Capacitor._logger.debug(`실행 결과: ${result}`);
107
+ Capacitor._logger.debug(`execution result: ${result}`);
108
108
  return result;
109
109
  }
110
110
 
111
111
  /**
112
- * F10: 동시 실행 방지를 위한 잠금 획득
112
+ * F10: Acquire lock to prevent concurrent execution
113
113
  */
114
114
  private async _acquireLock(): Promise<void> {
115
115
  const lockPath = path.resolve(this._capPath, Capacitor._LOCK_FILE_NAME);
116
116
  if (await fsExists(lockPath)) {
117
117
  const lockContent = await fsRead(lockPath);
118
118
  throw new Error(
119
- `다른 Capacitor 작업이 진행 중입니다 (PID: ${lockContent}). ` +
120
- `문제가 있다면 ${lockPath} 파일을 삭제하세요.`,
119
+ `Another Capacitor operation is in progress (PID: ${lockContent}). ` +
120
+ `If there's an issue, delete the ${lockPath} file.`,
121
121
  );
122
122
  }
123
123
  await fsMkdir(this._capPath);
@@ -125,7 +125,7 @@ export class Capacitor {
125
125
  }
126
126
 
127
127
  /**
128
- * F10: 잠금 해제
128
+ * F10: Release lock
129
129
  */
130
130
  private async _releaseLock(): Promise<void> {
131
131
  const lockPath = path.resolve(this._capPath, Capacitor._LOCK_FILE_NAME);
@@ -133,65 +133,65 @@ export class Capacitor {
133
133
  }
134
134
 
135
135
  /**
136
- * F4: 외부 도구 검증
136
+ * F4: Validate external tools
137
137
  */
138
138
  private async _validateTools(): Promise<void> {
139
- // Android SDK 확인
139
+ // Check Android SDK
140
140
  const sdkPath = await this._findAndroidSdk();
141
141
  if (sdkPath == null) {
142
142
  throw new Error(
143
- "Android SDK 찾을 수 없습니다.\n" +
144
- "1. Android Studio 설치하거나\n" +
145
- "2. ANDROID_HOME 또는 ANDROID_SDK_ROOT 환경변수를 설정하세요.",
143
+ "Android SDK not found.\n" +
144
+ "1. Install Android Studio or\n" +
145
+ "2. Set ANDROID_HOME or ANDROID_SDK_ROOT environment variable.",
146
146
  );
147
147
  }
148
148
 
149
- // Java 확인 (android 플랫폼일 때만)
149
+ // Check Java (only for android platform)
150
150
  if (this._platforms.includes("android")) {
151
151
  const javaPath = await this._findJava21();
152
152
  if (javaPath == null) {
153
153
  Capacitor._logger.warn(
154
- "Java 21 찾을 없습니다. Gradle 내장 JDK 사용하거나 빌드가 실패할 있습니다.",
154
+ "Java 21 not found. Gradle may use embedded JDK or the build may fail.",
155
155
  );
156
156
  }
157
157
  }
158
158
  }
159
159
 
160
160
  /**
161
- * Capacitor 프로젝트 초기화
161
+ * Initialize Capacitor project
162
162
  *
163
- * 1. package.json 생성 의존성 설치
164
- * 2. capacitor.config.ts 생성
165
- * 3. 플랫폼 추가 (android)
166
- * 4. 아이콘 설정
167
- * 5. Android 네이티브 설정
168
- * 6. cap sync 또는 cap copy 실행
163
+ * 1. Create package.json and install dependencies
164
+ * 2. Create capacitor.config.ts
165
+ * 3. Add platform (android)
166
+ * 4. Set up icon
167
+ * 5. Configure Android native settings
168
+ * 6. Run cap sync or cap copy
169
169
  */
170
170
  async initialize(): Promise<void> {
171
171
  await this._acquireLock();
172
172
 
173
173
  try {
174
- // F4: 외부 도구 검증
174
+ // F4: Validate external tools
175
175
  await this._validateTools();
176
176
 
177
- // 1. Capacitor 프로젝트 초기화
177
+ // 1. Initialize Capacitor project
178
178
  const changed = await this._initCap();
179
179
 
180
- // 2. Capacitor 설정 파일 생성
180
+ // 2. Create Capacitor config file
181
181
  await this._writeCapConf();
182
182
 
183
- // 3. 플랫폼 관리 (F12: 멱등성 - 이미 존재하면 스킵)
183
+ // 3. Manage platform (F12: idempotent - skip if already exists)
184
184
  await this._addPlatforms();
185
185
 
186
- // 4. 아이콘 설정 (F6: 에러 복구)
186
+ // 4. Set up icon (F6: error recovery)
187
187
  await this._setupIcon();
188
188
 
189
- // 5. Android 네이티브 설정
189
+ // 5. Configure Android native settings
190
190
  if (this._platforms.includes("android")) {
191
191
  await this._configureAndroid();
192
192
  }
193
193
 
194
- // 6. 자산 동기화
194
+ // 6. Synchronize web assets
195
195
  if (changed) {
196
196
  await this._exec("npx", ["cap", "sync"], this._capPath);
197
197
  } else {
@@ -203,7 +203,7 @@ export class Capacitor {
203
203
  }
204
204
 
205
205
  /**
206
- * Android APK/AAB 빌드
206
+ * Build Android APK/AAB
207
207
  */
208
208
  async build(outPath: string): Promise<void> {
209
209
  await this._acquireLock();
@@ -217,7 +217,7 @@ export class Capacitor {
217
217
  if (platform === "android") {
218
218
  await this._buildAndroid(outPath, buildType);
219
219
  } else {
220
- throw new Error(`지원하지 않는 플랫폼: ${platform}`);
220
+ throw new Error(`unsupported platform: ${platform}`);
221
221
  }
222
222
  }
223
223
  } finally {
@@ -226,10 +226,10 @@ export class Capacitor {
226
226
  }
227
227
 
228
228
  /**
229
- * 디바이스에서 실행 (WebView 개발 서버로 연결)
229
+ * Run app on device (connect WebView to development server)
230
230
  */
231
231
  async runOnDevice(url?: string): Promise<void> {
232
- // F11: URL 검증
232
+ // F11: Validate URL
233
233
  if (url != null) {
234
234
  this._validateUrl(url);
235
235
  await this._updateServerUrl(url);
@@ -245,7 +245,7 @@ export class Capacitor {
245
245
  try {
246
246
  await this._exec("adb", ["kill-server"], this._capPath);
247
247
  } catch {
248
- // adb kill-server 실패는 무시
248
+ // adb kill-server failure is ignored
249
249
  }
250
250
  }
251
251
  throw err;
@@ -254,26 +254,26 @@ export class Capacitor {
254
254
  }
255
255
 
256
256
  /**
257
- * F11: URL 검증
257
+ * F11: Validate URL
258
258
  */
259
259
  private _validateUrl(url: string): void {
260
260
  try {
261
261
  const parsed = new URL(url);
262
262
  if (!["http:", "https:"].includes(parsed.protocol)) {
263
- throw new Error(`지원하지 않는 프로토콜: ${parsed.protocol}`);
263
+ throw new Error(`unsupported protocol: ${parsed.protocol}`);
264
264
  }
265
265
  } catch (err) {
266
266
  if (err instanceof TypeError) {
267
- throw new Error(`유효하지 않은 URL: ${url}`);
267
+ throw new Error(`invalid URL: ${url}`);
268
268
  }
269
269
  throw err;
270
270
  }
271
271
  }
272
272
 
273
- //#region Private - 초기화
273
+ //#region Private - Initialization
274
274
 
275
275
  /**
276
- * Capacitor 프로젝트 기본 초기화 (package.json, npm install, cap init)
276
+ * Basic Capacitor project initialization (package.json, npm install, cap init)
277
277
  */
278
278
  private async _initCap(): Promise<boolean> {
279
279
  const depChanged = await this._setupNpmConf();
@@ -281,9 +281,9 @@ export class Capacitor {
281
281
 
282
282
  // pnpm install
283
283
  const installResult = await this._exec("pnpm", ["install"], this._capPath);
284
- Capacitor._logger.debug(`pnpm install 완료: ${installResult}`);
284
+ Capacitor._logger.debug(`pnpm install completed: ${installResult}`);
285
285
 
286
- // F12: cap init 멱등성 - capacitor.config.ts 없을 때만 실행
286
+ // F12: cap init idempotency - execute only when capacitor.config.ts does not exist
287
287
  const configPath = path.resolve(this._capPath, "capacitor.config.ts");
288
288
  if (!(await fsExists(configPath))) {
289
289
  await this._exec(
@@ -293,7 +293,7 @@ export class Capacitor {
293
293
  );
294
294
  }
295
295
 
296
- // 기본 www/index.html 생성
296
+ // Create default www/index.html
297
297
  const wwwPath = path.resolve(this._capPath, "www");
298
298
  await fsMkdir(wwwPath);
299
299
  await fsWrite(
@@ -305,14 +305,14 @@ export class Capacitor {
305
305
  }
306
306
 
307
307
  /**
308
- * package.json 설정
308
+ * Configure package.json
309
309
  */
310
310
  private async _setupNpmConf(): Promise<boolean> {
311
311
  const projNpmConfigPath = path.resolve(this._pkgPath, "../../package.json");
312
312
 
313
- // F3: 파일 존재 확인
313
+ // F3: Check if file exists
314
314
  if (!(await fsExists(projNpmConfigPath))) {
315
- throw new Error(`루트 package.json 찾을 없습니다: ${projNpmConfigPath}`);
315
+ throw new Error(`root package.json not found: ${projNpmConfigPath}`);
316
316
  }
317
317
 
318
318
  const projNpmConfig = await fsReadJson<NpmConfig>(projNpmConfigPath);
@@ -329,7 +329,7 @@ export class Capacitor {
329
329
  capNpmConf.volta = projNpmConfig.volta;
330
330
  }
331
331
 
332
- // 기본 의존성
332
+ // Default dependencies
333
333
  capNpmConf.dependencies = capNpmConf.dependencies ?? {};
334
334
  capNpmConf.dependencies["@capacitor/core"] = "^7.0.0";
335
335
  capNpmConf.dependencies["@capacitor/app"] = "^7.0.0";
@@ -341,7 +341,7 @@ export class Capacitor {
341
341
  capNpmConf.devDependencies["@capacitor/cli"] = "^7.0.0";
342
342
  capNpmConf.devDependencies["@capacitor/assets"] = "^3.0.0";
343
343
 
344
- // 플러그인 패키지 설정
344
+ // Configure plugin packages
345
345
  const mainDeps = {
346
346
  ...this._npmConfig.dependencies,
347
347
  ...this._npmConfig.devDependencies,
@@ -357,28 +357,28 @@ export class Capacitor {
357
357
  ),
358
358
  );
359
359
 
360
- // 사용하지 않는 플러그인 제거
360
+ // Remove unused plugins
361
361
  for (const prevPlugin of prevPlugins) {
362
362
  if (!usePlugins.includes(prevPlugin)) {
363
363
  delete capNpmConf.dependencies[prevPlugin];
364
- Capacitor._logger.debug(`플러그인 제거: ${prevPlugin}`);
364
+ Capacitor._logger.debug(`plugin removed: ${prevPlugin}`);
365
365
  }
366
366
  }
367
367
 
368
- // 플러그인 추가
368
+ // Add new plugins
369
369
  for (const plugin of usePlugins) {
370
370
  if (!(plugin in capNpmConf.dependencies)) {
371
371
  const version = mainDeps[plugin] ?? "*";
372
372
  capNpmConf.dependencies[plugin] = version;
373
- Capacitor._logger.debug(`플러그인 추가: ${plugin}@${version}`);
373
+ Capacitor._logger.debug(`plugin added: ${plugin}@${version}`);
374
374
  }
375
375
  }
376
376
 
377
- // 저장
377
+ // Save
378
378
  await fsMkdir(this._capPath);
379
379
  await fsWriteJson(capNpmConfPath, capNpmConf, { space: 2 });
380
380
 
381
- // 의존성 변경 여부 확인
381
+ // Check if dependencies changed
382
382
  const isChanged =
383
383
  orgCapNpmConf.volta !== capNpmConf.volta ||
384
384
  JSON.stringify(orgCapNpmConf.dependencies) !== JSON.stringify(capNpmConf.dependencies) ||
@@ -388,12 +388,12 @@ export class Capacitor {
388
388
  }
389
389
 
390
390
  /**
391
- * capacitor.config.ts 생성
391
+ * Create capacitor.config.ts
392
392
  */
393
393
  private async _writeCapConf(): Promise<void> {
394
394
  const confPath = path.resolve(this._capPath, "capacitor.config.ts");
395
395
 
396
- // 플러그인 옵션 생성
396
+ // Create plugin options
397
397
  const pluginOptions: Record<string, Record<string, unknown>> = {};
398
398
  for (const [pluginName, options] of Object.entries(this._config.plugins ?? {})) {
399
399
  if (options !== true) {
@@ -427,13 +427,13 @@ export default config;
427
427
  }
428
428
 
429
429
  /**
430
- * 플랫폼 추가 (F12: 멱등성 보장)
430
+ * Add platform (F12: ensure idempotency)
431
431
  */
432
432
  private async _addPlatforms(): Promise<void> {
433
433
  for (const platform of this._platforms) {
434
434
  const platformPath = path.resolve(this._capPath, platform);
435
435
  if (await fsExists(platformPath)) {
436
- Capacitor._logger.debug(`플랫폼 이미 존재: ${platform}`);
436
+ Capacitor._logger.debug(`platform already exists: ${platform}`);
437
437
  continue;
438
438
  }
439
439
 
@@ -442,7 +442,7 @@ export default config;
442
442
  }
443
443
 
444
444
  /**
445
- * 아이콘 설정 (F6: 에러 복구)
445
+ * Set up icon (F6: error recovery)
446
446
  */
447
447
  private async _setupIcon(): Promise<void> {
448
448
  const assetsDirPath = path.resolve(this._capPath, "assets");
@@ -450,10 +450,10 @@ export default config;
450
450
  if (this._config.icon != null) {
451
451
  const iconSource = path.resolve(this._pkgPath, this._config.icon);
452
452
 
453
- // F6: 소스 아이콘 존재 확인
453
+ // F6: Check if source icon exists
454
454
  if (!(await fsExists(iconSource))) {
455
455
  Capacitor._logger.warn(
456
- `아이콘 파일을 찾을 없습니다: ${iconSource}. 기본 아이콘을 사용합니다.`,
456
+ `icon file not found: ${iconSource}. Using default icon.`,
457
457
  );
458
458
  return;
459
459
  }
@@ -461,13 +461,13 @@ export default config;
461
461
  try {
462
462
  await fsMkdir(assetsDirPath);
463
463
 
464
- // 아이콘 생성
464
+ // Create icon
465
465
  const logoPath = path.resolve(assetsDirPath, "logo.png");
466
466
 
467
467
  const logoSize = Math.floor(1024 * 0.6);
468
468
  const padding = Math.floor((1024 - logoSize) / 2);
469
469
 
470
- // F6: sharp 에러 처리
470
+ // F6: Handle sharp errors
471
471
  await sharp(iconSource)
472
472
  .resize(logoSize, logoSize, {
473
473
  fit: "contain",
@@ -496,9 +496,9 @@ export default config;
496
496
  );
497
497
  } catch (err) {
498
498
  Capacitor._logger.warn(
499
- `아이콘 생성 실패: ${err instanceof Error ? err.message : err}. 기본 아이콘을 사용합니다.`,
499
+ `icon generation failed: ${err instanceof Error ? err.message : err}. Using default icon.`,
500
500
  );
501
- // F6: 실패해도 계속 진행 (기본 아이콘 사용)
501
+ // F6: Continue even if it fails (use default icon)
502
502
  }
503
503
  } else {
504
504
  await fsRm(assetsDirPath);
@@ -507,17 +507,17 @@ export default config;
507
507
 
508
508
  //#endregion
509
509
 
510
- //#region Private - Android 설정
510
+ //#region Private - Android Configuration
511
511
 
512
512
  /**
513
- * Android 네이티브 설정
513
+ * Configure Android native settings
514
514
  */
515
515
  private async _configureAndroid(): Promise<void> {
516
516
  const androidPath = path.resolve(this._capPath, "android");
517
517
 
518
- // F3: Android 디렉토리 존재 확인
518
+ // F3: Check if Android directory exists
519
519
  if (!(await fsExists(androidPath))) {
520
- throw new Error(`Android 프로젝트 디렉토리가 없습니다: ${androidPath}`);
520
+ throw new Error(`Android project directory not found: ${androidPath}`);
521
521
  }
522
522
 
523
523
  await this._configureAndroidJavaHomePath(androidPath);
@@ -527,14 +527,14 @@ export default config;
527
527
  }
528
528
 
529
529
  /**
530
- * JAVA_HOME 경로 설정 (gradle.properties)
530
+ * Set up JAVA_HOME path (gradle.properties)
531
531
  */
532
532
  private async _configureAndroidJavaHomePath(androidPath: string): Promise<void> {
533
533
  const gradlePropsPath = path.resolve(androidPath, "gradle.properties");
534
534
 
535
- // F3: 파일 존재 확인
535
+ // F3: Check if file exists
536
536
  if (!(await fsExists(gradlePropsPath))) {
537
- Capacitor._logger.warn(`gradle.properties 파일이 없습니다: ${gradlePropsPath}`);
537
+ Capacitor._logger.warn(`gradle.properties file not found: ${gradlePropsPath}`);
538
538
  return;
539
539
  }
540
540
 
@@ -542,7 +542,7 @@ export default config;
542
542
 
543
543
  const java21Path = await this._findJava21();
544
544
  if (java21Path != null && !content.includes("org.gradle.java.home")) {
545
- // F9: Windows 경로 이스케이프 개선
545
+ // F9: Improved Windows path escaping
546
546
  const escapedPath = java21Path.replace(/\\/g, "\\\\");
547
547
  content += `\norg.gradle.java.home=${escapedPath}\n`;
548
548
  await fsWrite(gradlePropsPath, content);
@@ -550,7 +550,7 @@ export default config;
550
550
  }
551
551
 
552
552
  /**
553
- * Java 21 경로 자동 탐색
553
+ * Auto-detect Java 21 path
554
554
  */
555
555
  private async _findJava21(): Promise<string | undefined> {
556
556
  const patterns = [
@@ -573,26 +573,26 @@ export default config;
573
573
  }
574
574
 
575
575
  /**
576
- * Android SDK 경로 설정 (local.properties)
576
+ * Set up Android SDK path (local.properties)
577
577
  */
578
578
  private async _configureAndroidSdkPath(androidPath: string): Promise<void> {
579
579
  const localPropsPath = path.resolve(androidPath, "local.properties");
580
580
 
581
581
  const sdkPath = await this._findAndroidSdk();
582
582
  if (sdkPath != null) {
583
- // F9: 항상 forward slash 사용 (Gradle 호환)
583
+ // F9: Always use forward slash (Gradle compatible)
584
584
  await fsWrite(localPropsPath, `sdk.dir=${sdkPath.replace(/\\/g, "/")}\n`);
585
585
  } else {
586
586
  throw new Error(
587
- "Android SDK 찾을 수 없습니다.\n" +
588
- "1. Android Studio 설치하거나\n" +
589
- "2. ANDROID_HOME 또는 ANDROID_SDK_ROOT 환경변수를 설정하세요.",
587
+ "Android SDK not found.\n" +
588
+ "1. Install Android Studio or\n" +
589
+ "2. Set ANDROID_HOME or ANDROID_SDK_ROOT environment variable.",
590
590
  );
591
591
  }
592
592
  }
593
593
 
594
594
  /**
595
- * Android SDK 경로 탐색
595
+ * Search for Android SDK path
596
596
  */
597
597
  private async _findAndroidSdk(): Promise<string | undefined> {
598
598
  const fromEnv = (env["ANDROID_HOME"] ?? env["ANDROID_SDK_ROOT"]) as string | undefined;
@@ -617,24 +617,24 @@ export default config;
617
617
  }
618
618
 
619
619
  /**
620
- * AndroidManifest.xml 수정 (F3: 에러 처리 추가)
620
+ * Modify AndroidManifest.xml (F3: add error handling)
621
621
  */
622
622
  private async _configureAndroidManifest(androidPath: string): Promise<void> {
623
623
  const manifestPath = path.resolve(androidPath, "app/src/main/AndroidManifest.xml");
624
624
 
625
- // F3: 파일 존재 확인
625
+ // F3: Check if file exists
626
626
  if (!(await fsExists(manifestPath))) {
627
- throw new Error(`AndroidManifest.xml 파일이 없습니다: ${manifestPath}`);
627
+ throw new Error(`AndroidManifest.xml file not found: ${manifestPath}`);
628
628
  }
629
629
 
630
630
  let content = await fsRead(manifestPath);
631
631
 
632
- // usesCleartextTraffic 설정
632
+ // Configure usesCleartextTraffic
633
633
  if (!content.includes("android:usesCleartextTraffic")) {
634
634
  content = content.replace("<application", '<application android:usesCleartextTraffic="true"');
635
635
  }
636
636
 
637
- // 추가 권한 설정
637
+ // Configure additional permissions
638
638
  const permissions = this._config.platform?.android?.permissions ?? [];
639
639
  for (const perm of permissions) {
640
640
  const permTag = `<uses-permission android:name="android.permission.${perm.name}"`;
@@ -655,7 +655,7 @@ export default config;
655
655
  }
656
656
  }
657
657
 
658
- // 추가 application 설정
658
+ // Configure additional application settings
659
659
  const appConfig = this._config.platform?.android?.config;
660
660
  if (appConfig) {
661
661
  for (const [key, value] of Object.entries(appConfig)) {
@@ -666,7 +666,7 @@ export default config;
666
666
  }
667
667
  }
668
668
 
669
- // intentFilters 설정
669
+ // Configure intentFilters
670
670
  const intentFilters = this._config.platform?.android?.intentFilters ?? [];
671
671
  for (const filter of intentFilters) {
672
672
  const filterKey = filter.action ?? filter.category ?? "";
@@ -690,19 +690,19 @@ export default config;
690
690
  }
691
691
 
692
692
  /**
693
- * build.gradle 수정 (F3: 에러 처리 추가)
693
+ * Modify build.gradle (F3: add error handling)
694
694
  */
695
695
  private async _configureAndroidBuildGradle(androidPath: string): Promise<void> {
696
696
  const buildGradlePath = path.resolve(androidPath, "app/build.gradle");
697
697
 
698
- // F3: 파일 존재 확인
698
+ // F3: Check if file exists
699
699
  if (!(await fsExists(buildGradlePath))) {
700
- throw new Error(`build.gradle 파일이 없습니다: ${buildGradlePath}`);
700
+ throw new Error(`build.gradle file not found: ${buildGradlePath}`);
701
701
  }
702
702
 
703
703
  let content = await fsRead(buildGradlePath);
704
704
 
705
- // versionName, versionCode 설정
705
+ // Configure versionName and versionCode
706
706
  const version = this._npmConfig.version;
707
707
  const cleanVersion = version.replace(/-.*$/, "");
708
708
  const versionParts = cleanVersion.split(".");
@@ -714,7 +714,7 @@ export default config;
714
714
  content = content.replace(/versionCode \d+/, `versionCode ${versionCode}`);
715
715
  content = content.replace(/versionName "[^"]+"/, `versionName "${version}"`);
716
716
 
717
- // SDK 버전 설정
717
+ // Configure SDK version
718
718
  if (this._config.platform?.android?.sdkVersion != null) {
719
719
  const sdkVersion = this._config.platform.android.sdkVersion;
720
720
  content = content.replace(/minSdkVersion .+/, `minSdkVersion ${sdkVersion}`);
@@ -727,18 +727,18 @@ export default config;
727
727
  );
728
728
  }
729
729
 
730
- // Signing 설정
730
+ // Configure signing
731
731
  const keystorePath = path.resolve(this._capPath, Capacitor._ANDROID_KEYSTORE_FILE_NAME);
732
732
  const signConfig = this._config.platform?.android?.sign;
733
733
  if (signConfig) {
734
734
  const keystoreSource = path.resolve(this._pkgPath, signConfig.keystore);
735
- // F3: keystore 파일 존재 확인
735
+ // F3: Check if keystore file exists
736
736
  if (!(await fsExists(keystoreSource))) {
737
- throw new Error(`keystore 파일을 찾을 없습니다: ${keystoreSource}`);
737
+ throw new Error(`keystore file not found: ${keystoreSource}`);
738
738
  }
739
739
  await fsCopy(keystoreSource, keystorePath);
740
740
 
741
- // F9: 상대 경로를 forward slash로 변환
741
+ // F9: Convert relative path to forward slash
742
742
  const keystoreRelativePath = path
743
743
  .relative(path.dirname(buildGradlePath), keystorePath)
744
744
  .replace(/\\/g, "/");
@@ -774,10 +774,10 @@ export default config;
774
774
 
775
775
  //#endregion
776
776
 
777
- //#region Private - 빌드
777
+ //#region Private - Build
778
778
 
779
779
  /**
780
- * Android 빌드
780
+ * Build Android
781
781
  */
782
782
  private async _buildAndroid(outPath: string, buildType: string): Promise<void> {
783
783
  const androidPath = path.resolve(this._capPath, "android");
@@ -787,20 +787,20 @@ export default config;
787
787
  const gradleTask =
788
788
  buildType === "release" ? (isBundle ? "bundleRelease" : "assembleRelease") : "assembleDebug";
789
789
 
790
- // Gradle 빌드 실행 (크로스 플랫폼)
791
- // F9: Windows에서 cmd.exe 통해 실행 (shell: false 이므로)
790
+ // Execute Gradle build (cross-platform)
791
+ // F9: Run via cmd.exe on Windows (because shell: false)
792
792
  if (process.platform === "win32") {
793
793
  await this._exec("cmd", ["/c", "gradlew.bat", gradleTask, "--no-daemon"], androidPath);
794
794
  } else {
795
795
  await this._exec("sh", ["./gradlew", gradleTask, "--no-daemon"], androidPath);
796
796
  }
797
797
 
798
- // 빌드 결과물 복사
798
+ // Copy build output
799
799
  await this._copyAndroidBuildOutput(androidPath, targetOutPath, buildType);
800
800
  }
801
801
 
802
802
  /**
803
- * Android 빌드 결과물 복사
803
+ * Copy Android build output
804
804
  */
805
805
  private async _copyAndroidBuildOutput(
806
806
  androidPath: string,
@@ -833,7 +833,7 @@ export default config;
833
833
  );
834
834
 
835
835
  if (!(await fsExists(actualPath))) {
836
- Capacitor._logger.warn(`빌드 결과물을 찾을 없습니다: ${actualPath}`);
836
+ Capacitor._logger.warn(`build output not found: ${actualPath}`);
837
837
  return;
838
838
  }
839
839
 
@@ -842,7 +842,7 @@ export default config;
842
842
  await fsMkdir(targetOutPath);
843
843
  await fsCopy(actualPath, path.resolve(targetOutPath, outputFileName));
844
844
 
845
- // 버전별 저장
845
+ // Save per-version
846
846
  const updatesPath = path.resolve(targetOutPath, "updates");
847
847
  await fsMkdir(updatesPath);
848
848
  await fsCopy(actualPath, path.resolve(updatesPath, `${this._npmConfig.version}.${ext}`));
@@ -850,10 +850,10 @@ export default config;
850
850
 
851
851
  //#endregion
852
852
 
853
- //#region Private - 디바이스 실행
853
+ //#region Private - Device Execution
854
854
 
855
855
  /**
856
- * capacitor.config.ts의 server.url 업데이트
856
+ * Update server.url in capacitor.config.ts
857
857
  */
858
858
  private async _updateServerUrl(url: string): Promise<void> {
859
859
  const configPath = path.resolve(this._capPath, "capacitor.config.ts");
@@ -873,10 +873,10 @@ export default config;
873
873
 
874
874
  //#endregion
875
875
 
876
- //#region Private - 유틸리티
876
+ //#region Private - Utilities
877
877
 
878
878
  /**
879
- * 문자열을 PascalCase로 변환
879
+ * Convert string to PascalCase
880
880
  */
881
881
  private _toPascalCase(str: string): string {
882
882
  return str