# DEK

[![npm package](https://nodei.co/npm/dek.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/dek/)

## O que é o DEK

O DEK é uma ferramenta de código aberto para a criação de novos projetos onde é preciso ter controle sobre o fluxo de inicialização e controle das execuções sejam elas síncronas ou assíncronas.

## Instalação
Se você deseja iniciar um novo projeto utilizando o Dek, na maioria dos casos, a melhor maneira é usar nossa **ferramenta CLI**.

```bash
$ npm install dek -g
```

## Criação de um novo projeto dek
Para criar um novo projeto Dek use o comando **```dek init```**.

```bash
$ dek init nomeDoProjetoDek
```


## Estrutura de pastas do DEK

Ao executar o **``dek init``**, a estrutura do diretório do seu projeto deve ser como o exemplo abaixo:
```
nomeDoProjetoDek
│-- README.md
│-- index.js  
│-- main.js
|-- package.json
|-- .env.example
└───loaders
    │-- AfterLoad.js
    │-- BeforeLoad.js
```

## Iniciando o seu projeto
Após criar o esqueleto do seu projeto, acesse o diretório

```bash
$ cd nomeDoProjetoDek
```

Ao acessar o diretório do projeto,
```bash
$ npm install
```

## Fluxo de carregamento

### O carregamento de uma **aplicação DEK** é dividido em 3 partes:

### 1. Before Load (loaders/BeforeLoad.js)
Nesse arquivo você define tudo o que precisa ser carregado antes da sua aplicação.

Um bom exemplo da sua utilidade é iniciar o mongodb, redis e outras conexões e dependências antes da sua lógica principal

Exemplo:
```javascript

import { dek, add } from 'dek'
import express from 'express'

export default async () => {
    console.log('(BeforeLoad.js) Aqui começa o fluxo de carregamento.')

    try{
        add('app', express())
    } catch (err) {
        console.log(err.message)
    }
}

```

**Atenção! Para esse exemplo em específico é necessário instalar o express** ```$ npm install express```

### 2. Main (main.js)
Este é o script onde a lógica da sua aplicação deve começar. Todas as dependências adicionadas no BeforeLoad.js estão disponíveis agora no escopo do projeto. Você pode acessar, por exemplo, através de *```dek.variavelAdicionadaAoEscopo``` (Ex: ```dek.express```)*  ou  *```let { variavelAdicionadaAoEscopo } = dek```*.

Exemplo:
```javascript

import { dek } from 'dek'

export default async () => {

    console.log('(main.js) Aqui inicia a sua aplicação')

    let { app } = dek

    app.get('/', (req, res) => {

        res.json({
            _id: "5c4a06735fa556025d0c460e",
            name: "Teste"
        })

    })

}

```


### 3. After Load (loaders/AfterLoad.js)
Após toda a sua aplicação ser carregada, o script de AfterLoad é chamado.

Exemplo:
```javascript

import { dek } from 'dek'

export default async () => {

    let { app } = dek

    try{
        await app.listen(3000)
        console.log('(express) Servidor conectado com sucesso na porta 3000!')
    } catch (err) {
        console.log(err)
    }

    console.log('(AfterLoad.js) O fluxo de carregamento da aplicação dek termina aqui.')    

}

```

## Executando sua aplicação DEK

Ao terminar de escrever o seu código nos scripts BeforeLoad.js, main.js e AfterLoad.js, execute o comando :

```bash
node index.js
```

ou

```bash
npm start
```

Seu terminal mostrará a ordem de carregamento dos arquivos do DEK. Mostrando a sequência de ações feitas dentro do código que você escreveu anteriormente.

```bash
(BeforeLoad.js) Aqui começa o fluxo de carregamento.
(main.js) Aqui inicia a sua aplicação
(express) Servidor conectado com sucesso na porta 3000!
(AfterLoad.js) O fluxo de carregamento da aplicação dek termina aqui.
```

Para testar se a sua aplicação está funcionando, acesse http://localhost:3000.

Se você seguir todas as instruções citadas acima, a api deverá retornar o resultado abaixo.

```json
{
  "_id": "5c4a06735fa556025d0c460e",
  "name": "Teste"
}
```

## Plugins
A ideia por trás do DEK é que ele sozinho apenas organize a ordem e carregamento da sua aplicação e nada mais. Quem dá poder a ele são seus plugins.

Imagine montar uma aplicação inteira apenas instalando plugins.

### Como funcionam os plugins?
Os plugins são carregados antes do ``BeforeLoad.js`` e seguem um **pattern** para que o DEK entenda o que deve ser feito em seu CORE.

### Como criar um plugin?
Para criar um novo plugin, execute o comando baixo:

```bash
$ dek new plugin HelloWorld
```

Ao executar este comando, a pasta ``plugins`` será criada junto de uma sub-pasta com o nome escolhido para o seu plugin.

```
└───plugins
    └───HelloWorld
        |-- main.js
        |-- npm.js

```

### Estrutura do plugin

#### main.js
O arquivo main.js contem a estrutura principal de um plugin. É o primeiro arquivo que o DEK vai ler ao carregar o seu plugin.

**O plugin conta com os seguintes atributos**
- **name**: Nome do seu plugin
- **version**: Versão do seu plugin seguindo o padrão [Semantic Version](https://semver.org/ "Clique aqui para saber mais sobre Semantic Version")
- **dependencies**: Lista de dependências que devem ser carregadas antes do plugin.
- **default**: Função principal de um plugin. Ela é executada na hora em que o sistema carrega o plugin.
  - **add**:
    - Função que adiciona uma variável ou função ao escopo do projeto.
    - No código gerado, a função ```add``` adiciona uma função vazia com o nome ```HelloWorld``` ao escopo do projeto.
- **cli**: Adiciona uma função ao CLI do dek. Seu funcionamento será explicado em mais detalhes posteriormente.
    - Ex: ```dek HelloWorld```
- **generator**: Adiciona uma função geradora ao CLI do dek. Seu funcionamento será explicado em mais detalhes posteriormente.
    - Ex:  ```dek new HelloWorld```


Veja abaixo um exemplo do código gerado:
```javascript
// plugins/HelloWorld/main.js

import { add } from 'dek'

export let name          =  'HelloWorld'
export let version       =  'v0.1.0'
export let dependencies  =  []

export default async (arg) => {

    add('HelloWorld', async () => {

    })

}

export let cli = {
    name: 'HelloWorld',
    action: async () => {

    }
}

export let generator = {
    name: 'HelloWorld',
    action: async () => {

    }
}

```


Adicione ``console.log('HelloWorld')`` dentro do callback da função add, como no exemplo abaixo.
```javascript
// plugins/HelloWorld/main.js

export default async (arg) => {

    add('HelloWorld', async () => {

    })

    console.log('HelloWorld')
}

```

Agora inicie sua aplicação novamente ``node index.js``
```bash
$ node index.js

HelloWold
(BeforeLoad.js) Aqui começa o fluxo de carregamento.
(main.js) Aqui inicia a sua aplicação
(express) Servidor conectado com sucesso na porta 3000!
(AfterLoad.js) O fluxo de carregamento da aplicação dek termina aqui.
```

Veja que **HelloWorld** foi exibido antes do fluxo de toda a aplicação. Esse é o momento exato onde os plugins são carregados. Mas não é só isso que os plugins são capazes de fazer.

#### A função add
A função add funciona de uma maneira muito simples. Você define uma variável que vai existir dentro do escopo DEK e em seguida define um valor ou função para ele.

Veja no exemplo abaixo como adicionar uma função chamada OlaMundo ao escopo DEK.

```javascript
// plugins/HelloWorld/main.js

export default async (arg) => {

    add('OlaMundo', async () => {
        console.log(' \n\nOLÁ MUNDOOOOO!!!!! ESSE É O MEU PRIMEIRO PLUGIN PARA O DEK\n\n ')
    })

    console.log('HelloWorld')
}

```

Pronto. Agora o escopo da nossa aplicação DEK conta com a função OlaMundo.

Para testar, abra o arquivo main.js da sua aplicação (não o main.js do plugin) e adicione as linhas abaixo:

```javascript
// main.js

import { dek } from 'dek'

export default async () => {

    console.log('(main.js) Aqui inicia a sua aplicação')

    let { app, OlaMundo } = dek // <--- OlaMundo foi chamado

    OlaMundo() // <--- A função OlaMundo foi executada

    app.get('/', (req, res) => {

        res.json({
            _id: "5c4a06735fa556025d0c460e",
            name: "Teste"
        })

    })

}

```

Inicie sua aplcação novamente. O resultado será exatamente como o do exemplo abaixo:

```bash
$ node index.js

HelloWold
(BeforeLoad.js) Aqui começa o fluxo de carregamento.
(main.js) Aqui inicia a sua aplicação


OLÁ MUNDOOOOO!!!!! ESSE É O MEU PRIMEIRO PLUGIN PARA O DEK


(express) Servidor conectado com sucesso na porta 3000!
(AfterLoad.js) O fluxo de carregamento da aplicação dek termina aqui.

```

#### O arquivo npm.js
Neste arquivo você define quais dependências do npm são necessárias para o plugin funcionar corretamente.

```javascript
// plugins/HelloWorld/npm.js

module.exports = {
    npm: []
}
```

Para exemplificar, vamos adicionar o pacote do npm chamado **chalk**

```javascript
// plugins/HelloWorld/npm.js

module.exports = {
    npm: ['chalk@2.4.2']
}
```

Adicione o chalk ao seu plugin
```javascript

// plugins/HelloWorld/main.js

import { add } from 'dek'
import chalk from 'chalk' // importa o pacote para o seu plugin

export let name          =  'HelloWorld'
export let version       =  'v0.1.0'
export let dependencies  =  []

export default async (arg) => {

    add('OlaMundo', async () => {
        console.log('\n\nOLÁ MUNDOOOOO!!!!! ESSE É O MEU PRIMEIRO PLUGIN PARA O DEK\n\n')
    })

    console.log(chalk.blue('HelloWorld')) // chalk.blue() deixa o texto do console.log() azul

}

// ...
```

Agora execute novamente sua aplicação

```bash
$ node index.js

(node:12321) UnhandledPromiseRejectionWarning: file:///home/dekDeveloper/exemplos/plugins/HelloWorld/main.js:1
Error: Cannot find module 'chalk'
(node:12321) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:12321) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

```

Perceba que o npm chalk não foi encontrado.

#### dek install
Para contornar este problema execute o comando ``dek install`` ou ``dek i ``

```bash
$ dek install
Instalando dependências

Repositório Express instalado com sucesso!

Repositório Controllers instalado com sucesso!

+ express@4.16.4
+ express@4.16.4
+ chalk@2.4.2
added 7 packages from 3 contributors, updated 1 package and audited 161 packages in 5.494s
found 0 vulnerabilities


npm WARN dek-skeleton@0.7.5 No description
```

Perceba que chalk foi instalado, mas espere...

Apareceram algumas linhas que nada tem a ver com o que estamos fazendo. Fique tranquilo que nos próximos exemplos você entenderá do que se trata.

Vamos voltar ao nosso exemplo.

Execute novamente a aplicação.

```bash
$ node index.js

HelloWorld
(BeforeLoad.js) Aqui começa o fluxo de carregamento.
(main.js) Aqui inicia a sua aplicação


OLÁ MUNDOOOOO!!!!! ESSE É O MEU PRIMEIRO PLUGIN PARA O DEK


(express) Servidor conectado com sucesso na porta 3000!
(AfterLoad.js) O fluxo de carregamento da aplicação dek termina aqui.

```

Perceba que HelloWorld agora aparece com uma linha azul e nosso plugin está terminado.

### Trabalhando com plugins em repositórios do GitHub e outros

Ao executarmos o comando ``dek install``, além de instalar a dependência **chalk@2.4.2** também instalamos dois plugins.
O plugin Express, responsável por adicioinar o express ai escopo DEK e o Controllers, responsável por gerar controllers para a nossa aplicação.

Abra o arquivo package.json e dê uma olhada no atributo ``dek dependencie`` (preste bem atenção, é dekDependencies e não devDependencies).

```json
  "dekDependencies": {
    "vigiadepreco/Express": "v1.0.0",
    "vigiadepreco/Controllers": "v1.0.1"
  }
```

Repare bem no padrão.

```json
"vigiadepreco/Express": "v1.0.0"
```

- vigiadepreco <- é a conta no gitgub
- Express <- é o nome do repositório
- v1.0.0 <- é a tag criada no repositório para marcar a versão

Você também pode adicionar essa dependência ao ``dekDependencies`` com os padrões:
- https: https://github.com/vigiadepreco/Express.git
- ssh: git@github.com:vigiadepreco/Express.git

Caso seu repositório seja privado, poderão ocorrer as seguintes situações:
- Caso seja https, seu nome de usuário e senha serão solicitados
- Caso seja ssh, o sistema utilizará a chave privada presente na sua máquina

Acesse a pasta **plugins** e veja que mais duas pastas foram criadas:
- Express
- Controllers

A partir desse momento, a instância do express criada no BeforeLoad.js não será mais necessária pois ela já é gerada dentro do plugin.

Remova as linhas de BeforeLoad.js abaixo:

```javascript
        // ...
        import express from 'express'
        // ...
        try{

            add('app', express())

        } catch (err) {
            console.log(err.message)
        }
        // ...

```
Seu arquivo BeforeLoad.js deverá ficar como no exemplo abaixo:

```javascript
import { dek, add } from 'dek'

export default async () => {
        console.log('(BeforeLoad.js) Aqui começa o fluxo de carregamento.')
}

```

Execute a sua aplicação novamente e verá que a api ainda está funcionando perfeitamente.
