@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,265 @@
1
+ import { readFileSync, existsSync, mkdirSync, writeFileSync, rmSync, statSync } from 'fs';
2
+ import { dirname, extname } from 'path';
3
+ import { mergeRoutes } from '../utils/route-merger.js';
4
+ import * as logger from '../utils/logger.js';
5
+
6
+ const INHERIT_PREFIX = '__inherit__';
7
+
8
+ export class FileOperationError extends Error {
9
+ constructor(message: string) {
10
+ super(message);
11
+ this.name = 'FileOperationError';
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Fix import paths by removing __inherit__ prefix from import/require statements
17
+ *
18
+ * Examples:
19
+ * - import { x } from './__inherit__routes' -> import { x } from './routes'
20
+ * - import x from '../__inherit__routes.tsx' -> import x from '../routes.tsx'
21
+ * - require('./__inherit__file') -> require('./file')
22
+ *
23
+ * @param content - File content to process
24
+ * @returns Content with fixed import paths
25
+ */
26
+ function fixInheritImportPaths(content: string): string {
27
+ // Match import/export statements with __inherit__ in the path
28
+ // Handles: import ... from '...__inherit__...'
29
+ // export ... from '...__inherit__...'
30
+ // import('...__inherit__...')
31
+ // require('...__inherit__...')
32
+
33
+ // Pattern explanation:
34
+ // (from\s+|import\(|require\() - matches 'from ', 'import(', or 'require('
35
+ // (['"`]) - captures opening quote
36
+ // ([^'"`]*) - captures path before __inherit__
37
+ // __inherit__ - the prefix to remove
38
+ // ([^'"`]*) - captures rest of path
39
+ // \2 - matches same quote type as opening
40
+
41
+ return content.replace(
42
+ /(from\s+|import\(|require\()(['"`])([^'"`]*)__inherit__([^'"`]*)\2/g,
43
+ (match, prefix, quote, before, after) => {
44
+ return `${prefix}${quote}${before}${after}${quote}`;
45
+ }
46
+ );
47
+ }
48
+
49
+ /**
50
+ * Check if file is a JS/TS file that may contain imports
51
+ */
52
+ function isJavaScriptFile(filePath: string): boolean {
53
+ const ext = extname(filePath);
54
+ return ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'].includes(ext);
55
+ }
56
+
57
+ /**
58
+ * Apply a file from patch to target, optionally merging with base
59
+ *
60
+ * @param patchFilePath - Full path to the patch file from the feature
61
+ * @param baseFilePath - Full path to the original base app file (used for merging)
62
+ * @param targetFilePath - Full path to where the result should be written
63
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/routes.tsx")
64
+ * @param shouldMerge - If true, merges patch with base using route merge strategy
65
+ */
66
+ export async function applyFile(
67
+ patchFilePath: string,
68
+ baseFilePath: string,
69
+ targetFilePath: string,
70
+ relativeTargetPath: string,
71
+ shouldMerge: boolean = false
72
+ ): Promise<void> {
73
+ if (!existsSync(patchFilePath)) {
74
+ throw new FileOperationError(
75
+ `Patch file not found: ${patchFilePath}`
76
+ );
77
+ }
78
+
79
+ // Read the patch content
80
+ let patchContent = readFileSync(patchFilePath, 'utf-8');
81
+
82
+ // Fix __inherit__ import paths for JS/TS files
83
+ if (isJavaScriptFile(patchFilePath)) {
84
+ patchContent = fixInheritImportPaths(patchContent);
85
+ }
86
+
87
+ if (shouldMerge) {
88
+ // Merge strategy - merge patch with base, write to target
89
+ if (!existsSync(baseFilePath)) {
90
+ throw new FileOperationError(
91
+ `Base file not found: ${baseFilePath}. Merge requires base file to exist.`
92
+ );
93
+ }
94
+
95
+ // Merge patch with base (note: mergeRoutes reads files internally, so we write fixed content to temp)
96
+ let mergedContent = mergeRoutes(patchFilePath, baseFilePath);
97
+
98
+ // Fix imports in merged content
99
+ if (isJavaScriptFile(targetFilePath)) {
100
+ mergedContent = fixInheritImportPaths(mergedContent);
101
+ }
102
+
103
+ // Check if target already has this content
104
+ if (existsSync(targetFilePath)) {
105
+ const existingContent = readFileSync(targetFilePath, 'utf-8');
106
+ if (existingContent === mergedContent) {
107
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged after merge)`);
108
+ return;
109
+ }
110
+ }
111
+
112
+ // Ensure target directory exists
113
+ const targetDirPath = dirname(targetFilePath);
114
+ if (!existsSync(targetDirPath)) {
115
+ mkdirSync(targetDirPath, { recursive: true });
116
+ }
117
+
118
+ writeFileSync(targetFilePath, mergedContent, 'utf-8');
119
+ logger.success(`Merged ${relativeTargetPath}`);
120
+ } else {
121
+ // Add/Update strategy - copy patch to target
122
+ const targetExists = existsSync(targetFilePath);
123
+
124
+ if (targetExists) {
125
+ const existingContent = readFileSync(targetFilePath, 'utf-8');
126
+ if (existingContent === patchContent) {
127
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged)`);
128
+ return;
129
+ }
130
+ }
131
+
132
+ // Ensure target directory exists
133
+ const targetDirPath = dirname(targetFilePath);
134
+ if (!existsSync(targetDirPath)) {
135
+ mkdirSync(targetDirPath, { recursive: true });
136
+ }
137
+
138
+ // Write the file
139
+ writeFileSync(targetFilePath, patchContent, 'utf-8');
140
+
141
+ if (targetExists) {
142
+ logger.success(`Updated ${relativeTargetPath}`);
143
+ } else {
144
+ logger.success(`Added ${relativeTargetPath}`);
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Delete a file or directory from the target app
151
+ *
152
+ * @param targetFilePath - Full path to the file/directory to delete
153
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/routes.tsx")
154
+ */
155
+ export async function deleteFile(
156
+ targetFilePath: string,
157
+ relativeTargetPath: string
158
+ ): Promise<void> {
159
+ if (!existsSync(targetFilePath)) {
160
+ logger.info(`Skipped deleting ${relativeTargetPath} (does not exist)`);
161
+ return;
162
+ }
163
+
164
+ const stat = statSync(targetFilePath);
165
+
166
+ if (stat.isDirectory()) {
167
+ rmSync(targetFilePath, { recursive: true, force: true });
168
+ logger.success(`Deleted directory ${relativeTargetPath}`);
169
+ } else {
170
+ rmSync(targetFilePath, { force: true });
171
+ logger.success(`Deleted ${relativeTargetPath}`);
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Prepend content from a feature file to the beginning of a target file
177
+ *
178
+ * @param featureFilePath - Full path to the feature file with content to prepend
179
+ * @param targetFilePath - Full path to the target file to prepend to
180
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/styles/global.css")
181
+ */
182
+ export async function prependToFile(
183
+ featureFilePath: string,
184
+ targetFilePath: string,
185
+ relativeTargetPath: string
186
+ ): Promise<void> {
187
+ if (!existsSync(featureFilePath)) {
188
+ throw new FileOperationError(
189
+ `Feature file not found: ${featureFilePath}`
190
+ );
191
+ }
192
+
193
+ if (!existsSync(targetFilePath)) {
194
+ throw new FileOperationError(
195
+ `Target file not found: ${targetFilePath}`
196
+ );
197
+ }
198
+
199
+ // Read both files
200
+ let featureContent = readFileSync(featureFilePath, 'utf-8');
201
+ const targetContent = readFileSync(targetFilePath, 'utf-8');
202
+
203
+ // Fix __inherit__ imports in feature content if it's a JS/TS file
204
+ if (isJavaScriptFile(featureFilePath)) {
205
+ featureContent = fixInheritImportPaths(featureContent);
206
+ }
207
+
208
+ // Prepend feature content to target content
209
+ const newContent = featureContent + '\n' + targetContent;
210
+
211
+ // Check if content would actually change
212
+ if (targetContent === newContent) {
213
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged after prepend)`);
214
+ return;
215
+ }
216
+
217
+ writeFileSync(targetFilePath, newContent, 'utf-8');
218
+ logger.success(`Prepended to ${relativeTargetPath}`);
219
+ }
220
+
221
+ /**
222
+ * Append content from a feature file to the end of a target file
223
+ *
224
+ * @param featureFilePath - Full path to the feature file with content to append
225
+ * @param targetFilePath - Full path to the target file to append to
226
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/styles/global.css")
227
+ */
228
+ export async function appendToFile(
229
+ featureFilePath: string,
230
+ targetFilePath: string,
231
+ relativeTargetPath: string
232
+ ): Promise<void> {
233
+ if (!existsSync(featureFilePath)) {
234
+ throw new FileOperationError(
235
+ `Feature file not found: ${featureFilePath}`
236
+ );
237
+ }
238
+
239
+ if (!existsSync(targetFilePath)) {
240
+ throw new FileOperationError(
241
+ `Target file not found: ${targetFilePath}`
242
+ );
243
+ }
244
+
245
+ // Read both files
246
+ const targetContent = readFileSync(targetFilePath, 'utf-8');
247
+ let featureContent = readFileSync(featureFilePath, 'utf-8');
248
+
249
+ // Fix __inherit__ imports in feature content if it's a JS/TS file
250
+ if (isJavaScriptFile(featureFilePath)) {
251
+ featureContent = fixInheritImportPaths(featureContent);
252
+ }
253
+
254
+ // Append feature content to target content
255
+ const newContent = targetContent + '\n' + featureContent;
256
+
257
+ // Check if content would actually change
258
+ if (targetContent === newContent) {
259
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged after append)`);
260
+ return;
261
+ }
262
+
263
+ writeFileSync(targetFilePath, newContent, 'utf-8');
264
+ logger.success(`Appended to ${relativeTargetPath}`);
265
+ }
@@ -0,0 +1,129 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { execSync } from 'child_process';
4
+ import type { PackageJsonDependencies } from '../types.js';
5
+ import * as logger from '../utils/logger.js';
6
+ import { getWebApplicationPath } from '../utils/validation.js';
7
+
8
+ export class PackageJsonMergeError extends Error {
9
+ constructor(message: string) {
10
+ super(message);
11
+ this.name = 'PackageJsonMergeError';
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Build package specs array from dependencies object
17
+ * @param dependencies - Object mapping package names to versions
18
+ * @returns Array of package specs in format "package@version"
19
+ */
20
+ export function buildPackageSpecs(dependencies: Record<string, string>): string[] {
21
+ return Object.entries(dependencies).map(([name, version]) => `${name}@${version}`);
22
+ }
23
+
24
+ /**
25
+ * Build yarn command for package specs
26
+ * @param packageSpecs - Array of package specs
27
+ * @param isDev - Whether these are dev dependencies
28
+ * @returns yarn command string
29
+ */
30
+ export function buildInstallCommand(packageSpecs: string[], isDev: boolean): string {
31
+ const devFlag = isDev ? '--dev ' : '';
32
+ return `yarn ${devFlag}${packageSpecs.join(' ')}`;
33
+ }
34
+
35
+ /**
36
+ * Execute yarn command (extracted for testability)
37
+ * @param command - yarn command to execute
38
+ * @param cwd - Working directory
39
+ */
40
+ export function executeNpmInstall(command: string, cwd: string): void {
41
+ execSync(command, {
42
+ cwd,
43
+ stdio: 'inherit'
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Install dependencies using yarn
49
+ * @param targetDir - Base directory containing digitalExperiences/webApplications/<app-name>, or direct path to web app directory if webAppDirPath is provided
50
+ * @param webAppDirPath - Optional direct path to the web application directory
51
+ */
52
+ export async function mergePackageJson(
53
+ targetDir: string,
54
+ patchDependencies: PackageJsonDependencies,
55
+ webAppDirPath?: string
56
+ ): Promise<string[]> {
57
+ // Get the web application directory where package.json is located
58
+ const webAppDir = webAppDirPath || getWebApplicationPath(targetDir);
59
+ const packageJsonPath = join(webAppDir, 'package.json');
60
+
61
+ if (!existsSync(packageJsonPath)) {
62
+ throw new PackageJsonMergeError(
63
+ `package.json not found at '${packageJsonPath}'. Expected structure: digitalExperiences/webApplications/<app-name>`
64
+ );
65
+ }
66
+
67
+ try {
68
+ const changes: string[] = [];
69
+
70
+ // Install dependencies
71
+ if (patchDependencies.dependencies) {
72
+ const packages = Object.entries(patchDependencies.dependencies);
73
+
74
+ if (packages.length > 0) {
75
+ logger.info(`Installing ${packages.length} dependency/dependencies...`);
76
+
77
+ const packageSpecs = buildPackageSpecs(patchDependencies.dependencies);
78
+ packageSpecs.forEach(spec => logger.info(` ${spec}`));
79
+
80
+ try {
81
+ const command = buildInstallCommand(packageSpecs, false);
82
+ executeNpmInstall(command, webAppDir);
83
+ changes.push(...packageSpecs);
84
+ } catch (err) {
85
+ throw new PackageJsonMergeError(
86
+ `Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`
87
+ );
88
+ }
89
+ }
90
+ }
91
+
92
+ // Install devDependencies
93
+ if (patchDependencies.devDependencies) {
94
+ const packages = Object.entries(patchDependencies.devDependencies);
95
+
96
+ if (packages.length > 0) {
97
+ logger.info(`Installing ${packages.length} dev dependency/dependencies...`);
98
+
99
+ const packageSpecs = buildPackageSpecs(patchDependencies.devDependencies);
100
+ packageSpecs.forEach(spec => logger.info(` ${spec}`));
101
+
102
+ try {
103
+ const command = buildInstallCommand(packageSpecs, true);
104
+ executeNpmInstall(command, webAppDir);
105
+ changes.push(...packageSpecs.map(spec => `${spec} (dev)`));
106
+ } catch (err) {
107
+ throw new PackageJsonMergeError(
108
+ `Failed to install dev dependencies: ${err instanceof Error ? err.message : String(err)}`
109
+ );
110
+ }
111
+ }
112
+ }
113
+
114
+ if (changes.length > 0) {
115
+ logger.success(`Installed ${changes.length} dependency change(s)`);
116
+ } else {
117
+ logger.info('No new dependencies to install');
118
+ }
119
+
120
+ return changes;
121
+ } catch (err) {
122
+ if (err instanceof PackageJsonMergeError) {
123
+ throw err;
124
+ }
125
+ throw new PackageJsonMergeError(
126
+ `Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`
127
+ );
128
+ }
129
+ }
@@ -0,0 +1,128 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { pathToFileURL } from 'url';
4
+ import type { Feature, PathMappings } from '../types.js';
5
+
6
+ export class FeatureLoadError extends Error {
7
+ constructor(message: string) {
8
+ super(message);
9
+ this.name = 'FeatureLoadError';
10
+ }
11
+ }
12
+
13
+ export type FeatureConfig = {
14
+ features: Feature[];
15
+ templateDir: string;
16
+ webAppName: string;
17
+ routeFilePath: string;
18
+ dependencies: string[];
19
+ pathMappings: PathMappings;
20
+ };
21
+
22
+ /**
23
+ * Extract feature name from feature path
24
+ * Examples:
25
+ * - 'packages/feature-navigation-menu' -> 'feature-navigation-menu'
26
+ * - '/absolute/path/to/feature-name' -> 'feature-name'
27
+ * - 'packages/reference-app-vibe-coding-starter' -> 'reference-app-vibe-coding-starter'
28
+ */
29
+ function extractFeatureName(featurePath: string): string {
30
+ const parts = featurePath.split('/');
31
+ return parts[parts.length - 1];
32
+ }
33
+
34
+ /**
35
+ * Load features from a feature's feature.ts file
36
+ */
37
+ export async function loadFeature(featurePath: string): Promise<FeatureConfig> {
38
+ const featureFilePath = join(featurePath, 'feature.ts');
39
+
40
+ if (!existsSync(featureFilePath)) {
41
+ throw new FeatureLoadError(
42
+ `No feature.ts found in feature path '${featurePath}'`
43
+ );
44
+ }
45
+
46
+ try {
47
+ // Convert to file URL for dynamic import
48
+ const featurePathUrl = pathToFileURL(featureFilePath).href;
49
+ const module = await import(featurePathUrl);
50
+
51
+ // Require default export
52
+ if (!module.default) {
53
+ throw new FeatureLoadError(
54
+ `feature.ts must have a default export (array or object) in ${featureFilePath}`
55
+ );
56
+ }
57
+
58
+ // Helper to check if a value looks like a feature object
59
+ const isFeatureLike = (value: any): boolean => {
60
+ return value && typeof value === 'object' && !Array.isArray(value);
61
+ };
62
+
63
+ let features: Feature[];
64
+
65
+ if (Array.isArray(module.default)) {
66
+ features = module.default;
67
+ } else if (isFeatureLike(module.default)) {
68
+ features = [module.default];
69
+ } else {
70
+ throw new FeatureLoadError(
71
+ `Default export must be a Feature object or Feature[] array in ${featureFilePath}`
72
+ );
73
+ }
74
+
75
+ // Extract feature name from path for constructing defaults
76
+ const featureName = extractFeatureName(featurePath);
77
+
78
+ // Extract configuration from features (with defaults)
79
+ let templateDir = 'template';
80
+ let webAppName = featureName; // Default to feature name
81
+ let routeFilePath: string | undefined;
82
+ let dependencies: string[] = [];
83
+ let pathMappings: PathMappings = {}; // Default: enabled with no custom mappings
84
+
85
+ // Check if any feature specifies custom configuration
86
+ for (const feature of features) {
87
+ if (feature.templateDir) {
88
+ templateDir = feature.templateDir;
89
+ }
90
+ if (feature.webAppName) {
91
+ webAppName = feature.webAppName;
92
+ }
93
+ if (feature.routeFilePath) {
94
+ routeFilePath = feature.routeFilePath;
95
+ }
96
+ if (feature.dependencies) {
97
+ // Merge dependencies from all features
98
+ dependencies = [...new Set([...dependencies, ...feature.dependencies])];
99
+ }
100
+ if (feature.pathMappings) {
101
+ // If any feature specifies pathMappings, use it
102
+ // Last one wins if multiple features specify it
103
+ pathMappings = feature.pathMappings;
104
+ }
105
+ }
106
+
107
+ // Set default routeFilePath if not explicitly provided
108
+ if (!routeFilePath) {
109
+ routeFilePath = `digitalExperiences/webApplications/${webAppName}/src/routes.tsx`;
110
+ }
111
+
112
+ return {
113
+ features,
114
+ templateDir,
115
+ webAppName,
116
+ routeFilePath,
117
+ dependencies,
118
+ pathMappings
119
+ };
120
+ } catch (err) {
121
+ if (err instanceof FeatureLoadError) {
122
+ throw err;
123
+ }
124
+ throw new FeatureLoadError(
125
+ `Failed to load feature from ${featureFilePath}: ${err instanceof Error ? err.message : String(err)}`
126
+ );
127
+ }
128
+ }
package/src/index.ts ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { applyPatchesCommand } from './commands/apply-patches.js';
5
+ import { watchPatchesCommand } from './commands/watch-patches.js';
6
+ import { readFileSync } from 'fs';
7
+ import { join, dirname } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { newAppOrFeatureCommand } from './commands/new-app-feature.js';
10
+
11
+ // Get package.json for version info
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const packageJsonPath = join(__dirname, '../package.json');
14
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
15
+
16
+ const program = new Command();
17
+
18
+ program
19
+ .name('apply-patches')
20
+ .description('CLI tool for applying feature patches to base apps')
21
+ .version(packageJson.version);
22
+
23
+ program
24
+ .command('apply-patches')
25
+ .description('Apply feature patches to an app')
26
+ .argument('<feature-path>', 'Path to the feature (e.g., packages/feature-navigation-menu)')
27
+ .argument('<app-path>', 'Path to the app (e.g., packages/base-react-app or my-app)')
28
+ .argument('<target-dir>', 'Target directory to copy app to before applying patches')
29
+ .option('--skip-dependency-changes', 'Skip installing dependencies from package.json')
30
+ .option('--clean', 'Remove target directory if it exists before applying patches')
31
+ .action(async (featurePath: string, appPath: string, targetDir: string, options: { skipDependencyChanges?: boolean; clean?: boolean }) => {
32
+ try {
33
+ await applyPatchesCommand(featurePath, appPath, {
34
+ targetDirName: targetDir,
35
+ skipDependencyChanges: options.skipDependencyChanges,
36
+ clean: options.clean
37
+ });
38
+ process.exit(0);
39
+ } catch (err) {
40
+ process.exit(1);
41
+ }
42
+ });
43
+
44
+ program
45
+ .command('watch-patches')
46
+ .description('Watch feature template directory and auto-apply patches on changes')
47
+ .argument('<feature-path>', 'Path to the feature (e.g., packages/feature-navigation-menu)')
48
+ .argument('<app-path>', 'Path to the app (e.g., packages/base-react-app or my-app)')
49
+ .argument('<target-dir>', 'Target directory to apply patches to')
50
+ .option('--clean', 'Remove target directory if it exists before applying patches')
51
+ .action(async (featurePath: string, appPath: string, targetDir: string, options: { clean?: boolean }) => {
52
+ try {
53
+ await watchPatchesCommand(featurePath, appPath, targetDir, options);
54
+ } catch (err) {
55
+ process.exit(1);
56
+ }
57
+ });
58
+
59
+ program
60
+ .command('new-feature')
61
+ .description('Create a new feature package from the base-feature template')
62
+ .argument('<feature-name>', 'Name of the feature (will be prefixed with "feature-")')
63
+ .action(async (featureName: string) => {
64
+ try {
65
+ await newAppOrFeatureCommand(featureName, 'feature');
66
+ process.exit(0);
67
+ } catch (err) {
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+ program
73
+ .command('new-app')
74
+ .description('Create a new reference app package from the base-reference-app template')
75
+ .argument('<app-name>', 'Name of the app (will be prefixed with "app-")')
76
+ .action(async (appName: string) => {
77
+ try {
78
+ await newAppOrFeatureCommand(appName, 'app');
79
+ process.exit(0);
80
+ } catch (err) {
81
+ process.exit(1);
82
+ }
83
+ });
84
+
85
+ // If no command specified, default to apply-patches
86
+ if (process.argv.length > 2 && !process.argv[2].startsWith('-')) {
87
+ // If first argument is not a recognized command, treat as apply-patches command
88
+ const args = process.argv.slice(2);
89
+ const knownCommands = ['apply-patches', 'watch-patches', 'new-feature', 'new-app'];
90
+ if (!knownCommands.includes(args[0]) && !args[0].startsWith('-')) {
91
+ process.argv.splice(2, 0, 'apply-patches');
92
+ }
93
+ }
94
+
95
+ program.parse(process.argv);
package/src/types.ts ADDED
@@ -0,0 +1,23 @@
1
+ export type PackageJsonDependencies = {
2
+ dependencies?: Record<string, string>;
3
+ devDependencies?: Record<string, string>;
4
+ }
5
+
6
+ export type PathMapping = {
7
+ from: string; // Template path prefix (e.g., "webApp")
8
+ to: string; // Target path prefix (e.g., "digitalExperiences/webApplications/<feature-name>")
9
+ };
10
+
11
+ export type PathMappings = {
12
+ mappings?: PathMapping[]; // Array of custom path mappings
13
+ enabled?: boolean; // Enable/disable all mappings (default: true)
14
+ };
15
+
16
+ export type Feature = {
17
+ templateDir?: string; // The directory in the feature where the template files are located, defaults to 'template'
18
+ webAppName?: string; // The name of the web application, defaults to feature name
19
+ routeFilePath?: string; // The route file to merge (relative path from template dir), defaults to 'digitalExperiences/webApplications/<webAppName>/src/routes.tsx'
20
+ packageJson?: PackageJsonDependencies;
21
+ dependencies?: string[]; // Array of feature paths that this feature depends on (e.g., ['packages/feature-navigation-menu'])
22
+ pathMappings?: PathMappings; // Path mapping configuration for simplified directory structures (enabled by default)
23
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Creates a debounced function that delays invoking func until after wait milliseconds
3
+ * have elapsed since the last time the debounced function was invoked.
4
+ */
5
+ export function debounce<T extends (...args: any[]) => any>(
6
+ func: T,
7
+ wait: number
8
+ ): (...args: Parameters<T>) => void {
9
+ let timeoutId: NodeJS.Timeout | null = null;
10
+
11
+ return function debounced(...args: Parameters<T>): void {
12
+ // Clear any existing timeout
13
+ if (timeoutId !== null) {
14
+ clearTimeout(timeoutId);
15
+ }
16
+
17
+ // Set a new timeout
18
+ timeoutId = setTimeout(() => {
19
+ func(...args);
20
+ timeoutId = null;
21
+ }, wait);
22
+ };
23
+ }