@simplysm/sd-cli 14.0.38 → 14.0.39
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/dist/angular/angular-build-pipeline.d.ts +1 -1
- package/dist/angular/angular-build-pipeline.js +1 -1
- package/dist/angular/client-transform-stylesheet.d.ts +1 -1
- package/dist/angular/client-transform-stylesheet.js +3 -3
- package/dist/esbuild/esbuild-client-config.d.ts +0 -2
- package/dist/esbuild/esbuild-client-config.d.ts.map +1 -1
- package/dist/esbuild/esbuild-client-config.js +19 -9
- package/dist/esbuild/esbuild-client-config.js.map +1 -1
- package/dist/esbuild/esbuild-postcss-plugin.d.ts +8 -0
- package/dist/esbuild/esbuild-postcss-plugin.d.ts.map +1 -0
- package/dist/esbuild/esbuild-postcss-plugin.js +105 -0
- package/dist/esbuild/esbuild-postcss-plugin.js.map +1 -0
- package/dist/esbuild/esbuild-tsc-plugin.d.ts +23 -0
- package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -0
- package/dist/esbuild/esbuild-tsc-plugin.js +60 -0
- package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -0
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +32 -2
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +129 -90
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-esbuild-context.d.ts +27 -0
- package/dist/workers/server-esbuild-context.d.ts.map +1 -1
- package/dist/workers/server-esbuild-context.js +43 -3
- package/dist/workers/server-esbuild-context.js.map +1 -1
- package/package.json +6 -4
- package/src/angular/angular-build-pipeline.ts +2 -2
- package/src/angular/client-transform-stylesheet.ts +4 -4
- package/src/esbuild/esbuild-client-config.ts +21 -12
- package/src/esbuild/esbuild-postcss-plugin.ts +117 -0
- package/src/esbuild/esbuild-tsc-plugin.ts +83 -0
- package/src/workers/client.worker.ts +32 -2
- package/src/workers/server-build.worker.ts +136 -97
- package/src/workers/server-esbuild-context.ts +59 -3
- package/tests/angular/client-transform-stylesheet.spec.ts +1 -1
- package/tests/esbuild/esbuild-tsc-plugin.acc.spec.ts +349 -0
- package/tests/esbuild/esbuild-tsc-plugin.spec.ts +230 -0
- package/tests/utils/esbuild-client-config-postcss.verify.md +6 -0
- package/tests/utils/esbuild-client-config.acc.spec.ts +26 -14
- package/tests/utils/esbuild-client-config.spec.ts +73 -11
- package/tests/utils/esbuild-postcss-plugin.acc.spec.ts +299 -0
- package/tests/utils/esbuild-postcss-plugin.spec.ts +290 -0
- package/tests/utils/esbuild-scss-plugin.acc.spec.ts +1 -0
- package/tests/workers/server-build-lint.spec.ts +43 -0
- package/tests/workers/server-build-worker-refactoring.verify.md +14 -0
- package/tests/workers/server-build-worker.spec.ts +122 -9
- package/tests/workers/server-esbuild-context-tsc.verify.md +7 -0
- package/tests/workers/server-esbuild-context.acc.spec.ts +156 -2
- package/tests/workers/server-esbuild-context.spec.ts +320 -2
|
@@ -29,8 +29,8 @@ let mockMetafileInputs: Record<string, unknown> = {};
|
|
|
29
29
|
// tsc build mock
|
|
30
30
|
const mockRunTscPackageBuild = vi.fn(() => ({
|
|
31
31
|
success: true,
|
|
32
|
-
errors: undefined,
|
|
33
|
-
diagnostics: [],
|
|
32
|
+
errors: undefined as string[] | undefined,
|
|
33
|
+
diagnostics: [] as unknown[],
|
|
34
34
|
errorCount: 0,
|
|
35
35
|
warningCount: 0,
|
|
36
36
|
}));
|
|
@@ -116,6 +116,20 @@ vi.mock("../../src/utils/tsc-build", () => ({
|
|
|
116
116
|
runTscPackageBuild: mockRunTscPackageBuild,
|
|
117
117
|
}));
|
|
118
118
|
|
|
119
|
+
// tsc plugin mock (build() js=true path uses createTscPlugin)
|
|
120
|
+
const mockTscPlugin = {
|
|
121
|
+
plugin: { name: "sd-tsc", setup: vi.fn() },
|
|
122
|
+
getProgram: vi.fn(),
|
|
123
|
+
getAffectedFiles: vi.fn(),
|
|
124
|
+
getDiagnostics: vi.fn((): unknown[] => []),
|
|
125
|
+
getErrors: vi.fn((): string[] | undefined => undefined),
|
|
126
|
+
resetBuilderProgram: vi.fn(),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
vi.mock("../../src/esbuild/esbuild-tsc-plugin", () => ({
|
|
130
|
+
createTscPlugin: vi.fn(() => mockTscPlugin),
|
|
131
|
+
}));
|
|
132
|
+
|
|
119
133
|
vi.mock("../../src/workers/shared-worker-lifecycle", () => {
|
|
120
134
|
let guardCalled = false;
|
|
121
135
|
resetGuard = () => { guardCalled = false; };
|
|
@@ -175,7 +189,14 @@ describe("server-build.worker build()", () => {
|
|
|
175
189
|
diagnostics: [],
|
|
176
190
|
errorCount: 0,
|
|
177
191
|
warningCount: 0,
|
|
178
|
-
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Reset tsc plugin mock (used for js=true path)
|
|
195
|
+
mockTscPlugin.getProgram.mockReset();
|
|
196
|
+
mockTscPlugin.getAffectedFiles.mockReset();
|
|
197
|
+
mockTscPlugin.getDiagnostics.mockReset().mockReturnValue([]);
|
|
198
|
+
mockTscPlugin.getErrors.mockReset().mockReturnValue(undefined);
|
|
199
|
+
mockTscPlugin.resetBuilderProgram.mockReset();
|
|
179
200
|
|
|
180
201
|
// Reset lockfile content and cache
|
|
181
202
|
mockLockfileContent = "";
|
|
@@ -212,21 +233,65 @@ describe("server-build.worker build()", () => {
|
|
|
212
233
|
expect(result.mainJsPath).toBe(path.resolve(baseBuildInfo.pkgDir, "dist", "main.js").replace(/\\/g, "/"));
|
|
213
234
|
});
|
|
214
235
|
|
|
215
|
-
// Acceptance: type error detected
|
|
236
|
+
// Acceptance: type error detected via tsc plugin (js=true)
|
|
216
237
|
it("reports typecheck error in build field", async () => {
|
|
238
|
+
mockTscPlugin.getErrors.mockReturnValue(["TS2345: type error"]);
|
|
239
|
+
mockTscPlugin.getDiagnostics.mockReturnValue([{ code: 2345, category: 1 }]);
|
|
240
|
+
|
|
241
|
+
const result = await workerFns["build"](baseBuildInfo);
|
|
242
|
+
|
|
243
|
+
expect(result.build.success).toBe(false);
|
|
244
|
+
expect(result.build.errors).toContain("TS2345: type error");
|
|
245
|
+
expect(result.build.diagnostics).toHaveLength(1);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Acceptance: esbuild + tsc both error — merged
|
|
249
|
+
it("merges esbuild and tsc errors when both fail", async () => {
|
|
250
|
+
vi.mocked(esbuild.build).mockResolvedValueOnce({
|
|
251
|
+
errors: [{ text: "esbuild syntax error" }],
|
|
252
|
+
warnings: [],
|
|
253
|
+
outputFiles: [],
|
|
254
|
+
} as any);
|
|
255
|
+
mockTscPlugin.getErrors.mockReturnValue(["TS2322: type mismatch"]);
|
|
256
|
+
|
|
257
|
+
const result = await workerFns["build"](baseBuildInfo);
|
|
258
|
+
|
|
259
|
+
expect(result.build.success).toBe(false);
|
|
260
|
+
expect(result.build.errors).toContain("esbuild syntax error");
|
|
261
|
+
expect(result.build.errors).toContain("TS2322: type mismatch");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Acceptance: diagnostics from tsc plugin (js=true)
|
|
265
|
+
it("includes diagnostics from tsc plugin in build result", async () => {
|
|
266
|
+
mockTscPlugin.getDiagnostics.mockReturnValue([
|
|
267
|
+
{ code: 2322, category: 1, messageText: "Type mismatch" },
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
const result = await workerFns["build"](baseBuildInfo);
|
|
271
|
+
|
|
272
|
+
expect(result.build.diagnostics).toHaveLength(1);
|
|
273
|
+
expect(result.build.diagnostics[0]).toEqual(
|
|
274
|
+
expect.objectContaining({ code: 2322 }),
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Acceptance: js=false uses runTscPackageBuild directly
|
|
279
|
+
it("uses runTscPackageBuild directly when output.js=false", async () => {
|
|
217
280
|
mockRunTscPackageBuild.mockReturnValueOnce({
|
|
218
281
|
success: false,
|
|
219
|
-
errors: ["TS2345: type error"]
|
|
282
|
+
errors: ["TS2345: type error"],
|
|
220
283
|
diagnostics: [{ code: 2345, category: 1 }] as any,
|
|
221
284
|
errorCount: 1,
|
|
222
285
|
warningCount: 0,
|
|
223
|
-
|
|
286
|
+
});
|
|
224
287
|
|
|
225
|
-
const result = await workerFns["build"](
|
|
288
|
+
const result = await workerFns["build"]({
|
|
289
|
+
...baseBuildInfo,
|
|
290
|
+
output: { js: false, dts: true },
|
|
291
|
+
});
|
|
226
292
|
|
|
227
293
|
expect(result.build.success).toBe(false);
|
|
228
294
|
expect(result.build.errors).toContain("TS2345: type error");
|
|
229
|
-
expect(result.build.diagnostics).toHaveLength(1);
|
|
230
295
|
});
|
|
231
296
|
|
|
232
297
|
// Acceptance: esbuild error detected
|
|
@@ -466,7 +531,14 @@ describe("server-build.worker startWatch()", () => {
|
|
|
466
531
|
diagnostics: [],
|
|
467
532
|
errorCount: 0,
|
|
468
533
|
warningCount: 0,
|
|
469
|
-
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
// Reset tsc plugin mock (used for watch mode rebuild)
|
|
537
|
+
mockTscPlugin.getProgram.mockReset();
|
|
538
|
+
mockTscPlugin.getAffectedFiles.mockReset();
|
|
539
|
+
mockTscPlugin.getDiagnostics.mockReset().mockReturnValue([]);
|
|
540
|
+
mockTscPlugin.getErrors.mockReset().mockReturnValue(undefined);
|
|
541
|
+
mockTscPlugin.resetBuilderProgram.mockReset();
|
|
470
542
|
|
|
471
543
|
mockReadFileSync.mockImplementation((filePath: string) => {
|
|
472
544
|
if (String(filePath).endsWith("package.json")) {
|
|
@@ -567,6 +639,47 @@ describe("server-build.worker startWatch()", () => {
|
|
|
567
639
|
const buildCalls = mockSend.mock.calls.filter((c) => c[0] === "build");
|
|
568
640
|
expect(buildCalls.length).toBeGreaterThanOrEqual(1);
|
|
569
641
|
});
|
|
642
|
+
|
|
643
|
+
// Acceptance: rebuildAll js=true — single esbuildCtx.rebuild() call, tsc not called directly
|
|
644
|
+
it("uses esbuildCtx.rebuild() without direct tsc call in watch mode rebuild", async () => {
|
|
645
|
+
mockMetafileInputs = { "packages/my-server/src/main.ts": {} };
|
|
646
|
+
|
|
647
|
+
await workerFns["startWatch"](watchInfo);
|
|
648
|
+
|
|
649
|
+
const onChangeHandler = mockOnChange.mock.calls[0][1] as (
|
|
650
|
+
changes: Array<{ event: string; path: string }>,
|
|
651
|
+
) => Promise<void>;
|
|
652
|
+
|
|
653
|
+
mockRebuild.mockClear();
|
|
654
|
+
mockRunTscPackageBuild.mockClear();
|
|
655
|
+
mockSend.mockClear();
|
|
656
|
+
|
|
657
|
+
const absPath = path.resolve("/workspace", "packages/my-server/src/main.ts").replace(/\\/g, "/");
|
|
658
|
+
await onChangeHandler([{ event: "change", path: absPath }]);
|
|
659
|
+
|
|
660
|
+
// esbuild rebuild should have been called (tsc triggered by plugin inside)
|
|
661
|
+
expect(mockRebuild).toHaveBeenCalled();
|
|
662
|
+
// runTscPackageBuild should NOT be called directly for js=true
|
|
663
|
+
expect(mockRunTscPackageBuild).not.toHaveBeenCalled();
|
|
664
|
+
// Build event should be sent
|
|
665
|
+
expect(mockSend).toHaveBeenCalledWith("build", expect.objectContaining({
|
|
666
|
+
build: expect.objectContaining({ success: true }),
|
|
667
|
+
}));
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
// Acceptance: startWatch passes tsc options to createContext
|
|
671
|
+
it("passes tsc options to esbuildCtx.createContext", async () => {
|
|
672
|
+
await workerFns["startWatch"]({
|
|
673
|
+
...watchInfo,
|
|
674
|
+
output: { js: true, dts: true, env: "node" as any, includeTests: true },
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
expect(esbuild.context).toHaveBeenCalledWith(
|
|
678
|
+
expect.objectContaining({
|
|
679
|
+
plugins: [mockTscPlugin.plugin],
|
|
680
|
+
}),
|
|
681
|
+
);
|
|
682
|
+
});
|
|
570
683
|
});
|
|
571
684
|
|
|
572
685
|
describe("server-build.worker stopWatch()", () => {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# server-esbuild-context tsc 통합 — LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] `EsbuildContextOptions.tsc`가 optional이므로 `server-watch-manager.ts:66-71`의 기존 `recreateContext()` 호출이 타입 에러 없이 동작: 확인 — `tsc` 미전달 시 기존 플러그인 재사용 로직 정상
|
|
6
|
+
- [x] `server-watch-manager.spec.ts` 8개 테스트 전부 통과: 확인 — 회귀 없음
|
|
7
|
+
- [x] `server-watch-manager.ts`에 코드 변경 없음: 확인 — 파일 미수정
|
|
@@ -5,6 +5,15 @@ import { describe, it, expect, vi, afterEach } from "vitest";
|
|
|
5
5
|
const mockRebuild = vi.fn();
|
|
6
6
|
const mockDispose = vi.fn();
|
|
7
7
|
|
|
8
|
+
const mockTscPlugin = {
|
|
9
|
+
plugin: { name: "sd-tsc", setup: vi.fn() },
|
|
10
|
+
getProgram: vi.fn(),
|
|
11
|
+
getAffectedFiles: vi.fn(),
|
|
12
|
+
getDiagnostics: vi.fn((): unknown[] => []),
|
|
13
|
+
getErrors: vi.fn(),
|
|
14
|
+
resetBuilderProgram: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
8
17
|
vi.mock("esbuild", () => ({
|
|
9
18
|
default: {
|
|
10
19
|
context: vi.fn(() =>
|
|
@@ -21,11 +30,18 @@ vi.mock("../../src/esbuild/esbuild-config", async (importOriginal) => {
|
|
|
21
30
|
};
|
|
22
31
|
});
|
|
23
32
|
|
|
33
|
+
vi.mock("../../src/esbuild/esbuild-tsc-plugin", () => ({
|
|
34
|
+
createTscPlugin: vi.fn(() => mockTscPlugin),
|
|
35
|
+
}));
|
|
36
|
+
|
|
24
37
|
//#endregion
|
|
25
38
|
|
|
26
39
|
const esbuild = (await import("esbuild")).default;
|
|
27
|
-
const {
|
|
28
|
-
|
|
40
|
+
const {
|
|
41
|
+
createContext, rebuild, recreateContext, dispose, getMetafile, hasContext,
|
|
42
|
+
getTscProgram, getTscAffectedFiles, getTscDiagnostics,
|
|
43
|
+
} = await import("../../src/workers/server-esbuild-context");
|
|
44
|
+
const { createTscPlugin } = await import("../../src/esbuild/esbuild-tsc-plugin");
|
|
29
45
|
|
|
30
46
|
const baseOptions = {
|
|
31
47
|
pkgDir: "/workspace/packages/my-server",
|
|
@@ -33,11 +49,22 @@ const baseOptions = {
|
|
|
33
49
|
external: [],
|
|
34
50
|
};
|
|
35
51
|
|
|
52
|
+
const baseTscOptions = {
|
|
53
|
+
cwd: "/workspace",
|
|
54
|
+
output: { dts: true },
|
|
55
|
+
};
|
|
56
|
+
|
|
36
57
|
describe("server-esbuild-context lifecycle", () => {
|
|
37
58
|
afterEach(async () => {
|
|
38
59
|
mockRebuild.mockReset();
|
|
39
60
|
mockDispose.mockReset();
|
|
61
|
+
mockTscPlugin.getProgram.mockReset();
|
|
62
|
+
mockTscPlugin.getAffectedFiles.mockReset();
|
|
63
|
+
mockTscPlugin.getDiagnostics.mockReset().mockReturnValue([]);
|
|
64
|
+
mockTscPlugin.getErrors.mockReset();
|
|
65
|
+
mockTscPlugin.resetBuilderProgram.mockReset();
|
|
40
66
|
vi.mocked(esbuild.context).mockClear();
|
|
67
|
+
vi.mocked(createTscPlugin).mockClear();
|
|
41
68
|
await dispose();
|
|
42
69
|
});
|
|
43
70
|
|
|
@@ -96,3 +123,130 @@ describe("server-esbuild-context lifecycle", () => {
|
|
|
96
123
|
expect(result).toBeNull();
|
|
97
124
|
});
|
|
98
125
|
});
|
|
126
|
+
|
|
127
|
+
describe("server-esbuild-context tsc integration lifecycle", () => {
|
|
128
|
+
afterEach(async () => {
|
|
129
|
+
mockRebuild.mockReset();
|
|
130
|
+
mockDispose.mockReset();
|
|
131
|
+
mockTscPlugin.getProgram.mockReset();
|
|
132
|
+
mockTscPlugin.getAffectedFiles.mockReset();
|
|
133
|
+
mockTscPlugin.getDiagnostics.mockReset().mockReturnValue([]);
|
|
134
|
+
mockTscPlugin.getErrors.mockReset();
|
|
135
|
+
mockTscPlugin.resetBuilderProgram.mockReset();
|
|
136
|
+
vi.mocked(esbuild.context).mockClear();
|
|
137
|
+
vi.mocked(createTscPlugin).mockClear();
|
|
138
|
+
await dispose();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Acceptance: create with tsc → delegation works → dispose clears all
|
|
142
|
+
it("manages tsc plugin lifecycle: create with tsc → delegation returns plugin values → dispose clears", async () => {
|
|
143
|
+
const fakeProgram = { id: "fake-program" };
|
|
144
|
+
const fakeAffectedFiles = new Set(["/src/main.ts"]);
|
|
145
|
+
const fakeDiagnostics = [{ category: 1, code: 2322, messageText: "Type error" }];
|
|
146
|
+
mockTscPlugin.getProgram.mockReturnValue(fakeProgram);
|
|
147
|
+
mockTscPlugin.getAffectedFiles.mockReturnValue(fakeAffectedFiles);
|
|
148
|
+
mockTscPlugin.getDiagnostics.mockReturnValue(fakeDiagnostics);
|
|
149
|
+
|
|
150
|
+
// Create with tsc options
|
|
151
|
+
await createContext({ ...baseOptions, tsc: baseTscOptions });
|
|
152
|
+
expect(hasContext()).toBe(true);
|
|
153
|
+
|
|
154
|
+
// Delegation methods return plugin values
|
|
155
|
+
expect(getTscProgram()).toBe(fakeProgram);
|
|
156
|
+
expect(getTscAffectedFiles()).toBe(fakeAffectedFiles);
|
|
157
|
+
expect(getTscDiagnostics()).toEqual(fakeDiagnostics);
|
|
158
|
+
|
|
159
|
+
// Dispose clears everything
|
|
160
|
+
await dispose();
|
|
161
|
+
expect(hasContext()).toBe(false);
|
|
162
|
+
expect(getTscProgram()).toBeUndefined();
|
|
163
|
+
expect(getTscAffectedFiles()).toBeUndefined();
|
|
164
|
+
expect(getTscDiagnostics()).toEqual([]);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Acceptance: create with tsc → recreate without tsc → plugin persists
|
|
168
|
+
it("persists tsc plugin across context recreation when tsc options omitted", async () => {
|
|
169
|
+
const fakeProgram = { id: "persisted-program" };
|
|
170
|
+
mockTscPlugin.getProgram.mockReturnValue(fakeProgram);
|
|
171
|
+
|
|
172
|
+
// Initial create with tsc
|
|
173
|
+
await createContext({ ...baseOptions, tsc: baseTscOptions });
|
|
174
|
+
expect(getTscProgram()).toBe(fakeProgram);
|
|
175
|
+
|
|
176
|
+
// Recreate without tsc options — plugin persists
|
|
177
|
+
await recreateContext(baseOptions);
|
|
178
|
+
expect(hasContext()).toBe(true);
|
|
179
|
+
expect(getTscProgram()).toBe(fakeProgram);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Acceptance: create without tsc → no plugin → delegation returns defaults
|
|
183
|
+
it("returns default values from delegation methods when no tsc plugin exists", async () => {
|
|
184
|
+
await createContext(baseOptions);
|
|
185
|
+
|
|
186
|
+
expect(hasContext()).toBe(true);
|
|
187
|
+
expect(getTscProgram()).toBeUndefined();
|
|
188
|
+
expect(getTscAffectedFiles()).toBeUndefined();
|
|
189
|
+
expect(getTscDiagnostics()).toEqual([]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Acceptance: rebuild merges esbuild + tsc errors
|
|
193
|
+
it("merges esbuild and tsc errors in rebuild result", async () => {
|
|
194
|
+
mockRebuild.mockResolvedValue({
|
|
195
|
+
errors: [{ text: "esbuild syntax error" }],
|
|
196
|
+
warnings: [{ text: "deprecation" }],
|
|
197
|
+
outputFiles: [],
|
|
198
|
+
metafile: undefined,
|
|
199
|
+
});
|
|
200
|
+
mockTscPlugin.getErrors.mockReturnValue(["TS2322: type mismatch"]);
|
|
201
|
+
|
|
202
|
+
await createContext({ ...baseOptions, tsc: baseTscOptions });
|
|
203
|
+
const result = await rebuild();
|
|
204
|
+
|
|
205
|
+
expect(result).toEqual({
|
|
206
|
+
success: false,
|
|
207
|
+
errors: ["esbuild syntax error", "TS2322: type mismatch"],
|
|
208
|
+
warnings: ["deprecation"],
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Acceptance: recreateContext resets tsc and persists plugin
|
|
213
|
+
it("resets tsc builderProgram on recreateContext and persists plugin for next rebuild", async () => {
|
|
214
|
+
mockRebuild.mockResolvedValue({
|
|
215
|
+
errors: [],
|
|
216
|
+
warnings: [],
|
|
217
|
+
outputFiles: [],
|
|
218
|
+
metafile: { inputs: {}, outputs: {} },
|
|
219
|
+
});
|
|
220
|
+
mockTscPlugin.getErrors.mockReturnValue(undefined);
|
|
221
|
+
|
|
222
|
+
await createContext({ ...baseOptions, tsc: baseTscOptions });
|
|
223
|
+
|
|
224
|
+
// recreateContext — resets tsc + creates new esbuild context
|
|
225
|
+
await recreateContext(baseOptions);
|
|
226
|
+
|
|
227
|
+
expect(mockTscPlugin.resetBuilderProgram).toHaveBeenCalled();
|
|
228
|
+
expect(hasContext()).toBe(true);
|
|
229
|
+
|
|
230
|
+
// rebuild still works with merged result
|
|
231
|
+
const result = await rebuild();
|
|
232
|
+
expect(result).toEqual({
|
|
233
|
+
success: true,
|
|
234
|
+
errors: undefined,
|
|
235
|
+
warnings: undefined,
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Acceptance: LOGIC-001 — recreateContext failure preserves tsc plugin reset
|
|
240
|
+
it("resets tsc and disposes old context even when recreateContext fails (LOGIC-001)", async () => {
|
|
241
|
+
await createContext({ ...baseOptions, tsc: baseTscOptions });
|
|
242
|
+
|
|
243
|
+
// New context creation fails
|
|
244
|
+
vi.mocked(esbuild.context).mockRejectedValueOnce(new Error("creation failed"));
|
|
245
|
+
|
|
246
|
+
await expect(recreateContext(baseOptions)).rejects.toThrow("creation failed");
|
|
247
|
+
|
|
248
|
+
expect(mockTscPlugin.resetBuilderProgram).toHaveBeenCalled();
|
|
249
|
+
expect(mockDispose).toHaveBeenCalled();
|
|
250
|
+
expect(hasContext()).toBe(false);
|
|
251
|
+
});
|
|
252
|
+
});
|