feat: rewrite generator
This commit is contained in:
parent
1646dbd919
commit
18aeef9e35
30
tools/brick_generator/bin/brick.yaml
Normal file
30
tools/brick_generator/bin/brick.yaml
Normal file
@ -0,0 +1,30 @@
|
||||
name: <brick_name>
|
||||
description: <brick_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 ?
|
||||
|
@ -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;
|
||||
|
||||
|
182
tools/brick_generator/bin/brickgen.dart
Normal file
182
tools/brick_generator/bin/brickgen.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<void> 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<void> main(List<String> 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);
|
||||
}
|
357
tools/brick_generator/lib/core/file_system.dart
Normal file
357
tools/brick_generator/lib/core/file_system.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<int>);
|
||||
} else {
|
||||
file.writeAsStringSync(content as String);
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> copyFolder(
|
||||
String from,
|
||||
String to, {
|
||||
IgnoreList? ignoreList,
|
||||
}) async {
|
||||
if (!FileSystemEntity.isDirectorySync(from)) {
|
||||
throw ArgumentError('Path must be a directory', 'from');
|
||||
}
|
||||
|
||||
final List<String> copiedFolders = [];
|
||||
|
||||
// Copy folders
|
||||
await Future.wait<void>(
|
||||
Directory(from)
|
||||
.listSync(recursive: true)
|
||||
.whereType<Directory>()
|
||||
.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<void>(
|
||||
Directory(from)
|
||||
.listSync(recursive: true)
|
||||
.whereType<File>()
|
||||
.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<File>()
|
||||
.forEach((file) {
|
||||
String? contents;
|
||||
|
||||
try {
|
||||
contents = file.readAsStringSync();
|
||||
} catch (e) {
|
||||
Logger.error(e);
|
||||
}
|
||||
|
||||
config.variables.whereType<BrickVariableString>().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<Directory>()
|
||||
.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<Directory>()
|
||||
.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<File>()
|
||||
.forEach((file) {
|
||||
config.variables.whereType<BrickVariableString>().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}`',
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -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) {
|
@ -16,23 +16,20 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:brick_generator/logger.dart';
|
||||
import 'package:brick_generator/core/logger.dart';
|
||||
|
||||
class Shell {
|
||||
static Future<void> cp(String source, String destination) {
|
||||
return _Cmd.run('cp', ['-Rf', source, destination]);
|
||||
}
|
||||
abstract class Shell {
|
||||
static Future<void> cp(String source, String destination) =>
|
||||
_Cmd.run('cp', ['-Rf', source, destination]);
|
||||
|
||||
static Future<void> mkdir(String destination) {
|
||||
return _Cmd.run('mkdir', ['-p', destination]);
|
||||
}
|
||||
static Future<void> mkdir(String destination) =>
|
||||
_Cmd.run('mkdir', ['-p', destination]);
|
||||
|
||||
static Future<void> rm(String target, {bool recursive = false}) {
|
||||
return _Cmd.run('rm', ['-f${recursive ? "r" : ""}', target]);
|
||||
}
|
||||
static Future<void> rm(String target, {bool recursive = false}) =>
|
||||
_Cmd.run('rm', ['-f${recursive ? "r" : ""}', target]);
|
||||
}
|
||||
|
||||
class _Cmd {
|
||||
abstract class _Cmd {
|
||||
static Future<ProcessResult> run(
|
||||
String cmd,
|
||||
List<String> args, {
|
@ -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()} }}';
|
||||
}
|
@ -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);
|
||||
|
69
tools/brick_generator/lib/models/boolean_file_system.dart
Normal file
69
tools/brick_generator/lib/models/boolean_file_system.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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)';
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<String> onTrueNames;
|
||||
final List<String> onFalseNames;
|
||||
|
||||
BooleanFileSystemVariable copyWith({
|
||||
List<String>? onTrueNames,
|
||||
List<String>? onFalseNames,
|
||||
}) =>
|
||||
BooleanFileSystemVariable(
|
||||
onTrueNames: onTrueNames ?? this.onTrueNames,
|
||||
onFalseNames: onFalseNames ?? this.onFalseNames,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => 'BooleanFileSystemVariable(onTrueNames: $onTrueNames, '
|
||||
'onFalseNames: $onFalseNames)';
|
||||
}
|
77
tools/brick_generator/lib/models/boolean_mapping.dart
Normal file
77
tools/brick_generator/lib/models/boolean_mapping.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<BooleanNameSingleMapping> folders;
|
||||
List<BooleanNameSingleMapping> files;
|
||||
|
||||
BooleanMapping copyWith({
|
||||
String? booleanName,
|
||||
List<BooleanNameSingleMapping>? folders,
|
||||
List<BooleanNameSingleMapping>? files,
|
||||
}) =>
|
||||
BooleanMapping(
|
||||
booleanName: booleanName ?? this.booleanName,
|
||||
folders: folders ?? this.folders,
|
||||
files: files ?? this.files,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => 'BooleanMapping(booleanName: $booleanName, '
|
||||
'folders: $folders, files: $files)';
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<String> onTrueNames;
|
||||
final List<String> onFalseNames;
|
||||
|
||||
BooleanNameListMapping copyWith({
|
||||
String? fileSystemEntityName,
|
||||
List<String>? onTrueNames,
|
||||
List<String>? 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)';
|
||||
}
|
21
tools/brick_generator/lib/models/boolean_name_mapping.dart
Normal file
21
tools/brick_generator/lib/models/boolean_name_mapping.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
abstract class BooleanNameMapping {
|
||||
String get fileSystemEntityName;
|
||||
String get onTrueName;
|
||||
String get onFalseName;
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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)';
|
||||
}
|
@ -14,96 +14,86 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<String>? brickIgnore;
|
||||
List<BrickVariable?>? 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, BrickVariable?>(
|
||||
(dynamic key, dynamic value) =>
|
||||
MapEntry<dynamic, BrickVariable?>(
|
||||
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<BrickVariable<dynamic>> 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)';
|
||||
}
|
||||
|
@ -14,53 +14,46 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<String, String>? syntax;
|
||||
|
||||
abstract class BrickVariable<T> {
|
||||
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<dynamic> 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
|
||||
''';
|
||||
}
|
||||
|
53
tools/brick_generator/lib/models/brick_variable_boolean.dart
Normal file
53
tools/brick_generator/lib/models/brick_variable_boolean.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<bool> {
|
||||
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,)';
|
||||
}
|
62
tools/brick_generator/lib/models/brick_variable_string.dart
Normal file
62
tools/brick_generator/lib/models/brick_variable_string.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<String> {
|
||||
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<String, String>? syntax;
|
||||
|
||||
@override
|
||||
String toString() => 'BrickVariableString(name: $name, '
|
||||
'description: $description, compilable: $compilable, '
|
||||
'defaultValue: $defaultValue, prompt: $prompt,)';
|
||||
}
|
84
tools/brick_generator/lib/models/brickgen_config.dart
Normal file
84
tools/brick_generator/lib/models/brickgen_config.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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> booleanMapping;
|
||||
final List<BooleanFileSystem> 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)';
|
||||
}
|
108
tools/brick_generator/lib/models/ignore_list.dart
Normal file
108
tools/brick_generator/lib/models/ignore_list.dart
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
class IgnoreList {
|
||||
final List<String> ignoredFiles;
|
||||
final List<String> 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<String> ignoredFiles = [];
|
||||
final List<String> ignoredFolders = [];
|
||||
|
||||
final ignored =
|
||||
list?.map<String>((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)';
|
||||
}
|
@ -20,7 +20,7 @@ enum LogLevel {
|
||||
success('✅'),
|
||||
error('❌');
|
||||
|
||||
final String prefix;
|
||||
|
||||
const LogLevel(this.prefix);
|
||||
|
||||
final String prefix;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user