@nutin/cli 1.3.1 → 2.1.0

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/CHANGELOG.md +106 -9
  2. package/README.md +17 -35
  3. package/bin/add-feature.mjs +9 -0
  4. package/bin/cli.mjs +8 -0
  5. package/bin/create-app.mjs +5 -4
  6. package/bin/update-app.mjs +9 -0
  7. package/lib/index.mjs +76 -25
  8. package/lib/src/add-feature/feature-adder.mjs +83 -0
  9. package/lib/src/add-feature/feature-context-builder.mjs +25 -0
  10. package/lib/src/add-feature/nutin-config-updater.mjs +29 -0
  11. package/lib/src/add-feature/package-json-updater.mjs +49 -0
  12. package/lib/src/common/feature-registry.mjs +11 -0
  13. package/lib/src/common/file-generator.mjs +159 -0
  14. package/lib/src/common/meta-bootstrap-prompt.mjs +33 -0
  15. package/lib/src/common/package-data.mjs +10 -0
  16. package/lib/src/common/package-json-helper.mjs +103 -0
  17. package/lib/src/common/project-meta.mjs +54 -0
  18. package/lib/src/create-app/context-builder.mjs +21 -0
  19. package/lib/src/{git-manager.mjs → create-app/git-manager.mjs} +2 -2
  20. package/lib/src/create-app/json-manager.mjs +73 -0
  21. package/lib/src/{prompts.mjs → create-app/new-app-prompt.mjs} +6 -6
  22. package/lib/src/{project-generator.mjs → create-app/project-generator.mjs} +10 -8
  23. package/lib/src/create-app/success-message.mjs +13 -0
  24. package/lib/src/update-app/conflict-report-writer.mjs +31 -0
  25. package/lib/src/update-app/fetch-old-templates.mjs +61 -0
  26. package/lib/src/update-app/project-updater.mjs +142 -0
  27. package/lib/src/update-app/template-differ.mjs +124 -0
  28. package/lib/src/update-app/update-context-builder.mjs +25 -0
  29. package/lib/src/update-app/update-summary-printer.mjs +22 -0
  30. package/lib/src/update-app/version-compare.mjs +12 -0
  31. package/lib/src/utils/print.mjs +36 -0
  32. package/lib/src/utils/promise-exec-alias.mjs +4 -0
  33. package/package.json +17 -12
  34. package/templates/base/.gitignore.hbs +6 -1
  35. package/templates/base/AGENTS.md.hbs +168 -0
  36. package/templates/base/GETTING_STARTED.md.hbs +199 -0
  37. package/templates/base/README.md.hbs +8 -17
  38. package/templates/base/config/languages.json.hbs +6 -0
  39. package/templates/base/config/seo.json.hbs +12 -0
  40. package/templates/base/nutin.config.js.hbs +44 -0
  41. package/templates/base/src/app/components/index.ts.hbs +1 -2
  42. package/templates/base/src/app/globals.d.ts.hbs +3 -19
  43. package/templates/base/src/{libs/guards → app}/guards.ts.hbs +1 -5
  44. package/templates/base/src/app/main.ts.hbs +6 -26
  45. package/templates/base/src/app/services/index.ts.hbs +1 -1
  46. package/templates/base/src/app/views/home/home.view.html.hbs +7 -0
  47. package/templates/base/src/app/views/home/home.view.ts.hbs +2 -57
  48. package/templates/base/src/app/views/index.ts.hbs +1 -0
  49. package/templates/base/src/app/views/not-found/not-found.view.html.hbs +8 -0
  50. package/templates/base/src/app/views/not-found/not-found.view.ts.hbs +5 -38
  51. package/templates/base/src/core/base-classes/base-component/base-component.test.js.hbs +158 -0
  52. package/templates/base/src/core/base-classes/base-component/base-component.ts.hbs +68 -35
  53. package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.test.js.hbs +124 -0
  54. package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.ts.hbs +9 -8
  55. package/templates/base/src/core/base-classes/base-component/helpers/children.helper.test.js.hbs +96 -0
  56. package/templates/base/src/core/base-classes/base-component/helpers/children.helper.ts.hbs +6 -3
  57. package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.test.js.hbs +151 -0
  58. package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.ts.hbs +8 -2
  59. package/templates/base/src/core/base-classes/base-component/helpers/event.helper.test.js.hbs +88 -0
  60. package/templates/base/src/core/base-classes/base-component/helpers/event.helper.ts.hbs +2 -2
  61. package/templates/base/src/core/base-classes/base-component/helpers/i18n.helper.test.js.hbs +62 -0
  62. package/templates/base/src/core/base-classes/base-component/helpers/pipe.helper.test.js.hbs +89 -0
  63. package/templates/base/src/core/base-classes/base-component/helpers/pipe.helper.ts.hbs +4 -1
  64. package/templates/base/src/core/base-classes/base-component/helpers/security.helper.test.js.hbs +142 -0
  65. package/templates/base/src/core/base-classes/base-component/helpers/security.helper.ts.hbs +67 -22
  66. package/templates/base/src/core/base-classes/base-component/helpers/token.helper.test.js.hbs +183 -0
  67. package/templates/base/src/core/base-classes/component/component.test.js.hbs +85 -0
  68. package/templates/base/src/core/base-classes/component/component.ts.hbs +24 -33
  69. package/templates/base/src/core/base-classes/component/helpers/config.helper.test.js.hbs +58 -0
  70. package/templates/base/src/core/base-classes/component/helpers/data-binding.helper.test.js.hbs +75 -0
  71. package/templates/base/src/core/base-classes/service/service.test.js.hbs +150 -0
  72. package/templates/base/src/core/base-classes/service/service.ts.hbs +26 -20
  73. package/templates/base/src/core/base-classes/view/view.test.js.hbs +71 -0
  74. package/templates/base/src/core/base-classes/view/view.ts.hbs +24 -49
  75. package/templates/base/src/core/config.ts.hbs +10 -0
  76. package/templates/base/src/core/index.ts.hbs +0 -3
  77. package/templates/base/src/core/internals.d.ts.hbs +27 -0
  78. package/templates/base/src/core/nutin-config.d.ts.hbs +4 -0
  79. package/templates/base/src/core/services/event-bus/event-bus.test.js.hbs +67 -3
  80. package/templates/base/src/core/services/event-bus/event-bus.ts.hbs +9 -4
  81. package/templates/base/src/core/services/event-bus/index.ts.hbs +3 -0
  82. package/templates/base/src/core/services/event-bus/lifecycle.facade.test.js.hbs +123 -0
  83. package/templates/base/src/core/services/event-bus/lifecycle.facade.ts.hbs +61 -0
  84. package/templates/base/src/core/services/event-bus/navigation.facade.test.js.hbs +46 -0
  85. package/templates/base/src/core/services/event-bus/navigation.facade.ts.hbs +25 -0
  86. package/templates/base/src/core/services/globals/globals.test.js.hbs +187 -0
  87. package/templates/base/src/core/services/globals/globals.ts.hbs +104 -0
  88. package/templates/base/src/core/services/http-client/helpers/http-builder.helper.test.js.hbs +25 -0
  89. package/templates/base/src/core/services/http-client/helpers/http-manager.helper.test.js.hbs +20 -0
  90. package/templates/base/src/core/services/http-client/http-client.test.js.hbs +73 -2
  91. package/templates/base/src/core/services/http-client/http-client.ts.hbs +4 -1
  92. package/templates/base/src/core/services/i18n/i18n.test.js.hbs +270 -0
  93. package/templates/{features/i18n → base}/src/core/services/i18n/i18n.ts.hbs +22 -4
  94. package/templates/base/src/core/services/index.ts.hbs +5 -6
  95. package/templates/base/src/core/services/pipe-registry/pipe-registry.test.js.hbs +60 -1
  96. package/templates/base/src/core/services/pipe-registry/pipe-registry.ts.hbs +1 -1
  97. package/templates/base/src/core/services/pipe-registry/pipes.test.js.hbs +128 -0
  98. package/templates/base/src/{libs/pipes → core/services/pipe-registry}/pipes.ts.hbs +8 -5
  99. package/templates/base/src/core/services/router/helpers/navigation-manager.helper.test.js.hbs +257 -6
  100. package/templates/base/src/core/services/router/helpers/navigation-manager.helper.ts.hbs +56 -29
  101. package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.test.js.hbs +27 -0
  102. package/templates/base/src/core/services/router/helpers/view-render-manager.helper.test.js.hbs +83 -17
  103. package/templates/base/src/core/services/router/helpers/view-render-manager.helper.ts.hbs +14 -38
  104. package/templates/base/src/core/services/router/router.test.js.hbs +304 -2
  105. package/templates/base/src/core/services/router/router.ts.hbs +47 -12
  106. package/templates/base/src/index.html.hbs +2 -6
  107. package/templates/base/src/styles/_styles.scss.hbs +102 -43
  108. package/templates/base/src/styles/base/_variables.scss.hbs +1 -86
  109. package/templates/base/src/styles/main.scss.hbs +1 -18
  110. package/templates/base/src/styles/tailwind.css.hbs +2 -0
  111. package/templates/base/tools/builder/builder.config.js.hbs +40 -0
  112. package/templates/base/tools/builder/builder.js.hbs +24 -26
  113. package/templates/base/tools/builder/core/app/binary-extensions.test.js.hbs +16 -0
  114. package/templates/base/tools/builder/core/app/compile-ts.js.hbs +16 -0
  115. package/templates/base/tools/builder/core/{copy-static.js.hbs → app/copy-static.js.hbs} +27 -34
  116. package/templates/base/tools/builder/core/app/validate-routes.js.hbs +77 -0
  117. package/templates/base/tools/builder/core/finalize-build.js.hbs +16 -7
  118. package/templates/base/tools/builder/core/{add-tags.js.hbs → html-index/add-tags.js.hbs} +2 -2
  119. package/templates/base/tools/builder/core/html-index/add-tags.test.js.hbs +56 -0
  120. package/templates/base/tools/builder/core/{validate-html.js.hbs → html-index/validate-html.js.hbs} +5 -11
  121. package/templates/base/tools/builder/core/html-templates/merge-templates.js.hbs +152 -0
  122. package/templates/base/tools/builder/core/html-templates/minify-html.js.hbs +15 -0
  123. package/templates/base/tools/builder/core/html-templates/process-html-templates.js.hbs +8 -0
  124. package/templates/{features/i18n/tools/builder/core → base/tools/builder/core/i18n}/build-i18n.js.hbs +6 -17
  125. package/templates/base/tools/builder/core/prod-bundle/compress-files.js.hbs +37 -0
  126. package/templates/base/tools/builder/core/prod-bundle/esbuild.js.hbs +30 -0
  127. package/templates/base/tools/builder/core/{hash-files.js.hbs → prod-bundle/hash-files.js.hbs} +14 -11
  128. package/templates/base/tools/builder/core/seo/generate-robots-txt.js.hbs +51 -0
  129. package/templates/base/tools/builder/core/seo/generate-seo-files.js.hbs +16 -0
  130. package/templates/base/tools/builder/core/seo/generate-seo-html.js.hbs +128 -0
  131. package/templates/base/tools/builder/core/seo/generate-sitemap-xml.js.hbs +43 -0
  132. package/templates/base/tools/builder/core/seo/html-substitutions.js.hbs +99 -0
  133. package/templates/base/tools/builder/core/seo/i18n-resolution.js.hbs +66 -0
  134. package/templates/base/tools/builder/core/seo/route-output.js.hbs +64 -0
  135. package/templates/base/tools/builder/core/seo/ssr/ssr-bundle.js.hbs +54 -0
  136. package/templates/base/tools/builder/core/seo/ssr/ssr-polyfills.js.hbs +132 -0
  137. package/templates/base/tools/builder/core/seo/ssr/ssr-render.js.hbs +95 -0
  138. package/templates/base/tools/builder/core/styles/sass.js.hbs +40 -0
  139. package/templates/base/tools/builder/core/styles/tailwind.js.hbs +84 -0
  140. package/templates/base/tools/dev/dev-serve.js.hbs +26 -18
  141. package/templates/base/tools/dev/serve.js.hbs +11 -1
  142. package/templates/base/tools/dev/watcher.js.hbs +14 -6
  143. package/templates/base/tools/generator/generator.js.hbs +44 -47
  144. package/templates/base/tools/generator/handle-file.js.hbs +17 -44
  145. package/templates/base/tools/generator/handle-file.test.js.hbs +72 -0
  146. package/templates/base/tools/generator/templates/{component.template.js.hbs → component/component.template.js.hbs} +3 -2
  147. package/templates/base/tools/generator/templates/component/component.template.test.js.hbs +23 -0
  148. package/templates/base/tools/generator/templates/html/html.template.js.hbs +2 -0
  149. package/templates/base/tools/generator/templates/html/html.template.test.js.hbs +7 -0
  150. package/templates/base/tools/generator/templates/index.js.hbs +7 -12
  151. package/templates/base/tools/generator/templates/locale/locale.template.js.hbs +8 -0
  152. package/templates/base/tools/generator/templates/locale/locale.template.test.js.hbs +17 -0
  153. package/templates/base/tools/generator/templates/scss/scss.template.js.hbs +1 -0
  154. package/templates/base/tools/generator/templates/scss/scss.template.test.js.hbs +7 -0
  155. package/templates/base/tools/generator/templates/service/service.template.js.hbs +17 -0
  156. package/templates/base/tools/generator/templates/service/service.template.test.js.hbs +22 -0
  157. package/templates/base/tools/generator/templates/test/test.template.js.hbs +10 -0
  158. package/templates/base/tools/generator/templates/test/test.template.test.js.hbs +27 -0
  159. package/templates/base/tools/generator/templates/{view.template.js.hbs → view/view.template.js.hbs} +4 -3
  160. package/templates/base/tools/generator/templates/view/view.template.test.js.hbs +24 -0
  161. package/templates/base/tools/testin-nutin/core/coverage/collect-coverage.js.hbs +39 -0
  162. package/templates/base/tools/testin-nutin/core/coverage/compute-coverage.js.hbs +115 -0
  163. package/templates/base/tools/testin-nutin/core/coverage/compute-coverage.test.js.hbs +74 -0
  164. package/templates/base/tools/testin-nutin/core/coverage/write-summary-report.js.hbs +54 -0
  165. package/templates/base/tools/testin-nutin/core/coverage/write-uncovered-report.js.hbs +44 -0
  166. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/assertion-lib.js.hbs +62 -24
  167. package/templates/base/tools/testin-nutin/core/globals/clock.js.hbs +206 -0
  168. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/jsdom-setup.js.hbs +19 -6
  169. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/register-test-globals.js.hbs +13 -4
  170. package/templates/base/tools/testin-nutin/core/globals/silence-console.js.hbs +23 -0
  171. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/spyon.js.hbs +2 -0
  172. package/templates/base/tools/testin-nutin/core/index.js.hbs +9 -0
  173. package/templates/base/tools/testin-nutin/core/printer.js.hbs +85 -0
  174. package/templates/base/tools/testin-nutin/core/queue/queue.test.js.hbs +46 -0
  175. package/templates/base/tools/testin-nutin/core/queue/test-discovery.test.js.hbs +46 -0
  176. package/templates/base/tools/testin-nutin/core/queue/test-queue.js.hbs +154 -0
  177. package/templates/{features/testinNutin → base/tools}/testin-nutin/core/tests/assertions.test.js.hbs +27 -0
  178. package/templates/base/tools/testin-nutin/core/tests/clock.test.js.hbs +118 -0
  179. package/templates/base/tools/testin-nutin/core/tests/globals-each-all.test.js.hbs +28 -0
  180. package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/create-mock-method.js.hbs +2 -1
  181. package/templates/base/tools/testin-nutin/mocks/create-mock-method.test.js.hbs +64 -0
  182. package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-event-bus.js.hbs +3 -2
  183. package/templates/base/tools/testin-nutin/mocks/mock-event-bus.test.js.hbs +66 -0
  184. package/templates/base/tools/testin-nutin/mocks/mock-http-client.test.js.hbs +26 -0
  185. package/templates/base/tools/testin-nutin/mocks/mock-i18n.test.js.hbs +61 -0
  186. package/templates/base/tools/testin-nutin/mocks/mock-router.test.js.hbs +29 -0
  187. package/templates/base/tools/testin-nutin/runner.js.hbs +100 -0
  188. package/templates/base/tools/testin-nutin/watch-tests.js.hbs +37 -0
  189. package/templates/base/tools/utils/error-exit.js.hbs +8 -0
  190. package/templates/base/tools/utils/format.js.hbs +10 -10
  191. package/templates/base/tools/utils/format.test.js.hbs +45 -0
  192. package/templates/base/tools/utils/get-files-recursive.js.hbs +6 -1
  193. package/templates/base/tools/utils/get-files-recursive.test.js.hbs +49 -0
  194. package/templates/base/tools/utils/get-rel-to-core.test.js.hbs +18 -0
  195. package/templates/base/tools/utils/index.js.hbs +1 -3
  196. package/templates/base/tools/utils/languages.js.hbs +15 -0
  197. package/templates/base/tools/utils/languages.test.js.hbs +16 -0
  198. package/templates/base/tools/utils/print.js.hbs +19 -13
  199. package/templates/base/tools/utils/print.test.js.hbs +60 -0
  200. package/templates/base/tools/utils/prompt-boolean.js.hbs +7 -0
  201. package/templates/base/tools/utils/prompt-boolean.test.js.hbs +54 -0
  202. package/templates/base/tools/utils/run-command.js.hbs +4 -2
  203. package/templates/base/tools/utils/run-command.test.js.hbs +19 -0
  204. package/templates/base/tools/utils/run-script.js.hbs +14 -3
  205. package/templates/base/tools/utils/run-script.test.js.hbs +40 -0
  206. package/templates/features/{deployHelper → docker}/.dockerignore.hbs +4 -4
  207. package/templates/features/docker/tools/docker/Dockerfile.template.hbs +51 -0
  208. package/templates/features/{deployHelper/tools/deployment/nginx.conf.hbs → docker/tools/docker/nginx.conf.template} +4 -2
  209. package/templates/features/docker/tools/docker/scripts/docker-build.js.hbs +20 -0
  210. package/templates/features/docker/tools/docker/scripts/docker-ports.js.hbs +48 -0
  211. package/templates/features/docker/tools/docker/scripts/docker-ports.test.js.hbs +52 -0
  212. package/templates/features/docker/tools/docker/scripts/docker-run.js.hbs +28 -0
  213. package/templates/features/docker/tools/docker/scripts/render-docker-template.js.hbs +23 -0
  214. package/templates/features/docker/tools/docker/scripts/render-docker-template.test.js.hbs +60 -0
  215. package/templates/features/docker/tools/docker/scripts/validate-docker.js.hbs +30 -0
  216. package/lib/src/context-builder.mjs +0 -40
  217. package/lib/src/file-generator.mjs +0 -109
  218. package/lib/src/json-generator.mjs +0 -31
  219. package/lib/src/package-manager.mjs +0 -139
  220. package/lib/src/print.mjs +0 -32
  221. package/lib/src/utils.mjs +0 -18
  222. package/lib/src/version.mjs +0 -1
  223. package/templates/base/builder.config.js.hbs +0 -36
  224. package/templates/base/src/app/components/common/anchor/anchor.component.ts.hbs +0 -32
  225. package/templates/base/src/app/components/common/button/button.component.ts.hbs +0 -40
  226. package/templates/base/src/app/dom.test.js.hbs +0 -13
  227. package/templates/base/src/app/services/example/example.service.ts.hbs +0 -18
  228. package/templates/base/src/app/views/home/home.view.test.js.hbs +0 -26
  229. package/templates/base/src/core/services/store/store.test.js.hbs +0 -8
  230. package/templates/base/src/core/services/store/store.ts.hbs +0 -39
  231. package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.test.js.hbs +0 -0
  232. package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.ts.hbs +0 -113
  233. package/templates/base/src/core/utils/button-manager/button-manager.utils.test.js.hbs +0 -249
  234. package/templates/base/src/core/utils/button-manager/button-manager.utils.ts.hbs +0 -131
  235. package/templates/base/src/core/utils/helpers/attributes.helper.ts.hbs +0 -50
  236. package/templates/base/src/core/utils/index.ts.hbs +0 -2
  237. package/templates/base/src/libs/index.ts.hbs +0 -4
  238. package/templates/base/src/libs/popover/helpers/focus-trap.helper.ts.hbs +0 -197
  239. package/templates/base/src/libs/popover/helpers/popover-dom.helper.ts.hbs +0 -75
  240. package/templates/base/src/libs/popover/popover.ts.hbs +0 -138
  241. package/templates/base/src/libs/snackbar/snackbar.ts.hbs +0 -75
  242. package/templates/base/src/styles/base/_functions.scss.hbs +0 -9
  243. package/templates/base/src/styles/core/_anchors.scss.hbs +0 -10
  244. package/templates/base/src/styles/core/_index.scss.hbs +0 -6
  245. package/templates/base/src/styles/core/_popover.scss.hbs +0 -96
  246. package/templates/base/src/styles/core/_snackbar.scss.hbs +0 -50
  247. package/templates/base/tools/builder/core/esbuild.js.hbs +0 -25
  248. package/templates/base/tools/builder/core/minify-html.js.hbs +0 -60
  249. package/templates/base/tools/builder/core/sass.js.hbs +0 -22
  250. package/templates/base/tools/builder/core/tsc.js.hbs +0 -12
  251. package/templates/base/tools/generator/templates/service.template.js.hbs +0 -17
  252. package/templates/base/tools/utils/export-flags.js.hbs +0 -6
  253. package/templates/features/deployHelper/tools/builder/core/compress-files.js.hbs +0 -56
  254. package/templates/features/deployHelper/tools/deployment/Dockerfile.hbs +0 -30
  255. package/templates/features/i18n/src/app/views/home/locales/en.json.hbs +0 -9
  256. package/templates/features/i18n/src/app/views/not-found/locales/en.json +0 -8
  257. package/templates/features/i18n/src/app/views/not-found/locales/fr.json +0 -8
  258. package/templates/features/i18n/src/core/config.ts.hbs +0 -3
  259. package/templates/features/i18n/src/core/services/i18n/i18n.test.js.hbs +0 -125
  260. package/templates/features/i18n/tools/generator/templates/json.template.js.hbs +0 -8
  261. package/templates/features/i18n/tools/utils/languages.js.hbs +0 -7
  262. package/templates/features/stylinNutin/src/styles/_custom-classes.scss.hbs +0 -9
  263. package/templates/features/stylinNutin/src/styles/base/_mixins.scss.hbs +0 -372
  264. package/templates/features/stylinNutin/src/styles/components/_index.scss.hbs +0 -3
  265. package/templates/features/stylinNutin/src/styles/core/_utilities.scss.hbs +0 -254
  266. package/templates/features/stylinNutin/src/styles/views/_index.scss.hbs +0 -0
  267. package/templates/features/stylinNutin/tools/generator/templates/scss.template.js.hbs +0 -4
  268. package/templates/features/template/src/app/views/home/home.view.html.hbs +0 -56
  269. package/templates/features/template/src/app/views/not-found/not-found.view.html.hbs +0 -19
  270. package/templates/features/template/tools/builder/core/merge-templates.js.hbs +0 -49
  271. package/templates/features/template/tools/generator/templates/html.template.js.hbs +0 -2
  272. package/templates/features/testinNutin/testin-nutin/core/index.js.hbs +0 -5
  273. package/templates/features/testinNutin/testin-nutin/core/src/utils/print.js.hbs +0 -64
  274. package/templates/features/testinNutin/testin-nutin/core/src/utils/test-queue.js.hbs +0 -64
  275. package/templates/features/testinNutin/testin-nutin/core/tests/globals-each-all.test.js.hbs +0 -28
  276. package/templates/features/testinNutin/testin-nutin/mocks/mock-store.js.hbs +0 -38
  277. package/templates/features/testinNutin/testin-nutin/runner.js.hbs +0 -36
  278. package/templates/features/testinNutin/testin-nutin/watch-tests.js.hbs +0 -21
  279. package/templates/features/testinNutin/testin-nutin.config.js.hbs +0 -14
  280. /package/lib/src/{template-compiler.mjs → common/template-compiler.mjs} +0 -0
  281. /package/templates/{features/i18n → base}/src/core/base-classes/base-component/helpers/i18n.helper.ts.hbs +0 -0
  282. /package/templates/{features/i18n → base}/src/core/services/i18n/languages.ts.hbs +0 -0
  283. /package/templates/base/tools/builder/{variables → core/app}/binary-extensions.js.hbs +0 -0
  284. /package/templates/base/tools/builder/core/{paths.js.hbs → app/paths.js.hbs} +0 -0
  285. /package/templates/{features/testinNutin/testin-nutin/core/src/utils → base/tools/testin-nutin/core/queue}/queue.js.hbs +0 -0
  286. /package/templates/{features/testinNutin/testin-nutin/core/src/utils → base/tools/testin-nutin/core/queue}/test-discovery.js.hbs +0 -0
  287. /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-http-client.js.hbs +0 -0
  288. /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-i18n.js.hbs +0 -0
  289. /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-router.js.hbs +0 -0
@@ -0,0 +1,19 @@
1
+ import { runCommand } from './run-command.js';
2
+
3
+ describe('runCommand', () => {
4
+ it('resolves when the child process exits with code 0', async () => {
5
+ const result = await runCommand('node', ['-e', 'process.exitCode=0']);
6
+ expect(result).toBe(undefined);
7
+ });
8
+
9
+ it('rejects with the exit code when the child process exits non-zero', async () => {
10
+ let error;
11
+ try {
12
+ await runCommand('node', ['-e', 'process.exitCode=7']);
13
+ } catch (err) {
14
+ error = err;
15
+ }
16
+ expect(error).toBeDefined();
17
+ expect(error.message).toContain('7');
18
+ });
19
+ });
@@ -4,17 +4,28 @@ import process from 'process';
4
4
  import { print } from './index.js';
5
5
 
6
6
  export function runScript(path, message) {
7
- print.boldSection(message);
7
+ if (!message) print.boldSection(`Running ${path}...`);
8
+ else print.boldSection(`${message}`);
8
9
 
9
- const args = [resolve(path)];
10
+ const args = [resolve(path), '--silent'];
10
11
 
11
- const result = spawnSync('node', args,
12
+ const result = spawnSync('node', args,
12
13
  {
13
14
  stdio: 'inherit',
14
15
  env: { ...process.env },
15
16
  }
16
17
  );
17
18
 
19
+ if (result.error) {
20
+ print.boldError(`\nScript ${path} could not be started: ${result.error.message}`);
21
+ process.exit(1);
22
+ }
23
+
24
+ if (result.signal) {
25
+ print.boldError(`\nScript ${path} was terminated by signal ${result.signal}.`);
26
+ process.exit(1);
27
+ }
28
+
18
29
  if (result.status !== 0) {
19
30
  print.boldError(`\nScript ${path} failed.`);
20
31
  process.exit(result.status ?? 1);
@@ -0,0 +1,40 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { runScript } from './run-script.js';
5
+
6
+ describe('runScript', () => {
7
+ let tmpDir;
8
+ let exitSpy;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'nutin-run-script-'));
12
+ exitSpy = spyOn(process, 'exit').andCallFake(() => {});
13
+ });
14
+
15
+ afterEach(() => {
16
+ exitSpy.restore();
17
+ fs.rmSync(tmpDir, { recursive: true, force: true });
18
+ });
19
+
20
+ it('does not call process.exit when the script exits 0', () => {
21
+ const scriptPath = path.join(tmpDir, 'ok.js');
22
+ fs.writeFileSync(scriptPath, '// no-op, exits 0 by default\n');
23
+
24
+ // runScript prints its status message via console.info as part of its real behavior
25
+ silenceConsole('info', () => runScript(scriptPath, 'running ok script'));
26
+
27
+ expect(exitSpy.callCount).toBe(0);
28
+ });
29
+
30
+ it('calls process.exit with the script status when it exits non-zero', () => {
31
+ const scriptPath = path.join(tmpDir, 'fail.js');
32
+ fs.writeFileSync(scriptPath, 'process.exitCode = 3;\n');
33
+
34
+ // runScript prints its status message and a failure message via console.info/console.error
35
+ silenceConsole(['info', 'error'], () => runScript(scriptPath, 'running failing script'));
36
+
37
+ expect(exitSpy.callCount).toBe(1);
38
+ expect(exitSpy.lastCall).toEqual([3]);
39
+ });
40
+ });
@@ -8,13 +8,13 @@ dist-build
8
8
  *.md
9
9
  .env
10
10
  *.txt
11
- {{#if testinNutin}}
12
11
  *.test.js
13
- testin-nutin
14
- {{/if}}
15
12
  *.log
16
13
 
17
- npm-debug.log
14
+ npm-debug.log*
15
+ yarn-debug.log*
16
+ yarn-error.log*
17
+ pnpm-debug.log*
18
18
  .nyc_output
19
19
  coverage
20
20
  .DS_Store
@@ -0,0 +1,51 @@
1
+ ARG NODE_VERSION=22.23.2
2
+ ARG ALPINE_VERSION=3.20
3
+ ARG PORT="__PORTS_PLACEHOLDER__"
4
+
5
+ FROM node:${NODE_VERSION}-alpine AS builder
6
+ WORKDIR /usr/src/app
7
+ RUN corepack enable
8
+ {{#if (eq packageManager "npm")}}
9
+ COPY package.json package-lock.json* .
10
+ {{/if}}
11
+ {{#if (eq packageManager "pnpm")}}
12
+ COPY package.json pnpm-lock.yaml .
13
+ {{/if}}
14
+ {{#if (eq packageManager "yarn")}}
15
+ COPY package.json yarn.lock .
16
+ {{/if}}
17
+ {{#if (eq packageManager "bun")}}
18
+ COPY package.json bun.lock* bun.lockb* .
19
+ RUN npm install -g bun
20
+ {{/if}}
21
+ {{#if (eq packageManager "pnpm")}}
22
+ RUN {{ciCommand}} || pnpm approve-builds --all
23
+ {{else}}
24
+ RUN {{ciCommand}}
25
+ {{/if}}
26
+ COPY tsconfig.json .
27
+ COPY ./src ./src
28
+ COPY ./public ./public
29
+ COPY ./nutin.config.js .
30
+ COPY ./config ./config
31
+ COPY ./tools/builder ./tools/builder
32
+ COPY ./tools/docker ./tools/docker
33
+ COPY ./tools/utils ./tools/utils
34
+ RUN {{packageManager}} run build:prod
35
+
36
+ FROM alpine:${ALPINE_VERSION}
37
+ ARG PORT
38
+ ENV PORT=${PORT}
39
+
40
+ RUN apk add --no-cache nginx nginx-mod-http-brotli
41
+
42
+ RUN rm -f /etc/nginx/http.d/default.conf
43
+ COPY --from=builder /usr/src/app/tools/docker/nginx.conf /etc/nginx/http.d/default.conf
44
+ COPY --from=builder /usr/src/app/dist/src /usr/share/nginx/html
45
+
46
+ EXPOSE ${PORT}
47
+
48
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
49
+ CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:__PRIMARY_PORT_PLACEHOLDER__/health || exit 1
50
+
51
+ CMD ["nginx", "-g", "daemon off;"]
@@ -30,14 +30,16 @@ map $uri $csp_policy {
30
30
  # ---------------------------
31
31
  gzip on;
32
32
  gzip_static on;
33
- gzip_vary on;
34
33
  gzip_proxied any;
35
34
 
35
+ brotli on;
36
+ brotli_static on;
37
+
36
38
  server {
37
39
  # ---------------------------
38
40
  # LISTEN PORTS
39
41
  # ---------------------------
40
- listen 9090;
42
+ __PORTS_PLACEHOLDER__
41
43
  server_name _;
42
44
 
43
45
  # ---------------------------
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from 'path';
4
+ import { readFileSync } from 'fs';
5
+ import { spawn } from 'child_process';
6
+ import { print, runScript } from '../../utils/index.js';
7
+
8
+ const { name: projectName } = JSON.parse(readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'));
9
+
10
+ runScript(path.join(process.cwd(), 'tools', 'docker', 'scripts', 'validate-docker.js'), 'Validating Docker configuration...');
11
+
12
+ const args = ['build', '-t', projectName, '-f', 'tools/docker/Dockerfile', '.'];
13
+ print.boldSection(`Running: docker ${args.join(' ')}`);
14
+
15
+ const child = spawn('docker', args, { stdio: 'inherit' });
16
+ child.on('error', (err) => {
17
+ print.boldError(`Failed to start docker: ${err.message}`);
18
+ process.exit(1);
19
+ });
20
+ child.on('exit', (code) => process.exit(code ?? 1));
@@ -0,0 +1,48 @@
1
+ // Registered/user port range only — excludes privileged ports (<1024, may need
2
+ // elevated host privileges to bind) and the OS ephemeral range (>=49152, reserved
3
+ // for outgoing/dynamic connections, not meant for fixed service ports).
4
+ const MIN_PORT = 1024;
5
+ const MAX_PORT = 49151;
6
+
7
+ export function validateDockerPorts(rawPorts) {
8
+ if (rawPorts === undefined) {
9
+ throw new Error('nutin.config.js: "dockerPorts" not found. It must be an array of integers (e.g. [9090, 6969])');
10
+ }
11
+
12
+ if (!Array.isArray(rawPorts)) {
13
+ throw new Error('nutin.config.js: "dockerPorts" must be an array of integers (e.g. [9090, 6969]).');
14
+ }
15
+
16
+ if (rawPorts.length === 0) {
17
+ throw new Error('nutin.config.js: "dockerPorts" must contain at least one port (e.g. [9090]).');
18
+ }
19
+
20
+ const seen = new Set();
21
+
22
+ for (let i = 0; i < rawPorts.length; i++) {
23
+ const port = rawPorts[i];
24
+
25
+ if (typeof port !== 'number' || !Number.isInteger(port)) {
26
+ throw new Error(`nutin.config.js: "dockerPorts[${i}]" must be an integer; ports must be numbers, e.g. 9090 not "9090".`);
27
+ }
28
+
29
+ if (port < MIN_PORT) {
30
+ throw new Error(`nutin.config.js: "dockerPorts[${i}]" (${port}) is a privileged port (<1024) — use a registered port between ${MIN_PORT} and ${MAX_PORT}.`);
31
+ }
32
+
33
+ if (port > MAX_PORT) {
34
+ throw new Error(`nutin.config.js: "dockerPorts[${i}]" (${port}) is in the OS ephemeral port range (49152-65535) — use a registered port between ${MIN_PORT} and ${MAX_PORT}.`);
35
+ }
36
+
37
+ if (port < MIN_PORT || port > MAX_PORT) {
38
+ throw new Error(`nutin.config.js: "dockerPorts[${i}]" (${port}) is outside of port range (${MIN_PORT} / ${MAX_PORT} .`);
39
+ }
40
+
41
+ if (seen.has(port)) {
42
+ throw new Error(`nutin.config.js: "dockerPorts" contains duplicate port ${port} — each port must be listed once.`);
43
+ }
44
+ seen.add(port);
45
+ }
46
+
47
+ return rawPorts;
48
+ }
@@ -0,0 +1,52 @@
1
+ import { validateDockerPorts } from './docker-ports.js';
2
+
3
+ describe('validateDockerPorts', () => {
4
+ it('throws when dockerPorts is not set', () => {
5
+ expect(() => validateDockerPorts(undefined)).toThrow('"dockerPorts" not found');
6
+ });
7
+
8
+ it('throws when dockerPorts is not an array', () => {
9
+ expect(() => validateDockerPorts(9090)).toThrow('must be an array of integers');
10
+ expect(() => validateDockerPorts('9090')).toThrow('must be an array of integers');
11
+ expect(() => validateDockerPorts({ port: 9090 })).toThrow('must be an array of integers');
12
+ });
13
+
14
+ it('throws when dockerPorts is empty', () => {
15
+ expect(() => validateDockerPorts([])).toThrow('must contain at least one port');
16
+ });
17
+
18
+ it('throws when an entry is not an integer', () => {
19
+ expect(() => validateDockerPorts(['8080'])).toThrow('must be an integer');
20
+ expect(() => validateDockerPorts([8080.5])).toThrow('must be an integer');
21
+ expect(() => validateDockerPorts([NaN])).toThrow('must be an integer');
22
+ expect(() => validateDockerPorts([true])).toThrow('must be an integer');
23
+ expect(() => validateDockerPorts([null])).toThrow('must be an integer');
24
+ });
25
+
26
+ it('throws for privileged ports below 1024', () => {
27
+ expect(() => validateDockerPorts([80])).toThrow('privileged port');
28
+ expect(() => validateDockerPorts([1023])).toThrow('privileged port');
29
+ });
30
+
31
+ it('throws for ephemeral ports at or above 49152', () => {
32
+ expect(() => validateDockerPorts([49152])).toThrow('ephemeral port range');
33
+ expect(() => validateDockerPorts([60000])).toThrow('ephemeral port range');
34
+ });
35
+
36
+ it('throws for duplicate ports', () => {
37
+ expect(() => validateDockerPorts([8080, 8080])).toThrow('duplicate port');
38
+ });
39
+
40
+ it('identifies the invalid entry by index in the error message', () => {
41
+ expect(() => validateDockerPorts([8080, 80])).toThrow('dockerPorts[1]');
42
+ });
43
+
44
+ it('accepts the registered-port range boundaries', () => {
45
+ expect(validateDockerPorts([1024])).toEqual([1024]);
46
+ expect(validateDockerPorts([49151])).toEqual([49151]);
47
+ });
48
+
49
+ it('returns a valid multi-port array unchanged', () => {
50
+ expect(validateDockerPorts([8080, 8081, 3000])).toEqual([8080, 8081, 3000]);
51
+ });
52
+ });
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'fs';
4
+ import path from 'path';
5
+ import { spawn } from 'child_process';
6
+ import { print, errorExit } from '../../utils/index.js';
7
+ import nutinConfig from '../../../nutin.config.js';
8
+ import { validateDockerPorts } from './docker-ports.js';
9
+
10
+ const { name: projectName } = JSON.parse(readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'));
11
+
12
+ let ports;
13
+ try {
14
+ ports = validateDockerPorts(nutinConfig.dockerPorts);
15
+ } catch (err) {
16
+ errorExit(err.message);
17
+ }
18
+
19
+ const portArgs = ports.flatMap((port) => ['-p', `${port}:${port}`]);
20
+ const args = ['run', ...portArgs, `${projectName}:latest`];
21
+ print.boldSection(`Running: docker ${args.join(' ')}`);
22
+
23
+ const child = spawn('docker', args, { stdio: 'inherit' });
24
+ child.on('error', (err) => {
25
+ print.boldError(`Failed to start docker: ${err.message}`);
26
+ process.exit(1);
27
+ });
28
+ child.on('exit', (code) => process.exit(code ?? 1));
@@ -0,0 +1,23 @@
1
+ import { readFile, writeFile } from 'fs/promises';
2
+ import path from 'path';
3
+
4
+ export async function renderFromTemplate(dockerDir, templateName, outputName, replacements) {
5
+ const templatePath = path.join(dockerDir, templateName);
6
+ const outputPath = path.join(dockerDir, outputName);
7
+
8
+ let content;
9
+ try {
10
+ content = await readFile(templatePath, 'utf-8');
11
+ } catch {
12
+ throw new Error(`tools/docker/${templateName} not found — re-run "nutin-add docker" or restore the file.`);
13
+ }
14
+
15
+ for (const [placeholder, value] of replacements) {
16
+ if (!content.includes(placeholder)) {
17
+ throw new Error(`tools/docker/${templateName} is missing the "${placeholder}" token — validate-docker has nothing to substitute. Restore the token or re-run "nutin-add docker".`);
18
+ }
19
+ content = content.replace(placeholder, value);
20
+ }
21
+
22
+ await writeFile(outputPath, content);
23
+ }
@@ -0,0 +1,60 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { renderFromTemplate } from './render-docker-template.js';
5
+
6
+ describe('renderFromTemplate', () => {
7
+ let tmpDir;
8
+
9
+ beforeEach(() => {
10
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'nutin-render-docker-template-'));
11
+ });
12
+
13
+ afterEach(() => {
14
+ fs.rmSync(tmpDir, { recursive: true, force: true });
15
+ });
16
+
17
+ it('substitutes a single placeholder and writes the output file', async () => {
18
+ fs.writeFileSync(path.join(tmpDir, 'nginx.conf.template'), '__PORTS_PLACEHOLDER__;\n');
19
+
20
+ await renderFromTemplate(tmpDir, 'nginx.conf.template', 'nginx.conf', [
21
+ ['__PORTS_PLACEHOLDER__', 'listen 8080;'],
22
+ ]);
23
+
24
+ const output = fs.readFileSync(path.join(tmpDir, 'nginx.conf'), 'utf-8');
25
+ expect(output).toBe('listen 8080;;\n');
26
+ });
27
+
28
+ it('substitutes multiple placeholders in one call', async () => {
29
+ fs.writeFileSync(
30
+ path.join(tmpDir, 'Dockerfile.template'),
31
+ 'ARG PORT="__PORTS_PLACEHOLDER__"\nCMD wget http://127.0.0.1:__PRIMARY_PORT_PLACEHOLDER__/health\n'
32
+ );
33
+
34
+ await renderFromTemplate(tmpDir, 'Dockerfile.template', 'Dockerfile', [
35
+ ['__PORTS_PLACEHOLDER__', '8080 8081 3000'],
36
+ ['__PRIMARY_PORT_PLACEHOLDER__', '8080'],
37
+ ]);
38
+
39
+ const output = fs.readFileSync(path.join(tmpDir, 'Dockerfile'), 'utf-8');
40
+ expect(output).toBe('ARG PORT="8080 8081 3000"\nCMD wget http://127.0.0.1:8080/health\n');
41
+ });
42
+
43
+ it('throws when the template file does not exist', async () => {
44
+ await expect(() =>
45
+ renderFromTemplate(tmpDir, 'missing.template', 'missing', [['__X__', 'y']])
46
+ ).toThrow('missing.template');
47
+ });
48
+
49
+ it('throws when a placeholder token is missing from the template, without writing the output', async () => {
50
+ fs.writeFileSync(path.join(tmpDir, 'nginx.conf.template'), 'listen 9090;\n');
51
+
52
+ await expect(() =>
53
+ renderFromTemplate(tmpDir, 'nginx.conf.template', 'nginx.conf', [
54
+ ['__PORTS_PLACEHOLDER__', 'listen 8080;'],
55
+ ])
56
+ ).toThrow('__PORTS_PLACEHOLDER__');
57
+
58
+ expect(fs.existsSync(path.join(tmpDir, 'nginx.conf'))).toBeFalsy();
59
+ });
60
+ });
@@ -0,0 +1,30 @@
1
+ import path from 'path';
2
+ import { errorExit } from '../../utils/index.js';
3
+ import nutinConfig from '../../../nutin.config.js';
4
+ import { validateDockerPorts } from './docker-ports.js';
5
+ import { renderFromTemplate } from './render-docker-template.js';
6
+
7
+ const DOCKER_DIR = path.join(process.cwd(), 'tools', 'docker');
8
+ const PLACEHOLDER = '__PORTS_PLACEHOLDER__';
9
+
10
+ async function validateDocker() {
11
+ let ports;
12
+ try {
13
+ ports = validateDockerPorts(nutinConfig.dockerPorts);
14
+ } catch (err) {
15
+ errorExit(err.message);
16
+ }
17
+
18
+ await renderFromTemplate(DOCKER_DIR, 'Dockerfile.template', 'Dockerfile', [
19
+ [PLACEHOLDER, ports.join(' ')],
20
+ ['__PRIMARY_PORT_PLACEHOLDER__', String(ports[0])],
21
+ ]).catch((err) => errorExit(err.message));
22
+
23
+ await renderFromTemplate(DOCKER_DIR, 'nginx.conf.template', 'nginx.conf', [
24
+ [PLACEHOLDER, ports.map((port) => `listen ${port};`).join('\n ')],
25
+ ]).catch((err) => errorExit(err.message));
26
+ }
27
+
28
+ validateDocker().catch((err) => {
29
+ errorExit(err, 'validate-docker');
30
+ });
@@ -1,40 +0,0 @@
1
- import { getCiCommand } from './package-manager.mjs';
2
- import { packageVersion } from './version.mjs';
3
-
4
- const PRESET_MAP = {
5
- default: { template: false, stylinNutin: false, i18n: false, deployHelper: false, testinNutin: false },
6
- minimal: { template: true, stylinNutin: false, i18n: false, deployHelper: false, testinNutin: false },
7
- standard: { template: true, stylinNutin: true, i18n: true, deployHelper: false, testinNutin: false },
8
- full: { template: true, stylinNutin: true, i18n: true, deployHelper: true, testinNutin: true },
9
- cicd: { template: true, stylinNutin: false, i18n: false, deployHelper: true, testinNutin: false },
10
- };
11
-
12
- export const defaults = {
13
- projectName: 'my-nutin-app',
14
- packageManager: 'npm',
15
- ...PRESET_MAP['default']
16
- };
17
-
18
- export class ContextBuilder {
19
- buildContext(preferences) {
20
- const version = packageVersion;
21
- const ciCommand = getCiCommand(preferences.packageManager);
22
-
23
- const preset = PRESET_MAP[preferences.preset] ?? PRESET_MAP['default'];
24
-
25
- return {
26
- projectName: preferences.projectName,
27
- packageManager: preferences.packageManager,
28
-
29
- template: preset.template,
30
- stylinNutin: preset.stylinNutin,
31
- i18n: preferences.i18n ?? preset.i18n,
32
- deployHelper: preferences.deployHelper ?? preset.deployHelper,
33
- testinNutin: preferences.testinNutin ?? preset.testinNutin,
34
- transition: preferences.transition,
35
-
36
- ciCommand: ciCommand,
37
- version: version
38
- };
39
- }
40
- }
@@ -1,109 +0,0 @@
1
- import path from 'path';
2
- import { fileURLToPath } from 'url';
3
- import * as fsExtra from 'fs-extra';
4
- import { TemplateCompiler } from './template-compiler.mjs';
5
- import { print } from './print.mjs';
6
-
7
- const fs = fsExtra.default;
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- const BINARY_EXTENSIONS = new Set([
12
- '.png', '.jpg', '.jpeg', '.gif', '.webp', '.avif', '.svg',
13
- '.ico', '.woff', '.woff2', '.ttf', '.otf', '.eot',
14
- '.mp4', '.webm', '.mp3', '.wav', '.ogg',
15
- '.pdf', '.zip', '.tar', '.gz'
16
- ]);
17
-
18
- export class FileGenerator {
19
- constructor() {
20
- this.compiler = new TemplateCompiler();
21
- }
22
-
23
- async generateProjectFromTemplates(projectPath, context) {
24
- const templateDir = this.getTemplateDirectory();
25
-
26
- print.section('📝 Processing templates...');
27
- await this.processTemplateDirectory(templateDir, projectPath, context);
28
-
29
- await this.processFeatureTemplates(projectPath, context);
30
- }
31
-
32
- getTemplateDirectory() {
33
- return path.join(__dirname, '..', '..', 'templates', 'base');
34
- }
35
-
36
- async processTemplateDirectory(templateDir, outputDir, context) {
37
- if (!(await fs.pathExists(templateDir))) {
38
- throw new Error(`Template directory not found: ${templateDir}`);
39
- }
40
-
41
- const entries = await fs.readdir(templateDir, { withFileTypes: true });
42
-
43
- for (const entry of entries) {
44
- if (entry.name === '.DS_Store') continue;
45
-
46
- const templatePath = path.join(templateDir, entry.name);
47
-
48
- if (entry.isDirectory()) {
49
- const outputPath = path.join(outputDir, entry.name);
50
- await fs.ensureDir(outputPath);
51
- await this.processTemplateDirectory(templatePath, outputPath, context);
52
- } else {
53
- await this.processTemplateFile(templatePath, outputDir, entry.name, context);
54
- }
55
- }
56
- }
57
-
58
- async processFeatureTemplates(projectPath, context) {
59
- const featuresDir = path.join(__dirname, '..', '..', 'templates', 'features');
60
-
61
- if (!(await fs.pathExists(featuresDir))) {
62
- return;
63
- }
64
-
65
- const features = [ 'template', 'i18n', 'stylinNutin', 'testinNutin', 'deployHelper' ];
66
-
67
- for (const feature of features) {
68
- if (context[feature]) {
69
- const featureTemplateDir = path.join(featuresDir, feature);
70
-
71
- if (await fs.pathExists(featureTemplateDir)) {
72
- print.info(` 🔧 Adding ${feature} feature...`);
73
- await this.processTemplateDirectory(featureTemplateDir, projectPath, context);
74
- }
75
- }
76
- }
77
- }
78
-
79
- async processTemplateFile(templatePath, outputDir, fileName, context) {
80
- if (fileName.includes("test.js") && !(context.testinNutin)) {
81
- return;
82
- }
83
-
84
- const fileExt = path.extname(fileName).toLowerCase();
85
-
86
- if (BINARY_EXTENSIONS.has(fileExt)) {
87
- const outputPath = path.join(outputDir, fileName);
88
- await fs.copy(templatePath, outputPath);
89
- // print.info(`📄 Copied: ${fileName}`);
90
- } else if (fileName.endsWith('.hbs')) {
91
-
92
- const outputFileName = fileName.replace('.hbs', '');
93
- const outputPath = path.join(outputDir, outputFileName);
94
-
95
- try {
96
- const compiledContent = await this.compiler.compileFile(templatePath, context);
97
- await fs.writeFile(outputPath, compiledContent);
98
- // print.info(`📝 Generated: ${outputFileName}`);
99
- } catch (error) {
100
- print.boldError(`❌ Failed to process template: ${fileName}`);
101
- throw error;
102
- }
103
- } else {
104
- const outputPath = path.join(outputDir, fileName);
105
- await fs.copy(templatePath, outputPath);
106
- // print.info(`📄 Copied: ${fileName}`);
107
- }
108
- }
109
- }
@@ -1,31 +0,0 @@
1
- import path from 'path';
2
- import * as fsExtra from 'fs-extra';
3
- import { generatePackageJson, generateTsconfigJson } from './package-manager.mjs';
4
-
5
- const fs = fsExtra.default;
6
-
7
- export class JsonGenerator {
8
- async generateJsonFiles(projectPath, context) {
9
- await generatePackageJson(projectPath, context);
10
- await generateTsconfigJson(projectPath, context);
11
- this.generateConfigFiles(projectPath, context);
12
- }
13
-
14
- async generateConfigFiles(projectPath, context) {
15
- const configPath = path.join(projectPath, 'config');
16
-
17
- if (context.i18n) {
18
- await fs.ensureDir(configPath);
19
- await this.generateLanguageConfig(configPath);
20
- }
21
- }
22
-
23
- async generateLanguageConfig(configPath) {
24
- const languages = {
25
- "languages": [ "en" ],
26
- "defaultLanguage": "en"
27
- };
28
-
29
- await fs.writeJSON(path.join(configPath, 'languages.json'), languages, { spaces: 2 });
30
- }
31
- }