work brick template generator, clean code, and enable multiple string variables

This commit is contained in:
Malo Léon 2022-08-08 14:25:01 +01:00
parent fbe7abcc4f
commit b2f9aeb570
11 changed files with 471 additions and 90 deletions

126
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,126 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "wyatt_clean_code",
"cwd": "apps/wyatt_clean_code",
"request": "launch",
"type": "dart"
},
{
"name": "wyatt_clean_code (profile mode)",
"cwd": "apps/wyatt_clean_code",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "wyatt_clean_code (release mode)",
"cwd": "apps/wyatt_clean_code",
"request": "launch",
"type": "dart",
"flutterMode": "release"
},
{
"name": "brick_generator",
"cwd": "tools/brick_generator",
"request": "launch",
"type": "dart"
},
{
"name": "__brick__",
"cwd": "bricks/core_app_brick/__brick__",
"request": "launch",
"type": "dart"
},
{
"name": "__brick__ (profile mode)",
"cwd": "bricks/core_app_brick/__brick__",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "__brick__ (release mode)",
"cwd": "bricks/core_app_brick/__brick__",
"request": "launch",
"type": "dart",
"flutterMode": "release"
},
{
"name": "__brick__",
"cwd": "bricks/wyatt_clean_code/__brick__",
"request": "launch",
"type": "dart"
},
{
"name": "__brick__ (profile mode)",
"cwd": "bricks/wyatt_clean_code/__brick__",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "__brick__ (release mode)",
"cwd": "bricks/wyatt_clean_code/__brick__",
"request": "launch",
"type": "dart",
"flutterMode": "release"
},
{
"name": "hooks",
"cwd": "bricks/wyatt_clean_code/hooks",
"request": "launch",
"type": "dart"
},
{
"name": "__brick__",
"cwd": "bricks/wyatt_package/__brick__",
"request": "launch",
"type": "dart"
},
{
"name": "__brick__ (profile mode)",
"cwd": "bricks/wyatt_package/__brick__",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "__brick__ (release mode)",
"cwd": "bricks/wyatt_package/__brick__",
"request": "launch",
"type": "dart",
"flutterMode": "release"
},
{
"name": "hooks",
"cwd": "bricks/wyatt_package/hooks",
"request": "launch",
"type": "dart"
},
{
"name": "example",
"cwd": "bricks/wyatt_package/__brick__/example",
"request": "launch",
"type": "dart"
},
{
"name": "example (profile mode)",
"cwd": "bricks/wyatt_package/__brick__/example",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "example (release mode)",
"cwd": "bricks/wyatt_package/__brick__/example",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View File

@ -0,0 +1,38 @@
brick_name: wyatt_feature_brick
path_to_brickify: lib/feature_brick_folder
variables:
feature_brick:
variable_name: feature_brick
type: string
syntax:
camel_case: featureBrick
constant_case: FEATURE_BRICK
dot_case: feature.brick
header_case: Feature-Brick
lower_case: feature brick
pascal_case: FeatureBrick
param_case: feature-brick
sentence_case: Feature brick
snake_case: feature_brick
title_case: Feature Brick
upper_case: FEATURE BRICK
description:
variable_name: description
type: string
syntax:
camel_case: description
constant_case: DESCRIPTION
dot_case: description
header_case: Description
lower_case: description
pascal_case: Description
param_case: description
sentence_case: Description
snake_case: description
title_case: Description
upper_case: DESCRIPTION
isBloc:
variable_name: bloc
type: bool

View File

@ -0,0 +1,7 @@
class FeatureBrick {
var featureBrick = 0;
}
class DescriptionClass {
var descriptionClass = 0;
}

View File

@ -6,7 +6,6 @@ in `lib/`.
- Add your app in `apps`.
- Add `brick_config.yaml` in you app folder and add this fields :
```yaml
brick_name: wyatt_feature_brick
project_name: projet_name
@ -34,5 +33,4 @@ dart tools/brick_generator/bin/brick_generator.dart ./apps/wyatt_feature_brick
```
# TODO
- Work on bool variables
- Add several variables (here only one is possible)
- Work on bool variables

View File

@ -1,35 +1,11 @@
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';
import 'package:brick_generator/shell.dart';
import 'package:brick_generator/yaml_reader.dart';
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart';
// Keys
enum Syntax {
camelCase('camel_case', 'camelCase'),
constantCase('constant_case', 'constantCase'),
dotCase('dot_case', 'dotCase'),
headerCase('header_case', 'headerCase'),
lowerCase('lower_case', 'lowerCase'),
pascalCase('pascal_case', 'pascalCase'),
paramCase('param_case', 'paramCase'),
sentenceCase('sentence_case', 'sentenceCase'),
snakeCase('snake_case', 'snakeCase'),
titleCase('title_case', 'titleCase'),
upperCase('upper_case', 'upperCase');
final String mapKey;
final String id;
const Syntax(this.mapKey, this.id);
}
// Other Keys
const _projectNameKey = 'project_name';
const _brickNameKey = 'brick_name';
const _pathToBrickifyKey = 'path_to_brickify';
const _syntaxKey = 'syntax';
// Constants
const _bricks = 'bricks';
@ -45,26 +21,23 @@ Future<void> main(List<String> arguments) async {
final projectPath = arguments[0];
// Store options from yaml file
final option =
final configs =
YamlReader.readYamlFile(path.join(projectPath, _yamlFileName));
final syntaxMap = option[_syntaxKey] as YamlMap;
stdout.writeln('🍺 get options $syntaxMap');
final brickConfig = BrickConfig.from(configs);
stdout.writeln('🍺 config retrieved');
for (final syntax in Syntax.values) {
if (syntaxMap[syntax.mapKey] == null) {
throw ArgumentError(
'Yaml file is not conform : ${syntax.toString()} is missing',
);
}
}
final projectName = option[_projectNameKey] as String;
final brickName = option[_brickNameKey] as String;
brickConfig?.checkFormat();
// Define paths
final sourcePath =
path.join(projectPath, option[_pathToBrickifyKey] as String);
final targetPath = path.join(_bricks, brickName, _brickFolderLabel);
final sourcePath = path.join(
projectPath,
brickConfig!.pathToBrickify,
);
final targetPath = path.join(
_bricks,
brickConfig.brickName,
_brickFolderLabel,
);
stdout.writeln('🍺 path defined');
// Remove previously generated files
@ -88,53 +61,66 @@ Future<void> main(List<String> arguments) async {
.map((_) async {
var file = _;
try {
var contents = await file.readAsString();
var contents = await file.readAsString();
// Transform all values in variables
for (final syntax in Syntax.values) {
contents = contents.replaceAll(
syntaxMap[syntax.mapKey] as String,
'{{#${syntax.id}}}{{$projectName}}{{/${syntax.id}}}',
);
}
file = await file.writeAsString(contents);
// Rename file if needed
final filePath = file.path;
if (filePath.contains(syntaxMap[Syntax.snakeCase.mapKey] as String)) {
try {
var pathList = filePath.split(Platform.pathSeparator).sublist(3);
pathList = pathList
.map(
(segment) => segment.replaceAll(
syntaxMap[Syntax.snakeCase.mapKey] as String,
'{{$projectName.snakeCase()}}',
),
)
.toList();
final newPath = path.join(
filePath
.split(Platform.pathSeparator)
.sublist(0, 3)
.join(Platform.pathSeparator),
pathList.join(Platform.pathSeparator),
);
File(newPath).createSync(recursive: true);
file.renameSync(newPath);
Directory(file.parent.path).deleteSync(recursive: true);
} catch (_) {
stdout.writeln('${_.toString()}');
// Transform all values in variables
if (brickConfig.variables != null) {
for (final variable in brickConfig.variables!) {
if (variable?.type == VariabelType.string) {
for (final syntax in VariableStringSyntax.values) {
final toReplace = variable?.syntax?.getValue(syntax);
if (toReplace != null) {
contents = contents.replaceAll(
variable!.syntax!.getValue(syntax)!,
'{{#${syntax.id}}}{{${variable.name}}}{{/${syntax.id}}}',
);
}
}
}
}
} catch (_) {
stdout.writeln('${_.toString()}');
}
// 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) {
if (filePath.contains(variable!.syntax!.snakeCase!)) {
var pathList =
filePath.split(Platform.pathSeparator).sublist(3);
pathList = pathList
.map(
(segment) => segment.replaceAll(
variable.syntax!.snakeCase!,
'{{${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');
} catch (_) {
stdout.writeln('${_.toString()}');
}

View File

@ -0,0 +1,51 @@
import 'package:brick_generator/models/brick_variable.dart';
import 'package:yaml/yaml.dart';
const _brickNameKey = 'brick_name';
const _pathToBrickifyKey = 'path_to_brickify';
const _variablesKey = 'variables';
class BrickConfig {
String? brickName;
String? pathToBrickify;
List<BrickVariable?>? variables;
BrickConfig({
required this.brickName,
required this.pathToBrickify,
required this.variables,
});
BrickConfig._();
factory BrickConfig.parser() => BrickConfig._();
static BrickConfig? from(YamlMap? data) => data != null
? BrickConfig(
brickName: data[_brickNameKey] as String?,
pathToBrickify: data[_pathToBrickifyKey] as String?,
variables: (data[_variablesKey] as YamlMap?)
?.map<dynamic, BrickVariable?>(
(dynamic key, dynamic value) =>
MapEntry<dynamic, BrickVariable?>(
key,
BrickVariable.from(value as YamlMap?),
),
)
.values
.toList(),
)
: null;
void checkFormat() {
if (brickName == null || pathToBrickify == null) {
throw ArgumentError(
'Yaml file is not conform',
);
}
if (variables != null) {
for (final variable in variables!) {
variable?.checkFormat();
}
}
}
}

View File

@ -0,0 +1,42 @@
import 'package:brick_generator/models/variable_syntax.dart';
import 'package:brick_generator/models/variable_type.dart';
import 'package:yaml/yaml.dart';
const _variableNameKey = 'variable_name';
const _typeKey = 'type';
const _syntaxKey = 'syntax';
class BrickVariable {
String? name;
VariabelType? type;
VariableSyntax? syntax;
BrickVariable({
required this.name,
required this.type,
required this.syntax,
});
BrickVariable._();
factory BrickVariable.parser() => BrickVariable._();
static BrickVariable? from(YamlMap? data) => data != null
? BrickVariable(
name: data[_variableNameKey] as String?,
type: VariabelType.stringToEnum(data[_typeKey] as String?),
syntax: VariableSyntax.from(data[_syntaxKey] as YamlMap?),
)
: null;
void checkFormat() {
if (name == null || type == null) {
throw ArgumentError(
'Yaml file is not conform',
);
}
if (type == VariabelType.string) {
syntax?.checkFormat();
}
}
}

View File

@ -0,0 +1,18 @@
enum VariableStringSyntax {
camelCase('camel_case', 'camelCase'),
constantCase('constant_case', 'constantCase'),
dotCase('dot_case', 'dotCase'),
headerCase('header_case', 'headerCase'),
lowerCase('lower_case', 'lowerCase'),
pascalCase('pascal_case', 'pascalCase'),
paramCase('param_case', 'paramCase'),
sentenceCase('sentence_case', 'sentenceCase'),
snakeCase('snake_case', 'snakeCase'),
titleCase('title_case', 'titleCase'),
upperCase('upper_case', 'upperCase');
final String mapKey;
final String id;
const VariableStringSyntax(this.mapKey, this.id);
}

View File

@ -0,0 +1,95 @@
import 'package:brick_generator/models/variable_string_syntax.dart';
import 'package:yaml/yaml.dart';
class VariableSyntax {
String? camelCase;
String? constantCase;
String? dotCase;
String? headerCase;
String? lowerCase;
String? pascalCase;
String? paramCase;
String? sentenceCase;
String? snakeCase;
String? titleCase;
String? upperCase;
VariableSyntax({
required this.camelCase,
required this.constantCase,
required this.dotCase,
required this.headerCase,
required this.lowerCase,
required this.pascalCase,
required this.paramCase,
required this.sentenceCase,
required this.snakeCase,
required this.titleCase,
required this.upperCase,
});
VariableSyntax._();
factory VariableSyntax.parser() => VariableSyntax._();
static VariableSyntax? from(YamlMap? data) => data != null
? VariableSyntax(
camelCase: data[VariableStringSyntax.camelCase.mapKey] as String?,
constantCase:
data[VariableStringSyntax.constantCase.mapKey] as String?,
dotCase: data[VariableStringSyntax.dotCase.mapKey] as String?,
headerCase: data[VariableStringSyntax.headerCase.mapKey] as String?,
lowerCase: data[VariableStringSyntax.lowerCase.mapKey] as String?,
pascalCase: data[VariableStringSyntax.pascalCase.mapKey] as String?,
paramCase: data[VariableStringSyntax.paramCase.mapKey] as String?,
sentenceCase:
data[VariableStringSyntax.sentenceCase.mapKey] as String?,
snakeCase: data[VariableStringSyntax.snakeCase.mapKey] as String?,
titleCase: data[VariableStringSyntax.titleCase.mapKey] as String?,
upperCase: data[VariableStringSyntax.upperCase.mapKey] as String?,
)
: null;
String? getValue(VariableStringSyntax key) {
switch (key) {
case VariableStringSyntax.camelCase:
return camelCase;
case VariableStringSyntax.constantCase:
return constantCase;
case VariableStringSyntax.dotCase:
return dotCase;
case VariableStringSyntax.headerCase:
return headerCase;
case VariableStringSyntax.lowerCase:
return lowerCase;
case VariableStringSyntax.pascalCase:
return pascalCase;
case VariableStringSyntax.paramCase:
return paramCase;
case VariableStringSyntax.sentenceCase:
return sentenceCase;
case VariableStringSyntax.snakeCase:
return snakeCase;
case VariableStringSyntax.titleCase:
return titleCase;
case VariableStringSyntax.upperCase:
return upperCase;
}
}
void checkFormat() {
if (camelCase == null ||
constantCase == null ||
dotCase == null ||
headerCase == null ||
lowerCase == null ||
pascalCase == null ||
paramCase == null ||
sentenceCase == null ||
snakeCase == null ||
titleCase == null ||
upperCase == null) {
throw ArgumentError(
'Yaml file is not conform',
);
}
}
}

View File

@ -0,0 +1,16 @@
enum VariabelType {
none,
string,
bool;
static VariabelType stringToEnum(String? type) {
switch (type) {
case 'string':
return string;
case 'bool':
return bool;
default:
return none;
}
}
}

View File

@ -17,8 +17,12 @@ class _Cmd {
bool throwOnError = true,
String? processWorkingDir,
}) async {
final result = await Process.run(cmd, args,
workingDirectory: processWorkingDir, runInShell: true);
final result = await Process.run(
cmd,
args,
workingDirectory: processWorkingDir,
runInShell: true,
);
if (throwOnError) {
_throwIfProcessFailed(result, cmd, args);
@ -49,4 +53,4 @@ class _Cmd {
throw ProcessException(process, args, message, pr.exitCode);
}
}
}
}