Skip to content

Commit

Permalink
feat: Create Widget command (#24)
Browse files Browse the repository at this point in the history
* Replace appName argument on runBuildRunner with workingDirectory

* Add create widget command

* Fix and refactor unit tests
  • Loading branch information
ferrarafer authored Jun 1, 2023
1 parent 4511e57 commit b922402
Show file tree
Hide file tree
Showing 41 changed files with 807 additions and 338 deletions.
34 changes: 17 additions & 17 deletions lib/src/commands/create/create_app_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class CreateAppCommand extends Command {

@override
String get description =>
'Creates a stacked application with all the basics setup';
'Creates a Stacked application with all the basics setup.';

@override
String get name => kTemplateNameApp;
Expand Down Expand Up @@ -68,30 +68,30 @@ class CreateAppCommand extends Command {
configFilePath: argResults![ksConfigPath],
);

final appName = argResults!.rest.first;
final appNameWithoutPath = appName.split('/').last;
final workingDirectory = argResults!.rest.first;
final appName = workingDirectory.split('/').last;
final templateType = argResults![ksTemplateType];

unawaited(_analyticsService.createAppEvent(name: appNameWithoutPath));
unawaited(_analyticsService.createAppEvent(name: appName));
_processService.formattingLineLength = argResults![ksLineLength];
await _processService.runCreateApp(appName: appName);
await _processService.runCreateApp(appName: workingDirectory);

_log.stackedOutput(message: 'Add Stacked Magic ... ', isBold: true);

await _templateService.renderTemplate(
templateName: name,
name: appNameWithoutPath,
name: appName,
verbose: true,
outputPath: appName,
outputPath: workingDirectory,
useBuilder: argResults![ksV1] ?? _configService.v1,
templateType: templateType,
);

_replaceConfigFile(appName: appName);
await _processService.runPubGet(appName: appName);
await _processService.runBuildRunner(appName: appName);
await _processService.runFormat(appName: appName);
await _clean(appName: appName);
_replaceConfigFile(appName: workingDirectory);
await _processService.runPubGet(appName: workingDirectory);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
await _processService.runFormat(appName: workingDirectory);
await _clean(workingDirectory: workingDirectory);
} catch (e) {
_log.warn(message: e.toString());
}
Expand All @@ -101,29 +101,29 @@ class CreateAppCommand extends Command {
///
/// - Deletes widget_test.dart file
/// - Removes unused imports
Future<void> _clean({required String appName}) async {
Future<void> _clean({required String workingDirectory}) async {
_log.stackedOutput(message: 'Cleaning project...');

// Removes `widget_test` file to avoid failing unit tests on created app
if (await _fileService.fileExists(
filePath: '$appName/test/widget_test.dart',
filePath: '$workingDirectory/test/widget_test.dart',
)) {
await _fileService.deleteFile(
filePath: '$appName/test/widget_test.dart',
filePath: '$workingDirectory/test/widget_test.dart',
verbose: false,
);
}

// Analyze the project and return output lines
final issues = await _processService.runAnalyze(appName: appName);
final issues = await _processService.runAnalyze(appName: workingDirectory);

for (var i in issues) {
if (!i.endsWith('unused_import')) continue;

final log = i.split(' • ')[2].split(':');

await _fileService.removeLinesOnFile(
filePath: '$appName/${log[0]}',
filePath: '$workingDirectory/${log[0]}',
linesNumber: [int.parse(log[1])],
);
}
Expand Down
12 changes: 6 additions & 6 deletions lib/src/commands/create/create_bottom_sheet_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,27 @@ class CreateBottomSheetCommand extends Command with ProjectStructureValidator {
final templateType = argResults![ksTemplateType];
unawaited(
_analyticsService.createBottomSheetEvent(name: bottomSheetName));
final outputPath =
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;
await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: outputPath,
projectPath: workingDirectory,
);
_processService.formattingLineLength = argResults![ksLineLength];
await _pubspecService.initialise(workingDirectory: outputPath);
await validateStructure(outputPath: outputPath);
await _pubspecService.initialise(workingDirectory: workingDirectory);
await validateStructure(outputPath: workingDirectory);

await _templateService.renderTemplate(
templateName: name,
name: bottomSheetName,
outputPath: outputPath,
outputPath: workingDirectory,
verbose: true,
excludeRoute: argResults![ksExcludeRoute],
hasModel: argResults![ksModel],
templateType: templateType,
);

await _processService.runBuildRunner(appName: outputPath);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
} catch (e) {
_log.warn(message: e.toString());
}
Expand Down
6 changes: 4 additions & 2 deletions lib/src/commands/create/create_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'create_bottom_sheet_command.dart';
import 'create_dialog_command.dart';
import 'create_service_command.dart';
import 'create_view_command.dart';
import 'create_widget_command.dart';

/// A command with subcommands that allows you to create / scaffold
/// different parts of the stacked application
Expand All @@ -17,10 +18,11 @@ class CreateCommand extends Command {
String get name => 'create';

CreateCommand() {
addSubcommand(CreateViewCommand());
addSubcommand(CreateServiceCommand());
addSubcommand(CreateAppCommand());
addSubcommand(CreateBottomSheetCommand());
addSubcommand(CreateDialogCommand());
addSubcommand(CreateServiceCommand());
addSubcommand(CreateViewCommand());
addSubcommand(CreateWidgetCommand());
}
}
12 changes: 6 additions & 6 deletions lib/src/commands/create/create_dialog_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,27 +69,27 @@ class CreateDialogCommand extends Command with ProjectStructureValidator {
final dialogName = argResults!.rest.first;
final templateType = argResults![ksTemplateType];
unawaited(_analyticsService.createDialogEvent(name: dialogName));
final outputPath =
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;
await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: outputPath,
projectPath: workingDirectory,
);
_processService.formattingLineLength = argResults![ksLineLength];
await _pubspecService.initialise(workingDirectory: outputPath);
await validateStructure(outputPath: outputPath);
await _pubspecService.initialise(workingDirectory: workingDirectory);
await validateStructure(outputPath: workingDirectory);

await _templateService.renderTemplate(
templateName: name,
name: dialogName,
outputPath: outputPath,
outputPath: workingDirectory,
verbose: true,
excludeRoute: argResults![ksExcludeRoute],
hasModel: argResults![ksModel],
templateType: templateType,
);

await _processService.runBuildRunner(appName: outputPath);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
} catch (e) {
_log.warn(message: e.toString());
}
Expand Down
12 changes: 6 additions & 6 deletions lib/src/commands/create/create_service_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,25 @@ class CreateServiceCommand extends Command with ProjectStructureValidator {
final serviceName = argResults!.rest.first;
final templateType = argResults![ksTemplateType];
unawaited(_analyticsService.createServiceEvent(name: serviceName));
final outputPath =
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;
await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: outputPath,
projectPath: workingDirectory,
);
_processService.formattingLineLength = argResults?[ksLineLength];
await _pubspecService.initialise(workingDirectory: outputPath);
await validateStructure(outputPath: outputPath);
await _pubspecService.initialise(workingDirectory: workingDirectory);
await validateStructure(outputPath: workingDirectory);

await _templateService.renderTemplate(
templateName: name,
name: serviceName,
outputPath: outputPath,
outputPath: workingDirectory,
verbose: true,
excludeRoute: argResults![ksExcludeDependency],
templateType: templateType,
);
await _processService.runBuildRunner(appName: outputPath);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
} catch (e) {
_log.warn(message: e.toString());
}
Expand Down
13 changes: 7 additions & 6 deletions lib/src/commands/create/create_view_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CreateViewCommand extends Command with ProjectStructureValidator {
defaultsTo: false,
help: kCommandHelpExcludeRoute,
);

argParser.addFlag(
ksV1,
aliases: [ksUseBuilder],
Expand Down Expand Up @@ -69,15 +70,15 @@ class CreateViewCommand extends Command with ProjectStructureValidator {
final viewName = argResults!.rest.first;
var templateType = argResults![ksTemplateType] as String?;
unawaited(_analyticsService.createViewEvent(name: viewName));
final outputPath =
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;
await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: outputPath,
projectPath: workingDirectory,
);
_processService.formattingLineLength = argResults![ksLineLength];
await _pubspecService.initialise(workingDirectory: outputPath);
await validateStructure(outputPath: outputPath);
await _pubspecService.initialise(workingDirectory: workingDirectory);
await validateStructure(outputPath: workingDirectory);

// Determine which template to use with the following rules:
// 1. If the template is supplied we use that template
Expand All @@ -88,13 +89,13 @@ class CreateViewCommand extends Command with ProjectStructureValidator {
await _templateService.renderTemplate(
templateName: name,
name: viewName,
outputPath: outputPath,
outputPath: workingDirectory,
verbose: true,
excludeRoute: argResults![ksExcludeRoute],
useBuilder: argResults![ksV1] ?? _configService.v1,
templateType: templateType,
);
await _processService.runBuildRunner(appName: outputPath);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
} catch (e) {
_log.warn(message: e.toString());
}
Expand Down
90 changes: 90 additions & 0 deletions lib/src/commands/create/create_widget_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import 'dart:async';

import 'package:args/command_runner.dart';
import 'package:stacked_cli/src/constants/command_constants.dart';
import 'package:stacked_cli/src/constants/message_constants.dart';
import 'package:stacked_cli/src/locator.dart';
import 'package:stacked_cli/src/mixins/project_structure_validator_mixin.dart';
import 'package:stacked_cli/src/services/analytics_service.dart';
import 'package:stacked_cli/src/services/colorized_log_service.dart';
import 'package:stacked_cli/src/services/config_service.dart';
import 'package:stacked_cli/src/services/process_service.dart';
import 'package:stacked_cli/src/services/pubspec_service.dart';
import 'package:stacked_cli/src/services/template_service.dart';
import 'package:stacked_cli/src/templates/template_constants.dart';

class CreateWidgetCommand extends Command with ProjectStructureValidator {
final _log = locator<ColorizedLogService>();
final _configService = locator<ConfigService>();
final _processService = locator<ProcessService>();
final _pubspecService = locator<PubspecService>();
final _templateService = locator<TemplateService>();
final _analyticsService = locator<AnalyticsService>();

@override
String get description => 'Creates a widget with their model file.';

@override
String get name => kTemplateNameWidget;

CreateWidgetCommand() {
argParser
..addOption(
ksLineLength,
abbr: 'l',
help: kCommandHelpLineLength,
valueHelp: '80',
)
..addOption(
ksTemplateType,
abbr: 't',
// TODO (Create Widget Templates): Generate a constant with these values
// when running the compile command
allowed: ['empty'],
defaultsTo: 'empty',
help: kCommandHelpCreateWidgetTemplate,
)
..addOption(
ksConfigPath,
abbr: 'c',
help: kCommandHelpConfigFilePath,
)
..addFlag(
ksModel,
defaultsTo: true,
help: kCommandHelpModel,
);
}

@override
Future<void> run() async {
try {
final widgetName = argResults!.rest.first;
final templateType = argResults![ksTemplateType];
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;

await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: workingDirectory,
);

_processService.formattingLineLength = argResults![ksLineLength];
await _pubspecService.initialise(workingDirectory: workingDirectory);
await validateStructure(outputPath: workingDirectory);

await _templateService.renderTemplate(
templateName: name,
name: widgetName,
outputPath: workingDirectory,
verbose: true,
hasModel: argResults![ksModel],
templateType: templateType,
);

unawaited(_analyticsService.createWidgetEvent(name: widgetName));
} catch (e) {
_log.warn(message: e.toString());
}
}
}
2 changes: 1 addition & 1 deletion lib/src/commands/delete/delete_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DeleteCommand extends Command {
String get name => 'delete';

DeleteCommand() {
addSubcommand(DeleteViewCommand());
addSubcommand(DeleteServiceCommand());
addSubcommand(DeleteViewCommand());
}
}
17 changes: 9 additions & 8 deletions lib/src/commands/delete/delete_service_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,19 @@ class DeleteServiceCommand extends Command with ProjectStructureValidator {
unawaited(_analyticsService.deleteServiceEvent(
name: argResults!.rest.first,
));
final outputPath = argResults!.rest.length > 1 ? argResults!.rest[1] : null;
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;
await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: outputPath,
projectPath: workingDirectory,
);
_processService.formattingLineLength = argResults?[ksLineLength];
await _pubspecService.initialise(workingDirectory: outputPath);
await validateStructure(outputPath: outputPath);
await deleteServiceAndTestFiles(outputPath: outputPath);
await removeServiceFromTestHelper(outputPath: outputPath);
await removeServiceFromDependency(outputPath: outputPath);
await _processService.runBuildRunner(appName: outputPath);
await _pubspecService.initialise(workingDirectory: workingDirectory);
await validateStructure(outputPath: workingDirectory);
await deleteServiceAndTestFiles(outputPath: workingDirectory);
await removeServiceFromTestHelper(outputPath: workingDirectory);
await removeServiceFromDependency(outputPath: workingDirectory);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
}

/// It deletes the service and test files
Expand Down
Loading

0 comments on commit b922402

Please sign in to comment.