@simplysm/sd-cli 14.0.7 → 14.0.9

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 (265) hide show
  1. package/dist/angular/client-transform-stylesheet.d.ts.map +1 -1
  2. package/dist/angular/client-transform-stylesheet.js.map +1 -1
  3. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  4. package/dist/angular/vite-angular-plugin.js +15 -8
  5. package/dist/angular/vite-angular-plugin.js.map +1 -1
  6. package/dist/angular/vite-postcss-inline-plugin.d.ts.map +1 -1
  7. package/dist/angular/vite-postcss-inline-plugin.js.map +1 -1
  8. package/dist/capacitor/capacitor.d.ts +1 -1
  9. package/dist/capacitor/capacitor.d.ts.map +1 -1
  10. package/dist/capacitor/capacitor.js +43 -44
  11. package/dist/capacitor/capacitor.js.map +1 -1
  12. package/dist/commands/build.d.ts.map +1 -1
  13. package/dist/commands/build.js.map +1 -1
  14. package/dist/commands/check.d.ts.map +1 -1
  15. package/dist/commands/check.js +2 -2
  16. package/dist/commands/check.js.map +1 -1
  17. package/dist/commands/dev.d.ts.map +1 -1
  18. package/dist/commands/dev.js.map +1 -1
  19. package/dist/commands/lint.d.ts.map +1 -1
  20. package/dist/commands/lint.js.map +1 -1
  21. package/dist/commands/publish.d.ts.map +1 -1
  22. package/dist/commands/publish.js +12 -13
  23. package/dist/commands/publish.js.map +1 -1
  24. package/dist/commands/replace-deps.d.ts.map +1 -1
  25. package/dist/commands/replace-deps.js.map +1 -1
  26. package/dist/commands/typecheck.d.ts.map +1 -1
  27. package/dist/commands/typecheck.js +12 -12
  28. package/dist/commands/typecheck.js.map +1 -1
  29. package/dist/commands/watch.d.ts.map +1 -1
  30. package/dist/commands/watch.js.map +1 -1
  31. package/dist/electron/electron.d.ts.map +1 -1
  32. package/dist/electron/electron.js +42 -37
  33. package/dist/electron/electron.js.map +1 -1
  34. package/dist/engines/BaseEngine.d.ts +1 -5
  35. package/dist/engines/BaseEngine.d.ts.map +1 -1
  36. package/dist/engines/BaseEngine.js +7 -16
  37. package/dist/engines/BaseEngine.js.map +1 -1
  38. package/dist/engines/NgtscEngine.d.ts.map +1 -1
  39. package/dist/engines/NgtscEngine.js +10 -11
  40. package/dist/engines/NgtscEngine.js.map +1 -1
  41. package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
  42. package/dist/engines/ServerEsbuildEngine.js +10 -11
  43. package/dist/engines/ServerEsbuildEngine.js.map +1 -1
  44. package/dist/engines/TscEngine.d.ts.map +1 -1
  45. package/dist/engines/TscEngine.js +10 -11
  46. package/dist/engines/TscEngine.js.map +1 -1
  47. package/dist/engines/ViteEngine.d.ts.map +1 -1
  48. package/dist/engines/ViteEngine.js +3 -13
  49. package/dist/engines/ViteEngine.js.map +1 -1
  50. package/dist/engines/index.d.ts.map +1 -1
  51. package/dist/engines/index.js.map +1 -1
  52. package/dist/engines/types.d.ts +3 -6
  53. package/dist/engines/types.d.ts.map +1 -1
  54. package/dist/engines/types.js.map +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/infra/ResultCollector.d.ts +1 -1
  58. package/dist/infra/ResultCollector.d.ts.map +1 -1
  59. package/dist/infra/ResultCollector.js.map +1 -1
  60. package/dist/infra/SignalHandler.d.ts.map +1 -1
  61. package/dist/infra/SignalHandler.js.map +1 -1
  62. package/dist/infra/WorkerManager.d.ts.map +1 -1
  63. package/dist/infra/WorkerManager.js.map +1 -1
  64. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  65. package/dist/orchestrators/BuildOrchestrator.js +30 -61
  66. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  67. package/dist/orchestrators/DevWatchOrchestrator.d.ts +2 -0
  68. package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
  69. package/dist/orchestrators/DevWatchOrchestrator.js +40 -44
  70. package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
  71. package/dist/sd-cli-entry.d.ts.map +1 -1
  72. package/dist/sd-cli-entry.js +2 -13
  73. package/dist/sd-cli-entry.js.map +1 -1
  74. package/dist/sd-cli.d.ts.map +1 -1
  75. package/dist/sd-cli.js +5 -5
  76. package/dist/sd-cli.js.map +1 -1
  77. package/dist/sd-config.types.d.ts.map +1 -1
  78. package/dist/sd-config.types.js.map +1 -1
  79. package/dist/utils/SdCliReporter.d.ts +18 -0
  80. package/dist/utils/SdCliReporter.d.ts.map +1 -0
  81. package/dist/utils/SdCliReporter.js +144 -0
  82. package/dist/utils/SdCliReporter.js.map +1 -0
  83. package/dist/utils/angular-build.d.ts.map +1 -1
  84. package/dist/utils/angular-build.js.map +1 -1
  85. package/dist/utils/angular-compiler.d.ts.map +1 -1
  86. package/dist/utils/angular-compiler.js +11 -4
  87. package/dist/utils/angular-compiler.js.map +1 -1
  88. package/dist/utils/build-env.d.ts.map +1 -1
  89. package/dist/utils/build-env.js +2 -1
  90. package/dist/utils/build-env.js.map +1 -1
  91. package/dist/utils/concurrency.d.ts.map +1 -1
  92. package/dist/utils/concurrency.js.map +1 -1
  93. package/dist/utils/copy-public.d.ts.map +1 -1
  94. package/dist/utils/copy-public.js +21 -21
  95. package/dist/utils/copy-public.js.map +1 -1
  96. package/dist/utils/copy-src.d.ts.map +1 -1
  97. package/dist/utils/copy-src.js +12 -12
  98. package/dist/utils/copy-src.js.map +1 -1
  99. package/dist/utils/diagnostic-utils.d.ts.map +1 -1
  100. package/dist/utils/diagnostic-utils.js +3 -2
  101. package/dist/utils/diagnostic-utils.js.map +1 -1
  102. package/dist/utils/engine-stop.d.ts.map +1 -1
  103. package/dist/utils/engine-stop.js.map +1 -1
  104. package/dist/utils/esbuild-config.d.ts.map +1 -1
  105. package/dist/utils/esbuild-config.js +2 -0
  106. package/dist/utils/esbuild-config.js.map +1 -1
  107. package/dist/utils/generate-pwa-icons.d.ts.map +1 -1
  108. package/dist/utils/generate-pwa-icons.js.map +1 -1
  109. package/dist/utils/hmr-candidates.d.ts.map +1 -1
  110. package/dist/utils/hmr-candidates.js.map +1 -1
  111. package/dist/utils/lint-utils.d.ts.map +1 -1
  112. package/dist/utils/lint-utils.js.map +1 -1
  113. package/dist/utils/lint-with-program.d.ts.map +1 -1
  114. package/dist/utils/lint-with-program.js +7 -3
  115. package/dist/utils/lint-with-program.js.map +1 -1
  116. package/dist/utils/ngtsc-build-core.d.ts +2 -10
  117. package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
  118. package/dist/utils/ngtsc-build-core.js +16 -15
  119. package/dist/utils/ngtsc-build-core.js.map +1 -1
  120. package/dist/utils/orchestrator-utils.d.ts.map +1 -1
  121. package/dist/utils/orchestrator-utils.js.map +1 -1
  122. package/dist/utils/output-path-rewriter.d.ts.map +1 -1
  123. package/dist/utils/output-path-rewriter.js +7 -7
  124. package/dist/utils/output-path-rewriter.js.map +1 -1
  125. package/dist/utils/output-utils.d.ts.map +1 -1
  126. package/dist/utils/output-utils.js +1 -1
  127. package/dist/utils/output-utils.js.map +1 -1
  128. package/dist/utils/package-utils.d.ts +4 -0
  129. package/dist/utils/package-utils.d.ts.map +1 -1
  130. package/dist/utils/package-utils.js +34 -13
  131. package/dist/utils/package-utils.js.map +1 -1
  132. package/dist/utils/rebuild-manager.d.ts +1 -1
  133. package/dist/utils/rebuild-manager.d.ts.map +1 -1
  134. package/dist/utils/rebuild-manager.js +3 -1
  135. package/dist/utils/rebuild-manager.js.map +1 -1
  136. package/dist/utils/replace-deps.d.ts.map +1 -1
  137. package/dist/utils/replace-deps.js +10 -10
  138. package/dist/utils/replace-deps.js.map +1 -1
  139. package/dist/utils/scss-compiler.d.ts.map +1 -1
  140. package/dist/utils/scss-compiler.js.map +1 -1
  141. package/dist/utils/sd-config.d.ts.map +1 -1
  142. package/dist/utils/sd-config.js +2 -3
  143. package/dist/utils/sd-config.js.map +1 -1
  144. package/dist/utils/tsc-build.d.ts +3 -1
  145. package/dist/utils/tsc-build.d.ts.map +1 -1
  146. package/dist/utils/tsc-build.js +7 -4
  147. package/dist/utils/tsc-build.js.map +1 -1
  148. package/dist/utils/tsconfig.d.ts.map +1 -1
  149. package/dist/utils/tsconfig.js.map +1 -1
  150. package/dist/utils/typecheck-non-package.d.ts.map +1 -1
  151. package/dist/utils/typecheck-non-package.js +10 -5
  152. package/dist/utils/typecheck-non-package.js.map +1 -1
  153. package/dist/utils/typecheck-serialization.d.ts.map +1 -1
  154. package/dist/utils/typecheck-serialization.js.map +1 -1
  155. package/dist/utils/vite-config.d.ts.map +1 -1
  156. package/dist/utils/vite-config.js +2 -1
  157. package/dist/utils/vite-config.js.map +1 -1
  158. package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
  159. package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
  160. package/dist/utils/worker-events.d.ts +1 -1
  161. package/dist/utils/worker-events.d.ts.map +1 -1
  162. package/dist/utils/worker-events.js +1 -0
  163. package/dist/utils/worker-events.js.map +1 -1
  164. package/dist/utils/worker-utils.d.ts +1 -1
  165. package/dist/utils/worker-utils.d.ts.map +1 -1
  166. package/dist/utils/worker-utils.js +3 -1
  167. package/dist/utils/worker-utils.js.map +1 -1
  168. package/dist/vitest-plugin.d.ts.map +1 -1
  169. package/dist/vitest-plugin.js +2 -0
  170. package/dist/vitest-plugin.js.map +1 -1
  171. package/dist/workers/client.worker.d.ts.map +1 -1
  172. package/dist/workers/client.worker.js +4 -0
  173. package/dist/workers/client.worker.js.map +1 -1
  174. package/dist/workers/library-build.worker.d.ts +2 -10
  175. package/dist/workers/library-build.worker.d.ts.map +1 -1
  176. package/dist/workers/library-build.worker.js +38 -14
  177. package/dist/workers/library-build.worker.js.map +1 -1
  178. package/dist/workers/lint.worker.d.ts.map +1 -1
  179. package/dist/workers/lint.worker.js.map +1 -1
  180. package/dist/workers/ngtsc-build.worker.d.ts.map +1 -1
  181. package/dist/workers/ngtsc-build.worker.js +40 -14
  182. package/dist/workers/ngtsc-build.worker.js.map +1 -1
  183. package/dist/workers/server-build.worker.d.ts +2 -10
  184. package/dist/workers/server-build.worker.d.ts.map +1 -1
  185. package/dist/workers/server-build.worker.js +30 -22
  186. package/dist/workers/server-build.worker.js.map +1 -1
  187. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  188. package/dist/workers/server-runtime.worker.js.map +1 -1
  189. package/package.json +4 -5
  190. package/src/angular/vite-angular-plugin.ts +18 -9
  191. package/src/capacitor/capacitor.ts +43 -44
  192. package/src/commands/check.ts +2 -2
  193. package/src/commands/publish.ts +12 -13
  194. package/src/commands/typecheck.ts +12 -12
  195. package/src/electron/electron.ts +44 -38
  196. package/src/engines/BaseEngine.ts +8 -19
  197. package/src/engines/NgtscEngine.ts +11 -11
  198. package/src/engines/ServerEsbuildEngine.ts +11 -11
  199. package/src/engines/TscEngine.ts +11 -11
  200. package/src/engines/ViteEngine.ts +3 -14
  201. package/src/engines/types.ts +3 -6
  202. package/src/infra/ResultCollector.ts +1 -1
  203. package/src/orchestrators/BuildOrchestrator.ts +31 -62
  204. package/src/orchestrators/DevWatchOrchestrator.ts +41 -44
  205. package/src/sd-cli-entry.ts +2 -12
  206. package/src/sd-cli.ts +8 -5
  207. package/src/utils/SdCliReporter.ts +177 -0
  208. package/src/utils/angular-compiler.ts +11 -4
  209. package/src/utils/build-env.ts +2 -1
  210. package/src/utils/copy-public.ts +21 -21
  211. package/src/utils/copy-src.ts +12 -12
  212. package/src/utils/diagnostic-utils.ts +3 -2
  213. package/src/utils/esbuild-config.ts +2 -0
  214. package/src/utils/lint-with-program.ts +7 -3
  215. package/src/utils/ngtsc-build-core.ts +18 -18
  216. package/src/utils/output-path-rewriter.ts +7 -7
  217. package/src/utils/output-utils.ts +1 -1
  218. package/src/utils/package-utils.ts +37 -13
  219. package/src/utils/rebuild-manager.ts +4 -2
  220. package/src/utils/replace-deps.ts +10 -10
  221. package/src/utils/sd-config.ts +2 -3
  222. package/src/utils/tsc-build.ts +9 -4
  223. package/src/utils/typecheck-non-package.ts +10 -5
  224. package/src/utils/vite-config.ts +2 -1
  225. package/src/utils/worker-events.ts +2 -1
  226. package/src/utils/worker-utils.ts +3 -1
  227. package/src/vitest-plugin.ts +5 -0
  228. package/src/workers/client.worker.ts +4 -0
  229. package/src/workers/library-build.worker.ts +48 -18
  230. package/src/workers/ngtsc-build.worker.ts +48 -13
  231. package/src/workers/server-build.worker.ts +32 -26
  232. package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +11 -7
  233. package/tests/angular/vite-angular-plugin-lint.spec.ts +6 -1
  234. package/tests/capacitor/capacitor-build.spec.ts +14 -7
  235. package/tests/capacitor/capacitor-icon.spec.ts +14 -7
  236. package/tests/capacitor/capacitor-init.spec.ts +13 -6
  237. package/tests/capacitor/capacitor-run.spec.ts +18 -11
  238. package/tests/capacitor/capacitor-workspace.spec.ts +13 -6
  239. package/tests/commands/check.spec.ts +5 -2
  240. package/tests/commands/publish.spec.ts +4 -4
  241. package/tests/commands/typecheck.spec.ts +20 -31
  242. package/tests/electron/electron.spec.ts +32 -23
  243. package/tests/engines/base-engine.spec.ts +15 -21
  244. package/tests/engines/engine-lint-integration.spec.ts +5 -10
  245. package/tests/engines/ngtsc-engine.spec.ts +27 -41
  246. package/tests/engines/server-esbuild-engine.spec.ts +18 -29
  247. package/tests/engines/tsc-engine.spec.ts +14 -23
  248. package/tests/engines/vite-engine.spec.ts +10 -15
  249. package/tests/infra/result-collector.spec.ts +2 -2
  250. package/tests/orchestrators/build-orchestrator.spec.ts +19 -29
  251. package/tests/orchestrators/dev-watch-orchestrator.spec.ts +110 -95
  252. package/tests/utils/copy-src.spec.ts +25 -19
  253. package/tests/utils/diagnostic-utils.spec.ts +72 -0
  254. package/tests/utils/ngtsc-build-core-angular-compiler.spec.ts +2 -3
  255. package/tests/utils/output-path-rewriter.spec.ts +7 -6
  256. package/tests/utils/output-utils.spec.ts +5 -5
  257. package/tests/utils/rebuild-manager.spec.ts +1 -1
  258. package/tests/utils/sd-config.spec.ts +4 -0
  259. package/tests/utils/tsc-build.spec.ts +23 -5
  260. package/tests/workers/library-build-worker.spec.ts +113 -20
  261. package/tests/workers/ngtsc-build-lint.spec.ts +3 -6
  262. package/tests/workers/ngtsc-build-worker.spec.ts +11 -13
  263. package/tests/workers/server-build-lint.spec.ts +4 -1
  264. package/tests/workers/server-build-worker.spec.ts +25 -25
  265. package/tests/angular/migration-cleanup.spec.ts +0 -59
@@ -1,6 +1,6 @@
1
1
  import path from "path";
2
2
  import ts from "typescript";
3
- import { createWorker, FsWatcher } from "@simplysm/core-node";
3
+ import { createWorker, FsWatcher, pathx } from "@simplysm/core-node";
4
4
  import { err as errNs } from "@simplysm/core-common";
5
5
  import { consola } from "consola";
6
6
  import { registerCleanupHandlers, createOnceGuard, applyDebugLevel } from "../utils/worker-utils";
@@ -22,6 +22,7 @@ import { LintWithProgramRunner, type LintWithProgramResult } from "../utils/lint
22
22
  import {
23
23
  parseTsconfig,
24
24
  getPackageSourceFiles,
25
+ getPackageFiles,
25
26
  getCompilerOptionsForEnv,
26
27
  } from "../utils/tsconfig";
27
28
  import { AngularCompiler, AngularSourceFileCache } from "../utils/angular-compiler";
@@ -50,6 +51,7 @@ let fsWatcher: FsWatcher | undefined;
50
51
  async function cleanup(): Promise<void> {
51
52
  const watcherToClose = fsWatcher;
52
53
  fsWatcher = undefined;
54
+ lastSourceFilePaths = undefined;
53
55
 
54
56
  if (watcherToClose != null) {
55
57
  await watcherToClose.close();
@@ -65,15 +67,17 @@ registerCleanupHandlers(cleanup, logger);
65
67
  async function build(info: NgtscBuildInfo): Promise<NgtscBuildResult> {
66
68
  logger.debug(`[${info.name}] ngtsc worker build 시작 (pkgDir: ${info.pkgDir})`);
67
69
  const { program, ...result } = await runNgtscBuild({ ...info, env: info.output.env });
68
- logger.debug(`[${info.name}] ngtsc worker build 완료 (dts.success: ${result.dts.success})`);
70
+ logger.debug(`[${info.name}] ngtsc worker build 완료 (build.success: ${result.build.success})`);
69
71
 
70
72
  // Run lint if enabled and program is available
71
73
  if (info.output.lint === true && program != null) {
74
+ logger.debug(`[${info.name}] lint 시작`);
72
75
  const lintRunner = new LintWithProgramRunner({
73
76
  cwd: info.cwd,
74
77
  pkgName: info.name,
75
78
  });
76
79
  result.lint = await lintRunner.lint({ program });
80
+ logger.debug(`[${info.name}] lint 완료`);
77
81
  }
78
82
 
79
83
  return result;
@@ -88,8 +92,17 @@ const guardStartWatch = createOnceGuard("startWatch");
88
92
  let watchInfo: NgtscBuildInfo | undefined;
89
93
  let currentScssDependencies: Map<string, Set<string>> | undefined;
90
94
  let watchLintRunner: LintWithProgramRunner | undefined;
95
+ let lastSourceFilePaths: Set<string> | undefined;
91
96
  const sideEffectScssRegistry = new Map<string, SideEffectScssEntry>();
92
97
 
98
+ function extractSourceFilePaths(program: ReturnType<AngularCompiler["getTsProgram"]>): Set<string> {
99
+ const paths = new Set<string>();
100
+ for (const sf of program.getSourceFiles()) {
101
+ paths.add(pathx.posix(sf.fileName));
102
+ }
103
+ return paths;
104
+ }
105
+
93
106
  /**
94
107
  * Perform a watch build (initial or incremental) using AngularCompiler.
95
108
  * Returns NgtscCombinedBuildEvent for sending to the engine.
@@ -105,8 +118,9 @@ async function performWatchBuild(
105
118
  affectedFileNames?: ReadonlySet<string>,
106
119
  hasScssChanges = true,
107
120
  ): Promise<NgtscCombinedBuildEvent> {
121
+ logger.debug(`[${info.name}] performWatchBuild 시작`);
108
122
  const pkgSrcDir = path.join(info.pkgDir, "src");
109
- const normalizedSrcDir = pkgSrcDir.replace(/\\/g, "/");
123
+ const normalizedSrcDir = pathx.posix(pkgSrcDir);
110
124
 
111
125
  // Collect diagnostics — workspace scope (no package-level filtering)
112
126
  const allDiagnostics = [...compiler.collectDiagnostics()].filter(
@@ -124,7 +138,7 @@ async function performWatchBuild(
124
138
  const loadPaths = buildScssLoadPaths(info);
125
139
  const emitResults = compiler.emitAffectedFiles({
126
140
  sourceFilter: (fileName: string) =>
127
- fileName.replace(/\\/g, "/").startsWith(normalizedSrcDir + "/"),
141
+ pathx.posix(fileName).startsWith(normalizedSrcDir + "/"),
128
142
  });
129
143
  writeEmitResults(emitResults, info.pkgDir, {
130
144
  loadPaths,
@@ -146,6 +160,7 @@ async function performWatchBuild(
146
160
  // Run lint if enabled
147
161
  let lint: LintWithProgramResult | undefined;
148
162
  if (info.output.lint === true) {
163
+ logger.debug(`[${info.name}] lint 시작`);
149
164
  if (watchLintRunner == null) {
150
165
  watchLintRunner = new LintWithProgramRunner({
151
166
  cwd: info.cwd,
@@ -156,11 +171,12 @@ async function performWatchBuild(
156
171
  program: compiler.getTsProgram(),
157
172
  affectedFiles: affectedFileNames,
158
173
  });
174
+ logger.debug(`[${info.name}] lint 완료`);
159
175
  }
160
176
 
177
+ logger.debug(`[${info.name}] performWatchBuild 완료`);
161
178
  return {
162
- js: { success: true },
163
- dts: {
179
+ build: {
164
180
  success: errorCount === 0 && scssErrors.length === 0 && globalScssErrors.length === 0,
165
181
  errors: allErrors.length > 0 ? allErrors : undefined,
166
182
  },
@@ -175,17 +191,16 @@ async function startWatch(info: NgtscBuildInfo): Promise<void> {
175
191
  try {
176
192
  // Parse tsconfig and prepare compiler options
177
193
  const parsedConfig = parseTsconfig(watchInfo.pkgDir);
178
- const sourceFiles = getPackageSourceFiles(watchInfo.pkgDir, parsedConfig);
194
+ const sourceFiles = watchInfo.output.includeTests === true
195
+ ? getPackageFiles(watchInfo.pkgDir, parsedConfig)
196
+ : getPackageSourceFiles(watchInfo.pkgDir, parsedConfig);
179
197
  const baseOptions =
180
198
  watchInfo.env != null
181
199
  ? getCompilerOptionsForEnv(parsedConfig.options, watchInfo.env, watchInfo.pkgDir)
182
200
  : parsedConfig.options;
183
201
  const compilerOptions = buildCompilerOptions(baseOptions, watchInfo.pkgDir, watchInfo.output);
184
202
 
185
- // Read angularCompilerOptions from root tsconfig
186
- const rootTsconfigPath = path.join(watchInfo.cwd, "tsconfig.json");
187
- const rootRawConfig = ts.readConfigFile(rootTsconfigPath, ts.sys.readFile);
188
- const angularOptions = rootRawConfig.config?.angularCompilerOptions ?? {};
203
+ const angularOptions = (parsedConfig.raw?.angularCompilerOptions ?? {}) as Record<string, unknown>;
189
204
 
190
205
  // SCSS closure variables
191
206
  const scssErrors: string[] = [];
@@ -204,6 +219,7 @@ async function startWatch(info: NgtscBuildInfo): Promise<void> {
204
219
  });
205
220
  // Initial build
206
221
  await compiler.initialize();
222
+ lastSourceFilePaths = extractSourceFilePaths(compiler.getTsProgram());
207
223
  const initialResult = await performWatchBuild(watchInfo, compiler, scssDependencies, scssErrors);
208
224
  sender.send("build", initialResult);
209
225
 
@@ -215,6 +231,7 @@ async function startWatch(info: NgtscBuildInfo): Promise<void> {
215
231
  );
216
232
 
217
233
  // Start FsWatcher
234
+ logger.debug(`[${watchInfo.name}] FsWatcher 시작`);
218
235
  const watchPaths = [
219
236
  path.join(watchInfo.pkgDir, "src", "**", "*.{ts,scss,css}"),
220
237
  path.join(watchInfo.pkgDir, "scss", "**", "*.{scss,css}"),
@@ -234,7 +251,9 @@ async function startWatch(info: NgtscBuildInfo): Promise<void> {
234
251
 
235
252
  fsWatcher.onChange({ delay: 300 }, async (changedFiles) => {
236
253
  try {
237
- sender.send("buildStart", {});
254
+ const hasFileAddOrRemove = changedFiles.some(
255
+ (c) => c.event === "add" || c.event === "unlink",
256
+ );
238
257
 
239
258
  // Collect modified files (all changed + SCSS dependency reverse-lookup)
240
259
  const modifiedFiles = new Set<string>();
@@ -254,6 +273,19 @@ async function startWatch(info: NgtscBuildInfo): Promise<void> {
254
273
  }
255
274
  }
256
275
 
276
+ // Dependency filter: skip rebuild if no relevant changes
277
+ if (!hasFileAddOrRemove && lastSourceFilePaths != null) {
278
+ const hasRelevantChange = [...modifiedFiles].some((p) =>
279
+ lastSourceFilePaths!.has(p),
280
+ );
281
+ if (!hasRelevantChange) {
282
+ logger.debug("변경된 파일이 빌드에 포함되지 않아 리빌드 건너뜀");
283
+ return;
284
+ }
285
+ }
286
+
287
+ sender.send("buildStart", {});
288
+
257
289
  // Clear SCSS errors for fresh rebuild
258
290
  scssErrors.length = 0;
259
291
  scssDependencies.clear();
@@ -261,10 +293,13 @@ async function startWatch(info: NgtscBuildInfo): Promise<void> {
261
293
  // Incremental rebuild via AngularCompiler.update()
262
294
  const updateResult = await compiler.update(modifiedFiles);
263
295
 
296
+ // Update source file paths after rebuild
297
+ lastSourceFilePaths = extractSourceFilePaths(compiler.getTsProgram());
298
+
264
299
  // Convert affected ts.SourceFile set to file name strings for incremental lint
265
300
  const affectedFileNames = new Set<string>();
266
301
  for (const sf of updateResult.affectedFiles) {
267
- affectedFileNames.add(sf.fileName.replace(/\\/g, "/"));
302
+ affectedFileNames.add(pathx.posix(sf.fileName));
268
303
  }
269
304
 
270
305
  const hasScssChanges = changedFiles.some(
@@ -1,8 +1,7 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- import { execaSync } from "execa";
4
3
  import esbuild from "esbuild";
5
- import { createWorker, FsWatcher, pathx } from "@simplysm/core-node";
4
+ import { cpx, createWorker, FsWatcher, pathx } from "@simplysm/core-node";
6
5
  import { err as errNs } from "@simplysm/core-common";
7
6
  import { consola } from "consola";
8
7
  import type { BuildOutput } from "../engines/types";
@@ -70,8 +69,7 @@ export interface ServerWatchInfo {
70
69
  * Server build result (aligned with LibraryBuildResult + mainJsPath)
71
70
  */
72
71
  export interface ServerBuildResult {
73
- js: { success: boolean; errors?: string[]; warnings?: string[] };
74
- dts: { success: boolean; errors?: string[]; diagnostics: SerializedDiagnostic[] };
72
+ build: { success: boolean; errors?: string[]; warnings?: string[]; diagnostics: SerializedDiagnostic[] };
75
73
  lint?: LintWithProgramResult;
76
74
  mainJsPath: string;
77
75
  }
@@ -80,8 +78,7 @@ export interface ServerBuildResult {
80
78
  * Combined build event for watch mode
81
79
  */
82
80
  export interface ServerCombinedBuildEvent {
83
- js: { success: boolean; errors?: string[]; warnings?: string[] };
84
- dts: { success: boolean; errors?: string[] };
81
+ build: { success: boolean; errors?: string[]; warnings?: string[] };
85
82
  lint?: LintWithProgramResult;
86
83
  mainJsPath: string;
87
84
  }
@@ -231,7 +228,7 @@ function generateProductionFiles(
231
228
  distPkgJson["dependencies"] = resolveLockedVersions(info.cwd, externals);
232
229
  }
233
230
  if (info.packageManager === "volta") {
234
- const nodeVersion = execaSync("node", ["-v"]).stdout.trim();
231
+ const nodeVersion = cpx.execSync("node", ["-v"]).stdout.trim();
235
232
  distPkgJson["volta"] = { node: nodeVersion };
236
233
  }
237
234
  fs.writeFileSync(path.join(distDir, "package.json"), JSON.stringify(distPkgJson, undefined, 2));
@@ -325,7 +322,7 @@ registerCleanupHandlers(cleanup, logger);
325
322
  * One-time build (production)
326
323
  */
327
324
  async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
328
- const mainJsPath = path.join(info.pkgDir, "dist", "main.js");
325
+ const mainJsPath = pathx.posixResolve(info.pkgDir, "dist", "main.js");
329
326
  logger.debug(`[${info.name}] server worker build 시작 (js: ${info.output.js}, dts: ${info.output.dts})`);
330
327
 
331
328
  try {
@@ -370,6 +367,7 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
370
367
  output: { js: false, dts: info.output.dts },
371
368
  parsedConfig,
372
369
  env: info.output.env,
370
+ includeTests: info.output.includeTests,
373
371
  });
374
372
 
375
373
  const jsResult = esbuildPromise
@@ -379,11 +377,13 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
379
377
  // Run lint if enabled and program is available
380
378
  let lint: LintWithProgramResult | undefined;
381
379
  if (info.output.lint === true && tscResult.program != null) {
380
+ logger.debug(`[${info.name}] lint 시작`);
382
381
  const lintRunner = new LintWithProgramRunner({
383
382
  cwd: info.cwd,
384
383
  pkgName: info.name,
385
384
  });
386
385
  lint = await lintRunner.lint({ program: tscResult.program });
386
+ logger.debug(`[${info.name}] lint 완료`);
387
387
  }
388
388
 
389
389
  // Generate production artifacts only when JS output is requested
@@ -396,16 +396,13 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
396
396
  generateProductionFiles(info, external);
397
397
  }
398
398
 
399
- logger.debug(`[${info.name}] server worker build 완료 (js: ${jsResult.success}, dts: ${tscResult.success})`);
399
+ const allErrors = [...(jsResult.errors ?? []), ...(tscResult.errors ?? [])];
400
+ logger.debug(`[${info.name}] server worker build 완료 (js: ${jsResult.success}, tsc: ${tscResult.success})`);
400
401
  return {
401
- js: {
402
- success: jsResult.success,
403
- errors: jsResult.errors,
402
+ build: {
403
+ success: jsResult.success && tscResult.success,
404
+ errors: allErrors.length > 0 ? allErrors : undefined,
404
405
  warnings: jsResult.warnings,
405
- },
406
- dts: {
407
- success: tscResult.success,
408
- errors: tscResult.errors,
409
406
  diagnostics: tscResult.diagnostics,
410
407
  },
411
408
  lint,
@@ -419,8 +416,7 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
419
416
  logger.debug(`[${info.name}] 스택 트레이스:\n${stack}`);
420
417
  }
421
418
  return {
422
- js: { success: false, errors: [message] },
423
- dts: { success: false, errors: [message], diagnostics: [] },
419
+ build: { success: false, errors: [message], diagnostics: [] },
424
420
  mainJsPath,
425
421
  };
426
422
  }
@@ -437,7 +433,8 @@ let watchLintRunner: LintWithProgramRunner | undefined;
437
433
  */
438
434
  async function rebuildAll(): Promise<ServerCombinedBuildEvent> {
439
435
  const info = watchInfo!;
440
- const mainJsPath = path.join(info.pkgDir, "dist", "main.js");
436
+ logger.debug(`[${info.name}] rebuildAll 시작`);
437
+ const mainJsPath = pathx.posixResolve(info.pkgDir, "dist", "main.js");
441
438
  const parsedConfig = parseTsconfig(info.pkgDir);
442
439
 
443
440
  // esbuild rebuild (async)
@@ -469,11 +466,13 @@ async function rebuildAll(): Promise<ServerCombinedBuildEvent> {
469
466
  output: { js: false, dts: info.output.dts },
470
467
  parsedConfig,
471
468
  env: info.output.env,
469
+ includeTests: info.output.includeTests,
472
470
  });
473
471
 
474
472
  // Run lint if enabled and program is available
475
473
  let lint: LintWithProgramResult | undefined;
476
474
  if (info.output.lint === true && tscResult.program != null) {
475
+ logger.debug(`[${info.name}] lint 시작`);
477
476
  if (watchLintRunner == null) {
478
477
  watchLintRunner = new LintWithProgramRunner({
479
478
  cwd: info.cwd,
@@ -484,15 +483,21 @@ async function rebuildAll(): Promise<ServerCombinedBuildEvent> {
484
483
  program: tscResult.program,
485
484
  affectedFiles: tscResult.affectedFiles,
486
485
  });
486
+ logger.debug(`[${info.name}] lint 완료`);
487
487
  }
488
488
 
489
489
  const jsResult = esbuildPromise
490
490
  ? await esbuildPromise
491
491
  : { success: true, errors: undefined, warnings: undefined };
492
492
 
493
+ const allErrors = [...(jsResult.errors ?? []), ...(tscResult.errors ?? [])];
494
+ logger.debug(`[${info.name}] rebuildAll 완료`);
493
495
  return {
494
- js: { success: jsResult.success, errors: jsResult.errors, warnings: jsResult.warnings },
495
- dts: { success: tscResult.success, errors: tscResult.errors },
496
+ build: {
497
+ success: jsResult.success && tscResult.success,
498
+ errors: allErrors.length > 0 ? allErrors : undefined,
499
+ warnings: jsResult.warnings,
500
+ },
496
501
  lint,
497
502
  mainJsPath,
498
503
  };
@@ -542,6 +547,7 @@ async function startWatch(info: ServerWatchInfo): Promise<void> {
542
547
  }
543
548
 
544
549
  // Initial build: esbuild + tsc parallel
550
+ sender.send("buildStart", {});
545
551
  const initialResult = await rebuildAll();
546
552
 
547
553
  // Write .config.json on first build
@@ -561,17 +567,17 @@ async function startWatch(info: ServerWatchInfo): Promise<void> {
561
567
  // Server package itself + workspace dependency packages source
562
568
  const watchDirs = [
563
569
  info.pkgDir,
564
- ...workspaceDeps.map((d) => path.join(info.cwd, "packages", d)),
570
+ ...workspaceDeps.map((d) => pathx.posixResolve(info.cwd, "packages", d)),
565
571
  ];
566
572
  for (const dir of watchDirs) {
567
- watchPaths.push(path.join(dir, "src", "**", "*"));
573
+ watchPaths.push(pathx.posixResolve(dir, "src", "**", "*"));
568
574
  }
569
575
 
570
576
  // ReplaceDeps dependency packages dist
571
577
  for (const pkg of replaceDeps) {
572
- watchPaths.push(path.join(info.cwd, "node_modules", ...pkg.split("/"), "dist", "**", "*.{js,mjs,cjs}"));
578
+ watchPaths.push(pathx.posixResolve(info.cwd, "node_modules", ...pkg.split("/"), "dist", "**", "*.{js,mjs,cjs}"));
573
579
  watchPaths.push(
574
- path.join(info.pkgDir, "node_modules", ...pkg.split("/"), "dist", "**", "*.{js,mjs,cjs}"),
580
+ pathx.posixResolve(info.pkgDir, "node_modules", ...pkg.split("/"), "dist", "**", "*.{js,mjs,cjs}"),
575
581
  );
576
582
  }
577
583
 
@@ -628,7 +634,7 @@ async function startWatch(info: ServerWatchInfo): Promise<void> {
628
634
 
629
635
  // Filter by metafile inputs
630
636
  const metafileAbsPaths = new Set(
631
- Object.keys(lastMetafile.inputs).map((key) => pathx.norm(info.cwd, key)),
637
+ Object.keys(lastMetafile.inputs).map((key) => pathx.posixResolve(info.cwd, key)),
632
638
  );
633
639
 
634
640
  const hasRelevantChange = changes.some((c) => metafileAbsPaths.has(c.path));
@@ -138,8 +138,8 @@ describe("sdAngularPlugin CSS HMR compatibility", () => {
138
138
  await (plugin as any).buildEnd?.call({});
139
139
  });
140
140
 
141
- // Unit: .scss 파일은 위임하지 않고 Angular가 처리한다 (대조군)
142
- it("processes .scss files (does NOT delegate to Vite default)", async () => {
141
+ // Unit: .scss 파일이 TS 프로그램에 없으면 리빌드를 건너뛴다
142
+ it("skips .scss files not in the TypeScript program", async () => {
143
143
  const onBuildStart = vi.fn();
144
144
  const onBuild = vi.fn();
145
145
  const plugin = sdAngularPlugin({
@@ -151,6 +151,10 @@ describe("sdAngularPlugin CSS HMR compatibility", () => {
151
151
 
152
152
  await (plugin as any).buildStart?.call({});
153
153
 
154
+ // buildStart 완료 후 초기 빌드 결과 콜백 리셋
155
+ onBuildStart.mockClear();
156
+ onBuild.mockClear();
157
+
154
158
  const scssFilePath = path
155
159
  .join(FIXTURE_DIR, "src/styles.scss")
156
160
  .replace(/\\/g, "/");
@@ -163,12 +167,12 @@ describe("sdAngularPlugin CSS HMR compatibility", () => {
163
167
  read: () => Promise.resolve(""),
164
168
  });
165
169
 
166
- // .scss Angular가 처리하므로 undefined 아닌 배열 반환
167
- expect(Array.isArray(result)).toBe(true);
170
+ // .scss 파일이 TS 프로그램에 없으므로 undefined 반환 (리빌드 건너뜀)
171
+ expect(result).toBeUndefined();
168
172
 
169
- // Angular compiler update가 호출되어야 한다
170
- expect(onBuildStart).toHaveBeenCalled();
171
- expect(onBuild).toHaveBeenCalled();
173
+ // Angular compiler update가 호출되지 않아야 한다
174
+ expect(onBuildStart).not.toHaveBeenCalled();
175
+ expect(onBuild).not.toHaveBeenCalled();
172
176
 
173
177
  await (plugin as any).buildEnd?.call({});
174
178
  });
@@ -19,7 +19,12 @@ vi.mock("../../src/utils/lint-with-program", () => ({
19
19
  LintWithProgramRunner: MockLintWithProgramRunner,
20
20
  }));
21
21
 
22
- const mockTsProgram = { getSourceFiles: () => [] };
22
+ const mockTsProgram = {
23
+ getSourceFiles: () => [
24
+ { fileName: "/workspace/packages/client/src/main.ts" },
25
+ { fileName: "/workspace/packages/client/src/app.ts" },
26
+ ],
27
+ };
23
28
 
24
29
  const mockCompiler = {
25
30
  initialize: vi.fn().mockResolvedValue({ affectedFiles: new Set() }),
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
3
 
3
4
  //#region Mocks
@@ -25,6 +26,14 @@ vi.mock("@simplysm/core-node", () => ({
25
26
  glob: mockFsxGlob,
26
27
  copy: mockFsxCopy,
27
28
  },
29
+ cpx: {
30
+ exec: mockCpxExec,
31
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
32
+ },
33
+ pathx: {
34
+ posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
35
+ posix: (p: string) => p.replace(/\\/g, "/"),
36
+ },
28
37
  }));
29
38
 
30
39
  // env mock
@@ -35,14 +44,12 @@ vi.mock("@simplysm/core-common", () => ({
35
44
  }),
36
45
  }));
37
46
 
38
- // execa mock
47
+ // cpx mock (was execa)
39
48
  const execaCalls: { command: string; args: string[] }[] = [];
40
- vi.mock("execa", () => ({
41
- execa: vi.fn((...args: unknown[]) => {
42
- execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
43
- return Promise.resolve({ stdout: "", stderr: "" });
44
- }),
45
- }));
49
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
50
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
51
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
52
+ });
46
53
 
47
54
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
48
55
  vi.mock("node:fs", () => ({
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
3
 
3
4
  //#region Mocks
@@ -23,6 +24,14 @@ vi.mock("@simplysm/core-node", () => ({
23
24
  rm: mockFsxRm,
24
25
  glob: mockFsxGlob,
25
26
  },
27
+ cpx: {
28
+ exec: mockCpxExec,
29
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
30
+ },
31
+ pathx: {
32
+ posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
33
+ posix: (p: string) => p.replace(/\\/g, "/"),
34
+ },
26
35
  }));
27
36
 
28
37
  // env mock
@@ -33,14 +42,12 @@ vi.mock("@simplysm/core-common", () => ({
33
42
  }),
34
43
  }));
35
44
 
36
- // execa mock
45
+ // cpx mock (was execa)
37
46
  const execaCalls: { command: string; args: string[] }[] = [];
38
- vi.mock("execa", () => ({
39
- execa: vi.fn((...args: unknown[]) => {
40
- execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
41
- return Promise.resolve({ stdout: "", stderr: "" });
42
- }),
43
- }));
47
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
48
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
49
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
50
+ });
44
51
 
45
52
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
46
53
  vi.mock("node:fs", () => ({
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
3
 
3
4
  //#region Mocks
@@ -24,6 +25,14 @@ vi.mock("@simplysm/core-node", () => ({
24
25
  glob: mockFsxGlob,
25
26
  copy: mockFsxCopy,
26
27
  },
28
+ cpx: {
29
+ exec: mockCpxExec,
30
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
31
+ },
32
+ pathx: {
33
+ posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
34
+ posix: (p: string) => p.replace(/\\/g, "/"),
35
+ },
27
36
  }));
28
37
 
29
38
  let mockEnv: Record<string, unknown> = {};
@@ -34,12 +43,10 @@ vi.mock("@simplysm/core-common", () => ({
34
43
  }));
35
44
 
36
45
  const execaCalls: { command: string; args: string[] }[] = [];
37
- vi.mock("execa", () => ({
38
- execa: vi.fn((...args: unknown[]) => {
39
- execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
40
- return Promise.resolve({ stdout: "", stderr: "" });
41
- }),
42
- }));
46
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
47
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
48
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
49
+ });
43
50
 
44
51
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
45
52
  vi.mock("node:fs", () => ({
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
3
 
3
4
  //#region Mocks
@@ -25,6 +26,14 @@ vi.mock("@simplysm/core-node", () => ({
25
26
  glob: mockFsxGlob,
26
27
  copy: mockFsxCopy,
27
28
  },
29
+ cpx: {
30
+ exec: mockCpxExec,
31
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
32
+ },
33
+ pathx: {
34
+ posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
35
+ posix: (p: string) => p.replace(/\\/g, "/"),
36
+ },
28
37
  }));
29
38
 
30
39
  // env mock
@@ -35,17 +44,15 @@ vi.mock("@simplysm/core-common", () => ({
35
44
  }),
36
45
  }));
37
46
 
38
- // execa mock — tracks commands and resolves immediately
47
+ // cpx mock (was execa) — tracks commands and resolves immediately
39
48
  const execaCalls: { command: string; args: string[] }[] = [];
40
- let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string }> = () =>
41
- Promise.resolve({ stdout: "", stderr: "" });
49
+ let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string; exitCode: number }> = () =>
50
+ Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
42
51
 
43
- vi.mock("execa", () => ({
44
- execa: vi.fn((...args: unknown[]) => {
45
- execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
46
- return execaFactory(...args);
47
- }),
48
- }));
52
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
53
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
54
+ return execaFactory(...args);
55
+ });
49
56
 
50
57
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
51
58
  vi.mock("node:fs", () => ({
@@ -135,7 +142,7 @@ export default config;`;
135
142
  mockEnv = { ANDROID_HOME: "C:/Android/Sdk" };
136
143
 
137
144
  execaCalls.length = 0;
138
- execaFactory = () => Promise.resolve({ stdout: "", stderr: "" });
145
+ execaFactory = () => Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
139
146
  mockFsWriteFile.mockReset();
140
147
  mockFsWriteFile.mockResolvedValue(undefined);
141
148
  }
@@ -195,7 +202,7 @@ describe("Capacitor.run()", () => {
195
202
  return Promise.reject(new Error("cap run failed"));
196
203
  }
197
204
  }
198
- return Promise.resolve({ stdout: "", stderr: "" });
205
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
199
206
  };
200
207
 
201
208
  const cap = await Capacitor.create(PKG_PATH, {
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
3
 
3
4
  //#region Mocks
@@ -24,6 +25,14 @@ vi.mock("@simplysm/core-node", () => ({
24
25
  glob: mockFsxGlob,
25
26
  copy: mockFsxCopy,
26
27
  },
28
+ cpx: {
29
+ exec: mockCpxExec,
30
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
31
+ },
32
+ pathx: {
33
+ posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
34
+ posix: (p: string) => p.replace(/\\/g, "/"),
35
+ },
27
36
  }));
28
37
 
29
38
  let mockEnv: Record<string, unknown> = {};
@@ -34,12 +43,10 @@ vi.mock("@simplysm/core-common", () => ({
34
43
  }));
35
44
 
36
45
  const execaCalls: { command: string; args: string[] }[] = [];
37
- vi.mock("execa", () => ({
38
- execa: vi.fn((...args: unknown[]) => {
39
- execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
40
- return Promise.resolve({ stdout: "", stderr: "" });
41
- }),
42
- }));
46
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
47
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
48
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
49
+ });
43
50
 
44
51
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
45
52
  vi.mock("node:fs", () => ({
@@ -35,8 +35,11 @@ vi.mock("../../src/utils/sd-config", () => ({
35
35
  loadSdConfig: mocks.loadSdConfig,
36
36
  }));
37
37
 
38
- vi.mock("execa", () => ({
39
- execa: mocks.execa,
38
+ vi.mock("@simplysm/core-node", () => ({
39
+ cpx: {
40
+ exec: mocks.execa,
41
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
42
+ },
40
43
  }));
41
44
 
42
45
  vi.mock("../../src/utils/package-utils", async (importOriginal) => {