Commandes
Introduction
Les commandes vous permettent d'etendre le CLI de Nylo Website avec des outils personnalises specifiques a votre projet. En heritant de NyCustomCommand, vous pouvez automatiser des taches repetitives, creer des workflows de deploiement, generer du code ou ajouter toute fonctionnalite dont vous avez besoin directement dans votre terminal.
Chaque commande personnalisee a acces a un riche ensemble de helpers integres pour les E/S de fichiers, JSON/YAML, les invites interactives, les spinners, les barres de progression, les requetes API, et plus encore -- le tout sans importer de packages supplementaires.
Note : Les commandes personnalisees s'executent en dehors du runtime Flutter. Vous ne pouvez pas importer
nylo_framework.dartdans vos commandes. Utilisezny_cli.darta la place.
Creer des commandes
Creez une nouvelle commande en utilisant Metro ou le CLI Dart :
metro make:command current_time
Vous pouvez specifier une categorie pour votre commande en utilisant l'option --category :
metro make:command current_time --category="project"
Cela cree un nouveau fichier dans lib/app/commands/current_time.dart et l'enregistre dans le registre des commandes.
Structure d'une commande
Chaque commande etend NyCustomCommand et implemente deux methodes cles :
builder()-- configurer les options et les drapeauxhandle()-- executer la logique de la commande
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");
}
}
Executer des commandes
Executez votre commande en utilisant Metro ou Dart :
metro app:current_time
Le nom de la commande suit le modele categorie:nom. Lorsque vous executez metro sans arguments, les commandes personnalisees apparaissent dans la section Custom Commands :
[Custom Commands]
app:current_time
project:install_firebase
project:deploy
Pour afficher l'aide d'une commande :
metro app:current_time --help
Registre des commandes
Toutes les commandes personnalisees sont enregistrees dans lib/app/commands/commands.json. Ce fichier est mis a jour automatiquement lorsque vous utilisez make:command :
[
{
"name": "install_firebase",
"category": "project",
"script": "install_firebase.dart"
},
{
"name": "current_time",
"category": "app",
"script": "current_time.dart"
}
]
Chaque entree contient :
| Champ | Description |
|---|---|
name |
Le nom de la commande (utilise apres le prefixe de categorie) |
category |
La categorie de la commande (par ex. app, project) |
script |
Le fichier Dart dans lib/app/commands/ |
Options et drapeaux
Configurez les options et les drapeaux de votre commande dans la methode builder() en utilisant CommandBuilder.
Ajouter des options
Les options acceptent une valeur de l'utilisateur :
@override
CommandBuilder builder(CommandBuilder command) {
command.addOption(
'environment',
abbr: 'e',
help: 'Target deployment environment',
defaultValue: 'development',
allowed: ['development', 'staging', 'production'],
);
return command;
}
Utilisation :
metro project:deploy --environment=production
# or using abbreviation
metro project:deploy -e production
| Parametre | Type | Description |
|---|---|---|
name |
String |
Nom de l'option |
abbr |
String? |
Abreviation d'un seul caractere |
help |
String? |
Texte d'aide affiche avec --help |
allowed |
List<String>? |
Restreindre aux valeurs autorisees |
defaultValue |
String? |
Valeur par defaut si non fournie |
Ajouter des drapeaux
Les drapeaux sont des interrupteurs booleens :
@override
CommandBuilder builder(CommandBuilder command) {
command.addFlag(
'verbose',
abbr: 'v',
help: 'Enable verbose output',
defaultValue: false,
);
return command;
}
Utilisation :
metro project:deploy --verbose
metro project:deploy -v
| Parametre | Type | Description |
|---|---|---|
name |
String |
Nom du drapeau |
abbr |
String? |
Abreviation d'un seul caractere |
help |
String? |
Texte d'aide affiche avec --help |
defaultValue |
bool |
Valeur par defaut (par defaut : false) |
Resultat de la commande
La methode handle() recoit un objet CommandResult avec des accesseurs types pour lire les options, drapeaux et arguments analyses.
@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;
}
| Methode / Propriete | Retourne | Description |
|---|---|---|
getString(String name, {String? defaultValue}) |
String? |
Obtenir une valeur de type chaine |
getBool(String name, {bool? defaultValue}) |
bool? |
Obtenir une valeur booleenne |
getInt(String name, {int? defaultValue}) |
int? |
Obtenir une valeur entiere |
get<T>(String name) |
T? |
Obtenir une valeur typee |
hasForceFlag |
bool |
Si --force a ete passe |
hasHelpFlag |
bool |
Si --help a ete passe |
arguments |
List<String> |
Tous les arguments de la ligne de commande |
rest |
List<String> |
Arguments restants non analyses |
Saisie interactive
NyCustomCommand fournit des methodes pour collecter les saisies de l'utilisateur dans le terminal.
Saisie de texte
// 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:');
| Parametre | Type | Description |
|---|---|---|
question |
String |
La question a afficher |
defaultValue |
String |
Valeur par defaut si l'utilisateur appuie sur Entree (par defaut : '') |
Confirmation
if (confirm('Would you like to continue?', defaultValue: true)) {
await runProcess('flutter pub get');
} else {
info('Operation canceled');
}
| Parametre | Type | Description |
|---|---|---|
question |
String |
La question oui/non |
defaultValue |
bool |
Reponse par defaut (par defaut : false) |
Selection unique
final environment = select(
'Select deployment environment:',
['development', 'staging', 'production'],
defaultOption: 'development',
);
| Parametre | Type | Description |
|---|---|---|
question |
String |
Le texte de l'invite |
options |
List<String> |
Choix disponibles |
defaultOption |
String? |
Option pre-selectionnee |
Selection multiple
final packages = multiSelect(
'Select packages to install:',
['firebase_auth', 'dio', 'provider', 'shared_preferences'],
);
if (packages.isNotEmpty) {
addPackages(packages);
await runProcess('flutter pub get');
}
L'utilisateur saisit des numeros separes par des virgules ou "all".
Saisie secrete
final apiKey = promptSecret('Enter your API key:');
La saisie est masquee dans le terminal. Revient a une saisie visible si le mode echo n'est pas supporte.
Formatage de la sortie
Methodes pour afficher une sortie stylisee dans la 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
}
| Methode | Description |
|---|---|
info(String message) |
Afficher du texte bleu |
error(String message) |
Afficher du texte rouge |
success(String message) |
Afficher du texte vert |
warning(String message) |
Afficher du texte jaune |
line(String message) |
Afficher du texte brut (sans couleur) |
newLine([int count = 1]) |
Afficher des lignes vides |
comment(String message) |
Afficher du texte gris/attenue |
alert(String message) |
Afficher une boite d'alerte encadree |
abort([String? message, int exitCode = 1]) |
Quitter la commande avec une erreur |
Spinner et progression
Les spinners et les barres de progression fournissent un retour visuel pendant les operations de longue duree.
Utiliser withSpinner
Encapsulez une tache asynchrone avec un spinner automatique :
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');
| Parametre | Type | Description |
|---|---|---|
task |
Future<T> Function() |
La fonction asynchrone a executer |
message |
String |
Texte affiche pendant l'execution du spinner |
successMessage |
String? |
Affiche en cas de succes |
errorMessage |
String? |
Affiche en cas d'echec |
Controle manuel du spinner
Pour les workflows a plusieurs etapes, creez un spinner et controlez-le manuellement :
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);
}
Methodes de ConsoleSpinner :
| Methode | Description |
|---|---|
start([String? message]) |
Demarrer l'animation du spinner |
update(String message) |
Modifier le message affiche |
stop({String? completionMessage, bool success = true}) |
Arreter le spinner |
Barre de progression
Creez et gerez une barre de progression manuellement :
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');
Methodes de ConsoleProgressBar :
| Methode / Propriete | Description |
|---|---|
start() |
Demarrer la barre de progression |
tick([int amount = 1]) |
Incrementer la progression |
update(int value) |
Definir la progression a une valeur specifique |
updateMessage(String newMessage) |
Modifier le message affiche |
complete([String? completionMessage]) |
Terminer avec un message optionnel |
stop() |
Arreter sans terminer |
current |
Valeur de progression actuelle (getter) |
percentage |
Progression en pourcentage 0-100 (getter) |
Traiter des elements avec progression
Traitez une liste d'elements avec un suivi automatique de la progression :
// 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
Le helper api fournit un wrapper simplifie autour de Dio pour effectuer des requetes 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},
)
);
Combinez avec withSpinner pour une meilleure experience utilisateur :
final data = await withSpinner(
task: () => api((request) =>
request.get('https://api.example.com/config')
),
message: 'Loading configuration',
);
ApiService supporte les methodes get, post, put, delete et patch, chacune acceptant des parametres optionnels queryParameters, data, options et cancelToken.
Helpers du systeme de fichiers
Helpers integres pour le systeme de fichiers afin que vous n'ayez pas besoin d'importer 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');
| Methode | Description |
|---|---|
fileExists(String path) |
Retourne true si le fichier existe |
directoryExists(String path) |
Retourne true si le repertoire existe |
readFile(String path) |
Lire le fichier en tant que chaine (asynchrone) |
readFileSync(String path) |
Lire le fichier en tant que chaine (synchrone) |
writeFile(String path, String content) |
Ecrire du contenu dans un fichier (asynchrone) |
writeFileSync(String path, String content) |
Ecrire du contenu dans un fichier (synchrone) |
appendFile(String path, String content) |
Ajouter du contenu a un fichier |
ensureDirectory(String path) |
Creer le repertoire s'il n'existe pas |
deleteFile(String path) |
Supprimer un fichier |
copyFile(String source, String destination) |
Copier un fichier |
Helpers JSON et YAML
Lisez et ecrivez des fichiers JSON et YAML avec les helpers integres :
// 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']}');
| Methode | Description |
|---|---|
readJson(String path) |
Lire un fichier JSON en tant que Map<String, dynamic> |
readJsonArray(String path) |
Lire un fichier JSON en tant que List<dynamic> |
writeJson(String path, dynamic data, {bool pretty = true}) |
Ecrire des donnees au format JSON |
appendToJsonArray(String path, Map item, {String? uniqueKey}) |
Ajouter a un fichier de tableau JSON |
readYaml(String path) |
Lire un fichier YAML en tant que Map<String, dynamic> |
Manipulation de fichiers Dart
Helpers pour editer programmatiquement des fichiers source Dart -- utiles lors de la creation d'outils de 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'),
);
| Methode | Description |
|---|---|
addImport(String filePath, String importStatement) |
Ajouter un import a un fichier Dart (ignore si deja present) |
insertBeforeClosingBrace(String filePath, String code) |
Inserer du code avant le dernier } du fichier |
fileContains(String filePath, String identifier) |
Verifier si un fichier contient une chaine |
fileContainsPattern(String filePath, Pattern pattern) |
Verifier si un fichier correspond a un motif |
Helpers de repertoires
Helpers pour travailler avec les repertoires et rechercher des fichiers :
// 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');
| Methode | Description |
|---|---|
listDirectory(String path, {bool recursive = false}) |
Lister le contenu d'un repertoire |
findFiles(String directory, {String? extension, Pattern? namePattern, bool recursive = true}) |
Trouver des fichiers correspondant aux criteres |
deleteDirectory(String path) |
Supprimer un repertoire recursivement |
copyDirectory(String source, String destination) |
Copier un repertoire recursivement |
Helpers de conversion de casse
Convertissez des chaines entre les conventions de nommage sans importer le package 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
| Methode | Format de sortie | Exemple |
|---|---|---|
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 |
Helpers de chemins du projet
Getters pour les repertoires standard d'un projet Nylo Website, retournant des chemins relatifs a la racine du projet :
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
| Propriete | Chemin |
|---|---|
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) |
Resout un chemin relatif dans le projet |
Helpers de plateforme
Verifiez la plateforme et accedez aux variables d'environnement :
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');
| Propriete / Methode | Description |
|---|---|
isWindows |
true si execution sur Windows |
isMacOS |
true si execution sur macOS |
isLinux |
true si execution sur Linux |
workingDirectory |
Chemin du repertoire de travail actuel |
env(String key, [String defaultValue = '']) |
Lire une variable d'environnement systeme |
Commandes Dart et Flutter
Executez des commandes courantes du CLI Dart et Flutter en tant que methodes helper. Chacune retourne le code de sortie du processus :
// 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/');
| Methode | Description |
|---|---|
dartFormat(String path) |
Executer dart format sur un fichier ou repertoire |
dartAnalyze([String? path]) |
Executer dart analyze |
flutterPubGet() |
Executer flutter pub get |
flutterClean() |
Executer flutter clean |
flutterBuild(String target, {List<String> args}) |
Executer flutter build <target> |
flutterTest([String? path]) |
Executer flutter test |
Helpers de validation
Helpers pour valider et nettoyer les saisies utilisateur pour la generation de code :
// 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'
| Methode | Description |
|---|---|
isValidDartIdentifier(String name) |
Valider un nom d'identifiant Dart |
requireArgument(CommandResult result, {String? message}) |
Exiger un premier argument non vide ou abandonner |
cleanClassName(String name, {List<String> removeSuffixes}) |
Nettoyer et mettre en PascalCase un nom de classe |
cleanFileName(String name, {String extension = '.dart'}) |
Nettoyer et mettre en snake_case un nom de fichier |
Scaffolding de fichiers
Creez un ou plusieurs fichiers avec du contenu en utilisant le systeme de scaffolding.
Fichier unique
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',
);
| Parametre | Type | Description |
|---|---|---|
path |
String |
Chemin du fichier a creer |
content |
String |
Contenu du fichier |
force |
bool |
Ecraser si existant (par defaut : false) |
successMessage |
String? |
Message affiche en cas de succes |
Fichiers multiples
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 :
| Propriete | Type | Description |
|---|---|---|
path |
String |
Chemin du fichier a creer |
content |
String |
Contenu du fichier |
successMessage |
String? |
Message affiche en cas de succes |
Executeur de taches
Executez une serie de taches nommees avec une sortie de statut automatique.
Executeur de taches basique
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,
),
]);
Executeur de taches avec spinner
await runTasksWithSpinner([
CommandTask(
'Preparing release',
() async {
await flutterClean();
await flutterPubGet();
},
),
CommandTask(
'Building APK',
() => flutterBuild('apk', args: ['--release']),
),
]);
La classe CommandTask :
| Propriete | Type | Defaut | Description |
|---|---|---|---|
name |
String |
requis | Nom de la tache affiche dans la sortie |
action |
Future<void> Function() |
requis | Fonction asynchrone a executer |
stopOnError |
bool |
true |
Arreter les taches restantes en cas d'echec |
Sortie en tableau
Affichez des tableaux ASCII formates dans la console :
table(
['Name', 'Version', 'Status'],
[
['nylo_framework', '7.0.0', 'installed'],
['nylo_support', '7.0.0', 'installed'],
['dio', '5.4.0', 'installed'],
],
);
Sortie :
┌─────────────────┬─────────┬───────────┐
│ Name │ Version │ Status │
├─────────────────┼─────────┼───────────┤
│ nylo_framework │ 7.0.0 │ installed │
│ nylo_support │ 7.0.0 │ installed │
│ dio │ 5.4.0 │ installed │
└─────────────────┴─────────┴───────────┘
Exemples
Commande heure actuelle
Une commande simple qui affiche l'heure actuelle :
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");
}
}
Commande de telechargement de polices
Une commande qui telecharge et installe des polices Google Fonts dans le projet :
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');
}
}
}
Commande de pipeline de deploiement
Une commande qui execute un pipeline de deploiement complet en utilisant l'executeur de taches :
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(),
);
}
}