@simplysm/sd-cli 14.0.47 → 14.0.49
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.
- package/README.md +782 -0
- package/dist/angular/ngtsc-build-core.js +2 -2
- package/dist/angular/ngtsc-build-core.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +3 -2
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/capacitor/capacitor-android.js +2 -2
- package/dist/capacitor/capacitor-android.js.map +1 -1
- package/dist/capacitor/capacitor-build.d.ts.map +1 -1
- package/dist/capacitor/capacitor-build.js +2 -1
- package/dist/capacitor/capacitor-build.js.map +1 -1
- package/dist/capacitor/capacitor-icon.d.ts.map +1 -1
- package/dist/capacitor/capacitor-icon.js +2 -1
- package/dist/capacitor/capacitor-icon.js.map +1 -1
- package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
- package/dist/capacitor/capacitor-npm-config.js +2 -1
- package/dist/capacitor/capacitor-npm-config.js.map +1 -1
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +2 -1
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/device.js +2 -2
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/replace-deps.js +2 -2
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/deps/replace-deps/collect-deps.js +2 -2
- package/dist/deps/replace-deps/collect-deps.js.map +1 -1
- package/dist/deps/replace-deps/replace-deps.d.ts.map +1 -1
- package/dist/deps/replace-deps/replace-deps.js +108 -81
- package/dist/deps/replace-deps/replace-deps.js.map +1 -1
- package/dist/deps/server-externals/server-production-files.js +2 -2
- package/dist/deps/server-externals/server-production-files.js.map +1 -1
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +2 -1
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +2 -2
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
- package/dist/engines/EsbuildClientEngine.js +2 -2
- package/dist/engines/EsbuildClientEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.js +2 -2
- package/dist/engines/NgtscEngine.js.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +2 -2
- package/dist/engines/ServerEsbuildEngine.js.map +1 -1
- package/dist/engines/TscEngine.js +2 -2
- package/dist/engines/TscEngine.js.map +1 -1
- package/dist/engines/engine-factory.d.ts.map +1 -1
- package/dist/engines/engine-factory.js +2 -2
- package/dist/engines/engine-factory.js.map +1 -1
- package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -1
- package/dist/esbuild/esbuild-angular-compiler-plugin.js +46 -18
- package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -1
- package/dist/esbuild/esbuild-config.js +2 -2
- package/dist/esbuild/esbuild-config.js.map +1 -1
- package/dist/lint/lint-with-program.js +2 -2
- package/dist/lint/lint-with-program.js.map +1 -1
- package/dist/runtime/lazy-logger.d.ts +14 -0
- package/dist/runtime/lazy-logger.d.ts.map +1 -0
- package/dist/runtime/lazy-logger.js +23 -0
- package/dist/runtime/lazy-logger.js.map +1 -0
- package/dist/sd-cli-entry.js +2 -2
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +2 -2
- package/dist/sd-cli.js.map +1 -1
- package/dist/ts-compiler/SdTsCompiler.d.ts +11 -0
- package/dist/ts-compiler/SdTsCompiler.d.ts.map +1 -1
- package/dist/ts-compiler/SdTsCompiler.js +223 -116
- package/dist/ts-compiler/SdTsCompiler.js.map +1 -1
- package/dist/typecheck/typecheck-non-package.js +2 -2
- package/dist/typecheck/typecheck-non-package.js.map +1 -1
- package/dist/typecheck/typecheck-serialization.d.ts +31 -9
- package/dist/typecheck/typecheck-serialization.d.ts.map +1 -1
- package/dist/typecheck/typecheck-serialization.js +62 -22
- package/dist/typecheck/typecheck-serialization.js.map +1 -1
- package/dist/utils/output-utils.js +2 -2
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/utils/package-classify.js +2 -2
- package/dist/utils/package-classify.js.map +1 -1
- package/dist/utils/package-utils.js +2 -2
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/sd-config.js +2 -2
- package/dist/utils/sd-config.js.map +1 -1
- package/dist/utils/tsconfig.d.ts.map +1 -1
- package/dist/utils/tsconfig.js +3 -5
- package/dist/utils/tsconfig.js.map +1 -1
- package/package.json +5 -5
- package/src/angular/ngtsc-build-core.ts +3 -3
- package/src/angular/vite-angular-plugin.ts +3 -2
- package/src/capacitor/capacitor-android.ts +2 -2
- package/src/capacitor/capacitor-build.ts +2 -1
- package/src/capacitor/capacitor-icon.ts +2 -1
- package/src/capacitor/capacitor-npm-config.ts +2 -1
- package/src/capacitor/capacitor.ts +2 -1
- package/src/commands/device.ts +2 -2
- package/src/commands/replace-deps.ts +2 -2
- package/src/deps/replace-deps/collect-deps.ts +2 -2
- package/src/deps/replace-deps/replace-deps.ts +119 -85
- package/src/deps/server-externals/server-production-files.ts +2 -2
- package/src/electron/electron.ts +2 -1
- package/src/engines/BaseEngine.ts +2 -2
- package/src/engines/EsbuildClientEngine.ts +2 -2
- package/src/engines/NgtscEngine.ts +2 -2
- package/src/engines/ServerEsbuildEngine.ts +2 -2
- package/src/engines/TscEngine.ts +2 -2
- package/src/engines/engine-factory.ts +2 -2
- package/src/esbuild/esbuild-angular-compiler-plugin.ts +60 -19
- package/src/esbuild/esbuild-config.ts +2 -2
- package/src/lint/lint-with-program.ts +2 -2
- package/src/runtime/lazy-logger.ts +23 -0
- package/src/sd-cli-entry.ts +2 -2
- package/src/sd-cli.ts +2 -2
- package/src/ts-compiler/SdTsCompiler.ts +280 -138
- package/src/typecheck/typecheck-non-package.ts +2 -2
- package/src/typecheck/typecheck-serialization.ts +100 -26
- package/src/utils/output-utils.ts +2 -2
- package/src/utils/package-classify.ts +2 -2
- package/src/utils/package-utils.ts +2 -2
- package/src/utils/sd-config.ts +2 -2
- package/src/utils/tsconfig.ts +3 -4
- package/tests/angular/angular-compiler-hmr-removal.verify.md +12 -12
- package/tests/angular/onbuild-lint-removal.verify.md +4 -4
- package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +9 -9
- package/tests/angular/vite-angular-plugin-vitest.verify.md +16 -16
- package/tests/capacitor/capacitor-android-exports.verify.md +7 -7
- package/tests/commands/publish-npm-local-split.verify.md +5 -5
- package/tests/commands/publish-responsibility-split.verify.md +9 -9
- package/tests/commands/publish-set.verify.md +3 -3
- package/tests/commands/publish-storage-split.verify.md +4 -4
- package/tests/commands/slice3-severity-cleanup.verify.md +8 -8
- package/tests/deps/deps-directory-separation.verify.md +11 -11
- package/tests/deps/replace-deps/replace-deps-perf.verify.md +6 -6
- package/tests/deps/server-externals/mise-toml-parse-intent.verify.md +8 -8
- package/tests/electron/electron-symlink-cleanup.verify.md +4 -4
- package/tests/engines/engine-duplicate-output-removal.verify.md +6 -6
- package/tests/engines/engine-typecheck-selection.verify.md +4 -4
- package/tests/engines/esbuild-client-engine.verify.md +11 -11
- package/tests/engines/normalize-result.verify.md +5 -5
- package/tests/engines/vite-dependency-cleanup.verify.md +11 -11
- package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +10 -10
- package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +17 -17
- package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +12 -12
- package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +11 -11
- package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +13 -13
- package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +32 -32
- package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +9 -9
- package/tests/esbuild/esbuild-postcss-plugin-chunking.verify.md +3 -3
- package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +9 -9
- package/tests/esbuild/esbuild-worker-plugin-node.verify.md +7 -7
- package/tests/esbuild/esbuild-worker-plugin.spec.ts +8 -0
- package/tests/esbuild/esbuild-worker-plugin.verify.md +3 -3
- package/tests/orchestrators/dist-delete-watcher.verify.md +6 -6
- package/tests/orchestrators/orchestrator-baseenv.verify.md +6 -6
- package/tests/orchestrators/orchestrator-diagnostic-formatting.verify.md +6 -6
- package/tests/orchestrators/orchestrator-initializemode-signature.verify.md +5 -5
- package/tests/orchestrators/slice1-stdout-to-consola.verify.md +6 -6
- package/tests/sd-cli-catch-all.verify.md +3 -3
- package/tests/sd-cli-log-tag.verify.md +7 -7
- package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +4 -4
- package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +8 -8
- package/tests/ts-compiler/SdTsCompiler-emit.verify.md +5 -5
- package/tests/ts-compiler/SdTsCompiler.verify.md +20 -20
- package/tests/ts-compiler/scss-lint-integration.verify.md +10 -10
- package/tests/utils/copy-public-outdir.verify.md +4 -4
- package/tests/utils/dev-http-server.verify.md +4 -4
- package/tests/utils/engine-watch-events.verify.md +8 -8
- package/tests/utils/esbuild-client-config-integration.verify.md +5 -5
- package/tests/utils/esbuild-client-config-postcss.verify.md +2 -2
- package/tests/utils/esbuild-client-config.verify.md +16 -16
- package/tests/utils/esbuild-index-html.verify.md +6 -6
- package/tests/utils/esbuild-pwa.verify.md +5 -5
- package/tests/utils/esbuild-scss-plugin.verify.md +4 -4
- package/tests/utils/hmr-service.verify.md +10 -10
- package/tests/utils/lint-core-import-paths.verify.md +6 -6
- package/tests/utils/replace-deps-split.verify.md +11 -11
- package/tests/utils/replace-deps-watch.acc.spec.ts +85 -0
- package/tests/utils/replace-deps-watch.spec.ts +198 -1
- package/tests/utils/replace-deps-watch.verify.md +5 -5
- package/tests/utils/server-production-files-import-paths.verify.md +10 -10
- package/tests/utils/vite-config-cleanup.verify.md +3 -3
- package/tests/workers/build-watch-paths-library.verify.md +6 -6
- package/tests/workers/build-watch-paths-ngtsc-server.verify.md +8 -8
- package/tests/workers/client-worker-browser-support.verify.md +3 -3
- package/tests/workers/client-worker-cleanup.verify.md +4 -4
- package/tests/workers/client-worker-initial-build-error.verify.md +3 -3
- package/tests/workers/client-worker-initial-build-warnings.verify.md +3 -3
- package/tests/workers/client-worker-mtime-incremental.verify.md +6 -6
- package/tests/workers/client-worker-onend-sync.verify.md +3 -3
- package/tests/workers/client-worker-refactor.verify.md +18 -18
- package/tests/workers/client-worker-ts-cache-invalidation.verify.md +8 -8
- package/tests/workers/dev-port-file.verify.md +3 -3
- package/tests/workers/ngtsc-build-rootnames-refresh.verify.md +4 -4
- package/tests/workers/server-build-context-dispose.verify.md +4 -4
- package/tests/workers/server-build-worker-plugin.verify.md +5 -5
- package/tests/workers/server-build-worker-refactoring.verify.md +10 -10
- package/tests/workers/server-esbuild-context-integration.verify.md +6 -6
- package/tests/workers/server-esbuild-context-tsc.verify.md +3 -3
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.d.ts +0 -3
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.d.ts.map +0 -1
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.js +0 -9
- 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
|
});
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
5
|
+
- watchReplaceDeps 시그니처에 optional `options` 파라미터가 추가되었는가: `replace-deps.ts:321`에 `options?: { onChanged?: () => void }` 확인
|
|
6
|
+
- onChanged 콜백이 파일 복사 루프 완료 후(for 루프 바깥) 호출되는가: `replace-deps.ts:393`에서 for 루프(346-392) 완료 후 `options?.onChanged?.()` 호출 확인
|
|
7
|
+
- 기존 watchReplaceDeps 호출자가 새 시그니처와 호환되는가: `DevWatchOrchestrator.ts:121`에서 2개 인자로 호출 — 3번째 optional 파라미터 생략으로 호환
|
|
8
|
+
- esbuild onEnd 플러그인(esbuild-client-config.ts)이 빌드 결과를 외부로 전달하는 경로가 존재하는가: `esbuild-client-config.ts:215-218`에 `sd-on-end` 플러그인이 `options.onEnd(result)` 호출
|
|
9
|
+
- hmrService.onBuildEnd()가 metafile 기반으로 HMR 메시지를 디스패치하는 경로가 존재하는가: `hmr-service.ts:49-133`에 metafile 기반 변경 판별 → WS broadcast 로직 존재
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
5
|
+
- 4개 함수가 utils/server-production-files.ts에 export되어 있다: line 14, 27, 68, 87에 각각 export function 확인
|
|
6
|
+
- worker에서 4개 함수 정의가 제거되었다: worker에 함수 정의 없음, import와 호출만 존재
|
|
7
|
+
- worker에서 collectAllExternals, generateProductionFiles를 새 모듈에서 import한다: line 19 `import { collectAllExternals, generateProductionFiles } from "../utils/server-production-files"`
|
|
8
|
+
- collectAllExternals 시그니처: `(pkgDir: string, manualExternals?: string[]) => string[]` — line 14 확인
|
|
9
|
+
- parseLockfileVersions 시그니처: `(cwd: string) => Map<string, string>` — line 27 확인
|
|
10
|
+
- resolveLockedVersions 시그니처: `(cwd: string, pkgNames: string[]) => Record<string, string>` — line 68 확인
|
|
11
|
+
- generateProductionFiles 시그니처: `(info: ServerBuildInfo, externals: string[]) => void` — line 87 확인
|
|
12
|
+
- worker에 build, rebuildAll, startWatch, stopWatch, cleanup, createEsbuildWatchContext가 존재한다: line 116, 148, 259, 336, 359, 488 확인
|
|
13
|
+
- worker에서 cpx import가 제거되었다: grep 결과 매칭 없음
|
|
14
|
+
- worker에서 collectAllDependencyExternals import가 제거되었다: grep 결과 매칭 없음
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- enableLint 옵션 제거: `CreateClientViteConfigOptions` 인터페이스에서 `enableLint` 필드가 완전히 제거됨. `vite-config.ts` 전체에서 `enableLint` 문자열 검색 결과 0건.
|
|
6
|
+
- replaceDepDistPaths 계산 제거: `vite-config.ts` 전체에서 `replaceDepDistPaths` 문자열 검색 결과 0건. 기존 line 98-114의 계산 로직(fs.realpathSync, pathx.posix 사용)이 완전히 제거됨. `fs`와 `pathx` import도 함께 제거됨.
|
|
7
|
+
- tsconfigPath, browserslist, postCssPlugins, legacyModule은 인터페이스 옵션이 아닌 함수 내부 로컬 변수로만 존재: 모두 `loadSdConfig()` 결과에서 추출하거나 `pkgDir`에서 derive됨.
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
5
|
+
- buildWatchPaths 호출 인자가 기존 코드와 동등: `srcGlobs: ["*.ts"]`, `replaceDeps: info.replaceDeps` — 기존 `pathx.posixResolve(info.pkgDir, "src", "**", "*.ts")` 패턴과 동일한 경로 생성 확인
|
|
6
|
+
- workspace deps 경로 생성이 동일: 기존 `workspaceDeps.map((d) => pathx.posixResolve(info.cwd, "packages", d, "src", "**", "*.ts"))` → buildWatchPaths 내부에서 동일하게 `pathx.posixResolve(cwd, "packages", d)` + `src/**/*.ts` 생성
|
|
7
|
+
- replaceDeps dist 경로가 cwd와 pkgDir 양쪽에서 생성됨: buildWatchPaths 내부에서 `pathx.posixResolve(cwd, "node_modules", ...pkg.split("/"), "dist", "**", "*.{js,mjs,cjs}")` 및 pkgDir 경로 동일하게 생성
|
|
8
|
+
- collectDeps import 제거됨: library-build.worker.ts에서 collectDeps가 더 이상 직접 import되지 않음 — buildWatchPaths가 내부에서 호출
|
|
9
|
+
- 변경 필터링 동작 동일: 기존 `hasFileAddOrRemove` 인라인 로직 + `lastSourceFilePaths` 교차가 `shouldSkipRebuild(changes.map(c => c.path), hasFileAddOrRemove(changes), lastSourceFilePaths, logger)`로 동일하게 대체됨
|
|
10
|
+
- 기존 테스트(library-build-worker.spec.ts) 16건 모두 통과 확인
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
5
|
+
- ngtsc-build watchPaths 동일성: `srcGlobs: ["*.{ts,scss,css}"]`, `extraDirs: [{ dir: "scss", globs: ["*.{scss,css}"] }]` — 기존 코드의 `src/**/*.{ts,scss,css}` + `scss/**/*.{scss,css}` + deps 동일 패턴과 매칭 확인
|
|
6
|
+
- ngtsc-build SCSS 역방향 탐색 유지: `hasFileAddOrRemove` → `hasFileAddOrRemoveFn`으로 변경 후에도 `modifiedFiles` 구성 로직(pipeline.findAffectedByScss)이 그대로 유지됨
|
|
7
|
+
- ngtsc-build `shouldSkipRebuild(modifiedFiles, addOrRemove, ...)`: SCSS 역방향 탐색 결과가 포함된 `modifiedFiles` Set을 Iterable로 전달하여 정확한 필터링 수행
|
|
8
|
+
- server-build watchPaths 동일성: `srcGlobs: ["*"]` — 기존 `src/**/*` 패턴과 동일
|
|
9
|
+
- server-build metafile 기반 필터링 유지: `hasFileAddOrRemoveFn(changes)` → `addOrRemove` 변수명으로 변경 외에 metafile 기반 로직(L444-470) 무변경
|
|
10
|
+
- server-build esbuild context 재생성 로직 유지: `if (addOrRemove)` 블록 내 context 재생성 로직이 기존과 동일
|
|
11
|
+
- collectDeps import 제거: ngtsc-build, server-build 모두에서 collectDeps 직접 import 제거됨 — buildWatchPaths가 내부에서 호출
|
|
12
|
+
- 기존 테스트 94건 모두 통과 확인
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- loadSdConfig import 제거: `client.worker.ts` — `import { loadSdConfig }` 라인이 제거됨. `sd-config` 모듈 import 없음
|
|
6
|
+
- resolvePackageInfo가 동기 함수: `client.worker.ts:73` — `function resolvePackageInfo(info: ClientBuildInfo): {` (async 제거, Promise 반환 없음)
|
|
7
|
+
- resolvePackageInfo가 info.browserSupport 사용: `client.worker.ts:83-86` — `info.browserSupport?.legacyModule`, `info.browserSupport?.browserslist`, `info.browserSupport?.postCss?.plugins`
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
5
|
+
- resolvePackageInfo에서 tsconfigPath 반환 제거: 반환 타입이 `{ pkgName: string }`으로 변경됨. 함수 내부에서 `tsconfigPath` 변수 선언 및 계산이 제거됨. 모든 호출부(startWatch:199, startLegacyWatch:266, build:396)에서 `{ pkgName }`으로만 구조분해.
|
|
6
|
+
- startWatch에서 제거된 옵션 미전달: `createClientViteConfig` 호출에서 `tsconfigPath`, `browserslist`, `postCssPlugins`, `legacyModule`, `enableLint` 모두 제거됨.
|
|
7
|
+
- startLegacyWatch에서 제거된 옵션 미전달: 동일하게 5개 옵션 모두 제거됨.
|
|
8
|
+
- build에서 제거된 옵션 미전달: 동일하게 5개 옵션 모두 제거됨.
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- client.worker.ts onEnd에서 초기 빌드 시 errors 필드가 포함되는지: `client.worker.ts:285-291` — `initialBuildResolve`에 `errors: result.errors.map((e) => e.text)` 포함 확인
|
|
6
|
+
- EsbuildClientEngine.startWatch에서 반환값의 success 확인 후 ResultCollector에 보고하는지: `EsbuildClientEngine.ts:129-138` — `!result.success` 조건으로 `resultCollector.add()` 호출 확인. logger.error는 Feature 1.2에서 제거됨 (중복 출력 방지)
|
|
7
|
+
- esbuild-client-config.ts에서 logLevel이 "silent"인지: `esbuild-client-config.ts:191` — `logLevel: "silent"` 확인. Feature 1.2에서 dev/build 모두 "silent"로 통일됨
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- client.worker.ts의 initialBuildResolve에 warnings 필드가 포함되는지: `client.worker.ts:305-315` — `initialBuildResolve`에 `warnings: result.warnings.length > 0 ? result.warnings.map(formatEsbuildMessage) : undefined` 포함 확인. 후속 빌드(line 295-298)와 동일 패턴
|
|
6
|
+
- warnings가 없을 때 undefined인지: `client.worker.ts:312-314` — `result.warnings.length > 0` 조건으로 빈 배열일 때 undefined 반환 확인
|
|
7
|
+
- ClientBuildResult 인터페이스에 warnings 필드가 있는지: `client.worker.ts:47` — `warnings?: string[]` 확인. 변경 불필요
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
5
|
+
- createSourceFileCachePlugin이 IncrementalMtimeTracker를 사용하는지 확인: `client.worker.ts:198` — `const mtimeTracker = new IncrementalMtimeTracker();` 확인됨
|
|
6
|
+
- onStart에서 detectChanges 결과로 invalidate가 호출되는지 확인: `client.worker.ts:210-213` — `mtimeTracker.detectChanges(watchTargets)` 결과를 `sourceFileCache.invalidate(changedFiles)`에 전달. 기존 로직과 동작 동일
|
|
7
|
+
- onEnd에서 updateMtimes가 호출되는지 확인: `client.worker.ts:228` — `mtimeTracker.updateMtimes(watchTargets)` 호출 확인. `prevMtimes.clear()` + 전체 순회 제거됨
|
|
8
|
+
- esbuildResult == null 가드가 유지되는지 확인: onStart의 `if (esbuildResult != null)` (라인 202), onEnd의 `if (esbuildResult == null) return;` (라인 222) 모두 유지됨
|
|
9
|
+
- isInitialBuild 가드와 sender.send("buildStart")가 유지되는지 확인: `client.worker.ts:216-218` — `if (!isInitialBuild) { sender.send("buildStart", {}); }` 유지됨
|
|
10
|
+
- import 경로에 .js 확장자가 없는지 확인: `client.worker.ts:20` — `from "./incremental-mtime-tracker"` (확장자 없음)
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- onEnd 타입이 `void | Promise<void>`를 허용: `esbuild-client-config.ts:29` — `onEnd?: (result: esbuild.BuildResult) => void | Promise<void>;`
|
|
6
|
+
- sd-on-end 플러그인이 onEnd 반환값을 return: `esbuild-client-config.ts:220` — `return options.onEnd!(result);`
|
|
7
|
+
- client.worker.ts onEnd가 async 직접 전달 (fire-and-forget 제거): `client.worker.ts:240` — `onEnd: async (result: esbuild.BuildResult) => {` (이전의 `void (async () => { ... })()` 패턴 제거됨)
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
5
|
+
- createSourceFileCachePlugin이 모듈 스코프에 존재하고 esbuild.Plugin을 반환한다: lines 192-250, `function createSourceFileCachePlugin(): esbuild.Plugin` 반환 타입 명시, `name: "sd-build-start"` 유지
|
|
6
|
+
- createDevBuildEndHandler가 모듈 스코프에 존재하고 onEnd 콜백을 반환한다: lines 255-322, 반환 타입 `(result: esbuild.BuildResult) => Promise<void>`
|
|
7
|
+
- startWatch에서 추출 함수를 호출한다: line 385 `plugins: [createSourceFileCachePlugin()]`, line 386 `onEnd: createDevBuildEndHandler(basePath, actualPort, outdir, entryNames, info.pkgDir)`
|
|
8
|
+
- 파일 변경 감지 로직이 동일하다: createSourceFileCachePlugin onStart (lines 198-230) — watchFiles + typeScriptFileCache 순회, mtime 비교, invalidate 호출, buildStart 이벤트 전송 모두 원본과 동일
|
|
9
|
+
- mtime 기록 로직이 동일하다: createSourceFileCachePlugin onEnd (lines 232-247) — prevMtimes.clear() + mtime 기록 원본과 동일
|
|
10
|
+
- index.html 재생성 로직이 동일하다: createDevBuildEndHandler (lines 264-279) — lastMetafile 보관 + generateIndexHtml + writeFileSync 원본과 동일
|
|
11
|
+
- HMR 디스패치 로직이 동일하다: lines 281-284, `hmrService.onBuildEnd(result.metafile)` 조건부 호출 원본과 동일
|
|
12
|
+
- build 이벤트 전송 로직이 동일하다: lines 286-300, `sender.send("build", ...)` 조건부 호출 원본과 동일
|
|
13
|
+
- 초기 빌드 resolve 로직이 동일하다: lines 302-312, `isInitialBuild = false` + `initialBuildResolve?.()` 원본과 동일
|
|
14
|
+
- 에러 핸들링 로직이 동일하다: lines 313-320, catch 블록 원본과 동일
|
|
15
|
+
- 외부 인터페이스가 변경되지 않았다: export는 `export default sender`만 존재 (line 501), ClientBuildInfo/ClientBuildResult/ClientWorkerEvents 타입 변경 없음
|
|
16
|
+
- build 함수가 변경되지 않았다: lines 96-187, 원본과 동일
|
|
17
|
+
- stopWatch에 리셋 로직이 추가되었다: lines 472-475, `lastMetafile = undefined`, `isInitialBuild = true`, `initialBuildResolve = undefined`
|
|
18
|
+
- stopWatch 기존 정리 로직이 변경되지 않았다: lines 439-470, 5단계 정리(esbuild dispose, HMR 종료, HTTP 종료, public 감시 종료, index.html 감시 종료) 원본과 동일
|
|
19
|
+
- 모듈 스코프 변수가 올바르게 선언되었다: lines 67-69, 기존 변수(62-66) 바로 아래 배치
|
|
20
|
+
- startWatch가 ~110줄로 축소되었다: lines 327-434 = 107줄 (목표 ~110줄 달성)
|
|
21
|
+
- index.html watcher에서 lastMetafile 접근이 정상 동작한다: line 400, `if (lastMetafile == null) return;` — 모듈 스코프 변수로 접근
|
|
22
|
+
- 기존 테스트 6개 전부 통과: client-worker.spec.ts (3), client-worker.acc.spec.ts (3) — 회귀 없음
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
5
|
+
- onStart에서 `typeScriptFileCache.keys()`가 watchTargets에 포함: `client.worker.ts:266` — `...typeScriptFileCache.keys()`가 `watchTargets` 배열에 spread되어 포함됨
|
|
6
|
+
- onStart에서 `loadResultCache.watchFiles`도 여전히 watchTargets에 포함: `client.worker.ts:265` — `...loadResultCache.watchFiles`가 첫 번째로 spread됨 (기존 JS 동작 보존)
|
|
7
|
+
- onStart에서 watchTargets의 각 파일에 대해 mtime 비교 수행: `client.worker.ts:268-279` — `for (const file of watchTargets)` 루프에서 `fs.statSync(file).mtimeMs`와 `prevMtimes.get(file)` 비교
|
|
8
|
+
- 초기 빌드 직후 prevMtimes가 비어있으면 mtime 비교 스킵: `client.worker.ts:271-273` — `prev != null` 조건에 의해 `prevMtimes`에 없는 파일은 `changedFiles`에 추가되지 않음
|
|
9
|
+
- onEnd에서 `typeScriptFileCache.keys()`가 prevMtimes 기록 대상에 포함: `client.worker.ts:297` — `...esbuildResult.sourceFileCache.typeScriptFileCache.keys()`가 watchTargets에 spread됨
|
|
10
|
+
- onEnd에서 `loadResultCache.watchFiles`도 여전히 prevMtimes 기록 대상에 포함: `client.worker.ts:296` — `...esbuildResult.sourceFileCache.loadResultCache.watchFiles`가 첫 번째로 spread됨
|
|
11
|
+
- `typeScriptFileCache`가 `sourceFileCache`에서 destructuring으로 접근: `client.worker.ts:260` — `const { loadResultCache, typeScriptFileCache } = esbuildResult.sourceFileCache;` SourceFileCache의 public 속성 (`source-file-cache.js:52`)
|
|
12
|
+
- 삭제된 TS 파일에 대한 catch 처리: `client.worker.ts:275-279` — `catch` 블록에서 `prevMtimes.has(file)`인 경우 `changedFiles`에 추가 (기존 로직 동일)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 포트 파일 기록/삭제 — LLM 검증
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
|
-
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
4
|
+
- client.worker에서 dev 모드 serverReady 후 writeDevPort 호출: `client.worker.ts:250-253` — serverReady(248) 직후 `fs.writeFileSync(path.join(distDir, ".dev-port"), String(actualPort))` 확인
|
|
5
|
+
- client.worker에서 legacy 모드 serverReady 후 writeDevPort 호출: `client.worker.ts:331-332` — serverReady(329) 직후 `fs.writeFileSync(path.join(info.pkgDir, "dist", ".dev-port"), String(serverPort))` 확인
|
|
6
|
+
- ViteEngine.stop()에서 deleteDevPort 호출: `ViteEngine.ts:202-204` — `fs.unlinkSync(portFile)` with try-catch 확인
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
5
|
+
- onChange에서 addOrRemove === true일 때 parseTsconfig + getPackageSourceFiles + pipeline.updateRootNames 호출: `ngtsc-build.worker.ts:299-306` — `if (addOrRemove)` 블록 내에서 `parseTsconfig(watchInfo!.pkgDir)` → `getPackageSourceFiles()` 또는 `getPackageFiles()` → `pipeline.updateRootNames(newSourceFiles)` 호출 체인이 정확히 구현됨
|
|
6
|
+
- includeTests 분기가 초기 설정(line 233-235)과 동일 패턴: 초기 설정 `watchInfo.output.includeTests === true ? getPackageFiles(...) : getPackageSourceFiles(...)` (line 233-235)와 onChange 내 분기 `watchInfo!.output.includeTests === true ? getPackageFiles(...) : getPackageSourceFiles(...)` (line 302-304)가 동일한 패턴을 사용
|
|
7
|
+
- addOrRemove === false일 때 rootNames 미갱신: `if (addOrRemove)` 블록(line 300-306) 내부에서만 rootNames 재스캔이 수행되므로, addOrRemove가 false일 때는 `pipeline.updateRootNames()`가 호출되지 않음. `shouldSkipRebuild`(line 293)에서 `hasAddOrRemove`가 false이고 변경 파일이 lastSourceFilePaths에 있으면 정상적으로 `pipeline.update(modifiedFiles)`만 실행됨
|
|
8
|
+
- rootNames 재스캔이 shouldSkipRebuild 이후 + pipeline.update() 이전에 위치: line 293에서 shouldSkipRebuild 체크 → line 299에서 rootNames 재스캔 → line 310에서 pipeline.update(). 올바른 순서
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
5
|
+
- try-finally 패턴 적용: `server-build.worker.ts:434-442` — oldContext 캡처 후 try 블록에서 새 context 생성, finally에서 oldContext.dispose() 호출
|
|
6
|
+
- 성공 시 dispose: try 블록에서 새 context 생성 성공 → finally에서 oldContext.dispose() 실행
|
|
7
|
+
- 실패 시 dispose: createEsbuildWatchContext() 예외 시 → finally에서 oldContext.dispose() 실행 보장
|
|
8
|
+
- null 안전: `if (oldContext != null)` 가드로 oldContext가 없는 경우(output.js=false 등) 안전
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
5
|
+
- 프로덕션 빌드에 Worker 플러그인 포함: `server-build.worker.ts:169`에서 `plugins: [createWorkerBundlePlugin(), tscPlugin.plugin]`로 설정됨. Worker 플러그인이 tsc 플러그인보다 앞에 위치.
|
|
6
|
+
- Watch/dev 빌드에 Worker 플러그인 포함: `server-esbuild-context.ts:66-69`에서 `workerPlugin` 변수로 생성 후 tsc 유무에 따라 `[workerPlugin, tscPlugin.plugin]` 또는 `[workerPlugin]`으로 설정됨.
|
|
7
|
+
- Worker 패턴 없는 서버 코드 투명 통과: `esbuild-worker-plugin.ts:83-85`에서 `content.includes("Worker")`가 false면 즉시 `undefined` 반환. `esbuild-worker-plugin.ts:197`의 onLoad에서 `result == null`이면 `undefined` 반환하여 다음 핸들러에 위임.
|
|
8
|
+
- 기존 tsc 플러그인/external 처리 미변경: `createServerEsbuildOptions` 함수 미수정. tsc 플러그인 생성 로직 미변경. external 처리 미변경.
|
|
9
|
+
- import 경로에 `.js` 확장자 미사용: 두 파일 모두 `from "../esbuild/esbuild-worker-plugin"` (확장자 없음)
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
5
|
+
- rebuildAll()이 startWatch() 내부 클로저로 정의: `server-build.worker.ts:272` — startWatch (`:259`) 내부에 `async function rebuildAll()` 정의 확인
|
|
6
|
+
- lastBuilderProgram이 startWatch 로컬 변수: `server-build.worker.ts:264` — `let lastBuilderProgram` startWatch 함수 스코프 내 정의 확인
|
|
7
|
+
- watchLintRunner가 startWatch 로컬 변수: `server-build.worker.ts:265` — `let watchLintRunner` startWatch 함수 스코프 내 정의 확인
|
|
8
|
+
- watchInfo 모듈 스코프 변수 제거: 모듈 스코프에 `watchInfo` 선언 없음 확인, startWatch의 `info` 파라미터를 직접 사용
|
|
9
|
+
- cleanup()에서 lastBuilderProgram 참조 제거: `server-build.worker.ts:108-123` — cleanup 함수에 lastBuilderProgram 참조 없음 확인
|
|
10
|
+
- startWatch에서 createContext에 tsc 옵션 전달: `server-build.worker.ts:348-359` — `tsc: { cwd, output: { dts }, env, includeTests }` 옵션 포함 확인
|
|
11
|
+
- build() js=true에서 createTscPlugin 로컬 생성: `server-build.worker.ts:153-159` — build 함수 내 `const tscPlugin = createTscPlugin({...})` 확인
|
|
12
|
+
- build() js=false에서 runTscPackageBuild 직접 호출: `server-build.worker.ts:192-199` — `runTscPackageBuild({...})` 직접 호출 확인
|
|
13
|
+
- 외부 인터페이스(ServerBuildInfo/WatchInfo/Result/WorkerEvents) 변경 없음: 타입 정의 `:33-96` 변경 없음 확인
|
|
14
|
+
- runTscPackageBuild import 유지: `server-build.worker.ts:19` — import 존재 확인 (js=false fallback용)
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
5
|
+
- rebuildAll()이 esbuildCtx.rebuild()를 호출한다: `server-build.worker.ts` line 252에서 `const esbuildPromise = info.output.js ? esbuildCtx.rebuild() : null;` 확인. 기존 inline esbuild.rebuild() 호출이 모듈 함수로 대체됨.
|
|
6
|
+
- rebuild() 결과의 null 처리: line 301에서 `(await esbuildPromise) ?? { success: true, ... }` — esbuildCtx.rebuild()가 null 반환 시 (context 없음) 기본 성공 결과로 폴백.
|
|
7
|
+
- cleanup()이 esbuildCtx.dispose()를 호출한다: `server-build.worker.ts` line 104에서 `await esbuildCtx.dispose();` 확인. 기존 inline context dispose가 모듈 함수로 대체됨.
|
|
8
|
+
- startWatch()가 esbuildCtx.createContext()를 호출한다: line 345에서 `await esbuildCtx.createContext({...})` 확인. 기존 createEsbuildWatchContext 로컬 함수가 제거됨.
|
|
9
|
+
- onChange의 context 재생성이 esbuildCtx.recreateContext()를 사용한다: line 395에서 `await esbuildCtx.recreateContext({...})` 확인. LOGIC-001 패턴이 모듈 내부로 캡슐화됨.
|
|
10
|
+
- metafile 필터링이 esbuildCtx.getMetafile()/hasContext()를 사용한다: lines 408, 414에서 `esbuildCtx.hasContext()`, `esbuildCtx.getMetafile()` 확인.
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## 검증 항목
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- `EsbuildContextOptions.tsc`가 optional이므로 `server-watch-manager.ts:66-71`의 기존 `recreateContext()` 호출이 타입 에러 없이 동작: 확인 — `tsc` 미전달 시 기존 플러그인 재사용 로직 정상
|
|
6
|
+
- `server-watch-manager.spec.ts` 8개 테스트 전부 통과: 확인 — 회귀 없음
|
|
7
|
+
- `server-watch-manager.ts`에 코드 변경 없음: 확인 — 파일 미수정
|
|
@@ -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"}
|