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/`. | in `lib/`. | ||||||
| 
 | 
 | ||||||
| ```sh | # How to use | ||||||
| dart /bin/brick_generator.dart wyatt_clean_code wyatt_clean_code wyatt-clean-code "Wyatt Demo" app.wyatt.io | 
 | ||||||
|  | - 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, | include: package:wyatt_analysis/analysis_options.yaml | ||||||
| # 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 |  | ||||||
|  | |||||||
| @ -1,102 +1,141 @@ | |||||||
| import 'dart:io'; | import 'dart:io'; | ||||||
| 
 | 
 | ||||||
| import 'package:brick_generator/shell.dart'; | import 'package:brick_generator/shell.dart'; | ||||||
|  | import 'package:brick_generator/yaml_reader.dart'; | ||||||
| import 'package:path/path.dart' as path; | 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 | // Constants | ||||||
| final _apps = 'apps'; | const _bricks = 'bricks'; | ||||||
| final _bricks = 'bricks'; | const _brickFolderLabel = '__brick__'; | ||||||
| final _staticDir = path.join('tools', 'brick_generator', 'assets'); | const _yamlFileName = 'brick_config.yaml'; | ||||||
| 
 | 
 | ||||||
| Future<void> main(List<String> arguments) async { | 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 projectPath = arguments[0]; | ||||||
|   final _projectParamName = arguments[2]; |  | ||||||
|   final _projectTitleName = arguments[3]; |  | ||||||
|   final _orgName = arguments[4]; |  | ||||||
| 
 | 
 | ||||||
|   final _sourcePath = path.join(_apps, _appName); |     // Store options from yaml file | ||||||
|   final _targetPath = path.join(_bricks, _appName, '__brick__'); |     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'); |     for (final syntax in Syntax.values) { | ||||||
|   final _androidKotlinPath = |       if (syntaxMap[syntax.mapKey] == null) { | ||||||
|       path.join(_androidPath, 'app', 'src', 'main', 'kotlin'); |         throw ArgumentError( | ||||||
|   final _orgPath = path.join(_androidKotlinPath, 'com'); |           'Yaml file is not conform : ${syntax.toString()} is missing', | ||||||
| 
 |  | ||||||
|   // 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}}', |  | ||||||
|               ), |  | ||||||
|         ); |         ); | ||||||
|         final fileSegments = file.path.split('/').sublist(2); |       } | ||||||
|         if (fileSegments.contains(_projectSnakeName)) { |     } | ||||||
|           final newPathSegment = fileSegments.join('/').replaceAll( | 
 | ||||||
|                 _projectSnakeName, |     final projectName = option[_projectNameKey] as String; | ||||||
|                 '{{#snakeCase}}{{project_name}}{{/snakeCase}}', |     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(newPath).createSync(recursive: true); | ||||||
|           file.renameSync(newPath); |               file.renameSync(newPath); | ||||||
|           Directory(file.parent.path).deleteSync(recursive: true); |               Directory(file.parent.path).deleteSync(recursive: true); | ||||||
|  |             } catch (_) { | ||||||
|  |               stdout.writeln('❌ ${_.toString()}'); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } catch (_) { | ||||||
|  |           stdout.writeln('❌ ${_.toString()}'); | ||||||
|         } |         } | ||||||
|       } catch (_) {} |       }), | ||||||
|     }), |     ); | ||||||
|   ); |   } catch (_) { | ||||||
| 
 |     stdout.writeln('❌ ${_.toString()}'); | ||||||
|   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); |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										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 | publish_to: none | ||||||
| 
 | 
 | ||||||
| environment: | environment: | ||||||
|   sdk: '>=2.17.0 <3.0.0' |   sdk: ">=2.17.0 <3.0.0" | ||||||
| 
 | 
 | ||||||
| dependencies: | dependencies: | ||||||
|   path: ^1.8.2 |   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