@simplysm/sd-cli 13.0.68 → 13.0.70
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 +10 -957
- package/dist/builders/BaseBuilder.d.ts +23 -23
- package/dist/builders/BaseBuilder.d.ts.map +1 -1
- package/dist/builders/BaseBuilder.js +15 -15
- package/dist/builders/DtsBuilder.d.ts +4 -4
- package/dist/builders/DtsBuilder.js +1 -1
- package/dist/builders/LibraryBuilder.d.ts +3 -3
- package/dist/builders/types.d.ts +10 -10
- package/dist/capacitor/capacitor.d.ts +36 -36
- package/dist/capacitor/capacitor.js +63 -63
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/add-client.d.ts +8 -8
- package/dist/commands/add-client.js +15 -15
- package/dist/commands/add-client.js.map +1 -1
- package/dist/commands/add-server.d.ts +9 -9
- package/dist/commands/add-server.js +13 -13
- package/dist/commands/add-server.js.map +1 -1
- package/dist/commands/build.d.ts +9 -9
- package/dist/commands/check.js +3 -3
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/dev.d.ts +9 -9
- package/dist/commands/device.d.ts +9 -9
- package/dist/commands/device.d.ts.map +1 -1
- package/dist/commands/device.js +17 -17
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/init.d.ts +6 -6
- package/dist/commands/init.js +12 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.d.ts +23 -23
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +25 -25
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/publish.d.ts +13 -13
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +61 -61
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/replace-deps.d.ts +3 -3
- package/dist/commands/replace-deps.d.ts.map +1 -1
- package/dist/commands/replace-deps.js +1 -1
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/commands/typecheck.d.ts +20 -20
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +20 -20
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/commands/watch.d.ts +7 -7
- package/dist/electron/electron.d.ts +27 -27
- package/dist/electron/electron.js +32 -32
- package/dist/electron/electron.js.map +1 -1
- package/dist/infra/ResultCollector.d.ts +9 -9
- package/dist/infra/ResultCollector.js +5 -5
- package/dist/infra/SignalHandler.d.ts +7 -7
- package/dist/infra/SignalHandler.js +4 -4
- package/dist/infra/WorkerManager.d.ts +14 -14
- package/dist/infra/WorkerManager.js +11 -11
- package/dist/orchestrators/BuildOrchestrator.d.ts +19 -19
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +26 -26
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevOrchestrator.d.ts +25 -25
- package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevOrchestrator.js +30 -30
- package/dist/orchestrators/DevOrchestrator.js.map +1 -1
- package/dist/orchestrators/WatchOrchestrator.d.ts +13 -13
- package/dist/orchestrators/WatchOrchestrator.js +17 -17
- package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +2 -2
- package/dist/sd-cli-entry.js +38 -38
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.d.ts +2 -2
- package/dist/sd-cli.js +1 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +84 -84
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/build-env.d.ts +1 -1
- package/dist/utils/config-editor.d.ts +5 -5
- package/dist/utils/config-editor.js +2 -2
- package/dist/utils/config-editor.js.map +1 -1
- package/dist/utils/copy-public.d.ts +9 -9
- package/dist/utils/copy-src.d.ts +9 -9
- package/dist/utils/esbuild-config.d.ts +30 -30
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/output-utils.d.ts +6 -6
- package/dist/utils/package-utils.d.ts +6 -6
- package/dist/utils/package-utils.js +1 -1
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/rebuild-manager.js +3 -3
- package/dist/utils/rebuild-manager.js.map +1 -1
- package/dist/utils/replace-deps.d.ts +25 -25
- package/dist/utils/replace-deps.js +3 -3
- package/dist/utils/replace-deps.js.map +1 -1
- package/dist/utils/sd-config.d.ts +3 -3
- package/dist/utils/sd-config.js +3 -3
- package/dist/utils/sd-config.js.map +1 -1
- package/dist/utils/tailwind-config-deps.d.ts +3 -3
- package/dist/utils/template.d.ts +8 -8
- package/dist/utils/tsconfig.d.ts +16 -16
- package/dist/utils/tsconfig.js +2 -2
- package/dist/utils/tsconfig.js.map +1 -1
- package/dist/utils/typecheck-serialization.d.ts +8 -8
- package/dist/utils/vite-config.d.ts +8 -8
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +3 -3
- package/dist/utils/worker-events.d.ts +12 -12
- package/dist/utils/worker-events.d.ts.map +1 -1
- package/dist/utils/worker-utils.d.ts +3 -3
- package/dist/utils/worker-utils.js +2 -2
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/workers/client.worker.d.ts +14 -14
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +1 -1
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/dts.worker.d.ts +13 -13
- package/dist/workers/dts.worker.d.ts.map +1 -1
- package/dist/workers/dts.worker.js +3 -3
- package/dist/workers/dts.worker.js.map +1 -1
- package/dist/workers/library.worker.d.ts +12 -12
- package/dist/workers/library.worker.js +1 -1
- package/dist/workers/library.worker.js.map +1 -1
- package/dist/workers/lint.worker.d.ts +1 -1
- package/dist/workers/server-runtime.worker.d.ts +6 -6
- package/dist/workers/server-runtime.worker.js +6 -6
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/dist/workers/server.worker.d.ts +20 -20
- package/dist/workers/server.worker.d.ts.map +1 -1
- package/dist/workers/server.worker.js +6 -6
- package/dist/workers/server.worker.js.map +1 -1
- package/package.json +8 -7
- package/src/builders/BaseBuilder.ts +33 -33
- package/src/builders/DtsBuilder.ts +5 -5
- package/src/builders/LibraryBuilder.ts +9 -9
- package/src/builders/types.ts +10 -10
- package/src/capacitor/capacitor.ts +119 -119
- package/src/commands/add-client.ts +31 -31
- package/src/commands/add-server.ts +34 -34
- package/src/commands/build.ts +9 -9
- package/src/commands/check.ts +5 -5
- package/src/commands/dev.ts +9 -9
- package/src/commands/device.ts +30 -30
- package/src/commands/init.ts +25 -25
- package/src/commands/lint.ts +64 -64
- package/src/commands/publish.ts +139 -139
- package/src/commands/replace-deps.ts +4 -4
- package/src/commands/typecheck.ts +74 -74
- package/src/commands/watch.ts +7 -7
- package/src/electron/electron.ts +51 -51
- package/src/infra/ResultCollector.ts +9 -9
- package/src/infra/SignalHandler.ts +7 -7
- package/src/infra/WorkerManager.ts +14 -14
- package/src/orchestrators/BuildOrchestrator.ts +76 -76
- package/src/orchestrators/DevOrchestrator.ts +88 -88
- package/src/orchestrators/WatchOrchestrator.ts +39 -39
- package/src/sd-cli-entry.ts +43 -43
- package/src/sd-cli.ts +15 -15
- package/src/sd-config.types.ts +85 -85
- package/src/utils/build-env.ts +1 -1
- package/src/utils/config-editor.ts +19 -19
- package/src/utils/copy-public.ts +17 -17
- package/src/utils/copy-src.ts +11 -11
- package/src/utils/esbuild-config.ts +33 -33
- package/src/utils/output-utils.ts +11 -11
- package/src/utils/package-utils.ts +12 -12
- package/src/utils/rebuild-manager.ts +3 -3
- package/src/utils/replace-deps.ts +361 -361
- package/src/utils/sd-config.ts +44 -44
- package/src/utils/tailwind-config-deps.ts +98 -98
- package/src/utils/template.ts +56 -56
- package/src/utils/tsconfig.ts +127 -127
- package/src/utils/typecheck-serialization.ts +86 -86
- package/src/utils/vite-config.ts +341 -341
- package/src/utils/worker-events.ts +16 -16
- package/src/utils/worker-utils.ts +45 -45
- package/src/workers/client.worker.ts +34 -34
- package/src/workers/dts.worker.ts +467 -467
- package/src/workers/library.worker.ts +314 -314
- package/src/workers/lint.worker.ts +16 -16
- package/src/workers/server-runtime.worker.ts +157 -157
- package/src/workers/server.worker.ts +572 -572
- package/templates/add-client/__CLIENT__/package.json.hbs +1 -1
- package/templates/add-server/__SERVER__/package.json.hbs +2 -2
- package/templates/init/package.json.hbs +3 -3
- package/tests/config-editor.spec.ts +160 -0
- package/tests/copy-src.spec.ts +50 -0
- package/tests/get-compiler-options-for-package.spec.ts +139 -0
- package/tests/get-package-source-files.spec.ts +181 -0
- package/tests/get-types-from-package-json.spec.ts +107 -0
- package/tests/infra/ResultCollector.spec.ts +39 -0
- package/tests/infra/SignalHandler.spec.ts +38 -0
- package/tests/infra/WorkerManager.spec.ts +97 -0
- package/tests/load-ignore-patterns.spec.ts +188 -0
- package/tests/load-sd-config.spec.ts +137 -0
- package/tests/package-utils.spec.ts +188 -0
- package/tests/parse-root-tsconfig.spec.ts +89 -0
- package/tests/replace-deps.spec.ts +308 -0
- package/tests/run-lint.spec.ts +415 -0
- package/tests/run-typecheck.spec.ts +653 -0
- package/tests/run-watch.spec.ts +75 -0
- package/tests/sd-cli.spec.ts +330 -0
- package/tests/tailwind-config-deps.spec.ts +30 -0
- package/tests/template.spec.ts +70 -0
- package/tests/utils/rebuild-manager.spec.ts +43 -0
- package/tests/write-changed-output-files.spec.ts +97 -0
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import "@simplysm/core-common"; // Import to use Map.getOrCreate extension method
|
|
3
|
+
|
|
4
|
+
// 외부 의존성 모킹
|
|
5
|
+
vi.mock("typescript", () => {
|
|
6
|
+
const DiagnosticCategory = {
|
|
7
|
+
Error: 1,
|
|
8
|
+
Warning: 0,
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
default: {
|
|
12
|
+
sys: {
|
|
13
|
+
readFile: vi.fn(),
|
|
14
|
+
newLine: "\n",
|
|
15
|
+
},
|
|
16
|
+
readConfigFile: vi.fn(),
|
|
17
|
+
parseJsonConfigFileContent: vi.fn(),
|
|
18
|
+
createIncrementalProgram: vi.fn(),
|
|
19
|
+
getPreEmitDiagnostics: vi.fn(),
|
|
20
|
+
formatDiagnosticsWithColorAndContext: vi.fn(),
|
|
21
|
+
sortAndDeduplicateDiagnostics: vi.fn(),
|
|
22
|
+
createSourceFile: vi.fn().mockReturnValue({}),
|
|
23
|
+
ScriptTarget: { Latest: 99 },
|
|
24
|
+
ScriptKind: { TS: 3 },
|
|
25
|
+
DiagnosticCategory,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
vi.mock("@simplysm/core-node", () => {
|
|
31
|
+
const posix = (p: string) => p.replace(/\\/g, "/");
|
|
32
|
+
const isChildPath = (child: string, parent: string) => {
|
|
33
|
+
if (child === parent) return false;
|
|
34
|
+
const parentWithSlash = parent.endsWith("/") ? parent : parent + "/";
|
|
35
|
+
return child.startsWith(parentWithSlash);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Mock worker proxy - provides build and terminate methods
|
|
39
|
+
const createMockWorkerProxy = () => ({
|
|
40
|
+
build: vi.fn(() =>
|
|
41
|
+
Promise.resolve({
|
|
42
|
+
success: true,
|
|
43
|
+
diagnostics: [],
|
|
44
|
+
errorCount: 0,
|
|
45
|
+
warningCount: 0,
|
|
46
|
+
}),
|
|
47
|
+
),
|
|
48
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
fsExists: vi.fn(),
|
|
53
|
+
fsExistsSync: vi.fn(() => false),
|
|
54
|
+
fsReadJson: vi.fn(),
|
|
55
|
+
fsReadSync: vi.fn(() => ""),
|
|
56
|
+
pathPosix: vi.fn(posix),
|
|
57
|
+
pathIsChildPath: vi.fn(isChildPath),
|
|
58
|
+
pathFilterByTargets: vi.fn((files: string[], targets: string[], cwd: string) => {
|
|
59
|
+
if (targets.length === 0) return files;
|
|
60
|
+
return files.filter((file) => {
|
|
61
|
+
const relativePath = posix(file.replace(cwd + "/", ""));
|
|
62
|
+
return targets.some(
|
|
63
|
+
(target) => relativePath === target || isChildPath(relativePath, target),
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
}),
|
|
67
|
+
Worker: {
|
|
68
|
+
create: vi.fn(() => createMockWorkerProxy()),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
vi.mock("consola", () => {
|
|
74
|
+
const mockLogger = {
|
|
75
|
+
debug: vi.fn(),
|
|
76
|
+
info: vi.fn(),
|
|
77
|
+
error: vi.fn(),
|
|
78
|
+
warn: vi.fn(),
|
|
79
|
+
start: vi.fn(),
|
|
80
|
+
success: vi.fn(),
|
|
81
|
+
fail: vi.fn(),
|
|
82
|
+
withTag: vi.fn(() => mockLogger),
|
|
83
|
+
level: 3, // info level
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
consola: mockLogger,
|
|
87
|
+
default: mockLogger,
|
|
88
|
+
LogLevels: { debug: 4, info: 3, warn: 2, error: 1 },
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const mockJitiImport = vi.fn();
|
|
93
|
+
vi.mock("jiti", () => ({
|
|
94
|
+
createJiti: vi.fn(() => ({
|
|
95
|
+
import: mockJitiImport,
|
|
96
|
+
})),
|
|
97
|
+
}));
|
|
98
|
+
|
|
99
|
+
import path from "path";
|
|
100
|
+
import ts from "typescript";
|
|
101
|
+
import { fsExists, fsReadJson } from "@simplysm/core-node";
|
|
102
|
+
import { runTypecheck } from "../src/commands/typecheck";
|
|
103
|
+
|
|
104
|
+
describe("runTypecheck", () => {
|
|
105
|
+
let originalExitCode: typeof process.exitCode;
|
|
106
|
+
let originalCwd: () => string;
|
|
107
|
+
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
vi.clearAllMocks();
|
|
110
|
+
originalExitCode = process.exitCode;
|
|
111
|
+
originalCwd = process.cwd;
|
|
112
|
+
process.cwd = vi.fn().mockReturnValue("/project");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
afterEach(() => {
|
|
116
|
+
vi.restoreAllMocks();
|
|
117
|
+
process.exitCode = originalExitCode;
|
|
118
|
+
process.cwd = originalCwd;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("exits early when no files to typecheck", async () => {
|
|
122
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
123
|
+
config: {},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
127
|
+
options: { lib: ["ES2024"], types: [] },
|
|
128
|
+
fileNames: [],
|
|
129
|
+
errors: [],
|
|
130
|
+
} as unknown as ts.ParsedCommandLine);
|
|
131
|
+
|
|
132
|
+
await runTypecheck({ targets: [], options: [] });
|
|
133
|
+
|
|
134
|
+
expect(process.exitCode).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("sets exitCode to 1 when tsconfig.json fails to load", async () => {
|
|
138
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
139
|
+
error: {
|
|
140
|
+
category: ts.DiagnosticCategory.Error,
|
|
141
|
+
messageText: "Failed to read tsconfig.json",
|
|
142
|
+
} as ts.Diagnostic,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
vi.mocked(ts.formatDiagnosticsWithColorAndContext).mockReturnValue("");
|
|
146
|
+
|
|
147
|
+
await runTypecheck({ targets: [], options: [] });
|
|
148
|
+
|
|
149
|
+
expect(process.exitCode).toBe(1);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("sets exitCode to 1 when tsconfig.json fails to parse", async () => {
|
|
153
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
154
|
+
config: {},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
158
|
+
options: {},
|
|
159
|
+
fileNames: [],
|
|
160
|
+
errors: [{ category: ts.DiagnosticCategory.Error, messageText: "Parse error" }],
|
|
161
|
+
} as unknown as ts.ParsedCommandLine);
|
|
162
|
+
|
|
163
|
+
vi.mocked(ts.formatDiagnosticsWithColorAndContext).mockReturnValue("");
|
|
164
|
+
|
|
165
|
+
await runTypecheck({ targets: [], options: [] });
|
|
166
|
+
|
|
167
|
+
expect(process.exitCode).toBe(1);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("filters files using targets option", async () => {
|
|
171
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
172
|
+
config: {},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
176
|
+
options: { lib: ["ES2024"], types: [] },
|
|
177
|
+
fileNames: [
|
|
178
|
+
"/project/packages/core-common/src/index.ts",
|
|
179
|
+
"/project/packages/core-node/src/index.ts",
|
|
180
|
+
"/project/packages/cli/src/index.ts",
|
|
181
|
+
],
|
|
182
|
+
errors: [],
|
|
183
|
+
} as unknown as ts.ParsedCommandLine);
|
|
184
|
+
|
|
185
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
186
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
187
|
+
|
|
188
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
189
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
await runTypecheck({
|
|
193
|
+
targets: ["packages/core-common"],
|
|
194
|
+
options: [],
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Worker를 통해 실행되므로 exitCode가 설정되지 않아야 함
|
|
198
|
+
expect(process.exitCode).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("filters files using targets option (including tests)", async () => {
|
|
202
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
203
|
+
config: {},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
207
|
+
options: { lib: ["ES2024"], types: [] },
|
|
208
|
+
fileNames: [
|
|
209
|
+
"/project/packages/core-common/src/index.ts",
|
|
210
|
+
"/project/packages/core-common/tests/utils.spec.ts",
|
|
211
|
+
"/project/packages/core-node/src/index.ts",
|
|
212
|
+
"/project/packages/cli/src/index.ts",
|
|
213
|
+
],
|
|
214
|
+
errors: [],
|
|
215
|
+
} as unknown as ts.ParsedCommandLine);
|
|
216
|
+
|
|
217
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
218
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
219
|
+
|
|
220
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
221
|
+
const mockBuildDts = vi.fn(() =>
|
|
222
|
+
Promise.resolve({
|
|
223
|
+
success: true,
|
|
224
|
+
diagnostics: [],
|
|
225
|
+
errorCount: 0,
|
|
226
|
+
warningCount: 0,
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
230
|
+
build: mockBuildDts,
|
|
231
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
232
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
233
|
+
|
|
234
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
235
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
await runTypecheck({
|
|
239
|
+
targets: ["packages/core-common"],
|
|
240
|
+
options: [],
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Call buildDts only for core-common package
|
|
244
|
+
expect(mockBuildDts).toHaveBeenCalledTimes(2); // neutral: node + browser
|
|
245
|
+
for (const call of mockBuildDts.mock.calls as unknown[][]) {
|
|
246
|
+
expect((call[0] as { name: string }).name).toBe("core-common");
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("continues with default value when sd.config.ts fails to load", async () => {
|
|
251
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
252
|
+
config: {},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
256
|
+
options: { lib: ["ES2024"], types: [] },
|
|
257
|
+
fileNames: ["/project/sd.config.ts"],
|
|
258
|
+
errors: [],
|
|
259
|
+
} as unknown as ts.ParsedCommandLine);
|
|
260
|
+
|
|
261
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
262
|
+
|
|
263
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
264
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// Should proceed without error even if sd.config.ts fails to load
|
|
268
|
+
await runTypecheck({ targets: [], options: [] });
|
|
269
|
+
|
|
270
|
+
expect(process.exitCode).toBeUndefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("uses default value when default export is not a function", async () => {
|
|
274
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
275
|
+
config: {},
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
279
|
+
options: { lib: ["ES2024"], types: [] },
|
|
280
|
+
fileNames: ["/project/packages/core-common/src/index.ts"],
|
|
281
|
+
errors: [],
|
|
282
|
+
} as unknown as ts.ParsedCommandLine);
|
|
283
|
+
|
|
284
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
285
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
286
|
+
|
|
287
|
+
// When sd.config.ts's default export is an object, not a function
|
|
288
|
+
mockJitiImport.mockResolvedValue({
|
|
289
|
+
default: { packages: {} }, // object, not a function
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
293
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
// Should proceed with default value without error
|
|
297
|
+
await runTypecheck({ targets: [], options: [] });
|
|
298
|
+
|
|
299
|
+
expect(process.exitCode).toBeUndefined();
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("uses default value when no default export in sd.config.ts", async () => {
|
|
303
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
304
|
+
config: {},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
308
|
+
options: { lib: ["ES2024"], types: [] },
|
|
309
|
+
fileNames: ["/project/packages/core-common/src/index.ts"],
|
|
310
|
+
errors: [],
|
|
311
|
+
} as unknown as ts.ParsedCommandLine);
|
|
312
|
+
|
|
313
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
314
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
315
|
+
|
|
316
|
+
// When sd.config.ts has no default export
|
|
317
|
+
mockJitiImport.mockResolvedValue({
|
|
318
|
+
someOtherExport: () => ({}),
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
322
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
323
|
+
build: vi.fn(() =>
|
|
324
|
+
Promise.resolve({
|
|
325
|
+
success: true,
|
|
326
|
+
diagnostics: [],
|
|
327
|
+
errorCount: 0,
|
|
328
|
+
warningCount: 0,
|
|
329
|
+
}),
|
|
330
|
+
),
|
|
331
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
332
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
333
|
+
|
|
334
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
335
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
// Should proceed with default value without error
|
|
339
|
+
await runTypecheck({ targets: [], options: [] });
|
|
340
|
+
|
|
341
|
+
expect(process.exitCode).toBeUndefined();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("typecheck multiple packages", async () => {
|
|
345
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
346
|
+
config: {},
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
350
|
+
options: { lib: ["ES2024", "DOM"], types: [] },
|
|
351
|
+
fileNames: [
|
|
352
|
+
"/project/packages/core-node/src/index.ts",
|
|
353
|
+
"/project/packages/core-browser/src/index.ts",
|
|
354
|
+
"/project/packages/core-common/src/index.ts",
|
|
355
|
+
],
|
|
356
|
+
errors: [],
|
|
357
|
+
} as unknown as ts.ParsedCommandLine);
|
|
358
|
+
|
|
359
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
360
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
361
|
+
|
|
362
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
363
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
364
|
+
build: vi.fn(() =>
|
|
365
|
+
Promise.resolve({
|
|
366
|
+
success: true,
|
|
367
|
+
diagnostics: [],
|
|
368
|
+
errorCount: 0,
|
|
369
|
+
warningCount: 0,
|
|
370
|
+
}),
|
|
371
|
+
),
|
|
372
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
373
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
374
|
+
|
|
375
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
376
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
await runTypecheck({ targets: [], options: [] });
|
|
380
|
+
|
|
381
|
+
expect(process.exitCode).toBeUndefined();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("sets exitCode to 1 when typecheck errors occur", async () => {
|
|
385
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: {} });
|
|
386
|
+
|
|
387
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
388
|
+
options: { lib: ["ES2024"], types: [] },
|
|
389
|
+
fileNames: ["/project/packages/core-common/src/index.ts"],
|
|
390
|
+
errors: [],
|
|
391
|
+
} as unknown as ts.ParsedCommandLine);
|
|
392
|
+
|
|
393
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
394
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
395
|
+
|
|
396
|
+
// Worker가 에러 결과를 반환하도록 모킹
|
|
397
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
398
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
399
|
+
build: vi.fn(() =>
|
|
400
|
+
Promise.resolve({
|
|
401
|
+
success: false,
|
|
402
|
+
diagnostics: [
|
|
403
|
+
{
|
|
404
|
+
category: 1,
|
|
405
|
+
code: 2322,
|
|
406
|
+
messageText: "Type error",
|
|
407
|
+
fileName: "/project/packages/core-common/src/index.ts",
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
errorCount: 1,
|
|
411
|
+
warningCount: 0,
|
|
412
|
+
}),
|
|
413
|
+
),
|
|
414
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
415
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
416
|
+
|
|
417
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
418
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
419
|
+
);
|
|
420
|
+
vi.mocked(ts.formatDiagnosticsWithColorAndContext).mockReturnValue("");
|
|
421
|
+
|
|
422
|
+
await runTypecheck({ targets: [], options: [] });
|
|
423
|
+
|
|
424
|
+
expect(process.exitCode).toBe(1);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it("creates other task when non-package files (like tests/) are included", async () => {
|
|
428
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: {} });
|
|
429
|
+
|
|
430
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
431
|
+
options: { lib: ["ES2024"], types: [] },
|
|
432
|
+
fileNames: ["/project/packages/core-node/src/index.ts", "/project/tests/orm/some-test.ts"],
|
|
433
|
+
errors: [],
|
|
434
|
+
} as unknown as ts.ParsedCommandLine);
|
|
435
|
+
|
|
436
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
437
|
+
// Set core-node as node target package
|
|
438
|
+
vi.mocked(fsReadJson).mockImplementation((filePath: string) => {
|
|
439
|
+
if (filePath.includes("core-node")) {
|
|
440
|
+
return Promise.resolve({ name: "@simplysm/core-node" });
|
|
441
|
+
}
|
|
442
|
+
return Promise.resolve({ devDependencies: {} });
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// Mock sd.config.ts: set core-node as node target
|
|
446
|
+
mockJitiImport.mockResolvedValue({
|
|
447
|
+
default: () => ({
|
|
448
|
+
packages: {
|
|
449
|
+
"core-node": { target: "node" },
|
|
450
|
+
},
|
|
451
|
+
}),
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
455
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
459
|
+
const mockBuildDts = vi.fn(() =>
|
|
460
|
+
Promise.resolve({
|
|
461
|
+
success: true,
|
|
462
|
+
diagnostics: [],
|
|
463
|
+
errorCount: 0,
|
|
464
|
+
warningCount: 0,
|
|
465
|
+
}),
|
|
466
|
+
);
|
|
467
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
468
|
+
build: mockBuildDts,
|
|
469
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
470
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
471
|
+
|
|
472
|
+
await runTypecheck({ targets: [], options: [] });
|
|
473
|
+
|
|
474
|
+
// Verify buildDts call
|
|
475
|
+
expect(mockBuildDts).toHaveBeenCalled();
|
|
476
|
+
|
|
477
|
+
// Other task: called without pkgDir/env
|
|
478
|
+
const calls = mockBuildDts.mock.calls as unknown[][];
|
|
479
|
+
const nonPkgCall = calls.find((call) => (call[0] as { name: string }).name === "root");
|
|
480
|
+
expect(nonPkgCall).toBeDefined();
|
|
481
|
+
expect((nonPkgCall![0] as { pkgDir?: string }).pkgDir).toBeUndefined();
|
|
482
|
+
expect((nonPkgCall![0] as { env?: string }).env).toBeUndefined();
|
|
483
|
+
|
|
484
|
+
// core-node package task also exists
|
|
485
|
+
const pkgCall = calls.find((call) => (call[0] as { name: string }).name === "core-node");
|
|
486
|
+
expect(pkgCall).toBeDefined();
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it("does not create other task when only packages/ files exist", async () => {
|
|
490
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: {} });
|
|
491
|
+
|
|
492
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
493
|
+
options: { lib: ["ES2024"], types: [] },
|
|
494
|
+
fileNames: ["/project/packages/core-common/src/index.ts"],
|
|
495
|
+
errors: [],
|
|
496
|
+
} as unknown as ts.ParsedCommandLine);
|
|
497
|
+
|
|
498
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
499
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
500
|
+
|
|
501
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
502
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
506
|
+
const mockBuildDts = vi.fn(() =>
|
|
507
|
+
Promise.resolve({
|
|
508
|
+
success: true,
|
|
509
|
+
diagnostics: [],
|
|
510
|
+
errorCount: 0,
|
|
511
|
+
warningCount: 0,
|
|
512
|
+
}),
|
|
513
|
+
);
|
|
514
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
515
|
+
build: mockBuildDts,
|
|
516
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
517
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
518
|
+
|
|
519
|
+
await runTypecheck({ targets: [], options: [] });
|
|
520
|
+
|
|
521
|
+
// Should have no call with name="root"
|
|
522
|
+
const nonPkgCall = (mockBuildDts.mock.calls as unknown[][]).find(
|
|
523
|
+
(call) => (call[0] as { name: string }).name === "root",
|
|
524
|
+
);
|
|
525
|
+
expect(nonPkgCall).toBeUndefined();
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
describe("executeTypecheck", () => {
|
|
530
|
+
const cwd = "/project";
|
|
531
|
+
let originalExitCode: typeof process.exitCode;
|
|
532
|
+
let originalCwd: () => string;
|
|
533
|
+
|
|
534
|
+
beforeEach(() => {
|
|
535
|
+
vi.clearAllMocks();
|
|
536
|
+
originalExitCode = process.exitCode;
|
|
537
|
+
originalCwd = process.cwd;
|
|
538
|
+
process.cwd = vi.fn().mockReturnValue(cwd);
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
afterEach(() => {
|
|
542
|
+
vi.restoreAllMocks();
|
|
543
|
+
process.exitCode = originalExitCode;
|
|
544
|
+
process.cwd = originalCwd;
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it("returns success result when no errors", async () => {
|
|
548
|
+
const { executeTypecheck } = await import("../src/commands/typecheck");
|
|
549
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
550
|
+
|
|
551
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: { compilerOptions: {} } });
|
|
552
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
553
|
+
fileNames: [path.resolve(cwd, "packages/core-common/src/index.ts")],
|
|
554
|
+
options: {},
|
|
555
|
+
errors: [],
|
|
556
|
+
} as never);
|
|
557
|
+
|
|
558
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
559
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
560
|
+
|
|
561
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
562
|
+
build: vi.fn(() =>
|
|
563
|
+
Promise.resolve({
|
|
564
|
+
success: true,
|
|
565
|
+
diagnostics: [],
|
|
566
|
+
errorCount: 0,
|
|
567
|
+
warningCount: 0,
|
|
568
|
+
}),
|
|
569
|
+
),
|
|
570
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
571
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
572
|
+
|
|
573
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockReturnValue(
|
|
574
|
+
[] as unknown as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
const result = await executeTypecheck({ targets: [], options: [] });
|
|
578
|
+
|
|
579
|
+
expect(result.success).toBe(true);
|
|
580
|
+
expect(result.errorCount).toBe(0);
|
|
581
|
+
// executeTypecheck should not set process.exitCode
|
|
582
|
+
expect(process.exitCode).toBeUndefined();
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it("returns failure result without setting exitCode when errors exist", async () => {
|
|
586
|
+
const { executeTypecheck } = await import("../src/commands/typecheck");
|
|
587
|
+
const { Worker } = await import("@simplysm/core-node");
|
|
588
|
+
|
|
589
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: { compilerOptions: {} } });
|
|
590
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
591
|
+
fileNames: [path.resolve(cwd, "packages/core-common/src/index.ts")],
|
|
592
|
+
options: {},
|
|
593
|
+
errors: [],
|
|
594
|
+
} as never);
|
|
595
|
+
|
|
596
|
+
vi.mocked(fsExists).mockResolvedValue(false);
|
|
597
|
+
vi.mocked(fsReadJson).mockResolvedValue({ devDependencies: {} });
|
|
598
|
+
|
|
599
|
+
// Mock worker to return error results
|
|
600
|
+
vi.mocked(Worker.create).mockReturnValue({
|
|
601
|
+
build: vi.fn(() =>
|
|
602
|
+
Promise.resolve({
|
|
603
|
+
success: false,
|
|
604
|
+
diagnostics: [
|
|
605
|
+
{
|
|
606
|
+
category: 1,
|
|
607
|
+
code: 2322,
|
|
608
|
+
messageText: "Type error",
|
|
609
|
+
fileName: "/project/packages/core-common/src/index.ts",
|
|
610
|
+
},
|
|
611
|
+
],
|
|
612
|
+
errorCount: 1,
|
|
613
|
+
warningCount: 0,
|
|
614
|
+
}),
|
|
615
|
+
),
|
|
616
|
+
terminate: vi.fn(() => Promise.resolve()),
|
|
617
|
+
} as unknown as ReturnType<typeof Worker.create>);
|
|
618
|
+
|
|
619
|
+
vi.mocked(ts.sortAndDeduplicateDiagnostics).mockImplementation(
|
|
620
|
+
(diagnostics) => diagnostics as ts.SortedReadonlyArray<ts.Diagnostic>,
|
|
621
|
+
);
|
|
622
|
+
vi.mocked(ts.formatDiagnosticsWithColorAndContext).mockReturnValue("error output");
|
|
623
|
+
|
|
624
|
+
const result = await executeTypecheck({ targets: [], options: [] });
|
|
625
|
+
|
|
626
|
+
expect(result.success).toBe(false);
|
|
627
|
+
// core-common is neutral, so creates 2 tasks (node + browser), each with errorCount 1
|
|
628
|
+
expect(result.errorCount).toBe(2);
|
|
629
|
+
expect(result.formattedOutput).toBe("error output");
|
|
630
|
+
// executeTypecheck should not set process.exitCode
|
|
631
|
+
expect(process.exitCode).toBeUndefined();
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
it("returns failure result when tsconfig.json fails to load", async () => {
|
|
635
|
+
const { executeTypecheck } = await import("../src/commands/typecheck");
|
|
636
|
+
|
|
637
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({
|
|
638
|
+
error: {
|
|
639
|
+
category: ts.DiagnosticCategory.Error,
|
|
640
|
+
messageText: "Failed to read tsconfig.json",
|
|
641
|
+
} as ts.Diagnostic,
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
vi.mocked(ts.formatDiagnosticsWithColorAndContext).mockReturnValue("");
|
|
645
|
+
|
|
646
|
+
const result = await executeTypecheck({ targets: [], options: [] });
|
|
647
|
+
|
|
648
|
+
expect(result.success).toBe(false);
|
|
649
|
+
expect(result.errorCount).toBe(1);
|
|
650
|
+
// executeTypecheck should not set process.exitCode
|
|
651
|
+
expect(process.exitCode).toBeUndefined();
|
|
652
|
+
});
|
|
653
|
+
});
|