From 18aeef9e353797231649522a2d45440155af19d9 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Thu, 26 Jan 2023 16:29:16 +0100 Subject: [PATCH] feat: rewrite generator --- tools/brick_generator/bin/brick.yaml | 30 ++ .../brick_generator/bin/brick_generator.dart | 4 +- tools/brick_generator/bin/brickgen.dart | 182 +++++++++ .../brick_generator/lib/core/file_system.dart | 357 ++++++++++++++++++ .../lib/{ => core}/logger.dart | 8 +- .../brick_generator/lib/{ => core}/shell.dart | 21 +- .../lib/{ => core}/string_extension.dart | 20 +- .../lib/file_system_utils.dart | 8 +- .../lib/models/boolean_file_system.dart | 69 ++++ .../models/boolean_file_system_variable.dart | 61 +++ .../lib/models/boolean_mapping.dart | 77 ++++ .../lib/models/boolean_name_list_mapping.dart | 78 ++++ .../lib/models/boolean_name_mapping.dart | 21 ++ .../models/boolean_name_single_mapping.dart | 70 ++++ .../lib/models/brick_config.dart | 112 +++--- .../lib/models/brick_variable.dart | 59 ++- .../lib/models/brick_variable_boolean.dart | 53 +++ .../lib/models/brick_variable_string.dart | 62 +++ .../lib/models/brickgen_config.dart | 84 +++++ .../lib/models/ignore_list.dart | 108 ++++++ .../brick_generator/lib/models/log_level.dart | 4 +- .../lib/models/variable_string_syntax.dart | 4 +- .../lib/models/variable_type.dart | 10 +- tools/brick_generator/pubspec.yaml | 9 +- tools/brick_generator/test/string_test.dart | 10 +- 25 files changed, 1376 insertions(+), 145 deletions(-) create mode 100644 tools/brick_generator/bin/brick.yaml create mode 100644 tools/brick_generator/bin/brickgen.dart create mode 100644 tools/brick_generator/lib/core/file_system.dart rename tools/brick_generator/lib/{ => core}/logger.dart (91%) rename tools/brick_generator/lib/{ => core}/shell.dart (83%) rename tools/brick_generator/lib/{ => core}/string_extension.dart (96%) create mode 100644 tools/brick_generator/lib/models/boolean_file_system.dart create mode 100644 tools/brick_generator/lib/models/boolean_file_system_variable.dart create mode 100644 tools/brick_generator/lib/models/boolean_mapping.dart create mode 100644 tools/brick_generator/lib/models/boolean_name_list_mapping.dart create mode 100644 tools/brick_generator/lib/models/boolean_name_mapping.dart create mode 100644 tools/brick_generator/lib/models/boolean_name_single_mapping.dart create mode 100644 tools/brick_generator/lib/models/brick_variable_boolean.dart create mode 100644 tools/brick_generator/lib/models/brick_variable_string.dart create mode 100644 tools/brick_generator/lib/models/brickgen_config.dart create mode 100644 tools/brick_generator/lib/models/ignore_list.dart diff --git a/tools/brick_generator/bin/brick.yaml b/tools/brick_generator/bin/brick.yaml new file mode 100644 index 0000000..0d107b1 --- /dev/null +++ b/tools/brick_generator/bin/brick.yaml @@ -0,0 +1,30 @@ +name: +description: + +version: 0.1.0 + +vars: + display_name: + type: string + description: The display name + default: Display Name + prompt: What is the display name? + + project_name: + type: string + description: The project name + default: wyatt_app + prompt: What is the project name? + + bundle_id: + type: string + description: The bundle id used in Android and iOS + default: io.wyattapp.new + prompt: What is the bundle id? + + flutter: + type: boolean + description: If this app is a Flutter or Dart project. + default: false + prompt: Is it Flutter app ? + diff --git a/tools/brick_generator/bin/brick_generator.dart b/tools/brick_generator/bin/brick_generator.dart index eccf02e..ceecce0 100644 --- a/tools/brick_generator/bin/brick_generator.dart +++ b/tools/brick_generator/bin/brick_generator.dart @@ -1,9 +1,9 @@ import 'dart:io'; +import 'package:brick_generator/core/logger.dart'; +import 'package:brick_generator/core/shell.dart'; import 'package:brick_generator/file_system_utils.dart'; -import 'package:brick_generator/logger.dart'; import 'package:brick_generator/models/brick_config.dart'; -import 'package:brick_generator/shell.dart'; import 'package:brick_generator/yaml_reader.dart'; import 'package:path/path.dart' as path; diff --git a/tools/brick_generator/bin/brickgen.dart b/tools/brick_generator/bin/brickgen.dart new file mode 100644 index 0000000..fc162b7 --- /dev/null +++ b/tools/brick_generator/bin/brickgen.dart @@ -0,0 +1,182 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:brick_generator/core/file_system.dart'; +import 'package:brick_generator/core/logger.dart'; +import 'package:brick_generator/models/brick_config.dart'; +import 'package:path/path.dart'; + +const _configurationFileName = 'brickgen.yaml'; +const _masonConfigurationFileName = 'brick.yaml'; +const _brickFolderName = '__brick__'; + +const _helpOption = 'help'; +const _verboseOption = 'verbose'; +const _removeEmptyOption = 'remove-empty'; + +class Brickgen { + final String brickPath; + final String outputPath; + final bool deleteEmptyFolders; + + late String configPath; + + String? toBrickifyPath; + String? masonConfigPath; + String? targetPath; + + Brickgen({ + required this.brickPath, + required this.outputPath, + required this.deleteEmptyFolders, + }) { + configPath = join(brickPath, _configurationFileName); + } + + Future run() async { + // Load config + final config = BrickConfig.fromFile(configPath); + Logger.debug('Read config: \n${config.toMason()}'); + Logger.info('Config retrieved.'); + + // Define paths + toBrickifyPath = FileSystem.joinExists( + brickPath, + config.brickgenConfig.pathToBrickify, + ); + Logger.debug('Define `toBrickifyPath`: $toBrickifyPath'); + + masonConfigPath = FileSystem.joinTouch( + outputPath, + config.name, + _masonConfigurationFileName, + ); + Logger.debug('Define `masonConfigPath`: $masonConfigPath'); + + targetPath = FileSystem.joinRecreate( + outputPath, + config.name, + _brickFolderName, + ); + Logger.debug('Define `targetPath`: $targetPath'); + + // Check paths + if (toBrickifyPath == null || targetPath == null) { + throw Exception('An error occures during path definition.'); + } + Logger.info('Paths defined.'); + + // Copy (and exclude from copy) project files + await FileSystem.copyFolder( + toBrickifyPath!, + targetPath!, + ignoreList: config.brickgenConfig.ignore, + ); + Logger.info('Project copied.'); + + // Convert compilable values -> variables (in files) + FileSystem.convertCompilableVariablesInFolder(config, targetPath!); + Logger.info('Files content converted with variables.'); + + // Create `.gitkeep` in empty folders (to keep them in brick generation) + // Or remove them (depending of --remove option) + if (deleteEmptyFolders) { + FileSystem.removeEmptyFolders(targetPath!); + Logger.info('Empty folders removed.'); + } else { + FileSystem.createGitKeepInEmptyFolders(targetPath!); + Logger.info('Empty folders marked as to keep.'); + } + + // Convert compilable values -> variables (files/folder names) + FileSystem.renameCompilableFilesInFolder(config, targetPath!); + Logger.info('Files renamed with variables.'); + + // Take care of boolean mapping and boolean fs + + // Create Mason config + FileSystem.writeFile(masonConfigPath!, config.toMason()); + Logger.info('Mason `brick.yaml` generated.'); + + // Create gitkeep hook + + // Copy custom hooks + + // Success! + } +} + +Future main(List args) async { + int exitCode = 0; + + final parser = ArgParser() + ..addFlag( + _helpOption, + negatable: false, + abbr: 'h', + help: 'Show this help dialog', + ) + ..addFlag( + _verboseOption, + negatable: false, + abbr: 'v', + help: 'Show additional diagnostic info', + ) + ..addFlag( + _removeEmptyOption, + negatable: false, + abbr: 'r', + help: 'Remove empty folders (if not it creates ' + '.gitkeep in each empty folders)', + ); + + final argResults = parser.parse(args); + + if (argResults[_helpOption] as bool? ?? false) { + Logger.info('Brickgen\n${parser.usage}'); + exit(0); + } + + if (argResults[_verboseOption] as bool? ?? false) { + Logger.setVerbose(); + } + + final paths = argResults.rest; + + if (paths.length < 2) { + Logger.error('Please provide input and output paths.'); + if (!(argResults[_helpOption] as bool? ?? false)) { + Logger.info('Brickgen\n${parser.usage}'); + } + exitCode = 1; + exit(exitCode); + } + + final brickPath = paths[0]; + final outputPath = paths[1]; + + await Brickgen( + brickPath: brickPath, + outputPath: outputPath, + deleteEmptyFolders: argResults[_removeEmptyOption] as bool? ?? false, + ).run(); + + exit(exitCode); +} diff --git a/tools/brick_generator/lib/core/file_system.dart b/tools/brick_generator/lib/core/file_system.dart new file mode 100644 index 0000000..60e77fd --- /dev/null +++ b/tools/brick_generator/lib/core/file_system.dart @@ -0,0 +1,357 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:io'; + +import 'package:brick_generator/core/logger.dart'; +import 'package:brick_generator/core/shell.dart'; +import 'package:brick_generator/models/brick_config.dart'; +import 'package:brick_generator/models/brick_variable_string.dart'; +import 'package:brick_generator/models/ignore_list.dart'; +import 'package:brick_generator/models/variable_string_syntax.dart'; +import 'package:path/path.dart'; + +abstract class FileSystem { + static void writeFile(String path, Object? content, {bool binary = false}) { + final file = File(join(path))..createSync(recursive: true); + + if (content == null) { + // Just create an empty file + return; + } + + try { + if (binary) { + file.writeAsBytesSync(content as List); + } else { + file.writeAsStringSync(content as String); + } + } catch (e) { + Logger.error(e); + } + } + + static Future copyFolder( + String from, + String to, { + IgnoreList? ignoreList, + }) async { + if (!FileSystemEntity.isDirectorySync(from)) { + throw ArgumentError('Path must be a directory', 'from'); + } + + final List copiedFolders = []; + + // Copy folders + await Future.wait( + Directory(from) + .listSync(recursive: true) + .whereType() + .map((directory) async { + final absolutPath = directory.path; + final name = absolutPath.split('/').last; + + if (ignoreList != null && ignoreList.contains(from, absolutPath)) { + Logger.debug('Ignoring $absolutPath'); + } else { + Logger.debug('cp -Rf $absolutPath $to/$name'); + copiedFolders.add(absolutPath); + await Shell.cp(absolutPath, '$to/$name'); + } + }), + ); + + // Copy files + await Future.wait( + Directory(from) + .listSync(recursive: true) + .whereType() + .map((file) async { + final absolutPath = file.path; + final name = absolutPath.split('/').last; + + if (ignoreList != null && ignoreList.contains(from, absolutPath)) { + Logger.debug('Ignoring $absolutPath'); + } else { + if (copiedFolders.any(absolutPath.startsWith)) { + Logger.debug('$absolutPath already copied!'); + } else { + Logger.debug('cp -Rf $absolutPath $to/$name'); + await Shell.cp(absolutPath, '$to/$name'); + } + } + }), + ); + } + + static void makeDirectory(String path) { + final dir = Directory(path); + if (dir.existsSync()) { + dir.deleteSync(recursive: true); + } + dir.createSync(recursive: true); + } + + /// Join and verify if the joined path exists. + static String joinExists( + String part1, [ + String? part2, + String? part3, + String? part4, + String? part5, + String? part6, + String? part7, + String? part8, + ]) { + final path = join(part1, part2, part3, part4, part5, part6, part7, part8); + + if (FileSystemEntity.isDirectorySync(path)) { + Logger.debug('$path is a directory, and it exists.'); + return path; + } + + if (FileSystemEntity.isFileSync(path)) { + Logger.debug('$path is a file, and it exists.'); + return path; + } + + throw ArgumentError('Joined path is not existing.'); + } + + /// Join and verify if the joined path exists. If not, create it. + static String joinCreate( + String part1, [ + String? part2, + String? part3, + String? part4, + String? part5, + String? part6, + String? part7, + String? part8, + ]) { + final path = join(part1, part2, part3, part4, part5, part6, part7, part8); + + if (FileSystemEntity.isDirectorySync(path)) { + Logger.debug('$path is a directory, and it exists.'); + return path; + } + + if (FileSystemEntity.isFileSync(path)) { + Logger.debug('$path is a file, and it exists.'); + return path; + } + + makeDirectory(path); + Logger.debug('$path directory was created.'); + return path; + } + + /// Join and verify if the joined path exists. If yes, recreate it. + static String joinRecreate( + String part1, [ + String? part2, + String? part3, + String? part4, + String? part5, + String? part6, + String? part7, + String? part8, + ]) { + final path = join(part1, part2, part3, part4, part5, part6, part7, part8); + + if (FileSystemEntity.isDirectorySync(path)) { + makeDirectory(path); + Logger.debug('$path directory was recreated.'); + return path; + } + + if (FileSystemEntity.isFileSync(path)) { + Logger.debug('$path is a file ! No recreate it!'); + return path; + } + + makeDirectory(path); + Logger.debug('$path directory was created.'); + return path; + } + + /// Join and verify if the joined path exists. If yes, touch it. If not + /// create an empty file. + static String joinTouch( + String part1, [ + String? part2, + String? part3, + String? part4, + String? part5, + String? part6, + String? part7, + String? part8, + ]) { + final path = join(part1, part2, part3, part4, part5, part6, part7, part8); + + if (FileSystemEntity.isDirectorySync(path)) { + Logger.debug('$path is a directory ! No recreate it!'); + return path; + } + + if (FileSystemEntity.isFileSync(path)) { + writeFile(path, null); + Logger.debug('$path files was touched!'); + return path; + } + + writeFile(path, null); + Logger.debug('$path file was created.'); + return path; + } + + /// Transforms compilable variables: + /// For each String `vars` in config, search for compilable in code, then + /// convert it to his mustache format. + /// + /// Example: + /// ```yaml + /// bundle_id: + /// compilable: io.wyattapp.new + /// type: string + /// description: The bundle id used in Android and iOS + /// default: io.wyattapp.new + /// prompt: "What is the bundle id?" + /// ``` + /// + /// Search for `io.wyattapp.new` then converts + /// it to `{{#dotCase}}{{bundle_id}}{{/dotCase}}` + static void convertCompilableVariablesInFolder( + BrickConfig config, + String targetPath, + ) { + if (!FileSystemEntity.isDirectorySync(targetPath)) { + throw ArgumentError('Target must be a directory', 'targetPath'); + } + + Directory(targetPath) + .listSync(recursive: true) + .whereType() + .forEach((file) { + String? contents; + + try { + contents = file.readAsStringSync(); + } catch (e) { + Logger.error(e); + } + + config.variables.whereType().forEach((variable) { + // Replace all string variables + for (final syntax in VariableStringSyntax.values) { + final toReplace = variable.syntax?[syntax.mapKey]; + if (toReplace != null) { + contents = contents!.replaceAll( + toReplace, + '{{#${syntax.id}}}{{${variable.name}}}{{/${syntax.id}}}', + ); + } + } + Logger.debug('Variable `${variable.name}` replaced in ${file.path}'); + }); + + file.writeAsStringSync(contents!); + }); + } + + static void createGitKeepInEmptyFolders(String targetPath) { + if (!FileSystemEntity.isDirectorySync(targetPath)) { + throw ArgumentError('Target must be a directory', 'targetPath'); + } + + Directory(targetPath) + .listSync(recursive: true) + .whereType() + .forEach((directory) { + if (directory.existsSync() && + directory.listSync(recursive: true).isEmpty) { + joinTouch(directory.path, '.gitkeep'); + Logger.debug('${directory.path} (empty) marked as to keep.'); + } + }); + } + + static void removeEmptyFolders(String targetPath) { + if (!FileSystemEntity.isDirectorySync(targetPath)) { + throw ArgumentError('Target must be a directory', 'targetPath'); + } + + Directory(targetPath) + .listSync(recursive: true) + .whereType() + .forEach((directory) { + if (directory.existsSync() && + directory.listSync(recursive: true).isEmpty) { + directory.deleteSync(recursive: true); + Logger.debug('${directory.path} (empty) deleted.'); + } + }); + } + + /// Transforms compilable file/folder names: + /// For each String `vars` in config, search for compilable in code, then + /// convert it to his mustache format. + /// + /// Example: + /// ```yaml + /// project_name: + /// compilable: wyatt_app_template + /// type: string + /// description: The project name + /// default: wyatt_app + /// prompt: "What is the project name?" + /// ``` + /// + /// Search for `wyatt_app_template` files and folders then converts + /// it to `{{project_name.snakeCase()}}` + static void renameCompilableFilesInFolder( + BrickConfig config, + String targetPath, + ) { + if (!FileSystemEntity.isDirectorySync(targetPath)) { + throw ArgumentError('Target must be a directory', 'targetPath'); + } + + Directory(targetPath) + .listSync(recursive: true) + .whereType() + .forEach((file) { + config.variables.whereType().forEach((variable) { + // Replace all string variables + for (final syntax in VariableStringSyntax.values) { + final toReplace = variable.syntax?[syntax.mapKey]; + if (toReplace != null && file.path.contains(toReplace)) { + final newPath = file.path.replaceAll( + toReplace, + '{{${variable.name}.${syntax.id}}}', + ); + + File(newPath).createSync(recursive: true); + file.renameSync(newPath); + Logger.debug( + '${file.path} renamed with variable `${variable.name}`', + ); + } + } + }); + }); + } +} diff --git a/tools/brick_generator/lib/logger.dart b/tools/brick_generator/lib/core/logger.dart similarity index 91% rename from tools/brick_generator/lib/logger.dart rename to tools/brick_generator/lib/core/logger.dart index 1e60a6d..5176418 100644 --- a/tools/brick_generator/lib/logger.dart +++ b/tools/brick_generator/lib/core/logger.dart @@ -19,12 +19,18 @@ import 'dart:io'; import 'package:brick_generator/models/log_level.dart'; class Logger { + static bool verbose = false; + + static void setVerbose() => verbose = true; + static void log(Object? message, {LogLevel level = LogLevel.info}) { stdout.writeln('${level.prefix} ${message.toString()}'); } static void debug(Object? message) { - log(message, level: LogLevel.debug); + if (verbose) { + log(message, level: LogLevel.debug); + } } static void info(Object? message) { diff --git a/tools/brick_generator/lib/shell.dart b/tools/brick_generator/lib/core/shell.dart similarity index 83% rename from tools/brick_generator/lib/shell.dart rename to tools/brick_generator/lib/core/shell.dart index 7eaac2f..ad5a92e 100644 --- a/tools/brick_generator/lib/shell.dart +++ b/tools/brick_generator/lib/core/shell.dart @@ -16,23 +16,20 @@ import 'dart:io'; -import 'package:brick_generator/logger.dart'; +import 'package:brick_generator/core/logger.dart'; -class Shell { - static Future cp(String source, String destination) { - return _Cmd.run('cp', ['-Rf', source, destination]); - } +abstract class Shell { + static Future cp(String source, String destination) => + _Cmd.run('cp', ['-Rf', source, destination]); - static Future mkdir(String destination) { - return _Cmd.run('mkdir', ['-p', destination]); - } + static Future mkdir(String destination) => + _Cmd.run('mkdir', ['-p', destination]); - static Future rm(String target, {bool recursive = false}) { - return _Cmd.run('rm', ['-f${recursive ? "r" : ""}', target]); - } + static Future rm(String target, {bool recursive = false}) => + _Cmd.run('rm', ['-f${recursive ? "r" : ""}', target]); } -class _Cmd { +abstract class _Cmd { static Future run( String cmd, List args, { diff --git a/tools/brick_generator/lib/string_extension.dart b/tools/brick_generator/lib/core/string_extension.dart similarity index 96% rename from tools/brick_generator/lib/string_extension.dart rename to tools/brick_generator/lib/core/string_extension.dart index 2dcbebf..4edff8e 100644 --- a/tools/brick_generator/lib/string_extension.dart +++ b/tools/brick_generator/lib/core/string_extension.dart @@ -291,27 +291,21 @@ extension StringExtension on String { /// print('Hello World'.sentence()) // Hello world /// print('helloWorld'.sentence()) // Hello world /// ``` - String sentence() { - return lower().capitalize(); - } + String sentence() => lower().capitalize(); /// ```dart /// print('Hello World'.title()) // Hello World /// print('helloWorld'.title()) // Hello World /// ``` - String title() { - return header().splitMapJoin( - _defaultMatcher, - onMatch: (m) => ' ', - onNonMatch: (n) => n, - ); - } + String title() => header().splitMapJoin( + _defaultMatcher, + onMatch: (m) => ' ', + onNonMatch: (n) => n, + ); /// ```dart /// print('Hello World'.mustache()) // {{ Hello World }} /// print('helloWorld'.mustache()) // {{ Hello World }} /// ``` - String mustache() { - return '{{ ${title()} }}'; - } + String mustache() => '{{ ${title()} }}'; } diff --git a/tools/brick_generator/lib/file_system_utils.dart b/tools/brick_generator/lib/file_system_utils.dart index 94bead9..b499f55 100644 --- a/tools/brick_generator/lib/file_system_utils.dart +++ b/tools/brick_generator/lib/file_system_utils.dart @@ -16,11 +16,11 @@ import 'dart:io'; -import 'package:brick_generator/logger.dart'; +import 'package:brick_generator/core/logger.dart'; +import 'package:brick_generator/core/shell.dart'; import 'package:brick_generator/models/brick_config.dart'; import 'package:brick_generator/models/variable_string_syntax.dart'; import 'package:brick_generator/models/variable_type.dart'; -import 'package:brick_generator/shell.dart'; import 'package:path/path.dart'; class FileSystemUtils { @@ -88,7 +88,7 @@ class FileSystemUtils { final snake = variable!.syntax![VariableStringSyntax.snakeCase.mapKey]; if (snake == null) { - final err = 'Invalid snake_case syntax'; + const err = 'Invalid snake_case syntax'; Logger.throwError(ArgumentError(err), err); } final newPath = file.path.replaceAll( @@ -123,7 +123,7 @@ class FileSystemUtils { BrickConfig brickConfig, String brickPath, ) async { - for (final String ignore in brickConfig.brickIgnore ?? []) { + for (final String ignore in brickConfig.brickgenConfig.ignore.ignored) { final String toDelete = join(brickPath, ignore); if (FileSystemEntity.isDirectorySync(toDelete)) { await Shell.rm(toDelete, recursive: true); diff --git a/tools/brick_generator/lib/models/boolean_file_system.dart b/tools/brick_generator/lib/models/boolean_file_system.dart new file mode 100644 index 0000000..f03f227 --- /dev/null +++ b/tools/brick_generator/lib/models/boolean_file_system.dart @@ -0,0 +1,69 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/models/boolean_file_system_variable.dart'; +import 'package:yaml/yaml.dart'; + +const _foldersKey = 'folders'; +const _filesKey = 'files'; + +class BooleanFileSystem { + BooleanFileSystem({ + required this.booleanName, + required this.folders, + required this.files, + }); + + factory BooleanFileSystem.fromYaml(String key, YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + final variableName = key; + final folders = BooleanFileSystemVariable.fromYaml( + source.nodes[_foldersKey] as YamlMap?, + ); + final files = BooleanFileSystemVariable.fromYaml( + source.nodes[_filesKey] as YamlMap?, + ); + + return BooleanFileSystem( + booleanName: variableName, + folders: folders, + files: files, + ); + } + + String booleanName; + BooleanFileSystemVariable folders; + BooleanFileSystemVariable files; + + BooleanFileSystem copyWith({ + String? booleanName, + BooleanFileSystemVariable? folders, + BooleanFileSystemVariable? files, + }) => + BooleanFileSystem( + booleanName: booleanName ?? this.booleanName, + folders: folders ?? this.folders, + files: files ?? this.files, + ); + + @override + String toString() => 'BooleanFileSystem(booleanName: $booleanName, ' + 'folders: $folders, files: $files)'; +} diff --git a/tools/brick_generator/lib/models/boolean_file_system_variable.dart b/tools/brick_generator/lib/models/boolean_file_system_variable.dart new file mode 100644 index 0000000..6fa2eb2 --- /dev/null +++ b/tools/brick_generator/lib/models/boolean_file_system_variable.dart @@ -0,0 +1,61 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:yaml/yaml.dart'; + +const _onTrueKey = 'on_true'; +const _onFalseKey = 'on_false'; + +class BooleanFileSystemVariable { + BooleanFileSystemVariable({ + required this.onTrueNames, + required this.onFalseNames, + }); + + factory BooleanFileSystemVariable.fromYaml(YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + final onTrueNames = (source[_onTrueKey] as YamlList?) + ?.map((element) => element as String) + .toList(); + final onFalseNames = (source[_onFalseKey] as YamlList?) + ?.map((element) => element as String) + .toList(); + + return BooleanFileSystemVariable( + onTrueNames: onTrueNames ?? [], + onFalseNames: onFalseNames ?? [], + ); + } + + final List onTrueNames; + final List onFalseNames; + + BooleanFileSystemVariable copyWith({ + List? onTrueNames, + List? onFalseNames, + }) => + BooleanFileSystemVariable( + onTrueNames: onTrueNames ?? this.onTrueNames, + onFalseNames: onFalseNames ?? this.onFalseNames, + ); + + @override + String toString() => 'BooleanFileSystemVariable(onTrueNames: $onTrueNames, ' + 'onFalseNames: $onFalseNames)'; +} diff --git a/tools/brick_generator/lib/models/boolean_mapping.dart b/tools/brick_generator/lib/models/boolean_mapping.dart new file mode 100644 index 0000000..28e413f --- /dev/null +++ b/tools/brick_generator/lib/models/boolean_mapping.dart @@ -0,0 +1,77 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/models/boolean_name_single_mapping.dart'; +import 'package:yaml/yaml.dart'; + +const _foldersKey = 'folders'; +const _filesKey = 'files'; + +class BooleanMapping { + BooleanMapping({ + required this.booleanName, + required this.folders, + required this.files, + }); + + factory BooleanMapping.fromYaml(String key, YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + final variableName = key; + final folders = (source.nodes[_foldersKey] as YamlList?) + ?.map( + (element) => + BooleanNameSingleMapping.fromYaml(element as YamlMap?), + ) + .toList() ?? + []; + final files = (source.nodes[_filesKey] as YamlList?) + ?.map( + (element) => + BooleanNameSingleMapping.fromYaml(element as YamlMap?), + ) + .toList() ?? + []; + + return BooleanMapping( + booleanName: variableName, + folders: folders, + files: files, + ); + } + + String booleanName; + List folders; + List files; + + BooleanMapping copyWith({ + String? booleanName, + List? folders, + List? files, + }) => + BooleanMapping( + booleanName: booleanName ?? this.booleanName, + folders: folders ?? this.folders, + files: files ?? this.files, + ); + + @override + String toString() => 'BooleanMapping(booleanName: $booleanName, ' + 'folders: $folders, files: $files)'; +} diff --git a/tools/brick_generator/lib/models/boolean_name_list_mapping.dart b/tools/brick_generator/lib/models/boolean_name_list_mapping.dart new file mode 100644 index 0000000..164621e --- /dev/null +++ b/tools/brick_generator/lib/models/boolean_name_list_mapping.dart @@ -0,0 +1,78 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/models/boolean_name_mapping.dart'; +import 'package:yaml/yaml.dart'; + +const _onTrueKey = 'on_true'; +const _onFalseKey = 'on_false'; + +class BooleanNameListMapping extends BooleanNameMapping { + BooleanNameListMapping({ + required this.fileSystemEntityName, + required this.onTrueNames, + required this.onFalseNames, + }); + + factory BooleanNameListMapping.fromYaml(YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + final fsEntityName = source.keys.first as String; + final onTrueNames = + ((source.values.first as YamlMap?)?[_onTrueKey] as YamlList?) + ?.map((element) => element as String) + .toList(); + final onFalseNames = + ((source.values.first as YamlMap?)?[_onFalseKey] as YamlList?) + ?.map((element) => element as String) + .toList(); + + return BooleanNameListMapping( + fileSystemEntityName: fsEntityName, + onTrueNames: onTrueNames ?? [], + onFalseNames: onFalseNames ?? [], + ); + } + + @override + final String fileSystemEntityName; + final List onTrueNames; + final List onFalseNames; + + BooleanNameListMapping copyWith({ + String? fileSystemEntityName, + List? onTrueNames, + List? onFalseNames, + }) => + BooleanNameListMapping( + fileSystemEntityName: fileSystemEntityName ?? this.fileSystemEntityName, + onTrueNames: onTrueNames ?? this.onTrueNames, + onFalseNames: onFalseNames ?? this.onFalseNames, + ); + + @override + String get onFalseName => onFalseNames.first; + + @override + String get onTrueName => onTrueNames.first; + + @override + String toString() => + 'BooleanNameListMapping(fileSystemEntityName: $fileSystemEntityName, ' + 'onTrueNames: $onTrueNames, onFalseNames: $onFalseNames)'; +} diff --git a/tools/brick_generator/lib/models/boolean_name_mapping.dart b/tools/brick_generator/lib/models/boolean_name_mapping.dart new file mode 100644 index 0000000..0a8858f --- /dev/null +++ b/tools/brick_generator/lib/models/boolean_name_mapping.dart @@ -0,0 +1,21 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +abstract class BooleanNameMapping { + String get fileSystemEntityName; + String get onTrueName; + String get onFalseName; +} diff --git a/tools/brick_generator/lib/models/boolean_name_single_mapping.dart b/tools/brick_generator/lib/models/boolean_name_single_mapping.dart new file mode 100644 index 0000000..1dfb068 --- /dev/null +++ b/tools/brick_generator/lib/models/boolean_name_single_mapping.dart @@ -0,0 +1,70 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/models/boolean_name_mapping.dart'; +import 'package:yaml/yaml.dart'; + +const _onTrueKey = 'on_true'; +const _onFalseKey = 'on_false'; + +class BooleanNameSingleMapping extends BooleanNameMapping { + BooleanNameSingleMapping({ + required this.fileSystemEntityName, + required this.onTrueName, + required this.onFalseName, + }); + + factory BooleanNameSingleMapping.fromYaml(YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + final fsEntityName = source.keys.first as String; + final onTrueName = + (source.values.first as YamlMap?)?[_onTrueKey] as String?; + final onFalseName = + (source.values.first as YamlMap?)?[_onFalseKey] as String?; + + return BooleanNameSingleMapping( + fileSystemEntityName: fsEntityName, + onTrueName: onTrueName ?? fsEntityName, + onFalseName: onFalseName ?? fsEntityName, + ); + } + + @override + final String fileSystemEntityName; + @override + final String onTrueName; + @override + final String onFalseName; + + BooleanNameSingleMapping copyWith({ + String? fileSystemEntityName, + String? onTrueName, + String? onFalseName, + }) => + BooleanNameSingleMapping( + fileSystemEntityName: fileSystemEntityName ?? this.fileSystemEntityName, + onTrueName: onTrueName ?? this.onTrueName, + onFalseName: onFalseName ?? this.onFalseName, + ); + + @override + String toString() => + 'BooleanNameSingleMapping(fileSystemEntityName: $fileSystemEntityName, ' + 'onTrueName: $onTrueName, onFalseName: $onFalseName)'; +} diff --git a/tools/brick_generator/lib/models/brick_config.dart b/tools/brick_generator/lib/models/brick_config.dart index cd3f8e5..a514dcf 100644 --- a/tools/brick_generator/lib/models/brick_config.dart +++ b/tools/brick_generator/lib/models/brick_config.dart @@ -14,96 +14,86 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:brick_generator/logger.dart'; import 'package:brick_generator/models/brick_variable.dart'; +import 'package:brick_generator/models/brickgen_config.dart'; +import 'package:brick_generator/yaml_reader.dart'; import 'package:yaml/yaml.dart'; const _nameKey = 'name'; const _descriptionKey = 'description'; const _versionKey = 'version'; -const _pathToBrickifyKey = 'path_to_brickify'; -const _brickIgnoreKey = 'brick_ignore'; const _varsKey = 'vars'; +const _brickgenKey = 'brickgen'; class BrickConfig { - String? name; - String? description; - String? version; - String? pathToBrickify; - List? brickIgnore; - List? variables; - BrickConfig({ required this.name, required this.description, required this.version, - required this.pathToBrickify, - required this.brickIgnore, required this.variables, + required this.brickgenConfig, }); - BrickConfig._(); - factory BrickConfig.parser() => BrickConfig._(); + factory BrickConfig.parse(YamlMap? data) { + if (data == null) { + throw ArgumentError.notNull('data'); + } - static BrickConfig? from(YamlMap? data) => data != null - ? BrickConfig( - name: data[_nameKey] as String?, - description: data[_descriptionKey] as String?, - version: data[_versionKey] as String?, - pathToBrickify: data[_pathToBrickifyKey] as String?, - brickIgnore: (data[_brickIgnoreKey] as YamlList?) - ?.map((dynamic element) => element as String) - .toList(), - variables: (data[_varsKey] as YamlMap?) - ?.map( - (dynamic key, dynamic value) => - MapEntry( - key, - BrickVariable.from(value as YamlMap?), - ), - ) - .values - .toList(), + final variables = (data[_varsKey] as YamlMap?) + ?.entries + .map( + (e) => BrickVariable.fromYaml(e.key as String, e.value as YamlMap?), ) - : null; + .toList(); - void checkFormat() { - if (name == null || description == null || pathToBrickify == null) { - final err = 'Yaml file is not conform'; - Logger.throwError(ArgumentError(err), err); - } - if (variables != null) { - for (final variable in variables!) { - variable?.checkFormat(); - } - } + final config = BrickConfig( + name: data[_nameKey] as String? ?? '', + description: data[_descriptionKey] as String? ?? '', + version: data[_versionKey] as String? ?? '', + variables: variables ?? [], + brickgenConfig: BrickgenConfig.parse(data[_brickgenKey] as YamlMap?), + ); + + return config; } - String toBrickYaml() { - String content = ''' + factory BrickConfig.fromFile(String? path) { + if (path == null) { + throw ArgumentError.notNull('path'); + } + + final config = YamlReader.readYamlFile(path); + + return BrickConfig.parse(config); + } + + String name; + String description; + String version; + List> variables; + BrickgenConfig brickgenConfig; + + String toMason() { + final content = StringBuffer(''' name: $name description: $description version: $version -'''; +'''); - if (variables?.isNotEmpty ?? false) { - content += 'vars:\n'; - for (final BrickVariable? v in variables!) { - if (v != null) { - final vString = ''' - ${v.name}: - type: ${v.type.toString()} - description: ${v.description} - default: ${v.defaultValue} - prompt: ${v.prompt} -'''; - content += vString; - } + if (variables.isNotEmpty) { + content.writeln('vars:'); + for (final variable in variables) { + content.writeln(variable.toMason()); } } - return content; + return content.toString(); } + + @override + String toString() => 'BrickConfig(name: $name, ' + 'description: $description, version: $version, variables: $variables, ' + 'brickgenConfig: $brickgenConfig)'; } diff --git a/tools/brick_generator/lib/models/brick_variable.dart b/tools/brick_generator/lib/models/brick_variable.dart index ea75004..23827e8 100644 --- a/tools/brick_generator/lib/models/brick_variable.dart +++ b/tools/brick_generator/lib/models/brick_variable.dart @@ -14,53 +14,46 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:brick_generator/logger.dart'; +import 'package:brick_generator/models/brick_variable_boolean.dart'; +import 'package:brick_generator/models/brick_variable_string.dart'; import 'package:brick_generator/models/variable_type.dart'; -import 'package:brick_generator/string_extension.dart'; import 'package:yaml/yaml.dart'; const _typeKey = 'type'; -const _nameKey = 'name'; -const _descriptionKey = 'description'; -const _defaultKey = 'default'; -const _promptKey = 'prompt'; - -class BrickVariable { - VariableType? type; - String? name; - String? description; - String? defaultValue; - String? prompt; - Map? syntax; +abstract class BrickVariable { BrickVariable({ required this.type, required this.name, required this.description, required this.defaultValue, required this.prompt, - required this.syntax, }); - BrickVariable._(); + String name; + VariableType type; + String description; + T defaultValue; + String prompt; - factory BrickVariable.parser() => BrickVariable._(); - - static BrickVariable? from(YamlMap? data) => data != null - ? BrickVariable( - type: VariableType.fromString(data[_typeKey] as String?), - name: data[_nameKey] as String?, - description: data[_descriptionKey] as String?, - defaultValue: data[_defaultKey] as String?, - prompt: data[_promptKey] as String?, - syntax: (data[_nameKey] as String? ?? '').syntaxes, - ) - : null; - - void checkFormat() { - if (name == null || description == null || type == null) { - final err = 'Yaml file is not conform'; - Logger.throwError(ArgumentError(err), err); + static BrickVariable fromYaml(String key, YamlMap? source) { + final type = VariableType.fromString(source?[_typeKey] as String?); + switch (type) { + case VariableType.string: + return BrickVariableString.fromYaml(key, source); + case VariableType.boolean: + return BrickVariableBoolean.fromYaml(key, source); + case VariableType.none: + throw ArgumentError('Invalid variable type', 'type'); } } + + // TODO(wyatt): use `yaml_writer` to dumps YAML properly. + String toMason() => ''' + $name: + type: $type + description: $description + default: $defaultValue + prompt: $prompt +'''; } diff --git a/tools/brick_generator/lib/models/brick_variable_boolean.dart b/tools/brick_generator/lib/models/brick_variable_boolean.dart new file mode 100644 index 0000000..b286de9 --- /dev/null +++ b/tools/brick_generator/lib/models/brick_variable_boolean.dart @@ -0,0 +1,53 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/models/brick_variable.dart'; +import 'package:brick_generator/models/variable_type.dart'; +import 'package:yaml/yaml.dart'; + +const _typeKey = 'type'; +const _descriptionKey = 'description'; +const _defaultKey = 'default'; +const _promptKey = 'prompt'; + +class BrickVariableBoolean extends BrickVariable { + BrickVariableBoolean({ + required super.type, + required super.name, + required super.description, + required super.defaultValue, + required super.prompt, + }); + + factory BrickVariableBoolean.fromYaml(String key, YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + return BrickVariableBoolean( + type: VariableType.fromString(source[_typeKey] as String?), + name: key, + description: source[_descriptionKey] as String? ?? '', + defaultValue: source[_defaultKey] as bool? ?? false, + prompt: source[_promptKey] as String? ?? '', + ); + } + + @override + String toString() => 'BrickVariableBoolean(name: $name, ' + 'description: $description, defaultValue: $defaultValue, ' + 'prompt: $prompt,)'; +} diff --git a/tools/brick_generator/lib/models/brick_variable_string.dart b/tools/brick_generator/lib/models/brick_variable_string.dart new file mode 100644 index 0000000..4661b1b --- /dev/null +++ b/tools/brick_generator/lib/models/brick_variable_string.dart @@ -0,0 +1,62 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/core/string_extension.dart'; +import 'package:brick_generator/models/brick_variable.dart'; +import 'package:brick_generator/models/variable_type.dart'; +import 'package:yaml/yaml.dart'; + +const _compilableKey = 'compilable'; +const _typeKey = 'type'; +const _descriptionKey = 'description'; +const _defaultKey = 'default'; +const _promptKey = 'prompt'; + +class BrickVariableString extends BrickVariable { + BrickVariableString({ + required this.compilable, + required this.syntax, + required super.type, + required super.name, + required super.description, + required super.defaultValue, + required super.prompt, + }); + + factory BrickVariableString.fromYaml(String key, YamlMap? source) { + if (source == null) { + throw ArgumentError.notNull('source'); + } + + return BrickVariableString( + compilable: source[_compilableKey] as String? ?? '', + type: VariableType.fromString(source[_typeKey] as String?), + name: key, + description: source[_descriptionKey] as String? ?? '', + defaultValue: source[_defaultKey] as String? ?? '', + prompt: source[_promptKey] as String? ?? '', + syntax: (source[_compilableKey] as String? ?? '').syntaxes, + ); + } + + String compilable; + Map? syntax; + + @override + String toString() => 'BrickVariableString(name: $name, ' + 'description: $description, compilable: $compilable, ' + 'defaultValue: $defaultValue, prompt: $prompt,)'; +} diff --git a/tools/brick_generator/lib/models/brickgen_config.dart b/tools/brick_generator/lib/models/brickgen_config.dart new file mode 100644 index 0000000..271dff9 --- /dev/null +++ b/tools/brick_generator/lib/models/brickgen_config.dart @@ -0,0 +1,84 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:brick_generator/models/boolean_file_system.dart'; +import 'package:brick_generator/models/boolean_mapping.dart'; +import 'package:brick_generator/models/ignore_list.dart'; +import 'package:yaml/yaml.dart'; + +const _pathToBrickifyKey = 'path_to_brickify'; +const _ignoreKey = 'ignore'; +const _hooksKey = 'hooks'; +const _booleanMappingKey = 'boolean_mapping'; +const _booleanFileSystemKey = 'boolean_file_system'; + +class BrickgenConfig { + final String pathToBrickify; + final IgnoreList ignore; + final bool hooks; + final List booleanMapping; + final List booleanFileSystem; + + BrickgenConfig({ + required this.pathToBrickify, + required this.ignore, + required this.hooks, + required this.booleanMapping, + required this.booleanFileSystem, + }); + + factory BrickgenConfig.parse(YamlMap? data) { + if (data == null) { + throw ArgumentError.notNull('data'); + } + + final booleanMapping = (data[_booleanMappingKey] as YamlMap?) + ?.entries + .map( + (e) => + BooleanMapping.fromYaml(e.key as String, e.value as YamlMap?), + ) + .toList() ?? + []; + + final booleanFileSystem = (data[_booleanFileSystemKey] as YamlMap?) + ?.entries + .map( + (e) => BooleanFileSystem.fromYaml( + e.key as String, + e.value as YamlMap?, + ), + ) + .toList() ?? + []; + + final config = BrickgenConfig( + pathToBrickify: data[_pathToBrickifyKey] as String? ?? '', + ignore: IgnoreList.fromConfig(data[_ignoreKey] as YamlList?), + hooks: data[_hooksKey] as bool? ?? false, + booleanMapping: booleanMapping, + booleanFileSystem: booleanFileSystem, + ); + + return config; + } + + @override + String toString() => 'BrickgenConfig(pathToBrickify: $pathToBrickify, ' + 'ignore: $ignore, hooks: $hooks, booleanMapping: $booleanMapping, ' + 'booleanFileSystem: $booleanFileSystem)'; +} diff --git a/tools/brick_generator/lib/models/ignore_list.dart b/tools/brick_generator/lib/models/ignore_list.dart new file mode 100644 index 0000000..5121d63 --- /dev/null +++ b/tools/brick_generator/lib/models/ignore_list.dart @@ -0,0 +1,108 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:io'; + +import 'package:path/path.dart'; +import 'package:yaml/yaml.dart'; + +class IgnoreList { + final List ignoredFiles; + final List ignoredFolders; + + IgnoreList({ + required this.ignoredFiles, + required this.ignoredFolders, + }); + + /// Only parse files an folders (no glob) + /// - file <- file + /// - folder/ <- folder, ends with "/" + /// - infolder/file <- file + /// - sub/folder/ <- folder, ends with "/" + factory IgnoreList.fromConfig(YamlList? list) { + final List ignoredFiles = []; + final List ignoredFolders = []; + + final ignored = + list?.map((element) => element as String).toList() ?? []; + + for (final element in ignored) { + if (element.endsWith('/')) { + // This is a folder + ignoredFolders.add(element.substring(0, element.length - 1)); + } else { + // This is a file + ignoredFiles.add(element); + } + } + + return IgnoreList( + ignoredFiles: ignoredFiles, + ignoredFolders: ignoredFolders, + ); + } + + factory IgnoreList.fromBrickIgnoreFile() { + throw UnimplementedError('.brickignore is not yet supported'); + } + + bool contains(String root, String path) { + final FileSystemEntityType type = FileSystemEntity.typeSync(path); + + // Check if file/folder is an ignored folder (or any subtree of it) + for (final element in ignoredFolders) { + final ignoredPath = join(root, element); + if (path.startsWith(ignoredPath)) { + return true; + } + } + + switch (type) { + case FileSystemEntityType.file: + for (final element in ignoredFiles) { + final ignoredPath = join(root, element); + if (ignoredPath == path) { + return true; + } + } + return false; + case FileSystemEntityType.directory: + for (final element in ignoredFolders) { + final ignoredPath = join(root, element); + if (ignoredPath == path) { + return true; + } + } + return false; + case FileSystemEntityType.link: + case FileSystemEntityType.notFound: + case FileSystemEntityType.pipe: + case FileSystemEntityType.unixDomainSock: + throw ArgumentError( + 'This file system entity type is not supported', + 'from', + ); + } + + return false; + } + + @override + String toString() => 'IgnoreList(ignoredFiles: $ignoredFiles, ' + 'ignoredFolders: $ignoredFolders)'; +} diff --git a/tools/brick_generator/lib/models/log_level.dart b/tools/brick_generator/lib/models/log_level.dart index 73a0ec1..113a169 100644 --- a/tools/brick_generator/lib/models/log_level.dart +++ b/tools/brick_generator/lib/models/log_level.dart @@ -20,7 +20,7 @@ enum LogLevel { success('✅'), error('❌'); - final String prefix; - const LogLevel(this.prefix); + + final String prefix; } diff --git a/tools/brick_generator/lib/models/variable_string_syntax.dart b/tools/brick_generator/lib/models/variable_string_syntax.dart index 8b59d3f..8c9bd9b 100644 --- a/tools/brick_generator/lib/models/variable_string_syntax.dart +++ b/tools/brick_generator/lib/models/variable_string_syntax.dart @@ -29,8 +29,8 @@ enum VariableStringSyntax { pathCase('path_case', 'pathCase'), mustacheCase('mustache_case', 'mustacheCase'); + const VariableStringSyntax(this.mapKey, this.id); + final String mapKey; final String id; - - const VariableStringSyntax(this.mapKey, this.id); } diff --git a/tools/brick_generator/lib/models/variable_type.dart b/tools/brick_generator/lib/models/variable_type.dart index 29d99a9..750f1f7 100644 --- a/tools/brick_generator/lib/models/variable_type.dart +++ b/tools/brick_generator/lib/models/variable_type.dart @@ -17,21 +17,19 @@ enum VariableType { none, string, - bool; + boolean; static VariableType fromString(String? type) { switch (type) { case 'string': return string; - case 'bool': - return bool; + case 'boolean': + return boolean; default: return none; } } @override - String toString() { - return name; - } + String toString() => name; } diff --git a/tools/brick_generator/pubspec.yaml b/tools/brick_generator/pubspec.yaml index 52d38a9..bccc5e3 100644 --- a/tools/brick_generator/pubspec.yaml +++ b/tools/brick_generator/pubspec.yaml @@ -8,13 +8,14 @@ environment: sdk: ">=2.17.0 <3.0.0" dependencies: + args: ^2.3.2 path: ^1.8.2 yaml: ^3.1.1 dev_dependencies: test: ^1.22.2 wyatt_analysis: - git: - url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages - ref: wyatt_analysis-v2.1.0 - path: packages/wyatt_analysis + hosted: + url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ + name: wyatt_analysis + version: 2.3.0 diff --git a/tools/brick_generator/test/string_test.dart b/tools/brick_generator/test/string_test.dart index 8275a26..7d0d637 100644 --- a/tools/brick_generator/test/string_test.dart +++ b/tools/brick_generator/test/string_test.dart @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:brick_generator/string_extension.dart'; +import 'package:brick_generator/core/string_extension.dart'; import 'package:test/test.dart'; void main() { @@ -32,22 +32,22 @@ void main() { 'snake_case': 'feature_name', }; test('transforms `feature_name`', () { - final name = 'feature_name'; + const name = 'feature_name'; expect(name.syntaxes, equals(expected)); }); test('transforms `featureName`', () { - final name = 'feature_name'; + const name = 'feature_name'; expect(name.syntaxes, equals(expected)); }); test('transforms `feature-Name`', () { - final name = 'feature_name'; + const name = 'feature_name'; expect(name.syntaxes, equals(expected)); }); test('transforms `Feature Name`', () { - final name = 'feature_name'; + const name = 'feature_name'; expect(name.syntaxes, equals(expected)); }); }