@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,293 @@
1
+ import { SourceFile } from 'ts-morph';
2
+
3
+ /**
4
+ * Merge imports from feature file into target file
5
+ * Handles:
6
+ * - Deduplicating imports from the same module
7
+ * - Merging named imports from the same module
8
+ * - Preventing duplicate default import names from different modules
9
+ * - Merging different import types from the same module
10
+ * - Removing imports from __delete__ marked files
11
+ */
12
+ export function mergeImports(featureFile: SourceFile, targetFile: SourceFile): void {
13
+ const featureImports = featureFile.getImportDeclarations();
14
+ const targetImports = targetFile.getImportDeclarations();
15
+
16
+ // Build a map of existing target imports by module specifier
17
+ // This handles multiple imports from the same module in the target
18
+ const targetImportsMap = new Map<string, typeof targetImports[0]>();
19
+ const duplicateTargetImports: typeof targetImports = [];
20
+
21
+ for (const imp of targetImports) {
22
+ const moduleSpecifier = imp.getModuleSpecifierValue();
23
+
24
+ if (!targetImportsMap.has(moduleSpecifier)) {
25
+ targetImportsMap.set(moduleSpecifier, imp);
26
+ } else {
27
+ // Found a duplicate import from same module, mark for merging
28
+ duplicateTargetImports.push(imp);
29
+ }
30
+ }
31
+
32
+ // Merge duplicate imports in target first
33
+ for (const duplicateImport of duplicateTargetImports) {
34
+ const moduleSpecifier = duplicateImport.getModuleSpecifierValue();
35
+ const primaryImport = targetImportsMap.get(moduleSpecifier);
36
+
37
+ if (primaryImport) {
38
+ mergeImportDeclarations(duplicateImport, primaryImport);
39
+ duplicateImport.remove();
40
+ }
41
+ }
42
+
43
+ // Track all default import names already in target (to prevent conflicts)
44
+ const existingDefaultImportNames = new Set<string>();
45
+ for (const imp of targetFile.getImportDeclarations()) {
46
+ const defaultImport = imp.getDefaultImport();
47
+ if (defaultImport) {
48
+ existingDefaultImportNames.add(defaultImport.getText());
49
+ }
50
+ }
51
+
52
+ // Add/merge imports from feature
53
+ for (const featureImport of featureImports) {
54
+ const moduleSpecifier = featureImport.getModuleSpecifierValue();
55
+ const targetImport = targetImportsMap.get(moduleSpecifier);
56
+ const featureDefaultImport = featureImport.getDefaultImport()?.getText();
57
+
58
+ if (!targetImport) {
59
+ // Import from this module doesn't exist in target
60
+ // Check if default import name would conflict
61
+ if (featureDefaultImport && existingDefaultImportNames.has(featureDefaultImport)) {
62
+ // Feature import has same name as existing import from different module
63
+ // Feature should take precedence - find and replace the conflicting import
64
+ const conflictingImport = targetFile.getImportDeclarations().find(imp =>
65
+ imp.getDefaultImport()?.getText() === featureDefaultImport &&
66
+ imp.getModuleSpecifierValue() !== moduleSpecifier
67
+ );
68
+
69
+ if (conflictingImport) {
70
+ // Replace the module specifier of the conflicting import
71
+ conflictingImport.setModuleSpecifier(moduleSpecifier);
72
+
73
+ // Merge any named imports from feature into the updated import
74
+ const featureNamedImports = featureImport.getNamedImports();
75
+ if (featureNamedImports.length > 0) {
76
+ const existingNamedImports = new Set(
77
+ conflictingImport.getNamedImports().map(ni => ni.getName())
78
+ );
79
+ for (const namedImport of featureNamedImports) {
80
+ const importName = namedImport.getName();
81
+ if (!existingNamedImports.has(importName)) {
82
+ conflictingImport.addNamedImport({
83
+ name: importName,
84
+ alias: namedImport.getAliasNode()?.getText()
85
+ });
86
+ }
87
+ }
88
+ }
89
+
90
+ // Update the map to point to the updated import
91
+ targetImportsMap.set(moduleSpecifier, conflictingImport);
92
+ continue;
93
+ }
94
+ }
95
+
96
+ // Add the import
97
+ targetFile.addImportDeclaration({
98
+ moduleSpecifier: moduleSpecifier,
99
+ isTypeOnly: featureImport.isTypeOnly(),
100
+ namedImports: featureImport.getNamedImports().map(ni => ({
101
+ name: ni.getName(),
102
+ alias: ni.getAliasNode()?.getText(),
103
+ isTypeOnly: ni.isTypeOnly()
104
+ })),
105
+ defaultImport: featureDefaultImport,
106
+ namespaceImport: featureImport.getNamespaceImport()?.getText()
107
+ });
108
+
109
+ // Track the new default import
110
+ if (featureDefaultImport) {
111
+ existingDefaultImportNames.add(featureDefaultImport);
112
+ }
113
+ // Update map with new import
114
+ const newImports = targetFile.getImportDeclarations();
115
+ const addedImport = newImports[newImports.length - 1];
116
+ targetImportsMap.set(moduleSpecifier, addedImport);
117
+ } else {
118
+ // Import from this module exists, merge them
119
+ mergeImportDeclarations(featureImport, targetImport);
120
+ }
121
+ }
122
+
123
+ // Final deduplication pass for named imports
124
+ deduplicateNamedImports(targetFile);
125
+
126
+ // Remove imports from __delete__ marked files
127
+ removeDeleteMarkedImports(targetFile);
128
+
129
+ // Ensure proper formatting: blank line after imports
130
+ ensureBlankLineAfterImports(targetFile);
131
+
132
+ // Don't call organizeImports() as it can be too aggressive and remove imports
133
+ // that are actually needed but appear unused in the isolated file context
134
+ }
135
+
136
+ /**
137
+ * Merge sourceImport into targetImport
138
+ * Combines default imports, named imports, and namespace imports
139
+ * Handles type imports vs regular imports appropriately
140
+ */
141
+ function mergeImportDeclarations(
142
+ sourceImport: ReturnType<SourceFile['getImportDeclarations']>[0],
143
+ targetImport: ReturnType<SourceFile['getImportDeclarations']>[0]
144
+ ): void {
145
+ const sourceIsTypeOnly = sourceImport.isTypeOnly();
146
+ const targetIsTypeOnly = targetImport.isTypeOnly();
147
+
148
+ // If type-only status differs, we need to add a separate import declaration
149
+ // instead of merging, because you can't mix type and regular imports
150
+ if (sourceIsTypeOnly !== targetIsTypeOnly) {
151
+ // Get the source file and add a new import
152
+ const targetFile = targetImport.getSourceFile();
153
+ const moduleSpecifier = sourceImport.getModuleSpecifierValue();
154
+
155
+ // Check if an import with matching type-only status already exists
156
+ const existingMatchingImport = targetFile.getImportDeclarations().find(imp =>
157
+ imp.getModuleSpecifierValue() === moduleSpecifier &&
158
+ imp.isTypeOnly() === sourceIsTypeOnly &&
159
+ imp !== targetImport
160
+ );
161
+
162
+ if (existingMatchingImport) {
163
+ // Merge into the matching import instead
164
+ mergeImportDeclarations(sourceImport, existingMatchingImport);
165
+ return;
166
+ }
167
+
168
+ // Add new import with same type-only status as source
169
+ targetFile.addImportDeclaration({
170
+ moduleSpecifier: moduleSpecifier,
171
+ isTypeOnly: sourceIsTypeOnly,
172
+ namedImports: sourceImport.getNamedImports().map(ni => ({
173
+ name: ni.getName(),
174
+ alias: ni.getAliasNode()?.getText(),
175
+ isTypeOnly: ni.isTypeOnly()
176
+ })),
177
+ defaultImport: sourceImport.getDefaultImport()?.getText(),
178
+ namespaceImport: sourceImport.getNamespaceImport()?.getText()
179
+ });
180
+ return;
181
+ }
182
+
183
+ // Same type-only status, proceed with merge
184
+
185
+ // Add default import if target doesn't have one and source does
186
+ const sourceDefaultImport = sourceImport.getDefaultImport();
187
+ const targetDefaultImport = targetImport.getDefaultImport();
188
+
189
+ if (sourceDefaultImport && !targetDefaultImport) {
190
+ targetImport.setDefaultImport(sourceDefaultImport.getText());
191
+ }
192
+
193
+ // Add namespace import if target doesn't have one and source does
194
+ const sourceNamespaceImport = sourceImport.getNamespaceImport();
195
+ const targetNamespaceImport = targetImport.getNamespaceImport();
196
+
197
+ if (sourceNamespaceImport && !targetNamespaceImport) {
198
+ targetImport.setNamespaceImport(sourceNamespaceImport.getText());
199
+ }
200
+
201
+ // Merge named imports
202
+ const targetNamedImports = new Set(
203
+ targetImport.getNamedImports().map(ni => ni.getName())
204
+ );
205
+
206
+ for (const sourceNamedImport of sourceImport.getNamedImports()) {
207
+ const importName = sourceNamedImport.getName();
208
+ if (!targetNamedImports.has(importName)) {
209
+ targetImport.addNamedImport({
210
+ name: importName,
211
+ alias: sourceNamedImport.getAliasNode()?.getText(),
212
+ isTypeOnly: sourceNamedImport.isTypeOnly()
213
+ });
214
+ }
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Remove duplicate named imports within each import declaration
220
+ */
221
+ function deduplicateNamedImports(file: SourceFile): void {
222
+ const allImports = file.getImportDeclarations();
223
+
224
+ for (const imp of allImports) {
225
+ const namedImports = imp.getNamedImports();
226
+ const seen = new Set<string>();
227
+
228
+ for (const namedImport of namedImports) {
229
+ const name = namedImport.getName();
230
+ if (seen.has(name)) {
231
+ namedImport.remove();
232
+ } else {
233
+ seen.add(name);
234
+ }
235
+ }
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Remove imports from files marked with __delete__ prefix
241
+ * These imports reference deleted files and should be removed
242
+ */
243
+ function removeDeleteMarkedImports(file: SourceFile): void {
244
+ const DELETE_PREFIX = '__delete__';
245
+ const allImports = file.getImportDeclarations();
246
+
247
+ for (const imp of allImports) {
248
+ const moduleSpecifier = imp.getModuleSpecifierValue();
249
+
250
+ // Check if the module specifier contains __delete__ prefix
251
+ // This covers both direct paths like "./__delete__new" and path segments
252
+ if (moduleSpecifier.includes(DELETE_PREFIX)) {
253
+ imp.remove();
254
+ }
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Ensure there's a blank line after the last import declaration
260
+ * This maintains proper formatting between imports and code
261
+ */
262
+ function ensureBlankLineAfterImports(file: SourceFile): void {
263
+ const imports = file.getImportDeclarations();
264
+
265
+ if (imports.length === 0) {
266
+ return; // No imports, nothing to do
267
+ }
268
+
269
+ const lastImport = imports[imports.length - 1];
270
+
271
+ // Get the next statement after imports (if any)
272
+ const statements = file.getStatements();
273
+ const lastImportIndex = statements.indexOf(lastImport as any);
274
+
275
+ if (lastImportIndex === -1 || lastImportIndex === statements.length - 1) {
276
+ return; // Last import is the last statement, no code after it
277
+ }
278
+
279
+ const nextStatement = statements[lastImportIndex + 1];
280
+
281
+ // Check if there's already proper spacing
282
+ const fullText = file.getFullText();
283
+ const textBetween = fullText.substring(lastImport.getEnd(), nextStatement.getStart());
284
+
285
+ // Count newlines in the text between
286
+ const newlineCount = (textBetween.match(/\n/g) || []).length;
287
+
288
+ // We want at least 2 newlines (one ends the import, one creates blank line)
289
+ if (newlineCount < 2) {
290
+ // Insert additional newline after the last import
291
+ file.insertText(lastImport.getEnd(), '\n');
292
+ }
293
+ }
@@ -0,0 +1,21 @@
1
+ import chalk from 'chalk';
2
+
3
+ export function success(message: string): void {
4
+ console.log(chalk.green('✓'), message);
5
+ }
6
+
7
+ export function error(message: string): void {
8
+ console.error(chalk.red('✗'), message);
9
+ }
10
+
11
+ export function info(message: string): void {
12
+ console.log(chalk.blue('ℹ'), message);
13
+ }
14
+
15
+ export function warning(message: string): void {
16
+ console.log(chalk.yellow('⚠'), message);
17
+ }
18
+
19
+ export function heading(message: string): void {
20
+ console.log(chalk.bold.cyan(`\n${message}`));
21
+ }
@@ -0,0 +1,154 @@
1
+ import { PathMapping, PathMappings } from '../types.js';
2
+
3
+ /**
4
+ * Get default path mappings for a feature
5
+ * Maps webApp → digitalExperiences/webApplications/<featureName>
6
+ *
7
+ * @param featureName - The name of the feature (e.g., 'feature-navigation-menu')
8
+ * @returns Array containing the default path mapping
9
+ *
10
+ * @example
11
+ * getDefaultPathMappings('feature-nav')
12
+ * // Returns: [{ from: 'webApp', to: 'digitalExperiences/webApplications/feature-nav' }]
13
+ */
14
+ export function getDefaultPathMappings(featureName: string): PathMapping[] {
15
+ return [
16
+ {
17
+ from: 'webApp',
18
+ to: `digitalExperiences/webApplications/${featureName}`
19
+ }
20
+ ];
21
+ }
22
+
23
+ /**
24
+ * Check if path mappings are enabled for a feature
25
+ * Default: true (enabled by default, opt-out)
26
+ *
27
+ * @param pathMappings - The path mappings configuration from the feature
28
+ * @returns true if mappings are enabled (default), false if explicitly disabled
29
+ *
30
+ * @example
31
+ * arePathMappingsEnabled(undefined) // Returns: true (default enabled)
32
+ * arePathMappingsEnabled({ enabled: false }) // Returns: false
33
+ * arePathMappingsEnabled({ enabled: true }) // Returns: true
34
+ * arePathMappingsEnabled({ mappings: [...] }) // Returns: true (enabled by default)
35
+ */
36
+ export function arePathMappingsEnabled(pathMappings?: PathMappings): boolean {
37
+ // If pathMappings is undefined, default to enabled
38
+ if (!pathMappings) return true;
39
+
40
+ // If pathMappings.enabled is explicitly set, use that value
41
+ if (pathMappings.enabled !== undefined) return pathMappings.enabled;
42
+
43
+ // Otherwise, enabled by default
44
+ return true;
45
+ }
46
+
47
+ /**
48
+ * Get the effective path mappings for a feature
49
+ * Returns custom mappings if provided, otherwise default mappings
50
+ *
51
+ * @param featureName - The name of the feature
52
+ * @param pathMappings - The path mappings configuration from the feature
53
+ * @returns Array of path mappings to apply (empty if disabled)
54
+ *
55
+ * @example
56
+ * // Default behavior (no config)
57
+ * getEffectivePathMappings('feature-nav', undefined)
58
+ * // Returns: [{ from: 'webApp', to: 'digitalExperiences/webApplications/feature-nav' }]
59
+ *
60
+ * // Disabled
61
+ * getEffectivePathMappings('feature-nav', { enabled: false })
62
+ * // Returns: []
63
+ *
64
+ * // Custom mappings
65
+ * getEffectivePathMappings('feature-nav', { mappings: [{ from: 'web', to: 'custom/path' }] })
66
+ * // Returns: [{ from: 'web', to: 'custom/path' }]
67
+ */
68
+ export function getEffectivePathMappings(
69
+ featureName: string,
70
+ pathMappings?: PathMappings
71
+ ): PathMapping[] {
72
+ // If disabled, return empty array (no mappings)
73
+ if (!arePathMappingsEnabled(pathMappings)) {
74
+ return [];
75
+ }
76
+
77
+ // If custom mappings provided, use those
78
+ if (pathMappings?.mappings && pathMappings.mappings.length > 0) {
79
+ return pathMappings.mappings;
80
+ }
81
+
82
+ // Otherwise, use default mappings
83
+ return getDefaultPathMappings(featureName);
84
+ }
85
+
86
+ /**
87
+ * Apply path mappings to a template file path
88
+ *
89
+ * This function transforms simplified paths (e.g., "webApp/src/app.tsx") into
90
+ * their full target paths (e.g., "digitalExperiences/webApplications/feature-name/src/app.tsx")
91
+ * based on the provided mappings.
92
+ *
93
+ * The function checks each mapping in order and applies the first one that matches.
94
+ * If no mapping matches, the path is returned unchanged (backwards compatibility).
95
+ *
96
+ * @param templatePath - Path relative to template directory (e.g., "webApp/src/app.tsx")
97
+ * @param mappings - Array of path mappings to apply
98
+ * @returns Transformed path with mapping applied
99
+ *
100
+ * @example
101
+ * // Apply default webApp mapping
102
+ * applyPathMappings('webApp/src/app.tsx', [{
103
+ * from: 'webApp',
104
+ * to: 'digitalExperiences/webApplications/feature-nav'
105
+ * }])
106
+ * // Returns: 'digitalExperiences/webApplications/feature-nav/src/app.tsx'
107
+ *
108
+ * @example
109
+ * // Backwards compatibility - old paths pass through
110
+ * applyPathMappings('digitalExperiences/webApplications/feature-nav/src/app.tsx', [...])
111
+ * // Returns: 'digitalExperiences/webApplications/feature-nav/src/app.tsx'
112
+ *
113
+ * @example
114
+ * // No mappings - path unchanged
115
+ * applyPathMappings('webApp/src/app.tsx', [])
116
+ * // Returns: 'webApp/src/app.tsx'
117
+ *
118
+ * @example
119
+ * // No match - path unchanged
120
+ * applyPathMappings('src/app.tsx', [{ from: 'webApp', to: '...' }])
121
+ * // Returns: 'src/app.tsx'
122
+ */
123
+ export function applyPathMappings(
124
+ templatePath: string,
125
+ mappings: PathMapping[]
126
+ ): string {
127
+ // If no mappings, return path as-is (backwards compatibility)
128
+ if (mappings.length === 0) {
129
+ return templatePath;
130
+ }
131
+
132
+ // Try each mapping in order (first match wins)
133
+ for (const mapping of mappings) {
134
+ const fromPrefix = mapping.from + '/';
135
+
136
+ // Check if path starts with the mapping's "from" prefix
137
+ if (templatePath.startsWith(fromPrefix)) {
138
+ // Replace prefix with "to" prefix
139
+ const remainder = templatePath.substring(fromPrefix.length);
140
+ return mapping.to + '/' + remainder;
141
+ }
142
+
143
+ // Also handle exact match (no trailing slash)
144
+ if (templatePath === mapping.from) {
145
+ return mapping.to;
146
+ }
147
+ }
148
+
149
+ // No mapping matched, return original path
150
+ // This handles both:
151
+ // 1. Old-style full paths (digitalExperiences/webApplications/...)
152
+ // 2. Other paths that don't use the mapping shorthand
153
+ return templatePath;
154
+ }
@@ -0,0 +1,121 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { join, dirname, basename } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ /**
6
+ * Find the monorepo root by searching upward for package.json with workspaces
7
+ */
8
+ export function getMonorepoRoot(): string {
9
+ let currentDir = dirname(fileURLToPath(import.meta.url));
10
+
11
+ while (currentDir !== '/') {
12
+ const packageJsonPath = join(currentDir, 'package.json');
13
+
14
+ if (existsSync(packageJsonPath)) {
15
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
16
+ if (packageJson.workspaces) {
17
+ return currentDir;
18
+ }
19
+ }
20
+
21
+ currentDir = dirname(currentDir);
22
+ }
23
+
24
+ throw new Error('Could not find monorepo root (package.json with workspaces)');
25
+ }
26
+
27
+ /**
28
+ * Get the features directory path
29
+ */
30
+ export function getFeaturesDir(): string {
31
+ return join(getMonorepoRoot(), 'packages', 'features');
32
+ }
33
+
34
+ /**
35
+ * Get the directory path for a specific feature
36
+ */
37
+ export function getFeatureDir(featureName: string): string {
38
+ return join(getFeaturesDir(), featureName);
39
+ }
40
+
41
+ /**
42
+ * Resolve a file path within a feature
43
+ */
44
+ export function resolveFeatureFile(featureName: string, filePath: string): string {
45
+ return join(getFeatureDir(featureName), filePath);
46
+ }
47
+
48
+ /**
49
+ * Translate a feature file path to the corresponding base app path
50
+ * Replaces feature name with base app name in the nested structure
51
+ *
52
+ * Handles three formats:
53
+ * 1. Full path: "digitalExperiences/webApplications/feature-simple/src/routes.tsx"
54
+ * → "digitalExperiences/webApplications/base-app/src/routes.tsx"
55
+ * 2. WebApp path: "webApp/src/routes.tsx"
56
+ * → "digitalExperiences/webApplications/base-app/src/routes.tsx"
57
+ * 3. Other SFDX paths: "classes/NavMenu.cls"
58
+ * → "classes/NavMenu.cls" (unchanged, stays at root)
59
+ */
60
+ export function translatePathToBaseApp(featurePath: string, featureName: string, baseAppPath: string): string {
61
+ // Extract base app name from base app path (last directory component)
62
+ const baseAppName = basename(baseAppPath);
63
+
64
+ // Pattern: digitalExperiences/webApplications/<feature-name>/...
65
+ const prefix = 'digitalExperiences/webApplications/';
66
+
67
+ if (featurePath.startsWith(prefix)) {
68
+ // Full path format - remove prefix to get: <feature-name>/...
69
+ const remainder = featurePath.substring(prefix.length);
70
+
71
+ // Check if it starts with the feature name
72
+ if (remainder.startsWith(featureName + '/')) {
73
+ // Replace feature name with base app name
74
+ const pathAfterFeatureName = remainder.substring(featureName.length + 1);
75
+ return `${prefix}${baseAppName}/${pathAfterFeatureName}`;
76
+ }
77
+ } else if (featurePath.startsWith('webApp/')) {
78
+ // WebApp path - strip webApp/ prefix and add full digitalExperiences path
79
+ const pathAfterWebApp = featurePath.substring('webApp/'.length);
80
+ return `${prefix}${baseAppName}/${pathAfterWebApp}`;
81
+ }
82
+
83
+ // All other paths (SFDX metadata, etc.) - return as is (stays at root level)
84
+ return featurePath;
85
+ }
86
+
87
+ /**
88
+ * Translate a feature file path to use a target app name
89
+ * Replaces feature name with target app name in the nested structure
90
+ *
91
+ * Handles three formats:
92
+ * 1. Full path: "digitalExperiences/webApplications/feature-simple/src/routes.tsx"
93
+ * → "digitalExperiences/webApplications/target-app/src/routes.tsx"
94
+ * 2. WebApp path: "webApp/src/routes.tsx"
95
+ * → "digitalExperiences/webApplications/target-app/src/routes.tsx"
96
+ * 3. Other SFDX paths: "classes/NavMenu.cls"
97
+ * → "classes/NavMenu.cls" (unchanged, stays at root)
98
+ */
99
+ export function translatePathToTargetApp(featurePath: string, featureName: string, targetAppName: string): string {
100
+ // Pattern: digitalExperiences/webApplications/<feature-name>/...
101
+ const prefix = 'digitalExperiences/webApplications/';
102
+
103
+ if (featurePath.startsWith(prefix)) {
104
+ // Full path format - remove prefix to get: <feature-name>/...
105
+ const remainder = featurePath.substring(prefix.length);
106
+
107
+ // Check if it starts with the feature name
108
+ if (remainder.startsWith(featureName + '/')) {
109
+ // Replace feature name with target app name
110
+ const pathAfterFeatureName = remainder.substring(featureName.length + 1);
111
+ return `${prefix}${targetAppName}/${pathAfterFeatureName}`;
112
+ }
113
+ } else if (featurePath.startsWith('webApp/')) {
114
+ // WebApp path - strip webApp/ prefix and add full digitalExperiences path
115
+ const pathAfterWebApp = featurePath.substring('webApp/'.length);
116
+ return `${prefix}${targetAppName}/${pathAfterWebApp}`;
117
+ }
118
+
119
+ // All other paths (SFDX metadata, etc.) - return as is (stays at root level)
120
+ return featurePath;
121
+ }