@effijs/templates 0.0.0-stage → 1.0.0-alpha.0
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/CONTRIBUTING.md +27 -0
- package/LICENSE +22 -0
- package/README.md +32 -2
- package/ai/SETUP.md +5 -0
- package/docs/catalog.md +85 -0
- package/forge.manifest.js +75 -0
- package/lib/compat.js +40 -0
- package/lib/docs/build.js +146 -0
- package/lib/install.js +51 -0
- package/lib/journal.js +40 -0
- package/lib/jsonConfig.js +33 -0
- package/lib/migration.js +35 -0
- package/lib/names.js +42 -0
- package/lib/patch.js +62 -0
- package/lib/paths.js +12 -0
- package/lib/project.js +48 -0
- package/lib/registry.js +99 -0
- package/package.json +46 -4
- package/platforms/react-native/CATALOG.md +391 -0
- package/platforms/react-native/ORIGIN.md +42 -0
- package/platforms/react-native/README.md +78 -0
- package/platforms/react-native/ai/AGENTS.md.hbs +36 -0
- package/platforms/react-native/ai/SETUP.md +89 -0
- package/platforms/react-native/compat/matrix.js +150 -0
- package/platforms/react-native/configs/babel.js +63 -0
- package/platforms/react-native/configs/forgeConfig.js +35 -0
- package/platforms/react-native/configs/jsConfigs.js +96 -0
- package/platforms/react-native/configs/metro.js +86 -0
- package/platforms/react-native/generators/add/generator.js +12 -0
- package/platforms/react-native/generators/add/run.js +64 -0
- package/platforms/react-native/generators/component/generator.js +75 -0
- package/platforms/react-native/generators/component/render.js +69 -0
- package/platforms/react-native/generators/component/templates/Common.tsx.hbs +13 -0
- package/platforms/react-native/generators/component/templates/index.ts.hbs +13 -0
- package/platforms/react-native/generators/component/templates/pm.ts.hbs +7 -0
- package/platforms/react-native/generators/component/templates/types.ts.hbs +3 -0
- package/platforms/react-native/generators/demo/files/api/app.http +8 -0
- package/platforms/react-native/generators/demo/files/api/environment/http-client.env.json +5 -0
- package/platforms/react-native/generators/demo/files/entity/category/category.api.ts +18 -0
- package/platforms/react-native/generators/demo/files/entity/category/category.dto.ts +15 -0
- package/platforms/react-native/generators/demo/files/entity/category/category.service.ts +42 -0
- package/platforms/react-native/generators/demo/files/entity/category/category.store.ts +26 -0
- package/platforms/react-native/generators/demo/files/entity/category/index.ts +2 -0
- package/platforms/react-native/generators/demo/files/entity/product/index.ts +2 -0
- package/platforms/react-native/generators/demo/files/entity/product/product.api.ts +49 -0
- package/platforms/react-native/generators/demo/files/entity/product/product.dto.ts +120 -0
- package/platforms/react-native/generators/demo/files/entity/product/product.service.ts +139 -0
- package/platforms/react-native/generators/demo/files/entity/product/product.store.ts +37 -0
- package/platforms/react-native/generators/demo/files/feature/product/components/Product.CategorySelect.tsx +36 -0
- package/platforms/react-native/generators/demo/files/feature/product/detail/Product.Detail.Screen.tsx +100 -0
- package/platforms/react-native/generators/demo/files/feature/product/detail/product.detail.service.ts +33 -0
- package/platforms/react-native/generators/demo/files/feature/product/filter/Product.Filter.Screen.tsx +59 -0
- package/platforms/react-native/generators/demo/files/feature/product/filter/product.filter.service.ts +78 -0
- package/platforms/react-native/generators/demo/files/feature/product/form/Product.Form.Screen.tsx +71 -0
- package/platforms/react-native/generators/demo/files/feature/product/form/product.form.service.ts +142 -0
- package/platforms/react-native/generators/demo/files/feature/product/index.ts +7 -0
- package/platforms/react-native/generators/demo/files/feature/product/list/Product.List.Item.tsx +34 -0
- package/platforms/react-native/generators/demo/files/feature/product/list/Product.List.Screen.tsx +106 -0
- package/platforms/react-native/generators/demo/files/feature/product/list/product.list.service.ts +47 -0
- package/platforms/react-native/generators/demo/files/feature/product/product.feature.ts +29 -0
- package/platforms/react-native/generators/demo/files/feature/product/product.hooks.ts +7 -0
- package/platforms/react-native/generators/demo/files/feature/product/search/Product.Search.Screen.tsx +82 -0
- package/platforms/react-native/generators/demo/files/feature/product/search/product.search.service.ts +97 -0
- package/platforms/react-native/generators/demo/files/navigation/navigation.product.ts +46 -0
- package/platforms/react-native/generators/demo/generator.js +93 -0
- package/platforms/react-native/generators/entity/generator.js +68 -0
- package/platforms/react-native/generators/feature/generator.js +224 -0
- package/platforms/react-native/generators/feature/render.js +163 -0
- package/platforms/react-native/generators/feature/templates/detail.screen.tsx.hbs +25 -0
- package/platforms/react-native/generators/feature/templates/detail.service.ts.hbs +14 -0
- package/platforms/react-native/generators/feature/templates/feature.ts.hbs +18 -0
- package/platforms/react-native/generators/feature/templates/filter.screen.tsx.hbs +17 -0
- package/platforms/react-native/generators/feature/templates/filter.service.ts.hbs +14 -0
- package/platforms/react-native/generators/feature/templates/form.screen.tsx.hbs +21 -0
- package/platforms/react-native/generators/feature/templates/form.service.ts.hbs +37 -0
- package/platforms/react-native/generators/feature/templates/hooks.ts.hbs +7 -0
- package/platforms/react-native/generators/feature/templates/index.ts.hbs +2 -0
- package/platforms/react-native/generators/feature/templates/list.item.tsx.hbs +16 -0
- package/platforms/react-native/generators/feature/templates/list.screen.tsx.hbs +34 -0
- package/platforms/react-native/generators/feature/templates/list.service.ts.hbs +15 -0
- package/platforms/react-native/generators/feature/templates/navigation.ts.hbs +12 -0
- package/platforms/react-native/generators/feature/templates/search.screen.tsx.hbs +24 -0
- package/platforms/react-native/generators/feature/templates/search.service.ts.hbs +13 -0
- package/platforms/react-native/generators/feature/templates/tab.tsx.hbs +8 -0
- package/platforms/react-native/generators/init/files/app/app.controller.ts +41 -0
- package/platforms/react-native/generators/init/files/app/app.error.ts +1 -0
- package/platforms/react-native/generators/init/files/app/app.store.ts +12 -0
- package/platforms/react-native/generators/init/files/app/index.ts +19 -0
- package/platforms/react-native/generators/init/files/app/splash/Onboarding.Screen.tsx +31 -0
- package/platforms/react-native/generators/init/files/app/splash/Splash.Screen.tsx +14 -0
- package/platforms/react-native/generators/init/files/app/tabs/home/Home.tab.tsx +24 -0
- package/platforms/react-native/generators/init/files/app/tabs/profile/Profile.tab.tsx +1 -0
- package/platforms/react-native/generators/init/files/configs/dev.ts.hbs +5 -0
- package/platforms/react-native/generators/init/files/configs/index.ts +4 -0
- package/platforms/react-native/generators/init/files/configs/prod.ts.hbs +5 -0
- package/platforms/react-native/generators/init/files/entity/auth/auth.api.ts +36 -0
- package/platforms/react-native/generators/init/files/entity/auth/auth.dto.ts +26 -0
- package/platforms/react-native/generators/init/files/entity/auth/auth.service.ts +94 -0
- package/platforms/react-native/generators/init/files/entity/auth/auth.session.store.ts +14 -0
- package/platforms/react-native/generators/init/files/entity/auth/auth.store.ts +20 -0
- package/platforms/react-native/generators/init/files/entity/auth/index.ts +2 -0
- package/platforms/react-native/generators/init/files/entity/index.ts +2 -0
- package/platforms/react-native/generators/init/files/feature/auth/auth.feature.ts +10 -0
- package/platforms/react-native/generators/init/files/feature/auth/auth.hooks.ts +7 -0
- package/platforms/react-native/generators/init/files/feature/auth/index.ts +1 -0
- package/platforms/react-native/generators/init/files/feature/auth/sign-in/SignIn.Screen.tsx +39 -0
- package/platforms/react-native/generators/init/files/feature/auth/sign-in/signIn.service.ts +54 -0
- package/platforms/react-native/generators/init/files/feature/auth/sign-up/SignUp.Screen.tsx +64 -0
- package/platforms/react-native/generators/init/files/feature/auth/sign-up/signUp.service.ts +73 -0
- package/platforms/react-native/generators/init/files/feature/feature.hooks.ts +15 -0
- package/platforms/react-native/generators/init/files/feature/index.ts +3 -0
- package/platforms/react-native/generators/init/files/feature/profile/Profile.Screen.tsx +52 -0
- package/platforms/react-native/generators/init/files/feature/profile/index.ts +1 -0
- package/platforms/react-native/generators/init/files/feature/profile/profile.feature.ts +18 -0
- package/platforms/react-native/generators/init/files/feature/profile/profile.hooks.ts +7 -0
- package/platforms/react-native/generators/init/files/index.ts +16 -0
- package/platforms/react-native/generators/init/files/navigation/index.ts +18 -0
- package/platforms/react-native/generators/init/files/navigation/navigation.app.ts +58 -0
- package/platforms/react-native/generators/init/files/navigation/navigation.features.ts +9 -0
- package/platforms/react-native/generators/init/files/navigation/navigation.hooks.ts +5 -0
- package/platforms/react-native/generators/init/files/navigation/navigation.tabs.ts +55 -0
- package/platforms/react-native/generators/init/files/navigation/navigation.widgets.ts +23 -0
- package/platforms/react-native/generators/init/files/services/http/http.base.ts +69 -0
- package/platforms/react-native/generators/init/files/services/http/http.error.ts +10 -0
- package/platforms/react-native/generators/init/files/services/http/http.service.ts +24 -0
- package/platforms/react-native/generators/init/files/services/http/middleware/index.ts +12 -0
- package/platforms/react-native/generators/init/files/services/http/middleware/middleware.error.ts +36 -0
- package/platforms/react-native/generators/init/files/services/http/middleware/middleware.registry.ts +3 -0
- package/platforms/react-native/generators/init/files/services/http/middleware/middleware.token.ts +97 -0
- package/platforms/react-native/generators/init/files/services/index.ts +15 -0
- package/platforms/react-native/generators/init/files/ui/components/Box/Common.tsx +19 -0
- package/platforms/react-native/generators/init/files/ui/components/Box/box.pm.ts +111 -0
- package/platforms/react-native/generators/init/files/ui/components/Box/box.types.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/components/Box/index.ts +13 -0
- package/platforms/react-native/generators/init/files/ui/components/Button/Common.tsx +50 -0
- package/platforms/react-native/generators/init/files/ui/components/Button/Touchable.tsx +19 -0
- package/platforms/react-native/generators/init/files/ui/components/Button/button.pm.ts +197 -0
- package/platforms/react-native/generators/init/files/ui/components/Button/button.types.ts +22 -0
- package/platforms/react-native/generators/init/files/ui/components/Button/button.utils.ts +16 -0
- package/platforms/react-native/generators/init/files/ui/components/Button/index.ts +19 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/Colours.tsx +50 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/Common.tsx +38 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/ErrorText.tsx +11 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/Input.tsx +115 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/InputArea.tsx +70 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/Label.tsx +18 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/Select.tsx +86 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/components/SecureTextEntry.tsx +19 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/form.error.ts +18 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/form.pm.ts +134 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/form.types.ts +59 -0
- package/platforms/react-native/generators/init/files/ui/components/Form/index.ts +67 -0
- package/platforms/react-native/generators/init/files/ui/components/Grid/Common.tsx +11 -0
- package/platforms/react-native/generators/init/files/ui/components/Grid/grid.pm.ts +93 -0
- package/platforms/react-native/generators/init/files/ui/components/Grid/grid.types.ts +79 -0
- package/platforms/react-native/generators/init/files/ui/components/Grid/index.ts +13 -0
- package/platforms/react-native/generators/init/files/ui/components/Icon/Common.tsx +19 -0
- package/platforms/react-native/generators/init/files/ui/components/Icon/icons.pm.ts +74 -0
- package/platforms/react-native/generators/init/files/ui/components/Icon/icons.types.ts +19 -0
- package/platforms/react-native/generators/init/files/ui/components/Icon/index.ts +3 -0
- package/platforms/react-native/generators/init/files/ui/components/Loading/Loading.tsx +10 -0
- package/platforms/react-native/generators/init/files/ui/components/Loading/loading.hook.ts +5 -0
- package/platforms/react-native/generators/init/files/ui/components/Loading/loading.service.ts +22 -0
- package/platforms/react-native/generators/init/files/ui/components/Loading/loading.store.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/components/Screen/Common.tsx +87 -0
- package/platforms/react-native/generators/init/files/ui/components/Screen/Content.tsx +77 -0
- package/platforms/react-native/generators/init/files/ui/components/Screen/Header.tsx +80 -0
- package/platforms/react-native/generators/init/files/ui/components/Screen/HeaderTab.tsx +17 -0
- package/platforms/react-native/generators/init/files/ui/components/Screen/SafeAreaHOC.tsx +9 -0
- package/platforms/react-native/generators/init/files/ui/components/Screen/index.ts +22 -0
- package/platforms/react-native/generators/init/files/ui/components/Text/Common.tsx +20 -0
- package/platforms/react-native/generators/init/files/ui/components/Text/index.ts +13 -0
- package/platforms/react-native/generators/init/files/ui/components/Text/text.pm.ts +55 -0
- package/platforms/react-native/generators/init/files/ui/components/Text/text.types.ts +27 -0
- package/platforms/react-native/generators/init/files/ui/components/TextInput/Common.tsx +19 -0
- package/platforms/react-native/generators/init/files/ui/components/TextInput/index.ts +15 -0
- package/platforms/react-native/generators/init/files/ui/components/TextInput/textInput.pm.ts +65 -0
- package/platforms/react-native/generators/init/files/ui/components/TextInput/textInput.types.ts +16 -0
- package/platforms/react-native/generators/init/files/ui/components/ThemePicker/ThemePicker.tsx +92 -0
- package/platforms/react-native/generators/init/files/ui/components/ThemePicker/index.ts +1 -0
- package/platforms/react-native/generators/init/files/ui/components/index.ts +27 -0
- package/platforms/react-native/generators/init/files/ui/components/utils/color.ts +19 -0
- package/platforms/react-native/generators/init/files/ui/components/utils/index.ts +3 -0
- package/platforms/react-native/generators/init/files/ui/components/utils/useLoading.hook.spec.tsx +202 -0
- package/platforms/react-native/generators/init/files/ui/components/utils/useLoading.hook.ts +172 -0
- package/platforms/react-native/generators/init/files/ui/components/utils/useStore.ts +34 -0
- package/platforms/react-native/generators/init/files/ui/fonts/font-icons.ttf +0 -0
- package/platforms/react-native/generators/init/files/ui/icons/font-icons.json +53 -0
- package/platforms/react-native/generators/init/files/ui/icons/logo.png +0 -0
- package/platforms/react-native/generators/init/files/ui/icons/logo.svg +304 -0
- package/platforms/react-native/generators/init/files/ui/icons/tabs/icon-1.png +0 -0
- package/platforms/react-native/generators/init/files/ui/icons/tabs/icon-2.png +0 -0
- package/platforms/react-native/generators/init/files/ui/theme/black/black.color.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/theme/black/index.ts +10 -0
- package/platforms/react-native/generators/init/files/ui/theme/blue/blue.color.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/theme/blue/index.ts +10 -0
- package/platforms/react-native/generators/init/files/ui/theme/green/green.color.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/theme/green/index.ts +10 -0
- package/platforms/react-native/generators/init/files/ui/theme/index.ts +11 -0
- package/platforms/react-native/generators/init/files/ui/theme/pink/index.ts +10 -0
- package/platforms/react-native/generators/init/files/ui/theme/pink/pink.color.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/theme/scheme/index.ts +23 -0
- package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.color.ts +139 -0
- package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.radius.ts +21 -0
- package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.spacing.ts +24 -0
- package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.ts +25 -0
- package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.typography.ts +98 -0
- package/platforms/react-native/generators/init/files/ui/theme/shared/index.ts +4 -0
- package/platforms/react-native/generators/init/files/ui/theme/shared/shared.color.base.ts +79 -0
- package/platforms/react-native/generators/init/files/ui/theme/shared/shared.radius.ts +8 -0
- package/platforms/react-native/generators/init/files/ui/theme/shared/shared.spacing.ts +9 -0
- package/platforms/react-native/generators/init/files/ui/theme/shared/shared.typography.ts +105 -0
- package/platforms/react-native/generators/init/files/ui/theme/theme.hooks.ts +7 -0
- package/platforms/react-native/generators/init/files/ui/theme/theme.meta.ts +10 -0
- package/platforms/react-native/generators/init/files/ui/theme/theme.provider.tsx +19 -0
- package/platforms/react-native/generators/init/files/ui/theme/theme.service.ts +36 -0
- package/platforms/react-native/generators/init/files/ui/theme/theme.ts +27 -0
- package/platforms/react-native/generators/init/files/ui/widgets/index.ts +1 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/Toast.Item.tsx +175 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/Toast.Overlay.tsx +46 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/Toast.Stack.tsx +75 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/index.ts +7 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.hooks.ts +18 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.service.ts +39 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.store.ts +59 -0
- package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.types.ts +18 -0
- package/platforms/react-native/generators/init/files/ui/widgets/widgets.feature.ts +14 -0
- package/platforms/react-native/generators/init/files/utils/date.ts +11 -0
- package/platforms/react-native/generators/init/files/utils/index.ts +12 -0
- package/platforms/react-native/generators/init/files/utils/store.persistent.ts +103 -0
- package/platforms/react-native/generators/init/files/utils/store.registry.ts +14 -0
- package/platforms/react-native/generators/init/files/utils/string.ts +100 -0
- package/platforms/react-native/generators/init/generator.js +86 -0
- package/platforms/react-native/generators/init/kit.js +23 -0
- package/platforms/react-native/generators/init/navigators/expo-router/index.ts +18 -0
- package/platforms/react-native/generators/init/navigators/expo-router/navigation.app.ts +8 -0
- package/platforms/react-native/generators/init/navigators/expo-router/navigation.features.ts +9 -0
- package/platforms/react-native/generators/init/navigators/expo-router/navigation.hooks.ts +5 -0
- package/platforms/react-native/generators/init/navigators/expo-router/navigation.tabs.ts +7 -0
- package/platforms/react-native/generators/init/navigators/expo-router/navigation.widgets.ts +5 -0
- package/platforms/react-native/generators/init/navigators/react-navigation/index.ts +18 -0
- package/platforms/react-native/generators/init/navigators/react-navigation/navigation.app.ts +8 -0
- package/platforms/react-native/generators/init/navigators/react-navigation/navigation.features.ts +9 -0
- package/platforms/react-native/generators/init/navigators/react-navigation/navigation.hooks.ts +5 -0
- package/platforms/react-native/generators/init/navigators/react-navigation/navigation.tabs.ts +7 -0
- package/platforms/react-native/generators/init/navigators/react-navigation/navigation.widgets.ts +5 -0
- package/platforms/react-native/generators/setup/generator.js +225 -0
- package/platforms/react-native/generators/util/generator.js +12 -0
- package/platforms/react-native/platform.js +32 -0
- package/platforms/react-native/runtime.js +57 -0
- package/platforms/react-native/solutions/components/BottomSheet/README.md +29 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/Common.tsx +120 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/Content.tsx +57 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/Context.tsx +22 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/FlatList.tsx +50 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/Header.tsx +57 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/Search.tsx +24 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/bottomSheet.constants.ts +13 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/bottomSheet.types.ts +31 -0
- package/platforms/react-native/solutions/components/BottomSheet/files/index.ts +33 -0
- package/platforms/react-native/solutions/components/BottomSheet/solution.js +38 -0
- package/platforms/react-native/solutions/components/BottomSheetWidgets/README.md +29 -0
- package/platforms/react-native/solutions/components/BottomSheetWidgets/files/SelectPicker.tsx +47 -0
- package/platforms/react-native/solutions/components/BottomSheetWidgets/files/bottomSheet/Content.BottomSheet.tsx +22 -0
- package/platforms/react-native/solutions/components/BottomSheetWidgets/files/bottomSheet/DateTimePicker.BottomSheet.tsx +74 -0
- package/platforms/react-native/solutions/components/BottomSheetWidgets/files/bottomSheet/List.BottomSheet.tsx +62 -0
- package/platforms/react-native/solutions/components/BottomSheetWidgets/solution.js +49 -0
- package/platforms/react-native/solutions/components/Calendar/README.md +29 -0
- package/platforms/react-native/solutions/components/Calendar/files/Common.tsx +16 -0
- package/platforms/react-native/solutions/components/Calendar/files/Context.tsx +466 -0
- package/platforms/react-native/solutions/components/Calendar/files/DayCell.tsx +89 -0
- package/platforms/react-native/solutions/components/Calendar/files/MonthView.tsx +41 -0
- package/platforms/react-native/solutions/components/Calendar/files/MonthYearOverlay.tsx +51 -0
- package/platforms/react-native/solutions/components/Calendar/files/SwipeablePeriod.tsx +44 -0
- package/platforms/react-native/solutions/components/Calendar/files/WeekDayTitles.tsx +31 -0
- package/platforms/react-native/solutions/components/Calendar/files/WeekView.tsx +40 -0
- package/platforms/react-native/solutions/components/Calendar/files/calendar.styles.ts +142 -0
- package/platforms/react-native/solutions/components/Calendar/files/calendar.types.ts +126 -0
- package/platforms/react-native/solutions/components/Calendar/files/calendar.utils.ts +143 -0
- package/platforms/react-native/solutions/components/Calendar/files/index.ts +40 -0
- package/platforms/react-native/solutions/components/Calendar/solution.js +38 -0
- package/platforms/react-native/solutions/components/Chart/README.md +29 -0
- package/platforms/react-native/solutions/components/Chart/files/Cilcular.tsx +140 -0
- package/platforms/react-native/solutions/components/Chart/files/index.ts +3 -0
- package/platforms/react-native/solutions/components/Chart/solution.js +38 -0
- package/platforms/react-native/solutions/components/CheckBox/README.md +29 -0
- package/platforms/react-native/solutions/components/CheckBox/files/Common.tsx +55 -0
- package/platforms/react-native/solutions/components/CheckBox/files/checkbox.pm.ts +71 -0
- package/platforms/react-native/solutions/components/CheckBox/files/index.ts +9 -0
- package/platforms/react-native/solutions/components/CheckBox/form/Checkbox.tsx +22 -0
- package/platforms/react-native/solutions/components/CheckBox/solution.js +57 -0
- package/platforms/react-native/solutions/components/DateTimePicker/README.md +29 -0
- package/platforms/react-native/solutions/components/DateTimePicker/files/DateTimePicker.tsx +44 -0
- package/platforms/react-native/solutions/components/DateTimePicker/solution.js +45 -0
- package/platforms/react-native/solutions/components/Image/README.md +29 -0
- package/platforms/react-native/solutions/components/Image/files/SVG.tsx +74 -0
- package/platforms/react-native/solutions/components/Image/files/image.pm.ts +25 -0
- package/platforms/react-native/solutions/components/Image/files/image.utils.ts +35 -0
- package/platforms/react-native/solutions/components/Image/files/index.ts +5 -0
- package/platforms/react-native/solutions/components/Image/solution.js +40 -0
- package/platforms/react-native/solutions/components/InputSecurity/README.md +29 -0
- package/platforms/react-native/solutions/components/InputSecurity/files/InputSecurity.ts +142 -0
- package/platforms/react-native/solutions/components/InputSecurity/solution.js +28 -0
- package/platforms/react-native/solutions/components/OTP/README.md +29 -0
- package/platforms/react-native/solutions/components/OTP/files/Item.tsx +16 -0
- package/platforms/react-native/solutions/components/OTP/files/Items.tsx +33 -0
- package/platforms/react-native/solutions/components/OTP/files/index.tsx +120 -0
- package/platforms/react-native/solutions/components/OTP/files/otp.pm.ts +30 -0
- package/platforms/react-native/solutions/components/OTP/solution.js +38 -0
- package/platforms/react-native/solutions/components/ProgressIndicator/README.md +29 -0
- package/platforms/react-native/solutions/components/ProgressIndicator/files/Circular.tsx +154 -0
- package/platforms/react-native/solutions/components/ProgressIndicator/files/Linear.tsx +133 -0
- package/platforms/react-native/solutions/components/ProgressIndicator/files/circular.pm.ts +34 -0
- package/platforms/react-native/solutions/components/ProgressIndicator/files/index.ts +16 -0
- package/platforms/react-native/solutions/components/ProgressIndicator/solution.js +39 -0
- package/platforms/react-native/solutions/components/Ruler/README.md +29 -0
- package/platforms/react-native/solutions/components/Ruler/files/Common.tsx +44 -0
- package/platforms/react-native/solutions/components/Ruler/files/Context.tsx +210 -0
- package/platforms/react-native/solutions/components/Ruler/files/Track.tsx +686 -0
- package/platforms/react-native/solutions/components/Ruler/files/Value.tsx +60 -0
- package/platforms/react-native/solutions/components/Ruler/files/index.ts +23 -0
- package/platforms/react-native/solutions/components/Ruler/files/ruler.constants.ts +70 -0
- package/platforms/react-native/solutions/components/Ruler/files/ruler.types.ts +98 -0
- package/platforms/react-native/solutions/components/Ruler/files/ruler.utils.ts +332 -0
- package/platforms/react-native/solutions/components/Ruler/solution.js +38 -0
- package/platforms/react-native/solutions/components/Section/README.md +29 -0
- package/platforms/react-native/solutions/components/Section/files/Common.tsx +144 -0
- package/platforms/react-native/solutions/components/Section/solution.js +37 -0
- package/platforms/react-native/solutions/components/Slider/README.md +29 -0
- package/platforms/react-native/solutions/components/Slider/files/Container.tsx +5 -0
- package/platforms/react-native/solutions/components/Slider/files/Content.tsx +44 -0
- package/platforms/react-native/solutions/components/Slider/files/Context.tsx +30 -0
- package/platforms/react-native/solutions/components/Slider/files/Pagination.Dot.tsx +61 -0
- package/platforms/react-native/solutions/components/Slider/files/index.ts +22 -0
- package/platforms/react-native/solutions/components/Slider/solution.js +38 -0
- package/platforms/react-native/solutions/components/Switch/README.md +29 -0
- package/platforms/react-native/solutions/components/Switch/files/Common.tsx +38 -0
- package/platforms/react-native/solutions/components/Switch/files/index.ts +9 -0
- package/platforms/react-native/solutions/components/Switch/files/switch.pm.ts +53 -0
- package/platforms/react-native/solutions/components/Switch/solution.js +38 -0
- package/platforms/react-native/solutions/install.js +97 -0
- package/platforms/react-native/solutions/services/firebase-core/README.md +31 -0
- package/platforms/react-native/solutions/services/firebase-core/files/index.ts +5 -0
- package/platforms/react-native/solutions/services/firebase-core/solution.js +39 -0
- package/platforms/react-native/solutions/services/firebase-messaging/README.md +31 -0
- package/platforms/react-native/solutions/services/firebase-messaging/files/index.ts +20 -0
- package/platforms/react-native/solutions/services/firebase-messaging/solution.js +42 -0
- package/platforms/react-native/solutions/utils/permissions/README.md +29 -0
- package/platforms/react-native/solutions/utils/permissions/files/permissions.ts +10 -0
- package/platforms/react-native/solutions/utils/permissions/solution.js +32 -0
- package/presets/react-native-fsd/index.js +25 -0
- package/shared/generators/entity/render.js +88 -0
- package/shared/generators/entity/templates/crud/api.ts.hbs +36 -0
- package/shared/generators/entity/templates/crud/dto.ts.hbs +36 -0
- package/shared/generators/entity/templates/crud/service.ts.hbs +73 -0
- package/shared/generators/entity/templates/crud/store.ts.hbs +27 -0
- package/shared/generators/entity/templates/index.ts.hbs +2 -0
- package/shared/generators/entity/templates/simple/api.ts.hbs +16 -0
- package/shared/generators/entity/templates/simple/dto.ts.hbs +5 -0
- package/shared/generators/entity/templates/simple/service.ts.hbs +26 -0
- package/shared/generators/entity/templates/simple/store.ts.hbs +18 -0
- package/shared/solutions/utils/date/README.md +29 -0
- package/shared/solutions/utils/date/files/date.ts +11 -0
- package/shared/solutions/utils/date/solution.js +27 -0
- package/shared/solutions/utils/string/README.md +29 -0
- package/shared/solutions/utils/string/files/string.ts +100 -0
- package/shared/solutions/utils/string/solution.js +27 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Add a component, service, or utility
|
|
4
|
+
|
|
5
|
+
1. Create `platforms/<platform>/solutions/<type>/<Name>/` or `shared/solutions/utils/<name>/` when the code does not import React Native.
|
|
6
|
+
2. Add `solution.js` with `id`, `type` (`component`, `service`, or `util`), `platforms`, `title`, `description`, `status` (`stable`, `experimental`, or `stub`), `since`, `tags`, `requires`, `dependencies` (keys from the platform matrix), `files`, `register` (`file`, `marker`, `code`), and `manual`.
|
|
7
|
+
3. Add `README.md` with purpose, API, example, dependencies, manual steps, and the version that added it.
|
|
8
|
+
4. Put copied files under `files/`. Registration code must target an existing `// forge:<name>` marker.
|
|
9
|
+
5. Run `npm run docs` and `npm test`.
|
|
10
|
+
|
|
11
|
+
`forge g util` is `add` filtered to `type: util`. A utility that is already listed in `.forge/state.json`, or whose first file already exists, is skipped.
|
|
12
|
+
|
|
13
|
+
## Add a generator
|
|
14
|
+
|
|
15
|
+
1. Add `platforms/<platform>/generators/<name>/generator.js` exporting `{ description, prompts, actions }`.
|
|
16
|
+
2. Register it on the preset and in `forge.manifest.js` (prompts and flags).
|
|
17
|
+
3. Put defaults on the prompts. `forge g --yes` applies those defaults.
|
|
18
|
+
4. Custom actions must honor `data.dryRun`.
|
|
19
|
+
5. Insert code with `append`, `pattern`, `before: true`, and `unique: true` at a `// forge:<name>` marker.
|
|
20
|
+
6. Copy static trees with `addMany`. Files that are not `.hbs` are byte copies, so JSX and binaries stay intact. Use `.hbs` only when a value must be substituted.
|
|
21
|
+
|
|
22
|
+
## Add a platform
|
|
23
|
+
|
|
24
|
+
1. Add `platforms/<id>/platform.js` with `id`, navigator or router list, markers, and a compat matrix.
|
|
25
|
+
2. Add `presets/<preset>/index.js` whose `id` is the generator namespace (`rn-fsd` today, `react-fsd` later).
|
|
26
|
+
3. Keep `lib/` free of platform imports. Pass platform data into generators.
|
|
27
|
+
4. Add the platform to `forge.manifest.js` and regenerate the catalog.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020-2026 Yevhenii Kyrychok
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @effijs/templates
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Forge presets for EffiJS. React Native Feature-Sliced Design is ready. A React (web) preset is planned and will use the same platform contract.
|
|
4
|
+
|
|
5
|
+
## Platforms
|
|
6
|
+
|
|
7
|
+
| Platform | Preset | Status |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| React Native | `rn-fsd` | Ready |
|
|
10
|
+
| React | `react-fsd` | Planned |
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @react-native-community/cli init MyApp --version 0.86.3
|
|
16
|
+
cd MyApp
|
|
17
|
+
yarn add -D @effijs/forge @effijs/templates
|
|
18
|
+
npx forge init
|
|
19
|
+
npx forge g setup
|
|
20
|
+
npx forge g init
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`setup` installs dependencies and patches configs. `init` copies the `src` base. Optional next steps: `forge g demo`, `forge g entity`, `forge g feature`, `forge g component`, `forge g add`.
|
|
24
|
+
|
|
25
|
+
`setup` writes `presetMap` as the package path `@effijs/templates/presets/react-native-fsd`. `addMany` byte-copies every file that is not `.hbs`; Handlebars runs only on `.hbs` and the suffix is stripped, so JSX `{{` stays intact. Barrel lines are an `append` with `pattern`, `before: true`, and `unique: true`, which inserts once in front of `// forge:<name>`.
|
|
26
|
+
|
|
27
|
+
## Docs
|
|
28
|
+
|
|
29
|
+
- [React Native guide](platforms/react-native/README.md)
|
|
30
|
+
- [Catalog](docs/catalog.md)
|
|
31
|
+
- [Contributing](CONTRIBUTING.md)
|
|
32
|
+
|
|
33
|
+
`npm run docs` regenerates the catalog from manifests. `npm run docs:check` fails when the catalog is stale or a solution is missing its README.
|
package/ai/SETUP.md
ADDED
package/docs/catalog.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<!-- GENERATED. Не редагувати вручну. Run `npm run docs` in @effijs/templates. -->
|
|
2
|
+
|
|
3
|
+
# Catalog
|
|
4
|
+
|
|
5
|
+
Generated from solution manifests, the init kit, and forge.manifest.js.
|
|
6
|
+
|
|
7
|
+
## react-native
|
|
8
|
+
|
|
9
|
+
Status: ready.
|
|
10
|
+
|
|
11
|
+
### Генератори
|
|
12
|
+
|
|
13
|
+
| Command | Description |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| forge g setup | Install EffiJS dependencies and patch React Native configs. |
|
|
16
|
+
| forge g init | Copy the FSD base: app shell, auth, profile, http, theme, and the base UI kit. |
|
|
17
|
+
| forge g demo | Add product and category on top of init, including BottomSheet and Image. |
|
|
18
|
+
| forge g entity | Add an entity. crud matches product; simple matches category. |
|
|
19
|
+
| forge g feature | Add a feature and the screens you select. filter implies list. search still generates the list item. |
|
|
20
|
+
| forge g component | Add a props-manager component: Common, pm, types, and index. |
|
|
21
|
+
| forge g add | Install a catalog solution and its requirements. |
|
|
22
|
+
| forge g util | Install a utility. Same engine as add, filtered to type util. |
|
|
23
|
+
|
|
24
|
+
### Базовий набір (init)
|
|
25
|
+
|
|
26
|
+
| Name | Type | Path | Description |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| Box | component | ui/components/Box | View with theme color, radius, and shadow props. |
|
|
29
|
+
| Grid | component | ui/components/Grid | Layout primitive with spacing and alignment props. |
|
|
30
|
+
| Text | component | ui/components/Text | Themed text with typography props. |
|
|
31
|
+
| Button | component | ui/components/Button | Pressable button. Loading uses ActivityIndicator. |
|
|
32
|
+
| Screen | component | ui/components/Screen | Screen shell with header, content, and safe area. Built for Wix navigation. |
|
|
33
|
+
| Form | component | ui/components/Form | EffiJS form bindings. DateTimePicker, SelectPicker, and InputSecurity are separate solutions. |
|
|
34
|
+
| TextInput | component | ui/components/TextInput | Themed text input. OTP is a separate solution. |
|
|
35
|
+
| Icon | component | ui/components/Icon | Icon font glyph. |
|
|
36
|
+
| Loading | component | ui/components/Loading | Loading overlay driven by a small store. |
|
|
37
|
+
| ThemePicker | component | ui/components/ThemePicker | Switches the active theme scheme. |
|
|
38
|
+
| toast | widget | ui/widgets/toast | Toast stack shown through navigation.widgets.showToast. |
|
|
39
|
+
| http | service | services/http | HTTP client with token and error middleware. |
|
|
40
|
+
| string | util | utils/string.ts | Text transforms used by form inputs. |
|
|
41
|
+
| date | util | utils/date.ts | Date helpers. |
|
|
42
|
+
| store.persistent | util | utils/store.persistent.ts | MMKV-backed persistent store. |
|
|
43
|
+
| auth | entity | entity/auth | Session, sign-in, and sign-up entity. |
|
|
44
|
+
| auth | feature | feature/auth | Sign-in and sign-up screens. |
|
|
45
|
+
| profile | feature | feature/profile | Profile screen and theme picker. |
|
|
46
|
+
|
|
47
|
+
### Компоненти
|
|
48
|
+
|
|
49
|
+
| Id | Status | Description |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| component:BottomSheet | stable | Gesture-driven sheet with header and content slots. |
|
|
52
|
+
| component:BottomSheetWidgets | stable | List and date-time sheets, plus Form.Element.SelectPicker. |
|
|
53
|
+
| component:Calendar | experimental | Calendar from the previous template kit. Treat the API as experimental until it is wired into a screen. |
|
|
54
|
+
| component:Chart | experimental | Chart from the previous template kit. Treat the API as experimental until it is wired into a screen. |
|
|
55
|
+
| component:CheckBox | stable | Themed checkbox and the matching form element. |
|
|
56
|
+
| component:DateTimePicker | stable | Form date field that opens the bottom-sheet picker. |
|
|
57
|
+
| component:Image | stable | Native and SVG image with theme sizing. SVG rendering uses Skia. |
|
|
58
|
+
| component:InputSecurity | experimental | Sanitize and validate text with the validator package. |
|
|
59
|
+
| component:OTP | stable | One-time code field attached to TextInput. |
|
|
60
|
+
| component:ProgressIndicator | stable | Linear and circular progress drawn with Skia. |
|
|
61
|
+
| component:Ruler | experimental | Ruler from the previous template kit. Treat the API as experimental until it is wired into a screen. |
|
|
62
|
+
| component:Section | stable | Segmented section control. |
|
|
63
|
+
| component:Slider | experimental | Slider from the previous template kit. Treat the API as experimental until it is wired into a screen. |
|
|
64
|
+
| component:Switch | stable | Themed switch. |
|
|
65
|
+
|
|
66
|
+
### Сервіси
|
|
67
|
+
|
|
68
|
+
| Id | Status | Description |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| service:firebase-core | stable | Resolves the default Firebase app. |
|
|
71
|
+
| service:firebase-messaging | stable | Requests notification permission and reads the FCM token. |
|
|
72
|
+
|
|
73
|
+
### Утиліти
|
|
74
|
+
|
|
75
|
+
| Id | Status | Description |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| util:permissions | stable | Asks for notification permission on iOS and Android. |
|
|
78
|
+
| util:date | stable | Pure date helpers. init already copies this file for React Native. |
|
|
79
|
+
| util:string | stable | Pure string transforms. init already copies this file for React Native. |
|
|
80
|
+
|
|
81
|
+
## react
|
|
82
|
+
|
|
83
|
+
Status: planned.
|
|
84
|
+
|
|
85
|
+
Not implemented yet.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
platforms: [
|
|
3
|
+
{ id: 'react-native', status: 'ready', preset: 'rn-fsd', doc: 'platforms/react-native/README.md' },
|
|
4
|
+
{ id: 'react', status: 'planned', preset: 'react-fsd', doc: null },
|
|
5
|
+
],
|
|
6
|
+
presets: {
|
|
7
|
+
'rn-fsd': './presets/react-native-fsd',
|
|
8
|
+
},
|
|
9
|
+
generators: [
|
|
10
|
+
{
|
|
11
|
+
id: 'rn-fsd:setup',
|
|
12
|
+
command: 'forge g setup',
|
|
13
|
+
description: 'Install EffiJS dependencies and patch React Native configs.',
|
|
14
|
+
platforms: ['react-native'],
|
|
15
|
+
prompts: ['packageManager', 'navigator', 'moveStarter'],
|
|
16
|
+
flags: ['--package-manager', '--navigator', '--link-local <path>', '--move-starter', '--yes'],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'rn-fsd:init',
|
|
20
|
+
command: 'forge g init',
|
|
21
|
+
description: 'Copy the FSD base: app shell, auth, profile, http, theme, and the base UI kit.',
|
|
22
|
+
platforms: ['react-native'],
|
|
23
|
+
prompts: ['apiUrl'],
|
|
24
|
+
flags: ['--api-url', '--navigator', '--yes'],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'rn-fsd:demo',
|
|
28
|
+
command: 'forge g demo',
|
|
29
|
+
description: 'Add product and category on top of init, including BottomSheet and Image.',
|
|
30
|
+
platforms: ['react-native'],
|
|
31
|
+
prompts: [],
|
|
32
|
+
flags: ['--yes'],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'rn-fsd:entity',
|
|
36
|
+
command: 'forge g entity',
|
|
37
|
+
description: 'Add an entity. crud matches product; simple matches category.',
|
|
38
|
+
platforms: ['react-native'],
|
|
39
|
+
prompts: ['name', 'variant', 'apiUrl', 'fields'],
|
|
40
|
+
flags: ['--name', '--variant crud|simple', '--api-url', '--fields title:string,price:number'],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'rn-fsd:feature',
|
|
44
|
+
command: 'forge g feature',
|
|
45
|
+
description: 'Add a feature and the screens you select. filter implies list. search still generates the list item.',
|
|
46
|
+
platforms: ['react-native'],
|
|
47
|
+
prompts: ['name', 'entity', 'screens', 'tab'],
|
|
48
|
+
flags: ['--name', '--entity', '--screens all', '--tab'],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'rn-fsd:component',
|
|
52
|
+
command: 'forge g component',
|
|
53
|
+
description: 'Add a props-manager component: Common, pm, types, and index.',
|
|
54
|
+
platforms: ['react-native'],
|
|
55
|
+
prompts: ['name', 'base', 'extend', 'slots', 'location'],
|
|
56
|
+
flags: ['--name', '--base View|Pressable|Text', '--extend Box|Grid|Text|none', '--slots container', '--location ui'],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'rn-fsd:add',
|
|
60
|
+
command: 'forge g add',
|
|
61
|
+
description: 'Install a catalog solution and its requirements.',
|
|
62
|
+
platforms: ['react-native'],
|
|
63
|
+
prompts: ['id'],
|
|
64
|
+
flags: ['--id component:BottomSheet'],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'rn-fsd:util',
|
|
68
|
+
command: 'forge g util',
|
|
69
|
+
description: 'Install a utility. Same engine as add, filtered to type util.',
|
|
70
|
+
platforms: ['react-native'],
|
|
71
|
+
prompts: ['id'],
|
|
72
|
+
flags: ['--id util:permissions'],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
package/lib/compat.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
|
|
3
|
+
export function resolveRange(version, matrix) {
|
|
4
|
+
const coerced = semver.coerce(version);
|
|
5
|
+
if (!coerced) {
|
|
6
|
+
const fallback = matrix[matrix.length - 1];
|
|
7
|
+
return {
|
|
8
|
+
entry: fallback,
|
|
9
|
+
warning: `Could not parse React Native version "${version}". Using the newest matrix range ${fallback.id}.`,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const exact = matrix.find((entry) => semver.satisfies(coerced, entry.range));
|
|
14
|
+
if (exact) return { entry: exact, warning: null };
|
|
15
|
+
|
|
16
|
+
const ranked = matrix
|
|
17
|
+
.map((entry) => {
|
|
18
|
+
const min = semver.minVersion(entry.range);
|
|
19
|
+
return { entry, distance: Math.abs(coerced.compare(min)) };
|
|
20
|
+
})
|
|
21
|
+
.sort((a, b) => a.distance - b.distance || semver.compare(semver.minVersion(b.entry.range), semver.minVersion(a.entry.range)));
|
|
22
|
+
|
|
23
|
+
const nearest = ranked[0]?.entry ?? matrix[matrix.length - 1];
|
|
24
|
+
return {
|
|
25
|
+
entry: nearest,
|
|
26
|
+
warning: `React Native ${coerced.version} is outside the compatibility matrix. Using the nearest range ${nearest.id} (${nearest.range}).`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function depsByKeys(entry, keys = []) {
|
|
31
|
+
const dependencies = {};
|
|
32
|
+
const devDependencies = {};
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
const block = entry.optional?.[key];
|
|
35
|
+
if (!block) continue;
|
|
36
|
+
Object.assign(block.dev ? devDependencies : dependencies, block.dependencies ?? {});
|
|
37
|
+
Object.assign(devDependencies, block.devDependencies ?? {});
|
|
38
|
+
}
|
|
39
|
+
return { dependencies, devDependencies };
|
|
40
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
+
|
|
5
|
+
import { packageRoot } from '../paths.js';
|
|
6
|
+
import { loadSolutions, solutionReadmePath } from '../registry.js';
|
|
7
|
+
import { matrix } from '../../platforms/react-native/compat/matrix.js';
|
|
8
|
+
|
|
9
|
+
const HEADER = '<!-- GENERATED. Не редагувати вручну. Run `npm run docs` in @effijs/templates. -->\n';
|
|
10
|
+
|
|
11
|
+
export async function buildCatalogs() {
|
|
12
|
+
const root = packageRoot();
|
|
13
|
+
const manifest = (await import(pathToFileURL(path.join(root, 'forge.manifest.js')).href)).default;
|
|
14
|
+
const solutions = await loadSolutions(root);
|
|
15
|
+
for (const solution of solutions) {
|
|
16
|
+
if (!fs.existsSync(solutionReadmePath(solution))) {
|
|
17
|
+
throw new Error(`${solution.id} is missing README.md`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const kit = (await import(pathToFileURL(path.join(root, 'platforms/react-native/generators/init/kit.js')).href)).default;
|
|
21
|
+
const byPlatform = new Map();
|
|
22
|
+
for (const platform of manifest.platforms) {
|
|
23
|
+
byPlatform.set(platform.id, {
|
|
24
|
+
platform,
|
|
25
|
+
solutions: solutions.filter((solution) => solution.platforms.includes(platform.id)),
|
|
26
|
+
generators: manifest.generators.filter((generator) => generator.platforms.includes(platform.id)),
|
|
27
|
+
kit: kit.platform === platform.id ? kit.items : [],
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const catalog = [HEADER, '# Catalog', '', 'Generated from solution manifests, the init kit, and forge.manifest.js.', ''];
|
|
32
|
+
for (const platform of manifest.platforms) {
|
|
33
|
+
catalog.push(`## ${platform.id}`, '', `Status: ${platform.status}.`, '');
|
|
34
|
+
if (platform.status !== 'ready') {
|
|
35
|
+
catalog.push('Not implemented yet.', '');
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const bucket = byPlatform.get(platform.id);
|
|
39
|
+
catalog.push('### Генератори', '', table(bucket.generators.map((item) => [item.command, item.description])));
|
|
40
|
+
catalog.push('### Базовий набір (init)', '', table(bucket.kit.map((item) => [item.name, item.type, item.path, item.description])));
|
|
41
|
+
catalog.push('### Компоненти', '', table(ofType(bucket.solutions, 'component').map(solutionRow)));
|
|
42
|
+
catalog.push('### Сервіси', '', table(ofType(bucket.solutions, 'service').map(solutionRow)));
|
|
43
|
+
catalog.push('### Утиліти', '', table(ofType(bucket.solutions, 'util').map(solutionRow)));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const files = {
|
|
47
|
+
[path.join(root, 'docs/catalog.md')]: catalog.join('\n'),
|
|
48
|
+
};
|
|
49
|
+
for (const [id, bucket] of byPlatform) {
|
|
50
|
+
if (bucket.platform.status !== 'ready') continue;
|
|
51
|
+
files[path.join(root, 'platforms', id, 'CATALOG.md')] = renderPlatform(bucket, path.join(root, 'platforms', id));
|
|
52
|
+
}
|
|
53
|
+
return files;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function renderPlatform(bucket, dir) {
|
|
57
|
+
const lines = [HEADER, `# ${bucket.platform.id} catalog`, ''];
|
|
58
|
+
lines.push('## Генератори', '');
|
|
59
|
+
for (const generator of bucket.generators) {
|
|
60
|
+
lines.push(`### ${generator.id}`, '', generator.description, '', `Command: \`${generator.command}\``, '', `Prompts: ${generator.prompts.join(', ') || 'none'}`, '', `Flags: ${generator.flags.join(', ')}`, '');
|
|
61
|
+
}
|
|
62
|
+
lines.push('## Базовий набір (init)', '');
|
|
63
|
+
for (const item of bucket.kit) {
|
|
64
|
+
lines.push(`### ${item.name}`, '', `- Type: ${item.type}`, `- Path: \`${item.path}\``, `- ${item.description}`, '');
|
|
65
|
+
}
|
|
66
|
+
for (const type of ['component', 'service', 'util']) {
|
|
67
|
+
lines.push(`## ${label(type)}`, '');
|
|
68
|
+
for (const solution of ofType(bucket.solutions, type)) {
|
|
69
|
+
lines.push(renderSolution(solution, dir));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return lines.join('\n');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function renderSolution(solution, dir) {
|
|
76
|
+
const deps = npmDeps(solution);
|
|
77
|
+
const command = `forge g ${solution.type === 'util' ? 'util' : 'add'} --id ${solution.id}`;
|
|
78
|
+
const readme = path.relative(dir, solutionReadmePath(solution));
|
|
79
|
+
return [
|
|
80
|
+
`### ${solution.id}`,
|
|
81
|
+
'',
|
|
82
|
+
`- Status: ${solution.status}`,
|
|
83
|
+
`- ${solution.description}`,
|
|
84
|
+
`- Requires: ${solution.requires.length ? solution.requires.join(', ') : 'none'}`,
|
|
85
|
+
`- npm: ${deps.length ? deps.join(', ') : 'none'}`,
|
|
86
|
+
`- Command: \`${command}\``,
|
|
87
|
+
`- Manual: ${solution.manual.length ? solution.manual.join(' ') : 'none'}`,
|
|
88
|
+
`- Guide: [${readme}](${readme})`,
|
|
89
|
+
'',
|
|
90
|
+
].join('\n');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function npmDeps(solution) {
|
|
94
|
+
const names = new Set();
|
|
95
|
+
for (const entry of matrix) {
|
|
96
|
+
for (const key of solution.dependencies ?? []) {
|
|
97
|
+
const block = entry.optional?.[key];
|
|
98
|
+
for (const name of Object.keys(block?.dependencies ?? {})) names.add(name);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return [...names];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function ofType(solutions, type) {
|
|
105
|
+
return solutions.filter((solution) => solution.type === type);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function solutionRow(solution) {
|
|
109
|
+
return [solution.id, solution.status, solution.description];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function label(type) {
|
|
113
|
+
if (type === 'component') return 'Компоненти';
|
|
114
|
+
if (type === 'service') return 'Сервіси';
|
|
115
|
+
return 'Утиліти';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function table(rows) {
|
|
119
|
+
if (!rows.length) return 'None yet.\n';
|
|
120
|
+
const width = rows[0].length;
|
|
121
|
+
const head = width === 4 ? ['Name', 'Type', 'Path', 'Description'] : width === 3 ? ['Id', 'Status', 'Description'] : ['Command', 'Description'];
|
|
122
|
+
const line = (cells) => `| ${cells.join(' | ')} |`;
|
|
123
|
+
return [line(head), line(head.map(() => '---')), ...rows.map((row) => line(row)), ''].join('\n');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function main() {
|
|
127
|
+
const files = await buildCatalogs();
|
|
128
|
+
const check = process.argv.includes('--check');
|
|
129
|
+
let dirty = false;
|
|
130
|
+
for (const [file, content] of Object.entries(files)) {
|
|
131
|
+
const current = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
132
|
+
if (current !== content) {
|
|
133
|
+
dirty = true;
|
|
134
|
+
if (check) console.error(`Out of date: ${path.relative(packageRoot(), file)}`);
|
|
135
|
+
else {
|
|
136
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
137
|
+
fs.writeFileSync(file, content);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (check && dirty) process.exit(1);
|
|
142
|
+
if (!check) console.log('Wrote catalog docs');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const invoked = process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
|
|
146
|
+
if (invoked) main();
|
package/lib/install.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
export function formatPackageSpec(name, version) {
|
|
6
|
+
return version ? `${name}@${version}` : name;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function installCommand(packageManager, dependencies = {}, devDependencies = {}) {
|
|
10
|
+
const deps = Object.entries(dependencies).map(([name, version]) => formatPackageSpec(name, version));
|
|
11
|
+
const dev = Object.entries(devDependencies).map(([name, version]) => formatPackageSpec(name, version));
|
|
12
|
+
const commands = [];
|
|
13
|
+
if (deps.length) {
|
|
14
|
+
if (packageManager === 'yarn') commands.push(`yarn add ${deps.join(' ')}`);
|
|
15
|
+
else if (packageManager === 'pnpm') commands.push(`pnpm add ${deps.join(' ')}`);
|
|
16
|
+
else commands.push(`npm install ${deps.join(' ')}`);
|
|
17
|
+
}
|
|
18
|
+
if (dev.length) {
|
|
19
|
+
if (packageManager === 'yarn') commands.push(`yarn add -D ${dev.join(' ')}`);
|
|
20
|
+
else if (packageManager === 'pnpm') commands.push(`pnpm add -D ${dev.join(' ')}`);
|
|
21
|
+
else commands.push(`npm install -D ${dev.join(' ')}`);
|
|
22
|
+
}
|
|
23
|
+
return commands.join(' && ');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function mergePackageJson(root, { dependencies = {}, devDependencies = {} }) {
|
|
27
|
+
const file = path.join(root, 'package.json');
|
|
28
|
+
const pkg = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
29
|
+
pkg.dependencies = { ...(pkg.dependencies ?? {}), ...dependencies };
|
|
30
|
+
pkg.devDependencies = { ...(pkg.devDependencies ?? {}), ...devDependencies };
|
|
31
|
+
fs.writeFileSync(file, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
32
|
+
return file;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function installPackages({ root, packageManager, dependencies = {}, devDependencies = {}, dryRun = false }) {
|
|
36
|
+
const command = installCommand(packageManager, dependencies, devDependencies);
|
|
37
|
+
if (!command) return { success: true, skipped: true };
|
|
38
|
+
if (dryRun) {
|
|
39
|
+
console.log(`[dry-run] Would run: ${command}`);
|
|
40
|
+
return { success: true, dryRun: true, command };
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
execSync(command, { cwd: root, stdio: 'inherit' });
|
|
44
|
+
return { success: true, command };
|
|
45
|
+
} catch (error) {
|
|
46
|
+
mergePackageJson(root, { dependencies, devDependencies });
|
|
47
|
+
console.warn(`Dependency install failed (${error.message}). Versions were merged into package.json.`);
|
|
48
|
+
console.warn(`Run manually: ${command}`);
|
|
49
|
+
return { success: true, merged: true, command, error: error.message };
|
|
50
|
+
}
|
|
51
|
+
}
|
package/lib/journal.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { stamp } from './patch.js';
|
|
5
|
+
|
|
6
|
+
export async function readState(root) {
|
|
7
|
+
const file = path.join(root, '.forge/state.json');
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(await fs.promises.readFile(file, 'utf8'));
|
|
10
|
+
} catch {
|
|
11
|
+
return { installed: [] };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function writeState(root, state, { dryRun = false } = {}) {
|
|
16
|
+
if (dryRun) return;
|
|
17
|
+
const file = path.join(root, '.forge/state.json');
|
|
18
|
+
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
19
|
+
await fs.promises.writeFile(file, `${JSON.stringify(state, null, 2)}\n`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function markInstalled(root, id, { dryRun = false } = {}) {
|
|
23
|
+
const state = await readState(root);
|
|
24
|
+
const installed = new Set(state.installed ?? []);
|
|
25
|
+
installed.add(id);
|
|
26
|
+
state.installed = [...installed];
|
|
27
|
+
await writeState(root, state, { dryRun });
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function writeSummary(root, { generator, name, lines, dryRun = false }) {
|
|
32
|
+
const text = [`# ${generator}${name ? `: ${name}` : ''}`, '', ...lines.map((line) => `- ${line}`), ''].join('\n');
|
|
33
|
+
console.log(`\n${text}`);
|
|
34
|
+
if (dryRun) return null;
|
|
35
|
+
const dir = path.join(root, '.forge/summary');
|
|
36
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
37
|
+
const file = path.join(dir, `${stamp()}-${generator}${name ? `-${name}` : ''}.md`);
|
|
38
|
+
await fs.promises.writeFile(file, text);
|
|
39
|
+
return file;
|
|
40
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { applyEdits, modify } from 'jsonc-parser';
|
|
2
|
+
|
|
3
|
+
const formattingOptions = { insertSpaces: true, tabSize: 2 };
|
|
4
|
+
|
|
5
|
+
export function setJsonPath(text, jsonPath, value) {
|
|
6
|
+
const edits = modify(text, jsonPath, value, { formattingOptions });
|
|
7
|
+
return applyEdits(text, edits);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function patchTsconfig(text, { paths, types, exclude }) {
|
|
11
|
+
let next = text;
|
|
12
|
+
next = setJsonPath(next, ['compilerOptions', 'experimentalDecorators'], true);
|
|
13
|
+
next = setJsonPath(next, ['compilerOptions', 'emitDecoratorMetadata'], true);
|
|
14
|
+
if (types) next = setJsonPath(next, ['compilerOptions', 'types'], types);
|
|
15
|
+
if (paths) next = setJsonPath(next, ['compilerOptions', 'paths'], paths);
|
|
16
|
+
if (exclude) next = setJsonPath(next, ['exclude'], exclude);
|
|
17
|
+
if (!next.endsWith('\n')) next += '\n';
|
|
18
|
+
return next;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const TSCONFIG_PATHS = {
|
|
22
|
+
'@*': ['./src/*'],
|
|
23
|
+
'@components': ['./src/ui/components'],
|
|
24
|
+
'@components/*': ['./src/ui/components/*'],
|
|
25
|
+
'@icons': ['./src/ui/icons'],
|
|
26
|
+
'@icons/*': ['./src/ui/icons/*'],
|
|
27
|
+
'@images': ['./src/ui/images'],
|
|
28
|
+
'@images/*': ['./src/ui/images/*'],
|
|
29
|
+
'@widgets': ['./src/ui/widgets'],
|
|
30
|
+
'@widgets/*': ['./src/ui/widgets/*'],
|
|
31
|
+
'@theme': ['./src/ui/theme'],
|
|
32
|
+
'@theme/*': ['./src/ui/theme/*'],
|
|
33
|
+
};
|
package/lib/migration.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { stamp } from './patch.js';
|
|
5
|
+
|
|
6
|
+
export function migrationFileName(target) {
|
|
7
|
+
const base = path.basename(target).replace(/[^\w.]+/g, '-');
|
|
8
|
+
return `${stamp()}-${base}.md`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function writeMigration(root, { title, target, reason, required, prompt }) {
|
|
12
|
+
const dir = path.join(root, '.forge/migrations');
|
|
13
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
14
|
+
const file = path.join(dir, migrationFileName(target));
|
|
15
|
+
const body = `# ${title}
|
|
16
|
+
|
|
17
|
+
Target: \`${target}\`
|
|
18
|
+
|
|
19
|
+
${reason}
|
|
20
|
+
|
|
21
|
+
## Required change
|
|
22
|
+
|
|
23
|
+
${required}
|
|
24
|
+
|
|
25
|
+
## AI prompt
|
|
26
|
+
|
|
27
|
+
${prompt}
|
|
28
|
+
`;
|
|
29
|
+
await fs.promises.writeFile(file, body);
|
|
30
|
+
return file;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function aiPrompt(relativeMigration) {
|
|
34
|
+
return `Apply \`${relativeMigration}\` following \`node_modules/@effijs/templates/platforms/react-native/ai/SETUP.md\`.`;
|
|
35
|
+
}
|
package/lib/names.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function kebabCase(value) {
|
|
2
|
+
return String(value ?? '')
|
|
3
|
+
.trim()
|
|
4
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
5
|
+
.replace(/[\s_]+/g, '-')
|
|
6
|
+
.replace(/[^a-zA-Z0-9-]/g, '')
|
|
7
|
+
.replace(/-+/g, '-')
|
|
8
|
+
.replace(/^-|-$/g, '')
|
|
9
|
+
.toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function pascalCase(value) {
|
|
13
|
+
return kebabCase(value)
|
|
14
|
+
.split('-')
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
17
|
+
.join('');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function camelCase(value) {
|
|
21
|
+
const pascal = pascalCase(value);
|
|
22
|
+
return pascal ? pascal.charAt(0).toLowerCase() + pascal.slice(1) : '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function pluralize(value) {
|
|
26
|
+
const kebab = kebabCase(value);
|
|
27
|
+
if (!kebab) return kebab;
|
|
28
|
+
if (kebab.endsWith('s')) return kebab;
|
|
29
|
+
if (kebab.endsWith('y') && !/[aeiou]y$/.test(kebab)) return `${kebab.slice(0, -1)}ies`;
|
|
30
|
+
return `${kebab}s`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function namesOf(value) {
|
|
34
|
+
const kebab = kebabCase(value);
|
|
35
|
+
return {
|
|
36
|
+
raw: String(value ?? '').trim(),
|
|
37
|
+
kebab,
|
|
38
|
+
pascal: pascalCase(kebab),
|
|
39
|
+
camel: camelCase(kebab),
|
|
40
|
+
plural: pluralize(kebab),
|
|
41
|
+
};
|
|
42
|
+
}
|