@simplysm/sd-cli 13.0.99 → 14.0.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.
- package/dist/commands/build.js +29 -19
- package/dist/commands/build.js.map +1 -6
- package/dist/commands/check.d.ts +1 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +130 -115
- package/dist/commands/check.js.map +1 -6
- package/dist/commands/dev.d.ts +6 -7
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +24 -14
- package/dist/commands/dev.js.map +1 -6
- package/dist/commands/lint.d.ts +1 -1
- package/dist/commands/lint.js +158 -116
- package/dist/commands/lint.js.map +1 -6
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +637 -510
- package/dist/commands/publish.js.map +1 -6
- package/dist/commands/replace-deps.js +12 -12
- package/dist/commands/replace-deps.js.map +1 -6
- package/dist/commands/typecheck.d.ts +5 -30
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +144 -207
- package/dist/commands/typecheck.js.map +1 -6
- package/dist/commands/watch.d.ts +6 -4
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +25 -16
- package/dist/commands/watch.js.map +1 -6
- package/dist/engines/NgtscEngine.d.ts +47 -0
- package/dist/engines/NgtscEngine.d.ts.map +1 -0
- package/dist/engines/NgtscEngine.js +151 -0
- package/dist/engines/NgtscEngine.js.map +1 -0
- package/dist/engines/ServerEsbuildEngine.d.ts +47 -0
- package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -0
- package/dist/engines/ServerEsbuildEngine.js +159 -0
- package/dist/engines/ServerEsbuildEngine.js.map +1 -0
- package/dist/engines/TscEngine.d.ts +47 -0
- package/dist/engines/TscEngine.d.ts.map +1 -0
- package/dist/engines/TscEngine.js +153 -0
- package/dist/engines/TscEngine.js.map +1 -0
- package/dist/engines/ViteEngine.d.ts +49 -0
- package/dist/engines/ViteEngine.d.ts.map +1 -0
- package/dist/engines/ViteEngine.js +161 -0
- package/dist/engines/ViteEngine.js.map +1 -0
- package/dist/engines/index.d.ts +26 -0
- package/dist/engines/index.d.ts.map +1 -0
- package/dist/engines/index.js +30 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/types.d.ts +77 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +2 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -6
- package/dist/infra/ResultCollector.d.ts +1 -1
- package/dist/infra/ResultCollector.d.ts.map +1 -1
- package/dist/infra/ResultCollector.js +30 -27
- package/dist/infra/ResultCollector.js.map +1 -6
- package/dist/infra/SignalHandler.js +45 -42
- package/dist/infra/SignalHandler.js.map +1 -6
- package/dist/infra/WorkerManager.js +56 -53
- package/dist/infra/WorkerManager.js.map +1 -6
- package/dist/orchestrators/BuildOrchestrator.d.ts +33 -1
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +314 -309
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -6
- package/dist/orchestrators/DevWatchOrchestrator.d.ts +60 -0
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -0
- package/dist/orchestrators/DevWatchOrchestrator.js +465 -0
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -0
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +190 -266
- package/dist/sd-cli-entry.js.map +1 -6
- package/dist/sd-cli.js +77 -49
- package/dist/sd-cli.js.map +1 -6
- package/dist/sd-config.types.d.ts +2 -0
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/sd-config.types.js +2 -1
- package/dist/sd-config.types.js.map +1 -6
- package/dist/utils/angular-build.d.ts +77 -0
- package/dist/utils/angular-build.d.ts.map +1 -0
- package/dist/utils/angular-build.js +84 -0
- package/dist/utils/angular-build.js.map +1 -0
- package/dist/utils/build-env.js +9 -9
- package/dist/utils/build-env.js.map +1 -6
- package/dist/utils/concurrency.d.ts +15 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +38 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/copy-public.js +104 -87
- package/dist/utils/copy-public.js.map +1 -6
- package/dist/utils/copy-src.js +49 -35
- package/dist/utils/copy-src.js.map +1 -6
- package/dist/utils/esbuild-config.d.ts +0 -29
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +151 -218
- package/dist/utils/esbuild-config.js.map +1 -6
- package/dist/utils/ngtsc-build-core.d.ts +49 -0
- package/dist/utils/ngtsc-build-core.d.ts.map +1 -0
- package/dist/utils/ngtsc-build-core.js +250 -0
- package/dist/utils/ngtsc-build-core.js.map +1 -0
- package/dist/utils/output-path-rewriter.d.ts +23 -0
- package/dist/utils/output-path-rewriter.d.ts.map +1 -0
- package/dist/utils/output-path-rewriter.js +74 -0
- package/dist/utils/output-path-rewriter.js.map +1 -0
- package/dist/utils/output-utils.js +55 -40
- package/dist/utils/output-utils.js.map +1 -6
- package/dist/utils/package-utils.d.ts +8 -0
- package/dist/utils/package-utils.d.ts.map +1 -1
- package/dist/utils/package-utils.js +103 -73
- package/dist/utils/package-utils.js.map +1 -6
- package/dist/utils/rebuild-manager.js +41 -44
- package/dist/utils/rebuild-manager.js.map +1 -6
- package/dist/utils/replace-deps.js +283 -184
- package/dist/utils/replace-deps.js.map +1 -6
- package/dist/utils/scss-compiler.d.ts +10 -0
- package/dist/utils/scss-compiler.d.ts.map +1 -0
- package/dist/utils/scss-compiler.js +36 -0
- package/dist/utils/scss-compiler.js.map +1 -0
- package/dist/utils/sd-config.js +29 -19
- package/dist/utils/sd-config.js.map +1 -6
- package/dist/utils/tsc-build.d.ts +36 -0
- package/dist/utils/tsc-build.d.ts.map +1 -0
- package/dist/utils/tsc-build.js +130 -0
- package/dist/utils/tsc-build.js.map +1 -0
- package/dist/utils/tsconfig.d.ts +7 -26
- package/dist/utils/tsconfig.d.ts.map +1 -1
- package/dist/utils/tsconfig.js +39 -64
- package/dist/utils/tsconfig.js.map +1 -6
- package/dist/utils/typecheck-non-package.d.ts +18 -0
- package/dist/utils/typecheck-non-package.d.ts.map +1 -0
- package/dist/utils/typecheck-non-package.js +64 -0
- package/dist/utils/typecheck-non-package.js.map +1 -0
- package/dist/utils/typecheck-serialization.js +58 -40
- package/dist/utils/typecheck-serialization.js.map +1 -6
- package/dist/utils/worker-events.js +48 -40
- package/dist/utils/worker-events.js.map +1 -6
- package/dist/utils/worker-utils.js +48 -28
- package/dist/utils/worker-utils.js.map +1 -6
- package/dist/vitest-plugin.d.ts +9 -0
- package/dist/vitest-plugin.d.ts.map +1 -0
- package/dist/vitest-plugin.js +85 -0
- package/dist/vitest-plugin.js.map +1 -0
- package/dist/workers/library-build.worker.d.ts +54 -0
- package/dist/workers/library-build.worker.d.ts.map +1 -0
- package/dist/workers/library-build.worker.js +97 -0
- package/dist/workers/library-build.worker.js.map +1 -0
- package/dist/workers/lint.worker.js +9 -6
- package/dist/workers/lint.worker.js.map +1 -6
- package/dist/workers/ngtsc-build.worker.d.ts +23 -0
- package/dist/workers/ngtsc-build.worker.d.ts.map +1 -0
- package/dist/workers/ngtsc-build.worker.js +98 -0
- package/dist/workers/ngtsc-build.worker.js.map +1 -0
- package/dist/workers/{server.worker.d.ts → server-build.worker.d.ts} +39 -29
- package/dist/workers/server-build.worker.d.ts.map +1 -0
- package/dist/workers/server-build.worker.js +399 -0
- package/dist/workers/server-build.worker.js.map +1 -0
- package/dist/workers/server-runtime.worker.d.ts +3 -2
- package/dist/workers/server-runtime.worker.d.ts.map +1 -1
- package/dist/workers/server-runtime.worker.js +100 -95
- package/dist/workers/server-runtime.worker.js.map +1 -6
- package/dist/workers/vite-build.worker.d.ts +56 -0
- package/dist/workers/vite-build.worker.d.ts.map +1 -0
- package/dist/workers/vite-build.worker.js +167 -0
- package/dist/workers/vite-build.worker.js.map +1 -0
- package/package.json +10 -16
- package/src/commands/check.ts +21 -3
- package/src/commands/dev.ts +10 -8
- package/src/commands/lint.ts +1 -1
- package/src/commands/publish.ts +4 -0
- package/src/commands/typecheck.ts +89 -256
- package/src/commands/watch.ts +9 -8
- package/src/engines/NgtscEngine.ts +190 -0
- package/src/engines/ServerEsbuildEngine.ts +195 -0
- package/src/engines/TscEngine.ts +189 -0
- package/src/engines/ViteEngine.ts +203 -0
- package/src/engines/index.ts +49 -0
- package/src/engines/types.ts +79 -0
- package/src/index.ts +0 -3
- package/src/infra/ResultCollector.ts +1 -1
- package/src/orchestrators/BuildOrchestrator.ts +87 -157
- package/src/orchestrators/DevWatchOrchestrator.ts +573 -0
- package/src/sd-cli-entry.ts +13 -116
- package/src/sd-config.types.ts +2 -0
- package/src/utils/angular-build.ts +157 -0
- package/src/utils/concurrency.ts +43 -0
- package/src/utils/esbuild-config.ts +1 -122
- package/src/utils/ngtsc-build-core.ts +379 -0
- package/src/utils/output-path-rewriter.ts +82 -0
- package/src/utils/package-utils.ts +20 -0
- package/src/utils/scss-compiler.ts +58 -0
- package/src/utils/tsc-build.ts +175 -0
- package/src/utils/tsconfig.ts +27 -95
- package/src/utils/typecheck-non-package.ts +87 -0
- package/src/vitest-plugin.ts +118 -0
- package/src/workers/library-build.worker.ts +153 -0
- package/src/workers/ngtsc-build.worker.ts +146 -0
- package/src/workers/server-build.worker.ts +565 -0
- package/src/workers/server-runtime.worker.ts +17 -26
- package/src/workers/vite-build.worker.ts +252 -0
- package/tests/commands/check.spec.ts +276 -0
- package/tests/commands/dev.spec.ts +53 -0
- package/tests/commands/lint.spec.ts +243 -0
- package/tests/commands/publish.spec.ts +1159 -0
- package/tests/commands/typecheck.spec.ts +294 -0
- package/tests/commands/watch.spec.ts +53 -0
- package/tests/engines/engine-selection.spec.ts +247 -0
- package/tests/engines/ngtsc-engine.spec.ts +274 -0
- package/tests/engines/server-esbuild-engine.spec.ts +256 -0
- package/tests/engines/tsc-engine.spec.ts +213 -0
- package/tests/engines/vite-engine.spec.ts +358 -0
- package/tests/infra/result-collector.spec.ts +46 -0
- package/tests/infra/signal-handler.spec.ts +32 -0
- package/tests/infra/worker-manager.spec.ts +63 -0
- package/tests/orchestrators/build-orchestrator.spec.ts +772 -0
- package/tests/orchestrators/dev-watch-orchestrator.spec.ts +1173 -0
- package/tests/sd-cli-entry.spec.ts +49 -0
- package/tests/utils/angular-build.spec.ts +251 -0
- package/tests/utils/build-env.spec.ts +33 -0
- package/tests/utils/concurrency.spec.ts +65 -0
- package/tests/utils/copy-src.spec.ts +144 -0
- package/tests/utils/esbuild-config.spec.ts +186 -0
- package/tests/utils/external-modules.spec.ts +161 -0
- package/tests/utils/ngtsc-scss-refactor.spec.ts +66 -0
- package/tests/utils/output-path-rewriter.spec.ts +165 -0
- package/tests/utils/output-utils.spec.ts +104 -0
- package/tests/utils/package-utils.spec.ts +52 -0
- package/tests/utils/rebuild-manager.spec.ts +30 -27
- package/tests/utils/replace-deps.spec.ts +69 -0
- package/tests/utils/scss-compiler.spec.ts +131 -0
- package/tests/utils/sd-config.spec.ts +77 -0
- package/tests/utils/tsc-build.spec.ts +358 -0
- package/tests/utils/tsconfig-angular.spec.ts +71 -0
- package/tests/utils/typecheck-non-package.spec.ts +120 -0
- package/tests/utils/worker-events.spec.ts +155 -0
- package/tests/utils/worker-utils.spec.ts +43 -0
- package/tests/vitest-plugin-cwd.spec.ts +68 -0
- package/tests/vitest-plugin.spec.ts +103 -0
- package/tests/workers/library-build-worker.spec.ts +258 -0
- package/tests/workers/ngtsc-build-worker.spec.ts +187 -0
- package/tests/workers/server-build-worker.spec.ts +566 -0
- package/tests/workers/server-runtime-worker.spec.ts +251 -0
- package/README.md +0 -295
- package/dist/builders/BaseBuilder.d.ts +0 -88
- package/dist/builders/BaseBuilder.d.ts.map +0 -1
- package/dist/builders/BaseBuilder.js +0 -142
- package/dist/builders/BaseBuilder.js.map +0 -6
- package/dist/builders/DtsBuilder.d.ts +0 -22
- package/dist/builders/DtsBuilder.d.ts.map +0 -1
- package/dist/builders/DtsBuilder.js +0 -72
- package/dist/builders/DtsBuilder.js.map +0 -6
- package/dist/builders/LibraryBuilder.d.ts +0 -22
- package/dist/builders/LibraryBuilder.d.ts.map +0 -1
- package/dist/builders/LibraryBuilder.js +0 -85
- package/dist/builders/LibraryBuilder.js.map +0 -6
- package/dist/builders/types.d.ts +0 -55
- package/dist/builders/types.d.ts.map +0 -1
- package/dist/builders/types.js +0 -1
- package/dist/builders/types.js.map +0 -6
- package/dist/capacitor/capacitor.d.ts +0 -151
- package/dist/capacitor/capacitor.d.ts.map +0 -1
- package/dist/capacitor/capacitor.js +0 -694
- package/dist/capacitor/capacitor.js.map +0 -6
- package/dist/commands/device.d.ts +0 -22
- package/dist/commands/device.d.ts.map +0 -1
- package/dist/commands/device.js +0 -98
- package/dist/commands/device.js.map +0 -6
- package/dist/commands/init.d.ts +0 -14
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -72
- package/dist/commands/init.js.map +0 -6
- package/dist/electron/electron.d.ts +0 -84
- package/dist/electron/electron.d.ts.map +0 -1
- package/dist/electron/electron.js +0 -263
- package/dist/electron/electron.js.map +0 -6
- package/dist/orchestrators/DevOrchestrator.d.ts +0 -83
- package/dist/orchestrators/DevOrchestrator.d.ts.map +0 -1
- package/dist/orchestrators/DevOrchestrator.js +0 -540
- package/dist/orchestrators/DevOrchestrator.js.map +0 -6
- package/dist/orchestrators/WatchOrchestrator.d.ts +0 -57
- package/dist/orchestrators/WatchOrchestrator.d.ts.map +0 -1
- package/dist/orchestrators/WatchOrchestrator.js +0 -199
- package/dist/orchestrators/WatchOrchestrator.js.map +0 -6
- package/dist/utils/tailwind-config-deps.d.ts +0 -8
- package/dist/utils/tailwind-config-deps.d.ts.map +0 -1
- package/dist/utils/tailwind-config-deps.js +0 -82
- package/dist/utils/tailwind-config-deps.js.map +0 -6
- package/dist/utils/template.d.ts +0 -14
- package/dist/utils/template.d.ts.map +0 -1
- package/dist/utils/template.js +0 -33
- package/dist/utils/template.js.map +0 -6
- package/dist/utils/vite-config.d.ts +0 -35
- package/dist/utils/vite-config.d.ts.map +0 -1
- package/dist/utils/vite-config.js +0 -259
- package/dist/utils/vite-config.js.map +0 -6
- package/dist/workers/client.worker.d.ts +0 -83
- package/dist/workers/client.worker.d.ts.map +0 -1
- package/dist/workers/client.worker.js +0 -111
- package/dist/workers/client.worker.js.map +0 -6
- package/dist/workers/dts.worker.d.ts +0 -75
- package/dist/workers/dts.worker.d.ts.map +0 -1
- package/dist/workers/dts.worker.js +0 -270
- package/dist/workers/dts.worker.js.map +0 -6
- package/dist/workers/library.worker.d.ts +0 -75
- package/dist/workers/library.worker.d.ts.map +0 -1
- package/dist/workers/library.worker.js +0 -166
- package/dist/workers/library.worker.js.map +0 -6
- package/dist/workers/server.worker.d.ts.map +0 -1
- package/dist/workers/server.worker.js +0 -482
- package/dist/workers/server.worker.js.map +0 -6
- package/src/builders/BaseBuilder.ts +0 -218
- package/src/builders/DtsBuilder.ts +0 -92
- package/src/builders/LibraryBuilder.ts +0 -110
- package/src/builders/types.ts +0 -60
- package/src/capacitor/capacitor.ts +0 -931
- package/src/commands/device.ts +0 -140
- package/src/commands/init.ts +0 -113
- package/src/electron/electron.ts +0 -362
- package/src/orchestrators/DevOrchestrator.ts +0 -744
- package/src/orchestrators/WatchOrchestrator.ts +0 -277
- package/src/utils/tailwind-config-deps.ts +0 -98
- package/src/utils/template.ts +0 -56
- package/src/utils/vite-config.ts +0 -390
- package/src/workers/client.worker.ts +0 -250
- package/src/workers/dts.worker.ts +0 -453
- package/src/workers/library.worker.ts +0 -316
- package/src/workers/server.worker.ts +0 -734
- package/templates/init/.gitignore.hbs +0 -34
- package/templates/init/.npmrc.hbs +0 -1
- package/templates/init/.prettierignore +0 -1
- package/templates/init/.prettierrc.yaml +0 -12
- package/templates/init/eslint.config.ts +0 -15
- package/templates/init/mise.toml +0 -3
- package/templates/init/package.json.hbs +0 -32
- package/templates/init/packages/client-admin/index.html.hbs +0 -144
- package/templates/init/packages/client-admin/package.json.hbs +0 -27
- package/templates/init/packages/client-admin/public/assets/logo-landscape.png +0 -0
- package/templates/init/packages/client-admin/public/assets/logo.png +0 -0
- package/templates/init/packages/client-admin/public/favicon.ico +0 -0
- package/templates/init/packages/client-admin/src/App.tsx +0 -42
- package/templates/init/packages/client-admin/src/dev/DevDialog.tsx +0 -34
- package/templates/init/packages/client-admin/src/events/AuthChangeEvent.ts +0 -3
- package/templates/init/packages/client-admin/src/main.css +0 -4
- package/templates/init/packages/client-admin/src/main.tsx.hbs +0 -146
- package/templates/init/packages/client-admin/src/providers/AppServiceProvider.tsx.hbs +0 -103
- package/templates/init/packages/client-admin/src/providers/AppStructureProvider.tsx +0 -84
- package/templates/init/packages/client-admin/src/providers/AuthProvider.tsx.hbs +0 -96
- package/templates/init/packages/client-admin/src/providers/configureSharedData.ts.hbs +0 -67
- package/templates/init/packages/client-admin/src/views/auth/LoginView.tsx +0 -132
- package/templates/init/packages/client-admin/src/views/home/HomeView.tsx +0 -108
- package/templates/init/packages/client-admin/src/views/home/base/employee/EmployeeDetail.tsx.hbs +0 -243
- package/templates/init/packages/client-admin/src/views/home/base/employee/EmployeeSheet.tsx.hbs +0 -271
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RoleDetail.tsx.hbs +0 -146
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RolePermissionDetail.tsx.hbs +0 -121
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RolePermissionView.tsx +0 -52
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RoleSheet.tsx.hbs +0 -125
- package/templates/init/packages/client-admin/src/views/home/main/MainView.tsx.hbs +0 -13
- package/templates/init/packages/client-admin/src/views/home/my-info/MyInfoDetail.tsx.hbs +0 -241
- package/templates/init/packages/client-admin/src/views/home/system/system-log/SystemLogSheet.tsx.hbs +0 -169
- package/templates/init/packages/client-admin/src/views/not-found/NotFoundView.tsx +0 -15
- package/templates/init/packages/client-admin/tailwind.config.ts +0 -10
- package/templates/init/packages/db-main/package.json.hbs +0 -13
- package/templates/init/packages/db-main/src/MainDbContext.ts +0 -22
- package/templates/init/packages/db-main/src/dataLogExt.ts +0 -127
- package/templates/init/packages/db-main/src/index.ts +0 -14
- package/templates/init/packages/db-main/src/tables/base/Employee.ts +0 -24
- package/templates/init/packages/db-main/src/tables/base/EmployeeConfig.ts +0 -13
- package/templates/init/packages/db-main/src/tables/base/Role.ts +0 -9
- package/templates/init/packages/db-main/src/tables/base/RolePermission.ts +0 -13
- package/templates/init/packages/db-main/src/tables/system/_DataLog.ts +0 -19
- package/templates/init/packages/db-main/src/tables/system/_Log.ts +0 -16
- package/templates/init/packages/server/package.json.hbs +0 -20
- package/templates/init/packages/server/public-dev/dev//354/264/210/352/270/260/355/231/224.xlsx +0 -0
- package/templates/init/packages/server/src/index.ts +0 -4
- package/templates/init/packages/server/src/main.ts.hbs +0 -34
- package/templates/init/packages/server/src/services/AuthService.ts.hbs +0 -171
- package/templates/init/packages/server/src/services/DevService.ts.hbs +0 -94
- package/templates/init/packages/server/src/services/EmployeeService.ts.hbs +0 -122
- package/templates/init/packages/server/src/services/RoleService.ts.hbs +0 -59
- package/templates/init/pnpm-workspace.yaml +0 -15
- package/templates/init/sd.config.ts.hbs +0 -48
- package/templates/init/tsconfig.json.hbs +0 -39
- package/templates/init/vitest.config.ts +0 -36
- package/tests/capacitor-exclude.spec.ts +0 -78
- package/tests/capacitor.spec.ts +0 -49
- package/tests/copy-src.spec.ts +0 -50
- package/tests/electron-exclude.spec.ts +0 -61
- package/tests/get-compiler-options-for-package.spec.ts +0 -80
- package/tests/get-package-source-files.spec.ts +0 -139
- package/tests/get-types-from-package-json.spec.ts +0 -92
- package/tests/infra/ResultCollector.spec.ts +0 -30
- package/tests/infra/SignalHandler.spec.ts +0 -38
- package/tests/infra/WorkerManager.spec.ts +0 -63
- package/tests/load-ignore-patterns.spec.ts +0 -163
- package/tests/load-sd-config.spec.ts +0 -100
- package/tests/package-utils.spec.ts +0 -188
- package/tests/parse-root-tsconfig.spec.ts +0 -89
- package/tests/publish-config-narrowing.spec.ts +0 -20
- package/tests/replace-deps.spec.ts +0 -308
- package/tests/run-lint.spec.ts +0 -366
- package/tests/run-typecheck.spec.ts +0 -544
- package/tests/run-watch.spec.ts +0 -76
- package/tests/sd-cli.spec.ts +0 -265
- package/tests/sd-public-dev-plugin-mime.spec.ts +0 -19
- package/tests/tailwind-config-deps.spec.ts +0 -30
- package/tests/template.spec.ts +0 -70
- package/tests/vite-config-exclude.spec.ts +0 -35
- package/tests/vite-config-outdir.spec.ts +0 -38
- package/tests/write-changed-output-files.spec.ts +0 -97
|
@@ -1,931 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { fsx } from "@simplysm/core-node";
|
|
3
|
-
import { env } from "@simplysm/core-common";
|
|
4
|
-
import { consola } from "consola";
|
|
5
|
-
import sharp from "sharp";
|
|
6
|
-
import type { SdCapacitorConfig } from "../sd-config.types";
|
|
7
|
-
import { execa } from "execa";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* package.json type
|
|
11
|
-
*/
|
|
12
|
-
interface NpmConfig {
|
|
13
|
-
name: string;
|
|
14
|
-
version: string;
|
|
15
|
-
dependencies?: Record<string, string>;
|
|
16
|
-
devDependencies?: Record<string, string>;
|
|
17
|
-
peerDependencies?: Record<string, string>;
|
|
18
|
-
volta?: unknown;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Configuration validation error
|
|
23
|
-
*/
|
|
24
|
-
class CapacitorConfigError extends Error {
|
|
25
|
-
constructor(message: string) {
|
|
26
|
-
super(message);
|
|
27
|
-
this.name = "CapacitorConfigError";
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Capacitor project management class
|
|
33
|
-
*
|
|
34
|
-
* - Initialize Capacitor project
|
|
35
|
-
* - Build Android APK/AAB
|
|
36
|
-
* - Run app on device
|
|
37
|
-
*/
|
|
38
|
-
export class Capacitor {
|
|
39
|
-
private static readonly _ANDROID_KEYSTORE_FILE_NAME = "android.keystore";
|
|
40
|
-
private static readonly _LOCK_FILE_NAME = ".capacitor.lock";
|
|
41
|
-
private static readonly _logger = consola.withTag("sd:cli:capacitor");
|
|
42
|
-
private static readonly _utf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
43
|
-
private static readonly _fallbackDecoder = new TextDecoder("euc-kr");
|
|
44
|
-
|
|
45
|
-
private readonly _capPath: string;
|
|
46
|
-
private readonly _platforms: string[];
|
|
47
|
-
private readonly _npmConfig: NpmConfig;
|
|
48
|
-
|
|
49
|
-
private constructor(
|
|
50
|
-
private readonly _pkgPath: string,
|
|
51
|
-
private readonly _config: SdCapacitorConfig,
|
|
52
|
-
npmConfig: NpmConfig,
|
|
53
|
-
private readonly _exclude: string[],
|
|
54
|
-
) {
|
|
55
|
-
this._platforms = Object.keys(this._config.platform ?? {});
|
|
56
|
-
this._npmConfig = npmConfig;
|
|
57
|
-
this._capPath = path.resolve(this._pkgPath, ".capacitor");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Create Capacitor instance (with configuration validation)
|
|
62
|
-
*/
|
|
63
|
-
static async create(
|
|
64
|
-
pkgPath: string,
|
|
65
|
-
config: SdCapacitorConfig,
|
|
66
|
-
exclude?: string[],
|
|
67
|
-
): Promise<Capacitor> {
|
|
68
|
-
// F5: validate runtime configuration
|
|
69
|
-
Capacitor._validateConfig(config);
|
|
70
|
-
|
|
71
|
-
const npmConfig = await fsx.readJson<NpmConfig>(path.resolve(pkgPath, "package.json"));
|
|
72
|
-
return new Capacitor(pkgPath, config, npmConfig, exclude ?? []);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* F5: Validate configuration
|
|
77
|
-
*/
|
|
78
|
-
private static _validateConfig(config: SdCapacitorConfig): void {
|
|
79
|
-
if (typeof config.appId !== "string" || config.appId.trim() === "") {
|
|
80
|
-
throw new CapacitorConfigError("capacitor.appId is required.");
|
|
81
|
-
}
|
|
82
|
-
if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/i.test(config.appId)) {
|
|
83
|
-
throw new CapacitorConfigError(`capacitor.appId format is invalid: ${config.appId}`);
|
|
84
|
-
}
|
|
85
|
-
if (typeof config.appName !== "string" || config.appName.trim() === "") {
|
|
86
|
-
throw new CapacitorConfigError("capacitor.appName is required.");
|
|
87
|
-
}
|
|
88
|
-
if (!/^[\p{L}\p{N} \-]+$/u.test(config.appName)) {
|
|
89
|
-
throw new CapacitorConfigError(`capacitor.appName contains invalid characters: ${config.appName}`);
|
|
90
|
-
}
|
|
91
|
-
if (config.platform != null) {
|
|
92
|
-
const platforms = Object.keys(config.platform);
|
|
93
|
-
for (const p of platforms) {
|
|
94
|
-
if (p !== "android") {
|
|
95
|
-
throw new CapacitorConfigError(`unsupported platform: ${p} (currently only android is supported)`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Execute a Capacitor CLI command via npx
|
|
103
|
-
*/
|
|
104
|
-
private async _execCap(args: string[]): Promise<string> {
|
|
105
|
-
return this._exec("npx", ["cap", ...args], this._capPath);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Execute capacitor-assets CLI command via npx
|
|
110
|
-
*/
|
|
111
|
-
private async _execCapAssets(args: string[]): Promise<string> {
|
|
112
|
-
return this._exec("npx", ["capacitor-assets", ...args], this._capPath);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Execute command (with logging)
|
|
117
|
-
*/
|
|
118
|
-
private async _exec(cmd: string, args: string[], cwd: string): Promise<string> {
|
|
119
|
-
Capacitor._logger.debug(`executed command: ${cmd} ${args.join(" ")}`);
|
|
120
|
-
|
|
121
|
-
const result = await execa(cmd, args, { cwd, reject: false, encoding: "buffer" });
|
|
122
|
-
const stdout = Capacitor._decodeOutput(result.stdout);
|
|
123
|
-
|
|
124
|
-
if (result.exitCode !== 0) {
|
|
125
|
-
const stderr = Capacitor._decodeOutput(result.stderr);
|
|
126
|
-
throw new Error(`${cmd} ${args.join(" ")} failed (exit ${result.exitCode}): ${stderr || stdout}`);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
Capacitor._logger.debug(`execution result: ${stdout}`);
|
|
130
|
-
return stdout;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Decode command output (UTF-8 first, fallback to EUC-KR for Windows CP949)
|
|
135
|
-
*/
|
|
136
|
-
private static _decodeOutput(bytes: Uint8Array): string {
|
|
137
|
-
try {
|
|
138
|
-
return Capacitor._utf8Decoder.decode(bytes);
|
|
139
|
-
} catch {
|
|
140
|
-
return Capacitor._fallbackDecoder.decode(bytes);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* F10: Acquire lock to prevent concurrent execution
|
|
146
|
-
*/
|
|
147
|
-
private async _acquireLock(): Promise<void> {
|
|
148
|
-
const lockPath = path.resolve(this._capPath, Capacitor._LOCK_FILE_NAME);
|
|
149
|
-
if (await fsx.exists(lockPath)) {
|
|
150
|
-
const lockContent = await fsx.read(lockPath);
|
|
151
|
-
throw new Error(
|
|
152
|
-
`Another Capacitor operation is in progress (PID: ${lockContent}). ` +
|
|
153
|
-
`If there's an issue, delete the ${lockPath} file.`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
await fsx.mkdir(this._capPath);
|
|
157
|
-
await fsx.write(lockPath, String(process.pid));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* F10: Release lock
|
|
162
|
-
*/
|
|
163
|
-
private async _releaseLock(): Promise<void> {
|
|
164
|
-
const lockPath = path.resolve(this._capPath, Capacitor._LOCK_FILE_NAME);
|
|
165
|
-
await fsx.rm(lockPath);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* F4: Validate external tools
|
|
170
|
-
*/
|
|
171
|
-
private async _validateTools(): Promise<void> {
|
|
172
|
-
// Check Android SDK
|
|
173
|
-
const sdkPath = await this._findAndroidSdk();
|
|
174
|
-
if (sdkPath == null) {
|
|
175
|
-
throw new Error(
|
|
176
|
-
"Android SDK not found.\n" +
|
|
177
|
-
"1. Install Android Studio or\n" +
|
|
178
|
-
"2. Set ANDROID_HOME or ANDROID_SDK_ROOT environment variable.",
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Check Java (only for android platform)
|
|
183
|
-
if (this._platforms.includes("android")) {
|
|
184
|
-
const javaPath = await this._findJava21();
|
|
185
|
-
if (javaPath == null) {
|
|
186
|
-
Capacitor._logger.warn(
|
|
187
|
-
"Java 21 not found. Gradle may use embedded JDK or the build may fail.",
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Initialize Capacitor project
|
|
195
|
-
*
|
|
196
|
-
* 1. Create package.json and install dependencies
|
|
197
|
-
* 2. Create capacitor.config.ts
|
|
198
|
-
* 3. Add platform (android)
|
|
199
|
-
* 4. Set up icon
|
|
200
|
-
* 5. Configure Android native settings
|
|
201
|
-
* 6. Run cap sync or cap copy
|
|
202
|
-
*/
|
|
203
|
-
async initialize(): Promise<void> {
|
|
204
|
-
await this._acquireLock();
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
// F4: Validate external tools
|
|
208
|
-
await this._validateTools();
|
|
209
|
-
|
|
210
|
-
// 1. Initialize Capacitor project
|
|
211
|
-
const changed = await this._initCap();
|
|
212
|
-
|
|
213
|
-
// 2. Create Capacitor config file
|
|
214
|
-
await this._writeCapConf();
|
|
215
|
-
|
|
216
|
-
// 3. Manage platform (F12: idempotent - skip if already exists)
|
|
217
|
-
await this._addPlatforms();
|
|
218
|
-
|
|
219
|
-
// 4. Set up icon (F6: error recovery)
|
|
220
|
-
await this._setupIcon();
|
|
221
|
-
|
|
222
|
-
// 5. Configure Android native settings
|
|
223
|
-
if (this._platforms.includes("android")) {
|
|
224
|
-
await this._configureAndroid();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// 6. Synchronize web assets
|
|
228
|
-
if (changed) {
|
|
229
|
-
await this._execCap(["sync"]);
|
|
230
|
-
} else {
|
|
231
|
-
await this._execCap(["copy"]);
|
|
232
|
-
}
|
|
233
|
-
} finally {
|
|
234
|
-
await this._releaseLock();
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Build Android APK/AAB
|
|
240
|
-
*/
|
|
241
|
-
async build(outPath: string): Promise<void> {
|
|
242
|
-
await this._acquireLock();
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
const buildType = this._config.debug ? "debug" : "release";
|
|
246
|
-
|
|
247
|
-
for (const platform of this._platforms) {
|
|
248
|
-
await this._execCap(["copy", platform]);
|
|
249
|
-
|
|
250
|
-
if (platform === "android") {
|
|
251
|
-
await this._buildAndroid(outPath, buildType);
|
|
252
|
-
} else {
|
|
253
|
-
throw new Error(`unsupported platform: ${platform}`);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
} finally {
|
|
257
|
-
await this._releaseLock();
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Run app on device (connect WebView to development server)
|
|
263
|
-
*/
|
|
264
|
-
async runOnDevice(url?: string): Promise<void> {
|
|
265
|
-
// F11: Validate URL
|
|
266
|
-
if (url != null) {
|
|
267
|
-
this._validateUrl(url);
|
|
268
|
-
await this._updateServerUrl(url);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
for (const platform of this._platforms) {
|
|
272
|
-
await this._execCap(["copy", platform]);
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
await this._execCap(["run", platform]);
|
|
276
|
-
} catch (err) {
|
|
277
|
-
if (platform === "android") {
|
|
278
|
-
try {
|
|
279
|
-
await this._exec("adb", ["kill-server"], this._capPath);
|
|
280
|
-
} catch {
|
|
281
|
-
// adb kill-server failure is ignored
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
throw err;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* F11: Validate URL
|
|
291
|
-
*/
|
|
292
|
-
private _validateUrl(url: string): void {
|
|
293
|
-
try {
|
|
294
|
-
const parsed = new URL(url);
|
|
295
|
-
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
296
|
-
throw new Error(`unsupported protocol: ${parsed.protocol}`);
|
|
297
|
-
}
|
|
298
|
-
} catch (err) {
|
|
299
|
-
if (err instanceof TypeError) {
|
|
300
|
-
throw new Error(`invalid URL: ${url}`);
|
|
301
|
-
}
|
|
302
|
-
throw err;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
//#region Private - Initialization
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Basic Capacitor project initialization (package.json, pnpm install, cap init)
|
|
310
|
-
*/
|
|
311
|
-
private async _initCap(): Promise<boolean> {
|
|
312
|
-
const depChanged = await this._setupNpmConf();
|
|
313
|
-
const nodeModulesExists = await fsx.exists(path.resolve(this._capPath, "node_modules"));
|
|
314
|
-
|
|
315
|
-
if (!depChanged && nodeModulesExists) return false;
|
|
316
|
-
|
|
317
|
-
// pnpm install
|
|
318
|
-
const installResult = await this._exec("npm", ["install"], this._capPath);
|
|
319
|
-
Capacitor._logger.debug(`npm install completed: ${installResult}`);
|
|
320
|
-
|
|
321
|
-
// F12: cap init idempotency - execute only when capacitor.config.ts does not exist
|
|
322
|
-
const configPath = path.resolve(this._capPath, "capacitor.config.ts");
|
|
323
|
-
if (!(await fsx.exists(configPath))) {
|
|
324
|
-
await this._execCap(["init", this._config.appId, this._config.appId]);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Create default www/index.html
|
|
328
|
-
const wwwPath = path.resolve(this._capPath, "www");
|
|
329
|
-
await fsx.mkdir(wwwPath);
|
|
330
|
-
await fsx.write(
|
|
331
|
-
path.resolve(wwwPath, "index.html"),
|
|
332
|
-
"<!DOCTYPE html><html><head></head><body></body></html>",
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
return true;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Configure package.json
|
|
340
|
-
*/
|
|
341
|
-
private async _setupNpmConf(): Promise<boolean> {
|
|
342
|
-
const projNpmConfigPath = path.resolve(this._pkgPath, "../../package.json");
|
|
343
|
-
|
|
344
|
-
// F3: Check if file exists
|
|
345
|
-
if (!(await fsx.exists(projNpmConfigPath))) {
|
|
346
|
-
throw new Error(`root package.json not found: ${projNpmConfigPath}`);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const projNpmConfig = await fsx.readJson<NpmConfig>(projNpmConfigPath);
|
|
350
|
-
|
|
351
|
-
const capNpmConfPath = path.resolve(this._capPath, "package.json");
|
|
352
|
-
const orgCapNpmConf: NpmConfig = (await fsx.exists(capNpmConfPath))
|
|
353
|
-
? await fsx.readJson<NpmConfig>(capNpmConfPath)
|
|
354
|
-
: { name: "", version: "" };
|
|
355
|
-
|
|
356
|
-
const capNpmConf: NpmConfig = { ...orgCapNpmConf };
|
|
357
|
-
capNpmConf.name = this._config.appId;
|
|
358
|
-
capNpmConf.version = this._npmConfig.version;
|
|
359
|
-
if (projNpmConfig.volta != null) {
|
|
360
|
-
capNpmConf.volta = projNpmConfig.volta;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Default dependencies
|
|
364
|
-
capNpmConf.dependencies = capNpmConf.dependencies ?? {};
|
|
365
|
-
capNpmConf.dependencies["@capacitor/core"] = "^7.0.0";
|
|
366
|
-
capNpmConf.dependencies["@capacitor/app"] = "^7.0.0";
|
|
367
|
-
for (const platform of this._platforms) {
|
|
368
|
-
capNpmConf.dependencies[`@capacitor/${platform}`] = "^7.0.0";
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
capNpmConf.devDependencies = capNpmConf.devDependencies ?? {};
|
|
372
|
-
capNpmConf.devDependencies["@capacitor/cli"] = "^7.0.0";
|
|
373
|
-
capNpmConf.devDependencies["@capacitor/assets"] = "^3.0.0";
|
|
374
|
-
|
|
375
|
-
// Configure plugin packages
|
|
376
|
-
const mainDeps = {
|
|
377
|
-
...this._npmConfig.dependencies,
|
|
378
|
-
...this._npmConfig.devDependencies,
|
|
379
|
-
...this._npmConfig.peerDependencies,
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
const usePlugins = Object.keys(this._config.plugins ?? {});
|
|
383
|
-
|
|
384
|
-
const prevPlugins = Object.keys(capNpmConf.dependencies).filter(
|
|
385
|
-
(item) =>
|
|
386
|
-
!["@capacitor/core", "@capacitor/android", "@capacitor/ios", "@capacitor/app"].includes(
|
|
387
|
-
item,
|
|
388
|
-
),
|
|
389
|
-
);
|
|
390
|
-
|
|
391
|
-
// Remove unused plugins
|
|
392
|
-
for (const prevPlugin of prevPlugins) {
|
|
393
|
-
if (!usePlugins.includes(prevPlugin)) {
|
|
394
|
-
delete capNpmConf.dependencies[prevPlugin];
|
|
395
|
-
Capacitor._logger.debug(`plugin removed: ${prevPlugin}`);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// Add new plugins
|
|
400
|
-
for (const plugin of usePlugins) {
|
|
401
|
-
if (!(plugin in capNpmConf.dependencies)) {
|
|
402
|
-
const version = mainDeps[plugin] ?? "*";
|
|
403
|
-
capNpmConf.dependencies[plugin] = version;
|
|
404
|
-
Capacitor._logger.debug(`plugin added: ${plugin}@${version}`);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Add exclude packages
|
|
409
|
-
for (const excludePkg of this._exclude) {
|
|
410
|
-
if (!(excludePkg in capNpmConf.dependencies)) {
|
|
411
|
-
const version = mainDeps[excludePkg] ?? "*";
|
|
412
|
-
capNpmConf.dependencies[excludePkg] = version;
|
|
413
|
-
Capacitor._logger.debug(`exclude package added: ${excludePkg}@${version}`);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// Save
|
|
418
|
-
await fsx.mkdir(this._capPath);
|
|
419
|
-
await fsx.writeJson(capNpmConfPath, capNpmConf, { space: 2 });
|
|
420
|
-
|
|
421
|
-
// Check if dependencies changed
|
|
422
|
-
const isChanged =
|
|
423
|
-
orgCapNpmConf.volta !== capNpmConf.volta ||
|
|
424
|
-
JSON.stringify(orgCapNpmConf.dependencies) !== JSON.stringify(capNpmConf.dependencies) ||
|
|
425
|
-
JSON.stringify(orgCapNpmConf.devDependencies) !== JSON.stringify(capNpmConf.devDependencies);
|
|
426
|
-
|
|
427
|
-
return isChanged;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Create capacitor.config.ts
|
|
432
|
-
*/
|
|
433
|
-
private async _writeCapConf(): Promise<void> {
|
|
434
|
-
const confPath = path.resolve(this._capPath, "capacitor.config.ts");
|
|
435
|
-
|
|
436
|
-
// Create plugin options
|
|
437
|
-
const pluginOptions: Record<string, Record<string, unknown>> = {};
|
|
438
|
-
for (const [pluginName, options] of Object.entries(this._config.plugins ?? {})) {
|
|
439
|
-
if (options !== true) {
|
|
440
|
-
const configKey = this._toPascalCase(pluginName.split("/").at(-1)!);
|
|
441
|
-
pluginOptions[configKey] = options;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const pluginsConfigStr =
|
|
446
|
-
Object.keys(pluginOptions).length > 0
|
|
447
|
-
? JSON.stringify(pluginOptions, null, 2).replace(/^/gm, " ").trim()
|
|
448
|
-
: "{}";
|
|
449
|
-
|
|
450
|
-
const configContent = `import type { CapacitorConfig } from "@capacitor/cli";
|
|
451
|
-
|
|
452
|
-
const config: CapacitorConfig = {
|
|
453
|
-
appId: "${this._config.appId}",
|
|
454
|
-
appName: "${this._config.appName}",
|
|
455
|
-
server: {
|
|
456
|
-
androidScheme: "http",
|
|
457
|
-
cleartext: true
|
|
458
|
-
},
|
|
459
|
-
android: {},
|
|
460
|
-
plugins: ${pluginsConfigStr},
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
export default config;
|
|
464
|
-
`;
|
|
465
|
-
|
|
466
|
-
await fsx.write(confPath, configContent);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Add platform (F12: ensure idempotency)
|
|
471
|
-
*/
|
|
472
|
-
private async _addPlatforms(): Promise<void> {
|
|
473
|
-
for (const platform of this._platforms) {
|
|
474
|
-
const platformPath = path.resolve(this._capPath, platform);
|
|
475
|
-
if (await fsx.exists(platformPath)) {
|
|
476
|
-
Capacitor._logger.debug(`platform already exists: ${platform}`);
|
|
477
|
-
continue;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
await this._execCap(["add", platform]);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* Set up icon (F6: error recovery)
|
|
486
|
-
*/
|
|
487
|
-
private async _setupIcon(): Promise<void> {
|
|
488
|
-
const assetsDirPath = path.resolve(this._capPath, "assets");
|
|
489
|
-
|
|
490
|
-
if (this._config.icon != null) {
|
|
491
|
-
const iconSource = path.resolve(this._pkgPath, this._config.icon);
|
|
492
|
-
|
|
493
|
-
// F6: Check if source icon exists
|
|
494
|
-
if (!(await fsx.exists(iconSource))) {
|
|
495
|
-
Capacitor._logger.warn(
|
|
496
|
-
`icon file not found: ${iconSource}. Using default icon.`,
|
|
497
|
-
);
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
try {
|
|
502
|
-
await fsx.mkdir(assetsDirPath);
|
|
503
|
-
|
|
504
|
-
// Create icon
|
|
505
|
-
const logoPath = path.resolve(assetsDirPath, "logo.png");
|
|
506
|
-
|
|
507
|
-
const logoSize = Math.floor(1024 * 0.6);
|
|
508
|
-
const padding = Math.floor((1024 - logoSize) / 2);
|
|
509
|
-
|
|
510
|
-
// F6: Handle sharp errors
|
|
511
|
-
await sharp(iconSource)
|
|
512
|
-
.resize(logoSize, logoSize, {
|
|
513
|
-
fit: "contain",
|
|
514
|
-
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
515
|
-
})
|
|
516
|
-
.extend({
|
|
517
|
-
top: padding,
|
|
518
|
-
bottom: padding,
|
|
519
|
-
left: padding,
|
|
520
|
-
right: padding,
|
|
521
|
-
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
522
|
-
})
|
|
523
|
-
.toFile(logoPath);
|
|
524
|
-
|
|
525
|
-
await this._execCapAssets([
|
|
526
|
-
"generate",
|
|
527
|
-
"--iconBackgroundColor",
|
|
528
|
-
"#ffffff",
|
|
529
|
-
"--splashBackgroundColor",
|
|
530
|
-
"#ffffff",
|
|
531
|
-
]);
|
|
532
|
-
} catch (err) {
|
|
533
|
-
Capacitor._logger.warn(
|
|
534
|
-
`icon generation failed: ${err instanceof Error ? err.message : err}. Using default icon.`,
|
|
535
|
-
);
|
|
536
|
-
// F6: Continue even if it fails (use default icon)
|
|
537
|
-
}
|
|
538
|
-
} else {
|
|
539
|
-
await fsx.rm(assetsDirPath);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
//#endregion
|
|
544
|
-
|
|
545
|
-
//#region Private - Android Configuration
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Configure Android native settings
|
|
549
|
-
*/
|
|
550
|
-
private async _configureAndroid(): Promise<void> {
|
|
551
|
-
const androidPath = path.resolve(this._capPath, "android");
|
|
552
|
-
|
|
553
|
-
// F3: Check if Android directory exists
|
|
554
|
-
if (!(await fsx.exists(androidPath))) {
|
|
555
|
-
throw new Error(`Android project directory not found: ${androidPath}`);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
await this._configureAndroidJavaHomePath(androidPath);
|
|
559
|
-
await this._configureAndroidSdkPath(androidPath);
|
|
560
|
-
await this._configureAndroidManifest(androidPath);
|
|
561
|
-
await this._configureAndroidBuildGradle(androidPath);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Set up JAVA_HOME path (gradle.properties)
|
|
566
|
-
*/
|
|
567
|
-
private async _configureAndroidJavaHomePath(androidPath: string): Promise<void> {
|
|
568
|
-
const gradlePropsPath = path.resolve(androidPath, "gradle.properties");
|
|
569
|
-
|
|
570
|
-
// F3: Check if file exists
|
|
571
|
-
if (!(await fsx.exists(gradlePropsPath))) {
|
|
572
|
-
Capacitor._logger.warn(`gradle.properties file not found: ${gradlePropsPath}`);
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
let content = await fsx.read(gradlePropsPath);
|
|
577
|
-
|
|
578
|
-
const java21Path = await this._findJava21();
|
|
579
|
-
if (java21Path != null && !content.includes("org.gradle.java.home")) {
|
|
580
|
-
// F9: Improved Windows path escaping
|
|
581
|
-
const escapedPath = java21Path.replace(/\\/g, "\\\\");
|
|
582
|
-
content += `\norg.gradle.java.home=${escapedPath}\n`;
|
|
583
|
-
await fsx.write(gradlePropsPath, content);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* Auto-detect Java 21 path
|
|
589
|
-
*/
|
|
590
|
-
private async _findJava21(): Promise<string | undefined> {
|
|
591
|
-
const patterns = [
|
|
592
|
-
"C:/Program Files/Amazon Corretto/jdk21*",
|
|
593
|
-
"C:/Program Files/Eclipse Adoptium/jdk-21*",
|
|
594
|
-
"C:/Program Files/Java/jdk-21*",
|
|
595
|
-
"C:/Program Files/Microsoft/jdk-21*",
|
|
596
|
-
"/usr/lib/jvm/java-21*",
|
|
597
|
-
"/usr/lib/jvm/temurin-21*",
|
|
598
|
-
];
|
|
599
|
-
|
|
600
|
-
for (const pattern of patterns) {
|
|
601
|
-
const matches = await fsx.glob(pattern);
|
|
602
|
-
if (matches.length > 0) {
|
|
603
|
-
return matches.sort().at(-1);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
return undefined;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/**
|
|
611
|
-
* Set up Android SDK path (local.properties)
|
|
612
|
-
*/
|
|
613
|
-
private async _configureAndroidSdkPath(androidPath: string): Promise<void> {
|
|
614
|
-
const localPropsPath = path.resolve(androidPath, "local.properties");
|
|
615
|
-
|
|
616
|
-
const sdkPath = await this._findAndroidSdk();
|
|
617
|
-
if (sdkPath != null) {
|
|
618
|
-
// F9: Always use forward slash (Gradle compatible)
|
|
619
|
-
await fsx.write(localPropsPath, `sdk.dir=${sdkPath.replace(/\\/g, "/")}\n`);
|
|
620
|
-
} else {
|
|
621
|
-
throw new Error(
|
|
622
|
-
"Android SDK not found.\n" +
|
|
623
|
-
"1. Install Android Studio or\n" +
|
|
624
|
-
"2. Set ANDROID_HOME or ANDROID_SDK_ROOT environment variable.",
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
/**
|
|
630
|
-
* Search for Android SDK path
|
|
631
|
-
*/
|
|
632
|
-
private async _findAndroidSdk(): Promise<string | undefined> {
|
|
633
|
-
const fromEnv = (env["ANDROID_HOME"] ?? env["ANDROID_SDK_ROOT"]) as string | undefined;
|
|
634
|
-
if (fromEnv != null && (await fsx.exists(fromEnv))) {
|
|
635
|
-
return fromEnv;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const candidates = [
|
|
639
|
-
path.resolve((env["LOCALAPPDATA"] as string | undefined) ?? "", "Android/Sdk"),
|
|
640
|
-
path.resolve((env["HOME"] as string | undefined) ?? "", "Android/Sdk"),
|
|
641
|
-
"C:/Program Files/Android/Sdk",
|
|
642
|
-
"C:/Android/Sdk",
|
|
643
|
-
];
|
|
644
|
-
|
|
645
|
-
for (const candidate of candidates) {
|
|
646
|
-
if (await fsx.exists(candidate)) {
|
|
647
|
-
return candidate;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
return undefined;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* Modify AndroidManifest.xml (F3: add error handling)
|
|
656
|
-
*/
|
|
657
|
-
private async _configureAndroidManifest(androidPath: string): Promise<void> {
|
|
658
|
-
const manifestPath = path.resolve(androidPath, "app/src/main/AndroidManifest.xml");
|
|
659
|
-
|
|
660
|
-
// F3: Check if file exists
|
|
661
|
-
if (!(await fsx.exists(manifestPath))) {
|
|
662
|
-
throw new Error(`AndroidManifest.xml file not found: ${manifestPath}`);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
let content = await fsx.read(manifestPath);
|
|
666
|
-
|
|
667
|
-
// Configure usesCleartextTraffic
|
|
668
|
-
if (!content.includes("android:usesCleartextTraffic")) {
|
|
669
|
-
content = content.replace("<application", '<application android:usesCleartextTraffic="true"');
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Configure additional permissions
|
|
673
|
-
const permissions = this._config.platform?.android?.permissions ?? [];
|
|
674
|
-
for (const perm of permissions) {
|
|
675
|
-
const permTag = `<uses-permission android:name="android.permission.${perm.name}"`;
|
|
676
|
-
if (!content.includes(permTag)) {
|
|
677
|
-
const maxSdkAttr =
|
|
678
|
-
perm.maxSdkVersion != null ? ` android:maxSdkVersion="${perm.maxSdkVersion}"` : "";
|
|
679
|
-
const ignoreAttr = perm.ignore != null ? ` tools:ignore="${perm.ignore}"` : "";
|
|
680
|
-
const permLine = ` ${permTag}${maxSdkAttr}${ignoreAttr} />\n`;
|
|
681
|
-
|
|
682
|
-
if (perm.ignore != null && !content.includes("xmlns:tools=")) {
|
|
683
|
-
content = content.replace(
|
|
684
|
-
"<manifest xmlns:android",
|
|
685
|
-
'<manifest xmlns:tools="http://schemas.android.com/tools" xmlns:android',
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
content = content.replace("</manifest>", `${permLine}</manifest>`);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// Configure additional application settings
|
|
694
|
-
const appConfig = this._config.platform?.android?.config;
|
|
695
|
-
if (appConfig) {
|
|
696
|
-
for (const [key, value] of Object.entries(appConfig)) {
|
|
697
|
-
const attr = `android:${key}="${value}"`;
|
|
698
|
-
if (!content.includes(`android:${key}=`)) {
|
|
699
|
-
content = content.replace("<application", `<application ${attr}`);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// Configure intentFilters
|
|
705
|
-
const intentFilters = this._config.platform?.android?.intentFilters ?? [];
|
|
706
|
-
for (const filter of intentFilters) {
|
|
707
|
-
const filterKey = filter.action ?? filter.category ?? "";
|
|
708
|
-
if (filterKey && !content.includes(filterKey)) {
|
|
709
|
-
const actionLine = filter.action != null ? `<action android:name="${filter.action}"/>` : "";
|
|
710
|
-
const categoryLine =
|
|
711
|
-
filter.category != null ? `<category android:name="${filter.category}"/>` : "";
|
|
712
|
-
|
|
713
|
-
content = content.replace(
|
|
714
|
-
/(<activity[\s\S]*?android:name="\.MainActivity"[\s\S]*?>)/,
|
|
715
|
-
`$1
|
|
716
|
-
<intent-filter>
|
|
717
|
-
${actionLine}
|
|
718
|
-
${categoryLine}
|
|
719
|
-
</intent-filter>`,
|
|
720
|
-
);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
await fsx.write(manifestPath, content);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* Modify build.gradle (F3: add error handling)
|
|
729
|
-
*/
|
|
730
|
-
private async _configureAndroidBuildGradle(androidPath: string): Promise<void> {
|
|
731
|
-
const buildGradlePath = path.resolve(androidPath, "app/build.gradle");
|
|
732
|
-
|
|
733
|
-
// F3: Check if file exists
|
|
734
|
-
if (!(await fsx.exists(buildGradlePath))) {
|
|
735
|
-
throw new Error(`build.gradle file not found: ${buildGradlePath}`);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
let content = await fsx.read(buildGradlePath);
|
|
739
|
-
|
|
740
|
-
// Configure versionName and versionCode
|
|
741
|
-
const version = this._npmConfig.version;
|
|
742
|
-
const cleanVersion = version.replace(/-.*$/, "");
|
|
743
|
-
const versionParts = cleanVersion.split(".");
|
|
744
|
-
const versionCode =
|
|
745
|
-
parseInt(versionParts[0] ?? "0") * 10000 +
|
|
746
|
-
parseInt(versionParts[1] ?? "0") * 100 +
|
|
747
|
-
parseInt(versionParts[2] ?? "0");
|
|
748
|
-
|
|
749
|
-
content = content.replace(/versionCode \d+/, `versionCode ${versionCode}`);
|
|
750
|
-
content = content.replace(/versionName "[^"]+"/, `versionName "${version}"`);
|
|
751
|
-
|
|
752
|
-
// Configure SDK version
|
|
753
|
-
if (this._config.platform?.android?.sdkVersion != null) {
|
|
754
|
-
const sdkVersion = this._config.platform.android.sdkVersion;
|
|
755
|
-
content = content.replace(/minSdkVersion .+/, `minSdkVersion ${sdkVersion}`);
|
|
756
|
-
content = content.replace(/targetSdkVersion .+/, `targetSdkVersion ${sdkVersion}`);
|
|
757
|
-
} else {
|
|
758
|
-
content = content.replace(/minSdkVersion .+/, `minSdkVersion rootProject.ext.minSdkVersion`);
|
|
759
|
-
content = content.replace(
|
|
760
|
-
/targetSdkVersion .+/,
|
|
761
|
-
`targetSdkVersion rootProject.ext.targetSdkVersion`,
|
|
762
|
-
);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
// Configure signing
|
|
766
|
-
const keystorePath = path.resolve(this._capPath, Capacitor._ANDROID_KEYSTORE_FILE_NAME);
|
|
767
|
-
const signConfig = this._config.platform?.android?.sign;
|
|
768
|
-
if (signConfig) {
|
|
769
|
-
const keystoreSource = path.resolve(this._pkgPath, signConfig.keystore);
|
|
770
|
-
// F3: Check if keystore file exists
|
|
771
|
-
if (!(await fsx.exists(keystoreSource))) {
|
|
772
|
-
throw new Error(`keystore file not found: ${keystoreSource}`);
|
|
773
|
-
}
|
|
774
|
-
await fsx.copy(keystoreSource, keystorePath);
|
|
775
|
-
|
|
776
|
-
// F9: Convert relative path to forward slash
|
|
777
|
-
const keystoreRelativePath = path
|
|
778
|
-
.relative(path.dirname(buildGradlePath), keystorePath)
|
|
779
|
-
.replace(/\\/g, "/");
|
|
780
|
-
const keystoreType = signConfig.keystoreType ?? "jks";
|
|
781
|
-
|
|
782
|
-
if (!content.includes("signingConfigs")) {
|
|
783
|
-
const signingConfigsBlock = `
|
|
784
|
-
signingConfigs {
|
|
785
|
-
release {
|
|
786
|
-
storeFile file("${keystoreRelativePath}")
|
|
787
|
-
storePassword '${Capacitor._escapeGroovyString(signConfig.storePassword)}'
|
|
788
|
-
keyAlias '${Capacitor._escapeGroovyString(signConfig.alias)}'
|
|
789
|
-
keyPassword '${Capacitor._escapeGroovyString(signConfig.password)}'
|
|
790
|
-
storeType "${keystoreType}"
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
`;
|
|
794
|
-
content = content.replace(/(android\s*\{)/, (match) => `${match}${signingConfigsBlock}`);
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
if (!content.includes("signingConfig signingConfigs.release")) {
|
|
798
|
-
content = content.replace(
|
|
799
|
-
/(buildTypes\s*\{[\s\S]*?release\s*\{)/,
|
|
800
|
-
`$1\n signingConfig signingConfigs.release`,
|
|
801
|
-
);
|
|
802
|
-
}
|
|
803
|
-
} else {
|
|
804
|
-
await fsx.rm(keystorePath);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
await fsx.write(buildGradlePath, content);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
* Escape single quotes in Groovy string (for use in single-quoted strings)
|
|
812
|
-
* Groovy: 'string with \'single quote\' inside'
|
|
813
|
-
*/
|
|
814
|
-
private static _escapeGroovyString(value: string): string {
|
|
815
|
-
return value.replace(/'/g, "\\'");
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
//#endregion
|
|
819
|
-
|
|
820
|
-
//#region Private - Build
|
|
821
|
-
|
|
822
|
-
/**
|
|
823
|
-
* Build Android
|
|
824
|
-
*/
|
|
825
|
-
private async _buildAndroid(outPath: string, buildType: string): Promise<void> {
|
|
826
|
-
const androidPath = path.resolve(this._capPath, "android");
|
|
827
|
-
const targetOutPath = path.resolve(outPath, "android");
|
|
828
|
-
|
|
829
|
-
const isBundle = this._config.platform?.android?.bundle;
|
|
830
|
-
const gradleTask =
|
|
831
|
-
buildType === "release" ? (isBundle ? "bundleRelease" : "assembleRelease") : "assembleDebug";
|
|
832
|
-
|
|
833
|
-
// Execute Gradle build (cross-platform)
|
|
834
|
-
// F9: Run via cmd.exe on Windows (because shell: false)
|
|
835
|
-
if (process.platform === "win32") {
|
|
836
|
-
await this._exec("cmd", ["/c", "gradlew.bat", gradleTask, "--no-daemon"], androidPath);
|
|
837
|
-
} else {
|
|
838
|
-
await this._exec("sh", ["./gradlew", gradleTask, "--no-daemon"], androidPath);
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// Copy build output
|
|
842
|
-
await this._copyAndroidBuildOutput(androidPath, targetOutPath, buildType);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
/**
|
|
846
|
-
* Copy Android build output
|
|
847
|
-
*/
|
|
848
|
-
private async _copyAndroidBuildOutput(
|
|
849
|
-
androidPath: string,
|
|
850
|
-
targetOutPath: string,
|
|
851
|
-
buildType: string,
|
|
852
|
-
): Promise<void> {
|
|
853
|
-
const isBundle = this._config.platform?.android?.bundle;
|
|
854
|
-
const isSigned = Boolean(this._config.platform?.android?.sign);
|
|
855
|
-
|
|
856
|
-
const ext = isBundle ? "aab" : "apk";
|
|
857
|
-
const outputType = isBundle ? "bundle" : "apk";
|
|
858
|
-
const fileName = isSigned ? `app-${buildType}.${ext}` : `app-${buildType}-unsigned.${ext}`;
|
|
859
|
-
|
|
860
|
-
const sourcePath = path.resolve(
|
|
861
|
-
androidPath,
|
|
862
|
-
"app/build/outputs",
|
|
863
|
-
outputType,
|
|
864
|
-
buildType,
|
|
865
|
-
fileName,
|
|
866
|
-
);
|
|
867
|
-
|
|
868
|
-
const actualPath = (await fsx.exists(sourcePath))
|
|
869
|
-
? sourcePath
|
|
870
|
-
: path.resolve(
|
|
871
|
-
androidPath,
|
|
872
|
-
"app/build/outputs",
|
|
873
|
-
outputType,
|
|
874
|
-
buildType,
|
|
875
|
-
`app-${buildType}.${ext}`,
|
|
876
|
-
);
|
|
877
|
-
|
|
878
|
-
if (!(await fsx.exists(actualPath))) {
|
|
879
|
-
Capacitor._logger.warn(`build output not found: ${actualPath}`);
|
|
880
|
-
return;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
const outputFileName = `${this._config.appName}${isSigned ? "" : "-unsigned"}-latest.${ext}`;
|
|
884
|
-
|
|
885
|
-
await fsx.mkdir(targetOutPath);
|
|
886
|
-
await fsx.copy(actualPath, path.resolve(targetOutPath, outputFileName));
|
|
887
|
-
|
|
888
|
-
// Save per-version
|
|
889
|
-
const updatesPath = path.resolve(targetOutPath, "updates");
|
|
890
|
-
await fsx.mkdir(updatesPath);
|
|
891
|
-
await fsx.copy(actualPath, path.resolve(updatesPath, `${this._npmConfig.version}.${ext}`));
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
//#endregion
|
|
895
|
-
|
|
896
|
-
//#region Private - Device Execution
|
|
897
|
-
|
|
898
|
-
/**
|
|
899
|
-
* Update server.url in capacitor.config.ts
|
|
900
|
-
*/
|
|
901
|
-
private async _updateServerUrl(url: string): Promise<void> {
|
|
902
|
-
const configPath = path.resolve(this._capPath, "capacitor.config.ts");
|
|
903
|
-
|
|
904
|
-
if (!(await fsx.exists(configPath))) return;
|
|
905
|
-
|
|
906
|
-
let content = await fsx.read(configPath);
|
|
907
|
-
|
|
908
|
-
if (content.includes("url:")) {
|
|
909
|
-
content = content.replace(/url:\s*"[^"]*"/, `url: "${url}"`);
|
|
910
|
-
} else if (content.includes("server:")) {
|
|
911
|
-
content = content.replace(/server:\s*\{/, `server: {\n url: "${url}",`);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
await fsx.write(configPath, content);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
//#endregion
|
|
918
|
-
|
|
919
|
-
//#region Private - Utilities
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
* Convert string to PascalCase
|
|
923
|
-
*/
|
|
924
|
-
private _toPascalCase(str: string): string {
|
|
925
|
-
return str
|
|
926
|
-
.replace(/[-_](.)/g, (_, c: string) => c.toUpperCase())
|
|
927
|
-
.replace(/^./, (c) => c.toUpperCase());
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
//#endregion
|
|
931
|
-
}
|