@simplysm/sd-cli 14.0.7 → 14.0.8

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 (37) hide show
  1. package/dist/capacitor/capacitor.d.ts +1 -1
  2. package/dist/capacitor/capacitor.d.ts.map +1 -1
  3. package/dist/capacitor/capacitor.js +3 -4
  4. package/dist/capacitor/capacitor.js.map +1 -1
  5. package/dist/commands/check.js +2 -2
  6. package/dist/commands/check.js.map +1 -1
  7. package/dist/commands/publish.d.ts.map +1 -1
  8. package/dist/commands/publish.js +12 -13
  9. package/dist/commands/publish.js.map +1 -1
  10. package/dist/electron/electron.d.ts.map +1 -1
  11. package/dist/electron/electron.js +19 -13
  12. package/dist/electron/electron.js.map +1 -1
  13. package/dist/sd-cli.js +5 -5
  14. package/dist/sd-cli.js.map +1 -1
  15. package/dist/vitest-plugin.d.ts.map +1 -1
  16. package/dist/vitest-plugin.js +2 -0
  17. package/dist/vitest-plugin.js.map +1 -1
  18. package/dist/workers/server-build.worker.d.ts.map +1 -1
  19. package/dist/workers/server-build.worker.js +2 -3
  20. package/dist/workers/server-build.worker.js.map +1 -1
  21. package/package.json +4 -5
  22. package/src/capacitor/capacitor.ts +3 -4
  23. package/src/commands/check.ts +2 -2
  24. package/src/commands/publish.ts +12 -13
  25. package/src/electron/electron.ts +21 -14
  26. package/src/sd-cli.ts +8 -5
  27. package/src/vitest-plugin.ts +5 -0
  28. package/src/workers/server-build.worker.ts +2 -3
  29. package/tests/capacitor/capacitor-build.spec.ts +9 -7
  30. package/tests/capacitor/capacitor-icon.spec.ts +9 -7
  31. package/tests/capacitor/capacitor-init.spec.ts +8 -6
  32. package/tests/capacitor/capacitor-run.spec.ts +13 -11
  33. package/tests/capacitor/capacitor-workspace.spec.ts +8 -6
  34. package/tests/commands/check.spec.ts +5 -2
  35. package/tests/commands/publish.spec.ts +4 -4
  36. package/tests/electron/electron.spec.ts +27 -23
  37. package/tests/workers/server-build-worker.spec.ts +6 -3
@@ -25,6 +25,10 @@ vi.mock("@simplysm/core-node", () => ({
25
25
  glob: mockFsxGlob,
26
26
  copy: mockFsxCopy,
27
27
  },
28
+ cpx: {
29
+ exec: mockCpxExec,
30
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
31
+ },
28
32
  }));
29
33
 
30
34
  // env mock
@@ -35,17 +39,15 @@ vi.mock("@simplysm/core-common", () => ({
35
39
  }),
36
40
  }));
37
41
 
38
- // execa mock — tracks commands and resolves immediately
42
+ // cpx mock (was execa) — tracks commands and resolves immediately
39
43
  const execaCalls: { command: string; args: string[] }[] = [];
40
- let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string }> = () =>
41
- Promise.resolve({ stdout: "", stderr: "" });
44
+ let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string; exitCode: number }> = () =>
45
+ Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
42
46
 
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
- }));
47
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
48
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
49
+ return execaFactory(...args);
50
+ });
49
51
 
50
52
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
51
53
  vi.mock("node:fs", () => ({
@@ -135,7 +137,7 @@ export default config;`;
135
137
  mockEnv = { ANDROID_HOME: "C:/Android/Sdk" };
136
138
 
137
139
  execaCalls.length = 0;
138
- execaFactory = () => Promise.resolve({ stdout: "", stderr: "" });
140
+ execaFactory = () => Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
139
141
  mockFsWriteFile.mockReset();
140
142
  mockFsWriteFile.mockResolvedValue(undefined);
141
143
  }
@@ -195,7 +197,7 @@ describe("Capacitor.run()", () => {
195
197
  return Promise.reject(new Error("cap run failed"));
196
198
  }
197
199
  }
198
- return Promise.resolve({ stdout: "", stderr: "" });
200
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
199
201
  };
200
202
 
201
203
  const cap = await Capacitor.create(PKG_PATH, {
@@ -24,6 +24,10 @@ vi.mock("@simplysm/core-node", () => ({
24
24
  glob: mockFsxGlob,
25
25
  copy: mockFsxCopy,
26
26
  },
27
+ cpx: {
28
+ exec: mockCpxExec,
29
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
30
+ },
27
31
  }));
28
32
 
29
33
  let mockEnv: Record<string, unknown> = {};
@@ -34,12 +38,10 @@ vi.mock("@simplysm/core-common", () => ({
34
38
  }));
35
39
 
36
40
  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
- }));
41
+ const mockCpxExec = vi.fn((...args: unknown[]) => {
42
+ execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
43
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
44
+ });
43
45
 
44
46
  const mockFsWriteFile = vi.fn().mockResolvedValue(undefined);
45
47
  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) => {
@@ -48,12 +48,12 @@ vi.mock("../../src/utils/replace-deps", () => ({
48
48
  parseWorkspaceGlobs: mocks.parseWorkspaceGlobs,
49
49
  }));
50
50
 
51
- vi.mock("execa", () => ({
52
- execa: mocks.execa,
53
- }));
54
-
55
51
  vi.mock("@simplysm/core-node", () => ({
56
52
  fsx: mocks.fsx,
53
+ cpx: {
54
+ exec: mocks.execa,
55
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
56
+ },
57
57
  }));
58
58
 
59
59
  vi.mock("@simplysm/core-common", () => {
@@ -21,13 +21,14 @@ vi.mock("@simplysm/core-node", () => ({
21
21
  readdir: mockFsxReaddir,
22
22
  glob: mockFsxGlob,
23
23
  },
24
+ cpx: {
25
+ exec: mockCpxExec,
26
+ execSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
27
+ },
24
28
  }));
25
29
 
26
- // execa mock
27
- const mockExeca = vi.fn().mockResolvedValue({ stdout: "" });
28
- vi.mock("execa", () => ({
29
- execa: mockExeca,
30
- }));
30
+ // cpx mock (was execa)
31
+ const mockCpxExec = vi.fn().mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
31
32
 
32
33
  // esbuild mock
33
34
  const mockEsbuildBuild = vi.fn().mockResolvedValue({});
@@ -91,13 +92,15 @@ function setupDefaultMocks() {
91
92
  });
92
93
  mockFsxReaddir.mockResolvedValue(["index.html", "assets", "electron"]);
93
94
  // Default: glob returns one exe file matching the builder output
94
- mockFsxGlob.mockImplementation((pattern: string, opts?: { cwd?: string }) => {
95
- if (pattern === "*.exe" && opts?.cwd != null) {
96
- return Promise.resolve([opts.cwd.replace(/\\/g, "/") + "/My App Setup 1.0.0.exe"]);
95
+ mockFsxGlob.mockImplementation((pattern: string) => {
96
+ const normalized = pattern.replace(/\\/g, "/");
97
+ if (normalized.endsWith(".electron/dist/*.exe")) {
98
+ const dir = normalized.replace("/*.exe", "");
99
+ return Promise.resolve([dir + "/My App Setup 1.0.0.exe"]);
97
100
  }
98
101
  return Promise.resolve([]);
99
102
  });
100
- mockExeca.mockResolvedValue({ stdout: "" });
103
+ mockCpxExec.mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
101
104
  mockEsbuildBuild.mockResolvedValue({});
102
105
  }
103
106
 
@@ -171,7 +174,7 @@ describe("Electron", () => {
171
174
 
172
175
  expect(findElectronPackageJson()).toBeDefined();
173
176
 
174
- const execaCalls = mockExeca.mock.calls;
177
+ const execaCalls = mockCpxExec.mock.calls;
175
178
  expect(
176
179
  execaCalls.find((c) => c[0] === "npm" && (c[1] as string[]).includes("install")),
177
180
  ).toBeDefined();
@@ -188,7 +191,7 @@ describe("Electron", () => {
188
191
  const electron = await Electron.create(PKG_PATH, { appId: "com.test.app" });
189
192
  await electron.initialize();
190
193
 
191
- const rebuildCall = mockExeca.mock.calls.find(
194
+ const rebuildCall = mockCpxExec.mock.calls.find(
192
195
  (c) => typeof c[0] === "string" && c[0].includes("electron-rebuild"),
193
196
  );
194
197
  expect(rebuildCall).toBeUndefined();
@@ -418,7 +421,8 @@ describe("Electron", () => {
418
421
 
419
422
  it("빌드 산출물이 없으면 경고를 출력한다", async () => {
420
423
  mockFsxGlob.mockImplementation((pattern: string) => {
421
- if (pattern === "*.exe") return Promise.resolve([]);
424
+ const normalized = pattern.replace(/\\/g, "/");
425
+ if (normalized.endsWith(".electron/dist/*.exe")) return Promise.resolve([]);
422
426
  return Promise.resolve([]);
423
427
  });
424
428
 
@@ -436,15 +440,15 @@ describe("Electron", () => {
436
440
  //#region Rule: 개발 모드에서 Electron 앱을 실행한다
437
441
 
438
442
  describe("인수 테스트: run()", () => {
439
- // Helper: creates a deferred execa mock where Electron process can be controlled
440
- function setupExecaForRun(): {
443
+ // Helper: creates a deferred cpx mock where Electron process can be controlled
444
+ function setupCpxForRun(): {
441
445
  electronKill: ReturnType<typeof vi.fn>;
442
446
  resolveElectron: () => void;
443
447
  } {
444
448
  const electronKill = vi.fn();
445
449
  let resolveElectron: () => void = () => {};
446
450
 
447
- mockExeca.mockImplementation((cmd: string) => {
451
+ mockCpxExec.mockImplementation((cmd: string) => {
448
452
  if (typeof cmd === "string" && cmd.includes("electron")) {
449
453
  // Electron process: create a deferred promise we can resolve externally
450
454
  const p = new Promise<void>((resolve) => {
@@ -453,14 +457,14 @@ describe("Electron", () => {
453
457
  p.kill = electronKill;
454
458
  return p;
455
459
  }
456
- return Promise.resolve({ stdout: "" });
460
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
457
461
  });
458
462
 
459
463
  return { electronKill, resolveElectron: () => resolveElectron() };
460
464
  }
461
465
 
462
466
  it("creates esbuild context with banner for env and spawns Electron", async () => {
463
- const { resolveElectron } = setupExecaForRun();
467
+ const { resolveElectron } = setupCpxForRun();
464
468
 
465
469
  const { Electron } = await import("../../src/electron/electron.js");
466
470
  const electron = await Electron.create(PKG_PATH, { appId: "com.test.app" });
@@ -503,7 +507,7 @@ describe("Electron", () => {
503
507
  });
504
508
 
505
509
  it("resolves on SIGINT signal", async () => {
506
- const { electronKill } = setupExecaForRun();
510
+ const { electronKill } = setupCpxForRun();
507
511
 
508
512
  const { Electron } = await import("../../src/electron/electron.js");
509
513
  const electron = await Electron.create(PKG_PATH, { appId: "com.test.app" });
@@ -526,7 +530,7 @@ describe("Electron", () => {
526
530
  describe("단위: run() 플러그인 동작", () => {
527
531
  it("passes custom env and ELECTRON_DEV_URL via esbuild banner", async () => {
528
532
  let resolveElectron: () => void = () => {};
529
- mockExeca.mockImplementation((cmd: string) => {
533
+ mockCpxExec.mockImplementation((cmd: string) => {
530
534
  if (typeof cmd === "string" && cmd.includes("electron")) {
531
535
  const p = new Promise<void>((resolve) => {
532
536
  resolveElectron = resolve;
@@ -534,7 +538,7 @@ describe("Electron", () => {
534
538
  p.kill = vi.fn();
535
539
  return p;
536
540
  }
537
- return Promise.resolve({ stdout: "" });
541
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
538
542
  });
539
543
 
540
544
  const { Electron } = await import("../../src/electron/electron.js");
@@ -559,7 +563,7 @@ describe("Electron", () => {
559
563
 
560
564
  it("calls initialize() before starting esbuild context", async () => {
561
565
  let resolveElectron: () => void = () => {};
562
- mockExeca.mockImplementation((cmd: string) => {
566
+ mockCpxExec.mockImplementation((cmd: string) => {
563
567
  if (typeof cmd === "string" && cmd.includes("electron")) {
564
568
  const p = new Promise<void>((resolve) => {
565
569
  resolveElectron = resolve;
@@ -567,7 +571,7 @@ describe("Electron", () => {
567
571
  p.kill = vi.fn();
568
572
  return p;
569
573
  }
570
- return Promise.resolve({ stdout: "" });
574
+ return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
571
575
  });
572
576
 
573
577
  const { Electron } = await import("../../src/electron/electron.js");
@@ -579,7 +583,7 @@ describe("Electron", () => {
579
583
  await runPromise;
580
584
 
581
585
  // initialize calls npm install -> execa should have been called with npm install
582
- const npmInstallCall = mockExeca.mock.calls.find(
586
+ const npmInstallCall = mockCpxExec.mock.calls.find(
583
587
  (c: any[]) => c[0] === "npm" && (c[1] as string[]).includes("install"),
584
588
  );
585
589
  expect(npmInstallCall).toBeDefined();
@@ -35,6 +35,8 @@ const mockRunTscPackageBuild = vi.fn(() => ({
35
35
  warningCount: 0,
36
36
  }));
37
37
 
38
+ const mockCpxExecSync = vi.fn().mockReturnValue({ stdout: "v20.11.0", stderr: "", exitCode: 0 });
39
+
38
40
  vi.mock("@simplysm/core-node", () => ({
39
41
  createWorker: vi.fn((fns: Record<string, Function>) => {
40
42
  workerFns = fns as any;
@@ -50,6 +52,10 @@ vi.mock("@simplysm/core-node", () => ({
50
52
  pathx: {
51
53
  norm: vi.fn((...args: string[]) => path.resolve(...args).replace(/\\/g, "/")),
52
54
  },
55
+ cpx: {
56
+ exec: vi.fn().mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 }),
57
+ execSync: mockCpxExecSync,
58
+ },
53
59
  }));
54
60
 
55
61
  vi.mock("@simplysm/core-common", () => ({
@@ -95,9 +101,6 @@ vi.mock("fs", () => ({
95
101
  existsSync: (...args: unknown[]) => mockExistsSync(...(args as [string])),
96
102
  }));
97
103
 
98
- vi.mock("execa", () => ({
99
- execaSync: vi.fn(() => ({ stdout: "v20.11.0" })),
100
- }));
101
104
 
102
105
  // Mock lockfile content for resolveLockedVersion
103
106
  let mockLockfileContent = "";