@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,237 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { join } from 'path';
3
+ import { existsSync, writeFileSync, unlinkSync, readFileSync, mkdirSync } from 'fs';
4
+ import { createTempDir, cleanupTempDir } from '../helpers/create-temp-dir.js';
5
+ import { copyFixture, getFixturePath } from '../helpers/fixtures.js';
6
+ import { spawnWatchPatches } from '../helpers/cli-runner.js';
7
+ import type { ChildProcess } from 'child_process';
8
+
9
+ describe('watch-patches E2E', () => {
10
+ let tempDir: string;
11
+ let watchProcess: ChildProcess | null = null;
12
+
13
+ beforeEach(() => {
14
+ tempDir = createTempDir();
15
+ });
16
+
17
+ afterEach(async () => {
18
+ // Cleanup watcher if still running
19
+ if (watchProcess) {
20
+ watchProcess.kill('SIGTERM');
21
+ // Wait for process to exit
22
+ await new Promise(resolve => setTimeout(resolve, 100));
23
+ watchProcess = null;
24
+ }
25
+ cleanupTempDir(tempDir);
26
+ });
27
+
28
+ describe('Basic watch functionality', () => {
29
+ it('should detect and re-apply changes to feature files', async () => {
30
+ // Setup: Copy base app and watch fixture to temp location
31
+ const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
32
+ const targetDir = join(tempDir, 'watch-basic-target');
33
+
34
+ // Copy watch-basic fixture to a modifiable temp location
35
+ const featureDir = join(tempDir, 'watch-basic-feature');
36
+ copyFixture('watch/watch-basic', featureDir);
37
+
38
+ // Start watch mode via CLI
39
+ const watcher = spawnWatchPatches(featureDir, baseAppDir, targetDir, { clean: false });
40
+ watchProcess = watcher.process;
41
+
42
+ // Wait for initial application (longer timeout for spawned process)
43
+ await new Promise(resolve => setTimeout(resolve, 1500));
44
+
45
+ // Verify initial application
46
+ const targetFile = join(targetDir, 'digitalExperiences/webApplications/watch-basic/src/placeholder.tsx');
47
+ expect(existsSync(targetFile)).toBe(true);
48
+ const initialContent = readFileSync(targetFile, 'utf-8');
49
+
50
+ // Modify a file in the feature directory
51
+ const featureFile = join(featureDir, 'template/digitalExperiences/webApplications/watch-basic/src/placeholder.tsx');
52
+ const newContent = '// Modified content\nexport default function Placeholder() { return <div>Modified!</div>; }';
53
+ writeFileSync(featureFile, newContent);
54
+
55
+ // Wait for watch to detect and re-apply (debounce is 500ms)
56
+ await new Promise(resolve => setTimeout(resolve, 1000));
57
+
58
+ // Verify the change was applied
59
+ const updatedContent = readFileSync(targetFile, 'utf-8');
60
+ expect(updatedContent).toContain('Modified!');
61
+ expect(updatedContent).not.toBe(initialContent);
62
+
63
+ // Stop watch mode
64
+ if (watchProcess) {
65
+ watchProcess.kill('SIGTERM');
66
+ await new Promise(resolve => setTimeout(resolve, 100));
67
+ watchProcess = null;
68
+ }
69
+ }, 10000);
70
+ });
71
+
72
+ describe('Debounce functionality', () => {
73
+ it('should debounce rapid file changes', async () => {
74
+ // Setup
75
+ const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
76
+ const targetDir = join(tempDir, 'watch-debounce-target');
77
+ const featureDir = join(tempDir, 'watch-debounce-feature');
78
+ copyFixture('watch/watch-debounce', featureDir);
79
+
80
+ // Start watch mode via CLI
81
+ const watcher = spawnWatchPatches(featureDir, baseAppDir, targetDir, { clean: false });
82
+ watchProcess = watcher.process;
83
+
84
+ // Wait for initial application (longer timeout for spawned process)
85
+ await new Promise(resolve => setTimeout(resolve, 1500));
86
+
87
+ const featureFile = join(featureDir, 'template/digitalExperiences/webApplications/watch-debounce/src/placeholder.tsx');
88
+ const targetFile = join(targetDir, 'digitalExperiences/webApplications/watch-debounce/src/placeholder.tsx');
89
+
90
+ // Track how many times the file changed
91
+ let changeCount = 0;
92
+ const originalContent = readFileSync(targetFile, 'utf-8');
93
+
94
+ // Make rapid changes (3 changes within 200ms)
95
+ writeFileSync(featureFile, '// Change 1');
96
+ await new Promise(resolve => setTimeout(resolve, 50));
97
+ writeFileSync(featureFile, '// Change 2');
98
+ await new Promise(resolve => setTimeout(resolve, 50));
99
+ writeFileSync(featureFile, '// Change 3 - Final');
100
+
101
+ // Wait for debounce + apply (debounce is 500ms, so total ~800ms should be enough)
102
+ await new Promise(resolve => setTimeout(resolve, 1000));
103
+
104
+ // Verify only the final change was applied (debounced)
105
+ const finalContent = readFileSync(targetFile, 'utf-8');
106
+ expect(finalContent).toContain('Change 3 - Final');
107
+ expect(finalContent).not.toContain('Change 1');
108
+ expect(finalContent).not.toContain('Change 2');
109
+
110
+ // Stop watch mode
111
+ if (watchProcess) {
112
+ watchProcess.kill('SIGTERM');
113
+ await new Promise(resolve => setTimeout(resolve, 100));
114
+ watchProcess = null;
115
+ }
116
+ }, 10000);
117
+ });
118
+
119
+ describe('Multiple files', () => {
120
+ it('should detect changes across multiple files', async () => {
121
+ // Setup
122
+ const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
123
+ const targetDir = join(tempDir, 'watch-multiple-target');
124
+ const featureDir = join(tempDir, 'watch-multiple-feature');
125
+ copyFixture('watch/watch-multiple-files', featureDir);
126
+
127
+ // Start watch mode via CLI
128
+ const watcher = spawnWatchPatches(featureDir, baseAppDir, targetDir, { clean: false });
129
+ watchProcess = watcher.process;
130
+
131
+ // Wait for initial application (longer timeout for spawned process)
132
+ await new Promise(resolve => setTimeout(resolve, 1500));
133
+
134
+ // Modify multiple files
135
+ const componentsDir = join(featureDir, 'template/digitalExperiences/webApplications/watch-multiple-files/src/components');
136
+ const stylesDir = join(featureDir, 'template/digitalExperiences/webApplications/watch-multiple-files/src/styles');
137
+
138
+ if (!existsSync(componentsDir)) mkdirSync(componentsDir, { recursive: true });
139
+ if (!existsSync(stylesDir)) mkdirSync(stylesDir, { recursive: true });
140
+
141
+ writeFileSync(join(componentsDir, 'Header.tsx'), '// Header component');
142
+ await new Promise(resolve => setTimeout(resolve, 100));
143
+ writeFileSync(join(stylesDir, 'theme.css'), '/* Theme styles */');
144
+
145
+ // Wait for changes to be applied
146
+ await new Promise(resolve => setTimeout(resolve, 1000));
147
+
148
+ // Verify both files were applied
149
+ expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/watch-multiple-files/src/components/Header.tsx'))).toBe(true);
150
+ expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/watch-multiple-files/src/styles/theme.css'))).toBe(true);
151
+
152
+ // Stop watch mode
153
+ if (watchProcess) {
154
+ watchProcess.kill('SIGTERM');
155
+ await new Promise(resolve => setTimeout(resolve, 100));
156
+ watchProcess = null;
157
+ }
158
+ }, 10000);
159
+ });
160
+
161
+ describe('File additions and deletions', () => {
162
+ it('should handle file additions during watch', async () => {
163
+ // Setup
164
+ const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
165
+ const targetDir = join(tempDir, 'watch-add-delete-target');
166
+ const featureDir = join(tempDir, 'watch-add-delete-feature');
167
+ copyFixture('watch/watch-add-delete-files', featureDir);
168
+
169
+ // Start watch mode via CLI
170
+ const watcher = spawnWatchPatches(featureDir, baseAppDir, targetDir, { clean: false });
171
+ watchProcess = watcher.process;
172
+
173
+ // Wait for initial application (longer timeout for spawned process)
174
+ await new Promise(resolve => setTimeout(resolve, 1500));
175
+
176
+ // Add a new file to the feature
177
+ const srcDir = join(featureDir, 'template/digitalExperiences/webApplications/watch-add-delete-files/src');
178
+ const newFile = join(srcDir, 'NewComponent.tsx');
179
+ writeFileSync(newFile, '// New component added during watch');
180
+
181
+ // Wait for detection and application
182
+ await new Promise(resolve => setTimeout(resolve, 1000));
183
+
184
+ // Verify new file was applied
185
+ const targetNewFile = join(targetDir, 'digitalExperiences/webApplications/watch-add-delete-files/src/NewComponent.tsx');
186
+ expect(existsSync(targetNewFile)).toBe(true);
187
+ expect(readFileSync(targetNewFile, 'utf-8')).toContain('New component added during watch');
188
+
189
+ // Stop watch mode
190
+ if (watchProcess) {
191
+ watchProcess.kill('SIGTERM');
192
+ await new Promise(resolve => setTimeout(resolve, 100));
193
+ watchProcess = null;
194
+ }
195
+ }, 10000);
196
+
197
+ it('should handle file deletions during watch', async () => {
198
+ // Setup
199
+ const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
200
+ const targetDir = join(tempDir, 'watch-delete-target');
201
+ const featureDir = join(tempDir, 'watch-delete-feature');
202
+ copyFixture('watch/watch-add-delete-files', featureDir);
203
+
204
+ // Start watch mode with clean: true to properly handle deletions via CLI
205
+ const watcher = spawnWatchPatches(featureDir, baseAppDir, targetDir, { clean: true });
206
+ watchProcess = watcher.process;
207
+
208
+ // Wait for initial application (longer timeout for spawned process)
209
+ await new Promise(resolve => setTimeout(resolve, 1500));
210
+
211
+ // Verify initial file exists
212
+ const initialFile = join(featureDir, 'template/digitalExperiences/webApplications/watch-add-delete-files/src/initial.tsx');
213
+ const targetInitialFile = join(targetDir, 'digitalExperiences/webApplications/watch-add-delete-files/src/initial.tsx');
214
+ expect(existsSync(targetInitialFile)).toBe(true);
215
+
216
+ // Delete a file from the feature
217
+ if (existsSync(initialFile)) {
218
+ unlinkSync(initialFile);
219
+ }
220
+
221
+ // Wait for detection and handling
222
+ await new Promise(resolve => setTimeout(resolve, 1000));
223
+
224
+ // After deletion, the file should be restored from base app or removed
225
+ // (depending on whether it exists in base app)
226
+ // For this test, since it's a feature-specific file, it should be removed
227
+ expect(existsSync(targetInitialFile)).toBe(false);
228
+
229
+ // Stop watch mode
230
+ if (watchProcess) {
231
+ watchProcess.kill('SIGTERM');
232
+ await new Promise(resolve => setTimeout(resolve, 100));
233
+ watchProcess = null;
234
+ }
235
+ }, 10000);
236
+ });
237
+ });
@@ -0,0 +1,100 @@
1
+ import { spawn } from 'child_process';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const CLI_PATH = join(__dirname, '../../src/index.ts');
7
+
8
+ export interface CliResult {
9
+ exitCode: number;
10
+ stdout: string;
11
+ stderr: string;
12
+ }
13
+
14
+ /**
15
+ * Runs the CLI command via tsx (for TypeScript execution without build step)
16
+ */
17
+ export async function runCli(args: string[]): Promise<CliResult> {
18
+ return new Promise((resolve) => {
19
+ const child = spawn('tsx', [CLI_PATH, ...args], {
20
+ env: { ...process.env, FORCE_COLOR: '0' } // Disable colors for easier parsing
21
+ });
22
+
23
+ let stdout = '';
24
+ let stderr = '';
25
+
26
+ child.stdout?.on('data', (data) => {
27
+ stdout += data.toString();
28
+ });
29
+
30
+ child.stderr?.on('data', (data) => {
31
+ stderr += data.toString();
32
+ });
33
+
34
+ child.on('close', (code) => {
35
+ resolve({
36
+ exitCode: code ?? 1,
37
+ stdout,
38
+ stderr
39
+ });
40
+ });
41
+
42
+ child.on('error', (err) => {
43
+ resolve({
44
+ exitCode: 1,
45
+ stdout,
46
+ stderr: stderr + err.message
47
+ });
48
+ });
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Runs apply-patches command via CLI
54
+ */
55
+ export async function runApplyPatches(
56
+ featurePath: string,
57
+ appPath: string,
58
+ targetDir: string,
59
+ options: { skipDependencyChanges?: boolean; clean?: boolean } = {}
60
+ ): Promise<CliResult> {
61
+ const args = ['apply-patches', featurePath, appPath, targetDir];
62
+
63
+ if (options.skipDependencyChanges) {
64
+ args.push('--skip-dependency-changes');
65
+ }
66
+
67
+ if (options.clean) {
68
+ args.push('--clean');
69
+ }
70
+
71
+ return runCli(args);
72
+ }
73
+
74
+ /**
75
+ * Runs watch-patches command via CLI
76
+ * Note: For watch mode, caller must handle terminating the process
77
+ */
78
+ export function spawnWatchPatches(
79
+ featurePath: string,
80
+ appPath: string,
81
+ targetDir: string,
82
+ options: { clean?: boolean } = {}
83
+ ): { process: ReturnType<typeof spawn>; kill: () => void } {
84
+ const args = ['watch-patches', featurePath, appPath, targetDir];
85
+
86
+ if (options.clean) {
87
+ args.push('--clean');
88
+ }
89
+
90
+ const child = spawn('tsx', [CLI_PATH, ...args], {
91
+ env: { ...process.env, FORCE_COLOR: '0' }
92
+ });
93
+
94
+ return {
95
+ process: child,
96
+ kill: () => {
97
+ child.kill('SIGTERM');
98
+ }
99
+ };
100
+ }
@@ -0,0 +1,197 @@
1
+ import { readdirSync, statSync, readFileSync, existsSync, cpSync, mkdirSync, rmSync } from 'fs';
2
+ import { join, relative } from 'path';
3
+
4
+ export interface FileDifference {
5
+ type: 'missing' | 'extra' | 'content' | 'type-mismatch';
6
+ path: string;
7
+ details?: string;
8
+ }
9
+
10
+ /**
11
+ * Normalize whitespace and line endings for comparison
12
+ */
13
+ function normalizeContent(content: string): string {
14
+ return content
15
+ .replace(/\r\n/g, '\n') // Normalize line endings
16
+ .trim(); // Remove trailing whitespace
17
+ }
18
+
19
+ /**
20
+ * Check if a path should be ignored in comparisons
21
+ */
22
+ function shouldIgnore(path: string): boolean {
23
+ const ignoredNames = [
24
+ 'node_modules',
25
+ 'dist',
26
+ '.git',
27
+ '.DS_Store',
28
+ 'package-lock.json',
29
+ 'npm-debug.log'
30
+ ];
31
+
32
+ return ignoredNames.some(ignored => path.includes(ignored));
33
+ }
34
+
35
+ /**
36
+ * Recursively get all files in a directory
37
+ */
38
+ function getAllFiles(dir: string, baseDir: string = dir): string[] {
39
+ if (!existsSync(dir)) {
40
+ return [];
41
+ }
42
+
43
+ const files: string[] = [];
44
+ const entries = readdirSync(dir);
45
+
46
+ for (const entry of entries) {
47
+ const fullPath = join(dir, entry);
48
+ const relativePath = relative(baseDir, fullPath);
49
+
50
+ if (shouldIgnore(relativePath)) {
51
+ continue;
52
+ }
53
+
54
+ const stat = statSync(fullPath);
55
+
56
+ if (stat.isDirectory()) {
57
+ files.push(...getAllFiles(fullPath, baseDir));
58
+ } else if (stat.isFile()) {
59
+ files.push(relativePath);
60
+ }
61
+ }
62
+
63
+ return files;
64
+ }
65
+
66
+ /**
67
+ * Compare two directories and return differences
68
+ * @param actualDir - Directory with actual output
69
+ * @param expectedDir - Directory with expected output (gold files)
70
+ * @returns Array of differences (empty if identical)
71
+ */
72
+ export function compareDirectories(actualDir: string, expectedDir: string): FileDifference[] {
73
+ const differences: FileDifference[] = [];
74
+
75
+ // Get all files from both directories
76
+ const actualFiles = new Set(getAllFiles(actualDir));
77
+ const expectedFiles = new Set(getAllFiles(expectedDir));
78
+
79
+ // Check for missing files (in expected but not in actual)
80
+ for (const file of expectedFiles) {
81
+ if (!actualFiles.has(file)) {
82
+ differences.push({
83
+ type: 'missing',
84
+ path: file,
85
+ details: `File exists in gold but not in actual output`
86
+ });
87
+ }
88
+ }
89
+
90
+ // Check for extra files (in actual but not in expected)
91
+ for (const file of actualFiles) {
92
+ if (!expectedFiles.has(file)) {
93
+ differences.push({
94
+ type: 'extra',
95
+ path: file,
96
+ details: `File exists in actual output but not in gold`
97
+ });
98
+ }
99
+ }
100
+
101
+ // Compare content of common files
102
+ for (const file of actualFiles) {
103
+ if (!expectedFiles.has(file)) {
104
+ continue; // Already reported as extra
105
+ }
106
+
107
+ const actualPath = join(actualDir, file);
108
+ const expectedPath = join(expectedDir, file);
109
+
110
+ const actualStat = statSync(actualPath);
111
+ const expectedStat = statSync(expectedPath);
112
+
113
+ // Check if both are same type (file vs directory)
114
+ if (actualStat.isDirectory() !== expectedStat.isDirectory()) {
115
+ differences.push({
116
+ type: 'type-mismatch',
117
+ path: file,
118
+ details: actualStat.isDirectory()
119
+ ? 'Actual is directory but expected is file'
120
+ : 'Actual is file but expected is directory'
121
+ });
122
+ continue;
123
+ }
124
+
125
+ // Compare file contents
126
+ if (actualStat.isFile()) {
127
+ const actualContent = normalizeContent(readFileSync(actualPath, 'utf-8'));
128
+ const expectedContent = normalizeContent(readFileSync(expectedPath, 'utf-8'));
129
+
130
+ if (actualContent !== expectedContent) {
131
+ // Generate a simple diff preview
132
+ const actualLines = actualContent.split('\n');
133
+ const expectedLines = expectedContent.split('\n');
134
+ const maxLines = Math.max(actualLines.length, expectedLines.length);
135
+ let diffPreview = '';
136
+
137
+ for (let i = 0; i < Math.min(5, maxLines); i++) {
138
+ if (actualLines[i] !== expectedLines[i]) {
139
+ diffPreview += `\n Line ${i + 1}:\n`;
140
+ diffPreview += ` Expected: ${expectedLines[i] || '(empty)'}\n`;
141
+ diffPreview += ` Actual: ${actualLines[i] || '(empty)'}`;
142
+ break; // Show first difference only
143
+ }
144
+ }
145
+
146
+ differences.push({
147
+ type: 'content',
148
+ path: file,
149
+ details: `File contents differ${diffPreview}`
150
+ });
151
+ }
152
+ }
153
+ }
154
+
155
+ return differences;
156
+ }
157
+
158
+ /**
159
+ * Update gold files with actual output
160
+ * Use with UPDATE_GOLD=1 environment variable
161
+ */
162
+ export function updateGoldFiles(actualDir: string, goldDir: string): void {
163
+ if (!existsSync(actualDir)) {
164
+ throw new Error(`Actual directory does not exist: ${actualDir}`);
165
+ }
166
+
167
+ // Remove existing gold directory
168
+ if (existsSync(goldDir)) {
169
+ rmSync(goldDir, { recursive: true, force: true });
170
+ }
171
+
172
+ // Create gold directory
173
+ mkdirSync(goldDir, { recursive: true });
174
+
175
+ // Copy actual output to gold
176
+ cpSync(actualDir, goldDir, {
177
+ recursive: true,
178
+ filter: (src) => {
179
+ const relativePath = relative(actualDir, src);
180
+ return !shouldIgnore(relativePath);
181
+ }
182
+ });
183
+
184
+ console.warn(`⚠️ Updated gold files: ${goldDir}`);
185
+ }
186
+
187
+ /**
188
+ * Compare or update gold files based on UPDATE_GOLD environment variable
189
+ */
190
+ export function compareOrUpdate(actualDir: string, goldDir: string): FileDifference[] {
191
+ if (process.env.UPDATE_GOLD === '1') {
192
+ updateGoldFiles(actualDir, goldDir);
193
+ return []; // Return no differences when updating
194
+ }
195
+
196
+ return compareDirectories(actualDir, goldDir);
197
+ }
@@ -0,0 +1,34 @@
1
+ import { mkdtempSync, rmSync, existsSync } from 'fs';
2
+ import { tmpdir } from 'os';
3
+ import { join } from 'path';
4
+
5
+ /**
6
+ * Create a temporary directory for testing
7
+ * @returns Absolute path to the temporary directory
8
+ */
9
+ export function createTempDir(): string {
10
+ const prefix = join(tmpdir(), 'cli-test-');
11
+ return mkdtempSync(prefix);
12
+ }
13
+
14
+ /**
15
+ * Clean up a temporary directory
16
+ * @param tempDir - Path to the temporary directory to remove
17
+ */
18
+ export function cleanupTempDir(tempDir: string): void {
19
+ if (existsSync(tempDir)) {
20
+ rmSync(tempDir, { recursive: true, force: true });
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Create a temporary directory and return cleanup function
26
+ * Use with afterEach: const cleanup = useTempDir();
27
+ */
28
+ export function useTempDir(): { path: string; cleanup: () => void } {
29
+ const tempDir = createTempDir();
30
+ return {
31
+ path: tempDir,
32
+ cleanup: () => cleanupTempDir(tempDir)
33
+ };
34
+ }
@@ -0,0 +1,67 @@
1
+ import { cpSync, existsSync } from 'fs';
2
+ import { join, resolve, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ /**
9
+ * Get the absolute path to the test directory
10
+ */
11
+ export function getTestDir(): string {
12
+ return resolve(__dirname, '..');
13
+ }
14
+
15
+ /**
16
+ * Get the absolute path to a fixture
17
+ */
18
+ export function getFixturePath(fixtureName: string): string {
19
+ return join(getTestDir(), 'e2e', 'fixtures', fixtureName);
20
+ }
21
+
22
+ /**
23
+ * Get the absolute path to a gold file directory
24
+ */
25
+ export function getGoldPath(goldName: string): string {
26
+ return join(getTestDir(), 'e2e', 'gold', goldName);
27
+ }
28
+
29
+ /**
30
+ * Get the absolute path to a unit test gold file
31
+ */
32
+ export function getUnitGoldPath(category: string, filename: string): string {
33
+ return join(getTestDir(), 'unit', 'gold', category, filename);
34
+ }
35
+
36
+ /**
37
+ * Copy a fixture to a target directory
38
+ * @param fixtureName - Name of the fixture in test/e2e/fixtures/
39
+ * @param targetPath - Absolute path where to copy the fixture
40
+ * @returns The target path
41
+ */
42
+ export function copyFixture(fixtureName: string, targetPath: string): string {
43
+ const fixturePath = getFixturePath(fixtureName);
44
+
45
+ if (!existsSync(fixturePath)) {
46
+ throw new Error(`Fixture not found: ${fixturePath}`);
47
+ }
48
+
49
+ cpSync(fixturePath, targetPath, {
50
+ recursive: true,
51
+ filter: (src) => {
52
+ // Don't copy node_modules or dist directories
53
+ return !src.includes('node_modules') && !src.includes('dist');
54
+ }
55
+ });
56
+
57
+ return targetPath;
58
+ }
59
+
60
+ /**
61
+ * Read a gold file's content
62
+ */
63
+ export function readGoldFile(category: string, filename: string): string {
64
+ const { readFileSync } = require('fs');
65
+ const goldPath = getUnitGoldPath(category, filename);
66
+ return readFileSync(goldPath, 'utf-8');
67
+ }
package/test/setup.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Global test setup for Vitest
3
+ * This file runs before all tests
4
+ */
5
+
6
+ // Add any global test utilities or setup here