Comandi
Introduzione
I comandi ti permettono di estendere la CLI di Nylo Website con strumenti personalizzati specifici per il progetto. Estendendo NyCustomCommand, puoi automatizzare attivita' ripetitive, costruire workflow di deploy, generare codice o aggiungere qualsiasi funzionalita' di cui hai bisogno direttamente nel tuo terminale.
Ogni comando personalizzato ha accesso a un ricco set di helper integrati per I/O su file, JSON/YAML, prompt interattivi, spinner, barre di progresso, richieste API e altro ancora -- il tutto senza importare pacchetti aggiuntivi.
Nota: I comandi personalizzati vengono eseguiti al di fuori del runtime Flutter. Non puoi importare
nylo_framework.dartnei tuoi comandi. Usa inveceny_cli.dart.
Creare Comandi
Crea un nuovo comando utilizzando Metro o la CLI Dart:
metro make:command current_time
Puoi specificare una categoria per il tuo comando utilizzando l'opzione --category:
metro make:command current_time --category="project"
Questo crea un nuovo file in lib/app/commands/current_time.dart e lo registra nel registro dei comandi.
Struttura del Comando
Ogni comando estende NyCustomCommand e implementa due metodi chiave:
builder()-- configura opzioni e flaghandle()-- esegue la logica del comando
import 'package:nylo_framework/metro/ny_cli.dart';
void main(arguments) => _CurrentTimeCommand(arguments).run();
/// Current Time Command
///
/// Usage:
/// metro app:current_time
class _CurrentTimeCommand extends NyCustomCommand {
_CurrentTimeCommand(super.arguments);
@override
CommandBuilder builder(CommandBuilder command) {
command.addOption('format', defaultValue: 'HH:mm:ss');
return command;
}
@override
Future<void> handle(CommandResult result) async {
final format = result.getString("format");
info("Current time format: $format");
}
}
Eseguire Comandi
Esegui il tuo comando utilizzando Metro o Dart:
metro app:current_time
Il nome del comando segue il formato categoria:nome. Quando esegui metro senza argomenti, i comandi personalizzati appaiono nella sezione Custom Commands:
[Custom Commands]
app:current_time
project:install_firebase
project:deploy
Per visualizzare l'aiuto per un comando:
metro app:current_time --help
Registro dei Comandi
Tutti i comandi personalizzati sono registrati in lib/app/commands/commands.json. Questo file viene aggiornato automaticamente quando usi make:command:
[
{
"name": "install_firebase",
"category": "project",
"script": "install_firebase.dart"
},
{
"name": "current_time",
"category": "app",
"script": "current_time.dart"
}
]
Ogni voce contiene:
| Campo | Descrizione |
|---|---|
name |
Il nome del comando (usato dopo il prefisso della categoria) |
category |
La categoria del comando (es. app, project) |
script |
Il file Dart in lib/app/commands/ |
Opzioni e Flag
Configura le opzioni e i flag del tuo comando nel metodo builder() utilizzando CommandBuilder.
Aggiungere Opzioni
Le opzioni accettano un valore dall'utente:
@override
CommandBuilder builder(CommandBuilder command) {
command.addOption(
'environment',
abbr: 'e',
help: 'Target deployment environment',
defaultValue: 'development',
allowed: ['development', 'staging', 'production'],
);
return command;
}
Utilizzo:
metro project:deploy --environment=production
# or using abbreviation
metro project:deploy -e production
| Parametro | Tipo | Descrizione |
|---|---|---|
name |
String |
Nome dell'opzione |
abbr |
String? |
Abbreviazione a singolo carattere |
help |
String? |
Testo di aiuto mostrato con --help |
allowed |
List<String>? |
Limita ai valori consentiti |
defaultValue |
String? |
Valore predefinito se non fornito |
Aggiungere Flag
I flag sono interruttori booleani:
@override
CommandBuilder builder(CommandBuilder command) {
command.addFlag(
'verbose',
abbr: 'v',
help: 'Enable verbose output',
defaultValue: false,
);
return command;
}
Utilizzo:
metro project:deploy --verbose
metro project:deploy -v
| Parametro | Tipo | Descrizione |
|---|---|---|
name |
String |
Nome del flag |
abbr |
String? |
Abbreviazione a singolo carattere |
help |
String? |
Testo di aiuto mostrato con --help |
defaultValue |
bool |
Valore predefinito (default: false) |
Risultato del Comando
Il metodo handle() riceve un oggetto CommandResult con accessori tipizzati per leggere opzioni, flag e argomenti analizzati.
@override
Future<void> handle(CommandResult result) async {
// Get a string option
final name = result.getString('name');
// Get a boolean flag
final verbose = result.getBool('verbose');
// Get an integer option
final count = result.getInt('count');
// Generic typed access
final value = result.get<String>('key');
// Built-in flag checks
if (result.hasForceFlag) { /* --force was passed */ }
if (result.hasHelpFlag) { /* --help was passed */ }
// Raw arguments
List<String> allArgs = result.arguments;
List<String> unparsed = result.rest;
}
| Metodo / Proprieta' | Ritorna | Descrizione |
|---|---|---|
getString(String name, {String? defaultValue}) |
String? |
Ottieni il valore stringa |
getBool(String name, {bool? defaultValue}) |
bool? |
Ottieni il valore booleano |
getInt(String name, {int? defaultValue}) |
int? |
Ottieni il valore intero |
get<T>(String name) |
T? |
Ottieni il valore tipizzato |
hasForceFlag |
bool |
Se --force e' stato passato |
hasHelpFlag |
bool |
Se --help e' stato passato |
arguments |
List<String> |
Tutti gli argomenti della riga di comando |
rest |
List<String> |
Argomenti residui non analizzati |
Input Interattivo
NyCustomCommand fornisce metodi per raccogliere l'input dell'utente nel terminale.
Input Testuale
// Ask a question with optional default
final name = prompt('What is your project name?', defaultValue: 'my_app');
// ask() is an alias for prompt()
final description = ask('Enter a description:');
| Parametro | Tipo | Descrizione |
|---|---|---|
question |
String |
La domanda da visualizzare |
defaultValue |
String |
Valore predefinito se l'utente preme Invio (default: '') |
Conferma
if (confirm('Would you like to continue?', defaultValue: true)) {
await runProcess('flutter pub get');
} else {
info('Operation canceled');
}
| Parametro | Tipo | Descrizione |
|---|---|---|
question |
String |
La domanda si/no |
defaultValue |
bool |
Risposta predefinita (default: false) |
Selezione Singola
final environment = select(
'Select deployment environment:',
['development', 'staging', 'production'],
defaultOption: 'development',
);
| Parametro | Tipo | Descrizione |
|---|---|---|
question |
String |
Il testo del prompt |
options |
List<String> |
Le scelte disponibili |
defaultOption |
String? |
Opzione preselezionata |
Selezione Multipla
final packages = multiSelect(
'Select packages to install:',
['firebase_auth', 'dio', 'provider', 'shared_preferences'],
);
if (packages.isNotEmpty) {
addPackages(packages);
await runProcess('flutter pub get');
}
L'utente inserisce numeri separati da virgola oppure "all".
Input Segreto
final apiKey = promptSecret('Enter your API key:');
L'input viene nascosto dalla visualizzazione nel terminale. Se la modalita' echo non e' supportata, viene usato l'input visibile come fallback.
Formattazione dell'Output
Metodi per stampare output formattato nella console:
@override
Future<void> handle(CommandResult result) async {
info('Processing files...'); // Blue text
error('Operation failed'); // Red text
success('Deployment complete'); // Green text
warning('Outdated package'); // Yellow text
line('Plain text output'); // No color
comment('Background note'); // Gray text
alert('Important notice'); // Bordered alert box
newLine(); // One blank line
newLine(3); // Three blank lines
// Exit the command with an error
abort('Fatal error occurred'); // Prints red, exits with code 1
}
| Metodo | Descrizione |
|---|---|
info(String message) |
Stampa testo blu |
error(String message) |
Stampa testo rosso |
success(String message) |
Stampa testo verde |
warning(String message) |
Stampa testo giallo |
line(String message) |
Stampa testo semplice (senza colore) |
newLine([int count = 1]) |
Stampa righe vuote |
comment(String message) |
Stampa testo grigio/attenuato |
alert(String message) |
Stampa un riquadro di avviso con bordo |
abort([String? message, int exitCode = 1]) |
Esce dal comando con un errore |
Spinner e Progresso
Gli spinner e le barre di progresso forniscono un feedback visivo durante operazioni di lunga durata.
Utilizzare withSpinner
Avvolgi un'attivita' asincrona con uno spinner automatico:
final projectFiles = await withSpinner(
task: () async {
await sleep(2);
return ['pubspec.yaml', 'lib/main.dart', 'README.md'];
},
message: 'Analyzing project structure',
successMessage: 'Project analysis complete',
errorMessage: 'Failed to analyze project',
);
info('Found ${projectFiles.length} key files');
| Parametro | Tipo | Descrizione |
|---|---|---|
task |
Future<T> Function() |
La funzione asincrona da eseguire |
message |
String |
Testo mostrato durante l'esecuzione dello spinner |
successMessage |
String? |
Mostrato in caso di successo |
errorMessage |
String? |
Mostrato in caso di errore |
Controllo Manuale dello Spinner
Per workflow a piu' passaggi, crea uno spinner e controllalo manualmente:
final spinner = createSpinner('Deploying to production');
spinner.start();
try {
await runProcess('flutter clean', silent: true);
spinner.update('Building release version');
await runProcess('flutter build web --release', silent: true);
spinner.update('Uploading to server');
await runProcess('./deploy.sh', silent: true);
spinner.stop(completionMessage: 'Deployment completed', success: true);
} catch (e) {
spinner.stop(completionMessage: 'Deployment failed: $e', success: false);
}
Metodi di ConsoleSpinner:
| Metodo | Descrizione |
|---|---|
start([String? message]) |
Avvia l'animazione dello spinner |
update(String message) |
Cambia il messaggio visualizzato |
stop({String? completionMessage, bool success = true}) |
Ferma lo spinner |
Barra di Progresso
Crea e gestisci una barra di progresso manualmente:
final progress = progressBar(100, message: 'Processing files');
progress.start();
for (int i = 0; i < 100; i++) {
await Future.delayed(Duration(milliseconds: 50));
progress.tick();
}
progress.complete('All files processed');
Metodi di ConsoleProgressBar:
| Metodo / Proprieta' | Descrizione |
|---|---|
start() |
Avvia la barra di progresso |
tick([int amount = 1]) |
Incrementa il progresso |
update(int value) |
Imposta il progresso a un valore specifico |
updateMessage(String newMessage) |
Cambia il messaggio visualizzato |
complete([String? completionMessage]) |
Completa con messaggio opzionale |
stop() |
Ferma senza completare |
current |
Valore corrente del progresso (getter) |
percentage |
Progresso in percentuale 0-100 (getter) |
Elaborazione di Elementi con Progresso
Elabora una lista di elementi con tracciamento automatico del progresso:
// Async processing
final results = await withProgress<File, String>(
items: findFiles('lib/', extension: '.dart'),
process: (file, index) async {
return file.path;
},
message: 'Analyzing Dart files',
completionMessage: 'Analysis complete',
);
// Synchronous processing
final upperItems = withProgressSync<String, String>(
items: ['a', 'b', 'c', 'd', 'e'],
process: (item, index) => item.toUpperCase(),
message: 'Converting items',
);
Helper API
L'helper api fornisce un wrapper semplificato attorno a Dio per effettuare richieste HTTP:
// GET request
final userData = await api((request) =>
request.get('https://api.example.com/users/1')
);
// POST request
final result = await api((request) =>
request.post(
'https://api.example.com/items',
data: {'name': 'New Item', 'price': 19.99},
)
);
// PUT request
final updateResult = await api((request) =>
request.put(
'https://api.example.com/items/42',
data: {'name': 'Updated Item', 'price': 29.99},
)
);
// DELETE request
final deleteResult = await api((request) =>
request.delete('https://api.example.com/items/42')
);
// PATCH request
final patchResult = await api((request) =>
request.patch(
'https://api.example.com/items/42',
data: {'price': 24.99},
)
);
// With query parameters
final searchResults = await api((request) =>
request.get(
'https://api.example.com/search',
queryParameters: {'q': 'keyword', 'limit': 10},
)
);
Combina con withSpinner per una migliore esperienza utente:
final data = await withSpinner(
task: () => api((request) =>
request.get('https://api.example.com/config')
),
message: 'Loading configuration',
);
ApiService supporta i metodi get, post, put, delete e patch, ognuno dei quali accetta opzionalmente queryParameters, data, options e cancelToken.
Helper per il File System
Helper integrati per il file system, cosi' non devi importare dart:io:
// Check existence
if (fileExists('lib/config/app.dart')) { /* ... */ }
if (directoryExists('lib/app/models')) { /* ... */ }
// Read files
String content = await readFile('pubspec.yaml');
String contentSync = readFileSync('pubspec.yaml');
// Write files
await writeFile('lib/generated/output.dart', 'class Output {}');
writeFileSync('lib/generated/output.dart', 'class Output {}');
// Append to a file
await appendFile('log.txt', 'New log entry\n');
// Ensure a directory exists
await ensureDirectory('lib/generated');
// Delete and copy files
await deleteFile('lib/generated/output.dart');
await copyFile('lib/config/app.dart', 'lib/config/app.bak.dart');
| Metodo | Descrizione |
|---|---|
fileExists(String path) |
Restituisce true se il file esiste |
directoryExists(String path) |
Restituisce true se la directory esiste |
readFile(String path) |
Legge il file come stringa (asincrono) |
readFileSync(String path) |
Legge il file come stringa (sincrono) |
writeFile(String path, String content) |
Scrive il contenuto nel file (asincrono) |
writeFileSync(String path, String content) |
Scrive il contenuto nel file (sincrono) |
appendFile(String path, String content) |
Aggiunge contenuto al file |
ensureDirectory(String path) |
Crea la directory se non esiste |
deleteFile(String path) |
Elimina un file |
copyFile(String source, String destination) |
Copia un file |
Helper JSON e YAML
Leggi e scrivi file JSON e YAML con gli helper integrati:
// Read JSON as Map
Map<String, dynamic> config = await readJson('config.json');
// Read JSON as List
List<dynamic> items = await readJsonArray('lib/app/commands/commands.json');
// Write JSON (pretty printed by default)
await writeJson('output.json', {'name': 'MyApp', 'version': '1.0.0'});
// Write compact JSON
await writeJson('output.json', data, pretty: false);
// Append to a JSON array file (with duplicate prevention)
await appendToJsonArray(
'lib/app/commands/commands.json',
{'name': 'my_command', 'category': 'app', 'script': 'my_command.dart'},
uniqueKey: 'name',
);
// Read YAML as Map
Map<String, dynamic> pubspec = await readYaml('pubspec.yaml');
info('Project: ${pubspec['name']}');
| Metodo | Descrizione |
|---|---|
readJson(String path) |
Legge un file JSON come Map<String, dynamic> |
readJsonArray(String path) |
Legge un file JSON come List<dynamic> |
writeJson(String path, dynamic data, {bool pretty = true}) |
Scrive dati come JSON |
appendToJsonArray(String path, Map item, {String? uniqueKey}) |
Aggiunge a un file di array JSON |
readYaml(String path) |
Legge un file YAML come Map<String, dynamic> |
Manipolazione di File Dart
Helper per modificare programmaticamente file sorgente Dart -- utili quando si costruiscono strumenti di scaffolding:
// Add an import (skips if already present)
await addImport(
'lib/bootstrap/providers.dart',
"import '/app/providers/firebase_provider.dart';",
);
// Insert code before the last closing brace
await insertBeforeClosingBrace(
'lib/bootstrap/providers.dart',
' FirebaseProvider(),',
);
// Check if a file contains a string
bool hasImport = await fileContains(
'lib/bootstrap/providers.dart',
'firebase_provider',
);
// Check if a file matches a regex pattern
bool hasClass = await fileContainsPattern(
'lib/app/models/user.dart',
RegExp(r'class User'),
);
| Metodo | Descrizione |
|---|---|
addImport(String filePath, String importStatement) |
Aggiunge un import al file Dart (salta se presente) |
insertBeforeClosingBrace(String filePath, String code) |
Inserisce codice prima dell'ultima } nel file |
fileContains(String filePath, String identifier) |
Verifica se il file contiene una stringa |
fileContainsPattern(String filePath, Pattern pattern) |
Verifica se il file corrisponde a un pattern |
Helper per le Directory
Helper per lavorare con directory e trovare file:
// List directory contents
var entities = listDirectory('lib/app/models');
var allEntities = listDirectory('lib/', recursive: true);
// Find files by extension
List<File> dartFiles = findFiles(
'lib/app/models',
extension: '.dart',
recursive: true,
);
// Find files by name pattern
List<File> testFiles = findFiles(
'test/',
namePattern: RegExp(r'_test\.dart$'),
);
// Delete a directory recursively
await deleteDirectory('build/');
// Copy a directory recursively
await copyDirectory('lib/templates', 'lib/generated');
| Metodo | Descrizione |
|---|---|
listDirectory(String path, {bool recursive = false}) |
Elenca il contenuto della directory |
findFiles(String directory, {String? extension, Pattern? namePattern, bool recursive = true}) |
Trova file corrispondenti ai criteri |
deleteDirectory(String path) |
Elimina la directory ricorsivamente |
copyDirectory(String source, String destination) |
Copia la directory ricorsivamente |
Helper per la Conversione di Formato
Converti stringhe tra diverse convenzioni di denominazione senza importare il pacchetto recase:
String input = 'user profile page';
snakeCase(input); // user_profile_page
camelCase(input); // userProfilePage
pascalCase(input); // UserProfilePage
titleCase(input); // User Profile Page
kebabCase(input); // user-profile-page
constantCase(input); // USER_PROFILE_PAGE
| Metodo | Formato di Output | Esempio |
|---|---|---|
snakeCase(String input) |
snake_case |
user_profile |
camelCase(String input) |
camelCase |
userProfile |
pascalCase(String input) |
PascalCase |
UserProfile |
titleCase(String input) |
Title Case |
User Profile |
kebabCase(String input) |
kebab-case |
user-profile |
constantCase(String input) |
CONSTANT_CASE |
USER_PROFILE |
Helper per i Percorsi del Progetto
Getter per le directory standard del progetto Nylo Website, che restituiscono percorsi relativi alla radice del progetto:
info(modelsPath); // lib/app/models
info(controllersPath); // lib/app/controllers
info(widgetsPath); // lib/resources/widgets
info(pagesPath); // lib/resources/pages
info(commandsPath); // lib/app/commands
info(configPath); // lib/config
info(providersPath); // lib/app/providers
info(eventsPath); // lib/app/events
info(networkingPath); // lib/app/networking
info(themesPath); // lib/resources/themes
// Build a custom path
String customPath = projectPath('app/services/auth_service.dart');
// Returns: lib/app/services/auth_service.dart
| Proprieta' | Percorso |
|---|---|
modelsPath |
lib/app/models |
controllersPath |
lib/app/controllers |
widgetsPath |
lib/resources/widgets |
pagesPath |
lib/resources/pages |
commandsPath |
lib/app/commands |
configPath |
lib/config |
providersPath |
lib/app/providers |
eventsPath |
lib/app/events |
networkingPath |
lib/app/networking |
themesPath |
lib/resources/themes |
projectPath(String relativePath) |
Risolve un percorso relativo all'interno del progetto |
Helper per la Piattaforma
Verifica la piattaforma e accedi alle variabili d'ambiente:
if (isWindows) {
info('Running on Windows');
} else if (isMacOS) {
info('Running on macOS');
} else if (isLinux) {
info('Running on Linux');
}
info('Working in: $workingDirectory');
String home = env('HOME', '/default/path');
| Proprieta' / Metodo | Descrizione |
|---|---|
isWindows |
true se in esecuzione su Windows |
isMacOS |
true se in esecuzione su macOS |
isLinux |
true se in esecuzione su Linux |
workingDirectory |
Percorso della directory di lavoro corrente |
env(String key, [String defaultValue = '']) |
Legge una variabile d'ambiente di sistema |
Comandi Dart e Flutter
Esegui comandi comuni della CLI Dart e Flutter come metodi helper. Ognuno restituisce il codice di uscita del processo:
// Format a Dart file or directory
await dartFormat('lib/app/models/user.dart');
// Run dart analyze
int analyzeResult = await dartAnalyze('lib/');
// Run flutter pub get
await flutterPubGet();
// Run flutter clean
await flutterClean();
// Build for a target with additional args
await flutterBuild('apk', args: ['--release', '--split-per-abi']);
await flutterBuild('web', args: ['--release']);
// Run flutter test
await flutterTest();
await flutterTest('test/unit/');
| Metodo | Descrizione |
|---|---|
dartFormat(String path) |
Esegue dart format su un file o directory |
dartAnalyze([String? path]) |
Esegue dart analyze |
flutterPubGet() |
Esegue flutter pub get |
flutterClean() |
Esegue flutter clean |
flutterBuild(String target, {List<String> args}) |
Esegue flutter build <target> |
flutterTest([String? path]) |
Esegue flutter test |
Helper per la Validazione
Helper per validare e pulire l'input dell'utente per la generazione di codice:
// Validate a Dart identifier
if (!isValidDartIdentifier('MyClass')) {
error('Invalid Dart identifier');
}
// Require a non-empty first argument (aborts if missing)
String name = requireArgument(result, message: 'Please provide a name');
// Clean a class name (PascalCase, remove suffixes)
String className = cleanClassName('user_model', removeSuffixes: ['_model']);
// Returns: 'User'
// Clean a file name (snake_case with extension)
String fileName = cleanFileName('UserModel', extension: '.dart');
// Returns: 'user_model.dart'
| Metodo | Descrizione |
|---|---|
isValidDartIdentifier(String name) |
Valida un nome identificatore Dart |
requireArgument(CommandResult result, {String? message}) |
Richiede un primo argomento non vuoto oppure interrompe |
cleanClassName(String name, {List<String> removeSuffixes}) |
Pulisce e converte in PascalCase un nome di classe |
cleanFileName(String name, {String extension = '.dart'}) |
Pulisce e converte in snake_case un nome di file |
Scaffolding di File
Crea uno o piu' file con contenuto utilizzando il sistema di scaffolding.
File Singolo
await scaffold(
path: 'lib/app/services/auth_service.dart',
content: '''
class AuthService {
Future<bool> login(String email, String password) async {
return false;
}
}
''',
force: false,
successMessage: 'AuthService created',
);
| Parametro | Tipo | Descrizione |
|---|---|---|
path |
String |
Percorso del file da creare |
content |
String |
Contenuto del file |
force |
bool |
Sovrascrive se esiste (default: false) |
successMessage |
String? |
Messaggio mostrato in caso di successo |
File Multipli
await scaffoldMany([
ScaffoldFile(
path: 'lib/app/models/product.dart',
content: 'class Product {}',
successMessage: 'Product model created',
),
ScaffoldFile(
path: 'lib/app/networking/product_api_service.dart',
content: 'class ProductApiService {}',
successMessage: 'Product API service created',
),
], force: false);
La classe ScaffoldFile:
| Proprieta' | Tipo | Descrizione |
|---|---|---|
path |
String |
Percorso del file da creare |
content |
String |
Contenuto del file |
successMessage |
String? |
Messaggio mostrato in caso di successo |
Task Runner
Esegui una serie di task con nome e output di stato automatico.
Task Runner Base
await runTasks([
CommandTask(
'Clean project',
() => runProcess('flutter clean', silent: true),
),
CommandTask(
'Fetch dependencies',
() => runProcess('flutter pub get', silent: true),
),
CommandTask(
'Run tests',
() => runProcess('flutter test', silent: true),
stopOnError: true,
),
]);
Task Runner con Spinner
await runTasksWithSpinner([
CommandTask(
'Preparing release',
() async {
await flutterClean();
await flutterPubGet();
},
),
CommandTask(
'Building APK',
() => flutterBuild('apk', args: ['--release']),
),
]);
La classe CommandTask:
| Proprieta' | Tipo | Default | Descrizione |
|---|---|---|---|
name |
String |
obbligatorio | Nome del task mostrato nell'output |
action |
Future<void> Function() |
obbligatorio | Funzione asincrona da eseguire |
stopOnError |
bool |
true |
Se fermare i task rimanenti in caso di errore |
Output a Tabella
Visualizza tabelle ASCII formattate nella console:
table(
['Name', 'Version', 'Status'],
[
['nylo_framework', '7.0.0', 'installed'],
['nylo_support', '7.0.0', 'installed'],
['dio', '5.4.0', 'installed'],
],
);
Output:
┌─────────────────┬─────────┬───────────┐
│ Name │ Version │ Status │
├─────────────────┼─────────┼───────────┤
│ nylo_framework │ 7.0.0 │ installed │
│ nylo_support │ 7.0.0 │ installed │
│ dio │ 5.4.0 │ installed │
└─────────────────┴─────────┴───────────┘
Esempi
Comando Ora Corrente
Un semplice comando che visualizza l'ora corrente:
import 'package:nylo_framework/metro/ny_cli.dart';
void main(arguments) => _CurrentTimeCommand(arguments).run();
class _CurrentTimeCommand extends NyCustomCommand {
_CurrentTimeCommand(super.arguments);
@override
CommandBuilder builder(CommandBuilder command) {
command.addOption('format', defaultValue: 'HH:mm:ss');
return command;
}
@override
Future<void> handle(CommandResult result) async {
final format = result.getString("format");
final now = DateTime.now();
info("The current time is ${now.toIso8601String()}");
info("Requested format: $format");
}
}
Comando Download Font
Un comando che scarica e installa Google Fonts nel progetto:
import 'package:nylo_framework/metro/ny_cli.dart';
void main(arguments) => _DownloadFontsCommand(arguments).run();
class _DownloadFontsCommand extends NyCustomCommand {
_DownloadFontsCommand(super.arguments);
@override
CommandBuilder builder(CommandBuilder command) {
command.addOption('font', abbr: 'f', help: 'Font family name');
command.addFlag('verbose', abbr: 'v', defaultValue: false);
return command;
}
@override
Future<void> handle(CommandResult result) async {
final fontName = result.getString('font') ??
prompt('Enter font family name:', defaultValue: 'Roboto');
final verbose = result.getBool('verbose') ?? false;
await withSpinner(
task: () async {
await ensureDirectory('assets/fonts');
final fontData = await api((request) =>
request.get('https://fonts.google.com/download?family=$fontName')
);
if (fontData != null) {
await writeFile('assets/fonts/$fontName.ttf', fontData.toString());
}
},
message: 'Downloading $fontName font',
successMessage: '$fontName font installed',
errorMessage: 'Failed to download $fontName',
);
if (verbose) {
info('Font saved to: assets/fonts/$fontName.ttf');
}
}
}
Comando Pipeline di Deploy
Un comando che esegue una pipeline completa di deploy utilizzando il task runner:
import 'package:nylo_framework/metro/ny_cli.dart';
void main(arguments) => _DeployCommand(arguments).run();
class _DeployCommand extends NyCustomCommand {
_DeployCommand(super.arguments);
@override
CommandBuilder builder(CommandBuilder command) {
command.addOption(
'environment',
abbr: 'e',
defaultValue: 'development',
allowed: ['development', 'staging', 'production'],
);
command.addFlag('skip-tests', defaultValue: false);
return command;
}
@override
Future<void> handle(CommandResult result) async {
final env = result.getString('environment') ?? 'development';
final skipTests = result.getBool('skip-tests') ?? false;
alert('Deploying to $env');
newLine();
if (env == 'production') {
if (!confirm('Are you sure you want to deploy to production?')) {
abort('Deployment canceled');
}
}
final tasks = <CommandTask>[
CommandTask('Clean project', () => flutterClean()),
CommandTask('Fetch dependencies', () => flutterPubGet()),
];
if (!skipTests) {
tasks.add(CommandTask(
'Run tests',
() => flutterTest(),
stopOnError: true,
));
}
tasks.add(CommandTask(
'Build for web',
() => flutterBuild('web', args: ['--release']),
));
await runTasksWithSpinner(tasks);
newLine();
success('Deployment to $env completed');
table(
['Step', 'Status'],
tasks.map((t) => [t.name, 'Done']).toList(),
);
}
}