@sfdc-webapps/cli 1.0.2

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 (405) hide show
  1. package/README.md +1414 -0
  2. package/dist/commands/apply-patches.d.ts +23 -0
  3. package/dist/commands/apply-patches.d.ts.map +1 -0
  4. package/dist/commands/apply-patches.js +524 -0
  5. package/dist/commands/apply-patches.js.map +1 -0
  6. package/dist/commands/new-app-feature.d.ts +7 -0
  7. package/dist/commands/new-app-feature.d.ts.map +1 -0
  8. package/dist/commands/new-app-feature.js +166 -0
  9. package/dist/commands/new-app-feature.js.map +1 -0
  10. package/dist/commands/new-app.d.ts +1 -0
  11. package/dist/commands/new-app.d.ts.map +1 -0
  12. package/dist/commands/new-app.js +2 -0
  13. package/dist/commands/new-app.js.map +1 -0
  14. package/dist/commands/watch-patches.d.ts +6 -0
  15. package/dist/commands/watch-patches.d.ts.map +1 -0
  16. package/dist/commands/watch-patches.js +152 -0
  17. package/dist/commands/watch-patches.js.map +1 -0
  18. package/dist/core/dependency-resolver.d.ts +40 -0
  19. package/dist/core/dependency-resolver.d.ts.map +1 -0
  20. package/dist/core/dependency-resolver.js +122 -0
  21. package/dist/core/dependency-resolver.js.map +1 -0
  22. package/dist/core/file-operations.d.ts +37 -0
  23. package/dist/core/file-operations.d.ts.map +1 -0
  24. package/dist/core/file-operations.js +201 -0
  25. package/dist/core/file-operations.js.map +1 -0
  26. package/dist/core/package-json-merger.d.ts +30 -0
  27. package/dist/core/package-json-merger.d.ts.map +1 -0
  28. package/dist/core/package-json-merger.js +104 -0
  29. package/dist/core/package-json-merger.js.map +1 -0
  30. package/dist/core/patch-loader.d.ts +17 -0
  31. package/dist/core/patch-loader.d.ts.map +1 -0
  32. package/dist/core/patch-loader.js +100 -0
  33. package/dist/core/patch-loader.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +90 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/types.d.ts +21 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/utils/debounce.d.ts +6 -0
  43. package/dist/utils/debounce.d.ts.map +1 -0
  44. package/dist/utils/debounce.js +19 -0
  45. package/dist/utils/debounce.js.map +1 -0
  46. package/dist/utils/import-merger.d.ts +12 -0
  47. package/dist/utils/import-merger.d.ts.map +1 -0
  48. package/dist/utils/import-merger.js +240 -0
  49. package/dist/utils/import-merger.js.map +1 -0
  50. package/dist/utils/logger.d.ts +6 -0
  51. package/dist/utils/logger.d.ts.map +1 -0
  52. package/dist/utils/logger.js +17 -0
  53. package/dist/utils/logger.js.map +1 -0
  54. package/dist/utils/path-mappings.d.ts +88 -0
  55. package/dist/utils/path-mappings.d.ts.map +1 -0
  56. package/dist/utils/path-mappings.js +138 -0
  57. package/dist/utils/path-mappings.js.map +1 -0
  58. package/dist/utils/paths.d.ts +43 -0
  59. package/dist/utils/paths.d.ts.map +1 -0
  60. package/dist/utils/paths.js +107 -0
  61. package/dist/utils/paths.js.map +1 -0
  62. package/dist/utils/route-merger.d.ts +107 -0
  63. package/dist/utils/route-merger.d.ts.map +1 -0
  64. package/dist/utils/route-merger.js +303 -0
  65. package/dist/utils/route-merger.js.map +1 -0
  66. package/dist/utils/validation.d.ts +29 -0
  67. package/dist/utils/validation.d.ts.map +1 -0
  68. package/dist/utils/validation.js +109 -0
  69. package/dist/utils/validation.js.map +1 -0
  70. package/package.json +39 -0
  71. package/src/commands/apply-patches.ts +594 -0
  72. package/src/commands/new-app-feature.ts +203 -0
  73. package/src/commands/new-app.ts +0 -0
  74. package/src/commands/watch-patches.ts +173 -0
  75. package/src/core/dependency-resolver.ts +175 -0
  76. package/src/core/file-operations.ts +265 -0
  77. package/src/core/package-json-merger.ts +129 -0
  78. package/src/core/patch-loader.ts +128 -0
  79. package/src/index.ts +95 -0
  80. package/src/types.ts +23 -0
  81. package/src/utils/debounce.ts +23 -0
  82. package/src/utils/import-merger.ts +293 -0
  83. package/src/utils/logger.ts +21 -0
  84. package/src/utils/path-mappings.ts +154 -0
  85. package/src/utils/paths.ts +121 -0
  86. package/src/utils/route-merger.ts +357 -0
  87. package/src/utils/validation.ts +150 -0
  88. package/test/e2e/E2E_TEST_FIXTURES.md +509 -0
  89. package/test/e2e/apply-patches.spec.ts +861 -0
  90. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/package.json +10 -0
  91. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/appLayout.tsx +27 -0
  92. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/home.tsx +8 -0
  93. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/index.tsx +10 -0
  94. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/old-page.tsx +8 -0
  95. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/routes.tsx +23 -0
  96. package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/styles/global.css +14 -0
  97. package/test/e2e/fixtures/basic-operations/dep-chain-linear/feature.ts +11 -0
  98. package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/__inherit__appLayout.tsx +27 -0
  99. package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx +8 -0
  100. package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx +17 -0
  101. package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/feature.ts +10 -0
  102. package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/__inherit__appLayout.tsx +27 -0
  103. package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/__inherit__home.tsx +0 -0
  104. package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx +8 -0
  105. package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx +17 -0
  106. package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/feature.ts +10 -0
  107. package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/__inherit__appLayout.tsx +27 -0
  108. package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/__prepend__index.tsx +2 -0
  109. package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/routes.tsx +17 -0
  110. package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx +9 -0
  111. package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/styles/__append__global.css +10 -0
  112. package/test/e2e/fixtures/basic-operations/feature-file-route-delete/feature.ts +10 -0
  113. package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/__delete__old-page.tsx +2 -0
  114. package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/__inherit__appLayout.tsx +27 -0
  115. package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx +16 -0
  116. package/test/e2e/fixtures/composition-5-features/5-features-about/feature.ts +3 -0
  117. package/test/e2e/fixtures/composition-5-features/5-features-about/template/digitalExperiences/webApplications/5-features-about/src/about.tsx +8 -0
  118. package/test/e2e/fixtures/composition-5-features/5-features-about/template/digitalExperiences/webApplications/5-features-about/src/routes.tsx +17 -0
  119. package/test/e2e/fixtures/composition-5-features/5-features-analytics/feature.ts +3 -0
  120. package/test/e2e/fixtures/composition-5-features/5-features-analytics/template/digitalExperiences/webApplications/5-features-analytics/src/__prepend__index.tsx +2 -0
  121. package/test/e2e/fixtures/composition-5-features/5-features-footer/feature.ts +3 -0
  122. package/test/e2e/fixtures/composition-5-features/5-features-footer/template/digitalExperiences/webApplications/5-features-footer/src/footer.tsx +7 -0
  123. package/test/e2e/fixtures/composition-5-features/5-features-footer/template/digitalExperiences/webApplications/5-features-footer/src/routes.tsx +17 -0
  124. package/test/e2e/fixtures/composition-5-features/5-features-navigation/feature.ts +3 -0
  125. package/test/e2e/fixtures/composition-5-features/5-features-navigation/template/digitalExperiences/webApplications/5-features-navigation/src/navigation.tsx +7 -0
  126. package/test/e2e/fixtures/composition-5-features/5-features-navigation/template/digitalExperiences/webApplications/5-features-navigation/src/routes.tsx +17 -0
  127. package/test/e2e/fixtures/composition-5-features/5-features-theme/feature.ts +3 -0
  128. package/test/e2e/fixtures/composition-5-features/5-features-theme/template/digitalExperiences/webApplications/5-features-theme/src/styles/__append__global.css +5 -0
  129. package/test/e2e/fixtures/composition-append/composition-append-1/feature.ts +10 -0
  130. package/test/e2e/fixtures/composition-append/composition-append-1/template/digitalExperiences/webApplications/composition-append-1/src/styles/__append__global.css +4 -0
  131. package/test/e2e/fixtures/composition-append/composition-append-2/feature.ts +10 -0
  132. package/test/e2e/fixtures/composition-append/composition-append-2/template/digitalExperiences/webApplications/composition-append-2/src/styles/__append__global.css +4 -0
  133. package/test/e2e/fixtures/composition-append/composition-append-3/feature.ts +10 -0
  134. package/test/e2e/fixtures/composition-append/composition-append-3/template/digitalExperiences/webApplications/composition-append-3/src/styles/__append__global.css +4 -0
  135. package/test/e2e/fixtures/composition-inherit-modify/composition-inherit-layout/feature.ts +3 -0
  136. package/test/e2e/fixtures/composition-inherit-modify/composition-inherit-layout/template/digitalExperiences/webApplications/composition-inherit-layout/src/__inherit__appLayout.tsx +1 -0
  137. package/test/e2e/fixtures/composition-inherit-modify/composition-modify-layout/feature.ts +3 -0
  138. package/test/e2e/fixtures/composition-inherit-modify/composition-modify-layout/template/digitalExperiences/webApplications/composition-modify-layout/src/__append__appLayout.tsx +2 -0
  139. package/test/e2e/fixtures/composition-prepend/composition-prepend-1/feature.ts +10 -0
  140. package/test/e2e/fixtures/composition-prepend/composition-prepend-1/template/digitalExperiences/webApplications/composition-prepend-1/src/__prepend__index.tsx +2 -0
  141. package/test/e2e/fixtures/composition-prepend/composition-prepend-2/feature.ts +10 -0
  142. package/test/e2e/fixtures/composition-prepend/composition-prepend-2/template/digitalExperiences/webApplications/composition-prepend-2/src/__prepend__index.tsx +2 -0
  143. package/test/e2e/fixtures/composition-prepend/composition-prepend-3/feature.ts +10 -0
  144. package/test/e2e/fixtures/composition-prepend/composition-prepend-3/template/digitalExperiences/webApplications/composition-prepend-3/src/__prepend__index.tsx +2 -0
  145. package/test/e2e/fixtures/dep-chain-long/dep-chain-a/feature.ts +11 -0
  146. package/test/e2e/fixtures/dep-chain-long/dep-chain-a/template/digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx +8 -0
  147. package/test/e2e/fixtures/dep-chain-long/dep-chain-a/template/digitalExperiences/webApplications/dep-chain-a/src/routes.tsx +17 -0
  148. package/test/e2e/fixtures/dep-chain-long/dep-chain-b/feature.ts +11 -0
  149. package/test/e2e/fixtures/dep-chain-long/dep-chain-b/template/digitalExperiences/webApplications/dep-chain-b/src/page-b.tsx +8 -0
  150. package/test/e2e/fixtures/dep-chain-long/dep-chain-b/template/digitalExperiences/webApplications/dep-chain-b/src/routes.tsx +17 -0
  151. package/test/e2e/fixtures/dep-chain-long/dep-chain-c/feature.ts +11 -0
  152. package/test/e2e/fixtures/dep-chain-long/dep-chain-c/template/digitalExperiences/webApplications/dep-chain-c/src/page-c.tsx +8 -0
  153. package/test/e2e/fixtures/dep-chain-long/dep-chain-c/template/digitalExperiences/webApplications/dep-chain-c/src/routes.tsx +17 -0
  154. package/test/e2e/fixtures/dep-chain-long/dep-chain-d/feature.ts +10 -0
  155. package/test/e2e/fixtures/dep-chain-long/dep-chain-d/template/digitalExperiences/webApplications/dep-chain-d/src/page-d.tsx +8 -0
  156. package/test/e2e/fixtures/dep-chain-long/dep-chain-d/template/digitalExperiences/webApplications/dep-chain-d/src/routes.tsx +17 -0
  157. package/test/e2e/fixtures/dep-circular/dep-circular-a/feature.ts +11 -0
  158. package/test/e2e/fixtures/dep-circular/dep-circular-a/template/digitalExperiences/webApplications/dep-circular-a/src/page-a.tsx +8 -0
  159. package/test/e2e/fixtures/dep-circular/dep-circular-b/feature.ts +11 -0
  160. package/test/e2e/fixtures/dep-circular/dep-circular-b/template/digitalExperiences/webApplications/dep-circular-b/src/page-b.tsx +8 -0
  161. package/test/e2e/fixtures/dep-complex-graph/README.md +119 -0
  162. package/test/e2e/fixtures/dep-complex-graph/create-placeholders.sh +25 -0
  163. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/feature.ts +14 -0
  164. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/__delete__old-page.tsx +1 -0
  165. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/__inherit__appLayout.tsx +1 -0
  166. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/login.tsx +8 -0
  167. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/routes.tsx +29 -0
  168. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/signup.tsx +1 -0
  169. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/feature.ts +14 -0
  170. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/__inherit__appLayout.tsx +1 -0
  171. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/analytics.tsx +1 -0
  172. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/dashboard.tsx +8 -0
  173. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/reports.tsx +1 -0
  174. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/routes.tsx +32 -0
  175. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/feature.ts +14 -0
  176. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/__inherit__appLayout.tsx +1 -0
  177. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/profile-edit.tsx +1 -0
  178. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/profile.tsx +8 -0
  179. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/routes.tsx +26 -0
  180. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/feature.ts +14 -0
  181. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/template/digitalExperiences/webApplications/dep-complex-graph-shared-components/src/__inherit__appLayout.tsx +1 -0
  182. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/template/digitalExperiences/webApplications/dep-complex-graph-shared-components/src/components.tsx +8 -0
  183. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/template/digitalExperiences/webApplications/dep-complex-graph-shared-components/src/routes.tsx +18 -0
  184. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/feature.ts +10 -0
  185. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/template/digitalExperiences/webApplications/dep-complex-graph-shared-types/src/__inherit__appLayout.tsx +1 -0
  186. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/template/digitalExperiences/webApplications/dep-complex-graph-shared-types/src/routes.tsx +17 -0
  187. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/template/digitalExperiences/webApplications/dep-complex-graph-shared-types/src/types.tsx +8 -0
  188. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/feature.ts +10 -0
  189. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/template/digitalExperiences/webApplications/dep-complex-graph-shared-utils/src/__inherit__appLayout.tsx +1 -0
  190. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/template/digitalExperiences/webApplications/dep-complex-graph-shared-utils/src/routes.tsx +18 -0
  191. package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/template/digitalExperiences/webApplications/dep-complex-graph-shared-utils/src/tools.tsx +1 -0
  192. package/test/e2e/fixtures/dep-complex-graph/feature.ts +15 -0
  193. package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/__inherit__appLayout.tsx +1 -0
  194. package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx +1 -0
  195. package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx +1 -0
  196. package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx +24 -0
  197. package/test/e2e/fixtures/dep-diamond/dep-diamond-left/feature.ts +11 -0
  198. package/test/e2e/fixtures/dep-diamond/dep-diamond-left/template/digitalExperiences/webApplications/dep-diamond-left/src/left-page.tsx +8 -0
  199. package/test/e2e/fixtures/dep-diamond/dep-diamond-left/template/digitalExperiences/webApplications/dep-diamond-left/src/routes.tsx +17 -0
  200. package/test/e2e/fixtures/dep-diamond/dep-diamond-right/feature.ts +11 -0
  201. package/test/e2e/fixtures/dep-diamond/dep-diamond-right/template/digitalExperiences/webApplications/dep-diamond-right/src/right-page.tsx +8 -0
  202. package/test/e2e/fixtures/dep-diamond/dep-diamond-right/template/digitalExperiences/webApplications/dep-diamond-right/src/routes.tsx +17 -0
  203. package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/feature.ts +10 -0
  204. package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/template/digitalExperiences/webApplications/dep-diamond-shared/src/routes.tsx +17 -0
  205. package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/template/digitalExperiences/webApplications/dep-diamond-shared/src/shared-utils.tsx +8 -0
  206. package/test/e2e/fixtures/edges/edge-binary-files/feature.ts +13 -0
  207. package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/__inherit__appLayout.tsx +1 -0
  208. package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/assets/test-image.png +0 -0
  209. package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/placeholder.tsx +0 -0
  210. package/test/e2e/fixtures/edges/edge-conflicting-prefixes/feature.ts +13 -0
  211. package/test/e2e/fixtures/edges/edge-conflicting-prefixes/template/digitalExperiences/webApplications/edge-conflicting-prefixes/src/__inherit____delete__conflicting.tsx +5 -0
  212. package/test/e2e/fixtures/edges/edge-conflicting-prefixes/template/digitalExperiences/webApplications/edge-conflicting-prefixes/src/placeholder.tsx +0 -0
  213. package/test/e2e/fixtures/edges/edge-empty-feature/feature.ts +16 -0
  214. package/test/e2e/fixtures/edges/edge-empty-feature/template/digitalExperiences/webApplications/edge-empty-feature/src/placeholder.tsx +0 -0
  215. package/test/e2e/fixtures/edges/edge-invalid-routes/feature.ts +12 -0
  216. package/test/e2e/fixtures/edges/edge-invalid-routes/template/digitalExperiences/webApplications/edge-invalid-routes/src/placeholder.tsx +0 -0
  217. package/test/e2e/fixtures/edges/edge-invalid-routes/template/digitalExperiences/webApplications/edge-invalid-routes/src/routes.tsx +8 -0
  218. package/test/e2e/fixtures/edges/edge-line-endings/feature.ts +13 -0
  219. package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/__prepend__index.tsx +2 -0
  220. package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/crlf.tsx +4 -0
  221. package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/placeholder.tsx +0 -0
  222. package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/styles/__append__global.css +4 -0
  223. package/test/e2e/fixtures/edges/edge-missing-base-files/feature.ts +13 -0
  224. package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/__inherit__missing.tsx +1 -0
  225. package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/__prepend__nonexistent.tsx +2 -0
  226. package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/placeholder.tsx +0 -0
  227. package/test/e2e/fixtures/edges/edge-package-json-conflicts-a/feature.ts +14 -0
  228. package/test/e2e/fixtures/edges/edge-package-json-conflicts-a/template/digitalExperiences/webApplications/edge-package-json-conflicts-a/src/placeholder.tsx +1 -0
  229. package/test/e2e/fixtures/edges/edge-package-json-conflicts-b/feature.ts +14 -0
  230. package/test/e2e/fixtures/edges/edge-package-json-conflicts-b/template/digitalExperiences/webApplications/edge-package-json-conflicts-b/src/placeholder.tsx +1 -0
  231. package/test/e2e/fixtures/edges/edge-performance-many/feature.ts +26 -0
  232. package/test/e2e/fixtures/edges/edge-performance-many/template/digitalExperiences/webApplications/edge-performance-many/src/placeholder.tsx +0 -0
  233. package/test/e2e/fixtures/path-mappings/feature-custom-mapping/feature.ts +16 -0
  234. package/test/e2e/fixtures/path-mappings/feature-custom-mapping/template/web/src/custom-component.tsx +3 -0
  235. package/test/e2e/fixtures/path-mappings/feature-custom-mapping/template/web/src/routes.tsx +8 -0
  236. package/test/e2e/fixtures/path-mappings/feature-mixed-paths/feature.ts +7 -0
  237. package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/digitalExperiences/webApplications/feature-mixed-paths/assets/icon.svg +3 -0
  238. package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/webApp/src/mapped-component.tsx +3 -0
  239. package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/webApp/src/routes.tsx +8 -0
  240. package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/feature.ts +7 -0
  241. package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/template/webApp/src/app.tsx +3 -0
  242. package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/template/webApp/src/routes.tsx +8 -0
  243. package/test/e2e/fixtures/path-mappings/feature-without-mapping/feature.ts +11 -0
  244. package/test/e2e/fixtures/path-mappings/feature-without-mapping/template/digitalExperiences/webApplications/feature-without-mapping/src/legacy-component.tsx +3 -0
  245. package/test/e2e/fixtures/path-mappings/feature-without-mapping/template/digitalExperiences/webApplications/feature-without-mapping/src/routes.tsx +8 -0
  246. package/test/e2e/fixtures/scenarios/scenario-authentication/feature.ts +10 -0
  247. package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/components/LoginForm.tsx +25 -0
  248. package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/context/AuthContext.tsx +28 -0
  249. package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/login.tsx +10 -0
  250. package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/placeholder.tsx +0 -0
  251. package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/routes.tsx +17 -0
  252. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/feature.ts +11 -0
  253. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/__inherit__appLayout.tsx +1 -0
  254. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactDetail.tsx +54 -0
  255. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactForm.tsx +146 -0
  256. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactList.tsx +77 -0
  257. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/placeholder.tsx +0 -0
  258. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/routes.tsx +36 -0
  259. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/styles/__append__global.css +176 -0
  260. package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/utils/contactsApi.ts +42 -0
  261. package/test/e2e/fixtures/scenarios/scenario-navigation-menu/feature.ts +10 -0
  262. package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/__append__appLayout.tsx +4 -0
  263. package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/components/NavigationMenu.tsx +17 -0
  264. package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/placeholder.tsx +0 -0
  265. package/test/e2e/fixtures/single-operations/feature-file-append/feature.ts +10 -0
  266. package/test/e2e/fixtures/single-operations/feature-file-append/template/digitalExperiences/webApplications/feature-file-append/src/styles/__append__global.css +10 -0
  267. package/test/e2e/fixtures/single-operations/feature-file-inherit/feature.ts +10 -0
  268. package/test/e2e/fixtures/single-operations/feature-file-inherit/template/digitalExperiences/webApplications/feature-file-inherit/src/__inherit__appLayout.tsx +1 -0
  269. package/test/e2e/fixtures/single-operations/feature-file-inherit/template/digitalExperiences/webApplications/feature-file-inherit/src/__inherit__home.tsx +1 -0
  270. package/test/e2e/fixtures/single-operations/feature-file-prepend/feature.ts +10 -0
  271. package/test/e2e/fixtures/single-operations/feature-file-prepend/template/digitalExperiences/webApplications/feature-file-prepend/src/__prepend__index.tsx +2 -0
  272. package/test/e2e/fixtures/single-operations/feature-import-merge/feature.ts +10 -0
  273. package/test/e2e/fixtures/single-operations/feature-import-merge/template/digitalExperiences/webApplications/feature-import-merge/src/routes.tsx +18 -0
  274. package/test/e2e/fixtures/single-operations/feature-import-merge/template/digitalExperiences/webApplications/feature-import-merge/src/settings.tsx +8 -0
  275. package/test/e2e/fixtures/single-operations/feature-route-add/feature.ts +10 -0
  276. package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/about.tsx +8 -0
  277. package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/routes.tsx +23 -0
  278. package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/services.tsx +8 -0
  279. package/test/e2e/fixtures/watch/watch-add-delete-files/feature.ts +13 -0
  280. package/test/e2e/fixtures/watch/watch-add-delete-files/template/digitalExperiences/webApplications/watch-add-delete-files/src/initial.tsx +4 -0
  281. package/test/e2e/fixtures/watch/watch-add-delete-files/template/digitalExperiences/webApplications/watch-add-delete-files/src/placeholder.tsx +4 -0
  282. package/test/e2e/fixtures/watch/watch-basic/feature.ts +13 -0
  283. package/test/e2e/fixtures/watch/watch-basic/template/digitalExperiences/webApplications/watch-basic/src/placeholder.tsx +4 -0
  284. package/test/e2e/fixtures/watch/watch-basic/template/digitalExperiences/webApplications/watch-basic/src/watchTest.tsx +3 -0
  285. package/test/e2e/fixtures/watch/watch-debounce/feature.ts +13 -0
  286. package/test/e2e/fixtures/watch/watch-debounce/template/digitalExperiences/webApplications/watch-debounce/src/placeholder.tsx +4 -0
  287. package/test/e2e/fixtures/watch/watch-multiple-files/feature.ts +13 -0
  288. package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/components/WatchComponent.tsx +3 -0
  289. package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/placeholder.tsx +4 -0
  290. package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/styles/theme.css +4 -0
  291. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/package.json +10 -0
  292. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/about.tsx +8 -0
  293. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/appLayout.tsx +27 -0
  294. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx +8 -0
  295. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/home.tsx +8 -0
  296. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/index.tsx +10 -0
  297. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/old-page.tsx +8 -0
  298. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx +35 -0
  299. package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/styles/global.css +14 -0
  300. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/package.json +10 -0
  301. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/appLayout.tsx +27 -0
  302. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/home.tsx +8 -0
  303. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/index.tsx +10 -0
  304. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/old-page.tsx +8 -0
  305. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx +8 -0
  306. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-b.tsx +8 -0
  307. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-c.tsx +8 -0
  308. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-d.tsx +8 -0
  309. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/routes.tsx +47 -0
  310. package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/styles/global.css +14 -0
  311. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/package.json +10 -0
  312. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx +1 -0
  313. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx +1 -0
  314. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/analytics.tsx +1 -0
  315. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/appLayout.tsx +27 -0
  316. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/components.tsx +8 -0
  317. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/dashboard.tsx +8 -0
  318. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/home.tsx +8 -0
  319. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/index.tsx +10 -0
  320. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/login.tsx +8 -0
  321. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/profile-edit.tsx +1 -0
  322. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/profile.tsx +8 -0
  323. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/reports.tsx +1 -0
  324. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx +94 -0
  325. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/signup.tsx +1 -0
  326. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/styles/global.css +14 -0
  327. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/tools.tsx +1 -0
  328. package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/types.tsx +8 -0
  329. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/package.json +10 -0
  330. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/appLayout.tsx +27 -0
  331. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/custom-component.tsx +3 -0
  332. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/home.tsx +8 -0
  333. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/index.tsx +10 -0
  334. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/old-page.tsx +8 -0
  335. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/routes.tsx +28 -0
  336. package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/styles/global.css +14 -0
  337. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/package.json +10 -0
  338. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx +8 -0
  339. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/appLayout.tsx +27 -0
  340. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/home.tsx +8 -0
  341. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/index.tsx +10 -0
  342. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/old-page.tsx +8 -0
  343. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx +29 -0
  344. package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/styles/global.css +14 -0
  345. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/package.json +10 -0
  346. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/appLayout.tsx +27 -0
  347. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/home.tsx +8 -0
  348. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/index.tsx +13 -0
  349. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/old-page.tsx +8 -0
  350. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/routes.tsx +29 -0
  351. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx +9 -0
  352. package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/styles/global.css +25 -0
  353. package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/package.json +10 -0
  354. package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/appLayout.tsx +27 -0
  355. package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/home.tsx +8 -0
  356. package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/index.tsx +10 -0
  357. package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx +17 -0
  358. package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/styles/global.css +14 -0
  359. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/assets/icon.svg +3 -0
  360. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/package.json +10 -0
  361. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/appLayout.tsx +27 -0
  362. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/home.tsx +8 -0
  363. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/index.tsx +10 -0
  364. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/mapped-component.tsx +3 -0
  365. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/old-page.tsx +8 -0
  366. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/routes.tsx +28 -0
  367. package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/styles/global.css +14 -0
  368. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/package.json +10 -0
  369. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/app.tsx +3 -0
  370. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/appLayout.tsx +27 -0
  371. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/home.tsx +8 -0
  372. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/index.tsx +10 -0
  373. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/old-page.tsx +8 -0
  374. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/routes.tsx +28 -0
  375. package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/styles/global.css +14 -0
  376. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/package.json +10 -0
  377. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/appLayout.tsx +27 -0
  378. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/home.tsx +8 -0
  379. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/index.tsx +10 -0
  380. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/legacy-component.tsx +3 -0
  381. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/old-page.tsx +8 -0
  382. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/routes.tsx +28 -0
  383. package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/styles/global.css +14 -0
  384. package/test/e2e/path-mappings.spec.ts +232 -0
  385. package/test/e2e/watch-patches.spec.ts +237 -0
  386. package/test/helpers/cli-runner.ts +100 -0
  387. package/test/helpers/compare-directories.ts +197 -0
  388. package/test/helpers/create-temp-dir.ts +34 -0
  389. package/test/helpers/fixtures.ts +67 -0
  390. package/test/setup.ts +6 -0
  391. package/test/unit/debounce.spec.ts +159 -0
  392. package/test/unit/dependency-resolver.spec.ts +260 -0
  393. package/test/unit/file-operations.spec.ts +264 -0
  394. package/test/unit/import-merger.spec.ts +395 -0
  395. package/test/unit/index.spec.ts +158 -0
  396. package/test/unit/new-app.spec.ts +178 -0
  397. package/test/unit/new-feature.spec.ts +178 -0
  398. package/test/unit/package-json-merger.spec.ts +275 -0
  399. package/test/unit/patch-loader.spec.ts +238 -0
  400. package/test/unit/path-mappings.spec.ts +241 -0
  401. package/test/unit/paths.spec.ts +247 -0
  402. package/test/unit/route-merger.spec.ts +265 -0
  403. package/test/unit/validation.spec.ts +311 -0
  404. package/tsconfig.json +20 -0
  405. package/vitest.config.ts +18 -0
@@ -0,0 +1,178 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { newAppOrFeatureCommand } from '../../src/commands/new-app-feature.js';
3
+ import { ValidationError } from '../../src/utils/validation.js';
4
+ import { rmSync, existsSync, readFileSync } from 'fs';
5
+ import { join } from 'path';
6
+
7
+ // Note: These tests run against the actual monorepo structure
8
+ // They create real apps in packages/ directory and clean them up after
9
+ describe('new-app command', () => {
10
+ let testAppNames: string[] = [];
11
+ let monorepoRoot: string;
12
+
13
+ beforeEach(() => {
14
+ // Track app names created during tests for cleanup
15
+ testAppNames = [];
16
+ monorepoRoot = process.cwd().includes('/packages/cli')
17
+ ? join(process.cwd(), '../..')
18
+ : process.cwd();
19
+ });
20
+
21
+ afterEach(() => {
22
+ // Clean up any test apps that were created
23
+ for (const appName of testAppNames) {
24
+ const appPath = join(monorepoRoot, 'packages', appName);
25
+ if (existsSync(appPath)) {
26
+ rmSync(appPath, { recursive: true, force: true });
27
+ }
28
+ }
29
+ });
30
+
31
+ describe('validation', () => {
32
+ it('should reject invalid app names', async () => {
33
+ await expect(newAppOrFeatureCommand('Invalid_Name', 'app')).rejects.toThrow(ValidationError);
34
+ await expect(newAppOrFeatureCommand('Invalid_Name', 'app')).rejects.toThrow(/invalid.*kebab-case/);
35
+ });
36
+
37
+ it('should reject empty app names', async () => {
38
+ await expect(newAppOrFeatureCommand('', 'app')).rejects.toThrow(ValidationError);
39
+ await expect(newAppOrFeatureCommand('', 'app')).rejects.toThrow(/cannot be empty/);
40
+ });
41
+
42
+ it('should reject reserved names', async () => {
43
+ await expect(newAppOrFeatureCommand('app', 'app')).rejects.toThrow(ValidationError);
44
+ await expect(newAppOrFeatureCommand('app', 'app')).rejects.toThrow(/reserved/);
45
+
46
+ await expect(newAppOrFeatureCommand('feature', 'app')).rejects.toThrow(ValidationError);
47
+ await expect(newAppOrFeatureCommand('feature', 'app')).rejects.toThrow(/reserved/);
48
+ });
49
+
50
+ it('should reject if app already exists', async () => {
51
+ // Use an existing app (navigation-menu) which should already exist
52
+ await expect(newAppOrFeatureCommand('vibe-coding-starter', 'app')).rejects.toThrow(ValidationError);
53
+ await expect(newAppOrFeatureCommand('vibe-coding-starter', 'app')).rejects.toThrow(/already exists/);
54
+ });
55
+
56
+ it('should reject names that are too long', async () => {
57
+ const tooLongName = 'a'.repeat(51);
58
+ await expect(newAppOrFeatureCommand(tooLongName, 'app')).rejects.toThrow(ValidationError);
59
+ await expect(newAppOrFeatureCommand(tooLongName, 'app')).rejects.toThrow(/too long/);
60
+ });
61
+ });
62
+
63
+ describe('app creation', () => {
64
+ it('should create app directory with all required files', async () => {
65
+ const testName = `test-unit-${Date.now()}`;
66
+ testAppNames.push(`app-${testName}`);
67
+
68
+ await newAppOrFeatureCommand(testName, 'app');
69
+
70
+ const appPath = join(monorepoRoot, 'packages', `app-${testName}`);
71
+
72
+ // Check directory and files exist
73
+ expect(existsSync(appPath)).toBe(true);
74
+ expect(existsSync(join(appPath, 'package.json'))).toBe(true);
75
+ expect(existsSync(join(appPath, 'feature.ts'))).toBe(true);
76
+ expect(existsSync(join(appPath, 'tsconfig.app.json'))).toBe(true);
77
+ expect(existsSync(join(appPath, 'template'))).toBe(true);
78
+ });
79
+
80
+ it('should update package.json with correct name and scripts', async () => {
81
+ const testName = `test-pkgjson-${Date.now()}`;
82
+ testAppNames.push(`app-${testName}`);
83
+
84
+ await newAppOrFeatureCommand(testName, 'app');
85
+
86
+ const appPath = join(monorepoRoot, 'packages', `app-${testName}`);
87
+ const packageJson = JSON.parse(readFileSync(join(appPath, 'package.json'), 'utf-8'));
88
+
89
+ // Check name
90
+ expect(packageJson.name).toBe(`app-${testName}`);
91
+
92
+ // Check scripts are updated
93
+ expect(packageJson.scripts.dev).toContain(`app-${testName}`);
94
+ expect(packageJson.scripts.dev).not.toContain('base-reference-app');
95
+ });
96
+
97
+ // it('should update tsconfig.app.json include path', async () => {
98
+ // const testName = `test-tsconfig-${Date.now()}`;
99
+ // testFeatureNames.push(`feature-${testName}`);
100
+
101
+ // await newFeatureCommand(testName);
102
+
103
+ // const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
104
+ // const tsconfigContent = readFileSync(join(featurePath, 'tsconfig.app.json'), 'utf-8');
105
+
106
+ // // Should contain the new path
107
+ // expect(tsconfigContent).toContain(`template/digitalExperiences/webApplications/${testName}`);
108
+
109
+ // // Should not contain base-feature
110
+ // expect(tsconfigContent).not.toContain('base-feature');
111
+ // });
112
+
113
+ it('should auto-prefix app name with "app-"', async () => {
114
+ const testName = `autoprefix-${Date.now()}`;
115
+ testAppNames.push(`app-${testName}`);
116
+
117
+ await newAppOrFeatureCommand(testName, 'app');
118
+
119
+ const appPath = join(monorepoRoot, 'packages', `app-${testName}`);
120
+ expect(existsSync(appPath)).toBe(true);
121
+
122
+ const packageJson = JSON.parse(readFileSync(join(appPath, 'package.json'), 'utf-8'));
123
+ expect(packageJson.name).toBe(`app-${testName}`);
124
+ });
125
+
126
+ it('should not double-prefix if name already starts with "app-"', async () => {
127
+ const testName = `doubleprefix-${Date.now()}`;
128
+ testAppNames.push(`app-${testName}`);
129
+
130
+ await newAppOrFeatureCommand(`app-${testName}`, 'app');
131
+
132
+ const appPath = join(monorepoRoot, 'packages', `app-${testName}`);
133
+ expect(existsSync(appPath)).toBe(true);
134
+
135
+ // Should not create app-app-{testName}
136
+ const wrongPath = join(monorepoRoot, 'packages', `app-app-${testName}`);
137
+ expect(existsSync(wrongPath)).toBe(false);
138
+ });
139
+
140
+ it('should handle hyphenated app names', async () => {
141
+ const testName = `user-auth-${Date.now()}`;
142
+ testAppNames.push(`app-${testName}`);
143
+
144
+ await newAppOrFeatureCommand(testName, 'app');
145
+
146
+ const appPath = join(monorepoRoot, 'packages', `app-${testName}`);
147
+ expect(existsSync(appPath)).toBe(true);
148
+
149
+ const packageJson = JSON.parse(readFileSync(join(appPath, 'package.json'), 'utf-8'));
150
+ expect(packageJson.name).toBe(`app-${testName}`);
151
+ });
152
+ });
153
+
154
+ describe('error handling', () => {
155
+ it('should throw ValidationError for duplicate app', async () => {
156
+ const testName = `duplicate-${Date.now()}`;
157
+ testAppNames.push(`app-${testName}`);
158
+
159
+ // Create first app
160
+ await newAppOrFeatureCommand(testName, 'app');
161
+
162
+ // Try to create again with same name
163
+ await expect(newAppOrFeatureCommand(testName, 'app')).rejects.toThrow(ValidationError);
164
+ await expect(newAppOrFeatureCommand(testName, 'app')).rejects.toThrow(/already exists/);
165
+ });
166
+
167
+ it('should provide clear error messages', async () => {
168
+ try {
169
+ await newAppOrFeatureCommand('Invalid_Name', 'app');
170
+ expect.fail('Should have thrown an error');
171
+ } catch (err) {
172
+ expect(err).toBeInstanceOf(ValidationError);
173
+ expect((err as Error).message).toContain('invalid');
174
+ expect((err as Error).message).toContain('Examples:');
175
+ }
176
+ });
177
+ });
178
+ });
@@ -0,0 +1,178 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { newAppOrFeatureCommand } from '../../src/commands/new-app-feature.js';
3
+ import { ValidationError } from '../../src/utils/validation.js';
4
+ import { rmSync, existsSync, readFileSync } from 'fs';
5
+ import { join } from 'path';
6
+
7
+ // Note: These tests run against the actual monorepo structure
8
+ // They create real features in packages/ directory and clean them up after
9
+ describe('new-feature command', () => {
10
+ let testFeatureNames: string[] = [];
11
+ let monorepoRoot: string;
12
+
13
+ beforeEach(() => {
14
+ // Track feature names created during tests for cleanup
15
+ testFeatureNames = [];
16
+ monorepoRoot = process.cwd().includes('/packages/cli')
17
+ ? join(process.cwd(), '../..')
18
+ : process.cwd();
19
+ });
20
+
21
+ afterEach(() => {
22
+ // Clean up any test features that were created
23
+ for (const featureName of testFeatureNames) {
24
+ const featurePath = join(monorepoRoot, 'packages', featureName);
25
+ if (existsSync(featurePath)) {
26
+ rmSync(featurePath, { recursive: true, force: true });
27
+ }
28
+ }
29
+ });
30
+
31
+ describe('validation', () => {
32
+ it('should reject invalid feature names', async () => {
33
+ await expect(newAppOrFeatureCommand('Invalid_Name', 'feature')).rejects.toThrow(ValidationError);
34
+ await expect(newAppOrFeatureCommand('Invalid_Name', 'feature')).rejects.toThrow(/invalid.*kebab-case/);
35
+ });
36
+
37
+ it('should reject empty feature names', async () => {
38
+ await expect(newAppOrFeatureCommand('', 'feature')).rejects.toThrow(ValidationError);
39
+ await expect(newAppOrFeatureCommand('', 'feature')).rejects.toThrow(/cannot be empty/);
40
+ });
41
+
42
+ it('should reject reserved names', async () => {
43
+ await expect(newAppOrFeatureCommand('app', 'feature')).rejects.toThrow(ValidationError);
44
+ await expect(newAppOrFeatureCommand('app', 'feature')).rejects.toThrow(/reserved/);
45
+
46
+ await expect(newAppOrFeatureCommand('feature', 'feature')).rejects.toThrow(ValidationError);
47
+ await expect(newAppOrFeatureCommand('feature', 'feature')).rejects.toThrow(/reserved/);
48
+ });
49
+
50
+ it('should reject if feature already exists', async () => {
51
+ // Use an existing feature (navigation-menu) which should already exist
52
+ await expect(newAppOrFeatureCommand('navigation-menu', 'feature')).rejects.toThrow(ValidationError);
53
+ await expect(newAppOrFeatureCommand('navigation-menu', 'feature')).rejects.toThrow(/already exists/);
54
+ });
55
+
56
+ it('should reject names that are too long', async () => {
57
+ const tooLongName = 'a'.repeat(51);
58
+ await expect(newAppOrFeatureCommand(tooLongName, 'feature')).rejects.toThrow(ValidationError);
59
+ await expect(newAppOrFeatureCommand(tooLongName, 'feature')).rejects.toThrow(/too long/);
60
+ });
61
+ });
62
+
63
+ describe('feature creation', () => {
64
+ it('should create feature directory with all required files', async () => {
65
+ const testName = `test-unit-${Date.now()}`;
66
+ testFeatureNames.push(`feature-${testName}`);
67
+
68
+ await newAppOrFeatureCommand(testName, 'feature');
69
+
70
+ const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
71
+
72
+ // Check directory and files exist
73
+ expect(existsSync(featurePath)).toBe(true);
74
+ expect(existsSync(join(featurePath, 'package.json'))).toBe(true);
75
+ expect(existsSync(join(featurePath, 'feature.ts'))).toBe(true);
76
+ expect(existsSync(join(featurePath, 'tsconfig.app.json'))).toBe(true);
77
+ expect(existsSync(join(featurePath, 'template'))).toBe(true);
78
+ });
79
+
80
+ it('should update package.json with correct name and scripts', async () => {
81
+ const testName = `test-pkgjson-${Date.now()}`;
82
+ testFeatureNames.push(`feature-${testName}`);
83
+
84
+ await newAppOrFeatureCommand(testName, 'feature');
85
+
86
+ const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
87
+ const packageJson = JSON.parse(readFileSync(join(featurePath, 'package.json'), 'utf-8'));
88
+
89
+ // Check name
90
+ expect(packageJson.name).toBe(`feature-${testName}`);
91
+
92
+ // Check scripts are updated
93
+ expect(packageJson.scripts.dev).toContain(`feature-${testName}`);
94
+ expect(packageJson.scripts.dev).not.toContain('base-feature');
95
+ });
96
+
97
+ // it('should update tsconfig.app.json include path', async () => {
98
+ // const testName = `test-tsconfig-${Date.now()}`;
99
+ // testFeatureNames.push(`feature-${testName}`);
100
+
101
+ // await newFeatureCommand(testName);
102
+
103
+ // const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
104
+ // const tsconfigContent = readFileSync(join(featurePath, 'tsconfig.app.json'), 'utf-8');
105
+
106
+ // // Should contain the new path
107
+ // expect(tsconfigContent).toContain(`template/digitalExperiences/webApplications/${testName}`);
108
+
109
+ // // Should not contain base-feature
110
+ // expect(tsconfigContent).not.toContain('base-feature');
111
+ // });
112
+
113
+ it('should auto-prefix feature name with "feature-"', async () => {
114
+ const testName = `autoprefix-${Date.now()}`;
115
+ testFeatureNames.push(`feature-${testName}`);
116
+
117
+ await newAppOrFeatureCommand(testName, 'feature');
118
+
119
+ const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
120
+ expect(existsSync(featurePath)).toBe(true);
121
+
122
+ const packageJson = JSON.parse(readFileSync(join(featurePath, 'package.json'), 'utf-8'));
123
+ expect(packageJson.name).toBe(`feature-${testName}`);
124
+ });
125
+
126
+ it('should not double-prefix if name already starts with "feature-"', async () => {
127
+ const testName = `doubleprefix-${Date.now()}`;
128
+ testFeatureNames.push(`feature-${testName}`);
129
+
130
+ await newAppOrFeatureCommand(`feature-${testName}`, 'feature');
131
+
132
+ const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
133
+ expect(existsSync(featurePath)).toBe(true);
134
+
135
+ // Should not create feature-feature-{testName}
136
+ const wrongPath = join(monorepoRoot, 'packages', `feature-feature-${testName}`);
137
+ expect(existsSync(wrongPath)).toBe(false);
138
+ });
139
+
140
+ it('should handle hyphenated feature names', async () => {
141
+ const testName = `user-auth-${Date.now()}`;
142
+ testFeatureNames.push(`feature-${testName}`);
143
+
144
+ await newAppOrFeatureCommand(testName, 'feature');
145
+
146
+ const featurePath = join(monorepoRoot, 'packages', `feature-${testName}`);
147
+ expect(existsSync(featurePath)).toBe(true);
148
+
149
+ const packageJson = JSON.parse(readFileSync(join(featurePath, 'package.json'), 'utf-8'));
150
+ expect(packageJson.name).toBe(`feature-${testName}`);
151
+ });
152
+ });
153
+
154
+ describe('error handling', () => {
155
+ it('should throw ValidationError for duplicate feature', async () => {
156
+ const testName = `duplicate-${Date.now()}`;
157
+ testFeatureNames.push(`feature-${testName}`);
158
+
159
+ // Create first feature
160
+ await newAppOrFeatureCommand(testName, 'feature');
161
+
162
+ // Try to create again with same name
163
+ await expect(newAppOrFeatureCommand(testName, 'feature')).rejects.toThrow(ValidationError);
164
+ await expect(newAppOrFeatureCommand(testName, 'feature')).rejects.toThrow(/already exists/);
165
+ });
166
+
167
+ it('should provide clear error messages', async () => {
168
+ try {
169
+ await newAppOrFeatureCommand('Invalid_Name', 'feature');
170
+ expect.fail('Should have thrown an error');
171
+ } catch (err) {
172
+ expect(err).toBeInstanceOf(ValidationError);
173
+ expect((err as Error).message).toContain('invalid');
174
+ expect((err as Error).message).toContain('Examples:');
175
+ }
176
+ });
177
+ });
178
+ });
@@ -0,0 +1,275 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { PackageJsonMergeError } from '../../src/core/package-json-merger.js';
3
+
4
+ // Mock dependencies at the top level
5
+ vi.mock('fs');
6
+ vi.mock('../../src/utils/validation.js');
7
+ vi.mock('../../src/utils/logger.js');
8
+ vi.mock('child_process');
9
+
10
+ describe('package-json-merger', () => {
11
+ beforeEach(() => {
12
+ vi.resetModules();
13
+ vi.clearAllMocks();
14
+ });
15
+
16
+ describe('buildPackageSpecs', () => {
17
+ it('should build package specs from dependencies object', async () => {
18
+ const { buildPackageSpecs } = await import('../../src/core/package-json-merger.js');
19
+ const dependencies = {
20
+ 'react': '^18.0.0',
21
+ 'react-dom': '^18.0.0'
22
+ };
23
+
24
+ const result = buildPackageSpecs(dependencies);
25
+
26
+ expect(result).toEqual(['react@^18.0.0', 'react-dom@^18.0.0']);
27
+ });
28
+
29
+ it('should handle single dependency', async () => {
30
+ const { buildPackageSpecs } = await import('../../src/core/package-json-merger.js');
31
+ const dependencies = {
32
+ 'lodash': '^4.17.21'
33
+ };
34
+
35
+ const result = buildPackageSpecs(dependencies);
36
+
37
+ expect(result).toEqual(['lodash@^4.17.21']);
38
+ });
39
+
40
+ it('should handle empty dependencies object', async () => {
41
+ const { buildPackageSpecs } = await import('../../src/core/package-json-merger.js');
42
+ const dependencies = {};
43
+
44
+ const result = buildPackageSpecs(dependencies);
45
+
46
+ expect(result).toEqual([]);
47
+ });
48
+
49
+ it('should handle scoped packages', async () => {
50
+ const { buildPackageSpecs } = await import('../../src/core/package-json-merger.js');
51
+ const dependencies = {
52
+ '@types/node': '^20.0.0',
53
+ '@babel/core': '^7.22.0'
54
+ };
55
+
56
+ const result = buildPackageSpecs(dependencies);
57
+
58
+ expect(result).toEqual(['@types/node@^20.0.0', '@babel/core@^7.22.0']);
59
+ });
60
+ });
61
+
62
+ describe('buildInstallCommand', () => {
63
+ it('should build yarn command for regular dependencies', async () => {
64
+ const { buildInstallCommand } = await import('../../src/core/package-json-merger.js');
65
+ const packageSpecs = ['react@^18.0.0', 'react-dom@^18.0.0'];
66
+
67
+ const result = buildInstallCommand(packageSpecs, false);
68
+
69
+ expect(result).toBe('yarn react@^18.0.0 react-dom@^18.0.0');
70
+ });
71
+
72
+ it('should build yarn command for dev dependencies', async () => {
73
+ const { buildInstallCommand } = await import('../../src/core/package-json-merger.js');
74
+ const packageSpecs = ['typescript@^5.0.0', 'vitest@^1.0.0'];
75
+
76
+ const result = buildInstallCommand(packageSpecs, true);
77
+
78
+ expect(result).toBe('yarn --dev typescript@^5.0.0 vitest@^1.0.0');
79
+ });
80
+
81
+ it('should differentiate between dev and regular dependencies', async () => {
82
+ const { buildInstallCommand } = await import('../../src/core/package-json-merger.js');
83
+ const packageSpecs = ['example@1.0.0'];
84
+
85
+ const regularCmd = buildInstallCommand(packageSpecs, false);
86
+ const devCmd = buildInstallCommand(packageSpecs, true);
87
+
88
+ expect(regularCmd).not.toContain('--dev');
89
+ expect(devCmd).toContain('--dev');
90
+ });
91
+ });
92
+
93
+ describe('executeNpmInstall', () => {
94
+ it('should call execSync with correct parameters', async () => {
95
+ const { execSync } = await import('child_process');
96
+ const { executeNpmInstall } = await import('../../src/core/package-json-merger.js');
97
+
98
+ vi.mocked(execSync).mockImplementation(() => Buffer.from(''));
99
+
100
+ executeNpmInstall('yarn react@^18.0.0', '/path/to/dir');
101
+
102
+ expect(execSync).toHaveBeenCalledWith('yarn react@^18.0.0', {
103
+ cwd: '/path/to/dir',
104
+ stdio: 'inherit'
105
+ });
106
+ });
107
+ });
108
+
109
+ describe('mergePackageJson', () => {
110
+ it('should return empty array when no dependencies', async () => {
111
+ const fs = await import('fs');
112
+ const validation = await import('../../src/utils/validation.js');
113
+
114
+ vi.mocked(fs.existsSync).mockReturnValue(true);
115
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
116
+
117
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
118
+
119
+ const result = await mergePackageJson('/target', {});
120
+
121
+ expect(result).toEqual([]);
122
+ });
123
+
124
+ it('should throw if package.json does not exist', async () => {
125
+ const fs = await import('fs');
126
+ const validation = await import('../../src/utils/validation.js');
127
+
128
+ vi.mocked(fs.existsSync).mockReturnValue(false);
129
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
130
+
131
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
132
+
133
+ await expect(mergePackageJson('/target', { dependencies: { 'react': '1.0.0' } }))
134
+ .rejects.toThrow(/package.json not found/);
135
+
136
+ try {
137
+ await mergePackageJson('/target', { dependencies: { 'react': '1.0.0' } });
138
+ } catch (err) {
139
+ expect((err as Error).name).toBe('PackageJsonMergeError');
140
+ }
141
+ });
142
+
143
+ it('should install dependencies successfully', async () => {
144
+ const fs = await import('fs');
145
+ const validation = await import('../../src/utils/validation.js');
146
+ const childProcess = await import('child_process');
147
+
148
+ vi.mocked(fs.existsSync).mockReturnValue(true);
149
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
150
+ vi.mocked(childProcess.execSync).mockImplementation(() => Buffer.from(''));
151
+
152
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
153
+
154
+ const result = await mergePackageJson('/target', {
155
+ dependencies: { 'react': '^18.0.0' }
156
+ });
157
+
158
+ expect(result).toContain('react@^18.0.0');
159
+ expect(childProcess.execSync).toHaveBeenCalledWith(
160
+ 'yarn react@^18.0.0',
161
+ expect.objectContaining({ cwd: '/app/path' })
162
+ );
163
+ });
164
+
165
+ it('should install devDependencies successfully', async () => {
166
+ const fs = await import('fs');
167
+ const validation = await import('../../src/utils/validation.js');
168
+ const childProcess = await import('child_process');
169
+
170
+ vi.mocked(fs.existsSync).mockReturnValue(true);
171
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
172
+ vi.mocked(childProcess.execSync).mockImplementation(() => Buffer.from(''));
173
+
174
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
175
+
176
+ const result = await mergePackageJson('/target', {
177
+ devDependencies: { 'typescript': '^5.0.0' }
178
+ });
179
+
180
+ expect(result).toContain('typescript@^5.0.0 (dev)');
181
+ expect(childProcess.execSync).toHaveBeenCalledWith(
182
+ 'yarn --dev typescript@^5.0.0',
183
+ expect.objectContaining({ cwd: '/app/path' })
184
+ );
185
+ });
186
+
187
+ it('should handle both dependencies and devDependencies', async () => {
188
+ const fs = await import('fs');
189
+ const validation = await import('../../src/utils/validation.js');
190
+ const childProcess = await import('child_process');
191
+
192
+ vi.mocked(fs.existsSync).mockReturnValue(true);
193
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
194
+ vi.mocked(childProcess.execSync).mockImplementation(() => Buffer.from(''));
195
+
196
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
197
+
198
+ const result = await mergePackageJson('/target', {
199
+ dependencies: { 'react': '^18.0.0' },
200
+ devDependencies: { 'typescript': '^5.0.0' }
201
+ });
202
+
203
+ expect(result).toContain('react@^18.0.0');
204
+ expect(result).toContain('typescript@^5.0.0 (dev)');
205
+ expect(childProcess.execSync).toHaveBeenCalledTimes(2);
206
+ });
207
+
208
+ it('should throw error if yarn fails', async () => {
209
+ const fs = await import('fs');
210
+ const validation = await import('../../src/utils/validation.js');
211
+ const childProcess = await import('child_process');
212
+
213
+ vi.mocked(fs.existsSync).mockReturnValue(true);
214
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
215
+ vi.mocked(childProcess.execSync).mockImplementation(() => {
216
+ throw new Error('yarn failed');
217
+ });
218
+
219
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
220
+
221
+ await expect(mergePackageJson('/target', { dependencies: { 'react': '1.0.0' } }))
222
+ .rejects.toThrow(/Failed to install dependencies/);
223
+
224
+ try {
225
+ await mergePackageJson('/target', { dependencies: { 'react': '1.0.0' } });
226
+ } catch (err) {
227
+ expect((err as Error).name).toBe('PackageJsonMergeError');
228
+ }
229
+ });
230
+
231
+ it('should use provided webAppDirPath', async () => {
232
+ const fs = await import('fs');
233
+ const childProcess = await import('child_process');
234
+
235
+ vi.mocked(fs.existsSync).mockReturnValue(true);
236
+ vi.mocked(childProcess.execSync).mockImplementation(() => Buffer.from(''));
237
+
238
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
239
+
240
+ await mergePackageJson('/target', { dependencies: { 'react': '1.0.0' } }, '/custom/path');
241
+
242
+ expect(childProcess.execSync).toHaveBeenCalledWith(
243
+ 'yarn react@1.0.0',
244
+ expect.objectContaining({ cwd: '/custom/path' })
245
+ );
246
+ });
247
+
248
+ it('should handle empty dependencies object', async () => {
249
+ const fs = await import('fs');
250
+ const validation = await import('../../src/utils/validation.js');
251
+ const childProcess = await import('child_process');
252
+
253
+ vi.mocked(fs.existsSync).mockReturnValue(true);
254
+ vi.mocked(validation.getWebApplicationPath).mockReturnValue('/app/path');
255
+ vi.mocked(childProcess.execSync).mockImplementation(() => Buffer.from(''));
256
+
257
+ const { mergePackageJson } = await import('../../src/core/package-json-merger.js');
258
+
259
+ const result = await mergePackageJson('/target', { dependencies: {} });
260
+
261
+ expect(result).toEqual([]);
262
+ expect(childProcess.execSync).not.toHaveBeenCalled();
263
+ });
264
+ });
265
+
266
+ describe('PackageJsonMergeError', () => {
267
+ it('should be throwable with custom message', () => {
268
+ const error = new PackageJsonMergeError('Custom merge error');
269
+
270
+ expect(error.message).toBe('Custom merge error');
271
+ expect(error.name).toBe('PackageJsonMergeError');
272
+ expect(error).toBeInstanceOf(Error);
273
+ });
274
+ });
275
+ });