@nutin/cli 1.3.1 → 2.0.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 (287) hide show
  1. package/CHANGELOG.md +89 -9
  2. package/README.md +20 -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 +14 -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 +136 -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 +169 -0
  36. package/templates/base/GETTING_STARTED.md.hbs +227 -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 +51 -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 +7 -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 +1 -56
  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 +4 -37
  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 +74 -0
  56. package/templates/base/src/core/base-classes/base-component/helpers/children.helper.ts.hbs +1 -1
  57. package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.test.js.hbs +145 -0
  58. package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.ts.hbs +7 -1
  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 +82 -0
  63. package/templates/base/src/core/base-classes/base-component/helpers/security.helper.test.js.hbs +142 -0
  64. package/templates/base/src/core/base-classes/base-component/helpers/security.helper.ts.hbs +67 -22
  65. package/templates/base/src/core/base-classes/base-component/helpers/token.helper.test.js.hbs +183 -0
  66. package/templates/base/src/core/base-classes/component/component.test.js.hbs +85 -0
  67. package/templates/base/src/core/base-classes/component/component.ts.hbs +24 -33
  68. package/templates/base/src/core/base-classes/component/helpers/config.helper.test.js.hbs +58 -0
  69. package/templates/base/src/core/base-classes/component/helpers/data-binding.helper.test.js.hbs +75 -0
  70. package/templates/base/src/core/base-classes/service/service.test.js.hbs +150 -0
  71. package/templates/base/src/core/base-classes/service/service.ts.hbs +26 -20
  72. package/templates/base/src/core/base-classes/view/view.test.js.hbs +74 -0
  73. package/templates/base/src/core/base-classes/view/view.ts.hbs +17 -41
  74. package/templates/base/src/core/config.ts.hbs +7 -0
  75. package/templates/base/src/core/index.ts.hbs +0 -3
  76. package/templates/base/src/core/internals.d.ts.hbs +27 -0
  77. package/templates/base/src/core/nutin-config.d.ts.hbs +4 -0
  78. package/templates/base/src/core/services/event-bus/event-bus.test.js.hbs +67 -3
  79. package/templates/base/src/core/services/event-bus/event-bus.ts.hbs +9 -4
  80. package/templates/base/src/core/services/event-bus/index.ts.hbs +3 -0
  81. package/templates/base/src/core/services/event-bus/lifecycle.facade.test.js.hbs +123 -0
  82. package/templates/base/src/core/services/event-bus/lifecycle.facade.ts.hbs +61 -0
  83. package/templates/base/src/core/services/event-bus/navigation.facade.test.js.hbs +46 -0
  84. package/templates/base/src/core/services/event-bus/navigation.facade.ts.hbs +25 -0
  85. package/templates/base/src/core/services/globals/globals.test.js.hbs +149 -0
  86. package/templates/base/src/core/services/globals/globals.ts.hbs +95 -0
  87. package/templates/base/src/core/services/http-client/helpers/http-builder.helper.test.js.hbs +25 -0
  88. package/templates/base/src/core/services/http-client/helpers/http-manager.helper.test.js.hbs +20 -0
  89. package/templates/base/src/core/services/http-client/http-client.test.js.hbs +43 -0
  90. package/templates/base/src/core/services/i18n/i18n.test.js.hbs +270 -0
  91. package/templates/{features/i18n → base}/src/core/services/i18n/i18n.ts.hbs +22 -4
  92. package/templates/base/src/core/services/index.ts.hbs +5 -6
  93. package/templates/base/src/core/services/pipe-registry/pipe-registry.test.js.hbs +60 -1
  94. package/templates/base/src/core/services/pipe-registry/pipe-registry.ts.hbs +1 -1
  95. package/templates/base/src/core/services/pipe-registry/pipes.test.js.hbs +128 -0
  96. package/templates/base/src/{libs/pipes → core/services/pipe-registry}/pipes.ts.hbs +8 -5
  97. package/templates/base/src/core/services/router/helpers/navigation-manager.helper.test.js.hbs +149 -6
  98. package/templates/base/src/core/services/router/helpers/navigation-manager.helper.ts.hbs +40 -29
  99. package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.test.js.hbs +27 -0
  100. package/templates/base/src/core/services/router/helpers/view-render-manager.helper.test.js.hbs +83 -17
  101. package/templates/base/src/core/services/router/helpers/view-render-manager.helper.ts.hbs +14 -38
  102. package/templates/base/src/core/services/router/router.test.js.hbs +226 -2
  103. package/templates/base/src/core/services/router/router.ts.hbs +40 -8
  104. package/templates/base/src/index.html.hbs +2 -6
  105. package/templates/base/src/styles/_styles.scss.hbs +102 -43
  106. package/templates/base/src/styles/base/_variables.scss.hbs +1 -86
  107. package/templates/base/src/styles/main.scss.hbs +1 -18
  108. package/templates/base/src/styles/tailwind.css.hbs +2 -0
  109. package/templates/base/tools/builder/builder.config.js.hbs +40 -0
  110. package/templates/base/tools/builder/builder.js.hbs +24 -26
  111. package/templates/base/tools/builder/core/app/binary-extensions.test.js.hbs +16 -0
  112. package/templates/base/tools/builder/core/app/compile-ts.js.hbs +16 -0
  113. package/templates/base/tools/builder/core/{copy-static.js.hbs → app/copy-static.js.hbs} +27 -34
  114. package/templates/base/tools/builder/core/app/validate-routes.js.hbs +77 -0
  115. package/templates/base/tools/builder/core/finalize-build.js.hbs +16 -7
  116. package/templates/base/tools/builder/core/{add-tags.js.hbs → html-index/add-tags.js.hbs} +2 -2
  117. package/templates/base/tools/builder/core/html-index/add-tags.test.js.hbs +56 -0
  118. package/templates/base/tools/builder/core/{validate-html.js.hbs → html-index/validate-html.js.hbs} +5 -11
  119. package/templates/base/tools/builder/core/html-templates/merge-templates.js.hbs +152 -0
  120. package/templates/base/tools/builder/core/html-templates/minify-html.js.hbs +15 -0
  121. package/templates/base/tools/builder/core/html-templates/process-html-templates.js.hbs +8 -0
  122. package/templates/{features/i18n/tools/builder/core → base/tools/builder/core/i18n}/build-i18n.js.hbs +6 -17
  123. package/templates/base/tools/builder/core/prod-bundle/compress-files.js.hbs +37 -0
  124. package/templates/base/tools/builder/core/prod-bundle/esbuild.js.hbs +30 -0
  125. package/templates/base/tools/builder/core/{hash-files.js.hbs → prod-bundle/hash-files.js.hbs} +14 -11
  126. package/templates/base/tools/builder/core/seo/generate-robots-txt.js.hbs +51 -0
  127. package/templates/base/tools/builder/core/seo/generate-seo-files.js.hbs +16 -0
  128. package/templates/base/tools/builder/core/seo/generate-seo-html.js.hbs +128 -0
  129. package/templates/base/tools/builder/core/seo/generate-sitemap-xml.js.hbs +43 -0
  130. package/templates/base/tools/builder/core/seo/html-substitutions.js.hbs +99 -0
  131. package/templates/base/tools/builder/core/seo/i18n-resolution.js.hbs +66 -0
  132. package/templates/base/tools/builder/core/seo/route-output.js.hbs +64 -0
  133. package/templates/base/tools/builder/core/seo/ssr/ssr-bundle.js.hbs +54 -0
  134. package/templates/base/tools/builder/core/seo/ssr/ssr-polyfills.js.hbs +132 -0
  135. package/templates/base/tools/builder/core/seo/ssr/ssr-render.js.hbs +95 -0
  136. package/templates/base/tools/builder/core/styles/sass.js.hbs +40 -0
  137. package/templates/base/tools/builder/core/styles/tailwind.js.hbs +84 -0
  138. package/templates/base/tools/dev/dev-serve.js.hbs +26 -18
  139. package/templates/base/tools/dev/serve.js.hbs +11 -1
  140. package/templates/base/tools/dev/watcher.js.hbs +14 -6
  141. package/templates/base/tools/generator/generator.js.hbs +64 -47
  142. package/templates/base/tools/generator/handle-file.js.hbs +17 -44
  143. package/templates/base/tools/generator/handle-file.test.js.hbs +72 -0
  144. package/templates/base/tools/generator/templates/{component.template.js.hbs → component/component.template.js.hbs} +3 -2
  145. package/templates/base/tools/generator/templates/component/component.template.test.js.hbs +23 -0
  146. package/templates/base/tools/generator/templates/html/html.template.js.hbs +2 -0
  147. package/templates/base/tools/generator/templates/html/html.template.test.js.hbs +7 -0
  148. package/templates/base/tools/generator/templates/index.js.hbs +7 -12
  149. package/templates/base/tools/generator/templates/locale/locale.template.js.hbs +4 -0
  150. package/templates/base/tools/generator/templates/locale/locale.template.test.js.hbs +7 -0
  151. package/templates/base/tools/generator/templates/scss/scss.template.js.hbs +1 -0
  152. package/templates/base/tools/generator/templates/scss/scss.template.test.js.hbs +7 -0
  153. package/templates/base/tools/generator/templates/service/service.template.js.hbs +17 -0
  154. package/templates/base/tools/generator/templates/service/service.template.test.js.hbs +22 -0
  155. package/templates/base/tools/generator/templates/test/test.template.js.hbs +10 -0
  156. package/templates/base/tools/generator/templates/test/test.template.test.js.hbs +27 -0
  157. package/templates/base/tools/generator/templates/{view.template.js.hbs → view/view.template.js.hbs} +3 -2
  158. package/templates/base/tools/generator/templates/view/view.template.test.js.hbs +24 -0
  159. package/templates/base/tools/testin-nutin/core/coverage/collect-coverage.js.hbs +39 -0
  160. package/templates/base/tools/testin-nutin/core/coverage/compute-coverage.js.hbs +115 -0
  161. package/templates/base/tools/testin-nutin/core/coverage/compute-coverage.test.js.hbs +74 -0
  162. package/templates/base/tools/testin-nutin/core/coverage/write-summary-report.js.hbs +54 -0
  163. package/templates/base/tools/testin-nutin/core/coverage/write-uncovered-report.js.hbs +44 -0
  164. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/assertion-lib.js.hbs +62 -24
  165. package/templates/base/tools/testin-nutin/core/globals/clock.js.hbs +206 -0
  166. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/jsdom-setup.js.hbs +19 -6
  167. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/register-test-globals.js.hbs +13 -4
  168. package/templates/base/tools/testin-nutin/core/globals/silence-console.js.hbs +23 -0
  169. package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/spyon.js.hbs +2 -0
  170. package/templates/base/tools/testin-nutin/core/index.js.hbs +9 -0
  171. package/templates/base/tools/testin-nutin/core/printer.js.hbs +85 -0
  172. package/templates/base/tools/testin-nutin/core/queue/queue.test.js.hbs +46 -0
  173. package/templates/base/tools/testin-nutin/core/queue/test-discovery.test.js.hbs +46 -0
  174. package/templates/base/tools/testin-nutin/core/queue/test-queue.js.hbs +154 -0
  175. package/templates/{features/testinNutin → base/tools}/testin-nutin/core/tests/assertions.test.js.hbs +27 -0
  176. package/templates/base/tools/testin-nutin/core/tests/clock.test.js.hbs +118 -0
  177. package/templates/base/tools/testin-nutin/core/tests/globals-each-all.test.js.hbs +28 -0
  178. package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/create-mock-method.js.hbs +2 -1
  179. package/templates/base/tools/testin-nutin/mocks/create-mock-method.test.js.hbs +64 -0
  180. package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-event-bus.js.hbs +3 -2
  181. package/templates/base/tools/testin-nutin/mocks/mock-event-bus.test.js.hbs +66 -0
  182. package/templates/base/tools/testin-nutin/mocks/mock-http-client.test.js.hbs +26 -0
  183. package/templates/base/tools/testin-nutin/mocks/mock-i18n.test.js.hbs +61 -0
  184. package/templates/base/tools/testin-nutin/mocks/mock-router.test.js.hbs +29 -0
  185. package/templates/base/tools/testin-nutin/runner.js.hbs +100 -0
  186. package/templates/base/tools/testin-nutin/watch-tests.js.hbs +37 -0
  187. package/templates/base/tools/utils/error-exit.js.hbs +8 -0
  188. package/templates/base/tools/utils/format.js.hbs +10 -10
  189. package/templates/base/tools/utils/format.test.js.hbs +45 -0
  190. package/templates/base/tools/utils/get-files-recursive.js.hbs +6 -1
  191. package/templates/base/tools/utils/get-files-recursive.test.js.hbs +49 -0
  192. package/templates/base/tools/utils/get-rel-to-core.test.js.hbs +18 -0
  193. package/templates/base/tools/utils/index.js.hbs +1 -3
  194. package/templates/base/tools/utils/languages.js.hbs +15 -0
  195. package/templates/base/tools/utils/languages.test.js.hbs +16 -0
  196. package/templates/base/tools/utils/print.js.hbs +19 -13
  197. package/templates/base/tools/utils/print.test.js.hbs +60 -0
  198. package/templates/base/tools/utils/prompt-boolean.js.hbs +7 -0
  199. package/templates/base/tools/utils/prompt-boolean.test.js.hbs +54 -0
  200. package/templates/base/tools/utils/run-command.js.hbs +4 -2
  201. package/templates/base/tools/utils/run-command.test.js.hbs +19 -0
  202. package/templates/base/tools/utils/run-script.js.hbs +14 -3
  203. package/templates/base/tools/utils/run-script.test.js.hbs +40 -0
  204. package/templates/features/{deployHelper → docker}/.dockerignore.hbs +4 -4
  205. package/templates/features/docker/tools/docker/Dockerfile.template.hbs +51 -0
  206. package/templates/features/{deployHelper/tools/deployment/nginx.conf.hbs → docker/tools/docker/nginx.conf.template} +4 -2
  207. package/templates/features/docker/tools/docker/scripts/docker-build.js.hbs +20 -0
  208. package/templates/features/docker/tools/docker/scripts/docker-ports.js.hbs +48 -0
  209. package/templates/features/docker/tools/docker/scripts/docker-ports.test.js.hbs +52 -0
  210. package/templates/features/docker/tools/docker/scripts/docker-run.js.hbs +28 -0
  211. package/templates/features/docker/tools/docker/scripts/render-docker-template.js.hbs +23 -0
  212. package/templates/features/docker/tools/docker/scripts/render-docker-template.test.js.hbs +60 -0
  213. package/templates/features/docker/tools/docker/scripts/validate-docker.js.hbs +30 -0
  214. package/lib/src/context-builder.mjs +0 -40
  215. package/lib/src/file-generator.mjs +0 -109
  216. package/lib/src/json-generator.mjs +0 -31
  217. package/lib/src/package-manager.mjs +0 -139
  218. package/lib/src/print.mjs +0 -32
  219. package/lib/src/utils.mjs +0 -18
  220. package/lib/src/version.mjs +0 -1
  221. package/templates/base/builder.config.js.hbs +0 -36
  222. package/templates/base/src/app/components/common/anchor/anchor.component.ts.hbs +0 -32
  223. package/templates/base/src/app/components/common/button/button.component.ts.hbs +0 -40
  224. package/templates/base/src/app/dom.test.js.hbs +0 -13
  225. package/templates/base/src/app/services/example/example.service.ts.hbs +0 -18
  226. package/templates/base/src/app/views/home/home.view.test.js.hbs +0 -26
  227. package/templates/base/src/core/services/store/store.test.js.hbs +0 -8
  228. package/templates/base/src/core/services/store/store.ts.hbs +0 -39
  229. package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.test.js.hbs +0 -0
  230. package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.ts.hbs +0 -113
  231. package/templates/base/src/core/utils/button-manager/button-manager.utils.test.js.hbs +0 -249
  232. package/templates/base/src/core/utils/button-manager/button-manager.utils.ts.hbs +0 -131
  233. package/templates/base/src/core/utils/helpers/attributes.helper.ts.hbs +0 -50
  234. package/templates/base/src/core/utils/index.ts.hbs +0 -2
  235. package/templates/base/src/libs/index.ts.hbs +0 -4
  236. package/templates/base/src/libs/popover/helpers/focus-trap.helper.ts.hbs +0 -197
  237. package/templates/base/src/libs/popover/helpers/popover-dom.helper.ts.hbs +0 -75
  238. package/templates/base/src/libs/popover/popover.ts.hbs +0 -138
  239. package/templates/base/src/libs/snackbar/snackbar.ts.hbs +0 -75
  240. package/templates/base/src/styles/base/_functions.scss.hbs +0 -9
  241. package/templates/base/src/styles/core/_anchors.scss.hbs +0 -10
  242. package/templates/base/src/styles/core/_index.scss.hbs +0 -6
  243. package/templates/base/src/styles/core/_popover.scss.hbs +0 -96
  244. package/templates/base/src/styles/core/_snackbar.scss.hbs +0 -50
  245. package/templates/base/tools/builder/core/esbuild.js.hbs +0 -25
  246. package/templates/base/tools/builder/core/minify-html.js.hbs +0 -60
  247. package/templates/base/tools/builder/core/sass.js.hbs +0 -22
  248. package/templates/base/tools/builder/core/tsc.js.hbs +0 -12
  249. package/templates/base/tools/generator/templates/service.template.js.hbs +0 -17
  250. package/templates/base/tools/utils/export-flags.js.hbs +0 -6
  251. package/templates/features/deployHelper/tools/builder/core/compress-files.js.hbs +0 -56
  252. package/templates/features/deployHelper/tools/deployment/Dockerfile.hbs +0 -30
  253. package/templates/features/i18n/src/app/views/home/locales/en.json.hbs +0 -9
  254. package/templates/features/i18n/src/app/views/not-found/locales/en.json +0 -8
  255. package/templates/features/i18n/src/app/views/not-found/locales/fr.json +0 -8
  256. package/templates/features/i18n/src/core/config.ts.hbs +0 -3
  257. package/templates/features/i18n/src/core/services/i18n/i18n.test.js.hbs +0 -125
  258. package/templates/features/i18n/tools/generator/templates/json.template.js.hbs +0 -8
  259. package/templates/features/i18n/tools/utils/languages.js.hbs +0 -7
  260. package/templates/features/stylinNutin/src/styles/_custom-classes.scss.hbs +0 -9
  261. package/templates/features/stylinNutin/src/styles/base/_mixins.scss.hbs +0 -372
  262. package/templates/features/stylinNutin/src/styles/components/_index.scss.hbs +0 -3
  263. package/templates/features/stylinNutin/src/styles/core/_utilities.scss.hbs +0 -254
  264. package/templates/features/stylinNutin/src/styles/views/_index.scss.hbs +0 -0
  265. package/templates/features/stylinNutin/tools/generator/templates/scss.template.js.hbs +0 -4
  266. package/templates/features/template/src/app/views/home/home.view.html.hbs +0 -56
  267. package/templates/features/template/src/app/views/not-found/not-found.view.html.hbs +0 -19
  268. package/templates/features/template/tools/builder/core/merge-templates.js.hbs +0 -49
  269. package/templates/features/template/tools/generator/templates/html.template.js.hbs +0 -2
  270. package/templates/features/testinNutin/testin-nutin/core/index.js.hbs +0 -5
  271. package/templates/features/testinNutin/testin-nutin/core/src/utils/print.js.hbs +0 -64
  272. package/templates/features/testinNutin/testin-nutin/core/src/utils/test-queue.js.hbs +0 -64
  273. package/templates/features/testinNutin/testin-nutin/core/tests/globals-each-all.test.js.hbs +0 -28
  274. package/templates/features/testinNutin/testin-nutin/mocks/mock-store.js.hbs +0 -38
  275. package/templates/features/testinNutin/testin-nutin/runner.js.hbs +0 -36
  276. package/templates/features/testinNutin/testin-nutin/watch-tests.js.hbs +0 -21
  277. package/templates/features/testinNutin/testin-nutin.config.js.hbs +0 -14
  278. /package/lib/src/{template-compiler.mjs → common/template-compiler.mjs} +0 -0
  279. /package/templates/{features/i18n → base}/src/core/base-classes/base-component/helpers/i18n.helper.ts.hbs +0 -0
  280. /package/templates/{features/i18n → base}/src/core/services/i18n/languages.ts.hbs +0 -0
  281. /package/templates/base/tools/builder/{variables → core/app}/binary-extensions.js.hbs +0 -0
  282. /package/templates/base/tools/builder/core/{paths.js.hbs → app/paths.js.hbs} +0 -0
  283. /package/templates/{features/testinNutin/testin-nutin/core/src/utils → base/tools/testin-nutin/core/queue}/queue.js.hbs +0 -0
  284. /package/templates/{features/testinNutin/testin-nutin/core/src/utils → base/tools/testin-nutin/core/queue}/test-discovery.js.hbs +0 -0
  285. /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-http-client.js.hbs +0 -0
  286. /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-i18n.js.hbs +0 -0
  287. /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-router.js.hbs +0 -0
@@ -1,86 +1 @@
1
- /*
2
- Variables used in libs (snackbar, popover){{#if stylinNutin}} and utility classes{{/if}}
3
- Adapt to customize
4
- */
5
-
6
- // colours (RGB)
7
- $background-color: rgb(255 255 255); // WHITE
8
- $text-color: rgb(0 0 0); // BLACK
9
- $primary-color: rgb(0 0 0); // BLACK
10
- $secondary-color: rgb(0 0 0); // BLACK
11
- $accent-color: rgb(0 0 0); // BLACK
12
-
13
- // snackbar colours
14
- $snack-success: rgb(76 175 80);
15
- $snack-error: rgb(244 67 54);
16
- $snack-info: rgb(33 150 243);
17
- $snack-default: rgb(153 153 153);
18
-
19
- {{#if stylinNutin}}
20
- /*
21
- Variables used in utility classes
22
- Adapt to customize
23
- */
24
-
25
- // fonts
26
- $primary-font: Arial, Helvetica, sans-serif;
27
- $secondary-font: Arial, Helvetica, sans-serif;
28
-
29
- // font sizes
30
- $font-sizes: (
31
- smallest: 0.75rem, // 12px
32
- small: 0.875rem, // 14px
33
- medium: 1rem, // 16px (base)
34
- large: 1.5rem, // 24px
35
- largest: 2rem, // 32px
36
- );
37
-
38
- // spacing (margin / padding / gap)
39
- $spacings: (
40
- smallest: 0.25rem, // 4px
41
- small: 0.5rem, // 8px
42
- medium: 1rem, // 16px
43
- large: 1.5rem, // 24px
44
- largest: 2rem, // 32px
45
- );
46
-
47
- // border radius
48
- $border-radius: (
49
- small: 2px,
50
- medium: 4px,
51
- large: 8px,
52
- pill: 9999px,
53
- );
54
-
55
- // box sizes
56
- $box-sizes: (
57
- small: 32px,
58
- medium: 64px,
59
- large: 128px,
60
- largest: 256px,
61
- );
62
-
63
- // shadows
64
- $shadows: (
65
- small: 0 1px 2px rgba(0, 0, 0, 0.05),
66
- medium: 0 4px 6px rgba(0, 0, 0, 0.1),
67
- large: 0 10px 15px rgba(0, 0, 0, 0.15),
68
- );
69
-
70
- // breakpoints
71
- $breakpoints: (
72
- small: 576px,
73
- medium: 768px,
74
- large: 992px,
75
- largest: 1201px,
76
- );
77
-
78
- // animations
79
- // transition Duration
80
- $transitions: (
81
- fast: 0.2s,
82
- normal: 0.3s,
83
- slow: 0.5s,
84
- );
85
-
86
- {{/if}}
1
+ // variables
@@ -1,19 +1,2 @@
1
- // Libraries styles (snackbar, popover){{#if transition}}, view transition styles{{/if}}.
2
- @use "core";
3
-
4
- {{#if stylinNutin}}
5
- // built-in classes
6
- @use "utilities";
7
-
8
- {{/if}}
9
- // global styles
1
+ // CSS reset & global styles
10
2
  @use "styles";
11
-
12
- {{#if stylinNutin}}
13
- // custom classes
14
- @use "custom-classes";
15
- // components styles
16
- @use "components";
17
- // views styles
18
- @use "views";
19
- {{/if}}
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss/theme.css" layer(theme);
2
+ @import "tailwindcss/utilities.css" layer(utilities);
@@ -0,0 +1,40 @@
1
+ import process from 'process';
2
+ import nutinConfig from '../../nutin.config.js';
3
+ import { errorExit } from '../utils/index.js';
4
+
5
+ function validateConfig(config) {
6
+ if (!config || typeof config !== 'object') {
7
+ errorExit(new Error('nutin.config.js must export a default object.'), 'builder.config');
8
+ }
9
+ if (!config.builder || typeof config.builder !== 'object') {
10
+ errorExit(new Error('nutin.config.js is missing the required "builder" object.'), 'builder.config');
11
+ }
12
+ if (!Array.isArray(config.builder.sass?.paths)) {
13
+ errorExit(new Error('nutin.config.js is missing "builder.sass.paths" (expected an array).'), 'builder.config');
14
+ }
15
+ if (!config.builder.esbuild || typeof config.builder.esbuild !== 'object') {
16
+ errorExit(new Error('nutin.config.js is missing the required "builder.esbuild" object.'), 'builder.config');
17
+ }
18
+ }
19
+
20
+ validateConfig(nutinConfig);
21
+
22
+ const wellKnownNonSEORoutes = [
23
+ '/400',
24
+ '/401',
25
+ '/403',
26
+ '/404',
27
+ '/500',
28
+ '/502',
29
+ '/503',
30
+ '/504',
31
+ ]
32
+
33
+ export const builderConfig = {
34
+ ...nutinConfig.builder,
35
+ isProd: process.env.NODE_ENV === 'production',
36
+ i18n: nutinConfig.i18n,
37
+ tailwind: nutinConfig.tailwind,
38
+ generateSEO: nutinConfig.generateSEOFiles,
39
+ WELL_KNOWN_NON_SEO_ROUTES: wellKnownNonSEORoutes,
40
+ };
@@ -1,38 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import path from 'path';
4
- import { print, isProd, runScript } from '../utils/index.js';
4
+ import { print, runScript } from '../utils/index.js';
5
+ import { builderConfig } from './builder.config.js';
5
6
 
6
7
  const scriptsDir = path.join(process.cwd(), 'tools', 'builder', 'core');
7
8
 
8
- if (!isProd) print.boldInfo('For production, use build:prod.\n');
9
- print.boldHead(`Starting build...\n`);
10
-
11
- runScript(path.join(scriptsDir, 'copy-static.js'), 'Copying files...');
12
-
13
- if(!isProd) runScript(path.join(scriptsDir, 'tsc.js'), 'Running TypeScript compiler...');
14
-
15
- {{#if template}}
16
- runScript(path.join(scriptsDir, 'merge-templates.js'), 'Merging HTML templates in temp files...');
17
- {{else}}
18
- runScript(path.join(scriptsDir, 'minify-html.js'), 'Minifying inline templates...');
19
- {{/if}}
20
- {{#if i18n}}
21
- runScript(path.join(scriptsDir, 'build-i18n.js'), 'Combining locales for production...');
22
- {{/if}}
23
- runScript(path.join(scriptsDir, 'sass.js'), 'Compiling styles from main.scss...');
24
- runScript(path.join(scriptsDir, 'validate-html.js'), 'Adding and validating tags in index.html...');
25
-
26
- if (isProd) {
27
- runScript(path.join(scriptsDir, 'esbuild.js'), 'Running esbuild...');
28
- runScript(path.join(scriptsDir, 'hash-files.js'), 'Hashing files...');
29
- {{#if deployHelper}}
30
- runScript(path.join(scriptsDir, 'compress-files.js'), 'Compressing files...');
31
- {{/if}}
9
+ print.boldHead(`\nStarting build...`);
10
+
11
+ runScript(path.join(scriptsDir, 'app', 'copy-static.js'), 'Copying files...');
12
+
13
+ runScript(path.join(scriptsDir, 'html-index', 'validate-html.js'), 'Processing index.html...');
14
+ runScript(path.join(scriptsDir, 'app', 'validate-routes.js'), 'Validating app routes...');
15
+
16
+ runScript(path.join(scriptsDir, 'app', 'compile-ts.js'), 'Compiling TypeScript...');
17
+
18
+ runScript(path.join(scriptsDir, 'html-templates', 'process-html-templates.js'), 'Processing HTML templates...');
19
+
20
+ runScript(path.join(scriptsDir, 'styles', 'sass.js'), 'Compiling styles...');
21
+ if (builderConfig.tailwind) runScript(path.join(scriptsDir, 'styles', 'tailwind.js'), 'Compiling Tailwind CSS...');
22
+
23
+ if (builderConfig.i18n) runScript(path.join(scriptsDir, 'i18n', 'build-i18n.js'), 'Combining locales...');
24
+
25
+ if (builderConfig.isProd) {
26
+ runScript(path.join(scriptsDir, 'prod-bundle', 'esbuild.js'), 'Running esbuild...');
27
+ runScript(path.join(scriptsDir, 'prod-bundle', 'hash-files.js'), 'Hashing files...');
28
+ runScript(path.join(scriptsDir, 'prod-bundle', 'compress-files.js'), 'Compressing files...');
29
+ if (builderConfig.generateSEO) runScript(path.join(scriptsDir, 'seo', 'generate-seo-files.js'), 'Generating SEO Files...');
32
30
  }
33
31
 
34
32
  runScript(path.join(scriptsDir, 'finalize-build.js'), 'Finalizing build...')
35
33
 
36
34
  print.boldSuccess(`\nBuild successful!\n`);
37
35
 
38
- if (!isProd) print.boldInfo('For production, use build:prod.');
36
+ if (!builderConfig.isProd) print.info('For production, use "{{packageManager}} run build:prod"');
@@ -0,0 +1,16 @@
1
+ import { BINARY_EXTENSIONS } from './binary-extensions.js';
2
+
3
+ describe('BINARY_EXTENSIONS', () => {
4
+ it('is a Set containing common binary asset extensions', () => {
5
+ expect(BINARY_EXTENSIONS).toBeInstanceOf(Set);
6
+ expect(BINARY_EXTENSIONS.has('.png')).toBeTruthy();
7
+ expect(BINARY_EXTENSIONS.has('.woff2')).toBeTruthy();
8
+ expect(BINARY_EXTENSIONS.has('.gz')).toBeTruthy();
9
+ });
10
+
11
+ it('does not treat text/source extensions as binary', () => {
12
+ expect(BINARY_EXTENSIONS.has('.js')).toBeFalsy();
13
+ expect(BINARY_EXTENSIONS.has('.css')).toBeFalsy();
14
+ expect(BINARY_EXTENSIONS.has('.html')).toBeFalsy();
15
+ });
16
+ });
@@ -0,0 +1,16 @@
1
+ import { runCommand, print, errorExit } from "../../../utils/index.js";
2
+ import { builderConfig } from '../../builder.config.js';
3
+
4
+ async function compileTS() {
5
+ // Prod bundles straight from .ts source (see prod-bundle/esbuild.js), so tsc only
6
+ // needs to type-check there, not emit — emitting would leave a stale, unmerged .js
7
+ // sibling next to each merged .ts view/component's source.
8
+ const args = ['--project', 'tsconfig.json'];
9
+ if (builderConfig.isProd) args.push('--noEmit');
10
+
11
+ await runCommand('tsc', args);
12
+ }
13
+
14
+ compileTS().catch((err) => {
15
+ errorExit(err, 'compile-ts');
16
+ });
@@ -1,22 +1,23 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
- import { exit } from 'process';
4
- import { getFilesRecursive, print, isVerbose, isProd } from '../../utils/index.js';
5
- import { BINARY_EXTENSIONS } from '../variables/binary-extensions.js';
3
+ import { getFilesRecursive, print, errorExit } from '../../../utils/index.js';
4
+ import { BINARY_EXTENSIONS } from './binary-extensions.js';
6
5
  import { PATHS } from './paths.js';
6
+ import { builderConfig } from '../../builder.config.js';
7
7
 
8
8
  async function copyStatic() {
9
- const extensions = [...BINARY_EXTENSIONS, 'html'];
10
- if (isProd) extensions.push('.ts');
11
-
12
- if (isVerbose) print.info(`File types that will be copied: ${Array.from(extensions)}`);
13
-
9
+ const extensions = [...BINARY_EXTENSIONS, '.html'];
10
+ if (builderConfig.isProd) extensions.push('.ts');
11
+
12
+ // Every build starts from a clean dist-build: a failed/interrupted prior
13
+ // build never gets renamed away by finalize-build.js, so a stale sibling
14
+ // (already merged, placeholder gone) can otherwise sit next to the next
15
+ // run's fresh output and trip merge-templates.js's per-sibling check.
16
+ await fs.rm(PATHS.temp, { recursive: true, force: true });
14
17
  await ensureDir(PATHS.tempSource);
15
18
 
16
19
  await copyFavicon();
17
- {{#if i18n}}
18
20
  await copyConfig();
19
- {{/if}}
20
21
 
21
22
  for (const extension of extensions) {
22
23
  const files = await getFilesRecursive(PATHS.source, extension);
@@ -27,17 +28,13 @@ async function copyStatic() {
27
28
 
28
29
  try {
29
30
  await copyFile(file, dest);
30
- if (isVerbose) print.info(`✅ Copied: ${file} → ${dest}`);
31
31
  } catch (err) {
32
- print.error(`❌ Failed to copy: ${file}. ${err.message}`);
33
- exit(1);
32
+ throw new Error(`Failed to copy: ${file}. ${err.message}`, { cause: err });
34
33
  }
35
34
  }
36
35
  }
37
36
 
38
- if (isProd) await copyJsonFiles(PATHS.source, PATHS.tempSource);
39
-
40
- if (isVerbose) print.boldInfo(`Copy complete.\n`);
37
+ if (builderConfig.isProd) await copyJsonFiles(PATHS.source, PATHS.tempSource);
41
38
  }
42
39
 
43
40
  async function ensureDir(dir) {
@@ -55,33 +52,31 @@ async function copyFavicon() {
55
52
 
56
53
  try {
57
54
  await copyFile(srcPath, destPath);
58
- if (isVerbose) print.info('Copied: favicon.ico');
59
- } catch {
60
- print.boldError('⚠️ No favicon found at public/favicon.ico');
55
+ } catch (err) {
56
+ if (err.code === 'ENOENT') print.warn('No favicon found at public/favicon.ico');
57
+ else errorExit(err, 'copy-static');
61
58
  }
62
59
  }
63
60
 
64
- {{#if i18n}}
65
61
  async function copyConfig() {
66
62
  const srcPath = path.resolve(path.join('config'));
67
- const temp = isProd ? PATHS.temp : PATHS.tempSource;
63
+ const temp = builderConfig.isProd ? PATHS.temp : PATHS.tempSource;
68
64
  const destPath = path.join(temp, 'config');
69
65
  try {
70
66
  await copyJsonFiles(srcPath, destPath);
71
- {{#if testinNutin}}
72
- // for tests to run
73
- if (!isProd) await copyJsonFiles(srcPath, path.join(PATHS.temp, 'config'))
74
- {{/if}}
75
- if (isVerbose) print.info('Config files copied');
76
- } catch {
77
- print.boldError('Issue when copying config files.');
78
- exit(1);
67
+ await copyFile(path.resolve('nutin.config.js'), path.join(temp, 'nutin.config.js'));
68
+
69
+ // for testin-nutin tests to run
70
+ if (!builderConfig.isProd) {
71
+ await copyJsonFiles(srcPath, path.join(PATHS.temp, 'config'));
72
+ await copyFile(path.resolve('nutin.config.js'), path.join(PATHS.temp, 'nutin.config.js'));
73
+ }
74
+ } catch (err) {
75
+ errorExit(err, 'copy-static');
79
76
  }
80
77
  }
81
78
 
82
- {{/if}}
83
79
  async function copyJsonFiles(sourceDir, destDir) {
84
-
85
80
  const items = await fs.readdir(sourceDir, { withFileTypes: true });
86
81
 
87
82
  for (const item of items) {
@@ -93,12 +88,10 @@ async function copyJsonFiles(sourceDir, destDir) {
93
88
  } else if (item.isFile() && path.extname(item.name) === '.json') {
94
89
  await fs.mkdir(path.dirname(destPath), { recursive: true });
95
90
  await fs.copyFile(sourcePath, destPath);
96
- if (isVerbose) print.info(`Copied JSON: ${sourcePath} -> ${destPath}`);
97
91
  }
98
92
  }
99
93
  }
100
94
 
101
95
  copyStatic().catch((err) => {
102
- print.boldError(`Unexpected error: ${err.message}`);
103
- exit(1);
96
+ errorExit(err, 'copy-static');
104
97
  });
@@ -0,0 +1,77 @@
1
+ import { readFileSync } from 'fs';
2
+ import path from 'path';
3
+ import ts from 'typescript';
4
+ import { print, errorExit } from '../../../utils/index.js';
5
+ import { PATHS } from './paths.js';
6
+
7
+ const ROUTES_FILE = path.join(PATHS.sourceApp, 'routes.ts');
8
+
9
+ function findAppRoutesObjectLiteral(sourceFile) {
10
+ let objectLiteral;
11
+
12
+ ts.forEachChild(sourceFile, function visit(node) {
13
+ if (
14
+ ts.isVariableDeclaration(node) &&
15
+ ts.isIdentifier(node.name) &&
16
+ node.name.text === 'appRoutes' &&
17
+ node.initializer &&
18
+ ts.isObjectLiteralExpression(node.initializer)
19
+ ) {
20
+ objectLiteral = node.initializer;
21
+ return;
22
+ }
23
+ ts.forEachChild(node, visit);
24
+ });
25
+
26
+ return objectLiteral;
27
+ }
28
+
29
+ function getRouteKeys(objectLiteral) {
30
+ return objectLiteral.properties
31
+ .filter((prop) => ts.isPropertyAssignment(prop) && ts.isStringLiteralLike(prop.name))
32
+ .map((prop) => prop.name.text);
33
+ }
34
+
35
+ function findDuplicates(keys) {
36
+ const seen = new Set();
37
+ const duplicates = new Set();
38
+
39
+ for (const key of keys) {
40
+ if (seen.has(key)) duplicates.add(key);
41
+ seen.add(key);
42
+ }
43
+
44
+ return [...duplicates];
45
+ }
46
+
47
+ function validateRoutes() {
48
+ let source;
49
+ try {
50
+ source = readFileSync(ROUTES_FILE, 'utf-8');
51
+ } catch {
52
+ errorExit(`Failed to read ${ROUTES_FILE}`);
53
+ }
54
+
55
+ const sourceFile = ts.createSourceFile(ROUTES_FILE, source, ts.ScriptTarget.Latest, true);
56
+ const objectLiteral = findAppRoutesObjectLiteral(sourceFile);
57
+
58
+ if (!objectLiteral) {
59
+ errorExit(`Could not find an "appRoutes" object literal in ${ROUTES_FILE}`);
60
+ }
61
+
62
+ const duplicates = findDuplicates(getRouteKeys(objectLiteral));
63
+
64
+ if (duplicates.length > 0) {
65
+ const list = duplicates.map((key) => `"${key}"`).join(', ');
66
+ errorExit(
67
+ `Duplicate route key(s) in ${ROUTES_FILE}: ${list} — an earlier route with this path is silently unreachable.`
68
+ );
69
+ }
70
+
71
+ }
72
+
73
+ try {
74
+ validateRoutes();
75
+ } catch(err) {
76
+ errorExit(err, 'validate-routes');
77
+ }
@@ -1,19 +1,24 @@
1
- import { print, isProd, isVerbose } from "../../utils/index.js";
2
1
  import fs from 'fs';
3
2
  import path from 'path';
4
- import { PATHS } from "./paths.js";
3
+ import { PATHS } from "./app/paths.js";
4
+ import { builderConfig } from '../builder.config.js';
5
+ import { print, errorExit } from "../../utils/index.js";
5
6
 
6
7
  function finalizeBuild() {
7
- if (isProd) removeFoldersAfterBundle();
8
+ if (builderConfig.isProd) removeFoldersAfterBundle();
9
+ if (builderConfig.isProd) removeNutinConfig();
8
10
  replaceDir(PATHS.temp, PATHS.build);
9
- if (isVerbose) print.boldInfo('Build finalized.\n');
10
11
  }
11
12
 
12
13
  function removeFoldersAfterBundle() {
13
- const foldersToRemove = ['core', 'libs', 'app'];
14
+ const foldersToRemove = [ 'core', 'app', path.join('..', 'config') ];
14
15
  const pathToFolder = (folder) => path.join(PATHS.tempSource, folder);
15
16
 
16
- foldersToRemove.forEach(folder => fs.rmSync(pathToFolder(folder), { recursive : true }));
17
+ foldersToRemove.forEach(folder => fs.rmSync(pathToFolder(folder), { recursive: true, force: true }));
18
+ }
19
+
20
+ function removeNutinConfig() {
21
+ fs.rmSync(path.join(PATHS.temp, 'nutin.config.js'));
17
22
  }
18
23
 
19
24
  function replaceDir(src, dest) {
@@ -21,4 +26,8 @@ function replaceDir(src, dest) {
21
26
  fs.renameSync(src, dest);
22
27
  }
23
28
 
24
- finalizeBuild();
29
+ try {
30
+ finalizeBuild();
31
+ } catch(err) {
32
+ errorExit(err, 'finalize-build')
33
+ }
@@ -1,8 +1,8 @@
1
- import { print, isProd } from '../../utils/index.js';
2
1
  import { writeFile } from 'fs/promises';
2
+ import { builderConfig } from '../../builder.config.js';
3
3
 
4
4
  export async function addTags(htmlContent, filePath) {
5
- const scriptSrc = isProd ? "bundle.js" : "app/main.js";
5
+ const scriptSrc = builderConfig.isProd ? "bundle.js" : "app/main.js";
6
6
 
7
7
  const tags = [
8
8
  { type: 'stylesheet', href: 'main.css', position: 'head' },
@@ -0,0 +1,56 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { addTags } from './add-tags.js';
5
+
6
+ describe('addTags', () => {
7
+ let tmpDir;
8
+ let filePath;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'nutin-add-tags-'));
12
+ filePath = path.join(tmpDir, 'index.html');
13
+ });
14
+
15
+ afterEach(() => {
16
+ fs.rmSync(tmpDir, { recursive: true, force: true });
17
+ });
18
+
19
+ it('inserts the stylesheet before </head> and the script before </body>', async () => {
20
+ const html = '<html><head><title>T</title></head><body></body></html>';
21
+
22
+ const result = await addTags(html, filePath);
23
+
24
+ expect(result).toBe(
25
+ '<html><head><title>T</title><link rel="stylesheet" href="/main.css"></head><body><script type="module" src="/app/main.js"></script></body></html>'
26
+ );
27
+ });
28
+
29
+ it('falls back to inserting the stylesheet before <title> when there is no </head>', async () => {
30
+ const html = '<html><title>T</title><body></body></html>';
31
+
32
+ const result = await addTags(html, filePath);
33
+
34
+ expect(result).toBe(
35
+ '<html><link rel="stylesheet" href="/main.css"><title>T</title><body><script type="module" src="/app/main.js"></script></body></html>'
36
+ );
37
+ });
38
+
39
+ it('appends both tags to the end when neither anchor is present', async () => {
40
+ const html = '<html></html>';
41
+
42
+ const result = await addTags(html, filePath);
43
+
44
+ expect(result).toBe(
45
+ '<html></html><link rel="stylesheet" href="/main.css"><script type="module" src="/app/main.js"></script>'
46
+ );
47
+ });
48
+
49
+ it('writes the modified html to filePath', async () => {
50
+ const html = '<html><head></head><body></body></html>';
51
+
52
+ const result = await addTags(html, filePath);
53
+
54
+ expect(fs.readFileSync(filePath, 'utf8')).toBe(result);
55
+ });
56
+ });
@@ -1,8 +1,7 @@
1
1
  import { readFile } from 'fs/promises';
2
- import { exit } from 'process';
3
- import { print, isVerbose } from '../../utils/index.js';
4
- import { PATHS } from './paths.js';
5
2
  import path from 'path';
3
+ import { print, errorExit } from '../../../utils/index.js';
4
+ import { PATHS } from '../app/paths.js';
6
5
  import { addTags } from './add-tags.js';
7
6
 
8
7
  async function validateHtml() {
@@ -27,13 +26,8 @@ async function validateHtml() {
27
26
  if (!/<link[^>]*rel=["']stylesheet["']/.test(htmlContent)) {
28
27
  errorExit('No stylesheet found in HTML');
29
28
  }
30
-
31
- if (isVerbose) print.boldInfo('HTML validation passed\n');
32
- }
33
-
34
- function errorExit(message) {
35
- print.boldError(`[ERROR] ${message}`);
36
- exit(1);
37
29
  }
38
30
 
39
- validateHtml();
31
+ validateHtml().catch((err) => {
32
+ errorExit(err, 'validate-html');
33
+ });