ylyx-cli 1.0.16 → 1.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 (289) hide show
  1. package/README.md +313 -276
  2. package/bin/ylyx.js +176 -168
  3. package/lib/config.js +325 -283
  4. package/lib/deploy.js +509 -529
  5. package/lib/environments.js +111 -0
  6. package/lib/generator.js +192 -192
  7. package/lib/index.js +113 -113
  8. package/lib/interactive.js +87 -87
  9. package/lib/remote.js +179 -179
  10. package/lib/template.js +174 -174
  11. package/lib/utils.js +148 -148
  12. package/package.json +61 -59
  13. package/templates/react-app/files/.gitignore +22 -0
  14. package/templates/react-app/files/README.md +23 -23
  15. package/templates/react-app/files/package.json +28 -28
  16. package/templates/react-app/files/public/index.html +11 -11
  17. package/templates/react-app/files/src/App.css +15 -15
  18. package/templates/react-app/files/src/App.js +15 -15
  19. package/templates/react-app/files/src/index.css +10 -10
  20. package/templates/react-app/files/src/index.js +11 -11
  21. package/templates/react-app/template.json +11 -11
  22. package/templates/react-component/files/Component.module.css +5 -5
  23. package/templates/react-component/files/Component.tsx +31 -31
  24. package/templates/react-component/files/index.ts +2 -2
  25. package/templates/react-component/template.json +48 -48
  26. package/templates/vue-app/files/.editorconfig +14 -14
  27. package/templates/vue-app/files/.env.development +21 -21
  28. package/templates/vue-app/files/.env.production +18 -18
  29. package/templates/vue-app/files/.eslintignore +5 -5
  30. package/templates/vue-app/files/.eslintrc.js +267 -267
  31. package/templates/vue-app/files/.gitignore +24 -0
  32. package/templates/vue-app/files/.prettierignore +11 -11
  33. package/templates/vue-app/files/.travis.yml +5 -5
  34. package/templates/vue-app/files/.vscode/extensions.json +7 -7
  35. package/templates/vue-app/files/.vscode/settings.json +39 -39
  36. package/templates/vue-app/files/LICENSE +191 -191
  37. package/templates/vue-app/files/README.md +87 -87
  38. package/templates/vue-app/files/babel.config.js +11 -11
  39. package/templates/vue-app/files/jest.config.js +24 -24
  40. package/templates/vue-app/files/package.json +136 -136
  41. package/templates/vue-app/files/plopfile.js +7 -7
  42. package/templates/vue-app/files/postcss.config.js +5 -5
  43. package/templates/vue-app/files/public/default.js +25 -25
  44. package/templates/vue-app/files/public/index.html +26 -26
  45. package/templates/vue-app/files/src/App.vue +54 -54
  46. package/templates/vue-app/files/src/api/bigDataV/index.js +198 -198
  47. package/templates/vue-app/files/src/api/data.js +42 -42
  48. package/templates/vue-app/files/src/api/dataArchive/index.js +186 -186
  49. package/templates/vue-app/files/src/api/generator/genConfig.js +16 -16
  50. package/templates/vue-app/files/src/api/generator/generator.js +32 -32
  51. package/templates/vue-app/files/src/api/indexManagement/index.js +39 -39
  52. package/templates/vue-app/files/src/api/institutionMonitor/index.js +396 -396
  53. package/templates/vue-app/files/src/api/institutionSet/index.js +120 -120
  54. package/templates/vue-app/files/src/api/login.js +44 -44
  55. package/templates/vue-app/files/src/api/selfStatistics/index.js +50 -50
  56. package/templates/vue-app/files/src/api/system/code.js +15 -15
  57. package/templates/vue-app/files/src/api/system/dict.js +34 -34
  58. package/templates/vue-app/files/src/api/system/dictDetail.js +52 -52
  59. package/templates/vue-app/files/src/api/system/equipment.js +35 -35
  60. package/templates/vue-app/files/src/api/system/examManage.js +49 -49
  61. package/templates/vue-app/files/src/api/system/examProject.js +48 -48
  62. package/templates/vue-app/files/src/api/system/hosModel.js +35 -35
  63. package/templates/vue-app/files/src/api/system/hospital.js +88 -88
  64. package/templates/vue-app/files/src/api/system/job.js +40 -40
  65. package/templates/vue-app/files/src/api/system/menu.js +67 -67
  66. package/templates/vue-app/files/src/api/system/model.js +42 -42
  67. package/templates/vue-app/files/src/api/system/risConfig.js +9 -9
  68. package/templates/vue-app/files/src/api/system/role.js +64 -64
  69. package/templates/vue-app/files/src/api/system/sysSet.js +19 -19
  70. package/templates/vue-app/files/src/api/system/timing.js +41 -41
  71. package/templates/vue-app/files/src/api/system/user.js +121 -121
  72. package/templates/vue-app/files/src/api/tools/alipay.js +25 -25
  73. package/templates/vue-app/files/src/api/tools/email.js +24 -24
  74. package/templates/vue-app/files/src/api/tools/localStorage.js +27 -27
  75. package/templates/vue-app/files/src/api/tools/qiniu.js +40 -40
  76. package/templates/vue-app/files/src/assets/css/font-awesome.css +2342 -2342
  77. package/templates/vue-app/files/src/assets/css/font-awesome.min.css +2336 -2336
  78. package/templates/vue-app/files/src/assets/fonts/fontawesome-webfont.svg +2671 -2671
  79. package/templates/vue-app/files/src/assets/icons/index.js +9 -9
  80. package/templates/vue-app/files/src/assets/icons/svg/hospital.svg +1 -1
  81. package/templates/vue-app/files/src/assets/icons/svg/hospital1.svg +1 -1
  82. package/templates/vue-app/files/src/assets/icons/svg/loginOne.svg +35 -35
  83. package/templates/vue-app/files/src/assets/icons/svg/loginOneWhite.svg +19 -19
  84. package/templates/vue-app/files/src/assets/icons/svg/loginOr.svg +93 -93
  85. package/templates/vue-app/files/src/assets/icons/svg/loginUp.svg +96 -96
  86. package/templates/vue-app/files/src/assets/icons/svg/monitor.svg +1 -1
  87. package/templates/vue-app/files/src/assets/icons/svg/offline.svg +1 -1
  88. package/templates/vue-app/files/src/assets/icons/svg/online.svg +1 -1
  89. package/templates/vue-app/files/src/assets/icons/svg/system.svg +1 -1
  90. package/templates/vue-app/files/src/assets/icons/svgo.yml +21 -21
  91. package/templates/vue-app/files/src/assets/styles/btn.scss +103 -103
  92. package/templates/vue-app/files/src/assets/styles/eladmin.scss +124 -124
  93. package/templates/vue-app/files/src/assets/styles/element-ui.scss +217 -217
  94. package/templates/vue-app/files/src/assets/styles/element-variables.scss +31 -31
  95. package/templates/vue-app/files/src/assets/styles/global.scss +73 -73
  96. package/templates/vue-app/files/src/assets/styles/index.scss +220 -220
  97. package/templates/vue-app/files/src/assets/styles/mixin.scss +60 -60
  98. package/templates/vue-app/files/src/assets/styles/publicStyle.scss +224 -224
  99. package/templates/vue-app/files/src/assets/styles/sidebar.scss +239 -239
  100. package/templates/vue-app/files/src/assets/styles/transition.scss +48 -48
  101. package/templates/vue-app/files/src/assets/styles/variables.scss +44 -44
  102. package/templates/vue-app/files/src/common/flexible.js +145 -145
  103. package/templates/vue-app/files/src/components/Breadcrumb/index.vue +87 -87
  104. package/templates/vue-app/files/src/components/Crud/CRUD.operation.vue +248 -248
  105. package/templates/vue-app/files/src/components/Crud/Pagination.vue +20 -20
  106. package/templates/vue-app/files/src/components/Crud/RR.operation.vue +39 -39
  107. package/templates/vue-app/files/src/components/Crud/UD.operation.vue +106 -106
  108. package/templates/vue-app/files/src/components/Crud/crud.js +907 -907
  109. package/templates/vue-app/files/src/components/Crud/user/UR.operation.vue +154 -154
  110. package/templates/vue-app/files/src/components/DateRangePicker/index.vue +42 -42
  111. package/templates/vue-app/files/src/components/DateRangePickerProhibitNext/index.vue +42 -42
  112. package/templates/vue-app/files/src/components/DateRangePickerProhibitTodayNext/index.vue +48 -48
  113. package/templates/vue-app/files/src/components/Dict/Dict.js +31 -31
  114. package/templates/vue-app/files/src/components/Dict/index.js +29 -29
  115. package/templates/vue-app/files/src/components/Doc/index.vue +16 -16
  116. package/templates/vue-app/files/src/components/Echarts/BarChart.vue +115 -115
  117. package/templates/vue-app/files/src/components/Echarts/Category.vue +768 -768
  118. package/templates/vue-app/files/src/components/Echarts/Funnel.vue +120 -120
  119. package/templates/vue-app/files/src/components/Echarts/Gauge.vue +74 -74
  120. package/templates/vue-app/files/src/components/Echarts/Graph.vue +101 -101
  121. package/templates/vue-app/files/src/components/Echarts/HeatMap.vue +301 -301
  122. package/templates/vue-app/files/src/components/Echarts/Line3D.vue +110 -110
  123. package/templates/vue-app/files/src/components/Echarts/PieChart.vue +84 -84
  124. package/templates/vue-app/files/src/components/Echarts/Point.vue +161 -161
  125. package/templates/vue-app/files/src/components/Echarts/RadarChart.vue +123 -123
  126. package/templates/vue-app/files/src/components/Echarts/Rich.vue +160 -160
  127. package/templates/vue-app/files/src/components/Echarts/Sankey.vue +114 -114
  128. package/templates/vue-app/files/src/components/Echarts/Scatter.vue +192 -192
  129. package/templates/vue-app/files/src/components/Echarts/Sunburst.vue +127 -127
  130. package/templates/vue-app/files/src/components/Echarts/ThemeRiver.vue +233 -233
  131. package/templates/vue-app/files/src/components/Echarts/WordCloud.vue +201 -201
  132. package/templates/vue-app/files/src/components/GithubCorner/index.vue +55 -55
  133. package/templates/vue-app/files/src/components/Hamburger/index.vue +44 -44
  134. package/templates/vue-app/files/src/components/HeaderSearch/index.vue +196 -196
  135. package/templates/vue-app/files/src/components/IconSelect/index.vue +74 -74
  136. package/templates/vue-app/files/src/components/IconSelect/requireIcons.js +10 -10
  137. package/templates/vue-app/files/src/components/Iframe/index.vue +30 -30
  138. package/templates/vue-app/files/src/components/JavaEdit/index.vue +78 -78
  139. package/templates/vue-app/files/src/components/Pagination/index.vue +100 -100
  140. package/templates/vue-app/files/src/components/PanThumb/index.vue +149 -149
  141. package/templates/vue-app/files/src/components/ParentView/index.vue +3 -3
  142. package/templates/vue-app/files/src/components/Permission/index.js +13 -13
  143. package/templates/vue-app/files/src/components/Permission/permission.js +21 -21
  144. package/templates/vue-app/files/src/components/RightPanel/index.vue +149 -149
  145. package/templates/vue-app/files/src/components/Screenfull/index.vue +60 -60
  146. package/templates/vue-app/files/src/components/SizeSelect/index.vue +60 -60
  147. package/templates/vue-app/files/src/components/SvgIcon/index.vue +66 -66
  148. package/templates/vue-app/files/src/components/ThemePicker/index.vue +177 -177
  149. package/templates/vue-app/files/src/components/UploadExcel/index.vue +149 -149
  150. package/templates/vue-app/files/src/components/WaterMark/setWaterMark.js +68 -68
  151. package/templates/vue-app/files/src/components/WaterMark/waterMark.vue +69 -69
  152. package/templates/vue-app/files/src/components/Xgplayer/index.vue +49 -49
  153. package/templates/vue-app/files/src/components/YamlEdit/index.vue +81 -81
  154. package/templates/vue-app/files/src/layout/components/AppMain.vue +67 -67
  155. package/templates/vue-app/files/src/layout/components/Navbar.vue +209 -209
  156. package/templates/vue-app/files/src/layout/components/Settings/index.vue +125 -125
  157. package/templates/vue-app/files/src/layout/components/Sidebar/FixiOSBug.js +26 -26
  158. package/templates/vue-app/files/src/layout/components/Sidebar/Item.vue +29 -29
  159. package/templates/vue-app/files/src/layout/components/Sidebar/Link.vue +35 -35
  160. package/templates/vue-app/files/src/layout/components/Sidebar/Logo.vue +93 -93
  161. package/templates/vue-app/files/src/layout/components/Sidebar/SidebarItem.vue +104 -104
  162. package/templates/vue-app/files/src/layout/components/Sidebar/index.vue +79 -79
  163. package/templates/vue-app/files/src/layout/components/TagsView/ScrollPane.vue +90 -90
  164. package/templates/vue-app/files/src/layout/components/TagsView/index.vue +299 -299
  165. package/templates/vue-app/files/src/layout/components/index.js +5 -5
  166. package/templates/vue-app/files/src/layout/index.vue +119 -119
  167. package/templates/vue-app/files/src/layout/mixin/ResizeHandler.js +45 -45
  168. package/templates/vue-app/files/src/main.js +89 -89
  169. package/templates/vue-app/files/src/mixins/crud.js +348 -348
  170. package/templates/vue-app/files/src/router/index.js +156 -156
  171. package/templates/vue-app/files/src/router/routers.js +203 -203
  172. package/templates/vue-app/files/src/settings.js +57 -57
  173. package/templates/vue-app/files/src/store/getters.js +29 -29
  174. package/templates/vue-app/files/src/store/index.js +25 -25
  175. package/templates/vue-app/files/src/store/modules/api.js +33 -33
  176. package/templates/vue-app/files/src/store/modules/app.js +55 -55
  177. package/templates/vue-app/files/src/store/modules/permission.js +79 -79
  178. package/templates/vue-app/files/src/store/modules/register.js +17 -17
  179. package/templates/vue-app/files/src/store/modules/settings.js +46 -46
  180. package/templates/vue-app/files/src/store/modules/tagsView.js +168 -168
  181. package/templates/vue-app/files/src/store/modules/user.js +119 -119
  182. package/templates/vue-app/files/src/utils/auth.js +18 -18
  183. package/templates/vue-app/files/src/utils/base64ToFile.js +27 -27
  184. package/templates/vue-app/files/src/utils/clipboard.js +36 -36
  185. package/templates/vue-app/files/src/utils/datetime.js +289 -289
  186. package/templates/vue-app/files/src/utils/getBlobFile.js +10 -10
  187. package/templates/vue-app/files/src/utils/getTime.js +29 -29
  188. package/templates/vue-app/files/src/utils/index.js +520 -520
  189. package/templates/vue-app/files/src/utils/permission.js +29 -29
  190. package/templates/vue-app/files/src/utils/pinyin.js +450 -450
  191. package/templates/vue-app/files/src/utils/request.js +139 -139
  192. package/templates/vue-app/files/src/utils/rsaEncrypt.js +37 -37
  193. package/templates/vue-app/files/src/utils/shortcuts.js +210 -210
  194. package/templates/vue-app/files/src/utils/upload.js +12 -12
  195. package/templates/vue-app/files/src/utils/validate.js +262 -262
  196. package/templates/vue-app/files/src/views/components/Echarts.vue +124 -124
  197. package/templates/vue-app/files/src/views/components/Editor.vue +75 -75
  198. package/templates/vue-app/files/src/views/components/MarkDown.vue +44 -44
  199. package/templates/vue-app/files/src/views/components/UVideo.vue +37 -37
  200. package/templates/vue-app/files/src/views/components/YamlEdit.vue +206 -206
  201. package/templates/vue-app/files/src/views/components/camera/camera.vue +115 -115
  202. package/templates/vue-app/files/src/views/components/camera/cameraTest.vue +158 -158
  203. package/templates/vue-app/files/src/views/components/excel/upload-excel.vue +41 -41
  204. package/templates/vue-app/files/src/views/components/icons/element-icons.js +74 -74
  205. package/templates/vue-app/files/src/views/components/icons/index.vue +106 -106
  206. package/templates/vue-app/files/src/views/components/icons/svg-icons.js +10 -10
  207. package/templates/vue-app/files/src/views/components/scroll/index.vue +107 -107
  208. package/templates/vue-app/files/src/views/components/scrollFull/index.vue +99 -99
  209. package/templates/vue-app/files/src/views/dashboard/LineChart.vue +138 -138
  210. package/templates/vue-app/files/src/views/dashboard/PanelGroup.vue +173 -173
  211. package/templates/vue-app/files/src/views/dashboard/mixins/resize.js +57 -57
  212. package/templates/vue-app/files/src/views/dataArchive/delTable.vue +354 -354
  213. package/templates/vue-app/files/src/views/dataArchive/exportDetail.vue +121 -121
  214. package/templates/vue-app/files/src/views/dataArchive/exportList.vue +160 -160
  215. package/templates/vue-app/files/src/views/dataArchive/index.vue +2104 -2104
  216. package/templates/vue-app/files/src/views/features/401.vue +83 -83
  217. package/templates/vue-app/files/src/views/features/404.vue +226 -226
  218. package/templates/vue-app/files/src/views/features/redirect.vue +12 -12
  219. package/templates/vue-app/files/src/views/generator/config.vue +348 -348
  220. package/templates/vue-app/files/src/views/generator/index.vue +143 -143
  221. package/templates/vue-app/files/src/views/generator/preview.vue +39 -39
  222. package/templates/vue-app/files/src/views/home.vue +80 -80
  223. package/templates/vue-app/files/src/views/indexManagement/index.vue +422 -422
  224. package/templates/vue-app/files/src/views/indexManagement/other.vue +286 -286
  225. package/templates/vue-app/files/src/views/institutionMonitor/components/LineChart.vue +191 -191
  226. package/templates/vue-app/files/src/views/institutionMonitor/index.scss +339 -339
  227. package/templates/vue-app/files/src/views/institutionMonitor/index.vue +1385 -1385
  228. package/templates/vue-app/files/src/views/institutionMonitor/mixins/resize.js +57 -57
  229. package/templates/vue-app/files/src/views/institutionMonitor/monitorDetail/checkProjectCode.vue +267 -267
  230. package/templates/vue-app/files/src/views/institutionMonitor/monitorDetail/imageAbnormalMonitor.vue +361 -361
  231. package/templates/vue-app/files/src/views/institutionMonitor/monitorDetail/index.vue +686 -686
  232. package/templates/vue-app/files/src/views/institutionMonitor/monitorDetail/leakageAnomaly.vue +270 -270
  233. package/templates/vue-app/files/src/views/institutionMonitor/monitorDetail/moveMonitore.vue +114 -114
  234. package/templates/vue-app/files/src/views/institutionMonitor/monitorDetail/qualityMonitore.vue +338 -338
  235. package/templates/vue-app/files/src/views/institutionSet/cloudSet.vue +534 -534
  236. package/templates/vue-app/files/src/views/institutionSet/index.vue +2550 -2550
  237. package/templates/vue-app/files/src/views/login.vue +243 -243
  238. package/templates/vue-app/files/src/views/qualityLogin.vue +280 -280
  239. package/templates/vue-app/files/src/views/selfStatistics/components/LineChart.vue +296 -296
  240. package/templates/vue-app/files/src/views/selfStatistics/hospitalDetail/index.vue +533 -533
  241. package/templates/vue-app/files/src/views/selfStatistics/index.scss +447 -447
  242. package/templates/vue-app/files/src/views/selfStatistics/index.vue +903 -903
  243. package/templates/vue-app/files/src/views/selfStatistics/mixins/resize.js +57 -57
  244. package/templates/vue-app/files/src/views/selfStatistics/monitorDetail/index.vue +285 -285
  245. package/templates/vue-app/files/src/views/selfStatistics/offlineDetail/index.vue +104 -104
  246. package/templates/vue-app/files/src/views/selfStatistics/selfActiveDetail/index.vue +104 -104
  247. package/templates/vue-app/files/src/views/selfStatistics/selfMonitorDetail/index.vue +420 -420
  248. package/templates/vue-app/files/src/views/selfStatistics/setWaterMark/setWaterMark.js +68 -68
  249. package/templates/vue-app/files/src/views/selfStatistics/setWaterMark/waterMark.vue +69 -69
  250. package/templates/vue-app/files/src/views/system/dept/index.vue +144 -144
  251. package/templates/vue-app/files/src/views/system/dict/dictDetail.vue +146 -146
  252. package/templates/vue-app/files/src/views/system/dict/index.vue +159 -159
  253. package/templates/vue-app/files/src/views/system/examModality/index.vue +174 -174
  254. package/templates/vue-app/files/src/views/system/examPart/index.vue +184 -184
  255. package/templates/vue-app/files/src/views/system/examProject/index.vue +321 -321
  256. package/templates/vue-app/files/src/views/system/examine/index.vue +66 -66
  257. package/templates/vue-app/files/src/views/system/job/index.vue +119 -119
  258. package/templates/vue-app/files/src/views/system/job/module/form.vue +72 -72
  259. package/templates/vue-app/files/src/views/system/job/module/header.vue +48 -48
  260. package/templates/vue-app/files/src/views/system/menu/index.vue +327 -327
  261. package/templates/vue-app/files/src/views/system/model/index.vue +285 -285
  262. package/templates/vue-app/files/src/views/system/role/index.vue +434 -434
  263. package/templates/vue-app/files/src/views/system/sysSet/index.vue +84 -84
  264. package/templates/vue-app/files/src/views/system/timing/index.vue +289 -289
  265. package/templates/vue-app/files/src/views/system/timing/log.vue +143 -143
  266. package/templates/vue-app/files/src/views/system/user/admin.vue +414 -414
  267. package/templates/vue-app/files/src/views/system/user/center/updateEmail.vue +146 -146
  268. package/templates/vue-app/files/src/views/system/user/center/updatePass.vue +168 -168
  269. package/templates/vue-app/files/src/views/system/user/center.vue +140 -140
  270. package/templates/vue-app/files/src/views/system/user/index.vue +972 -972
  271. package/templates/vue-app/files/src/views/systemSet/role/index.vue +314 -314
  272. package/templates/vue-app/files/src/views/systemSet/user/admin.vue +414 -414
  273. package/templates/vue-app/files/src/views/systemSet/user/center/updateEmail.vue +146 -146
  274. package/templates/vue-app/files/src/views/systemSet/user/center/updatePass.vue +115 -115
  275. package/templates/vue-app/files/src/views/systemSet/user/center.vue +351 -351
  276. package/templates/vue-app/files/src/views/systemSet/user/index.vue +928 -928
  277. package/templates/vue-app/files/src/views/tools/aliPay/config.vue +102 -102
  278. package/templates/vue-app/files/src/views/tools/aliPay/index.vue +48 -48
  279. package/templates/vue-app/files/src/views/tools/aliPay/toPay.vue +91 -91
  280. package/templates/vue-app/files/src/views/tools/email/config.vue +91 -91
  281. package/templates/vue-app/files/src/views/tools/email/index.vue +42 -42
  282. package/templates/vue-app/files/src/views/tools/email/send.vue +159 -159
  283. package/templates/vue-app/files/src/views/tools/storage/index.vue +35 -35
  284. package/templates/vue-app/files/src/views/tools/storage/local/index.vue +207 -207
  285. package/templates/vue-app/files/src/views/tools/storage/qiniu/form.vue +108 -108
  286. package/templates/vue-app/files/src/views/tools/storage/qiniu/index.vue +241 -241
  287. package/templates/vue-app/files/src/views/tools/swagger/index.vue +14 -14
  288. package/templates/vue-app/files/vue.config.js +173 -173
  289. package/templates/vue-app/template.json +29 -29
package/lib/config.js CHANGED
@@ -1,283 +1,325 @@
1
- const path = require('path');
2
- const fs = require('fs-extra');
3
- const { log } = require('./utils');
4
-
5
- function getConfigPath() {
6
- return path.join(process.cwd(), '.ylyxrc.json');
7
- }
8
-
9
- function normalizeMode(mode) {
10
- if (typeof mode !== 'string') return null;
11
- const m = mode.trim().toLowerCase();
12
- if (m === 'dev' || m === 'prod') return m;
13
- return null;
14
- }
15
-
16
- function parseDotEnvFile(envPath) {
17
- if (!fs.existsSync(envPath)) return {};
18
- const content = fs.readFileSync(envPath, 'utf-8');
19
- const lines = content.split(/\r?\n/);
20
- const out = {};
21
- for (const raw of lines) {
22
- const line = raw.trim();
23
- if (!line || line.startsWith('#')) continue;
24
- const idx = line.indexOf('=');
25
- if (idx < 0) continue;
26
- const key = line.slice(0, idx).trim();
27
- let value = line.slice(idx + 1).trim();
28
- if (
29
- (value.startsWith('"') && value.endsWith('"')) ||
30
- (value.startsWith("'") && value.endsWith("'"))
31
- ) {
32
- value = value.slice(1, -1);
33
- }
34
- out[key] = value;
35
- }
36
- return out;
37
- }
38
-
39
- function normalizePublicUrlToDir(publicUrl) {
40
- if (!publicUrl || typeof publicUrl !== 'string') return '';
41
- let v = publicUrl.trim();
42
- v = v.replace(/\\/g, '/');
43
- // ignore full urls
44
- if (/^https?:\/\//i.test(v)) return '';
45
- v = v.replace(/^\/+/, '').replace(/\/+$/, '');
46
- return v;
47
- }
48
-
49
- function resolveProdBuildDir(config) {
50
- // 1) 优先使用 .ylyxrc.json 的 buildDir(可为相对/绝对路径)
51
- if (config.buildDir) {
52
- return path.resolve(process.cwd(), config.buildDir);
53
- }
54
-
55
- // 2) 默认:读取 .env.production 的 VUE_APP_PUBLIC_URL,拼成 <publicUrlDir>
56
- const envProdPath = path.join(process.cwd(), '.env.production');
57
- const env = parseDotEnvFile(envProdPath);
58
- const publicUrlDir = normalizePublicUrlToDir(env.VUE_APP_PUBLIC_URL);
59
- if (publicUrlDir) {
60
- return path.resolve(process.cwd(), publicUrlDir);
61
- }
62
- throw new Error(
63
- '无法确定 prod 打包输出目录:请在 .ylyxrc.json 中配置 buildDir,或在 .env.production 中配置 VUE_APP_PUBLIC_URL'
64
- );
65
- }
66
-
67
- function readConfigSafe(configPath) {
68
- if (!fs.existsSync(configPath)) return {};
69
- try {
70
- return fs.readJsonSync(configPath);
71
- } catch (e) {
72
- throw new Error(`读取 .ylyxrc.json 失败,请确认它是有效 JSON:${e.message}`);
73
- }
74
- }
75
-
76
- function writeIfAllowed(filePath, content, force) {
77
- if (fs.existsSync(filePath) && !force) {
78
- log.warn(`已存在,跳过:${path.relative(process.cwd(), filePath)}`);
79
- return false;
80
- }
81
- fs.ensureDirSync(path.dirname(filePath));
82
- fs.writeFileSync(filePath, content, 'utf-8');
83
- log.success(`已写入:${path.relative(process.cwd(), filePath)}`);
84
- return true;
85
- }
86
-
87
- function deriveDefaultVariantContent(baseContent, mode) {
88
- const isDev = mode === 'dev';
89
-
90
- let content = baseContent || '';
91
- const devRe = /let\s+isDev\s*=\s*[^;]*;/;
92
-
93
- if (devRe.test(content)) {
94
- content = content.replace(devRe, `let isDev = ${isDev};`);
95
- } else {
96
- content = `let isDev = ${isDev};\n` + content;
97
- }
98
-
99
- // isProd 已废弃:prod 使用 isDev=false 表示
100
- // 删除历史遗留的 isProd 变量与输出字段(若存在)
101
- content = content.replace(/let\s+isProd\s*=\s*[^;]*;\s*\r?\n?/g, '');
102
- content = content.replace(/window\.config\.IS_PROD\s*=\s*[^;]*;\s*\r?\n?/g, '');
103
- // 删除对象形式的 IS_PROD 字段(例如 IS_PROD: isProd,)
104
- content = content.replace(/^\s*IS_PROD\s*:\s*[^,}]*,?\s*\r?\n?/gm, '');
105
-
106
- return content;
107
- }
108
-
109
- function copyFile({ src, dest }) {
110
- fs.ensureDirSync(path.dirname(dest));
111
- if (!fs.existsSync(src)) {
112
- log.warn(`未找到源文件:${path.relative(process.cwd(), src)}`);
113
- return { ok: false, method: 'missing' };
114
- }
115
-
116
- // 如果目标已存在,先删除
117
- if (fs.existsSync(dest)) {
118
- fs.removeSync(dest);
119
- }
120
-
121
- try {
122
- fs.copyFileSync(src, dest);
123
- return { ok: true };
124
- } catch (e) {
125
- log.error(`写入失败:${e.message}`);
126
- return { ok: false };
127
- }
128
- }
129
-
130
- /**
131
- * 写入/更新 .ylyxrc.json 的 mode 字段(dev|prod),并与已有配置合并
132
- */
133
- function setMode(mode) {
134
- const normalized = normalizeMode(mode);
135
- if (!normalized) {
136
- throw new Error(`mode 取值只能是 dev 或 prod(当前: ${mode})`);
137
- }
138
-
139
- const configPath = getConfigPath();
140
- const config = readConfigSafe(configPath);
141
-
142
- // 可选:如果当前项目目录存在 public/default-{mode}.js,则复制到 public/default.js
143
- // 注意:切换应发生在“项目目录”(process.cwd()),而不是 CLI 自身的 lib 目录(__dirname)
144
- // 优先从 .ylyxrc.json 中读取 publicDir,其次使用默认 ./public
145
- const configDir = path.resolve(process.cwd(), config.configDir || 'config');
146
- const publicDir = path.resolve(process.cwd(), config.publicDir || 'public');
147
- const defaultVariant = path.join(configDir, `default-${normalized}.js`);
148
- const defaultFile =
149
- normalized === 'prod'
150
- ? path.join(resolveProdBuildDir(config), 'default.js')
151
- : path.join(publicDir, 'default.js');
152
-
153
- // 将对应 variant 文件 copy 到目标路径
154
- const result = copyFile({
155
- src: defaultVariant,
156
- dest: defaultFile,
157
- });
158
-
159
- if (result.ok) {
160
- log.success(
161
- `已切换 ${path.relative(process.cwd(), defaultFile)} <- ${path.relative(
162
- process.cwd(),
163
- defaultVariant
164
- )}`
165
- );
166
- } else if (!result.ok && !fs.existsSync(defaultVariant)) {
167
- log.warn(`未找到 ${path.relative(process.cwd(), defaultVariant)},请先运行 ylyx init config`);
168
- }
169
-
170
- config.mode = normalized;
171
- fs.writeJsonSync(configPath, config, { spaces: 2 });
172
- log.success(`已写入配置:mode=${normalized}`);
173
- log.info(`配置文件:${configPath}`);
174
- }
175
-
176
- /**
177
- * init config:初始化配置目录与示例文件
178
- * - 写入/补齐 .ylyxrc.json(mode/publicDir/configDir)
179
- * - 生成 config/default-dev.js config/default-prod.js(基于现有 public/default.js 派生)
180
- * - 若 public/default.js 不存在,则按当前 mode 生成一份
181
- */
182
- function initConfig(options = {}) {
183
- const force = !!options.force;
184
- const configPath = getConfigPath();
185
- const existing = readConfigSafe(configPath);
186
-
187
- const next = {
188
- ...existing,
189
- mode: existing.mode || 'dev',
190
- publicDir: existing.publicDir || './public',
191
- configDir: existing.configDir || './config',
192
- // npm scripts:默认对 dev 与 build:prod 增加前置脚本 pre<name>
193
- // 可在 .ylyxrc.json 中改成你的项目脚本名(例如 dev=serve,prod=build)
194
- preScripts: existing.preScripts || { dev: 'dev', prod: 'build:prod' },
195
- };
196
-
197
- if (options.mode) {
198
- const normalized = normalizeMode(options.mode);
199
- if (!normalized) throw new Error(`mode 取值只能是 dev 或 prod(当前: ${options.mode})`);
200
- next.mode = normalized;
201
- }
202
-
203
- fs.writeJsonSync(configPath, next, { spaces: 2 });
204
- log.success(`已初始化配置文件:${path.relative(process.cwd(), configPath)}`);
205
-
206
- const publicDirAbs = path.resolve(process.cwd(), next.publicDir || 'public');
207
- const configDirAbs = path.resolve(process.cwd(), next.configDir || 'config');
208
- fs.ensureDirSync(publicDirAbs);
209
- fs.ensureDirSync(configDirAbs);
210
-
211
- const publicDefault = path.join(publicDirAbs, 'default.js');
212
- let baseContent = '';
213
- if (fs.existsSync(publicDefault)) {
214
- baseContent = fs.readFileSync(publicDefault, 'utf-8');
215
- } else {
216
- baseContent =
217
- "// 自动生成的默认配置(请按项目需要补全)\n" +
218
- "let isDev = true;\n"
219
- }
220
-
221
- const devVariantPath = path.join(configDirAbs, 'default-dev.js');
222
- const prodVariantPath = path.join(configDirAbs, 'default-prod.js');
223
-
224
- writeIfAllowed(devVariantPath, deriveDefaultVariantContent(baseContent, 'dev'), force);
225
- writeIfAllowed(prodVariantPath, deriveDefaultVariantContent(baseContent, 'prod'), force);
226
-
227
- // 如果 public/default.js 不存在,则按当前 mode 生成一份
228
- if (!fs.existsSync(publicDefault)) {
229
- const src =
230
- next.mode === 'prod'
231
- ? path.join(configDirAbs, 'default-prod.js')
232
- : path.join(configDirAbs, 'default-dev.js');
233
- if (fs.existsSync(src)) {
234
- fs.copyFileSync(src, publicDefault);
235
- log.success(
236
- `已生成 ${path.relative(process.cwd(), publicDefault)} <- ${path.relative(process.cwd(), src)}`
237
- );
238
- }
239
- } else {
240
- log.info(`已存在:${path.relative(process.cwd(), publicDefault)}(未覆盖)`);
241
- }
242
-
243
- // 初始化 package.json 的 npm 前置脚本:pre<devScript> / pre<prodScript>
244
- const packageJsonPath = path.join(process.cwd(), 'package.json');
245
- if (!fs.existsSync(packageJsonPath)) {
246
- log.warn('未找到 package.json,已跳过 npm 前置脚本初始化');
247
- return;
248
- }
249
-
250
- let pkg = {};
251
- try {
252
- pkg = fs.readJsonSync(packageJsonPath);
253
- } catch (e) {
254
- throw new Error(`读取 package.json 失败,请确认它是有效 JSON:${e.message}`);
255
- }
256
-
257
- pkg.scripts = pkg.scripts || {};
258
- const devTarget = (next.preScripts && next.preScripts.dev) || 'dev';
259
- const prodTarget = (next.preScripts && next.preScripts.prod) || 'build:prod';
260
-
261
- const desired = [
262
- { name: `pre${devTarget}`, value: 'ylyx config dev' },
263
- { name: `post${prodTarget}`, value: 'ylyx config prod && ylyx deploy' },
264
- ];
265
-
266
- for (const item of desired) {
267
- if (pkg.scripts[item.name] && !force) {
268
- log.warn(`package.json scripts 已存在,跳过:${item.name}`);
269
- continue;
270
- }
271
- pkg.scripts[item.name] = item.value;
272
- log.success(`已写入 package.json scripts:${item.name}`);
273
- }
274
-
275
- fs.writeJsonSync(packageJsonPath, pkg, { spaces: 2 });
276
- log.info(`package.json:${path.relative(process.cwd(), packageJsonPath)}`);
277
- }
278
-
279
- module.exports = {
280
- setMode,
281
- normalizeMode,
282
- initConfig,
283
- };
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const inquirer = require('inquirer');
4
+ const { log } = require('./utils');
5
+ const {
6
+ getConfigPath,
7
+ readConfigSafe,
8
+ assertConfigMigrated,
9
+ findEnvironment,
10
+ buildMigratedConfig,
11
+ CONFIG_VERSION,
12
+ } = require('./environments');
13
+
14
+ function writeIfAllowed(filePath, content, force) {
15
+ if (fs.existsSync(filePath) && !force) {
16
+ log.warn(`已存在,跳过:${path.relative(process.cwd(), filePath)}`);
17
+ return false;
18
+ }
19
+ fs.ensureDirSync(path.dirname(filePath));
20
+ fs.writeFileSync(filePath, content, 'utf-8');
21
+ log.success(`已写入:${path.relative(process.cwd(), filePath)}`);
22
+ return true;
23
+ }
24
+
25
+ /**
26
+ * 生成 config/default-<envName>.js 的内容:
27
+ * 注入 `let env = '<envName>';` 与 `let isDev = (envName === 'dev');`(向后兼容旧代码)
28
+ */
29
+ function deriveDefaultVariantContent(baseContent, envName) {
30
+ const isDev = envName === 'dev';
31
+
32
+ let content = baseContent || '';
33
+ const envRe = /let\s+env\s*=\s*[^;]*;/;
34
+ const devRe = /let\s+isDev\s*=\s*[^;]*;/;
35
+
36
+ if (envRe.test(content)) {
37
+ content = content.replace(envRe, `let env = '${envName}';`);
38
+ } else {
39
+ content = `let env = '${envName}';\n` + content;
40
+ }
41
+
42
+ if (devRe.test(content)) {
43
+ content = content.replace(devRe, `let isDev = ${isDev};`);
44
+ } else {
45
+ content = `let isDev = ${isDev};\n` + content;
46
+ }
47
+
48
+ // isProd 已废弃:prod 使用 isDev=false 表示
49
+ // 删除历史遗留的 isProd 变量与输出字段(若存在)
50
+ content = content.replace(/let\s+isProd\s*=\s*[^;]*;\s*\r?\n?/g, '');
51
+ content = content.replace(/window\.config\.IS_PROD\s*=\s*[^;]*;\s*\r?\n?/g, '');
52
+ content = content.replace(/^\s*IS_PROD\s*:\s*[^,}]*,?\s*\r?\n?/gm, '');
53
+
54
+ return content;
55
+ }
56
+
57
+ function copyFile({ src, dest }) {
58
+ fs.ensureDirSync(path.dirname(dest));
59
+ if (!fs.existsSync(src)) {
60
+ log.warn(`未找到源文件:${path.relative(process.cwd(), src)}`);
61
+ return { ok: false, method: 'missing' };
62
+ }
63
+
64
+ if (fs.existsSync(dest)) {
65
+ fs.removeSync(dest);
66
+ }
67
+
68
+ try {
69
+ fs.copyFileSync(src, dest);
70
+ return { ok: true };
71
+ } catch (e) {
72
+ log.error(`写入失败:${e.message}`);
73
+ return { ok: false };
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 切换到指定环境:把 config/default-<name>.js 复制到该环境的目标位置
79
+ * - isLocal 环境 -> publicDir/default.js
80
+ * - 其他环境 -> <环境 buildDir>/default.js
81
+ */
82
+ function setEnv(name) {
83
+ const configPath = getConfigPath();
84
+ const configExists = fs.existsSync(configPath);
85
+ const config = readConfigSafe(configPath);
86
+ assertConfigMigrated(config, configExists);
87
+
88
+ const env = findEnvironment(config, name);
89
+
90
+ const configDir = path.resolve(process.cwd(), config.configDir || 'config');
91
+ const publicDir = path.resolve(process.cwd(), config.publicDir || 'public');
92
+ const defaultVariant = path.join(configDir, `default-${env.name}.js`);
93
+
94
+ // ponytail: 信任本地 .ylyxrc.json 的路径配置,不做路径穿越校验(本地 CLI 工具,配置由用户自行维护)
95
+ let targetDir;
96
+ if (env.isLocal) {
97
+ targetDir = publicDir;
98
+ } else {
99
+ if (!env.buildDir) {
100
+ throw new Error(`环境 "${env.name}" 未配置 buildDir,无法确定切换目标目录`);
101
+ }
102
+ targetDir = path.resolve(process.cwd(), env.buildDir);
103
+ }
104
+ const defaultFile = path.join(targetDir, 'default.js');
105
+
106
+ const result = copyFile({ src: defaultVariant, dest: defaultFile });
107
+
108
+ if (result.ok) {
109
+ log.success(
110
+ `已切换 ${path.relative(process.cwd(), defaultFile)} <- ${path.relative(
111
+ process.cwd(),
112
+ defaultVariant
113
+ )}`
114
+ );
115
+ } else if (!result.ok && !fs.existsSync(defaultVariant)) {
116
+ log.warn(`未找到 ${path.relative(process.cwd(), defaultVariant)},请先运行 ylyx init config`);
117
+ }
118
+
119
+ config.currentEnv = env.name;
120
+ fs.writeJsonSync(configPath, config, { spaces: 2 });
121
+ log.success(`已写入配置:currentEnv=${env.name}`);
122
+ log.info(`配置文件:${configPath}`);
123
+ }
124
+
125
+ /**
126
+ * 交互式选择环境并切换:按 isLocal 分组展示,当前环境标注"(当前)",
127
+ * 默认光标停在当前环境,选定后复用 setEnv 完成实际切换
128
+ */
129
+ async function chooseEnvInteractive() {
130
+ const configPath = getConfigPath();
131
+ const configExists = fs.existsSync(configPath);
132
+ const config = readConfigSafe(configPath);
133
+ assertConfigMigrated(config, configExists);
134
+
135
+ const environments = config.environments || [];
136
+ if (environments.length === 0) {
137
+ throw new Error('环境列表为空,请先在 .ylyxrc.json 配置 environments 或运行 ylyx init config');
138
+ }
139
+
140
+ const currentEnv = config.currentEnv;
141
+ const toChoice = (e) => ({
142
+ name: e.name === currentEnv ? `${e.name}(当前)` : e.name,
143
+ value: e.name,
144
+ });
145
+
146
+ const localEnvs = environments.filter((e) => e.isLocal);
147
+ const remoteEnvs = environments.filter((e) => !e.isLocal);
148
+
149
+ const choices = [];
150
+ if (localEnvs.length > 0) {
151
+ choices.push(new inquirer.Separator('-- 本地环境 --'));
152
+ choices.push(...localEnvs.map(toChoice));
153
+ }
154
+ if (remoteEnvs.length > 0) {
155
+ choices.push(new inquirer.Separator('-- 部署环境 --'));
156
+ choices.push(...remoteEnvs.map(toChoice));
157
+ }
158
+
159
+ const ans = await inquirer.prompt([
160
+ {
161
+ type: 'list',
162
+ name: 'env',
163
+ message: '请选择要切换到的环境',
164
+ choices,
165
+ default: currentEnv,
166
+ },
167
+ ]);
168
+
169
+ setEnv(ans.env);
170
+ }
171
+
172
+ /**
173
+ * 迁移旧版 .ylyxrc.json(mode/deploy/顶层 buildDir/preScripts)到 environments 结构
174
+ */
175
+ function migrateConfig() {
176
+ const configPath = getConfigPath();
177
+ const existing = readConfigSafe(configPath);
178
+
179
+ if (typeof existing.configVersion === 'number' && existing.configVersion >= CONFIG_VERSION) {
180
+ log.info(`当前配置已是最新版本(configVersion=${existing.configVersion}),无需迁移`);
181
+ return;
182
+ }
183
+
184
+ const migrated = buildMigratedConfig(existing);
185
+ fs.writeJsonSync(configPath, migrated, { spaces: 2 });
186
+
187
+ const names = migrated.environments.map((e) => e.name).join(', ');
188
+ log.success(`迁移完成,已生成环境:${names}`);
189
+ log.warn('请检查 test/prod 环境的 host/username/password 等敏感信息是否正确');
190
+ log.info('请运行 `ylyx init config --force` 以补写 package.json pre/post 钩子(迁移命令不会修改 package.json)');
191
+ }
192
+
193
+ /**
194
+ * init config:初始化配置目录与示例文件
195
+ * - 写入/补齐 .ylyxrc.json(configVersion/environments/currentEnv/publicDir/configDir)
196
+ * - 为每个环境生成 config/default-<name>.js(基于现有 public/default.js 派生)
197
+ * - 若 public/default.js 不存在,则按 currentEnv 生成一份
198
+ * - 按每个环境的 npmScript 写 package.json 的 pre/post 钩子
199
+ */
200
+ function initConfig(options = {}) {
201
+ const force = !!options.force;
202
+ const configPath = getConfigPath();
203
+ const existing = readConfigSafe(configPath);
204
+
205
+ const hasEnvironments = Array.isArray(existing.environments) && existing.environments.length > 0;
206
+ if (Array.isArray(existing.environments) && existing.environments.length === 0) {
207
+ log.info('检测到 .ylyxrc.json environments 为空数组,已使用默认环境(dev/prod)填充');
208
+ }
209
+ const environments = hasEnvironments
210
+ ? existing.environments
211
+ : [
212
+ { name: 'dev', isLocal: true, npmScript: 'dev', deployMethod: 'none' },
213
+ {
214
+ name: 'prod',
215
+ npmScript: 'build:prod',
216
+ deployMethod: 'zip',
217
+ buildDir: 'dist/app',
218
+ zipOutDir: './.ylyx-deploy',
219
+ },
220
+ ];
221
+
222
+ let currentEnv = existing.currentEnv || 'dev';
223
+ if (options.env) {
224
+ const exists = environments.some((e) => e.name === options.env);
225
+ if (!exists) {
226
+ throw new Error(
227
+ `环境不存在: ${options.env}\n可用环境: ${environments.map((e) => e.name).join(', ')}`
228
+ );
229
+ }
230
+ currentEnv = options.env;
231
+ }
232
+
233
+ const next = {
234
+ ...existing,
235
+ configVersion: CONFIG_VERSION,
236
+ publicDir: existing.publicDir || './public',
237
+ configDir: existing.configDir || './config',
238
+ currentEnv,
239
+ environments,
240
+ };
241
+
242
+ fs.writeJsonSync(configPath, next, { spaces: 2 });
243
+ log.success(`已初始化配置文件:${path.relative(process.cwd(), configPath)}`);
244
+
245
+ const publicDirAbs = path.resolve(process.cwd(), next.publicDir);
246
+ const configDirAbs = path.resolve(process.cwd(), next.configDir);
247
+ fs.ensureDirSync(publicDirAbs);
248
+ fs.ensureDirSync(configDirAbs);
249
+
250
+ const publicDefault = path.join(publicDirAbs, 'default.js');
251
+ let baseContent = '';
252
+ if (fs.existsSync(publicDefault)) {
253
+ baseContent = fs.readFileSync(publicDefault, 'utf-8');
254
+ } else {
255
+ baseContent = '// 自动生成的默认配置(请按项目需要补全)\n';
256
+ }
257
+
258
+ for (const env of next.environments) {
259
+ const variantPath = path.join(configDirAbs, `default-${env.name}.js`);
260
+ writeIfAllowed(variantPath, deriveDefaultVariantContent(baseContent, env.name), force);
261
+ }
262
+
263
+ if (!fs.existsSync(publicDefault)) {
264
+ const src = path.join(configDirAbs, `default-${next.currentEnv}.js`);
265
+ if (fs.existsSync(src)) {
266
+ fs.copyFileSync(src, publicDefault);
267
+ log.success(
268
+ `已生成 ${path.relative(process.cwd(), publicDefault)} <- ${path.relative(process.cwd(), src)}`
269
+ );
270
+ }
271
+ } else {
272
+ log.info(`已存在:${path.relative(process.cwd(), publicDefault)}(未覆盖)`);
273
+ }
274
+
275
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
276
+ if (!fs.existsSync(packageJsonPath)) {
277
+ log.warn('未找到 package.json,已跳过 npm 钩子初始化');
278
+ return;
279
+ }
280
+
281
+ let pkg = {};
282
+ try {
283
+ pkg = fs.readJsonSync(packageJsonPath);
284
+ } catch (e) {
285
+ throw new Error(`读取 package.json 失败,请确认它是有效 JSON:${e.message}`);
286
+ }
287
+
288
+ pkg.scripts = pkg.scripts || {};
289
+
290
+ for (const env of next.environments) {
291
+ const npmScript = env.npmScript;
292
+ if (!npmScript) continue;
293
+
294
+ let hookName;
295
+ let hookValue;
296
+ if (env.isLocal) {
297
+ hookName = `pre${npmScript}`;
298
+ hookValue = `ylyx config ${env.name}`;
299
+ } else {
300
+ hookName = `post${npmScript}`;
301
+ hookValue =
302
+ env.deployMethod && env.deployMethod !== 'none'
303
+ ? `ylyx config ${env.name} && ylyx deploy --env ${env.name}`
304
+ : `ylyx config ${env.name}`;
305
+ }
306
+
307
+ if (pkg.scripts[hookName] && !force) {
308
+ log.warn(`package.json scripts 已存在,跳过:${hookName}`);
309
+ continue;
310
+ }
311
+ pkg.scripts[hookName] = hookValue;
312
+ log.success(`已写入 package.json scripts:${hookName}`);
313
+ }
314
+
315
+ fs.writeJsonSync(packageJsonPath, pkg, { spaces: 2 });
316
+ log.info(`package.json:${path.relative(process.cwd(), packageJsonPath)}`);
317
+ }
318
+
319
+ module.exports = {
320
+ setEnv,
321
+ initConfig,
322
+ migrateConfig,
323
+ chooseEnvInteractive,
324
+ deriveDefaultVariantContent,
325
+ };