work on brick generator dart script #3
| @ -1,6 +1,38 @@ | ||||
| A sample command-line application with an entrypoint in `bin/`, library code | ||||
| A sample command-line application to generate which allows to generate the template of a brick from a project which compiles. with an entrypoint in `bin/`, library code | ||||
| in `lib/`. | ||||
| 
 | ||||
| ```sh | ||||
| dart /bin/brick_generator.dart wyatt_clean_code wyatt_clean_code wyatt-clean-code "Wyatt Demo" app.wyatt.io | ||||
| # How to use | ||||
| 
 | ||||
| - Add your app in `apps`. | ||||
| - Add `brick_config.yaml` in you app folder and add this fields : | ||||
| 
 | ||||
| 
 | ||||
| ```yaml | ||||
| brick_name: wyatt_feature_brick | ||||
| project_name: projet_name | ||||
| 
 | ||||
| path_to_brickify: lib/feature_brick_test_folder | ||||
| 
 | ||||
| syntax: | ||||
|   camel_case: featureBrick | ||||
|   constant_case: FEATURE_BRICK | ||||
|   dot_case: feature.brick | ||||
|   header_case: Feature-Brick | ||||
|   lower_case: feature brick | ||||
|   pascal_case: FeatureBrick | ||||
|   param_case: feature-brick | ||||
|   sentence_case: Feature brick | ||||
|   snake_case: feature_brick | ||||
|   title_case: Feature Brick | ||||
|   upper_case: FEATURE BRICK | ||||
| ``` | ||||
| 
 | ||||
| then run command with project path | ||||
| 
 | ||||
| ```sh | ||||
| dart tools/brick_generator/bin/brick_generator.dart ./apps/wyatt_feature_brick | ||||
| ``` | ||||
| 
 | ||||
| # TODO | ||||
| - Work on bool variables | ||||
| - Add several variables (here only one is possible) | ||||
| @ -1,30 +1 @@ | ||||
| # This file configures the static analysis results for your project (errors, | ||||
| # warnings, and lints). | ||||
| # | ||||
| # This enables the 'recommended' set of lints from `package:lints`. | ||||
| # This set helps identify many issues that may lead to problems when running | ||||
| # or consuming Dart code, and enforces writing Dart using a single, idiomatic | ||||
| # style and format. | ||||
| # | ||||
| # If you want a smaller set of lints you can change this to specify | ||||
| # 'package:lints/core.yaml'. These are just the most critical lints | ||||
| # (the recommended set includes the core lints). | ||||
| # The core lints are also what is used by pub.dev for scoring packages. | ||||
| 
 | ||||
| include: package:lints/recommended.yaml | ||||
| 
 | ||||
| # Uncomment the following section to specify additional rules. | ||||
| 
 | ||||
| # linter: | ||||
| #   rules: | ||||
| #     - camel_case_types | ||||
| 
 | ||||
| # analyzer: | ||||
| #   exclude: | ||||
| #     - path/to/excluded/files/** | ||||
| 
 | ||||
| # For more information about the core and recommended set of lints, see | ||||
| # https://dart.dev/go/core-lints | ||||
| 
 | ||||
| # For additional information about configuring this file, see | ||||
| # https://dart.dev/guides/language/analysis-options | ||||
| include: package:wyatt_analysis/analysis_options.yaml | ||||
|  | ||||
| @ -1,102 +1,141 @@ | ||||
| import 'dart:io'; | ||||
| 
 | ||||
| import 'package:brick_generator/shell.dart'; | ||||
| import 'package:brick_generator/yaml_reader.dart'; | ||||
| import 'package:path/path.dart' as path; | ||||
| import 'package:yaml/yaml.dart'; | ||||
| 
 | ||||
| // Keys | ||||
| enum Syntax { | ||||
|   camelCase('camel_case', 'camelCase'), | ||||
|   constantCase('constant_case', 'constantCase'), | ||||
|   dotCase('dot_case', 'dotCase'), | ||||
|   headerCase('header_case', 'headerCase'), | ||||
|   lowerCase('lower_case', 'lowerCase'), | ||||
|   pascalCase('pascal_case', 'pascalCase'), | ||||
|   paramCase('param_case', 'paramCase'), | ||||
|   sentenceCase('sentence_case', 'sentenceCase'), | ||||
|   snakeCase('snake_case', 'snakeCase'), | ||||
|   titleCase('title_case', 'titleCase'), | ||||
|   upperCase('upper_case', 'upperCase'); | ||||
| 
 | ||||
|   final String mapKey; | ||||
|   final String id; | ||||
| 
 | ||||
|   const Syntax(this.mapKey, this.id); | ||||
| } | ||||
| 
 | ||||
| // Other Keys | ||||
| const _projectNameKey = 'project_name'; | ||||
| const _brickNameKey = 'brick_name'; | ||||
| const _pathToBrickifyKey = 'path_to_brickify'; | ||||
| const _syntaxKey = 'syntax'; | ||||
| 
 | ||||
| // Constants | ||||
| final _apps = 'apps'; | ||||
| final _bricks = 'bricks'; | ||||
| final _staticDir = path.join('tools', 'brick_generator', 'assets'); | ||||
| const _bricks = 'bricks'; | ||||
| const _brickFolderLabel = '__brick__'; | ||||
| const _yamlFileName = 'brick_config.yaml'; | ||||
| 
 | ||||
| Future<void> main(List<String> arguments) async { | ||||
|   final _appName = arguments[0]; | ||||
|   try { | ||||
|     if (arguments.length != 1) { | ||||
|       throw ArgumentError('Please entry exemple project path'); | ||||
|     } | ||||
| 
 | ||||
|   final _projectSnakeName = arguments[1]; | ||||
|   final _projectParamName = arguments[2]; | ||||
|   final _projectTitleName = arguments[3]; | ||||
|   final _orgName = arguments[4]; | ||||
|     final projectPath = arguments[0]; | ||||
| 
 | ||||
|   final _sourcePath = path.join(_apps, _appName); | ||||
|   final _targetPath = path.join(_bricks, _appName, '__brick__'); | ||||
|     // Store options from yaml file | ||||
|     final option = | ||||
|         YamlReader.readYamlFile(path.join(projectPath, _yamlFileName)); | ||||
|     final syntaxMap = option[_syntaxKey] as YamlMap; | ||||
|     stdout.writeln('🍺 get options $syntaxMap'); | ||||
| 
 | ||||
|   final _androidPath = path.join(_targetPath, 'android'); | ||||
|   final _androidKotlinPath = | ||||
|       path.join(_androidPath, 'app', 'src', 'main', 'kotlin'); | ||||
|   final _orgPath = path.join(_androidKotlinPath, 'com'); | ||||
| 
 | ||||
|   // Remove Previously Generated Files | ||||
|   final targetDir = Directory(_targetPath); | ||||
|   if (targetDir.existsSync()) { | ||||
|     await targetDir.delete(recursive: true); | ||||
|   } | ||||
| 
 | ||||
|   // Copy Project Files | ||||
|   await Shell.cp(_sourcePath, _targetPath); | ||||
| 
 | ||||
|   // Delete Android's Organization Folder Hierarchy | ||||
|   Directory(_orgPath).deleteSync(recursive: true); | ||||
| 
 | ||||
|   // Convert Values to Variables | ||||
|   await Future.wait( | ||||
|     Directory(_targetPath) | ||||
|         .listSync(recursive: true) | ||||
|         .whereType<File>() | ||||
|         .map((_) async { | ||||
|       var file = _; | ||||
| 
 | ||||
|       try { | ||||
| 
 | ||||
|         if (path.extension(file.path) == '.dart') { | ||||
|           final contents = await file.readAsString(); | ||||
|           file = await file.writeAsString(contents); | ||||
|         } | ||||
| 
 | ||||
|         final contents = await file.readAsString(); | ||||
|         file = await file.writeAsString( | ||||
|           contents | ||||
|               .replaceAll( | ||||
|                 _projectSnakeName, | ||||
|                 '{{#snakeCase}}{{project_name}}{{/snakeCase}}', | ||||
|               ) | ||||
|               .replaceAll( | ||||
|                 _projectParamName, | ||||
|                 '{{#paramCase}}{{project_name}}{{/paramCase}}', | ||||
|               ) | ||||
|               .replaceAll('A new Flutter project.', '{{{description}}}') | ||||
|               .replaceAll( | ||||
|                 _projectTitleName, | ||||
|                 '{{#titleCase}}{{project_name}}{{/titleCase}}', | ||||
|               ) | ||||
|               .replaceAll( | ||||
|                 _orgName, | ||||
|                 path.isWithin(_androidPath, file.path) | ||||
|                     ? '{{#dotCase}}{{org_name}}{{/dotCase}}.{{#snakeCase}}{{project_name}}{{/snakeCase}}' | ||||
|                     : '{{#dotCase}}{{org_name}}{{/dotCase}}.{{#paramCase}}{{project_name}}{{/paramCase}}', | ||||
|               ), | ||||
|     for (final syntax in Syntax.values) { | ||||
|       if (syntaxMap[syntax.mapKey] == null) { | ||||
|         throw ArgumentError( | ||||
|           'Yaml file is not conform : ${syntax.toString()} is missing', | ||||
|         ); | ||||
|         final fileSegments = file.path.split('/').sublist(2); | ||||
|         if (fileSegments.contains(_projectSnakeName)) { | ||||
|           final newPathSegment = fileSegments.join('/').replaceAll( | ||||
|                 _projectSnakeName, | ||||
|                 '{{#snakeCase}}{{project_name}}{{/snakeCase}}', | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     final projectName = option[_projectNameKey] as String; | ||||
|     final brickName = option[_brickNameKey] as String; | ||||
| 
 | ||||
|     // Define paths | ||||
|     final sourcePath = | ||||
|         path.join(projectPath, option[_pathToBrickifyKey] as String); | ||||
|     final targetPath = path.join(_bricks, brickName, _brickFolderLabel); | ||||
|     stdout.writeln('🍺 path defined'); | ||||
| 
 | ||||
|     // Remove previously generated files | ||||
|     final targetDir = Directory(targetPath); | ||||
|     if (targetDir.existsSync()) { | ||||
|       await targetDir.delete(recursive: true); | ||||
|     } | ||||
| 
 | ||||
|     // create target folder | ||||
|     await Shell.mkdir(targetPath); | ||||
| 
 | ||||
|     // Copy project files | ||||
|     await Shell.cp(sourcePath, targetPath); | ||||
|     stdout.writeln('🍺 files copied'); | ||||
| 
 | ||||
|     // Convert values to variables | ||||
|     await Future.wait( | ||||
|       Directory(targetPath) | ||||
|           .listSync(recursive: true) | ||||
|           .whereType<File>() | ||||
|           .map((_) async { | ||||
|         var file = _; | ||||
| 
 | ||||
|         try { | ||||
|           var contents = await file.readAsString(); | ||||
| 
 | ||||
|           // Transform all values in variables | ||||
|           for (final syntax in Syntax.values) { | ||||
|             contents = contents.replaceAll( | ||||
|               syntaxMap[syntax.mapKey] as String, | ||||
|               '{{#${syntax.id}}}{{$projectName}}{{/${syntax.id}}}', | ||||
|             ); | ||||
|           } | ||||
| 
 | ||||
|           file = await file.writeAsString(contents); | ||||
| 
 | ||||
|           // Rename file if needed | ||||
|           final filePath = file.path; | ||||
|           if (filePath.contains(syntaxMap[Syntax.snakeCase.mapKey] as String)) { | ||||
|             try { | ||||
|               var pathList = filePath.split(Platform.pathSeparator).sublist(3); | ||||
|               pathList = pathList | ||||
|                   .map( | ||||
|                     (segment) => segment.replaceAll( | ||||
|                       syntaxMap[Syntax.snakeCase.mapKey] as String, | ||||
|                       '{{$projectName.snakeCase()}}', | ||||
|                     ), | ||||
|                   ) | ||||
|                   .toList(); | ||||
| 
 | ||||
|               final newPath = path.join( | ||||
|                 filePath | ||||
|                     .split(Platform.pathSeparator) | ||||
|                     .sublist(0, 3) | ||||
|                     .join(Platform.pathSeparator), | ||||
|                 pathList.join(Platform.pathSeparator), | ||||
|               ); | ||||
|           final newPath = path.join(_targetPath, newPathSegment); | ||||
|           File(newPath).createSync(recursive: true); | ||||
|           file.renameSync(newPath); | ||||
|           Directory(file.parent.path).deleteSync(recursive: true); | ||||
| 
 | ||||
|               File(newPath).createSync(recursive: true); | ||||
|               file.renameSync(newPath); | ||||
|               Directory(file.parent.path).deleteSync(recursive: true); | ||||
|             } catch (_) { | ||||
|               stdout.writeln('❌ ${_.toString()}'); | ||||
|             } | ||||
|           } | ||||
|         } catch (_) { | ||||
|           stdout.writeln('❌ ${_.toString()}'); | ||||
|         } | ||||
|       } catch (_) {} | ||||
|     }), | ||||
|   ); | ||||
| 
 | ||||
|   final mainActivityKt = File( | ||||
|     path.join( | ||||
|       _androidKotlinPath, | ||||
|       '{{#pathCase}}{{org_name}}{{/pathCase}}', | ||||
|       'MainActivity.kt', | ||||
|     ), | ||||
|   ); | ||||
| 
 | ||||
|   await Shell.mkdir(mainActivityKt.parent.path); | ||||
|   await Shell.cp(path.join(_staticDir, 'MainActivity.kt'), mainActivityKt.path); | ||||
|       }), | ||||
|     ); | ||||
|   } catch (_) { | ||||
|     stdout.writeln('❌ ${_.toString()}'); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										7
									
								
								tools/brick_generator/lib/yaml_reader.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tools/brick_generator/lib/yaml_reader.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| import 'dart:io'; | ||||
| import 'package:yaml/yaml.dart'; | ||||
| 
 | ||||
| class YamlReader { | ||||
|   static YamlMap readYamlFile(String path) => | ||||
|       loadYaml(File(path).readAsStringSync()) as YamlMap; | ||||
| } | ||||
| @ -5,7 +5,15 @@ version: 1.0.0 | ||||
| publish_to: none | ||||
| 
 | ||||
| environment: | ||||
|   sdk: '>=2.17.0 <3.0.0' | ||||
|   sdk: ">=2.17.0 <3.0.0" | ||||
| 
 | ||||
| dependencies: | ||||
|   path: ^1.8.2 | ||||
|   yaml: ^3.1.1 | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   wyatt_analysis: | ||||
|     git: | ||||
|       url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages | ||||
|       ref: wyatt_analysis-v2.1.0 | ||||
|       path: packages/wyatt_analysis | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user