Criando um app de terminal (CLI) para criar arquivos react #1
Tags: dotnet, csharp, cli, braziliandevs
Published: 2024-02-01 01:07:41

## Tabela de Conteúdos
 * [Parte 1: Ideia](#parte-1)
 * [Parte 2: Tecnologias](#parte-2)
 * [Parte 3: Criando Projeto](#parte-3)
 * [Parte 4: Configurando o app](#parte-4)
 * [Parte 5: Primeiro comando](#parte-5)
 * [Parte 6: Passando argumento](#parte-6)
 * [Final](#final)

## Parte 1: Ideia <a name="parte-1"></a>

A ideia desse artigo é apresentar a biblioteca **[Spectre.Console](https://spectreconsole.net)** e criar um aplicativo de linha de comando ou command line interface (CLI) em .Net que crie arquivos vazios para uso em desenvolvimento de projetos react.

## Parte 2: Tecnologias <a name="parte-2"></a>

O projeto vai utilizar como base (além do óbvio C# e .Net) a biblioteca **[Spectre.Console](https://spectreconsole.net)**.

### Pré-requisitos

- .Net 7.0 ou o 8.0
- IDE ou um editor de texto

## Parte 3: Criando Projeto <a name="parte-3"></a>

Abra o seu terminal e rode o comando a seguir na pasta que desejada, vai criar um novo projeto C# para o terminal.

```bash
dotnet new console -o reactcomponent
```

Acesse a pasta do projeto e abra o terminal novamente, rode os seguintes comandos para adicionar a biblioteca como referência ao projeto.

```bash
dotnet add package Spectre.Console
dotnet add package Spectre.Console.Cli
```

Acesse o projeto com sua IDE ou editor de texto preferido e abra o arquivo **Program.cs**, o arquivo deve se parecer com isso:

```csharp
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
```

Com isso podemos iniciar a usar a biblioteca, para rodarmos o **spectre.console** precisamos de um aplicativo do tipo CommandApp e que esse app receba os _args_ que serão passados ao rodar o programa no terminal. Vamos substituir o código antigo por esse:
```csharp
using Spectre.Console;
using Spectre.Console.Cli;

var app = new CommandApp();

app.Run(args);
```

Pronto, agora já temos a estrutura na qual o nosso programa vai funcionar. 

## Passo 4: Configurando o app <a name="parte-4"></a>

Com essa estrutura podemos configurar o aplicativo, é nessa configuração que podemos definir quais comando vão existir no aplicativo, entre outras configurações. Para isso precisamos apenas usar o método Configure do App.

 ```csharp
using Spectre.Console;
using Spectre.Console.Cli;

var app = new CommandApp();

app.Configure(app =>
{
//configuração
});

app.Run(args);
```

## Passo 5: Primeiro comando <a name="parte-5"></a>

Primeiramente, o que é um "comando"? Um comando é uma palavra chave que ao ser passada para o aplicativo (CLI) vai executar algo. Nesse post, queremos criar um comando que exibe o nome do componente passado como argumento ao comando.

No **spectre.console** cada comando que desejarmos criar deve herdar da classe **Command**. Com isso já podemos começar, vamos criar um arquivo **CreateComponentCommand.cs**. Neste arquivos vamos criar a classe CreateComponentCommand que vai herdar de Command.

```csharp
using Spectre.Console.Cli;

namespace reactcomponent;
internal class CreateComponentCommand: Command
{
}
```

Usando uma IDE ela vai avisar que a nossa classe não implementa o método **Execute** herdado da classe **Command**. Podemos implementar o método e ele vai ficar nessa estrutura:

```csharp
using Spectre.Console.Cli;

namespace reactcomponent;
internal class CreateComponentCommand: Command
{
    public override int Execute(CommandContext context)
    {
        throw new NotImplementedException();
    }
}
```

Nós não queremos que esse método lance uma exceção, por isso vamos substituir o conteúdo do método para exibir uma mensagem no console e retornar um valor inteiro, neste caso, o Zero, valor que indica que o código foi executado com sucesso.

```csharp
...
public override int Execute(CommandContext context)
{
    Console.WriteLine("comando executado");
    return 0;
}
```

Com isso já podemos fazer o nosso app usar esse comando. Para isso vamos no **Program.cs** e vamos adicionar essa classe ao nosso app e definir qual palavra será o comando para executar esse código.

```csharp
...
app.Configure(app =>
{
    app.AddCommand<CreateComponentCommand>("create");
});
...
```

Pronto, assim definimos que o nosso app terá o comando "create" que vai usar a nossa classe **CreateComponentCommand**.

Agora já podemos testar, vá no seu terminal e na pasta do projeto e digite:

```bash
dotnet run -- create
```

A saída no seu terminal deve ser igual a essa:
![Rodando o comando create no terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62o402synk4wo3g2t91f.png)

## Parte 6: Passando argumento <a name="parte-6"></a>

Agora já temos um programa operacional, mas inútil já ele que ele sempre exibe a mesma mensagem. E se a gente quisesse passar um valor a ser exibido, ou melhor, o nome do componente que desejamos criar?

Para isso o **specret.console** fornece a classe **CommandSettings** que vai ser a classe que vai conter as propriedades que passaremos como argumento. Vamos criar uma classe dentro do arquivo **CreateComponentCommand.cs** apenas pela facilidade.

```csharp
using Spectre.Console.Cli;

namespace reactcomponent;
internal class CreateComponentCommand : Command
{
  ...
}

internal class CreateComponentSettings : CommandSettings
{
    public string ComponentName { get; set; }
}
```

Agora temos uma classe **CreateComponentSettings** que vai conter os parâmetros que desejamos passar para executar um comando nesse caso o **CreateComponentCommand**. Mas neste momento a propriedade não vai ser reconhecida pela biblioteca e nem está configurada para ser usada no comando. Para isso vamos precisar adicionar um atributo, o **CommandArgument**, a essa propriedade que defina ela como um argumento.

```csharp
...

internal class CreateComponentSettings : CommandSettings
{
    [CommandArgument(0, "<componentName>")]
    public string ComponentName { get; set; }
}
```

OBS: O uso do **<** e **>** neste caso denota que esse valor é obrigatório e o 0 representa para a biblioteca que o primeiro valor após o nome do comando deve ser passado para essa propriedade.

Com isso precisamos agora informar que o nosso comando vai utilizar essa configuração. Para isso vamos adicionar um tipo a Command e precisamos adicionar um novo parâmetro ao método **Execute**.

```csharp
...
internal class CreateComponentCommand : Command<CreateComponentSettings>
{
    public override int Execute(CommandContext context, CreateComponentSettings settings)
    {
        Console.WriteLine("comando executado");
        return 0;
    }
}
...
```

Agora podemos utilizar o nome do componente que passarmos durante a execução do programa no terminal. Para isso vamos substituir o que está sendo impresso no terminal.

```csharp
...
public override int Execute(CommandContext context, CreateComponentSettings settings)
{
    Console.WriteLine($"nome do component {settings.ComponentName}");
    return 0;
}
...
```

Ao executarmos novamente o projeto no terminal, agora passando um valor como nome do componente:

```bash
dotnet run -- create Menu
```

Veremos algo assim: 

![Executando projeto com o comando create](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zqicif3glujtn963py5.png)


## Final <a name="final"></a>

Pronto com isso temos um pequeno aplicativo funcional, que por enquanto apenas recebe um valor e exibe ele na tela, mas na próxima parte faremos esse comando criar um arquivo com o nome passado.

[Github](https://github.com/jos3s/reactcomponent/tree/52c1bc5b3e780e385e62464f232e048965a40d19)