@simplysm/sd-cli 11.0.39 → 11.1.1

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.
Files changed (51) hide show
  1. package/dist/build-cluster.d.ts +1 -1
  2. package/dist/build-cluster.js +181 -181
  3. package/dist/build-tools/SdCliCordova.d.ts +21 -21
  4. package/dist/build-tools/SdCliCordova.js +217 -217
  5. package/dist/build-tools/SdCliIndexFileGenerator.d.ts +5 -5
  6. package/dist/build-tools/SdCliIndexFileGenerator.js +50 -50
  7. package/dist/build-tools/SdCliNgRoutesFileGenerator.d.ts +4 -4
  8. package/dist/build-tools/SdCliNgRoutesFileGenerator.js +57 -57
  9. package/dist/build-tools/SdLinter.d.ts +5 -5
  10. package/dist/build-tools/SdLinter.js +54 -54
  11. package/dist/build-tools/SdNgBundler.d.ts +35 -35
  12. package/dist/build-tools/SdNgBundler.js +545 -533
  13. package/dist/build-tools/SdNgBundler.js.map +1 -1
  14. package/dist/build-tools/SdNgBundlerContext.d.ts +16 -16
  15. package/dist/build-tools/SdNgBundlerContext.js +97 -97
  16. package/dist/build-tools/SdTsBundler.d.ts +15 -15
  17. package/dist/build-tools/SdTsBundler.js +87 -87
  18. package/dist/build-tools/SdTsCompiler.d.ts +29 -29
  19. package/dist/build-tools/SdTsCompiler.js +227 -227
  20. package/dist/builders/SdCliClientBuilder.d.ts +18 -18
  21. package/dist/builders/SdCliClientBuilder.js +129 -129
  22. package/dist/builders/SdCliJsLibLinter.d.ts +14 -14
  23. package/dist/builders/SdCliJsLibLinter.js +59 -59
  24. package/dist/builders/SdCliServerBuilder.d.ts +20 -20
  25. package/dist/builders/SdCliServerBuilder.js +215 -215
  26. package/dist/builders/SdCliTsLibBuilder.d.ts +17 -17
  27. package/dist/builders/SdCliTsLibBuilder.js +79 -79
  28. package/dist/commons.d.ts +132 -132
  29. package/dist/commons.js +1 -1
  30. package/dist/entry/SdCliElectron.d.ts +12 -12
  31. package/dist/entry/SdCliElectron.js +99 -99
  32. package/dist/entry/SdCliLocalUpdate.d.ts +12 -12
  33. package/dist/entry/SdCliLocalUpdate.js +90 -90
  34. package/dist/entry/SdCliProject.d.ts +26 -26
  35. package/dist/entry/SdCliProject.js +477 -477
  36. package/dist/index.d.ts +19 -19
  37. package/dist/index.js +19 -19
  38. package/dist/sd-cli.d.ts +2 -2
  39. package/dist/sd-cli.js +210 -210
  40. package/dist/server-worker.d.ts +1 -1
  41. package/dist/server-worker.js +38 -38
  42. package/dist/utils/SdCliBuildResultUtil.d.ts +6 -6
  43. package/dist/utils/SdCliBuildResultUtil.js +37 -37
  44. package/dist/utils/SdMemoryLoadResultCache.d.ts +9 -9
  45. package/dist/utils/SdMemoryLoadResultCache.js +34 -34
  46. package/dist/utils/SdSourceFileCache.d.ts +6 -6
  47. package/dist/utils/SdSourceFileCache.js +14 -14
  48. package/dist/utils/SdSourceFileCache.js.map +1 -1
  49. package/package.json +19 -19
  50. package/src/build-tools/SdNgBundler.ts +21 -12
  51. package/src/utils/SdSourceFileCache.ts +1 -1
@@ -1,117 +1,117 @@
1
- import * as path from "path";
2
- import { FsUtil, Logger, SdProcess } from "@simplysm/sd-core-node";
3
- import xml2js from "xml2js";
4
- import JSZip from "jszip";
5
- const BIN_PATH = path.resolve(process.cwd(), "node_modules/.bin/cordova.cmd");
6
- export class SdCliCordova {
7
- constructor(_opt) {
8
- this._opt = _opt;
9
- this._logger = Logger.get(["simplysm", "sd-cli", "SdCliCordova"]);
10
- this._platforms = Object.keys(this._opt.config.platform ?? { browser: {} });
11
- this._npmConfig = FsUtil.readJson(path.resolve(this._opt.pkgPath, "package.json"));
12
- // this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, this._npmConfig.name]);
13
- }
14
- async _execAsync(cmd, cwd) {
15
- this._logger.debug(cmd);
16
- const msg = await SdProcess.spawnAsync(cmd, { cwd });
17
- this._logger.debug(msg);
18
- }
19
- async initializeAsync() {
20
- if (FsUtil.exists(this._opt.cordovaPath)) {
21
- this._logger.log("이미 생성되어있는 '.cordova'를 사용합니다.");
22
- }
23
- else {
24
- await this._execAsync(`${BIN_PATH} telemetry on`, this._opt.pkgPath);
25
- // 프로젝트 생성
26
- await this._execAsync(`${BIN_PATH} create "${this._opt.cordovaPath}" "${this._opt.config.appId}" "${this._opt.config.appName}"`, process.cwd());
27
- }
28
- // platforms 폴더 혹시 없으면 생성
29
- await FsUtil.mkdirsAsync(path.resolve(this._opt.cordovaPath, "platforms"));
30
- // www 폴더 혹시 없으면 생성
31
- await FsUtil.mkdirsAsync(path.resolve(this._opt.cordovaPath, "www"));
32
- // 미설치 빌드 플랫폼 신규 생성
33
- const alreadyPlatforms = await FsUtil.readdirAsync(path.resolve(this._opt.cordovaPath, "platforms"));
34
- for (const platform of this._platforms) {
35
- if (!alreadyPlatforms.includes(platform)) {
36
- await this._execAsync(`${BIN_PATH} platform add ${platform}`, this._opt.cordovaPath);
37
- }
38
- }
39
- // 설치 미빌드 플랫폼 삭제
40
- for (const alreadyPlatform of alreadyPlatforms) {
41
- if (!this._platforms.includes(alreadyPlatform)) {
42
- await this._execAsync(`${BIN_PATH} platform remove ${alreadyPlatform}`, this._opt.cordovaPath);
43
- }
44
- }
45
- // 설치된 미사용 플러그인 삭제
46
- const pluginsFetch = FsUtil.exists(path.resolve(this._opt.cordovaPath, "plugins/fetch.json"))
47
- ? await FsUtil.readJsonAsync(path.resolve(this._opt.cordovaPath, "plugins/fetch.json"))
48
- : undefined;
49
- const alreadyPluginIds = pluginsFetch != undefined
50
- ? Object.keys(pluginsFetch)
51
- // Object.values(pluginsFetch).map((item: any) => item.source.id ?? item.source.url ?? item.source.path)
52
- : [];
53
- const usePlugins = ["cordova-plugin-ionic-webview", ...this._opt.config.plugins ?? []].distinct();
54
- for (const alreadyPluginId of alreadyPluginIds) {
55
- let hasPlugin = false;
56
- for (const usePlugin of usePlugins) {
57
- if (alreadyPluginId === usePlugin) {
58
- hasPlugin = true;
59
- break;
60
- }
61
- /*if (
62
- (usePlugin.includes("@") && alreadyPluginId === usePlugin) ||
63
- (!usePlugin.includes("@") && alreadyPluginId.replace(/@.*$/, "") === usePlugin)
64
- ) {
65
- hasPlugin = true;
66
- break;
67
- }*/
68
- }
69
- if (!hasPlugin) {
70
- await this._execAsync(`${BIN_PATH} plugin remove ${alreadyPluginId}`, this._opt.cordovaPath);
71
- }
72
- }
73
- // 미설치 플러그인들 설치
74
- for (const usePlugin of usePlugins) {
75
- if ((usePlugin.includes("@") && !alreadyPluginIds.includes(usePlugin)) ||
76
- (!usePlugin.includes("@") && !alreadyPluginIds.map((alreadyPluginId) => alreadyPluginId.replace(/@.*$/, "")).includes(usePlugin))) {
77
- await this._execAsync(`${BIN_PATH} plugin add ${usePlugin}`, this._opt.cordovaPath);
78
- }
79
- }
80
- // ANDROID SIGN 파일 복사
81
- if (this._opt.config.platform?.android?.sign) {
82
- await FsUtil.copyAsync(path.resolve(this._opt.pkgPath, "src", this._opt.config.platform.android.sign.keystore), path.resolve(this._opt.cordovaPath, "android.keystore"));
83
- }
84
- else {
85
- await FsUtil.removeAsync(path.resolve(this._opt.cordovaPath, "android.keystore"));
86
- // SIGN을 안쓸경우 아래 파일이 생성되어 있으면 오류남
87
- await FsUtil.removeAsync(path.resolve(this._opt.cordovaPath, "platforms/android/release-signing.properties"));
88
- }
89
- // 빌드 옵션 파일 생성
90
- await FsUtil.writeJsonAsync(path.resolve(this._opt.cordovaPath, "build.json"), {
91
- ...this._opt.config.platform?.android ? {
92
- android: {
93
- release: {
94
- packageType: this._opt.config.platform.android.bundle ? "bundle" : "apk",
95
- ...this._opt.config.platform.android.sign ? {
96
- keystore: path.resolve(this._opt.cordovaPath, "android.keystore"),
97
- storePassword: this._opt.config.platform.android.sign.storePassword,
98
- alias: this._opt.config.platform.android.sign.alias,
99
- password: this._opt.config.platform.android.sign.password,
100
- keystoreType: this._opt.config.platform.android.sign.keystoreType
101
- } : {}
102
- }
103
- }
104
- } : {}
105
- });
106
- // ICON 파일 복사
107
- if (this._opt.config.icon != null) {
108
- await FsUtil.copyAsync(path.resolve(this._opt.pkgPath, "src", this._opt.config.icon), path.resolve(this._opt.cordovaPath, "res/icons", path.basename(this._opt.config.icon)));
109
- }
110
- else {
111
- await FsUtil.removeAsync(path.resolve(this._opt.cordovaPath, "res/icons"));
112
- }
113
- // SplashScreen 파일 생성
114
- if (this._opt.config.platform?.android && this._opt.config.icon != null) {
1
+ import * as path from "path";
2
+ import { FsUtil, Logger, SdProcess } from "@simplysm/sd-core-node";
3
+ import xml2js from "xml2js";
4
+ import JSZip from "jszip";
5
+ const BIN_PATH = path.resolve(process.cwd(), "node_modules/.bin/cordova.cmd");
6
+ export class SdCliCordova {
7
+ constructor(_opt) {
8
+ this._opt = _opt;
9
+ this._logger = Logger.get(["simplysm", "sd-cli", "SdCliCordova"]);
10
+ this._platforms = Object.keys(this._opt.config.platform ?? { browser: {} });
11
+ this._npmConfig = FsUtil.readJson(path.resolve(this._opt.pkgPath, "package.json"));
12
+ // this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, this._npmConfig.name]);
13
+ }
14
+ async _execAsync(cmd, cwd) {
15
+ this._logger.debug(cmd);
16
+ const msg = await SdProcess.spawnAsync(cmd, { cwd });
17
+ this._logger.debug(msg);
18
+ }
19
+ async initializeAsync() {
20
+ if (FsUtil.exists(this._opt.cordovaPath)) {
21
+ this._logger.log("이미 생성되어있는 '.cordova'를 사용합니다.");
22
+ }
23
+ else {
24
+ await this._execAsync(`${BIN_PATH} telemetry on`, this._opt.pkgPath);
25
+ // 프로젝트 생성
26
+ await this._execAsync(`${BIN_PATH} create "${this._opt.cordovaPath}" "${this._opt.config.appId}" "${this._opt.config.appName}"`, process.cwd());
27
+ }
28
+ // platforms 폴더 혹시 없으면 생성
29
+ await FsUtil.mkdirsAsync(path.resolve(this._opt.cordovaPath, "platforms"));
30
+ // www 폴더 혹시 없으면 생성
31
+ await FsUtil.mkdirsAsync(path.resolve(this._opt.cordovaPath, "www"));
32
+ // 미설치 빌드 플랫폼 신규 생성
33
+ const alreadyPlatforms = await FsUtil.readdirAsync(path.resolve(this._opt.cordovaPath, "platforms"));
34
+ for (const platform of this._platforms) {
35
+ if (!alreadyPlatforms.includes(platform)) {
36
+ await this._execAsync(`${BIN_PATH} platform add ${platform}`, this._opt.cordovaPath);
37
+ }
38
+ }
39
+ // 설치 미빌드 플랫폼 삭제
40
+ for (const alreadyPlatform of alreadyPlatforms) {
41
+ if (!this._platforms.includes(alreadyPlatform)) {
42
+ await this._execAsync(`${BIN_PATH} platform remove ${alreadyPlatform}`, this._opt.cordovaPath);
43
+ }
44
+ }
45
+ // 설치된 미사용 플러그인 삭제
46
+ const pluginsFetch = FsUtil.exists(path.resolve(this._opt.cordovaPath, "plugins/fetch.json"))
47
+ ? await FsUtil.readJsonAsync(path.resolve(this._opt.cordovaPath, "plugins/fetch.json"))
48
+ : undefined;
49
+ const alreadyPluginIds = pluginsFetch != undefined
50
+ ? Object.keys(pluginsFetch)
51
+ // Object.values(pluginsFetch).map((item: any) => item.source.id ?? item.source.url ?? item.source.path)
52
+ : [];
53
+ const usePlugins = ["cordova-plugin-ionic-webview", ...this._opt.config.plugins ?? []].distinct();
54
+ for (const alreadyPluginId of alreadyPluginIds) {
55
+ let hasPlugin = false;
56
+ for (const usePlugin of usePlugins) {
57
+ if (alreadyPluginId === usePlugin) {
58
+ hasPlugin = true;
59
+ break;
60
+ }
61
+ /*if (
62
+ (usePlugin.includes("@") && alreadyPluginId === usePlugin) ||
63
+ (!usePlugin.includes("@") && alreadyPluginId.replace(/@.*$/, "") === usePlugin)
64
+ ) {
65
+ hasPlugin = true;
66
+ break;
67
+ }*/
68
+ }
69
+ if (!hasPlugin) {
70
+ await this._execAsync(`${BIN_PATH} plugin remove ${alreadyPluginId}`, this._opt.cordovaPath);
71
+ }
72
+ }
73
+ // 미설치 플러그인들 설치
74
+ for (const usePlugin of usePlugins) {
75
+ if ((usePlugin.includes("@") && !alreadyPluginIds.includes(usePlugin)) ||
76
+ (!usePlugin.includes("@") && !alreadyPluginIds.map((alreadyPluginId) => alreadyPluginId.replace(/@.*$/, "")).includes(usePlugin))) {
77
+ await this._execAsync(`${BIN_PATH} plugin add ${usePlugin}`, this._opt.cordovaPath);
78
+ }
79
+ }
80
+ // ANDROID SIGN 파일 복사
81
+ if (this._opt.config.platform?.android?.sign) {
82
+ await FsUtil.copyAsync(path.resolve(this._opt.pkgPath, "src", this._opt.config.platform.android.sign.keystore), path.resolve(this._opt.cordovaPath, "android.keystore"));
83
+ }
84
+ else {
85
+ await FsUtil.removeAsync(path.resolve(this._opt.cordovaPath, "android.keystore"));
86
+ // SIGN을 안쓸경우 아래 파일이 생성되어 있으면 오류남
87
+ await FsUtil.removeAsync(path.resolve(this._opt.cordovaPath, "platforms/android/release-signing.properties"));
88
+ }
89
+ // 빌드 옵션 파일 생성
90
+ await FsUtil.writeJsonAsync(path.resolve(this._opt.cordovaPath, "build.json"), {
91
+ ...this._opt.config.platform?.android ? {
92
+ android: {
93
+ release: {
94
+ packageType: this._opt.config.platform.android.bundle ? "bundle" : "apk",
95
+ ...this._opt.config.platform.android.sign ? {
96
+ keystore: path.resolve(this._opt.cordovaPath, "android.keystore"),
97
+ storePassword: this._opt.config.platform.android.sign.storePassword,
98
+ alias: this._opt.config.platform.android.sign.alias,
99
+ password: this._opt.config.platform.android.sign.password,
100
+ keystoreType: this._opt.config.platform.android.sign.keystoreType
101
+ } : {}
102
+ }
103
+ }
104
+ } : {}
105
+ });
106
+ // ICON 파일 복사
107
+ if (this._opt.config.icon != null) {
108
+ await FsUtil.copyAsync(path.resolve(this._opt.pkgPath, "src", this._opt.config.icon), path.resolve(this._opt.cordovaPath, "res/icons", path.basename(this._opt.config.icon)));
109
+ }
110
+ else {
111
+ await FsUtil.removeAsync(path.resolve(this._opt.cordovaPath, "res/icons"));
112
+ }
113
+ // SplashScreen 파일 생성
114
+ if (this._opt.config.platform?.android && this._opt.config.icon != null) {
115
115
  await FsUtil.writeFileAsync(path.resolve(this._opt.cordovaPath, "res/screen/android/splashscreen.xml"), `
116
116
  <?xml version="1.0" encoding="utf-8"?>
117
117
  <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
@@ -120,107 +120,107 @@ export class SdCliCordova {
120
120
  android:height="48dp"
121
121
  android:drawable="@mipmap/ic_launcher"
122
122
  android:gravity="center" />
123
- </layer-list>`.trim());
124
- }
125
- // CONFIG: 초기값 백업
126
- const configFilePath = path.resolve(this._opt.cordovaPath, "config.xml");
127
- const configBackFilePath = path.resolve(this._opt.cordovaPath, "config.xml.bak");
128
- if (!FsUtil.exists(configBackFilePath)) {
129
- await FsUtil.copyAsync(configFilePath, configBackFilePath);
130
- }
131
- // CONFIG: 초기값 읽기
132
- const configFileContent = await FsUtil.readFileAsync(configBackFilePath);
133
- const configXml = await xml2js.parseStringPromise(configFileContent);
134
- // CONFIG: 버전 설정
135
- configXml.widget.$.version = this._npmConfig.version;
136
- // CONFIG: ICON 설정
137
- if (this._opt.config.icon != null) {
138
- configXml["widget"]["icon"] = [{ "$": { "src": "res/icons/" + path.basename(this._opt.config.icon) } }];
139
- }
140
- // CONFIG: 접근허용 세팅
141
- configXml["widget"]["access"] = [{ "$": { "origin": "*" } }];
142
- configXml["widget"]["allow-navigation"] = [{ "$": { "href": "*" } }];
143
- configXml["widget"]["allow-intent"] = [{ "$": { "href": "*" } }];
144
- configXml["widget"]["preference"] = [{ "$": { "name": "MixedContentMode", "value": "0" } }];
145
- // CONFIG: ANDROID usesCleartextTraffic 설정 및 splashscreen 파일 설정
146
- if (this._opt.config.platform?.android) {
147
- configXml.widget.$["xmlns:android"] = "http://schemas.android.com/apk/res/android";
148
- configXml["widget"]["platform"] = configXml["widget"]["platform"] ?? [];
149
- configXml["widget"]["platform"].push({
150
- "$": {
151
- "name": "android"
152
- },
153
- "preference": [{
154
- "$": {
155
- "name": "AndroidWindowSplashScreenAnimatedIcon",
156
- "value": "res/screen/android/splashscreen.xml"
157
- }
158
- }],
159
- "edit-config": [{
160
- "$": {
161
- "file": "app/src/main/AndroidManifest.xml",
162
- "mode": "merge",
163
- "target": "/manifest/application"
164
- },
165
- "application": [{
166
- "$": {
167
- "android:usesCleartextTraffic": "true"
168
- }
169
- }]
170
- }]
171
- });
172
- }
173
- // CONFIG: 파일 새로 쓰기
174
- const configResultContent = new xml2js.Builder().buildObject(configXml);
175
- await FsUtil.writeFileAsync(configFilePath, configResultContent);
176
- // 각 플랫폼 www 준비
177
- await this._execAsync(`${BIN_PATH} prepare`, this._opt.cordovaPath);
178
- }
179
- async buildAsync(outPath) {
180
- // 실행
181
- const buildType = this._opt.config.debug ? "debug" : "release";
182
- for (const platform of this._platforms) {
183
- await this._execAsync(`${BIN_PATH} build ${platform} --${buildType}`, this._opt.cordovaPath);
184
- }
185
- for (const platform of Object.keys(this._opt.config.platform ?? {})) {
186
- const targetOutPath = path.resolve(outPath, platform);
187
- // 결과물 복사: ANDROID
188
- if (platform === "android") {
189
- const apkFileName = this._opt.config.platform.android.sign ? `app-${buildType}.apk` : `app-${buildType}-unsigned.apk`;
190
- const latestDistApkFileName = path.basename(`${this._opt.config.appName}${this._opt.config.platform.android.sign ? "" : "-unsigned"}-latest.apk`);
191
- await FsUtil.mkdirsAsync(targetOutPath);
192
- await FsUtil.copyAsync(path.resolve(this._opt.cordovaPath, "platforms/android/app/build/outputs/apk", buildType, apkFileName), path.resolve(targetOutPath, latestDistApkFileName));
193
- }
194
- // 자동업데이트를 위한 파일 쓰기 (ZIP)
195
- const zip = new JSZip();
196
- const wwwFiles = await FsUtil.globAsync(path.resolve(this._opt.cordovaPath, "www/**/*"), { nodir: true });
197
- for (const wwwFile of wwwFiles) {
198
- const relFilePath = path.relative(path.resolve(this._opt.cordovaPath, "www"), wwwFile);
199
- const fileBuffer = await FsUtil.readFileBufferAsync(wwwFile);
200
- zip.file(relFilePath, fileBuffer);
201
- }
202
- const platformWwwFiles = await FsUtil.globAsync(path.resolve(this._opt.cordovaPath, "platforms", platform, "platform_www/**/*"), { nodir: true });
203
- for (const platformWwwFile of platformWwwFiles) {
204
- const relFilePath = path.relative(path.resolve(this._opt.cordovaPath, "platforms", platform, "platform_www"), platformWwwFile);
205
- const fileBuffer = await FsUtil.readFileBufferAsync(platformWwwFile);
206
- zip.file(relFilePath, fileBuffer);
207
- }
208
- await FsUtil.writeFileAsync(path.resolve(path.resolve(outPath, platform, "updates"), this._npmConfig.version + ".zip"), await zip.generateAsync({ type: "nodebuffer" }));
209
- }
210
- }
211
- static async runWebviewOnDeviceAsync(opt) {
212
- const cordovaPath = path.resolve(process.cwd(), `packages/${opt.pkgName}/.cordova/`);
213
- if (opt.url !== undefined) {
214
- await FsUtil.removeAsync(path.resolve(cordovaPath, "www"));
215
- await FsUtil.mkdirsAsync(path.resolve(cordovaPath, "www"));
216
- await FsUtil.writeFileAsync(path.resolve(cordovaPath, "www/index.html"), `'${opt.url}'로 이동중... <script>setTimeout(function () {window.location.href = "${opt.url.replace(/\/$/, "")}/${opt.pkgName}/cordova/"}, 3000);</script>`.trim());
217
- }
218
- /*else {
219
- await FsUtil.removeAsync(path.resolve(cordovaPath, "www"));
220
- await FsUtil.copyAsync(path.resolve(process.cwd(), `packages/${opt.pkgName}/dist/cordova`), path.resolve(cordovaPath, "www"));
221
- }*/
222
- const binPath = path.resolve(process.cwd(), "node_modules/.bin/cordova.cmd");
223
- await SdProcess.spawnAsync(`${binPath} run ${opt.platform} --device`, { cwd: cordovaPath }, true);
224
- }
225
- }
123
+ </layer-list>`.trim());
124
+ }
125
+ // CONFIG: 초기값 백업
126
+ const configFilePath = path.resolve(this._opt.cordovaPath, "config.xml");
127
+ const configBackFilePath = path.resolve(this._opt.cordovaPath, "config.xml.bak");
128
+ if (!FsUtil.exists(configBackFilePath)) {
129
+ await FsUtil.copyAsync(configFilePath, configBackFilePath);
130
+ }
131
+ // CONFIG: 초기값 읽기
132
+ const configFileContent = await FsUtil.readFileAsync(configBackFilePath);
133
+ const configXml = await xml2js.parseStringPromise(configFileContent);
134
+ // CONFIG: 버전 설정
135
+ configXml.widget.$.version = this._npmConfig.version;
136
+ // CONFIG: ICON 설정
137
+ if (this._opt.config.icon != null) {
138
+ configXml["widget"]["icon"] = [{ "$": { "src": "res/icons/" + path.basename(this._opt.config.icon) } }];
139
+ }
140
+ // CONFIG: 접근허용 세팅
141
+ configXml["widget"]["access"] = [{ "$": { "origin": "*" } }];
142
+ configXml["widget"]["allow-navigation"] = [{ "$": { "href": "*" } }];
143
+ configXml["widget"]["allow-intent"] = [{ "$": { "href": "*" } }];
144
+ configXml["widget"]["preference"] = [{ "$": { "name": "MixedContentMode", "value": "0" } }];
145
+ // CONFIG: ANDROID usesCleartextTraffic 설정 및 splashscreen 파일 설정
146
+ if (this._opt.config.platform?.android) {
147
+ configXml.widget.$["xmlns:android"] = "http://schemas.android.com/apk/res/android";
148
+ configXml["widget"]["platform"] = configXml["widget"]["platform"] ?? [];
149
+ configXml["widget"]["platform"].push({
150
+ "$": {
151
+ "name": "android"
152
+ },
153
+ "preference": [{
154
+ "$": {
155
+ "name": "AndroidWindowSplashScreenAnimatedIcon",
156
+ "value": "res/screen/android/splashscreen.xml"
157
+ }
158
+ }],
159
+ "edit-config": [{
160
+ "$": {
161
+ "file": "app/src/main/AndroidManifest.xml",
162
+ "mode": "merge",
163
+ "target": "/manifest/application"
164
+ },
165
+ "application": [{
166
+ "$": {
167
+ "android:usesCleartextTraffic": "true"
168
+ }
169
+ }]
170
+ }]
171
+ });
172
+ }
173
+ // CONFIG: 파일 새로 쓰기
174
+ const configResultContent = new xml2js.Builder().buildObject(configXml);
175
+ await FsUtil.writeFileAsync(configFilePath, configResultContent);
176
+ // 각 플랫폼 www 준비
177
+ await this._execAsync(`${BIN_PATH} prepare`, this._opt.cordovaPath);
178
+ }
179
+ async buildAsync(outPath) {
180
+ // 실행
181
+ const buildType = this._opt.config.debug ? "debug" : "release";
182
+ for (const platform of this._platforms) {
183
+ await this._execAsync(`${BIN_PATH} build ${platform} --${buildType}`, this._opt.cordovaPath);
184
+ }
185
+ for (const platform of Object.keys(this._opt.config.platform ?? {})) {
186
+ const targetOutPath = path.resolve(outPath, platform);
187
+ // 결과물 복사: ANDROID
188
+ if (platform === "android") {
189
+ const apkFileName = this._opt.config.platform.android.sign ? `app-${buildType}.apk` : `app-${buildType}-unsigned.apk`;
190
+ const latestDistApkFileName = path.basename(`${this._opt.config.appName}${this._opt.config.platform.android.sign ? "" : "-unsigned"}-latest.apk`);
191
+ await FsUtil.mkdirsAsync(targetOutPath);
192
+ await FsUtil.copyAsync(path.resolve(this._opt.cordovaPath, "platforms/android/app/build/outputs/apk", buildType, apkFileName), path.resolve(targetOutPath, latestDistApkFileName));
193
+ }
194
+ // 자동업데이트를 위한 파일 쓰기 (ZIP)
195
+ const zip = new JSZip();
196
+ const wwwFiles = await FsUtil.globAsync(path.resolve(this._opt.cordovaPath, "www/**/*"), { nodir: true });
197
+ for (const wwwFile of wwwFiles) {
198
+ const relFilePath = path.relative(path.resolve(this._opt.cordovaPath, "www"), wwwFile);
199
+ const fileBuffer = await FsUtil.readFileBufferAsync(wwwFile);
200
+ zip.file(relFilePath, fileBuffer);
201
+ }
202
+ const platformWwwFiles = await FsUtil.globAsync(path.resolve(this._opt.cordovaPath, "platforms", platform, "platform_www/**/*"), { nodir: true });
203
+ for (const platformWwwFile of platformWwwFiles) {
204
+ const relFilePath = path.relative(path.resolve(this._opt.cordovaPath, "platforms", platform, "platform_www"), platformWwwFile);
205
+ const fileBuffer = await FsUtil.readFileBufferAsync(platformWwwFile);
206
+ zip.file(relFilePath, fileBuffer);
207
+ }
208
+ await FsUtil.writeFileAsync(path.resolve(path.resolve(outPath, platform, "updates"), this._npmConfig.version + ".zip"), await zip.generateAsync({ type: "nodebuffer" }));
209
+ }
210
+ }
211
+ static async runWebviewOnDeviceAsync(opt) {
212
+ const cordovaPath = path.resolve(process.cwd(), `packages/${opt.pkgName}/.cordova/`);
213
+ if (opt.url !== undefined) {
214
+ await FsUtil.removeAsync(path.resolve(cordovaPath, "www"));
215
+ await FsUtil.mkdirsAsync(path.resolve(cordovaPath, "www"));
216
+ await FsUtil.writeFileAsync(path.resolve(cordovaPath, "www/index.html"), `'${opt.url}'로 이동중... <script>setTimeout(function () {window.location.href = "${opt.url.replace(/\/$/, "")}/${opt.pkgName}/cordova/"}, 3000);</script>`.trim());
217
+ }
218
+ /*else {
219
+ await FsUtil.removeAsync(path.resolve(cordovaPath, "www"));
220
+ await FsUtil.copyAsync(path.resolve(process.cwd(), `packages/${opt.pkgName}/dist/cordova`), path.resolve(cordovaPath, "www"));
221
+ }*/
222
+ const binPath = path.resolve(process.cwd(), "node_modules/.bin/cordova.cmd");
223
+ await SdProcess.spawnAsync(`${binPath} run ${opt.platform} --device`, { cwd: cordovaPath }, true);
224
+ }
225
+ }
226
226
  //# sourceMappingURL=SdCliCordova.js.map
@@ -1,5 +1,5 @@
1
- export declare class SdCliIndexFileGenerator {
2
- static watchAsync(pkgPath: string, polyfills?: string[]): Promise<void>;
3
- static runAsync(pkgPath: string, polyfills?: string[], cache?: string): Promise<string>;
4
- private static _getFilePathsAsync;
5
- }
1
+ export declare class SdCliIndexFileGenerator {
2
+ static watchAsync(pkgPath: string, polyfills?: string[]): Promise<void>;
3
+ static runAsync(pkgPath: string, polyfills?: string[], cache?: string): Promise<string>;
4
+ private static _getFilePathsAsync;
5
+ }
@@ -1,51 +1,51 @@
1
- import path from "path";
2
- import { FsUtil, PathUtil, SdFsWatcher } from "@simplysm/sd-core-node";
3
- export class SdCliIndexFileGenerator {
4
- static async watchAsync(pkgPath, polyfills) {
5
- const indexFilePath = path.resolve(pkgPath, "src/index.ts");
6
- let cache = FsUtil.exists(indexFilePath) ? FsUtil.readFile(indexFilePath) : undefined;
7
- SdFsWatcher
8
- .watch([path.resolve(pkgPath, "src")])
9
- .onChange({}, async () => {
10
- cache = await this.runAsync(pkgPath, polyfills, cache);
11
- });
12
- cache = await this.runAsync(pkgPath, polyfills, cache);
13
- }
14
- static async runAsync(pkgPath, polyfills, cache) {
15
- const indexFilePath = path.resolve(pkgPath, "src/index.ts");
16
- const importTexts = [];
17
- // polyfills 를 모두 import
18
- if (polyfills) {
19
- for (const polyfill of polyfills.orderBy()) {
20
- importTexts.push(`import "${polyfill}";`);
21
- }
22
- }
23
- // 내부 파일들 import
24
- const filePaths = await this._getFilePathsAsync(pkgPath);
25
- for (const filePath of filePaths.orderBy()) {
26
- const requirePath = PathUtil.posix(path.relative(path.dirname(indexFilePath), filePath))
27
- .replace(/\.tsx?$/, "")
28
- .replace(/\/index$/, "");
29
- const sourceTsFileContent = await FsUtil.readFileAsync(filePath);
30
- if (sourceTsFileContent.split("\n").some((line) => line.startsWith("export "))) {
31
- importTexts.push(`export * from "./${requirePath}";`);
32
- }
33
- else {
34
- importTexts.push(`import "./${requirePath}";`);
35
- }
36
- }
37
- const content = importTexts.join("\n") + "\n";
38
- if (content.trim() !== cache?.trim()) {
39
- await FsUtil.writeFileAsync(indexFilePath, content);
40
- }
41
- return content;
42
- }
43
- static async _getFilePathsAsync(pkgPath) {
44
- const indexFilePath = path.resolve(pkgPath, "src/index.ts");
45
- const tsconfig = await FsUtil.readJsonAsync(path.resolve(pkgPath, "tsconfig.json"));
46
- const entryFilePaths = tsconfig.files?.map((item) => path.resolve(pkgPath, item)) ?? [];
47
- return (await FsUtil.globAsync(path.resolve(pkgPath, "src/**/*{.ts,.tsx}"), { nodir: true }))
48
- .filter((item) => !entryFilePaths.includes(item) && item !== indexFilePath && !item.endsWith(".d.ts"));
49
- }
50
- }
1
+ import path from "path";
2
+ import { FsUtil, PathUtil, SdFsWatcher } from "@simplysm/sd-core-node";
3
+ export class SdCliIndexFileGenerator {
4
+ static async watchAsync(pkgPath, polyfills) {
5
+ const indexFilePath = path.resolve(pkgPath, "src/index.ts");
6
+ let cache = FsUtil.exists(indexFilePath) ? FsUtil.readFile(indexFilePath) : undefined;
7
+ SdFsWatcher
8
+ .watch([path.resolve(pkgPath, "src")])
9
+ .onChange({}, async () => {
10
+ cache = await this.runAsync(pkgPath, polyfills, cache);
11
+ });
12
+ cache = await this.runAsync(pkgPath, polyfills, cache);
13
+ }
14
+ static async runAsync(pkgPath, polyfills, cache) {
15
+ const indexFilePath = path.resolve(pkgPath, "src/index.ts");
16
+ const importTexts = [];
17
+ // polyfills 를 모두 import
18
+ if (polyfills) {
19
+ for (const polyfill of polyfills.orderBy()) {
20
+ importTexts.push(`import "${polyfill}";`);
21
+ }
22
+ }
23
+ // 내부 파일들 import
24
+ const filePaths = await this._getFilePathsAsync(pkgPath);
25
+ for (const filePath of filePaths.orderBy()) {
26
+ const requirePath = PathUtil.posix(path.relative(path.dirname(indexFilePath), filePath))
27
+ .replace(/\.tsx?$/, "")
28
+ .replace(/\/index$/, "");
29
+ const sourceTsFileContent = await FsUtil.readFileAsync(filePath);
30
+ if (sourceTsFileContent.split("\n").some((line) => line.startsWith("export "))) {
31
+ importTexts.push(`export * from "./${requirePath}";`);
32
+ }
33
+ else {
34
+ importTexts.push(`import "./${requirePath}";`);
35
+ }
36
+ }
37
+ const content = importTexts.join("\n") + "\n";
38
+ if (content.trim() !== cache?.trim()) {
39
+ await FsUtil.writeFileAsync(indexFilePath, content);
40
+ }
41
+ return content;
42
+ }
43
+ static async _getFilePathsAsync(pkgPath) {
44
+ const indexFilePath = path.resolve(pkgPath, "src/index.ts");
45
+ const tsconfig = await FsUtil.readJsonAsync(path.resolve(pkgPath, "tsconfig.json"));
46
+ const entryFilePaths = tsconfig.files?.map((item) => path.resolve(pkgPath, item)) ?? [];
47
+ return (await FsUtil.globAsync(path.resolve(pkgPath, "src/**/*{.ts,.tsx}"), { nodir: true }))
48
+ .filter((item) => !entryFilePaths.includes(item) && item !== indexFilePath && !item.endsWith(".d.ts"));
49
+ }
50
+ }
51
51
  //# sourceMappingURL=SdCliIndexFileGenerator.js.map
@@ -1,4 +1,4 @@
1
- export declare class SdCliNgRoutesFileGenerator {
2
- static watchAsync(pkgPath: string): Promise<void>;
3
- static runAsync(pkgPath: string, cache?: string): Promise<string>;
4
- }
1
+ export declare class SdCliNgRoutesFileGenerator {
2
+ static watchAsync(pkgPath: string): Promise<void>;
3
+ static runAsync(pkgPath: string, cache?: string): Promise<string>;
4
+ }