fix and improve generator algo

This commit is contained in:
Malo Léon 2022-08-10 15:48:45 +01:00
parent 5734b09510
commit 60088f6621
18 changed files with 244 additions and 89 deletions

View File

@ -4,7 +4,7 @@ path_to_brickify: lib/feature_name
variables:
feature_name:
variable_name: feature_brick
variable_name: feature_name
type: string
syntax:
camel_case: featureName
@ -15,6 +15,6 @@ variables:
pascal_case: FeatureName
param_case: feature-name
sentence_case: Feature name
snake_case: feature_name
title_case: Feature Name
upper_case: FEATURE NAME
snake_case: feature_name

View File

@ -1 +0,0 @@
Hello {{name}}!

View File

@ -0,0 +1,14 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part '{{#snakeCase}}{{feature_name}}{{/snakeCase}}_state.dart';
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}Cubit extends Cubit<{{#pascalCase}}{{feature_name}}{{/pascalCase}}State> {
{{#pascalCase}}{{feature_name}}{{/pascalCase}}Cubit() : super(const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Initial());
/// A description for yourCustomFunction
FutureOr<void> yourCustomFunction() {
// TODO(wyattstudio): Add Logic
}
}

View File

@ -0,0 +1,20 @@
part of '{{#snakeCase}}{{feature_name}}{{/snakeCase}}_cubit.dart';
/// {@template {{{#snakeCase}}{{feature_name}}{{/snakeCase}}}}
/// {{#pascalCase}}{{feature_name}}{{/pascalCase}}State description
/// {@endtemplate}
abstract class {{#pascalCase}}{{feature_name}}{{/pascalCase}}State extends Equatable {
/// {@macro {{{#snakeCase}}{{feature_name}}{{/snakeCase}}}}
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}State();
}
/// {@template {{#snakeCase}}{{feature_name}}{{/snakeCase}}_initial}
/// The initial state of {{#pascalCase}}{{feature_name}}{{/pascalCase}}State
/// {@endtemplate}
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}Initial extends {{#pascalCase}}{{feature_name}}{{/pascalCase}}State {
/// {@macro {{#snakeCase}}{{feature_name}}{{/snakeCase}}_initial}
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Initial() : super();
@override
List<Object?> get props => [];
}

View File

@ -0,0 +1,8 @@
import 'package:flutter/material.dart';
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}Widget extends StatelessWidget {
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Widget({super.key});
@override
Widget build(BuildContext context) => const SizedBox();
}

View File

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
// ignore: always_use_package_imports
import './{{#snakeCase}}{{feature_name}}{{/snakeCase}}_wrapper_widget.dart';
// ignore: always_use_package_imports
import './widgets/{{#snakeCase}}{{feature_name}}{{/snakeCase}}_widget.dart';
// ignore: always_use_package_imports
import '../cubit/{{#snakeCase}}{{feature_name}}{{/snakeCase}}_cubit.dart';
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}CubitStateManagement
extends CubitScreen<{{#pascalCase}}{{feature_name}}{{/pascalCase}}Cubit, {{#pascalCase}}{{feature_name}}{{/pascalCase}}State> {
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}CubitStateManagement({super.key});
@override
{{#pascalCase}}{{feature_name}}{{/pascalCase}}Cubit create(BuildContext context) => {{#pascalCase}}{{feature_name}}{{/pascalCase}}Cubit();
@override
Widget onWrap(BuildContext context, Widget child) =>
{{#pascalCase}}{{feature_name}}{{/pascalCase}}WrapperWidget(child: child);
@override
Widget onBuild(BuildContext context, {{#pascalCase}}{{feature_name}}{{/pascalCase}}State state) =>
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Widget();
}

View File

@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}WrapperWidget extends StatelessWidget {
final Widget child;
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}WrapperWidget({super.key, required this.child});
@override
Widget build(BuildContext context) => Container(
child: child,
);
}

View File

@ -0,0 +1 @@
export './state_management/{{#snakeCase}}{{feature_name}}{{/snakeCase}}_state_management.dart';

View File

@ -0,0 +1,22 @@
// isBloc
import 'dart:async';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
part '{{#snakeCase}}{{feature_name}}{{/snakeCase}}_event.dart';
part '{{#snakeCase}}{{feature_name}}{{/snakeCase}}_state.dart';
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}Bloc extends Bloc<{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event, {{#pascalCase}}{{feature_name}}{{/pascalCase}}State> {
{{#pascalCase}}{{feature_name}}{{/pascalCase}}Bloc() : super(const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Initial()) {
on<Custom{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event>(_onCustom{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event);
}
FutureOr<void> _onCustom{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event(
Custom{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event event,
Emitter<{{#pascalCase}}{{feature_name}}{{/pascalCase}}State> emit,
) {
// TODO(wyattstudio): Add Logic
}
}

View File

@ -0,0 +1,18 @@
// isBloc
part of '{{#snakeCase}}{{feature_name}}{{/snakeCase}}_bloc.dart';
abstract class {{#pascalCase}}{{feature_name}}{{/pascalCase}}Event extends Equatable {
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Event();
}
/// {@template custom_{{#snakeCase}}{{feature_name}}{{/snakeCase}}_event}
/// Event added when some custom logic happens
/// {@endtemplate}
class Custom{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event extends {{#pascalCase}}{{feature_name}}{{/pascalCase}}Event {
/// {@macro custom_{{#snakeCase}}{{feature_name}}{{/snakeCase}}_event}
const Custom{{#pascalCase}}{{feature_name}}{{/pascalCase}}Event();
@override
List<Object?> get props => [];
}

View File

@ -0,0 +1,22 @@
// isBloc
part of '{{#snakeCase}}{{feature_name}}{{/snakeCase}}_bloc.dart';
/// {@template {{#snakeCase}}{{feature_name}}{{/snakeCase}}_state}
/// {{#pascalCase}}{{feature_name}}{{/pascalCase}}State description
/// {@endtemplate}
abstract class {{#pascalCase}}{{feature_name}}{{/pascalCase}}State extends Equatable {
/// {@macro {{#snakeCase}}{{feature_name}}{{/snakeCase}}_state}
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}State();
}
/// {@template {{#snakeCase}}{{feature_name}}{{/snakeCase}}_initial}
/// The initial state of {{#pascalCase}}{{feature_name}}{{/pascalCase}}State
/// {@endtemplate}
class {{#pascalCase}}{{feature_name}}{{/pascalCase}}Initial extends {{#pascalCase}}{{feature_name}}{{/pascalCase}}State {
/// {@macro {{#snakeCase}}{{feature_name}}{{/snakeCase}}_initial}
const {{#pascalCase}}{{feature_name}}{{/pascalCase}}Initial();
@override
List<Object?> get props => [];
}

View File

@ -12,14 +12,3 @@ vars:
description: Name of the feature
default: Dash
prompt: What is the name of your new feature
state_management:
type: enum
default: cubit
description: The features state management
prompt: What is the feature state management?
values:
- bloc
- cubit
- provider
- riverpod
- none

View File

@ -1,8 +1,7 @@
import 'dart:io';
import 'package:brick_generator/file_system_utils.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:brick_generator/yaml_reader.dart';
import 'package:path/path.dart' as path;
@ -54,80 +53,18 @@ Future<void> main(List<String> arguments) async {
stdout.writeln('🍺 files copied');
// Convert values to variables
await Future.wait(
Directory(targetPath)
.listSync(recursive: true)
.whereType<File>()
.map((_) async {
var file = _;
await FileSystemUtils.convertValuesToVariablesInFolder(
brickConfig, targetPath);
stdout.writeln('🍺 values converted into variables');
var contents = await file.readAsString();
// Rename files and folders
await FileSystemUtils.renamePathsInFolder(brickConfig, targetPath);
stdout.writeln('🍺 folders and files renamed');
// Transform all values in variables
if (brickConfig.variables != null) {
for (final variable in brickConfig.variables!) {
// Replace all string variables
if (variable?.type == VariabelType.string) {
for (final syntax in VariableStringSyntax.values) {
final toReplace = variable?.syntax?[syntax.mapKey] as String?;
if (toReplace != null) {
contents = contents.replaceAll(
toReplace,
'{{#${syntax.id}}}{{${variable?.name}}}{{/${syntax.id}}}',
);
}
}
}
}
}
// Replace content
file = await file.writeAsString(contents);
stdout.writeln('🍺 variables added');
// Rename file if needed
final filePath = file.path;
if (brickConfig.variables != null) {
for (final variable in brickConfig.variables!) {
if (variable?.type == VariabelType.string &&
variable?.syntax?[VariableStringSyntax.snakeCase.mapKey] !=
null) {
if (filePath.contains(
variable!.syntax![VariableStringSyntax.snakeCase.mapKey]
as String,
)) {
var pathList =
filePath.split(Platform.pathSeparator).sublist(3);
pathList = pathList
.map(
(segment) => segment.replaceAll(
variable.syntax![VariableStringSyntax.snakeCase.mapKey]
as String,
'{{${variable.name}.snakeCase()}}',
),
)
.toList();
final newPath = path.join(
filePath
.split(Platform.pathSeparator)
.sublist(0, 3)
.join(Platform.pathSeparator),
pathList.join(Platform.pathSeparator),
);
File(newPath).createSync(recursive: true);
file.renameSync(newPath);
Directory(file.parent.path).deleteSync(recursive: true);
}
}
}
}
stdout.writeln('🍺 folders and files renamed');
}),
);
stdout.writeln('🍺 done');
await FileSystemUtils.deleteEmptyFolders(targetPath);
stdout
..writeln('🍺 empty folders removed')
..writeln('✅ brick template available at $targetPath');
} catch (_) {
stdout.writeln('${_.toString()}');
}

View File

@ -0,0 +1,89 @@
import 'dart:io';
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';
class FileSystemUtils {
static Future<void> convertValuesToVariablesInFolder(
BrickConfig brickConfig,
String path,
) async {
await Future.wait(
Directory(path)
.listSync(recursive: true)
.whereType<File>()
.map((_) async {
var file = _;
var contents = await file.readAsString();
// Transform all values in variables
if (brickConfig.variables != null) {
for (final variable in brickConfig.variables!) {
// Replace all string variables
if (variable?.type == VariabelType.string) {
for (final syntax in VariableStringSyntax.values) {
final toReplace = variable?.syntax?[syntax.mapKey] as String?;
if (toReplace != null) {
contents = contents.replaceAll(
toReplace,
'{{#${syntax.id}}}{{${variable?.name}}}{{/${syntax.id}}}',
);
}
}
}
stdout.writeln(
'🍺 variables ${variable?.name} added in ${file.path}',
);
}
}
// Replace content
file = await file.writeAsString(contents);
}),
);
}
static Future<void> renamePathsInFolder(
BrickConfig brickConfig,
String path,
) async {
await Future.wait(
Directory(path)
.listSync(recursive: true)
.whereType<File>()
.map((_) async {
final file = _;
// Rename file if needed
if (brickConfig.variables != null) {
for (final variable in brickConfig.variables!) {
if (variable?.type == VariabelType.string &&
variable?.syntax?[VariableStringSyntax.snakeCase.mapKey] !=
null) {
final newPath = file.path.replaceAll(
variable!.syntax![VariableStringSyntax.snakeCase.mapKey]
as String,
'{{${variable.name}.snakeCase()}}',
);
await File(newPath).create(recursive: true);
await file.rename(newPath);
}
}
}
}),
);
}
static Future<void> deleteEmptyFolders(String path) async {
for (final dir in Directory(path).listSync(recursive: true).reversed) {
if (dir is Directory) {
if (await dir.exists() && await dir.list().isEmpty) {
await dir.delete(recursive: true);
}
}
}
}
}

View File

@ -1,4 +1,5 @@
enum VariableStringSyntax {
snakeCase('snake_case', 'snakeCase'),
camelCase('camel_case', 'camelCase'),
constantCase('constant_case', 'constantCase'),
dotCase('dot_case', 'dotCase'),
@ -7,7 +8,6 @@ enum VariableStringSyntax {
pascalCase('pascal_case', 'pascalCase'),
paramCase('param_case', 'paramCase'),
sentenceCase('sentence_case', 'sentenceCase'),
snakeCase('snake_case', 'snakeCase'),
titleCase('title_case', 'titleCase'),
upperCase('upper_case', 'upperCase');