@simplysm/sd-cli 14.1.9 → 14.1.10
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/capacitor/capacitor-icon.js +2 -2
- package/dist/capacitor/capacitor-icon.js.map +1 -1
- package/dist/capacitor/capacitor-npm-config.d.ts +1 -1
- package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
- package/dist/capacitor/capacitor-npm-config.js +11 -18
- package/dist/capacitor/capacitor-npm-config.js.map +1 -1
- package/dist/capacitor/capacitor.d.ts +1 -1
- package/dist/capacitor/capacitor.js +2 -2
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +1 -0
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/device.js +2 -2
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/init/generators/root.d.ts.map +1 -1
- package/dist/commands/init/generators/root.js +0 -1
- package/dist/commands/init/generators/root.js.map +1 -1
- package/dist/commands/init/init-client.js +1 -1
- package/dist/commands/init/init-client.js.map +1 -1
- package/dist/commands/init/init.js +2 -2
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/publish/deployment-phase.d.ts.map +1 -1
- package/dist/commands/publish/deployment-phase.js +1 -0
- package/dist/commands/publish/deployment-phase.js.map +1 -1
- package/dist/commands/publish/npm-publisher.js +3 -3
- package/dist/commands/publish/npm-publisher.js.map +1 -1
- package/dist/commands/publish/post-publish-phase.d.ts.map +1 -1
- package/dist/commands/publish/post-publish-phase.js +1 -0
- package/dist/commands/publish/post-publish-phase.js.map +1 -1
- package/dist/commands/publish/publish-command.d.ts.map +1 -1
- package/dist/commands/publish/publish-command.js +7 -12
- package/dist/commands/publish/publish-command.js.map +1 -1
- package/dist/deps/replace-deps/collect-deps.js +4 -4
- package/dist/deps/replace-deps/collect-deps.js.map +1 -1
- package/dist/deps/replace-deps/replace-deps-resolve.d.ts +4 -12
- package/dist/deps/replace-deps/replace-deps-resolve.d.ts.map +1 -1
- package/dist/deps/replace-deps/replace-deps-resolve.js +13 -49
- package/dist/deps/replace-deps/replace-deps-resolve.js.map +1 -1
- package/dist/deps/replace-deps/replace-deps.d.ts +2 -2
- package/dist/deps/replace-deps/replace-deps.js +3 -3
- package/dist/deps/server-externals/server-production-files.d.ts +3 -3
- package/dist/deps/server-externals/server-production-files.d.ts.map +1 -1
- package/dist/deps/server-externals/server-production-files.js +24 -17
- package/dist/deps/server-externals/server-production-files.js.map +1 -1
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +6 -11
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts +1 -0
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +2 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/esbuild/esbuild-config.d.ts +6 -2
- package/dist/esbuild/esbuild-config.d.ts.map +1 -1
- package/dist/esbuild/esbuild-config.js +4 -3
- package/dist/esbuild/esbuild-config.js.map +1 -1
- package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -1
- package/dist/esbuild/esbuild-tsc-plugin.js +3 -1
- package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -1
- package/dist/orchestrators/BaseOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BaseOrchestrator.js +1 -0
- package/dist/orchestrators/BaseOrchestrator.js.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +3 -5
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevOrchestrator.js +1 -0
- package/dist/orchestrators/DevOrchestrator.js.map +1 -1
- package/dist/orchestrators/ServerRuntimeManager.d.ts.map +1 -1
- package/dist/orchestrators/ServerRuntimeManager.js +4 -0
- package/dist/orchestrators/ServerRuntimeManager.js.map +1 -1
- package/dist/orchestrators/TypecheckOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/TypecheckOrchestrator.js +4 -6
- package/dist/orchestrators/TypecheckOrchestrator.js.map +1 -1
- package/dist/runtime/engine-watch-events.d.ts.map +1 -1
- package/dist/runtime/engine-watch-events.js +5 -0
- package/dist/runtime/engine-watch-events.js.map +1 -1
- package/dist/runtime/worker-events.d.ts +1 -0
- package/dist/runtime/worker-events.d.ts.map +1 -1
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +0 -4
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +2 -0
- package/dist/sd-cli.js.map +1 -1
- package/dist/typecheck/typecheck-non-package.d.ts.map +1 -1
- package/dist/typecheck/typecheck-non-package.js +10 -0
- package/dist/typecheck/typecheck-non-package.js.map +1 -1
- package/dist/utils/package-utils.d.ts +8 -6
- package/dist/utils/package-utils.d.ts.map +1 -1
- package/dist/utils/package-utils.js +26 -24
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/workspace-utils.d.ts +17 -0
- package/dist/utils/workspace-utils.d.ts.map +1 -0
- package/dist/utils/workspace-utils.js +95 -0
- package/dist/utils/workspace-utils.js.map +1 -0
- package/dist/workers/client.worker.d.ts +1 -0
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +8 -3
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts +1 -0
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +3 -2
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts +1 -0
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +12 -12
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-esbuild-context.d.ts.map +1 -1
- package/dist/workers/server-esbuild-context.js +4 -2
- package/dist/workers/server-esbuild-context.js.map +1 -1
- package/dist/workers/server-runtime.worker.d.ts +1 -0
- package/dist/workers/server-runtime.worker.d.ts.map +1 -1
- package/dist/workers/server-runtime.worker.js +9 -3
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/dist/workers/server-watch-manager.d.ts +1 -1
- package/dist/workers/server-watch-manager.d.ts.map +1 -1
- package/dist/workers/server-watch-manager.js +2 -2
- package/dist/workers/server-watch-manager.js.map +1 -1
- package/package.json +11 -11
- package/src/capacitor/capacitor-icon.ts +2 -2
- package/src/capacitor/capacitor-npm-config.ts +10 -19
- package/src/capacitor/capacitor.ts +2 -2
- package/src/commands/check.ts +1 -0
- package/src/commands/device.ts +2 -2
- package/src/commands/init/generators/root.ts +0 -1
- package/src/commands/init/init-client.ts +1 -1
- package/src/commands/init/init.ts +2 -2
- package/src/commands/init/templates/workspace-root/mise.toml.hbs +1 -1
- package/src/commands/publish/deployment-phase.ts +1 -0
- package/src/commands/publish/npm-publisher.ts +3 -3
- package/src/commands/publish/post-publish-phase.ts +1 -0
- package/src/commands/publish/publish-command.ts +7 -15
- package/src/deps/replace-deps/collect-deps.ts +4 -4
- package/src/deps/replace-deps/replace-deps-resolve.ts +13 -56
- package/src/deps/replace-deps/replace-deps.ts +3 -3
- package/src/deps/server-externals/server-production-files.ts +31 -18
- package/src/electron/electron.ts +7 -13
- package/src/engines/BaseEngine.ts +3 -2
- package/src/esbuild/esbuild-config.ts +12 -3
- package/src/esbuild/esbuild-tsc-plugin.ts +4 -1
- package/src/orchestrators/BaseOrchestrator.ts +1 -0
- package/src/orchestrators/BuildOrchestrator.ts +3 -5
- package/src/orchestrators/DevOrchestrator.ts +1 -0
- package/src/orchestrators/ServerRuntimeManager.ts +4 -0
- package/src/orchestrators/TypecheckOrchestrator.ts +4 -6
- package/src/runtime/engine-watch-events.ts +7 -1
- package/src/runtime/worker-events.ts +1 -0
- package/src/sd-cli-entry.ts +0 -9
- package/src/sd-cli.ts +2 -0
- package/src/typecheck/typecheck-non-package.ts +11 -0
- package/src/utils/package-utils.ts +30 -23
- package/src/utils/workspace-utils.ts +117 -0
- package/src/workers/client.worker.ts +9 -4
- package/src/workers/library-build.worker.ts +4 -3
- package/src/workers/server-build.worker.ts +13 -13
- package/src/workers/server-esbuild-context.ts +5 -2
- package/src/workers/server-runtime.worker.ts +10 -3
- package/src/workers/server-watch-manager.ts +3 -3
- package/tests/capacitor/capacitor-build.spec.ts +142 -142
- package/tests/capacitor/capacitor-init.spec.ts +181 -181
- package/tests/capacitor/capacitor-npm-config.acc.spec.ts +114 -114
- package/tests/capacitor/capacitor-npm-config.spec.ts +94 -94
- package/tests/commands/publish-manifest.acc.spec.ts +67 -0
- package/tests/deps/replace-deps/collect-deps.acc.spec.ts +16 -1
- package/tests/deps/replace-deps/replace-deps-resolve.acc.spec.ts +9 -5
- package/tests/deps/replace-deps/replace-deps-setup.acc.spec.ts +3 -3
- package/tests/deps/server-externals/server-production-files.spec.ts +68 -0
- package/tests/electron/electron.spec.ts +608 -608
- package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-browser.tsbuildinfo +1 -1
- package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-node.tsbuildinfo +1 -1
- package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck.tsbuildinfo +1 -1
- package/tests/utils/engine-watch-events.spec.ts +17 -0
- package/tests/utils/esbuild-config.spec.ts +15 -0
- package/tests/utils/package-utils.spec.ts +36 -4
- package/tests/utils/replace-deps-watch.acc.spec.ts +4 -4
- package/tests/utils/replace-deps-watch.spec.ts +3 -3
- package/tests/utils/replace-deps.spec.ts +1 -35
- package/tests/utils/workspace-utils.spec.ts +87 -0
- package/tests/workers/library-build-worker.spec.ts +1 -1
- package/tests/workers/server-esbuild-context.spec.ts +4 -3
- package/dist/commands/reinstall.d.ts +0 -13
- package/dist/commands/reinstall.d.ts.map +0 -1
- package/dist/commands/reinstall.js +0 -56
- package/dist/commands/reinstall.js.map +0 -1
- package/src/commands/init/templates/workspace-root/pnpm-workspace.yaml +0 -5
- package/src/commands/reinstall.ts +0 -63
- package/tests/angular/angular-compiler-hmr-removal.verify.md +0 -16
- package/tests/angular/onbuild-lint-removal.verify.md +0 -8
- package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +0 -13
- package/tests/angular/vite-angular-plugin-vitest.verify.md +0 -20
- package/tests/capacitor/capacitor-android-exports.verify.md +0 -11
- package/tests/commands/publish-npm-local-split.verify.md +0 -9
- package/tests/commands/publish-responsibility-split.verify.md +0 -13
- package/tests/commands/publish-set.verify.md +0 -7
- package/tests/commands/publish-storage-split.verify.md +0 -8
- package/tests/commands/slice3-severity-cleanup.verify.md +0 -12
- package/tests/deps/deps-directory-separation.verify.md +0 -15
- package/tests/deps/replace-deps/replace-deps-perf.verify.md +0 -15
- package/tests/deps/server-externals/mise-toml-parse-intent.verify.md +0 -16
- package/tests/electron/electron-symlink-cleanup.verify.md +0 -8
- package/tests/engines/engine-duplicate-output-removal.verify.md +0 -10
- package/tests/engines/engine-typecheck-selection.verify.md +0 -8
- package/tests/engines/esbuild-client-engine.verify.md +0 -15
- package/tests/engines/normalize-result.verify.md +0 -9
- package/tests/engines/vite-dependency-cleanup.verify.md +0 -24
- package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +0 -23
- package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +0 -21
- package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +0 -16
- package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +0 -15
- package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +0 -31
- package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +0 -59
- package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +0 -21
- package/tests/esbuild/esbuild-postcss-plugin-chunking.verify.md +0 -17
- package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +0 -13
- package/tests/esbuild/esbuild-worker-plugin-node.verify.md +0 -12
- package/tests/esbuild/esbuild-worker-plugin.verify.md +0 -7
- package/tests/orchestrators/dist-delete-watcher.verify.md +0 -10
- package/tests/orchestrators/orchestrator-baseenv.verify.md +0 -10
- package/tests/orchestrators/orchestrator-diagnostic-formatting.verify.md +0 -10
- package/tests/orchestrators/orchestrator-initializemode-signature.verify.md +0 -9
- package/tests/orchestrators/slice1-stdout-to-consola.verify.md +0 -10
- package/tests/sd-cli-catch-all.verify.md +0 -7
- package/tests/sd-cli-log-tag.verify.md +0 -11
- package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +0 -8
- package/tests/ts-compiler/SdTsCompiler-crash-handling.verify.md +0 -24
- package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +0 -12
- package/tests/ts-compiler/SdTsCompiler-emit.verify.md +0 -9
- package/tests/ts-compiler/SdTsCompiler.verify.md +0 -41
- package/tests/ts-compiler/scss-lint-integration.verify.md +0 -14
- package/tests/utils/copy-public-outdir.verify.md +0 -8
- package/tests/utils/dev-http-server.verify.md +0 -8
- package/tests/utils/engine-watch-events.verify.md +0 -17
- package/tests/utils/esbuild-client-config-integration.verify.md +0 -9
- package/tests/utils/esbuild-client-config-postcss.verify.md +0 -6
- package/tests/utils/esbuild-client-config.verify.md +0 -26
- package/tests/utils/esbuild-index-html.verify.md +0 -10
- package/tests/utils/esbuild-pwa.verify.md +0 -9
- package/tests/utils/esbuild-scss-plugin.verify.md +0 -8
- package/tests/utils/hmr-service.verify.md +0 -17
- package/tests/utils/lint-core-import-paths.verify.md +0 -10
- package/tests/utils/replace-deps-split.verify.md +0 -15
- package/tests/utils/replace-deps-watch.verify.md +0 -9
- package/tests/utils/server-production-files-import-paths.verify.md +0 -14
- package/tests/utils/vite-config-cleanup.verify.md +0 -7
- package/tests/workers/build-watch-paths-library.verify.md +0 -10
- package/tests/workers/build-watch-paths-ngtsc-server.verify.md +0 -12
- package/tests/workers/client-worker-browser-support.verify.md +0 -7
- package/tests/workers/client-worker-cleanup.verify.md +0 -8
- package/tests/workers/client-worker-initial-build-error.verify.md +0 -7
- package/tests/workers/client-worker-initial-build-warnings.verify.md +0 -7
- package/tests/workers/client-worker-mtime-incremental.verify.md +0 -10
- package/tests/workers/client-worker-onend-sync.verify.md +0 -7
- package/tests/workers/client-worker-refactor.verify.md +0 -22
- package/tests/workers/client-worker-ts-cache-invalidation.verify.md +0 -12
- package/tests/workers/dev-port-file.verify.md +0 -6
- package/tests/workers/ngtsc-build-rootnames-refresh.verify.md +0 -8
- package/tests/workers/server-build-context-dispose.verify.md +0 -8
- package/tests/workers/server-build-worker-plugin.verify.md +0 -9
- package/tests/workers/server-build-worker-refactoring.verify.md +0 -14
- package/tests/workers/server-esbuild-context-integration.verify.md +0 -10
- package/tests/workers/server-esbuild-context-tsc.verify.md +0 -7
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { globSync } from "glob";
|
|
4
|
+
import { pathx } from "@simplysm/core-node";
|
|
5
|
+
|
|
6
|
+
export interface WorkspacePackageDir {
|
|
7
|
+
dirName: string;
|
|
8
|
+
packageName: string;
|
|
9
|
+
relPath: string;
|
|
10
|
+
absPath: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface WorkspaceRootPackageJson {
|
|
14
|
+
workspaces?: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface WorkspacePackageJson {
|
|
18
|
+
name?: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* root package.json의 workspaces 값을 Bun workspace 패턴 배열로 정규화한다.
|
|
23
|
+
*/
|
|
24
|
+
export function parsePackageJsonWorkspaces(workspaces: unknown): string[] {
|
|
25
|
+
const rawPatterns = Array.isArray(workspaces)
|
|
26
|
+
? workspaces
|
|
27
|
+
: typeof workspaces === "object" && workspaces != null && Array.isArray((workspaces as { packages?: unknown }).packages)
|
|
28
|
+
? (workspaces as { packages: unknown[] }).packages
|
|
29
|
+
: [];
|
|
30
|
+
|
|
31
|
+
return rawPatterns
|
|
32
|
+
.filter((item): item is string => typeof item === "string")
|
|
33
|
+
.map((item) => item.trim())
|
|
34
|
+
.filter((item) => item !== "");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function readWorkspacePatterns(workspaceRoot: string): string[] {
|
|
38
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json");
|
|
39
|
+
if (!fs.existsSync(packageJsonPath)) return [];
|
|
40
|
+
|
|
41
|
+
const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as WorkspaceRootPackageJson;
|
|
42
|
+
return parsePackageJsonWorkspaces(pkgJson.workspaces);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function findWorkspaceRoot(startDir: string): string | undefined {
|
|
46
|
+
let current = path.resolve(startDir);
|
|
47
|
+
if (fs.existsSync(current) && fs.statSync(current).isFile()) {
|
|
48
|
+
current = path.dirname(current);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
while (true) {
|
|
52
|
+
if (readWorkspacePatterns(current).length > 0) {
|
|
53
|
+
return pathx.posix(current);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const parent = path.dirname(current);
|
|
57
|
+
if (parent === current) return undefined;
|
|
58
|
+
current = parent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function splitWorkspacePatterns(patterns: string[]): { include: string[]; exclude: string[] } {
|
|
63
|
+
const include: string[] = [];
|
|
64
|
+
const exclude: string[] = [];
|
|
65
|
+
|
|
66
|
+
for (const pattern of patterns) {
|
|
67
|
+
if (pattern.startsWith("!")) {
|
|
68
|
+
const excluded = pattern.slice(1).trim();
|
|
69
|
+
if (excluded !== "") exclude.push(excluded);
|
|
70
|
+
} else {
|
|
71
|
+
include.push(pattern);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { include, exclude };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Bun workspace root의 package.json#workspaces 기준으로 실제 패키지 디렉터리를 수집한다.
|
|
80
|
+
*/
|
|
81
|
+
export function collectWorkspacePackages(workspaceRoot: string): WorkspacePackageDir[] {
|
|
82
|
+
const root = pathx.posix(path.resolve(workspaceRoot));
|
|
83
|
+
const patterns = readWorkspacePatterns(root);
|
|
84
|
+
const { include, exclude } = splitWorkspacePatterns(patterns);
|
|
85
|
+
const absDirs = new Set<string>();
|
|
86
|
+
|
|
87
|
+
for (const pattern of include) {
|
|
88
|
+
const matches = globSync(pattern, {
|
|
89
|
+
cwd: root,
|
|
90
|
+
absolute: true,
|
|
91
|
+
nodir: false,
|
|
92
|
+
ignore: exclude,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
for (const match of matches) {
|
|
96
|
+
const absPath = pathx.posix(path.resolve(match));
|
|
97
|
+
const packageJsonPath = path.join(absPath, "package.json");
|
|
98
|
+
if (!fs.existsSync(packageJsonPath)) continue;
|
|
99
|
+
if (!fs.statSync(absPath).isDirectory()) continue;
|
|
100
|
+
absDirs.add(absPath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return [...absDirs]
|
|
105
|
+
.sort((a, b) => a.localeCompare(b))
|
|
106
|
+
.map((absPath): WorkspacePackageDir => {
|
|
107
|
+
const relPath = pathx.posix(path.relative(root, absPath));
|
|
108
|
+
const pkgJson = JSON.parse(fs.readFileSync(path.join(absPath, "package.json"), "utf-8")) as WorkspacePackageJson;
|
|
109
|
+
const packageName = typeof pkgJson.name === "string" ? pkgJson.name : path.basename(absPath);
|
|
110
|
+
return {
|
|
111
|
+
dirName: path.basename(absPath),
|
|
112
|
+
packageName,
|
|
113
|
+
relPath,
|
|
114
|
+
absPath,
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -57,7 +57,7 @@ export interface ClientWorkerEvents extends Record<string, unknown> {
|
|
|
57
57
|
buildStart: Record<string, never>;
|
|
58
58
|
build: ClientBuildResult;
|
|
59
59
|
serverReady: { port: number };
|
|
60
|
-
error: { message: string };
|
|
60
|
+
error: { message: string; stack?: string };
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
//#endregion
|
|
@@ -207,6 +207,7 @@ async function build(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
|
207
207
|
errors.push(errNs.message(err));
|
|
208
208
|
}
|
|
209
209
|
logger.debug(`[${info.name}] client worker build 예외: ${errors.join("\n")}`);
|
|
210
|
+
logger.debug(`[${info.name}] client worker build 예외 스택:\n${errNs.stack(err)}`);
|
|
210
211
|
return { success: false, errors };
|
|
211
212
|
}
|
|
212
213
|
}
|
|
@@ -313,8 +314,10 @@ function createDevBuildEndHandler(
|
|
|
313
314
|
}
|
|
314
315
|
} catch (err) {
|
|
315
316
|
const message = errNs.message(err);
|
|
317
|
+
const stack = errNs.stack(err);
|
|
318
|
+
logger.debug(`client dev build end 예외 스택:\n${stack}`);
|
|
316
319
|
if (!isInitialBuild) {
|
|
317
|
-
sender.send("error", { message });
|
|
320
|
+
sender.send("error", { message, stack });
|
|
318
321
|
} else {
|
|
319
322
|
isInitialBuild = false;
|
|
320
323
|
initialBuildResolve?.({
|
|
@@ -423,7 +426,7 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
|
423
426
|
hmrService?.broadcast({ type: "full-reload" });
|
|
424
427
|
sender.send("build", { success: true });
|
|
425
428
|
} catch (err) {
|
|
426
|
-
sender.send("error", { message: errNs.message(err) });
|
|
429
|
+
sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
|
|
427
430
|
}
|
|
428
431
|
});
|
|
429
432
|
|
|
@@ -437,7 +440,9 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
|
|
|
437
440
|
return initialResult;
|
|
438
441
|
} catch (err) {
|
|
439
442
|
const message = errNs.message(err);
|
|
440
|
-
|
|
443
|
+
const stack = errNs.stack(err);
|
|
444
|
+
logger.debug(`[${info.name}] client worker startWatch 예외 스택:\n${stack}`);
|
|
445
|
+
sender.send("error", { message, stack });
|
|
441
446
|
return { success: false, errors: [message] };
|
|
442
447
|
}
|
|
443
448
|
}
|
|
@@ -36,7 +36,7 @@ export interface CombinedBuildEvent {
|
|
|
36
36
|
export interface LibraryBuildWorkerEvents extends Record<string, unknown> {
|
|
37
37
|
buildStart: Record<string, never>;
|
|
38
38
|
build: CombinedBuildEvent;
|
|
39
|
-
error: { message: string };
|
|
39
|
+
error: { message: string; stack?: string };
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
//#endregion
|
|
@@ -135,6 +135,7 @@ async function build(info: LibraryBuildInfo): Promise<LibraryBuildResult> {
|
|
|
135
135
|
} catch (err) {
|
|
136
136
|
const message = errNs.message(err);
|
|
137
137
|
logger.debug(`[${info.name}] library worker build 예외 발생: ${message}`);
|
|
138
|
+
logger.debug(`[${info.name}] library worker build 예외 스택:\n${errNs.stack(err)}`);
|
|
138
139
|
return {
|
|
139
140
|
build: { success: false, errors: [message], diagnostics: [] },
|
|
140
141
|
};
|
|
@@ -323,11 +324,11 @@ async function startWatch(info: LibraryBuildInfo): Promise<void> {
|
|
|
323
324
|
const event = buildWatchEvent(info, result, changedScssFiles);
|
|
324
325
|
sender.send("build", event);
|
|
325
326
|
} catch (err) {
|
|
326
|
-
sender.send("error", { message: errNs.message(err) });
|
|
327
|
+
sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
|
|
327
328
|
}
|
|
328
329
|
});
|
|
329
330
|
} catch (err) {
|
|
330
|
-
sender.send("error", { message: errNs.message(err) });
|
|
331
|
+
sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
|
|
331
332
|
}
|
|
332
333
|
}
|
|
333
334
|
|
|
@@ -92,7 +92,7 @@ export interface ServerCombinedBuildEvent {
|
|
|
92
92
|
export interface ServerBuildWorkerEvents extends Record<string, unknown> {
|
|
93
93
|
buildStart: Record<string, never>;
|
|
94
94
|
build: ServerCombinedBuildEvent;
|
|
95
|
-
error: { message: string };
|
|
95
|
+
error: { message: string; stack?: string };
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
//#endregion
|
|
@@ -169,7 +169,7 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
|
|
|
169
169
|
jsResult = await esbuild.build({ ...esbuildOptions, plugins: [createWorkerBundlePlugin(), tscPlugin.plugin] })
|
|
170
170
|
.then(async (result) => {
|
|
171
171
|
if (result.outputFiles) {
|
|
172
|
-
await writeChangedOutputFiles(result.outputFiles);
|
|
172
|
+
await writeChangedOutputFiles(result.outputFiles, { rewriteJsExtensions: false });
|
|
173
173
|
}
|
|
174
174
|
const errors = formatEsbuildMessages(result.errors, "error");
|
|
175
175
|
const warnings = formatEsbuildMessages(result.warnings, "warning");
|
|
@@ -179,11 +179,14 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
|
|
|
179
179
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
180
180
|
};
|
|
181
181
|
})
|
|
182
|
-
.catch((err) =>
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
.catch((err) => {
|
|
183
|
+
logger.debug(`[${info.name}] server esbuild build 예외 스택:\n${errNs.stack(err)}`);
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
errors: [errNs.message(err)],
|
|
187
|
+
warnings: undefined,
|
|
188
|
+
};
|
|
189
|
+
});
|
|
187
190
|
|
|
188
191
|
tscErrors = tscPlugin.getErrors() ?? [];
|
|
189
192
|
tscDiagnostics = tscPlugin.getDiagnostics();
|
|
@@ -231,11 +234,8 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
|
|
|
231
234
|
};
|
|
232
235
|
} catch (err) {
|
|
233
236
|
const message = errNs.message(err);
|
|
234
|
-
const stack = err instanceof Error ? err.stack : undefined;
|
|
235
237
|
logger.debug(`[${info.name}] server worker build 예외: ${message}`);
|
|
236
|
-
|
|
237
|
-
logger.debug(`[${info.name}] 스택 트레이스:\n${stack}`);
|
|
238
|
-
}
|
|
238
|
+
logger.debug(`[${info.name}] 스택 트레이스:\n${errNs.stack(err)}`);
|
|
239
239
|
return {
|
|
240
240
|
build: { success: false, errors: [message], diagnostics: [] },
|
|
241
241
|
mainJsPath,
|
|
@@ -358,11 +358,11 @@ async function startWatch(info: ServerWatchInfo): Promise<void> {
|
|
|
358
358
|
initialExternals: cachedExternal,
|
|
359
359
|
onBuildStart: () => sender.send("buildStart", {}),
|
|
360
360
|
onBuild: (result) => sender.send("build", result),
|
|
361
|
-
onError: (message) => sender.send("error", { message }),
|
|
361
|
+
onError: (message, stack) => sender.send("error", { message, stack }),
|
|
362
362
|
rebuild: () => rebuildAll(),
|
|
363
363
|
});
|
|
364
364
|
} catch (err) {
|
|
365
|
-
sender.send("error", { message: errNs.message(err) });
|
|
365
|
+
sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type ts from "typescript";
|
|
2
2
|
import esbuild from "esbuild";
|
|
3
|
-
import { err as errNs } from "@simplysm/core-common";
|
|
3
|
+
import { createLogger, err as errNs } from "@simplysm/core-common";
|
|
4
4
|
import { formatEsbuildMessages } from "../utils/output-utils";
|
|
5
5
|
import {
|
|
6
6
|
createServerEsbuildOptions,
|
|
@@ -12,6 +12,8 @@ import type { SerializedDiagnostic } from "../typecheck/typecheck-serialization"
|
|
|
12
12
|
import type { LintWithProgramResult } from "../lint/lint-with-program";
|
|
13
13
|
import { createWorkerBundlePlugin } from "../esbuild/esbuild-worker-plugin";
|
|
14
14
|
|
|
15
|
+
const logger = createLogger("sd:cli:server-esbuild-context");
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
18
|
* esbuild watch context 생성 옵션
|
|
17
19
|
*/
|
|
@@ -87,6 +89,7 @@ export async function rebuild(): Promise<{
|
|
|
87
89
|
try {
|
|
88
90
|
result = await context.rebuild();
|
|
89
91
|
} catch (err) {
|
|
92
|
+
logger.debug(`server esbuild rebuild 예외 스택:\n${errNs.stack(err)}`);
|
|
90
93
|
const tscErrors = tscPlugin?.getErrors() ?? [];
|
|
91
94
|
const allErrors = [errNs.message(err), ...tscErrors];
|
|
92
95
|
return {
|
|
@@ -101,7 +104,7 @@ export async function rebuild(): Promise<{
|
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
if (result.outputFiles) {
|
|
104
|
-
await writeChangedOutputFiles(result.outputFiles);
|
|
107
|
+
await writeChangedOutputFiles(result.outputFiles, { rewriteJsExtensions: false });
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
const esbuildErrors = formatEsbuildMessages(result.errors, "error");
|
|
@@ -32,6 +32,7 @@ export interface ServerRuntimeReadyEvent {
|
|
|
32
32
|
*/
|
|
33
33
|
export interface ServerRuntimeErrorEvent {
|
|
34
34
|
message: string;
|
|
35
|
+
stack?: string;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -73,18 +74,22 @@ async function cleanup(): Promise<void> {
|
|
|
73
74
|
// 서버 listen() 이후 발생하는 런타임 에러를 잡아 커스텀 "error" 이벤트로 전송
|
|
74
75
|
// (이 핸들러 없이는 워커가 크래시해도 빌드 Promise가 resolve되지 않아 프로세스가 중단될 수 있다)
|
|
75
76
|
process.on("uncaughtException", (err) => {
|
|
76
|
-
logger.error("서버 런타임 미처리 에러", err);
|
|
77
|
+
logger.error("서버 런타임 미처리 에러", errNs.message(err));
|
|
78
|
+
logger.debug(`서버 런타임 미처리 에러 스택:\n${errNs.stack(err)}`);
|
|
77
79
|
sender.send("error", {
|
|
78
80
|
message: errNs.message(err),
|
|
81
|
+
stack: errNs.stack(err),
|
|
79
82
|
});
|
|
80
83
|
// 이벤트 전송 후 종료할 수 있도록 대기
|
|
81
84
|
setTimeout(() => process.exit(1), 500);
|
|
82
85
|
});
|
|
83
86
|
|
|
84
87
|
process.on("unhandledRejection", (reason) => {
|
|
85
|
-
logger.error("서버 런타임 미처리 Promise 거부", reason);
|
|
88
|
+
logger.error("서버 런타임 미처리 Promise 거부", errNs.message(reason));
|
|
89
|
+
logger.debug(`서버 런타임 미처리 Promise 거부 스택:\n${errNs.stack(reason)}`);
|
|
86
90
|
sender.send("error", {
|
|
87
91
|
message: errNs.message(reason),
|
|
92
|
+
stack: errNs.stack(reason),
|
|
88
93
|
});
|
|
89
94
|
// 이벤트 전송 후 종료할 수 있도록 대기
|
|
90
95
|
setTimeout(() => process.exit(1), 500);
|
|
@@ -195,9 +200,11 @@ async function start(info: ServerRuntimeStartInfo): Promise<void> {
|
|
|
195
200
|
|
|
196
201
|
sender.send("serverReady", { port: server.options.port });
|
|
197
202
|
} catch (err) {
|
|
198
|
-
logger.error("서버 런타임 시작 실패", err);
|
|
203
|
+
logger.error("서버 런타임 시작 실패", errNs.message(err));
|
|
204
|
+
logger.debug(`서버 런타임 시작 실패 스택:\n${errNs.stack(err)}`);
|
|
199
205
|
sender.send("error", {
|
|
200
206
|
message: errNs.message(err),
|
|
207
|
+
stack: errNs.stack(err),
|
|
201
208
|
});
|
|
202
209
|
}
|
|
203
210
|
}
|
|
@@ -25,7 +25,7 @@ export interface ServerWatchLoopConfig {
|
|
|
25
25
|
/** 빌드 완료 이벤트 콜백 */
|
|
26
26
|
onBuild: (result: { build: { success: boolean; errors?: string[]; warnings?: string[] }; mainJsPath: string }) => void;
|
|
27
27
|
/** 에러 이벤트 콜백 */
|
|
28
|
-
onError: (message: string) => void;
|
|
28
|
+
onError: (message: string, stack?: string) => void;
|
|
29
29
|
/** 리빌드 실행 콜백 */
|
|
30
30
|
rebuild: () => Promise<{ build: { success: boolean; errors?: string[]; warnings?: string[] }; mainJsPath: string }>;
|
|
31
31
|
}
|
|
@@ -99,7 +99,7 @@ export async function startServerWatchLoop(config: ServerWatchLoopConfig): Promi
|
|
|
99
99
|
|
|
100
100
|
const hasRelevantChange = changes.some((c) => {
|
|
101
101
|
if (metafileAbsPaths.has(c.path)) return true;
|
|
102
|
-
//
|
|
102
|
+
// package manager symlink 경로와 esbuild resolved 경로 불일치 대응
|
|
103
103
|
try {
|
|
104
104
|
const realPath = pathx.posix(fs.realpathSync(c.path));
|
|
105
105
|
return metafileAbsPaths.has(realPath);
|
|
@@ -116,7 +116,7 @@ export async function startServerWatchLoop(config: ServerWatchLoopConfig): Promi
|
|
|
116
116
|
logger.debug("변경된 파일이 빌드에 포함되지 않아 리빌드 건너뜀");
|
|
117
117
|
}
|
|
118
118
|
} catch (err) {
|
|
119
|
-
config.onError(errNs.message(err));
|
|
119
|
+
config.onError(errNs.message(err), errNs.stack(err));
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
|
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
/* eslint-disable no-restricted-properties -- 테스트 환경변수 조작 필요 */
|
|
2
|
-
import { describe, it, expect, vi, beforeAll, afterAll, beforeEach, afterEach } from "vitest";
|
|
3
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { fsx, cpx } from "@simplysm/core-node";
|
|
7
|
-
|
|
8
|
-
// sharp는 외부 npm 네이티브 라이브러리로 이미지 처리 시간이 크고 결정적 검증에 mock 필요
|
|
9
|
-
vi.mock("sharp", () => ({
|
|
10
|
-
default: vi.fn().mockReturnValue({
|
|
11
|
-
resize: vi.fn().mockReturnThis(),
|
|
12
|
-
composite: vi.fn().mockReturnThis(),
|
|
13
|
-
png: vi.fn().mockReturnThis(),
|
|
14
|
-
toBuffer: vi.fn().mockResolvedValue(new Uint8Array([0])),
|
|
15
|
-
toFile: vi.fn().mockResolvedValue(undefined),
|
|
16
|
-
}),
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
const mockFsxExists = vi.spyOn(fsx, "exists");
|
|
20
|
-
const mockFsxRead = vi.spyOn(fsx, "read");
|
|
21
|
-
vi.spyOn(fsx, "write").mockResolvedValue(undefined);
|
|
22
|
-
const mockFsxReadJson = vi.spyOn(fsx, "readJson");
|
|
23
|
-
vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
|
|
24
|
-
vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
|
|
25
|
-
vi.spyOn(fsx, "rm").mockResolvedValue(undefined);
|
|
26
|
-
const mockFsxGlob = vi.spyOn(fsx, "glob").mockResolvedValue([]);
|
|
27
|
-
vi.spyOn(fsx, "copy").mockResolvedValue(undefined);
|
|
28
|
-
|
|
29
|
-
vi.spyOn(cpx, "spawn").mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
|
|
30
|
-
vi.spyOn(cpx, "spawnSync").mockReturnValue({ stdout: "", stderr: "", exitCode: 0 });
|
|
31
|
-
|
|
32
|
-
let tmpRoot: string;
|
|
33
|
-
let PKG_PATH: string;
|
|
34
|
-
|
|
35
|
-
beforeAll(() => {
|
|
36
|
-
tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-build-"));
|
|
37
|
-
writeFileSync(path.join(tmpRoot, "
|
|
38
|
-
PKG_PATH = path.join(tmpRoot, "pkg");
|
|
39
|
-
mkdirSync(path.join(PKG_PATH, ".capacitor"), { recursive: true });
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
afterAll(() => {
|
|
43
|
-
rmSync(tmpRoot, { recursive: true, force: true });
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
function setupDefaultMocks() {
|
|
47
|
-
mockFsxExists.mockResolvedValue(true);
|
|
48
|
-
|
|
49
|
-
mockFsxReadJson.mockImplementation(((p: string) => {
|
|
50
|
-
const normalized = p.replace(/\\/g, "/");
|
|
51
|
-
if (normalized.includes(".capacitor/package.json")) {
|
|
52
|
-
return {
|
|
53
|
-
name: "com.test.app",
|
|
54
|
-
version: "1.2.3",
|
|
55
|
-
dependencies: {
|
|
56
|
-
"@capacitor/core": "^7.0.0",
|
|
57
|
-
"@capacitor/app": "^7.0.0",
|
|
58
|
-
"@capacitor/android": "^7.0.0",
|
|
59
|
-
},
|
|
60
|
-
devDependencies: {
|
|
61
|
-
"@capacitor/cli": "^7.0.0",
|
|
62
|
-
"@capacitor/assets": "^3.0.0",
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return { name: "test-pkg", version: "1.2.3" };
|
|
67
|
-
}) as never);
|
|
68
|
-
|
|
69
|
-
mockFsxRead.mockImplementation(((p: string) => {
|
|
70
|
-
if (p.includes("AndroidManifest.xml")) {
|
|
71
|
-
return '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n<application>\n</application>\n</manifest>';
|
|
72
|
-
}
|
|
73
|
-
if (p.includes("build.gradle")) {
|
|
74
|
-
return `android {
|
|
75
|
-
defaultConfig {
|
|
76
|
-
versionCode 1
|
|
77
|
-
versionName "1.0"
|
|
78
|
-
minSdkVersion rootProject.ext.minSdkVersion
|
|
79
|
-
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
80
|
-
}
|
|
81
|
-
buildTypes { release { } }
|
|
82
|
-
}`;
|
|
83
|
-
}
|
|
84
|
-
if (p.includes("gradle.properties")) {
|
|
85
|
-
return "org.gradle.jvmargs=-Xmx2048m";
|
|
86
|
-
}
|
|
87
|
-
return "";
|
|
88
|
-
}) as never);
|
|
89
|
-
|
|
90
|
-
mockFsxGlob.mockImplementation(((pattern: string) => {
|
|
91
|
-
if (pattern.includes("Corretto") || pattern.includes("jdk")) {
|
|
92
|
-
return ["C:/Program Files/Amazon Corretto/jdk21.0.1"];
|
|
93
|
-
}
|
|
94
|
-
return [];
|
|
95
|
-
}) as never);
|
|
96
|
-
|
|
97
|
-
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
let savedEnv: Record<string, string | undefined>;
|
|
101
|
-
beforeEach(() => {
|
|
102
|
-
savedEnv = { ...process.env };
|
|
103
|
-
});
|
|
104
|
-
afterEach(() => {
|
|
105
|
-
process.env = savedEnv;
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe("Capacitor 빌드", () => {
|
|
109
|
-
beforeEach(() => {
|
|
110
|
-
vi.clearAllMocks();
|
|
111
|
-
setupDefaultMocks();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
describe("서명", () => {
|
|
115
|
-
it("keystore 파일이 없으면 에러가 발생한다", async () => {
|
|
116
|
-
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
117
|
-
|
|
118
|
-
// keystore 파일만 존재하지 않도록 설정
|
|
119
|
-
mockFsxExists.mockImplementation(((p: string) => {
|
|
120
|
-
if (p.includes("my-release.keystore")) return false;
|
|
121
|
-
return true;
|
|
122
|
-
}) as never);
|
|
123
|
-
|
|
124
|
-
const cap = await Capacitor.create(PKG_PATH, {
|
|
125
|
-
appId: "com.test.app",
|
|
126
|
-
appName: "Test App",
|
|
127
|
-
platform: {
|
|
128
|
-
android: {
|
|
129
|
-
sign: {
|
|
130
|
-
keystore: "my-release.keystore",
|
|
131
|
-
storePassword: "store123",
|
|
132
|
-
alias: "my-key",
|
|
133
|
-
password: "key123",
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
await expect(cap.build("/fake/out")).rejects.toThrow("keystore");
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
});
|
|
1
|
+
/* eslint-disable no-restricted-properties -- 테스트 환경변수 조작 필요 */
|
|
2
|
+
import { describe, it, expect, vi, beforeAll, afterAll, beforeEach, afterEach } from "vitest";
|
|
3
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fsx, cpx } from "@simplysm/core-node";
|
|
7
|
+
|
|
8
|
+
// sharp는 외부 npm 네이티브 라이브러리로 이미지 처리 시간이 크고 결정적 검증에 mock 필요
|
|
9
|
+
vi.mock("sharp", () => ({
|
|
10
|
+
default: vi.fn().mockReturnValue({
|
|
11
|
+
resize: vi.fn().mockReturnThis(),
|
|
12
|
+
composite: vi.fn().mockReturnThis(),
|
|
13
|
+
png: vi.fn().mockReturnThis(),
|
|
14
|
+
toBuffer: vi.fn().mockResolvedValue(new Uint8Array([0])),
|
|
15
|
+
toFile: vi.fn().mockResolvedValue(undefined),
|
|
16
|
+
}),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const mockFsxExists = vi.spyOn(fsx, "exists");
|
|
20
|
+
const mockFsxRead = vi.spyOn(fsx, "read");
|
|
21
|
+
vi.spyOn(fsx, "write").mockResolvedValue(undefined);
|
|
22
|
+
const mockFsxReadJson = vi.spyOn(fsx, "readJson");
|
|
23
|
+
vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
|
|
24
|
+
vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
|
|
25
|
+
vi.spyOn(fsx, "rm").mockResolvedValue(undefined);
|
|
26
|
+
const mockFsxGlob = vi.spyOn(fsx, "glob").mockResolvedValue([]);
|
|
27
|
+
vi.spyOn(fsx, "copy").mockResolvedValue(undefined);
|
|
28
|
+
|
|
29
|
+
vi.spyOn(cpx, "spawn").mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
|
|
30
|
+
vi.spyOn(cpx, "spawnSync").mockReturnValue({ stdout: "", stderr: "", exitCode: 0 });
|
|
31
|
+
|
|
32
|
+
let tmpRoot: string;
|
|
33
|
+
let PKG_PATH: string;
|
|
34
|
+
|
|
35
|
+
beforeAll(() => {
|
|
36
|
+
tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-build-"));
|
|
37
|
+
writeFileSync(path.join(tmpRoot, "package.json"), JSON.stringify({ private: true, workspaces: ["pkg"] }));
|
|
38
|
+
PKG_PATH = path.join(tmpRoot, "pkg");
|
|
39
|
+
mkdirSync(path.join(PKG_PATH, ".capacitor"), { recursive: true });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterAll(() => {
|
|
43
|
+
rmSync(tmpRoot, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
function setupDefaultMocks() {
|
|
47
|
+
mockFsxExists.mockResolvedValue(true);
|
|
48
|
+
|
|
49
|
+
mockFsxReadJson.mockImplementation(((p: string) => {
|
|
50
|
+
const normalized = p.replace(/\\/g, "/");
|
|
51
|
+
if (normalized.includes(".capacitor/package.json")) {
|
|
52
|
+
return {
|
|
53
|
+
name: "com.test.app",
|
|
54
|
+
version: "1.2.3",
|
|
55
|
+
dependencies: {
|
|
56
|
+
"@capacitor/core": "^7.0.0",
|
|
57
|
+
"@capacitor/app": "^7.0.0",
|
|
58
|
+
"@capacitor/android": "^7.0.0",
|
|
59
|
+
},
|
|
60
|
+
devDependencies: {
|
|
61
|
+
"@capacitor/cli": "^7.0.0",
|
|
62
|
+
"@capacitor/assets": "^3.0.0",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return { name: "test-pkg", version: "1.2.3" };
|
|
67
|
+
}) as never);
|
|
68
|
+
|
|
69
|
+
mockFsxRead.mockImplementation(((p: string) => {
|
|
70
|
+
if (p.includes("AndroidManifest.xml")) {
|
|
71
|
+
return '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n<application>\n</application>\n</manifest>';
|
|
72
|
+
}
|
|
73
|
+
if (p.includes("build.gradle")) {
|
|
74
|
+
return `android {
|
|
75
|
+
defaultConfig {
|
|
76
|
+
versionCode 1
|
|
77
|
+
versionName "1.0"
|
|
78
|
+
minSdkVersion rootProject.ext.minSdkVersion
|
|
79
|
+
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
80
|
+
}
|
|
81
|
+
buildTypes { release { } }
|
|
82
|
+
}`;
|
|
83
|
+
}
|
|
84
|
+
if (p.includes("gradle.properties")) {
|
|
85
|
+
return "org.gradle.jvmargs=-Xmx2048m";
|
|
86
|
+
}
|
|
87
|
+
return "";
|
|
88
|
+
}) as never);
|
|
89
|
+
|
|
90
|
+
mockFsxGlob.mockImplementation(((pattern: string) => {
|
|
91
|
+
if (pattern.includes("Corretto") || pattern.includes("jdk")) {
|
|
92
|
+
return ["C:/Program Files/Amazon Corretto/jdk21.0.1"];
|
|
93
|
+
}
|
|
94
|
+
return [];
|
|
95
|
+
}) as never);
|
|
96
|
+
|
|
97
|
+
process.env["ANDROID_HOME"] = "C:/Android/Sdk";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let savedEnv: Record<string, string | undefined>;
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
savedEnv = { ...process.env };
|
|
103
|
+
});
|
|
104
|
+
afterEach(() => {
|
|
105
|
+
process.env = savedEnv;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("Capacitor 빌드", () => {
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
vi.clearAllMocks();
|
|
111
|
+
setupDefaultMocks();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("서명", () => {
|
|
115
|
+
it("keystore 파일이 없으면 에러가 발생한다", async () => {
|
|
116
|
+
const { Capacitor } = await import("../../src/capacitor/capacitor.js");
|
|
117
|
+
|
|
118
|
+
// keystore 파일만 존재하지 않도록 설정
|
|
119
|
+
mockFsxExists.mockImplementation(((p: string) => {
|
|
120
|
+
if (p.includes("my-release.keystore")) return false;
|
|
121
|
+
return true;
|
|
122
|
+
}) as never);
|
|
123
|
+
|
|
124
|
+
const cap = await Capacitor.create(PKG_PATH, {
|
|
125
|
+
appId: "com.test.app",
|
|
126
|
+
appName: "Test App",
|
|
127
|
+
platform: {
|
|
128
|
+
android: {
|
|
129
|
+
sign: {
|
|
130
|
+
keystore: "my-release.keystore",
|
|
131
|
+
storePassword: "store123",
|
|
132
|
+
alias: "my-key",
|
|
133
|
+
password: "key123",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await expect(cap.build("/fake/out")).rejects.toThrow("keystore");
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|