@simplysm/sd-cli 14.0.42 → 14.0.43

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 (321) hide show
  1. package/dist/angular/angular-compiler.d.ts +0 -35
  2. package/dist/angular/angular-compiler.d.ts.map +1 -1
  3. package/dist/angular/angular-compiler.js +0 -374
  4. package/dist/angular/angular-compiler.js.map +1 -1
  5. package/dist/angular/hmr-candidates.d.ts +13 -0
  6. package/dist/angular/hmr-candidates.d.ts.map +1 -0
  7. package/dist/angular/hmr-candidates.js +230 -0
  8. package/dist/angular/hmr-candidates.js.map +1 -0
  9. package/dist/angular/ngtsc-build-core.d.ts +29 -34
  10. package/dist/angular/ngtsc-build-core.d.ts.map +1 -1
  11. package/dist/angular/ngtsc-build-core.js +90 -51
  12. package/dist/angular/ngtsc-build-core.js.map +1 -1
  13. package/dist/angular/vite-angular-plugin.d.ts +1 -1
  14. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  15. package/dist/angular/vite-angular-plugin.js +63 -56
  16. package/dist/angular/vite-angular-plugin.js.map +1 -1
  17. package/dist/angular/web-worker-transformer.d.ts +9 -0
  18. package/dist/angular/web-worker-transformer.d.ts.map +1 -0
  19. package/dist/angular/web-worker-transformer.js +73 -0
  20. package/dist/angular/web-worker-transformer.js.map +1 -0
  21. package/dist/capacitor/capacitor.d.ts.map +1 -1
  22. package/dist/capacitor/capacitor.js +6 -4
  23. package/dist/capacitor/capacitor.js.map +1 -1
  24. package/dist/commands/check.d.ts +1 -1
  25. package/dist/commands/check.d.ts.map +1 -1
  26. package/dist/commands/check.js +15 -65
  27. package/dist/commands/check.js.map +1 -1
  28. package/dist/commands/publish/deployment-phase.d.ts.map +1 -1
  29. package/dist/commands/publish/deployment-phase.js +13 -5
  30. package/dist/commands/publish/deployment-phase.js.map +1 -1
  31. package/dist/commands/publish/npm-publisher.js +1 -1
  32. package/dist/commands/publish/npm-publisher.js.map +1 -1
  33. package/dist/commands/publish/publish-command.js +1 -1
  34. package/dist/commands/publish/publish-command.js.map +1 -1
  35. package/dist/commands/publish/version-upgrade.js +1 -1
  36. package/dist/commands/publish/version-upgrade.js.map +1 -1
  37. package/dist/commands/replace-deps.d.ts.map +1 -1
  38. package/dist/commands/replace-deps.js +2 -1
  39. package/dist/commands/replace-deps.js.map +1 -1
  40. package/dist/deps/replace-deps/collect-deps.d.ts.map +1 -1
  41. package/dist/deps/replace-deps/collect-deps.js +5 -2
  42. package/dist/deps/replace-deps/collect-deps.js.map +1 -1
  43. package/dist/deps/replace-deps/replace-deps.d.ts +21 -3
  44. package/dist/deps/replace-deps/replace-deps.d.ts.map +1 -1
  45. package/dist/deps/replace-deps/replace-deps.js +107 -62
  46. package/dist/deps/replace-deps/replace-deps.js.map +1 -1
  47. package/dist/electron/electron.js +7 -7
  48. package/dist/electron/electron.js.map +1 -1
  49. package/dist/engines/BaseEngine.d.ts.map +1 -1
  50. package/dist/engines/BaseEngine.js +2 -5
  51. package/dist/engines/BaseEngine.js.map +1 -1
  52. package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
  53. package/dist/engines/EsbuildClientEngine.js +16 -9
  54. package/dist/engines/EsbuildClientEngine.js.map +1 -1
  55. package/dist/engines/NgtscEngine.d.ts +4 -4
  56. package/dist/engines/NgtscEngine.d.ts.map +1 -1
  57. package/dist/engines/NgtscEngine.js +5 -5
  58. package/dist/engines/NgtscEngine.js.map +1 -1
  59. package/dist/engines/TscEngine.d.ts.map +1 -1
  60. package/dist/engines/TscEngine.js +0 -2
  61. package/dist/engines/TscEngine.js.map +1 -1
  62. package/dist/engines/types.d.ts +2 -0
  63. package/dist/engines/types.d.ts.map +1 -1
  64. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts +36 -0
  65. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -0
  66. package/dist/esbuild/esbuild-angular-compiler-plugin.js +464 -0
  67. package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -0
  68. package/dist/esbuild/esbuild-client-config.d.ts +8 -2
  69. package/dist/esbuild/esbuild-client-config.d.ts.map +1 -1
  70. package/dist/esbuild/esbuild-client-config.js +48 -33
  71. package/dist/esbuild/esbuild-client-config.js.map +1 -1
  72. package/dist/esbuild/esbuild-tsc-plugin.d.ts +4 -1
  73. package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -1
  74. package/dist/esbuild/esbuild-tsc-plugin.js +27 -23
  75. package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -1
  76. package/dist/esbuild/file-reference-tracker.d.ts +24 -0
  77. package/dist/esbuild/file-reference-tracker.d.ts.map +1 -0
  78. package/dist/esbuild/file-reference-tracker.js +57 -0
  79. package/dist/esbuild/file-reference-tracker.js.map +1 -0
  80. package/dist/esbuild/lmdb-cache-store.d.ts +18 -0
  81. package/dist/esbuild/lmdb-cache-store.d.ts.map +1 -0
  82. package/dist/esbuild/lmdb-cache-store.js +41 -0
  83. package/dist/esbuild/lmdb-cache-store.js.map +1 -0
  84. package/dist/esbuild/load-result-cache.d.ts +17 -0
  85. package/dist/esbuild/load-result-cache.d.ts.map +1 -0
  86. package/dist/esbuild/load-result-cache.js +61 -0
  87. package/dist/esbuild/load-result-cache.js.map +1 -0
  88. package/dist/index.d.ts +3 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +2 -0
  91. package/dist/index.js.map +1 -1
  92. package/dist/lint/lint-core.js +7 -7
  93. package/dist/lint/lint-core.js.map +1 -1
  94. package/dist/orchestrators/BaseOrchestrator.js +2 -2
  95. package/dist/orchestrators/BaseOrchestrator.js.map +1 -1
  96. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  97. package/dist/orchestrators/BuildOrchestrator.js +5 -19
  98. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  99. package/dist/orchestrators/DevOrchestrator.js +5 -5
  100. package/dist/orchestrators/DevOrchestrator.js.map +1 -1
  101. package/dist/orchestrators/WatchOrchestrator.js +6 -6
  102. package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
  103. package/dist/runtime/ResultCollector.d.ts +1 -0
  104. package/dist/runtime/ResultCollector.d.ts.map +1 -1
  105. package/dist/runtime/ResultCollector.js.map +1 -1
  106. package/dist/runtime/engine-watch-events.d.ts.map +1 -1
  107. package/dist/runtime/engine-watch-events.js +3 -0
  108. package/dist/runtime/engine-watch-events.js.map +1 -1
  109. package/dist/runtime/rebuild-manager.js +1 -1
  110. package/dist/runtime/rebuild-manager.js.map +1 -1
  111. package/dist/runtime/worker-utils.js +1 -1
  112. package/dist/runtime/worker-utils.js.map +1 -1
  113. package/dist/sd-cli-entry.d.ts.map +1 -1
  114. package/dist/sd-cli-entry.js +4 -3
  115. package/dist/sd-cli-entry.js.map +1 -1
  116. package/dist/sd-cli.js +3 -3
  117. package/dist/sd-cli.js.map +1 -1
  118. package/dist/ts-compiler/SdTsCompiler.d.ts +39 -0
  119. package/dist/ts-compiler/SdTsCompiler.d.ts.map +1 -0
  120. package/dist/ts-compiler/SdTsCompiler.js +593 -0
  121. package/dist/ts-compiler/SdTsCompiler.js.map +1 -0
  122. package/dist/ts-compiler/sd-ts-compiler-options.d.ts +40 -0
  123. package/dist/ts-compiler/sd-ts-compiler-options.d.ts.map +1 -0
  124. package/dist/ts-compiler/sd-ts-compiler-options.js +2 -0
  125. package/dist/ts-compiler/sd-ts-compiler-options.js.map +1 -0
  126. package/dist/ts-compiler/sd-ts-compiler-result.d.ts +34 -0
  127. package/dist/ts-compiler/sd-ts-compiler-result.d.ts.map +1 -0
  128. package/dist/ts-compiler/sd-ts-compiler-result.js +2 -0
  129. package/dist/ts-compiler/sd-ts-compiler-result.js.map +1 -0
  130. package/dist/utils/copy-public.d.ts +6 -4
  131. package/dist/utils/copy-public.d.ts.map +1 -1
  132. package/dist/utils/copy-public.js +9 -7
  133. package/dist/utils/copy-public.js.map +1 -1
  134. package/dist/utils/diagnostic-utils.d.ts +2 -3
  135. package/dist/utils/diagnostic-utils.d.ts.map +1 -1
  136. package/dist/utils/diagnostic-utils.js +8 -9
  137. package/dist/utils/diagnostic-utils.js.map +1 -1
  138. package/dist/utils/output-utils.d.ts +8 -2
  139. package/dist/utils/output-utils.d.ts.map +1 -1
  140. package/dist/utils/output-utils.js +32 -8
  141. package/dist/utils/output-utils.js.map +1 -1
  142. package/dist/workers/client.worker.d.ts +1 -1
  143. package/dist/workers/client.worker.d.ts.map +1 -1
  144. package/dist/workers/client.worker.js +136 -110
  145. package/dist/workers/client.worker.js.map +1 -1
  146. package/dist/workers/library-build.worker.d.ts +0 -2
  147. package/dist/workers/library-build.worker.d.ts.map +1 -1
  148. package/dist/workers/library-build.worker.js +147 -70
  149. package/dist/workers/library-build.worker.js.map +1 -1
  150. package/dist/workers/server-build.worker.d.ts.map +1 -1
  151. package/dist/workers/server-build.worker.js +30 -57
  152. package/dist/workers/server-build.worker.js.map +1 -1
  153. package/dist/workers/server-esbuild-context.d.ts +7 -0
  154. package/dist/workers/server-esbuild-context.d.ts.map +1 -1
  155. package/dist/workers/server-esbuild-context.js +11 -2
  156. package/dist/workers/server-esbuild-context.js.map +1 -1
  157. package/package.json +5 -4
  158. package/src/angular/angular-compiler.ts +0 -502
  159. package/src/angular/hmr-candidates.ts +295 -0
  160. package/src/angular/ngtsc-build-core.ts +125 -92
  161. package/src/angular/vite-angular-plugin.ts +71 -65
  162. package/src/angular/web-worker-transformer.ts +117 -0
  163. package/src/capacitor/capacitor.ts +6 -4
  164. package/src/commands/check.ts +17 -76
  165. package/src/commands/publish/deployment-phase.ts +11 -7
  166. package/src/commands/publish/npm-publisher.ts +1 -1
  167. package/src/commands/publish/publish-command.ts +1 -1
  168. package/src/commands/publish/version-upgrade.ts +1 -1
  169. package/src/commands/replace-deps.ts +3 -1
  170. package/src/deps/replace-deps/collect-deps.ts +4 -2
  171. package/src/deps/replace-deps/replace-deps.ts +114 -66
  172. package/src/electron/electron.ts +7 -7
  173. package/src/engines/BaseEngine.ts +2 -6
  174. package/src/engines/EsbuildClientEngine.ts +16 -10
  175. package/src/engines/NgtscEngine.ts +7 -7
  176. package/src/engines/TscEngine.ts +0 -2
  177. package/src/engines/types.ts +2 -0
  178. package/src/esbuild/esbuild-angular-compiler-plugin.ts +647 -0
  179. package/src/esbuild/esbuild-client-config.ts +57 -41
  180. package/src/esbuild/esbuild-tsc-plugin.ts +33 -23
  181. package/src/esbuild/file-reference-tracker.ts +61 -0
  182. package/src/esbuild/lmdb-cache-store.ts +46 -0
  183. package/src/esbuild/load-result-cache.ts +85 -0
  184. package/src/index.ts +5 -0
  185. package/src/lint/lint-core.ts +7 -7
  186. package/src/orchestrators/BaseOrchestrator.ts +2 -2
  187. package/src/orchestrators/BuildOrchestrator.ts +5 -24
  188. package/src/orchestrators/DevOrchestrator.ts +5 -5
  189. package/src/orchestrators/WatchOrchestrator.ts +6 -6
  190. package/src/runtime/ResultCollector.ts +1 -0
  191. package/src/runtime/engine-watch-events.ts +3 -0
  192. package/src/runtime/rebuild-manager.ts +1 -1
  193. package/src/runtime/worker-utils.ts +1 -1
  194. package/src/sd-cli-entry.ts +5 -3
  195. package/src/sd-cli.ts +4 -4
  196. package/src/ts-compiler/SdTsCompiler.ts +815 -0
  197. package/src/ts-compiler/sd-ts-compiler-options.ts +46 -0
  198. package/src/ts-compiler/sd-ts-compiler-result.ts +34 -0
  199. package/src/utils/copy-public.ts +9 -6
  200. package/src/utils/diagnostic-utils.ts +8 -9
  201. package/src/utils/output-utils.ts +38 -8
  202. package/src/workers/client.worker.ts +160 -126
  203. package/src/workers/library-build.worker.ts +187 -75
  204. package/src/workers/server-build.worker.ts +31 -61
  205. package/src/workers/server-esbuild-context.ts +14 -2
  206. package/tests/angular/fixtures/packages/basic-app/dist/styles.css +3 -0
  207. package/tests/angular/fixtures/packages/basic-app/scss/styles.scss +5 -0
  208. package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +13 -0
  209. package/tests/angular/web-worker-transformer.spec.ts +154 -0
  210. package/tests/capacitor/capacitor-build.spec.ts +1 -1
  211. package/tests/capacitor/capacitor-icon.spec.ts +1 -1
  212. package/tests/capacitor/capacitor-init.spec.ts +1 -1
  213. package/tests/commands/check.spec.ts +90 -104
  214. package/tests/commands/publish.spec.ts +12 -4
  215. package/tests/commands/slice3-severity-cleanup.verify.md +12 -0
  216. package/tests/deps/replace-deps/collect-deps.acc.spec.ts +62 -0
  217. package/tests/deps/replace-deps/collect-deps.spec.ts +49 -0
  218. package/tests/deps/replace-deps/replace-deps-filter.spec.ts +103 -0
  219. package/tests/deps/replace-deps/replace-deps-setup.acc.spec.ts +156 -0
  220. package/tests/electron/electron.spec.ts +4 -1
  221. package/tests/engines/engine-adapter-isolation.spec.ts +5 -6
  222. package/tests/engines/engine-duplicate-output-removal.verify.md +10 -0
  223. package/tests/engines/esbuild-client-engine.acc.spec.ts +79 -0
  224. package/tests/engines/esbuild-client-engine.spec.ts +73 -3
  225. package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +23 -0
  226. package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +21 -0
  227. package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +16 -0
  228. package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +15 -0
  229. package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +31 -0
  230. package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +31 -0
  231. package/tests/esbuild/esbuild-angular-compiler-plugin.spec.ts +397 -0
  232. package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +21 -0
  233. package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +13 -0
  234. package/tests/esbuild/esbuild-tsc-plugin.acc.spec.ts +56 -111
  235. package/tests/esbuild/esbuild-tsc-plugin.spec.ts +116 -52
  236. package/tests/esbuild/file-reference-tracker.spec.ts +99 -0
  237. package/tests/esbuild/lmdb-cache-store.spec.ts +58 -0
  238. package/tests/esbuild/load-result-cache.acc.spec.ts +55 -0
  239. package/tests/esbuild/load-result-cache.spec.ts +133 -0
  240. package/tests/orchestrators/build-orchestrator.spec.ts +4 -3
  241. package/tests/orchestrators/dev-orchestrator.spec.ts +5 -5
  242. package/tests/orchestrators/slice1-stdout-to-consola.verify.md +10 -0
  243. package/tests/orchestrators/typecheck-orchestrator.spec.ts +1 -1
  244. package/tests/orchestrators/watch-orchestrator.spec.ts +7 -7
  245. package/tests/runtime/result-collector.spec.ts +64 -0
  246. package/tests/sd-cli-entry.spec.ts +3 -4
  247. package/tests/sd-cli-log-tag.verify.md +11 -0
  248. package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +8 -0
  249. package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +12 -0
  250. package/tests/ts-compiler/SdTsCompiler-emit.verify.md +9 -0
  251. package/tests/ts-compiler/SdTsCompiler.acc.spec.ts +603 -0
  252. package/tests/ts-compiler/SdTsCompiler.spec.ts +265 -0
  253. package/tests/ts-compiler/SdTsCompiler.verify.md +41 -0
  254. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-browser.tsbuildinfo +1 -0
  255. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-node.tsbuildinfo +1 -0
  256. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck.tsbuildinfo +1 -0
  257. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.d.ts +2 -0
  258. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.d.ts.map +1 -0
  259. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.js +4 -0
  260. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.js.map +1 -0
  261. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.d.ts +2 -0
  262. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.d.ts.map +1 -0
  263. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.js +4 -0
  264. package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.js.map +1 -0
  265. package/tests/ts-compiler/fixtures/non-angular-pkg/src/index.ts +3 -0
  266. package/tests/ts-compiler/fixtures/non-angular-pkg/src/util.ts +3 -0
  267. package/tests/ts-compiler/fixtures/non-angular-pkg/tests/sample.test-file.ts +3 -0
  268. package/tests/ts-compiler/fixtures/non-angular-pkg/tsconfig.json +12 -0
  269. package/tests/ts-compiler/scss-lint-integration.verify.md +14 -0
  270. package/tests/utils/angular-build.spec.ts +1 -1
  271. package/tests/utils/copy-public-outdir.verify.md +8 -0
  272. package/tests/utils/copy-public.acc.spec.ts +52 -0
  273. package/tests/utils/copy-public.spec.ts +56 -0
  274. package/tests/utils/diagnostic-utils.spec.ts +24 -15
  275. package/tests/utils/engine-watch-events.acc.spec.ts +59 -0
  276. package/tests/utils/engine-watch-events.spec.ts +58 -0
  277. package/tests/utils/esbuild-client-config-integration.verify.md +9 -0
  278. package/tests/utils/esbuild-client-config.acc.spec.ts +45 -61
  279. package/tests/utils/esbuild-client-config.spec.ts +70 -52
  280. package/tests/utils/ngtsc-build-core-write-emit.spec.ts +12 -12
  281. package/tests/utils/ngtsc-build-core.spec.ts +1 -44
  282. package/tests/utils/output-utils.spec.ts +133 -13
  283. package/tests/utils/replace-deps-watch.acc.spec.ts +7 -1
  284. package/tests/utils/replace-deps-watch.spec.ts +57 -1
  285. package/tests/utils/worker-utils.spec.ts +8 -2
  286. package/tests/workers/client-worker-initial-build-error.verify.md +2 -3
  287. package/tests/workers/client-worker-initial-build-warnings.verify.md +7 -0
  288. package/tests/workers/client-worker-refactor.verify.md +22 -0
  289. package/tests/workers/client-worker-ts-cache-invalidation.verify.md +12 -0
  290. package/tests/workers/client-worker.acc.spec.ts +6 -3
  291. package/tests/workers/library-build-lint.spec.ts +40 -45
  292. package/tests/workers/library-build-worker.spec.ts +294 -40
  293. package/tests/workers/server-build-lint.spec.ts +59 -45
  294. package/tests/workers/server-build-worker.spec.ts +63 -24
  295. package/tests/workers/server-esbuild-context.acc.spec.ts +2 -0
  296. package/tests/workers/server-esbuild-context.spec.ts +2 -0
  297. package/tests/workers/server-runtime-worker.spec.ts +1 -1
  298. package/tests/workers/shared-worker-lifecycle.acc.spec.ts +1 -1
  299. package/dist/angular/angular-build-pipeline.d.ts +0 -97
  300. package/dist/angular/angular-build-pipeline.d.ts.map +0 -1
  301. package/dist/angular/angular-build-pipeline.js +0 -285
  302. package/dist/angular/angular-build-pipeline.js.map +0 -1
  303. package/dist/utils/tsc-build.d.ts +0 -51
  304. package/dist/utils/tsc-build.d.ts.map +0 -1
  305. package/dist/utils/tsc-build.js +0 -156
  306. package/dist/utils/tsc-build.js.map +0 -1
  307. package/dist/workers/ngtsc-build.worker.d.ts +0 -23
  308. package/dist/workers/ngtsc-build.worker.d.ts.map +0 -1
  309. package/dist/workers/ngtsc-build.worker.js +0 -267
  310. package/dist/workers/ngtsc-build.worker.js.map +0 -1
  311. package/src/angular/angular-build-pipeline.ts +0 -406
  312. package/src/utils/tsc-build.ts +0 -226
  313. package/src/workers/ngtsc-build.worker.ts +0 -351
  314. package/tests/angular/angular-build-pipeline.spec.ts +0 -247
  315. package/tests/angular/angular-compiler-aot.acc.spec.ts +0 -68
  316. package/tests/angular/angular-compiler-aot.spec.ts +0 -80
  317. package/tests/utils/angular-compiler-emit.spec.ts +0 -666
  318. package/tests/utils/angular-compiler.spec.ts +0 -707
  319. package/tests/utils/tsc-build.spec.ts +0 -527
  320. package/tests/workers/ngtsc-build-lint.spec.ts +0 -141
  321. package/tests/workers/ngtsc-build-worker.spec.ts +0 -199
@@ -0,0 +1,154 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import ts from "typescript";
3
+
4
+ const { createWorkerTransformer } = await import(
5
+ "../../src/angular/web-worker-transformer.js"
6
+ );
7
+
8
+ //#region 헬퍼
9
+
10
+ /**
11
+ * TypeScript 소스 코드에 transformer를 적용하고 결과 코드를 반환한다.
12
+ */
13
+ function transformCode(
14
+ code: string,
15
+ fileProcessor: (workerFile: string, containingFile: string) => string,
16
+ fileName = "test.ts",
17
+ ): string {
18
+ const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.ES2022, true);
19
+ const transformer = createWorkerTransformer(fileProcessor);
20
+ const result = ts.transform(sourceFile, [transformer]);
21
+ const printer = ts.createPrinter();
22
+ const output = printer.printFile(result.transformed[0]);
23
+ result.dispose();
24
+ return output;
25
+ }
26
+
27
+ //#endregion
28
+
29
+ describe("createWorkerTransformer", () => {
30
+ // Acceptance: Worker 표준 패턴을 감지하여 번들된 경로로 치환한다
31
+ it("Worker 표준 패턴 — URL 치환 + { type: 'module' } 자동 추가", () => {
32
+ const fileProcessor = vi.fn().mockReturnValue("worker-ABCD1234.js");
33
+ const code = `const w = new Worker(new URL('./my-worker.ts', import.meta.url));`;
34
+
35
+ const output = transformCode(code, fileProcessor);
36
+
37
+ expect(fileProcessor).toHaveBeenCalledWith("./my-worker.ts", "test.ts");
38
+ expect(output).toContain('"worker-ABCD1234.js"');
39
+ expect(output).toContain('type');
40
+ expect(output).toContain('"module"');
41
+ expect(output).not.toContain("./my-worker.ts");
42
+ });
43
+
44
+ // Acceptance: SharedWorker도 동일하게 처리한다
45
+ it("SharedWorker도 동일하게 변환한다", () => {
46
+ const fileProcessor = vi.fn().mockReturnValue("worker-SHARED01.js");
47
+ const code = `const sw = new SharedWorker(new URL('./shared.ts', import.meta.url));`;
48
+
49
+ const output = transformCode(code, fileProcessor);
50
+
51
+ expect(fileProcessor).toHaveBeenCalledWith("./shared.ts", "test.ts");
52
+ expect(output).toContain('"worker-SHARED01.js"');
53
+ });
54
+
55
+ // Acceptance: Worker의 기존 options 인자가 있으면 유지한다
56
+ it("기존 options 인자가 있으면 유지한다", () => {
57
+ const fileProcessor = vi.fn().mockReturnValue("worker-OPT00001.js");
58
+ const code = `const w = new Worker(new URL('./w.ts', import.meta.url), { name: 'test' });`;
59
+
60
+ const output = transformCode(code, fileProcessor);
61
+
62
+ expect(output).toContain('"worker-OPT00001.js"');
63
+ expect(output).toContain("name");
64
+ // { type: 'module' } 자동 추가 없이 기존 options가 유지됨
65
+ expect(output).not.toMatch(/type.*module.*name/);
66
+ });
67
+ });
68
+
69
+ describe("createWorkerTransformer — 변환하지 않는 케이스", () => {
70
+ const noopProcessor = vi.fn().mockReturnValue("should-not-appear.js");
71
+
72
+ // URL 패턴이 아닌 Worker 생성
73
+ it("URL 패턴 없이 문자열 인자만 있으면 변환하지 않는다", () => {
74
+ const code = `const w = new Worker('./my-worker.ts');`;
75
+ const output = transformCode(code, noopProcessor);
76
+
77
+ expect(noopProcessor).not.toHaveBeenCalled();
78
+ expect(output).toContain("./my-worker.ts");
79
+ });
80
+
81
+ // import.meta.url이 아닌 URL
82
+ it("import.meta.url이 아닌 URL은 변환하지 않는다", () => {
83
+ const code = `const w = new Worker(new URL('./w.ts', 'http://example.com'));`;
84
+ const output = transformCode(code, noopProcessor);
85
+
86
+ expect(noopProcessor).not.toHaveBeenCalled();
87
+ expect(output).toContain("./w.ts");
88
+ });
89
+
90
+ // Worker 인자 없음
91
+ it("Worker 인자가 없으면 변환하지 않는다", () => {
92
+ const code = `const w = new Worker();`;
93
+ transformCode(code, noopProcessor);
94
+
95
+ expect(noopProcessor).not.toHaveBeenCalled();
96
+ });
97
+
98
+ // Worker 인자 3개 이상
99
+ it("Worker 인자가 3개 이상이면 변환하지 않는다", () => {
100
+ const code = `const w = new Worker(new URL('./w.ts', import.meta.url), {}, 'extra');`;
101
+ transformCode(code, noopProcessor);
102
+
103
+ expect(noopProcessor).not.toHaveBeenCalled();
104
+ });
105
+
106
+ // URL 인자가 1개
107
+ it("URL 인자가 1개면 변환하지 않는다", () => {
108
+ const code = `const w = new Worker(new URL('./w.ts'));`;
109
+ transformCode(code, noopProcessor);
110
+
111
+ expect(noopProcessor).not.toHaveBeenCalled();
112
+ });
113
+
114
+ // URL 인자가 3개
115
+ it("URL 인자가 3개면 변환하지 않는다", () => {
116
+ const code = `const w = new Worker(new URL('./w.ts', import.meta.url, 'extra'));`;
117
+ transformCode(code, noopProcessor);
118
+
119
+ expect(noopProcessor).not.toHaveBeenCalled();
120
+ });
121
+
122
+ // 'Worker' 문자열 없으면 skip
123
+ it("소스에 'Worker' 문자열이 없으면 변환을 건너뛴다", () => {
124
+ const code = `const x = 1 + 2;`;
125
+ const output = transformCode(code, noopProcessor);
126
+
127
+ expect(noopProcessor).not.toHaveBeenCalled();
128
+ expect(output).toContain("1 + 2");
129
+ });
130
+ });
131
+
132
+ describe("createWorkerTransformer — 추가 경계 케이스", () => {
133
+ // fileProcessor가 원본과 동일한 경로를 반환하면 변환하지 않는다
134
+ it("fileProcessor가 원본 경로를 그대로 반환하면 AST를 변경하지 않는다", () => {
135
+ const fileProcessor = vi.fn().mockReturnValue("./my-worker.ts");
136
+ const code = `const w = new Worker(new URL('./my-worker.ts', import.meta.url));`;
137
+
138
+ const output = transformCode(code, fileProcessor);
139
+
140
+ expect(fileProcessor).toHaveBeenCalledWith("./my-worker.ts", "test.ts");
141
+ // 원본 경로가 그대로 유지 (변환 없음)
142
+ expect(output).toContain("./my-worker.ts");
143
+ });
144
+
145
+ // 소스에 Worker 문자열은 있지만 new 표현이 아닌 경우
146
+ it("Worker 문자열이 있지만 new 표현이 아니면 변환하지 않는다", () => {
147
+ const fileProcessor = vi.fn();
148
+ const code = `const WorkerName = "test";`;
149
+
150
+ transformCode(code, fileProcessor);
151
+
152
+ expect(fileProcessor).not.toHaveBeenCalled();
153
+ });
154
+ });
@@ -66,7 +66,7 @@ vi.mock("sharp", () => ({
66
66
 
67
67
  // consola mock (logger assertion 필요)
68
68
  const mockLoggerWarn = vi.fn();
69
- vi.spyOn(consola, "withTag").mockReturnValue({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn() } as any);
69
+ vi.spyOn(consola, "withTag").mockReturnValue({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn(), start: vi.fn() } as any);
70
70
 
71
71
  //#endregion
72
72
 
@@ -66,7 +66,7 @@ vi.mock("sharp", () => ({ default: mockSharp }));
66
66
 
67
67
  // consola mock (logger assertion 필요)
68
68
  const mockLoggerWarn = vi.fn();
69
- vi.spyOn(consola, "withTag").mockReturnValue({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn() } as any);
69
+ vi.spyOn(consola, "withTag").mockReturnValue({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn(), start: vi.fn() } as any);
70
70
 
71
71
  //#endregion
72
72
 
@@ -62,7 +62,7 @@ vi.mock("sharp", () => ({
62
62
  }));
63
63
 
64
64
  const mockLoggerWarn = vi.fn();
65
- vi.spyOn(consola, "withTag").mockReturnValue({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn() } as any);
65
+ vi.spyOn(consola, "withTag").mockReturnValue({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn(), start: vi.fn() } as any);
66
66
 
67
67
  //#endregion
68
68
 
@@ -1,10 +1,21 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { consola } from "consola";
3
+
4
+ const mockLogger = {
5
+ debug: vi.fn(),
6
+ info: vi.fn(),
7
+ warn: vi.fn(),
8
+ error: vi.fn(),
9
+ start: vi.fn(),
10
+ success: vi.fn(),
11
+ };
12
+
13
+ vi.spyOn(consola, "withTag").mockReturnValue(mockLogger as any);
2
14
 
3
15
  const mocks = vi.hoisted(() => ({
4
16
  executeTypecheck: vi.fn(),
5
17
  executeLint: vi.fn(),
6
18
  runLintInWorker: vi.fn(),
7
- execa: vi.fn(),
8
19
  loadSdConfig: vi.fn(),
9
20
  discoverWorkspacePackages: vi.fn(),
10
21
  }));
@@ -25,13 +36,6 @@ vi.mock("../../src/utils/sd-config", () => ({
25
36
  loadSdConfig: mocks.loadSdConfig,
26
37
  }));
27
38
 
28
- vi.mock("@simplysm/core-node", () => ({
29
- cpx: {
30
- spawn: mocks.execa,
31
- spawnSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
32
- },
33
- }));
34
-
35
39
  vi.mock("../../src/utils/package-utils", async (importOriginal) => {
36
40
  const actual = await importOriginal<typeof import("../../src/utils/package-utils")>();
37
41
  return {
@@ -42,20 +46,21 @@ vi.mock("../../src/utils/package-utils", async (importOriginal) => {
42
46
 
43
47
  const { runCheck } = await import("../../src/commands/check");
44
48
 
49
+ /**
50
+ * Collects all calls to the given mock function's first argument into an array,
51
+ * preserving call order for sequential assertions.
52
+ */
53
+ function collectArgs(fn: ReturnType<typeof vi.fn>): string[] {
54
+ return fn.mock.calls.map((call) => String(call[0]));
55
+ }
56
+
45
57
  describe("runCheck", () => {
46
58
  let savedExitCode: typeof process.exitCode;
47
- let writeSpy: ReturnType<typeof vi.spyOn>;
48
- let stdoutOutput: string;
49
59
 
50
60
  beforeEach(() => {
51
61
  vi.clearAllMocks();
52
62
  savedExitCode = process.exitCode;
53
63
  process.exitCode = undefined;
54
- stdoutOutput = "";
55
- writeSpy = vi.spyOn(process.stdout, "write").mockImplementation((chunk: unknown) => {
56
- stdoutOutput += String(chunk);
57
- return true;
58
- });
59
64
 
60
65
  // Default: workspace packages
61
66
  mocks.discoverWorkspacePackages.mockReturnValue(
@@ -89,41 +94,22 @@ describe("runCheck", () => {
89
94
  mocks.runLintInWorker.mockResolvedValue({
90
95
  success: true, errorCount: 0, warningCount: 0, formattedOutput: "",
91
96
  });
92
- mocks.execa.mockResolvedValue({
93
- stdout: "Tests 1 passed", stderr: "", exitCode: 0,
94
- });
95
97
  });
96
98
 
97
99
  afterEach(() => {
98
100
  process.exitCode = savedExitCode;
99
- writeSpy.mockRestore();
100
101
  });
101
102
 
102
- it("runs typecheck+lint and test", async () => {
103
- await runCheck({ targets: [], types: ["typecheck", "lint", "test"], fix: false });
104
-
105
- expect(stdoutOutput).toContain("TYPECHECK");
106
- expect(stdoutOutput).toContain("TEST");
107
- });
103
+ it("outputs success sections in TYPECHECK → LINT order via logger.success", async () => {
104
+ await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
108
105
 
109
- it("outputs results in TYPECHECK → LINT → TEST → 요약 order", async () => {
110
- await runCheck({ targets: [], types: ["typecheck", "lint", "test"], fix: false });
111
-
112
- const tcIdx = stdoutOutput.indexOf("TYPECHECK");
113
- const lintIdx = stdoutOutput.indexOf("LINT");
114
- const testIdx = stdoutOutput.indexOf("TEST");
115
- const summaryIdx = stdoutOutput.indexOf("요약");
106
+ const successArgs = collectArgs(mockLogger.success);
107
+ const tcIdx = successArgs.findIndex((a) => a.includes("TYPECHECK"));
108
+ const lintIdx = successArgs.findIndex((a) => a.includes("LINT"));
116
109
 
110
+ expect(tcIdx).toBeGreaterThanOrEqual(0);
111
+ expect(lintIdx).toBeGreaterThanOrEqual(0);
117
112
  expect(tcIdx).toBeLessThan(lintIdx);
118
- expect(lintIdx).toBeLessThan(testIdx);
119
- expect(testIdx).toBeLessThan(summaryIdx);
120
- });
121
-
122
- it("runs only specified check types", async () => {
123
- await runCheck({ targets: [], types: ["test"], fix: false });
124
-
125
- expect(stdoutOutput).not.toContain("TYPECHECK");
126
- expect(stdoutOutput).toContain("TEST");
127
113
  });
128
114
 
129
115
  it("sets exitCode 1 when typecheck fails", async () => {
@@ -133,35 +119,52 @@ describe("runCheck", () => {
133
119
  scriptsPackagePaths: [],
134
120
  });
135
121
 
136
- await runCheck({ targets: [], types: ["typecheck", "lint", "test"], fix: false });
122
+ await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
137
123
 
138
124
  expect(process.exitCode).toBe(1);
139
125
  });
140
126
 
141
- it("sets exitCode to 1 when lint fails", async () => {
142
- mocks.executeLint.mockResolvedValue({
143
- success: false, errorCount: 1, warningCount: 0, formattedOutput: "lint errors",
127
+ it("outputs failed section via logger.error with formattedOutput", async () => {
128
+ mocks.executeTypecheck.mockResolvedValue({
129
+ success: false, errorCount: 2, warningCount: 0, formattedOutput: "type errors",
130
+ lint: { success: true, errorCount: 0, warningCount: 0, formattedOutput: "" },
131
+ scriptsPackagePaths: [],
144
132
  });
145
133
 
146
- await runCheck({ targets: [], types: ["lint"], fix: false });
134
+ await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
147
135
 
148
- expect(process.exitCode).toBe(1);
136
+ const errorArgs = collectArgs(mockLogger.error);
137
+ expect(errorArgs.some((a) => a.includes("TYPECHECK"))).toBe(true);
138
+ expect(errorArgs.some((a) => a.includes("type errors"))).toBe(true);
139
+ });
140
+
141
+ it("outputs success summary via logger.success when all pass", async () => {
142
+ await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
143
+
144
+ const successArgs = collectArgs(mockLogger.success);
145
+ expect(successArgs.some((a) => a.includes("전체 통과"))).toBe(true);
149
146
  });
150
147
 
151
- it("sets exitCode 1 when test fails", async () => {
152
- mocks.execa.mockResolvedValue({
153
- stdout: "3 tests failed", stderr: "", exitCode: 1,
148
+ it("outputs failure summary via logger.error when any fails", async () => {
149
+ mocks.executeTypecheck.mockResolvedValue({
150
+ success: false, errorCount: 1, warningCount: 0, formattedOutput: "err",
151
+ lint: { success: true, errorCount: 0, warningCount: 0, formattedOutput: "" },
152
+ scriptsPackagePaths: [],
154
153
  });
155
154
 
156
- await runCheck({ targets: [], types: ["test"], fix: false });
155
+ await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
157
156
 
158
- expect(process.exitCode).toBe(1);
157
+ const errorArgs = collectArgs(mockLogger.error);
158
+ expect(errorArgs.some((a) => a.includes("실패"))).toBe(true);
159
+ expect(errorArgs.some((a) => a.includes("합계"))).toBe(true);
159
160
  });
160
161
 
161
- it("handles vitest execution error gracefully", async () => {
162
- mocks.execa.mockRejectedValue(new Error("vitest not found"));
162
+ it("sets exitCode to 1 when lint fails", async () => {
163
+ mocks.executeLint.mockResolvedValue({
164
+ success: false, errorCount: 1, warningCount: 0, formattedOutput: "lint errors",
165
+ });
163
166
 
164
- await runCheck({ targets: [], types: ["test"], fix: false });
167
+ await runCheck({ targets: [], types: ["lint"], fix: false });
165
168
 
166
169
  expect(process.exitCode).toBe(1);
167
170
  });
@@ -179,51 +182,45 @@ describe("runCheck", () => {
179
182
  it("resolves package target to packages/ path", async () => {
180
183
  await runCheck({ targets: ["core-node"], types: ["typecheck"], fix: false });
181
184
 
182
- expect(stdoutOutput).toContain("TYPECHECK");
185
+ const successArgs = collectArgs(mockLogger.success);
186
+ expect(successArgs.some((a) => a.includes("TYPECHECK"))).toBe(true);
183
187
  expect(process.exitCode).toBeUndefined();
184
188
  });
185
189
 
186
190
  it("resolves test directory target to tests/ path", async () => {
187
191
  await runCheck({ targets: ["orm"], types: ["typecheck"], fix: false });
188
192
 
189
- expect(stdoutOutput).toContain("TYPECHECK");
193
+ const successArgs = collectArgs(mockLogger.success);
194
+ expect(successArgs.some((a) => a.includes("TYPECHECK"))).toBe(true);
190
195
  expect(process.exitCode).toBeUndefined();
191
196
  });
192
197
 
193
198
  it("resolves mixed targets to correct paths", async () => {
194
199
  await runCheck({ targets: ["core-node", "orm"], types: ["typecheck"], fix: false });
195
200
 
196
- expect(stdoutOutput).toContain("TYPECHECK");
201
+ const successArgs = collectArgs(mockLogger.success);
202
+ expect(successArgs.some((a) => a.includes("TYPECHECK"))).toBe(true);
197
203
  expect(process.exitCode).toBeUndefined();
198
204
  });
199
205
 
200
206
  it("resolves lint target to correct path", async () => {
201
207
  await runCheck({ targets: ["orm"], types: ["lint"], fix: false });
202
208
 
203
- expect(stdoutOutput).toContain("LINT");
209
+ const successArgs = collectArgs(mockLogger.success);
210
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
204
211
  expect(process.exitCode).toBeUndefined();
205
212
  });
206
213
 
207
- it("passes resolved paths to vitest", async () => {
208
- await runCheck({ targets: ["orm"], types: ["test"], fix: false });
209
-
210
- expect(mocks.execa).toHaveBeenCalledWith(
211
- "pnpm",
212
- ["vitest", "tests/orm", "--run"],
213
- expect.any(Object),
214
- );
215
- });
216
-
217
214
  it("passes empty targets for all when no targets specified", async () => {
218
215
  await runCheck({ targets: [], types: ["typecheck"], fix: false });
219
216
 
220
- expect(stdoutOutput).toContain("TYPECHECK");
217
+ const successArgs = collectArgs(mockLogger.success);
218
+ expect(successArgs.some((a) => a.includes("TYPECHECK"))).toBe(true);
221
219
  expect(process.exitCode).toBeUndefined();
222
220
  });
223
221
 
224
222
  describe("lint via engine integration", () => {
225
223
  beforeEach(() => {
226
- // Default: executeTypecheck returns lint result and scriptsPackagePaths
227
224
  mocks.executeTypecheck.mockResolvedValue({
228
225
  success: true, errorCount: 0, warningCount: 0, formattedOutput: "",
229
226
  lint: { success: true, errorCount: 0, warningCount: 0, formattedOutput: "" },
@@ -231,15 +228,14 @@ describe("runCheck", () => {
231
228
  });
232
229
  });
233
230
 
234
- // Scenario: typecheck+lint 요청 시 TYPECHECK과 LINT 섹션이 출력된다
235
231
  it("outputs TYPECHECK and LINT sections when both are requested", async () => {
236
232
  await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
237
233
 
238
- expect(stdoutOutput).toContain("TYPECHECK");
239
- expect(stdoutOutput).toContain("LINT");
234
+ const successArgs = collectArgs(mockLogger.success);
235
+ expect(successArgs.some((a) => a.includes("TYPECHECK"))).toBe(true);
236
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
240
237
  });
241
238
 
242
- // Scenario: lint 실패 시 exitCode 설정
243
239
  it("sets exitCode 1 when engine lint fails", async () => {
244
240
  mocks.executeTypecheck.mockResolvedValue({
245
241
  success: true, errorCount: 0, warningCount: 0, formattedOutput: "",
@@ -252,7 +248,6 @@ describe("runCheck", () => {
252
248
  expect(process.exitCode).toBe(1);
253
249
  });
254
250
 
255
- // Scenario: scripts 패키지 포함 시 lint가 성공한다
256
251
  it("succeeds when scriptsPackagePaths is non-empty", async () => {
257
252
  mocks.executeTypecheck.mockResolvedValue({
258
253
  success: true, errorCount: 0, warningCount: 0, formattedOutput: "",
@@ -265,69 +260,62 @@ describe("runCheck", () => {
265
260
 
266
261
  await runCheck({ targets: [], types: ["typecheck", "lint"], fix: false });
267
262
 
268
- expect(stdoutOutput).toContain("LINT");
263
+ const successArgs = collectArgs(mockLogger.success);
264
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
269
265
  expect(process.exitCode).toBeUndefined();
270
266
  });
271
267
  });
272
268
 
273
269
  describe("lint-only path", () => {
274
- // Scenario: lint만 요청 시 LINT 섹션만 출력된다
275
270
  it("outputs LINT section when only lint type is requested", async () => {
276
271
  await runCheck({ targets: [], types: ["lint"], fix: false });
277
272
 
278
- expect(stdoutOutput).toContain("LINT");
279
- expect(stdoutOutput).not.toContain("TYPECHECK");
273
+ const successArgs = collectArgs(mockLogger.success);
274
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
275
+ const allArgs = [...collectArgs(mockLogger.success), ...collectArgs(mockLogger.error)];
276
+ expect(allArgs.some((a) => a.includes("TYPECHECK"))).toBe(false);
280
277
  });
281
278
 
282
- // Scenario: lint,test 요청 시 LINT과 TEST 섹션 출력 (TYPECHECK 없음)
283
- it("outputs LINT and TEST sections when lint,test are requested", async () => {
284
- await runCheck({ targets: [], types: ["lint", "test"], fix: false });
285
-
286
- expect(stdoutOutput).toContain("LINT");
287
- expect(stdoutOutput).toContain("TEST");
288
- expect(stdoutOutput).not.toContain("TYPECHECK");
289
- });
290
-
291
- // Scenario: scripts 패키지 포함 전체 lint
292
279
  it("handles all packages via lint including scripts", async () => {
293
280
  mocks.discoverWorkspacePackages.mockReturnValue(
294
281
  new Map([
295
282
  ["core-common", "packages/core-common"],
296
- ["sd-claude", "packages/sd-claude"], // scripts package
283
+ ["sd-claude", "packages/sd-claude"],
297
284
  ]),
298
285
  );
299
286
 
300
287
  await runCheck({ targets: [], types: ["lint"], fix: false });
301
288
 
302
- expect(stdoutOutput).toContain("LINT");
303
- expect(stdoutOutput).not.toContain("TYPECHECK");
289
+ const successArgs = collectArgs(mockLogger.success);
290
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
291
+ const allArgs = [...collectArgs(mockLogger.success), ...collectArgs(mockLogger.error)];
292
+ expect(allArgs.some((a) => a.includes("TYPECHECK"))).toBe(false);
304
293
  });
305
294
 
306
- // Scenario: 특정 타겟 지정 lint
307
295
  it("succeeds with normalized target paths for lint", async () => {
308
296
  await runCheck({ targets: ["core-common"], types: ["lint"], fix: false });
309
297
 
310
- expect(stdoutOutput).toContain("LINT");
298
+ const successArgs = collectArgs(mockLogger.success);
299
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
311
300
  expect(process.exitCode).toBeUndefined();
312
301
  });
313
302
 
314
- // Scenario: --fix 옵션으로 자동 수정
315
303
  it("succeeds when --fix is specified", async () => {
316
304
  await runCheck({ targets: [], types: ["lint"], fix: true });
317
305
 
318
- expect(stdoutOutput).toContain("LINT");
306
+ const successArgs = collectArgs(mockLogger.success);
307
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
319
308
  expect(process.exitCode).toBeUndefined();
320
309
  });
321
310
 
322
- // Scenario: --fix 없이 실행
323
311
  it("succeeds when --fix is not specified", async () => {
324
312
  await runCheck({ targets: [], types: ["lint"], fix: false });
325
313
 
326
- expect(stdoutOutput).toContain("LINT");
314
+ const successArgs = collectArgs(mockLogger.success);
315
+ expect(successArgs.some((a) => a.includes("LINT"))).toBe(true);
327
316
  expect(process.exitCode).toBeUndefined();
328
317
  });
329
318
 
330
- // Scenario: lint 에러 없음
331
319
  it("does not set exitCode when lint passes", async () => {
332
320
  mocks.executeLint.mockResolvedValue({
333
321
  success: true, errorCount: 0, warningCount: 0, formattedOutput: "",
@@ -338,7 +326,6 @@ describe("runCheck", () => {
338
326
  expect(process.exitCode).toBeUndefined();
339
327
  });
340
328
 
341
- // Scenario: lint 에러 발생
342
329
  it("sets exitCode 1 when lint has errors", async () => {
343
330
  mocks.executeLint.mockResolvedValue({
344
331
  success: false, errorCount: 3, warningCount: 2, formattedOutput: "lint errors",
@@ -349,12 +336,11 @@ describe("runCheck", () => {
349
336
  expect(process.exitCode).toBe(1);
350
337
  });
351
338
 
352
- // typecheck 관련 로그 메시지가 출력되지 않는다
353
339
  it("does not output typecheck-related sections when only lint is requested", async () => {
354
340
  await runCheck({ targets: [], types: ["lint"], fix: false });
355
341
 
356
- expect(stdoutOutput).not.toContain("TYPECHECK");
342
+ const allArgs = [...collectArgs(mockLogger.success), ...collectArgs(mockLogger.error)];
343
+ expect(allArgs.some((a) => a.includes("TYPECHECK"))).toBe(false);
357
344
  });
358
345
  });
359
-
360
346
  });
@@ -298,8 +298,16 @@ describe("runPublish", () => {
298
298
  },
299
299
  });
300
300
 
301
- const writeSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
301
+ const { consola } = await import("consola");
302
+ const infoSpy = vi.fn();
303
+ const origWithTag = consola.withTag.bind(consola);
304
+ const withTagSpy = vi.spyOn(consola, "withTag").mockImplementation((tag: string) => {
305
+ const logger = origWithTag(tag);
306
+ logger.info = infoSpy as any;
307
+ return logger;
308
+ });
302
309
 
310
+ // Re-import to pick up the spy (module already loaded, but logger is created at call time)
303
311
  await runPublish({
304
312
  targets: [],
305
313
  noBuild: false,
@@ -307,9 +315,9 @@ describe("runPublish", () => {
307
315
  options: [],
308
316
  });
309
317
 
310
- const output = writeSpy.mock.calls.map((c) => String(c[0])).join("");
311
- expect(output).toContain("배포할 패키지가 없습니다");
312
- writeSpy.mockRestore();
318
+ const infoArgs = infoSpy.mock.calls.map((c: unknown[]) => String(c[0]));
319
+ expect(infoArgs.some((a: string) => a.includes("배포할 패키지가 없습니다"))).toBe(true);
320
+ withTagSpy.mockRestore();
313
321
  });
314
322
  });
315
323
 
@@ -0,0 +1,12 @@
1
+ # Slice 3: severity 정리 — LLM 검증
2
+
3
+ ## 검증 항목
4
+
5
+ - [x] replace-deps.ts:5 — `const logger = consola.withTag("sd:cli:replace-deps")` 모듈-레벨 로거 추가 확인
6
+ - [x] replace-deps.ts:24 — `consola.warn(...)` → `logger.warn(...)` 변경 확인
7
+ - [x] deployment-phase.ts:66-70 — DRY-RUN 성공 메시지 `debug` → `info` 전환 확인: `dryRun ? logger.info("[DRY-RUN] ...") : logger.debug(...)`
8
+ - [x] deployment-phase.ts:76-80 — DRY-RUN 재시도 메시지 `debug` → `info` 전환 확인: 동일 패턴
9
+ - [x] deployment-phase.ts:102 — `logger.fail(...)` → `logger.error(...)` 전환 확인
10
+ - [x] BuildOrchestrator.ts:251 — `this._logger.success("빌드 실행 완료")` 행 제거 확인: 250행 뒤에 바로 `return` 문
11
+ - [x] BuildOrchestrator.ts:477 — `this._logger.info("빌드 완료")` → `this._logger.success("빌드 완료")` 전환 확인
12
+ - [x] BuildOrchestrator.ts:232-233 — `this._logger.start("빌드 실행 중...")` 유지 확인: start(232)/success(477) 쌍 정상화
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ import { collectDeps } from "../../../src/deps/replace-deps/collect-deps";
6
+ import { pathx } from "@simplysm/core-node";
7
+
8
+ describe("collectDeps — tests/ 패키지 제외", () => {
9
+ let tmpDir: string;
10
+
11
+ beforeEach(() => {
12
+ tmpDir = pathx.posix(fs.mkdtempSync(path.join(os.tmpdir(), "sd-cli-test-")));
13
+ });
14
+
15
+ afterEach(() => {
16
+ fs.rmSync(tmpDir, { recursive: true, force: true });
17
+ });
18
+
19
+ function createPkg(relDir: string, name: string, deps: Record<string, string> = {}): void {
20
+ const dir = pathx.posix(path.join(tmpDir, relDir));
21
+ fs.mkdirSync(dir, { recursive: true });
22
+ fs.writeFileSync(
23
+ pathx.posix(path.join(dir, "package.json")),
24
+ JSON.stringify({ name, dependencies: deps }),
25
+ );
26
+ }
27
+
28
+ // Scenario: packages/ 패키지는 워크스페이스 맵에 포함된다
29
+ it("packages/ 패키지를 workspaceDeps에 포함한다", () => {
30
+ createPkg("packages/core-common", "@test/core-common");
31
+ createPkg("packages/my-lib", "@test/my-lib", { "@test/core-common": "workspace:*" });
32
+
33
+ const result = collectDeps(pathx.posix(path.join(tmpDir, "packages/my-lib")), tmpDir);
34
+
35
+ expect(result.workspaceDeps).toContain("core-common");
36
+ });
37
+
38
+ // Scenario: tests/ 패키지는 워크스페이스 맵에서 제외된다
39
+ it("tests/ 패키지를 workspaceDeps에 포함하지 않는다", () => {
40
+ createPkg("packages/my-lib", "@test/my-lib", { "@test/orm": "workspace:*" });
41
+ createPkg("tests/orm", "@test/orm");
42
+
43
+ const result = collectDeps(pathx.posix(path.join(tmpDir, "packages/my-lib")), tmpDir);
44
+
45
+ expect(result.workspaceDeps).not.toContain("orm");
46
+ });
47
+
48
+ // Scenario: 패키지의 dependency에 tests/ 패키지가 있으면 workspaceDeps에서 무시된다
49
+ it("dependency에 tests/ 패키지가 있어도 workspaceDeps에서 무시한다", () => {
50
+ createPkg("packages/core-common", "@test/core-common");
51
+ createPkg("tests/orm", "@test/orm");
52
+ createPkg("packages/my-lib", "@test/my-lib", {
53
+ "@test/core-common": "workspace:*",
54
+ "@test/orm": "workspace:*",
55
+ });
56
+
57
+ const result = collectDeps(pathx.posix(path.join(tmpDir, "packages/my-lib")), tmpDir);
58
+
59
+ expect(result.workspaceDeps).toContain("core-common");
60
+ expect(result.workspaceDeps).not.toContain("orm");
61
+ });
62
+ });