@simplysm/sd-cli 14.1.8 → 14.1.10

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/capacitor/capacitor-icon.js +2 -2
  2. package/dist/capacitor/capacitor-icon.js.map +1 -1
  3. package/dist/capacitor/capacitor-npm-config.d.ts +1 -1
  4. package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
  5. package/dist/capacitor/capacitor-npm-config.js +11 -18
  6. package/dist/capacitor/capacitor-npm-config.js.map +1 -1
  7. package/dist/capacitor/capacitor.d.ts +1 -1
  8. package/dist/capacitor/capacitor.js +2 -2
  9. package/dist/capacitor/capacitor.js.map +1 -1
  10. package/dist/commands/check.d.ts.map +1 -1
  11. package/dist/commands/check.js +1 -0
  12. package/dist/commands/check.js.map +1 -1
  13. package/dist/commands/device.js +2 -2
  14. package/dist/commands/device.js.map +1 -1
  15. package/dist/commands/init/generators/client.d.ts.map +1 -1
  16. package/dist/commands/init/generators/client.js +1 -0
  17. package/dist/commands/init/generators/client.js.map +1 -1
  18. package/dist/commands/init/generators/root.d.ts.map +1 -1
  19. package/dist/commands/init/generators/root.js +0 -1
  20. package/dist/commands/init/generators/root.js.map +1 -1
  21. package/dist/commands/init/init-client.js +1 -1
  22. package/dist/commands/init/init-client.js.map +1 -1
  23. package/dist/commands/init/init.js +2 -2
  24. package/dist/commands/init/init.js.map +1 -1
  25. package/dist/commands/publish/deployment-phase.d.ts.map +1 -1
  26. package/dist/commands/publish/deployment-phase.js +1 -0
  27. package/dist/commands/publish/deployment-phase.js.map +1 -1
  28. package/dist/commands/publish/npm-publisher.js +3 -3
  29. package/dist/commands/publish/npm-publisher.js.map +1 -1
  30. package/dist/commands/publish/post-publish-phase.d.ts.map +1 -1
  31. package/dist/commands/publish/post-publish-phase.js +1 -0
  32. package/dist/commands/publish/post-publish-phase.js.map +1 -1
  33. package/dist/commands/publish/publish-command.d.ts.map +1 -1
  34. package/dist/commands/publish/publish-command.js +7 -12
  35. package/dist/commands/publish/publish-command.js.map +1 -1
  36. package/dist/deps/replace-deps/collect-deps.js +4 -4
  37. package/dist/deps/replace-deps/collect-deps.js.map +1 -1
  38. package/dist/deps/replace-deps/replace-deps-resolve.d.ts +4 -12
  39. package/dist/deps/replace-deps/replace-deps-resolve.d.ts.map +1 -1
  40. package/dist/deps/replace-deps/replace-deps-resolve.js +13 -49
  41. package/dist/deps/replace-deps/replace-deps-resolve.js.map +1 -1
  42. package/dist/deps/replace-deps/replace-deps.d.ts +2 -2
  43. package/dist/deps/replace-deps/replace-deps.js +3 -3
  44. package/dist/deps/server-externals/server-production-files.d.ts +3 -3
  45. package/dist/deps/server-externals/server-production-files.d.ts.map +1 -1
  46. package/dist/deps/server-externals/server-production-files.js +24 -17
  47. package/dist/deps/server-externals/server-production-files.js.map +1 -1
  48. package/dist/electron/electron.d.ts.map +1 -1
  49. package/dist/electron/electron.js +6 -11
  50. package/dist/electron/electron.js.map +1 -1
  51. package/dist/engines/BaseEngine.d.ts +1 -0
  52. package/dist/engines/BaseEngine.d.ts.map +1 -1
  53. package/dist/engines/BaseEngine.js +2 -1
  54. package/dist/engines/BaseEngine.js.map +1 -1
  55. package/dist/esbuild/esbuild-config.d.ts +6 -2
  56. package/dist/esbuild/esbuild-config.d.ts.map +1 -1
  57. package/dist/esbuild/esbuild-config.js +4 -3
  58. package/dist/esbuild/esbuild-config.js.map +1 -1
  59. package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -1
  60. package/dist/esbuild/esbuild-tsc-plugin.js +3 -1
  61. package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -1
  62. package/dist/orchestrators/BaseOrchestrator.d.ts.map +1 -1
  63. package/dist/orchestrators/BaseOrchestrator.js +1 -0
  64. package/dist/orchestrators/BaseOrchestrator.js.map +1 -1
  65. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  66. package/dist/orchestrators/BuildOrchestrator.js +3 -5
  67. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  68. package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
  69. package/dist/orchestrators/DevOrchestrator.js +1 -0
  70. package/dist/orchestrators/DevOrchestrator.js.map +1 -1
  71. package/dist/orchestrators/ServerRuntimeManager.d.ts.map +1 -1
  72. package/dist/orchestrators/ServerRuntimeManager.js +4 -0
  73. package/dist/orchestrators/ServerRuntimeManager.js.map +1 -1
  74. package/dist/orchestrators/TypecheckOrchestrator.d.ts.map +1 -1
  75. package/dist/orchestrators/TypecheckOrchestrator.js +4 -6
  76. package/dist/orchestrators/TypecheckOrchestrator.js.map +1 -1
  77. package/dist/runtime/engine-watch-events.d.ts.map +1 -1
  78. package/dist/runtime/engine-watch-events.js +5 -0
  79. package/dist/runtime/engine-watch-events.js.map +1 -1
  80. package/dist/runtime/worker-events.d.ts +1 -0
  81. package/dist/runtime/worker-events.d.ts.map +1 -1
  82. package/dist/sd-cli-entry.d.ts.map +1 -1
  83. package/dist/sd-cli-entry.js +0 -4
  84. package/dist/sd-cli-entry.js.map +1 -1
  85. package/dist/sd-cli.js +2 -0
  86. package/dist/sd-cli.js.map +1 -1
  87. package/dist/typecheck/typecheck-non-package.d.ts.map +1 -1
  88. package/dist/typecheck/typecheck-non-package.js +10 -0
  89. package/dist/typecheck/typecheck-non-package.js.map +1 -1
  90. package/dist/utils/package-utils.d.ts +8 -6
  91. package/dist/utils/package-utils.d.ts.map +1 -1
  92. package/dist/utils/package-utils.js +26 -24
  93. package/dist/utils/package-utils.js.map +1 -1
  94. package/dist/utils/workspace-utils.d.ts +17 -0
  95. package/dist/utils/workspace-utils.d.ts.map +1 -0
  96. package/dist/utils/workspace-utils.js +95 -0
  97. package/dist/utils/workspace-utils.js.map +1 -0
  98. package/dist/workers/client.worker.d.ts +1 -0
  99. package/dist/workers/client.worker.d.ts.map +1 -1
  100. package/dist/workers/client.worker.js +8 -3
  101. package/dist/workers/client.worker.js.map +1 -1
  102. package/dist/workers/library-build.worker.d.ts +1 -0
  103. package/dist/workers/library-build.worker.d.ts.map +1 -1
  104. package/dist/workers/library-build.worker.js +3 -2
  105. package/dist/workers/library-build.worker.js.map +1 -1
  106. package/dist/workers/server-build.worker.d.ts +1 -0
  107. package/dist/workers/server-build.worker.d.ts.map +1 -1
  108. package/dist/workers/server-build.worker.js +12 -12
  109. package/dist/workers/server-build.worker.js.map +1 -1
  110. package/dist/workers/server-esbuild-context.d.ts.map +1 -1
  111. package/dist/workers/server-esbuild-context.js +4 -2
  112. package/dist/workers/server-esbuild-context.js.map +1 -1
  113. package/dist/workers/server-runtime.worker.d.ts +1 -0
  114. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  115. package/dist/workers/server-runtime.worker.js +9 -3
  116. package/dist/workers/server-runtime.worker.js.map +1 -1
  117. package/dist/workers/server-watch-manager.d.ts +1 -1
  118. package/dist/workers/server-watch-manager.d.ts.map +1 -1
  119. package/dist/workers/server-watch-manager.js +2 -2
  120. package/dist/workers/server-watch-manager.js.map +1 -1
  121. package/package.json +11 -11
  122. package/src/capacitor/capacitor-icon.ts +2 -2
  123. package/src/capacitor/capacitor-npm-config.ts +10 -19
  124. package/src/capacitor/capacitor.ts +2 -2
  125. package/src/commands/check.ts +1 -0
  126. package/src/commands/device.ts +2 -2
  127. package/src/commands/init/generators/client.ts +1 -0
  128. package/src/commands/init/generators/root.ts +0 -1
  129. package/src/commands/init/init-client.ts +1 -1
  130. package/src/commands/init/init.ts +2 -2
  131. package/src/commands/init/templates/client/src/sd-env.d.ts +1 -0
  132. package/src/commands/init/templates/workspace-root/mise.toml.hbs +1 -1
  133. package/src/commands/publish/deployment-phase.ts +1 -0
  134. package/src/commands/publish/npm-publisher.ts +3 -3
  135. package/src/commands/publish/post-publish-phase.ts +1 -0
  136. package/src/commands/publish/publish-command.ts +7 -15
  137. package/src/deps/replace-deps/collect-deps.ts +4 -4
  138. package/src/deps/replace-deps/replace-deps-resolve.ts +13 -56
  139. package/src/deps/replace-deps/replace-deps.ts +3 -3
  140. package/src/deps/server-externals/server-production-files.ts +31 -18
  141. package/src/electron/electron.ts +7 -13
  142. package/src/engines/BaseEngine.ts +3 -2
  143. package/src/esbuild/esbuild-config.ts +12 -3
  144. package/src/esbuild/esbuild-tsc-plugin.ts +4 -1
  145. package/src/orchestrators/BaseOrchestrator.ts +1 -0
  146. package/src/orchestrators/BuildOrchestrator.ts +3 -5
  147. package/src/orchestrators/DevOrchestrator.ts +1 -0
  148. package/src/orchestrators/ServerRuntimeManager.ts +4 -0
  149. package/src/orchestrators/TypecheckOrchestrator.ts +4 -6
  150. package/src/runtime/engine-watch-events.ts +7 -1
  151. package/src/runtime/worker-events.ts +1 -0
  152. package/src/sd-cli-entry.ts +0 -9
  153. package/src/sd-cli.ts +2 -0
  154. package/src/typecheck/typecheck-non-package.ts +11 -0
  155. package/src/utils/package-utils.ts +30 -23
  156. package/src/utils/workspace-utils.ts +117 -0
  157. package/src/workers/client.worker.ts +9 -4
  158. package/src/workers/library-build.worker.ts +4 -3
  159. package/src/workers/server-build.worker.ts +13 -13
  160. package/src/workers/server-esbuild-context.ts +5 -2
  161. package/src/workers/server-runtime.worker.ts +10 -3
  162. package/src/workers/server-watch-manager.ts +3 -3
  163. package/tests/capacitor/capacitor-build.spec.ts +142 -142
  164. package/tests/capacitor/capacitor-init.spec.ts +181 -181
  165. package/tests/capacitor/capacitor-npm-config.acc.spec.ts +114 -114
  166. package/tests/capacitor/capacitor-npm-config.spec.ts +94 -94
  167. package/tests/commands/publish-manifest.acc.spec.ts +67 -0
  168. package/tests/deps/replace-deps/collect-deps.acc.spec.ts +16 -1
  169. package/tests/deps/replace-deps/replace-deps-resolve.acc.spec.ts +9 -5
  170. package/tests/deps/replace-deps/replace-deps-setup.acc.spec.ts +3 -3
  171. package/tests/deps/server-externals/server-production-files.spec.ts +68 -0
  172. package/tests/electron/electron.spec.ts +608 -608
  173. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-browser.tsbuildinfo +1 -1
  174. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-node.tsbuildinfo +1 -1
  175. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck.tsbuildinfo +1 -1
  176. package/tests/utils/engine-watch-events.spec.ts +17 -0
  177. package/tests/utils/esbuild-config.spec.ts +15 -0
  178. package/tests/utils/package-utils.spec.ts +36 -4
  179. package/tests/utils/replace-deps-watch.acc.spec.ts +4 -4
  180. package/tests/utils/replace-deps-watch.spec.ts +3 -3
  181. package/tests/utils/replace-deps.spec.ts +1 -35
  182. package/tests/utils/workspace-utils.spec.ts +87 -0
  183. package/tests/workers/library-build-worker.spec.ts +1 -1
  184. package/tests/workers/server-esbuild-context.spec.ts +4 -3
  185. package/dist/commands/reinstall.d.ts +0 -13
  186. package/dist/commands/reinstall.d.ts.map +0 -1
  187. package/dist/commands/reinstall.js +0 -56
  188. package/dist/commands/reinstall.js.map +0 -1
  189. package/src/commands/init/templates/workspace-root/pnpm-workspace.yaml +0 -5
  190. package/src/commands/reinstall.ts +0 -63
  191. package/tests/angular/angular-compiler-hmr-removal.verify.md +0 -16
  192. package/tests/angular/onbuild-lint-removal.verify.md +0 -8
  193. package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +0 -13
  194. package/tests/angular/vite-angular-plugin-vitest.verify.md +0 -20
  195. package/tests/capacitor/capacitor-android-exports.verify.md +0 -11
  196. package/tests/commands/publish-npm-local-split.verify.md +0 -9
  197. package/tests/commands/publish-responsibility-split.verify.md +0 -13
  198. package/tests/commands/publish-set.verify.md +0 -7
  199. package/tests/commands/publish-storage-split.verify.md +0 -8
  200. package/tests/commands/slice3-severity-cleanup.verify.md +0 -12
  201. package/tests/deps/deps-directory-separation.verify.md +0 -15
  202. package/tests/deps/replace-deps/replace-deps-perf.verify.md +0 -15
  203. package/tests/deps/server-externals/mise-toml-parse-intent.verify.md +0 -16
  204. package/tests/electron/electron-symlink-cleanup.verify.md +0 -8
  205. package/tests/engines/engine-duplicate-output-removal.verify.md +0 -10
  206. package/tests/engines/engine-typecheck-selection.verify.md +0 -8
  207. package/tests/engines/esbuild-client-engine.verify.md +0 -15
  208. package/tests/engines/normalize-result.verify.md +0 -9
  209. package/tests/engines/vite-dependency-cleanup.verify.md +0 -24
  210. package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +0 -23
  211. package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +0 -21
  212. package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +0 -16
  213. package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +0 -15
  214. package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +0 -31
  215. package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +0 -59
  216. package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +0 -21
  217. package/tests/esbuild/esbuild-postcss-plugin-chunking.verify.md +0 -17
  218. package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +0 -13
  219. package/tests/esbuild/esbuild-worker-plugin-node.verify.md +0 -12
  220. package/tests/esbuild/esbuild-worker-plugin.verify.md +0 -7
  221. package/tests/orchestrators/dist-delete-watcher.verify.md +0 -10
  222. package/tests/orchestrators/orchestrator-baseenv.verify.md +0 -10
  223. package/tests/orchestrators/orchestrator-diagnostic-formatting.verify.md +0 -10
  224. package/tests/orchestrators/orchestrator-initializemode-signature.verify.md +0 -9
  225. package/tests/orchestrators/slice1-stdout-to-consola.verify.md +0 -10
  226. package/tests/sd-cli-catch-all.verify.md +0 -7
  227. package/tests/sd-cli-log-tag.verify.md +0 -11
  228. package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +0 -8
  229. package/tests/ts-compiler/SdTsCompiler-crash-handling.verify.md +0 -24
  230. package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +0 -12
  231. package/tests/ts-compiler/SdTsCompiler-emit.verify.md +0 -9
  232. package/tests/ts-compiler/SdTsCompiler.verify.md +0 -41
  233. package/tests/ts-compiler/scss-lint-integration.verify.md +0 -14
  234. package/tests/utils/copy-public-outdir.verify.md +0 -8
  235. package/tests/utils/dev-http-server.verify.md +0 -8
  236. package/tests/utils/engine-watch-events.verify.md +0 -17
  237. package/tests/utils/esbuild-client-config-integration.verify.md +0 -9
  238. package/tests/utils/esbuild-client-config-postcss.verify.md +0 -6
  239. package/tests/utils/esbuild-client-config.verify.md +0 -26
  240. package/tests/utils/esbuild-index-html.verify.md +0 -10
  241. package/tests/utils/esbuild-pwa.verify.md +0 -9
  242. package/tests/utils/esbuild-scss-plugin.verify.md +0 -8
  243. package/tests/utils/hmr-service.verify.md +0 -17
  244. package/tests/utils/lint-core-import-paths.verify.md +0 -10
  245. package/tests/utils/replace-deps-split.verify.md +0 -15
  246. package/tests/utils/replace-deps-watch.verify.md +0 -9
  247. package/tests/utils/server-production-files-import-paths.verify.md +0 -14
  248. package/tests/utils/vite-config-cleanup.verify.md +0 -7
  249. package/tests/workers/build-watch-paths-library.verify.md +0 -10
  250. package/tests/workers/build-watch-paths-ngtsc-server.verify.md +0 -12
  251. package/tests/workers/client-worker-browser-support.verify.md +0 -7
  252. package/tests/workers/client-worker-cleanup.verify.md +0 -8
  253. package/tests/workers/client-worker-initial-build-error.verify.md +0 -7
  254. package/tests/workers/client-worker-initial-build-warnings.verify.md +0 -7
  255. package/tests/workers/client-worker-mtime-incremental.verify.md +0 -10
  256. package/tests/workers/client-worker-onend-sync.verify.md +0 -7
  257. package/tests/workers/client-worker-refactor.verify.md +0 -22
  258. package/tests/workers/client-worker-ts-cache-invalidation.verify.md +0 -12
  259. package/tests/workers/dev-port-file.verify.md +0 -6
  260. package/tests/workers/ngtsc-build-rootnames-refresh.verify.md +0 -8
  261. package/tests/workers/server-build-context-dispose.verify.md +0 -8
  262. package/tests/workers/server-build-worker-plugin.verify.md +0 -9
  263. package/tests/workers/server-build-worker-refactoring.verify.md +0 -14
  264. package/tests/workers/server-esbuild-context-integration.verify.md +0 -10
  265. package/tests/workers/server-esbuild-context-tsc.verify.md +0 -7
@@ -1,114 +1,114 @@
1
- import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
2
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import path from "node:path";
5
- import { fsx, cpx } from "@simplysm/core-node";
6
-
7
- const mockFsxExists = vi.spyOn(fsx, "exists");
8
- vi.spyOn(fsx, "read");
9
- vi.spyOn(fsx, "write").mockResolvedValue(undefined);
10
- const mockFsxReadJson = vi.spyOn(fsx, "readJson");
11
- vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
12
- vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
13
-
14
- const execaCalls: { command: string; args: string[]; options: unknown }[] = [];
15
- vi.spyOn(cpx, "spawn").mockImplementation(((cmd: string, args: string[], options: unknown) => {
16
- execaCalls.push({
17
- command: cmd,
18
- args,
19
- options,
20
- });
21
- return { stdout: "", stderr: "", exitCode: 0 };
22
- }) as never);
23
-
24
- //#endregion
25
-
26
- let tmpRoot: string;
27
- let CAP_PATH: string;
28
- let PKG_PATH: string;
29
-
30
- beforeAll(() => {
31
- tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-npm-config-acc-"));
32
- writeFileSync(path.join(tmpRoot, "pnpm-workspace.yaml"), "");
33
- PKG_PATH = path.join(tmpRoot, "pkg");
34
- CAP_PATH = path.join(PKG_PATH, ".capacitor");
35
- });
36
-
37
- afterAll(() => {
38
- rmSync(tmpRoot, { recursive: true, force: true });
39
- });
40
-
41
- function setupDefaultMocks() {
42
- mockFsxExists.mockImplementation(((p: string) => {
43
- const n = p.replace(/\\/g, "/");
44
- if (n.includes(".capacitor.lock")) return false;
45
- return true;
46
- }) as never);
47
-
48
- mockFsxReadJson.mockImplementation(((p: string) => {
49
- const normalized = p.replace(/\\/g, "/");
50
- if (normalized.includes(".capacitor/package.json")) {
51
- return {
52
- name: "com.test.app",
53
- version: "1.0.0",
54
- dependencies: {
55
- "@capacitor/core": "^7",
56
- "@capacitor/app": "^7",
57
- "@capacitor/android": "^7",
58
- },
59
- devDependencies: {
60
- "@capacitor/cli": "^7",
61
- "@capacitor/assets": "^3",
62
- },
63
- };
64
- }
65
- return { name: "test-pkg", version: "1.0.0" };
66
- }) as never);
67
-
68
- execaCalls.length = 0;
69
- }
70
-
71
- describe("initCapNpmProject", () => {
72
- beforeEach(() => {
73
- vi.clearAllMocks();
74
- setupDefaultMocks();
75
- });
76
-
77
- it("의존성 미변경 + node_modules 존재 시 false를 반환하고 pnpm install을 실행하지 않는다", async () => {
78
- const { initCapNpmProject } = await import(
79
- "../../src/capacitor/capacitor-npm-config.js"
80
- );
81
-
82
- const changed = await initCapNpmProject(CAP_PATH, PKG_PATH, {
83
- appId: "com.test.app",
84
- appName: "Test App",
85
- platform: { android: {} },
86
- }, { name: "test-pkg", version: "1.0.0" }, ["android"], []);
87
-
88
- expect(changed).toBe(false);
89
- });
90
-
91
- it("node_modules가 없으면 true를 반환하고 pnpm install을 실행한다", async () => {
92
- mockFsxExists.mockImplementation(((p: string) => {
93
- const n = p.replace(/\\/g, "/");
94
- if (n.includes(".capacitor.lock")) return false;
95
- if (n.includes("node_modules")) return false;
96
- return true;
97
- }) as never);
98
-
99
- const { initCapNpmProject } = await import(
100
- "../../src/capacitor/capacitor-npm-config.js"
101
- );
102
-
103
- const changed = await initCapNpmProject(CAP_PATH, PKG_PATH, {
104
- appId: "com.test.app",
105
- appName: "Test App",
106
- platform: { android: {} },
107
- }, {
108
- name: "test-pkg",
109
- version: "1.0.0",
110
- }, ["android"], []);
111
-
112
- expect(changed).toBe(true);
113
- });
114
- });
1
+ import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { fsx, cpx } from "@simplysm/core-node";
6
+
7
+ const mockFsxExists = vi.spyOn(fsx, "exists");
8
+ vi.spyOn(fsx, "read");
9
+ vi.spyOn(fsx, "write").mockResolvedValue(undefined);
10
+ const mockFsxReadJson = vi.spyOn(fsx, "readJson");
11
+ vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
12
+ vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
13
+
14
+ const execaCalls: { command: string; args: string[]; options: unknown }[] = [];
15
+ vi.spyOn(cpx, "spawn").mockImplementation(((cmd: string, args: string[], options: unknown) => {
16
+ execaCalls.push({
17
+ command: cmd,
18
+ args,
19
+ options,
20
+ });
21
+ return { stdout: "", stderr: "", exitCode: 0 };
22
+ }) as never);
23
+
24
+ //#endregion
25
+
26
+ let tmpRoot: string;
27
+ let CAP_PATH: string;
28
+ let PKG_PATH: string;
29
+
30
+ beforeAll(() => {
31
+ tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-npm-config-acc-"));
32
+ writeFileSync(path.join(tmpRoot, "package.json"), JSON.stringify({ private: true, workspaces: ["pkg"] }));
33
+ PKG_PATH = path.join(tmpRoot, "pkg");
34
+ CAP_PATH = path.join(PKG_PATH, ".capacitor");
35
+ });
36
+
37
+ afterAll(() => {
38
+ rmSync(tmpRoot, { recursive: true, force: true });
39
+ });
40
+
41
+ function setupDefaultMocks() {
42
+ mockFsxExists.mockImplementation(((p: string) => {
43
+ const n = p.replace(/\\/g, "/");
44
+ if (n.includes(".capacitor.lock")) return false;
45
+ return true;
46
+ }) as never);
47
+
48
+ mockFsxReadJson.mockImplementation(((p: string) => {
49
+ const normalized = p.replace(/\\/g, "/");
50
+ if (normalized.includes(".capacitor/package.json")) {
51
+ return {
52
+ name: "com.test.app",
53
+ version: "1.0.0",
54
+ dependencies: {
55
+ "@capacitor/core": "^7",
56
+ "@capacitor/app": "^7",
57
+ "@capacitor/android": "^7",
58
+ },
59
+ devDependencies: {
60
+ "@capacitor/cli": "^7",
61
+ "@capacitor/assets": "^3",
62
+ },
63
+ };
64
+ }
65
+ return { name: "test-pkg", version: "1.0.0" };
66
+ }) as never);
67
+
68
+ execaCalls.length = 0;
69
+ }
70
+
71
+ describe("initCapNpmProject", () => {
72
+ beforeEach(() => {
73
+ vi.clearAllMocks();
74
+ setupDefaultMocks();
75
+ });
76
+
77
+ it("의존성 미변경 + node_modules 존재 시 false를 반환하고 bun install을 실행하지 않는다", async () => {
78
+ const { initCapNpmProject } = await import(
79
+ "../../src/capacitor/capacitor-npm-config.js"
80
+ );
81
+
82
+ const changed = await initCapNpmProject(CAP_PATH, PKG_PATH, {
83
+ appId: "com.test.app",
84
+ appName: "Test App",
85
+ platform: { android: {} },
86
+ }, { name: "test-pkg", version: "1.0.0" }, ["android"], []);
87
+
88
+ expect(changed).toBe(false);
89
+ });
90
+
91
+ it("node_modules가 없으면 true를 반환하고 bun install을 실행한다", async () => {
92
+ mockFsxExists.mockImplementation(((p: string) => {
93
+ const n = p.replace(/\\/g, "/");
94
+ if (n.includes(".capacitor.lock")) return false;
95
+ if (n.includes("node_modules")) return false;
96
+ return true;
97
+ }) as never);
98
+
99
+ const { initCapNpmProject } = await import(
100
+ "../../src/capacitor/capacitor-npm-config.js"
101
+ );
102
+
103
+ const changed = await initCapNpmProject(CAP_PATH, PKG_PATH, {
104
+ appId: "com.test.app",
105
+ appName: "Test App",
106
+ platform: { android: {} },
107
+ }, {
108
+ name: "test-pkg",
109
+ version: "1.0.0",
110
+ }, ["android"], []);
111
+
112
+ expect(changed).toBe(true);
113
+ });
114
+ });
@@ -1,94 +1,94 @@
1
- import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
2
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import path from "node:path";
5
- import { fsx, cpx } from "@simplysm/core-node";
6
-
7
- const mockFsxExists = vi.spyOn(fsx, "exists");
8
- vi.spyOn(fsx, "write").mockResolvedValue(undefined);
9
- const mockFsxReadJson = vi.spyOn(fsx, "readJson");
10
- vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
11
- vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
12
- vi.spyOn(fsx, "read");
13
-
14
- vi.spyOn(cpx, "spawn").mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
15
-
16
- let tmpRoot: string;
17
- let CAP_PATH: string;
18
- let PKG_PATH: string;
19
-
20
- beforeAll(() => {
21
- tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-npm-config-"));
22
- writeFileSync(path.join(tmpRoot, "pnpm-workspace.yaml"), "");
23
- PKG_PATH = path.join(tmpRoot, "pkg");
24
- CAP_PATH = path.join(PKG_PATH, ".capacitor");
25
- });
26
-
27
- afterAll(() => {
28
- rmSync(tmpRoot, { recursive: true, force: true });
29
- });
30
-
31
- describe("setupCapNpmConfig", () => {
32
- beforeEach(() => {
33
- vi.clearAllMocks();
34
- mockFsxExists.mockResolvedValue(true);
35
- mockFsxReadJson.mockImplementation(((p: string) => {
36
- const normalized = p.replace(/\\/g, "/");
37
- if (normalized.includes(".capacitor/package.json")) {
38
- return {
39
- name: "com.test.app",
40
- version: "1.0.0",
41
- dependencies: {
42
- "@capacitor/core": "^7",
43
- "@capacitor/app": "^7",
44
- "@capacitor/android": "^7",
45
- },
46
- devDependencies: {
47
- "@capacitor/cli": "^7",
48
- "@capacitor/assets": "^3",
49
- },
50
- };
51
- }
52
- return { name: "test-pkg", version: "1.0.0" };
53
- }) as never);
54
- });
55
-
56
- it("루트 package.json이 없으면 에러를 던진다", async () => {
57
- mockFsxExists.mockImplementation(((p: string) => {
58
- const n = p.replace(/\\/g, "/");
59
- if (n.endsWith("package.json") && !n.includes(".capacitor")) return false;
60
- return true;
61
- }) as never);
62
-
63
- const { setupCapNpmConfig } = await import(
64
- "../../src/capacitor/capacitor-npm-config.js"
65
- );
66
-
67
- await expect(
68
- setupCapNpmConfig(CAP_PATH, PKG_PATH, {
69
- appId: "com.test.app",
70
- appName: "Test App",
71
- }, { name: "test-pkg", version: "1.0.0" }, [], []),
72
- ).rejects.toThrow("루트 package.json");
73
- });
74
-
75
- it(".capacitor/package.json이 없으면 빈 설정으로 시작한다", async () => {
76
- mockFsxExists.mockImplementation(((p: string) => {
77
- const n = p.replace(/\\/g, "/");
78
- if (n.includes(".capacitor/package.json")) return false;
79
- return true;
80
- }) as never);
81
-
82
- const { setupCapNpmConfig } = await import(
83
- "../../src/capacitor/capacitor-npm-config.js"
84
- );
85
-
86
- const changed = await setupCapNpmConfig(CAP_PATH, PKG_PATH, {
87
- appId: "com.test.app",
88
- appName: "Test App",
89
- }, { name: "test-pkg", version: "1.0.0" }, [], []);
90
-
91
- // 빈 설정에서 시작하므로 dependencies가 추가되어 변경됨
92
- expect(changed).toBe(true);
93
- });
94
- });
1
+ import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { fsx, cpx } from "@simplysm/core-node";
6
+
7
+ const mockFsxExists = vi.spyOn(fsx, "exists");
8
+ vi.spyOn(fsx, "write").mockResolvedValue(undefined);
9
+ const mockFsxReadJson = vi.spyOn(fsx, "readJson");
10
+ vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
11
+ vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
12
+ vi.spyOn(fsx, "read");
13
+
14
+ vi.spyOn(cpx, "spawn").mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
15
+
16
+ let tmpRoot: string;
17
+ let CAP_PATH: string;
18
+ let PKG_PATH: string;
19
+
20
+ beforeAll(() => {
21
+ tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-npm-config-"));
22
+ writeFileSync(path.join(tmpRoot, "package.json"), JSON.stringify({ private: true, workspaces: ["pkg"] }));
23
+ PKG_PATH = path.join(tmpRoot, "pkg");
24
+ CAP_PATH = path.join(PKG_PATH, ".capacitor");
25
+ });
26
+
27
+ afterAll(() => {
28
+ rmSync(tmpRoot, { recursive: true, force: true });
29
+ });
30
+
31
+ describe("setupCapNpmConfig", () => {
32
+ beforeEach(() => {
33
+ vi.clearAllMocks();
34
+ mockFsxExists.mockResolvedValue(true);
35
+ mockFsxReadJson.mockImplementation(((p: string) => {
36
+ const normalized = p.replace(/\\/g, "/");
37
+ if (normalized.includes(".capacitor/package.json")) {
38
+ return {
39
+ name: "com.test.app",
40
+ version: "1.0.0",
41
+ dependencies: {
42
+ "@capacitor/core": "^7",
43
+ "@capacitor/app": "^7",
44
+ "@capacitor/android": "^7",
45
+ },
46
+ devDependencies: {
47
+ "@capacitor/cli": "^7",
48
+ "@capacitor/assets": "^3",
49
+ },
50
+ };
51
+ }
52
+ return { name: "test-pkg", version: "1.0.0" };
53
+ }) as never);
54
+ });
55
+
56
+ it("루트 package.json이 없으면 에러를 던진다", async () => {
57
+ mockFsxExists.mockImplementation(((p: string) => {
58
+ const n = p.replace(/\\/g, "/");
59
+ if (n.endsWith("package.json") && !n.includes(".capacitor")) return false;
60
+ return true;
61
+ }) as never);
62
+
63
+ const { setupCapNpmConfig } = await import(
64
+ "../../src/capacitor/capacitor-npm-config.js"
65
+ );
66
+
67
+ await expect(
68
+ setupCapNpmConfig(CAP_PATH, PKG_PATH, {
69
+ appId: "com.test.app",
70
+ appName: "Test App",
71
+ }, { name: "test-pkg", version: "1.0.0" }, [], []),
72
+ ).rejects.toThrow("루트 package.json");
73
+ });
74
+
75
+ it(".capacitor/package.json이 없으면 빈 설정으로 시작한다", async () => {
76
+ mockFsxExists.mockImplementation(((p: string) => {
77
+ const n = p.replace(/\\/g, "/");
78
+ if (n.includes(".capacitor/package.json")) return false;
79
+ return true;
80
+ }) as never);
81
+
82
+ const { setupCapNpmConfig } = await import(
83
+ "../../src/capacitor/capacitor-npm-config.js"
84
+ );
85
+
86
+ const changed = await setupCapNpmConfig(CAP_PATH, PKG_PATH, {
87
+ appId: "com.test.app",
88
+ appName: "Test App",
89
+ }, { name: "test-pkg", version: "1.0.0" }, [], []);
90
+
91
+ // 빈 설정에서 시작하므로 dependencies가 추가되어 변경됨
92
+ expect(changed).toBe(true);
93
+ });
94
+ });
@@ -0,0 +1,67 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import fs from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ import { gunzipSync } from "zlib";
7
+ import { cpx } from "@simplysm/core-node";
8
+
9
+ const tmpDirs: string[] = [];
10
+
11
+ function readTarEntry(tgzPath: string, entryName: string): string {
12
+ const tarBuffer = gunzipSync(fs.readFileSync(tgzPath));
13
+ let offset = 0;
14
+
15
+ while (offset + 512 <= tarBuffer.length) {
16
+ const header = tarBuffer.subarray(offset, offset + 512);
17
+ const name = header.toString("utf-8", 0, 100).replace(/\0.*$/s, "");
18
+ if (name === "") break;
19
+
20
+ const sizeText = header.toString("utf-8", 124, 136).replace(/\0.*$/s, "").trim();
21
+ const size = Number.parseInt(sizeText, 8);
22
+ const dataStart = offset + 512;
23
+ const dataEnd = dataStart + size;
24
+
25
+ if (name === entryName) {
26
+ return tarBuffer.toString("utf-8", dataStart, dataEnd);
27
+ }
28
+
29
+ offset = dataStart + Math.ceil(size / 512) * 512;
30
+ }
31
+
32
+ throw new Error(`tar entry not found: ${entryName}`);
33
+ }
34
+
35
+ afterEach(() => {
36
+ for (const dir of tmpDirs.splice(0)) {
37
+ fs.rmSync(dir, { recursive: true, force: true });
38
+ }
39
+ });
40
+
41
+ describe("npm package manifest", () => {
42
+ it("keeps CLI binary and replaces workspace dependency ranges in Bun pack output", async () => {
43
+ const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
44
+ const destination = fs.mkdtempSync(path.join(os.tmpdir(), "sd-cli-pack-"));
45
+ tmpDirs.push(destination);
46
+
47
+ await cpx.spawn(
48
+ "bun",
49
+ ["pm", "pack", "--destination", destination, "--ignore-scripts", "--quiet"],
50
+ { cwd: pkgRoot },
51
+ );
52
+
53
+ const tarball = fs.readdirSync(destination).find((item) => item.endsWith(".tgz"));
54
+ if (tarball == null) throw new Error("package tarball not created");
55
+
56
+ const packedPackageJson = JSON.parse(
57
+ readTarEntry(path.join(destination, tarball), "package/package.json"),
58
+ ) as Record<string, unknown>;
59
+ const bin = packedPackageJson["bin"] as Record<string, unknown>;
60
+ const dependencies = packedPackageJson["dependencies"] as Record<string, string>;
61
+
62
+ expect(bin["sd-cli"]).toBe("./dist/sd-cli.js");
63
+ expect(dependencies["@simplysm/core-common"]).not.toContain("workspace:");
64
+ expect(dependencies["@simplysm/core-node"]).not.toContain("workspace:");
65
+ expect(dependencies["@simplysm/storage"]).not.toContain("workspace:");
66
+ }, 120_000);
67
+ });
@@ -5,11 +5,16 @@ import path from "path";
5
5
  import { collectDeps } from "../../../src/deps/replace-deps/collect-deps";
6
6
  import { pathx } from "@simplysm/core-node";
7
7
 
8
- describe("collectDeps — tests/ 패키지 제외", () => {
8
+ describe("collectDeps — packages/ 워크스페이스 제외", () => {
9
9
  let tmpDir: string;
10
10
 
11
11
  beforeEach(() => {
12
12
  tmpDir = pathx.posix(fs.mkdtempSync(path.join(os.tmpdir(), "sd-cli-test-")));
13
+ // 워크스페이스 루트 선언 (discoverWorkspacePackages는 package.json#workspaces 기반)
14
+ fs.writeFileSync(
15
+ pathx.posix(path.join(tmpDir, "package.json")),
16
+ JSON.stringify({ private: true, workspaces: ["packages/*", "tests/*", "plugins/*"] }),
17
+ );
13
18
  });
14
19
 
15
20
  afterEach(() => {
@@ -59,4 +64,14 @@ describe("collectDeps — tests/ 패키지 제외", () => {
59
64
  expect(result.workspaceDeps).toContain("core-common");
60
65
  expect(result.workspaceDeps).not.toContain("orm");
61
66
  });
67
+
68
+ // Scenario: plugins/ 패키지도 packages/ 가 아니므로 workspaceDeps에서 제외된다
69
+ it("dependency에 plugins/ 패키지가 있어도 workspaceDeps에서 무시한다", () => {
70
+ createPkg("packages/my-lib", "@test/my-lib", { "@test/sd": "workspace:*" });
71
+ createPkg("plugins/sd", "@test/sd");
72
+
73
+ const result = collectDeps(pathx.posix(path.join(tmpDir, "packages/my-lib")), tmpDir);
74
+
75
+ expect(result.workspaceDeps).not.toContain("sd");
76
+ });
62
77
  });
@@ -16,8 +16,8 @@ describe("resolveAllReplaceDepEntries", () => {
16
16
  projectRoot = pathx.posix(path.join(tmpDir, "project"));
17
17
  await fs.promises.mkdir(projectRoot, { recursive: true });
18
18
  await fs.promises.writeFile(
19
- pathx.posix(path.join(projectRoot, "pnpm-workspace.yaml")),
20
- "packages:\n",
19
+ pathx.posix(path.join(projectRoot, "package.json")),
20
+ JSON.stringify({ private: true, workspaces: [] }),
21
21
  );
22
22
  });
23
23
 
@@ -66,12 +66,16 @@ describe("resolveAllReplaceDepEntries", () => {
66
66
  const nodeModulesDir = pathx.posix(path.join(projectRoot, "node_modules"));
67
67
  await createNodeModulesPkg(nodeModulesDir, "@test/pkg");
68
68
 
69
- // workspace 패키지 설정 (pnpm-workspace.yaml에 추가)
69
+ // workspace 패키지 설정 (package.json#workspaces에 추가)
70
70
  const workspacePkgDir = pathx.posix(path.join(projectRoot, "packages", "my-app"));
71
71
  await fs.promises.mkdir(workspacePkgDir, { recursive: true });
72
72
  await fs.promises.writeFile(
73
- pathx.posix(path.join(projectRoot, "pnpm-workspace.yaml")),
74
- "packages:\n - packages/*\n",
73
+ pathx.posix(path.join(workspacePkgDir, "package.json")),
74
+ JSON.stringify({ name: "my-app" }),
75
+ );
76
+ await fs.promises.writeFile(
77
+ pathx.posix(path.join(projectRoot, "package.json")),
78
+ JSON.stringify({ private: true, workspaces: ["packages/*"] }),
75
79
  );
76
80
 
77
81
  // workspace 패키지의 node_modules에도 동일 패키지 생성
@@ -11,12 +11,12 @@ describe("setupReplaceDeps 화이트리스트 복사", () => {
11
11
  beforeEach(async () => {
12
12
  tmpDir = pathx.posix(await fs.promises.mkdtemp(path.join(os.tmpdir(), "sd-replace-deps-")));
13
13
 
14
- // pnpm-workspace.yaml
14
+ // package.json#workspaces
15
15
  const projectRoot = pathx.posix(path.join(tmpDir, "project"));
16
16
  await fs.promises.mkdir(projectRoot, { recursive: true });
17
17
  await fs.promises.writeFile(
18
- pathx.posix(path.join(projectRoot, "pnpm-workspace.yaml")),
19
- "packages:\n",
18
+ pathx.posix(path.join(projectRoot, "package.json")),
19
+ JSON.stringify({ private: true, workspaces: [] }),
20
20
  );
21
21
 
22
22
  // 타겟 (node_modules에 기존 패키지)
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it, afterEach } from "vitest";
2
+ import fs from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ import {
6
+ parseLockfileVersions,
7
+ resolveLockedVersions,
8
+ } from "../../../src/deps/server-externals/server-production-files";
9
+
10
+ const tmpDirs: string[] = [];
11
+
12
+ function createLock(content: string): string {
13
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "sd-bun-lock-"));
14
+ tmpDirs.push(dir);
15
+ fs.writeFileSync(path.join(dir, "bun.lock"), content);
16
+ return dir;
17
+ }
18
+
19
+ afterEach(() => {
20
+ for (const dir of tmpDirs.splice(0)) {
21
+ fs.rmSync(dir, { recursive: true, force: true });
22
+ }
23
+ });
24
+
25
+ describe("parseLockfileVersions", () => {
26
+ it("reads unscoped, scoped, alias, and optional entries from bun.lock", () => {
27
+ const cwd = createLock(`{
28
+ "lockfileVersion": 1,
29
+ "packages": {
30
+ "is-number": ["is-number@7.0.0", "", {}, "sha512-a"],
31
+ "@types/node": ["@types/node@24.13.2", "", {}, "sha512-b"],
32
+ "alias-pkg": ["is-number@6.0.0", "", {}, "sha512-c"],
33
+ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-d"],
34
+ }
35
+ }`);
36
+
37
+ const map = parseLockfileVersions(cwd);
38
+
39
+ expect(map.get("is-number")).toBe("7.0.0");
40
+ expect(map.get("@types/node")).toBe("24.13.2");
41
+ expect(map.get("alias-pkg")).toBe("6.0.0");
42
+ expect(map.get("fsevents")).toBe("2.3.3");
43
+ });
44
+
45
+ it("strips peer suffix from package references", () => {
46
+ const cwd = createLock(`{
47
+ "lockfileVersion": 1,
48
+ "packages": {
49
+ "react-dom": ["react-dom@19.2.7(react@19.2.7)", "", {}, "sha512-a"],
50
+ }
51
+ }`);
52
+
53
+ expect(parseLockfileVersions(cwd).get("react-dom")).toBe("19.2.7");
54
+ });
55
+ });
56
+
57
+ describe("resolveLockedVersions", () => {
58
+ it("throws when an external dependency is missing from bun.lock", () => {
59
+ const cwd = createLock(`{
60
+ "lockfileVersion": 1,
61
+ "packages": {
62
+ "is-number": ["is-number@7.0.0", "", {}, "sha512-a"],
63
+ }
64
+ }`);
65
+
66
+ expect(() => resolveLockedVersions(cwd, ["missing"])).toThrow("bun.lock");
67
+ });
68
+ });