@team-codeme/crud-forge 0.0.0-stage → 1.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 (415) hide show
  1. package/.cursor/agents/generator-engineer.md +31 -0
  2. package/.cursor/agents/keycloak-engineer.md +33 -0
  3. package/.cursor/agents/qa-engineer.md +32 -0
  4. package/.cursor/agents/security-reviewer.md +30 -0
  5. package/.cursor/mcp.json +13 -0
  6. package/.cursor/rules/crudforge-precautions.mdc +16 -0
  7. package/.cursor/rules/playwright-browser.mdc +30 -0
  8. package/.cursor/rules/readme-todo-sync.mdc +13 -0
  9. package/.env.qa.example +19 -0
  10. package/.github/workflows/qa-live.yml +32 -0
  11. package/.github/workflows/qa.yml +27 -0
  12. package/.vscode/settings.json +32 -0
  13. package/QA/IAM-PLAN.md +25 -0
  14. package/QA/IAM-RESULTS.md +39 -0
  15. package/QA/IAM-TESTCASES.md +36 -0
  16. package/QA/IAM-TODO.md +7 -0
  17. package/QA/KEYCLOAK-BOOTSTRAP.md +105 -0
  18. package/QA/PLAN.md +43 -0
  19. package/QA/RESULTS.md +59 -0
  20. package/QA/TESTCASES.md +65 -0
  21. package/QA/TODO.md +14 -0
  22. package/QA/pmb-dev/README.md +49 -0
  23. package/QA/pmb-dev/config/config.yml +152 -0
  24. package/QA/pmb-dev/gdl/i.gdl +17 -0
  25. package/README.md +851 -2
  26. package/Todo.md +207 -0
  27. package/assets/branding/crudforge-logo.png +0 -0
  28. package/assets/branding/crudforge-mark.png +0 -0
  29. package/branding/poster-crudforge.jpg +0 -0
  30. package/chat/last-chat/Investigating Mock Data Configuration.md +428 -0
  31. package/cli.js +167 -0
  32. package/config/default-config.yml +245 -0
  33. package/docs/performance/README.md +217 -0
  34. package/docs/performance/after.json +111 -0
  35. package/docs/performance/before.json +111 -0
  36. package/docs/quality/README.md +276 -0
  37. package/e2e/crudforge.e2e.yml +47 -0
  38. package/e2e/crudforge.field-profile.yml +33 -0
  39. package/e2e/crudforge.iam-live.yml +124 -0
  40. package/e2e/crudforge.iam.yml +62 -0
  41. package/e2e/tests/field-profile.spec.js +152 -0
  42. package/e2e/tests/generated-crud.spec.js +251 -0
  43. package/e2e/tests/iam-live.spec.js +149 -0
  44. package/e2e/tests/iam-pack.spec.js +151 -0
  45. package/e2e/tests/list-state.spec.js +73 -0
  46. package/features.csv +27 -0
  47. package/fuse-starter-pack/branding/crudforge-mark-source.jpg +0 -0
  48. package/fuse-starter-pack/branding/crudforge-mark-source.png +0 -0
  49. package/fuse-starter-pack/branding/crudforge-mark.png +0 -0
  50. package/fuse-starter-pack/branding/crudforge-wordmark-source.jpg +0 -0
  51. package/fuse-starter-pack/branding/crudforge-wordmark-source.png +0 -0
  52. package/fuse-starter-pack/branding/crudforge-wordmark.png +0 -0
  53. package/fuse-starter-pack/fuse-v21.1/Dockerfile +14 -0
  54. package/fuse-starter-pack/fuse-v21.1/LICENSE.md +6 -0
  55. package/fuse-starter-pack/fuse-v21.1/README.md +59 -0
  56. package/fuse-starter-pack/fuse-v21.1/angular.json +113 -0
  57. package/fuse-starter-pack/fuse-v21.1/eslint.config.ts +150 -0
  58. package/fuse-starter-pack/fuse-v21.1/nginx.conf +23 -0
  59. package/fuse-starter-pack/fuse-v21.1/nginx.dev.conf +18 -0
  60. package/fuse-starter-pack/fuse-v21.1/package-lock.json +11513 -0
  61. package/fuse-starter-pack/fuse-v21.1/package.json +69 -0
  62. package/fuse-starter-pack/fuse-v21.1/postcss.config.json +5 -0
  63. package/fuse-starter-pack/fuse-v21.1/prettier.config.ts +15 -0
  64. package/fuse-starter-pack/fuse-v21.1/proxy.conf.json +8 -0
  65. package/fuse-starter-pack/fuse-v21.1/proxy.dev.conf.json +8 -0
  66. package/fuse-starter-pack/fuse-v21.1/public/favicon.png +0 -0
  67. package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/Geist-Italic.woff2 +0 -0
  68. package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/Geist.woff2 +0 -0
  69. package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/GeistMono-Italic.woff2 +0 -0
  70. package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/GeistMono.woff2 +0 -0
  71. package/fuse-starter-pack/fuse-v21.1/public/i18n/en.json +8 -0
  72. package/fuse-starter-pack/fuse-v21.1/public/i18n/es.json +8 -0
  73. package/fuse-starter-pack/fuse-v21.1/public/images/flags/ES.svg +79 -0
  74. package/fuse-starter-pack/fuse-v21.1/public/images/flags/US.svg +14 -0
  75. package/fuse-starter-pack/fuse-v21.1/public/images/flags/where-to-find-other-flags.txt +5 -0
  76. package/fuse-starter-pack/fuse-v21.1/public/images/logo/logo-mark.png +0 -0
  77. package/fuse-starter-pack/fuse-v21.1/public/images/logo/logo.png +0 -0
  78. package/fuse-starter-pack/fuse-v21.1/push.sh +27 -0
  79. package/fuse-starter-pack/fuse-v21.1/src/app/app.config.server.ts +10 -0
  80. package/fuse-starter-pack/fuse-v21.1/src/app/app.config.ts +64 -0
  81. package/fuse-starter-pack/fuse-v21.1/src/app/app.routes.server.ts +8 -0
  82. package/fuse-starter-pack/fuse-v21.1/src/app/app.routes.ts +39 -0
  83. package/fuse-starter-pack/fuse-v21.1/src/app/app.ts +22 -0
  84. package/fuse-starter-pack/fuse-v21.1/src/app/core/icons/index.ts +1 -0
  85. package/fuse-starter-pack/fuse-v21.1/src/app/core/icons/lucide.ts +1 -0
  86. package/fuse-starter-pack/fuse-v21.1/src/app/core/icons/provider.ts +23 -0
  87. package/fuse-starter-pack/fuse-v21.1/src/app/core/local-storage/index.ts +2 -0
  88. package/fuse-starter-pack/fuse-v21.1/src/app/core/local-storage/local-storage.ts +109 -0
  89. package/fuse-starter-pack/fuse-v21.1/src/app/core/local-storage/provider.ts +15 -0
  90. package/fuse-starter-pack/fuse-v21.1/src/app/core/media/index.ts +2 -0
  91. package/fuse-starter-pack/fuse-v21.1/src/app/core/media/media.ts +64 -0
  92. package/fuse-starter-pack/fuse-v21.1/src/app/core/media/provider.ts +15 -0
  93. package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/index.ts +3 -0
  94. package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/models/theming.ts +13 -0
  95. package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/palette.ts +209 -0
  96. package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/provider.ts +24 -0
  97. package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/theming.ts +129 -0
  98. package/fuse-starter-pack/fuse-v21.1/src/app/core/transloco/transloco-http-loader.ts +12 -0
  99. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/data/navigation.ts +176 -0
  100. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/layout.ts +77 -0
  101. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/language-switcher.ts +91 -0
  102. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/navigation.ts +238 -0
  103. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/notifications.ts +252 -0
  104. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/scheme-switcher.ts +58 -0
  105. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/sidebar.ts +31 -0
  106. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/user.ts +132 -0
  107. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/data/academy.ts +753 -0
  108. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/data/model.ts +27 -0
  109. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/features/course.ts +318 -0
  110. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/features/courses.ts +228 -0
  111. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/routes.ts +14 -0
  112. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/data/contacts.ts +4372 -0
  113. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/data/model.ts +34 -0
  114. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/features/contact.ts +239 -0
  115. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/features/contacts.ts +185 -0
  116. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/routes.ts +16 -0
  117. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/data/file-manager.ts +261 -0
  118. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/data/model.ts +12 -0
  119. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/features/file-manager.ts +131 -0
  120. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/routes.ts +15 -0
  121. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/ui/list.ts +164 -0
  122. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/faq.ts +288 -0
  123. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/guide.ts +134 -0
  124. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/home.ts +219 -0
  125. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/support.ts +161 -0
  126. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/routes.ts +33 -0
  127. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/data/model.ts +18 -0
  128. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/data/notes.ts +324 -0
  129. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/features/note.ts +152 -0
  130. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/features/notes.ts +118 -0
  131. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/routes.ts +16 -0
  132. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/data/model.ts +17 -0
  133. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/data/tasks.ts +562 -0
  134. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/features/task.ts +195 -0
  135. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/features/tasks.ts +271 -0
  136. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/routes.ts +16 -0
  137. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/data/analytics.ts +1620 -0
  138. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/data/finance.ts +1065 -0
  139. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/data/project.ts +376 -0
  140. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/analytics/analytics.ts +1096 -0
  141. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/finance/finance.ts +658 -0
  142. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/project/budget-table.ts +188 -0
  143. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/project/project.ts +565 -0
  144. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/routes.ts +23 -0
  145. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/changelog/changelog.ts +932 -0
  146. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/getting-started/building.ts +33 -0
  147. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/getting-started/development.ts +42 -0
  148. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/getting-started/installation.ts +47 -0
  149. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/layout.ts +9 -0
  150. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/routes.ts +45 -0
  151. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/error/features/error-page.ts +70 -0
  152. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/error/routes.ts +21 -0
  153. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/notifications/features/notifications.ts +262 -0
  154. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/notifications/routes.ts +10 -0
  155. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/account.ts +238 -0
  156. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/notifications.ts +134 -0
  157. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/plan-and-billing.ts +238 -0
  158. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/security.ts +211 -0
  159. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/team.ts +188 -0
  160. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/layout.ts +109 -0
  161. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/routes.ts +37 -0
  162. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/welcome/welcome.component.ts +22 -0
  163. package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/routes.ts +95 -0
  164. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/forgot-password/forgot-password.html +54 -0
  165. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/forgot-password/forgot-password.ts +51 -0
  166. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/reset-password/reset-password.html +82 -0
  167. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/reset-password/reset-password.ts +69 -0
  168. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-in/sign-in.html +132 -0
  169. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-in/sign-in.ts +54 -0
  170. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-up/sign-up.html +183 -0
  171. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-up/sign-up.ts +56 -0
  172. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/layout.ts +9 -0
  173. package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/routes.ts +34 -0
  174. package/fuse-starter-pack/fuse-v21.1/src/app/domains/coming-soon/features/coming-soon.ts +156 -0
  175. package/fuse-starter-pack/fuse-v21.1/src/app/domains/coming-soon/layout.ts +9 -0
  176. package/fuse-starter-pack/fuse-v21.1/src/app/domains/coming-soon/routes.ts +16 -0
  177. package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/layout/layout.ts +9 -0
  178. package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/modules/home/features/home.ts +23 -0
  179. package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/modules/home/routes.ts +10 -0
  180. package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/routes.ts +30 -0
  181. package/fuse-starter-pack/fuse-v21.1/src/environments/environment.mock.ts +5 -0
  182. package/fuse-starter-pack/fuse-v21.1/src/environments/environment.prod.ts +5 -0
  183. package/fuse-starter-pack/fuse-v21.1/src/environments/environment.ts +5 -0
  184. package/fuse-starter-pack/fuse-v21.1/src/index.html +66 -0
  185. package/fuse-starter-pack/fuse-v21.1/src/main.server.ts +11 -0
  186. package/fuse-starter-pack/fuse-v21.1/src/main.ts +5 -0
  187. package/fuse-starter-pack/fuse-v21.1/src/server.ts +70 -0
  188. package/fuse-starter-pack/fuse-v21.1/src/styles/base/base.css +63 -0
  189. package/fuse-starter-pack/fuse-v21.1/src/styles/base/typography.css +54 -0
  190. package/fuse-starter-pack/fuse-v21.1/src/styles/components/a.css +18 -0
  191. package/fuse-starter-pack/fuse-v21.1/src/styles/components/input.css +22 -0
  192. package/fuse-starter-pack/fuse-v21.1/src/styles/components/kbd.css +55 -0
  193. package/fuse-starter-pack/fuse-v21.1/src/styles/components/material.css +1149 -0
  194. package/fuse-starter-pack/fuse-v21.1/src/styles/styles.css +31 -0
  195. package/fuse-starter-pack/fuse-v21.1/src/styles/tailwind/theme.css +147 -0
  196. package/fuse-starter-pack/fuse-v21.1/src/styles/tailwind/utilities.css +563 -0
  197. package/fuse-starter-pack/fuse-v21.1/src/styles/tailwind/variants.css +4 -0
  198. package/fuse-starter-pack/fuse-v21.1/src/styles/third-party/lucide-icons.css +12 -0
  199. package/fuse-starter-pack/fuse-v21.1/tsconfig.app.json +16 -0
  200. package/fuse-starter-pack/fuse-v21.1/tsconfig.json +37 -0
  201. package/fuse-starter-pack/fuse-v21.1/tsconfig.spec.json +10 -0
  202. package/generator/README.md +12 -0
  203. package/generator/issues/.gitkeep +0 -0
  204. package/package.json +56 -4
  205. package/playwright.config.js +29 -0
  206. package/playwright.field-profile.config.js +6 -0
  207. package/playwright.iam-live.config.js +31 -0
  208. package/playwright.iam.config.js +29 -0
  209. package/playwright.list-state.config.js +6 -0
  210. package/playwright.performance.config.js +1 -0
  211. package/run-config-tests.sh +5 -0
  212. package/scripts/e2e-paths.js +89 -0
  213. package/scripts/e2e-prepare-field-profile.js +17 -0
  214. package/scripts/e2e-prepare-iam-live.js +135 -0
  215. package/scripts/e2e-prepare-iam.js +65 -0
  216. package/scripts/e2e-prepare.js +72 -0
  217. package/scripts/e2e-serve-iam-live.js +28 -0
  218. package/scripts/e2e-serve-iam.js +28 -0
  219. package/scripts/e2e-serve.js +28 -0
  220. package/scripts/performance/generate.js +17 -0
  221. package/scripts/performance/measure.js +55 -0
  222. package/scripts/postinstall.js +9 -0
  223. package/scripts/prepare-quality-apps.js +34 -0
  224. package/scripts/run-config-tests.js +63 -0
  225. package/src/assets/logo-with-lable.jpeg +0 -0
  226. package/src/assets/logo.jpeg +0 -0
  227. package/src/commands/bootstrap.js +92 -0
  228. package/src/commands/doctor.js +403 -0
  229. package/src/commands/generate.js +301 -0
  230. package/src/commands/init-config.js +310 -0
  231. package/src/commands/keycloak-options.js +182 -0
  232. package/src/commands/validate.js +52 -0
  233. package/src/config/auth-config.js +183 -0
  234. package/src/config/default-values.js +235 -0
  235. package/src/config/env-refs.js +71 -0
  236. package/src/config/field-preferences.js +99 -0
  237. package/src/config/input-sources.js +104 -0
  238. package/src/config/load-config.js +166 -0
  239. package/src/config/proxy-routes.js +44 -0
  240. package/src/generator/access-control-tools.js +334 -0
  241. package/src/generator/ai-docs.js +691 -0
  242. package/src/generator/application-tests.js +252 -0
  243. package/src/generator/auth-pack.js +965 -0
  244. package/src/generator/embed-config.js +431 -0
  245. package/src/generator/entity-layout.js +30 -0
  246. package/src/generator/fuse-build.js +57 -0
  247. package/src/generator/fuse-runtime.js +344 -0
  248. package/src/generator/generated-banner.js +137 -0
  249. package/src/generator/index.js +874 -0
  250. package/src/generator/project-output.js +126 -0
  251. package/src/generator/team-pack.js +220 -0
  252. package/src/index.js +68 -0
  253. package/src/parser/gdl-parser.js +169 -0
  254. package/src/parser/jdl-parser.js +171 -0
  255. package/src/presets/pmb-test.js +139 -0
  256. package/src/presets/static-source.js +73 -0
  257. package/src/presets/store.js +96 -0
  258. package/src/provision/admin-service.js +148 -0
  259. package/src/provision/bootstrap.js +147 -0
  260. package/src/provision/http.js +123 -0
  261. package/src/provision/keycloak-admin-rest.js +335 -0
  262. package/src/provision/state.js +51 -0
  263. package/src/provision/token.js +52 -0
  264. package/src/templates/angular/auth/access-control.service.ts.ejs +179 -0
  265. package/src/templates/angular/auth/access-ctrl.pipe.ts.ejs +20 -0
  266. package/src/templates/angular/auth/auth.guard.ts.ejs +27 -0
  267. package/src/templates/angular/auth/auth.interceptor.ts.ejs +53 -0
  268. package/src/templates/angular/auth/auth.service.ts.ejs +594 -0
  269. package/src/templates/angular/auth/auth.utils.ts.ejs +28 -0
  270. package/src/templates/angular/auth/current-user.ts.ejs +24 -0
  271. package/src/templates/angular/auth/disabled-account-overlay.component.css.ejs +95 -0
  272. package/src/templates/angular/auth/disabled-account-overlay.component.html.ejs +33 -0
  273. package/src/templates/angular/auth/disabled-account-overlay.component.ts.ejs +23 -0
  274. package/src/templates/angular/auth/fuse-account.ts.ejs +234 -0
  275. package/src/templates/angular/auth/fuse-user.ts.ejs +264 -0
  276. package/src/templates/angular/auth/has-permission.directive.ts.ejs +51 -0
  277. package/src/templates/angular/auth/index.ts.ejs +24 -0
  278. package/src/templates/angular/auth/keycloak-admin.service.ts.ejs +670 -0
  279. package/src/templates/angular/auth/landing.guard.ts.ejs +61 -0
  280. package/src/templates/angular/auth/no-auth.guard.ts.ejs +19 -0
  281. package/src/templates/angular/auth/permission-attribute.util.ts.ejs +182 -0
  282. package/src/templates/angular/auth/sign-in.ts.ejs +60 -0
  283. package/src/templates/angular/entity/_entity_.model.ts.ejs +64 -0
  284. package/src/templates/angular/entity/_entity_.routes.ts.ejs +9 -0
  285. package/src/templates/angular/entity/components/forms/form/_entity_-form.component.html.ejs +168 -0
  286. package/src/templates/angular/entity/components/forms/form/_entity_-form.component.ts.ejs +175 -0
  287. package/src/templates/angular/entity/components/forms/form-page/_entity_-form-page.component.html.ejs +10 -0
  288. package/src/templates/angular/entity/components/forms/form-page/_entity_-form-page.component.ts.ejs +86 -0
  289. package/src/templates/angular/entity/components/forms/update/_entity_-form.service.ts.ejs +136 -0
  290. package/src/templates/angular/entity/components/interaction/actions/_entity_-actions.component.html.ejs +68 -0
  291. package/src/templates/angular/entity/components/interaction/actions/_entity_-actions.component.ts.ejs +69 -0
  292. package/src/templates/angular/entity/components/interaction/filter/_entity_-filter.component.html.ejs +111 -0
  293. package/src/templates/angular/entity/components/interaction/filter/_entity_-filter.component.ts.ejs +102 -0
  294. package/src/templates/angular/entity/components/presentation/card/_entity_-card.component.css.ejs +33 -0
  295. package/src/templates/angular/entity/components/presentation/card/_entity_-card.component.html.ejs +29 -0
  296. package/src/templates/angular/entity/components/presentation/card/_entity_-card.component.ts.ejs +93 -0
  297. package/src/templates/angular/entity/components/presentation/detail/_entity_-detail.component.css.ejs +54 -0
  298. package/src/templates/angular/entity/components/presentation/detail/_entity_-detail.component.html.ejs +58 -0
  299. package/src/templates/angular/entity/components/presentation/detail/_entity_-detail.component.ts.ejs +47 -0
  300. package/src/templates/angular/entity/components/presentation/list/_entity_-list.component.html.ejs +419 -0
  301. package/src/templates/angular/entity/components/presentation/list/_entity_-list.component.scss.ejs +48 -0
  302. package/src/templates/angular/entity/components/presentation/list/_entity_-list.component.ts.ejs +592 -0
  303. package/src/templates/angular/entity/service/_entity_.service.ts.ejs +153 -0
  304. package/src/templates/angular/entity/settings/_entity_.settings.ts.ejs +49 -0
  305. package/src/templates/angular/enums/_enum_.model.ts.ejs +11 -0
  306. package/src/templates/angular/iam/change-password.component.html.ejs +39 -0
  307. package/src/templates/angular/iam/change-password.component.ts.ejs +44 -0
  308. package/src/templates/angular/iam/no-access.component.ts.ejs +17 -0
  309. package/src/templates/angular/iam/role-list.component.html.ejs +331 -0
  310. package/src/templates/angular/iam/role-list.component.scss.ejs +107 -0
  311. package/src/templates/angular/iam/role-list.component.ts.ejs +597 -0
  312. package/src/templates/angular/iam/role-management/role-header.component.html.ejs +51 -0
  313. package/src/templates/angular/iam/role-management/role-header.component.ts.ejs +45 -0
  314. package/src/templates/angular/iam/role-management/role-inheritance.component.html.ejs +15 -0
  315. package/src/templates/angular/iam/role-management/role-inheritance.component.ts.ejs +19 -0
  316. package/src/templates/angular/iam/role-management/role-permissions-panel.component.css.ejs +24 -0
  317. package/src/templates/angular/iam/role-management/role-permissions-panel.component.html.ejs +108 -0
  318. package/src/templates/angular/iam/role-management/role-permissions-panel.component.ts.ejs +122 -0
  319. package/src/templates/angular/iam/role-management/role-users.component.html.ejs +104 -0
  320. package/src/templates/angular/iam/role-management/role-users.component.ts.ejs +53 -0
  321. package/src/templates/angular/iam/role-management/user-select-dialog.component.html.ejs +113 -0
  322. package/src/templates/angular/iam/role-management/user-select-dialog.component.ts.ejs +157 -0
  323. package/src/templates/angular/iam/role-permission-matrix.component.html.ejs +355 -0
  324. package/src/templates/angular/iam/role-permission-matrix.component.scss.ejs +217 -0
  325. package/src/templates/angular/iam/role-permission-matrix.component.ts.ejs +800 -0
  326. package/src/templates/angular/iam/screen-catalog.ts.ejs +147 -0
  327. package/src/templates/angular/iam/shared/confirm-dialog.component.ts.ejs +83 -0
  328. package/src/templates/angular/iam/shared/matrix-hierarchy.util.ts.ejs +196 -0
  329. package/src/templates/angular/iam/shared/permission-matrix-sound.ts.ejs +59 -0
  330. package/src/templates/angular/iam/shared/role-display.util.ts.ejs +43 -0
  331. package/src/templates/angular/iam/shared/role-permission-skeleton.component.ts.ejs +54 -0
  332. package/src/templates/angular/iam/shared/screen-matrix.util.ts.ejs +554 -0
  333. package/src/templates/angular/iam/shared/screen-navigation-map.ts.ejs +187 -0
  334. package/src/templates/angular/iam/shared/screen-navigation.registry.ts.ejs +64 -0
  335. package/src/templates/angular/iam/shared/text-highlight.pipe.ts.ejs +39 -0
  336. package/src/templates/angular/iam/user-access-matrix.component.html.ejs +212 -0
  337. package/src/templates/angular/iam/user-access-matrix.component.scss.ejs +34 -0
  338. package/src/templates/angular/iam/user-access-matrix.component.ts.ejs +239 -0
  339. package/src/templates/angular/iam/user-detail.component.html.ejs +143 -0
  340. package/src/templates/angular/iam/user-detail.component.ts.ejs +108 -0
  341. package/src/templates/angular/iam/user-form.component.html.ejs +63 -0
  342. package/src/templates/angular/iam/user-form.component.ts.ejs +100 -0
  343. package/src/templates/angular/iam/user-list.component.html.ejs +369 -0
  344. package/src/templates/angular/iam/user-list.component.scss.ejs +242 -0
  345. package/src/templates/angular/iam/user-list.component.ts.ejs +446 -0
  346. package/src/templates/angular/iam/user-management.routes.ts.ejs +47 -0
  347. package/src/templates/angular/iam/user-permission-matrix.component.html.ejs +231 -0
  348. package/src/templates/angular/iam/user-permission-matrix.component.scss.ejs +216 -0
  349. package/src/templates/angular/iam/user-permission-matrix.component.ts.ejs +516 -0
  350. package/src/templates/angular/shared/base/audit-user-name.pipe.ts.ejs +69 -0
  351. package/src/templates/angular/shared/base/base-filter.component.ts.ejs +245 -0
  352. package/src/templates/angular/shared/base/base-form.component.ts.ejs +109 -0
  353. package/src/templates/angular/shared/base/base-list.component.ts.ejs +507 -0
  354. package/src/templates/angular/shared/base/filter-types.ts.ejs +55 -0
  355. package/src/templates/angular/shared/base/input-format.directive.ts.ejs +47 -0
  356. package/src/templates/angular/shared/base/input-format.ts.ejs +15 -0
  357. package/src/templates/angular/shared/confirm-with-input-dialog.component.ts.ejs +91 -0
  358. package/src/templates/angular/shared/confirmation-dialog.component.ts.ejs +80 -0
  359. package/src/templates/angular/shared/list-styles.css.ejs +103 -0
  360. package/src/templates/angular/shared/loading-overlay.component.ts.ejs +24 -0
  361. package/src/templates/angular/shared/resizable.directive.ts.ejs +115 -0
  362. package/src/templates/angular/shared/snackbar-styles.css.ejs +11 -0
  363. package/src/templates/fuse-packs/access-control-tools/access-control-sync.js +819 -0
  364. package/src/templates/fuse-packs/access-control-tools/build-rename-map.js +67 -0
  365. package/src/templates/fuse-packs/access-control-tools/inject-qa-ids.js +14 -0
  366. package/src/templates/fuse-packs/access-control-tools/lib/hierarchy-scanner.js +628 -0
  367. package/src/templates/fuse-packs/access-control-tools/lib/hierarchy-scanner.test.js +323 -0
  368. package/src/templates/fuse-packs/access-control-tools/lib/html-scanner.js +362 -0
  369. package/src/templates/fuse-packs/access-control-tools/lib/id-rules.duplicate.test.js +136 -0
  370. package/src/templates/fuse-packs/access-control-tools/lib/id-rules.js +1095 -0
  371. package/src/templates/fuse-packs/access-control-tools/lib/ts-component-index.js +482 -0
  372. package/src/templates/fuse-packs/access-control-tools/output/.gitkeep +0 -0
  373. package/src/templates/fuse-packs/access-control-tools/run.sh +223 -0
  374. package/src/templates/fuse-packs/access-control-tools/scan-access-control.js +14 -0
  375. package/src/templates/fuse-packs/iam-assets/sound/apple-play.mp3 +0 -0
  376. package/src/templates/fuse-packs/iam-assets/sound/remove.mp3 +0 -0
  377. package/src/templates/generator/README.md +12 -0
  378. package/src/templates/testing/ci.cjs +45 -0
  379. package/src/templates/testing/mock.cjs +149 -0
  380. package/src/templates/testing/playwright.config.cjs +25 -0
  381. package/src/templates/testing/serve.cjs +22 -0
  382. package/src/templates/testing/smoke.spec.cjs +180 -0
  383. package/src/utils/branding.js +39 -0
  384. package/src/utils/colors.js +18 -0
  385. package/src/utils/diff.js +109 -0
  386. package/src/utils/merger.js +115 -0
  387. package/src/validator/backend-diagnostics.js +30 -0
  388. package/src/validator/blueprint-validator.js +276 -0
  389. package/src/validator/diagnostics.js +608 -0
  390. package/src/validator/pattern.js +28 -0
  391. package/test/auth-interceptor.js +84 -0
  392. package/test/auth-provision-checks.js +297 -0
  393. package/test/field-preferences.js +145 -0
  394. package/test/fixtures/field-profile.gdl +7 -0
  395. package/test/fixtures/mock.jdl +17 -0
  396. package/test/fixtures/mock.png +0 -0
  397. package/test/fixtures/performance/config.yml +33 -0
  398. package/test/fixtures/performance/large.gdl +199 -0
  399. package/test/fixtures/performance/small.gdl +7 -0
  400. package/test/fixtures/quality/custom.yml +22 -0
  401. package/test/fixtures/quality/go-duck.yml +22 -0
  402. package/test/fixtures/quality/jhipster.yml +30 -0
  403. package/test/fixtures/quality/representative.gdl +14 -0
  404. package/test/list-state.js +138 -0
  405. package/test/micro-functions-layout.js +95 -0
  406. package/test/performance-generation.js +32 -0
  407. package/test/pmb-preset.js +127 -0
  408. package/test/project-workflow.js +111 -0
  409. package/test/quality-features.js +250 -0
  410. package/test/verify-commands.js +83 -0
  411. package/test/verify.js +959 -0
  412. package/test-files/GDL/example.gdl +15 -0
  413. package/test-files/JDL/example.jdl +15 -0
  414. package/test-files/config/crudforge.config.yml +127 -0
  415. package/test-run.sh +272 -0
@@ -0,0 +1,301 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const inquirer = require('inquirer');
4
+ const { loadConfig } = require('../config/load-config');
5
+ const { parseJdl } = require('../parser/jdl-parser');
6
+ const { parseGdl } = require('../parser/gdl-parser');
7
+ const { generateProject: runGenerator } = require('../generator/project-output');
8
+ const colors = require('../utils/colors');
9
+ const branding = require('../utils/branding');
10
+
11
+ async function generateCommand(jdlFile, outputFolder, options = {}) {
12
+ const cwd = process.cwd();
13
+ const startTime = Date.now();
14
+
15
+ // 1. Load preferences
16
+ const projectMode = !jdlFile;
17
+ const { config, configPath, projectRoot } = await loadConfig(cwd, options.preferences, {
18
+ required: projectMode, projectPaths: projectMode,
19
+ });
20
+ const { resolveInputSources } = require('../config/input-sources');
21
+
22
+ // CLI positional file overrides config; otherwise use input.sources[] or input.file.
23
+ let inputSources;
24
+ if (jdlFile) {
25
+ const resolved = path.resolve(cwd, jdlFile);
26
+ if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) {
27
+ throw new Error(`Input file not found: "${resolved}".`);
28
+ }
29
+ if (!/\.(gdl|jdl)$/i.test(resolved)) throw new Error(`Unsupported schema "${resolved}". Use .gdl or .jdl.`);
30
+ const type = path.extname(resolved).slice(1).toLowerCase();
31
+ const folder =
32
+ String(config.fuse?.folderType || '').trim() || (type === 'gdl' ? 'micro-functions' : 'microservice');
33
+ inputSources = [
34
+ {
35
+ name: folder,
36
+ file: resolved,
37
+ type,
38
+ microservice: String(config.api?.microservice || '').trim(),
39
+ folder,
40
+ },
41
+ ];
42
+ } else {
43
+ inputSources = resolveInputSources(config, projectRoot);
44
+ if (!inputSources.length) {
45
+ throw new Error(
46
+ `Missing schema input in "${configPath}". Set input.file or input.sources[{ name, file, microservice }].`
47
+ );
48
+ }
49
+ }
50
+
51
+ for (const source of inputSources) {
52
+ if (!fs.existsSync(source.file) || !fs.statSync(source.file).isFile()) {
53
+ throw new Error(
54
+ `Input file not found: "${source.file}" (service "${source.name}"). Update input.sources / input.file.`
55
+ );
56
+ }
57
+ if (!/\.(gdl|jdl)$/i.test(source.file)) {
58
+ throw new Error(`Unsupported schema "${source.file}". Use .gdl or .jdl.`);
59
+ }
60
+ }
61
+
62
+ // Keep legacy single-file fields populated for embed/docs/tools.
63
+ config.input.file = inputSources[0].file;
64
+ config.input.type = inputSources[0].type;
65
+ config._inputSources = inputSources;
66
+
67
+ if (configPath) {
68
+ console.log(colors.cyan(`🔵 Loaded configuration preferences from: ${configPath}`));
69
+ } else {
70
+ console.log(colors.dim(`🔵 No configuration file found. Using default developer preferences.`));
71
+ }
72
+ if (inputSources.length > 1) {
73
+ console.log(
74
+ colors.cyan(
75
+ `🔵 Multi-service schemas: ${inputSources.map((s) => `${s.name} (${path.basename(s.file)})`).join(', ')}`
76
+ )
77
+ );
78
+ }
79
+
80
+ // Display banner dynamically based on configuration preferences
81
+ branding.printBanner(config);
82
+
83
+ // Override configuration using CLI arguments if provided
84
+ if (outputFolder) {
85
+ config.output.directory = path.isAbsolute(outputFolder)
86
+ ? outputFolder
87
+ : path.resolve(cwd, outputFolder);
88
+ }
89
+
90
+ if (options.fuse) {
91
+ config.fuse = config.fuse || {};
92
+ config.fuse.enabled = true;
93
+ }
94
+ if (options.fusePath) {
95
+ config.fuse = config.fuse || {};
96
+ config.fuse.starterPackPath = path.isAbsolute(options.fusePath)
97
+ ? options.fusePath
98
+ : path.resolve(cwd, options.fusePath);
99
+ }
100
+ if (options.cleanLayout) {
101
+ config.fuse = config.fuse || {};
102
+ config.fuse.cleanLayout = true;
103
+ }
104
+ if (options.sidebarTheme) {
105
+ config.fuse = config.fuse || {};
106
+ config.fuse.sidebarTheme = options.sidebarTheme;
107
+ }
108
+ if (options.folderType) {
109
+ config.fuse = config.fuse || {};
110
+ config.fuse.folderType = options.folderType;
111
+ if (jdlFile || !config.input.sources?.length) inputSources[0].folder = options.folderType;
112
+ }
113
+
114
+ if (options.microservice) {
115
+ config.api.microservice = options.microservice;
116
+ }
117
+
118
+ if (options.dryRun) {
119
+ config.dryRun = true;
120
+ }
121
+
122
+ if (options.overwritePolicy) {
123
+ if (!config.output) config.output = {};
124
+ config.output.overwritePolicy = options.overwritePolicy;
125
+ }
126
+
127
+ // Prompt for microservice when any source still lacks one (global or per-source).
128
+ const missingMs = inputSources.filter((s) => !s.microservice);
129
+ if (missingMs.length) {
130
+ if (!config.api.microservice) {
131
+ if (!process.stdout.isTTY || options.yes) {
132
+ throw new Error(
133
+ `Set api.microservice or each input.sources[].microservice in "${configPath || 'your configuration'}" (or pass --microservice <name>).`
134
+ );
135
+ }
136
+ const answers = await inquirer.prompt([{
137
+ type: 'input',
138
+ name: 'microservice',
139
+ message: 'Enter microservice identifier for API resource paths (e.g. keycloak-service):',
140
+ validate: (input) => (input.trim().length > 0 ? true : 'Microservice name cannot be blank.'),
141
+ }]);
142
+ config.api.microservice = answers.microservice;
143
+ }
144
+ for (const source of missingMs) {
145
+ source.microservice = config.api.microservice;
146
+ }
147
+ }
148
+ if (!config.api.microservice && inputSources[0]?.microservice) {
149
+ config.api.microservice = inputSources[0].microservice;
150
+ }
151
+
152
+ // When services are configured, confirm which proxy file(s) to update (unless set / --yes).
153
+ config.api = config.api || {};
154
+ config.proxy = config.proxy || {};
155
+ const serviceKeys = config.api.services && typeof config.api.services === 'object'
156
+ ? Object.keys(config.api.services).filter((k) => k && config.api.services[k])
157
+ : [];
158
+ if (
159
+ config.fuse?.enabled !== false &&
160
+ serviceKeys.length > 0 &&
161
+ process.stdout.isTTY &&
162
+ !options.yes &&
163
+ !options.proxyWrite
164
+ ) {
165
+ const current = String(config.proxy.write || 'both').toLowerCase();
166
+ const answers = await inquirer.prompt([{
167
+ type: 'list',
168
+ name: 'proxyWrite',
169
+ message: 'Update which Fuse proxy config for api.services / Keycloak?',
170
+ default: ['both', 'prod', 'dev'].includes(current) ? current : 'both',
171
+ choices: [
172
+ { name: 'Both (proxy.conf.json + proxy.dev.conf.json)', value: 'both' },
173
+ { name: 'Prod only (proxy.conf.json)', value: 'prod' },
174
+ { name: 'Dev only (proxy.dev.conf.json)', value: 'dev' },
175
+ ],
176
+ }]);
177
+ config.proxy.write = answers.proxyWrite;
178
+ }
179
+ if (options.proxyWrite) {
180
+ config.proxy.write = String(options.proxyWrite).trim().toLowerCase();
181
+ }
182
+
183
+ // 2. Parse one or more schema files and merge (tag entities with their service source).
184
+ const { requireValidSchema, formatDiagnostics } = require('../validator/diagnostics');
185
+ const parsedData = { entities: [], enums: [], relationships: [] };
186
+ const entityOwners = new Map();
187
+ const allDiagnostics = [];
188
+
189
+ for (const source of inputSources) {
190
+ const isGdl = source.type === 'gdl' || source.file.toLowerCase().endsWith('.gdl');
191
+ const fileContent = fs.readFileSync(source.file, 'utf8');
192
+ const checked = requireValidSchema(fileContent, { file: source.file, isGdl, config });
193
+ if (checked.diagnostics.length) {
194
+ allDiagnostics.push(...checked.diagnostics);
195
+ console.warn(formatDiagnostics(checked.diagnostics));
196
+ }
197
+ const chunk = checked.parsed || { entities: [], enums: [], relationships: [] };
198
+ for (const entity of chunk.entities || []) {
199
+ const key = String(entity.name || '').toLowerCase();
200
+ if (entityOwners.has(key)) {
201
+ throw new Error(
202
+ `Entity "${entity.name}" is defined in both "${entityOwners.get(key)}" and "${source.file}". Rename one or split carefully.`
203
+ );
204
+ }
205
+ entityOwners.set(key, source.file);
206
+ entity.sourceName = source.name;
207
+ entity.microservice = source.microservice;
208
+ entity.folderName = source.folder;
209
+ parsedData.entities.push(entity);
210
+ }
211
+ for (const en of chunk.enums || []) {
212
+ en.sourceName = source.name;
213
+ en.microservice = source.microservice;
214
+ en.folderName = source.folder;
215
+ if (config.fuse?.enabled || !parsedData.enums.some((existing) => existing.name === en.name)) {
216
+ parsedData.enums.push(en);
217
+ }
218
+ }
219
+ parsedData.relationships.push(...(chunk.relationships || []));
220
+ }
221
+
222
+ if (!parsedData.entities.length) {
223
+ throw new Error(
224
+ `No entities found in schema(s): ${inputSources.map((s) => s.file).join(', ')}. Add a valid entity and retry.`
225
+ );
226
+ }
227
+ const checked = { diagnostics: allDiagnostics, parsed: parsedData };
228
+ const resolvedJdlFile = inputSources[0].file;
229
+
230
+ const { applyDeveloperKeycloakOptions } = require('./keycloak-options');
231
+ await applyDeveloperKeycloakOptions(config, options, { cwd: projectRoot });
232
+
233
+ if (config.auth) {
234
+ const { stripSecretsForGenerate, deriveAuthUrls } = require('../config/auth-config');
235
+ deriveAuthUrls(config.auth);
236
+ config.auth = stripSecretsForGenerate(config.auth);
237
+ }
238
+
239
+ // 3. Generate outputs
240
+ console.log(colors.cyan(`🚀 Executing generator engine...`));
241
+ const stats = await runGenerator(parsedData, config, { configPath, inputPath: resolvedJdlFile, options });
242
+
243
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
244
+
245
+ console.log('\\n');
246
+ branding.printBanner(config);
247
+
248
+ if (stats.dryRun) {
249
+ console.log(colors.yellow(colors.bold(` 🔍 DRY RUN PREVIEW: No files were modified on disk.\\n`)));
250
+
251
+ const newFiles = stats.dryRunReport.newFiles;
252
+ if (newFiles.length > 0) {
253
+ console.log(colors.green(colors.bold(` Proposed New Files (${newFiles.length}):`)));
254
+ newFiles.forEach(file => {
255
+ console.log(colors.green(` [NEW] ${file.path}`));
256
+ const preview = file.content.split(/\r?\n/).slice(0, 3).map(l => ` + ${l}`).join('\n');
257
+ console.log(colors.dim(preview));
258
+ if (file.content.split(/\\r?\\n/).length > 3) {
259
+ console.log(colors.dim(' + ...'));
260
+ }
261
+ });
262
+ console.log();
263
+ }
264
+
265
+ const modifiedFiles = stats.dryRunReport.modifiedFiles;
266
+ if (modifiedFiles.length > 0) {
267
+ console.log(colors.yellow(colors.bold(` Proposed File Modifications (${modifiedFiles.length}):`)));
268
+ const { formatDiff, colorizeDiff } = require('../utils/diff');
269
+ modifiedFiles.forEach(file => {
270
+ console.log(colors.yellow(` [MODIFIED] ${file.path}`));
271
+ const diffLines = formatDiff(file.oldContent, file.content);
272
+ const colorDiff = colorizeDiff(diffLines);
273
+ const indentedDiff = colorDiff.split('\\n').map(l => ` \${l}`).join('\\n');
274
+ console.log(indentedDiff);
275
+ });
276
+ console.log();
277
+ } else if (newFiles.length === 0) {
278
+ console.log(colors.dim(' No file changes proposed. Output is identical to existing files on disk.\\n'));
279
+ }
280
+
281
+ console.log(` ${colors.bold('Output Directory:')} ${colors.cyan(config.output.directory)}`);
282
+ console.log(` ${colors.bold('Entities Inspected:')} ${colors.yellow(stats.entityCount)}`);
283
+ console.log(` ${colors.bold('Proposed Writes:')} ${colors.yellow(newFiles.length + modifiedFiles.length)}`);
284
+ console.log(` ${colors.bold('Elapsed Time:')} ${colors.yellow(elapsed + 's')}\n`);
285
+ } else {
286
+ console.log(colors.green(colors.bold(` 🎉 SUCCESS: Generation Completed Successfully!\\n`)));
287
+ console.log(` ${colors.bold('Output Directory:')} ${colors.cyan(config.output.directory)}`);
288
+ console.log(` ${colors.bold('Entities Processed:')} ${colors.yellow(stats.entityCount)}`);
289
+ console.log(` ${colors.bold('Files Generated:')} ${colors.yellow(stats.fileCount)}`);
290
+ console.log(` ${colors.bold('Elapsed Time:')} ${colors.yellow(elapsed + 's')}\n`);
291
+
292
+ console.log(colors.bold(' Suggested Next Steps:'));
293
+ console.log(colors.dim(` 1. Navigate to your project folder.`));
294
+ console.log(colors.dim(` 2. Run ${colors.cyan('npm install')} to install dependencies.`));
295
+ console.log(colors.dim(` 3. ${colors.cyan(`npm run dev -- --port ${config.devServer?.port || 4200}`)} → http://localhost:${config.devServer?.port || 4200}\n`));
296
+ branding.printSuccessFooter();
297
+ }
298
+ return {stats,diagnostics:checked.diagnostics};
299
+ }
300
+
301
+ module.exports = { generateCommand };
@@ -0,0 +1,310 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const colors = require('../utils/colors');
4
+
5
+ const exampleJdl = `
6
+ entity Book {
7
+ title String required
8
+ description TextBlob
9
+ publicationDate LocalDate
10
+ price BigDecimal
11
+ }
12
+
13
+ entity Author {
14
+ firstName String required
15
+ lastName String required
16
+ }
17
+
18
+ relationship OneToMany {
19
+ Author{book} to Book{author}
20
+ }
21
+ `;
22
+
23
+ const exampleGdl = `entity Book {
24
+ string title required
25
+ bigDecimal price
26
+ }
27
+ `;
28
+
29
+ const defaultConfigYml = `
30
+ # CRUDForge CLI Configuration
31
+ project:
32
+ name: CRUDForge App
33
+ description: Angular Material CRUD generated by CRUDForge
34
+ repositoryUrl: ""
35
+
36
+ input:
37
+ type: "gdl"
38
+ file: ""
39
+ # Multi-service example (uncomment and point at your GDL/JDL files):
40
+ # sources:
41
+ # - name: identity-access
42
+ # file: ./GDL/identity-access.gdl
43
+ # microservice: identity-access-module
44
+ # - name: inventory
45
+ # file: ./GDL/inventory.gdl
46
+ # microservice: inventory-service
47
+ sources: []
48
+
49
+ output:
50
+ directory: "./generated-app"
51
+ structure: "entity-folder"
52
+ embedConfig: true
53
+ teamPack:
54
+ enabled: true
55
+ cursorAgents: true
56
+ codexAgents: true
57
+ antigravityAgents: true
58
+ vscodeExtensions: true
59
+ aiDocs:
60
+ enabled: true
61
+
62
+ git:
63
+ enabled: true
64
+
65
+ preset: "crud"
66
+ dryRun: false
67
+ validation: true
68
+
69
+ branding:
70
+ banner: true
71
+ bannerColor: "green"
72
+
73
+ fuse:
74
+ rendering: spa # spa (Nginx) | ssr (Node server)
75
+ enabled: false
76
+ routesFile: "src/app/domains/admin/routes.ts"
77
+ navigationFile: "src/app/domains/admin/layout/data/navigation.ts"
78
+ cleanLayout: false
79
+ includePrebuilt: true
80
+ folderType: ""
81
+ theme:
82
+ scheme: "system"
83
+ primary: "#0D1E3A"
84
+ error: "#dc2626"
85
+
86
+ generate:
87
+ models: true
88
+ services: true
89
+ formServices: true
90
+ routes: true
91
+ enums: true
92
+ relationships: true
93
+ components:
94
+ list: true
95
+ card: true
96
+ detail: true
97
+ forms:
98
+ form: true
99
+ formPage: true
100
+ update: true
101
+ validators: true
102
+ mappers: true
103
+ interaction:
104
+ actions: true
105
+ filter: true
106
+ globals:
107
+ constants: true
108
+ tests: false
109
+ sharedAssets: true
110
+ registrations:
111
+ navigation: true
112
+ routes: true
113
+
114
+ ui:
115
+ framework: "material"
116
+ useSkeletonLoading: true
117
+ viewMode: "table"
118
+ formMode: "sidebar"
119
+ searchMode: "field"
120
+ cardBreakpointPx: 640
121
+ gridCols:
122
+ mobile: 1
123
+ tablet: 2
124
+ desktop: 3
125
+ styling:
126
+ snackbarSuccessColor: "#16a34a"
127
+ snackbarErrorColor: "#dc2626"
128
+
129
+ api:
130
+ baseUrl: "/api"
131
+ microservice: ""
132
+ endpointStyle: "kebab-plural"
133
+ dateLibrary: "dayjs"
134
+ responseType: "http-response"
135
+ # Backend modules → environment.services + proxy targets
136
+ # identityaccessmodule: "http://62.84.188.166:30084"
137
+ services: {}
138
+
139
+ # both | prod (proxy.conf.json) | dev (proxy.dev.conf.json)
140
+ proxy:
141
+ write: both
142
+
143
+ fields:
144
+ # Exact entity and field names from your GDL/JDL. Only String/TextBlob fields.
145
+ # entities:
146
+ # Province:
147
+ # fields:
148
+ # referenceCode: { inputFormat: uppercase }
149
+ # email: { inputFormat: lowercase }
150
+ # description: { inputFormat: none }
151
+ entities: {}
152
+ audit:
153
+ enabled: true
154
+ hideInForms: true
155
+ hideInFilters: true
156
+ hideInSearch: true
157
+ hideInLists: true
158
+ showInDetail: true
159
+ names:
160
+ - createdBy
161
+ - createdDate
162
+ - lastModifiedBy
163
+ - lastModifiedDate
164
+ technical:
165
+ enabled: true
166
+ names:
167
+ - debug
168
+ - refType
169
+ - refId
170
+ formatting:
171
+ dateMediumFormat: "medium"
172
+ numberFormat: "1.0-2"
173
+ stringCase: "default"
174
+
175
+ formBehavior:
176
+ uppercaseInputs: false
177
+ updateOn: "change"
178
+ showErrorMessages: true
179
+ autoFocusFirstInput: true
180
+
181
+ # Keycloak — set provider: keycloak and fill serverUrl / clientId / adminServiceUrl.
182
+ # Put KEYCLOAK_ADMIN_USERNAME and KEYCLOAK_ADMIN_PASSWORD in a local .env (never commit).
183
+ # generate never provisions — use crudforge bootstrap when provision.enabled is true.
184
+ auth:
185
+ provider: none
186
+ serverUrl: ""
187
+ realm: CRUD-FORDGE
188
+ clientId: ""
189
+ clientSecret: ""
190
+ issuerUrl: ""
191
+ tokenUrl: ""
192
+ adminBaseUrl: /auth
193
+ useMockAuth: false
194
+ adminRoles:
195
+ - ROLE_ADMIN
196
+ - ADMIN
197
+ - ROLE_SUPER_ADMIN
198
+ sessionIdleTimeoutMs: 0
199
+ session:
200
+ idleTimeoutMs: 0
201
+ persistAcrossReload: true
202
+ crossTabSync: true
203
+ refreshOnFocus: true
204
+ statusProbeIntervalMs: 60000
205
+ disabledAccount:
206
+ enabled: false
207
+ countdownSeconds: 20
208
+ message: "Your account has been disabled. Please contact your administrator."
209
+ sound: false
210
+ forwardedProto: ""
211
+ provision:
212
+ enabled: false
213
+ dryRun: false
214
+ adapter: admin-service
215
+ adminServiceUrl: ""
216
+ adminUsernameEnv: KEYCLOAK_ADMIN_USERNAME
217
+ adminPasswordEnv: KEYCLOAK_ADMIN_PASSWORD
218
+ tokenClientId: admin-cli
219
+ clientId: ""
220
+ clientName: ""
221
+ publicClient: true
222
+ directAccessGrantsEnabled: true
223
+ redirectUris: []
224
+ webOrigins: []
225
+ roles: []
226
+ users: []
227
+ resetExistingPasswords: false
228
+ stateFile: ".crudforge/provision-state.json"
229
+
230
+ iam:
231
+ enabled: false
232
+ users: true
233
+ roles: true
234
+ rolePermissions: true
235
+ userAccess: true
236
+ userPermissions: true
237
+ inheritance: true
238
+ screens: []
239
+ `;
240
+
241
+ async function initConfig() {
242
+ const cwd = process.cwd();
243
+ const configPath = path.join(cwd, 'crudforge.config.yml');
244
+ const jdlPath = path.join(cwd, 'example.jdl');
245
+ const gdlPath = path.join(cwd, 'example.gdl');
246
+
247
+ if (!fs.existsSync(configPath)) {
248
+ fs.writeFileSync(configPath, defaultConfigYml.trim());
249
+ console.log(colors.green(`✅ Created default configuration file: ${configPath}`));
250
+ } else {
251
+ console.log(colors.yellow(`⚠️ Configuration file already exists at ${configPath}. Skipping creation.`));
252
+ }
253
+
254
+ if (!fs.existsSync(jdlPath)) {
255
+ fs.writeFileSync(jdlPath, exampleJdl.trim());
256
+ console.log(colors.green(`✅ Created example JDL file: ${jdlPath}`));
257
+ }
258
+
259
+ if (!fs.existsSync(gdlPath)) {
260
+ fs.writeFileSync(gdlPath, exampleGdl.trim());
261
+ console.log(colors.green(`✅ Created example GDL file: ${gdlPath}`));
262
+ }
263
+ }
264
+
265
+ async function initProject(directory, options = {}) {
266
+ const YAML = require('yaml');
267
+ const projectRoot = path.resolve(directory);
268
+ if (await fs.pathExists(projectRoot)) {
269
+ if (!(await fs.stat(projectRoot)).isDirectory() || (await fs.readdir(projectRoot)).length) {
270
+ throw new Error(`Project path "${projectRoot}" is not empty. Choose a new or empty directory; existing files are preserved.`);
271
+ }
272
+ }
273
+ if (options.source && !options.preset) throw new Error('--source requires --preset pmb-test.');
274
+ let preset;
275
+ if (options.preset) {
276
+ const { presetDirectory, importPreset, loadPreset } = require('../presets/store');
277
+ const registry = presetDirectory(options.preset);
278
+ const relative = path.relative(projectRoot, registry);
279
+ if (!relative || (!relative.startsWith('..' + path.sep) && relative !== '..' && !path.isAbsolute(relative))) {
280
+ throw new Error(`Preset storage must be outside the generated project: ${registry}`);
281
+ }
282
+ preset = options.source
283
+ ? await importPreset(options.preset, options.source)
284
+ : await loadPreset(options.preset);
285
+ console.log(`Using preset: ${registry}`);
286
+ }
287
+ const config = YAML.parse(defaultConfigYml);
288
+ config.project.name = path.basename(projectRoot);
289
+ config.input = { file: './gdl/example.gdl', type: 'gdl' };
290
+ config.output.directory = '.';
291
+ config.output.overwritePolicy = 'fail';
292
+ config.fuse.enabled = true;
293
+ config.fuse.cleanLayout = true;
294
+ config.fuse.includePrebuilt = false;
295
+ config.api.microservice = 'book-service';
296
+ if (preset) {
297
+ require('lodash').mergeWith(config, preset.config, (_current, incoming) => Array.isArray(incoming) ? incoming : undefined);
298
+ config.project.name = path.basename(projectRoot);
299
+ }
300
+ const configPath = path.join(projectRoot, 'config/crudforge.config.yml');
301
+ const gdlPath = path.join(projectRoot, 'gdl/example.gdl');
302
+ await fs.ensureDir(path.dirname(configPath));
303
+ await fs.ensureDir(path.dirname(gdlPath));
304
+ await fs.writeFile(configPath, '# Project paths are relative to the project root, not config/.\n' + YAML.stringify(config), { flag: 'wx' });
305
+ await fs.writeFile(gdlPath, preset?.gdl || exampleGdl, { flag: 'wx' });
306
+ console.log(`Initialized project inputs in ${projectRoot}\nEdit: ${configPath}\nEdit: ${gdlPath}\n\nNext:\n cd ${JSON.stringify(projectRoot)}\n crudforge generate`);
307
+ if (preset) console.log(`After generation:\n npm install\n npm run dev -- --port ${config.devServer.port}\nOpen http://localhost:${config.devServer.port}/auth/sign-in and enter your PMB login. Backend access is not yet verified.`);
308
+ }
309
+
310
+ module.exports = { initConfig, initProject };