@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.
- package/README.md +1414 -0
- package/dist/commands/apply-patches.d.ts +23 -0
- package/dist/commands/apply-patches.d.ts.map +1 -0
- package/dist/commands/apply-patches.js +524 -0
- package/dist/commands/apply-patches.js.map +1 -0
- package/dist/commands/new-app-feature.d.ts +7 -0
- package/dist/commands/new-app-feature.d.ts.map +1 -0
- package/dist/commands/new-app-feature.js +166 -0
- package/dist/commands/new-app-feature.js.map +1 -0
- package/dist/commands/new-app.d.ts +1 -0
- package/dist/commands/new-app.d.ts.map +1 -0
- package/dist/commands/new-app.js +2 -0
- package/dist/commands/new-app.js.map +1 -0
- package/dist/commands/watch-patches.d.ts +6 -0
- package/dist/commands/watch-patches.d.ts.map +1 -0
- package/dist/commands/watch-patches.js +152 -0
- package/dist/commands/watch-patches.js.map +1 -0
- package/dist/core/dependency-resolver.d.ts +40 -0
- package/dist/core/dependency-resolver.d.ts.map +1 -0
- package/dist/core/dependency-resolver.js +122 -0
- package/dist/core/dependency-resolver.js.map +1 -0
- package/dist/core/file-operations.d.ts +37 -0
- package/dist/core/file-operations.d.ts.map +1 -0
- package/dist/core/file-operations.js +201 -0
- package/dist/core/file-operations.js.map +1 -0
- package/dist/core/package-json-merger.d.ts +30 -0
- package/dist/core/package-json-merger.d.ts.map +1 -0
- package/dist/core/package-json-merger.js +104 -0
- package/dist/core/package-json-merger.js.map +1 -0
- package/dist/core/patch-loader.d.ts +17 -0
- package/dist/core/patch-loader.d.ts.map +1 -0
- package/dist/core/patch-loader.js +100 -0
- package/dist/core/patch-loader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/debounce.d.ts +6 -0
- package/dist/utils/debounce.d.ts.map +1 -0
- package/dist/utils/debounce.js +19 -0
- package/dist/utils/debounce.js.map +1 -0
- package/dist/utils/import-merger.d.ts +12 -0
- package/dist/utils/import-merger.d.ts.map +1 -0
- package/dist/utils/import-merger.js +240 -0
- package/dist/utils/import-merger.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path-mappings.d.ts +88 -0
- package/dist/utils/path-mappings.d.ts.map +1 -0
- package/dist/utils/path-mappings.js +138 -0
- package/dist/utils/path-mappings.js.map +1 -0
- package/dist/utils/paths.d.ts +43 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +107 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/route-merger.d.ts +107 -0
- package/dist/utils/route-merger.d.ts.map +1 -0
- package/dist/utils/route-merger.js +303 -0
- package/dist/utils/route-merger.js.map +1 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +109 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +39 -0
- package/src/commands/apply-patches.ts +594 -0
- package/src/commands/new-app-feature.ts +203 -0
- package/src/commands/new-app.ts +0 -0
- package/src/commands/watch-patches.ts +173 -0
- package/src/core/dependency-resolver.ts +175 -0
- package/src/core/file-operations.ts +265 -0
- package/src/core/package-json-merger.ts +129 -0
- package/src/core/patch-loader.ts +128 -0
- package/src/index.ts +95 -0
- package/src/types.ts +23 -0
- package/src/utils/debounce.ts +23 -0
- package/src/utils/import-merger.ts +293 -0
- package/src/utils/logger.ts +21 -0
- package/src/utils/path-mappings.ts +154 -0
- package/src/utils/paths.ts +121 -0
- package/src/utils/route-merger.ts +357 -0
- package/src/utils/validation.ts +150 -0
- package/test/e2e/E2E_TEST_FIXTURES.md +509 -0
- package/test/e2e/apply-patches.spec.ts +861 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/package.json +10 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/appLayout.tsx +27 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/home.tsx +8 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/index.tsx +10 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/old-page.tsx +8 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/routes.tsx +23 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/styles/global.css +14 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/feature.ts +11 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx +8 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx +17 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/feature.ts +10 -0
- 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
- 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
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx +8 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx +17 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/feature.ts +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/routes.tsx +17 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx +9 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/styles/__append__global.css +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/feature.ts +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/__delete__old-page.tsx +2 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx +16 -0
- package/test/e2e/fixtures/composition-5-features/5-features-about/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-about/template/digitalExperiences/webApplications/5-features-about/src/about.tsx +8 -0
- package/test/e2e/fixtures/composition-5-features/5-features-about/template/digitalExperiences/webApplications/5-features-about/src/routes.tsx +17 -0
- package/test/e2e/fixtures/composition-5-features/5-features-analytics/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-analytics/template/digitalExperiences/webApplications/5-features-analytics/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/composition-5-features/5-features-footer/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-footer/template/digitalExperiences/webApplications/5-features-footer/src/footer.tsx +7 -0
- package/test/e2e/fixtures/composition-5-features/5-features-footer/template/digitalExperiences/webApplications/5-features-footer/src/routes.tsx +17 -0
- package/test/e2e/fixtures/composition-5-features/5-features-navigation/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-navigation/template/digitalExperiences/webApplications/5-features-navigation/src/navigation.tsx +7 -0
- package/test/e2e/fixtures/composition-5-features/5-features-navigation/template/digitalExperiences/webApplications/5-features-navigation/src/routes.tsx +17 -0
- package/test/e2e/fixtures/composition-5-features/5-features-theme/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-theme/template/digitalExperiences/webApplications/5-features-theme/src/styles/__append__global.css +5 -0
- package/test/e2e/fixtures/composition-append/composition-append-1/feature.ts +10 -0
- package/test/e2e/fixtures/composition-append/composition-append-1/template/digitalExperiences/webApplications/composition-append-1/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/composition-append/composition-append-2/feature.ts +10 -0
- package/test/e2e/fixtures/composition-append/composition-append-2/template/digitalExperiences/webApplications/composition-append-2/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/composition-append/composition-append-3/feature.ts +10 -0
- package/test/e2e/fixtures/composition-append/composition-append-3/template/digitalExperiences/webApplications/composition-append-3/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-inherit-layout/feature.ts +3 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-inherit-layout/template/digitalExperiences/webApplications/composition-inherit-layout/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-modify-layout/feature.ts +3 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-modify-layout/template/digitalExperiences/webApplications/composition-modify-layout/src/__append__appLayout.tsx +2 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-1/feature.ts +10 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-1/template/digitalExperiences/webApplications/composition-prepend-1/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-2/feature.ts +10 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-2/template/digitalExperiences/webApplications/composition-prepend-2/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-3/feature.ts +10 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-3/template/digitalExperiences/webApplications/composition-prepend-3/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-a/feature.ts +11 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-a/template/digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-a/template/digitalExperiences/webApplications/dep-chain-a/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-b/feature.ts +11 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-b/template/digitalExperiences/webApplications/dep-chain-b/src/page-b.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-b/template/digitalExperiences/webApplications/dep-chain-b/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-c/feature.ts +11 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-c/template/digitalExperiences/webApplications/dep-chain-c/src/page-c.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-c/template/digitalExperiences/webApplications/dep-chain-c/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-d/feature.ts +10 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-d/template/digitalExperiences/webApplications/dep-chain-d/src/page-d.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-d/template/digitalExperiences/webApplications/dep-chain-d/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-a/feature.ts +11 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-a/template/digitalExperiences/webApplications/dep-circular-a/src/page-a.tsx +8 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-b/feature.ts +11 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-b/template/digitalExperiences/webApplications/dep-circular-b/src/page-b.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/README.md +119 -0
- package/test/e2e/fixtures/dep-complex-graph/create-placeholders.sh +25 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/feature.ts +14 -0
- 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
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/login.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/routes.tsx +29 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/signup.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/feature.ts +14 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/analytics.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/dashboard.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/reports.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/routes.tsx +32 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/feature.ts +14 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/profile-edit.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/profile.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/routes.tsx +26 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/feature.ts +14 -0
- 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
- 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
- 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
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/feature.ts +10 -0
- 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
- 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
- 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
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/feature.ts +10 -0
- 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
- 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
- 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
- package/test/e2e/fixtures/dep-complex-graph/feature.ts +15 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx +24 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-left/feature.ts +11 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-left/template/digitalExperiences/webApplications/dep-diamond-left/src/left-page.tsx +8 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-left/template/digitalExperiences/webApplications/dep-diamond-left/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-right/feature.ts +11 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-right/template/digitalExperiences/webApplications/dep-diamond-right/src/right-page.tsx +8 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-right/template/digitalExperiences/webApplications/dep-diamond-right/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/feature.ts +10 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/template/digitalExperiences/webApplications/dep-diamond-shared/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/template/digitalExperiences/webApplications/dep-diamond-shared/src/shared-utils.tsx +8 -0
- package/test/e2e/fixtures/edges/edge-binary-files/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/assets/test-image.png +0 -0
- package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-conflicting-prefixes/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-conflicting-prefixes/template/digitalExperiences/webApplications/edge-conflicting-prefixes/src/__inherit____delete__conflicting.tsx +5 -0
- package/test/e2e/fixtures/edges/edge-conflicting-prefixes/template/digitalExperiences/webApplications/edge-conflicting-prefixes/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-empty-feature/feature.ts +16 -0
- package/test/e2e/fixtures/edges/edge-empty-feature/template/digitalExperiences/webApplications/edge-empty-feature/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-invalid-routes/feature.ts +12 -0
- package/test/e2e/fixtures/edges/edge-invalid-routes/template/digitalExperiences/webApplications/edge-invalid-routes/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-invalid-routes/template/digitalExperiences/webApplications/edge-invalid-routes/src/routes.tsx +8 -0
- package/test/e2e/fixtures/edges/edge-line-endings/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/crlf.tsx +4 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/__inherit__missing.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/__prepend__nonexistent.tsx +2 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-a/feature.ts +14 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-a/template/digitalExperiences/webApplications/edge-package-json-conflicts-a/src/placeholder.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-b/feature.ts +14 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-b/template/digitalExperiences/webApplications/edge-package-json-conflicts-b/src/placeholder.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-performance-many/feature.ts +26 -0
- package/test/e2e/fixtures/edges/edge-performance-many/template/digitalExperiences/webApplications/edge-performance-many/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/path-mappings/feature-custom-mapping/feature.ts +16 -0
- package/test/e2e/fixtures/path-mappings/feature-custom-mapping/template/web/src/custom-component.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-custom-mapping/template/web/src/routes.tsx +8 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/feature.ts +7 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/digitalExperiences/webApplications/feature-mixed-paths/assets/icon.svg +3 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/webApp/src/mapped-component.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/webApp/src/routes.tsx +8 -0
- package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/feature.ts +7 -0
- package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/template/webApp/src/app.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/template/webApp/src/routes.tsx +8 -0
- package/test/e2e/fixtures/path-mappings/feature-without-mapping/feature.ts +11 -0
- package/test/e2e/fixtures/path-mappings/feature-without-mapping/template/digitalExperiences/webApplications/feature-without-mapping/src/legacy-component.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-without-mapping/template/digitalExperiences/webApplications/feature-without-mapping/src/routes.tsx +8 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/feature.ts +10 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/components/LoginForm.tsx +25 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/context/AuthContext.tsx +28 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/login.tsx +10 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/routes.tsx +17 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/feature.ts +11 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactDetail.tsx +54 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactForm.tsx +146 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactList.tsx +77 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/routes.tsx +36 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/styles/__append__global.css +176 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/utils/contactsApi.ts +42 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/feature.ts +10 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/__append__appLayout.tsx +4 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/components/NavigationMenu.tsx +17 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/single-operations/feature-file-append/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-append/template/digitalExperiences/webApplications/feature-file-append/src/styles/__append__global.css +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-inherit/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-inherit/template/digitalExperiences/webApplications/feature-file-inherit/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/single-operations/feature-file-inherit/template/digitalExperiences/webApplications/feature-file-inherit/src/__inherit__home.tsx +1 -0
- package/test/e2e/fixtures/single-operations/feature-file-prepend/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-prepend/template/digitalExperiences/webApplications/feature-file-prepend/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/single-operations/feature-import-merge/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-import-merge/template/digitalExperiences/webApplications/feature-import-merge/src/routes.tsx +18 -0
- package/test/e2e/fixtures/single-operations/feature-import-merge/template/digitalExperiences/webApplications/feature-import-merge/src/settings.tsx +8 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/about.tsx +8 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/routes.tsx +23 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/services.tsx +8 -0
- package/test/e2e/fixtures/watch/watch-add-delete-files/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-add-delete-files/template/digitalExperiences/webApplications/watch-add-delete-files/src/initial.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-add-delete-files/template/digitalExperiences/webApplications/watch-add-delete-files/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-basic/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-basic/template/digitalExperiences/webApplications/watch-basic/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-basic/template/digitalExperiences/webApplications/watch-basic/src/watchTest.tsx +3 -0
- package/test/e2e/fixtures/watch/watch-debounce/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-debounce/template/digitalExperiences/webApplications/watch-debounce/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/components/WatchComponent.tsx +3 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/styles/theme.css +4 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/package.json +10 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/about.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/appLayout.tsx +27 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/home.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/index.tsx +10 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/old-page.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx +35 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/styles/global.css +14 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/package.json +10 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/appLayout.tsx +27 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/home.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/index.tsx +10 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/old-page.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-b.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-c.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-d.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/routes.tsx +47 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/styles/global.css +14 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/package.json +10 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/analytics.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/appLayout.tsx +27 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/components.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/dashboard.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/home.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/index.tsx +10 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/login.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/profile-edit.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/profile.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/reports.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx +94 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/signup.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/styles/global.css +14 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/tools.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/types.tsx +8 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/package.json +10 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/custom-component.tsx +3 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/home.tsx +8 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/index.tsx +10 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/package.json +10 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx +8 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/home.tsx +8 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/index.tsx +10 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx +29 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/package.json +10 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/home.tsx +8 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/index.tsx +13 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/routes.tsx +29 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx +9 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/styles/global.css +25 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/package.json +10 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/home.tsx +8 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/index.tsx +10 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx +17 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/assets/icon.svg +3 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/package.json +10 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/home.tsx +8 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/index.tsx +10 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/mapped-component.tsx +3 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/package.json +10 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/app.tsx +3 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/home.tsx +8 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/index.tsx +10 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/package.json +10 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/home.tsx +8 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/index.tsx +10 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/legacy-component.tsx +3 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/styles/global.css +14 -0
- package/test/e2e/path-mappings.spec.ts +232 -0
- package/test/e2e/watch-patches.spec.ts +237 -0
- package/test/helpers/cli-runner.ts +100 -0
- package/test/helpers/compare-directories.ts +197 -0
- package/test/helpers/create-temp-dir.ts +34 -0
- package/test/helpers/fixtures.ts +67 -0
- package/test/setup.ts +6 -0
- package/test/unit/debounce.spec.ts +159 -0
- package/test/unit/dependency-resolver.spec.ts +260 -0
- package/test/unit/file-operations.spec.ts +264 -0
- package/test/unit/import-merger.spec.ts +395 -0
- package/test/unit/index.spec.ts +158 -0
- package/test/unit/new-app.spec.ts +178 -0
- package/test/unit/new-feature.spec.ts +178 -0
- package/test/unit/package-json-merger.spec.ts +275 -0
- package/test/unit/patch-loader.spec.ts +238 -0
- package/test/unit/path-mappings.spec.ts +241 -0
- package/test/unit/paths.spec.ts +247 -0
- package/test/unit/route-merger.spec.ts +265 -0
- package/test/unit/validation.spec.ts +311 -0
- package/tsconfig.json +20 -0
- 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
|
+
}
|