@simplysm/sd-cli 14.0.19 → 14.0.21
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/vite-postcss-inline-plugin.d.ts.map +1 -1
- package/dist/angular/vite-postcss-inline-plugin.js +4 -1
- package/dist/angular/vite-postcss-inline-plugin.js.map +1 -1
- package/dist/capacitor/capacitor-android.d.ts +16 -0
- package/dist/capacitor/capacitor-android.d.ts.map +1 -0
- package/dist/capacitor/capacitor-android.js +289 -0
- package/dist/capacitor/capacitor-android.js.map +1 -0
- package/dist/capacitor/capacitor.d.ts +0 -49
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +4 -244
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.js +2 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/lint.d.ts +1 -42
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +1 -151
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +2 -1
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/typecheck.d.ts +3 -40
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +3 -232
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/electron/electron.js +11 -4
- package/dist/electron/electron.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts +1 -0
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +10 -6
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/orchestrators/TypecheckOrchestrator.d.ts +74 -0
- package/dist/orchestrators/TypecheckOrchestrator.d.ts.map +1 -0
- package/dist/orchestrators/TypecheckOrchestrator.js +285 -0
- package/dist/orchestrators/TypecheckOrchestrator.js.map +1 -0
- package/dist/sd-cli.js +6 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/utils/lint-core.d.ts +43 -0
- package/dist/utils/lint-core.d.ts.map +1 -0
- package/dist/utils/lint-core.js +154 -0
- package/dist/utils/lint-core.js.map +1 -0
- package/dist/utils/lint-utils.d.ts +1 -1
- package/dist/utils/lint-utils.d.ts.map +1 -1
- package/dist/utils/server-production-files.d.ts +22 -0
- package/dist/utils/server-production-files.d.ts.map +1 -0
- package/dist/utils/server-production-files.js +162 -0
- package/dist/utils/server-production-files.js.map +1 -0
- package/dist/workers/lint.worker.d.ts +1 -1
- package/dist/workers/lint.worker.d.ts.map +1 -1
- package/dist/workers/lint.worker.js +1 -1
- package/dist/workers/lint.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +11 -161
- package/dist/workers/server-build.worker.js.map +1 -1
- package/package.json +4 -4
- package/src/angular/vite-postcss-inline-plugin.ts +5 -1
- package/src/capacitor/capacitor-android.ts +368 -0
- package/src/capacitor/capacitor.ts +4 -317
- package/src/commands/check.ts +2 -2
- package/src/commands/lint.ts +1 -201
- package/src/commands/publish.ts +2 -1
- package/src/commands/typecheck.ts +7 -292
- package/src/electron/electron.ts +4 -4
- package/src/orchestrators/DevWatchOrchestrator.ts +10 -6
- package/src/orchestrators/TypecheckOrchestrator.ts +364 -0
- package/src/sd-cli.ts +6 -1
- package/src/utils/lint-core.ts +205 -0
- package/src/utils/lint-utils.ts +1 -1
- package/src/utils/server-production-files.ts +186 -0
- package/src/workers/lint.worker.ts +1 -1
- package/src/workers/server-build.worker.ts +10 -185
- package/tests/angular/vite-postcss-inline-plugin.spec.ts +10 -0
- package/tests/capacitor/capacitor-android-exports.verify.md +11 -0
- package/tests/capacitor/capacitor-android.spec.ts +219 -0
- package/tests/capacitor/capacitor-build.spec.ts +17 -21
- package/tests/capacitor/capacitor-icon.spec.ts +17 -19
- package/tests/capacitor/capacitor-init.spec.ts +18 -14
- package/tests/capacitor/capacitor-run.spec.ts +10 -24
- package/tests/capacitor/capacitor-workspace.spec.ts +10 -15
- package/tests/commands/check.spec.ts +2 -2
- package/tests/commands/lint.spec.ts +33 -194
- package/tests/commands/publish-set.verify.md +7 -0
- package/tests/electron/electron-symlink-cleanup.verify.md +8 -0
- package/tests/orchestrators/dist-delete-watcher.verify.md +10 -0
- package/tests/orchestrators/typecheck-orchestrator.spec.ts +180 -0
- package/tests/sd-cli-catch-all.verify.md +7 -0
- package/tests/utils/lint-core-import-paths.verify.md +10 -0
- package/tests/utils/lint-core.spec.ts +188 -0
- package/tests/utils/server-production-files-import-paths.verify.md +14 -0
- package/tests/workers/server-build-context-dispose.verify.md +8 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
//#region Mocks
|
|
5
5
|
|
|
@@ -36,14 +36,6 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
36
36
|
},
|
|
37
37
|
}));
|
|
38
38
|
|
|
39
|
-
// env mock
|
|
40
|
-
let mockEnv: Record<string, unknown> = {};
|
|
41
|
-
vi.mock("@simplysm/core-common", () => ({
|
|
42
|
-
env: new Proxy({} as Record<string, unknown>, {
|
|
43
|
-
get: (_target, prop) => mockEnv[prop as string],
|
|
44
|
-
}),
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
39
|
// cpx mock (was execa)
|
|
48
40
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
49
41
|
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
@@ -71,19 +63,15 @@ vi.mock("sharp", () => ({
|
|
|
71
63
|
}),
|
|
72
64
|
}));
|
|
73
65
|
|
|
74
|
-
// consola mock
|
|
75
|
-
const mockLoggerDebug = vi.fn();
|
|
66
|
+
// consola mock (logger assertion 필요)
|
|
76
67
|
const mockLoggerWarn = vi.fn();
|
|
77
|
-
const
|
|
68
|
+
const _mockConsola = {
|
|
69
|
+
level: 0,
|
|
70
|
+
withTag: () => ({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn() }),
|
|
71
|
+
};
|
|
78
72
|
vi.mock("consola", () => ({
|
|
79
|
-
consola:
|
|
80
|
-
|
|
81
|
-
debug: mockLoggerDebug,
|
|
82
|
-
warn: mockLoggerWarn,
|
|
83
|
-
success: mockLoggerSuccess,
|
|
84
|
-
}),
|
|
85
|
-
level: 0,
|
|
86
|
-
},
|
|
73
|
+
consola: _mockConsola,
|
|
74
|
+
default: _mockConsola,
|
|
87
75
|
LogLevels: { debug: 4 },
|
|
88
76
|
}));
|
|
89
77
|
|
|
@@ -167,7 +155,7 @@ function setupDefaultMocks() {
|
|
|
167
155
|
return [];
|
|
168
156
|
});
|
|
169
157
|
|
|
170
|
-
|
|
158
|
+
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
171
159
|
|
|
172
160
|
execaCalls.length = 0;
|
|
173
161
|
mockFsWriteFile.mockReset();
|
|
@@ -176,6 +164,14 @@ function setupDefaultMocks() {
|
|
|
176
164
|
|
|
177
165
|
//#endregion
|
|
178
166
|
|
|
167
|
+
let savedEnv: Record<string, string | undefined>;
|
|
168
|
+
beforeEach(() => {
|
|
169
|
+
savedEnv = { ...process.env };
|
|
170
|
+
});
|
|
171
|
+
afterEach(() => {
|
|
172
|
+
process.env = savedEnv;
|
|
173
|
+
});
|
|
174
|
+
|
|
179
175
|
describe("Capacitor 빌드", () => {
|
|
180
176
|
beforeEach(() => {
|
|
181
177
|
vi.clearAllMocks();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
//#region Mocks
|
|
5
5
|
|
|
@@ -34,12 +34,6 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
34
34
|
},
|
|
35
35
|
}));
|
|
36
36
|
|
|
37
|
-
// env mock
|
|
38
|
-
let mockEnv: Record<string, string | undefined> = {};
|
|
39
|
-
vi.mock("@simplysm/core-common", () => ({
|
|
40
|
-
env: (key: string) => mockEnv[key],
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
37
|
// cpx mock (was execa)
|
|
44
38
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
45
39
|
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
@@ -69,19 +63,15 @@ const mockSharpInstance = {
|
|
|
69
63
|
const mockSharp = vi.fn().mockReturnValue(mockSharpInstance);
|
|
70
64
|
vi.mock("sharp", () => ({ default: mockSharp }));
|
|
71
65
|
|
|
72
|
-
// consola mock
|
|
73
|
-
const mockLoggerDebug = vi.fn();
|
|
66
|
+
// consola mock (logger assertion 필요)
|
|
74
67
|
const mockLoggerWarn = vi.fn();
|
|
75
|
-
const
|
|
68
|
+
const _mockConsola = {
|
|
69
|
+
level: 0,
|
|
70
|
+
withTag: () => ({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn() }),
|
|
71
|
+
};
|
|
76
72
|
vi.mock("consola", () => ({
|
|
77
|
-
consola:
|
|
78
|
-
|
|
79
|
-
debug: mockLoggerDebug,
|
|
80
|
-
warn: mockLoggerWarn,
|
|
81
|
-
success: mockLoggerSuccess,
|
|
82
|
-
}),
|
|
83
|
-
level: 0,
|
|
84
|
-
},
|
|
73
|
+
consola: _mockConsola,
|
|
74
|
+
default: _mockConsola,
|
|
85
75
|
LogLevels: { debug: 4 },
|
|
86
76
|
}));
|
|
87
77
|
|
|
@@ -149,7 +139,7 @@ function setupDefaultMocks() {
|
|
|
149
139
|
mockFsxGlob.mockResolvedValue(["C:/Program Files/Amazon Corretto/jdk21.0.1"]);
|
|
150
140
|
|
|
151
141
|
// env: Android SDK
|
|
152
|
-
|
|
142
|
+
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
153
143
|
|
|
154
144
|
// execa 호출 기록 초기화
|
|
155
145
|
execaCalls.length = 0;
|
|
@@ -157,6 +147,14 @@ function setupDefaultMocks() {
|
|
|
157
147
|
|
|
158
148
|
//#endregion
|
|
159
149
|
|
|
150
|
+
let savedEnv: Record<string, string | undefined>;
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
savedEnv = { ...process.env };
|
|
153
|
+
});
|
|
154
|
+
afterEach(() => {
|
|
155
|
+
process.env = savedEnv;
|
|
156
|
+
});
|
|
157
|
+
|
|
160
158
|
describe("Capacitor 아이콘 처리", () => {
|
|
161
159
|
beforeEach(() => {
|
|
162
160
|
vi.clearAllMocks();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
//#region Mocks
|
|
5
5
|
|
|
@@ -35,11 +35,6 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
35
35
|
},
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
|
-
let mockEnv: Record<string, string | undefined> = {};
|
|
39
|
-
vi.mock("@simplysm/core-common", () => ({
|
|
40
|
-
env: (key: string) => mockEnv[key],
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
38
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
44
39
|
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
45
40
|
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
@@ -65,13 +60,14 @@ vi.mock("sharp", () => ({
|
|
|
65
60
|
}),
|
|
66
61
|
}));
|
|
67
62
|
|
|
68
|
-
const mockLoggerDebug = vi.fn();
|
|
69
63
|
const mockLoggerWarn = vi.fn();
|
|
64
|
+
const _mockConsola = {
|
|
65
|
+
level: 0,
|
|
66
|
+
withTag: () => ({ debug: vi.fn(), warn: mockLoggerWarn, error: vi.fn(), info: vi.fn(), success: vi.fn() }),
|
|
67
|
+
};
|
|
70
68
|
vi.mock("consola", () => ({
|
|
71
|
-
consola:
|
|
72
|
-
|
|
73
|
-
withTag: () => ({ debug: mockLoggerDebug, warn: mockLoggerWarn }),
|
|
74
|
-
},
|
|
69
|
+
consola: _mockConsola,
|
|
70
|
+
default: _mockConsola,
|
|
75
71
|
LogLevels: { debug: 4 },
|
|
76
72
|
}));
|
|
77
73
|
|
|
@@ -152,7 +148,7 @@ function setupDefaultMocks() {
|
|
|
152
148
|
|
|
153
149
|
mockFsxGlob.mockResolvedValue(["C:/Program Files/Amazon Corretto/jdk21.0.1"]);
|
|
154
150
|
|
|
155
|
-
|
|
151
|
+
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
156
152
|
|
|
157
153
|
execaCalls.length = 0;
|
|
158
154
|
mockFsWriteFile.mockReset();
|
|
@@ -161,6 +157,14 @@ function setupDefaultMocks() {
|
|
|
161
157
|
|
|
162
158
|
//#endregion
|
|
163
159
|
|
|
160
|
+
let savedEnv: Record<string, string | undefined>;
|
|
161
|
+
beforeEach(() => {
|
|
162
|
+
savedEnv = { ...process.env };
|
|
163
|
+
});
|
|
164
|
+
afterEach(() => {
|
|
165
|
+
process.env = savedEnv;
|
|
166
|
+
});
|
|
167
|
+
|
|
164
168
|
describe("Capacitor 설정 검증", () => {
|
|
165
169
|
beforeEach(() => {
|
|
166
170
|
vi.clearAllMocks();
|
|
@@ -398,7 +402,7 @@ describe("Android 개발 도구 감지", () => {
|
|
|
398
402
|
});
|
|
399
403
|
|
|
400
404
|
it("Android SDK 미설치 시 에러가 발생한다", async () => {
|
|
401
|
-
|
|
405
|
+
delete process.env["ANDROID_HOME"];
|
|
402
406
|
mockFsxExists.mockImplementation((p: string) => {
|
|
403
407
|
const n = p.replace(/\\/g, "/");
|
|
404
408
|
if (n.includes(".capacitor.lock")) return false;
|
|
@@ -518,7 +522,7 @@ describe("Android 네이티브 설정", () => {
|
|
|
518
522
|
typeof call[0] === "string" &&
|
|
519
523
|
call[0].includes("build.gradle") &&
|
|
520
524
|
typeof call[1] === "string" &&
|
|
521
|
-
call[1].includes("versionCode
|
|
525
|
+
call[1].includes("versionCode 1002003"),
|
|
522
526
|
);
|
|
523
527
|
expect(gradleWrite).toBeDefined();
|
|
524
528
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
//#region Mocks
|
|
5
5
|
|
|
@@ -36,14 +36,6 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
36
36
|
},
|
|
37
37
|
}));
|
|
38
38
|
|
|
39
|
-
// env mock
|
|
40
|
-
let mockEnv: Record<string, unknown> = {};
|
|
41
|
-
vi.mock("@simplysm/core-common", () => ({
|
|
42
|
-
env: new Proxy({} as Record<string, unknown>, {
|
|
43
|
-
get: (_target, prop) => mockEnv[prop as string],
|
|
44
|
-
}),
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
39
|
// cpx mock (was execa) — tracks commands and resolves immediately
|
|
48
40
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
49
41
|
let execaFactory: (...args: unknown[]) => Promise<{ stdout: string; stderr: string; exitCode: number }> = () =>
|
|
@@ -74,20 +66,6 @@ vi.mock("sharp", () => ({
|
|
|
74
66
|
}),
|
|
75
67
|
}));
|
|
76
68
|
|
|
77
|
-
// consola mock
|
|
78
|
-
const mockLoggerDebug = vi.fn();
|
|
79
|
-
const mockLoggerWarn = vi.fn();
|
|
80
|
-
vi.mock("consola", () => ({
|
|
81
|
-
consola: {
|
|
82
|
-
withTag: () => ({
|
|
83
|
-
debug: mockLoggerDebug,
|
|
84
|
-
warn: mockLoggerWarn,
|
|
85
|
-
info: vi.fn(),
|
|
86
|
-
}),
|
|
87
|
-
level: 0,
|
|
88
|
-
},
|
|
89
|
-
LogLevels: { debug: 4 },
|
|
90
|
-
}));
|
|
91
69
|
|
|
92
70
|
//#endregion
|
|
93
71
|
|
|
@@ -141,7 +119,7 @@ export default config;`;
|
|
|
141
119
|
return [];
|
|
142
120
|
});
|
|
143
121
|
|
|
144
|
-
|
|
122
|
+
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
145
123
|
|
|
146
124
|
execaCalls.length = 0;
|
|
147
125
|
execaFactory = () => Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
@@ -151,6 +129,14 @@ export default config;`;
|
|
|
151
129
|
|
|
152
130
|
//#endregion
|
|
153
131
|
|
|
132
|
+
let savedEnv: Record<string, string | undefined>;
|
|
133
|
+
beforeEach(() => {
|
|
134
|
+
savedEnv = { ...process.env };
|
|
135
|
+
});
|
|
136
|
+
afterEach(() => {
|
|
137
|
+
process.env = savedEnv;
|
|
138
|
+
});
|
|
139
|
+
|
|
154
140
|
describe("Capacitor.run()", () => {
|
|
155
141
|
beforeEach(() => {
|
|
156
142
|
vi.clearAllMocks();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
//#region Mocks
|
|
5
5
|
|
|
@@ -35,11 +35,6 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
35
35
|
},
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
|
-
let mockEnv: Record<string, string | undefined> = {};
|
|
39
|
-
vi.mock("@simplysm/core-common", () => ({
|
|
40
|
-
env: (key: string) => mockEnv[key],
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
38
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
44
39
|
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
45
40
|
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
@@ -81,14 +76,6 @@ vi.mock("module", () => ({
|
|
|
81
76
|
}),
|
|
82
77
|
}));
|
|
83
78
|
|
|
84
|
-
vi.mock("consola", () => ({
|
|
85
|
-
consola: {
|
|
86
|
-
withTag: () => ({ debug: vi.fn(), warn: vi.fn() }),
|
|
87
|
-
level: 0,
|
|
88
|
-
},
|
|
89
|
-
LogLevels: { debug: 4 },
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
79
|
//#endregion
|
|
93
80
|
|
|
94
81
|
//#region Helpers
|
|
@@ -154,12 +141,20 @@ function setupDefaultMocks() {
|
|
|
154
141
|
});
|
|
155
142
|
|
|
156
143
|
mockFsxGlob.mockResolvedValue(["C:/Program Files/Amazon Corretto/jdk21.0.1"]);
|
|
157
|
-
|
|
144
|
+
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
158
145
|
execaCalls.length = 0;
|
|
159
146
|
}
|
|
160
147
|
|
|
161
148
|
//#endregion
|
|
162
149
|
|
|
150
|
+
let savedEnv: Record<string, string | undefined>;
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
savedEnv = { ...process.env };
|
|
153
|
+
});
|
|
154
|
+
afterEach(() => {
|
|
155
|
+
process.env = savedEnv;
|
|
156
|
+
});
|
|
157
|
+
|
|
163
158
|
describe("workspace:* 플러그인 해석", () => {
|
|
164
159
|
beforeEach(() => {
|
|
165
160
|
vi.clearAllMocks();
|
|
@@ -9,11 +9,11 @@ const mocks = vi.hoisted(() => ({
|
|
|
9
9
|
discoverWorkspacePackages: vi.fn(),
|
|
10
10
|
}));
|
|
11
11
|
|
|
12
|
-
vi.mock("../../src/
|
|
12
|
+
vi.mock("../../src/orchestrators/TypecheckOrchestrator", () => ({
|
|
13
13
|
executeTypecheck: mocks.executeTypecheck,
|
|
14
14
|
}));
|
|
15
15
|
|
|
16
|
-
vi.mock("../../src/
|
|
16
|
+
vi.mock("../../src/utils/lint-core", () => ({
|
|
17
17
|
executeLint: mocks.executeLint,
|
|
18
18
|
}));
|
|
19
19
|
|
|
@@ -1,189 +1,16 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const mocks = vi.hoisted(() => ({
|
|
5
|
-
fsxExists: vi.fn<(path: string) => Promise<boolean>>(),
|
|
6
|
-
fsxGlob: vi.fn<(...args: unknown[]) => Promise<string[]>>(),
|
|
7
|
-
filterByTargets: vi.fn(
|
|
8
|
-
(files: string[], _targets: string[], _cwd: string) => files,
|
|
9
|
-
),
|
|
10
|
-
lintFiles: vi.fn<() => Promise<Array<{ errorCount: number; warningCount: number }>>>(),
|
|
11
|
-
loadFormatter: vi.fn(),
|
|
12
|
-
outputFixes: vi.fn(),
|
|
13
|
-
jitiImport: vi.fn(),
|
|
14
|
-
eslintCtor: vi.fn(),
|
|
15
|
-
}));
|
|
3
|
+
//#region Mocks
|
|
16
4
|
|
|
17
|
-
vi.
|
|
18
|
-
|
|
19
|
-
pathx: { filterByTargets: mocks.filterByTargets },
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
vi.mock("eslint", () => ({
|
|
23
|
-
ESLint: class MockESLint {
|
|
24
|
-
constructor(options: unknown) { mocks.eslintCtor(options); }
|
|
25
|
-
lintFiles = mocks.lintFiles;
|
|
26
|
-
loadFormatter = mocks.loadFormatter;
|
|
27
|
-
static outputFixes = mocks.outputFixes;
|
|
28
|
-
},
|
|
5
|
+
const mocks = vi.hoisted(() => ({
|
|
6
|
+
executeLint: vi.fn(),
|
|
29
7
|
}));
|
|
30
8
|
|
|
31
|
-
vi.mock("
|
|
32
|
-
|
|
9
|
+
vi.mock("../../src/utils/lint-core", () => ({
|
|
10
|
+
executeLint: mocks.executeLint,
|
|
33
11
|
}));
|
|
34
12
|
|
|
35
|
-
|
|
36
|
-
const fns = (): Record<string, unknown> => ({
|
|
37
|
-
debug: vi.fn(), start: vi.fn(), success: vi.fn(),
|
|
38
|
-
info: vi.fn(), error: vi.fn(), warn: vi.fn(), log: vi.fn(),
|
|
39
|
-
withTag: vi.fn(() => fns()),
|
|
40
|
-
level: 0,
|
|
41
|
-
});
|
|
42
|
-
const c = fns();
|
|
43
|
-
return { consola: c, default: c, LogLevels: {} };
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const { loadIgnorePatterns, executeLint, runLint } = await import("../../src/commands/lint");
|
|
47
|
-
|
|
48
|
-
//#region loadIgnorePatterns
|
|
49
|
-
|
|
50
|
-
describe("loadIgnorePatterns", () => {
|
|
51
|
-
beforeEach(() => vi.clearAllMocks());
|
|
52
|
-
|
|
53
|
-
it("extracts globalIgnores patterns from eslint config", async () => {
|
|
54
|
-
mocks.fsxExists.mockImplementation((p) =>
|
|
55
|
-
Promise.resolve(typeof p === "string" && p.endsWith("eslint.config.ts")),
|
|
56
|
-
);
|
|
57
|
-
mocks.jitiImport.mockResolvedValue({
|
|
58
|
-
default: [
|
|
59
|
-
{ ignores: ["dist/**", "node_modules/**"] },
|
|
60
|
-
{ files: ["*.ts"], rules: {} }, // not globalIgnores — has files key
|
|
61
|
-
{ ignores: [".cache/**"] },
|
|
62
|
-
],
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const result = await loadIgnorePatterns("/project");
|
|
66
|
-
expect(result).toEqual(["dist/**", "node_modules/**", ".cache/**"]);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("ignores config objects that have files key", async () => {
|
|
70
|
-
mocks.fsxExists.mockImplementation((p) =>
|
|
71
|
-
Promise.resolve(typeof p === "string" && p.endsWith("eslint.config.ts")),
|
|
72
|
-
);
|
|
73
|
-
mocks.jitiImport.mockResolvedValue({
|
|
74
|
-
default: [{ files: ["*.ts"], ignores: ["dist/**"] }],
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const result = await loadIgnorePatterns("/project");
|
|
78
|
-
expect(result).toEqual([]);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("throws when no eslint config file found", async () => {
|
|
82
|
-
mocks.fsxExists.mockResolvedValue(false);
|
|
83
|
-
|
|
84
|
-
await expect(loadIgnorePatterns("/project")).rejects.toThrow(
|
|
85
|
-
"ESLint 설정 파일",
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
//#endregion
|
|
91
|
-
|
|
92
|
-
//#region executeLint
|
|
93
|
-
|
|
94
|
-
describe("executeLint", () => {
|
|
95
|
-
beforeEach(() => {
|
|
96
|
-
vi.clearAllMocks();
|
|
97
|
-
// Default: eslint config exists with no ignores
|
|
98
|
-
mocks.fsxExists.mockImplementation((p) =>
|
|
99
|
-
Promise.resolve(typeof p === "string" && p.endsWith("eslint.config.ts")),
|
|
100
|
-
);
|
|
101
|
-
mocks.jitiImport.mockResolvedValue({ default: [] });
|
|
102
|
-
mocks.fsxGlob.mockResolvedValue(["/project/src/a.ts", "/project/src/b.ts"]);
|
|
103
|
-
mocks.filterByTargets.mockImplementation((files) => files);
|
|
104
|
-
mocks.lintFiles.mockResolvedValue([{ errorCount: 0, warningCount: 0 }]);
|
|
105
|
-
mocks.loadFormatter.mockResolvedValue({
|
|
106
|
-
format: vi.fn().mockResolvedValue(""),
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("lints all collected files and returns success when no errors", async () => {
|
|
111
|
-
const result = await executeLint({ targets: [], fix: false, timing: false });
|
|
112
|
-
|
|
113
|
-
expect(result.success).toBe(true);
|
|
114
|
-
expect(result.errorCount).toBe(0);
|
|
115
|
-
expect(result.warningCount).toBe(0);
|
|
116
|
-
expect(mocks.lintFiles).toHaveBeenCalled();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("filters files by targets via pathx.filterByTargets", async () => {
|
|
120
|
-
const filteredFiles = ["/project/packages/core-common/src/a.ts"];
|
|
121
|
-
mocks.filterByTargets.mockReturnValue(filteredFiles);
|
|
122
|
-
|
|
123
|
-
await executeLint({ targets: ["packages/core-common"], fix: false, timing: false });
|
|
124
|
-
|
|
125
|
-
expect(mocks.filterByTargets).toHaveBeenCalledWith(
|
|
126
|
-
expect.any(Array),
|
|
127
|
-
["packages/core-common"],
|
|
128
|
-
expect.any(String),
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it("applies auto-fix when fix option is true", async () => {
|
|
133
|
-
await executeLint({ targets: [], fix: true, timing: false });
|
|
134
|
-
|
|
135
|
-
expect(mocks.outputFixes).toHaveBeenCalled();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("sets TIMING env variable when timing option is true", async () => {
|
|
139
|
-
const origTiming = process.env["TIMING"];
|
|
140
|
-
|
|
141
|
-
await executeLint({ targets: [], fix: false, timing: true });
|
|
142
|
-
|
|
143
|
-
expect(process.env["TIMING"]).toBe("1");
|
|
144
|
-
|
|
145
|
-
// Cleanup
|
|
146
|
-
if (origTiming == null) delete process.env["TIMING"];
|
|
147
|
-
else process.env["TIMING"] = origTiming;
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("creates ESLint with cache enabled and correct cache location", async () => {
|
|
151
|
-
await executeLint({ targets: [], fix: false, timing: false });
|
|
152
|
-
|
|
153
|
-
expect(mocks.eslintCtor).toHaveBeenCalledWith(
|
|
154
|
-
expect.objectContaining({
|
|
155
|
-
cache: true,
|
|
156
|
-
cacheLocation: expect.stringContaining("eslint.cache"),
|
|
157
|
-
}),
|
|
158
|
-
);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("returns error count and formatted output when lint errors found", async () => {
|
|
162
|
-
mocks.lintFiles.mockResolvedValue([
|
|
163
|
-
{ errorCount: 3, warningCount: 1 },
|
|
164
|
-
{ errorCount: 1, warningCount: 2 },
|
|
165
|
-
]);
|
|
166
|
-
mocks.loadFormatter.mockResolvedValue({
|
|
167
|
-
format: vi.fn().mockResolvedValue("error details"),
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const result = await executeLint({ targets: [], fix: false, timing: false });
|
|
171
|
-
|
|
172
|
-
expect(result.success).toBe(false);
|
|
173
|
-
expect(result.errorCount).toBe(4);
|
|
174
|
-
expect(result.warningCount).toBe(3);
|
|
175
|
-
expect(result.formattedOutput).toBe("error details");
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it("returns success when no files to lint", async () => {
|
|
179
|
-
mocks.fsxGlob.mockResolvedValue([]);
|
|
180
|
-
|
|
181
|
-
const result = await executeLint({ targets: [], fix: false, timing: false });
|
|
182
|
-
|
|
183
|
-
expect(result.success).toBe(true);
|
|
184
|
-
expect(mocks.lintFiles).not.toHaveBeenCalled();
|
|
185
|
-
});
|
|
186
|
-
});
|
|
13
|
+
const { runLint } = await import("../../src/commands/lint");
|
|
187
14
|
|
|
188
15
|
//#endregion
|
|
189
16
|
|
|
@@ -200,15 +27,11 @@ describe("runLint", () => {
|
|
|
200
27
|
writeSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
|
|
201
28
|
|
|
202
29
|
// Default: successful lint
|
|
203
|
-
mocks.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
mocks.filterByTargets.mockImplementation((files) => files);
|
|
209
|
-
mocks.lintFiles.mockResolvedValue([{ errorCount: 0, warningCount: 0 }]);
|
|
210
|
-
mocks.loadFormatter.mockResolvedValue({
|
|
211
|
-
format: vi.fn().mockResolvedValue(""),
|
|
30
|
+
mocks.executeLint.mockResolvedValue({
|
|
31
|
+
success: true,
|
|
32
|
+
errorCount: 0,
|
|
33
|
+
warningCount: 0,
|
|
34
|
+
formattedOutput: "",
|
|
212
35
|
});
|
|
213
36
|
});
|
|
214
37
|
|
|
@@ -218,9 +41,11 @@ describe("runLint", () => {
|
|
|
218
41
|
});
|
|
219
42
|
|
|
220
43
|
it("writes formatted output to stdout when there are results", async () => {
|
|
221
|
-
mocks.
|
|
222
|
-
|
|
223
|
-
|
|
44
|
+
mocks.executeLint.mockResolvedValue({
|
|
45
|
+
success: false,
|
|
46
|
+
errorCount: 1,
|
|
47
|
+
warningCount: 0,
|
|
48
|
+
formattedOutput: "lint output here",
|
|
224
49
|
});
|
|
225
50
|
|
|
226
51
|
await runLint({ targets: [], fix: false, timing: false });
|
|
@@ -229,15 +54,29 @@ describe("runLint", () => {
|
|
|
229
54
|
});
|
|
230
55
|
|
|
231
56
|
it("sets exitCode to 1 when lint errors are found", async () => {
|
|
232
|
-
mocks.
|
|
233
|
-
|
|
234
|
-
|
|
57
|
+
mocks.executeLint.mockResolvedValue({
|
|
58
|
+
success: false,
|
|
59
|
+
errorCount: 1,
|
|
60
|
+
warningCount: 0,
|
|
61
|
+
formattedOutput: "errors",
|
|
235
62
|
});
|
|
236
63
|
|
|
237
64
|
await runLint({ targets: [], fix: false, timing: false });
|
|
238
65
|
|
|
239
66
|
expect(process.exitCode).toBe(1);
|
|
240
67
|
});
|
|
68
|
+
|
|
69
|
+
it("does not set exitCode when lint passes", async () => {
|
|
70
|
+
await runLint({ targets: [], fix: false, timing: false });
|
|
71
|
+
|
|
72
|
+
expect(process.exitCode).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("does not write to stdout when formattedOutput is empty", async () => {
|
|
76
|
+
await runLint({ targets: [], fix: false, timing: false });
|
|
77
|
+
|
|
78
|
+
expect(writeSpy).not.toHaveBeenCalled();
|
|
79
|
+
});
|
|
241
80
|
});
|
|
242
81
|
|
|
243
82
|
//#endregion
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# 배포 실패 패키지 ���색 Set 사용 -- LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] Set 생성: `publish.ts:773` — `const publishedSet = new Set(publishedPackages)` 확인
|
|
6
|
+
- [x] Set.has() 사용: `publish.ts:774` — `allPkgNames.filter(n => !publishedSet.has(n))` 확인
|
|
7
|
+
- [x] 동작 동등성: `Array.includes()` → `Set.has()` 변환은 동일한 boolean 결과를 반환하���로 기능 동등
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# symlink 테스트 임시 파일 정리 -- LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] try-catch-finally 구조 적용: `electron.ts:348-358` — try 블록에서 writeFile/symlink/lstat 수행, finally에서 정리
|
|
6
|
+
- [x] finally에서 testLink, testTarget 각각 unlink: `finally { try { fs.unlinkSync(testLink); } catch {} try { fs.unlinkSync(testTarget); } catch {} }` 확인
|
|
7
|
+
- [x] 성공 시에도 파일 정리: try 블록 return 후 finally가 실행되므로 정리 보장
|
|
8
|
+
- [x] 실패 시에도 파일 정리: catch 블록 return 후 finally가 실행되므로 정리 보장
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# dist 삭제 감지 watcher 일반화 -- LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] 디버그 하드코딩 제거: `DevWatchOrchestrator.ts:281` — `angular` 하드코딩 블록이 제거됨
|
|
6
|
+
- [x] 모든 라이브러리 패키지 감시: `_startWatchMode()`에서 `this._libraryPackages`를 순회하며 각 `pkg.dir/dist`를 감시
|
|
7
|
+
- [x] 클래스 필드 저장: `_distDeleteWatchers: FsWatcher[]` 필드에 push
|
|
8
|
+
- [x] shutdown() 정리: `shutdown()`에서 `this._distDeleteWatchers.map(w => w.close())` 호출 확인
|
|
9
|
+
- [x] 정리 후 초기화: `this._distDeleteWatchers = []`로 참조 해제 확인
|
|
10
|
+
- [x] 로그 형식: `[dist-delete:{패키지명}]` 형식으로 어떤 패키지의 dist가 삭제되었는지 식별 가능
|