@simplysm/sd-cli 14.0.42 → 14.0.44

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 (338) 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 +41 -37
  10. package/dist/angular/ngtsc-build-core.d.ts.map +1 -1
  11. package/dist/angular/ngtsc-build-core.js +155 -52
  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.d.ts.map +1 -1
  36. package/dist/commands/publish/version-upgrade.js +16 -13
  37. package/dist/commands/publish/version-upgrade.js.map +1 -1
  38. package/dist/commands/replace-deps.d.ts.map +1 -1
  39. package/dist/commands/replace-deps.js +2 -1
  40. package/dist/commands/replace-deps.js.map +1 -1
  41. package/dist/deps/replace-deps/collect-deps.d.ts.map +1 -1
  42. package/dist/deps/replace-deps/collect-deps.js +5 -2
  43. package/dist/deps/replace-deps/collect-deps.js.map +1 -1
  44. package/dist/deps/replace-deps/replace-deps-resolve.d.ts.map +1 -1
  45. package/dist/deps/replace-deps/replace-deps-resolve.js +6 -7
  46. package/dist/deps/replace-deps/replace-deps-resolve.js.map +1 -1
  47. package/dist/deps/replace-deps/replace-deps.d.ts +21 -3
  48. package/dist/deps/replace-deps/replace-deps.d.ts.map +1 -1
  49. package/dist/deps/replace-deps/replace-deps.js +175 -66
  50. package/dist/deps/replace-deps/replace-deps.js.map +1 -1
  51. package/dist/electron/electron.js +7 -7
  52. package/dist/electron/electron.js.map +1 -1
  53. package/dist/engines/BaseEngine.d.ts.map +1 -1
  54. package/dist/engines/BaseEngine.js +2 -5
  55. package/dist/engines/BaseEngine.js.map +1 -1
  56. package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
  57. package/dist/engines/EsbuildClientEngine.js +16 -9
  58. package/dist/engines/EsbuildClientEngine.js.map +1 -1
  59. package/dist/engines/NgtscEngine.d.ts +4 -4
  60. package/dist/engines/NgtscEngine.d.ts.map +1 -1
  61. package/dist/engines/NgtscEngine.js +5 -5
  62. package/dist/engines/NgtscEngine.js.map +1 -1
  63. package/dist/engines/TscEngine.d.ts.map +1 -1
  64. package/dist/engines/TscEngine.js +0 -2
  65. package/dist/engines/TscEngine.js.map +1 -1
  66. package/dist/engines/types.d.ts +2 -0
  67. package/dist/engines/types.d.ts.map +1 -1
  68. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts +36 -0
  69. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -0
  70. package/dist/esbuild/esbuild-angular-compiler-plugin.js +464 -0
  71. package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -0
  72. package/dist/esbuild/esbuild-client-config.d.ts +8 -2
  73. package/dist/esbuild/esbuild-client-config.d.ts.map +1 -1
  74. package/dist/esbuild/esbuild-client-config.js +48 -33
  75. package/dist/esbuild/esbuild-client-config.js.map +1 -1
  76. package/dist/esbuild/esbuild-postcss-plugin.d.ts.map +1 -1
  77. package/dist/esbuild/esbuild-postcss-plugin.js +9 -6
  78. package/dist/esbuild/esbuild-postcss-plugin.js.map +1 -1
  79. package/dist/esbuild/esbuild-tsc-plugin.d.ts +4 -1
  80. package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -1
  81. package/dist/esbuild/esbuild-tsc-plugin.js +27 -23
  82. package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -1
  83. package/dist/esbuild/file-reference-tracker.d.ts +24 -0
  84. package/dist/esbuild/file-reference-tracker.d.ts.map +1 -0
  85. package/dist/esbuild/file-reference-tracker.js +57 -0
  86. package/dist/esbuild/file-reference-tracker.js.map +1 -0
  87. package/dist/esbuild/lmdb-cache-store.d.ts +18 -0
  88. package/dist/esbuild/lmdb-cache-store.d.ts.map +1 -0
  89. package/dist/esbuild/lmdb-cache-store.js +41 -0
  90. package/dist/esbuild/lmdb-cache-store.js.map +1 -0
  91. package/dist/esbuild/load-result-cache.d.ts +17 -0
  92. package/dist/esbuild/load-result-cache.d.ts.map +1 -0
  93. package/dist/esbuild/load-result-cache.js +61 -0
  94. package/dist/esbuild/load-result-cache.js.map +1 -0
  95. package/dist/index.d.ts +3 -0
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +2 -0
  98. package/dist/index.js.map +1 -1
  99. package/dist/lint/lint-core.js +7 -7
  100. package/dist/lint/lint-core.js.map +1 -1
  101. package/dist/orchestrators/BaseOrchestrator.js +2 -2
  102. package/dist/orchestrators/BaseOrchestrator.js.map +1 -1
  103. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  104. package/dist/orchestrators/BuildOrchestrator.js +5 -19
  105. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  106. package/dist/orchestrators/DevOrchestrator.js +5 -5
  107. package/dist/orchestrators/DevOrchestrator.js.map +1 -1
  108. package/dist/orchestrators/WatchOrchestrator.js +6 -6
  109. package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
  110. package/dist/runtime/ResultCollector.d.ts +1 -0
  111. package/dist/runtime/ResultCollector.d.ts.map +1 -1
  112. package/dist/runtime/ResultCollector.js.map +1 -1
  113. package/dist/runtime/engine-watch-events.d.ts.map +1 -1
  114. package/dist/runtime/engine-watch-events.js +3 -0
  115. package/dist/runtime/engine-watch-events.js.map +1 -1
  116. package/dist/runtime/rebuild-manager.js +1 -1
  117. package/dist/runtime/rebuild-manager.js.map +1 -1
  118. package/dist/runtime/worker-utils.js +1 -1
  119. package/dist/runtime/worker-utils.js.map +1 -1
  120. package/dist/sd-cli-entry.d.ts.map +1 -1
  121. package/dist/sd-cli-entry.js +4 -3
  122. package/dist/sd-cli-entry.js.map +1 -1
  123. package/dist/sd-cli.js +3 -3
  124. package/dist/sd-cli.js.map +1 -1
  125. package/dist/ts-compiler/SdTsCompiler.d.ts +39 -0
  126. package/dist/ts-compiler/SdTsCompiler.d.ts.map +1 -0
  127. package/dist/ts-compiler/SdTsCompiler.js +593 -0
  128. package/dist/ts-compiler/SdTsCompiler.js.map +1 -0
  129. package/dist/ts-compiler/sd-ts-compiler-options.d.ts +40 -0
  130. package/dist/ts-compiler/sd-ts-compiler-options.d.ts.map +1 -0
  131. package/dist/ts-compiler/sd-ts-compiler-options.js +2 -0
  132. package/dist/ts-compiler/sd-ts-compiler-options.js.map +1 -0
  133. package/dist/ts-compiler/sd-ts-compiler-result.d.ts +34 -0
  134. package/dist/ts-compiler/sd-ts-compiler-result.d.ts.map +1 -0
  135. package/dist/ts-compiler/sd-ts-compiler-result.js +2 -0
  136. package/dist/ts-compiler/sd-ts-compiler-result.js.map +1 -0
  137. package/dist/utils/copy-public.d.ts +6 -4
  138. package/dist/utils/copy-public.d.ts.map +1 -1
  139. package/dist/utils/copy-public.js +9 -7
  140. package/dist/utils/copy-public.js.map +1 -1
  141. package/dist/utils/diagnostic-utils.d.ts +2 -3
  142. package/dist/utils/diagnostic-utils.d.ts.map +1 -1
  143. package/dist/utils/diagnostic-utils.js +8 -9
  144. package/dist/utils/diagnostic-utils.js.map +1 -1
  145. package/dist/utils/output-utils.d.ts +8 -2
  146. package/dist/utils/output-utils.d.ts.map +1 -1
  147. package/dist/utils/output-utils.js +32 -8
  148. package/dist/utils/output-utils.js.map +1 -1
  149. package/dist/workers/client.worker.d.ts +1 -1
  150. package/dist/workers/client.worker.d.ts.map +1 -1
  151. package/dist/workers/client.worker.js +115 -110
  152. package/dist/workers/client.worker.js.map +1 -1
  153. package/dist/workers/incremental-mtime-tracker.d.ts +13 -0
  154. package/dist/workers/incremental-mtime-tracker.d.ts.map +1 -0
  155. package/dist/workers/incremental-mtime-tracker.js +65 -0
  156. package/dist/workers/incremental-mtime-tracker.js.map +1 -0
  157. package/dist/workers/library-build.worker.d.ts +0 -2
  158. package/dist/workers/library-build.worker.d.ts.map +1 -1
  159. package/dist/workers/library-build.worker.js +169 -70
  160. package/dist/workers/library-build.worker.js.map +1 -1
  161. package/dist/workers/server-build.worker.d.ts.map +1 -1
  162. package/dist/workers/server-build.worker.js +30 -57
  163. package/dist/workers/server-build.worker.js.map +1 -1
  164. package/dist/workers/server-esbuild-context.d.ts +7 -0
  165. package/dist/workers/server-esbuild-context.d.ts.map +1 -1
  166. package/dist/workers/server-esbuild-context.js +11 -2
  167. package/dist/workers/server-esbuild-context.js.map +1 -1
  168. package/package.json +5 -4
  169. package/src/angular/angular-compiler.ts +0 -502
  170. package/src/angular/hmr-candidates.ts +295 -0
  171. package/src/angular/ngtsc-build-core.ts +192 -91
  172. package/src/angular/vite-angular-plugin.ts +71 -65
  173. package/src/angular/web-worker-transformer.ts +117 -0
  174. package/src/capacitor/capacitor.ts +6 -4
  175. package/src/commands/check.ts +17 -76
  176. package/src/commands/publish/deployment-phase.ts +11 -7
  177. package/src/commands/publish/npm-publisher.ts +1 -1
  178. package/src/commands/publish/publish-command.ts +1 -1
  179. package/src/commands/publish/version-upgrade.ts +44 -35
  180. package/src/commands/replace-deps.ts +3 -1
  181. package/src/deps/replace-deps/collect-deps.ts +4 -2
  182. package/src/deps/replace-deps/replace-deps-resolve.ts +12 -7
  183. package/src/deps/replace-deps/replace-deps.ts +191 -69
  184. package/src/electron/electron.ts +7 -7
  185. package/src/engines/BaseEngine.ts +2 -6
  186. package/src/engines/EsbuildClientEngine.ts +16 -10
  187. package/src/engines/NgtscEngine.ts +7 -7
  188. package/src/engines/TscEngine.ts +0 -2
  189. package/src/engines/types.ts +2 -0
  190. package/src/esbuild/esbuild-angular-compiler-plugin.ts +647 -0
  191. package/src/esbuild/esbuild-client-config.ts +57 -41
  192. package/src/esbuild/esbuild-postcss-plugin.ts +9 -6
  193. package/src/esbuild/esbuild-tsc-plugin.ts +33 -23
  194. package/src/esbuild/file-reference-tracker.ts +61 -0
  195. package/src/esbuild/lmdb-cache-store.ts +46 -0
  196. package/src/esbuild/load-result-cache.ts +85 -0
  197. package/src/index.ts +5 -0
  198. package/src/lint/lint-core.ts +7 -7
  199. package/src/orchestrators/BaseOrchestrator.ts +2 -2
  200. package/src/orchestrators/BuildOrchestrator.ts +5 -24
  201. package/src/orchestrators/DevOrchestrator.ts +5 -5
  202. package/src/orchestrators/WatchOrchestrator.ts +6 -6
  203. package/src/runtime/ResultCollector.ts +1 -0
  204. package/src/runtime/engine-watch-events.ts +3 -0
  205. package/src/runtime/rebuild-manager.ts +1 -1
  206. package/src/runtime/worker-utils.ts +1 -1
  207. package/src/sd-cli-entry.ts +5 -3
  208. package/src/sd-cli.ts +4 -4
  209. package/src/ts-compiler/SdTsCompiler.ts +815 -0
  210. package/src/ts-compiler/sd-ts-compiler-options.ts +46 -0
  211. package/src/ts-compiler/sd-ts-compiler-result.ts +34 -0
  212. package/src/utils/copy-public.ts +9 -6
  213. package/src/utils/diagnostic-utils.ts +8 -9
  214. package/src/utils/output-utils.ts +38 -8
  215. package/src/workers/client.worker.ts +141 -126
  216. package/src/workers/incremental-mtime-tracker.ts +68 -0
  217. package/src/workers/library-build.worker.ts +214 -75
  218. package/src/workers/server-build.worker.ts +31 -61
  219. package/src/workers/server-esbuild-context.ts +14 -2
  220. package/tests/angular/fixtures/packages/basic-app/dist/styles.css +3 -0
  221. package/tests/angular/fixtures/packages/basic-app/scss/styles.scss +5 -0
  222. package/tests/angular/ngtsc-build-core.acc.spec.ts +210 -0
  223. package/tests/angular/ngtsc-build-core.spec.ts +52 -0
  224. package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +13 -0
  225. package/tests/angular/web-worker-transformer.spec.ts +154 -0
  226. package/tests/capacitor/capacitor-build.spec.ts +1 -1
  227. package/tests/capacitor/capacitor-icon.spec.ts +1 -1
  228. package/tests/capacitor/capacitor-init.spec.ts +1 -1
  229. package/tests/commands/check.spec.ts +90 -104
  230. package/tests/commands/publish.spec.ts +12 -4
  231. package/tests/commands/slice3-severity-cleanup.verify.md +12 -0
  232. package/tests/commands/version-upgrade.acc.spec.ts +210 -0
  233. package/tests/commands/version-upgrade.spec.ts +148 -0
  234. package/tests/deps/replace-deps/collect-deps.acc.spec.ts +62 -0
  235. package/tests/deps/replace-deps/collect-deps.spec.ts +49 -0
  236. package/tests/deps/replace-deps/replace-deps-filter.spec.ts +103 -0
  237. package/tests/deps/replace-deps/replace-deps-perf.verify.md +15 -0
  238. package/tests/deps/replace-deps/replace-deps-resolve.acc.spec.ts +124 -0
  239. package/tests/deps/replace-deps/replace-deps-setup.acc.spec.ts +156 -0
  240. package/tests/electron/electron.spec.ts +4 -1
  241. package/tests/engines/engine-adapter-isolation.spec.ts +5 -6
  242. package/tests/engines/engine-duplicate-output-removal.verify.md +10 -0
  243. package/tests/engines/esbuild-client-engine.acc.spec.ts +79 -0
  244. package/tests/engines/esbuild-client-engine.spec.ts +73 -3
  245. package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +23 -0
  246. package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +21 -0
  247. package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +16 -0
  248. package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +15 -0
  249. package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +31 -0
  250. package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +31 -0
  251. package/tests/esbuild/esbuild-angular-compiler-plugin.spec.ts +397 -0
  252. package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +21 -0
  253. package/tests/esbuild/esbuild-postcss-plugin-chunking.verify.md +17 -0
  254. package/tests/esbuild/esbuild-postcss-plugin.acc.spec.ts +152 -0
  255. package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +13 -0
  256. package/tests/esbuild/esbuild-tsc-plugin.acc.spec.ts +56 -111
  257. package/tests/esbuild/esbuild-tsc-plugin.spec.ts +116 -52
  258. package/tests/esbuild/file-reference-tracker.spec.ts +99 -0
  259. package/tests/esbuild/lmdb-cache-store.spec.ts +58 -0
  260. package/tests/esbuild/load-result-cache.acc.spec.ts +55 -0
  261. package/tests/esbuild/load-result-cache.spec.ts +133 -0
  262. package/tests/orchestrators/build-orchestrator.spec.ts +4 -3
  263. package/tests/orchestrators/dev-orchestrator.spec.ts +5 -5
  264. package/tests/orchestrators/slice1-stdout-to-consola.verify.md +10 -0
  265. package/tests/orchestrators/typecheck-orchestrator.spec.ts +1 -1
  266. package/tests/orchestrators/watch-orchestrator.spec.ts +7 -7
  267. package/tests/runtime/result-collector.spec.ts +64 -0
  268. package/tests/sd-cli-entry.spec.ts +3 -4
  269. package/tests/sd-cli-log-tag.verify.md +11 -0
  270. package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +8 -0
  271. package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +12 -0
  272. package/tests/ts-compiler/SdTsCompiler-emit.verify.md +9 -0
  273. package/tests/ts-compiler/SdTsCompiler.acc.spec.ts +603 -0
  274. package/tests/ts-compiler/SdTsCompiler.spec.ts +265 -0
  275. package/tests/ts-compiler/SdTsCompiler.verify.md +41 -0
  276. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-browser.tsbuildinfo +1 -0
  277. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-node.tsbuildinfo +1 -0
  278. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck.tsbuildinfo +1 -0
  279. package/tests/ts-compiler/fixtures/non-angular-pkg/src/index.ts +3 -0
  280. package/tests/ts-compiler/fixtures/non-angular-pkg/src/util.ts +3 -0
  281. package/tests/ts-compiler/fixtures/non-angular-pkg/tests/sample.test-file.ts +3 -0
  282. package/tests/ts-compiler/fixtures/non-angular-pkg/tsconfig.json +12 -0
  283. package/tests/ts-compiler/scss-lint-integration.verify.md +14 -0
  284. package/tests/utils/angular-build.spec.ts +1 -1
  285. package/tests/utils/copy-public-outdir.verify.md +8 -0
  286. package/tests/utils/copy-public.acc.spec.ts +52 -0
  287. package/tests/utils/copy-public.spec.ts +56 -0
  288. package/tests/utils/diagnostic-utils.spec.ts +24 -15
  289. package/tests/utils/engine-watch-events.acc.spec.ts +59 -0
  290. package/tests/utils/engine-watch-events.spec.ts +58 -0
  291. package/tests/utils/esbuild-client-config-integration.verify.md +9 -0
  292. package/tests/utils/esbuild-client-config.acc.spec.ts +45 -61
  293. package/tests/utils/esbuild-client-config.spec.ts +70 -52
  294. package/tests/utils/ngtsc-build-core-write-emit.spec.ts +136 -12
  295. package/tests/utils/ngtsc-build-core.spec.ts +1 -44
  296. package/tests/utils/output-utils.spec.ts +133 -13
  297. package/tests/utils/replace-deps-watch.acc.spec.ts +7 -1
  298. package/tests/utils/replace-deps-watch.spec.ts +57 -1
  299. package/tests/utils/worker-utils.spec.ts +8 -2
  300. package/tests/workers/client-worker-initial-build-error.verify.md +2 -3
  301. package/tests/workers/client-worker-initial-build-warnings.verify.md +7 -0
  302. package/tests/workers/client-worker-mtime-incremental.verify.md +10 -0
  303. package/tests/workers/client-worker-refactor.verify.md +22 -0
  304. package/tests/workers/client-worker-ts-cache-invalidation.verify.md +12 -0
  305. package/tests/workers/client-worker.acc.spec.ts +6 -3
  306. package/tests/workers/incremental-mtime-tracker.acc.spec.ts +144 -0
  307. package/tests/workers/incremental-mtime-tracker.spec.ts +102 -0
  308. package/tests/workers/library-build-lint.spec.ts +40 -45
  309. package/tests/workers/library-build-worker.spec.ts +298 -40
  310. package/tests/workers/server-build-lint.spec.ts +59 -45
  311. package/tests/workers/server-build-worker.spec.ts +63 -24
  312. package/tests/workers/server-esbuild-context.acc.spec.ts +2 -0
  313. package/tests/workers/server-esbuild-context.spec.ts +2 -0
  314. package/tests/workers/server-runtime-worker.spec.ts +1 -1
  315. package/tests/workers/shared-worker-lifecycle.acc.spec.ts +1 -1
  316. package/dist/angular/angular-build-pipeline.d.ts +0 -97
  317. package/dist/angular/angular-build-pipeline.d.ts.map +0 -1
  318. package/dist/angular/angular-build-pipeline.js +0 -285
  319. package/dist/angular/angular-build-pipeline.js.map +0 -1
  320. package/dist/utils/tsc-build.d.ts +0 -51
  321. package/dist/utils/tsc-build.d.ts.map +0 -1
  322. package/dist/utils/tsc-build.js +0 -156
  323. package/dist/utils/tsc-build.js.map +0 -1
  324. package/dist/workers/ngtsc-build.worker.d.ts +0 -23
  325. package/dist/workers/ngtsc-build.worker.d.ts.map +0 -1
  326. package/dist/workers/ngtsc-build.worker.js +0 -267
  327. package/dist/workers/ngtsc-build.worker.js.map +0 -1
  328. package/src/angular/angular-build-pipeline.ts +0 -406
  329. package/src/utils/tsc-build.ts +0 -226
  330. package/src/workers/ngtsc-build.worker.ts +0 -351
  331. package/tests/angular/angular-build-pipeline.spec.ts +0 -247
  332. package/tests/angular/angular-compiler-aot.acc.spec.ts +0 -68
  333. package/tests/angular/angular-compiler-aot.spec.ts +0 -80
  334. package/tests/utils/angular-compiler-emit.spec.ts +0 -666
  335. package/tests/utils/angular-compiler.spec.ts +0 -707
  336. package/tests/utils/tsc-build.spec.ts +0 -527
  337. package/tests/workers/ngtsc-build-lint.spec.ts +0 -141
  338. package/tests/workers/ngtsc-build-worker.spec.ts +0 -199
@@ -0,0 +1,46 @@
1
+ import type ts from "typescript";
2
+ import type { AngularSourceFileCache } from "../angular/angular-compiler";
3
+ import type { TypecheckEnv } from "../utils/tsconfig";
4
+
5
+ export interface ISdTsCompilerEmitOptions {
6
+ /** emit 대상 소스 필터 (Angular only, 지정 시 해당 파일만 EmitResult에 포함) */
7
+ sourceFilter?: (fileName: string) => boolean;
8
+ /** Angular transformers 외 추가 transformers (Angular only) */
9
+ additionalTransformers?: {
10
+ before?: ts.TransformerFactory<ts.SourceFile>[];
11
+ after?: ts.TransformerFactory<ts.SourceFile>[];
12
+ };
13
+ }
14
+
15
+ export interface ISdTsCompilerOptions {
16
+ /** 패키지 디렉토리 */
17
+ pkgDir: string;
18
+ /** workspace 루트 (diagnostics 필터링 등에 사용) */
19
+ cwd: string;
20
+ /** 출력 제어 플래그 */
21
+ output: { js: boolean; dts: boolean };
22
+ /** tests/ 파일을 rootNames에 포함할지 여부. 기본값 false */
23
+ includeTests?: boolean;
24
+ /** 타입체크 환경. 설정 시 getCompilerOptionsForEnv()를 적용 */
25
+ env?: TypecheckEnv;
26
+
27
+ // === Angular 전용 (선택적, isForAngular 시 활성화) ===
28
+ /** SourceFile 캐시 (Angular 증분 빌드용). 미제공 시 내부 생성 */
29
+ sourceFileCache?: AngularSourceFileCache;
30
+ /** 스타일시트 변환 콜백 (Feature 1.3에서 활용) */
31
+ transformStylesheet?: (
32
+ data: string,
33
+ containingFile: string,
34
+ stylesheetFile?: string,
35
+ ) => Promise<string | null>;
36
+ /** 외부 스타일시트 맵 (클라이언트 빌드용, resourceNameToFileName에서 사용) */
37
+ externalStylesheets?: Map<string, string>;
38
+ /** compilerOptions 후처리 (클라이언트의 target/module 강제 등) */
39
+ compilerOptionsTransformer?: (options: ts.CompilerOptions) => ts.CompilerOptions;
40
+
41
+ // === SCSS/lint 통합 (Feature 1.3) ===
42
+ /** lint 실행 여부. true이면 compileAsync 결과에 lint 결과 포함 */
43
+ lint?: boolean;
44
+ /** 글로벌 SCSS 컴파일 여부. true이면 scss/styles.scss → dist/styles.css 생성 */
45
+ globalScss?: boolean;
46
+ }
@@ -0,0 +1,34 @@
1
+ import type ts from "typescript";
2
+ import type { SerializedDiagnostic } from "../typecheck/typecheck-serialization";
3
+ import type { EmitResult } from "../angular/angular-compiler";
4
+ import type { LintWithProgramResult } from "../lint/lint-with-program";
5
+ import type { NgtscProgram } from "../angular/angular-build";
6
+
7
+ export interface ISdTsCompilerResult {
8
+ /** TypeScript Program 참조 (lint, 외부 도구용) */
9
+ program: ts.Program;
10
+ /** Builder Program 참조 */
11
+ builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram;
12
+ /** Angular 패키지 여부 */
13
+ isForAngular: boolean;
14
+ /** 이 빌드에서 영향받은 파일 (posix 경로). undefined = 전역 변경 (전체 리빌드) */
15
+ affectedFiles: ReadonlySet<string> | undefined;
16
+ /** 직렬화된 진단 정보 (Worker 경계 통과용) */
17
+ diagnostics: SerializedDiagnostic[];
18
+ /** Error 카테고리 진단 수 */
19
+ errorCount: number;
20
+ /** Warning 카테고리 진단 수 */
21
+ warningCount: number;
22
+ /** Error 카테고리 진단을 "파일:줄:열: TS코드: 메시지" 형식으로 포맷한 배열 */
23
+ errors?: string[];
24
+ /** NgtscProgram 참조 (Angular only, HMR용). Non-Angular이면 undefined */
25
+ ngtscProgram?: NgtscProgram;
26
+ /** Angular emit 결과 (Non-Angular이면 undefined — writeFile 훅으로 디스크 직접 쓰기) */
27
+ emitResults?: EmitResult[];
28
+ /** lint 결과 (lint 옵션 활성 시) */
29
+ lint?: LintWithProgramResult;
30
+ /** SCSS 에러 목록 */
31
+ scssErrors: string[];
32
+ /** SCSS 의존성 맵 (소유자 파일 → 의존 SCSS 경로 집합). watch 역방향 탐색용 */
33
+ scssDependencies: ReadonlyMap<string, ReadonlySet<string>>;
34
+ }
@@ -6,14 +6,15 @@ import {
6
6
  } from "@simplysm/core-node";
7
7
 
8
8
  /**
9
- * public/ 및 public-dev/ 디렉토리의 파일을 dist/로 복사한다.
9
+ * public/ 및 public-dev/ 디렉토리의 파일을 출력 디렉토리로 복사한다.
10
10
  * public-dev/가 public/보다 우선한다 (오버레이).
11
11
  *
12
12
  * @param pkgDir 패키지 루트 디렉토리
13
13
  * @param includeDev public-dev/ 포함 여부 (dev 모드에서만 true)
14
+ * @param outDir 출력 디렉토리 (미지정 시 pkgDir/dist)
14
15
  */
15
- export async function copyPublicFiles(pkgDir: string, includeDev: boolean): Promise<void> {
16
- const distDir = pathx.posix(path.join(pkgDir, "dist"));
16
+ export async function copyPublicFiles(pkgDir: string, includeDev: boolean, outDir?: string): Promise<void> {
17
+ const distDir = pathx.posix(outDir ?? path.join(pkgDir, "dist"));
17
18
  await fsx.mkdir(distDir);
18
19
 
19
20
  // public/ 복사
@@ -48,23 +49,25 @@ export async function copyPublicFiles(pkgDir: string, includeDev: boolean): Prom
48
49
  }
49
50
 
50
51
  /**
51
- * public/ 및 public-dev/ 디렉토리를 감시하고 변경사항을 실시간으로 dist/에 복사한다.
52
+ * public/ 및 public-dev/ 디렉토리를 감시하고 변경사항을 실시간으로 출력 디렉토리에 복사한다.
52
53
  * 초기 복사 후 변경/추가/삭제를 자동으로 반영한다.
53
54
  *
54
55
  * @param pkgDir 패키지 루트 디렉토리
55
56
  * @param includeDev public-dev/ 포함 여부 (dev 모드에서만 true)
57
+ * @param outDir 출력 디렉토리 (미지정 시 pkgDir/dist)
56
58
  * @returns FsWatcher 인스턴스 (종료 시 close() 호출 필요) 또는 감시 대상이 없으면 undefined
57
59
  */
58
60
  export async function watchPublicFiles(
59
61
  pkgDir: string,
60
62
  includeDev: boolean,
63
+ outDir?: string,
61
64
  ): Promise<FsWatcher | undefined> {
62
- const distDir = pathx.posix(path.join(pkgDir, "dist"));
65
+ const distDir = pathx.posix(outDir ?? path.join(pkgDir, "dist"));
63
66
  const publicDir = pathx.posix(path.join(pkgDir, "public"));
64
67
  const publicDevDir = pathx.posix(path.join(pkgDir, "public-dev"));
65
68
 
66
69
  // 초기 복사
67
- await copyPublicFiles(pkgDir, includeDev);
70
+ await copyPublicFiles(pkgDir, includeDev, outDir);
68
71
 
69
72
  // 감시 대상 경로 수집
70
73
  const watchPaths: string[] = [];
@@ -30,14 +30,13 @@ export function formatDiagnosticsOutput(diagnostics: ts.Diagnostic[], cwd: strin
30
30
  }
31
31
 
32
32
  /**
33
- * 진단 에러를 "파일:줄:열: TS코드: 메시지" 형식으로 포맷한다.
34
- * 파일 정보가 없는 경우 "TS코드: 메시지" 형식으로 반환한다.
33
+ * 진단 에러를 TypeScript 네이티브 컬러+코드 컨텍스트 포맷으로 변환한다.
35
34
  */
36
- export function formatDiagnosticError(diagnostic: ts.Diagnostic): string {
37
- const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
38
- if (diagnostic.file != null && diagnostic.start != null) {
39
- const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
40
- return `${diagnostic.file.fileName}:${line + 1}:${character + 1}: TS${diagnostic.code}: ${message}`;
41
- }
42
- return `TS${diagnostic.code}: ${message}`;
35
+ export function formatDiagnosticError(diagnostic: ts.Diagnostic, cwd: string): string {
36
+ const formatHost: ts.FormatDiagnosticsHost = {
37
+ getCanonicalFileName: (f) => f,
38
+ getCurrentDirectory: () => cwd,
39
+ getNewLine: () => ts.sys.newLine,
40
+ };
41
+ return ts.formatDiagnosticsWithColorAndContext([diagnostic], formatHost).trimEnd();
43
42
  }
@@ -1,6 +1,23 @@
1
+ import { formatMessagesSync, type PartialMessage } from "esbuild";
1
2
  import { consola } from "consola";
2
3
  import type { BuildResult } from "../runtime/ResultCollector";
3
4
 
5
+ const logger = consola.withTag("sd:cli:output");
6
+
7
+ /**
8
+ * esbuild Message 배열을 포맷된 문자열 배열로 변환한다.
9
+ * esbuild 네이티브 포맷(코드 컨텍스트, 위치 정보, 밑줄)을 유지한다.
10
+ */
11
+ export function formatEsbuildMessages(
12
+ messages: PartialMessage[],
13
+ kind: "error" | "warning",
14
+ ): string[] {
15
+ if (messages.length === 0) return [];
16
+ return formatMessagesSync(messages, { kind, color: true }).map((msg) =>
17
+ msg.replace(/^.*?\x1b\[0m |^X \[ERROR] |^▲ \[WARNING] /, "").trimEnd(),
18
+ );
19
+ }
20
+
4
21
  /**
5
22
  * 빌드 경고/에러 메시지를 포맷팅한다.
6
23
  */
@@ -8,27 +25,40 @@ export function formatBuildMessages(name: string, label: string, messages: strin
8
25
  const lines: string[] = [`${name} (${label})`];
9
26
  for (const msg of messages) {
10
27
  for (const line of msg.split("\n")) {
11
- lines.push(` → ${line}`);
28
+ if (line === "") {
29
+ lines.push("");
30
+ } else {
31
+ lines.push(` ${line}`);
32
+ }
12
33
  }
13
34
  }
14
35
  return lines.join("\n");
15
36
  }
16
37
 
17
38
  /**
18
- * 에러만 출력한다.
39
+ * 에러와 경고를 출력한다. 에러를 먼저, 경고를 나중에 출력한다.
19
40
  * @param results 패키지별 빌드 결과 상태
20
41
  */
21
- export function printErrors(results: ReadonlyMap<string, BuildResult>): void {
42
+ export function printDiagnostics(results: ReadonlyMap<string, BuildResult>): void {
43
+ // 에러 출력
22
44
  for (const result of results.values()) {
23
45
  if (result.status === "error") {
24
46
  const typeLabel = result.type === "lint" ? "lint" : result.target;
25
47
  if (result.message != null && result.message !== "") {
26
- consola.error(formatBuildMessages(result.name, typeLabel, [result.message]));
48
+ logger.error(formatBuildMessages(result.name, typeLabel, [result.message]));
27
49
  } else {
28
- consola.error(`[${result.name}] (${typeLabel}) 실패`);
50
+ logger.error(`[${result.name}] (${typeLabel}) 실패`);
29
51
  }
30
52
  }
31
53
  }
54
+
55
+ // 경고 출력
56
+ for (const result of results.values()) {
57
+ if (result.warnings != null && result.warnings !== "") {
58
+ const typeLabel = result.type === "lint" ? "lint" : result.target;
59
+ logger.warn(formatBuildMessages(result.name, typeLabel, [result.warnings]));
60
+ }
61
+ }
32
62
  }
33
63
 
34
64
  /**
@@ -53,15 +83,15 @@ export function printServers(
53
83
  const activeClients = clients.filter((c) => results.get(`${c}:build`)?.status !== "error");
54
84
  if (activeClients.length > 0) {
55
85
  for (const clientName of activeClients) {
56
- consola.info(`[server] http://localhost:${server.port}/${clientName}/`);
86
+ logger.info(`[server] http://localhost:${server.port}/${clientName}/`);
57
87
  }
58
88
  } else {
59
89
  // 연결된 클라이언트가 없으면 서버 루트 URL 출력
60
- consola.info(`[server] http://localhost:${server.port}/`);
90
+ logger.info(`[server] http://localhost:${server.port}/`);
61
91
  }
62
92
  } else {
63
93
  // 독립형 클라이언트: 이름 포함하여 출력
64
- consola.info(`[server] http://localhost:${server.port}/${server.name}/`);
94
+ logger.info(`[server] http://localhost:${server.port}/${server.name}/`);
65
95
  }
66
96
  }
67
97
  }
@@ -2,19 +2,22 @@ import path from "path";
2
2
  import fs from "node:fs";
3
3
  import { createWorker, FsWatcher } from "@simplysm/core-node";
4
4
  import { err as errNs } from "@simplysm/core-common";
5
- import { setupWorkerLifecycle } from "./shared-worker-lifecycle.js";
5
+ import { setupWorkerLifecycle } from "./shared-worker-lifecycle";
6
6
  import {
7
7
  createClientEsbuildContext,
8
8
  type ClientEsbuildResult,
9
- } from "../esbuild/esbuild-client-config.js";
10
- import { generateIndexHtml } from "../esbuild/esbuild-index-html.js";
11
- import { applyPwa, createPwaHtmlTransform } from "../esbuild/esbuild-pwa.js";
12
- import { createDevHttpServer, type DevHttpServer } from "../dev-server/dev-http-server.js";
13
- import { createHmrService, type HmrService } from "../dev-server/hmr-service.js";
14
- import { createHmrPostTransform } from "../dev-server/hmr-client-script.js";
15
- import { copyPublicFiles, watchPublicFiles } from "../utils/copy-public.js";
16
- import type { SdBrowserSupportConfig, SdPwaConfig } from "../sd-config.types.js";
9
+ } from "../esbuild/esbuild-client-config";
10
+ import { generateIndexHtml } from "../esbuild/esbuild-index-html";
11
+ import { formatEsbuildMessages } from "../utils/output-utils";
12
+ import { applyPwa, createPwaHtmlTransform } from "../esbuild/esbuild-pwa";
13
+ import { createDevHttpServer, type DevHttpServer } from "../dev-server/dev-http-server";
14
+ import { createHmrService, type HmrService } from "../dev-server/hmr-service";
15
+ import { createHmrPostTransform } from "../dev-server/hmr-client-script";
16
+ import { copyPublicFiles, watchPublicFiles } from "../utils/copy-public";
17
+ import type { SdBrowserSupportConfig, SdPwaConfig } from "../sd-config.types";
17
18
  import type esbuild from "esbuild";
19
+ import type { PartialMessage } from "esbuild";
20
+ import { IncrementalMtimeTracker } from "./incremental-mtime-tracker";
18
21
 
19
22
  //#region Types
20
23
 
@@ -63,6 +66,9 @@ let devServer: DevHttpServer | undefined;
63
66
  let hmrService: HmrService | undefined;
64
67
  let publicWatcher: FsWatcher | undefined;
65
68
  let indexHtmlWatcher: FsWatcher | undefined;
69
+ let lastMetafile: esbuild.Metafile | undefined;
70
+ let isInitialBuild = true;
71
+ let initialBuildResolve: ((result: ClientBuildResult) => void) | undefined;
66
72
 
67
73
  const { logger, guardStartWatch } = setupWorkerLifecycle("client", async () => {
68
74
  await stopWatch();
@@ -98,7 +104,7 @@ async function build(info: ClientBuildInfo): Promise<ClientBuildResult> {
98
104
  const outdir = info.outDir ?? path.join(info.pkgDir, "dist");
99
105
 
100
106
  // 1. public/ 복사
101
- await copyPublicFiles(info.pkgDir, false);
107
+ await copyPublicFiles(info.pkgDir, false, outdir);
102
108
 
103
109
  // 2. polyfills 감지
104
110
  const polyfillsPath = path.join(info.pkgDir, "src", "polyfills.ts");
@@ -160,7 +166,7 @@ async function build(info: ClientBuildInfo): Promise<ClientBuildResult> {
160
166
  // SourceFileCache는 LMDB 기반. context.dispose()에 의해 정리됨.
161
167
 
162
168
  // 8. .config.json 기록
163
- writeConfigJson(path.join(info.pkgDir, "dist"), info.configs);
169
+ writeConfigJson(outdir, info.configs);
164
170
 
165
171
  logger.debug(`[${info.name}] client worker build 완료`);
166
172
  return {
@@ -171,17 +177,131 @@ async function build(info: ClientBuildInfo): Promise<ClientBuildResult> {
171
177
  } catch (err) {
172
178
  const errors: string[] = [];
173
179
  if (err != null && typeof err === "object" && "errors" in err) {
174
- const buildErrors = (err as { errors: Array<{ text: string }> }).errors;
175
- errors.push(...buildErrors.map((e) => e.text));
180
+ const buildErrors = (err as { errors: PartialMessage[] }).errors;
181
+ errors.push(...formatEsbuildMessages(buildErrors, "error"));
176
182
  }
177
183
  if (errors.length === 0) {
178
184
  errors.push(errNs.message(err));
179
185
  }
180
- logger.debug(`[${info.name}] client worker build 예외: ${errors.join("; ")}`);
186
+ logger.debug(`[${info.name}] client worker build 예외: ${errors.join("\n")}`);
181
187
  return { success: false, errors };
182
188
  }
183
189
  }
184
190
 
191
+ /**
192
+ * sourceFileCache 무효화 + mtime 추적 플러그인 생성
193
+ */
194
+ function createSourceFileCachePlugin(): esbuild.Plugin {
195
+ return {
196
+ name: "sd-build-start",
197
+ setup(pluginBuild: esbuild.PluginBuild) {
198
+ const mtimeTracker = new IncrementalMtimeTracker();
199
+
200
+ pluginBuild.onStart(() => {
201
+ // sourceFileCache 무효화: 변경된 파일의 loadResultCache + TypeScript 소스 캐시 모두 제거
202
+ if (esbuildResult != null) {
203
+ const { loadResultCache, typeScriptFileCache } =
204
+ esbuildResult.sourceFileCache;
205
+ // JS 파일 (loadResultCache) + TS 파일 (typeScriptFileCache) 모두 감시
206
+ const watchTargets = [
207
+ ...loadResultCache.watchFiles,
208
+ ...typeScriptFileCache.keys(),
209
+ ];
210
+ const changedFiles = mtimeTracker.detectChanges(watchTargets);
211
+ if (changedFiles.size > 0) {
212
+ esbuildResult.sourceFileCache.invalidate(changedFiles);
213
+ }
214
+ }
215
+
216
+ if (!isInitialBuild) {
217
+ sender.send("buildStart", {});
218
+ }
219
+ });
220
+
221
+ pluginBuild.onEnd(() => {
222
+ if (esbuildResult == null) return;
223
+ // JS 파일 (loadResultCache) + TS 파일 (typeScriptFileCache) 모두 기록
224
+ const watchTargets = [
225
+ ...esbuildResult.sourceFileCache.loadResultCache.watchFiles,
226
+ ...esbuildResult.sourceFileCache.typeScriptFileCache.keys(),
227
+ ];
228
+ mtimeTracker.updateMtimes(watchTargets);
229
+ });
230
+ },
231
+ };
232
+ }
233
+
234
+ /**
235
+ * dev watch 빌드 완료 핸들러 생성 (index.html 재생성 + HMR + 이벤트 전송)
236
+ */
237
+ function createDevBuildEndHandler(
238
+ basePath: string,
239
+ actualPort: number,
240
+ outdir: string,
241
+ entryNames: string[],
242
+ pkgDir: string,
243
+ ): (result: esbuild.BuildResult) => Promise<void> {
244
+ return async (result: esbuild.BuildResult) => {
245
+ try {
246
+ // index.html 재생성 (lastMetafile 보관 — index.html 단독 변경 시 재생성용)
247
+ if (result.metafile != null) {
248
+ lastMetafile = result.metafile;
249
+ const hmrPostTransform = createHmrPostTransform(basePath, actualPort);
250
+ const indexPath = path.join(pkgDir, "src", "index.html");
251
+ const indexResult = await generateIndexHtml({
252
+ indexPath,
253
+ metafile: result.metafile,
254
+ outdir,
255
+ baseHref: basePath,
256
+ mode: "dev",
257
+ entryNames,
258
+ postTransform: hmrPostTransform,
259
+ });
260
+ fs.writeFileSync(path.join(outdir, "index.html"), indexResult.content);
261
+ }
262
+
263
+ // HMR 메시지 디스패치
264
+ if (hmrService != null && result.metafile != null && !isInitialBuild) {
265
+ hmrService.onBuildEnd(result.metafile);
266
+ }
267
+
268
+ // build 이벤트 전송
269
+ const success = result.errors.length === 0;
270
+ const errors = result.errors.length > 0
271
+ ? formatEsbuildMessages(result.errors, "error")
272
+ : undefined;
273
+ const warnings = result.warnings.length > 0
274
+ ? formatEsbuildMessages(result.warnings, "warning")
275
+ : undefined;
276
+
277
+ if (!isInitialBuild) {
278
+ sender.send("build", { success, errors, warnings });
279
+ }
280
+
281
+ // 초기 빌드 완료 시 resolve
282
+ if (isInitialBuild) {
283
+ isInitialBuild = false;
284
+ initialBuildResolve?.({ success, errors, warnings });
285
+ }
286
+ } catch (err) {
287
+ const message = errNs.message(err);
288
+ if (!isInitialBuild) {
289
+ sender.send("error", { message });
290
+ } else {
291
+ isInitialBuild = false;
292
+ initialBuildResolve?.({
293
+ success: false,
294
+ errors: [message],
295
+ warnings:
296
+ result.warnings.length > 0
297
+ ? formatEsbuildMessages(result.warnings, "warning")
298
+ : undefined,
299
+ });
300
+ }
301
+ }
302
+ };
303
+ }
304
+
185
305
  /**
186
306
  * dev watch 시작
187
307
  */
@@ -232,10 +352,6 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
232
352
  });
233
353
 
234
354
  // 7. esbuild context 생성
235
- let lastMetafile: esbuild.Metafile | undefined;
236
- let initialBuildResolve: ((result: ClientBuildResult) => void) | undefined;
237
- let isInitialBuild = true;
238
-
239
355
  esbuildResult = await createClientEsbuildContext({
240
356
  pkgDir: info.pkgDir,
241
357
  cwd: info.cwd,
@@ -247,114 +363,8 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
247
363
  legacyModule,
248
364
  postcssPlugins,
249
365
  templateUpdates: legacyModule ? undefined : templateUpdates,
250
- plugins: [
251
- {
252
- name: "sd-build-start",
253
- setup(pluginBuild: esbuild.PluginBuild) {
254
- const prevMtimes = new Map<string, number>();
255
-
256
- pluginBuild.onStart(() => {
257
- // sourceFileCache 무효화: 변경된 파일의 loadResultCache + TypeScript 소스 캐시 모두 제거
258
- if (esbuildResult != null) {
259
- const { loadResultCache } = esbuildResult.sourceFileCache;
260
- const changedFiles = new Set<string>();
261
- for (const file of loadResultCache.watchFiles) {
262
- try {
263
- const mtime = fs.statSync(file).mtimeMs;
264
- const prev = prevMtimes.get(file);
265
- if (prev != null && prev !== mtime) {
266
- changedFiles.add(file);
267
- }
268
- } catch {
269
- if (prevMtimes.has(file)) {
270
- changedFiles.add(file);
271
- }
272
- }
273
- }
274
- if (changedFiles.size > 0) {
275
- esbuildResult.sourceFileCache.invalidate(changedFiles);
276
- }
277
- }
278
-
279
- if (!isInitialBuild) {
280
- sender.send("buildStart", {});
281
- }
282
- });
283
-
284
- pluginBuild.onEnd(() => {
285
- if (esbuildResult == null) return;
286
- prevMtimes.clear();
287
- for (const file of esbuildResult.sourceFileCache.loadResultCache.watchFiles) {
288
- try {
289
- prevMtimes.set(file, fs.statSync(file).mtimeMs);
290
- } catch {
291
- // 삭제된 파일
292
- }
293
- }
294
- });
295
- },
296
- },
297
- ],
298
- onEnd: async (result: esbuild.BuildResult) => {
299
- try {
300
- // index.html 재생성 (lastMetafile 보관 — index.html 단독 변경 시 재생성용)
301
- if (result.metafile != null) {
302
- lastMetafile = result.metafile;
303
- const hmrPostTransform = createHmrPostTransform(basePath, actualPort);
304
- const indexPath = path.join(info.pkgDir, "src", "index.html");
305
- const indexResult = await generateIndexHtml({
306
- indexPath,
307
- metafile: result.metafile,
308
- outdir,
309
- baseHref: basePath,
310
- mode: "dev",
311
- entryNames,
312
- postTransform: hmrPostTransform,
313
- });
314
- fs.writeFileSync(path.join(outdir, "index.html"), indexResult.content);
315
- }
316
-
317
- // HMR 메시지 디스패치
318
- if (hmrService != null && result.metafile != null && !isInitialBuild) {
319
- hmrService.onBuildEnd(result.metafile);
320
- }
321
-
322
- // build 이벤트 전송
323
- const success = result.errors.length === 0;
324
- if (!isInitialBuild) {
325
- sender.send("build", {
326
- success,
327
- errors:
328
- result.errors.length > 0
329
- ? result.errors.map((e) => e.text)
330
- : undefined,
331
- warnings:
332
- result.warnings.length > 0
333
- ? result.warnings.map((w) => w.text)
334
- : undefined,
335
- });
336
- }
337
-
338
- // 초기 빌드 완료 시 resolve
339
- if (isInitialBuild) {
340
- isInitialBuild = false;
341
- initialBuildResolve?.({
342
- success,
343
- errors:
344
- result.errors.length > 0
345
- ? result.errors.map((e) => e.text)
346
- : undefined,
347
- });
348
- }
349
- } catch (err) {
350
- const message = errNs.message(err);
351
- sender.send("error", { message });
352
- if (isInitialBuild) {
353
- isInitialBuild = false;
354
- initialBuildResolve?.({ success: false, errors: [message] });
355
- }
356
- }
357
- },
366
+ plugins: [createSourceFileCachePlugin()],
367
+ onEnd: createDevBuildEndHandler(basePath, actualPort, outdir, entryNames, info.pkgDir),
358
368
  });
359
369
 
360
370
  // 8. esbuild watch 시작 + 초기 빌드 대기
@@ -440,6 +450,11 @@ async function stopWatch(): Promise<void> {
440
450
  indexHtmlWatcher = undefined;
441
451
  }
442
452
 
453
+ // 6. 빌드 세션 상태 리셋
454
+ lastMetafile = undefined;
455
+ isInitialBuild = true;
456
+ initialBuildResolve = undefined;
457
+
443
458
  logger.debug("esbuild watch 정리 완료");
444
459
  }
445
460
 
@@ -0,0 +1,68 @@
1
+ import fs from "node:fs";
2
+
3
+ /**
4
+ * 증분 방식으로 파일 mtime을 추적하여 변경 파일을 감지한다.
5
+ *
6
+ * - `detectChanges`: watchTargets 전체를 stat하여 이전 mtime과 비교, 변경 파일 Set 반환
7
+ * - `updateMtimes`: 변경/신규 파일만 stat하여 prevMtimes를 증분 갱신
8
+ */
9
+ export class IncrementalMtimeTracker {
10
+ private readonly _prevMtimes = new Map<string, number>();
11
+ private _lastChangedFiles = new Set<string>();
12
+
13
+ detectChanges(watchTargets: Iterable<string>): Set<string> {
14
+ const changedFiles = new Set<string>();
15
+ for (const file of watchTargets) {
16
+ try {
17
+ const mtime = fs.statSync(file).mtimeMs;
18
+ const prev = this._prevMtimes.get(file);
19
+ if (prev != null && prev !== mtime) {
20
+ changedFiles.add(file);
21
+ }
22
+ } catch {
23
+ if (this._prevMtimes.has(file)) {
24
+ changedFiles.add(file);
25
+ }
26
+ }
27
+ }
28
+ this._lastChangedFiles = changedFiles;
29
+ return changedFiles;
30
+ }
31
+
32
+ updateMtimes(currentWatchTargets: Iterable<string>): void {
33
+ const targetSet =
34
+ currentWatchTargets instanceof Set
35
+ ? (currentWatchTargets as Set<string>)
36
+ : new Set(currentWatchTargets);
37
+
38
+ // 1) 삭제된 파일 정리: prevMtimes에 있지만 watchTargets에 없는 파일 제거
39
+ for (const file of this._prevMtimes.keys()) {
40
+ if (!targetSet.has(file)) {
41
+ this._prevMtimes.delete(file);
42
+ }
43
+ }
44
+
45
+ // 2) 변경된 파일 mtime 재조회 (watchTargets에 있는 파일만)
46
+ for (const file of this._lastChangedFiles) {
47
+ if (!targetSet.has(file)) continue;
48
+ try {
49
+ this._prevMtimes.set(file, fs.statSync(file).mtimeMs);
50
+ } catch {
51
+ this._prevMtimes.delete(file);
52
+ }
53
+ }
54
+
55
+ // 3) 신규 파일만 stat (prevMtimes에 없는 파일)
56
+ for (const file of targetSet) {
57
+ if (!this._prevMtimes.has(file)) {
58
+ try {
59
+ this._prevMtimes.set(file, fs.statSync(file).mtimeMs);
60
+ } catch {
61
+ // 삭제된 파일 — 무시
62
+ }
63
+ }
64
+ }
65
+
66
+ this._lastChangedFiles = new Set();
67
+ }
68
+ }