@simplysm/sd-cli 14.0.46 → 14.0.48

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 (134) hide show
  1. package/README.md +782 -0
  2. package/dist/angular/ngtsc-build-core.js +2 -2
  3. package/dist/angular/ngtsc-build-core.js.map +1 -1
  4. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  5. package/dist/angular/vite-angular-plugin.js +3 -2
  6. package/dist/angular/vite-angular-plugin.js.map +1 -1
  7. package/dist/capacitor/capacitor-android.js +2 -2
  8. package/dist/capacitor/capacitor-android.js.map +1 -1
  9. package/dist/capacitor/capacitor-build.d.ts.map +1 -1
  10. package/dist/capacitor/capacitor-build.js +2 -1
  11. package/dist/capacitor/capacitor-build.js.map +1 -1
  12. package/dist/capacitor/capacitor-icon.d.ts.map +1 -1
  13. package/dist/capacitor/capacitor-icon.js +2 -1
  14. package/dist/capacitor/capacitor-icon.js.map +1 -1
  15. package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
  16. package/dist/capacitor/capacitor-npm-config.js +2 -1
  17. package/dist/capacitor/capacitor-npm-config.js.map +1 -1
  18. package/dist/capacitor/capacitor.d.ts.map +1 -1
  19. package/dist/capacitor/capacitor.js +2 -1
  20. package/dist/capacitor/capacitor.js.map +1 -1
  21. package/dist/commands/device.js +2 -2
  22. package/dist/commands/device.js.map +1 -1
  23. package/dist/commands/publish/git-phase.js +1 -1
  24. package/dist/commands/publish/git-phase.js.map +1 -1
  25. package/dist/commands/replace-deps.js +2 -2
  26. package/dist/commands/replace-deps.js.map +1 -1
  27. package/dist/deps/replace-deps/collect-deps.js +2 -2
  28. package/dist/deps/replace-deps/collect-deps.js.map +1 -1
  29. package/dist/deps/replace-deps/replace-deps.d.ts.map +1 -1
  30. package/dist/deps/replace-deps/replace-deps.js +108 -81
  31. package/dist/deps/replace-deps/replace-deps.js.map +1 -1
  32. package/dist/deps/server-externals/server-production-files.js +2 -2
  33. package/dist/deps/server-externals/server-production-files.js.map +1 -1
  34. package/dist/electron/electron.d.ts.map +1 -1
  35. package/dist/electron/electron.js +2 -1
  36. package/dist/electron/electron.js.map +1 -1
  37. package/dist/engines/BaseEngine.d.ts.map +1 -1
  38. package/dist/engines/BaseEngine.js +2 -2
  39. package/dist/engines/BaseEngine.js.map +1 -1
  40. package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
  41. package/dist/engines/EsbuildClientEngine.js +2 -2
  42. package/dist/engines/EsbuildClientEngine.js.map +1 -1
  43. package/dist/engines/NgtscEngine.js +2 -2
  44. package/dist/engines/NgtscEngine.js.map +1 -1
  45. package/dist/engines/ServerEsbuildEngine.js +2 -2
  46. package/dist/engines/ServerEsbuildEngine.js.map +1 -1
  47. package/dist/engines/TscEngine.js +2 -2
  48. package/dist/engines/TscEngine.js.map +1 -1
  49. package/dist/engines/engine-factory.d.ts.map +1 -1
  50. package/dist/engines/engine-factory.js +2 -2
  51. package/dist/engines/engine-factory.js.map +1 -1
  52. package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -1
  53. package/dist/esbuild/esbuild-angular-compiler-plugin.js +52 -20
  54. package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -1
  55. package/dist/esbuild/esbuild-config.js +2 -2
  56. package/dist/esbuild/esbuild-config.js.map +1 -1
  57. package/dist/esbuild/esbuild-worker-plugin.d.ts +14 -2
  58. package/dist/esbuild/esbuild-worker-plugin.d.ts.map +1 -1
  59. package/dist/esbuild/esbuild-worker-plugin.js +13 -5
  60. package/dist/esbuild/esbuild-worker-plugin.js.map +1 -1
  61. package/dist/lint/lint-with-program.js +2 -2
  62. package/dist/lint/lint-with-program.js.map +1 -1
  63. package/dist/runtime/lazy-logger.d.ts +14 -0
  64. package/dist/runtime/lazy-logger.d.ts.map +1 -0
  65. package/dist/runtime/lazy-logger.js +23 -0
  66. package/dist/runtime/lazy-logger.js.map +1 -0
  67. package/dist/sd-cli-entry.js +2 -2
  68. package/dist/sd-cli-entry.js.map +1 -1
  69. package/dist/sd-cli.js +2 -2
  70. package/dist/sd-cli.js.map +1 -1
  71. package/dist/ts-compiler/SdTsCompiler.d.ts +11 -0
  72. package/dist/ts-compiler/SdTsCompiler.d.ts.map +1 -1
  73. package/dist/ts-compiler/SdTsCompiler.js +223 -116
  74. package/dist/ts-compiler/SdTsCompiler.js.map +1 -1
  75. package/dist/typecheck/typecheck-non-package.js +2 -2
  76. package/dist/typecheck/typecheck-non-package.js.map +1 -1
  77. package/dist/typecheck/typecheck-serialization.d.ts +31 -9
  78. package/dist/typecheck/typecheck-serialization.d.ts.map +1 -1
  79. package/dist/typecheck/typecheck-serialization.js +62 -22
  80. package/dist/typecheck/typecheck-serialization.js.map +1 -1
  81. package/dist/utils/output-utils.js +2 -2
  82. package/dist/utils/output-utils.js.map +1 -1
  83. package/dist/utils/package-classify.js +2 -2
  84. package/dist/utils/package-classify.js.map +1 -1
  85. package/dist/utils/package-utils.js +2 -2
  86. package/dist/utils/package-utils.js.map +1 -1
  87. package/dist/utils/sd-config.js +2 -2
  88. package/dist/utils/sd-config.js.map +1 -1
  89. package/dist/utils/tsconfig.d.ts.map +1 -1
  90. package/dist/utils/tsconfig.js +3 -5
  91. package/dist/utils/tsconfig.js.map +1 -1
  92. package/package.json +8 -8
  93. package/src/angular/ngtsc-build-core.ts +3 -3
  94. package/src/angular/vite-angular-plugin.ts +3 -2
  95. package/src/capacitor/capacitor-android.ts +2 -2
  96. package/src/capacitor/capacitor-build.ts +2 -1
  97. package/src/capacitor/capacitor-icon.ts +2 -1
  98. package/src/capacitor/capacitor-npm-config.ts +2 -1
  99. package/src/capacitor/capacitor.ts +2 -1
  100. package/src/commands/device.ts +2 -2
  101. package/src/commands/publish/git-phase.ts +1 -1
  102. package/src/commands/replace-deps.ts +2 -2
  103. package/src/deps/replace-deps/collect-deps.ts +2 -2
  104. package/src/deps/replace-deps/replace-deps.ts +119 -85
  105. package/src/deps/server-externals/server-production-files.ts +2 -2
  106. package/src/electron/electron.ts +2 -1
  107. package/src/engines/BaseEngine.ts +2 -2
  108. package/src/engines/EsbuildClientEngine.ts +2 -2
  109. package/src/engines/NgtscEngine.ts +2 -2
  110. package/src/engines/ServerEsbuildEngine.ts +2 -2
  111. package/src/engines/TscEngine.ts +2 -2
  112. package/src/engines/engine-factory.ts +2 -2
  113. package/src/esbuild/esbuild-angular-compiler-plugin.ts +66 -21
  114. package/src/esbuild/esbuild-config.ts +2 -2
  115. package/src/esbuild/esbuild-worker-plugin.ts +24 -4
  116. package/src/lint/lint-with-program.ts +2 -2
  117. package/src/runtime/lazy-logger.ts +23 -0
  118. package/src/sd-cli-entry.ts +2 -2
  119. package/src/sd-cli.ts +2 -2
  120. package/src/ts-compiler/SdTsCompiler.ts +280 -138
  121. package/src/typecheck/typecheck-non-package.ts +2 -2
  122. package/src/typecheck/typecheck-serialization.ts +100 -26
  123. package/src/utils/output-utils.ts +2 -2
  124. package/src/utils/package-classify.ts +2 -2
  125. package/src/utils/package-utils.ts +2 -2
  126. package/src/utils/sd-config.ts +2 -2
  127. package/src/utils/tsconfig.ts +3 -4
  128. package/tests/esbuild/esbuild-worker-plugin.spec.ts +245 -0
  129. package/tests/utils/replace-deps-watch.acc.spec.ts +85 -0
  130. package/tests/utils/replace-deps-watch.spec.ts +198 -1
  131. package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.d.ts +0 -3
  132. package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.d.ts.map +0 -1
  133. package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.js +0 -9
  134. package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.js.map +0 -1
@@ -1,7 +1,8 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
4
  import os from "os";
5
+ import { consola } from "consola";
5
6
  import { watchReplaceDeps } from "../../src/deps/replace-deps/replace-deps";
6
7
  import type { WatchReplaceDepResult } from "../../src/deps/replace-deps/replace-deps";
7
8
 
@@ -12,10 +13,28 @@ import type { WatchReplaceDepResult } from "../../src/deps/replace-deps/replace-
12
13
  describe("watchReplaceDeps onChanged", () => {
13
14
  let tmpDir: string;
14
15
  let watchResult: WatchReplaceDepResult | undefined;
16
+ let mockLogger: {
17
+ warn: ReturnType<typeof vi.fn>;
18
+ error: ReturnType<typeof vi.fn>;
19
+ info: ReturnType<typeof vi.fn>;
20
+ start: ReturnType<typeof vi.fn>;
21
+ success: ReturnType<typeof vi.fn>;
22
+ debug: ReturnType<typeof vi.fn>;
23
+ };
15
24
 
16
25
  beforeEach(async () => {
17
26
  tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "sd-replace-deps-unit-"));
18
27
 
28
+ mockLogger = {
29
+ warn: vi.fn(),
30
+ error: vi.fn(),
31
+ info: vi.fn(),
32
+ start: vi.fn(),
33
+ success: vi.fn(),
34
+ debug: vi.fn(),
35
+ };
36
+ vi.spyOn(consola, "withTag").mockReturnValue(mockLogger as any);
37
+
19
38
  // 소스 패키지 생성
20
39
  const sourcePkg = path.join(tmpDir, "source-pkg");
21
40
  await fs.promises.mkdir(sourcePkg, { recursive: true });
@@ -43,6 +62,7 @@ describe("watchReplaceDeps onChanged", () => {
43
62
  watchResult?.dispose();
44
63
  watchResult = undefined;
45
64
  await fs.promises.rm(tmpDir, { recursive: true, force: true });
65
+ vi.restoreAllMocks();
46
66
  });
47
67
 
48
68
  it("복수 파일 변경 시 300ms 배칭 후 onChanged가 한 번 호출된다", async () => {
@@ -131,6 +151,58 @@ describe("watchReplaceDeps onChanged", () => {
131
151
  await changedPromise;
132
152
  }, 10_000);
133
153
 
154
+ it("nested source 경로는 longest-prefix로 소속이 결정된다", async () => {
155
+ // sourceOuter: tmpDir/outer-pkg
156
+ // sourceInner: tmpDir/outer-pkg/inner-pkg (outer의 하위)
157
+ const outerPkg = path.join(tmpDir, "outer-pkg");
158
+ await fs.promises.mkdir(path.join(outerPkg, "src"), { recursive: true });
159
+ await fs.promises.writeFile(
160
+ path.join(outerPkg, "package.json"),
161
+ JSON.stringify({ name: "@test/outer", files: ["src"] }),
162
+ );
163
+ await fs.promises.writeFile(path.join(outerPkg, "src", "o.ts"), "o");
164
+
165
+ const innerPkg = path.join(outerPkg, "inner-pkg");
166
+ await fs.promises.mkdir(path.join(innerPkg, "src"), { recursive: true });
167
+ await fs.promises.writeFile(
168
+ path.join(innerPkg, "package.json"),
169
+ JSON.stringify({ name: "@test/inner", files: ["src"] }),
170
+ );
171
+ await fs.promises.writeFile(path.join(innerPkg, "src", "i.ts"), "i");
172
+
173
+ // target들
174
+ const outerTarget = path.join(
175
+ tmpDir, "project", "node_modules", "@test", "outer", "src",
176
+ );
177
+ const innerTarget = path.join(
178
+ tmpDir, "project", "node_modules", "@test", "inner", "src",
179
+ );
180
+ await fs.promises.mkdir(outerTarget, { recursive: true });
181
+ await fs.promises.mkdir(innerTarget, { recursive: true });
182
+ await fs.promises.writeFile(path.join(outerTarget, "o.ts"), "o");
183
+ await fs.promises.writeFile(path.join(innerTarget, "i.ts"), "i");
184
+
185
+ const projectRoot = path.join(tmpDir, "project");
186
+
187
+ watchResult = await watchReplaceDeps(
188
+ projectRoot,
189
+ { "@test/outer": outerPkg, "@test/inner": innerPkg },
190
+ );
191
+
192
+ // inner 파일 변경 — longest-prefix로 inner source에만 매칭되어야 함
193
+ await fs.promises.writeFile(path.join(innerPkg, "src", "i.ts"), "i2");
194
+ await new Promise((r) => setTimeout(r, 1500));
195
+
196
+ const innerCopied = await fs.promises.readFile(path.join(innerTarget, "i.ts"), "utf-8");
197
+ expect(innerCopied).toBe("i2");
198
+
199
+ // outer target에는 i.ts가 복사되지 않아야 함 (잘못된 매칭 방지)
200
+ const outerHasI = await fs.promises
201
+ .access(path.join(outerTarget, "inner-pkg", "src", "i.ts"))
202
+ .then(() => true, () => false);
203
+ expect(outerHasI).toBe(false);
204
+ }, 10_000);
205
+
134
206
  it("options 파라미터가 undefined일 때 에러가 발생하지 않는다", async () => {
135
207
  const projectRoot = path.join(tmpDir, "project");
136
208
  const sourcePath = path.join(tmpDir, "source-pkg");
@@ -144,4 +216,129 @@ describe("watchReplaceDeps onChanged", () => {
144
216
  await new Promise((r) => setTimeout(r, 1500));
145
217
  // 에러 없이 완료됨
146
218
  }, 10_000);
219
+
220
+ it("source의 files 필드가 없으면 경고를 출력하고 감시에서 제외한다", async () => {
221
+ const projectRoot = path.join(tmpDir, "project");
222
+ const sourcePath = path.join(tmpDir, "source-pkg");
223
+
224
+ // files 필드 제거
225
+ await fs.promises.writeFile(
226
+ path.join(sourcePath, "package.json"),
227
+ JSON.stringify({ name: "@test/pkg" }),
228
+ );
229
+
230
+ let callCount = 0;
231
+ watchResult = await watchReplaceDeps(projectRoot, { "@test/pkg": sourcePath }, {
232
+ onChanged: () => {
233
+ callCount++;
234
+ },
235
+ });
236
+
237
+ expect(mockLogger.warn).toHaveBeenCalledWith(
238
+ expect.stringContaining("package.json에 files 필드가 없어 감시 건너뜀"),
239
+ );
240
+
241
+ // 파일을 변경해도 감지되지 않음
242
+ await fs.promises.writeFile(
243
+ path.join(sourcePath, "src", "index.ts"),
244
+ "export const v = 2;",
245
+ );
246
+ await new Promise((r) => setTimeout(r, 1500));
247
+
248
+ expect(callCount).toBe(0);
249
+ }, 10_000);
250
+
251
+ it("동일 내용 재저장 시 isFileContentSame 스킵으로 onChanged가 호출되지 않는다", async () => {
252
+ const projectRoot = path.join(tmpDir, "project");
253
+ const sourcePath = path.join(tmpDir, "source-pkg");
254
+
255
+ // beforeEach에서 source와 target 모두 "export const v = 1;"로 설정된 상태
256
+ let callCount = 0;
257
+ watchResult = await watchReplaceDeps(projectRoot, { "@test/pkg": sourcePath }, {
258
+ onChanged: () => {
259
+ callCount++;
260
+ },
261
+ });
262
+
263
+ // 동일 내용으로 재저장 (mtime은 변경되지만 내용은 같음)
264
+ await fs.promises.writeFile(
265
+ path.join(sourcePath, "src", "index.ts"),
266
+ "export const v = 1;",
267
+ );
268
+
269
+ await new Promise((r) => setTimeout(r, 1500));
270
+
271
+ // isFileContentSame이 true를 반환하여 복사 스킵 → hasActualCopy=false → onChanged 미호출
272
+ expect(callCount).toBe(0);
273
+ }, 10_000);
274
+
275
+ it("dispose 이후의 파일 변경은 감지되지 않는다", async () => {
276
+ const projectRoot = path.join(tmpDir, "project");
277
+ const sourcePath = path.join(tmpDir, "source-pkg");
278
+
279
+ let callCount = 0;
280
+ const result = await watchReplaceDeps(projectRoot, { "@test/pkg": sourcePath }, {
281
+ onChanged: () => {
282
+ callCount++;
283
+ },
284
+ });
285
+
286
+ result.dispose();
287
+ // afterEach에서 중복 dispose 방지
288
+ watchResult = undefined;
289
+
290
+ // close 완료 대기
291
+ await new Promise((r) => setTimeout(r, 500));
292
+
293
+ await fs.promises.writeFile(
294
+ path.join(sourcePath, "src", "index.ts"),
295
+ "export const v = 99;",
296
+ );
297
+
298
+ await new Promise((r) => setTimeout(r, 1500));
299
+
300
+ expect(callCount).toBe(0);
301
+ }, 10_000);
302
+
303
+ it("모든 source의 files 필드가 없으면 감시 대상이 없음 경고를 출력한다", async () => {
304
+ const projectRoot = path.join(tmpDir, "project");
305
+ const sourcePath = path.join(tmpDir, "source-pkg");
306
+
307
+ // files 필드 제거
308
+ await fs.promises.writeFile(
309
+ path.join(sourcePath, "package.json"),
310
+ JSON.stringify({ name: "@test/pkg" }),
311
+ );
312
+
313
+ watchResult = await watchReplaceDeps(projectRoot, { "@test/pkg": sourcePath });
314
+
315
+ expect(mockLogger.warn).toHaveBeenCalledWith(
316
+ expect.stringContaining("감시 대상이 없어 워치가 시작되지 않음"),
317
+ );
318
+ }, 10_000);
319
+
320
+ it("files 필드가 없으면 해당 source에 대한 readdir이 호출되지 않는다", async () => {
321
+ const projectRoot = path.join(tmpDir, "project");
322
+ const sourcePath = path.join(tmpDir, "source-pkg");
323
+
324
+ // files 필드 제거
325
+ await fs.promises.writeFile(
326
+ path.join(sourcePath, "package.json"),
327
+ JSON.stringify({ name: "@test/pkg" }),
328
+ );
329
+
330
+ const readdirSpy = vi.spyOn(fs.promises, "readdir");
331
+
332
+ watchResult = await watchReplaceDeps(projectRoot, { "@test/pkg": sourcePath });
333
+
334
+ // sourcePath에 대한 readdir 호출이 없어야 함 (files null이면 생략되어야 함)
335
+ const sourcePathPosix = path.resolve(sourcePath).replace(/\\/g, "/");
336
+ const calledWithSource = readdirSpy.mock.calls.some((args) => {
337
+ const arg = args[0];
338
+ if (typeof arg !== "string") return false;
339
+ return arg.replace(/\\/g, "/") === sourcePathPosix;
340
+ });
341
+
342
+ expect(calledWithSource).toBe(false);
343
+ }, 10_000);
147
344
  });
@@ -1,3 +0,0 @@
1
- export declare class FixtureComponent {
2
- }
3
- //# sourceMappingURL=test.fixture.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test.fixture.d.ts","sourceRoot":"","sources":["../../../../../../../../tests/angular/fixtures/packages/basic-app/tests/test.fixture.ts"],"names":[],"mappings":"AAEA,qBAKa,gBAAgB;CAAG"}
@@ -1,9 +0,0 @@
1
- import { Component } from "@angular/core";
2
- @Component({
3
- selector: "app-fixture",
4
- standalone: true,
5
- template: `<span>fixture</span>`,
6
- })
7
- export class FixtureComponent {
8
- }
9
- //# sourceMappingURL=test.fixture.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test.fixture.js","sourceRoot":"","sources":["../../../../../../../../tests/angular/fixtures/packages/basic-app/tests/test.fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,CAAC,SAAS,CAAC;IACT,QAAQ,EAAE,aAAa;IACvB,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,sBAAsB;CACjC,CAAC;AACF,MAAM,OAAO,gBAAgB;CAAG"}