@simplysm/sd-cli 14.0.13 → 14.0.15
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-angular-plugin.d.ts +3 -1
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +4 -3
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +7 -0
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/engines/ViteEngine.d.ts +2 -2
- package/dist/engines/ViteEngine.d.ts.map +1 -1
- package/dist/engines/ViteEngine.js +4 -2
- package/dist/engines/ViteEngine.js.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +3 -39
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/sd-config.types.d.ts +2 -0
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/vite-config.d.ts +2 -0
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +16 -9
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/workers/client.worker.d.ts +2 -0
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +6 -3
- package/dist/workers/client.worker.js.map +1 -1
- package/package.json +5 -4
- package/src/angular/vite-angular-plugin.ts +7 -4
- package/src/capacitor/capacitor.ts +11 -0
- package/src/engines/ViteEngine.ts +4 -2
- package/src/orchestrators/BuildOrchestrator.ts +3 -39
- package/src/sd-config.types.ts +2 -0
- package/src/utils/vite-config.ts +27 -16
- package/src/workers/client.worker.ts +8 -3
- package/tests/orchestrators/build-orchestrator.spec.ts +7 -145
- package/tests/utils/vite-config.spec.ts +99 -0
- package/tests/workers/client-worker.spec.ts +2 -1
|
@@ -271,7 +271,7 @@ describe("BuildOrchestrator.start", () => {
|
|
|
271
271
|
|
|
272
272
|
// BuildEngine should be created and run() called
|
|
273
273
|
expect(createBuildEngine).toHaveBeenCalledOnce();
|
|
274
|
-
expect(mockEngines[0].run).toHaveBeenCalledWith({ js: true, dts: true, lint:
|
|
274
|
+
expect(mockEngines[0].run).toHaveBeenCalledWith({ js: true, dts: true, lint: false });
|
|
275
275
|
expect(mockEngines[0].stop).toHaveBeenCalled();
|
|
276
276
|
});
|
|
277
277
|
|
|
@@ -624,7 +624,7 @@ describe("BuildOrchestrator client build", () => {
|
|
|
624
624
|
expect.any(Object),
|
|
625
625
|
);
|
|
626
626
|
const engineMock = vi.mocked(createBuildEngine).mock.results[0].value;
|
|
627
|
-
expect(engineMock.run).toHaveBeenCalledWith({ js: true, dts: false, lint:
|
|
627
|
+
expect(engineMock.run).toHaveBeenCalledWith({ js: true, dts: false, lint: false });
|
|
628
628
|
expect(engineMock.stop).toHaveBeenCalled();
|
|
629
629
|
});
|
|
630
630
|
|
|
@@ -852,7 +852,7 @@ describe("BuildOrchestrator native build integration (Slice 1)", () => {
|
|
|
852
852
|
// ViteEngine should have been called
|
|
853
853
|
expect(createBuildEngine).toHaveBeenCalled();
|
|
854
854
|
const engineMock = vi.mocked(createBuildEngine).mock.results[0].value;
|
|
855
|
-
expect(engineMock.run).toHaveBeenCalledWith({ js: true, dts: false, lint:
|
|
855
|
+
expect(engineMock.run).toHaveBeenCalledWith({ js: true, dts: false, lint: false });
|
|
856
856
|
|
|
857
857
|
// Capacitor should have been created, initialized, and built
|
|
858
858
|
expect(Capacitor.create).toHaveBeenCalledWith(
|
|
@@ -980,8 +980,8 @@ describe("BuildOrchestrator native build integration (Slice 1)", () => {
|
|
|
980
980
|
const { runLintInWorker } = await import("../../src/utils/lint-utils");
|
|
981
981
|
|
|
982
982
|
describe("BuildOrchestrator lint integration", () => {
|
|
983
|
-
//
|
|
984
|
-
it("passes lint:
|
|
983
|
+
// build에서 lint를 실행하지 않는다 (lint는 check에서만 실행)
|
|
984
|
+
it("passes lint:false to engine.run for all package types", async () => {
|
|
985
985
|
setupDefaults({
|
|
986
986
|
packages: {
|
|
987
987
|
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
@@ -994,15 +994,13 @@ describe("BuildOrchestrator lint integration", () => {
|
|
|
994
994
|
await orchestrator.initialize();
|
|
995
995
|
await orchestrator.start();
|
|
996
996
|
|
|
997
|
-
// All 3 engines should receive lint: true
|
|
998
997
|
expect(mockEngines).toHaveLength(3);
|
|
999
998
|
for (const engine of mockEngines) {
|
|
1000
999
|
const runArgs = engine.run.mock.calls[0][0];
|
|
1001
|
-
expect(runArgs.lint).toBe(
|
|
1000
|
+
expect(runArgs.lint).toBe(false);
|
|
1002
1001
|
}
|
|
1003
1002
|
});
|
|
1004
1003
|
|
|
1005
|
-
// Scenario: build에서 기존 runLint() 병렬 태스크가 제거된다
|
|
1006
1004
|
it("does not call runLint (separate lint worker)", async () => {
|
|
1007
1005
|
setupDefaults({
|
|
1008
1006
|
packages: {
|
|
@@ -1017,32 +1015,7 @@ describe("BuildOrchestrator lint integration", () => {
|
|
|
1017
1015
|
expect(runLintInWorker).not.toHaveBeenCalled();
|
|
1018
1016
|
});
|
|
1019
1017
|
|
|
1020
|
-
|
|
1021
|
-
it("sets hasError when lint fails in engine result", async () => {
|
|
1022
|
-
setupDefaults({
|
|
1023
|
-
packages: {
|
|
1024
|
-
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
1025
|
-
},
|
|
1026
|
-
});
|
|
1027
|
-
vi.mocked(createBuildEngine).mockReturnValue({
|
|
1028
|
-
run: vi.fn().mockResolvedValue({
|
|
1029
|
-
success: true,
|
|
1030
|
-
build: { success: true, errors: [], warnings: [], diagnostics: [] },
|
|
1031
|
-
lint: { success: false, errorCount: 3, warningCount: 0, formattedOutput: "lint errors here" },
|
|
1032
|
-
}),
|
|
1033
|
-
startWatch: vi.fn(),
|
|
1034
|
-
stop: vi.fn().mockResolvedValue(undefined),
|
|
1035
|
-
} as any);
|
|
1036
|
-
|
|
1037
|
-
const orchestrator = new BuildOrchestrator({ targets: [], options: [] });
|
|
1038
|
-
await orchestrator.initialize();
|
|
1039
|
-
const hasError = await orchestrator.start();
|
|
1040
|
-
|
|
1041
|
-
expect(hasError).toBe(true);
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
|
-
// Scenario: build에서 scripts 패키지는 제외된다
|
|
1045
|
-
it("excludes scripts packages (no lint for scripts)", async () => {
|
|
1018
|
+
it("excludes scripts packages", async () => {
|
|
1046
1019
|
setupDefaults({
|
|
1047
1020
|
packages: {
|
|
1048
1021
|
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
@@ -1054,7 +1027,6 @@ describe("BuildOrchestrator lint integration", () => {
|
|
|
1054
1027
|
await orchestrator.initialize();
|
|
1055
1028
|
await orchestrator.start();
|
|
1056
1029
|
|
|
1057
|
-
// Only core-common should have engine (scripts excluded)
|
|
1058
1030
|
expect(mockEngines).toHaveLength(1);
|
|
1059
1031
|
expect(runLintInWorker).not.toHaveBeenCalled();
|
|
1060
1032
|
});
|
|
@@ -1062,114 +1034,4 @@ describe("BuildOrchestrator lint integration", () => {
|
|
|
1062
1034
|
|
|
1063
1035
|
//#endregion
|
|
1064
1036
|
|
|
1065
|
-
//#region Feature 2.1 Slice 3: build typeLabel에 lint 분기 추가
|
|
1066
|
-
|
|
1067
|
-
describe("Feature 2.1: build에서 lint 에러가 'lint' 라벨로 출력", () => {
|
|
1068
|
-
it("build에서 lint 에러가 'lint' 라벨로 출력된다", async () => {
|
|
1069
|
-
setupDefaults({
|
|
1070
|
-
packages: {
|
|
1071
|
-
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
1072
|
-
},
|
|
1073
|
-
});
|
|
1074
|
-
vi.mocked(createBuildEngine).mockReturnValue({
|
|
1075
|
-
run: vi.fn().mockResolvedValue({
|
|
1076
|
-
success: true,
|
|
1077
|
-
build: { success: true, errors: [], warnings: [], diagnostics: [] },
|
|
1078
|
-
lint: { success: false, errorCount: 1, warningCount: 0, formattedOutput: "no-unused-vars" },
|
|
1079
|
-
}),
|
|
1080
|
-
startWatch: vi.fn(),
|
|
1081
|
-
stop: vi.fn().mockResolvedValue(undefined),
|
|
1082
|
-
} as any);
|
|
1083
|
-
|
|
1084
|
-
const orchestrator = new BuildOrchestrator({ targets: [], options: [] });
|
|
1085
|
-
await orchestrator.initialize();
|
|
1086
|
-
await orchestrator.start();
|
|
1087
|
-
|
|
1088
|
-
// formatBuildMessages should have been called with "lint" label
|
|
1089
|
-
const { formatBuildMessages } = await import("../../src/utils/output-utils");
|
|
1090
|
-
const fmtCalls = vi.mocked(formatBuildMessages).mock.calls;
|
|
1091
|
-
const lintCall = fmtCalls.find((c) => c[1] === "lint");
|
|
1092
|
-
expect(lintCall).toBeDefined();
|
|
1093
|
-
expect(lintCall![0]).toBe("core-common");
|
|
1094
|
-
});
|
|
1095
|
-
|
|
1096
|
-
it("build에서 JS 빌드 에러는 target 라벨(neutral) 유지", async () => {
|
|
1097
|
-
setupDefaults({
|
|
1098
|
-
packages: {
|
|
1099
|
-
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
1100
|
-
},
|
|
1101
|
-
});
|
|
1102
|
-
vi.mocked(createBuildEngine).mockReturnValue({
|
|
1103
|
-
run: vi.fn().mockResolvedValue({
|
|
1104
|
-
success: false,
|
|
1105
|
-
build: { success: false, errors: ["Module not found"], warnings: [], diagnostics: [] },
|
|
1106
|
-
}),
|
|
1107
|
-
startWatch: vi.fn(),
|
|
1108
|
-
stop: vi.fn().mockResolvedValue(undefined),
|
|
1109
|
-
} as any);
|
|
1110
|
-
|
|
1111
|
-
const orchestrator = new BuildOrchestrator({ targets: [], options: [] });
|
|
1112
|
-
await orchestrator.initialize();
|
|
1113
|
-
await orchestrator.start();
|
|
1114
|
-
|
|
1115
|
-
const { formatBuildMessages } = await import("../../src/utils/output-utils");
|
|
1116
|
-
const fmtCalls = vi.mocked(formatBuildMessages).mock.calls;
|
|
1117
|
-
const jsCall = fmtCalls.find((c) => c[1] === "neutral");
|
|
1118
|
-
expect(jsCall).toBeDefined();
|
|
1119
|
-
});
|
|
1120
|
-
|
|
1121
|
-
it("build에서 빌드 에러는 target 라벨 유지", async () => {
|
|
1122
|
-
setupDefaults({
|
|
1123
|
-
packages: {
|
|
1124
|
-
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
1125
|
-
},
|
|
1126
|
-
});
|
|
1127
|
-
vi.mocked(createBuildEngine).mockReturnValue({
|
|
1128
|
-
run: vi.fn().mockResolvedValue({
|
|
1129
|
-
success: false,
|
|
1130
|
-
build: { success: false, errors: ["Type error"], warnings: [], diagnostics: [] },
|
|
1131
|
-
}),
|
|
1132
|
-
startWatch: vi.fn(),
|
|
1133
|
-
stop: vi.fn().mockResolvedValue(undefined),
|
|
1134
|
-
} as any);
|
|
1135
|
-
|
|
1136
|
-
const orchestrator = new BuildOrchestrator({ targets: [], options: [] });
|
|
1137
|
-
await orchestrator.initialize();
|
|
1138
|
-
await orchestrator.start();
|
|
1139
|
-
|
|
1140
|
-
const { formatBuildMessages } = await import("../../src/utils/output-utils");
|
|
1141
|
-
const fmtCalls = vi.mocked(formatBuildMessages).mock.calls;
|
|
1142
|
-
const buildCall = fmtCalls.find((c) => c[1] === "neutral");
|
|
1143
|
-
expect(buildCall).toBeDefined();
|
|
1144
|
-
});
|
|
1145
|
-
|
|
1146
|
-
it("build에서 lint 성공 시 에러 출력 없음", async () => {
|
|
1147
|
-
setupDefaults({
|
|
1148
|
-
packages: {
|
|
1149
|
-
"core-common": { target: "neutral", publish: { type: "npm" } },
|
|
1150
|
-
},
|
|
1151
|
-
});
|
|
1152
|
-
vi.mocked(createBuildEngine).mockReturnValue({
|
|
1153
|
-
run: vi.fn().mockResolvedValue({
|
|
1154
|
-
success: true,
|
|
1155
|
-
build: { success: true, errors: [], warnings: [], diagnostics: [] },
|
|
1156
|
-
lint: { success: true, errorCount: 0, warningCount: 0, formattedOutput: "" },
|
|
1157
|
-
}),
|
|
1158
|
-
startWatch: vi.fn(),
|
|
1159
|
-
stop: vi.fn().mockResolvedValue(undefined),
|
|
1160
|
-
} as any);
|
|
1161
|
-
|
|
1162
|
-
const orchestrator = new BuildOrchestrator({ targets: [], options: [] });
|
|
1163
|
-
await orchestrator.initialize();
|
|
1164
|
-
await orchestrator.start();
|
|
1165
|
-
|
|
1166
|
-
// No error log about lint
|
|
1167
|
-
const errorCalls = mockLogger.error.mock.calls;
|
|
1168
|
-
const lintErrorCall = errorCalls.find(
|
|
1169
|
-
(c: unknown[]) => typeof c[0] === "string" && (c[0]).includes("lint"),
|
|
1170
|
-
);
|
|
1171
|
-
expect(lintErrorCall).toBeUndefined();
|
|
1172
|
-
});
|
|
1173
|
-
});
|
|
1174
|
-
|
|
1175
1037
|
//#endregion
|
|
@@ -11,6 +11,11 @@ vi.mock("../../src/angular/vite-angular-plugin.js", () => ({
|
|
|
11
11
|
sdAngularPlugin: mockSdAngularPlugin,
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
+
const mockSolidPlugin = vi.fn(() => ({ name: "vite-plugin-solid" }));
|
|
15
|
+
vi.mock("vite-plugin-solid", () => ({
|
|
16
|
+
default: mockSolidPlugin,
|
|
17
|
+
}));
|
|
18
|
+
|
|
14
19
|
vi.mock("../../src/utils/vite-scope-watch-plugin.js", () => ({
|
|
15
20
|
sdScopeWatchPlugin: vi.fn(() => ({ name: "sd-scope-watch-plugin" })),
|
|
16
21
|
}));
|
|
@@ -577,6 +582,55 @@ describe("createClientViteConfig", () => {
|
|
|
577
582
|
expect(scopePlugin).toBeUndefined();
|
|
578
583
|
});
|
|
579
584
|
|
|
585
|
+
// --- framework selection (Feature 1.1: client-framework-selection) ---
|
|
586
|
+
|
|
587
|
+
// Acceptance: Scenario "Solid 프레임워크 선택"
|
|
588
|
+
it("uses solidPlugin when framework is 'solid'", async () => {
|
|
589
|
+
const config = await createClientViteConfig({
|
|
590
|
+
...createDefaultOptions(),
|
|
591
|
+
framework: "solid",
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
const plugins = config.plugins as Array<{ name: string }>;
|
|
595
|
+
expect(plugins.find((p) => p.name === "vite-plugin-solid")).toBeDefined();
|
|
596
|
+
expect(mockSolidPlugin).toHaveBeenCalled();
|
|
597
|
+
expect(mockSdAngularPlugin).not.toHaveBeenCalled();
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
// Acceptance: Scenario "framework 미지정 시 기본값"
|
|
601
|
+
it("uses sdAngularPlugin when framework is not specified", async () => {
|
|
602
|
+
await createClientViteConfig(createDefaultOptions());
|
|
603
|
+
|
|
604
|
+
expect(mockSdAngularPlugin).toHaveBeenCalled();
|
|
605
|
+
expect(mockSolidPlugin).not.toHaveBeenCalled();
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
// Acceptance: Scenario "Angular 프레임워크 명시 선택"
|
|
609
|
+
it("uses sdAngularPlugin when framework is 'angular'", async () => {
|
|
610
|
+
await createClientViteConfig({
|
|
611
|
+
...createDefaultOptions(),
|
|
612
|
+
framework: "angular",
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
expect(mockSdAngularPlugin).toHaveBeenCalled();
|
|
616
|
+
expect(mockSolidPlugin).not.toHaveBeenCalled();
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
// Acceptance: Scenario "Solid 빌드에서 PostCSS inline 플러그인 미적용"
|
|
620
|
+
it("does not add sdPostCssInlinePlugin when framework is 'solid' even with postCssPlugins", async () => {
|
|
621
|
+
const fakePlugin = { postcssPlugin: "autoprefixer" };
|
|
622
|
+
const config = await createClientViteConfig({
|
|
623
|
+
...createDefaultOptions(),
|
|
624
|
+
framework: "solid",
|
|
625
|
+
postCssPlugins: [fakePlugin],
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
const plugins = config.plugins as Array<{ name: string }>;
|
|
629
|
+
expect(plugins.find((p) => p.name === "sd-postcss-inline")).toBeUndefined();
|
|
630
|
+
// 하지만 css.postcss는 여전히 설정된다 (외부 CSS 파일용)
|
|
631
|
+
expect(config.css?.postcss).toEqual({ plugins: [fakePlugin] });
|
|
632
|
+
});
|
|
633
|
+
|
|
580
634
|
// Acceptance: Scenario "pwa 필드 미설정 시 기본값"
|
|
581
635
|
it("uses default manifest values from pkgName when pwa is undefined", async () => {
|
|
582
636
|
await createClientViteConfig(createDefaultOptions());
|
|
@@ -595,4 +649,49 @@ describe("createClientViteConfig", () => {
|
|
|
595
649
|
}),
|
|
596
650
|
);
|
|
597
651
|
});
|
|
652
|
+
|
|
653
|
+
// --- legacyModule dev mode (Feature: fix-legacy-ngdevmode) ---
|
|
654
|
+
|
|
655
|
+
// Acceptance: Scenario "legacyModule: true + dev 명령 실행 시 sdAngularPlugin에 dev: true 전달"
|
|
656
|
+
it("passes dev: true to sdAngularPlugin when mode is dev with legacyModule", async () => {
|
|
657
|
+
await createClientViteConfig({
|
|
658
|
+
...createDefaultOptions(),
|
|
659
|
+
mode: "dev",
|
|
660
|
+
legacyModule: true,
|
|
661
|
+
watch: true,
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
expect(mockSdAngularPlugin).toHaveBeenCalledWith(
|
|
665
|
+
expect.objectContaining({ dev: true }),
|
|
666
|
+
);
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
// Acceptance: Scenario "legacyModule dev에서 build output 설정이 적용된다"
|
|
670
|
+
it("applies build output settings when mode is dev with legacyModule", async () => {
|
|
671
|
+
const config = await createClientViteConfig({
|
|
672
|
+
...createDefaultOptions(),
|
|
673
|
+
mode: "dev",
|
|
674
|
+
legacyModule: true,
|
|
675
|
+
watch: true,
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
expect(config.build?.outDir).toMatch(/my-client[\\/]dist$/);
|
|
679
|
+
expect(config.build?.watch).toEqual({});
|
|
680
|
+
expect(config.build?.emptyOutDir).toBe(false);
|
|
681
|
+
expect(config.build?.minify).toBe(false);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
// Unit: legacyModule dev에서 PWA가 추가되지 않는다
|
|
685
|
+
it("does not add VitePWA plugin when mode is dev with legacyModule", async () => {
|
|
686
|
+
const config = await createClientViteConfig({
|
|
687
|
+
...createDefaultOptions(),
|
|
688
|
+
mode: "dev",
|
|
689
|
+
legacyModule: true,
|
|
690
|
+
watch: true,
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
const plugins = config.plugins as Array<{ name: string }>;
|
|
694
|
+
const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
|
|
695
|
+
expect(pwaPlugin).toBeUndefined();
|
|
696
|
+
});
|
|
598
697
|
});
|
|
@@ -228,9 +228,10 @@ describe("client.worker", () => {
|
|
|
228
228
|
|
|
229
229
|
expect(mockCreateClientViteConfig).toHaveBeenCalledWith(
|
|
230
230
|
expect.objectContaining({
|
|
231
|
-
mode: "
|
|
231
|
+
mode: "dev",
|
|
232
232
|
watch: true,
|
|
233
233
|
pwa: false,
|
|
234
|
+
legacyModule: true,
|
|
234
235
|
}),
|
|
235
236
|
);
|
|
236
237
|
});
|