@simplysm/sd-cli 14.0.10 → 14.0.12
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 +58 -253
- package/dist/angular/client-transform-stylesheet.js +1 -1
- package/dist/angular/client-transform-stylesheet.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts +1 -1
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +60 -34
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/angular/vite-postcss-inline-plugin.d.ts +1 -1
- package/dist/angular/vite-postcss-inline-plugin.js +1 -1
- package/dist/capacitor/capacitor.d.ts +14 -2
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +131 -17
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/build.d.ts +3 -10
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +3 -10
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/check.js +3 -3
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -9
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +3 -9
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/device.d.ts +13 -0
- package/dist/commands/device.d.ts.map +1 -0
- package/dist/commands/device.js +53 -0
- package/dist/commands/device.js.map +1 -0
- package/dist/commands/publish.d.ts +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +18 -26
- 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/typecheck.d.ts +4 -3
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +5 -11
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/commands/watch.d.ts +9 -9
- package/dist/commands/watch.js +9 -9
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +42 -3
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +3 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.d.ts +7 -7
- package/dist/engines/NgtscEngine.d.ts.map +1 -1
- package/dist/engines/NgtscEngine.js +3 -3
- package/dist/engines/ServerEsbuildEngine.d.ts +7 -7
- package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +3 -3
- package/dist/engines/TscEngine.d.ts +7 -7
- package/dist/engines/TscEngine.d.ts.map +1 -1
- package/dist/engines/TscEngine.js +3 -3
- package/dist/engines/ViteEngine.d.ts +1 -1
- package/dist/engines/ViteEngine.d.ts.map +1 -1
- package/dist/engines/ViteEngine.js +7 -12
- package/dist/engines/ViteEngine.js.map +1 -1
- package/dist/engines/index.d.ts +5 -5
- package/dist/engines/index.js +5 -5
- package/dist/engines/types.d.ts +20 -20
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/infra/ResultCollector.d.ts +9 -9
- package/dist/infra/ResultCollector.js +8 -8
- package/dist/infra/SignalHandler.d.ts +7 -7
- package/dist/infra/SignalHandler.js +7 -7
- package/dist/infra/WorkerManager.d.ts +14 -14
- package/dist/infra/WorkerManager.js +14 -14
- package/dist/orchestrators/BuildOrchestrator.d.ts +25 -25
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +29 -29
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts +7 -7
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +35 -57
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +2 -2
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +45 -9
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.d.ts +3 -3
- package/dist/sd-cli.js +16 -16
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +105 -105
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/angular-compiler.js +5 -5
- package/dist/utils/angular-compiler.js.map +1 -1
- package/dist/utils/build-env.d.ts +1 -1
- package/dist/utils/build-env.js +1 -1
- package/dist/utils/concurrency.d.ts +7 -7
- package/dist/utils/concurrency.js +7 -7
- package/dist/utils/copy-public.d.ts +9 -9
- package/dist/utils/copy-public.js +17 -17
- package/dist/utils/copy-public.js.map +1 -1
- package/dist/utils/copy-src.d.ts +9 -9
- package/dist/utils/copy-src.js +11 -11
- package/dist/utils/copy-src.js.map +1 -1
- package/dist/utils/engine-stop.d.ts +8 -9
- package/dist/utils/engine-stop.d.ts.map +1 -1
- package/dist/utils/engine-stop.js +9 -10
- package/dist/utils/engine-stop.js.map +1 -1
- package/dist/utils/esbuild-config.d.ts +23 -23
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +25 -25
- package/dist/utils/esbuild-config.js.map +1 -1
- package/dist/utils/lint-with-program.d.ts +15 -15
- package/dist/utils/lint-with-program.d.ts.map +1 -1
- package/dist/utils/lint-with-program.js +29 -29
- package/dist/utils/lint-with-program.js.map +1 -1
- package/dist/utils/ngtsc-build-core.d.ts +8 -8
- package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
- package/dist/utils/ngtsc-build-core.js +14 -14
- package/dist/utils/ngtsc-build-core.js.map +1 -1
- package/dist/utils/output-path-rewriter.d.ts +14 -14
- package/dist/utils/output-path-rewriter.js +18 -18
- package/dist/utils/output-path-rewriter.js.map +1 -1
- package/dist/utils/output-utils.d.ts +6 -6
- package/dist/utils/output-utils.js +11 -11
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/utils/package-utils.d.ts +21 -21
- package/dist/utils/package-utils.d.ts.map +1 -1
- package/dist/utils/package-utils.js +56 -45
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/replace-deps.d.ts +25 -25
- package/dist/utils/replace-deps.d.ts.map +1 -1
- package/dist/utils/replace-deps.js +84 -65
- 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/tsc-build.d.ts +13 -13
- package/dist/utils/tsc-build.d.ts.map +1 -1
- package/dist/utils/tsc-build.js +9 -9
- package/dist/utils/tsc-build.js.map +1 -1
- package/dist/utils/tsconfig.d.ts +11 -9
- package/dist/utils/tsconfig.d.ts.map +1 -1
- package/dist/utils/tsconfig.js +11 -9
- package/dist/utils/tsconfig.js.map +1 -1
- package/dist/utils/typecheck-non-package.d.ts +5 -6
- package/dist/utils/typecheck-non-package.d.ts.map +1 -1
- package/dist/utils/typecheck-non-package.js +7 -8
- package/dist/utils/typecheck-non-package.js.map +1 -1
- package/dist/utils/typecheck-serialization.d.ts +8 -8
- package/dist/utils/typecheck-serialization.d.ts.map +1 -1
- package/dist/utils/typecheck-serialization.js +12 -16
- package/dist/utils/typecheck-serialization.js.map +1 -1
- package/dist/utils/vite-config.d.ts +8 -5
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +36 -29
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.js +1 -1
- package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
- package/dist/utils/worker-events.d.ts +12 -12
- package/dist/utils/worker-events.d.ts.map +1 -1
- package/dist/utils/worker-events.js +10 -10
- package/dist/utils/worker-events.js.map +1 -1
- package/dist/utils/worker-utils.d.ts +12 -13
- package/dist/utils/worker-utils.d.ts.map +1 -1
- package/dist/utils/worker-utils.js +12 -13
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js +5 -7
- package/dist/vitest-plugin.js.map +1 -1
- package/dist/workers/client.worker.d.ts +4 -2
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +209 -1
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts +1 -1
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +7 -7
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/lint.worker.d.ts +2 -2
- package/dist/workers/lint.worker.js +2 -2
- package/dist/workers/ngtsc-build.worker.js +30 -30
- package/dist/workers/ngtsc-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts +17 -17
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +46 -46
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-runtime.worker.d.ts +7 -7
- package/dist/workers/server-runtime.worker.d.ts.map +1 -1
- package/dist/workers/server-runtime.worker.js +17 -17
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/docs/config.md +340 -0
- package/docs/publish-configuration-types.md +87 -0
- package/docs/pwa-configuration-types.md +55 -0
- package/docs/vitest-plugin.md +47 -0
- package/package.json +9 -7
- package/src/angular/client-transform-stylesheet.ts +1 -1
- package/src/angular/vite-angular-plugin.ts +70 -37
- package/src/angular/vite-postcss-inline-plugin.ts +1 -1
- package/src/capacitor/capacitor.ts +159 -23
- package/src/commands/build.ts +3 -10
- package/src/commands/check.ts +3 -3
- package/src/commands/dev.ts +3 -9
- package/src/commands/device.ts +65 -0
- package/src/commands/publish.ts +30 -26
- package/src/commands/replace-deps.ts +3 -3
- package/src/commands/typecheck.ts +7 -13
- package/src/commands/watch.ts +9 -9
- package/src/electron/electron.ts +49 -4
- package/src/engines/BaseEngine.ts +4 -1
- package/src/engines/NgtscEngine.ts +7 -7
- package/src/engines/ServerEsbuildEngine.ts +7 -7
- package/src/engines/TscEngine.ts +7 -7
- package/src/engines/ViteEngine.ts +8 -13
- package/src/engines/index.ts +5 -5
- package/src/engines/types.ts +20 -20
- 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 +37 -37
- package/src/orchestrators/DevWatchOrchestrator.ts +37 -61
- package/src/sd-cli-entry.ts +51 -9
- package/src/sd-cli.ts +16 -16
- package/src/sd-config.types.ts +107 -107
- package/src/utils/angular-compiler.ts +5 -5
- package/src/utils/build-env.ts +1 -1
- package/src/utils/concurrency.ts +7 -7
- package/src/utils/copy-public.ts +17 -17
- package/src/utils/copy-src.ts +11 -11
- package/src/utils/engine-stop.ts +9 -10
- package/src/utils/esbuild-config.ts +29 -29
- package/src/utils/lint-with-program.ts +34 -34
- package/src/utils/ngtsc-build-core.ts +17 -17
- package/src/utils/output-path-rewriter.ts +18 -18
- package/src/utils/output-utils.ts +11 -11
- package/src/utils/package-utils.ts +57 -45
- package/src/utils/replace-deps.ts +92 -67
- package/src/utils/sd-config.ts +3 -3
- package/src/utils/tsc-build.ts +18 -18
- package/src/utils/tsconfig.ts +11 -9
- package/src/utils/typecheck-non-package.ts +7 -8
- package/src/utils/typecheck-serialization.ts +13 -15
- package/src/utils/vite-config.ts +45 -35
- package/src/utils/vite-scope-watch-plugin.ts +6 -1
- package/src/utils/worker-events.ts +16 -16
- package/src/utils/worker-utils.ts +12 -13
- package/src/vitest-plugin.ts +5 -8
- package/src/workers/client.worker.ts +236 -2
- package/src/workers/library-build.worker.ts +8 -8
- package/src/workers/lint.worker.ts +2 -2
- package/src/workers/ngtsc-build.worker.ts +31 -31
- package/src/workers/server-build.worker.ts +60 -60
- package/src/workers/server-runtime.worker.ts +22 -22
- package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +1 -0
- package/tests/angular/vite-angular-plugin-hmr.spec.ts +78 -0
- package/tests/angular/vite-angular-plugin.spec.ts +67 -0
- package/tests/capacitor/capacitor-build.spec.ts +6 -4
- package/tests/capacitor/capacitor-icon.spec.ts +7 -5
- package/tests/capacitor/capacitor-init.spec.ts +120 -10
- package/tests/capacitor/capacitor-run.spec.ts +14 -17
- package/tests/capacitor/capacitor-workspace.spec.ts +5 -3
- package/tests/commands/check.spec.ts +2 -2
- package/tests/commands/device.spec.ts +147 -0
- package/tests/commands/publish.spec.ts +2 -2
- package/tests/commands/typecheck.spec.ts +8 -0
- package/tests/electron/electron.spec.ts +12 -10
- package/tests/engines/base-engine.spec.ts +37 -0
- package/tests/engines/vite-engine.spec.ts +115 -3
- package/tests/orchestrators/dev-watch-orchestrator.spec.ts +21 -93
- package/tests/utils/vite-config.spec.ts +144 -90
- package/tests/workers/client-worker.spec.ts +690 -0
- package/tests/workers/server-build-worker.spec.ts +3 -3
|
@@ -9,31 +9,31 @@ import { registerCleanupHandlers, applyDebugLevel } from "../utils/worker-utils"
|
|
|
9
9
|
//#region Types
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* 서버 런타임 시작 정보
|
|
13
13
|
*/
|
|
14
14
|
export interface ServerRuntimeStartInfo {
|
|
15
15
|
mainJsPath: string;
|
|
16
|
-
/** Client Vite dev server
|
|
16
|
+
/** @fastify/http-proxy 등록을 위한 Client Vite dev server 포트 */
|
|
17
17
|
clientPorts?: Record<string, number>;
|
|
18
18
|
env?: Record<string, string>;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* 서버 준비 완료 이벤트
|
|
23
23
|
*/
|
|
24
24
|
export interface ServerRuntimeReadyEvent {
|
|
25
25
|
port: number;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* 에러 이벤트
|
|
30
30
|
*/
|
|
31
31
|
export interface ServerRuntimeErrorEvent {
|
|
32
32
|
message: string;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* 워커 이벤트 타입
|
|
37
37
|
*/
|
|
38
38
|
export interface ServerRuntimeWorkerEvents extends Record<string, unknown> {
|
|
39
39
|
serverReady: ServerRuntimeReadyEvent;
|
|
@@ -46,11 +46,11 @@ applyDebugLevel();
|
|
|
46
46
|
|
|
47
47
|
const logger = consola.withTag("sd:cli:server-runtime:worker");
|
|
48
48
|
|
|
49
|
-
/**
|
|
49
|
+
/** 서버 인스턴스 (정리 대상) */
|
|
50
50
|
let serverInstance: { close: () => Promise<void> } | undefined;
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* 리소스 정리
|
|
54
54
|
*/
|
|
55
55
|
async function cleanup(): Promise<void> {
|
|
56
56
|
const server = serverInstance;
|
|
@@ -60,15 +60,15 @@ async function cleanup(): Promise<void> {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
//
|
|
64
|
-
// (
|
|
63
|
+
// 서버 listen() 이후 발생하는 런타임 에러를 잡아 커스텀 "error" 이벤트로 전송
|
|
64
|
+
// (이 핸들러 없이는 워커가 크래시해도 빌드 Promise가 resolve되지 않아 프로세스가 중단될 수 있다)
|
|
65
65
|
process.on("uncaughtException", (err) => {
|
|
66
66
|
logger.error("서버 런타임 미처리 에러", err);
|
|
67
67
|
sender.send("error", {
|
|
68
68
|
message: errNs.message(err),
|
|
69
69
|
});
|
|
70
|
-
//
|
|
71
|
-
setTimeout(() => process.exit(1),
|
|
70
|
+
// 이벤트 전송 후 종료할 수 있도록 대기
|
|
71
|
+
setTimeout(() => process.exit(1), 500);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
process.on("unhandledRejection", (reason) => {
|
|
@@ -76,14 +76,14 @@ process.on("unhandledRejection", (reason) => {
|
|
|
76
76
|
sender.send("error", {
|
|
77
77
|
message: errNs.message(reason),
|
|
78
78
|
});
|
|
79
|
-
//
|
|
80
|
-
setTimeout(() => process.exit(1),
|
|
79
|
+
// 이벤트 전송 후 종료할 수 있도록 대기
|
|
80
|
+
setTimeout(() => process.exit(1), 500);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
registerCleanupHandlers(cleanup, logger);
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
86
|
+
* 포트가 사용 가능한지 확인한다
|
|
87
87
|
*/
|
|
88
88
|
function isPortAvailable(port: number): Promise<boolean> {
|
|
89
89
|
return new Promise((resolve) => {
|
|
@@ -97,7 +97,7 @@ function isPortAvailable(port: number): Promise<boolean> {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
100
|
+
* 지정된 포트부터 사용 가능한 포트를 찾아 반환한다
|
|
101
101
|
*/
|
|
102
102
|
async function findAvailablePort(startPort: number, maxRetries = 20): Promise<number> {
|
|
103
103
|
for (let i = 0; i < maxRetries; i++) {
|
|
@@ -112,21 +112,21 @@ async function findAvailablePort(startPort: number, maxRetries = 20): Promise<nu
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
115
|
+
* 서버 런타임 시작
|
|
116
|
+
* main.js를 import한 후 listen 수행
|
|
117
117
|
*/
|
|
118
118
|
async function start(info: ServerRuntimeStartInfo): Promise<void> {
|
|
119
119
|
try {
|
|
120
120
|
const startTime = performance.now();
|
|
121
121
|
|
|
122
|
-
//
|
|
122
|
+
// main.js import 전에 환경변수를 process.env에 주입
|
|
123
123
|
if (info.env != null) {
|
|
124
124
|
for (const [key, value] of Object.entries(info.env)) {
|
|
125
125
|
process.env[key] = value;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
//
|
|
129
|
+
// main.js import (서버 인스턴스를 export해야 함)
|
|
130
130
|
logger.debug("main.js 임포트 중...");
|
|
131
131
|
let stepStart = performance.now();
|
|
132
132
|
const module = await import(pathToFileURL(info.mainJsPath).href);
|
|
@@ -137,10 +137,10 @@ async function start(info: ServerRuntimeStartInfo): Promise<void> {
|
|
|
137
137
|
throw new Error("main.js must export a server instance.");
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
//
|
|
140
|
+
// 서버 인스턴스 저장 (정리용)
|
|
141
141
|
serverInstance = server;
|
|
142
142
|
|
|
143
|
-
//
|
|
143
|
+
// 클라이언트 프록시 등록 (listen 전)
|
|
144
144
|
if (info.clientPorts != null && Object.keys(info.clientPorts).length > 0) {
|
|
145
145
|
for (const [name, port] of Object.entries(info.clientPorts)) {
|
|
146
146
|
logger.debug(`프록시 등록: /${name} → http://127.0.0.1:${String(port)}`);
|
|
@@ -153,7 +153,7 @@ async function start(info: ServerRuntimeStartInfo): Promise<void> {
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
//
|
|
156
|
+
// 사용 가능한 포트 탐색 (포트 충돌 시 자동 증가)
|
|
157
157
|
logger.debug("사용 가능한 포트 탐색 중...");
|
|
158
158
|
stepStart = performance.now();
|
|
159
159
|
const originalPort = server.options.port;
|
|
@@ -195,6 +195,7 @@ describe("sdAngularPlugin HMR fallback", () => {
|
|
|
195
195
|
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
196
196
|
[];
|
|
197
197
|
const mockServer = {
|
|
198
|
+
config: { base: "/" },
|
|
198
199
|
middlewares: {
|
|
199
200
|
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
200
201
|
middlewares.push(fn);
|
|
@@ -17,6 +17,7 @@ describe("sdAngularPlugin HMR + component-middleware", () => {
|
|
|
17
17
|
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
18
18
|
[];
|
|
19
19
|
const mockServer = {
|
|
20
|
+
config: { base: "/" },
|
|
20
21
|
middlewares: {
|
|
21
22
|
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
22
23
|
middlewares.push(fn);
|
|
@@ -72,6 +73,7 @@ describe("sdAngularPlugin HMR + component-middleware", () => {
|
|
|
72
73
|
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
73
74
|
[];
|
|
74
75
|
const mockServer = {
|
|
76
|
+
config: { base: "/" },
|
|
75
77
|
middlewares: {
|
|
76
78
|
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
77
79
|
middlewares.push(fn);
|
|
@@ -101,6 +103,7 @@ describe("sdAngularPlugin HMR + component-middleware", () => {
|
|
|
101
103
|
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
102
104
|
[];
|
|
103
105
|
const mockServer = {
|
|
106
|
+
config: { base: "/" },
|
|
104
107
|
middlewares: {
|
|
105
108
|
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
106
109
|
middlewares.push(fn);
|
|
@@ -138,6 +141,7 @@ describe("sdAngularPlugin HMR + component-middleware", () => {
|
|
|
138
141
|
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
139
142
|
[];
|
|
140
143
|
const mockServer = {
|
|
144
|
+
config: { base: "/" },
|
|
141
145
|
middlewares: {
|
|
142
146
|
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
143
147
|
middlewares.push(fn);
|
|
@@ -177,6 +181,7 @@ describe("sdAngularPlugin HMR + component-middleware", () => {
|
|
|
177
181
|
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
178
182
|
[];
|
|
179
183
|
const mockServer = {
|
|
184
|
+
config: { base: "/" },
|
|
180
185
|
middlewares: {
|
|
181
186
|
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
182
187
|
middlewares.push(fn);
|
|
@@ -223,4 +228,77 @@ describe("sdAngularPlugin HMR + component-middleware", () => {
|
|
|
223
228
|
|
|
224
229
|
await (plugin as any).buildEnd?.call({});
|
|
225
230
|
});
|
|
231
|
+
|
|
232
|
+
// Acceptance: base path가 포함된 /@ng/component 요청도 정상 응답한다
|
|
233
|
+
it("serves /@ng/component requests with base path prefix", async () => {
|
|
234
|
+
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: true });
|
|
235
|
+
await (plugin as any).buildStart?.call({});
|
|
236
|
+
|
|
237
|
+
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
238
|
+
[];
|
|
239
|
+
const mockServer = {
|
|
240
|
+
config: { base: "/client-pda/" },
|
|
241
|
+
middlewares: {
|
|
242
|
+
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
243
|
+
middlewares.push(fn);
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
httpServer: { on: vi.fn() },
|
|
247
|
+
};
|
|
248
|
+
(plugin as any).configureServer?.(mockServer);
|
|
249
|
+
|
|
250
|
+
const middleware = middlewares[0];
|
|
251
|
+
// 실제 브라우저에서는 /client-pda/src/services/@ng/component 형태로 요청됨
|
|
252
|
+
const mockReq = {
|
|
253
|
+
url: "/client-pda/src/services/@ng/component?c=testId",
|
|
254
|
+
} as IncomingMessage;
|
|
255
|
+
|
|
256
|
+
let statusCode: number | undefined;
|
|
257
|
+
let headers: Record<string, string> = {};
|
|
258
|
+
const mockRes = {
|
|
259
|
+
writeHead(code: number, hdrs: Record<string, string>) {
|
|
260
|
+
statusCode = code;
|
|
261
|
+
headers = hdrs;
|
|
262
|
+
},
|
|
263
|
+
end: vi.fn(),
|
|
264
|
+
} as unknown as ServerResponse;
|
|
265
|
+
|
|
266
|
+
const next = vi.fn();
|
|
267
|
+
middleware(mockReq, mockRes, next);
|
|
268
|
+
|
|
269
|
+
expect(statusCode).toBe(200);
|
|
270
|
+
expect(headers["Content-Type"]).toBe("text/javascript");
|
|
271
|
+
expect(next).not.toHaveBeenCalled();
|
|
272
|
+
|
|
273
|
+
await (plugin as any).buildEnd?.call({});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Acceptance: base path가 있지만 @ng/component가 아닌 요청은 next()로 통과
|
|
277
|
+
it("passes through non-/@ng/component requests with base path", async () => {
|
|
278
|
+
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: true });
|
|
279
|
+
await (plugin as any).buildStart?.call({});
|
|
280
|
+
|
|
281
|
+
const middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => void) => void> =
|
|
282
|
+
[];
|
|
283
|
+
const mockServer = {
|
|
284
|
+
config: { base: "/client-pda/" },
|
|
285
|
+
middlewares: {
|
|
286
|
+
use: (fn: (req: IncomingMessage, res: ServerResponse, next: () => void) => void) => {
|
|
287
|
+
middlewares.push(fn);
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
httpServer: { on: vi.fn() },
|
|
291
|
+
};
|
|
292
|
+
(plugin as any).configureServer?.(mockServer);
|
|
293
|
+
|
|
294
|
+
const middleware = middlewares[0];
|
|
295
|
+
const mockReq = { url: "/client-pda/other-path" } as IncomingMessage;
|
|
296
|
+
const mockRes = {} as ServerResponse;
|
|
297
|
+
const next = vi.fn();
|
|
298
|
+
|
|
299
|
+
middleware(mockReq, mockRes, next);
|
|
300
|
+
expect(next).toHaveBeenCalled();
|
|
301
|
+
|
|
302
|
+
await (plugin as any).buildEnd?.call({});
|
|
303
|
+
});
|
|
226
304
|
});
|
|
@@ -192,6 +192,73 @@ describe("sdAngularPlugin", () => {
|
|
|
192
192
|
// (in real use, Vite server close triggers this)
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
+
// Scenario: optimizeDeps에 Angular Linker esbuild 플러그인이 등록된다 (Feature 1.1 Angular Linker)
|
|
196
|
+
it("registers angular-vite-optimize-deps esbuild plugin in optimizeDeps config", () => {
|
|
197
|
+
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: true });
|
|
198
|
+
const config = (plugin as any).config?.();
|
|
199
|
+
|
|
200
|
+
const esbuildPlugins = config?.optimizeDeps?.esbuildOptions?.plugins as
|
|
201
|
+
| { name: string }[]
|
|
202
|
+
| undefined;
|
|
203
|
+
expect(esbuildPlugins).toBeDefined();
|
|
204
|
+
expect(esbuildPlugins!.some((p) => p.name === "angular-vite-optimize-deps")).toBe(true);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Scenario: .mjs 파일이 JavaScriptTransformer를 통과한다 (Feature 1.1 Angular Linker)
|
|
208
|
+
it("transforms .mjs files through JavaScriptTransformer", async () => {
|
|
209
|
+
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: true });
|
|
210
|
+
await (plugin as any).buildStart?.call({});
|
|
211
|
+
|
|
212
|
+
const mjsCode = "export const x = 1;";
|
|
213
|
+
const result = await (plugin as any).transform?.call(
|
|
214
|
+
{},
|
|
215
|
+
mjsCode,
|
|
216
|
+
"/some/library/module.mjs",
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// .mjs 파일은 transform 결과를 반환해야 한다 (undefined가 아님)
|
|
220
|
+
expect(result).toBeDefined();
|
|
221
|
+
expect(result.code).toBeDefined();
|
|
222
|
+
expect(typeof result.code).toBe("string");
|
|
223
|
+
|
|
224
|
+
await (plugin as any).buildEnd?.call({});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Scenario: .js 파일이 JavaScriptTransformer를 통과한다 (Feature 1.1 Angular Linker)
|
|
228
|
+
it("transforms .js files through JavaScriptTransformer", async () => {
|
|
229
|
+
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: true });
|
|
230
|
+
await (plugin as any).buildStart?.call({});
|
|
231
|
+
|
|
232
|
+
const jsCode = "export const y = 2;";
|
|
233
|
+
const result = await (plugin as any).transform?.call(
|
|
234
|
+
{},
|
|
235
|
+
jsCode,
|
|
236
|
+
"/some/library/module.js",
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
expect(result).toBeDefined();
|
|
240
|
+
expect(result.code).toBeDefined();
|
|
241
|
+
expect(typeof result.code).toBe("string");
|
|
242
|
+
|
|
243
|
+
await (plugin as any).buildEnd?.call({});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Scenario: 비대상 파일(.css 등)은 transform하지 않는다 (Feature 1.1 Angular Linker)
|
|
247
|
+
it("returns undefined for non-JS files like .css", async () => {
|
|
248
|
+
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: true });
|
|
249
|
+
await (plugin as any).buildStart?.call({});
|
|
250
|
+
|
|
251
|
+
const result = await (plugin as any).transform?.call(
|
|
252
|
+
{},
|
|
253
|
+
"body { color: red; }",
|
|
254
|
+
"/some/styles.css",
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(result).toBeUndefined();
|
|
258
|
+
|
|
259
|
+
await (plugin as any).buildEnd?.call({});
|
|
260
|
+
});
|
|
261
|
+
|
|
195
262
|
// Scenario: Angular .ts 파일 transform
|
|
196
263
|
it("transforms emitted .ts files with compiled JS", async () => {
|
|
197
264
|
const plugin = sdAngularPlugin({ tsconfig: TSCONFIG_PATH, dev: false });
|
|
@@ -27,8 +27,8 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
27
27
|
copy: mockFsxCopy,
|
|
28
28
|
},
|
|
29
29
|
cpx: {
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
spawn: mockCpxSpawn,
|
|
31
|
+
spawnSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
32
32
|
},
|
|
33
33
|
pathx: {
|
|
34
34
|
posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
|
|
@@ -46,7 +46,7 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
46
46
|
|
|
47
47
|
// cpx mock (was execa)
|
|
48
48
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
49
|
-
const
|
|
49
|
+
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
50
50
|
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
51
51
|
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
52
52
|
});
|
|
@@ -82,7 +82,9 @@ vi.mock("consola", () => ({
|
|
|
82
82
|
warn: mockLoggerWarn,
|
|
83
83
|
success: mockLoggerSuccess,
|
|
84
84
|
}),
|
|
85
|
+
level: 0,
|
|
85
86
|
},
|
|
87
|
+
LogLevels: { debug: 4 },
|
|
86
88
|
}));
|
|
87
89
|
|
|
88
90
|
//#endregion
|
|
@@ -270,7 +272,7 @@ describe("Capacitor 빌드", () => {
|
|
|
270
272
|
|
|
271
273
|
// cap copy가 gradlew보다 먼저 실행되는지 확인
|
|
272
274
|
const capCopyIndex = execaCalls.findIndex(
|
|
273
|
-
(c) => c.command === "
|
|
275
|
+
(c) => c.command === "pnpm" && c.args.includes("cap") && c.args.includes("copy"),
|
|
274
276
|
);
|
|
275
277
|
const gradlewIndex = execaCalls.findIndex((c) => c.command.includes("gradlew"));
|
|
276
278
|
expect(capCopyIndex).toBeGreaterThanOrEqual(0);
|
|
@@ -25,8 +25,8 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
25
25
|
glob: mockFsxGlob,
|
|
26
26
|
},
|
|
27
27
|
cpx: {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
spawn: mockCpxSpawn,
|
|
29
|
+
spawnSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
30
30
|
},
|
|
31
31
|
pathx: {
|
|
32
32
|
posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
|
|
@@ -44,7 +44,7 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
44
44
|
|
|
45
45
|
// cpx mock (was execa)
|
|
46
46
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
47
|
-
const
|
|
47
|
+
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
48
48
|
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
49
49
|
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
50
50
|
});
|
|
@@ -82,7 +82,9 @@ vi.mock("consola", () => ({
|
|
|
82
82
|
warn: mockLoggerWarn,
|
|
83
83
|
success: mockLoggerSuccess,
|
|
84
84
|
}),
|
|
85
|
+
level: 0,
|
|
85
86
|
},
|
|
87
|
+
LogLevels: { debug: 4 },
|
|
86
88
|
}));
|
|
87
89
|
|
|
88
90
|
//#endregion
|
|
@@ -178,7 +180,7 @@ describe("Capacitor 아이콘 처리", () => {
|
|
|
178
180
|
|
|
179
181
|
// capacitor-assets generate가 실행되었는지 확인
|
|
180
182
|
const assetsCmd = execaCalls.find(
|
|
181
|
-
(c) => c.command === "
|
|
183
|
+
(c) => c.command === "pnpm" && c.args.includes("capacitor-assets"),
|
|
182
184
|
);
|
|
183
185
|
expect(assetsCmd).toBeDefined();
|
|
184
186
|
|
|
@@ -202,7 +204,7 @@ describe("Capacitor 아이콘 처리", () => {
|
|
|
202
204
|
|
|
203
205
|
// capacitor-assets generate가 실행되지 않아야 한다
|
|
204
206
|
const assetsCmd = execaCalls.find(
|
|
205
|
-
(c) => c.command === "
|
|
207
|
+
(c) => c.command === "pnpm" && c.args.includes("capacitor-assets"),
|
|
206
208
|
);
|
|
207
209
|
expect(assetsCmd).toBeUndefined();
|
|
208
210
|
});
|
|
@@ -26,8 +26,8 @@ vi.mock("@simplysm/core-node", () => ({
|
|
|
26
26
|
copy: mockFsxCopy,
|
|
27
27
|
},
|
|
28
28
|
cpx: {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
spawn: mockCpxSpawn,
|
|
30
|
+
spawnSync: vi.fn().mockReturnValue({ stdout: "", stderr: "", exitCode: 0 }),
|
|
31
31
|
},
|
|
32
32
|
pathx: {
|
|
33
33
|
posixResolve: (...args: string[]) => path.resolve(...args).replace(/\\/g, "/"),
|
|
@@ -43,7 +43,7 @@ vi.mock("@simplysm/core-common", () => ({
|
|
|
43
43
|
}));
|
|
44
44
|
|
|
45
45
|
const execaCalls: { command: string; args: string[] }[] = [];
|
|
46
|
-
const
|
|
46
|
+
const mockCpxSpawn = vi.fn((...args: unknown[]) => {
|
|
47
47
|
execaCalls.push({ command: args[0] as string, args: (args[1] as string[] | undefined) ?? [] });
|
|
48
48
|
return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
|
|
49
49
|
});
|
|
@@ -71,8 +71,10 @@ const mockLoggerDebug = vi.fn();
|
|
|
71
71
|
const mockLoggerWarn = vi.fn();
|
|
72
72
|
vi.mock("consola", () => ({
|
|
73
73
|
consola: {
|
|
74
|
+
level: 0,
|
|
74
75
|
withTag: () => ({ debug: mockLoggerDebug, warn: mockLoggerWarn }),
|
|
75
76
|
},
|
|
77
|
+
LogLevels: { debug: 4 },
|
|
76
78
|
}));
|
|
77
79
|
|
|
78
80
|
//#endregion
|
|
@@ -131,6 +133,22 @@ function setupDefaultMocks() {
|
|
|
131
133
|
if (p.includes("gradle.properties")) {
|
|
132
134
|
return "org.gradle.jvmargs=-Xmx2048m";
|
|
133
135
|
}
|
|
136
|
+
if (p.includes("styles.xml")) {
|
|
137
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
138
|
+
<resources>
|
|
139
|
+
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
|
140
|
+
<item name="colorPrimary">@color/colorPrimary</item>
|
|
141
|
+
</style>
|
|
142
|
+
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
|
143
|
+
<item name="windowActionBar">false</item>
|
|
144
|
+
<item name="windowNoTitle">true</item>
|
|
145
|
+
<item name="android:background">@null</item>
|
|
146
|
+
</style>
|
|
147
|
+
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
|
148
|
+
<item name="android:background">@drawable/splash</item>
|
|
149
|
+
</style>
|
|
150
|
+
</resources>`;
|
|
151
|
+
}
|
|
134
152
|
return "";
|
|
135
153
|
});
|
|
136
154
|
|
|
@@ -197,7 +215,7 @@ describe("Capacitor 초기화", () => {
|
|
|
197
215
|
setupDefaultMocks();
|
|
198
216
|
});
|
|
199
217
|
|
|
200
|
-
it("최초 초기화:
|
|
218
|
+
it("최초 초기화: pnpm install, cap init, cap add android를 실행한다", async () => {
|
|
201
219
|
let androidAdded = false;
|
|
202
220
|
mockFsxExists.mockImplementation((p: string) => {
|
|
203
221
|
const n = p.replace(/\\/g, "/");
|
|
@@ -220,18 +238,18 @@ describe("Capacitor 초기화", () => {
|
|
|
220
238
|
});
|
|
221
239
|
await cap.initialize();
|
|
222
240
|
|
|
223
|
-
expect(execaCalls.some((c) => c.command === "
|
|
241
|
+
expect(execaCalls.some((c) => c.command === "pnpm" && c.args.includes("install"))).toBe(true);
|
|
224
242
|
expect(
|
|
225
|
-
execaCalls.some((c) => c.command === "
|
|
243
|
+
execaCalls.some((c) => c.command === "pnpm" && c.args.includes("cap") && c.args.includes("init")),
|
|
226
244
|
).toBe(true);
|
|
227
245
|
expect(
|
|
228
246
|
execaCalls.some(
|
|
229
|
-
(c) => c.command === "
|
|
247
|
+
(c) => c.command === "pnpm" && c.args.includes("cap") && c.args.includes("add"),
|
|
230
248
|
),
|
|
231
249
|
).toBe(true);
|
|
232
250
|
});
|
|
233
251
|
|
|
234
|
-
it("재초기화: 설정 미변경 시
|
|
252
|
+
it("재초기화: 설정 미변경 시 pnpm install을 건너뛴다", async () => {
|
|
235
253
|
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
236
254
|
const cap = await Capacitor.create(PKG_PATH, {
|
|
237
255
|
appId: "com.test.app",
|
|
@@ -240,10 +258,10 @@ describe("Capacitor 초기화", () => {
|
|
|
240
258
|
});
|
|
241
259
|
await cap.initialize();
|
|
242
260
|
|
|
243
|
-
expect(execaCalls.some((c) => c.command === "
|
|
261
|
+
expect(execaCalls.some((c) => c.command === "pnpm" && c.args.includes("install"))).toBe(false);
|
|
244
262
|
});
|
|
245
263
|
|
|
246
|
-
it("플러그인 추가: package.json에 플러그인을 추가하고
|
|
264
|
+
it("플러그인 추가: package.json에 플러그인을 추가하고 pnpm install을 실행한다", async () => {
|
|
247
265
|
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
248
266
|
|
|
249
267
|
// 클라이언트 패키지의 deps에 플러그인 포함
|
|
@@ -531,6 +549,98 @@ describe("Android 네이티브 설정", () => {
|
|
|
531
549
|
expect(manifestWrite).toBeDefined();
|
|
532
550
|
});
|
|
533
551
|
|
|
552
|
+
it("styles.xml의 Theme.SplashScreen parent를 Theme.AppCompat.DayNight.NoActionBar로 변경한다", async () => {
|
|
553
|
+
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
554
|
+
const cap = await Capacitor.create(PKG_PATH, {
|
|
555
|
+
appId: "com.test.app",
|
|
556
|
+
appName: "Test App",
|
|
557
|
+
platform: { android: {} },
|
|
558
|
+
});
|
|
559
|
+
await cap.initialize();
|
|
560
|
+
|
|
561
|
+
const writeCalls = mockFsxWrite.mock.calls;
|
|
562
|
+
const stylesWrite = writeCalls.find(
|
|
563
|
+
(call) =>
|
|
564
|
+
typeof call[0] === "string" &&
|
|
565
|
+
call[0].includes("styles.xml") &&
|
|
566
|
+
typeof call[1] === "string" &&
|
|
567
|
+
call[1].includes('parent="Theme.AppCompat.DayNight.NoActionBar"'),
|
|
568
|
+
);
|
|
569
|
+
expect(stylesWrite).toBeDefined();
|
|
570
|
+
// android:background는 유지
|
|
571
|
+
expect((stylesWrite![1] as string)).toContain("@drawable/splash");
|
|
572
|
+
// Theme.SplashScreen은 제거됨
|
|
573
|
+
expect((stylesWrite![1] as string)).not.toContain('parent="Theme.SplashScreen"');
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
it("이미 변경된 styles.xml은 재변경하지 않는다", async () => {
|
|
577
|
+
mockFsxRead.mockImplementation((p: string) => {
|
|
578
|
+
if (p.includes("styles.xml")) {
|
|
579
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
580
|
+
<resources>
|
|
581
|
+
<style name="AppTheme.NoActionBarLaunch" parent="Theme.AppCompat.DayNight.NoActionBar">
|
|
582
|
+
<item name="android:background">@drawable/splash</item>
|
|
583
|
+
</style>
|
|
584
|
+
</resources>`;
|
|
585
|
+
}
|
|
586
|
+
if (p.includes("AndroidManifest.xml")) {
|
|
587
|
+
return '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n<application>\n<activity android:name=".MainActivity">\n</activity>\n</application>\n</manifest>';
|
|
588
|
+
}
|
|
589
|
+
if (p.includes("build.gradle")) {
|
|
590
|
+
return `android {
|
|
591
|
+
defaultConfig {
|
|
592
|
+
versionCode 1
|
|
593
|
+
versionName "1.0"
|
|
594
|
+
minSdkVersion rootProject.ext.minSdkVersion
|
|
595
|
+
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
596
|
+
}
|
|
597
|
+
buildTypes { release { } }
|
|
598
|
+
}`;
|
|
599
|
+
}
|
|
600
|
+
if (p.includes("gradle.properties")) {
|
|
601
|
+
return "org.gradle.jvmargs=-Xmx2048m";
|
|
602
|
+
}
|
|
603
|
+
return "";
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
607
|
+
const cap = await Capacitor.create(PKG_PATH, {
|
|
608
|
+
appId: "com.test.app",
|
|
609
|
+
appName: "Test App",
|
|
610
|
+
platform: { android: {} },
|
|
611
|
+
});
|
|
612
|
+
await cap.initialize();
|
|
613
|
+
|
|
614
|
+
const writeCalls = mockFsxWrite.mock.calls;
|
|
615
|
+
const stylesWrite = writeCalls.find(
|
|
616
|
+
(call) =>
|
|
617
|
+
typeof call[0] === "string" &&
|
|
618
|
+
call[0].includes("styles.xml"),
|
|
619
|
+
);
|
|
620
|
+
expect(stylesWrite).toBeUndefined();
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it("styles.xml이 없으면 warn을 출력한다", async () => {
|
|
624
|
+
mockFsxExists.mockImplementation((p: string) => {
|
|
625
|
+
const n = p.replace(/\\/g, "/");
|
|
626
|
+
if (n.includes(".capacitor.lock")) return false;
|
|
627
|
+
if (n.includes("styles.xml")) return false;
|
|
628
|
+
return true;
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
632
|
+
const cap = await Capacitor.create(PKG_PATH, {
|
|
633
|
+
appId: "com.test.app",
|
|
634
|
+
appName: "Test App",
|
|
635
|
+
platform: { android: {} },
|
|
636
|
+
});
|
|
637
|
+
await cap.initialize();
|
|
638
|
+
|
|
639
|
+
expect(mockLoggerWarn).toHaveBeenCalledWith(
|
|
640
|
+
expect.stringContaining("styles.xml"),
|
|
641
|
+
);
|
|
642
|
+
});
|
|
643
|
+
|
|
534
644
|
it("application 태그에 커스텀 속성을 추가한다", async () => {
|
|
535
645
|
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
536
646
|
const cap = await Capacitor.create(PKG_PATH, {
|