@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,357 @@
|
|
|
1
|
+
import * as logger from './logger.js';
|
|
2
|
+
import { Project, ArrayLiteralExpression, SourceFile, Node } from 'ts-morph';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { mergeImports } from './import-merger.js';
|
|
5
|
+
|
|
6
|
+
// Simplified RouteObject type covering common react-router fields
|
|
7
|
+
interface RouteObject {
|
|
8
|
+
path?: string;
|
|
9
|
+
index?: boolean;
|
|
10
|
+
children?: RouteObject[];
|
|
11
|
+
element?: any;
|
|
12
|
+
handle?: any;
|
|
13
|
+
loader?: any;
|
|
14
|
+
action?: any;
|
|
15
|
+
errorElement?: any;
|
|
16
|
+
[key: string]: any; // Allow additional properties
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Route Merging Strategy: Replace-Matching with Deep Children Merge
|
|
21
|
+
*
|
|
22
|
+
* This function merges React Router routes from a feature into a base app using
|
|
23
|
+
* a "replace-matching" strategy with intelligent children array merging.
|
|
24
|
+
*
|
|
25
|
+
* ## How It Works:
|
|
26
|
+
*
|
|
27
|
+
* 1. **Top-Level Routes:**
|
|
28
|
+
* - Routes with the SAME path → Merge their children arrays
|
|
29
|
+
* - Routes with DIFFERENT paths → Add feature route to result
|
|
30
|
+
*
|
|
31
|
+
* 2. **Children Array Merging (when parent paths match):**
|
|
32
|
+
* - Index routes (`index: true`) → Feature replaces base if both exist
|
|
33
|
+
* - Named routes (`path: 'about'`) → Feature replaces base if paths match
|
|
34
|
+
* - New routes → Added to children array
|
|
35
|
+
* - Preserves base routes not in feature
|
|
36
|
+
*
|
|
37
|
+
* 3. **Route Deletion:**
|
|
38
|
+
* - Routes with path starting with `__delete__` are deletion markers
|
|
39
|
+
* - The route with matching path (without prefix) is removed from result
|
|
40
|
+
* - Example: `{ path: '__delete__new' }` removes the route with `path: 'new'`
|
|
41
|
+
*
|
|
42
|
+
* 4. **Recursion:**
|
|
43
|
+
* - Applies same logic to nested children arrays
|
|
44
|
+
*
|
|
45
|
+
* ## Example:
|
|
46
|
+
*
|
|
47
|
+
* **Base App Routes:**
|
|
48
|
+
* ```typescript
|
|
49
|
+
* [{
|
|
50
|
+
* path: '/',
|
|
51
|
+
* element: <AppLayout />,
|
|
52
|
+
* children: [
|
|
53
|
+
* { index: true, element: <Home /> }
|
|
54
|
+
* ]
|
|
55
|
+
* }]
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* **Feature Routes:**
|
|
59
|
+
* ```typescript
|
|
60
|
+
* [{
|
|
61
|
+
* path: '/',
|
|
62
|
+
* element: <AppLayout />,
|
|
63
|
+
* children: [
|
|
64
|
+
* { path: 'about', element: <About /> },
|
|
65
|
+
* { path: 'contact', element: <Contact /> }
|
|
66
|
+
* ]
|
|
67
|
+
* }]
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* **Merged Result:**
|
|
71
|
+
* ```typescript
|
|
72
|
+
* [{
|
|
73
|
+
* path: '/',
|
|
74
|
+
* element: <AppLayout />, // Uses feature's element
|
|
75
|
+
* children: [
|
|
76
|
+
* { index: true, element: <Home /> }, // Preserved from base
|
|
77
|
+
* { path: 'about', element: <About /> }, // Added from feature
|
|
78
|
+
* { path: 'contact', element: <Contact /> } // Added from feature
|
|
79
|
+
* ]
|
|
80
|
+
* }]
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* ## Deletion Example:
|
|
84
|
+
*
|
|
85
|
+
* **Base/Previous Routes:**
|
|
86
|
+
* ```typescript
|
|
87
|
+
* [{
|
|
88
|
+
* path: '/',
|
|
89
|
+
* children: [
|
|
90
|
+
* { path: 'home', element: <Home /> },
|
|
91
|
+
* { path: 'about', element: <About /> },
|
|
92
|
+
* { path: 'new', element: <New /> }
|
|
93
|
+
* ]
|
|
94
|
+
* }]
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* **Feature Routes (deleting 'new'):**
|
|
98
|
+
* ```typescript
|
|
99
|
+
* [{
|
|
100
|
+
* path: '/',
|
|
101
|
+
* children: [
|
|
102
|
+
* { path: '__delete__new', element: <></> }
|
|
103
|
+
* ]
|
|
104
|
+
* }]
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* **Merged Result:**
|
|
108
|
+
* ```typescript
|
|
109
|
+
* [{
|
|
110
|
+
* path: '/',
|
|
111
|
+
* children: [
|
|
112
|
+
* { path: 'home', element: <Home /> }, // Preserved
|
|
113
|
+
* { path: 'about', element: <About /> } // Preserved
|
|
114
|
+
* // 'new' route removed
|
|
115
|
+
* ]
|
|
116
|
+
* }]
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @param featurePath - Path to the feature's routes.tsx file
|
|
120
|
+
* @param targetPath - Path to the base app's routes.tsx file
|
|
121
|
+
* @returns The merged routes source code
|
|
122
|
+
*/
|
|
123
|
+
export function mergeRoutes(
|
|
124
|
+
featurePath: string,
|
|
125
|
+
targetPath: string,
|
|
126
|
+
project?: Project
|
|
127
|
+
): string {
|
|
128
|
+
try {
|
|
129
|
+
const proj = project || new Project();
|
|
130
|
+
|
|
131
|
+
const targetFile = project
|
|
132
|
+
? proj.getSourceFile(targetPath) || proj.addSourceFileAtPath(path.resolve(targetPath))
|
|
133
|
+
: proj.addSourceFileAtPath(path.resolve(targetPath));
|
|
134
|
+
|
|
135
|
+
const featureFile = project
|
|
136
|
+
? proj.getSourceFile(featurePath) || proj.addSourceFileAtPath(path.resolve(featurePath))
|
|
137
|
+
: proj.addSourceFileAtPath(path.resolve(featurePath));
|
|
138
|
+
|
|
139
|
+
// Get initial routes arrays to validate they exist
|
|
140
|
+
const initialTargetArray = getRoutesArrayLiteral(targetFile, 'routes');
|
|
141
|
+
const initialFeatureArray = getRoutesArrayLiteral(featureFile, 'routes');
|
|
142
|
+
|
|
143
|
+
if (!initialTargetArray) {
|
|
144
|
+
logger.warning('Could not extract routes array from target file');
|
|
145
|
+
return featureFile.getText();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!initialFeatureArray) {
|
|
149
|
+
logger.warning('Could not extract routes array from feature file');
|
|
150
|
+
return targetFile.getText();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Merge imports from feature file into target file
|
|
154
|
+
// Note: This calls organizeImports() which invalidates AST node references
|
|
155
|
+
mergeImports(featureFile, targetFile);
|
|
156
|
+
|
|
157
|
+
// Re-get routes arrays after import merging (organizeImports invalidates previous references)
|
|
158
|
+
const targetArray = getRoutesArrayLiteral(targetFile, 'routes');
|
|
159
|
+
const featureArray = getRoutesArrayLiteral(featureFile, 'routes');
|
|
160
|
+
|
|
161
|
+
if (!targetArray || !featureArray) {
|
|
162
|
+
logger.error('Routes array was lost after import merging');
|
|
163
|
+
throw new Error('Failed to re-acquire routes arrays after import merging');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Parse arrays to RouteObject[]
|
|
167
|
+
const targetRoutes = parseRoutesFromAST(targetArray);
|
|
168
|
+
const featureRoutes = parseRoutesFromAST(featureArray);
|
|
169
|
+
|
|
170
|
+
// Deep merge the routes
|
|
171
|
+
const mergedRoutes = deepMergeRoutes(targetRoutes, featureRoutes);
|
|
172
|
+
|
|
173
|
+
// Convert back to code and update the target
|
|
174
|
+
const mergedCode = generateRoutesCode(mergedRoutes);
|
|
175
|
+
targetArray.replaceWithText(mergedCode);
|
|
176
|
+
|
|
177
|
+
return targetFile.getText();
|
|
178
|
+
} catch (err) {
|
|
179
|
+
logger.error(`Route merge failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
180
|
+
throw new Error('Failed to merge routes');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get the array literal expression for the routes variable
|
|
186
|
+
*/
|
|
187
|
+
function getRoutesArrayLiteral(
|
|
188
|
+
file: SourceFile,
|
|
189
|
+
varName: string
|
|
190
|
+
): ArrayLiteralExpression | undefined {
|
|
191
|
+
const variable = file.getVariableDeclaration(varName);
|
|
192
|
+
|
|
193
|
+
if (!variable) {
|
|
194
|
+
logger.warning(`Variable "${varName}" not found in ${file.getFilePath()}`);
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const initializer = variable.getInitializer();
|
|
199
|
+
|
|
200
|
+
if (!initializer || !ArrayLiteralExpression.isArrayLiteralExpression(initializer)) {
|
|
201
|
+
logger.warning(`Variable "${varName}" is not initialized with an array literal`);
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return initializer;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Parse routes from AST ArrayLiteralExpression to RouteObject[]
|
|
210
|
+
*/
|
|
211
|
+
function parseRoutesFromAST(arrayLiteral: ArrayLiteralExpression): RouteObject[] {
|
|
212
|
+
const routes: RouteObject[] = [];
|
|
213
|
+
|
|
214
|
+
for (const element of arrayLiteral.getElements()) {
|
|
215
|
+
if (Node.isObjectLiteralExpression(element)) {
|
|
216
|
+
const route: RouteObject = {};
|
|
217
|
+
|
|
218
|
+
for (const prop of element.getProperties()) {
|
|
219
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
220
|
+
const name = prop.getName();
|
|
221
|
+
const initializer = prop.getInitializer();
|
|
222
|
+
|
|
223
|
+
if (!initializer) continue;
|
|
224
|
+
|
|
225
|
+
if (name === 'children' && Node.isArrayLiteralExpression(initializer)) {
|
|
226
|
+
// Recursively parse children
|
|
227
|
+
route.children = parseRoutesFromAST(initializer);
|
|
228
|
+
} else {
|
|
229
|
+
// Store the raw text for other properties
|
|
230
|
+
route[name] = initializer.getText();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
routes.push(route);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return routes;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Deep merge two route arrays
|
|
244
|
+
* - Routes are matched by path equality
|
|
245
|
+
* - Feature routes replace target routes with the same path
|
|
246
|
+
* - Children arrays are recursively merged
|
|
247
|
+
* - All properties from feature route are preserved
|
|
248
|
+
* - Routes with path starting with '__delete__' are deletion markers
|
|
249
|
+
*/
|
|
250
|
+
function deepMergeRoutes(targetRoutes: RouteObject[], featureRoutes: RouteObject[]): RouteObject[] {
|
|
251
|
+
const result = [...targetRoutes];
|
|
252
|
+
|
|
253
|
+
for (const featureRoute of featureRoutes) {
|
|
254
|
+
// Check if this is a deletion marker
|
|
255
|
+
const DELETE_PREFIX = '__delete__';
|
|
256
|
+
if (featureRoute.path && typeof featureRoute.path === 'string') {
|
|
257
|
+
// Remove quotes from path string if present
|
|
258
|
+
const pathValue = featureRoute.path.replace(/^['"`]|['"`]$/g, '');
|
|
259
|
+
|
|
260
|
+
if (pathValue.startsWith(DELETE_PREFIX)) {
|
|
261
|
+
// This is a deletion marker - remove the route with matching path
|
|
262
|
+
const targetPath = pathValue.substring(DELETE_PREFIX.length);
|
|
263
|
+
|
|
264
|
+
const deleteIndex = result.findIndex((targetRoute) => {
|
|
265
|
+
if (targetRoute.path && typeof targetRoute.path === 'string') {
|
|
266
|
+
const targetPathValue = targetRoute.path.replace(/^['"`]|['"`]$/g, '');
|
|
267
|
+
return targetPathValue === targetPath;
|
|
268
|
+
}
|
|
269
|
+
return false;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
if (deleteIndex >= 0) {
|
|
273
|
+
result.splice(deleteIndex, 1);
|
|
274
|
+
logger.info(`Deleted route with path: ${targetPath}`);
|
|
275
|
+
} else {
|
|
276
|
+
logger.error(`\nValidation error: Cannot delete route that doesn't exist!\n`);
|
|
277
|
+
logger.info(`Route marked for deletion: ${targetPath}`);
|
|
278
|
+
logger.warning(`The route doesn't exist in the current routes.\n`);
|
|
279
|
+
throw new Error('Route deletion failed - cannot proceed');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Don't add the deletion marker to result
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const matchIndex = result.findIndex((targetRoute) => {
|
|
288
|
+
// Match by path if both have paths
|
|
289
|
+
if (featureRoute.path && targetRoute.path) {
|
|
290
|
+
return featureRoute.path === targetRoute.path;
|
|
291
|
+
}
|
|
292
|
+
// Match index routes
|
|
293
|
+
if (featureRoute.index && targetRoute.index) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
return false;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (matchIndex >= 0) {
|
|
300
|
+
const targetRoute = result[matchIndex];
|
|
301
|
+
|
|
302
|
+
// Merge the route, starting with feature route properties
|
|
303
|
+
const mergedRoute: RouteObject = { ...featureRoute };
|
|
304
|
+
|
|
305
|
+
// If both have children, recursively merge them
|
|
306
|
+
if (targetRoute.children && featureRoute.children) {
|
|
307
|
+
mergedRoute.children = deepMergeRoutes(targetRoute.children, featureRoute.children);
|
|
308
|
+
} else if (targetRoute.children) {
|
|
309
|
+
// Only target has children, preserve them
|
|
310
|
+
mergedRoute.children = targetRoute.children;
|
|
311
|
+
}
|
|
312
|
+
// If only feature has children, they're already in mergedRoute
|
|
313
|
+
|
|
314
|
+
result[matchIndex] = mergedRoute;
|
|
315
|
+
} else {
|
|
316
|
+
// No match found, add the new route
|
|
317
|
+
result.push(featureRoute);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Generate TypeScript code from RouteObject[]
|
|
326
|
+
*/
|
|
327
|
+
function generateRoutesCode(routes: RouteObject[]): string {
|
|
328
|
+
if (routes.length === 0) {
|
|
329
|
+
return '[]';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const routeStrings = routes.map((route) => generateRouteCode(route, 1));
|
|
333
|
+
return `[\n${routeStrings.join(',\n')}\n]`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Generate code for a single route object
|
|
338
|
+
*/
|
|
339
|
+
function generateRouteCode(route: RouteObject, indentLevel: number): string {
|
|
340
|
+
const indent = ' '.repeat(indentLevel);
|
|
341
|
+
const props: string[] = [];
|
|
342
|
+
|
|
343
|
+
for (const [key, value] of Object.entries(route)) {
|
|
344
|
+
if (key === 'children' && Array.isArray(value)) {
|
|
345
|
+
// Recursively generate children
|
|
346
|
+
const childrenCode = value.length > 0
|
|
347
|
+
? `[\n${value.map((child) => generateRouteCode(child, indentLevel + 2)).join(',\n')}\n${indent} ]`
|
|
348
|
+
: '[]';
|
|
349
|
+
props.push(`children: ${childrenCode}`);
|
|
350
|
+
} else if (value !== undefined) {
|
|
351
|
+
// For other properties, use the raw text we stored
|
|
352
|
+
props.push(`${key}: ${value}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return `${indent}{\n${props.map((p) => `${indent} ${p}`).join(',\n')}\n${indent}}`;
|
|
357
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'fs';
|
|
2
|
+
import { getMonorepoRoot } from './paths.js';
|
|
3
|
+
import { join, isAbsolute, basename } from 'path';
|
|
4
|
+
|
|
5
|
+
export class ValidationError extends Error {
|
|
6
|
+
constructor(message: string) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'ValidationError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get the web application directory path from a base app path
|
|
14
|
+
* Structure: <basePath>/digitalExperiences/webApplications/<appName>
|
|
15
|
+
*/
|
|
16
|
+
export function getWebApplicationPath(basePath: string): string {
|
|
17
|
+
const appName = basename(basePath);
|
|
18
|
+
return join(basePath, 'digitalExperiences', 'webApplications', appName);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Validate that a feature path exists and resolve it to an absolute path
|
|
23
|
+
*/
|
|
24
|
+
export function validateAndResolveFeaturePath(featurePath: string): string {
|
|
25
|
+
let resolvedPath: string;
|
|
26
|
+
|
|
27
|
+
// If it's an absolute path, use it as-is
|
|
28
|
+
if (isAbsolute(featurePath)) {
|
|
29
|
+
resolvedPath = featurePath;
|
|
30
|
+
} else {
|
|
31
|
+
// If it's relative, resolve from monorepo root
|
|
32
|
+
resolvedPath = join(getMonorepoRoot(), featurePath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!existsSync(resolvedPath)) {
|
|
36
|
+
throw new ValidationError(
|
|
37
|
+
`Feature path '${featurePath}' does not exist`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!statSync(resolvedPath).isDirectory()) {
|
|
42
|
+
throw new ValidationError(
|
|
43
|
+
`Feature path '${featurePath}' is not a directory`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check if it has a feature.ts file
|
|
48
|
+
const featureFilePath = join(resolvedPath, 'feature.ts');
|
|
49
|
+
if (!existsSync(featureFilePath)) {
|
|
50
|
+
throw new ValidationError(
|
|
51
|
+
`Feature path '${featurePath}' does not contain a feature.ts file`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return resolvedPath;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Validate and resolve an app path (can be relative or absolute)
|
|
60
|
+
* Validates that the web application directory exists with proper structure
|
|
61
|
+
* Returns the absolute path to the base app directory
|
|
62
|
+
*/
|
|
63
|
+
export function validateAndResolveAppPath(appPath: string): string {
|
|
64
|
+
let resolvedBasePath: string;
|
|
65
|
+
|
|
66
|
+
// If it's an absolute path, use it as-is
|
|
67
|
+
if (isAbsolute(appPath)) {
|
|
68
|
+
resolvedBasePath = appPath;
|
|
69
|
+
} else {
|
|
70
|
+
// If it's relative, resolve from monorepo root
|
|
71
|
+
resolvedBasePath = join(getMonorepoRoot(), appPath);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!existsSync(resolvedBasePath)) {
|
|
75
|
+
throw new ValidationError(
|
|
76
|
+
`App path '${appPath}' does not exist`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!statSync(resolvedBasePath).isDirectory()) {
|
|
81
|
+
throw new ValidationError(
|
|
82
|
+
`App path '${appPath}' is not a directory`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Get the web application directory path
|
|
87
|
+
const webAppPath = getWebApplicationPath(resolvedBasePath);
|
|
88
|
+
|
|
89
|
+
if (!existsSync(webAppPath)) {
|
|
90
|
+
throw new ValidationError(
|
|
91
|
+
`Web application directory does not exist at '${webAppPath}'. Expected structure: digitalExperiences/webApplications/<app-name>`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!statSync(webAppPath).isDirectory()) {
|
|
96
|
+
throw new ValidationError(
|
|
97
|
+
`Web application path '${webAppPath}' is not a directory`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check if it has a package.json
|
|
102
|
+
const packageJsonPath = join(webAppPath, 'package.json');
|
|
103
|
+
if (!existsSync(packageJsonPath)) {
|
|
104
|
+
throw new ValidationError(
|
|
105
|
+
`Web application '${webAppPath}' does not contain a package.json file`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return resolvedBasePath;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const APP_FEATURE_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validate that a app or feature name is valid
|
|
116
|
+
* - Must be in kebab-case (lowercase with hyphens)
|
|
117
|
+
* - Only alphanumeric characters and hyphens allowed
|
|
118
|
+
* - Cannot start or end with hyphens
|
|
119
|
+
* - No consecutive hyphens
|
|
120
|
+
* - Cannot be reserved names: "base", "cli"
|
|
121
|
+
* - Max 50 characters
|
|
122
|
+
*/
|
|
123
|
+
export function validateAppOrFeatureName(name: string): void {
|
|
124
|
+
// Check empty
|
|
125
|
+
if (!name || name.trim().length === 0) {
|
|
126
|
+
throw new ValidationError('App or feature name cannot be empty');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check format
|
|
130
|
+
if (!APP_FEATURE_NAME_REGEX.test(name)) {
|
|
131
|
+
throw new ValidationError(
|
|
132
|
+
`App or feature name '${name}' is invalid. Must be kebab-case (lowercase letters, numbers, and hyphens only).\nExamples: "nav-menu", "user-auth", "dashboard-v2"`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check reserved names
|
|
137
|
+
const reserved = ['app', 'feature'];
|
|
138
|
+
if (reserved.includes(name)) {
|
|
139
|
+
throw new ValidationError(
|
|
140
|
+
`App or feature name '${name}' is reserved. Please choose a different name.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Check length
|
|
145
|
+
if (name.length > 50) {
|
|
146
|
+
throw new ValidationError(
|
|
147
|
+
`App or feature name '${name}' is too long. Maximum 50 characters.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|