Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
# Stacked CLI
# Stacked CLI - Extended Version with Subdirectory Support

The official CLI (Command Line Interface) dev tools for working with the Stacked framework. Stacked is a framework built in Flutter for production teams. It is built for maintenance, readability, and scaleability. To read about the usage of this tool read the [Stacked CLI docs](https://stacked.filledstacks.com/docs/Tooling/stacked-cli)

## πŸš€ Extended Features - Subdirectory Support

This version of the Stacked CLI has been extended to support creating components in subdirectories for better domain-driven organization:

### Create Views with Subdirectories
```bash
stacked create view sales/dashboard
stacked create view student/login
stacked create view signature_flow/client_form
```

### Create Services with Subdirectories
```bash
stacked create service api/auth
stacked create service sales/lead_management
```

### Create Other Components with Subdirectories
```bash
stacked create bottom_sheet forms/client_info
stacked create dialog alerts/error
stacked create widget charts/sales_graph
```

This enhancement allows for better organization by domain while maintaining full Stacked framework compatibility

## Running the code

_Todo: write out the steps to run this project locally_
Expand Down
19 changes: 11 additions & 8 deletions lib/src/commands/create/create_bottom_sheet_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ class CreateBottomSheetCommand extends Command with ProjectStructureValidator {
..addOption(
ksProjectPath,
help: kCommandHelpProjectPath,
)
..addFlag(
ksNoTest,
defaultsTo: false,
help: kCommandHelpNoTest,
);
}

Expand All @@ -85,19 +80,27 @@ class CreateBottomSheetCommand extends Command with ProjectStructureValidator {
await validateStructure(outputPath: argResults![ksProjectPath]);

for (var i = 0; i < bottomSheetNames.length; i++) {
// Parse the bottom sheet name to support subdirectories
final sheetPath = bottomSheetNames[i];
final pathParts = sheetPath.split('/');
final sheetName = pathParts.last;
final subfolders = pathParts.length > 1
? pathParts.sublist(0, pathParts.length - 1).join('/')
: null;

await _templateService.renderTemplate(
templateName: name,
name: bottomSheetNames[i],
name: sheetName,
subfolder: subfolders,
outputPath: argResults![ksProjectPath],
verbose: true,
excludeRoute: argResults![ksExcludeRoute],
hasModel: argResults![ksModel],
templateType: templateType,
noTest: argResults![ksNoTest],
);

await _analyticsService.createBottomSheetEvent(
name: bottomSheetNames[i],
name: sheetPath,
arguments: argResults!.arguments,
);
}
Expand Down
19 changes: 11 additions & 8 deletions lib/src/commands/create/create_dialog_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ class CreateDialogCommand extends Command with ProjectStructureValidator {
..addOption(
ksProjectPath,
help: kCommandHelpProjectPath,
)
..addFlag(
ksNoTest,
defaultsTo: false,
help: kCommandHelpNoTest,
);
}

Expand All @@ -85,19 +80,27 @@ class CreateDialogCommand extends Command with ProjectStructureValidator {
await validateStructure(outputPath: argResults![ksProjectPath]);

for (var i = 0; i < dialogNames.length; i++) {
// Parse the dialog name to support subdirectories
final dialogPath = dialogNames[i];
final pathParts = dialogPath.split('/');
final dialogName = pathParts.last;
final subfolders = pathParts.length > 1
? pathParts.sublist(0, pathParts.length - 1).join('/')
: null;

await _templateService.renderTemplate(
templateName: name,
name: dialogNames[i],
name: dialogName,
subfolder: subfolders,
outputPath: argResults![ksProjectPath],
verbose: true,
excludeRoute: argResults![ksExcludeRoute],
hasModel: argResults![ksModel],
templateType: templateType,
noTest: argResults![ksNoTest],
);

await _analyticsService.createDialogEvent(
name: dialogNames[i],
name: dialogPath,
arguments: argResults!.arguments,
);
}
Expand Down
19 changes: 11 additions & 8 deletions lib/src/commands/create/create_service_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,6 @@ class CreateServiceCommand extends Command with ProjectStructureValidator {
..addOption(
ksProjectPath,
help: kCommandHelpProjectPath,
)
..addFlag(
ksNoTest,
defaultsTo: false,
help: kCommandHelpNoTest,
);
}

Expand All @@ -80,18 +75,26 @@ class CreateServiceCommand extends Command with ProjectStructureValidator {
await validateStructure(outputPath: argResults![ksProjectPath]);

for (var i = 0; i < serviceNames.length; i++) {
// Parse the service name to support subdirectories
final servicePath = serviceNames[i];
final pathParts = servicePath.split('/');
final serviceName = pathParts.last;
final subfolders = pathParts.length > 1
? pathParts.sublist(0, pathParts.length - 1).join('/')
: null;

await _templateService.renderTemplate(
templateName: name,
name: serviceNames[i],
name: serviceName,
subfolder: subfolders,
outputPath: argResults![ksProjectPath],
verbose: true,
excludeRoute: argResults![ksExcludeDependency],
templateType: templateType,
noTest: argResults![ksNoTest],
);

await _analyticsService.createServiceEvent(
name: serviceNames[i],
name: servicePath,
arguments: argResults!.arguments,
);
}
Expand Down
20 changes: 12 additions & 8 deletions lib/src/commands/create/create_view_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ class CreateViewCommand extends Command with ProjectStructureValidator {
..addOption(
ksProjectPath,
help: kCommandHelpProjectPath,
)
..addFlag(
ksNoTest,
defaultsTo: false,
help: kCommandHelpNoTest,
);
}

Expand All @@ -93,19 +88,28 @@ class CreateViewCommand extends Command with ProjectStructureValidator {
templateType ??= _configService.preferWeb ? 'web' : 'empty';

for (var i = 0; i < viewNames.length; i++) {
// Parse the view name to support subdirectories
// e.g., "sales/dashboard" -> subfolder: "sales", viewName: "dashboard"
final viewPath = viewNames[i];
final pathParts = viewPath.split('/');
final viewName = pathParts.last;
final subfolders = pathParts.length > 1
? pathParts.sublist(0, pathParts.length - 1).join('/')
: null;

await _templateService.renderTemplate(
templateName: name,
name: viewNames[i],
name: viewName,
subfolder: subfolders,
outputPath: argResults![ksProjectPath],
verbose: true,
excludeRoute: argResults![ksExcludeRoute],
useBuilder: argResults![ksV1] ?? _configService.v1,
templateType: templateType,
noTest: argResults![ksNoTest],
);

await _analyticsService.createViewEvent(
name: viewNames[i],
name: viewPath,
arguments: argResults!.arguments,
);
}
Expand Down
19 changes: 11 additions & 8 deletions lib/src/commands/create/create_widget_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ class CreateWidgetCommand extends Command with ProjectStructureValidator {
..addOption(
ksProjectPath,
help: kCommandHelpProjectPath,
)
..addFlag(
ksNoTest,
defaultsTo: false,
help: kCommandHelpNoTest,
);
}

Expand All @@ -88,18 +83,26 @@ class CreateWidgetCommand extends Command with ProjectStructureValidator {
await validateStructure(outputPath: argResults![ksProjectPath]);

for (var i = 0; i < widgetNames.length; i++) {
// Parse the widget name to support subdirectories
final widgetPath = widgetNames[i];
final pathParts = widgetPath.split('/');
final widgetName = pathParts.last;
final subfolders = pathParts.length > 1
? pathParts.sublist(0, pathParts.length - 1).join('/')
: null;

await _templateService.renderTemplate(
templateName: name,
name: widgetNames[i],
name: widgetName,
subfolder: subfolders,
outputPath: argResults![ksProjectPath],
verbose: true,
hasModel: argResults![ksModel],
templateType: templateType,
noTest: argResults![ksNoTest],
);

await _analyticsService.createWidgetEvent(
name: widgetNames[i],
name: widgetPath,
arguments: argResults!.arguments,
);
}
Expand Down
39 changes: 32 additions & 7 deletions lib/src/commands/delete/delete_bottomsheet_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,15 @@ class DeleteBottomsheetCommand extends Command with ProjectStructureValidator {
try {
final workingDirectory =
argResults!.rest.length > 1 ? argResults!.rest[1] : null;
final bottomsheetName = argResults!.rest.first;

// Parse bottomsheet path to support subdirectories
final bottomsheetPath = argResults!.rest.first;
final pathParts = bottomsheetPath.split('/');
final bottomsheetName = pathParts.last;
final subfolder = pathParts.length > 1
? pathParts.sublist(0, pathParts.length - 1).join('/')
: null;

await _configService.composeAndLoadConfigFile(
configFilePath: argResults![ksConfigPath],
projectPath: workingDirectory,
Expand All @@ -67,9 +75,13 @@ class DeleteBottomsheetCommand extends Command with ProjectStructureValidator {

await validateStructure(outputPath: workingDirectory);
await _deletebottomsheet(
outputPath: workingDirectory, bottomsheetName: bottomsheetName);
outputPath: workingDirectory,
bottomsheetName: bottomsheetName,
subfolder: subfolder);
await _removebottomsheetFromDependency(
outputPath: workingDirectory, bottomsheetName: bottomsheetName);
outputPath: workingDirectory,
bottomsheetName: bottomsheetName,
subfolder: subfolder);
await _processService.runBuildRunner(workingDirectory: workingDirectory);
await _analyticsService.deleteBottomsheetEvent(
name: argResults!.rest.first,
Expand Down Expand Up @@ -98,12 +110,18 @@ class DeleteBottomsheetCommand extends Command with ProjectStructureValidator {
/// `outputPath` (String): The path to the output folder.
///
/// `bottomsheetName` (String): The name of the bottomsheet.
Future<void> _deletebottomsheet(
{String? outputPath, required String bottomsheetName}) async {
///
/// `subfolder` (String): Optional subfolder path for organized bottomsheets.
Future<void> _deletebottomsheet({
String? outputPath,
required String bottomsheetName,
String? subfolder,
}) async {
/// Deleting the bottomsheet folder.
String directoryPath = _templateService.getTemplateOutputPath(
inputTemplatePath: 'lib/ui/bottom_sheets/generic',
name: bottomsheetName,
subfolder: subfolder,
outputFolder: outputPath,
);
await _fileService.deleteFolder(directoryPath: directoryPath);
Expand All @@ -112,6 +130,7 @@ class DeleteBottomsheetCommand extends Command with ProjectStructureValidator {
final filePath = _templateService.getTemplateOutputPath(
inputTemplatePath: kBottomSheetEmptyTemplateGenericSheetModelTestPath,
name: bottomsheetName,
subfolder: subfolder,
outputFolder: outputPath,
);

Expand All @@ -128,11 +147,17 @@ class DeleteBottomsheetCommand extends Command with ProjectStructureValidator {
/// `outputPath` (String): The path to the output folder.
///
/// `bottomsheetName` (String): The name of the bottomsheet.
Future<void> _removebottomsheetFromDependency(
{String? outputPath, required String bottomsheetName}) async {
///
/// `subfolder` (String): Optional subfolder path for organized bottomsheets.
Future<void> _removebottomsheetFromDependency({
String? outputPath,
required String bottomsheetName,
String? subfolder,
}) async {
String filePath = _templateService.getTemplateOutputPath(
inputTemplatePath: kAppMobileTemplateAppPath,
name: bottomsheetName,
subfolder: subfolder,
outputFolder: outputPath,
);
await _fileService.removeSpecificFileLines(
Expand Down
Loading