@simplysm/sd-cli 14.0.17 → 14.0.19

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 (49) hide show
  1. package/dist/angular/vite-angular-plugin.d.ts +2 -0
  2. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  3. package/dist/angular/vite-angular-plugin.js +57 -28
  4. package/dist/angular/vite-angular-plugin.js.map +1 -1
  5. package/dist/capacitor/capacitor.d.ts +0 -1
  6. package/dist/capacitor/capacitor.d.ts.map +1 -1
  7. package/dist/capacitor/capacitor.js +12 -37
  8. package/dist/capacitor/capacitor.js.map +1 -1
  9. package/dist/commands/device.d.ts.map +1 -1
  10. package/dist/commands/device.js +3 -2
  11. package/dist/commands/device.js.map +1 -1
  12. package/dist/electron/electron.d.ts.map +1 -1
  13. package/dist/electron/electron.js +9 -4
  14. package/dist/electron/electron.js.map +1 -1
  15. package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
  16. package/dist/orchestrators/DevWatchOrchestrator.js +12 -0
  17. package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
  18. package/dist/utils/vite-config.d.ts +1 -1
  19. package/dist/utils/vite-config.d.ts.map +1 -1
  20. package/dist/utils/vite-config.js +76 -26
  21. package/dist/utils/vite-config.js.map +1 -1
  22. package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
  23. package/dist/utils/vite-scope-watch-plugin.js +7 -1
  24. package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
  25. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  26. package/dist/workers/server-runtime.worker.js +15 -0
  27. package/dist/workers/server-runtime.worker.js.map +1 -1
  28. package/package.json +9 -7
  29. package/src/angular/vite-angular-plugin.ts +88 -34
  30. package/src/capacitor/capacitor.ts +14 -46
  31. package/src/commands/device.ts +3 -2
  32. package/src/electron/electron.ts +11 -4
  33. package/src/orchestrators/DevWatchOrchestrator.ts +14 -0
  34. package/src/utils/vite-config.ts +83 -27
  35. package/src/utils/vite-scope-watch-plugin.ts +6 -1
  36. package/src/workers/server-runtime.worker.ts +15 -0
  37. package/tests/angular/linker-disk-cache.spec.ts +31 -25
  38. package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +15 -15
  39. package/tests/angular/vite-angular-plugin-hmr.spec.ts +9 -9
  40. package/tests/angular/vite-angular-plugin-legacy-watch.spec.ts +108 -0
  41. package/tests/angular/vite-angular-plugin-lint.spec.ts +4 -4
  42. package/tests/angular/vite-angular-plugin-scss-hmr.spec.ts +10 -15
  43. package/tests/angular/vite-angular-plugin.spec.ts +80 -15
  44. package/tests/capacitor/capacitor-workspace.spec.ts +22 -12
  45. package/tests/commands/device.spec.ts +12 -7
  46. package/tests/electron/electron.spec.ts +27 -2
  47. package/tests/utils/vite-config.spec.ts +255 -133
  48. package/tests/utils/vite-scope-watch-plugin.spec.ts +22 -0
  49. package/tests/workers/server-runtime-worker.spec.ts +48 -4
@@ -70,6 +70,17 @@ vi.mock("fs/promises", () => ({
70
70
  symlink: mockSymlink,
71
71
  }));
72
72
 
73
+ vi.mock("module", () => ({
74
+ createRequire: () => ({
75
+ resolve: (id: string) => {
76
+ if (id.includes("capacitor-plugin-auto-update")) {
77
+ return path.resolve("/fake/workspace/packages/capacitor-plugin-auto-update/package.json");
78
+ }
79
+ throw new Error(`Cannot find module '${id}'`);
80
+ },
81
+ }),
82
+ }));
83
+
73
84
  vi.mock("consola", () => ({
74
85
  consola: {
75
86
  withTag: () => ({ debug: vi.fn(), warn: vi.fn() }),
@@ -155,7 +166,7 @@ describe("workspace:* 플러그인 해석", () => {
155
166
  setupDefaultMocks();
156
167
  });
157
168
 
158
- it("workspace:* 플러그인을 package.json에 추가하지 않고 symlink로 연결한다", async () => {
169
+ it("workspace:* 플러그인이 link: 프로토콜로 package.json에 등록된다", async () => {
159
170
  const { Capacitor } = await import("../../src/capacitor/capacitor.js");
160
171
 
161
172
  const cap = await Capacitor.create(PKG_PATH, {
@@ -170,7 +181,6 @@ describe("workspace:* 플러그인 해석", () => {
170
181
 
171
182
  await cap.initialize();
172
183
 
173
- // 1. .capacitor/package.json에 workspace:* 플러그인이 포함되지 않아야 한다
174
184
  const writeJsonCalls = mockFsxWriteJson.mock.calls;
175
185
  const capPkgWrite = writeJsonCalls.find(
176
186
  (call) => typeof call[0] === "string" && call[0].includes("package.json"),
@@ -180,18 +190,18 @@ describe("workspace:* 플러그인 해석", () => {
180
190
  string,
181
191
  string
182
192
  >;
183
- expect(deps["@simplysm/capacitor-plugin-auto-update"]).toBeUndefined();
184
193
 
185
- // 2. 일반 npm 플러그인은 정상 추가되어야 한다
194
+ // 1. workspace:* 플러그인이 link: 프로토콜로 등록되어야 한다
195
+ expect(deps["@simplysm/capacitor-plugin-auto-update"]).toMatch(/^link:/);
196
+
197
+ // 2. link: 경로는 상대경로여야 한다 (절대경로가 아님)
198
+ const linkPath = deps["@simplysm/capacitor-plugin-auto-update"].replace(/^link:/, "");
199
+ expect(linkPath).not.toMatch(/^[A-Z]:|^\//i);
200
+
201
+ // 3. 일반 npm 플러그인은 버전 문자열로 등록되어야 한다
186
202
  expect(deps["@capacitor/camera"]).toBe("^7.0.0");
187
203
 
188
- // 3. symlink 생성되어야 한다
189
- expect(mockSymlink).toHaveBeenCalled();
190
- const symlinkCall = mockSymlink.mock.calls.find(
191
- (call) =>
192
- typeof call[1] === "string" &&
193
- call[1].replace(/\\/g, "/").includes("@simplysm/capacitor-plugin-auto-update"),
194
- );
195
- expect(symlinkCall).toBeDefined();
204
+ // 4. 수동 symlink 생성이 호출되지 않아야 한다
205
+ expect(mockSymlink).not.toHaveBeenCalled();
196
206
  });
197
207
  });
@@ -166,19 +166,19 @@ describe("runDevice", () => {
166
166
  await expect(runDevice({ target: "my-server", options: [] })).rejects.toThrow();
167
167
  });
168
168
 
169
- // Acceptance: Scenario "dev 서버 실행 device 실행 URL 자동 생성"
170
- it("auto-detects URL from .dev-port when server is a string", async () => {
169
+ // Acceptance: Scenario "server가 string일 서버 패키지의 .dev-port에서 포트 읽기"
170
+ it("reads .dev-port from server package directory when server is a string", async () => {
171
171
  vi.mocked(loadSdConfig).mockResolvedValue({
172
172
  packages: {
173
173
  "client-devtool": {
174
174
  target: "client",
175
- server: "server",
175
+ server: "my-server",
176
176
  electron: { appId: "com.test.electron" },
177
177
  },
178
178
  },
179
179
  });
180
180
 
181
- mockReadFileSync.mockReturnValue("5173");
181
+ mockReadFileSync.mockReturnValue("3000");
182
182
 
183
183
  // HTTP 헬스체크 성공 mock
184
184
  mockHttpGet.mockImplementation((_url: string, cb: Function) => {
@@ -189,8 +189,13 @@ describe("runDevice", () => {
189
189
 
190
190
  await runDevice({ target: "client-devtool", options: [] });
191
191
 
192
+ // 서버 패키지 경로의 .dev-port를 읽어야 함
193
+ expect(mockReadFileSync).toHaveBeenCalledWith(
194
+ expect.stringContaining("my-server"),
195
+ "utf-8",
196
+ );
192
197
  expect(mockElectronInstance.run).toHaveBeenCalledWith(
193
- "http://localhost:5173/client-devtool/",
198
+ "http://localhost:3000/client-devtool/",
194
199
  );
195
200
  });
196
201
 
@@ -200,7 +205,7 @@ describe("runDevice", () => {
200
205
  packages: {
201
206
  "client-devtool": {
202
207
  target: "client",
203
- server: "server",
208
+ server: "my-server",
204
209
  electron: { appId: "com.test.electron" },
205
210
  },
206
211
  },
@@ -221,7 +226,7 @@ describe("runDevice", () => {
221
226
  packages: {
222
227
  "client-devtool": {
223
228
  target: "client",
224
- server: "server",
229
+ server: "my-server",
225
230
  electron: { appId: "com.test.electron" },
226
231
  },
227
232
  },
@@ -245,6 +245,15 @@ describe("Electron", () => {
245
245
  expect(deps["sharp"]).toBe("^0.34.0");
246
246
  });
247
247
 
248
+ it("package.json에 type: module이 설정된다", async () => {
249
+ const { Electron } = await import("../../src/electron/electron.js");
250
+
251
+ const electron = await Electron.create(PKG_PATH, { appId: "com.test.app" });
252
+ await electron.initialize();
253
+
254
+ expect(findElectronPackageJson()!["type"]).toBe("module");
255
+ });
256
+
248
257
  it("postInstallScript가 설정되면 scripts.postinstall에 포함한다", async () => {
249
258
  const { Electron } = await import("../../src/electron/electron.js");
250
259
 
@@ -277,7 +286,7 @@ describe("Electron", () => {
277
286
  expect.objectContaining({
278
287
  platform: "node",
279
288
  target: "node20",
280
- format: "cjs",
289
+ format: "esm",
281
290
  bundle: true,
282
291
  external: expect.arrayContaining(["electron", "better-sqlite3"]),
283
292
  }),
@@ -314,6 +323,18 @@ describe("Electron", () => {
314
323
  expect(banner).not.toContain("ELECTRON_DEV_URL");
315
324
  expect(callArgs.define).toBeUndefined();
316
325
  });
326
+
327
+ it("ESM 배너에 createRequire shim이 포함된다", async () => {
328
+ const { Electron } = await import("../../src/electron/electron.js");
329
+
330
+ const electron = await Electron.create(PKG_PATH, { appId: "com.test.app" });
331
+ await electron.build("/fake/out");
332
+
333
+ const callArgs = mockEsbuildBuild.mock.calls[0][0];
334
+ const banner = callArgs.banner?.js as string;
335
+ expect(banner).toContain("createRequire");
336
+ expect(banner).toContain("import.meta.url");
337
+ });
317
338
  });
318
339
 
319
340
  //#endregion
@@ -503,9 +524,13 @@ describe("Electron", () => {
503
524
 
504
525
  expect(callArgs.platform).toBe("node");
505
526
  expect(callArgs.target).toBe("node20");
506
- expect(callArgs.format).toBe("cjs");
527
+ expect(callArgs.format).toBe("esm");
507
528
  expect(callArgs.bundle).toBe(true);
508
529
  expect(callArgs.external).toContain("electron");
530
+
531
+ // ESM 배너에 createRequire shim 포함
532
+ expect(banner).toContain("createRequire");
533
+ expect(banner).toContain("import.meta.url");
509
534
  }, 10_000);
510
535
 
511
536
  it("throws when electron-main.ts entry point is missing", async () => {