├── example ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── .gitignore ├── macos │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner │ │ ├── Configs │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ ├── Warnings.xcconfig │ │ │ └── AppInfo.xcconfig │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_512.png │ │ │ │ ├── app_icon_64.png │ │ │ │ ├── app_icon_1024.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Release.entitlements │ │ ├── DebugProfile.entitlements │ │ ├── MainFlutterWindow.swift │ │ └── Info.plist │ ├── .gitignore │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ └── index.html ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── lib │ ├── app │ │ ├── modules │ │ │ ├── profile │ │ │ │ ├── profile_store.dart │ │ │ │ ├── profile_module.dart │ │ │ │ └── profile_page.dart │ │ │ ├── insurence │ │ │ │ ├── insurence_store.dart │ │ │ │ └── insurence_page.dart │ │ │ ├── home │ │ │ │ ├── home_module.dart │ │ │ │ ├── home_store.dart │ │ │ │ └── home_page.dart │ │ │ └── insurence_module.dart │ │ ├── app_module.dart │ │ └── app_widget.dart │ └── main.dart ├── test │ └── app │ │ └── modules │ │ ├── profile │ │ ├── profile_module_test.dart │ │ └── profile_store_test.dart │ │ ├── insurence_module_test.dart │ │ └── insurence │ │ └── insurence_store_test.dart ├── .metadata ├── README.md ├── slidy_pipeline.yaml ├── .gitignore └── pubspec.yaml ├── .vscode ├── settings.json └── launch.json ├── lib ├── src │ ├── version.dart │ ├── core │ │ ├── entities │ │ │ └── slidy_process.dart │ │ ├── interfaces │ │ │ ├── usecase.dart │ │ │ └── yaml_service.dart │ │ ├── errors │ │ │ └── errors.dart │ │ ├── prints │ │ │ └── prints.dart │ │ └── services │ │ │ └── yaml_service_impl.dart │ ├── modules │ │ ├── package_instalation │ │ │ ├── infra │ │ │ │ ├── datasources │ │ │ │ │ └── get_package_version.dart │ │ │ │ └── repositories │ │ │ │ │ └── package_instalation_repository.dart │ │ │ ├── domain │ │ │ │ ├── errors │ │ │ │ │ └── errors.dart │ │ │ │ ├── models │ │ │ │ │ └── package_name.dart │ │ │ │ ├── repositories │ │ │ │ │ └── package_instalation_repository.dart │ │ │ │ └── usecases │ │ │ │ │ ├── install.dart │ │ │ │ │ └── uninstall.dart │ │ │ ├── package_instalation_module.dart │ │ │ ├── main │ │ │ │ └── package_instalation.dart │ │ │ └── external │ │ │ │ └── get_package_version.dart │ │ ├── pipelines │ │ │ └── domain │ │ │ │ ├── errors │ │ │ │ └── errors.dart │ │ │ │ ├── services │ │ │ │ └── yaml_to_map_service.dart │ │ │ │ ├── entities │ │ │ │ ├── pipeline.dart │ │ │ │ └── pipeline_v1.dart │ │ │ │ └── usecases │ │ │ │ ├── pipeline_execute.dart │ │ │ │ └── pipeline_v1_usecase.dart │ │ ├── template_creator │ │ │ ├── domain │ │ │ │ ├── errors │ │ │ │ │ └── errors.dart │ │ │ │ ├── models │ │ │ │ │ ├── line_params.dart │ │ │ │ │ └── template_info.dart │ │ │ │ └── usecases │ │ │ │ │ ├── add_line.dart │ │ │ │ │ └── create.dart │ │ │ └── main │ │ │ │ └── template_creator.dart │ │ └── yaml_edit │ │ │ ├── yaml_edit.dart │ │ │ └── src │ │ │ └── errors.dart │ └── main_module.dart ├── di │ └── injection.dart └── slidy.dart ├── .gitignore ├── tool └── grind.dart ├── bin ├── commands │ ├── command_base.dart │ ├── upgrade_command.dart │ ├── uninstall_command.dart │ ├── install_command.dart │ ├── sub_command │ │ ├── generate_widget_sub_command.dart │ │ ├── generate_page_sub_command.dart │ │ ├── clean_dart │ │ │ ├── generate_use_case_sub_command.dart │ │ │ └── generate_data_source_sub_command.dart │ │ ├── generate_triple_sub_command.dart │ │ ├── generate_rx_notifier_sub_command.dart │ │ ├── generate_module_sub_command.dart │ │ ├── generate_mobx_sub_command.dart │ │ ├── generate_cubit_sub_command.dart │ │ ├── generate_service_sub_command.dart │ │ ├── generate_repository_sub_command.dart │ │ └── generate_bloc_sub_command.dart │ └── generate_command.dart ├── templates │ ├── service.dart │ ├── repository.dart │ ├── module.dart │ ├── triple.dart │ ├── mobx.dart │ ├── use_case.dart │ ├── rx_notifier.dart │ ├── data_source.dart │ ├── bloc.dart │ └── widgets.dart ├── utils │ ├── template_file.dart │ └── utils.dart └── main.dart ├── analysis_options.yaml ├── test ├── di │ └── injection_test.dart └── src │ ├── modules │ ├── package_instalation │ │ ├── external │ │ │ └── get_package_version_test.dart │ │ ├── domain │ │ │ └── usecases │ │ │ │ ├── install_test.dart │ │ │ │ └── uninstall_test.dart │ │ ├── main │ │ │ └── package_instalation_test.dart │ │ └── infra │ │ │ └── repositories │ │ │ └── package_install_repository_test.dart │ ├── pipelines │ │ └── domain │ │ │ ├── entities │ │ │ └── pipeline_v1_test.dart │ │ │ └── usecases │ │ │ ├── pipeline_v1_usecase_test.dart │ │ │ └── pipeline_execute_test.dart │ └── template_creator │ │ └── domain │ │ └── usecases │ │ ├── create_test.dart │ │ └── add_line_test.dart │ └── core │ └── services │ ├── yaml_service_impl_include_test.dart │ └── yaml_service_impl_test.dart ├── .github └── workflows │ ├── deploy_homebrew.yml │ ├── cli_deploy_chocolatey.yaml │ └── release.yml ├── install.sh ├── pubspec.yaml ├── slidy.nuspec └── README.md /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dart.flutterSdkPath": "D:\\fvm\\images\\versions\\stable" 3 | } 4 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /lib/src/version.dart: -------------------------------------------------------------------------------- 1 | // Generated code. Do not modify. 2 | const packageVersion = '3.2.2+1'; 3 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /lib/src/core/entities/slidy_process.dart: -------------------------------------------------------------------------------- 1 | class SlidyProccess { 2 | final String result; 3 | 4 | SlidyProccess({required this.result}); 5 | } 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/infra/datasources/get_package_version.dart: -------------------------------------------------------------------------------- 1 | abstract class GetPackageVersion { 2 | Future fetch(String packageName); 3 | } 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /lib/src/core/interfaces/usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | 3 | abstract class UseCase { 4 | Future> call({required Params params}); 5 | } 6 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toshiossada/slidy/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/lib/app/modules/profile/profile_store.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_triple/flutter_triple.dart'; 2 | 3 | class ProfileStore extends NotifierStore { 4 | ProfileStore() : super(0); 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/modules/pipelines/domain/errors/errors.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/errors/errors.dart'; 2 | 3 | class PipelineError extends SlidyError { 4 | PipelineError(String message) : super(message); 5 | } 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/lib/app/modules/insurence/insurence_store.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_triple/flutter_triple.dart'; 2 | 3 | class InsurenceStore extends NotifierStore { 4 | InsurenceStore() : super(0); 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/modules/template_creator/domain/errors/errors.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/slidy.dart'; 2 | 3 | class TemplateCreatorError extends SlidyError { 4 | TemplateCreatorError(String message) : super(message); 5 | } 6 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/domain/errors/errors.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/errors/errors.dart'; 2 | 3 | class PackageInstalationError extends SlidyError { 4 | PackageInstalationError(String message) : super(message); 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | 6 | # Conventional directory for build outputs 7 | build/ 8 | 9 | # Directory created by dartdoc 10 | doc/api/ 11 | 12 | # MacOS 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | 9 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 10 | } 11 | -------------------------------------------------------------------------------- /lib/src/core/errors/errors.dart: -------------------------------------------------------------------------------- 1 | abstract class SlidyError implements Exception { 2 | final String message; 3 | 4 | SlidyError(this.message); 5 | 6 | @override 7 | String toString() { 8 | return '$runtimeType: message'; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_modular/flutter_modular.dart'; 3 | 4 | import 'app/app_module.dart'; 5 | import 'app/app_widget.dart'; 6 | 7 | void main() => runApp(ModularApp(module: AppModule(), child: AppWidget())); 8 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/src/modules/pipelines/domain/services/yaml_to_map_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:dartz/dartz.dart'; 4 | import 'package:slidy/src/modules/pipelines/domain/errors/errors.dart'; 5 | 6 | abstract class YamlToMapService { 7 | FutureOr> convert(String yamlPath); 8 | } 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/test/app/modules/profile/profile_module_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/app/modules/profile/profile_module.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:modular_test/modular_test.dart'; 4 | 5 | void main() { 6 | setUpAll(() { 7 | initModule(ProfileModule()); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/core/interfaces/yaml_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:yaml/yaml.dart'; 2 | 3 | abstract class YamlService { 4 | void update(List path, String value); 5 | bool remove(List path); 6 | YamlNode? getValue(List path); 7 | Future readAllIncludes(); 8 | Future save(); 9 | } 10 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/test/app/modules/insurence_module_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/app/modules/insurence_module.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:modular_test/modular_test.dart'; 4 | 5 | void main() { 6 | setUpAll(() { 7 | initModule( 8 | InsurenceModule(), 9 | ); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 791edc230db53c55401a8340b18ffc46d21299df 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /lib/src/modules/template_creator/domain/models/line_params.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | class LineParams { 4 | final File file; 5 | final int position; 6 | final List inserts; 7 | final String Function(String line)? replaceLine; 8 | 9 | LineParams(this.file, 10 | {this.position = 0, this.replaceLine, this.inserts = const []}); 11 | } 12 | -------------------------------------------------------------------------------- /example/lib/app/app_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_modular/flutter_modular.dart'; 2 | 3 | import 'modules/home/home_module.dart'; 4 | 5 | class AppModule extends Module { 6 | @override 7 | final List binds = []; 8 | 9 | @override 10 | final List routes = [ 11 | ModuleRoute(Modular.initialRoute, module: HomeModule()), 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /tool/grind.dart: -------------------------------------------------------------------------------- 1 | import 'package:grinder/grinder.dart'; 2 | import 'package:cli_pkg/cli_pkg.dart' as pkg; 3 | 4 | void main(List args) { 5 | pkg.name.value = 'slidy'; 6 | pkg.humanName.value = 'slidy'; 7 | pkg.githubUser.value = 'Flutterando'; 8 | pkg.homebrewRepo.value = 'Flutterando/homebrew-slidy'; 9 | 10 | pkg.addAllTasks(); 11 | grind(args); 12 | } 13 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/lib/app/app_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_modular/flutter_modular.dart'; 3 | 4 | class AppWidget extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return MaterialApp( 8 | title: 'Flutter Slidy', 9 | theme: ThemeData(primarySwatch: Colors.blue), 10 | ).modular(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/src/modules/template_creator/domain/models/template_info.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | class TemplateInfo { 4 | final File destiny; 5 | final File yaml; 6 | final String key; 7 | late final List args; 8 | 9 | TemplateInfo( 10 | {required this.key, 11 | required this.destiny, 12 | required this.yaml, 13 | List? args}) { 14 | this.args = args ?? []; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/lib/app/modules/home/home_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_modular/flutter_modular.dart'; 2 | import '../home/home_store.dart'; 3 | 4 | import 'home_page.dart'; 5 | 6 | class HomeModule extends Module { 7 | @override 8 | final List binds = [ 9 | Bind.lazySingleton((i) => HomeStore()), 10 | ]; 11 | 12 | @override 13 | final List routes = [ 14 | ChildRoute(Modular.initialRoute, child: (_, args) => HomePage()), 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /example/test/app/modules/profile/profile_store_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:example/app/modules/profile/profile_store.dart'; 3 | 4 | void main() { 5 | late ProfileStore store; 6 | 7 | setUpAll(() { 8 | store = ProfileStore(); 9 | }); 10 | 11 | test('increment count', () async { 12 | expect(store.state, equals(0)); 13 | store.update(store.state + 1); 14 | expect(store.state, equals(1)); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bin/commands/command_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/command_runner.dart'; 2 | 3 | abstract class CommandBase extends Command { 4 | String? get invocationSuffix; 5 | @override 6 | String get invocation { 7 | return invocationSuffix != null && invocationSuffix?.isNotEmpty == true 8 | ? '${super.invocation} $invocationSuffix' 9 | : '${super.invocation}'; 10 | } 11 | 12 | @override 13 | String get description; 14 | 15 | @override 16 | String get name; 17 | } 18 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/test/app/modules/insurence/insurence_store_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:example/app/modules/insurence/insurence_store.dart'; 3 | 4 | void main() { 5 | late InsurenceStore store; 6 | 7 | setUpAll(() { 8 | store = InsurenceStore(); 9 | }); 10 | 11 | test('increment count', () async { 12 | expect(store.state, equals(0)); 13 | store.update(store.state + 1); 14 | expect(store.state, equals(1)); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /example/lib/app/modules/insurence_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_modular/flutter_modular.dart'; 2 | 3 | import 'insurence/insurence_page.dart'; 4 | import 'insurence/insurence_store.dart'; 5 | 6 | class InsurenceModule extends Module { 7 | @override 8 | final List binds = [ 9 | Bind.lazySingleton((i) => InsurenceStore()), 10 | ]; 11 | 12 | @override 13 | final List routes = [ 14 | ChildRoute('/', child: (_, args) => InsurencePage()), 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:pedantic/analysis_options.yaml 5 | 6 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 7 | # Uncomment to specify additional rules. 8 | # linter: 9 | # rules: 10 | # - camel_case_types 11 | 12 | analyzer: 13 | # exclude: 14 | # - path/to/excluded/files/** 15 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/domain/models/package_name.dart: -------------------------------------------------------------------------------- 1 | class PackageName { 2 | final String name; 3 | final bool isDev; 4 | final String version; 5 | 6 | PackageName(this.name, {this.isDev = false, this.version = ''}); 7 | 8 | PackageName copyWith({ 9 | String? name, 10 | bool? isDev, 11 | String? version, 12 | }) { 13 | return PackageName( 14 | name ?? this.name, 15 | isDev: isDev ?? this.isDev, 16 | version: version ?? this.version, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/lib/app/modules/profile/profile_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/app/modules/profile/profile_Page.dart'; 2 | import 'package:example/app/modules/profile/profile_store.dart'; 3 | import 'package:flutter_modular/flutter_modular.dart'; 4 | 5 | class ProfileModule extends Module { 6 | @override 7 | final List binds = [ 8 | Bind.lazySingleton((i) => ProfileStore()), 9 | ]; 10 | 11 | @override 12 | final List routes = [ 13 | ChildRoute('/', child: (_, args) => ProfilePage()), 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/lib/app/modules/home/home_store.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_triple/flutter_triple.dart'; 2 | 3 | class HomeStore extends NotifierStore { 4 | HomeStore() : super(0); 5 | 6 | Future increment() async { 7 | setLoading(true); 8 | 9 | await Future.delayed(Duration(seconds: 1)); 10 | 11 | int value = state + 1; 12 | if (value < 5) { 13 | update(value); 14 | } else { 15 | setError(Exception('Error: state not can be > 4')); 16 | } 17 | 18 | setLoading(false); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/domain/repositories/package_instalation_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 3 | 4 | import '../../../../core/entities/slidy_process.dart'; 5 | import '../../../../core/errors/errors.dart'; 6 | 7 | abstract class PackageInstalationRepository { 8 | Future> install(PackageName package); 9 | Future> uninstall(PackageName package); 10 | } 11 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/main_module.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart'; 4 | import 'package:slidy/di/injection.dart'; 5 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 6 | import 'package:slidy/src/core/services/yaml_service_impl.dart'; 7 | 8 | import 'modules/package_instalation/package_instalation_module.dart'; 9 | 10 | void StartAllModules() { 11 | sl 12 | //services 13 | ..register((i) => YamlServiceImpl(yaml: File('pubspec.yaml'))) 14 | 15 | //external 16 | ..register((i) => Client()); 17 | 18 | PackageInstalationModule(); 19 | } 20 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /bin/templates/service.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _serviceTemplate = r''' 4 | service: | 5 | class $fileName|pascalcase { 6 | 7 | } 8 | i_service: | 9 | abstract class I$arg1 { 10 | 11 | } 12 | impl_service: | 13 | import '$fileName_interface.dart'; 14 | 15 | class $fileName|pascalcase implements I$fileName|pascalcase { 16 | 17 | } 18 | test_service: | 19 | import 'package:flutter_test/flutter_test.dart'; 20 | $arg2 21 | 22 | void main() { 23 | late $arg1 service; 24 | 25 | setUpAll(() { 26 | service = $arg1(); 27 | }); 28 | } 29 | '''; 30 | 31 | final serviceFile = CustomFile(yaml: _serviceTemplate); 32 | -------------------------------------------------------------------------------- /example/slidy_pipeline.yaml: -------------------------------------------------------------------------------- 1 | name: Slidy Pipeline 2 | version: v1 3 | 4 | create_custom_file: #this is command name 5 | name: Named Command 6 | steps: 7 | - id: First File Creation 8 | generate: 9 | path: lib/app/path/file.dart 10 | file: | 11 | Generate file line 1 12 | generate file line 2 ${{ fileName | camelcase }} 13 | module_injection: 14 | type: bind 15 | value: Bind.singleton((i) => ${{ fileName | camelcase }}()) 16 | run: echo "Custom Command" 17 | commands: 18 | - flutter pub get 19 | - flutter pub run build_runner build --delete-conflicting-outputs 20 | 21 | 22 | # slidy template ./slidy_pipeline.yaml create_custom_file 23 | -------------------------------------------------------------------------------- /bin/templates/repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _repositoryTemplate = r''' 4 | repository: | 5 | class $fileName|pascalcase { 6 | 7 | } 8 | i_repository: | 9 | abstract class I$arg1 { 10 | 11 | } 12 | impl_repository: | 13 | import '$fileName_interface.dart'; 14 | 15 | class $fileName|pascalcase implements I$fileName|pascalcase { 16 | 17 | } 18 | test_repository: | 19 | import 'package:flutter_test/flutter_test.dart'; 20 | $arg2 21 | 22 | void main() { 23 | late $arg1 repository; 24 | 25 | setUpAll(() { 26 | repository = $arg1(); 27 | }); 28 | } 29 | '''; 30 | 31 | final repositoryFile = CustomFile(yaml: _repositoryTemplate); 32 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/domain/usecases/install.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/src/modules/package_instalation/domain/repositories/package_instalation_repository.dart'; 3 | import '../../../../core/entities/slidy_process.dart'; 4 | import '../../../../core/errors/errors.dart'; 5 | import '../../../../core/interfaces/usecase.dart'; 6 | import '../models/package_name.dart'; 7 | 8 | class Install implements UseCase { 9 | final PackageInstalationRepository repository; 10 | 11 | Install(this.repository); 12 | 13 | @override 14 | Future> call( 15 | {required PackageName params}) async { 16 | return await repository.install(params); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bin/templates/module.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _generateTemplate = r''' 4 | module: | 5 | import 'package:flutter_modular/flutter_modular.dart'; 6 | 7 | class $fileName|pascalcase extends Module { 8 | @override 9 | final List binds = []; 10 | 11 | @override 12 | final List routes = []; 13 | 14 | } 15 | module_test: | 16 | import 'package:flutter_modular/flutter_modular.dart'; 17 | import 'package:modular_test/modular_test.dart'; 18 | import 'package:flutter_test/flutter_test.dart'; 19 | $arg2 20 | 21 | void main() { 22 | 23 | setUpAll(() { 24 | initModule($arg1()); 25 | }); 26 | } 27 | '''; 28 | 29 | final generateFile = CustomFile(yaml: _generateTemplate); 30 | -------------------------------------------------------------------------------- /lib/src/core/prints/prints.dart: -------------------------------------------------------------------------------- 1 | import 'package:ansicolor/ansicolor.dart'; 2 | import 'package:dartz/dartz.dart'; 3 | import 'package:slidy/slidy.dart'; 4 | 5 | AnsiPen red = AnsiPen()..red(bold: true); 6 | AnsiPen green = AnsiPen()..green(bold: true); 7 | AnsiPen white = AnsiPen()..white(bold: true); 8 | AnsiPen yellow = AnsiPen()..yellow(bold: true); 9 | 10 | void success(msg) => print(green('SUCCESS: $msg')); 11 | void title(msg) => print(green('$msg')); 12 | void warn(msg) => print(yellow('WARN: $msg')); 13 | void error(msg) => print(red('ERROR: $msg')); 14 | void msg(msg) => print(white(msg)); 15 | 16 | void execute(Either either) { 17 | either.fold((left) { 18 | error(left.message); 19 | }, (right) { 20 | success(right.result); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/domain/usecases/uninstall.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/src/modules/package_instalation/domain/repositories/package_instalation_repository.dart'; 3 | 4 | import '../../../../core/entities/slidy_process.dart'; 5 | import '../../../../core/errors/errors.dart'; 6 | import '../../../../core/interfaces/usecase.dart'; 7 | import '../models/package_name.dart'; 8 | 9 | class Uninstall implements UseCase { 10 | final PackageInstalationRepository repository; 11 | 12 | Uninstall(this.repository); 13 | 14 | @override 15 | Future> call( 16 | {required PackageName params}) async { 17 | return await repository.uninstall(params); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/modules/pipelines/domain/entities/pipeline.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:dartz/dartz.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | import 'package:slidy/src/modules/pipelines/domain/errors/errors.dart'; 6 | 7 | abstract class Pipeline { 8 | late final Future> Function( 9 | Pipeline pipeline, String command, List args) _usecase; 10 | 11 | Pipeline( 12 | Future> Function( 13 | Pipeline pipeline, String command, List args) 14 | usecase) { 15 | _usecase = usecase; 16 | } 17 | 18 | Future> call( 19 | String command, List args) async { 20 | return _usecase(this, command, args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/modules/template_creator/main/template_creator.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/slidy.dart'; 3 | import 'package:slidy/src/modules/template_creator/domain/models/line_params.dart'; 4 | import 'package:slidy/src/modules/template_creator/domain/models/template_info.dart'; 5 | import 'package:slidy/src/modules/template_creator/domain/usecases/add_line.dart'; 6 | import 'package:slidy/src/modules/template_creator/domain/usecases/create.dart'; 7 | 8 | class TemplateCreator { 9 | Future> createFile( 10 | {required TemplateInfo info}) { 11 | return Create()(params: info); 12 | } 13 | 14 | Future> addLine( 15 | {required LineParams params}) { 16 | return AddLine()(params: params); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bin/templates/triple.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _tripleTemplate = r''' 4 | triple: | 5 | import 'package:flutter_triple/flutter_triple.dart'; 6 | 7 | class $fileName|pascalcase extends NotifierStore { 8 | 9 | $fileName|pascalcase() : super(0); 10 | 11 | } 12 | triple_test: | 13 | import 'package:flutter_test/flutter_test.dart'; 14 | $arg2 15 | 16 | void main() { 17 | late $arg1 store; 18 | 19 | setUpAll(() { 20 | store = $arg1(); 21 | }); 22 | 23 | test('increment count', () async { 24 | expect(store.state, equals(0)); 25 | store.update(store.state + 1); 26 | expect(store.state, equals(1)); 27 | }); 28 | } 29 | '''; 30 | 31 | final tripleFile = CustomFile(yaml: _tripleTemplate); 32 | -------------------------------------------------------------------------------- /example/lib/app/modules/profile/profile_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_modular/flutter_modular.dart'; 2 | import 'package:example/app/modules/profile/profile_store.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class ProfilePage extends StatefulWidget { 6 | final String title; 7 | const ProfilePage({Key? key, this.title = 'ProfilePage'}) : super(key: key); 8 | @override 9 | ProfilePageState createState() => ProfilePageState(); 10 | } 11 | 12 | class ProfilePageState extends State { 13 | final ProfileStore store = Modular.get(); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text(widget.title), 20 | ), 21 | body: Column( 22 | children: [], 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/di/injection.dart: -------------------------------------------------------------------------------- 1 | final Map _dependencies = {}; 2 | 3 | class _Injection { 4 | void register(T Function(_Injection i) bind) { 5 | if (_dependencies.containsKey(T)) { 6 | throw Exception('bind alread registed'); 7 | } 8 | _dependencies[T] = bind; 9 | } 10 | 11 | void changeRegister(T Function(_Injection i) bind) { 12 | _dependencies[T] = bind; 13 | } 14 | 15 | void cleanModule() { 16 | _dependencies.clear(); 17 | } 18 | 19 | T call() => get(); 20 | 21 | T get() { 22 | if (_dependencies.containsKey(T)) { 23 | return _dependencies[T]!(this); 24 | } else { 25 | throw Exception('injection not found'); 26 | } 27 | } 28 | } 29 | 30 | _Injection getInjection() { 31 | return _Injection(); 32 | } 33 | 34 | final sl = getInjection(); 35 | -------------------------------------------------------------------------------- /example/lib/app/modules/insurence/insurence_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_modular/flutter_modular.dart'; 2 | import 'package:example/app/modules/insurence/insurence_store.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class InsurencePage extends StatefulWidget { 6 | final String title; 7 | const InsurencePage({Key? key, this.title = "InsurencePage"}) 8 | : super(key: key); 9 | @override 10 | InsurencePageState createState() => InsurencePageState(); 11 | } 12 | 13 | class InsurencePageState extends State { 14 | final InsurenceStore store = Modular.get(); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text(widget.title), 21 | ), 22 | body: Column( 23 | children: [], 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/package_instalation_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/di/injection.dart'; 2 | import 'package:slidy/src/modules/package_instalation/domain/usecases/install.dart'; 3 | 4 | import 'domain/repositories/package_instalation_repository.dart'; 5 | import 'domain/usecases/uninstall.dart'; 6 | import 'external/get_package_version.dart'; 7 | import 'infra/datasources/get_package_version.dart'; 8 | import 'infra/repositories/package_instalation_repository.dart'; 9 | 10 | void PackageInstalationModule() { 11 | sl 12 | //domain 13 | ..register((i) => Install(i())) 14 | ..register((i) => Uninstall(i())) 15 | //infra 16 | ..register( 17 | (i) => PackageInstalationRepositoryImpl(pubspec: i(), client: i())) 18 | //external 19 | ..register((i) => GetPackageVersionImpl(i())); 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/main/package_instalation.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/di/injection.dart'; 3 | import 'package:slidy/src/core/entities/slidy_process.dart'; 4 | import 'package:slidy/src/core/errors/errors.dart'; 5 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 6 | import 'package:slidy/src/modules/package_instalation/domain/usecases/install.dart'; 7 | import 'package:slidy/src/modules/package_instalation/domain/usecases/uninstall.dart'; 8 | 9 | class PackageInstalation { 10 | Future> install( 11 | {required PackageName package}) { 12 | return sl.get()(params: package); 13 | } 14 | 15 | Future> uninstall( 16 | {required PackageName package}) { 17 | return sl.get()(params: package); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bin/commands/upgrade_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'command_base.dart'; 5 | import 'package:slidy/src/core/prints/prints.dart' as output; 6 | 7 | class UpgradeCommand extends CommandBase { 8 | @override 9 | final name = 'upgrade'; 10 | @override 11 | final description = 'Upgrade the Slidy version'; 12 | 13 | @override 14 | void run() { 15 | try { 16 | output.title('Upgrading Slidy...'); 17 | Process.runSync('dart', ['pub', 'global', 'activate', 'slidy'], 18 | runInShell: true); 19 | output.success('upgraded!'); 20 | 21 | var process = Process.runSync('slidy', ['-v'], 22 | runInShell: true, stdoutEncoding: utf8); 23 | print(process.stdout); 24 | } catch (e) { 25 | output.error('Failure upgrade :('); 26 | } 27 | } 28 | 29 | @override 30 | String? get invocationSuffix => null; 31 | } 32 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /bin/templates/mobx.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _mobxTemplate = r''' 4 | mobx: | 5 | import 'package:mobx/mobx.dart'; 6 | 7 | part '$fileName.g.dart'; 8 | 9 | class $fileName|pascalcase = _$fileName|pascalcaseBase with _$$fileName|pascalcase; 10 | abstract class _$fileName|pascalcaseBase with Store { 11 | 12 | @observable 13 | int value = 0; 14 | 15 | @action 16 | void increment() { 17 | value++; 18 | } 19 | } 20 | mobx_test: | 21 | import 'package:flutter_test/flutter_test.dart'; 22 | $arg2 23 | 24 | void main() { 25 | late $arg1 store; 26 | 27 | setUpAll(() { 28 | store = $arg1(); 29 | }); 30 | 31 | test('increment count', () async { 32 | expect(store.value, equals(0)); 33 | store.increment(); 34 | expect(store.value, equals(1)); 35 | }); 36 | } 37 | '''; 38 | 39 | final mobxFile = CustomFile(yaml: _mobxTemplate); 40 | -------------------------------------------------------------------------------- /bin/templates/use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _useCaseTemplate = r''' 4 | use_case: | 5 | import 'package:dartz/dartz.dart'; 6 | 7 | abstract class I$fileName|pascalcase { 8 | Future>> call(); 9 | } 10 | 11 | class $fileName|pascalcase extends I$fileName|pascalcase { 12 | 13 | @override 14 | Future>> call() async { 15 | throw UnimplementedError(); 16 | } 17 | } 18 | 19 | use_case_test: | 20 | import 'package:flutter_test/flutter_test.dart'; 21 | $arg2 22 | 23 | void main() { 24 | 25 | setUpAll(() { 26 | }); 27 | 28 | test('increment count', () async { 29 | var featureMessage = await $arg1()(); 30 | expect(featureMessage | [], isInstanceOf>()); 31 | }); 32 | } 33 | '''; 34 | 35 | final use_case = CustomFile(yaml: _useCaseTemplate); 36 | -------------------------------------------------------------------------------- /bin/templates/rx_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _rxNotifierTemplate = r''' 4 | rx_notifier: | 5 | import 'package:rx_notifier/rx_notifier.dart'; 6 | 7 | class $fileName|pascalcase { 8 | final _count = RxNotifier(0); 9 | int get count => _count.value; 10 | setCount(int value) => _count.value = value; 11 | 12 | void increment() { 13 | setCount(count + 1); 14 | } 15 | } 16 | rx_notifier_test: | 17 | import 'package:flutter_test/flutter_test.dart'; 18 | $arg2 19 | 20 | void main() { 21 | late $arg1 controller; 22 | 23 | setUpAll(() { 24 | controller = $arg1(); 25 | }); 26 | 27 | test('increment count', () async { 28 | expect(controller.count, equals(0)); 29 | controller.increment(); 30 | expect(controller.count, equals(1)); 31 | }); 32 | } 33 | '''; 34 | 35 | final rxnotifierFile = CustomFile(yaml: _rxNotifierTemplate); 36 | -------------------------------------------------------------------------------- /test/di/injection_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/di/injection.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | tearDown(() { 6 | sl.cleanModule(); 7 | }); 8 | test('added injection', () { 9 | expect(() => sl.get(), throwsA(isA())); 10 | sl.register((i) => 'String'); 11 | expect(sl.get(), 'String'); 12 | 13 | expect(() => sl.get(), throwsA(isA())); 14 | sl.register((i) => true); 15 | expect(sl.get(), true); 16 | }); 17 | 18 | test('duplicate injection', () { 19 | sl.register((i) => 'String'); 20 | expect(() => sl.register((i) => 'String'), throwsA(isA())); 21 | }); 22 | 23 | test('constructor inject', () { 24 | sl.register((i) => Person(i())); 25 | sl.changeRegister((i) => 'Jacob'); 26 | expect(sl.get().name, 'Jacob'); 27 | }); 28 | } 29 | 30 | class Person { 31 | final String name; 32 | 33 | Person(this.name); 34 | } 35 | -------------------------------------------------------------------------------- /bin/templates/data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _dataSourceTemplate = r''' 4 | interface_data_source: | 5 | abstract class I$fileName|pascalcase { 6 | 7 | Future> getListData(); 8 | } 9 | 10 | data_source: | 11 | import 'package:dio/dio.dart'; 12 | $arg2 13 | class $fileName|pascalcaseImpl implements I$fileName|pascalcase { 14 | final Dio dio; 15 | 16 | $fileName|pascalcaseImpl(this.dio); 17 | 18 | @override 19 | Future> getListData() async { 20 | var response = await dio.get('url'); 21 | return response.data; 22 | } 23 | } 24 | 25 | data_source_test: | 26 | import 'package:flutter_test/flutter_test.dart'; 27 | 28 | void main() { 29 | //late $arg1 dataSource; 30 | 31 | setUpAll(() { 32 | // dataSource = $arg3(); 33 | }); 34 | } 35 | '''; 36 | 37 | final data_source = CustomFile(yaml: _dataSourceTemplate); 38 | -------------------------------------------------------------------------------- /.github/workflows/deploy_homebrew.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow that is manually triggered 2 | 3 | name: Homebrew Deploy 4 | 5 | # Controls when the action will run. Workflow runs when manually triggered using the UI 6 | # or API. 7 | on: 8 | workflow_dispatch: 9 | release: 10 | types: 11 | - published 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | deploy: 16 | name: Deploy Homebrew 17 | runs-on: ubuntu-latest 18 | env: 19 | PUB_CREDENTIALS: ${{ secrets.PUB_CREDENTIALS }} 20 | GITHUB_TOKEN: ${{ secrets.TOKEN_PUBLISH }} 21 | container: 22 | image: google/dart:latest 23 | steps: 24 | - uses: actions/checkout@v1 25 | 26 | - name: Install dependencies 27 | run: pub get 28 | 29 | - name: Build Version Number 30 | run: pub run build_runner build --delete-conflicting-outputs 31 | 32 | - name: Test 33 | run: pub run test 34 | 35 | - name: Deploy to Homebrew 36 | run: pub run grinder pkg-homebrew-update 37 | -------------------------------------------------------------------------------- /bin/commands/uninstall_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import 'command_base.dart'; 8 | 9 | class UninstallCommand extends CommandBase { 10 | @override 11 | final name = 'uninstall'; 12 | @override 13 | final description = 'Remove a package'; 14 | 15 | UninstallCommand() { 16 | argParser.addFlag('dev', 17 | negatable: false, help: 'Remove a package in a dev dependency'); 18 | } 19 | 20 | @override 21 | FutureOr run() async { 22 | if (argResults?.rest.isEmpty == true) { 23 | throw UsageException('value not passed for a module command', usage); 24 | } else { 25 | for (var pack in argResults!.rest) { 26 | final result = await Slidy.instance.instalation.uninstall( 27 | package: PackageName(pack, isDev: argResults?['dev'] == true)); 28 | execute(result); 29 | } 30 | } 31 | } 32 | 33 | @override 34 | String? get invocationSuffix => null; 35 | } 36 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd $HOME 3 | if [[ -f .temp_slidy_installer ]] 4 | then 5 | rm -rf .temp_slidy_installer 6 | fi 7 | 8 | mkdir $(pwd)/.temp_slidy_installer 9 | 10 | cd $(pwd)/.temp_slidy 11 | 12 | THEARCH=$(uname -m) 13 | THEBIT=$(getconf LONG_BIT) 14 | 15 | if [[ $THEBIT == *64* ]]; then 16 | 17 | echo "downloading the lastest slidy' version!" 18 | THEURL=$(curl -s https://api.github.com/repos/Flutterando/slidy/releases | grep browser_download_url | grep 'linux-x64[.]tar[.]gz' | head -n 1 | cut -d '"' -f 4) 19 | curl -L $THEURL > slidy_temp.tar.gz 20 | 21 | fi 22 | 23 | if [[ $THEBIT == *64* ]]; then 24 | 25 | echo "downloading the lastest slidy' version!" 26 | THEURL=$(curl -s https://api.github.com/repos/Flutterando/slidy/releases | grep browser_download_url | grep 'linux-ia32[.]tar[.]gz' | head -n 1 | cut -d '"' -f 4) 27 | curl -L $THEURL > slidy_temp.tar.gz 28 | 29 | fi 30 | 31 | tar -xvzf slidy_temp.tar.gz 32 | sudo cp slidy/slidy /usr/bin/ 33 | 34 | echo "Cleaning environment ..." 35 | cd $HOME 36 | rm -rf .temp_slidy_installer 37 | 38 | slidy -v -------------------------------------------------------------------------------- /.github/workflows/cli_deploy_chocolatey.yaml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow that is manually triggered 2 | 3 | name: Chocolatey Deploy 4 | 5 | # Controls when the action will run. Workflow runs when manually triggered using the UI 6 | # or API. 7 | on: 8 | workflow_dispatch: 9 | 10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 11 | jobs: 12 | deploy-windows: 13 | name: Cholatey Deploy (Windows) 14 | runs-on: windows-latest 15 | env: 16 | CHOCOLATEY_TOKEN: ${{ secrets.CHOCOLATEY_TOKEN }} 17 | steps: 18 | - uses: actions/checkout@v1 19 | 20 | - name: Setup Dart 21 | uses: DanTup/gh-actions/setup-dart@master 22 | with: 23 | channel: stable 24 | 25 | - name: Install dependencies 26 | run: pub get 27 | 28 | - name: Run Builder for Version 29 | run: pub run build_runner build --delete-conflicting-outputs 30 | 31 | - name: Run Test 32 | run: pub run test 33 | 34 | - name: Deploy Chocolatey (Windows) 35 | run: pub run grinder pkg-chocolatey-deploy 36 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/src/modules/template_creator/domain/usecases/add_line.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/slidy.dart'; 3 | import 'package:slidy/src/core/interfaces/usecase.dart'; 4 | import 'package:slidy/src/modules/template_creator/domain/models/line_params.dart'; 5 | 6 | class AddLine extends UseCase { 7 | @override 8 | Future> call( 9 | {required LineParams params}) async { 10 | var lines = await params.file.readAsLines(); 11 | lines = params.replaceLine == null 12 | ? lines 13 | : lines.map(params.replaceLine!).toList(); 14 | lines.insertAll(params.position, params.inserts); 15 | await params.file.writeAsString(lines.join('\n')); 16 | 17 | if (params.inserts.isEmpty) { 18 | return Right(SlidyProccess( 19 | result: '${params.file.uri.pathSegments.last} added line')); 20 | } 21 | return Right(SlidyProccess( 22 | result: 23 | '${params.file.uri.pathSegments.last} added line ${params.inserts.first}')); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: slidy 2 | description: CLI package manager and template for Flutter. Generate Modules, Pages, Widgets, BLoCs, MobX, Triple and more. 3 | version: 3.2.2+2 4 | homepage: https://github.com/Flutterando/slidy 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | 9 | dependencies: 10 | dart_console: ^1.0.0 11 | http: ^0.13.2 12 | args: ^2.1.0 13 | ansicolor: ^2.0.1 14 | recase: ^4.0.0 15 | file: ^6.1.0 16 | yaml: ^3.1.0 17 | collection: ^1.14.11 18 | meta: ^1.1.8 19 | source_span: ^1.7.0 20 | dartz: ^0.10.0-nullsafety.1 21 | fhir_yaml: ^0.4.0 22 | rxdart: ^0.26.0 23 | io: ^1.0.0 24 | 25 | dev_dependencies: 26 | build_runner: ^2.0.1 27 | build_version: ^2.0.3 28 | test: ^1.16.0-nullsafety.17 29 | mocktail: ^0.1.1 30 | build_test: ^2.1.0 31 | cli_pkg: 32 | git: https://github.com/leoafarias/dart_cli_pkg 33 | grinder: ^0.9.0 34 | 35 | # dependency_overrides: 36 | # args: '2.0.0-nullsafety.0' 37 | 38 | scripts: 39 | build: mkdir build\windows & dart compile exe bin\slidy.dart -o build\windows\slidy.exe 40 | 41 | 42 | executables: 43 | slidy: main 44 | -------------------------------------------------------------------------------- /slidy.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | slidy 5 | https://github.com/Flutterando/slidy 6 | flutterando 7 | 8 | Slidy 9 | flutterando 10 | https://github.com/Flutterando/slidy 11 | 12 | https://github.com/Flutterando/slidy/blob/master/LICENSE 13 | false 14 | https://github.com/Flutterando/slidy 15 | Slidy flutter dart 16 | Slidy. Templates for Flutter Modular apps 17 | CLI package manager and template for Flutter. Generate Modules, Pages, Widgets, BLoCs, MobX, Triple and more. 18 | https://github.com/Flutterando/slidy/blob/master/CHANGELOG.md 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/external/get_package_version.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:http/http.dart'; 4 | import 'package:slidy/src/modules/package_instalation/domain/errors/errors.dart'; 5 | import 'package:slidy/src/modules/package_instalation/infra/datasources/get_package_version.dart'; 6 | 7 | class GetPackageVersionImpl implements GetPackageVersion { 8 | final Client client; 9 | 10 | GetPackageVersionImpl(this.client); 11 | 12 | @override 13 | Future fetch(String packageName) async { 14 | final url = 'https://pub.dev/api/packages/$packageName'; 15 | try { 16 | var response = await client.get(Uri.parse(url)); 17 | if (response.statusCode == 200) { 18 | var json = jsonDecode(response.body); 19 | var map = json['latest']['pubspec']; 20 | return map['version']; 21 | } else { 22 | throw PackageInstalationError('pub.dev request error'); 23 | } 24 | } catch (e) { 25 | if (e is PackageInstalationError) { 26 | rethrow; 27 | } else { 28 | throw PackageInstalationError('Internet error'); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/slidy.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:slidy/src/modules/package_instalation/main/package_instalation.dart'; 4 | import 'package:slidy/src/modules/template_creator/main/template_creator.dart'; 5 | 6 | import 'di/injection.dart'; 7 | import 'src/main_module.dart'; 8 | 9 | export 'src/modules/template_creator/domain/models/template_info.dart'; 10 | export 'src/core/entities/slidy_process.dart'; 11 | export 'src/core/errors/errors.dart'; 12 | export 'src/modules/package_instalation/domain/models/package_name.dart'; 13 | export 'src/core/prints/prints.dart'; 14 | 15 | class Slidy { 16 | static final Slidy instance = Slidy._internal(); 17 | 18 | Slidy._(); 19 | 20 | factory Slidy._internal() { 21 | StartAllModules(); 22 | return Slidy._(); 23 | } 24 | 25 | T get() { 26 | return sl.get(); 27 | } 28 | 29 | final instalation = PackageInstalation(); 30 | final template = TemplateCreator(); 31 | 32 | Future getParentModule(Directory dir) async { 33 | await for (var file in dir.list()) { 34 | if (file.path.contains('_module.dart')) { 35 | return file as File; 36 | } 37 | } 38 | 39 | return await getParentModule(dir.parent); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /bin/commands/install_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:io/io.dart'; 5 | import 'package:slidy/slidy.dart'; 6 | 7 | import 'package:slidy/src/core/prints/prints.dart'; 8 | import 'command_base.dart'; 9 | 10 | class InstallCommand extends CommandBase { 11 | @override 12 | final name = 'install'; 13 | 14 | @override 15 | final description = 'Install (or update) a new package or packages:'; 16 | 17 | InstallCommand() { 18 | argParser.addFlag('dev', 19 | negatable: false, 20 | help: 'Install (or update) a package in a dev dependency'); 21 | } 22 | 23 | @override 24 | FutureOr run() async { 25 | if (argResults?.rest.isEmpty == true) { 26 | throw UsageException('value not passed for a module command', usage); 27 | } else { 28 | for (var pack in argResults!.rest) { 29 | final result = await Slidy.instance.instalation.install( 30 | package: PackageName(pack, isDev: argResults?['dev'] == true)); 31 | execute(result); 32 | } 33 | } 34 | } 35 | 36 | @override 37 | String? get invocationSuffix => null; 38 | } 39 | 40 | class InstallCommandAbbr extends InstallCommand { 41 | @override 42 | final name = 'i'; 43 | } 44 | -------------------------------------------------------------------------------- /example/lib/app/modules/home/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_modular/flutter_modular.dart'; 3 | import 'package:flutter_triple/flutter_triple.dart'; 4 | import 'home_store.dart'; 5 | 6 | class HomePage extends StatefulWidget { 7 | final String title; 8 | const HomePage({Key? key, this.title = "Home"}) : super(key: key); 9 | 10 | @override 11 | _HomePageState createState() => _HomePageState(); 12 | } 13 | 14 | class _HomePageState extends ModularState { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text('Counter'), 20 | ), 21 | body: ScopedBuilder( 22 | store: store, 23 | onState: (_, counter) { 24 | return Padding( 25 | padding: EdgeInsets.all(10), 26 | child: Text('$counter'), 27 | ); 28 | }, 29 | onError: (context, error) => Center( 30 | child: Text( 31 | 'Too many clicks', 32 | style: TextStyle(color: Colors.red), 33 | ), 34 | ), 35 | ), 36 | floatingActionButton: FloatingActionButton( 37 | onPressed: () { 38 | store.increment(); 39 | }, 40 | child: Icon(Icons.add), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/src/modules/package_instalation/external/get_package_version_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:http/http.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:slidy/src/modules/package_instalation/domain/errors/errors.dart'; 4 | 5 | import 'package:slidy/src/modules/package_instalation/external/get_package_version.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import 'external_json_result.dart'; 9 | 10 | class ClientMock extends Mock implements Client {} 11 | 12 | void main() { 13 | setUpAll(() { 14 | registerFallbackValue(Uri()); 15 | }); 16 | 17 | final client = ClientMock(); 18 | 19 | final datasource = GetPackageVersionImpl(client); 20 | 21 | test('should install package', () async { 22 | when(() => client.get(any())) 23 | .thenAnswer((_) async => Response(jsonPackageResult, 200)); 24 | final result = await datasource.fetch('package'); 25 | expect(result, '2.0.1'); 26 | }); 27 | test(' statusCode 404', () async { 28 | when(() => client.get(any())).thenAnswer((_) async => Response('', 404)); 29 | expect(() async => await datasource.fetch('package'), 30 | throwsA(isA())); 31 | }); 32 | 33 | test('Client http error', () async { 34 | when(() => client.get(any())).thenThrow(Exception('error')); 35 | expect(() async => await datasource.fetch('package'), 36 | throwsA(isA())); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/modules/yaml_edit/yaml_edit.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// YAML parsing is supported by `package:yaml`, and each time a change is 16 | /// made, the resulting YAML AST is compared against our expected output 17 | /// with deep equality to ensure that the output conforms to our expectations. 18 | /// 19 | /// **Example** 20 | /// ```dart 21 | /// import 'package:yaml_edit/yaml_edit.dart'; 22 | /// 23 | /// void main() { 24 | /// final yamlEditor = YamlEditor('{YAML: YAML}'); 25 | /// yamlEditor.update(['YAML'], "YAML Ain't Markup Language"); 26 | /// print(yamlEditor); 27 | /// // Expected Output: 28 | /// // {YAML: YAML Ain't Markup Language} 29 | /// } 30 | /// ``` 31 | /// 32 | /// [1]: https://yaml.org/ 33 | 34 | export 'src/editor.dart'; 35 | export 'src/source_edit.dart'; 36 | export 'src/wrap.dart' show wrapAsYamlNode; 37 | -------------------------------------------------------------------------------- /test/src/modules/pipelines/domain/entities/pipeline_v1_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/slidy.dart'; 3 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline_v1.dart'; 4 | import 'package:test/test.dart'; 5 | import 'package:yaml/yaml.dart'; 6 | 7 | void main() { 8 | test('fromJson', () { 9 | final yaml = loadYaml(yamlText); 10 | final pipeline = PipelineV1.fromMap(yaml as Map, 11 | (pipeline, c, a) async => Right(SlidyProccess(result: 'result'))); 12 | expect(pipeline.name, 'Slidy Pipeline'); 13 | expect(pipeline.version, 'v1'); 14 | expect(pipeline.jobs.first.name, 'Named Command'); 15 | expect(pipeline.jobs.first.steps.first.id, 'First File Creation'); 16 | expect(pipeline.jobs.first.steps.first.generate?.moduleInjection?.type, 17 | ModuleInjectionV1Type.bind); 18 | }); 19 | } 20 | 21 | const yamlText = r''' 22 | name: Slidy Pipeline 23 | version: v1 24 | 25 | create_custom_file: #this is command name 26 | name: Named Command 27 | steps: 28 | - id: First File Creation 29 | generate: 30 | path: lib/app/path/file.dart 31 | file: | 32 | Generate file line 1 33 | generate file line 2 ${{ fileName | camelcase }} 34 | module_injection: 35 | type: bind 36 | value: Bind.singleton((i) => ${{ fileName | camelcase }}()) 37 | run: echo "Custom Command" 38 | commands: 39 | - flutter pub get 40 | - flutter pub run build_runner build --delete-conflicting-outputs 41 | '''; 42 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | publish_to: "none" # Remove this line if you wish to publish to pub.dev 4 | version: 1.0.0+1 5 | environment: 6 | sdk: ">=2.12.0 <3.0.0" 7 | dependencies: 8 | flutter_modular: ^4.3.0 9 | flutter_triple: ^1.2.5 10 | flutter: 11 | sdk: flutter 12 | cupertino_icons: ^1.0.2 13 | rx_notifier: ^1.1.0 14 | 15 | dev_dependencies: 16 | modular_test: ^1.0.1 17 | flutter_test: 18 | sdk: flutter 19 | triple_test: ^0.0.5 20 | flutter: 21 | uses-material-design: true 22 | scripts: 23 | mobx: fvm flutter pub get & fvm flutter pub run build_runner watch --delete-conflicting-outputs 24 | mobb: flutter pub get & flutter pub run build_runner build --delete-conflicting-outputs 25 | mobd: flutter pub get & flutter pub run build_runner build 26 | mobw: fvm flutter pub get & fvm flutter pub run build_runner watch 27 | build_apk: flutter pub get & flutter build apk -t lib/main_production.dart --release 28 | build_apk_qa: fvm flutter pub get & fvm flutter build apk --flavor qa -t lib/main_qa.dart --release 29 | build_apk_prod: fvm flutter pub get & fvm flutter build apk --flavor prod -t lib/main_production.dart --release 30 | build_ios: flutter pub get & flutter build ios -t lib/main_production.dart --flavor prod --release 31 | build_web: flutter pub get & flutter build web -t lib/main_production.dart --release 32 | localization: dart lib\app\commands\localization.dart 33 | test: flutter pub get 34 | test_error: flutter pub get2 35 | print: echo $name 36 | vars: 37 | name: jacob 38 | -------------------------------------------------------------------------------- /bin/templates/bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _blocTemplate = r''' 4 | bloc: | 5 | import 'package:bloc/bloc.dart'; 6 | 7 | enum $arg1 {increment} 8 | 9 | class $fileName|pascalcase extends Bloc<$arg1, int> { 10 | $fileName|pascalcase() : super(0); 11 | 12 | @override 13 | Stream mapEventToState($arg1 event) async* { 14 | switch (event) { 15 | case $arg1.increment: 16 | yield state + 1; 17 | break; 18 | } 19 | } 20 | } 21 | bloc_test: | 22 | import 'package:flutter_test/flutter_test.dart'; 23 | import 'package:bloc_test/bloc_test.dart'; 24 | $arg2 25 | 26 | void main() { 27 | 28 | blocTest<$arg1, int>('emits [1] when increment is added', 29 | build: () => $arg1(), 30 | act: (bloc) => bloc.add($arg3.increment), 31 | expect: () => [1], 32 | ); 33 | } 34 | cubit: | 35 | import 'package:bloc/bloc.dart'; 36 | 37 | class $fileName|pascalcase extends Cubit { 38 | $fileName|pascalcase() : super(0); 39 | 40 | @override 41 | void increment() => emit(state+1); 42 | 43 | } 44 | cubit_test: | 45 | import 'package:flutter_test/flutter_test.dart'; 46 | import 'package:bloc_test/bloc_test.dart'; 47 | $arg2 48 | 49 | void main() { 50 | 51 | blocTest<$arg1, int>('emits [1] when increment is added', 52 | build: () => $arg1(), 53 | act: (cubit) => cubit.increment(), 54 | expect: () => [1], 55 | ); 56 | } 57 | '''; 58 | 59 | final blocFile = CustomFile(yaml: _blocTemplate); 60 | -------------------------------------------------------------------------------- /bin/utils/template_file.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:recase/recase.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 6 | import 'package:yaml/yaml.dart'; 7 | 8 | class TemplateFile { 9 | late final File file; 10 | late final File fileTest; 11 | late final String fileName; 12 | late final fileNameWithUppeCase; 13 | final String packageName; 14 | late final import; 15 | 16 | TemplateFile._(String path, String type, this.packageName) { 17 | file = File('lib/app/$path$type.dart'); 18 | fileTest = File('test/app/$path${type}_test.dart'); 19 | fileName = ReCase(Uri.parse(path).pathSegments.last).camelCase; 20 | fileNameWithUppeCase = fileName[0].toUpperCase() + fileName.substring(1); 21 | import = 'import \'package:$packageName/app/$path$type.dart\';'; 22 | } 23 | 24 | static Future getInstance(String path, String? type) async { 25 | final pubspec = Slidy.instance.get(); 26 | return TemplateFile._(path, type == null ? '' : '_$type', 27 | (pubspec.getValue(['name']))?.value); 28 | } 29 | 30 | Future checkDependencyIsExist(String dependency, 31 | [bool isDev = false]) async { 32 | try { 33 | final dependenciesLine = isDev ? 'dev_dependencies' : 'dependencies'; 34 | final pubspec = Slidy.instance.get(); 35 | final map = (pubspec.getValue([dependenciesLine]))?.value as YamlMap; 36 | return map.containsKey(dependency); 37 | } catch (e) { 38 | return false; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_widget_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:slidy/slidy.dart'; 4 | 5 | import 'package:slidy/src/core/prints/prints.dart'; 6 | import '../../templates/widgets.dart'; 7 | import '../../utils/template_file.dart'; 8 | import '../command_base.dart'; 9 | 10 | class GenerateWidgetSubCommand extends CommandBase { 11 | @override 12 | final name = 'widget'; 13 | 14 | @override 15 | final description = 'Creates a Widget file'; 16 | 17 | GenerateWidgetSubCommand() { 18 | argParser.addFlag('notest', 19 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 20 | } 21 | 22 | @override 23 | FutureOr run() async { 24 | final templateFile = 25 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'widget'); 26 | 27 | var result = await Slidy.instance.template.createFile( 28 | info: TemplateInfo( 29 | yaml: widgetsFile, destiny: templateFile.file, key: 'widget')); 30 | execute(result); 31 | 32 | if (!argResults!['notest']) { 33 | result = await Slidy.instance.template.createFile( 34 | info: TemplateInfo( 35 | yaml: widgetsFile, 36 | destiny: templateFile.fileTest, 37 | key: 'page_test', 38 | args: [ 39 | templateFile.fileNameWithUppeCase + 'Widget', 40 | templateFile.import 41 | ])); 42 | execute(result); 43 | } 44 | } 45 | 46 | @override 47 | String? get invocationSuffix => null; 48 | } 49 | 50 | class GenerateWidgetAbbrSubCommand extends GenerateWidgetSubCommand { 51 | @override 52 | final name = 'w'; 53 | } 54 | -------------------------------------------------------------------------------- /test/src/modules/package_instalation/domain/usecases/install_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:slidy/src/core/entities/slidy_process.dart'; 4 | import 'package:slidy/src/core/errors/errors.dart'; 5 | import 'package:slidy/src/modules/package_instalation/domain/errors/errors.dart'; 6 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 7 | import 'package:slidy/src/modules/package_instalation/domain/repositories/package_instalation_repository.dart'; 8 | import 'package:slidy/src/modules/package_instalation/domain/usecases/install.dart'; 9 | import 'package:test/test.dart'; 10 | 11 | class PackageInstalationRepositoryMock extends Mock 12 | implements PackageInstalationRepository {} 13 | 14 | void main() { 15 | setUpAll(() { 16 | registerFallbackValue(PackageName('')); 17 | }); 18 | final service = PackageInstalationRepositoryMock(); 19 | 20 | final usecase = Install(service); 21 | 22 | test('should install package', () async { 23 | when(() => service.install(any())).thenAnswer((_) async => 24 | Right(SlidyProccess(result: 'ok'))); 25 | final result = await usecase(params: PackageName('package')); 26 | expect(result.isRight(), true); 27 | }); 28 | 29 | test('install package error', () async { 30 | when(() => service.install(any())).thenAnswer((_) async => 31 | Left(PackageInstalationError('Error'))); 32 | final result = await usecase(params: PackageName('package')); 33 | expect(result.fold(id, id), isA()); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /test/src/modules/package_instalation/domain/usecases/uninstall_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:slidy/src/core/entities/slidy_process.dart'; 4 | import 'package:slidy/src/core/errors/errors.dart'; 5 | import 'package:slidy/src/modules/package_instalation/domain/errors/errors.dart'; 6 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 7 | import 'package:slidy/src/modules/package_instalation/domain/repositories/package_instalation_repository.dart'; 8 | import 'package:slidy/src/modules/package_instalation/domain/usecases/uninstall.dart'; 9 | import 'package:test/test.dart'; 10 | 11 | class PackageInstalationRepositoryMock extends Mock 12 | implements PackageInstalationRepository {} 13 | 14 | void main() { 15 | setUpAll(() { 16 | registerFallbackValue(PackageName('')); 17 | }); 18 | final service = PackageInstalationRepositoryMock(); 19 | 20 | final usecase = Uninstall(service); 21 | 22 | test('should install package', () async { 23 | when(() => service.uninstall(any())).thenAnswer((_) async => 24 | Right(SlidyProccess(result: 'ok'))); 25 | final result = await usecase(params: PackageName('package')); 26 | expect(result.isRight(), true); 27 | }); 28 | 29 | test('install package error', () async { 30 | when(() => service.uninstall(any())).thenAnswer((_) async => 31 | Left(PackageInstalationError('Error'))); 32 | final result = await usecase(params: PackageName('package')); 33 | expect(result.fold(id, id), isA()); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | example 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/src/modules/pipelines/domain/usecases/pipeline_v1_usecase_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:slidy/slidy.dart'; 3 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline_v1.dart'; 4 | import 'package:slidy/src/modules/pipelines/domain/usecases/pipeline_v1_usecase.dart'; 5 | import 'package:test/test.dart'; 6 | import 'package:yaml/yaml.dart'; 7 | 8 | void main() async { 9 | final usecase = PipelineV1UsecaseImpl(); 10 | final pipeline = PipelineV1.fromMap(loadYaml(yamlText), usecase); 11 | test('should execute pipeline v1', () async { 12 | final result = await pipeline.call('print_text', []); 13 | expect(result.isRight(), true); 14 | final pipelineResult = result.fold(id, id); 15 | expect(pipelineResult, isA()); 16 | expect((pipelineResult as SlidyProccess).result, 'Slidy Pipeline'); 17 | }); 18 | } 19 | 20 | const yamlText = r''' 21 | name: Slidy Pipeline 22 | version: v1 23 | 24 | print_text: 25 | name: Name Print 26 | steps: 27 | - id: Print 1 28 | commands: 29 | - echo teste 1; 30 | - id: Print 2 31 | commands: 32 | - echo teste 2; 33 | 34 | create_custom_file: #this is command name 35 | name: Named Command 36 | steps: 37 | - id: First File Creation 38 | generate: 39 | path: lib/app/path/file.dart 40 | file: | 41 | Generate file line 1 42 | generate file line 2 ${{ fileName | camelcase }} 43 | module_injection: 44 | type: bind 45 | value: Bind.singleton((i) => ${{ fileName | camelcase }}()) 46 | run: echo "Custom Command" 47 | commands: 48 | - flutter pub get 49 | - flutter pub run build_runner build --delete-conflicting-outputs 50 | '''; 51 | -------------------------------------------------------------------------------- /bin/templates/widgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/models/custom_file.dart'; 2 | 3 | final _widgetsTemplate = r''' 4 | page: | 5 | import 'package:flutter/material.dart'; 6 | 7 | class $fileName|pascalcase extends StatefulWidget { 8 | final String title; 9 | const $fileName|pascalcase({Key? key, this.title = '$fileName|pascalcase'}) : super(key: key); 10 | @override 11 | $fileName|pascalcaseState createState() => $fileName|pascalcaseState(); 12 | } 13 | class $fileName|pascalcaseState extends State<$fileName|pascalcase> { 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar( 18 | title: Text(widget.title), 19 | ), 20 | body: Column( 21 | children: [], 22 | ), 23 | ); 24 | } 25 | } 26 | page_test: | 27 | $arg2 28 | import 'package:flutter_test/flutter_test.dart'; 29 | import 'package:modular_test/modular_test.dart'; 30 | 31 | main() { 32 | group('$arg1', () { 33 | testWidgets('has a title and message', (WidgetTester tester) async { 34 | await tester.pumpWidget(buildTestableWidget($arg1(title: 'T'))); 35 | final titleFinder = find.text('T'); 36 | expect(titleFinder, findsOneWidget); 37 | }); 38 | }); 39 | } 40 | widget: | 41 | import 'package:flutter/material.dart'; 42 | 43 | class $fileName|pascalcase extends StatelessWidget { 44 | final String title; 45 | const $fileName|pascalcase({Key? key, this.title = "$fileName|pascalcase"}) : super(key: key); 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Container(child: Text(title)); 50 | } 51 | } 52 | '''; 53 | 54 | final widgetsFile = CustomFile(yaml: _widgetsTemplate); 55 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | test: 10 | name: "${{ matrix.sdk-version }} / ${{ matrix.os }}" 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [windows-latest, ubuntu-latest, macos-latest] 15 | sdk-version: [stable] #, dev] 16 | include: 17 | - os: macOS-latest 18 | TARGET: macos 19 | - os: ubuntu-latest 20 | TARGET: linux 21 | - os: windows-latest 22 | TARGET: windows 23 | 24 | steps: 25 | - uses: actions/checkout@v1 26 | with: 27 | fetch-depth: 0 28 | 29 | - name: Setup Dart ${{ matrix.dart-version }} 30 | uses: DanTup/gh-actions/setup-dart@master 31 | with: 32 | channel: ${{ matrix.sdk-version }} 33 | 34 | - name: Install dependencies 35 | run: pub get 36 | 37 | - name: Run Test and Builder 38 | run: pub run build_runner test --delete-conflicting-outputs 39 | 40 | release: 41 | name: Release 42 | needs: test 43 | runs-on: ubuntu-latest 44 | env: 45 | PUB_CREDENTIALS: ${{ secrets.PUB_CREDENTIALS }} 46 | GITHUB_TOKEN: ${{ secrets.TOKEN_PUBLISH }} 47 | container: 48 | image: google/dart:latest 49 | steps: 50 | - uses: actions/checkout@v1 51 | with: 52 | fetch-depth: 0 53 | 54 | - name: Install dependencies 55 | run: pub get 56 | 57 | - name: Build Version Number 58 | run: pub run build_runner build --delete-conflicting-outputs 59 | 60 | - name: Deploy Github 61 | run: pub run grinder pkg-github-all 62 | 63 | - name: Deploy to Pub 64 | run: pub run grinder pkg-pub-deploy 65 | -------------------------------------------------------------------------------- /test/src/modules/package_instalation/main/package_instalation_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:http/http.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:slidy/di/injection.dart'; 4 | import 'package:slidy/src/core/entities/slidy_process.dart'; 5 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 6 | 7 | import 'package:slidy/src/main_module.dart'; 8 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 9 | import 'package:slidy/src/modules/package_instalation/main/package_instalation.dart'; 10 | import 'package:test/test.dart'; 11 | 12 | import '../external/external_json_result.dart'; 13 | 14 | class ClientMock extends Mock implements Client {} 15 | 16 | class YamlServiceMock extends Mock implements YamlService { 17 | @override 18 | void update(List path, String value) {} 19 | } 20 | 21 | void main() { 22 | setUpAll(() { 23 | registerFallbackValue(Uri()); 24 | }); 25 | 26 | StartAllModules(); 27 | final main = PackageInstalation(); 28 | final client = ClientMock(); 29 | final pubspecService = YamlServiceMock(); 30 | 31 | sl.changeRegister((i) => client); 32 | sl.changeRegister((i) => pubspecService); 33 | 34 | test('install', () async { 35 | when(() => client.get(any())) 36 | .thenAnswer((_) async => Response(jsonPackageResult, 200)); 37 | when(() => pubspecService.save()).thenAnswer((_) async => true); 38 | final result = await main.install(package: PackageName('package')); 39 | expect(result.isRight(), true); 40 | }); 41 | 42 | test('uninstall', () async { 43 | when(() => pubspecService.remove(any())).thenReturn(true); 44 | when(() => pubspecService.save()).thenAnswer((_) async => true); 45 | final result = await main.uninstall(package: PackageName('package')); 46 | expect(result.isRight(), true); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.example" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /test/src/modules/package_instalation/infra/repositories/package_install_repository_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:mocktail/mocktail.dart'; 2 | import 'package:slidy/src/core/entities/slidy_process.dart'; 3 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 4 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 5 | import 'package:slidy/src/modules/package_instalation/infra/datasources/get_package_version.dart'; 6 | import 'package:slidy/src/modules/package_instalation/infra/repositories/package_instalation_repository.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | class YamlServiceMock extends Mock implements YamlService { 10 | @override 11 | void update(List path, String value) {} 12 | } 13 | 14 | class GetPackageVersionMock extends Mock implements GetPackageVersion {} 15 | 16 | void main() { 17 | setUpAll(() {}); 18 | final pubspecService = YamlServiceMock(); 19 | final client = GetPackageVersionMock(); 20 | 21 | final service = 22 | PackageInstalationRepositoryImpl(pubspec: pubspecService, client: client); 23 | 24 | test('should install package', () async { 25 | when(() => pubspecService.save()).thenAnswer((_) async => true); 26 | when(() => client.fetch(any())).thenAnswer((_) async => '1.0.0'); 27 | final result = await service.install(PackageName('package')); 28 | expect(result.isRight(), true); 29 | }); 30 | 31 | test('should install package with version', () async { 32 | when(() => pubspecService.save()).thenAnswer((_) async => true); 33 | final result = await service.install(PackageName('package@1.0.2')); 34 | expect(result.isRight(), true); 35 | }); 36 | 37 | test('should uninstall package', () async { 38 | when(() => pubspecService.save()).thenAnswer((_) async => true); 39 | when(() => pubspecService.remove(any())).thenReturn(true); 40 | final result = await service.uninstall(PackageName('package')); 41 | expect(result.isRight(), true); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_page_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:slidy/slidy.dart'; 4 | 5 | import 'package:slidy/src/core/prints/prints.dart'; 6 | import '../../templates/widgets.dart'; 7 | import '../../utils/template_file.dart'; 8 | import '../command_base.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | 11 | class GeneratePageSubCommand extends CommandBase { 12 | @override 13 | final name = 'page'; 14 | @override 15 | final description = 'Creates a Page file'; 16 | 17 | GeneratePageSubCommand() { 18 | argParser.addFlag('notest', 19 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 20 | argParser.addOption('routing', 21 | abbr: 'r', help: 'Define routing path in parent module'); 22 | } 23 | 24 | @override 25 | FutureOr run() async { 26 | final templateFile = 27 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'page'); 28 | 29 | var result = await Slidy.instance.template.createFile( 30 | info: TemplateInfo( 31 | yaml: widgetsFile, destiny: templateFile.file, key: 'page')); 32 | execute(result); 33 | 34 | if (argResults!['routing'] != null) { 35 | await utils.injectParentModuleRouting( 36 | argResults!['routing'], 37 | '${templateFile.fileNameWithUppeCase}Page()', 38 | templateFile.import, 39 | templateFile.file.parent); 40 | } 41 | 42 | if (!argResults!['notest']) { 43 | result = await Slidy.instance.template.createFile( 44 | info: TemplateInfo( 45 | yaml: widgetsFile, 46 | destiny: templateFile.fileTest, 47 | key: 'page_test', 48 | args: [ 49 | templateFile.fileNameWithUppeCase + 'Page', 50 | templateFile.import 51 | ])); 52 | execute(result); 53 | } 54 | } 55 | 56 | @override 57 | String? get invocationSuffix => null; 58 | } 59 | 60 | class GeneratePageAbbrSubCommand extends GeneratePageSubCommand { 61 | @override 62 | final name = 'p'; 63 | } 64 | -------------------------------------------------------------------------------- /test/src/core/services/yaml_service_impl_include_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:slidy/src/core/services/yaml_service_impl.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | class FileMock extends Mock implements File { 9 | String savedFile = ''; 10 | 11 | final String stringYaml; 12 | 13 | FileMock(this.stringYaml); 14 | 15 | @override 16 | Future writeAsString(String contents, 17 | {FileMode mode = FileMode.write, 18 | Encoding encoding = utf8, 19 | bool flush = false}) async { 20 | savedFile = contents; 21 | return this; 22 | } 23 | 24 | @override 25 | Future readAsString({Encoding encoding = utf8}) async { 26 | return stringYaml; 27 | } 28 | 29 | @override 30 | String readAsStringSync({Encoding encoding = utf8}) { 31 | return stringYaml; 32 | } 33 | } 34 | 35 | void main() { 36 | test('include one', () async { 37 | final file = FileMock(stringYaml); 38 | final service = await YamlServiceImpl( 39 | yaml: file, 40 | getYamlFileParam: (file, path) { 41 | return FileMock(otherYaml); 42 | }).readAllIncludes(); 43 | 44 | final node = service.getValue(['name']); 45 | expect(node?.value, 'slidy'); 46 | }); 47 | test('include list', () async { 48 | final file = FileMock(stringYamlList); 49 | var count = 0; 50 | final service = await YamlServiceImpl( 51 | yaml: file, 52 | getYamlFileParam: (file, path) { 53 | if (count == 0) { 54 | count++; 55 | return FileMock(otherYaml); 56 | } 57 | return FileMock(otherYaml2); 58 | }).readAllIncludes(); 59 | 60 | final node = service.getValue(['name']); 61 | expect(node?.value, 'slidy'); 62 | final node2 = service.getValue(['command']); 63 | expect(node2?.value, 'slidy-command'); 64 | }); 65 | } 66 | 67 | const stringYaml = ''' 68 | include: folder/other.yaml 69 | '''; 70 | const stringYamlList = ''' 71 | include: 72 | - folder/other.yaml 73 | - folder/other2.yaml 74 | '''; 75 | 76 | const otherYaml = ''' 77 | name: slidy 78 | '''; 79 | const otherYaml2 = ''' 80 | command: slidy-command 81 | '''; 82 | -------------------------------------------------------------------------------- /lib/src/modules/template_creator/domain/usecases/create.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:recase/recase.dart'; 3 | import 'package:slidy/src/core/services/yaml_service_impl.dart'; 4 | import 'package:slidy/src/modules/template_creator/domain/errors/errors.dart'; 5 | import 'package:slidy/src/modules/template_creator/domain/models/template_info.dart'; 6 | import 'package:yaml/yaml.dart'; 7 | import '../../../../core/entities/slidy_process.dart'; 8 | import '../../../../core/errors/errors.dart'; 9 | import '../../../../core/interfaces/usecase.dart'; 10 | 11 | class Create implements UseCase { 12 | @override 13 | Future> call( 14 | {required TemplateInfo params}) async { 15 | final fileName = 16 | params.destiny.uri.pathSegments.last.replaceFirst('.dart', ''); 17 | if (await params.destiny.exists()) { 18 | return Left(TemplateCreatorError('File $fileName exists')); 19 | } 20 | if (!await params.yaml.exists()) { 21 | return Left(TemplateCreatorError('YAML Not Exist')); 22 | } 23 | 24 | await params.destiny.create(recursive: true); 25 | 26 | final service = YamlServiceImpl(yaml: params.yaml); 27 | final node = service.getValue([params.key]); 28 | if (node is YamlScalar) { 29 | var list = node.value.toString().trim().split('/n'); 30 | list = list 31 | .map((e) => _processLine(e, params.args, fileName)) 32 | .toList(); 33 | await params.destiny.writeAsString(list.join('\n')); 34 | return Right(SlidyProccess(result: '$fileName created')); 35 | } else { 36 | return Left(TemplateCreatorError('Incorrect YAML')); 37 | } 38 | } 39 | 40 | String _processLine(String value, List args, String fileName) { 41 | value = 42 | value.replaceAll('\$fileName|camelcase', ReCase(fileName).camelCase); 43 | value = 44 | value.replaceAll('\$fileName|pascalcase', ReCase(fileName).pascalCase); 45 | value = value.replaceAll('\$fileName', fileName); 46 | 47 | if (args.isEmpty) return value; 48 | for (var i = 0; i < args.length; i++) { 49 | final key = '\$arg${i + 1}'; 50 | value = value.replaceAll(key, args[i]); 51 | } 52 | return value; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/src/modules/pipelines/domain/usecases/pipeline_execute.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:dartz/dartz.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | import 'package:slidy/src/core/interfaces/usecase.dart'; 6 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline.dart'; 7 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline_v1.dart'; 8 | import 'package:slidy/src/modules/pipelines/domain/errors/errors.dart'; 9 | import 'package:slidy/src/modules/pipelines/domain/services/yaml_to_map_service.dart'; 10 | import 'package:slidy/src/modules/pipelines/domain/usecases/pipeline_v1_usecase.dart'; 11 | 12 | class PipelineExecuteImpl 13 | implements UseCase { 14 | final PipelineV1Usecase v1; 15 | final YamlToMapService yamlToMapService; 16 | 17 | late final mapPipelineByVersion = { 18 | 'v1': (map) => PipelineV1.fromMap(map, v1) 19 | }; 20 | 21 | PipelineExecuteImpl({required this.v1, required this.yamlToMapService}); 22 | @override 23 | Future> call( 24 | {required PipelineParams params}) async { 25 | final yamlToMapResult = await yamlToMapService.convert(params.yamlPath); 26 | return yamlToMapResult 27 | .bind(_bindServiceResult) 28 | .asyncBind((pipeline) { 29 | return pipeline(params.command, params.args); 30 | }); 31 | } 32 | 33 | Either _bindServiceResult(Map map) { 34 | if (!map.containsKey('version')) { 35 | return left(PipelineError('Version \"${map['version']}\" not supported')); 36 | } else if (!mapPipelineByVersion.containsKey(map['version'])) { 37 | return left(PipelineError('Version \"${map['version']}\" not supported')); 38 | } 39 | return right(mapPipelineByVersion[map['version']]!.call(map)); 40 | } 41 | } 42 | 43 | extension EitherExtension on Either { 44 | Future> asyncBind( 45 | Future> Function(R) asyncF) async { 46 | return fold((l) async => left(l), asyncF); 47 | } 48 | } 49 | 50 | class PipelineParams { 51 | final String yamlPath; 52 | final String command; 53 | final List args; 54 | 55 | PipelineParams( 56 | {required this.yamlPath, required this.command, this.args = const []}); 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/modules/package_instalation/infra/repositories/package_instalation_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 2 | import 'package:slidy/src/modules/package_instalation/domain/errors/errors.dart'; 3 | import 'package:slidy/src/modules/package_instalation/domain/models/package_name.dart'; 4 | import 'package:slidy/src/core/errors/errors.dart'; 5 | import 'package:slidy/src/core/entities/slidy_process.dart'; 6 | import 'package:dartz/dartz.dart'; 7 | import 'package:slidy/src/modules/package_instalation/domain/repositories/package_instalation_repository.dart'; 8 | import 'package:slidy/src/modules/package_instalation/infra/datasources/get_package_version.dart'; 9 | 10 | class PackageInstalationRepositoryImpl implements PackageInstalationRepository { 11 | final YamlService pubspec; 12 | final GetPackageVersion client; 13 | 14 | PackageInstalationRepositoryImpl( 15 | {required this.pubspec, required this.client}); 16 | 17 | @override 18 | Future> install(PackageName package) async { 19 | try { 20 | if (package.name.contains('@')) { 21 | final elements = package.name.split('@'); 22 | package = package.copyWith( 23 | name: elements[0].trim(), version: elements[1].trim()); 24 | } else { 25 | package = 26 | package.copyWith(version: '^${await client.fetch(package.name)}'); 27 | } 28 | pubspec.update( 29 | [package.isDev ? 'dev_dependencies' : 'dependencies', package.name], 30 | package.version); 31 | final result = await pubspec.save(); 32 | return Right(SlidyProccess( 33 | result: result ? 'Added ${package.name}: ${package.version}' : '')); 34 | } on SlidyError catch (e) { 35 | return Left(e); 36 | } 37 | } 38 | 39 | @override 40 | Future> uninstall( 41 | PackageName package) async { 42 | try { 43 | final isRemoved = pubspec.remove( 44 | [package.isDev ? 'dev_dependencies' : 'dependencies', package.name]); 45 | if (!isRemoved) { 46 | throw PackageInstalationError('Dependency not exist'); 47 | } 48 | final result = await pubspec.save(); 49 | return Right( 50 | SlidyProccess(result: result ? 'Removed ${package.name}' : '')); 51 | } on SlidyError catch (e) { 52 | return Left(e); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /bin/commands/generate_command.dart: -------------------------------------------------------------------------------- 1 | import 'command_base.dart'; 2 | import 'sub_command/clean_dart/generate_data_source_sub_command.dart'; 3 | import 'sub_command/clean_dart/generate_use_case_sub_command.dart'; 4 | import 'sub_command/generate_mobx_sub_command.dart'; 5 | import 'sub_command/generate_bloc_sub_command.dart'; 6 | import 'sub_command/generate_cubit_sub_command.dart'; 7 | import 'sub_command/generate_module_sub_command.dart'; 8 | import 'sub_command/generate_rx_notifier_sub_command.dart'; 9 | import 'sub_command/generate_repository_sub_command.dart'; 10 | import 'sub_command/generate_page_sub_command.dart'; 11 | import 'sub_command/generate_service_sub_command.dart'; 12 | import 'sub_command/generate_triple_sub_command.dart'; 13 | import 'sub_command/generate_widget_sub_command.dart'; 14 | 15 | class GenerateCommand extends CommandBase { 16 | @override 17 | final name = 'generate'; 18 | @override 19 | final description = 20 | 'Creates a module, page, widget or repository according to the option.'; 21 | 22 | GenerateCommand() { 23 | addSubcommand(GenerateModuleSubCommand()); 24 | addSubcommand(GenerateModuleAbbrSubCommand()); 25 | addSubcommand(GenerateTripleSubCommand()); 26 | addSubcommand(GenerateTripleAbbrSubCommand()); 27 | addSubcommand(GenerateMobxSubCommand()); 28 | addSubcommand(GenerateMobxAbbrSubCommand()); 29 | addSubcommand(GenerateBlocSubCommand()); 30 | addSubcommand(GenerateBlocAbbrSubCommand()); 31 | addSubcommand(GenerateRxNotifierSubCommand()); 32 | addSubcommand(GenerateRxNotifierAbbrSubCommand()); 33 | addSubcommand(GenerateRepositorySubCommand()); 34 | addSubcommand(GenerateRepositoryAbbrSubCommand()); 35 | addSubcommand(GenerateServiceSubCommand()); 36 | addSubcommand(GenerateServiceAbbrSubCommand()); 37 | addSubcommand(GenerateCubitSubCommand()); 38 | addSubcommand(GenerateCubitAbbrSubCommand()); 39 | addSubcommand(GeneratePageSubCommand()); 40 | addSubcommand(GeneratePageAbbrSubCommand()); 41 | addSubcommand(GenerateWidgetSubCommand()); 42 | addSubcommand(GenerateWidgetAbbrSubCommand()); 43 | addSubcommand(GenerateUseCaseSubCommand()); 44 | addSubcommand(GenerateUseCaseAbbrSubCommand()); 45 | addSubcommand(GenerateDataSourceSubCommand()); 46 | addSubcommand(GenerateDataSourceAbbrSubCommand()); 47 | } 48 | 49 | @override 50 | String? get invocationSuffix => null; 51 | } 52 | 53 | class GenerateCommandAbbr extends GenerateCommand { 54 | @override 55 | final name = 'g'; 56 | } 57 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/src/core/services/yaml_service_impl.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:yaml/yaml.dart'; 4 | 5 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 6 | import 'package:slidy/src/modules/yaml_edit/yaml_edit.dart'; 7 | 8 | class YamlServiceImpl implements YamlService { 9 | final File yaml; 10 | late final YamlEditor yamlEditor; 11 | late final File Function(File yaml, String path) getYamlFile; 12 | 13 | YamlServiceImpl({ 14 | required this.yaml, 15 | YamlEditor? customyamlEditor, 16 | File Function(File yaml, String path)? getYamlFileParam, 17 | }) { 18 | if (customyamlEditor == null) { 19 | yamlEditor = YamlEditor(yaml.readAsStringSync()); 20 | } else { 21 | yamlEditor = customyamlEditor; 22 | } 23 | 24 | getYamlFile = getYamlFileParam ?? 25 | (File yaml, String path) { 26 | if (path.startsWith('/')) { 27 | return File(path); 28 | } else { 29 | return File(yaml.parent.path + '/$path'); 30 | } 31 | }; 32 | } 33 | 34 | @override 35 | bool remove(List path) { 36 | try { 37 | yamlEditor.remove(path); 38 | return true; 39 | } catch (e) { 40 | return false; 41 | } 42 | } 43 | 44 | @override 45 | void update(List path, String value) { 46 | yamlEditor.update(path, value); 47 | } 48 | 49 | @override 50 | YamlNode? getValue(List path) { 51 | return yamlEditor.parseAt(path, orElse: () => null); 52 | } 53 | 54 | @override 55 | Future save() async { 56 | try { 57 | await yaml.writeAsString(yamlEditor.toString()); 58 | return true; 59 | } catch (e) { 60 | return false; 61 | } 62 | } 63 | 64 | @override 65 | Future readAllIncludes() async { 66 | final node = getValue(['include']); 67 | if (node is YamlScalar) { 68 | final file = getYamlFile(yaml, node.value); 69 | final newYaml = 70 | yamlEditor.toString() + '\n' + (await file.readAsString()); 71 | return YamlServiceImpl( 72 | yaml: File(''), customyamlEditor: YamlEditor(newYaml)); 73 | } else if (node is YamlList) { 74 | var newYaml = yamlEditor.toString(); 75 | for (var path in node.value) { 76 | final file = getYamlFile(yaml, path); 77 | newYaml += '\n' + (await file.readAsString()); 78 | } 79 | return YamlServiceImpl( 80 | yaml: File(''), customyamlEditor: YamlEditor(newYaml)); 81 | } 82 | 83 | return this; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/src/modules/pipelines/domain/usecases/pipeline_execute_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:slidy/slidy.dart'; 4 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline.dart'; 5 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline_v1.dart'; 6 | import 'package:slidy/src/modules/pipelines/domain/services/yaml_to_map_service.dart'; 7 | import 'package:slidy/src/modules/pipelines/domain/usecases/pipeline_execute.dart'; 8 | import 'package:slidy/src/modules/pipelines/domain/usecases/pipeline_v1_usecase.dart'; 9 | import 'package:test/test.dart'; 10 | import 'package:yaml/yaml.dart'; 11 | 12 | class YamlToMapServiceMock extends Mock implements YamlToMapService {} 13 | 14 | class PipelineV1UsecaseMock extends Mock implements PipelineV1Usecase {} 15 | 16 | void main() async { 17 | final yamlToMapService = YamlToMapServiceMock(); 18 | final pipelineV1Usecase = PipelineV1UsecaseMock(); 19 | setUpAll(() { 20 | registerFallbackValue(PipelineV1.fromMap( 21 | loadYaml(yamlText), 22 | (pipeline, command, args) => 23 | pipelineV1Usecase.call(pipeline, command, args))); 24 | }); 25 | final usecase = PipelineExecuteImpl( 26 | v1: pipelineV1Usecase, yamlToMapService: yamlToMapService); 27 | test('should execute pipeline v1', () async { 28 | when(() => yamlToMapService.convert(any())) 29 | .thenAnswer((_) async => Right(loadYaml(yamlText))); 30 | when(() => pipelineV1Usecase.call(any(), any(), any())) 31 | .thenAnswer((_) async => Right(SlidyProccess(result: 'ok ok!'))); 32 | 33 | final result = await usecase.call( 34 | params: PipelineParams(yamlPath: '/path/yaml', command: 'command')); 35 | expect(result.isRight(), true); 36 | final pipelineResult = result.fold(id, id); 37 | expect(pipelineResult, isA()); 38 | expect((pipelineResult as SlidyProccess).result, 'ok ok!'); 39 | }); 40 | } 41 | 42 | const yamlText = r''' 43 | name: Slidy Pipeline 44 | version: v1 45 | 46 | create_custom_file: #this is command name 47 | name: Named Command 48 | steps: 49 | - id: First File Creation 50 | generate: 51 | path: lib/app/path/file.dart 52 | file: | 53 | Generate file line 1 54 | generate file line 2 ${{ fileName | camelcase }} 55 | module_injection: 56 | type: bind 57 | value: Bind.singleton((i) => ${{ fileName | camelcase }}()) 58 | run: echo "Custom Command" 59 | commands: 60 | - flutter pub get 61 | - flutter pub run build_runner build --delete-conflicting-outputs 62 | '''; 63 | -------------------------------------------------------------------------------- /test/src/core/services/yaml_service_impl_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 6 | import 'package:slidy/src/core/services/yaml_service_impl.dart'; 7 | import 'package:test/test.dart'; 8 | import 'package:yaml/yaml.dart'; 9 | 10 | class FileMock extends Mock implements File { 11 | String savedFile = ''; 12 | 13 | @override 14 | Future writeAsString(String contents, 15 | {FileMode mode = FileMode.write, 16 | Encoding encoding = utf8, 17 | bool flush = false}) async { 18 | savedFile = contents; 19 | return this; 20 | } 21 | 22 | @override 23 | Future readAsString({Encoding encoding = utf8}) async { 24 | return stringYaml; 25 | } 26 | 27 | @override 28 | String readAsStringSync({Encoding encoding = utf8}) { 29 | return stringYaml; 30 | } 31 | } 32 | 33 | void main() { 34 | test('update', () async { 35 | final file = FileMock(); 36 | final service = YamlServiceImpl(yaml: file); 37 | service.update(['dependencies', 'dart_console'], '2.0.0'); 38 | await service.save(); 39 | expect(loadYaml(file.savedFile)['dependencies']['dart_console'], '2.0.0'); 40 | }); 41 | test('remove', () async { 42 | final file = FileMock(); 43 | final service = YamlServiceImpl(yaml: file); 44 | service.remove(['dependencies', 'dart_console']); 45 | await service.save(); 46 | expect( 47 | (loadYaml(file.savedFile)['dependencies'] as Map) 48 | .containsKey('dart_console'), 49 | false); 50 | }); 51 | test('getValue', () async { 52 | final file = FileMock(); 53 | final service = YamlServiceImpl(yaml: file); 54 | final node = service.getValue(['dependencies', 'dart_console']); 55 | expect(node?.value, '^1.0.0'); 56 | }); 57 | } 58 | 59 | const stringYaml = ''' 60 | name: slidy 61 | description: CLI package manager and template for Flutter. Generate Modules, Pages, Widgets, BLoCs, MobX, Triple and more. 62 | version: 3.0.2 63 | homepage: https://github.com/Flutterando/slidy 64 | 65 | environment: 66 | sdk: '>=2.12.0 <3.0.0' 67 | 68 | dependencies: 69 | dart_console: ^1.0.0 70 | either_dart: ^0.1.0-nullsafety.1 71 | http: ^0.13.0 72 | args: ^2.0.0 73 | ansicolor: ^2.0.0-nullsafety.0 74 | recase: ^4.0.0-nullsafety.0 75 | file: ^6.1.0 76 | yaml: ^3.1.0 77 | collection: ^1.14.11 78 | meta: ^1.1.8 79 | source_span: ^1.7.0 80 | 81 | dev_dependencies: 82 | test: ^1.16.0-nullsafety.17 83 | mocktail: ^0.1.1 84 | 85 | # dependency_overrides: 86 | # args: '2.0.0-nullsafety.0' 87 | 88 | 89 | executables: 90 | slidy: slidy 91 | 92 | 93 | '''; 94 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "slidy version", 9 | "request": "launch", 10 | "program": "../bin/slidy.dart", 11 | "cwd": "example", 12 | "type": "dart", 13 | "args": ["--version"] 14 | }, { 15 | "name": "slidy install", 16 | "request": "launch", 17 | "program": "../bin/slidy.dart", 18 | "cwd": "example", 19 | "type": "dart", 20 | "args": ["install", "triple"] 21 | }, 22 | { 23 | "name": "slidy install error", 24 | "request": "launch", 25 | "program": "../bin/slidy.dart", 26 | "cwd": "example", 27 | "type": "dart", 28 | "args": ["install", "tripple"] 29 | }, 30 | { 31 | "name": "slidy uninstall", 32 | "request": "launch", 33 | "program": "../bin/slidy.dart", 34 | "cwd": "example", 35 | "type": "dart", 36 | "args": ["uninstall", "triple"] 37 | }, 38 | { 39 | "name": "slidy start", 40 | "request": "launch", 41 | "program": "../bin/slidy.dart", 42 | "cwd": "example", 43 | "console": "terminal", 44 | "type": "dart", 45 | "args": ["start", "-f"] 46 | }, 47 | { 48 | "name": "slidy generate m 1", 49 | "request": "launch", 50 | "program": "../bin/slidy.dart", 51 | "cwd": "example", 52 | "type": "dart", 53 | "args": ["g", "m","home"] 54 | }, 55 | { 56 | "name": "slidy generate m 2", 57 | "request": "launch", 58 | "program": "../bin/slidy.dart", 59 | "cwd": "example", 60 | "type": "dart", 61 | "args": ["g", "m","home/internal"] 62 | },{ 63 | "name": "slidy generate triple", 64 | "request": "launch", 65 | "program": "../bin/slidy.dart", 66 | "cwd": "example", 67 | "type": "dart", 68 | "args": ["g", "triple","home/home"] 69 | 70 | },{ 71 | "name": "slidy run test", 72 | "request": "launch", 73 | "program": "/Users/jacobmoura/Projects/slidy/bin/slidy.dart", 74 | "cwd": "/Users/jacobmoura/Projects/triple_pattern/examples/search", 75 | "type": "dart", 76 | "args": ["uninstall", "abcdd"] 77 | } 78 | ] 79 | } -------------------------------------------------------------------------------- /bin/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:args/args.dart'; 4 | import 'package:args/command_runner.dart'; 5 | import 'package:io/io.dart'; 6 | import 'package:slidy/src/version.dart'; 7 | 8 | import 'commands/generate_command.dart'; 9 | import 'commands/install_command.dart'; 10 | import 'commands/run_command.dart'; 11 | import 'commands/start_command.dart'; 12 | import 'commands/uninstall_command.dart'; 13 | import 'commands/upgrade_command.dart'; 14 | 15 | Future main(List arguments) async { 16 | final runner = configureCommand(arguments); 17 | 18 | var hasCommand = runner.commands.keys.any((x) => arguments.contains(x)); 19 | 20 | if (hasCommand) { 21 | try { 22 | await executeCommand(runner, arguments); 23 | exit(ExitCode.success.code); 24 | } on UsageException catch (error) { 25 | print(error); 26 | exit(ExitCode.ioError.code); 27 | } 28 | } else { 29 | var parser = ArgParser(); 30 | parser = runner.argParser; 31 | var results = parser.parse(arguments); 32 | executeOptions(results, arguments, runner); 33 | } 34 | } 35 | 36 | void executeOptions( 37 | ArgResults results, List arguments, CommandRunner runner) { 38 | if (results.wasParsed('help') || arguments.isEmpty) { 39 | print(runner.usage); 40 | } else if (results.wasParsed('version')) { 41 | version(packageVersion); 42 | } else { 43 | print('Command not found!\n'); 44 | print(runner.usage); 45 | } 46 | } 47 | 48 | Future executeCommand(CommandRunner runner, List arguments) { 49 | return runner.run(arguments); 50 | } 51 | 52 | CommandRunner configureCommand(List arguments) { 53 | var runner = 54 | CommandRunner('slidy', 'CLI package manager and template for Flutter.') 55 | ..addCommand(InstallCommand()) 56 | ..addCommand(InstallCommandAbbr()) 57 | ..addCommand(UninstallCommand()) 58 | ..addCommand(StartCommand()) 59 | ..addCommand(GenerateCommand()) 60 | ..addCommand(GenerateCommandAbbr()) 61 | ..addCommand(RunCommand()); 62 | // ..addCommand(UpgradeCommand()); 63 | 64 | runner.argParser.addFlag('version', abbr: 'v', negatable: false); 65 | return runner; 66 | } 67 | 68 | void version(String version) async { 69 | //String version = await getVersion(); 70 | //String version = '0.0.13'; 71 | print(''' 72 | ███████╗██╗ ██╗██████╗ ██╗ ██╗ ██████╗██╗ ██╗ 73 | ██╔════╝██║ ██║██╔══██╗╚██╗ ██╔╝ ██╔════╝██║ ██║ 74 | ███████╗██║ ██║██║ ██║ ╚████╔╝ ██║ ██║ ██║ 75 | ╚════██║██║ ██║██║ ██║ ╚██╔╝ ██║ ██║ ██║ 76 | ███████║███████╗██║██████╔╝ ██║ ╚██████╗███████╗██║ 77 | ╚══════╝╚══════╝╚═╝╚═════╝ ╚═╝ ╚═════╝╚══════╝╚═╝ 78 | '''); 79 | print('CLI package manager and template for Flutter'); 80 | print(''); 81 | print('Slidy version: $version'); 82 | } 83 | -------------------------------------------------------------------------------- /bin/commands/sub_command/clean_dart/generate_use_case_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../../templates/use_case.dart'; 8 | import '../../../utils/template_file.dart'; 9 | import '../../../utils/utils.dart' as utils; 10 | import '../../command_base.dart'; 11 | import '../../install_command.dart'; 12 | 13 | class GenerateUseCaseSubCommand extends CommandBase { 14 | @override 15 | final name = 'usecase'; 16 | @override 17 | final description = 'Creates a Use Case file'; 18 | 19 | GenerateUseCaseSubCommand() { 20 | argParser.addFlag('notest', 21 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 22 | argParser.addOption('bind', 23 | abbr: 'u', 24 | allowed: [ 25 | 'singleton', 26 | 'lazy-singleton', 27 | 'factory', 28 | ], 29 | defaultsTo: 'lazy-singleton', 30 | allowedHelp: { 31 | 'singleton': 'Object persist while module exists', 32 | 'lazy-singleton': 33 | 'Object persist while module exists, but only after being called first for the fist time', 34 | 'factory': 'A new object is created each time it is called.', 35 | }, 36 | help: 'Define type injection in parent module'); 37 | } 38 | 39 | @override 40 | FutureOr run() async { 41 | final templateFile = 42 | await TemplateFile.getInstance(argResults?.rest.single ?? '', null); 43 | 44 | if (!await templateFile.checkDependencyIsExist('dartz')) { 45 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 46 | await command.run(['install', 'dartz@0.10.0-nullsafety.1 ']); 47 | } 48 | 49 | var result = await Slidy.instance.template.createFile( 50 | info: TemplateInfo( 51 | yaml: use_case, 52 | destiny: templateFile.file, 53 | key: 'use_case', 54 | args: [templateFile.fileNameWithUppeCase + 'Event'])); 55 | execute(result); 56 | if (result.isRight()) { 57 | await utils.injectParentModule( 58 | argResults!['bind'], 59 | '${templateFile.fileNameWithUppeCase}()', 60 | templateFile.import, 61 | templateFile.file.parent); 62 | } 63 | 64 | if (!argResults!['notest']) { 65 | result = await Slidy.instance.template.createFile( 66 | info: TemplateInfo( 67 | yaml: use_case, 68 | destiny: templateFile.fileTest, 69 | key: 'use_case_test', 70 | args: [ 71 | templateFile.fileNameWithUppeCase, 72 | templateFile.import, 73 | templateFile.fileNameWithUppeCase 74 | ])); 75 | execute(result); 76 | } 77 | } 78 | 79 | @override 80 | String? get invocationSuffix => null; 81 | } 82 | 83 | class GenerateUseCaseAbbrSubCommand extends GenerateUseCaseSubCommand { 84 | @override 85 | final name = 'u'; 86 | } 87 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_triple_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/triple.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | import '../install_command.dart'; 12 | 13 | class GenerateTripleSubCommand extends CommandBase { 14 | @override 15 | final name = 'triple'; 16 | @override 17 | final description = 'Creates a Triple Store'; 18 | 19 | GenerateTripleSubCommand() { 20 | argParser.addFlag('notest', 21 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 22 | argParser.addFlag('page', 23 | abbr: 'p', negatable: true, help: 'Create a Page file'); 24 | argParser.addOption('bind', 25 | abbr: 'b', 26 | allowed: [ 27 | 'singleton', 28 | 'lazy-singleton', 29 | 'factory', 30 | ], 31 | defaultsTo: 'lazy-singleton', 32 | allowedHelp: { 33 | 'singleton': 'Object persist while module exists', 34 | 'lazy-singleton': 35 | 'Object persist while module exists, but only after being called first for the fist time', 36 | 'factory': 'A new object is created each time it is called.', 37 | }, 38 | help: 'Define type injection in parent module'); 39 | } 40 | 41 | @override 42 | FutureOr run() async { 43 | final templateFile = 44 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'store'); 45 | 46 | if (!await templateFile.checkDependencyIsExist('flutter_triple')) { 47 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 48 | await command.run(['install', 'flutter_triple']); 49 | await command.run(['install', 'triple_test', '--dev']); 50 | } 51 | 52 | var result = await Slidy.instance.template.createFile( 53 | info: TemplateInfo( 54 | yaml: tripleFile, destiny: templateFile.file, key: 'triple')); 55 | execute(result); 56 | if (result.isRight()) { 57 | if (argResults!['page'] == true) { 58 | await utils.addedInjectionInPage( 59 | templateFile: templateFile, 60 | pathCommand: argResults!.rest.single, 61 | noTest: !argResults!['notest'], 62 | type: 'Store'); 63 | } 64 | await utils.injectParentModule( 65 | argResults!['bind'], 66 | '${templateFile.fileNameWithUppeCase}Store()', 67 | templateFile.import, 68 | templateFile.file.parent); 69 | } 70 | 71 | if (!argResults!['notest']) { 72 | result = await Slidy.instance.template.createFile( 73 | info: TemplateInfo( 74 | yaml: tripleFile, 75 | destiny: templateFile.fileTest, 76 | key: 'triple_test', 77 | args: [ 78 | templateFile.fileNameWithUppeCase + 'Store', 79 | templateFile.import 80 | ])); 81 | execute(result); 82 | } 83 | } 84 | 85 | @override 86 | String? get invocationSuffix => null; 87 | } 88 | 89 | class GenerateTripleAbbrSubCommand extends GenerateTripleSubCommand { 90 | @override 91 | final name = 't'; 92 | } 93 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_rx_notifier_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/rx_notifier.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | import '../install_command.dart'; 12 | 13 | class GenerateRxNotifierSubCommand extends CommandBase { 14 | @override 15 | final name = 'rx_notifier'; 16 | @override 17 | final description = 'Creates a RxNotifier Controller'; 18 | 19 | GenerateRxNotifierSubCommand() { 20 | argParser.addFlag('notest', 21 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 22 | argParser.addFlag('page', 23 | abbr: 'p', negatable: true, help: 'Create a Page file'); 24 | argParser.addOption('bind', 25 | abbr: 'b', 26 | allowed: [ 27 | 'singleton', 28 | 'lazy-singleton', 29 | 'factory', 30 | ], 31 | defaultsTo: 'lazy-singleton', 32 | allowedHelp: { 33 | 'singleton': 'Object persist while module exists', 34 | 'lazy-singleton': 35 | 'Object persist while module exists, but only after being called first for the fist time', 36 | 'factory': 'A new object is created each time it is called.', 37 | }, 38 | help: 'Define type injection in parent module'); 39 | } 40 | 41 | @override 42 | FutureOr run() async { 43 | final templateFile = await TemplateFile.getInstance( 44 | argResults?.rest.single ?? '', 'controller'); 45 | 46 | if (!await templateFile.checkDependencyIsExist('rx_notifier')) { 47 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 48 | await command.run(['install', 'rx_notifier']); 49 | } 50 | 51 | var result = await Slidy.instance.template.createFile( 52 | info: TemplateInfo( 53 | yaml: rxnotifierFile, 54 | destiny: templateFile.file, 55 | key: 'rx_notifier')); 56 | execute(result); 57 | if (result.isRight()) { 58 | if (argResults!['page'] == true) { 59 | await utils.addedInjectionInPage( 60 | templateFile: templateFile, 61 | pathCommand: argResults!.rest.single, 62 | noTest: !argResults!['notest'], 63 | type: 'Controller'); 64 | } 65 | await utils.injectParentModule( 66 | argResults!['bind'], 67 | '${templateFile.fileNameWithUppeCase}Controller()', 68 | templateFile.import, 69 | templateFile.file.parent); 70 | } 71 | 72 | if (!argResults!['notest']) { 73 | result = await Slidy.instance.template.createFile( 74 | info: TemplateInfo( 75 | yaml: rxnotifierFile, 76 | destiny: templateFile.fileTest, 77 | key: 'rx_notifier_test', 78 | args: [ 79 | templateFile.fileNameWithUppeCase + 'Controller', 80 | templateFile.import 81 | ])); 82 | execute(result); 83 | } 84 | } 85 | 86 | @override 87 | String? get invocationSuffix => null; 88 | } 89 | 90 | class GenerateRxNotifierAbbrSubCommand extends GenerateRxNotifierSubCommand { 91 | @override 92 | final name = 'rx'; 93 | } 94 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_module_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import '../../utils/utils.dart' as utils; 3 | 4 | import 'package:args/command_runner.dart'; 5 | import 'package:slidy/slidy.dart'; 6 | import 'package:slidy/src/core/interfaces/yaml_service.dart'; 7 | 8 | import 'package:slidy/src/core/prints/prints.dart'; 9 | import '../../templates/module.dart'; 10 | import '../../utils/template_file.dart'; 11 | import '../command_base.dart'; 12 | import '../generate_command.dart'; 13 | 14 | class GenerateModuleSubCommand extends CommandBase { 15 | @override 16 | final name = 'module'; 17 | 18 | @override 19 | final description = 'Creates a module'; 20 | 21 | GenerateModuleSubCommand() { 22 | argParser.addFlag('notest', 23 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 24 | argParser.addFlag('complete', 25 | abbr: 'c', 26 | negatable: true, 27 | help: 28 | 'Creates a module with Page and Controller/Store files (Triple, MobX, BLoC, Cubit...)'); 29 | } 30 | 31 | @override 32 | FutureOr run() async { 33 | if (argResults?.rest.isNotEmpty == false) { 34 | throw UsageException('value not passed for a module command', usage); 35 | } 36 | 37 | var templateFile = 38 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'module'); 39 | templateFile = await TemplateFile.getInstance( 40 | '${argResults!.rest.first}/${templateFile.fileName}', 'module'); 41 | 42 | var result = await Slidy.instance.template.createFile( 43 | info: TemplateInfo( 44 | key: 'module', destiny: templateFile.file, yaml: generateFile)); 45 | execute(result); 46 | 47 | if (!argResults!['notest']) { 48 | result = await Slidy.instance.template.createFile( 49 | info: TemplateInfo( 50 | yaml: generateFile, 51 | destiny: templateFile.fileTest, 52 | key: 'module_test', 53 | args: [ 54 | templateFile.fileNameWithUppeCase + 'Module', 55 | templateFile.import 56 | ])); 57 | execute(result); 58 | } 59 | 60 | if (argResults!['complete'] != true) return; 61 | 62 | var command = CommandRunner('slidy', 'CLI')..addCommand(GenerateCommand()); 63 | final yamlService = Slidy.instance.get(); 64 | final node = yamlService.getValue(['dependencies']); 65 | final smList = [ 66 | 'flutter_triple', 67 | 'triple', 68 | 'flutter_bloc', 69 | 'bloc', 70 | 'flutter_mobx', 71 | 'bloc', 72 | 'rx_notifier' 73 | ]; 74 | final selected = node?.value.keys 75 | .firstWhere((element) => smList.contains(element)) as String; 76 | 77 | await command.run(['generate', selected.replaceFirst('flutter_', ''), '${argResults!.rest.first}/${templateFile.fileName}', '--page']); 78 | templateFile = await TemplateFile.getInstance('${argResults!.rest.first}/${templateFile.fileName}', 'page'); 79 | 80 | await utils.injectParentModuleRouting( 81 | '/', 82 | '${templateFile.fileNameWithUppeCase}Page()', 83 | templateFile.import, 84 | templateFile.file.parent); 85 | } 86 | 87 | @override 88 | String? get invocationSuffix => null; 89 | } 90 | 91 | class GenerateModuleAbbrSubCommand extends GenerateModuleSubCommand { 92 | @override 93 | final name = 'm'; 94 | } 95 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_mobx_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/mobx.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | import '../install_command.dart'; 12 | 13 | class GenerateMobxSubCommand extends CommandBase { 14 | @override 15 | final name = 'mobx'; 16 | @override 17 | final description = 'Creates a Mobx Store'; 18 | 19 | GenerateMobxSubCommand() { 20 | argParser.addFlag('notest', 21 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 22 | argParser.addFlag('page', 23 | abbr: 'p', negatable: true, help: 'Create a Page file'); 24 | argParser.addOption('bind', 25 | abbr: 'b', 26 | allowed: [ 27 | 'singleton', 28 | 'lazy-singleton', 29 | 'factory', 30 | ], 31 | defaultsTo: 'lazy-singleton', 32 | allowedHelp: { 33 | 'singleton': 'Object persist while module exists', 34 | 'lazy-singleton': 35 | 'Object persist while module exists, but only after being called first for the fist time', 36 | 'factory': 'A new object is created each time it is called.', 37 | }, 38 | help: 'Define type injection in parent module'); 39 | } 40 | 41 | @override 42 | FutureOr run() async { 43 | final templateFile = 44 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'store'); 45 | 46 | if (!await templateFile.checkDependencyIsExist('mobx')) { 47 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 48 | await command.run([ 49 | 'install', 50 | 'flutter_mobx@2.0.0-nullsafety.0', 51 | 'mobx@2.0.0-nullsafety.2' 52 | ]); 53 | await command.run(['install', 'mobx_codegen', 'build_runner', '--dev']); 54 | } 55 | 56 | var result = await Slidy.instance.template.createFile( 57 | info: TemplateInfo( 58 | yaml: mobxFile, destiny: templateFile.file, key: 'mobx')); 59 | execute(result); 60 | if (result.isRight()) { 61 | if (argResults!['page'] == true) { 62 | await utils.addedInjectionInPage( 63 | templateFile: templateFile, 64 | pathCommand: argResults!.rest.single, 65 | noTest: !argResults!['notest'], 66 | type: 'Store'); 67 | } 68 | await utils.injectParentModule( 69 | argResults!['bind'], 70 | '${templateFile.fileNameWithUppeCase}Store()', 71 | templateFile.import, 72 | templateFile.file.parent); 73 | } 74 | 75 | if (!argResults!['notest']) { 76 | result = await Slidy.instance.template.createFile( 77 | info: TemplateInfo( 78 | yaml: mobxFile, 79 | destiny: templateFile.fileTest, 80 | key: 'mobx_test', 81 | args: [ 82 | templateFile.fileNameWithUppeCase + 'Store', 83 | templateFile.import 84 | ])); 85 | execute(result); 86 | } 87 | } 88 | 89 | @override 90 | String? get invocationSuffix => null; 91 | } 92 | 93 | class GenerateMobxAbbrSubCommand extends GenerateMobxSubCommand { 94 | @override 95 | final name = 'mbx'; 96 | } 97 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_cubit_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/bloc.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | import '../install_command.dart'; 12 | 13 | class GenerateCubitSubCommand extends CommandBase { 14 | @override 15 | final name = 'cubit'; 16 | @override 17 | final description = 'Creates a Cubit file'; 18 | 19 | GenerateCubitSubCommand() { 20 | argParser.addFlag('notest', 21 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 22 | argParser.addFlag('page', 23 | abbr: 'p', negatable: true, help: 'Create a Page file'); 24 | argParser.addOption('bind', 25 | abbr: 'b', 26 | allowed: [ 27 | 'singleton', 28 | 'lazy-singleton', 29 | 'factory', 30 | ], 31 | defaultsTo: 'lazy-singleton', 32 | allowedHelp: { 33 | 'singleton': 'Object persist while module exists', 34 | 'lazy-singleton': 35 | 'Object persist while module exists, but only after being called first for the fist time', 36 | 'factory': 'A new object is created each time it is called.', 37 | }, 38 | help: 'Define type injection in parent module'); 39 | } 40 | 41 | @override 42 | FutureOr run() async { 43 | final templateFile = 44 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'cubit'); 45 | 46 | if (!await templateFile.checkDependencyIsExist('bloc')) { 47 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 48 | await command.run([ 49 | 'install', 50 | 'bloc@7.0.0-nullsafety.3', 51 | 'flutter_bloc@7.0.0-nullsafety.3' 52 | ]); 53 | await command.run(['install', 'bloc_test@8.0.0-nullsafety.2', '--dev']); 54 | } 55 | 56 | var result = await Slidy.instance.template.createFile( 57 | info: TemplateInfo( 58 | yaml: blocFile, destiny: templateFile.file, key: 'cubit')); 59 | execute(result); 60 | if (result.isRight()) { 61 | if (argResults!['page'] == true) { 62 | await utils.addedInjectionInPage( 63 | templateFile: templateFile, 64 | pathCommand: argResults!.rest.single, 65 | noTest: !argResults!['notest'], 66 | type: 'Cubit'); 67 | } 68 | await utils.injectParentModule( 69 | argResults!['bind'], 70 | '${templateFile.fileNameWithUppeCase}Cubit()', 71 | templateFile.import, 72 | templateFile.file.parent); 73 | } 74 | 75 | if (!argResults!['notest']) { 76 | result = await Slidy.instance.template.createFile( 77 | info: TemplateInfo( 78 | yaml: blocFile, 79 | destiny: templateFile.fileTest, 80 | key: 'cubit_test', 81 | args: [ 82 | templateFile.fileNameWithUppeCase + 'Cubit', 83 | templateFile.import 84 | ])); 85 | execute(result); 86 | } 87 | } 88 | 89 | @override 90 | String? get invocationSuffix => null; 91 | } 92 | 93 | class GenerateCubitAbbrSubCommand extends GenerateCubitSubCommand { 94 | @override 95 | final name = 'c'; 96 | } 97 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_service_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/service.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | 12 | class GenerateServiceSubCommand extends CommandBase { 13 | @override 14 | final name = 'service'; 15 | @override 16 | final description = 'Creates a Service'; 17 | 18 | GenerateServiceSubCommand() { 19 | argParser.addFlag('notest', 20 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 21 | argParser.addFlag('interface', 22 | abbr: 'i', negatable: false, help: 'Create Service Inteface'); 23 | argParser.addOption('bind', 24 | abbr: 'b', 25 | allowed: [ 26 | 'singleton', 27 | 'lazy-singleton', 28 | 'factory', 29 | ], 30 | defaultsTo: 'lazy-singleton', 31 | allowedHelp: { 32 | 'singleton': 'Object persist while module exists', 33 | 'lazy-singleton': 34 | 'Object persist while module exists, but only after being called first for the fist time', 35 | 'factory': 'A new object is created each time it is called.', 36 | }, 37 | help: 'Define type injection in parent module'); 38 | } 39 | 40 | @override 41 | FutureOr run() async { 42 | final templateFile = await TemplateFile.getInstance( 43 | argResults?.rest.single ?? '', 'service'); 44 | var result = await Slidy.instance.template.createFile( 45 | info: TemplateInfo( 46 | yaml: serviceFile, 47 | destiny: templateFile.file, 48 | key: argResults!['interface'] ? 'impl_service' : 'service', 49 | ), 50 | ); 51 | execute(result); 52 | if (result.isRight()) { 53 | await utils.injectParentModule( 54 | argResults!['bind'], 55 | '${templateFile.fileNameWithUppeCase}Service()', 56 | templateFile.import, 57 | templateFile.file.parent, 58 | ); 59 | } 60 | 61 | if (argResults!['interface']) { 62 | print( 63 | '${templateFile.file.parent.path}/${templateFile.fileName}_interface.dart'); 64 | result = await Slidy.instance.template.createFile( 65 | info: TemplateInfo( 66 | yaml: serviceFile, 67 | destiny: File( 68 | '${templateFile.file.parent.path}/${templateFile.fileName}_service_interface.dart'), 69 | key: 'i_service', 70 | args: [ 71 | templateFile.fileNameWithUppeCase + 'Service', 72 | templateFile.import 73 | ])); 74 | execute(result); 75 | } 76 | 77 | if (!argResults!['notest']) { 78 | result = await Slidy.instance.template.createFile( 79 | info: TemplateInfo( 80 | yaml: serviceFile, 81 | destiny: templateFile.fileTest, 82 | key: 'test_service', 83 | args: [ 84 | templateFile.fileNameWithUppeCase + 'Service', 85 | templateFile.import 86 | ])); 87 | execute(result); 88 | } 89 | } 90 | 91 | @override 92 | String? get invocationSuffix => null; 93 | } 94 | 95 | class GenerateServiceAbbrSubCommand extends GenerateServiceSubCommand { 96 | @override 97 | final name = 's'; 98 | } 99 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_repository_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/repository.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | 12 | class GenerateRepositorySubCommand extends CommandBase { 13 | @override 14 | final name = 'repository'; 15 | @override 16 | final description = 'Creates a Repository'; 17 | 18 | GenerateRepositorySubCommand() { 19 | argParser.addFlag('notest', 20 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 21 | argParser.addFlag('interface', 22 | abbr: 'i', negatable: false, help: 'Create Repository Inteface'); 23 | argParser.addOption('bind', 24 | abbr: 'b', 25 | allowed: [ 26 | 'singleton', 27 | 'lazy-singleton', 28 | 'factory', 29 | ], 30 | defaultsTo: 'lazy-singleton', 31 | allowedHelp: { 32 | 'singleton': 'Object persist while module exists', 33 | 'lazy-singleton': 34 | 'Object persist while module exists, but only after being called first for the fist time', 35 | 'factory': 'A new object is created each time it is called.', 36 | }, 37 | help: 'Define type injection in parent module'); 38 | } 39 | 40 | @override 41 | FutureOr run() async { 42 | final templateFile = await TemplateFile.getInstance( 43 | argResults?.rest.single ?? '', 'repository'); 44 | var result = await Slidy.instance.template.createFile( 45 | info: TemplateInfo( 46 | yaml: repositoryFile, 47 | destiny: templateFile.file, 48 | key: argResults!['interface'] ? 'impl_repository' : 'repository', 49 | ), 50 | ); 51 | execute(result); 52 | if (result.isRight()) { 53 | await utils.injectParentModule( 54 | argResults!['bind'], 55 | '${templateFile.fileNameWithUppeCase}Repository()', 56 | templateFile.import, 57 | templateFile.file.parent); 58 | } 59 | 60 | if (argResults!['interface']) { 61 | print( 62 | '${templateFile.file.parent.path}/${templateFile.fileName}_interface.dart'); 63 | result = await Slidy.instance.template.createFile( 64 | info: TemplateInfo( 65 | yaml: repositoryFile, 66 | destiny: File( 67 | '${templateFile.file.parent.path}/${templateFile.fileName}_repository_interface.dart'), 68 | key: 'i_repository', 69 | args: [ 70 | templateFile.fileNameWithUppeCase + 'Repository', 71 | templateFile.import 72 | ])); 73 | execute(result); 74 | } 75 | 76 | if (!argResults!['notest']) { 77 | result = await Slidy.instance.template.createFile( 78 | info: TemplateInfo( 79 | yaml: repositoryFile, 80 | destiny: templateFile.fileTest, 81 | key: 'test_repository', 82 | args: [ 83 | templateFile.fileNameWithUppeCase + 'Repository', 84 | templateFile.import 85 | ])); 86 | execute(result); 87 | } 88 | } 89 | 90 | @override 91 | String? get invocationSuffix => null; 92 | } 93 | 94 | class GenerateRepositoryAbbrSubCommand extends GenerateRepositorySubCommand { 95 | @override 96 | final name = 'r'; 97 | } 98 | -------------------------------------------------------------------------------- /test/src/modules/template_creator/domain/usecases/create_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'package:mocktail/mocktail.dart'; 4 | import 'package:slidy/src/core/entities/slidy_process.dart'; 5 | import 'package:slidy/src/modules/template_creator/domain/models/template_info.dart'; 6 | import 'package:slidy/src/modules/template_creator/domain/usecases/create.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | class FileYamlMock extends Mock implements File { 10 | String savedFile = ''; 11 | 12 | @override 13 | Future exists() async { 14 | return true; 15 | } 16 | 17 | @override 18 | Future writeAsString(String contents, 19 | {FileMode mode = FileMode.write, 20 | Encoding encoding = utf8, 21 | bool flush = false}) async { 22 | savedFile = contents; 23 | return this; 24 | } 25 | 26 | @override 27 | void writeAsStringSync(String contents, 28 | {FileMode mode = FileMode.write, 29 | Encoding encoding = utf8, 30 | bool flush = false}) { 31 | savedFile = contents; 32 | } 33 | } 34 | 35 | class FileDestinyMock extends Mock implements File { 36 | String savedFile = ''; 37 | 38 | @override 39 | Uri get uri => Uri.parse('lib/main.dart'); 40 | 41 | @override 42 | Future create({bool recursive = false}) async { 43 | return this; 44 | } 45 | 46 | @override 47 | Future exists() async { 48 | return false; 49 | } 50 | 51 | @override 52 | Future writeAsString(String contents, 53 | {FileMode mode = FileMode.write, 54 | Encoding encoding = utf8, 55 | bool flush = false}) async { 56 | savedFile = contents; 57 | return this; 58 | } 59 | 60 | @override 61 | void writeAsStringSync(String contents, 62 | {FileMode mode = FileMode.write, 63 | Encoding encoding = utf8, 64 | bool flush = false}) { 65 | savedFile = contents; 66 | } 67 | } 68 | 69 | void main() { 70 | final yaml = FileYamlMock(); 71 | final destiny = FileDestinyMock(); 72 | 73 | final usecase = Create(); 74 | 75 | test('should create template', () async { 76 | when(() => yaml.readAsStringSync()).thenReturn(yamlText); 77 | final result = await usecase( 78 | params: TemplateInfo(yaml: yaml, destiny: destiny, key: 'main')); 79 | expect(result.isRight(), true); 80 | expect(destiny.savedFile, savedText); 81 | }); 82 | test('should create template with args', () async { 83 | when(() => yaml.readAsStringSync()).thenReturn(yamlText); 84 | final result = await usecase( 85 | params: TemplateInfo( 86 | yaml: yaml, destiny: destiny, key: 'main', args: ['Modular()'])); 87 | expect(result.isRight(), true); 88 | expect(destiny.savedFile, savedTextWithArgs); 89 | }); 90 | 91 | test('should create template with real yaml', () async { 92 | // final result = await usecase(params: TemplateInfo(yaml: File('lib/'), destiny: destiny, key: 'main', args: ['Modular()'])); 93 | // expect(result.isRight(), true); 94 | // expect(destiny.savedFile, savedTextWithArgs); 95 | }); 96 | } 97 | 98 | const yamlText = ''' 99 | main: | 100 | void main() { 101 | runApp(myApp(\$arg1)); 102 | } 103 | '''; 104 | final savedText = ''' 105 | void main() { 106 | runApp(myApp(\$arg1)); 107 | }''' 108 | .trim(); 109 | 110 | final savedTextWithArgs = ''' 111 | void main() { 112 | runApp(myApp(Modular())); 113 | }''' 114 | .trim(); 115 | -------------------------------------------------------------------------------- /bin/commands/sub_command/generate_bloc_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | 6 | import 'package:slidy/src/core/prints/prints.dart'; 7 | import '../../templates/bloc.dart'; 8 | import '../../utils/template_file.dart'; 9 | import '../../utils/utils.dart' as utils; 10 | import '../command_base.dart'; 11 | import '../install_command.dart'; 12 | 13 | class GenerateBlocSubCommand extends CommandBase { 14 | @override 15 | final name = 'bloc'; 16 | @override 17 | final description = 'Creates a BLoC file'; 18 | 19 | GenerateBlocSubCommand() { 20 | argParser.addFlag('notest', 21 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 22 | argParser.addFlag('page', 23 | abbr: 'p', negatable: true, help: 'Create a Page file'); 24 | argParser.addOption('bind', 25 | abbr: 'b', 26 | allowed: [ 27 | 'singleton', 28 | 'lazy-singleton', 29 | 'factory', 30 | ], 31 | defaultsTo: 'lazy-singleton', 32 | allowedHelp: { 33 | 'singleton': 'Object persist while module exists', 34 | 'lazy-singleton': 35 | 'Object persist while module exists, but only after being called first for the fist time', 36 | 'factory': 'A new object is created each time it is called.', 37 | }, 38 | help: 'Define type injection in parent module'); 39 | } 40 | 41 | @override 42 | FutureOr run() async { 43 | final templateFile = 44 | await TemplateFile.getInstance(argResults?.rest.single ?? '', 'bloc'); 45 | 46 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 47 | if (!await templateFile.checkDependencyIsExist('bloc')) { 48 | await command.run([ 49 | 'install', 50 | 'bloc@7.0.0-nullsafety.3', 51 | 'flutter_bloc@7.0.0-nullsafety.3' 52 | ]); 53 | await command.run(['install', 'bloc_test@8.0.0-nullsafety.2', '--dev']); 54 | } 55 | 56 | var result = await Slidy.instance.template.createFile( 57 | info: TemplateInfo( 58 | yaml: blocFile, 59 | destiny: templateFile.file, 60 | key: 'bloc', 61 | args: [templateFile.fileNameWithUppeCase + 'Event'])); 62 | execute(result); 63 | if (result.isRight()) { 64 | if (argResults!['page'] == true) { 65 | await utils.addedInjectionInPage( 66 | templateFile: templateFile, 67 | pathCommand: argResults!.rest.single, 68 | noTest: !argResults!['notest'], 69 | type: 'Bloc'); 70 | } 71 | await utils.injectParentModule( 72 | argResults!['bind'], 73 | '${templateFile.fileNameWithUppeCase}Bloc()', 74 | templateFile.import, 75 | templateFile.file.parent); 76 | } 77 | 78 | if (!argResults!['notest']) { 79 | result = await Slidy.instance.template.createFile( 80 | info: TemplateInfo( 81 | yaml: blocFile, 82 | destiny: templateFile.fileTest, 83 | key: 'bloc_test', 84 | args: [ 85 | templateFile.fileNameWithUppeCase + 'Bloc', 86 | templateFile.import, 87 | templateFile.fileNameWithUppeCase + 'Event' 88 | ])); 89 | execute(result); 90 | } 91 | } 92 | 93 | @override 94 | String? get invocationSuffix => null; 95 | } 96 | 97 | class GenerateBlocAbbrSubCommand extends GenerateBlocSubCommand { 98 | @override 99 | final name = 'b'; 100 | } 101 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 71 | 73 | 79 | 80 | 81 | 82 | 84 | 85 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/src/modules/pipelines/domain/usecases/pipeline_v1_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | 5 | import 'package:dartz/dartz.dart'; 6 | import 'package:recase/recase.dart'; 7 | import 'package:rxdart/rxdart.dart'; 8 | import 'package:slidy/slidy.dart'; 9 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline_v1.dart'; 10 | import '../../../../core/prints/prints.dart' as output; 11 | import 'package:slidy/src/modules/pipelines/domain/entities/pipeline.dart'; 12 | import 'package:slidy/src/modules/pipelines/domain/errors/errors.dart'; 13 | 14 | abstract class PipelineV1Usecase { 15 | Future> call( 16 | Pipeline pipeline, String command, List args); 17 | } 18 | 19 | class PipelineV1UsecaseImpl implements PipelineV1Usecase { 20 | @override 21 | Future> call( 22 | Pipeline pipeline, String command, List args) async { 23 | final v1 = pipeline as PipelineV1; 24 | JobV1 job; 25 | try { 26 | job = v1.jobs.firstWhere((element) => element.key == command); 27 | } catch (e) { 28 | return Left(PipelineError('Command $command not found')); 29 | } 30 | var stepName = ''; 31 | try { 32 | for (var step in job.steps) { 33 | stepName = step.id; 34 | print(output.green('STEP: $stepName')); 35 | final fileName = step.generate?.path == null 36 | ? '' 37 | : ReCase(Uri.parse(step.generate!.path).pathSegments.last) 38 | .camelCase; 39 | if (step.generate != null) { 40 | await _executeGenerate(); 41 | } 42 | if (step.commands.isNotEmpty) { 43 | await _executeCommand(step.commands, args, fileName); 44 | } 45 | 46 | print('============\n'); 47 | } 48 | } catch (e) { 49 | output.error('step $stepName'); 50 | } 51 | 52 | return Right(SlidyProccess(result: v1.name)); 53 | } 54 | 55 | Future _executeGenerate() async {} 56 | 57 | Future _executeCommand( 58 | List commands, List args, String fileName) async { 59 | final regex = RegExp("[^\\s\'']+|\'[^\']*\'|'[^']*'"); 60 | 61 | for (var command in commands) { 62 | command = _processLine(command, args, fileName); 63 | print(output.green('RUN: $command')); 64 | await callProcess( 65 | regex.allMatches(command).map((v) => v.group(0)!).toList()); 66 | } 67 | } 68 | 69 | String _processLine(String value, List args, String fileName) { 70 | value = 71 | value.replaceAll('\$fileName|camelcase', ReCase(fileName).camelCase); 72 | value = 73 | value.replaceAll('\$fileName|pascalcase', ReCase(fileName).pascalCase); 74 | value = value.replaceAll('\$fileName', fileName); 75 | 76 | if (args.isEmpty) return value; 77 | for (var i = 0; i < args.length; i++) { 78 | final key = '\$arg${i + 1}'; 79 | value = value.replaceAll(key, args[i]); 80 | } 81 | return value; 82 | } 83 | 84 | Future callProcess(List commands) async { 85 | try { 86 | var process = await Process.start( 87 | commands.first, 88 | commands.length <= 1 89 | ? [] 90 | : commands.getRange(1, commands.length).toList(), 91 | runInShell: true); 92 | 93 | final error = process.stderr.transform(utf8.decoder).map(output.red); 94 | final success = process.stdout.transform(utf8.decoder); 95 | 96 | await for (var line in Rx.merge([success, error])) { 97 | print(line); 98 | } 99 | if (await process.exitCode == 0) { 100 | output.success(commands.join(' ')); 101 | return 0; 102 | } else { 103 | output.error(commands.join(' ')); 104 | return 1; 105 | } 106 | } catch (error) { 107 | output.error(commands.join(' ')); 108 | return 1; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /test/src/modules/template_creator/domain/usecases/add_line_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'package:mocktail/mocktail.dart'; 4 | import 'package:slidy/src/core/entities/slidy_process.dart'; 5 | import 'package:slidy/src/modules/template_creator/domain/models/line_params.dart'; 6 | import 'package:slidy/src/modules/template_creator/domain/usecases/add_line.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | class FileDestinyMock extends Mock implements File { 10 | String savedFile = ''; 11 | 12 | @override 13 | Uri get uri => Uri.parse('lib/main.dart'); 14 | 15 | @override 16 | Future create({bool recursive = false}) async { 17 | return this; 18 | } 19 | 20 | @override 21 | Future exists() async { 22 | return true; 23 | } 24 | 25 | @override 26 | Future writeAsString(String contents, 27 | {FileMode mode = FileMode.write, 28 | Encoding encoding = utf8, 29 | bool flush = false}) async { 30 | savedFile = contents; 31 | return this; 32 | } 33 | } 34 | 35 | void main() { 36 | final destiny = FileDestinyMock(); 37 | 38 | final usecase = AddLine(); 39 | 40 | test('should add one line in template', () async { 41 | when(() => destiny.readAsLines()) 42 | .thenAnswer((_) async => yamlText.split('\n')); 43 | final result = 44 | await usecase(params: LineParams(destiny, inserts: ['jacob'])); 45 | expect(result.isRight(), true); 46 | expect(destiny.savedFile, savedText); 47 | }); 48 | 49 | test('should add more then one line in template', () async { 50 | when(() => destiny.readAsLines()) 51 | .thenAnswer((_) async => yamlText.split('\n')); 52 | final result = await usecase( 53 | params: LineParams(destiny, inserts: ['jacob', 'joão', 'maria'])); 54 | expect(result.isRight(), true); 55 | expect(destiny.savedFile, savedMultipleTexts); 56 | }); 57 | 58 | test('should add line inside main()', () async { 59 | when(() => destiny.readAsLines()) 60 | .thenAnswer((_) async => yamlText.split('\n')); 61 | final result = await usecase( 62 | params: LineParams(destiny, position: 1, inserts: ['inside();'])); 63 | expect(result.isRight(), true); 64 | expect(destiny.savedFile, savedTextInsertedInExpecificPosition); 65 | }); 66 | 67 | test('should replace line', () async { 68 | when(() => destiny.readAsLines()) 69 | .thenAnswer((_) async => yamlText.split('\n')); 70 | final result = await usecase( 71 | params: LineParams( 72 | destiny, 73 | replaceLine: (line) { 74 | if (line.contains('runApp(myApp());')) { 75 | return line.replaceFirst( 76 | 'runApp(myApp());', 'runApp(myApp(), addedNew());'); 77 | } 78 | return line; 79 | }, 80 | )); 81 | expect(result.isRight(), true); 82 | expect(destiny.savedFile, savedTextAfterReplaced); 83 | }); 84 | test('should added above line', () async { 85 | when(() => destiny.readAsLines()) 86 | .thenAnswer((_) async => yamlText.split('\n')); 87 | final result = await usecase( 88 | params: LineParams( 89 | destiny, 90 | replaceLine: (line) { 91 | if (line.contains('void main(')) { 92 | return 'import \'test\';\n\n$line'; 93 | } 94 | return line; 95 | }, 96 | )); 97 | expect(result.isRight(), true); 98 | expect(destiny.savedFile, savedTextAboveLine); 99 | }); 100 | } 101 | 102 | const yamlText = ''' 103 | void main() { 104 | runApp(myApp()); 105 | }'''; 106 | 107 | const savedText = ''' 108 | jacob 109 | void main() { 110 | runApp(myApp()); 111 | }'''; 112 | 113 | const savedMultipleTexts = ''' 114 | jacob 115 | joão 116 | maria 117 | void main() { 118 | runApp(myApp()); 119 | }'''; 120 | 121 | const savedTextInsertedInExpecificPosition = ''' 122 | void main() { 123 | inside(); 124 | runApp(myApp()); 125 | }'''; 126 | 127 | const savedTextAfterReplaced = ''' 128 | void main() { 129 | runApp(myApp(), addedNew()); 130 | }'''; 131 | const savedTextAboveLine = ''' 132 | import 'test'; 133 | 134 | void main() { 135 | runApp(myApp()); 136 | }'''; 137 | -------------------------------------------------------------------------------- /lib/src/modules/yaml_edit/src/errors.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:meta/meta.dart'; 16 | import 'package:yaml/yaml.dart'; 17 | 18 | /// Error thrown when a function is passed an invalid path. 19 | @sealed 20 | class PathError extends ArgumentError { 21 | /// The full path that caused the error 22 | final Iterable path; 23 | 24 | /// The subpath that caused the error 25 | final Iterable subPath; 26 | 27 | /// The last element of [path] that could be traversed. 28 | YamlNode? parent; 29 | 30 | PathError(this.path, this.subPath, this.parent, [String? message]) 31 | : super.value(subPath, 'path', message); 32 | 33 | PathError.unexpected(this.path, String message) 34 | : subPath = path, 35 | super(message); 36 | 37 | @override 38 | String toString() { 39 | if (message == null) { 40 | var errorMessage = 'Failed to traverse to subpath $subPath!'; 41 | 42 | if (subPath.isNotEmpty) { 43 | errorMessage += 44 | ' Parent $parent does not contain key or index ${subPath.last}'; 45 | } 46 | 47 | return 'Invalid path: $path. $errorMessage.'; 48 | } 49 | 50 | return 'Invalid path: $path. $message'; 51 | } 52 | } 53 | 54 | /// Error thrown when the path contains an alias along the way. 55 | /// 56 | /// When a path contains an aliased node, the behavior becomes less well-defined 57 | /// because we cannot be certain if the user wishes for the change to 58 | /// propagate throughout all the other aliased nodes, or if the user wishes 59 | /// for only that particular node to be modified. As such, [AliasError] reflects 60 | /// the detection that our change will impact an alias, and we do not intend 61 | /// on supporting such changes for the foreseeable future. 62 | @sealed 63 | class AliasError extends UnsupportedError { 64 | /// The path that caused the error 65 | final Iterable path; 66 | 67 | /// The anchor node of the alias 68 | final YamlNode anchor; 69 | 70 | AliasError(this.path, this.anchor) 71 | : super('Encountered an alias node along $path! ' 72 | 'Alias nodes are nodes that refer to a previously serialized nodes, ' 73 | 'and are denoted by either the "*" or the "&" indicators in the ' 74 | 'original YAML. As the resulting behavior of mutations on these ' 75 | 'nodes is not well-defined, the operation will not be supported ' 76 | 'by this library.\n\n' 77 | '${anchor.span.message('The alias was first defined here.')}'); 78 | } 79 | 80 | /// Error thrown when an assertion about the YAML fails. Extends 81 | /// [AssertionError] to override the [toString] method for pretty printing. 82 | class _YamlAssertionError extends AssertionError { 83 | _YamlAssertionError(message) : super(message); 84 | 85 | @override 86 | String toString() { 87 | if (message != null) { 88 | return 'Assertion failed: $message'; 89 | } 90 | return 'Assertion failed'; 91 | } 92 | } 93 | 94 | /// Throws an [AssertionError] with the given [message], and format 95 | /// [oldYaml] and [newYaml] for information. 96 | Error createAssertionError(String message, String? oldYaml, String? newYaml) { 97 | return _YamlAssertionError(''' 98 | (package:yaml_edit) $message 99 | 100 | # YAML before edit: 101 | > ${oldYaml?.replaceAll('\n', '\n> ')} 102 | 103 | # YAML after edit: 104 | > ${newYaml?.replaceAll('\n', '\n> ')} 105 | 106 | Please file an issue at: 107 | ''' 108 | 'https://github.com/google/dart-neats/issues/new?labels=pkg%3Ayaml_edit' 109 | '%2C+pending-triage&template=yaml_edit.md\n'); 110 | } 111 | -------------------------------------------------------------------------------- /bin/utils/utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:slidy/slidy.dart'; 5 | import 'package:slidy/src/modules/template_creator/domain/models/line_params.dart'; 6 | 7 | import '../commands/generate_command.dart'; 8 | import 'package:slidy/src/core/prints/prints.dart'; 9 | import 'template_file.dart'; 10 | 11 | Future injectParentModule(String injectionType, String fileNameWithUppeCase, 12 | String import, Directory directory) async { 13 | final injection = _injectionTemplate(injectionType, fileNameWithUppeCase); 14 | 15 | final parentModule = await Slidy.instance.getParentModule(directory); 16 | 17 | var result = await Slidy.instance.template.addLine( 18 | params: LineParams(parentModule, replaceLine: (line) { 19 | if (line.contains('final List binds = [')) { 20 | return line.replaceFirst('final List binds = [', 21 | 'final List binds = [$injection,'); 22 | } else if (line.contains('List get binds => [')) { 23 | return line.replaceFirst('List get binds => [\n', 24 | 'List get binds => [$injection,'); 25 | } 26 | return line; 27 | })); 28 | 29 | execute(result); 30 | 31 | if (result.isRight()) { 32 | result = await Slidy.instance.template 33 | .addLine(params: LineParams(parentModule, inserts: [import])); 34 | execute(result); 35 | if (result.isRight()) { 36 | await formatFile(parentModule); 37 | } 38 | } 39 | } 40 | 41 | Future injectParentModuleRouting(String path, String fileNameWithUppeCase, 42 | String import, Directory directory) async { 43 | final injection = 44 | 'ChildRoute(\'$path\', child: (_, args) => $fileNameWithUppeCase)'; 45 | 46 | final parentModule = await Slidy.instance.getParentModule(directory); 47 | 48 | var result = await Slidy.instance.template.addLine( 49 | params: LineParams(parentModule, replaceLine: (line) { 50 | if (line.contains('final List routes = [')) { 51 | return line.replaceFirst('final List routes = [', 52 | 'final List routes = [$injection,'); 53 | } else if (line.contains('List get routes => [')) { 54 | return line.replaceFirst('List get routes => [\n', 55 | 'List get routes => [$injection,'); 56 | } 57 | return line; 58 | })); 59 | 60 | execute(result); 61 | 62 | if (result.isRight()) { 63 | result = await Slidy.instance.template 64 | .addLine(params: LineParams(parentModule, inserts: [import])); 65 | execute(result); 66 | if (result.isRight()) { 67 | await formatFile(parentModule); 68 | } 69 | } 70 | } 71 | 72 | Future addedInjectionInPage( 73 | {required TemplateFile templateFile, 74 | required String pathCommand, 75 | required bool noTest, 76 | required String type}) async { 77 | var command = CommandRunner('slidy', 'CLI')..addCommand(GenerateCommand()); 78 | await command.run(['generate', 'page', pathCommand, if (noTest) '--notest']); 79 | final insertLine = 80 | ' final ${templateFile.fileNameWithUppeCase}$type ${type.toLowerCase()} = Modular.get();'; 81 | final pageFile = File( 82 | templateFile.file.parent.path + '/${templateFile.fileName}_page.dart'); 83 | var result = await Slidy.instance.template.addLine( 84 | params: LineParams(pageFile, position: 9, inserts: [insertLine, ''])); 85 | execute(result); 86 | result = await Slidy.instance.template.addLine( 87 | params: LineParams(pageFile, inserts: [ 88 | 'import \'package:flutter_modular/flutter_modular.dart\';', 89 | templateFile.import 90 | ])); 91 | execute(result); 92 | } 93 | 94 | Future formatFile(File file) async { 95 | await Process.run('flutter', ['format', file.absolute.path], 96 | runInShell: true); 97 | } 98 | 99 | String _injectionTemplate(String injectionType, String classInstance) { 100 | if (injectionType == 'lazy-singleton') { 101 | return 'Bind.lazySingleton((i) => $classInstance)'; 102 | } else if (injectionType == 'singleton') { 103 | return 'Bind.singleton((i) => $classInstance)'; 104 | } else { 105 | return 'Bind.factory((i) => $classInstance)'; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /bin/commands/sub_command/clean_dart/generate_data_source_sub_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:args/command_runner.dart'; 5 | import 'package:slidy/slidy.dart'; 6 | 7 | import 'package:slidy/src/core/prints/prints.dart'; 8 | import '../../../templates/data_source.dart'; 9 | import '../../../utils/template_file.dart'; 10 | import '../../../utils/utils.dart' as utils; 11 | import '../../command_base.dart'; 12 | import '../../install_command.dart'; 13 | 14 | class GenerateDataSourceSubCommand extends CommandBase { 15 | @override 16 | final name = 'datasource'; 17 | @override 18 | final description = 'Creates a Data Source file'; 19 | 20 | GenerateDataSourceSubCommand() { 21 | argParser.addFlag('notest', 22 | abbr: 'n', negatable: false, help: 'Don`t create file test'); 23 | argParser.addOption('bind', 24 | abbr: 'd', 25 | allowed: [ 26 | 'singleton', 27 | 'lazy-singleton', 28 | 'factory', 29 | ], 30 | defaultsTo: 'lazy-singleton', 31 | allowedHelp: { 32 | 'singleton': 'Object persist while module exists', 33 | 'lazy-singleton': 34 | 'Object persist while module exists, but only after being called first for the fist time', 35 | 'factory': 'A new object is created each time it is called.', 36 | }, 37 | help: 'Define type injection in parent module'); 38 | } 39 | 40 | @override 41 | FutureOr run() async { 42 | final templateFile = 43 | await TemplateFile.getInstance(argResults?.rest.single ?? '', null); 44 | 45 | if (!await templateFile.checkDependencyIsExist('dio')) { 46 | var command = CommandRunner('slidy', 'CLI')..addCommand(InstallCommand()); 47 | await command.run(['install', 'dio@4.0.0-beta6']); 48 | } 49 | 50 | var splited = templateFile.file.path.split('/'); 51 | 52 | var last = splited.removeLast().replaceAll('.dart', '_data_source.dart'); 53 | var body = splited.join('/'); 54 | 55 | var result = await Slidy.instance.template.createFile( 56 | info: TemplateInfo( 57 | yaml: data_source, 58 | destiny: File(body + '/../infra/datasource/' + last), 59 | key: 'interface_data_source', 60 | args: [templateFile.fileNameWithUppeCase + 'Event'], 61 | ), 62 | ); 63 | 64 | execute(result); 65 | 66 | var importDataSourceInterface = 67 | 'import \'../../infra/datasource/' + last + '\';'; 68 | var importDataSource = 'import \'external/datasource/' + last + '\';'; 69 | 70 | result = await Slidy.instance.template.createFile( 71 | info: TemplateInfo( 72 | yaml: data_source, 73 | destiny: File(body + '/../external/datasource/' + last), 74 | key: 'data_source', 75 | args: [ 76 | templateFile.fileNameWithUppeCase + 'Event', 77 | importDataSourceInterface 78 | ], 79 | ), 80 | ); 81 | 82 | execute(result); 83 | 84 | if (result.isRight()) { 85 | await utils.injectParentModule( 86 | argResults!['bind'], 87 | '${templateFile.fileNameWithUppeCase}DataSourceImpl(i())', 88 | importDataSource, 89 | templateFile.file.parent.parent); 90 | } 91 | 92 | if (!argResults!['notest']) { 93 | if (!await templateFile.checkDependencyIsExist('mockito')) { 94 | var command = CommandRunner('slidy', 'CLI') 95 | ..addCommand(InstallCommand()); 96 | await command.run(['install', 'mockito@5.0.0']); 97 | } 98 | 99 | result = await Slidy.instance.template.createFile( 100 | info: TemplateInfo( 101 | yaml: data_source, 102 | destiny: templateFile.fileTest, 103 | key: 'data_source_test', 104 | args: [ 105 | 'I${templateFile.fileNameWithUppeCase}DataSource', 106 | templateFile.import, 107 | '${templateFile.fileNameWithUppeCase}DataSourceImpl' 108 | ], 109 | ), 110 | ); 111 | 112 | execute(result); 113 | } 114 | } 115 | 116 | @override 117 | String? get invocationSuffix => null; 118 | } 119 | 120 | class GenerateDataSourceAbbrSubCommand extends GenerateDataSourceSubCommand { 121 | @override 122 | final name = 'd'; 123 | } 124 | -------------------------------------------------------------------------------- /lib/src/modules/pipelines/domain/entities/pipeline_v1.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | 4 | import 'package:dartz/dartz.dart'; 5 | 6 | import 'package:slidy/src/core/entities/slidy_process.dart'; 7 | import 'package:slidy/src/modules/pipelines/domain/errors/errors.dart'; 8 | 9 | import 'pipeline.dart'; 10 | 11 | class PipelineV1 extends Pipeline { 12 | final String name; 13 | final String version; 14 | final List jobs; 15 | 16 | PipelineV1( 17 | Future> Function( 18 | Pipeline pipeline, String command, List args) 19 | usecase, 20 | {required this.name, 21 | this.version = 'v1', 22 | this.jobs = const []}) 23 | : super(usecase); 24 | 25 | factory PipelineV1.fromMap( 26 | Map map, 27 | Future> Function( 28 | Pipeline pipeline, String command, List args) 29 | usecase) { 30 | final jobs = []; 31 | 32 | for (var key in map.keys) { 33 | if (key == 'name' || key == 'version') { 34 | continue; 35 | } 36 | 37 | final job = JobV1.fromMap( 38 | {'key': key, 'name': map[key]['name'], 'steps': map[key]['steps']}); 39 | jobs.add(job); 40 | } 41 | 42 | return PipelineV1( 43 | usecase, 44 | name: map['name'], 45 | version: map['version'], 46 | jobs: jobs, 47 | ); 48 | } 49 | 50 | factory PipelineV1.fromJson( 51 | String source, 52 | Future> Function( 53 | Pipeline pipeline, String command, List args) 54 | usecase, 55 | ) => 56 | PipelineV1.fromMap(json.decode(source), usecase); 57 | } 58 | 59 | class JobV1 { 60 | final String key; 61 | final String? name; 62 | final List steps; 63 | 64 | const JobV1({required this.key, this.name, this.steps = const []}); 65 | 66 | factory JobV1.fromMap(Map map) { 67 | return JobV1( 68 | key: map['key'], 69 | name: map['name'], 70 | steps: map['steps'] == null 71 | ? [] 72 | : List.from(map['steps']?.map((x) => StepV1.fromMap(x))), 73 | ); 74 | } 75 | 76 | factory JobV1.fromJson(String source) => JobV1.fromMap(json.decode(source)); 77 | } 78 | 79 | class StepV1 { 80 | final String id; 81 | final List commands; 82 | final GenerateV1? generate; 83 | 84 | const StepV1({required this.id, this.commands = const [], this.generate}); 85 | 86 | factory StepV1.fromMap(Map map) { 87 | return StepV1( 88 | id: map['id'], 89 | commands: 90 | map['commands'] == null ? [] : List.from(map['commands']), 91 | generate: map.containsKey('generate') 92 | ? GenerateV1.fromMap(map['generate']) 93 | : null, 94 | ); 95 | } 96 | 97 | factory StepV1.fromJson(String source) => StepV1.fromMap(json.decode(source)); 98 | } 99 | 100 | class GenerateV1 { 101 | final String path; 102 | final String file; 103 | final ModuleInjectionV1? moduleInjection; 104 | final String? run; 105 | 106 | const GenerateV1( 107 | {this.run, required this.path, required this.file, this.moduleInjection}); 108 | 109 | factory GenerateV1.fromMap(Map map) { 110 | return GenerateV1( 111 | path: map['path'], 112 | file: map['file'], 113 | moduleInjection: ModuleInjectionV1.fromMap(map['module_injection']), 114 | run: map['run'], 115 | ); 116 | } 117 | 118 | factory GenerateV1.fromJson(String source) => 119 | GenerateV1.fromMap(json.decode(source)); 120 | } 121 | 122 | class ModuleInjectionV1 { 123 | final ModuleInjectionV1Type type; 124 | final String value; 125 | 126 | const ModuleInjectionV1({required this.type, required this.value}); 127 | 128 | factory ModuleInjectionV1.fromMap(Map map) { 129 | return ModuleInjectionV1( 130 | type: ModuleInjectionV1Type.values.firstWhere((element) => 131 | map['type'] == 132 | element.toString().replaceFirst('ModuleInjectionV1Type.', '')), 133 | value: map['value'], 134 | ); 135 | } 136 | 137 | factory ModuleInjectionV1.fromJson(String source) => 138 | ModuleInjectionV1.fromMap(json.decode(source)); 139 | } 140 | 141 | enum ModuleInjectionV1Type { bind, route } 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slidy 2 | 3 | CLI package manager and template generator for Flutter. Generate Modules, Pages, Widgets, BLoCs, Controllers, tests and more. 4 | 5 | Slidy supports mobx, bloc, cubit, rx_notifier and triple. 6 | 7 | # Why should I use it? 8 | 9 | Slidy's goal is to help you structure your project in a standardized way. Organizing your app in **Modules** formed by pages, repositories, widgets, BloCs, and also create unit tests automatically. The Module gives you a easier way to inject dependencies and blocs, including automatic dispose. Also helps you installing the dependencies and packages, updating and removing them. The best is that you can do all of this running a single command. 10 | 11 | # Motivations 12 | 13 | We realized that the project pattern absence is affecting the productivity of most developers, so we're proposing a development pattern along with a tool that imitates NPM (NodeJS) functionality as well as template generation capabilities (similar to Scaffold ). 14 | 15 | # About the Proposed Pattern 16 | 17 | The structure that slidy offers you, it's similar to MVC, where a page keeps it's own **business logic classes(BloC)**. 18 | 19 | We recommend you to use [flutter_modular](https://pub.dev/packages/flutter_modular) when structuring with slidy. It offers you the **module structure**(extending the WidgetModule) and dependency/bloc injection, or you will probably get an error. 20 | 21 | To understand **flutter_modular**, take a look at the [README](https://github.com/Flutterando/modular/blob/master/README.md). 22 | 23 | We also use the **Repository Pattern**, so the folder structure it's organized in **local modules** and a **global module**. The dependencies(repositories, BloCs, models, etc) can be accessed throughout the application. 24 | 25 | Sample folder structure generated by **slidy**: 26 | 27 | ## Installation 28 | 29 | You can get Slidy of many ways. 30 | 31 | ### **Flutter/Dart directly** 32 | 33 | ```bash 34 | dart pub global activate slidy 35 | ``` 36 | 37 | ### choco (only windows) 38 | 39 | ```bash 40 | choco install slidy 41 | ``` 42 | 43 | ### Homebrew (macos and linux) 44 | 45 | ```bash 46 | brew install slidy 47 | ``` 48 | 49 | ### curl and wget (linux) 50 | 51 | ```bash 52 | curl -o- https://raw.githubusercontent.com/Flutterando/slidy/master/install.sh | bash 53 | ``` 54 | 55 | ```bash 56 | wget -qO- https://raw.githubusercontent.com/Flutterando/slidy/master/install.sh | bash 57 | ``` 58 | 59 | ### Hello world! 60 | 61 | After install, exec the slidy version command. 62 | If the command was completed, the slidy was installed. 63 | 64 | ```bash 65 | slidy --version 66 | ``` 67 | 68 | ## Commands: 69 | 70 | **start:** 71 | Create a basic structure for your project (confirm that you have no data in the "lib" folder). 72 | 73 | ``` 74 | slidy start 75 | ``` 76 | 77 | **run:** 78 | Run scripts placed in the "scripts" parameter in pubspec.yaml 79 | 80 | ``` 81 | slidy run open_folder 82 | ``` 83 | 84 | **Install:** 85 | Install (or update) a new package or packages: 86 | 87 | ``` 88 | slidy install mockito dio modular 89 | ``` 90 | 91 | You can also install a package as dev_dependency using the flag --dev 92 | 93 | ``` 94 | slidy i flutter_launcher_icons --dev 95 | ``` 96 | 97 | ## Generate: 98 | 99 | Create a module, page, widget or repository according to the option. 100 | 101 | **Options:** 102 | 103 | Creates a new module with **slidy generate module**: 104 | 105 | ``` 106 | slidy generate module manager/product 107 | ``` 108 | 109 | Creates a new page with **slidy generate page**: 110 | 111 | ``` 112 | slidy generate page manager/product/pages/add_product 113 | ``` 114 | 115 | Creates a new widget with **slidy generate widget**: 116 | 117 | ``` 118 | slidy generate widget manager/product/widgets/product_detail 119 | ``` 120 | 121 | Create a new repository with **slidy generate repository** 122 | 123 | ``` 124 | slidy g r manager/product/repositories/product 125 | ``` 126 | 127 | Create a new rx notifier with **slidy generate rx** 128 | 129 | ``` 130 | slidy g rx manager/product/page/my_rx_notifier 131 | ``` 132 | 133 | Create a new triple with **slidy generate t** 134 | 135 | ``` 136 | slidy g t manager/product/page/my_triple 137 | ``` 138 | 139 | Create a new cubit with **slidy generate c** 140 | 141 | ``` 142 | slidy g c manager/product/page/my_cubit 143 | ``` 144 | 145 | Create a new mobx with **slidy generate mbx** 146 | 147 | ``` 148 | slidy g mbx manager/product/page/my_store 149 | ``` 150 | 151 | For more details [Telegram Group Flutterando](https://t.me/flutterando) 152 | --------------------------------------------------------------------------------